@toptal/picasso-forms 6.0.5 → 10.0.0

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 (237) hide show
  1. package/{dist-package/Autocomplete → Autocomplete}/Autocomplete.d.ts +0 -0
  2. package/{dist-package/Autocomplete → Autocomplete}/Autocomplete.js +0 -0
  3. package/{dist-package/Autocomplete → Autocomplete}/Autocomplete.js.map +0 -0
  4. package/{dist-package/Autocomplete → Autocomplete}/index.d.ts +0 -0
  5. package/{dist-package/Autocomplete → Autocomplete}/index.js +0 -0
  6. package/{dist-package/Autocomplete → Autocomplete}/index.js.map +0 -0
  7. package/{dist-package/ButtonCheckbox → ButtonCheckbox}/ButtonCheckbox.d.ts +0 -0
  8. package/{dist-package/ButtonCheckbox → ButtonCheckbox}/ButtonCheckbox.js +0 -0
  9. package/{dist-package/ButtonCheckbox → ButtonCheckbox}/ButtonCheckbox.js.map +0 -0
  10. package/{dist-package/ButtonCheckbox → ButtonCheckbox}/index.d.ts +0 -0
  11. package/{dist-package/ButtonCheckbox → ButtonCheckbox}/index.js +0 -0
  12. package/{dist-package/ButtonCheckbox → ButtonCheckbox}/index.js.map +0 -0
  13. package/{dist-package/ButtonRadio → ButtonRadio}/ButtonRadio.d.ts +0 -0
  14. package/{dist-package/ButtonRadio → ButtonRadio}/ButtonRadio.js +0 -0
  15. package/{dist-package/ButtonRadio → ButtonRadio}/ButtonRadio.js.map +0 -0
  16. package/{dist-package/ButtonRadio → ButtonRadio}/index.d.ts +0 -0
  17. package/{dist-package/ButtonRadio → ButtonRadio}/index.js +0 -0
  18. package/{dist-package/ButtonRadio → ButtonRadio}/index.js.map +0 -0
  19. package/{dist-package/Checkbox → Checkbox}/Checkbox.d.ts +0 -0
  20. package/{dist-package/Checkbox → Checkbox}/Checkbox.js +0 -0
  21. package/{dist-package/Checkbox → Checkbox}/Checkbox.js.map +0 -0
  22. package/{dist-package/Checkbox → Checkbox}/index.d.ts +0 -0
  23. package/{dist-package/Checkbox → Checkbox}/index.js +0 -0
  24. package/{dist-package/Checkbox → Checkbox}/index.js.map +0 -0
  25. package/{dist-package/CheckboxGroup → CheckboxGroup}/CheckboxGroup.d.ts +0 -0
  26. package/{dist-package/CheckboxGroup → CheckboxGroup}/CheckboxGroup.js +0 -0
  27. package/{dist-package/CheckboxGroup → CheckboxGroup}/CheckboxGroup.js.map +0 -0
  28. package/{dist-package/CheckboxGroup → CheckboxGroup}/CheckboxGroupContext.d.ts +0 -0
  29. package/{dist-package/CheckboxGroup → CheckboxGroup}/CheckboxGroupContext.js +0 -0
  30. package/{dist-package/CheckboxGroup → CheckboxGroup}/CheckboxGroupContext.js.map +0 -0
  31. package/{dist-package/CheckboxGroup → CheckboxGroup}/index.d.ts +0 -0
  32. package/{dist-package/CheckboxGroup → CheckboxGroup}/index.js +0 -0
  33. package/{dist-package/CheckboxGroup → CheckboxGroup}/index.js.map +0 -0
  34. package/{dist-package/DatePicker → DatePicker}/DatePicker.d.ts +0 -0
  35. package/{dist-package/DatePicker → DatePicker}/DatePicker.js +0 -0
  36. package/{dist-package/DatePicker → DatePicker}/DatePicker.js.map +0 -0
  37. package/{dist-package/DatePicker → DatePicker}/index.d.ts +0 -0
  38. package/{dist-package/DatePicker → DatePicker}/index.js +0 -0
  39. package/{dist-package/DatePicker → DatePicker}/index.js.map +0 -0
  40. package/{dist-package/FieldWrapper → FieldWrapper}/FieldWrapper.d.ts +0 -0
  41. package/{dist-package/FieldWrapper → FieldWrapper}/FieldWrapper.js +0 -0
  42. package/{dist-package/FieldWrapper → FieldWrapper}/FieldWrapper.js.map +0 -0
  43. package/{dist-package/FieldWrapper → FieldWrapper}/index.d.ts +0 -0
  44. package/{dist-package/FieldWrapper → FieldWrapper}/index.js +0 -0
  45. package/{dist-package/FieldWrapper → FieldWrapper}/index.js.map +0 -0
  46. package/{dist-package/FileInput → FileInput}/FileInput.d.ts +0 -0
  47. package/{dist-package/FileInput → FileInput}/FileInput.js +0 -0
  48. package/{dist-package/FileInput → FileInput}/FileInput.js.map +0 -0
  49. package/{dist-package/FileInput → FileInput}/index.d.ts +0 -0
  50. package/{dist-package/FileInput → FileInput}/index.js +0 -0
  51. package/{dist-package/FileInput → FileInput}/index.js.map +0 -0
  52. package/{dist-package/Form → Form}/Form.d.ts +0 -0
  53. package/{dist-package/Form → Form}/Form.js +0 -0
  54. package/{dist-package/Form → Form}/Form.js.map +0 -0
  55. package/{dist-package/Form → Form}/FormContext.d.ts +0 -0
  56. package/{dist-package/Form → Form}/FormContext.js +0 -0
  57. package/{dist-package/Form → Form}/FormContext.js.map +0 -0
  58. package/{dist-package/Form → Form}/index.d.ts +0 -0
  59. package/{dist-package/Form → Form}/index.js +0 -0
  60. package/{dist-package/Form → Form}/index.js.map +0 -0
  61. package/{dist-package/FormConfig → FormConfig}/FormConfig.d.ts +0 -0
  62. package/{dist-package/FormConfig → FormConfig}/FormConfig.js +0 -0
  63. package/{dist-package/FormConfig → FormConfig}/FormConfig.js.map +0 -0
  64. package/{dist-package/FormConfig → FormConfig}/index.d.ts +0 -0
  65. package/{dist-package/FormConfig → FormConfig}/index.js +0 -0
  66. package/{dist-package/FormConfig → FormConfig}/index.js.map +0 -0
  67. package/{dist-package/Input → Input}/Input.d.ts +0 -0
  68. package/Input/Input.js +25 -0
  69. package/Input/Input.js.map +1 -0
  70. package/{dist-package/Input → Input}/index.d.ts +0 -0
  71. package/{dist-package/Input → Input}/index.js +0 -0
  72. package/{dist-package/Input → Input}/index.js.map +0 -0
  73. package/{dist-package/NumberInput → NumberInput}/NumberInput.d.ts +0 -0
  74. package/{dist-package/NumberInput → NumberInput}/NumberInput.js +0 -0
  75. package/{dist-package/NumberInput → NumberInput}/NumberInput.js.map +0 -0
  76. package/{dist-package/NumberInput → NumberInput}/index.d.ts +0 -0
  77. package/{dist-package/NumberInput → NumberInput}/index.js +0 -0
  78. package/{dist-package/NumberInput → NumberInput}/index.js.map +0 -0
  79. package/{dist-package/Radio → Radio}/Radio.d.ts +0 -0
  80. package/{dist-package/Radio → Radio}/Radio.js +0 -0
  81. package/{dist-package/Radio → Radio}/Radio.js.map +0 -0
  82. package/{dist-package/Radio → Radio}/index.d.ts +0 -0
  83. package/{dist-package/Radio → Radio}/index.js +0 -0
  84. package/{dist-package/Radio → Radio}/index.js.map +0 -0
  85. package/{dist-package/RadioGroup → RadioGroup}/RadioGroup.d.ts +0 -0
  86. package/{dist-package/RadioGroup → RadioGroup}/RadioGroup.js +0 -0
  87. package/{dist-package/RadioGroup → RadioGroup}/RadioGroup.js.map +0 -0
  88. package/{dist-package/RadioGroup → RadioGroup}/RadioGroupContext.d.ts +0 -0
  89. package/{dist-package/RadioGroup → RadioGroup}/RadioGroupContext.js +0 -0
  90. package/{dist-package/RadioGroup → RadioGroup}/RadioGroupContext.js.map +0 -0
  91. package/{dist-package/RadioGroup → RadioGroup}/index.d.ts +0 -0
  92. package/{dist-package/RadioGroup → RadioGroup}/index.js +0 -0
  93. package/{dist-package/RadioGroup → RadioGroup}/index.js.map +0 -0
  94. package/{dist-package/Rating → Rating}/Rating.d.ts +0 -0
  95. package/{dist-package/Rating → Rating}/Rating.js +0 -0
  96. package/{dist-package/Rating → Rating}/Rating.js.map +0 -0
  97. package/{dist-package/Rating → Rating}/index.d.ts +0 -0
  98. package/{dist-package/Rating → Rating}/index.js +0 -0
  99. package/{dist-package/Rating → Rating}/index.js.map +0 -0
  100. package/{dist-package/Select → Select}/Select.d.ts +0 -0
  101. package/{dist-package/Select → Select}/Select.js +0 -0
  102. package/{dist-package/Select → Select}/Select.js.map +0 -0
  103. package/{dist-package/Select → Select}/index.d.ts +0 -0
  104. package/{dist-package/Select → Select}/index.js +0 -0
  105. package/{dist-package/Select → Select}/index.js.map +0 -0
  106. package/{dist-package/SubmitButton → SubmitButton}/SubmitButton.d.ts +0 -0
  107. package/{dist-package/SubmitButton → SubmitButton}/SubmitButton.js +0 -0
  108. package/{dist-package/SubmitButton → SubmitButton}/SubmitButton.js.map +0 -0
  109. package/{dist-package/SubmitButton → SubmitButton}/index.d.ts +0 -0
  110. package/{dist-package/SubmitButton → SubmitButton}/index.js +0 -0
  111. package/{dist-package/SubmitButton → SubmitButton}/index.js.map +0 -0
  112. package/{dist-package/Switch → Switch}/Switch.d.ts +0 -0
  113. package/{dist-package/Switch → Switch}/Switch.js +0 -0
  114. package/{dist-package/Switch → Switch}/Switch.js.map +0 -0
  115. package/{dist-package/Switch → Switch}/index.d.ts +0 -0
  116. package/{dist-package/Switch → Switch}/index.js +0 -0
  117. package/{dist-package/Switch → Switch}/index.js.map +0 -0
  118. package/{dist-package/TagSelector → TagSelector}/TagSelector.d.ts +0 -0
  119. package/{dist-package/TagSelector → TagSelector}/TagSelector.js +0 -0
  120. package/{dist-package/TagSelector → TagSelector}/TagSelector.js.map +0 -0
  121. package/{dist-package/TagSelector → TagSelector}/index.d.ts +0 -0
  122. package/{dist-package/TagSelector → TagSelector}/index.js +0 -0
  123. package/{dist-package/TagSelector → TagSelector}/index.js.map +0 -0
  124. package/{dist-package/TimePicker → TimePicker}/TimePicker.d.ts +0 -0
  125. package/{dist-package/TimePicker → TimePicker}/TimePicker.js +0 -0
  126. package/{dist-package/TimePicker → TimePicker}/TimePicker.js.map +0 -0
  127. package/{dist-package/TimePicker → TimePicker}/index.d.ts +0 -0
  128. package/{dist-package/TimePicker → TimePicker}/index.js +0 -0
  129. package/{dist-package/TimePicker → TimePicker}/index.js.map +0 -0
  130. package/{dist-package/index.d.ts → index.d.ts} +0 -0
  131. package/{dist-package/index.js → index.js} +0 -0
  132. package/{dist-package/index.js.map → index.js.map} +0 -0
  133. package/package.json +7 -7
  134. package/{dist-package/utils → utils}/flat-map.d.ts +0 -0
  135. package/{dist-package/utils → utils}/flat-map.js +0 -0
  136. package/{dist-package/utils → utils}/flat-map.js.map +0 -0
  137. package/{dist-package/utils → utils}/index.d.ts +0 -0
  138. package/{dist-package/utils → utils}/index.js +0 -0
  139. package/{dist-package/utils → utils}/index.js.map +0 -0
  140. package/{dist-package/utils → utils}/scroll-to-error-decorator.d.ts +0 -0
  141. package/{dist-package/utils → utils}/scroll-to-error-decorator.js +0 -0
  142. package/{dist-package/utils → utils}/scroll-to-error-decorator.js.map +0 -0
  143. package/{dist-package/utils → utils}/validators.d.ts +0 -0
  144. package/{dist-package/utils → utils}/validators.js +0 -0
  145. package/{dist-package/utils → utils}/validators.js.map +0 -0
  146. package/CHANGELOG.md +0 -657
  147. package/dist-package/Input/Input.js +0 -26
  148. package/dist-package/Input/Input.js.map +0 -1
  149. package/dist-package/Input/utils/get-input-name.d.ts +0 -2
  150. package/dist-package/Input/utils/get-input-name.js +0 -9
  151. package/dist-package/Input/utils/get-input-name.js.map +0 -1
  152. package/dist-package/Input/utils/get-input-name.test.d.ts +0 -1
  153. package/dist-package/Input/utils/get-input-name.test.js +0 -12
  154. package/dist-package/Input/utils/get-input-name.test.js.map +0 -1
  155. package/dist-package/README.md +0 -29
  156. package/dist-package/package.json +0 -44
  157. package/src/Autocomplete/Autocomplete.tsx +0 -21
  158. package/src/Autocomplete/index.ts +0 -1
  159. package/src/ButtonCheckbox/ButtonCheckbox.tsx +0 -57
  160. package/src/ButtonCheckbox/index.ts +0 -1
  161. package/src/ButtonRadio/ButtonRadio.tsx +0 -24
  162. package/src/ButtonRadio/index.ts +0 -1
  163. package/src/Checkbox/Checkbox.tsx +0 -73
  164. package/src/Checkbox/__snapshots__/test.tsx.snap +0 -254
  165. package/src/Checkbox/index.ts +0 -1
  166. package/src/Checkbox/test.tsx +0 -91
  167. package/src/CheckboxGroup/CheckboxGroup.tsx +0 -30
  168. package/src/CheckboxGroup/CheckboxGroupContext.ts +0 -3
  169. package/src/CheckboxGroup/index.ts +0 -3
  170. package/src/CheckboxGroup/test.tsx +0 -35
  171. package/src/DatePicker/DatePicker.tsx +0 -26
  172. package/src/DatePicker/index.ts +0 -1
  173. package/src/FieldWrapper/FieldWrapper.tsx +0 -287
  174. package/src/FieldWrapper/index.ts +0 -2
  175. package/src/FieldWrapper/story/index.jsx +0 -137
  176. package/src/FileInput/FileInput.tsx +0 -66
  177. package/src/FileInput/index.ts +0 -1
  178. package/src/Form/Form.tsx +0 -181
  179. package/src/Form/FormContext.ts +0 -38
  180. package/src/Form/__image_snapshots__/form-default-snap.png +0 -0
  181. package/src/Form/__image_snapshots__/form-form-level-configurations-snap.png +0 -0
  182. package/src/Form/__snapshots__/test.tsx.snap +0 -61
  183. package/src/Form/index.ts +0 -1
  184. package/src/Form/story/BackendCommunication.example.tsx +0 -139
  185. package/src/Form/story/CustomFormLevelConfiguration.example.tsx +0 -26
  186. package/src/Form/story/CustomValidator.example.tsx +0 -45
  187. package/src/Form/story/Default.example.tsx +0 -177
  188. package/src/Form/story/FileInput.example.tsx +0 -42
  189. package/src/Form/story/ParseInput.example.tsx +0 -28
  190. package/src/Form/story/TitleCase.example.tsx +0 -167
  191. package/src/Form/story/ValidateOnSubmit.example.tsx +0 -85
  192. package/src/Form/story/index.jsx +0 -203
  193. package/src/Form/test.tsx +0 -27
  194. package/src/FormConfig/FormConfig.ts +0 -12
  195. package/src/FormConfig/index.ts +0 -1
  196. package/src/FormConfig/test.tsx +0 -44
  197. package/src/Input/Input.tsx +0 -27
  198. package/src/Input/index.ts +0 -1
  199. package/src/Input/test.tsx +0 -34
  200. package/src/Input/utils/get-input-name.test.ts +0 -16
  201. package/src/Input/utils/get-input-name.ts +0 -11
  202. package/src/NumberInput/NumberInput.tsx +0 -45
  203. package/src/NumberInput/index.ts +0 -1
  204. package/src/Radio/Radio.tsx +0 -24
  205. package/src/Radio/__snapshots__/test.tsx.snap +0 -231
  206. package/src/Radio/index.ts +0 -1
  207. package/src/Radio/test.tsx +0 -49
  208. package/src/RadioGroup/RadioGroup.tsx +0 -39
  209. package/src/RadioGroup/RadioGroupContext.ts +0 -3
  210. package/src/RadioGroup/index.ts +0 -3
  211. package/src/RadioGroup/test.tsx +0 -35
  212. package/src/Rating/Rating.tsx +0 -22
  213. package/src/Rating/index.ts +0 -1
  214. package/src/Select/Select.tsx +0 -47
  215. package/src/Select/index.ts +0 -1
  216. package/src/SubmitButton/SubmitButton.tsx +0 -70
  217. package/src/SubmitButton/__image_snapshots__/submitbutton-button-types-snap.png +0 -0
  218. package/src/SubmitButton/__image_snapshots__/submitbutton-default-snap.png +0 -0
  219. package/src/SubmitButton/index.ts +0 -6
  220. package/src/SubmitButton/story/ButtonTypes.example.tsx +0 -46
  221. package/src/SubmitButton/story/Default.example.tsx +0 -15
  222. package/src/SubmitButton/story/index.jsx +0 -32
  223. package/src/Switch/Switch.tsx +0 -23
  224. package/src/Switch/index.ts +0 -1
  225. package/src/TagSelector/TagSelector.tsx +0 -25
  226. package/src/TagSelector/index.ts +0 -1
  227. package/src/TimePicker/TimePicker.tsx +0 -24
  228. package/src/TimePicker/index.ts +0 -1
  229. package/src/index.ts +0 -16
  230. package/src/story/Deserialization.example.tsx +0 -34
  231. package/src/story/FormSpy.example.tsx +0 -42
  232. package/src/story/index.jsx +0 -37
  233. package/src/utils/flat-map.ts +0 -4
  234. package/src/utils/index.ts +0 -3
  235. package/src/utils/scroll-to-error-decorator.ts +0 -78
  236. package/src/utils/validators.ts +0 -18
  237. package/tsconfig.build.json +0 -7
