Skip to content

Commit

Permalink
feat(FormikPeoplePicker): implement FormikNormalPicker, FormikCompact…
Browse files Browse the repository at this point in the history
…PeoplePicker and FormikListPeoplePicker
  • Loading branch information
kevicency committed Dec 9, 2018
1 parent a8d9ae9 commit 348f20f
Show file tree
Hide file tree
Showing 6 changed files with 446 additions and 3 deletions.
76 changes: 76 additions & 0 deletions src/FormikPeoplePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { FieldProps } from 'formik'
import {
CompactPeoplePicker,
IPeoplePickerProps,
ListPeoplePicker,
NormalPeoplePicker,
} from 'office-ui-fabric-react'
import * as React from 'react'
import { createFakeEvent, Omit } from './utils'

export function mapFieldToPeoplePicker<T = any>({
form,
field,
}: FieldProps<T>): Pick<
IPeoplePickerProps,
'selectedItems' | 'onChange' | 'onBlur'
> {
return {
selectedItems: field.value,
onBlur: () => field.onBlur(createFakeEvent(field)),
onChange: items => form.setFieldValue(field.name, items),
}
}
export type FormikPeoplePickerProps<T = any> = Omit<
IPeoplePickerProps,
'selectedItems' | 'onBlur' | 'onChange'
> &
FieldProps<T>

export function FormikNormalPeoplePicker<T = any>({
field,
form,
...props
}: FormikPeoplePickerProps<T>) {
return (
<NormalPeoplePicker
{...props}
{...mapFieldToPeoplePicker({
field,
form,
})}
/>
)
}

export function FormikCompactPeoplePicker<T = any>({
field,
form,
...props
}: FormikPeoplePickerProps<T>) {
return (
<CompactPeoplePicker
{...props}
{...mapFieldToPeoplePicker({
field,
form,
})}
/>
)
}

export function FormikListPeoplePicker<T = any>({
field,
form,
...props
}: FormikPeoplePickerProps<T>) {
return (
<ListPeoplePicker
{...props}
{...mapFieldToPeoplePicker({
field,
form,
})}
/>
)
}
110 changes: 110 additions & 0 deletions src/__tests__/FormikPeoplePicker.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// tslint:disable:jsx-no-lambda

import { Field, FieldProps, Form, Formik } from 'formik'
import {
CompactPeoplePicker,
IPersonaProps,
ListPeoplePicker,
NormalPeoplePicker,
setIconOptions,
} from 'office-ui-fabric-react'
import * as React from 'react'
import renderer from 'react-test-renderer'
import {
FormikCompactPeoplePicker,
FormikListPeoplePicker,
FormikNormalPeoplePicker,
mapFieldToPeoplePicker,
} from '../FormikPeoplePicker'
import { noop, serialize } from './utils'

// Suppress icon warnings.
setIconOptions({
disableWarnings: true,
})

const personas = [
{ text: 'Foo Bar', secondaryText: 'foo@bar.com' },
{ text: 'Jane Doe', secondaryText: 'jane@doe.com' },
{ text: 'John Doe', secondaryText: 'john@doe.com' },
]
const handleResolveSuggestions = (filter: string): IPersonaProps[] =>
personas.filter(x => x.text !== filter && x.secondaryText !== filter)
function createFieldProps(): FieldProps<{ people: IPersonaProps[] }> {
return {
field: {
value: [personas[0]],
onChange: jest.fn(),
onBlur: jest.fn(),
name: 'isChecked',
},
form: { setFieldValue: jest.fn(), handleBlur: jest.fn(() => jest.fn()) },
} as any
}

;[
[FormikNormalPeoplePicker, NormalPeoplePicker],
[FormikCompactPeoplePicker, CompactPeoplePicker],
[FormikListPeoplePicker, ListPeoplePicker],
].forEach(([FormikPeoplePicker, PeoplePicker]: any[]) => {
test(`<${
FormikPeoplePicker.name
} /> renders correctly as a field component`, () => {
const component = renderer.create(
<Formik initialValues={{ isChecked: true }} onSubmit={noop}>
<Form>
<Field
name="test"
render={(fieldProps: FieldProps<any>) => (
<FormikPeoplePicker
{...fieldProps}
onResolveSuggestions={handleResolveSuggestions}
/>
)}
/>
</Form>
</Formik>
)

expect(component.toJSON()).toMatchSnapshot()
})

test(`<${FormikPeoplePicker.name} /> renders a Fabric <${
PeoplePicker.name
} />`, () => {
const fieldProps = createFieldProps()

const formikPeoplePicker = renderer.create(
<FormikPeoplePicker
{...fieldProps}
onResolveSuggestions={handleResolveSuggestions}
/>
)
const fabricPeoplePicker = renderer.create(
<PeoplePicker
{...mapFieldToPeoplePicker(fieldProps)}
onResolveSuggestions={handleResolveSuggestions}
/>
)
expect(serialize(formikPeoplePicker)).toBe(serialize(fabricPeoplePicker))
})
})

