@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.
Files changed (236) hide show
  1. package/CHANGELOG.md +657 -0
  2. package/{Autocomplete → dist-package/Autocomplete}/Autocomplete.d.ts +0 -0
  3. package/{Autocomplete → dist-package/Autocomplete}/Autocomplete.js +0 -0
  4. package/{Autocomplete → dist-package/Autocomplete}/Autocomplete.js.map +0 -0
  5. package/{Autocomplete → dist-package/Autocomplete}/index.d.ts +0 -0
  6. package/{Autocomplete → dist-package/Autocomplete}/index.js +0 -0
  7. package/{Autocomplete → dist-package/Autocomplete}/index.js.map +0 -0
  8. package/{ButtonCheckbox → dist-package/ButtonCheckbox}/ButtonCheckbox.d.ts +0 -0
  9. package/{ButtonCheckbox → dist-package/ButtonCheckbox}/ButtonCheckbox.js +0 -0
  10. package/{ButtonCheckbox → dist-package/ButtonCheckbox}/ButtonCheckbox.js.map +0 -0
  11. package/{ButtonCheckbox → dist-package/ButtonCheckbox}/index.d.ts +0 -0
  12. package/{ButtonCheckbox → dist-package/ButtonCheckbox}/index.js +0 -0
  13. package/{ButtonCheckbox → dist-package/ButtonCheckbox}/index.js.map +0 -0
  14. package/{ButtonRadio → dist-package/ButtonRadio}/ButtonRadio.d.ts +0 -0
  15. package/{ButtonRadio → dist-package/ButtonRadio}/ButtonRadio.js +0 -0
  16. package/{ButtonRadio → dist-package/ButtonRadio}/ButtonRadio.js.map +0 -0
  17. package/{ButtonRadio → dist-package/ButtonRadio}/index.d.ts +0 -0
  18. package/{ButtonRadio → dist-package/ButtonRadio}/index.js +0 -0
  19. package/{ButtonRadio → dist-package/ButtonRadio}/index.js.map +0 -0
  20. package/{Checkbox → dist-package/Checkbox}/Checkbox.d.ts +0 -0
  21. package/{Checkbox → dist-package/Checkbox}/Checkbox.js +0 -0
  22. package/{Checkbox → dist-package/Checkbox}/Checkbox.js.map +0 -0
  23. package/{Checkbox → dist-package/Checkbox}/index.d.ts +0 -0
  24. package/{Checkbox → dist-package/Checkbox}/index.js +0 -0
  25. package/{Checkbox → dist-package/Checkbox}/index.js.map +0 -0
  26. package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroup.d.ts +0 -0
  27. package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroup.js +0 -0
  28. package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroup.js.map +0 -0
  29. package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroupContext.d.ts +0 -0
  30. package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroupContext.js +0 -0
  31. package/{CheckboxGroup → dist-package/CheckboxGroup}/CheckboxGroupContext.js.map +0 -0
  32. package/{CheckboxGroup → dist-package/CheckboxGroup}/index.d.ts +0 -0
  33. package/{CheckboxGroup → dist-package/CheckboxGroup}/index.js +0 -0
  34. package/{CheckboxGroup → dist-package/CheckboxGroup}/index.js.map +0 -0
  35. package/{DatePicker → dist-package/DatePicker}/DatePicker.d.ts +0 -0
  36. package/{DatePicker → dist-package/DatePicker}/DatePicker.js +0 -0
  37. package/{DatePicker → dist-package/DatePicker}/DatePicker.js.map +0 -0
  38. package/{DatePicker → dist-package/DatePicker}/index.d.ts +0 -0
  39. package/{DatePicker → dist-package/DatePicker}/index.js +0 -0
  40. package/{DatePicker → dist-package/DatePicker}/index.js.map +0 -0
  41. package/{FieldWrapper → dist-package/FieldWrapper}/FieldWrapper.d.ts +0 -0
  42. package/{FieldWrapper → dist-package/FieldWrapper}/FieldWrapper.js +0 -0
  43. package/{FieldWrapper → dist-package/FieldWrapper}/FieldWrapper.js.map +0 -0
  44. package/{FieldWrapper → dist-package/FieldWrapper}/index.d.ts +0 -0
  45. package/{FieldWrapper → dist-package/FieldWrapper}/index.js +0 -0
  46. package/{FieldWrapper → dist-package/FieldWrapper}/index.js.map +0 -0
  47. package/{FileInput → dist-package/FileInput}/FileInput.d.ts +0 -0
  48. package/{FileInput → dist-package/FileInput}/FileInput.js +0 -0
  49. package/{FileInput → dist-package/FileInput}/FileInput.js.map +0 -0
  50. package/{FileInput → dist-package/FileInput}/index.d.ts +0 -0
  51. package/{FileInput → dist-package/FileInput}/index.js +0 -0
  52. package/{FileInput → dist-package/FileInput}/index.js.map +0 -0
  53. package/{Form → dist-package/Form}/Form.d.ts +0 -0
  54. package/{Form → dist-package/Form}/Form.js +0 -0
  55. package/{Form → dist-package/Form}/Form.js.map +0 -0
  56. package/{Form → dist-package/Form}/FormContext.d.ts +0 -0
  57. package/{Form → dist-package/Form}/FormContext.js +0 -0
  58. package/{Form → dist-package/Form}/FormContext.js.map +0 -0
  59. package/{Form → dist-package/Form}/index.d.ts +0 -0
  60. package/{Form → dist-package/Form}/index.js +0 -0
  61. package/{Form → dist-package/Form}/index.js.map +0 -0
  62. package/{FormConfig → dist-package/FormConfig}/FormConfig.d.ts +0 -0
  63. package/{FormConfig → dist-package/FormConfig}/FormConfig.js +0 -0
  64. package/{FormConfig → dist-package/FormConfig}/FormConfig.js.map +0 -0
  65. package/{FormConfig → dist-package/FormConfig}/index.d.ts +0 -0
  66. package/{FormConfig → dist-package/FormConfig}/index.js +0 -0
  67. package/{FormConfig → dist-package/FormConfig}/index.js.map +0 -0
  68. package/{Input → dist-package/Input}/Input.d.ts +0 -0
  69. package/{Input → dist-package/Input}/Input.js +0 -0
  70. package/{Input → dist-package/Input}/Input.js.map +0 -0
  71. package/{Input → dist-package/Input}/index.d.ts +0 -0
  72. package/{Input → dist-package/Input}/index.js +0 -0
  73. package/{Input → dist-package/Input}/index.js.map +0 -0
  74. package/{Input → dist-package/Input}/utils/get-input-name.d.ts +0 -0
  75. package/{Input → dist-package/Input}/utils/get-input-name.js +0 -0
  76. package/{Input → dist-package/Input}/utils/get-input-name.js.map +0 -0
  77. package/{Input → dist-package/Input}/utils/get-input-name.test.d.ts +0 -0
  78. package/{Input → dist-package/Input}/utils/get-input-name.test.js +0 -0
  79. package/{Input → dist-package/Input}/utils/get-input-name.test.js.map +0 -0
  80. package/{NumberInput → dist-package/NumberInput}/NumberInput.d.ts +0 -0
  81. package/{NumberInput → dist-package/NumberInput}/NumberInput.js +0 -0
  82. package/{NumberInput → dist-package/NumberInput}/NumberInput.js.map +0 -0
  83. package/{NumberInput → dist-package/NumberInput}/index.d.ts +0 -0
  84. package/{NumberInput → dist-package/NumberInput}/index.js +0 -0
  85. package/{NumberInput → dist-package/NumberInput}/index.js.map +0 -0
  86. package/dist-package/README.md +29 -0
  87. package/{Radio → dist-package/Radio}/Radio.d.ts +0 -0
  88. package/{Radio → dist-package/Radio}/Radio.js +0 -0
  89. package/{Radio → dist-package/Radio}/Radio.js.map +0 -0
  90. package/{Radio → dist-package/Radio}/index.d.ts +0 -0
  91. package/{Radio → dist-package/Radio}/index.js +0 -0
  92. package/{Radio → dist-package/Radio}/index.js.map +0 -0
  93. package/{RadioGroup → dist-package/RadioGroup}/RadioGroup.d.ts +0 -0
  94. package/{RadioGroup → dist-package/RadioGroup}/RadioGroup.js +0 -0
  95. package/{RadioGroup → dist-package/RadioGroup}/RadioGroup.js.map +0 -0
  96. package/{RadioGroup → dist-package/RadioGroup}/RadioGroupContext.d.ts +0 -0
  97. package/{RadioGroup → dist-package/RadioGroup}/RadioGroupContext.js +0 -0
  98. package/{RadioGroup → dist-package/RadioGroup}/RadioGroupContext.js.map +0 -0
  99. package/{RadioGroup → dist-package/RadioGroup}/index.d.ts +0 -0
  100. package/{RadioGroup → dist-package/RadioGroup}/index.js +0 -0
  101. package/{RadioGroup → dist-package/RadioGroup}/index.js.map +0 -0
  102. package/{Rating → dist-package/Rating}/Rating.d.ts +0 -0
  103. package/{Rating → dist-package/Rating}/Rating.js +0 -0
  104. package/{Rating → dist-package/Rating}/Rating.js.map +0 -0
  105. package/{Rating → dist-package/Rating}/index.d.ts +0 -0
  106. package/{Rating → dist-package/Rating}/index.js +0 -0
  107. package/{Rating → dist-package/Rating}/index.js.map +0 -0
  108. package/{Select → dist-package/Select}/Select.d.ts +0 -0
  109. package/{Select → dist-package/Select}/Select.js +0 -0
  110. package/{Select → dist-package/Select}/Select.js.map +0 -0
  111. package/{Select → dist-package/Select}/index.d.ts +0 -0
  112. package/{Select → dist-package/Select}/index.js +0 -0
  113. package/{Select → dist-package/Select}/index.js.map +0 -0
  114. package/{SubmitButton → dist-package/SubmitButton}/SubmitButton.d.ts +0 -0
  115. package/{SubmitButton → dist-package/SubmitButton}/SubmitButton.js +0 -0
  116. package/{SubmitButton → dist-package/SubmitButton}/SubmitButton.js.map +0 -0
  117. package/{SubmitButton → dist-package/SubmitButton}/index.d.ts +0 -0
  118. package/{SubmitButton → dist-package/SubmitButton}/index.js +0 -0
  119. package/{SubmitButton → dist-package/SubmitButton}/index.js.map +0 -0
  120. package/{Switch → dist-package/Switch}/Switch.d.ts +0 -0
  121. package/{Switch → dist-package/Switch}/Switch.js +0 -0
  122. package/{Switch → dist-package/Switch}/Switch.js.map +0 -0
  123. package/{Switch → dist-package/Switch}/index.d.ts +0 -0
  124. package/{Switch → dist-package/Switch}/index.js +0 -0
  125. package/{Switch → dist-package/Switch}/index.js.map +0 -0
  126. package/{TagSelector → dist-package/TagSelector}/TagSelector.d.ts +0 -0
  127. package/{TagSelector → dist-package/TagSelector}/TagSelector.js +0 -0
  128. package/{TagSelector → dist-package/TagSelector}/TagSelector.js.map +0 -0
  129. package/{TagSelector → dist-package/TagSelector}/index.d.ts +0 -0
  130. package/{TagSelector → dist-package/TagSelector}/index.js +0 -0
  131. package/{TagSelector → dist-package/TagSelector}/index.js.map +0 -0
  132. package/{TimePicker → dist-package/TimePicker}/TimePicker.d.ts +0 -0
  133. package/{TimePicker → dist-package/TimePicker}/TimePicker.js +0 -0
  134. package/{TimePicker → dist-package/TimePicker}/TimePicker.js.map +0 -0
  135. package/{TimePicker → dist-package/TimePicker}/index.d.ts +0 -0
  136. package/{TimePicker → dist-package/TimePicker}/index.js +0 -0
  137. package/{TimePicker → dist-package/TimePicker}/index.js.map +0 -0
  138. package/{index.d.ts → dist-package/index.d.ts} +2 -1
  139. package/{index.js → dist-package/index.js} +0 -1
  140. package/dist-package/index.js.map +1 -0
  141. package/dist-package/package.json +44 -0
  142. package/{utils → dist-package/utils}/flat-map.d.ts +0 -0
  143. package/{utils → dist-package/utils}/flat-map.js +0 -0
  144. package/{utils → dist-package/utils}/flat-map.js.map +0 -0
  145. package/{utils → dist-package/utils}/index.d.ts +0 -0
  146. package/{utils → dist-package/utils}/index.js +0 -0
  147. package/{utils → dist-package/utils}/index.js.map +0 -0
  148. package/{utils → dist-package/utils}/scroll-to-error-decorator.d.ts +0 -0
  149. package/{utils → dist-package/utils}/scroll-to-error-decorator.js +0 -0
  150. package/{utils → dist-package/utils}/scroll-to-error-decorator.js.map +0 -0
  151. package/{utils → dist-package/utils}/validators.d.ts +0 -0
  152. package/{utils → dist-package/utils}/validators.js +0 -0
  153. package/{utils → dist-package/utils}/validators.js.map +0 -0
  154. package/package.json +4 -5
  155. package/src/Autocomplete/Autocomplete.tsx +21 -0
  156. package/src/Autocomplete/index.ts +1 -0
  157. package/src/ButtonCheckbox/ButtonCheckbox.tsx +57 -0
  158. package/src/ButtonCheckbox/index.ts +1 -0
  159. package/src/ButtonRadio/ButtonRadio.tsx +24 -0
  160. package/src/ButtonRadio/index.ts +1 -0
  161. package/src/Checkbox/Checkbox.tsx +73 -0
  162. package/src/Checkbox/__snapshots__/test.tsx.snap +254 -0
  163. package/src/Checkbox/index.ts +1 -0
  164. package/src/Checkbox/test.tsx +91 -0
  165. package/src/CheckboxGroup/CheckboxGroup.tsx +30 -0
  166. package/src/CheckboxGroup/CheckboxGroupContext.ts +3 -0
  167. package/src/CheckboxGroup/index.ts +3 -0
  168. package/src/CheckboxGroup/test.tsx +35 -0
  169. package/src/DatePicker/DatePicker.tsx +26 -0
  170. package/src/DatePicker/index.ts +1 -0
  171. package/src/FieldWrapper/FieldWrapper.tsx +287 -0
  172. package/src/FieldWrapper/index.ts +2 -0
  173. package/src/FieldWrapper/story/index.jsx +137 -0
  174. package/src/FileInput/FileInput.tsx +66 -0
  175. package/src/FileInput/index.ts +1 -0
  176. package/src/Form/Form.tsx +181 -0
  177. package/src/Form/FormContext.ts +38 -0
  178. package/src/Form/__image_snapshots__/form-default-snap.png +0 -0
  179. package/src/Form/__image_snapshots__/form-form-level-configurations-snap.png +0 -0
  180. package/src/Form/__snapshots__/test.tsx.snap +61 -0
  181. package/src/Form/index.ts +1 -0
  182. package/src/Form/story/BackendCommunication.example.tsx +139 -0
  183. package/src/Form/story/CustomFormLevelConfiguration.example.tsx +26 -0
  184. package/src/Form/story/CustomValidator.example.tsx +45 -0
  185. package/src/Form/story/Default.example.tsx +177 -0
  186. package/src/Form/story/FileInput.example.tsx +42 -0
  187. package/src/Form/story/ParseInput.example.tsx +28 -0
  188. package/src/Form/story/TitleCase.example.tsx +167 -0
  189. package/src/Form/story/ValidateOnSubmit.example.tsx +85 -0
  190. package/src/Form/story/index.jsx +203 -0
  191. package/src/Form/test.tsx +27 -0
  192. package/src/FormConfig/FormConfig.ts +12 -0
  193. package/src/FormConfig/index.ts +1 -0
  194. package/src/FormConfig/test.tsx +44 -0
  195. package/src/Input/Input.tsx +27 -0
  196. package/src/Input/index.ts +1 -0
  197. package/src/Input/test.tsx +34 -0
  198. package/src/Input/utils/get-input-name.test.ts +16 -0
  199. package/src/Input/utils/get-input-name.ts +11 -0
  200. package/src/NumberInput/NumberInput.tsx +45 -0
  201. package/src/NumberInput/index.ts +1 -0
  202. package/src/Radio/Radio.tsx +24 -0
  203. package/src/Radio/__snapshots__/test.tsx.snap +231 -0
  204. package/src/Radio/index.ts +1 -0
  205. package/src/Radio/test.tsx +49 -0
  206. package/src/RadioGroup/RadioGroup.tsx +39 -0
  207. package/src/RadioGroup/RadioGroupContext.ts +3 -0
  208. package/src/RadioGroup/index.ts +3 -0
  209. package/src/RadioGroup/test.tsx +35 -0
  210. package/src/Rating/Rating.tsx +22 -0
  211. package/src/Rating/index.ts +1 -0
  212. package/src/Select/Select.tsx +47 -0
  213. package/src/Select/index.ts +1 -0
  214. package/src/SubmitButton/SubmitButton.tsx +70 -0
  215. package/src/SubmitButton/__image_snapshots__/submitbutton-button-types-snap.png +0 -0
  216. package/src/SubmitButton/__image_snapshots__/submitbutton-default-snap.png +0 -0
  217. package/src/SubmitButton/index.ts +6 -0
  218. package/src/SubmitButton/story/ButtonTypes.example.tsx +46 -0
  219. package/src/SubmitButton/story/Default.example.tsx +15 -0
  220. package/src/SubmitButton/story/index.jsx +32 -0
  221. package/src/Switch/Switch.tsx +23 -0
  222. package/src/Switch/index.ts +1 -0
  223. package/src/TagSelector/TagSelector.tsx +25 -0
  224. package/src/TagSelector/index.ts +1 -0
  225. package/src/TimePicker/TimePicker.tsx +24 -0
  226. package/src/TimePicker/index.ts +1 -0
  227. package/src/index.ts +16 -0
  228. package/src/story/Deserialization.example.tsx +34 -0
  229. package/src/story/FormSpy.example.tsx +42 -0
  230. package/src/story/index.jsx +37 -0
  231. package/src/utils/flat-map.ts +4 -0
  232. package/src/utils/index.ts +3 -0
  233. package/src/utils/scroll-to-error-decorator.ts +78 -0
  234. package/src/utils/validators.ts +18 -0
  235. package/tsconfig.build.json +7 -0
  236. 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,4 @@
1
+ export const flatMap = <T, K>(arr: T[], fn: (item: T) => K[]) =>
2
+ arr.reduce<K[]>((acc, item) => acc.concat(fn(item)), [])
3
+
4
+ export default flatMap
@@ -0,0 +1,3 @@
1
+ export { default as validators } from './validators'
2
+ export { default as createScrollToErrorDecorator } from './scroll-to-error-decorator'
3
+ export { default as flatMap } from './flat-map'
@@ -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 }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.build.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist-package"
5
+ },
6
+ "include": ["src"]
7
+ }
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"}