@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
@@ -3,40 +3,30 @@ import { SvgClose } from '@bspk/icons/Close';
3
3
  import { ReactNode, useMemo, useRef } from 'react';
4
4
  import { Button, ButtonProps } from '-/components/Button';
5
5
  import { DialogProps, Dialog } from '-/components/Dialog';
6
- import { useDebounceCallback } from '-/hooks/useDebounceCallback';
7
6
  import { useEventListener } from '-/hooks/useEventListener';
8
7
  import { useUIContext } from '-/hooks/useUIContext';
9
8
  import { CallToActionButton } from '-/types/common';
10
9
 
11
- // This hook is used to set the height of the modal based on the dialog box height.
12
- // It listens to the resize event and updates the modal height accordingly.
13
- function useDialogHeight() {
14
- const onResize = () => {
15
- const { dialogBox, modal } = modalRefs.current || {};
16
- if (!dialogBox || !modal) return;
17
- modal.style.height = `${dialogBox.offsetHeight}px`;
18
- modal.style.visibility = '';
10
+ function useMatchParentHeight() {
11
+ const elementRef = useRef<HTMLDivElement | null>(null);
12
+ const updateHeight = () => {
13
+ const element = elementRef.current;
14
+ const parentElement = element?.parentElement;
15
+ if (!element || !parentElement) return;
16
+ // Reset height to allow shrinking or growing
17
+ element.style.height = '';
18
+ // Apply new height on next frame
19
+ requestAnimationFrame(() => {
20
+ element.style.height = `${parentElement.clientHeight}px`;
21
+ });
19
22
  };
20
-
21
- useEventListener('resize', useDebounceCallback(onResize, 100));
22
-
23
- const modalRefs = useRef<{
24
- dialogBox: HTMLDivElement | null;
25
- modal: HTMLDivElement | null;
26
- } | null>(null);
23
+ useEventListener('resize', updateHeight);
24
+ useEventListener('orientationchange', updateHeight);
27
25
 
28
26
  return {
29
- setModalRefs: (node: HTMLElement | null) => {
30
- if (!node) return;
31
- const dialogBox = node.querySelector<HTMLDivElement>('[data-dialog-box]');
32
- const modal = node.querySelector<HTMLDivElement>('[data-bspk="modal"]');
33
- modalRefs.current = {
34
- dialogBox,
35
- modal,
36
- };
37
- if (!dialogBox || !modal) return;
38
- modal.style.height = `${dialogBox.offsetHeight}px`;
39
- modal.style.visibility = '';
27
+ setElement: (el: HTMLDivElement | null) => {
28
+ elementRef.current = el;
29
+ updateHeight();
40
30
  },
41
31
  };
42
32
  }
@@ -168,7 +158,7 @@ export function Modal({
168
158
  return nextButtons;
169
159
  }, [callToAction, cancelButton, dialogProps.onClose, isMobile]);
170
160
 
171
- const { setModalRefs } = useDialogHeight();
161
+ const { setElement } = useMatchParentHeight();
172
162
 
173
163
  return (
174
164
  <Dialog
@@ -176,11 +166,16 @@ export function Modal({
176
166
  aria-description={description}
177
167
  aria-label={header}
178
168
  disableFocusTrap={disableFocusTrap}
179
- innerRef={setModalRefs}
180
169
  placement="center"
181
170
  showScrim
182
171
  >
183
- <div data-bspk="modal" ref={(node) => innerRef?.(node)} style={{ visibility: 'hidden' }}>
172
+ <div
173
+ data-bspk="modal"
174
+ ref={(node) => {
175
+ innerRef?.(node);
176
+ setElement(node);
177
+ }}
178
+ >
184
179
  <div data-modal-header>
185
180
  <div data-modal-title>{header}</div>
186
181
  <Button
@@ -188,6 +183,7 @@ export function Modal({
188
183
  iconOnly
189
184
  label="close"
190
185
  onClick={dialogProps.onClose}
186
+ size={isMobile ? 'medium' : 'small'}
191
187
  variant="tertiary"
192
188
  />
193
189
  </div>
@@ -47,7 +47,12 @@ export const ModalExample: ComponentExampleFn<ModalProps> = ({ action }) => ({
47
47
  header: 'Header Only',
48
48
  description: 'This modal has no buttons.',
49
49
  children: (
50
- <>
50
+ <div
51
+ style={{
52
+ display: 'flex',
53
+ flexDirection: 'column',
54
+ }}
55
+ >
51
56
  <p>
52
57
  This is a demo of a scrolling modal. Most modals won&apos;t scroll but mobile uses modals as
53
58
  dropdowns which may have more items than can fit in the screen.
@@ -63,7 +68,7 @@ export const ModalExample: ComponentExampleFn<ModalProps> = ({ action }) => ({
63
68
  trailing={<Checkbox aria-label="" name="" onChange={() => {}} value="" />}
64
69
  />
65
70
  ))}
66
- </>
71
+ </div>
67
72
  ),
68
73
  },
69
74
  },
@@ -5,7 +5,7 @@
5
5
  gap: var(--spacing-sizing-02);
6
6
  padding: var(--spacing-sizing-05);
7
7
 
8
- [data-screen-size='small'] & {
8
+ @media (width < 640px) {
9
9
  padding: var(--spacing-sizing-04);
10
10
  }
11
11
 
@@ -40,6 +40,7 @@
40
40
  [data-digit] {
41
41
  &[data-active] {
42
42
  outline: solid 2px var(--stroke-neutral-focus);
43
+ isolation: isolate;
43
44
 
44
45
  &:empty::before {
45
46
  // caret
@@ -3,7 +3,7 @@ import { SvgIcon } from '@bspk/icons/SvgIcon';
3
3
  import { AriaAttributes, useEffect, useState } from 'react';
4
4
  import { PageList } from './PageList';
5
5
  import { Button } from '-/components/Button';
6
- import { InputElement } from '-/components/Input';
6
+ import { Input } from '-/components/Input';
7
7
  import { sendAriaLiveMessage } from '-/utils/sendAriaLiveMessage';
8
8
 
9
9
  // After this point the manual input renders. With equal or fewer pages the individual page buttons render instead.
@@ -104,7 +104,7 @@ export function Pagination({
104
104
  submitInputChange();
105
105
  }}
106
106
  >
107
- <InputElement
107
+ <Input
108
108
  name="page-number"
109
109
  onBlur={() => submitInputChange()}
110
110
  onChange={setInputValue}
@@ -1,8 +1,8 @@
1
1
  import './password.scss';
2
2
  import { useState } from 'react';
3
3
  import { Button } from '-/components/Button';
4
- import { useFieldInit } from '-/components/Field';
5
- import { InputElement, InputProps } from '-/components/Input';
4
+ import { Input, InputProps } from '-/components/Input';
5
+ import { useId } from '-/hooks/useId';
6
6
  import { FieldControlProps } from '-/types/common';
7
7
 
8
8
  export type PasswordProps = FieldControlProps & Pick<InputProps, 'containerRef' | 'inputProps' | 'inputRef' | 'size'>;
@@ -13,23 +13,25 @@ export type PasswordProps = FieldControlProps & Pick<InputProps, 'containerRef'
13
13
  * For a more complete example with field usage, see the PasswordField component.
14
14
  *
15
15
  * @example
16
- * import { Password } from '@bspk/ui/Password';
17
- * import { Field, FieldLabel, FieldDescription } from '-/components/Field';
16
+ * import { Password } from '-/components/Password';
18
17
  *
19
18
  * () => {
20
19
  * const [value, setValue] = useState<string | undefined>('');
21
20
  *
22
21
  * return (
23
- * <div style={{ width: 320 }}>
24
- * <Field>
25
- * <FieldLabel>Password</FieldLabel>
22
+ * <div>
23
+ * <Field
24
+ * controlId="example-password"
25
+ * helperText="The password field allows you to enter a secure password."
26
+ * label="Password"
27
+ * >
26
28
  * <Password
27
29
  * aria-label="password"
30
+ * id="example-password"
28
31
  * name="password"
29
32
  * onChange={(next) => setValue(next)}
30
33
  * value={value}
31
34
  * />
32
- * <FieldDescription>The password field allows you to enter a secure password.</FieldDescription>
33
35
  * </Field>
34
36
  * </div>
35
37
  * );
@@ -45,20 +47,16 @@ export function Password({
45
47
  onChange,
46
48
  required = false,
47
49
  containerRef,
48
- invalid: invalidProp,
50
+ invalid = false,
49
51
  readOnly,
50
52
  disabled,
51
53
  id: idProp,
52
54
  'aria-label': ariaLabel,
55
+ 'aria-describedby': ariaDescribedBy,
56
+ 'aria-errormessage': ariaErrorMessage,
53
57
  ...props
54
58
  }: PasswordProps) {
55
- const { id, ariaDescribedBy, ariaErrorMessage, invalid } = useFieldInit({
56
- idProp,
57
- required,
58
- disabled,
59
- readOnly,
60
- invalidProp,
61
- });
59
+ const id = useId(idProp);
62
60
 
63
61
  const [isShowingPassword, setIsShowingPassword] = useState(false);
64
62
 
@@ -68,7 +66,7 @@ export function Password({
68
66
  };
69
67
 
70
68
  return (
71
- <InputElement
69
+ <Input
72
70
  {...props}
73
71
  aria-describedby={ariaDescribedBy}
74
72
  aria-errormessage={ariaErrorMessage}
@@ -1,6 +1,6 @@
1
1
  import { useState } from 'react';
2
2
  import { Password, PasswordProps } 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 PasswordExample: ComponentExample<PasswordProps> = {
@@ -15,10 +15,18 @@ export const Usage = () => {
15
15
 
16
16
  return (
17
17
  <div>
18
- <Field>
19
- <FieldLabel>Password</FieldLabel>
20
- <Password aria-label="password" name="password" onChange={(next) => setValue(next)} value={value} />
21
- <FieldDescription>The password field allows you to enter a secure password.</FieldDescription>
18
+ <Field
19
+ controlId="example-password"
20
+ helperText="The password field allows you to enter a secure password."
21
+ label="Password"
22
+ >
23
+ <Password
24
+ aria-label="password"
25
+ id="example-password"
26
+ name="password"
27
+ onChange={(next) => setValue(next)}
28
+ value={value}
29
+ />
22
30
  </Field>
23
31
  </div>
24
32
  );
@@ -1,7 +1,8 @@
1
- import { FormField, FormFieldControlProps } from '-/components/FormField';
1
+ import { Field, ComposedFieldProps, propsWithAria } from '-/components/Field';
2
2
  import { Password, PasswordProps } from '-/components/Password';
3
+ import { useId } from '-/hooks/useId';
3
4
 
4
- export type PasswordFieldProps = FormFieldControlProps<PasswordProps>;
5
+ export type PasswordFieldProps = ComposedFieldProps<PasswordProps>;
5
6
 
6
7
  /**
7
8
  * A field wrapper for the Password component.
@@ -9,7 +10,7 @@ export type PasswordFieldProps = FormFieldControlProps<PasswordProps>;
9
10
  * This component takes properties from the FormField and Password components.
10
11
  *
11
12
  * @name PasswordField
12
- * @phase Stable
13
+ * @phase UXReview
13
14
  *
14
15
  * @generated
15
16
  */
@@ -19,18 +20,22 @@ export function PasswordField({
19
20
  labelTrailing,
20
21
  errorMessage,
21
22
  style,
23
+ id: idProp,
22
24
  ...controlProps
23
25
  }: PasswordFieldProps) {
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
- <Password {...controlProps} />
33
- </FormField>
37
+ <Password {...propsWithAria({ id, controlProps, errorMessage, helperText })} />
38
+ </Field>
34
39
  );
35
40
  }
36
41
 
@@ -56,7 +56,6 @@ export type PopoverProps = CommonProps<'disabled'> &
56
56
  * Brief message that provide additional guidance and helps users perform an action if needed.
57
57
  *
58
58
  * @example
59
- * import { useState } from 'react';
60
59
  * import { Popover } from '@bspk/ui/Popover';
61
60
  * import { Button } from '@bspk/ui/Button';
62
61
  *
@@ -1,7 +1,7 @@
1
1
  import './radio-group.scss';
2
- import { useFieldInit } from '-/components/Field';
3
2
  import { RadioProps } from '-/components/Radio';
4
3
  import { RadioOption, RadioOptionProps } from '-/components/RadioOption';
4
+ import { useId } from '-/hooks/useId';
5
5
  import { ElementProps, FieldControlProps } from '-/types/common';
6
6
 
7
7
  export type RadioGroupOption = Pick<RadioOptionProps, 'checked' | 'description' | 'disabled' | 'label'> &
@@ -37,7 +37,6 @@ export type RadioGroupProps = Omit<FieldControlProps, 'readOnly'> & {
37
37
  * For a more complete example with field usage, see the RadioGroupField component.
38
38
  *
39
39
  * @example
40
- * import { useState } from 'react';
41
40
  * import { RadioGroup } from '@bspk/ui/RadioGroup';
42
41
  *
43
42
  * () => {
@@ -68,45 +67,40 @@ export function RadioGroup({
68
67
  onChange,
69
68
  options = [],
70
69
  name,
71
- value: groupValue,
70
+ value,
72
71
  disabled = false,
73
- invalid: invalidProp,
74
72
  required,
73
+ invalid = false,
75
74
  id: idProp,
76
- 'aria-describedby': ariaDescribedByProp,
77
- 'aria-errormessage': ariaErrorMessageProp,
75
+ 'aria-describedby': ariaDescribedBy,
76
+ 'aria-errormessage': ariaErrorMessage,
78
77
  ...props
79
78
  }: ElementProps<RadioGroupProps, 'div'>) {
80
- const { id, ariaDescribedBy, ariaErrorMessage, invalid } = useFieldInit({
81
- idProp,
82
- required,
83
- disabled,
84
- invalidProp,
85
- });
79
+ const id = useId(idProp);
86
80
 
87
81
  return (
88
82
  <div
89
83
  {...props}
90
- aria-describedby={ariaDescribedByProp || ariaDescribedBy || undefined}
84
+ aria-describedby={ariaDescribedBy || undefined}
91
85
  data-bspk="radio-group"
92
86
  id={id}
93
87
  role="radiogroup"
94
88
  >
95
- {options.map(({ label, description, value, ...option }, index) => {
89
+ {options.map(({ label, description, value: optionValue, ...option }) => {
96
90
  return (
97
91
  <RadioOption
98
- aria-describedby={ariaDescribedByProp || ariaDescribedBy || undefined}
99
- aria-errormessage={ariaErrorMessageProp || ariaErrorMessage || undefined}
100
- checked={groupValue === value}
92
+ aria-describedby={ariaDescribedBy || undefined}
93
+ aria-errormessage={ariaErrorMessage || undefined}
94
+ checked={value === optionValue}
101
95
  description={description}
102
96
  disabled={disabled || option.disabled}
103
97
  invalid={invalid || undefined}
104
- key={`radio-option-${value || index}`}
98
+ key={optionValue}
105
99
  label={label}
106
100
  name={name}
107
- onChange={(checked) => checked && onChange(value)}
101
+ onChange={(checked) => checked && onChange(optionValue)}
108
102
  required={required}
109
- value={value}
103
+ value={optionValue}
110
104
  />
111
105
  );
112
106
  })}
@@ -5,4 +5,8 @@
5
5
  max-width: 100%;
6
6
 
7
7
  --list-item-height: 'auto';
8
+
9
+ [data-bspk='list-item'] {
10
+ background: transparent;
11
+ }
8
12
  }
@@ -1,8 +1,8 @@
1
- import { Field, FieldDescription, FieldError, FieldLabel } from '-/components/Field';
2
- import { FormFieldControlProps } from '-/components/FormField';
1
+ import { ComposedFieldProps, Fieldset, propsWithAria } from '-/components/Field';
3
2
  import { RadioGroup, RadioGroupProps } from '-/components/RadioGroup';
3
+ import { useId } from '-/hooks/useId';
4
4
 
5
- export type RadioGroupFieldProps = FormFieldControlProps<RadioGroupProps>;
5
+ export type RadioGroupFieldProps = ComposedFieldProps<RadioGroupProps>;
6
6
 
7
7
  /**
8
8
  * A field wrapper for the RadioGroup component.
@@ -20,17 +20,22 @@ export function RadioGroupField({
20
20
  labelTrailing,
21
21
  errorMessage,
22
22
  style,
23
+ id: idProp,
23
24
  ...controlProps
24
25
  }: RadioGroupFieldProps) {
26
+ const id = useId(idProp);
25
27
  return (
26
- <Field as="fieldset">
27
- <FieldLabel as="legend" labelTrailing={labelTrailing} style={style}>
28
- {label}
29
- </FieldLabel>
30
- <RadioGroup {...controlProps} />
31
- {!errorMessage && helperText && <FieldDescription>{helperText}</FieldDescription>}
32
- {errorMessage && <FieldError>{errorMessage}</FieldError>}
33
- </Field>
28
+ <Fieldset
29
+ controlId={id}
30
+ errorMessage={errorMessage}
31
+ helperText={helperText}
32
+ label={label}
33
+ labelTrailing={labelTrailing}
34
+ required={controlProps.required}
35
+ style={style}
36
+ >
37
+ <RadioGroup {...propsWithAria({ id, controlProps, errorMessage, helperText })} />
38
+ </Fieldset>
34
39
  );
35
40
  }
36
41
 
@@ -69,7 +69,6 @@ export type SearchBarProps<O extends SearchBarOption = SearchBarOption> = Omit<
69
69
  * An input field that allows customers to input search queries and retrieve results.
70
70
  *
71
71
  * @example
72
- * import { useState } from 'react';
73
72
  * import { SearchBar } from '@bspk/ui/SearchBar';
74
73
  *
75
74
  * () => {
@@ -9,7 +9,6 @@ export type SegmentedControlProps = TabListProps<SegmentedControlOption>;
9
9
  * Navigation tool that organizes content across different screens and views.
10
10
  *
11
11
  * @example
12
- * import { useState } from 'react';
13
12
  * import { SegmentedControl } from '@bspk/ui/SegmentedControl';
14
13
  *
15
14
  * () => {
@@ -1,11 +1,11 @@
1
1
  import './select.scss';
2
2
  import { SvgKeyboardArrowDown } from '@bspk/icons/KeyboardArrowDown';
3
3
  import { useMemo, KeyboardEvent, MouseEvent } from 'react';
4
- import { useFieldInit } from '-/components/Field';
5
4
  import { ListItem, ListItemProps } from '-/components/ListItem';
6
5
  import { Menu, MenuProps } from '-/components/Menu';
7
6
  import { useArrowNavigation } from '-/hooks/useArrowNavigation';
8
7
  import { useFloating } from '-/hooks/useFloating';
8
+ import { useId } from '-/hooks/useId';
9
9
  import { useOutsideClick } from '-/hooks/useOutsideClick';
10
10
  import { CommonProps, ElementProps, FieldControlProps } from '-/types/common';
11
11
  import { getElementById } from '-/utils/dom';
@@ -82,9 +82,13 @@ export type SelectProps = CommonProps<'size'> &
82
82
  *
83
83
  * return (
84
84
  * <div style={{ width: 320 }}>
85
- * <Field>
86
- * <FieldLabel>Select an option</FieldLabel>
85
+ * <Field
86
+ * controlId="example-select"
87
+ * helperText="The select allows you to choose one option from a list of options."
88
+ * label="Select an option"
89
+ * >
87
90
  * <Select
91
+ * id="example-select"
88
92
  * name="example-select"
89
93
  * onChange={setSelected}
90
94
  * options={OPTIONS}
@@ -93,9 +97,6 @@ export type SelectProps = CommonProps<'size'> &
93
97
  * size="medium"
94
98
  * value={selected}
95
99
  * />
96
- * <FieldDescription>
97
- * The select allows you to choose one option from a list of options.
98
- * </FieldDescription>
99
100
  * </Field>
100
101
  * </div>
101
102
  * );
@@ -112,22 +113,19 @@ export function Select({
112
113
  size = 'medium',
113
114
  disabled,
114
115
  id: idProp,
115
- invalid: invalidProp,
116
+ invalid = false,
116
117
  readOnly,
117
118
  name,
118
119
  scrollLimit,
119
120
  required = false,
120
121
  'aria-label': ariaLabel,
121
122
  menuWidth,
123
+ 'aria-describedby': ariaDescribedBy,
124
+ 'aria-errormessage': ariaErrorMessage,
122
125
  ...elementProps
123
126
  }: ElementProps<SelectProps, 'button'>) {
124
- const { id, ariaDescribedBy, ariaErrorMessage, invalid } = useFieldInit({
125
- idProp,
126
- required,
127
- disabled,
128
- readOnly,
129
- invalidProp,
130
- });
127
+ const id = useId(idProp);
128
+
131
129
  const menuId = useMemo(() => `${id}-menu`, [id]);
132
130
 
133
131
  const { items, availableItems } = useMemo(() => {
@@ -188,6 +186,7 @@ export function Select({
188
186
  aria-expanded={open}
189
187
  aria-haspopup="listbox"
190
188
  aria-readonly={readOnly || undefined}
189
+ aria-required={required || undefined}
191
190
  data-bspk="select"
192
191
  data-invalid={invalid || undefined}
193
192
  data-open={open || undefined}
@@ -2,7 +2,7 @@
2
2
  import { useState } from 'react';
3
3
  import { Select, SelectProps } from '.';
4
4
  import { Avatar } from '-/components/Avatar';
5
- import { Field, FieldDescription, FieldLabel } from '-/components/Field';
5
+ import { Field } from '-/components/Field';
6
6
  import { Tag } from '-/components/Tag';
7
7
  import { Txt } from '-/components/Txt';
8
8
  import { ComponentExample, Preset } from '-/utils/demo';
@@ -180,9 +180,13 @@ export const Usage = () => {
180
180
 
181
181
  return (
182
182
  <div style={{ width: 320 }}>
183
- <Field>
184
- <FieldLabel>Select an option</FieldLabel>
183
+ <Field
184
+ controlId="example-select"
185
+ helperText="The select allows you to choose one option from a list of options."
186
+ label="Select an option"
187
+ >
185
188
  <Select
189
+ id="example-select"
186
190
  name="example-select"
187
191
  onChange={setSelected}
188
192
  options={OPTIONS}
@@ -191,7 +195,6 @@ export const Usage = () => {
191
195
  size="medium"
192
196
  value={selected}
193
197
  />
194
- <FieldDescription>The select allows you to choose one option from a list of options.</FieldDescription>
195
198
  </Field>
196
199
  </div>
197
200
  );
@@ -46,18 +46,6 @@
46
46
  color: var(--select-text-color);
47
47
  }
48
48
 
49
- [data-icon] {
50
- display: flex;
51
- flex-direction: column;
52
- justify-content: center;
53
- pointer-events: none;
54
-
55
- svg {
56
- transform: rotate(90deg);
57
- width: var(--select-icon-width);
58
- }
59
- }
60
-
61
49
  &[data-size='small'] {
62
50
  --select-height: var(--spacing-sizing-08);
63
51
  --select-font: var(--body-small);
@@ -1,28 +1,17 @@
1
- import { SelectField, SelectFieldProps } from './';
2
- import { presets } from '-/components/Select/SelectExample';
1
+ import { SelectField } from '.';
3
2
  import { hasNoBasicA11yIssues } from '-/rtl/hasNoBasicA11yIssues';
4
3
  import { render } from '-/rtl/util';
5
4
 
6
- const nonPresetProps = {
7
- name: 'Example name',
8
- onChange: () => {},
9
- };
10
-
11
- const TestBed = (props: SelectFieldProps) => <SelectField {...props} placeholder="SelectField an option" />;
5
+ const TestBed = () => (
6
+ <SelectField label="Example field label" name="example-field-name" onChange={() => {}} options={[]} value="" />
7
+ );
12
8
 
13
9
  describe('SelectField (RTL)', () => {
14
- presets.forEach((preset) => {
15
- it(
16
- `has no basic a11y issues - ${preset.label}`,
17
- hasNoBasicA11yIssues(<TestBed label={preset.label} {...preset.propState} {...nonPresetProps} />),
18
- );
19
- });
10
+ it('has no basic a11y issues', hasNoBasicA11yIssues(<TestBed />));
20
11
 
21
12
  it('renders', () => {
22
- const { queryByText } = render(
23
- <TestBed label={presets[0].label} {...presets[0].propState} {...nonPresetProps} />,
24
- );
13
+ const { getAllByLabelText } = render(<TestBed />);
25
14
 
26
- expect(queryByText('SelectField an option')).toBeInTheDocument();
15
+ expect(getAllByLabelText('Example field label')[0]).toBeInTheDocument();
27
16
  });
28
17
  });