test('mapFieldToPeoplePicker() maps FieldProps to IPeoplePickerProps', () => {
const { field, form } = createFieldProps()
const props = mapFieldToPeoplePicker({ form, field })

expect(props.selectedItems).toBe(field.value)

props.onChange!(personas.slice(0, 2))

expect(form.setFieldValue).toHaveBeenCalledTimes(1)
expect(form.setFieldValue).toHaveBeenCalledWith(
field.name,
personas.slice(0, 2)
)

props.onBlur!(null as any)

expect(field.onBlur).toHaveBeenCalled()
})
191 changes: 191 additions & 0 deletions src/__tests__/__snapshots__/FormikPeoplePicker.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<FormikCompactPeoplePicker /> renders correctly as a field component 1`] = `
<form
onReset={[Function]}
onSubmit={[Function]}
>
<div
className="ms-BasePicker"
onKeyDown={[Function]}
>
<div
className="ms-FocusZone"
data-focuszone-id="FocusZone26"
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
role="presentation"
>
<div
className="ms-SelectionZone"
onClick={[Function]}
onContextMenu={[Function]}
onDoubleClick={[Function]}
onFocusCapture={[Function]}
onKeyDown={[Function]}
onKeyDownCapture={[Function]}
onMouseDown={[Function]}
onMouseDownCapture={[Function]}
role="presentation"
>
<div
className="ms-BasePicker-text pickerText_e7c83bc9"
>
<span
className="pickerItems_e7c83bc9"
id="selected-items-id__25"
role="list"
/>
<input
aria-autocomplete="both"
aria-controls=" "
aria-describedby="selected-items-id__25"
aria-expanded={false}
aria-haspopup="true"
autoCapitalize="off"
autoComplete="off"
className="ms-BasePicker-input pickerInput_e7c83bc9"
data-lpignore={true}
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onCompositionEnd={[Function]}
onCompositionStart={[Function]}
onFocus={[Function]}
onInput={[Function]}
onKeyDown={[Function]}
role="combobox"
value=""
/>
</div>
</div>
</div>
</div>
</form>
`;

exports[`<FormikListPeoplePicker /> renders correctly as a field component 1`] = `
<form
onReset={[Function]}
onSubmit={[Function]}
>
<div>
<div
className="ms-BasePicker"
onKeyDown={[Function]}
>
<div
className="ms-BasePicker-text pickerText_e7c83bc9"
>
<input
aria-controls=" "
aria-expanded={false}
aria-haspopup="true"
autoCapitalize="off"
autoComplete="off"
className="ms-BasePicker-input pickerInput_e7c83bc9"
data-lpignore={true}
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onCompositionEnd={[Function]}
onCompositionStart={[Function]}
onFocus={[Function]}
onInput={[Function]}
onKeyDown={[Function]}
role="combobox"
value=""
/>
</div>
</div>
<div
className="ms-SelectionZone"
onClick={[Function]}
onContextMenu={[Function]}
onDoubleClick={[Function]}
onFocusCapture={[Function]}
onKeyDown={[Function]}
onKeyDownCapture={[Function]}
onMouseDown={[Function]}
onMouseDownCapture={[Function]}
role="presentation"
>
<div
className="ms-FocusZone ms-BasePicker-selectedItems"
data-focuszone-id="FocusZone50"
id="selected-items-id__49"
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
role="presentation"
/>
</div>
</div>
</form>
`;

exports[`<FormikNormalPeoplePicker /> renders correctly as a field component 1`] = `
<form
onReset={[Function]}
onSubmit={[Function]}
>
<div
className="ms-BasePicker"
onKeyDown={[Function]}
>
<div
className="ms-FocusZone"
data-focuszone-id="FocusZone2"
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
role="presentation"
>
<div
className="ms-SelectionZone"
onClick={[Function]}
onContextMenu={[Function]}
onDoubleClick={[Function]}
onFocusCapture={[Function]}
onKeyDown={[Function]}
onKeyDownCapture={[Function]}
onMouseDown={[Function]}
onMouseDownCapture={[Function]}
role="presentation"
>
<div
className="ms-BasePicker-text pickerText_e7c83bc9"
>
<span
className="pickerItems_e7c83bc9"
id="selected-items-id__1"
role="list"
/>
<input
aria-autocomplete="both"
aria-controls=" "
aria-describedby="selected-items-id__1"
aria-expanded={false}
aria-haspopup="true"
autoCapitalize="off"
autoComplete="off"
className="ms-BasePicker-input pickerInput_e7c83bc9"
data-lpignore={true}
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onCompositionEnd={[Function]}
onCompositionStart={[Function]}
onFocus={[Function]}
onInput={[Function]}
onKeyDown={[Function]}
role="combobox"
value=""
/>
</div>
</div>
</div>
</div>
</form>
`;
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './FormikCheckbox'
export * from './FormikChoiceGroup'
export * from './FormikDatePicker'
export * from './FormikDropdown'
export * from './FormikPeoplePicker'
export * from './FormikRating'
export * from './FormikSlider'
export * from './FormikTextField'
Expand Down
Loading

0 comments on commit 348f20f

Please sign in to comment.