@bspk/ui 1.3.20 → 1.3.22

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 (290) hide show
  1. package/dist/components/Accordion/Accordion.js +1 -1
  2. package/dist/components/Accordion/Accordion.js.map +1 -1
  3. package/dist/components/Accordion/accordion.css +19 -12
  4. package/dist/components/Accordion/accordion.css.js +19 -12
  5. package/dist/components/BottomNavigation/BottomNavigation.d.ts +0 -1
  6. package/dist/components/BottomNavigation/BottomNavigation.js +0 -1
  7. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  8. package/dist/components/BottomNavigation/bottom-navigation.css +1 -0
  9. package/dist/components/BottomNavigation/bottom-navigation.css.js +1 -0
  10. package/dist/components/Button/button.css +4 -0
  11. package/dist/components/Button/button.css.js +4 -0
  12. package/dist/components/Checkbox/Checkbox.js +3 -3
  13. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  14. package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +4 -5
  15. package/dist/components/CheckboxGroup/CheckboxGroup.js +8 -13
  16. package/dist/components/CheckboxGroup/CheckboxGroup.js.map +1 -1
  17. package/dist/components/CheckboxGroup/CheckboxGroupExample.js +5 -0
  18. package/dist/components/CheckboxGroup/CheckboxGroupExample.js.map +1 -1
  19. package/dist/components/CheckboxGroup/checkbox-group.css +2 -0
  20. package/dist/components/CheckboxGroup/checkbox-group.css.js +2 -0
  21. package/dist/components/CheckboxGroupField/CheckboxGroupField.d.ts +3 -3
  22. package/dist/components/CheckboxGroupField/CheckboxGroupField.js +6 -4
  23. package/dist/components/CheckboxGroupField/CheckboxGroupField.js.map +1 -1
  24. package/dist/components/ChipGroup/ChipGroup.d.ts +0 -1
  25. package/dist/components/ChipGroup/ChipGroup.js +0 -1
  26. package/dist/components/ChipGroup/ChipGroup.js.map +1 -1
  27. package/dist/components/ChipGroup/chip-group.css +3 -0
  28. package/dist/components/ChipGroup/chip-group.css.js +3 -0
  29. package/dist/components/DatePicker/DatePicker.d.ts +4 -8
  30. package/dist/components/DatePicker/DatePicker.js +6 -18
  31. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  32. package/dist/components/DatePicker/DatePickerExample.js +3 -3
  33. package/dist/components/DatePicker/DatePickerExample.js.map +1 -1
  34. package/dist/components/DatePickerField/DatePickerField.d.ts +4 -4
  35. package/dist/components/DatePickerField/DatePickerField.js +6 -4
  36. package/dist/components/DatePickerField/DatePickerField.js.map +1 -1
  37. package/dist/components/Dialog/Dialog.d.ts +2 -3
  38. package/dist/components/Dialog/Dialog.js +2 -3
  39. package/dist/components/Dialog/Dialog.js.map +1 -1
  40. package/dist/components/Fab/Fab.d.ts +8 -5
  41. package/dist/components/Fab/Fab.js +8 -5
  42. package/dist/components/Fab/Fab.js.map +1 -1
  43. package/dist/components/Fab/fab.css +1 -0
  44. package/dist/components/Fab/fab.css.js +1 -0
  45. package/dist/components/Field/Field.d.ts +32 -18
  46. package/dist/components/Field/Field.js +8 -38
  47. package/dist/components/Field/Field.js.map +1 -1
  48. package/dist/components/Field/FieldExample.d.ts +1 -0
  49. package/dist/components/Field/FieldExample.js +10 -3
  50. package/dist/components/Field/FieldExample.js.map +1 -1
  51. package/dist/components/Field/Fieldset.d.ts +40 -0
  52. package/dist/components/Field/Fieldset.js +44 -0
  53. package/dist/components/Field/Fieldset.js.map +1 -0
  54. package/dist/components/Field/field.css +5 -7
  55. package/dist/components/Field/field.css.js +5 -7
  56. package/dist/components/Field/index.d.ts +1 -3
  57. package/dist/components/Field/index.js +1 -3
  58. package/dist/components/Field/index.js.map +1 -1
  59. package/dist/components/Field/utils.d.ts +8 -38
  60. package/dist/components/Field/utils.js +6 -33
  61. package/dist/components/Field/utils.js.map +1 -1
  62. package/dist/components/FileUpload/FileUpload.js +1 -1
  63. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  64. package/dist/components/FileUploadItem/FileUploadItem.js +1 -1
  65. package/dist/components/FileUploadItem/FileUploadItem.js.map +1 -1
  66. package/dist/components/Flex/Flex.d.ts +11 -7
  67. package/dist/components/Flex/Flex.js +12 -8
  68. package/dist/components/Flex/Flex.js.map +1 -1
  69. package/dist/components/InlineAlert/InlineAlert.d.ts +2 -2
  70. package/dist/components/InlineAlert/InlineAlert.js +2 -2
  71. package/dist/components/InlineAlert/InlineAlert.js.map +1 -1
  72. package/dist/components/Input/Input.d.ts +60 -15
  73. package/dist/components/Input/Input.js +42 -25
  74. package/dist/components/Input/Input.js.map +1 -1
  75. package/dist/components/Input/InputExample.js +4 -4
  76. package/dist/components/Input/InputExample.js.map +1 -1
  77. package/dist/components/Input/index.d.ts +0 -1
  78. package/dist/components/Input/index.js +0 -1
  79. package/dist/components/Input/index.js.map +1 -1
  80. package/dist/components/InputField/InputField.d.ts +4 -4
  81. package/dist/components/InputField/InputField.js +6 -4
  82. package/dist/components/InputField/InputField.js.map +1 -1
  83. package/dist/components/InputNumber/InputNumber.d.ts +8 -7
  84. package/dist/components/InputNumber/InputNumber.js +9 -16
  85. package/dist/components/InputNumber/InputNumber.js.map +1 -1
  86. package/dist/components/InputNumber/InputNumberExample.js +3 -3
  87. package/dist/components/InputNumber/InputNumberExample.js.map +1 -1
  88. package/dist/components/InputNumber/input-number.css +1 -0
  89. package/dist/components/InputNumber/input-number.css.js +1 -0
  90. package/dist/components/InputNumberField/InputNumberField.d.ts +4 -4
  91. package/dist/components/InputNumberField/InputNumberField.js +6 -4
  92. package/dist/components/InputNumberField/InputNumberField.js.map +1 -1
  93. package/dist/components/InputPhone/InputPhone.d.ts +8 -8
  94. package/dist/components/InputPhone/InputPhone.js +12 -18
  95. package/dist/components/InputPhone/InputPhone.js.map +1 -1
  96. package/dist/components/InputPhone/InputPhoneExample.js +3 -3
  97. package/dist/components/InputPhone/InputPhoneExample.js.map +1 -1
  98. package/dist/components/InputPhone/input-phone.css +1 -0
  99. package/dist/components/InputPhone/input-phone.css.js +1 -0
  100. package/dist/components/InputPhoneField/InputPhoneField.d.ts +4 -4
  101. package/dist/components/InputPhoneField/InputPhoneField.js +6 -4
  102. package/dist/components/InputPhoneField/InputPhoneField.js.map +1 -1
  103. package/dist/components/ListItem/list-item.css +1 -0
  104. package/dist/components/ListItem/list-item.css.js +1 -0
  105. package/dist/components/Modal/Modal.js +22 -26
  106. package/dist/components/Modal/Modal.js.map +1 -1
  107. package/dist/components/Modal/ModalExample.js +4 -1
  108. package/dist/components/Modal/ModalExample.js.map +1 -1
  109. package/dist/components/Modal/modal.css +4 -2
  110. package/dist/components/Modal/modal.css.js +4 -2
  111. package/dist/components/OTPInput/otp-input.css +1 -0
  112. package/dist/components/OTPInput/otp-input.css.js +1 -0
  113. package/dist/components/Pagination/Pagination.js +2 -2
  114. package/dist/components/Pagination/Pagination.js.map +1 -1
  115. package/dist/components/Password/Password.d.ts +9 -7
  116. package/dist/components/Password/Password.js +13 -17
  117. package/dist/components/Password/Password.js.map +1 -1
  118. package/dist/components/Password/PasswordExample.js +3 -3
  119. package/dist/components/Password/PasswordExample.js.map +1 -1
  120. package/dist/components/PasswordField/PasswordField.d.ts +4 -4
  121. package/dist/components/PasswordField/PasswordField.js +6 -4
  122. package/dist/components/PasswordField/PasswordField.js.map +1 -1
  123. package/dist/components/Popover/Popover.d.ts +0 -1
  124. package/dist/components/Popover/Popover.js +0 -1
  125. package/dist/components/Popover/Popover.js.map +1 -1
  126. package/dist/components/RadioGroup/RadioGroup.d.ts +1 -2
  127. package/dist/components/RadioGroup/RadioGroup.js +5 -11
  128. package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
  129. package/dist/components/RadioGroupField/RadioGroupField.d.ts +3 -3
  130. package/dist/components/RadioGroupField/RadioGroupField.js +6 -4
  131. package/dist/components/RadioGroupField/RadioGroupField.js.map +1 -1
  132. package/dist/components/SearchBar/SearchBar.d.ts +0 -1
  133. package/dist/components/SearchBar/SearchBar.js +0 -1
  134. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  135. package/dist/components/SegmentedControl/SegmentedControl.d.ts +0 -1
  136. package/dist/components/SegmentedControl/SegmentedControl.js +0 -1
  137. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  138. package/dist/components/Select/Select.d.ts +7 -6
  139. package/dist/components/Select/Select.js +10 -15
  140. package/dist/components/Select/Select.js.map +1 -1
  141. package/dist/components/Select/SelectExample.js +3 -3
  142. package/dist/components/Select/SelectExample.js.map +1 -1
  143. package/dist/components/SelectField/SelectField.d.ts +4 -4
  144. package/dist/components/SelectField/SelectField.js +6 -4
  145. package/dist/components/SelectField/SelectField.js.map +1 -1
  146. package/dist/components/Slider/Slider.d.ts +1 -2
  147. package/dist/components/Slider/Slider.js +1 -2
  148. package/dist/components/Slider/Slider.js.map +1 -1
  149. package/dist/components/Snackbar/Snackbar.d.ts +0 -1
  150. package/dist/components/Snackbar/Snackbar.js +0 -1
  151. package/dist/components/Snackbar/Snackbar.js.map +1 -1
  152. package/dist/components/Switch/Switch.d.ts +0 -1
  153. package/dist/components/Switch/Switch.js +0 -1
  154. package/dist/components/Switch/Switch.js.map +1 -1
  155. package/dist/components/TabGroup/TabGroup.d.ts +0 -1
  156. package/dist/components/TabGroup/TabGroup.js +0 -1
  157. package/dist/components/TabGroup/TabGroup.js.map +1 -1
  158. package/dist/components/TabList/TabList.d.ts +0 -1
  159. package/dist/components/TabList/TabList.js +0 -1
  160. package/dist/components/TabList/TabList.js.map +1 -1
  161. package/dist/components/TabList/tab-list.css +1 -0
  162. package/dist/components/TabList/tab-list.css.js +1 -0
  163. package/dist/components/Table/table.css +2 -1
  164. package/dist/components/Table/table.css.js +2 -1
  165. package/dist/components/Textarea/Textarea.d.ts +4 -7
  166. package/dist/components/Textarea/Textarea.js +5 -16
  167. package/dist/components/Textarea/Textarea.js.map +1 -1
  168. package/dist/components/Textarea/TextareaExample.js +3 -3
  169. package/dist/components/Textarea/TextareaExample.js.map +1 -1
  170. package/dist/components/TextareaField/TextareaField.d.ts +4 -4
  171. package/dist/components/TextareaField/TextareaField.js +6 -4
  172. package/dist/components/TextareaField/TextareaField.js.map +1 -1
  173. package/dist/components/TimePicker/TimePicker.d.ts +8 -6
  174. package/dist/components/TimePicker/TimePicker.js +10 -14
  175. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  176. package/dist/components/TimePicker/TimePickerExample.js +3 -3
  177. package/dist/components/TimePicker/TimePickerExample.js.map +1 -1
  178. package/dist/components/TimePickerField/TimePickerField.d.ts +4 -4
  179. package/dist/components/TimePickerField/TimePickerField.js +6 -4
  180. package/dist/components/TimePickerField/TimePickerField.js.map +1 -1
  181. package/dist/types/common.d.ts +2 -0
  182. package/dist/types/common.js.map +1 -1
  183. package/dist/utils/demo.js +1 -1
  184. package/dist/utils/demo.js.map +1 -1
  185. package/package.json +3 -4
  186. package/src/components/Accordion/Accordion.tsx +2 -2
  187. package/src/components/Accordion/accordion.scss +10 -1
  188. package/src/components/BottomNavigation/BottomNavigation.tsx +0 -1
  189. package/src/components/BottomNavigation/bottom-navigation.scss +1 -0
  190. package/src/components/Button/button.scss +4 -0
  191. package/src/components/Checkbox/Checkbox.tsx +3 -3
  192. package/src/components/CheckboxGroup/CheckboxGroup.tsx +37 -52
  193. package/src/components/CheckboxGroup/CheckboxGroupExample.tsx +6 -0
  194. package/src/components/CheckboxGroup/checkbox-group.scss +2 -0
  195. package/src/components/CheckboxGroupField/CheckboxGroupField.tsx +15 -11
  196. package/src/components/ChipGroup/ChipGroup.tsx +0 -1
  197. package/src/components/ChipGroup/chip-group.scss +4 -0
  198. package/src/components/DatePicker/DatePicker.tsx +9 -20
  199. package/src/components/DatePicker/DatePickerExample.tsx +3 -5
  200. package/src/components/DatePickerField/DatePickerField.rtl.test.tsx +1 -1
  201. package/src/components/DatePickerField/DatePickerField.tsx +10 -6
  202. package/src/components/Dialog/Dialog.tsx +2 -3
  203. package/src/components/Fab/Fab.tsx +8 -5
  204. package/src/components/Fab/fab.scss +1 -0
  205. package/src/components/Field/Field.rtl.test.tsx +8 -6
  206. package/src/components/Field/Field.tsx +64 -61
  207. package/src/components/Field/FieldExample.tsx +27 -5
  208. package/src/components/Field/Fieldset.tsx +78 -0
  209. package/src/components/Field/field.scss +23 -27
  210. package/src/components/Field/index.tsx +1 -3
  211. package/src/components/Field/utils.ts +15 -77
  212. package/src/components/FileUpload/FileUpload.tsx +1 -1
  213. package/src/components/FileUploadItem/FileUploadItem.tsx +1 -1
  214. package/src/components/Flex/Flex.tsx +12 -7
  215. package/src/components/InlineAlert/InlineAlert.rtl.test.tsx +1 -1
  216. package/src/components/InlineAlert/InlineAlert.tsx +3 -3
  217. package/src/components/Input/Input.tsx +140 -48
  218. package/src/components/Input/InputExample.tsx +4 -6
  219. package/src/components/Input/index.tsx +0 -1
  220. package/src/components/InputField/InputField.tsx +10 -6
  221. package/src/components/InputNumber/InputNumber.tsx +11 -16
  222. package/src/components/InputNumber/InputNumberExample.tsx +7 -4
  223. package/src/components/InputNumber/input-number.scss +1 -0
  224. package/src/components/InputNumberField/InputNumberField.tsx +10 -6
  225. package/src/components/InputPhone/InputPhone.tsx +14 -18
  226. package/src/components/InputPhone/InputPhoneExample.tsx +7 -6
  227. package/src/components/InputPhone/input-phone.scss +1 -0
  228. package/src/components/InputPhoneField/InputPhoneField.tsx +10 -6
  229. package/src/components/ListItem/list-item.scss +1 -0
  230. package/src/components/Modal/Modal.tsx +26 -30
  231. package/src/components/Modal/ModalExample.tsx +7 -2
  232. package/src/components/Modal/modal.scss +1 -1
  233. package/src/components/OTPInput/otp-input.scss +1 -0
  234. package/src/components/Pagination/Pagination.tsx +2 -2
  235. package/src/components/Password/Password.tsx +15 -17
  236. package/src/components/Password/PasswordExample.tsx +13 -5
  237. package/src/components/PasswordField/PasswordField.tsx +10 -6
  238. package/src/components/Popover/Popover.tsx +0 -1
  239. package/src/components/RadioGroup/RadioGroup.tsx +14 -20
  240. package/src/components/RadioGroupField/RadioGroupField.tsx +16 -11
  241. package/src/components/SearchBar/SearchBar.tsx +0 -1
  242. package/src/components/SegmentedControl/SegmentedControl.tsx +0 -1
  243. package/src/components/Select/Select.tsx +13 -14
  244. package/src/components/Select/SelectExample.tsx +7 -4
  245. package/src/components/SelectField/SelectField.rtl.test.tsx +7 -18
  246. package/src/components/SelectField/SelectField.tsx +10 -6
  247. package/src/components/Slider/Slider.tsx +1 -2
  248. package/src/components/Snackbar/Snackbar.tsx +0 -1
  249. package/src/components/Switch/Switch.tsx +0 -1
  250. package/src/components/TabGroup/TabGroup.tsx +0 -1
  251. package/src/components/TabList/TabList.tsx +0 -1
  252. package/src/components/TabList/tab-list.scss +1 -0
  253. package/src/components/Table/table.scss +2 -1
  254. package/src/components/Textarea/Textarea.tsx +8 -17
  255. package/src/components/Textarea/TextareaExample.tsx +3 -5
  256. package/src/components/TextareaField/TextareaField.tsx +10 -6
  257. package/src/components/TimePicker/TimePicker.tsx +12 -15
  258. package/src/components/TimePicker/TimePickerExample.tsx +3 -5
  259. package/src/components/TimePickerField/TimePickerField.tsx +10 -6
  260. package/src/types/common.ts +8 -0
  261. package/src/utils/demo.ts +1 -1
  262. package/dist/components/Field/FieldDescription.d.ts +0 -9
  263. package/dist/components/Field/FieldDescription.js +0 -13
  264. package/dist/components/Field/FieldDescription.js.map +0 -1
  265. package/dist/components/Field/FieldError.d.ts +0 -11
  266. package/dist/components/Field/FieldError.js +0 -14
  267. package/dist/components/Field/FieldError.js.map +0 -1
  268. package/dist/components/Field/FieldLabel.d.ts +0 -21
  269. package/dist/components/Field/FieldLabel.js +0 -14
  270. package/dist/components/Field/FieldLabel.js.map +0 -1
  271. package/dist/components/FormField/FormField.d.ts +0 -66
  272. package/dist/components/FormField/FormField.js +0 -31
  273. package/dist/components/FormField/FormField.js.map +0 -1
  274. package/dist/components/FormField/FormFieldExample.d.ts +0 -9
  275. package/dist/components/FormField/FormFieldExample.js +0 -99
  276. package/dist/components/FormField/FormFieldExample.js.map +0 -1
  277. package/dist/components/FormField/index.d.ts +0 -1
  278. package/dist/components/FormField/index.js +0 -2
  279. package/dist/components/FormField/index.js.map +0 -1
  280. package/dist/components/Input/InputElement.d.ts +0 -82
  281. package/dist/components/Input/InputElement.js +0 -64
  282. package/dist/components/Input/InputElement.js.map +0 -1
  283. package/src/components/Field/FieldDescription.tsx +0 -17
  284. package/src/components/Field/FieldError.tsx +0 -25
  285. package/src/components/Field/FieldLabel.tsx +0 -44
  286. package/src/components/FormField/FormField.rtl.test.tsx +0 -20
  287. package/src/components/FormField/FormField.tsx +0 -95
  288. package/src/components/FormField/FormFieldExample.tsx +0 -277
  289. package/src/components/FormField/index.tsx +0 -1
  290. package/src/components/Input/InputElement.tsx +0 -192
