@toptal/picasso-forms 67.0.0 → 67.1.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 (104) hide show
  1. package/dist-package/src/Autocomplete/Autocomplete.d.ts +2 -1
  2. package/dist-package/src/Autocomplete/Autocomplete.d.ts.map +1 -1
  3. package/dist-package/src/Autocomplete/Autocomplete.js +2 -2
  4. package/dist-package/src/Autocomplete/Autocomplete.js.map +1 -1
  5. package/dist-package/src/AvatarUpload/AvatarUpload.d.ts +2 -1
  6. package/dist-package/src/AvatarUpload/AvatarUpload.d.ts.map +1 -1
  7. package/dist-package/src/AvatarUpload/AvatarUpload.js +3 -3
  8. package/dist-package/src/AvatarUpload/AvatarUpload.js.map +1 -1
  9. package/dist-package/src/Checkbox/Checkbox.d.ts.map +1 -1
  10. package/dist-package/src/Checkbox/Checkbox.js +5 -2
  11. package/dist-package/src/Checkbox/Checkbox.js.map +1 -1
  12. package/dist-package/src/CheckboxGroup/CheckboxGroup.d.ts +2 -1
  13. package/dist-package/src/CheckboxGroup/CheckboxGroup.d.ts.map +1 -1
  14. package/dist-package/src/CheckboxGroup/CheckboxGroup.js +2 -2
  15. package/dist-package/src/CheckboxGroup/CheckboxGroup.js.map +1 -1
  16. package/dist-package/src/DatePicker/DatePicker.d.ts +2 -1
  17. package/dist-package/src/DatePicker/DatePicker.d.ts.map +1 -1
  18. package/dist-package/src/DatePicker/DatePicker.js +2 -2
  19. package/dist-package/src/DatePicker/DatePicker.js.map +1 -1
  20. package/dist-package/src/Dropzone/Dropzone.d.ts +2 -1
  21. package/dist-package/src/Dropzone/Dropzone.d.ts.map +1 -1
  22. package/dist-package/src/Dropzone/Dropzone.js +1 -1
  23. package/dist-package/src/Dropzone/Dropzone.js.map +1 -1
  24. package/dist-package/src/FieldLabel/FieldLabel.d.ts +9 -4
  25. package/dist-package/src/FieldLabel/FieldLabel.d.ts.map +1 -1
  26. package/dist-package/src/FieldLabel/FieldLabel.js +2 -3
  27. package/dist-package/src/FieldLabel/FieldLabel.js.map +1 -1
  28. package/dist-package/src/FieldWrapper/FieldWrapper.d.ts +3 -4
  29. package/dist-package/src/FieldWrapper/FieldWrapper.d.ts.map +1 -1
  30. package/dist-package/src/FieldWrapper/FieldWrapper.js +2 -2
  31. package/dist-package/src/FieldWrapper/FieldWrapper.js.map +1 -1
  32. package/dist-package/src/FileInput/FileInput.d.ts +2 -1
  33. package/dist-package/src/FileInput/FileInput.d.ts.map +1 -1
  34. package/dist-package/src/FileInput/FileInput.js +1 -1
  35. package/dist-package/src/FileInput/FileInput.js.map +1 -1
  36. package/dist-package/src/Form/Form.d.ts +1 -0
  37. package/dist-package/src/Form/Form.d.ts.map +1 -1
  38. package/dist-package/src/Form/Form.js +2 -2
  39. package/dist-package/src/Form/Form.js.map +1 -1
  40. package/dist-package/src/FormCompound/index.d.ts +6 -1
  41. package/dist-package/src/FormCompound/index.d.ts.map +1 -1
  42. package/dist-package/src/Input/Input.d.ts +2 -1
  43. package/dist-package/src/Input/Input.d.ts.map +1 -1
  44. package/dist-package/src/Input/Input.js +2 -2
  45. package/dist-package/src/Input/Input.js.map +1 -1
  46. package/dist-package/src/NumberInput/NumberInput.d.ts +2 -1
  47. package/dist-package/src/NumberInput/NumberInput.d.ts.map +1 -1
  48. package/dist-package/src/NumberInput/NumberInput.js +2 -2
  49. package/dist-package/src/NumberInput/NumberInput.js.map +1 -1
  50. package/dist-package/src/PasswordInput/PasswordInput.d.ts +2 -1
  51. package/dist-package/src/PasswordInput/PasswordInput.d.ts.map +1 -1
  52. package/dist-package/src/PasswordInput/PasswordInput.js +1 -1
  53. package/dist-package/src/PasswordInput/PasswordInput.js.map +1 -1
  54. package/dist-package/src/RadioGroup/RadioGroup.d.ts +2 -1
  55. package/dist-package/src/RadioGroup/RadioGroup.d.ts.map +1 -1
  56. package/dist-package/src/RadioGroup/RadioGroup.js +2 -2
  57. package/dist-package/src/RadioGroup/RadioGroup.js.map +1 -1
  58. package/dist-package/src/Rating/Rating.d.ts +2 -1
  59. package/dist-package/src/Rating/Rating.d.ts.map +1 -1
  60. package/dist-package/src/Rating/Rating.js +4 -4
  61. package/dist-package/src/Rating/Rating.js.map +1 -1
  62. package/dist-package/src/RichTextEditor/RichTextEditor.d.ts +2 -1
  63. package/dist-package/src/RichTextEditor/RichTextEditor.d.ts.map +1 -1
  64. package/dist-package/src/RichTextEditor/RichTextEditor.js +2 -2
  65. package/dist-package/src/RichTextEditor/RichTextEditor.js.map +1 -1
  66. package/dist-package/src/Select/Select.d.ts +2 -1
  67. package/dist-package/src/Select/Select.d.ts.map +1 -1
  68. package/dist-package/src/Select/Select.js +2 -2
  69. package/dist-package/src/Select/Select.js.map +1 -1
  70. package/dist-package/src/Switch/Switch.d.ts +2 -1
  71. package/dist-package/src/Switch/Switch.d.ts.map +1 -1
  72. package/dist-package/src/Switch/Switch.js +1 -1
  73. package/dist-package/src/Switch/Switch.js.map +1 -1
  74. package/dist-package/src/TagSelector/TagSelector.d.ts +2 -1
  75. package/dist-package/src/TagSelector/TagSelector.d.ts.map +1 -1
  76. package/dist-package/src/TagSelector/TagSelector.js +2 -2
  77. package/dist-package/src/TagSelector/TagSelector.js.map +1 -1
  78. package/dist-package/src/TimePicker/TimePicker.d.ts +2 -1
  79. package/dist-package/src/TimePicker/TimePicker.d.ts.map +1 -1
  80. package/dist-package/src/TimePicker/TimePicker.js +2 -2
  81. package/dist-package/src/TimePicker/TimePicker.js.map +1 -1
  82. package/package.json +2 -2
  83. package/src/Autocomplete/Autocomplete.tsx +6 -2
  84. package/src/AvatarUpload/AvatarUpload.tsx +6 -1
  85. package/src/Checkbox/Checkbox.tsx +17 -7
  86. package/src/CheckboxGroup/CheckboxGroup.tsx +11 -2
  87. package/src/DatePicker/DatePicker.tsx +6 -2
  88. package/src/Dropzone/Dropzone.tsx +3 -1
  89. package/src/FieldLabel/FieldLabel.tsx +18 -5
  90. package/src/FieldWrapper/FieldWrapper.tsx +6 -6
  91. package/src/FieldWrapper/story/index.jsx +6 -1
  92. package/src/FileInput/FileInput.tsx +5 -1
  93. package/src/Form/Form.tsx +3 -0
  94. package/src/Form/story/Horizontal.example.tsx +68 -35
  95. package/src/Input/Input.tsx +6 -2
  96. package/src/NumberInput/NumberInput.tsx +14 -2
  97. package/src/PasswordInput/PasswordInput.tsx +5 -1
  98. package/src/RadioGroup/RadioGroup.tsx +6 -2
  99. package/src/Rating/Rating.tsx +15 -4
  100. package/src/RichTextEditor/RichTextEditor.tsx +13 -2
  101. package/src/Select/Select.tsx +11 -2
  102. package/src/Switch/Switch.tsx +9 -2
  103. package/src/TagSelector/TagSelector.tsx +6 -2
  104. package/src/TimePicker/TimePicker.tsx +6 -2
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from 'react'
1
2
  import React from 'react'
