@bspk/ui 1.3.21 → 1.3.23

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 (307) 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 +5 -0
  20. package/dist/components/CheckboxGroup/checkbox-group.css.js +5 -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 +39 -20
  46. package/dist/components/Field/Field.js +10 -40
  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 +9 -7
  55. package/dist/components/Field/field.css.js +9 -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 +10 -6
  67. package/dist/components/Flex/Flex.js +10 -6
  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 +59 -15
  73. package/dist/components/Input/Input.js +40 -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/Link/Link.d.ts +0 -1
  104. package/dist/components/Link/Link.js +0 -1
  105. package/dist/components/Link/Link.js.map +1 -1
  106. package/dist/components/ListItem/list-item.css +1 -0
  107. package/dist/components/ListItem/list-item.css.js +1 -0
  108. package/dist/components/Modal/Modal.js +22 -26
  109. package/dist/components/Modal/Modal.js.map +1 -1
  110. package/dist/components/Modal/ModalExample.js +4 -1
  111. package/dist/components/Modal/ModalExample.js.map +1 -1
  112. package/dist/components/Modal/modal.css +4 -2
  113. package/dist/components/Modal/modal.css.js +4 -2
  114. package/dist/components/OTPInput/otp-input.css +1 -0
  115. package/dist/components/OTPInput/otp-input.css.js +1 -0
  116. package/dist/components/Pagination/Pagination.js +2 -2
  117. package/dist/components/Pagination/Pagination.js.map +1 -1
  118. package/dist/components/Password/Password.d.ts +9 -7
  119. package/dist/components/Password/Password.js +13 -17
  120. package/dist/components/Password/Password.js.map +1 -1
  121. package/dist/components/Password/PasswordExample.js +3 -3
  122. package/dist/components/Password/PasswordExample.js.map +1 -1
  123. package/dist/components/PasswordField/PasswordField.d.ts +4 -4
  124. package/dist/components/PasswordField/PasswordField.js +6 -4
  125. package/dist/components/PasswordField/PasswordField.js.map +1 -1
  126. package/dist/components/Popover/Popover.d.ts +0 -1
  127. package/dist/components/Popover/Popover.js +0 -1
  128. package/dist/components/Popover/Popover.js.map +1 -1
  129. package/dist/components/RadioGroup/RadioGroup.d.ts +1 -2
  130. package/dist/components/RadioGroup/RadioGroup.js +5 -11
  131. package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
  132. package/dist/components/RadioGroup/radio-group.css +3 -0
  133. package/dist/components/RadioGroup/radio-group.css.js +3 -0
  134. package/dist/components/RadioGroupField/RadioGroupField.d.ts +3 -3
  135. package/dist/components/RadioGroupField/RadioGroupField.js +6 -4
  136. package/dist/components/RadioGroupField/RadioGroupField.js.map +1 -1
  137. package/dist/components/SearchBar/SearchBar.d.ts +0 -1
  138. package/dist/components/SearchBar/SearchBar.js +0 -1
  139. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  140. package/dist/components/SegmentedControl/SegmentedControl.d.ts +0 -1
  141. package/dist/components/SegmentedControl/SegmentedControl.js +0 -1
  142. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  143. package/dist/components/Select/Select.d.ts +7 -6
  144. package/dist/components/Select/Select.js +10 -15
  145. package/dist/components/Select/Select.js.map +1 -1
  146. package/dist/components/Select/SelectExample.js +3 -3
  147. package/dist/components/Select/SelectExample.js.map +1 -1
  148. package/dist/components/Select/select.css +0 -10
  149. package/dist/components/Select/select.css.js +0 -10
  150. package/dist/components/SelectField/SelectField.d.ts +4 -4
  151. package/dist/components/SelectField/SelectField.js +6 -4
  152. package/dist/components/SelectField/SelectField.js.map +1 -1
  153. package/dist/components/Slider/Slider.d.ts +1 -2
  154. package/dist/components/Slider/Slider.js +1 -2
  155. package/dist/components/Slider/Slider.js.map +1 -1
  156. package/dist/components/Snackbar/Snackbar.d.ts +0 -1
  157. package/dist/components/Snackbar/Snackbar.js +0 -1
  158. package/dist/components/Snackbar/Snackbar.js.map +1 -1
  159. package/dist/components/Switch/Switch.d.ts +0 -1
  160. package/dist/components/Switch/Switch.js +0 -1
  161. package/dist/components/Switch/Switch.js.map +1 -1
  162. package/dist/components/TabGroup/TabGroup.d.ts +0 -1
  163. package/dist/components/TabGroup/TabGroup.js +0 -1
  164. package/dist/components/TabGroup/TabGroup.js.map +1 -1
  165. package/dist/components/TabList/TabList.d.ts +0 -1
  166. package/dist/components/TabList/TabList.js +0 -1
  167. package/dist/components/TabList/TabList.js.map +1 -1
  168. package/dist/components/TabList/tab-list.css +1 -0
  169. package/dist/components/TabList/tab-list.css.js +1 -0
  170. package/dist/components/Table/table.css +2 -1
  171. package/dist/components/Table/table.css.js +2 -1
  172. package/dist/components/Textarea/Textarea.d.ts +4 -7
  173. package/dist/components/Textarea/Textarea.js +5 -16
  174. package/dist/components/Textarea/Textarea.js.map +1 -1
  175. package/dist/components/Textarea/TextareaExample.js +3 -3
  176. package/dist/components/Textarea/TextareaExample.js.map +1 -1
  177. package/dist/components/TextareaField/TextareaField.d.ts +4 -4
  178. package/dist/components/TextareaField/TextareaField.js +6 -4
  179. package/dist/components/TextareaField/TextareaField.js.map +1 -1
  180. package/dist/components/TimePicker/TimePicker.d.ts +8 -6
  181. package/dist/components/TimePicker/TimePicker.js +10 -14
  182. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  183. package/dist/components/TimePicker/TimePickerExample.js +3 -3
  184. package/dist/components/TimePicker/TimePickerExample.js.map +1 -1
  185. package/dist/components/TimePickerField/TimePickerField.d.ts +4 -4
  186. package/dist/components/TimePickerField/TimePickerField.js +6 -4
  187. package/dist/components/TimePickerField/TimePickerField.js.map +1 -1
  188. package/dist/hooks/useFloating.d.ts +0 -6
  189. package/dist/hooks/useFloating.js +0 -6
  190. package/dist/hooks/useFloating.js.map +1 -1
  191. package/dist/styles/base.css +71 -81
  192. package/dist/styles/base.css.js +71 -81
  193. package/dist/types/common.d.ts +3 -0
  194. package/dist/types/common.js.map +1 -1
  195. package/package.json +3 -4
  196. package/src/components/Accordion/Accordion.tsx +2 -2
  197. package/src/components/Accordion/accordion.scss +10 -1
  198. package/src/components/BottomNavigation/BottomNavigation.tsx +0 -1
  199. package/src/components/BottomNavigation/bottom-navigation.scss +1 -0
  200. package/src/components/Button/button.scss +4 -0
  201. package/src/components/Checkbox/Checkbox.tsx +3 -3
  202. package/src/components/CheckboxGroup/CheckboxGroup.tsx +37 -52
  203. package/src/components/CheckboxGroup/CheckboxGroupExample.tsx +6 -0
  204. package/src/components/CheckboxGroup/checkbox-group.scss +6 -0
  205. package/src/components/CheckboxGroupField/CheckboxGroupField.tsx +16 -11
  206. package/src/components/ChipGroup/ChipGroup.tsx +0 -1
  207. package/src/components/ChipGroup/chip-group.scss +4 -0
  208. package/src/components/DatePicker/DatePicker.tsx +9 -20
  209. package/src/components/DatePicker/DatePickerExample.tsx +3 -5
  210. package/src/components/DatePickerField/DatePickerField.rtl.test.tsx +1 -1
  211. package/src/components/DatePickerField/DatePickerField.tsx +11 -6
  212. package/src/components/Dialog/Dialog.tsx +2 -3
  213. package/src/components/Fab/Fab.tsx +8 -5
  214. package/src/components/Fab/fab.scss +1 -0
  215. package/src/components/Field/Field.rtl.test.tsx +8 -6
  216. package/src/components/Field/Field.tsx +71 -63
  217. package/src/components/Field/FieldExample.tsx +27 -5
  218. package/src/components/Field/Fieldset.tsx +82 -0
  219. package/src/components/Field/field.scss +27 -26
  220. package/src/components/Field/index.tsx +1 -3
  221. package/src/components/Field/utils.ts +15 -77
  222. package/src/components/FileUpload/FileUpload.tsx +1 -1
  223. package/src/components/FileUploadItem/FileUploadItem.tsx +1 -1
  224. package/src/components/Flex/Flex.tsx +10 -6
  225. package/src/components/InlineAlert/InlineAlert.rtl.test.tsx +1 -1
  226. package/src/components/InlineAlert/InlineAlert.tsx +3 -3
  227. package/src/components/Input/Input.tsx +135 -48
  228. package/src/components/Input/InputExample.tsx +4 -6
  229. package/src/components/Input/index.tsx +0 -1
  230. package/src/components/InputField/InputField.tsx +11 -6
  231. package/src/components/InputNumber/InputNumber.tsx +11 -16
  232. package/src/components/InputNumber/InputNumberExample.tsx +7 -4
  233. package/src/components/InputNumber/input-number.scss +1 -0
  234. package/src/components/InputNumberField/InputNumberField.tsx +11 -6
  235. package/src/components/InputPhone/InputPhone.tsx +14 -18
  236. package/src/components/InputPhone/InputPhoneExample.tsx +7 -6
  237. package/src/components/InputPhone/input-phone.scss +1 -0
  238. package/src/components/InputPhoneField/InputPhoneField.tsx +11 -6
  239. package/src/components/Link/Link.tsx +0 -1
  240. package/src/components/ListItem/list-item.scss +1 -0
  241. package/src/components/Modal/Modal.tsx +26 -30
  242. package/src/components/Modal/ModalExample.tsx +7 -2
  243. package/src/components/Modal/modal.scss +1 -1
  244. package/src/components/OTPInput/otp-input.scss +1 -0
  245. package/src/components/Pagination/Pagination.tsx +2 -2
  246. package/src/components/Password/Password.tsx +15 -17
  247. package/src/components/Password/PasswordExample.tsx +13 -5
  248. package/src/components/PasswordField/PasswordField.tsx +11 -6
  249. package/src/components/Popover/Popover.tsx +0 -1
  250. package/src/components/RadioGroup/RadioGroup.tsx +14 -20
  251. package/src/components/RadioGroup/radio-group.scss +4 -0
  252. package/src/components/RadioGroupField/RadioGroupField.tsx +16 -11
  253. package/src/components/SearchBar/SearchBar.tsx +0 -1
  254. package/src/components/SegmentedControl/SegmentedControl.tsx +0 -1
  255. package/src/components/Select/Select.tsx +13 -14
  256. package/src/components/Select/SelectExample.tsx +7 -4
  257. package/src/components/Select/select.scss +0 -12
  258. package/src/components/SelectField/SelectField.rtl.test.tsx +7 -18
  259. package/src/components/SelectField/SelectField.tsx +11 -6
  260. package/src/components/Slider/Slider.tsx +1 -2
  261. package/src/components/Snackbar/Snackbar.tsx +0 -1
  262. package/src/components/Switch/Switch.tsx +0 -1
  263. package/src/components/TabGroup/TabGroup.tsx +0 -1
  264. package/src/components/TabList/TabList.tsx +0 -1
  265. package/src/components/TabList/tab-list.scss +1 -0
  266. package/src/components/Table/table.scss +2 -1
  267. package/src/components/Textarea/Textarea.tsx +8 -17
  268. package/src/components/Textarea/TextareaExample.tsx +3 -5
  269. package/src/components/TextareaField/TextareaField.tsx +11 -6
  270. package/src/components/TimePicker/TimePicker.tsx +12 -15
  271. package/src/components/TimePicker/TimePickerExample.tsx +3 -5
  272. package/src/components/TimePickerField/TimePickerField.tsx +11 -6
  273. package/src/hooks/useFloating.ts +0 -6
  274. package/src/styles/base.scss +109 -87
  275. package/src/types/common.ts +9 -0
  276. package/dist/components/Field/FieldDescription.d.ts +0 -9
  277. package/dist/components/Field/FieldDescription.js +0 -13
  278. package/dist/components/Field/FieldDescription.js.map +0 -1
  279. package/dist/components/Field/FieldError.d.ts +0 -11
  280. package/dist/components/Field/FieldError.js +0 -14
  281. package/dist/components/Field/FieldError.js.map +0 -1
  282. package/dist/components/Field/FieldLabel.d.ts +0 -21
  283. package/dist/components/Field/FieldLabel.js +0 -14
  284. package/dist/components/Field/FieldLabel.js.map +0 -1
  285. package/dist/components/FormField/FormField.d.ts +0 -66
  286. package/dist/components/FormField/FormField.js +0 -31
  287. package/dist/components/FormField/FormField.js.map +0 -1
  288. package/dist/components/FormField/FormFieldExample.d.ts +0 -9
  289. package/dist/components/FormField/FormFieldExample.js +0 -99
  290. package/dist/components/FormField/FormFieldExample.js.map +0 -1
  291. package/dist/components/FormField/index.d.ts +0 -1
  292. package/dist/components/FormField/index.js +0 -2
  293. package/dist/components/FormField/index.js.map +0 -1
  294. package/dist/components/Input/InputElement.d.ts +0 -82
  295. package/dist/components/Input/InputElement.js +0 -64
  296. package/dist/components/Input/InputElement.js.map +0 -1
  297. package/dist/components/Link/link.css +0 -18
  298. package/dist/components/Link/link.css.js +0 -23
  299. package/src/components/Field/FieldDescription.tsx +0 -17
  300. package/src/components/Field/FieldError.tsx +0 -25
  301. package/src/components/Field/FieldLabel.tsx +0 -44
  302. package/src/components/FormField/FormField.rtl.test.tsx +0 -20
  303. package/src/components/FormField/FormField.tsx +0 -95
  304. package/src/components/FormField/FormFieldExample.tsx +0 -277
  305. package/src/components/FormField/index.tsx +0 -1
  306. package/src/components/Input/InputElement.tsx +0 -192
  307. package/src/components/Link/link.scss +0 -21
