@toptal/picasso-forms 6.0.4 → 6.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +657 -0
- package/{Autocomplete → dist-package/Autocomplete}/Autocomplete.d.ts +0 -0
- package/{Autocomplete → dist-package/Autocomplete}/Autocomplete.js +0 -0
- package/{Autocomplete → dist-package/Autocomplete}/Autocomplete.js.map +0 -0
- package/{Autocomplete → dist-package/Autocomplete}/index.d.ts +0 -0
- package/{Autocomplete → dist-package/Autocomplete}/index.js +0 -0
- package/{Autocomplete → dist-package/Autocomplete}/index.js.map +0 -0
- package/{ButtonCheckbox → dist-package/ButtonCheckbox}/ButtonCheckbox.d.ts +0 -0
- package/{ButtonCheckbox → dist-package/ButtonCheckbox}/ButtonCheckbox.js +0 -0
- package/{ButtonCheckbox → dist-package/ButtonCheckbox}/ButtonCheckbox.js.map +0 -0
- package/{ButtonCheckbox → dist-package/ButtonCheckbox}/index.d.ts +0 -0
- package/{ButtonCheckbox → dist-package/ButtonCheckbox}/index.js +0 -0
- package/{ButtonCheckbox → dist-package/ButtonCheckbox}/index.js.map +0 -0
- package/{ButtonRadio → dist-package/ButtonRadio}/ButtonRadio.d.ts +0 -0
- package/{ButtonRadio → dist-package/ButtonRadio}/ButtonRadio.js +0 -0
- package/{ButtonRadio → dist-package/ButtonRadio}/ButtonRadio.js.map +0 -0
- package/{ButtonRadio → dist-package/ButtonRadio}/index.d.ts +0 -0
- package/{ButtonRadio → dist-package/ButtonRadio}/index.js +0 -0
- package/{ButtonRadio → dist-package/ButtonRadio}/index.js.map +0 -0
- package/{Checkbox → dist-package/Checkbox}/Checkbox.d.ts +0 -0
- package/{Checkbox → dist-package/Checkbox}/Checkbox.js +0 -0
- package/{Checkbox → dist-package/Checkbox}/Checkbox.js.map +0 -0
- package/{Checkbox → dist-package/Checkbox}/index.d.ts +0 -0
- package/{Checkbox → dist-package/Checkbox}/index.js +0 -0
- package/{Checkbox → dist-package/Checkbox}/index.js.map +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroup.d.ts +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroup.js +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroup.js.map +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroupContext.d.ts +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroupContext.js +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroupContext.js.map +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/index.d.ts +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/index.js +0 -0
- package/{CheckboxGroup → dist-package/CheckboxGroup}/index.js.map +0 -0
- package/{DatePicker → dist-package/DatePicker}/DatePicker.d.ts +0 -0
- package/{DatePicker → dist-package/DatePicker}/DatePicker.js +0 -0
- package/{DatePicker → dist-package/DatePicker}/DatePicker.js.map +0 -0
- package/{DatePicker → dist-package/DatePicker}/index.d.ts +0 -0
- package/{DatePicker → dist-package/DatePicker}/index.js +0 -0
- package/{DatePicker → dist-package/DatePicker}/index.js.map +0 -0
- package/{FieldWrapper → dist-package/FieldWrapper}/FieldWrapper.d.ts +0 -0
- package/{FieldWrapper → dist-package/FieldWrapper}/FieldWrapper.js +0 -0
- package/{FieldWrapper → dist-package/FieldWrapper}/FieldWrapper.js.map +0 -0
- package/{FieldWrapper → dist-package/FieldWrapper}/index.d.ts +0 -0
- package/{FieldWrapper → dist-package/FieldWrapper}/index.js +0 -0
- package/{FieldWrapper → dist-package/FieldWrapper}/index.js.map +0 -0
- package/{FileInput → dist-package/FileInput}/FileInput.d.ts +0 -0
- package/{FileInput → dist-package/FileInput}/FileInput.js +0 -0
- package/{FileInput → dist-package/FileInput}/FileInput.js.map +0 -0
- package/{FileInput → dist-package/FileInput}/index.d.ts +0 -0
- package/{FileInput → dist-package/FileInput}/index.js +0 -0
- package/{FileInput → dist-package/FileInput}/index.js.map +0 -0
- package/{Form → dist-package/Form}/Form.d.ts +0 -0
- package/{Form → dist-package/Form}/Form.js +0 -0
- package/{Form → dist-package/Form}/Form.js.map +0 -0
- package/{Form → dist-package/Form}/FormContext.d.ts +0 -0
- package/{Form → dist-package/Form}/FormContext.js +0 -0
- package/{Form → dist-package/Form}/FormContext.js.map +0 -0
- package/{Form → dist-package/Form}/index.d.ts +0 -0
- package/{Form → dist-package/Form}/index.js +0 -0
- package/{Form → dist-package/Form}/index.js.map +0 -0
- package/{FormConfig → dist-package/FormConfig}/FormConfig.d.ts +0 -0
- package/{FormConfig → dist-package/FormConfig}/FormConfig.js +0 -0
- package/{FormConfig → dist-package/FormConfig}/FormConfig.js.map +0 -0
- package/{FormConfig → dist-package/FormConfig}/index.d.ts +0 -0
- package/{FormConfig → dist-package/FormConfig}/index.js +0 -0
- package/{FormConfig → dist-package/FormConfig}/index.js.map +0 -0
- package/{Input → dist-package/Input}/Input.d.ts +0 -0
- package/{Input → dist-package/Input}/Input.js +0 -0
- package/{Input → dist-package/Input}/Input.js.map +0 -0
- package/{Input → dist-package/Input}/index.d.ts +0 -0
- package/{Input → dist-package/Input}/index.js +0 -0
- package/{Input → dist-package/Input}/index.js.map +0 -0
- package/{Input → dist-package/Input}/utils/get-input-name.d.ts +0 -0
- package/{Input → dist-package/Input}/utils/get-input-name.js +0 -0
- package/{Input → dist-package/Input}/utils/get-input-name.js.map +0 -0
- package/{Input → dist-package/Input}/utils/get-input-name.test.d.ts +0 -0
- package/{Input → dist-package/Input}/utils/get-input-name.test.js +0 -0
- package/{Input → dist-package/Input}/utils/get-input-name.test.js.map +0 -0
- package/{NumberInput → dist-package/NumberInput}/NumberInput.d.ts +0 -0
- package/{NumberInput → dist-package/NumberInput}/NumberInput.js +0 -0
- package/{NumberInput → dist-package/NumberInput}/NumberInput.js.map +0 -0
- package/{NumberInput → dist-package/NumberInput}/index.d.ts +0 -0
- package/{NumberInput → dist-package/NumberInput}/index.js +0 -0
- package/{NumberInput → dist-package/NumberInput}/index.js.map +0 -0
- package/dist-package/README.md +29 -0
- package/{Radio → dist-package/Radio}/Radio.d.ts +0 -0
- package/{Radio → dist-package/Radio}/Radio.js +0 -0
- package/{Radio → dist-package/Radio}/Radio.js.map +0 -0
- package/{Radio → dist-package/Radio}/index.d.ts +0 -0
- package/{Radio → dist-package/Radio}/index.js +0 -0
- package/{Radio → dist-package/Radio}/index.js.map +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/RadioGroup.d.ts +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/RadioGroup.js +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/RadioGroup.js.map +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/RadioGroupContext.d.ts +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/RadioGroupContext.js +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/RadioGroupContext.js.map +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/index.d.ts +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/index.js +0 -0
- package/{RadioGroup → dist-package/RadioGroup}/index.js.map +0 -0
- package/{Rating → dist-package/Rating}/Rating.d.ts +0 -0
- package/{Rating → dist-package/Rating}/Rating.js +0 -0
- package/{Rating → dist-package/Rating}/Rating.js.map +0 -0
- package/{Rating → dist-package/Rating}/index.d.ts +0 -0
- package/{Rating → dist-package/Rating}/index.js +0 -0
- package/{Rating → dist-package/Rating}/index.js.map +0 -0
- package/{Select → dist-package/Select}/Select.d.ts +0 -0
- package/{Select → dist-package/Select}/Select.js +0 -0
- package/{Select → dist-package/Select}/Select.js.map +0 -0
- package/{Select → dist-package/Select}/index.d.ts +0 -0
- package/{Select → dist-package/Select}/index.js +0 -0
- package/{Select → dist-package/Select}/index.js.map +0 -0
- package/{SubmitButton → dist-package/SubmitButton}/SubmitButton.d.ts +0 -0
- package/{SubmitButton → dist-package/SubmitButton}/SubmitButton.js +0 -0
- package/{SubmitButton → dist-package/SubmitButton}/SubmitButton.js.map +0 -0
- package/{SubmitButton → dist-package/SubmitButton}/index.d.ts +0 -0
- package/{SubmitButton → dist-package/SubmitButton}/index.js +0 -0
- package/{SubmitButton → dist-package/SubmitButton}/index.js.map +0 -0
- package/{Switch → dist-package/Switch}/Switch.d.ts +0 -0
- package/{Switch → dist-package/Switch}/Switch.js +0 -0
- package/{Switch → dist-package/Switch}/Switch.js.map +0 -0
- package/{Switch → dist-package/Switch}/index.d.ts +0 -0
- package/{Switch → dist-package/Switch}/index.js +0 -0
- package/{Switch → dist-package/Switch}/index.js.map +0 -0
- package/{TagSelector → dist-package/TagSelector}/TagSelector.d.ts +0 -0
- package/{TagSelector → dist-package/TagSelector}/TagSelector.js +0 -0
- package/{TagSelector → dist-package/TagSelector}/TagSelector.js.map +0 -0
- package/{TagSelector → dist-package/TagSelector}/index.d.ts +0 -0
- package/{TagSelector → dist-package/TagSelector}/index.js +0 -0
- package/{TagSelector → dist-package/TagSelector}/index.js.map +0 -0
- package/{TimePicker → dist-package/TimePicker}/TimePicker.d.ts +0 -0
- package/{TimePicker → dist-package/TimePicker}/TimePicker.js +0 -0
- package/{TimePicker → dist-package/TimePicker}/TimePicker.js.map +0 -0
- package/{TimePicker → dist-package/TimePicker}/index.d.ts +0 -0
- package/{TimePicker → dist-package/TimePicker}/index.js +0 -0
- package/{TimePicker → dist-package/TimePicker}/index.js.map +0 -0
- package/{index.d.ts → dist-package/index.d.ts} +2 -1
- package/{index.js → dist-package/index.js} +0 -1
- package/dist-package/index.js.map +1 -0
- package/dist-package/package.json +44 -0
- package/{utils → dist-package/utils}/flat-map.d.ts +0 -0
- package/{utils → dist-package/utils}/flat-map.js +0 -0
- package/{utils → dist-package/utils}/flat-map.js.map +0 -0
- package/{utils → dist-package/utils}/index.d.ts +0 -0
- package/{utils → dist-package/utils}/index.js +0 -0
- package/{utils → dist-package/utils}/index.js.map +0 -0
- package/{utils → dist-package/utils}/scroll-to-error-decorator.d.ts +0 -0
- package/{utils → dist-package/utils}/scroll-to-error-decorator.js +0 -0
- package/{utils → dist-package/utils}/scroll-to-error-decorator.js.map +0 -0
- package/{utils → dist-package/utils}/validators.d.ts +0 -0
- package/{utils → dist-package/utils}/validators.js +0 -0
- package/{utils → dist-package/utils}/validators.js.map +0 -0
- package/package.json +4 -5
- package/src/Autocomplete/Autocomplete.tsx +21 -0
- package/src/Autocomplete/index.ts +1 -0
- package/src/ButtonCheckbox/ButtonCheckbox.tsx +57 -0
- package/src/ButtonCheckbox/index.ts +1 -0
- package/src/ButtonRadio/ButtonRadio.tsx +24 -0
- package/src/ButtonRadio/index.ts +1 -0
- package/src/Checkbox/Checkbox.tsx +73 -0
- package/src/Checkbox/__snapshots__/test.tsx.snap +254 -0
- package/src/Checkbox/index.ts +1 -0
- package/src/Checkbox/test.tsx +91 -0
- package/src/CheckboxGroup/CheckboxGroup.tsx +30 -0
- package/src/CheckboxGroup/CheckboxGroupContext.ts +3 -0
- package/src/CheckboxGroup/index.ts +3 -0
- package/src/CheckboxGroup/test.tsx +35 -0
- package/src/DatePicker/DatePicker.tsx +26 -0
- package/src/DatePicker/index.ts +1 -0
- package/src/FieldWrapper/FieldWrapper.tsx +287 -0
- package/src/FieldWrapper/index.ts +2 -0
- package/src/FieldWrapper/story/index.jsx +137 -0
- package/src/FileInput/FileInput.tsx +66 -0
- package/src/FileInput/index.ts +1 -0
- package/src/Form/Form.tsx +181 -0
- package/src/Form/FormContext.ts +38 -0
- package/src/Form/__image_snapshots__/form-default-snap.png +0 -0
- package/src/Form/__image_snapshots__/form-form-level-configurations-snap.png +0 -0
- package/src/Form/__snapshots__/test.tsx.snap +61 -0
- package/src/Form/index.ts +1 -0
- package/src/Form/story/BackendCommunication.example.tsx +139 -0
- package/src/Form/story/CustomFormLevelConfiguration.example.tsx +26 -0
- package/src/Form/story/CustomValidator.example.tsx +45 -0
- package/src/Form/story/Default.example.tsx +177 -0
- package/src/Form/story/FileInput.example.tsx +42 -0
- package/src/Form/story/ParseInput.example.tsx +28 -0
- package/src/Form/story/TitleCase.example.tsx +167 -0
- package/src/Form/story/ValidateOnSubmit.example.tsx +85 -0
- package/src/Form/story/index.jsx +203 -0
- package/src/Form/test.tsx +27 -0
- package/src/FormConfig/FormConfig.ts +12 -0
- package/src/FormConfig/index.ts +1 -0
- package/src/FormConfig/test.tsx +44 -0
- package/src/Input/Input.tsx +27 -0
- package/src/Input/index.ts +1 -0
- package/src/Input/test.tsx +34 -0
- package/src/Input/utils/get-input-name.test.ts +16 -0
- package/src/Input/utils/get-input-name.ts +11 -0
- package/src/NumberInput/NumberInput.tsx +45 -0
- package/src/NumberInput/index.ts +1 -0
- package/src/Radio/Radio.tsx +24 -0
- package/src/Radio/__snapshots__/test.tsx.snap +231 -0
- package/src/Radio/index.ts +1 -0
- package/src/Radio/test.tsx +49 -0
- package/src/RadioGroup/RadioGroup.tsx +39 -0
- package/src/RadioGroup/RadioGroupContext.ts +3 -0
- package/src/RadioGroup/index.ts +3 -0
- package/src/RadioGroup/test.tsx +35 -0
- package/src/Rating/Rating.tsx +22 -0
- package/src/Rating/index.ts +1 -0
- package/src/Select/Select.tsx +47 -0
- package/src/Select/index.ts +1 -0
- package/src/SubmitButton/SubmitButton.tsx +70 -0
- package/src/SubmitButton/__image_snapshots__/submitbutton-button-types-snap.png +0 -0
- package/src/SubmitButton/__image_snapshots__/submitbutton-default-snap.png +0 -0
- package/src/SubmitButton/index.ts +6 -0
- package/src/SubmitButton/story/ButtonTypes.example.tsx +46 -0
- package/src/SubmitButton/story/Default.example.tsx +15 -0
- package/src/SubmitButton/story/index.jsx +32 -0
- package/src/Switch/Switch.tsx +23 -0
- package/src/Switch/index.ts +1 -0
- package/src/TagSelector/TagSelector.tsx +25 -0
- package/src/TagSelector/index.ts +1 -0
- package/src/TimePicker/TimePicker.tsx +24 -0
- package/src/TimePicker/index.ts +1 -0
- package/src/index.ts +16 -0
- package/src/story/Deserialization.example.tsx +34 -0
- package/src/story/FormSpy.example.tsx +42 -0
- package/src/story/index.jsx +37 -0
- package/src/utils/flat-map.ts +4 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/scroll-to-error-decorator.ts +78 -0
- package/src/utils/validators.ts +18 -0
- package/tsconfig.build.json +7 -0
- package/index.js.map +0 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {
|
|
3
|
+
TimePicker as PicassoTimePicker,
|
|
4
|
+
TimePickerProps
|
|
5
|
+
} from '@toptal/picasso'
|
|
6
|
+
|
|
7
|
+
import FieldWrapper, { FieldProps } from '../FieldWrapper'
|
|
8
|
+
|
|
9
|
+
export type FormTimePickerProps = Omit<TimePickerProps, 'onChange'> & {
|
|
10
|
+
onChange?: TimePickerProps['onChange']
|
|
11
|
+
}
|
|
12
|
+
export type Props = FormTimePickerProps & FieldProps<TimePickerProps['value']>
|
|
13
|
+
|
|
14
|
+
export const TimePicker = (props: Props) => (
|
|
15
|
+
<FieldWrapper<FormTimePickerProps> {...props}>
|
|
16
|
+
{(inputProps: TimePickerProps) => {
|
|
17
|
+
return <PicassoTimePicker {...inputProps} />
|
|
18
|
+
}}
|
|
19
|
+
</FieldWrapper>
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
TimePicker.displayName = 'TimePicker'
|
|
23
|
+
|
|
24
|
+
export default TimePicker
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './TimePicker'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
// Final Form exports
|
|
3
|
+
export type { FormApi, MutableState, AnyObject, FieldValidator, SubmissionErrors, Config } from 'final-form'
|
|
4
|
+
export { FORM_ERROR, setIn } from 'final-form'
|
|
5
|
+
export { useForm, useField, useFormState, FormSpy, Form as FinalForm, Field as FinalField } from 'react-final-form'
|
|
6
|
+
export type { FieldMetaState, FieldRenderProps, FormRenderProps, FieldProps, FormProps, FieldInputProps } from 'react-final-form'
|
|
7
|
+
export { default as arrayMutators } from 'final-form-arrays'
|
|
8
|
+
export { useFieldArray, FieldArray } from 'react-final-form-arrays'
|
|
9
|
+
export type { FieldArrayProps, FieldArrayRenderProps } from 'react-final-form-arrays'
|
|
10
|
+
export { OnChange, OnFocus, ExternallyChanged, OnBlur } from 'react-final-form-listeners'
|
|
11
|
+
|
|
12
|
+
// Picasso Forms exports
|
|
13
|
+
export { default as Form } from './Form'
|
|
14
|
+
export { default as FieldWrapper } from './FieldWrapper'
|
|
15
|
+
export type { FormConfigProps, RequiredVariant } from './FormConfig'
|
|
16
|
+
// hygen code generator inserts export statements above this comment.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Container } from '@toptal/picasso'
|
|
3
|
+
import { Form } from '@toptal/picasso-forms'
|
|
4
|
+
|
|
5
|
+
const deserializeValue = <T extends unknown>(value: T) => {
|
|
6
|
+
if (value === 'true') {
|
|
7
|
+
return true
|
|
8
|
+
}
|
|
9
|
+
if (value === 'false') {
|
|
10
|
+
return false
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return value
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const Example = () => (
|
|
17
|
+
<Form
|
|
18
|
+
onSubmit={values => {
|
|
19
|
+
console.log('Raw: ', { foo: values.foo })
|
|
20
|
+
console.log('Deserialized: ', { foo: deserializeValue(values.foo) })
|
|
21
|
+
}}
|
|
22
|
+
initialValues={{ foo: 'true' }}
|
|
23
|
+
>
|
|
24
|
+
<Form.RadioGroup name='foo' label='Foo'>
|
|
25
|
+
<Form.Radio label='yes' value='true' />
|
|
26
|
+
<Form.Radio label='no' value='false' />
|
|
27
|
+
</Form.RadioGroup>
|
|
28
|
+
<Container top='small'>
|
|
29
|
+
<Form.SubmitButton>Submit</Form.SubmitButton>
|
|
30
|
+
</Container>
|
|
31
|
+
</Form>
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
export default Example
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Container } from '@toptal/picasso'
|
|
3
|
+
import { Form, FormSpy } from '@toptal/picasso-forms'
|
|
4
|
+
|
|
5
|
+
const Example = () => (
|
|
6
|
+
<Form onSubmit={values => window.alert(values)}>
|
|
7
|
+
<Form.Input
|
|
8
|
+
required
|
|
9
|
+
name='firstName'
|
|
10
|
+
label='First name'
|
|
11
|
+
placeholder='e.g. Bruce'
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
<FormSpy>
|
|
15
|
+
{({ values }) => (
|
|
16
|
+
<Form.Input
|
|
17
|
+
required
|
|
18
|
+
name='lastName'
|
|
19
|
+
disabled={!values?.firstName}
|
|
20
|
+
label='Last name'
|
|
21
|
+
placeholder='Disabled until first name is filled out'
|
|
22
|
+
/>
|
|
23
|
+
)}
|
|
24
|
+
</FormSpy>
|
|
25
|
+
|
|
26
|
+
<Container top='small'>
|
|
27
|
+
<FormSpy>
|
|
28
|
+
{({ pristine, values }) => {
|
|
29
|
+
const isDisabled = pristine || !values?.lastName
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Form.SubmitButton disabled={isDisabled}>
|
|
33
|
+
{isDisabled ? 'Fill out form to enable' : 'Submit'}
|
|
34
|
+
</Form.SubmitButton>
|
|
35
|
+
)
|
|
36
|
+
}}
|
|
37
|
+
</FormSpy>
|
|
38
|
+
</Container>
|
|
39
|
+
</Form>
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
export default Example
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { doc } from 'storybook-readme'
|
|
2
|
+
|
|
3
|
+
import PicassoBook from '~/.storybook/components/PicassoBook'
|
|
4
|
+
import README from '../../README.md'
|
|
5
|
+
import CHANGELOG from '../../CHANGELOG.md'
|
|
6
|
+
|
|
7
|
+
const section = PicassoBook.section('Picasso Forms')
|
|
8
|
+
|
|
9
|
+
section.createDocPage('README', doc(README), { alwaysOnTop: true })
|
|
10
|
+
section.createDocPage('CHANGELOG', doc(CHANGELOG), { alwaysOnTop: true })
|
|
11
|
+
|
|
12
|
+
const page = section.createPage('Final Form', 'Final Form')
|
|
13
|
+
|
|
14
|
+
page
|
|
15
|
+
.createChapter()
|
|
16
|
+
.addExample(
|
|
17
|
+
'story/FormSpy.example.tsx',
|
|
18
|
+
{
|
|
19
|
+
title: 'Form Spy',
|
|
20
|
+
description: `
|
|
21
|
+
Sometimes you might want to perform a conditional action based on the value of another field in the form or its overall state.
|
|
22
|
+
For smaller forms, you can just directly work with values, but with a larger form you can avoid prop drilling with FormSpy.`
|
|
23
|
+
},
|
|
24
|
+
'picasso-form'
|
|
25
|
+
) // picasso-skip-visuals
|
|
26
|
+
.addExample(
|
|
27
|
+
'story/Deserialization.example.tsx',
|
|
28
|
+
{
|
|
29
|
+
title: 'Deserialization',
|
|
30
|
+
description: `
|
|
31
|
+
By default final-form converts all values to strings.
|
|
32
|
+
If want to pass a boolean or a number value to a field,
|
|
33
|
+
you should pass it serialized and deserialize it later.
|
|
34
|
+
`
|
|
35
|
+
},
|
|
36
|
+
'picasso-form'
|
|
37
|
+
) // picasso-skip-visuals
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { FormApi } from 'final-form'
|
|
2
|
+
|
|
3
|
+
const UNHIDDEN_INPUT_SELECTOR = 'input:not([type=hidden])'
|
|
4
|
+
|
|
5
|
+
const getErrorField = () =>
|
|
6
|
+
document.querySelector<HTMLElement>('[data-field-has-error="true"]')
|
|
7
|
+
|
|
8
|
+
const getErrorFieldAfterNextPaint = () =>
|
|
9
|
+
new Promise<HTMLElement | null>(resolve => {
|
|
10
|
+
const resolveField = () => resolve(getErrorField())
|
|
11
|
+
|
|
12
|
+
if (typeof requestAnimationFrame === 'undefined') {
|
|
13
|
+
setTimeout(resolveField, 16)
|
|
14
|
+
} else {
|
|
15
|
+
requestAnimationFrame(resolveField)
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const getErrorFieldWithRetries = async () => {
|
|
20
|
+
for (let index = 0; index < 3; index++) {
|
|
21
|
+
const field = await getErrorFieldAfterNextPaint()
|
|
22
|
+
|
|
23
|
+
if (field) {
|
|
24
|
+
return field
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const scrollTo = (field: HTMLElement) => {
|
|
30
|
+
field.scrollIntoView({ block: 'center', behavior: 'smooth' })
|
|
31
|
+
field
|
|
32
|
+
.querySelector<HTMLInputElement>(UNHIDDEN_INPUT_SELECTOR)
|
|
33
|
+
?.focus({ preventScroll: true })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let state: { errors?: object; submitErrors?: object } = {}
|
|
37
|
+
|
|
38
|
+
export default () => <T>(form: FormApi<T>) => {
|
|
39
|
+
const originalSubmit = form.submit
|
|
40
|
+
|
|
41
|
+
const unsubscribe = form.subscribe(
|
|
42
|
+
nextState => {
|
|
43
|
+
state = nextState
|
|
44
|
+
},
|
|
45
|
+
{ errors: true, submitErrors: true }
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const scrollOnErrors = async () => {
|
|
49
|
+
const { errors = {}, submitErrors = {} } = state
|
|
50
|
+
|
|
51
|
+
if (Object.keys(errors).length || Object.keys(submitErrors).length) {
|
|
52
|
+
const field = await getErrorFieldWithRetries()
|
|
53
|
+
|
|
54
|
+
if (field) {
|
|
55
|
+
scrollTo(field)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Rewrite submit function
|
|
61
|
+
form.submit = () => {
|
|
62
|
+
const result = originalSubmit.call(form)
|
|
63
|
+
|
|
64
|
+
if (result && typeof result.then === 'function') {
|
|
65
|
+
result.then(scrollOnErrors).catch(() => {})
|
|
66
|
+
} else {
|
|
67
|
+
scrollOnErrors()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return () => {
|
|
74
|
+
state = {}
|
|
75
|
+
unsubscribe()
|
|
76
|
+
form.submit = originalSubmit
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const composeValidators = (validators: any[]) => (value: any, allValues: any) =>
|
|
2
|
+
validators
|
|
3
|
+
.filter(Boolean)
|
|
4
|
+
.reduce(
|
|
5
|
+
(error, validator) => error || validator(value, allValues),
|
|
6
|
+
undefined
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
const required = (value: unknown) =>
|
|
10
|
+
value === undefined ||
|
|
11
|
+
value === false ||
|
|
12
|
+
value === '' ||
|
|
13
|
+
value === null ||
|
|
14
|
+
(Array.isArray(value) && value.length === 0)
|
|
15
|
+
? 'Please complete this field.'
|
|
16
|
+
: undefined
|
|
17
|
+
|
|
18
|
+
export default { composeValidators, required }
|
package/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,qBAAqB;AACrB,OAAO,EAAE,UAAU,EAA8E,KAAK,EAAE,MAAM,YAAY,CAAA;AAC1H,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAEnH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEnE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAEzF,wBAAwB;AACxB,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAExD,qEAAqE"}
|