@@ -1,42 +0,0 @@
1
- import React from 'react'
2
- import { Container } from '@toptal/picasso'
3
- import { Form } from '@toptal/picasso-forms'
4
- import { FileUpload } from '@toptal/picasso/FileInput'
5
-
6
- type FormType = {
7
- attachments: FileUpload[]
8
- }
9
-
10
- const Example = () => {
11
- const MAX_SIZE = 2
12
- const initialAttachments = [
13
- { file: new File(['image.png'], 'image.png') },
14
- { file: new File(['resume.pdf'], 'resume.pdf') }
15
- ]
16
-
17
- const handleSubmit = ({ attachments }: FormType) => {
18
- window.alert(
19
- `Uploading: ${attachments.map(({ file }) => file.name).join(', ')}`
20
- )
21
- }
22
-
23
- return (
24
- <Form<FormType>
25
- autoComplete='off'
26
- onSubmit={handleSubmit}
27
- initialValues={{
28
- attachments: initialAttachments
29
- }}
30
- >
31
- <Form.FileInput
32
- name='attachments'
33
- hint={`Max file size: ${MAX_SIZE}MB.`}
34
- />
35
- <Container top='small'>
36
- <Form.SubmitButton>Submit</Form.SubmitButton>
37
- </Container>
38
- </Form>
39
- )
40
- }
41
-
42
- export default Example
@@ -1,28 +0,0 @@
1
- import React from 'react'
2
- import { Container, Typography } from '@toptal/picasso'
3
- import { Form } from '@toptal/picasso-forms'
4
-
5
- const ParseInputExample = () => (
6
- <Form onSubmit={values => window.alert(values)}>
7
- <Container bottom='small'>
8
- <Typography size='medium'>
9
- I want to trim my first name from the empty spaces:
10
- </Typography>
11
- </Container>
12
- <Container flex alignItems='flex-end'>
13
- <Form.Input
14
- name='parseInput.firstName'
15
- label='First name'
16
- placeholder='e.g. Bruce'
17
- parse={(value: string) => value.trim()}
18
- limit={24}
19
- />
20
-
21
- <Container left='small'>
22
- <Form.SubmitButton>Submit</Form.SubmitButton>
23
- </Container>
24
- </Container>
25
- </Form>
26
- )
27
-
28
- export default ParseInputExample
@@ -1,167 +0,0 @@
1
- import React, { useState } from 'react'
2
- import { Container } from '@toptal/picasso'
3
- import { Item } from '@toptal/picasso/Autocomplete'
4
- import { isSubstring } from '@toptal/picasso/utils'
5
- import { Form } from '@toptal/picasso-forms'
6
-
7
- const countries = [
8
- { value: 'Afghanistan', text: 'Afghanistan' },
9
- { value: 'Albania', text: 'Albania' },
10
- { value: 'Algeria', text: 'Algeria' },
11
- { value: 'Belarus', text: 'Belarus' },
12
- { value: 'Croatia', text: 'Croatia' },
13
- { value: 'Lithuania', text: 'Lithuania' },
14
- { value: 'Slovakia', text: 'Slovakia' },
15
- { value: 'Spain', text: 'Spain' },
16
- { value: 'Ukraine', text: 'Ukraine' }
17
- ]
18
-
19
- const skills = [
20
- { value: 0, text: 'HTML' },
21
- { value: 1, text: 'CSS' },
22
- { value: 2, text: 'Javascript' }
23
- ]
24
-
25
- const EMPTY_INPUT_VALUE = ''
26
- const getAutocompleteDisplayValue = (item: Item | null) =>
27
- item?.text || EMPTY_INPUT_VALUE
28
-
29
- const filterOptions = (str = '', options: Item[] = []): Item[] | null => {
30
- if (!str) {
31
- return options
32
- }
33
- const result = options.filter(option =>
34
- option?.text ? isSubstring(str, option.text) : false
35
- )
36
-
37
- return result.length > 0 ? result : null
38
- }
39
-
40
- const Example = () => {
41
- const [skillInputValue, setSkillInputValue] = useState<string>(
42
- EMPTY_INPUT_VALUE
43
- )
44
- const skillOptions = filterOptions(skillInputValue, skills)
45
-
46
- const [autocompleteValue, setAutocompleteValue] = useState<string>(
47
- EMPTY_INPUT_VALUE
48
- )
49
- const [autocompleteOptions, setAutocompleteOptions] = useState<Item[] | null>(
50
- countries
51
- )
52
-
53
- return (
54
- <Form
55
- autoComplete='off'
56
- onSubmit={values => window.alert(values)}
57
- initialValues={{ gender: 'female' }}
58
- >
59
- <Form.Input
60
- titleCase
61
- enableReset
62
- onResetClick={(set: (value: string) => void) => {
63
- set('')
64
- }}
65
- required
66
- name='firstName'
67
- label='First name'
68
- placeholder='e.g. Bruce'
69
- />
70
- <Form.NumberInput
71
- titleCase
72
- enableReset
73
- required
74
- name='age'
75
- label="What's your age?"
76
- placeholder='e.g. 25'
77
- />
78
- <Form.RadioGroup titleCase name='gender' label='Select gender'>
79
- <Form.Radio label='Male' value='male' />
80
- <Form.Radio label='Female' value='female' />
81
- </Form.RadioGroup>
82
- <Form.DatePicker titleCase name='dateOfBirth' label='Date of birth' />
83
- <Form.TimePicker titleCase name='timeOfBirth' label='Time of birth' />
84
- <Form.TagSelector
85
- titleCase
86
- name='skills'
87
- label='Your skills'
88
- inputValue={skillInputValue}
89
- options={skillOptions}
90
- onInputChange={setSkillInputValue}
91
- />
92
- <Form.CheckboxGroup titleCase name='hobbies' label='Your hobbies'>
93
- <Form.Checkbox label='Skiing' value='skiing' />
94
- <Form.Checkbox titleCase label='Free diving' value='freeDiving' />
95
- <Form.Checkbox label='Dancing' value='dancing' />
96
- </Form.CheckboxGroup>
97
- <Form.Select
98
- titleCase
99
- enableReset
100
- required
101
- name='businessType'
102
- label='Business type'
103
- width='auto'
104
- options={[
105
- { value: 0, text: 'Company' },
106
- { value: 1, text: 'Individual' }
107
- ]}
108
- />
109
- <Form.Autocomplete
110
- titleCase
111
- name='current_country'
112
- label='Current country'
113
- placeholder='Start typing country...'
114
- width='auto'
115
- value={autocompleteValue}
116
- options={autocompleteOptions}
117
- onSelect={(item: Item) => {
118
- console.log('onSelect returns item object:', item)
119
-
120
- const itemValue = getAutocompleteDisplayValue(item)
121
-
122
- if (autocompleteValue !== itemValue) {
123
- setAutocompleteValue(itemValue)
124
- }
125
- }}
126
- onChange={(newValue: string) => {
127
- console.log('onChange returns just item value:', newValue)
128
-
129
- setAutocompleteOptions(filterOptions(newValue, countries))
130
- setAutocompleteValue(newValue)
131
- }}
132
- getDisplayValue={getAutocompleteDisplayValue}
133
- />
134
- <Form.Rating
135
- titleCase
136
- name='rating'
137
- label='How much do you love Picasso?'
138
- required
139
- />
140
- <Form.FileInput
141
- titleCase
142
- required
143
- name='avatar'
144
- label='Your avatar'
145
- status='No file selected.'
146
- />
147
- <Form.Checkbox
148
- titleCase
149
- required
150
- name='legal'
151
- label='I confirm that I have legal permission from the client to feature this project.'
152
- />
153
- <Form.Switch
154
- titleCase
155
- name='publicProfile'
156
- label='Public profile'
157
- width='auto'
158
- />
159
-
160
- <Container top='small'>
161
- <Form.SubmitButton>Submit</Form.SubmitButton>
162
- </Container>
163
- </Form>
164
- )
165
- }
166
-
167
- export default Example
@@ -1,85 +0,0 @@
1
- import React, { useCallback } from 'react'
2
- import { useField } from 'react-final-form'
3
- import { Container } from '@toptal/picasso'
4
- import { Form } from '@toptal/picasso-forms'
5
-
6
- type FormType = {
7
- hide: boolean
8
- name: {
9
- first: string
10
- last: string
11
- }
12
- dob: string
13
- }
14
-
15
- const FormContent = () => {
16
- const {
17
- input: { value: hide }
18
- } = useField('hide')
19
-
20
- return (
21
- <>
22
- <Form.Checkbox name='hide' label='Check to hide fields below' />
23
-
24
- {!hide && (
25
- <>
26
- <Form.Input
27
- enableReset
28
- required
29
- name='name.first'
30
- label='Your first name'
31
- placeholder='e.g. Bruce'
32
- />
33
- <Form.Input
34
- enableReset
35
- required
36
- name='name.last'
37
- label='Your last name'
38
- placeholder='e.g. Wayne'
39
- />
40
- <Form.DatePicker required name='dob' label='DOB' />
41
- </>
42
- )}
43
- </>
44
- )
45
- }
46
-
47
- const Example = () => {
48
- const handleSubmit = useCallback((values: FormType) => api.submit(values), [])
49
-
50
- return (
51
- <Form.ConfigProvider value={{ validateOnSubmit: true }}>
52
- <Form<FormType>
53
- onSubmit={handleSubmit}
54
- successSubmitMessage='Success!'
55
- failedSubmitMessage='Failure!'
56
- >
57
- <FormContent />
58
-
59
- <Container top='small'>
60
- <Form.SubmitButton>Submit</Form.SubmitButton>
61
- </Container>
62
- </Form>
63
- </Form.ConfigProvider>
64
- )
65
- }
66
-
67
- // the emulation of the api call
68
- const responseWithDelay = async (response: any) =>
69
- new Promise(resolve => setTimeout(() => resolve(response), 2000))
70
-
71
- const api = {
72
- submit: async (values: FormType) => {
73
- if (values.hide || values.name?.first.toLowerCase() === 'bruce') {
74
- return responseWithDelay(undefined)
75
- }
76
-
77
- return responseWithDelay({
78
- name: {
79
- first: 'Unknown first name'
80
- }
81
- })
82
- }
83
- }
84
-
85
- export default Example
@@ -1,203 +0,0 @@
1
- import Form from '../Form'
2
- import formFieldStory from '../../FieldWrapper/story'
3
- import PicassoBook from '~/.storybook/components/PicassoBook'
4
-
5
- const page = PicassoBook.section('Picasso Forms').createPage('Form', 'Form')
6
-
7
- page
8
- .createTabChapter('Props')
9
- .addComponentDocs({
10
- component: Form,
11
- name: 'Form',
12
- additionalDocs: {
13
- autoComplete: {
14
- name: 'autoComplete',
15
- type: {
16
- name: 'string',
17
- enums: ['on', 'off']
18
- },
19
- description: `HTML Form autocomplete attribute.\n
20
- The autocomplete attribute specifies whether a form should have autocomplete 'on' or 'off'.
21
- When autocomplete is 'on', the browser automatically complete values based on values that the user has entered before.\n
22
- Tip: It is possible to have autocomplete 'on' for the form, and 'off' for specific input fields, or vice versa.`
23
- },
24
- debug: {
25
- name: 'debug',
26
- type: {
27
- name: 'function',
28
- description:
29
- '(state: FormState, fieldStates: { [string]: FieldState }) => void'
30
- },
31
- description:
32
- 'A callback for debugging that receives the form state and the states of all the fields'
33
- },
34
- decorators: {
35
- name: 'decorators',
36
- type: 'Decorator[]',
37
- description: 'An array of decorators to apply to the form'
38
- },
39
- initialValues: {
40
- name: 'initialValues',
41
- type: 'FormValues | Object',
42
- description: 'The initial values of the form'
43
- },
44
- initialValuesEqual: {
45
- name: 'initialValuesEqual',
46
- type: {
47
- name: 'function',
48
- description: '(Object | undefined, Object | undefined) => boolean'
49
- },
50
- description:
51
- 'A predicate to determine whether or not the initialValues prop has changed'
52
- },
53
- keepDirtyOnReinitialize: {
54
- name: 'keepDirtyOnReinitialize',
55
- type: 'boolean',
56
- description:
57
- 'If true, only pristine values will be overwritten when initialize(newValues) is called'
58
- },
59
- mutators: {
60
- name: 'mutators',
61
- type: {
62
- name: 'object',
63
- description: '{ [string]: Mutator }'
64
- },
65
- description: 'Named mutator functions'
66
- },
67
- onSubmit: {
68
- name: 'onSubmit',
69
- type: {
70
- name: 'function',
71
- description:
72
- '(values: FormValues, form: FormApi, callback: ?(errors: ?Object) => void) => ?Object | Promise<?Object> | void'
73
- },
74
- description: 'Function to call when the form is submitted',
75
- required: true
76
- },
77
- subscription: {
78
- name: 'subscription',
79
- type: {
80
- name: 'object',
81
- description: '{ [string]: boolean }'
82
- },
83
- description:
84
- 'An object of the parts of FormState (final-form) to subscribe to'
85
- },
86
- validate: {
87
- name: 'validate',
88
- type: {
89
- name: 'function',
90
- description: '(values: FormValues) => Object | Promise<Object>'
91
- },
92
- description:
93
- 'A whole-record validation function that takes all the values of the form and returns any validation errors'
94
- },
95
- validateOnBlur: {
96
- name: 'validateOnBlur',
97
- type: 'boolean',
98
- description:
99
- 'If true, validation will happen on blur. If false, validation will happen on change',
100
- defaultValue: false
101
- },
102
- successSubmitMessage: {
103
- name: 'successSubmitMessage',
104
- type: 'ReactNode',
105
- description:
106
- 'Message to display in a tooltip when form submitted successfully'
107
- },
108
- failedSubmitMessage: {
109
- name: 'failedSubmitMessage',
110
- type: 'ReactNode',
111
- description:
112
- 'Message to display in a tooltip when form submission failed'
113
- },
114
- scrollOffsetTop: {
115
- name: 'scrollOffsetTop',
116
- type: 'number',
117
- description:
118
- 'Offset from the viewport for inputs to focus on, defaults to the center of the window (deprecated, will not have any effect)'
119
- }
120
- }
121
- })
122
- .addComponentDocs(formFieldStory.componentDocs)
123
-
124
- page
125
- .createChapter()
126
- .addTextSection(
127
- `
128
- Form is a wrapper for 'react-final-form' Form component. It also
129
- provides inside all the necessary input components types.
130
- `
131
- )
132
- .addExample(
133
- 'Form/story/Default.example.tsx',
134
- {
135
- title: 'Default',
136
- description: `
137
- A general look of the form includes the examples of all the input
138
- types supported by picasso-forms.
139
- `
140
- },
141
- 'picasso-form'
142
- )
143
- .addExample(
144
- 'Form/story/CustomValidator.example.tsx',
145
- {
146
- title: 'Custom validator',
147
- description: `
148
- We have a 'required' validator included by default to each input type,
149
- however, you may need custom validators for more complex types of fields.
150
- `
151
- },
152
- 'picasso-form'
153
- ) // picasso-skip-visuals
154
- .addExample(
155
- 'Form/story/ParseInput.example.tsx',
156
- {
157
- title: 'Change form input value',
158
- description: `
159
- When you use picasso-forms your form input components are no longer
160
- completely controlled and they are controlled by final-form, which
161
- gives you the opportunity to rely on it with displaying errors,
162
- validations, etc.
163
-
164
- However, sometimes you may need to be able to modify the form input
165
- value.
166
- `
167
- },
168
- 'picasso-form'
169
- ) // picasso-skip-visuals
170
- .addExample(
171
- 'Form/story/BackendCommunication.example.tsx',
172
- {
173
- title: 'Backend communication',
174
- description: `
175
- The form usually need to send data to backend, so we need to have
176
- backend communication and display the process of submission and
177
- the results. The form-level results are represented by notifications.
178
- `
179
- },
180
- 'picasso-form'
181
- ) // picasso-skip-visuals
182
- .addExample(
183
- 'Form/story/CustomFormLevelConfiguration.example.tsx',
184
- 'Form Level Configurations'
185
- )
186
- .addExample(
187
- 'Form/story/ValidateOnSubmit.example.tsx',
188
- {
189
- title: 'Validate only on submit',
190
- description: `
191
- All fields should not show any validation error messages until submission is made.
192
- `
193
- },
194
- 'picasso-form'
195
- ) // picasso-skip-visuals
196
- .addExample('Form/story/FileInput.example.tsx', {
197
- title: 'File input on a Form',
198
- description: 'Showcase how to upload files on the form submission'
199
- }) // picasso-skip-visuals
200
- .addExample('Form/story/TitleCase.example.tsx', {
201
- title: 'Title case',
202
- description: "Display the field's label in title case."
203
- }) // picasso-skip-visuals
package/src/Form/test.tsx DELETED
@@ -1,27 +0,0 @@
1
- import React from 'react'
2
- import { render } from '@toptal/picasso/test-utils'
3
- import { OmitInternalProps } from '@toptal/picasso-shared'
4
- import { Button } from '@toptal/picasso'
5
-
6
- import Form, { Props } from './Form'
7
-
8
- const renderForm = (props: OmitInternalProps<Props>) => {
9
- const { onSubmit } = props
10
-
11
- return render(
12
- <Form onSubmit={onSubmit}>
13
- <Form.Input name='test' placeholder='test input' />
14
- <Button type='submit'>Submit</Button>
15
- </Form>
16
- )
17
- }
18
-
19
- describe('Form', () => {
20
- it('renders', () => {
21
- const { container } = renderForm({
22
- onSubmit: () => {}
23
- })
24
-
25
- expect(container).toMatchSnapshot()
26
- })
27
- })
@@ -1,12 +0,0 @@
1
- import { createContext, useContext } from 'react'
2
-
3
- export type RequiredVariant = 'default' | 'asterisk'
4
-
5
- export interface FormConfigProps {
6
- validateOnSubmit?: boolean
7
- requiredVariant?: RequiredVariant
8
- }
9
-
10
- export const FormConfigContext = createContext<FormConfigProps>({})
11
-
12
- export const useFormConfig = () => useContext(FormConfigContext)
@@ -1 +0,0 @@
1
- export * from './FormConfig'
@@ -1,44 +0,0 @@
1
- import React from 'react'
2
- import { screen, render, fireEvent } from '@toptal/picasso/test-utils'
3
-
4
- import Form from '../Form'
5
- import { FormConfigProps } from './FormConfig'
6
-
7
- const TEXT_INPUT_LABEL = 'Test text field'
8
-
9
- const renderForm = (configProps: FormConfigProps) => {
10
- return render(
11
- <Form.ConfigProvider value={configProps}>
12
- <Form onSubmit={() => {}}>
13
- <Form.Input label={TEXT_INPUT_LABEL} required name='test' />
14
- <Form.SubmitButton>Submit</Form.SubmitButton>
15
- </Form>
16
- </Form.ConfigProvider>
17
- )
18
- }
19
-
20
- describe('Form.ConfigProvider', () => {
21
- it('validate only on submit', async () => {
22
- renderForm({ validateOnSubmit: true })
23
-
24
- fireEvent.blur(screen.getByLabelText(TEXT_INPUT_LABEL))
25
-
26
- expect(
27
- screen.queryByText('Please complete this field.')
28
- ).not.toBeInTheDocument()
29
-
30
- fireEvent.click(screen.getByRole('button', { name: 'Submit' }))
31
-
32
- expect(
33
- await screen.findByText('Please complete this field.')
34
- ).toBeInTheDocument()
35
- })
36
-
37
- it('validate normally on blur / change', async () => {
38
- renderForm({ validateOnSubmit: false })
39
-
40
- fireEvent.blur(screen.getByLabelText(TEXT_INPUT_LABEL))
41
-
42
- expect(screen.getByText('Please complete this field.')).toBeInTheDocument()
43
- })
44
- })
@@ -1,27 +0,0 @@
1
- import React from 'react'
2
- import { Input as PicassoInput, InputProps } from '@toptal/picasso'
3
-
4
- import FieldWrapper, { FieldProps } from '../FieldWrapper'
5
- import getInputName from './utils/get-input-name'
6
-
7
- export type FormInputProps = Omit<InputProps, 'onResetClick'> & {
8
- /** Callback invoked when reset button was clicked */
9
- onResetClick?: (set: (value: string) => void) => void
10
- }
11
- export type Props = FormInputProps & FieldProps<InputProps['value']>
12
-
13
- export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => (
14
- <FieldWrapper<FormInputProps> {...props}>
15
- {({ name, ...inputProps }: InputProps) => (
16
- // TODO: remove getInputName completely when Chrome fixes autocomplete issue
17
- // Link to the issue: https://bugs.chromium.org/p/chromium/issues/detail?id=1255609
18
- <PicassoInput name={getInputName(name)} {...inputProps} ref={ref} />
19
- )}
20
- </FieldWrapper>
21
- ))
22
-
23
- Input.defaultProps = {}
24
-
25
- Input.displayName = 'Input'
26
-
27
- export default Input
@@ -1 +0,0 @@
1
- export { default } from './Input'
@@ -1,34 +0,0 @@
1
- import React from 'react'
2
- import { render, fireEvent } from '@toptal/picasso/test-utils'
3
- import { Button } from '@toptal/picasso'
4
-
5
- import Form, { Props as FormProps } from '../Form/Form'
6
- import { Props as InputProps } from './Input'
7
-
8
- type TestFormProps = Pick<FormProps, 'onSubmit'> & Pick<InputProps, 'onFocus'>
9
-
10
- const renderForm = (props: TestFormProps) => {
11
- const { onFocus, onSubmit } = props
12
-
13
- return render(
14
- <Form onSubmit={onSubmit}>
15
- <Form.Input onFocus={onFocus} name='test' placeholder='test input' />
16
- <Button type='submit'>Submit</Button>
17
- </Form>
18
- )
19
- }
20
-
21
- describe('Input', () => {
22
- it('fires the onFocus callback after focusing the input', () => {
23
- const handleFocus = jest.fn()
24
-
25
- const { getByPlaceholderText } = renderForm({
26
- onSubmit: () => {},
27
- onFocus: handleFocus
28
- })
29
-
30
- fireEvent.focus(getByPlaceholderText('test input'))
31
-
32
- expect(handleFocus).toHaveBeenCalled()
33
- })
34
- })