2
3
  import type { RequiredDecoration } from '@toptal/picasso'
3
4
  import { Form as PicassoForm } from '@toptal/picasso'
@@ -8,11 +9,17 @@ import { useFormConfig } from '../FormConfig'
8
9
 
9
10
  export type Props = {
10
11
  name?: string
11
- label?: React.ReactNode
12
+ label?: ReactNode
13
+ /** Label's end adornment */
14
+ labelEndAdornment?: ReactNode
12
15
  required?: boolean
13
- alignment?: 'top' | 'middle'
14
16
  } & TextLabelProps
15
17
 
18
+ type InternalProps = {
19
+ /** Whether label should be aligned to top of the container or not */
20
+ alignment?: 'top' | 'middle'
21
+ }
22
+
16
23
  const getRequiredDecoration = (
17
24
  required?: boolean,
18
25
  requiredVariant?: RequiredVariant
@@ -31,9 +38,14 @@ const getRequiredDecoration = (
31
38
  }
32
39
  }
33
40
 
34
- const FieldLabel = (props: Props) => {
35
- const { label, required, titleCase, name, alignment } = props
36
-
41
+ const FieldLabel = ({
42
+ label,
43
+ required,
44
+ titleCase,
45
+ name,
46
+ alignment,
47
+ labelEndAdornment,
48
+ }: Props & InternalProps) => {
37
49
  const formConfig = useFormConfig()
38
50
 
39
51
  if (!label) {
@@ -51,6 +63,7 @@ const FieldLabel = (props: Props) => {
51
63
  htmlFor={name}
52
64
  titleCase={titleCase}
53
65
  alignment={alignment}
66
+ labelEndAdornment={labelEndAdornment}
54
67
  >
55
68
  {label}
56
69
  </PicassoForm.Label>
@@ -1,17 +1,16 @@
1
- import type { ReactNode } from 'react'
2
1
  import React from 'react'
3
2
 
4
3
  import type { Props as FieldProps } from '../Field'
5
4
  import type { ValueType, IFormComponentProps } from '../FieldBase'
5
+ import type { Props as FieldLabelProps } from '../FieldLabel'
6
6
  import FieldLabel from '../FieldLabel'
7
7
  import InputField from '../InputField'
8
8
 
9
9
  export type Props<TWrappedComponentProps, TInputValue> = Omit<
10
10
  FieldProps<TWrappedComponentProps, TInputValue>,
11
11
  'label'
12
- > & {
13
- label?: ReactNode
14
- }
12
+ > &
13
+ Omit<FieldLabelProps, 'name'>
15
14
 
16
15
  const FieldWrapper = <
17
16
  TWrappedComponentProps extends IFormComponentProps,
@@ -19,7 +18,7 @@ const FieldWrapper = <
19
18
  >(
20
19
  props: Props<TWrappedComponentProps, TInputValue>
21
20
  ) => {
22
- const { label, name, titleCase, children, ...rest } = props
21
+ const { label, labelEndAdornment, name, titleCase, children, ...rest } = props
23
22
 
24
23
  return (
25
24
  <InputField<IFormComponentProps, TInputValue>
@@ -28,9 +27,10 @@ const FieldWrapper = <
28
27
  label={
29
28
  label ? (
30
29
  <FieldLabel
31
- name={props.name}
30
+ name={name}
32
31
  required={props.required}
33
32
  label={label}
33
+ labelEndAdornment={labelEndAdornment}
34
34
  titleCase={titleCase}
35
35
  />
36
36
  ) : null
@@ -14,9 +14,14 @@ const componentDocs = PicassoBook.createComponentDocs(
14
14
  },
15
15
  label: {
16
16
  name: 'label',
17
- type: 'string',
17
+ type: 'ReactNode',
18
18
  description: 'The field label text',
19
19
  },
20
+ labelEndAdornment: {
21
+ name: 'labelEndAdornment',
22
+ type: 'ReactNode',
23
+ description: "The label's end adornment",
24
+ },
20
25
  hint: {
21
26
  name: 'hint',
22
27
  type: 'string',
@@ -6,12 +6,15 @@ import type { FieldInputProps as FinalFieldInputProps } from 'react-final-form'
6
6
  import type { FieldProps } from '../Field'
7
7
  import PicassoField from '../Field'
8
8
  import FieldLabel from '../FieldLabel'
9
+ import type { Props as FieldLabelProps } from '../FieldLabel'
9
10
 
10
11
  type FinalFormOnChangeType = FinalFieldInputProps<
11
12
  FileInputProps['value']
12
13
  >['onChange']
13
14
 
14
- export type Props = FileInputProps & FieldProps<FileInputProps['value']>
15
+ export type Props = FileInputProps &
16
+ FieldProps<FileInputProps['value']> &
17
+ FieldLabelProps
15
18
 
16
19
  export const FileInput = (props: Props) => {
17
20
  const handleChange = (
@@ -53,6 +56,7 @@ export const FileInput = (props: Props) => {
53
56
  name={props.name}
54
57
  required={props.required}
55
58
  label={props.label}
59
+ labelEndAdornment={props.labelEndAdornment}
56
60
  titleCase={props.titleCase}
57
61
  />
58
62
  ) : null
package/src/Form/Form.tsx CHANGED
@@ -21,6 +21,7 @@ export type Props<T = AnyObject> = FinalFormProps<T> & {
21
21
  scrollOffsetTop?: number
22
22
  layout?: 'horizontal' | 'vertical'
23
23
  labelWidth?: FormProps['labelWidth']
24
+ className?: string
24
25
  'data-testid'?: string
25
26
  }
26
27
 
@@ -63,6 +64,7 @@ export const Form = <T extends AnyObject = AnyObject>(props: Props<T>) => {
63
64
  'data-testid': dataTestId,
64
65
  layout,
65
66
  labelWidth,
67
+ className,
66
68
  ...rest
67
69
  } = props
68
70
  const { showSuccess, showError } = useNotifications()
@@ -136,6 +138,7 @@ export const Form = <T extends AnyObject = AnyObject>(props: Props<T>) => {
136
138
  setActiveFieldTouched={form.mutators.setActiveFieldTouched}
137
139
  labelWidth={labelWidth}
138
140
  layout={layout}
141
+ className={className}
139
142
  >
140
143
  {children}
141
144
  </FormRenderer>
@@ -1,6 +1,12 @@
1
1
  import React, { useState } from 'react'
2
- import { FormActionsContainer } from '@toptal/picasso'
3
- import { SPACING_4, isSubstring } from '@toptal/picasso-utils'
2
+ import {
3
+ Button,
4
+ Container,
5
+ FormActionsContainer,
6
+ Info16,
7
+ Tooltip,
8
+ } from '@toptal/picasso'
9
+ import { SPACING_4, isSubstring, SPACING_1 } from '@toptal/picasso/utils'
4
10
  import type { Item } from '@toptal/picasso/Autocomplete'
5
11
  import {
6
12
  FormNonCompound as Form,
@@ -60,7 +66,7 @@ const filterOptions = (str = '', options: Item[] = []): Item[] | null => {
60
66
  }
61
67
 
62
68
  const initialValues = {
63
- 'default-gender': 'female',
69
+ 'horizontal-gender': 'female',
64
70
  }
65
71
 
66
72
  // eslint-disable-next-line max-lines-per-function
@@ -88,97 +94,124 @@ const Example = () => {
88
94
  set('')
89
95
  }}
90
96
  required
91
- name='default-firstName'
97
+ name='horizontal-firstName'
92
98
  label='First name'
93
99
  placeholder='e.g. Bruce'
94
100
  />
95
101
  <Input
96
102
  required
97
- name='default-lastName'
103
+ name='horizontal-lastName'
98
104
  label='Last name'
99
105
  placeholder='e.g. Wayne'
100
106
  size='small'
101
107
  />
102
108
  <Input
103
109
  required
104
- name='default-nickName'
110
+ name='horizontal-nickName'
105
111
  label='Nick name'
106
112
  placeholder='e.g. Batman'
107
113
  />
108
114
  <Input
109
115
  required
110
- name='default-website'
116
+ name='horizontal-website'
111
117
  label='Website'
112
118
  placeholder='e.g. google.com'
113
119
  size='large'
114
120
  />
115
- <Input name='default-multiline' label='Description' multiline rows={4} />
121
+ <Input
122
+ name='horizontal-multiline'
123
+ label='Description'
124
+ multiline
125
+ rows={4}
126
+ />
116
127
  <RichTextEditor
117
- name='default-richTextEditorName'
118
- id='default-richTextEditorName'
128
+ name='horizontal-richTextEditorName'
129
+ id='horizontal-richTextEditorName'
119
130
  label='Rich text editor'
120
131
  />
121
- <Dropzone label='Attachments' required name='default-attachments' />
132
+ <Dropzone label='Attachments' required name='horizontal-attachments' />
122
133
  <AvatarUpload
123
134
  label='Profile photo xxsmall'
124
135
  required
125
- name='default-avatarUpload-xxsmall'
136
+ name='horizontal-avatarUpload-xxsmall'
126
137
  size='xxsmall'
127
138
  />
128
139
  <AvatarUpload
129
140
  label='Profile photo xsmall'
130
141
  required
131
- name='default-avatarUpload-xsmall'
142
+ name='horizontal-avatarUpload-xsmall'
132
143
  size='xsmall'
133
144
  />
134
145
  <AvatarUpload
135
146
  label='Profile photo'
136
147
  required
137
- name='default-avatarUpload-small'
148
+ name='horizontal-avatarUpload-small'
138
149
  />
139
150
  <AvatarUpload
140
151
  label='Profile photo medium'
141
152
  required
142
- name='default-avatarUpload-medium'
153
+ name='horizontal-avatarUpload-medium'
143
154
  size='medium'
144
155
  />
145
156
  <AvatarUpload
146
157
  label='Profile photo large'
147
158
  required
148
- name='default-avatarUpload-large'
159
+ name='horizontal-avatarUpload-large'
149
160
  size='large'
150
161
  />
151
162
  <NumberInput
152
163
  enableReset
153
- required
154
- name='default-age'
164
+ name='horizontal-age'
155
165
  label="What's your age?"
156
166
  placeholder='e.g. 25'
167
+ labelEndAdornment={
168
+ <Container inline left={SPACING_1}>
169
+ <Tooltip content='Content goes here...' placement='right'>
170
+ <Button.Circular variant='flat' icon={<Info16 />} />
171
+ </Tooltip>
172
+ </Container>
173
+ }
157
174
  />
158
- <RadioGroup name='default-gender' label='Gender'>
175
+ <RadioGroup
176
+ name='horizontal-gender'
177
+ label='Gender'
178
+ required
179
+ labelEndAdornment={
180
+ <Container inline left={SPACING_1}>
181
+ <Tooltip content='Content goes here...' placement='right'>
182
+ <Button.Circular variant='flat' icon={<Info16 />} />
183
+ </Tooltip>
184
+ </Container>
185
+ }
186
+ >
159
187
  <Radio label='Male' value='male' />
160
188
  <Radio label='Female' value='female' />
161
189
  </RadioGroup>
162
- <RadioGroup name='default-language-radio' label='Languages'>
190
+ <RadioGroup name='horizontal-language-radio' label='Languages'>
163
191
  <Radio label='English' value='english' />
164
192
  <Radio label='French' value='french' />
165
193
  <Radio label='German' value='german' />
166
194
  </RadioGroup>
167
- <RadioGroup name='default-gender' label='Gender' horizontal spacing={8}>
195
+ <RadioGroup
196
+ name='horizontal-gender-2'
197
+ label='Gender'
198
+ horizontal
199
+ spacing={8}
200
+ >
168
201
  <ButtonRadio value='male'>Male</ButtonRadio>
169
202
  <ButtonRadio value='female'>Female</ButtonRadio>
170
203
  </RadioGroup>
171
- <CheckboxGroup name='default-hobbies' label='Hobbies'>
204
+ <CheckboxGroup name='horizontal-hobbies' label='Hobbies'>
172
205
  <Checkbox label='Skiing' value='skiing' />
173
206
  <Checkbox label='Free diving' value='freeDiving' />
174
207
  <Checkbox label='Dancing' value='dancing' />
175
208
  </CheckboxGroup>
176
- <CheckboxGroup name='default-language' label='Languages'>
209
+ <CheckboxGroup name='horizontal-language' label='Languages'>
177
210
  <Checkbox label='English' value='english' />
178
211
  <Checkbox label='French' value='french' />
179
212
  </CheckboxGroup>
180
213
  <CheckboxGroup
181
- name='default-hobbies-buttons'
214
+ name='horizontal-hobbies-buttons'
182
215
  label='Hobbies'
183
216
  horizontal
184
217
  spacing={8}
@@ -187,10 +220,10 @@ const Example = () => {
187
220
  <ButtonCheckbox value='freeDiving'>Free diving</ButtonCheckbox>
188
221
  <ButtonCheckbox value='dancing'>Dancing</ButtonCheckbox>
189
222
  </CheckboxGroup>
190
- <DatePicker name='default-dateOfBirth' label='Date of birth' />
191
- <TimePicker name='default-timeOfBirth' label='Time of birth' />
223
+ <DatePicker name='horizontal-dateOfBirth' label='Date of birth' />
224
+ <TimePicker name='horizontal-timeOfBirth' label='Time of birth' />
192
225
  <TagSelector
193
- name='default-skills'
226
+ name='horizontal-skills'
194
227
  label='Skills'
195
228
  inputValue={skillInputValue}
196
229
  options={skillOptions}
@@ -206,7 +239,7 @@ const Example = () => {
206
239
  <Select
207
240
  enableReset
208
241
  required
209
- name='default-businessType'
242
+ name='horizontal-businessType'
210
243
  label='Business type'
211
244
  width='auto'
212
245
  options={[
@@ -215,13 +248,13 @@ const Example = () => {
215
248
  ]}
216
249
  />
217
250
  <Select
218
- name='default-origin_country'
251
+ name='horizontal-origin_country'
219
252
  label='Origin country'
220
253
  width='auto'
221
254
  options={countries}
222
255
  />
223
256
  <Autocomplete
224
- name='default-current_country'
257
+ name='horizontal-current_country'
225
258
  label='Current country'
226
259
  placeholder='Start typing country...'
227
260
  width='auto'
@@ -245,28 +278,28 @@ const Example = () => {
245
278
  getDisplayValue={getAutocompleteDisplayValue}
246
279
  />
247
280
  <Rating.Stars
248
- name='default-rating'
281
+ name='horizontal-rating'
249
282
  label='How much do you love Picasso?'
250
283
  required
251
284
  />
252
285
  <Rating.Thumbs
253
- name='default-thumbs'
286
+ name='horizontal-thumbs'
254
287
  label='Would you recommend Picasso?'
255
288
  required
256
289
  />
257
290
  <FileInput
258
291
  required
259
- name='default-resume'
292
+ name='horizontal-resume'
260
293
  label='Resume'
261
294
  status='No file selected.'
262
295
  />
263
296
  <Checkbox
264
297
  required
265
- name='default-legal'
298
+ name='horizontal-legal'
266
299
  label='I confirm that I have legal permission from the client to feature this project.'
267
300
  />
268
301
  <Switch
269
- name='default-publicProfile'
302
+ name='horizontal-publicProfile'
270
303
  label='Public Profile'
271
304
  width='auto'
272
305
  />
@@ -4,6 +4,7 @@ import { Input as PicassoInput } from '@toptal/picasso'
4
4
  import { useForm } from 'react-final-form'
5
5
 
6
6
  import type { FieldProps } from '../Field'
7
+ import type { Props as FieldLabelProps } from '../FieldLabel'
7
8
  import FieldLabel from '../FieldLabel'
8
9
  import InputField from '../InputField'
9
10
 
@@ -11,7 +12,9 @@ export type FormInputProps = Omit<InputProps, 'onResetClick'> & {
11
12
  /** Callback invoked when reset button was clicked */
12
13
  onResetClick?: (set: (value: string) => void) => void
13
14
  }
14
- export type Props = FormInputProps & FieldProps<InputProps['value']>
15
+ export type Props = FormInputProps &
16
+ FieldProps<InputProps['value']> &
17
+ FieldLabelProps
15
18
 
16
19
  const warnAutocompleteDisabledInput = (name?: string) => {
17
20
  const autocompleteDisabled =
@@ -37,7 +40,7 @@ export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
37
40
  mutators: { setHasMultilineCounter },
38
41
  } = useForm()
39
42
 
40
- const { label, titleCase, ...rest } = props
43
+ const { label, labelEndAdornment, titleCase, ...rest } = props
41
44
  const { multiline, rows, rowsMax } = props
42
45
 
43
46
  const alignment = useMemo(() => {
@@ -62,6 +65,7 @@ export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
62
65
  name={props.name}
63
66
  required={props.required}
64
67
  label={label}
68
+ labelEndAdornment={labelEndAdornment}
65
69
  titleCase={titleCase}
66
70
  alignment={alignment}
67
71
  />
@@ -5,10 +5,13 @@ import type { FieldValidator } from 'final-form'
5
5
 
6
6
  import { validators } from '../utils'
7
7
  import type { FieldProps } from '../Field'
8
+ import type { Props as FieldLabelProps } from '../FieldLabel'
8
9
  import FieldLabel from '../FieldLabel'
9
10
  import InputField from '../InputField'
10
11
 
11
- export type Props = NumberInputProps & FieldProps<NumberInputProps['value']>
12
+ export type Props = NumberInputProps &
13
+ FieldProps<NumberInputProps['value']> &
14
+ FieldLabelProps
12
15
 
13
16
  const MIN = -2147483648
14
17
  const MAX = 2147483647
@@ -16,7 +19,15 @@ const MAX = 2147483647
16
19
  const { composeValidators } = validators
17
20
 
18
21
  export const NumberInput = (props: Props) => {
19
- const { min = MIN, max = MAX, validate, label, titleCase, ...rest } = props
22
+ const {
23
+ min = MIN,
24
+ max = MAX,
25
+ validate,
26
+ label,
27
+ labelEndAdornment,
28
+ titleCase,
29
+ ...rest
30
+ } = props
20
31
 
21
32
  const validateNumberLimits: FieldValidator<
22
33
  NumberInputProps['value']
@@ -39,6 +50,7 @@ export const NumberInput = (props: Props) => {
39
50
  name={props.name}
40
51
  required={props.required}
41
52
  label={label}
53
+ labelEndAdornment={labelEndAdornment}
42
54
  titleCase={titleCase}
43
55
  />
44
56
  ) : null
@@ -6,13 +6,16 @@ import type { FieldValidator } from 'final-form'
6
6
 
7
7
  import { validators } from '../utils'
8
8
  import type { FieldProps } from '../Field'
9
+ import type { Props as FieldLabelProps } from '../FieldLabel'
9
10
  import FieldLabel from '../FieldLabel'
10
11
  import passwordValidators from './validators'
11
12
  import InputField from '../InputField'
12
13
  import FieldRenderer from './FieldRenderer'
13
14
 
14
15
  export type Props = PasswordInputProps &
15
- FieldProps<PasswordInputProps['value']> & { hideRequirements?: boolean }
16
+ FieldProps<PasswordInputProps['value']> & {
17
+ hideRequirements?: boolean
18
+ } & FieldLabelProps
16
19
 
17
20
  const { composeValidators } = validators
18
21
 
@@ -121,6 +124,7 @@ export const PasswordInput = ({
121
124
  name={rest.name}
122
125
  required={rest.required}
123
126
  label={rest.label}
127
+ labelEndAdornment={rest.labelEndAdornment}
124
128
  titleCase={rest.titleCase}
125
129
  />
126
130
  ) : null
@@ -5,12 +5,15 @@ import { Radio as PicassoRadio } from '@toptal/picasso'
5
5
  import type { FieldProps } from '../Field'
6
6
  import PicassoField from '../Field'
7
7
  import FieldLabel from '../FieldLabel'
8
+ import type { Props as FieldLabelProps } from '../FieldLabel'
8
9
  import RadioGroupContext from './RadioGroupContext'
9
10
 
10
- export type Props = RadioGroupProps & FieldProps<RadioProps['value']>
11
+ export type Props = RadioGroupProps &
12
+ FieldProps<RadioProps['value']> &
13
+ FieldLabelProps
11
14
 
12
15
  export const RadioGroup = (props: Props) => {
13
- const { children, label, titleCase, ...rest } = props
16
+ const { children, label, labelEndAdornment, titleCase, ...rest } = props
14
17
 
15
18
  const alignment = Children.count(children) > 2 ? 'top' : 'middle'
16
19
 
@@ -25,6 +28,7 @@ export const RadioGroup = (props: Props) => {
25
28
  name={props.name}
26
29
  required={props.required}
27
30
  label={label}
31
+ labelEndAdornment={labelEndAdornment}
28
32
  titleCase={titleCase}
29
33
  alignment={alignment}
30
34
  />
@@ -8,13 +8,15 @@ import { Rating as PicassoRating } from '@toptal/picasso'
8
8
  import type { FieldProps } from '../Field'
9
9
  import PicassoField from '../Field'
10
10
  import FieldLabel from '../FieldLabel'
11
+ import type { Props as FieldLabelProps } from '../FieldLabel'
11
12
  import { validators } from '../utils'
12
13
 
13
14
  export type RatingStarsProps = PicassoRatingStarsProps &
14
- FieldProps<PicassoRatingStarsProps['value']>
15
+ FieldProps<PicassoRatingStarsProps['value']> &
16
+ FieldLabelProps
15
17
 
16
18
  const Stars = (props: RatingStarsProps) => {
17
- const { label, titleCase, ...rest } = props
19
+ const { label, labelEndAdornment, titleCase, ...rest } = props
18
20
 
19
21
  return (
20
22
  <PicassoField<PicassoRatingStarsProps>
@@ -26,6 +28,7 @@ const Stars = (props: RatingStarsProps) => {
26
28
  name={props.name}
27
29
  required={props.required}
28
30
  label={label}
31
+ labelEndAdornment={labelEndAdornment}
29
32
  titleCase={titleCase}
30
33
  />
31
34
  ) : null
@@ -58,8 +61,15 @@ const thumbsRequired = (value: boolean | undefined) =>
58
61
  value == null ? validators.required(null) : undefined
59
62
 
60
63
  const Thumbs = (props: RatingThumbsProps) => {
61
- const { required, validate, requirePositive, label, titleCase, ...rest } =
62
- props
64
+ const {
65
+ required,
66
+ validate,
67
+ requirePositive,
68
+ label,
69
+ labelEndAdornment,
70
+ titleCase,
71
+ ...rest
72
+ } = props
63
73
 
64
74
  const validateOverride = validators.composeValidators([
65
75
  required && !requirePositive ? thumbsRequired : undefined,
@@ -77,6 +87,7 @@ const Thumbs = (props: RatingThumbsProps) => {
77
87
  name={props.name}
78
88
  required={props.required}
79
89
  label={label}
90
+ labelEndAdornment={labelEndAdornment}
80
91
  titleCase={titleCase}
81
92
  />
82
93
  ) : null
@@ -10,6 +10,7 @@ import { useForm } from 'react-final-form'
10
10
  import type { FieldProps } from '../FieldWrapper'
11
11
  import InputField from '../InputField'
12
12
  import FieldLabel from '../FieldLabel'
13
+ import type { Props as FieldLabelProps } from '../FieldLabel'
13
14
  import { useEnforceHighlightAutofill } from './hooks'
14
15
 
15
16
  type OverriddenProps = {
@@ -20,12 +21,21 @@ type OverriddenProps = {
20
21
 
21
22
  export type Props = RichTextEditorProps &
22
23
  Except<FieldProps<string>, keyof OverriddenProps> &
23
- OverriddenProps
24
+ OverriddenProps &
25
+ FieldLabelProps
24
26
 
25
27
  type InternalProps = RichTextEditorProps & { value: string }
26
28
 
27
29
  export const RichTextEditor = (props: Props) => {
28
- const { onChange, onFocus, defaultValue, label, titleCase, ...rest } = props
30
+ const {
31
+ onChange,
32
+ onFocus,
33
+ defaultValue,
34
+ label,
35
+ labelEndAdornment,
36
+ titleCase,
37
+ ...rest
38
+ } = props
29
39
 
30
40
  const { enforceHighlightAutofill, registerChangeOrFocus } =
31
41
  useEnforceHighlightAutofill()
@@ -64,6 +74,7 @@ export const RichTextEditor = (props: Props) => {
64
74
  name={hiddenInputId}
65
75
  required={props.required}
66
76
  label={label}
77
+ labelEndAdornment={labelEndAdornment}
67
78
  titleCase={titleCase}
68
79
  alignment='top'
69
80
  />
@@ -6,16 +6,24 @@ import { generateRandomStringOrGetEmptyInTest } from '@toptal/picasso-utils'
6
6
  import type { FieldProps } from '../Field'
7
7
  import InputField from '../InputField'
8
8
  import FieldLabel from '../FieldLabel'
9
+ import type { Props as FieldLabelProps } from '../FieldLabel'
9
10
 
10
11
  export type Props<
11
12
  T extends SelectValueType,
12
13
  M extends boolean = false
13
- > = SelectProps<T, M> & FieldProps<SelectProps<T, M>['value']>
14
+ > = SelectProps<T, M> & FieldProps<SelectProps<T, M>['value']> & FieldLabelProps
14
15
 
15
16
  export const Select = <T extends SelectValueType, M extends boolean = false>(
16
17
  props: Props<T, M>
17
18
  ) => {
18
- const { name, id = name, label, titleCase, ...rest } = props
19
+ const {
20
+ name,
21
+ id = name,
22
+ label,
23
+ labelEndAdornment,
24
+ titleCase,
25
+ ...rest
26
+ } = props
19
27
  const randomizedId = id ? generateRandomStringOrGetEmptyInTest(id) : undefined
20
28
 
21
29
  return (
@@ -29,6 +37,7 @@ export const Select = <T extends SelectValueType, M extends boolean = false>(
29
37
  name={randomizedId}
30
38
  required={rest.required}
31
39
  label={label}
40
+ labelEndAdornment={labelEndAdornment}
32
41
  titleCase={titleCase}
33
42
  />
34
43
  ) : null