@@ -4,8 +4,7 @@ import { format, startOfToday } from 'date-fns';
4
4
  import { useMemo, useState } from 'react';
5
5
  import { Button } from '-/components/Button';
6
6
  import { Calendar, parseDate } from '-/components/Calendar';
7
- import { useFieldInit } from '-/components/Field';
8
- import { InputElement, InputProps } from '-/components/Input';
7
+ import { Input, InputProps } from '-/components/Input';
9
8
  import { useFloating } from '-/hooks/useFloating';
10
9
  import { useOutsideClick } from '-/hooks/useOutsideClick';
11
10
  import { FieldControlProps } from '-/types/common';
@@ -49,19 +48,15 @@ export type DatePickerProps = Omit<FieldControlProps, 'aria-label' | 'onChange'
49
48
  * For a more complete example with field usage, see the DatePickerField component.
50
49
  *
51
50
  * @example
52
- * import { DatePicker } from '@bspk/ui/DatePicker';
53
- * import { Field, FieldLabel } from '@bspk/ui/Field';
54
- * import { useState } from 'react';
51
+ * import { DatePicker } from '-/components/DatePicker';
55
52
  *
56
53
  * () => {
57
54
  * const [fieldDate, setFieldDate] = useState<string>();
58
55
  *
59
56
  * return (
60
57
  * <div style={{ width: 320 }}>
61
- * <Field>
62
- * <FieldLabel>Date</FieldLabel>
63
- * <DatePicker name="date1" onChange={setFieldDate} required value={fieldDate} />
64
- * <FieldDescription>The date picker allows you to select a date.</FieldDescription>
58
+ * <Field controlId="date1" helperText="The date picker allows you to select a date." label="Date">
59
+ * <DatePicker id="date1" name="date1" onChange={setFieldDate} required value={fieldDate} />
65
60
  * </Field>
66
61
  * </div>
67
62
  * );
@@ -78,20 +73,14 @@ export function DatePicker({
78
73
  closeCalendarOnChange = true,
79
74
  name,
80
75
  placeholder,
81
- invalid: invalidProp,
76
+ invalid,
82
77
  required = false,
83
78
  size,
84
- id: idProp,
79
+ id,
85
80
  'aria-label': ariaLabel = 'Enter or choose date',
81
+ 'aria-describedby': ariaDescribedBy,
82
+ 'aria-errormessage': ariaErrorMessage,
86
83
  }: DatePickerProps) {
87
- const { id, ariaDescribedBy, ariaErrorMessage, invalid } = useFieldInit({
88
- idProp,
89
- required,
90
- disabled,
91
- readOnly,
92
- invalidProp,
93
- });
94
-
95
84
  const [calendarVisible, setCalendarVisible] = useState(false);
96
85
 
97
86
  const { elements, floatingStyles } = useFloating({
@@ -118,7 +107,7 @@ export function DatePicker({
118
107
  elements.setReference(node);
119
108
  }}
120
109
  >
121
- <InputElement
110
+ <Input
122
111
  aria-describedby={ariaDescribedBy || undefined}
123
112
  aria-errormessage={ariaErrorMessage || undefined}
124
113
  aria-label={ariaLabel}
@@ -1,6 +1,6 @@
1
1
  import { useState } from 'react';
2
2
  import { DatePicker, DatePickerProps } from '.';
3
- import { Field, FieldLabel, FieldDescription } from '-/components/Field';
3
+ import { Field } from '-/components/Field';
4
4
  import { ComponentExample } from '-/utils/demo';
5
5
 
6
6
  export const DatePickerExample: ComponentExample<DatePickerProps> = {
@@ -19,10 +19,8 @@ export const Usage = () => {
19
19
 
20
20
  return (
21
21
  <div style={{ width: 320 }}>
22
- <Field>
23
- <FieldLabel>Date</FieldLabel>
24
- <DatePicker name="date1" onChange={setFieldDate} required value={fieldDate} />
25
- <FieldDescription>The date picker allows you to select a date.</FieldDescription>
22
+ <Field controlId="date1" helperText="The date picker allows you to select a date." label="Date">
23
+ <DatePicker id="date1" name="date1" onChange={setFieldDate} required value={fieldDate} />
26
24
  </Field>
27
25
  </div>
28
26
  );
@@ -3,7 +3,7 @@ import { hasNoBasicA11yIssues } from '-/rtl/hasNoBasicA11yIssues';
3
3
  import { render } from '-/rtl/util';
4
4
 
5
5
  const TestBed = () => (
6
- <DatePickerField label="Example field label" name="example-field-name" onChange={() => {}} value={undefined} />
6
+ <DatePickerField label="Example field label" name="example-field-name" onChange={() => {}} value="" />
7
7
  );
8
8
 
9
9
  describe('DatePickerField (RTL)', () => {
@@ -1,7 +1,8 @@
1
1
  import { DatePicker, DatePickerProps } from '-/components/DatePicker';
2
- import { FormField, FormFieldControlProps } from '-/components/FormField';
2
+ import { Field, FieldControlProps, propsWithAria } from '-/components/Field';
3
+ import { useId } from '-/hooks/useId';
3
4
 
4
- export type DatePickerFieldProps = FormFieldControlProps<DatePickerProps>;
5
+ export type DatePickerFieldProps = FieldControlProps<DatePickerProps>;
5
6
 
6
7
  /**
7
8
  * A field wrapper for the DatePicker component.
@@ -9,7 +10,7 @@ export type DatePickerFieldProps = FormFieldControlProps<DatePickerProps>;
9
10
  * This component takes properties from the FormField and DatePicker components.
10
11
  *
11
12
  * @name DatePickerField
12
- * @phase Stable
13
+ * @phase UXReview
13
14
  *
14
15
  * @generated
15
16
  */
@@ -19,18 +20,21 @@ export function DatePickerField({
19
20
  labelTrailing,
20
21
  errorMessage,
21
22
  style,
23
+ id: idProp,
22
24
  ...controlProps
23
25
  }: DatePickerFieldProps) {
26
+ const id = useId(idProp);
24
27
  return (
25
- <FormField
28
+ <Field
29
+ controlId={id}
26
30
  errorMessage={errorMessage}
27
31
  helperText={helperText}
28
32
  label={label}
29
33
  labelTrailing={labelTrailing}
30
34
  style={style}
31
35
  >
32
- <DatePicker {...controlProps} />
33
- </FormField>
36
+ <DatePicker {...propsWithAria({ id, controlProps, errorMessage, helperText })} />
37
+ </Field>
34
38
  );
35
39
  }
36
40
 
@@ -62,8 +62,7 @@ export type DialogProps = CommonProps<'id' | 'owner'> &
62
62
  * Also known as: Tray, Drawer, Flyout, Sheet
63
63
  *
64
64
  * @example
65
- * import { Dialog } from '@bspk/ui/Dialog';
66
- * import { Button } from '@bspk/ui/Button';
65
+ * import { Dialog } from '-/components/Dialog';
67
66
  *
68
67
  * () => {
69
68
  * const [open, setOpen] = useState(false);
@@ -74,7 +73,7 @@ export type DialogProps = CommonProps<'id' | 'owner'> &
74
73
  * <Dialog onClose={() => setOpen(false)} open={open}>
75
74
  * <div style={{ padding: 'var(--spacing-sizing-04)' }}>
76
75
  * <Flex align="center" justify="space-between">
77
- * <h4>Dialog Title</h4>
76
+ * <h1>Dialog Title</h1>
78
77
  * <Button
79
78
  * icon={<SvgClose />}
80
79
  * iconOnly
@@ -44,12 +44,15 @@ export type FabProps<As extends ElementType = ElementType> = Pick<
44
44
  * bottom right of a screen.
45
45
  *
46
46
  * @example
47
- * import { SvgBolt } from '@bspk/icons/Bolt';
48
- * import { Fab } from '@bspk/ui/Fab';
47
+ * import { Fab } from '-/components/Fab';
49
48
  *
50
- * <div style={{ width: '100%', height: 100 }}>
51
- * <Fab icon={<SvgBolt />} label="Example label" placement="bottom-right" variant="neutral" />
52
- * </div>;
49
+ * () => {
50
+ * return (
51
+ * <div style={{ width: '100%', height: 100 }}>
52
+ * <Fab icon={<SvgBolt />} label="Example label" placement="bottom-right" variant="neutral" />
53
+ * </div>
54
+ * );
55
+ * };
53
56
  *
54
57
  * @name Fab
55
58
  * @phase Stable
@@ -110,6 +110,7 @@
110
110
  [data-pseudo='focus'] > &,
111
111
  &:focus-visible {
112
112
  outline: solid 2px var(--stroke-neutral-focus);
113
+ isolation: isolate;
113
114
  }
114
115
 
115
116
  &[data-round] {
@@ -1,14 +1,16 @@
1
- import { Field, FieldDescription, FieldError, FieldLabel } from './';
1
+ import { Field } from './';
2
2
  import { Input } from '-/components/Input';
3
3
  import { hasNoBasicA11yIssues } from '-/rtl/hasNoBasicA11yIssues';
4
4
  import { render } from '-/rtl/util';
5
5
 
6
6
  const TestBed = () => (
7
- <Field>
8
- <FieldLabel>Example label</FieldLabel>
9
- <Input name="example-text" onChange={() => {}} value="Input text" />
10
- <FieldDescription>This is an example description.</FieldDescription>
11
- <FieldError>This is an error message.</FieldError>
7
+ <Field
8
+ controlId="example-field-id"
9
+ errorMessage="This is an error message."
10
+ helperText="This is an example description."
11
+ label="Example label"
12
+ >
13
+ <Input id="example-field-id" name="example-text" onChange={() => {}} value="Input text" />
12
14
  </Field>
13
15
  );
14
16
 
@@ -1,35 +1,46 @@
1
1
  import './field.scss';
2
- import { Children, ElementType, isValidElement, ReactNode, useMemo, useState } from 'react';
2
+ import { ReactNode } from 'react';
3
3
 
4
- import { describedById, errorMessageId, fieldContext, FieldContext, labelledById } from './utils';
5
- import { ElementProps } from '-/types/common';
6
- import { randomString } from '-/utils/random';
4
+ import { labelledById, errorMessageId, describedById } from './utils';
5
+ import { InlineAlert } from '-/components/InlineAlert';
6
+ import { CommonProps } from '-/types/common';
7
7
 
8
- export type FieldProps<As extends ElementType = ElementType> = {
8
+ export type FieldControlProps<P extends Record<string, unknown>> = Omit<FieldProps, 'children' | 'controlId'> &
9
+ Omit<P, keyof FieldProps>;
10
+
11
+ export type FieldProps = CommonProps<'style'> & {
12
+ /** Displays an error message and marks the field as invalid. */
13
+ errorMessage?: string;
14
+ /**
15
+ * The label of the field.
16
+ *
17
+ * @required
18
+ */
19
+ label: string;
20
+ /**
21
+ * This text provides additional context or instructions for the field.
22
+ *
23
+ * If an errorMessage is present, the helperText will not be displayed.
24
+ */
25
+ helperText?: string;
26
+ /** The trailing element of the label. */
27
+ labelTrailing?: string;
28
+ /** Marks the field as required. */
29
+ required?: boolean;
9
30
  /**
10
- * The children of the form field. This should be a control such as DatePicker, Input, InputNumber, InputPhone,
11
- * Password, Select, Textarea, or TimePicker.
31
+ * The children of the field. This should be a control such as DatePicker, Input, InputNumber, InputPhone, Password,
32
+ * Select, Textarea, or TimePicker.
12
33
  *
13
34
  * @required
14
35
  */
15
36
  children: ReactNode;
16
37
  /**
17
- * The element type to render the field as.
38
+ * The id attribute of the form control rendered in children (e.g., Input, Select, Textarea). Used to associate the
39
+ * label (htmlFor) with the control for accessibility. Must exactly match the control's id.
18
40
  *
19
- * @default div
20
- * @type ElementType
41
+ * @required
21
42
  */
22
- as?: As;
23
- /** The unique id for the field. */
24
- id?: string;
25
- };
26
-
27
- const isComponentName = (
28
- child: React.ReactElement<unknown, React.JSXElementConstructor<unknown> | string> | React.ReactPortal,
29
- name: string,
30
- ) => {
31
- const componentType = child.type as { name?: string; displayName?: string };
32
- return componentType.displayName === name || componentType.name === name;
43
+ controlId: string;
33
44
  };
34
45
 
35
46
  /**
@@ -40,25 +51,22 @@ const isComponentName = (
40
51
  *
41
52
  * @example
42
53
  * import { Input } from '@bspk/ui/Input';
43
- * import { Field, FieldLabel, FieldDescription, FieldError } from '@bspk/ui/Field';
54
+ * import { Field } from '@bspk/ui/Field';
44
55
  *
45
56
  * () => {
46
57
  * const [state, setState] = useState<string | undefined>(undefined);
47
- * const [error, setError] = useState<string | undefined>(undefined);
48
58
  *
49
59
  * return (
50
- * <Field label="Example label">
51
- * <FieldLabel>Example label</FieldLabel>
60
+ * <Field controlId="example-control-id" helperText="This is an example description." label="Example label">
52
61
  * <Input
53
62
  * aria-label="example aria-label"
63
+ * id="example-control-id"
54
64
  * name="example-text"
55
65
  * onChange={(next) => {
56
66
  * setState(next);
57
67
  * }}
58
68
  * value={state}
59
69
  * />
60
- * <FieldDescription>This is an example description.</FieldDescription>
61
- * {error && <FieldError>{error}</FieldError>}
62
70
  * </Field>
63
71
  * );
64
72
  * };
@@ -66,43 +74,38 @@ const isComponentName = (
66
74
  * @name Field
67
75
  * @phase Utility
68
76
  */
69
- export function Field<As extends ElementType = ElementType>({
77
+ export function Field({
70
78
  children,
71
- as,
72
- id: idProp,
79
+ label,
80
+ helperText,
81
+ labelTrailing,
82
+ errorMessage,
83
+ required,
84
+ controlId: id,
73
85
  ...props
74
- }: ElementProps<FieldProps<As>, As>) {
75
- const id = useMemo(() => idProp || `field-${randomString(8)}`, [idProp]);
76
-
77
- const childContext = useMemo(() => {
78
- const next: Pick<FieldContext, 'ariaDescribedBy' | 'ariaErrorMessage' | 'ariaLabelledBy'> = {};
79
- Children.forEach(children, (child) => {
80
- if (!isValidElement(child) || typeof child.type === 'string' || !child.props.children) return;
81
-
82
- if (isComponentName(child, 'FieldError')) next.ariaErrorMessage = errorMessageId(id);
83
- else if (isComponentName(child, 'FieldLabel')) next.ariaLabelledBy = labelledById(id);
84
- else if (isComponentName(child, 'FieldDescription')) next.ariaDescribedBy = describedById(id);
85
- });
86
- return next;
87
- }, [children, id]);
88
-
89
- const [contextState, setContext] = useState<Pick<FieldContext, 'htmlFor' | 'required'>>({});
90
-
91
- const As = as || 'div';
92
-
86
+ }: FieldProps) {
93
87
  return (
94
- <fieldContext.Provider
95
- value={{
96
- ...childContext,
97
- ...contextState,
98
- id,
99
- setContext,
100
- }}
101
- >
102
- <As {...props} data-bspk-utility="field" id={id} role="group">
103
- {children}
104
- </As>
105
- </fieldContext.Provider>
88
+ <div {...props} data-bspk-utility="field" role="group">
89
+ <label data-field-label htmlFor={id} id={labelledById(id)}>
90
+ <span>{label}</span>
91
+ {required && <span data-required>{' (Required)'}</span>}
92
+ {labelTrailing && (
93
+ <span aria-hidden data-trailing>
94
+ {labelTrailing}
95
+ </span>
96
+ )}
97
+ </label>
98
+ {children}
99
+ {errorMessage ? (
100
+ <InlineAlert id={errorMessageId(id)} label={errorMessage} owner="field-error" variant="error" />
101
+ ) : (
102
+ helperText && (
103
+ <p data-field-description id={describedById(id)}>
104
+ {helperText}
105
+ </p>
106
+ )
107
+ )}
108
+ </div>
106
109
  );
107
110
  }
108
111
 
@@ -1,4 +1,5 @@
1
- import { Field, FieldDescription, FieldError, FieldLabel, FieldProps } from './';
1
+ import { useState } from 'react';
2
+ import { Field, FieldProps } from './';
2
3
  import { Input } from '-/components/Input';
3
4
  import { ComponentExample } from '-/utils/demo';
4
5
  import { randomString } from '-/utils/random';
@@ -6,16 +7,37 @@ import { randomString } from '-/utils/random';
6
7
  export const FieldExample: ComponentExample<FieldProps & { value?: string }> = {
7
8
  render: ({ props, setState }) => {
8
9
  return (
9
- <Field {...props}>
10
- <FieldLabel>Example label</FieldLabel>
10
+ <Field
11
+ {...props}
12
+ errorMessage="This is an error message."
13
+ helperText="This is an example description."
14
+ label="Example label"
15
+ >
11
16
  <Input
17
+ id={props.controlId}
12
18
  name={`example-${randomString(6)}`}
13
19
  onChange={(next: string) => setState({ value: next })}
14
20
  value={props.value}
15
21
  />
16
- <FieldDescription>This is an example description.</FieldDescription>
17
- <FieldError>This is an error message.</FieldError>
18
22
  </Field>
19
23
  );
20
24
  },
21
25
  };
26
+
27
+ export const Usage = () => {
28
+ const [state, setState] = useState<string | undefined>(undefined);
29
+
30
+ return (
31
+ <Field controlId="example-control-id" helperText="This is an example description." label="Example label">
32
+ <Input
33
+ aria-label="example aria-label"
34
+ id="example-control-id"
35
+ name="example-text"
36
+ onChange={(next) => {
37
+ setState(next);
38
+ }}
39
+ value={state}
40
+ />
41
+ </Field>
42
+ );
43
+ };
@@ -0,0 +1,78 @@
1
+ import './field.scss';
2
+
3
+ import { FieldProps } from './Field';
4
+ import { labelledById, errorMessageId, describedById } from './utils';
5
+ import { InlineAlert } from '-/components/InlineAlert';
6
+
7
+ /**
8
+ * Wrapper component for form controls.
9
+ *
10
+ * Children should be one of the following: DatePicker, Input, InputNumber, InputPhone, Password, Select, Textarea, or
11
+ * TimePicker.
12
+ *
13
+ * @example
14
+ * import { Input } from '@bspk/ui/Input';
15
+ * import { Fieldset } from '@bspk/ui/Field';
16
+ *
17
+ * () => {
18
+ * const [state, setState] = useState<string | undefined>(undefined);
19
+ * const [error, setError] = useState<string | undefined>(undefined);
20
+ *
21
+ * return (
22
+ * <Fieldset
23
+ * label="Example label"
24
+ * helperText="This is an example description."
25
+ * errorMessage={error}
26
+ * required
27
+ * >
28
+ * <Input
29
+ * aria-label="example aria-label"
30
+ * name="example-text"
31
+ * onChange={(next) => {
32
+ * setState(next);
33
+ * }}
34
+ * value={state}
35
+ * />
36
+ * </Fieldset>
37
+ * );
38
+ * };
39
+ *
40
+ * @name Fieldset
41
+ * @phase Utility
42
+ */
43
+ export function Fieldset({
44
+ children,
45
+ label,
46
+ helperText,
47
+ labelTrailing,
48
+ errorMessage,
49
+ required,
50
+ controlId: id,
51
+ ...props
52
+ }: FieldProps) {
53
+ return (
54
+ <fieldset {...props} data-bspk-utility="field" role="group">
55
+ <legend data-field-label id={labelledById(id)}>
56
+ <span>{label}</span>
57
+ {required && <span data-required>{' (Required)'}</span>}
58
+ {labelTrailing && (
59
+ <span aria-hidden data-trailing>
60
+ {labelTrailing}
61
+ </span>
62
+ )}
63
+ </legend>
64
+ {children}
65
+ {errorMessage ? (
66
+ <InlineAlert id={errorMessageId(id)} label={errorMessage} owner="field-error" variant="error" />
67
+ ) : (
68
+ helperText && (
69
+ <p data-field-description id={describedById(id)}>
70
+ {helperText}
71
+ </p>
72
+ )
73
+ )}
74
+ </fieldset>
75
+ );
76
+ }
77
+
78
+ /** Copyright 2025 Anywhere Real Estate - CC BY 4.0 */
@@ -6,40 +6,36 @@
6
6
  border: none;
7
7
  max-width: 100%;
8
8
  min-inline-size: unset;
9
- }
10
9
 
11
- [data-bspk='field-label'] {
12
- display: flex;
13
- flex-direction: row;
14
- align-items: center;
15
- gap: var(--spacing-sizing-01);
10
+ [data-field-label] {
11
+ display: flex;
12
+ flex-direction: row;
13
+ align-items: center;
14
+ gap: var(--spacing-sizing-01);
16
15
 
17
- span {
18
- font: var(--labels-small);
19
- color: var(--foreground-neutral-on-surface);
16
+ span {
17
+ font: var(--labels-small);
18
+ color: var(--foreground-neutral-on-surface);
20
19
 
21
- &[data-required] {
22
- font: var(--body-small);
23
- color: var(--foreground-neutral-on-surface-variant-01);
24
- }
20
+ &[data-required] {
21
+ font: var(--body-small);
22
+ color: var(--foreground-neutral-on-surface-variant-01);
23
+ }
25
24
 
26
- &[data-trailing] {
27
- font: var(--body-small);
28
- color: var(--foreground-neutral-on-surface-variant-02);
29
- margin-left: auto;
25
+ &[data-trailing] {
26
+ font: var(--body-small);
27
+ color: var(--foreground-neutral-on-surface-variant-02);
28
+ margin-left: auto;
29
+ }
30
30
  }
31
31
  }
32
- }
33
-
34
- [data-bspk='field-description'] {
35
- font: var(--body-small);
36
- color: var(--foreground-neutral-on-surface-variant-01);
37
- margin: 0;
38
- padding: 0;
39
- }
40
32
 
41
- [data-bspk-owner='field-error'] {
42
- // Styles for FieldError component when used inside Field
33
+ [data-field-description] {
34
+ font: var(--body-small);
35
+ color: var(--foreground-neutral-on-surface-variant-01);
36
+ margin: 0;
37
+ padding: 0;
38
+ }
43
39
  }
44
40
 
45
41
  /** Copyright 2025 Anywhere Real Estate - CC BY 4.0 */
@@ -1,5 +1,3 @@
1
1
  export * from './Field';
2
- export * from './FieldLabel';
3
- export * from './FieldDescription';
4
- export * from './FieldError';
5
2
  export * from './utils';
3
+ export * from './Fieldset';