@@ -1,7 +1,8 @@
1
1
  import { DatePicker, DatePickerProps } from '-/components/DatePicker';
2
- import { FormField, FormFieldControlProps } from '-/components/FormField';
2
+ import { Field, ComposedFieldProps, propsWithAria } from '-/components/Field';
3
+ import { useId } from '-/hooks/useId';
3
4
 
4
- export type DatePickerFieldProps = FormFieldControlProps<DatePickerProps>;
5
+ export type DatePickerFieldProps = ComposedFieldProps<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,22 @@ 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}
34
+ required={controlProps.required}
30
35
  style={style}
31
36
  >
32
- <DatePicker {...controlProps} />
33
- </FormField>
37
+ <DatePicker {...propsWithAria({ id, controlProps, errorMessage, helperText })} />
38
+ </Field>
34
39
  );
35
40
  }
36
41
 
@@ -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,64 +1,77 @@
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
+ /**
9
+ * Props for Composed Field components.
10
+ *
11
+ * These are props that combine FieldProps with the props of a specific control component.
12
+ */
13
+ export type ComposedFieldProps<P extends Record<string, unknown>> = Omit<FieldProps, 'children' | 'controlId'> &
14
+ Omit<P, keyof FieldProps>;
15
+
16
+ export type FieldProps = CommonProps<'style'> & {
17
+ /** Displays an error message and marks the field as invalid. */
18
+ errorMessage?: string;
9
19
  /**
10
- * The children of the form field. This should be a control such as DatePicker, Input, InputNumber, InputPhone,
11
- * Password, Select, Textarea, or TimePicker.
20
+ * The label of the field.
21
+ *
22
+ * @required
23
+ */
24
+ label: string;
25
+ /**
26
+ * This text provides additional context or instructions for the field.
27
+ *
28
+ * If an errorMessage is present, the helperText will not be displayed.
29
+ */
30
+ helperText?: string;
31
+ /** The trailing element of the label. */
32
+ labelTrailing?: string;
33
+ /** Marks the field as required. */
34
+ required?: boolean;
35
+ /**
36
+ * The children of the field. This should be a control such as DatePicker, Input, InputNumber, InputPhone, Password,
37
+ * Select, Textarea, or TimePicker.
12
38
  *
13
39
  * @required
14
40
  */
15
41
  children: ReactNode;
16
42
  /**
17
- * The element type to render the field as.
43
+ * The id attribute of the form control rendered in children (e.g., Input, Select, Textarea). Used to associate the
44
+ * label (htmlFor) with the control for accessibility. Must exactly match the control's id.
18
45
  *
19
- * @default div
20
- * @type ElementType
46
+ * @required
21
47
  */
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;
48
+ controlId: string;
33
49
  };
34
50
 
35
51
  /**
36
52
  * Wrapper component for form controls.
37
53
  *
38
- * Children should be one of the following: DatePicker, Input, InputNumber, InputPhone, Password, Select, Textarea, or
39
- * TimePicker.
54
+ * Children should be one of the following: DatePicker, Input, InputNumber, InputPhone, Password, Select, Textarea,
55
+ * RadioGroup, CheckboxGroup, or TimePicker.
40
56
  *
41
57
  * @example
42
58
  * import { Input } from '@bspk/ui/Input';
43
- * import { Field, FieldLabel, FieldDescription, FieldError } from '@bspk/ui/Field';
59
+ * import { Field } from '@bspk/ui/Field';
44
60
  *
45
61
  * () => {
46
62
  * const [state, setState] = useState<string | undefined>(undefined);
47
- * const [error, setError] = useState<string | undefined>(undefined);
48
63
  *
49
64
  * return (
50
- * <Field label="Example label">
51
- * <FieldLabel>Example label</FieldLabel>
65
+ * <Field controlId="example-control-id" helperText="This is an example description." label="Example label">
52
66
  * <Input
53
67
  * aria-label="example aria-label"
68
+ * id="example-control-id"
54
69
  * name="example-text"
55
70
  * onChange={(next) => {
56
71
  * setState(next);
57
72
  * }}
58
73
  * value={state}
59
74
  * />
60
- * <FieldDescription>This is an example description.</FieldDescription>
61
- * {error && <FieldError>{error}</FieldError>}
62
75
  * </Field>
63
76
  * );
64
77
  * };
@@ -66,43 +79,38 @@ const isComponentName = (
66
79
  * @name Field
67
80
  * @phase Utility
68
81
  */
69
- export function Field<As extends ElementType = ElementType>({
82
+ export function Field({
70
83
  children,
71
- as,
72
- id: idProp,
84
+ label,
85
+ helperText,
86
+ labelTrailing,
87
+ errorMessage,
88
+ required,
89
+ controlId: id,
73
90
  ...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
-
91
+ }: FieldProps) {
93
92
  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>
93
+ <div {...props} data-bspk-utility="field" role="group">
94
+ <label data-field-label htmlFor={id} id={labelledById(id)}>
95
+ <span>{label}</span>
96
+ {required && <span data-required>{' (Required)'}</span>}
97
+ {labelTrailing && (
98
+ <span aria-hidden data-trailing>
99
+ {labelTrailing}
100
+ </span>
101
+ )}
102
+ </label>
103
+ {children}
104
+ {errorMessage ? (
105
+ <InlineAlert id={errorMessageId(id)} label={errorMessage} owner="field-error" variant="error" />
106
+ ) : (
107
+ helperText && (
108
+ <p data-field-description id={describedById(id)}>
109
+ {helperText}
110
+ </p>
111
+ )
112
+ )}
113
+ </div>
106
114
  );
107
115
  }
108
116
 
@@ -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,82 @@
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,
11
+ * RadioGroup, CheckboxGroup, or 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
+ <div {...props} data-bspk-utility="field">
55
+ <fieldset role="group">
56
+ <legend>
57
+ <span data-field-label id={labelledById(id)}>
58
+ <span>{label}</span>
59
+ {required && <span data-required>{' (Required)'}</span>}
60
+ {labelTrailing && (
61
+ <span aria-hidden data-trailing>
62
+ {labelTrailing}
63
+ </span>
64
+ )}
65
+ </span>
66
+ </legend>
67
+ {children}
68
+ {errorMessage ? (
69
+ <InlineAlert id={errorMessageId(id)} label={errorMessage} owner="field-error" variant="error" />
70
+ ) : (
71
+ helperText && (
72
+ <p data-field-description id={describedById(id)}>
73
+ {helperText}
74
+ </p>
75
+ )
76
+ )}
77
+ </fieldset>
78
+ </div>
79
+ );
80
+ }
81
+
82
+ /** Copyright 2025 Anywhere Real Estate - CC BY 4.0 */
@@ -6,40 +6,41 @@
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
32
 
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
- }
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
+ }
40
39
 
41
- [data-bspk-owner='field-error'] {
42
- // Styles for FieldError component when used inside Field
40
+ fieldset,
41
+ legend {
42
+ display: contents;
43
+ }
43
44
  }
44
45
 
45
46
  /** 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';
@@ -1,84 +1,22 @@
1
- import { createContext, useContext, useEffect, useMemo } from 'react';
2
- import { useId } from '-/hooks/useId';
3
- import { CommonProps } from '-/types/common';
4
-
5
1
  export const errorMessageId = (id: string) => `${id}-field-error`;
6
2
  export const labelledById = (id: string) => `${id}-label`;
7
3
  export const describedById = (id: string) => `${id}-description`;
8
-
9
- /** The props that are provided via context to all Field subcomponents. */
10
- export type FieldContextProps = CommonProps<'required'> & {
11
- /** The aria-describedby attribute value that should be applied to the field input element. */
12
- ariaDescribedBy?: string;
13
- /** The aria-errormessage attribute value that should be applied to the field input element. */
14
- ariaErrorMessage?: string;
15
- /** Text that appears after the label, but before the input (e.g. "optional"). */
16
- labelTrailing?: string;
17
- /** The aria-labelledby attribute value that should be applied to the field input element. */
18
- ariaLabelledBy?: string;
19
- /** The htmlFor attribute value that should be applied to the field label element. */
20
- htmlFor?: string;
21
- /** The id of the field. */
22
- id: string;
23
- };
24
-
25
- export type FieldContext = FieldContextProps & {
26
- setContext: (next: Pick<FieldContextProps, 'htmlFor' | 'required'>) => void;
27
- };
28
-
29
- export const fieldContext = createContext<FieldContext | null>(null);
30
-
31
- /**
32
- * Retrieves the current Field context.
33
- *
34
- * Will return a default context if used outside of a Field component.
35
- */
36
- export function useFieldContext(): FieldContext {
37
- return (
38
- useContext(fieldContext) || {
39
- id: undefined as unknown as string,
40
- setContext: () => {},
41
- }
42
- );
43
- }
44
-
45
- /**
46
- * Initializes field-related attributes and state for a form control component.
47
- *
48
- * Creates id if not provided, manages invalid state, and syncs with Field context.
49
- */
50
- export function useFieldInit({
51
- idProp,
52
- required,
53
- disabled,
54
- readOnly,
55
- invalidProp,
4
+ export function propsWithAria<T extends Record<string, unknown>>({
5
+ errorMessage,
6
+ helperText,
7
+ controlProps,
8
+ id,
56
9
  }: {
57
- idProp: string | undefined;
58
- required: boolean | undefined;
59
- disabled: boolean | undefined;
60
- readOnly?: boolean | undefined;
61
- invalidProp: boolean | undefined;
62
- }): Pick<FieldContext, 'ariaDescribedBy' | 'ariaErrorMessage'> & { invalid: boolean; id: string } {
63
- const context = useContext(fieldContext);
64
- const controlId = useId(idProp || context?.htmlFor);
65
-
66
- const invalid = useMemo(
67
- () => !disabled && !readOnly && (invalidProp || !!context?.ariaErrorMessage),
68
- [disabled, readOnly, invalidProp, context?.ariaErrorMessage],
69
- );
70
-
71
- useEffect(() => {
72
- if (!context) return;
73
-
74
- if (controlId !== context?.htmlFor || !!required !== !!context?.required) {
75
- context.setContext({ htmlFor: controlId, required: required });
76
- }
77
- }, [context, controlId, required]);
78
-
10
+ errorMessage?: string;
11
+ helperText?: string;
12
+ controlProps: T;
13
+ id: string;
14
+ }) {
79
15
  return {
80
- ...(context || {}),
81
- invalid,
82
- id: controlId,
16
+ ...controlProps,
17
+ id,
18
+ 'aria-errormessage': errorMessage ? errorMessageId(id) : undefined,
19
+ 'aria-describedby': helperText ? describedById(id) : undefined,
20
+ 'aria-invalid': errorMessage ? true : undefined,
83
21
  };
84
22
  }
@@ -205,7 +205,7 @@ export function FileUpload({
205
205
  />
206
206
  <Button label="Browse" onClick={handleBrowseClick} />
207
207
  {files.length === 1 && files[0].status === 'error' && (
208
- <InlineAlert variant="error">{files[0].errorMessage || DEFAULT_ERROR_MESSAGE}</InlineAlert>
208
+ <InlineAlert label={files[0].errorMessage || DEFAULT_ERROR_MESSAGE} variant="error" />
209
209
  )}
210
210
  </div>
211
211
  <div data-bspk-owner="file-upload" data-file-entries>
@@ -72,7 +72,7 @@ export function FileUploadItem({
72
72
  </div>
73
73
  <div data-status>
74
74
  {status === 'error' ? (
75
- <InlineAlert variant="error">{errorMessage}</InlineAlert>
75
+ <InlineAlert label={errorMessage} variant="error" />
76
76
  ) : (
77
77
  <ProgressBar
78
78
  align="left"
@@ -44,13 +44,17 @@ export type FlexProps<As extends ElementType = ElementType> = {
44
44
  * Utility component used within other components for layout purposes.
45
45
  *
46
46
  * @example
47
- * import { Flex } from '@bspk/ui/Flex';
47
+ * import { Flex } from '-/components/Flex';
48
48
  *
49
- * <Flex gap="24" justify="center" style={{ width: '100%' }}>
50
- * <div>Alpha</div>
51
- * <div>Beta</div>
52
- * <div>Gamma</div>
53
- * </Flex>;
49
+ * () => {
50
+ * return (
51
+ * <Flex gap="24" justify="center" style={{ width: '100%' }}>
52
+ * <div>Alpha</div>
53
+ * <div>Beta</div>
54
+ * <div>Gamma</div>
55
+ * </Flex>
56
+ * );
57
+ * };
54
58
  *
55
59
  * @name Flex
56
60
  * @phase Utility
@@ -2,7 +2,7 @@ import { InlineAlert } from './InlineAlert';
2
2
  import { hasNoBasicA11yIssues } from '-/rtl/hasNoBasicA11yIssues';
3
3
  import { render } from '-/rtl/util';
4
4
 
5
- const TestBed = () => <InlineAlert variant="informational">Example informational inline alert</InlineAlert>;
5
+ const TestBed = () => <InlineAlert label="Example informational inline alert" variant="informational" />;
6
6
 
7
7
  describe('InlineAlert (RTL)', () => {
8
8
  it('has no basic a11y issues', hasNoBasicA11yIssues(<TestBed />));