@boostdev/design-system-components 2.8.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (534) hide show
  1. package/AGENTS.md +54 -46
  2. package/README.md +34 -20
  3. package/dist/client.cjs +1317 -779
  4. package/dist/client.css +1029 -812
  5. package/dist/client.d.cts +88 -26
  6. package/dist/client.d.ts +88 -26
  7. package/dist/client.js +1278 -732
  8. package/dist/index.cjs +1317 -779
  9. package/dist/index.css +1029 -812
  10. package/dist/index.d.cts +88 -26
  11. package/dist/index.d.ts +88 -26
  12. package/dist/index.js +1278 -732
  13. package/dist/web-components/chunk-2OLVQUBU.js +193 -0
  14. package/dist/web-components/{chunk-OF6FFGOT.js → chunk-3AY2YKCM.js} +77 -21
  15. package/dist/web-components/chunk-3WAV6MDN.js +212 -0
  16. package/dist/web-components/{chunk-UUKSDCYS.js → chunk-47AT5KZD.js} +87 -15
  17. package/dist/web-components/chunk-4A2YYTYN.js +93 -0
  18. package/dist/web-components/{chunk-Q4T5BJT6.js → chunk-62NK3ZSC.js} +18 -3
  19. package/dist/web-components/chunk-66M6ETWD.js +77 -0
  20. package/dist/web-components/{chunk-NCPQ7AF3.js → chunk-6G22I2CK.js} +18 -3
  21. package/dist/web-components/{chunk-QDST57JC.js → chunk-7ZOJ7N4E.js} +14 -4
  22. package/dist/web-components/{chunk-QLT6MTZF.js → chunk-AIBOHNDU.js} +10 -0
  23. package/dist/web-components/{chunk-X3NQMBAQ.js → chunk-AP4RDUL2.js} +14 -3
  24. package/dist/web-components/{chunk-QWPACK5L.js → chunk-BPYKZVDK.js} +11 -1
  25. package/dist/web-components/{chunk-YLVTEY23.js → chunk-BTCMJQKB.js} +53 -21
  26. package/dist/web-components/chunk-CUKQ2L5B.js +245 -0
  27. package/dist/web-components/chunk-DIZDCL7Z.js +14 -0
  28. package/dist/web-components/{chunk-PC3IOQAH.js → chunk-DV5T43ZC.js} +27 -7
  29. package/dist/web-components/{chunk-2QA62WCQ.js → chunk-EF7IVYTY.js} +10 -0
  30. package/dist/web-components/{chunk-L3XHOMN6.js → chunk-F3ZDNHZZ.js} +26 -1
  31. package/dist/web-components/chunk-FEDABOR5.js +248 -0
  32. package/dist/web-components/{chunk-6I2DBFQ7.js → chunk-HGFCJXOQ.js} +36 -5
  33. package/dist/web-components/{chunk-SOQQ7RVJ.js → chunk-IPGHUCJT.js} +23 -8
  34. package/dist/web-components/chunk-ITD2MV5K.js +392 -0
  35. package/dist/web-components/{chunk-ARMKC4BQ.js → chunk-JH6LQKLK.js} +77 -5
  36. package/dist/web-components/chunk-JMCXAAFK.js +120 -0
  37. package/dist/web-components/{chunk-KUI55GFB.js → chunk-JUPCZVVW.js} +50 -18
  38. package/dist/web-components/chunk-JV5QT2OU.js +146 -0
  39. package/dist/web-components/{chunk-3GFWLSLS.js → chunk-KA3VPKMY.js} +29 -6
  40. package/dist/web-components/{chunk-CR5PGUHV.js → chunk-KJGRFDFI.js} +26 -11
  41. package/dist/web-components/{chunk-PY62FTRW.js → chunk-KZPRFY5P.js} +68 -33
  42. package/dist/web-components/{chunk-X46KL5BK.js → chunk-LDIPCTRN.js} +18 -1
  43. package/dist/web-components/chunk-M3ECULRH.js +174 -0
  44. package/dist/web-components/chunk-NBN2ENWJ.js +90 -0
  45. package/dist/web-components/chunk-NIN3JO6Q.js +189 -0
  46. package/dist/web-components/{chunk-2FGATTGT.js → chunk-NTQ4TCUT.js} +76 -55
  47. package/dist/web-components/chunk-OY74D4X6.js +302 -0
  48. package/dist/web-components/{chunk-3S42DZ7W.js → chunk-P24JYC5V.js} +7 -0
  49. package/dist/web-components/{chunk-BKIHQYJR.js → chunk-PXPPKCLT.js} +17 -2
  50. package/dist/web-components/{chunk-TQ7IQ4GZ.js → chunk-QEF2IRID.js} +71 -29
  51. package/dist/web-components/chunk-QZAIRJ75.js +111 -0
  52. package/dist/web-components/{chunk-6I3CFC26.js → chunk-RSZ3BWBK.js} +20 -5
  53. package/dist/web-components/chunk-RVF7W653.js +101 -0
  54. package/dist/web-components/chunk-SEO2F5KJ.js +234 -0
  55. package/dist/web-components/{chunk-VMMVWLXL.js → chunk-SFZ6Q4BP.js} +10 -0
  56. package/dist/web-components/{chunk-LY62SAVN.js → chunk-SYNLFKD3.js} +12 -2
  57. package/dist/web-components/chunk-TMWXRHGF.js +192 -0
  58. package/dist/web-components/{chunk-65JXQOBA.js → chunk-U3YZE6R6.js} +51 -7
  59. package/dist/web-components/chunk-UO7ROSHD.js +424 -0
  60. package/dist/web-components/chunk-VANAKB6D.js +152 -0
  61. package/dist/web-components/{chunk-PXZWYO6Z.js → chunk-VED2DFJ6.js} +108 -29
  62. package/dist/web-components/chunk-W6H5ID2U.js +161 -0
  63. package/dist/web-components/{chunk-FSZRP43R.js → chunk-WFVKU4GX.js} +21 -10
  64. package/dist/web-components/{chunk-OQTRTMAB.js → chunk-WIBAN7KP.js} +10 -0
  65. package/dist/web-components/chunk-XI7KRAH7.js +54 -0
  66. package/dist/web-components/{chunk-ORC56MDY.js → chunk-XIZWAWMJ.js} +45 -6
  67. package/dist/web-components/{chunk-FXURM6D5.js → chunk-YFAXGRPR.js} +10 -0
  68. package/dist/web-components/globals.js +1 -1
  69. package/dist/web-components/index.d.ts +77 -707
  70. package/dist/web-components/index.js +339 -2066
  71. package/dist/web-components/interaction/bds-accordion-item.js +1 -1
  72. package/dist/web-components/interaction/bds-accordion.js +1 -1
  73. package/dist/web-components/interaction/bds-button.d.ts +10 -2
  74. package/dist/web-components/interaction/bds-button.js +1 -1
  75. package/dist/web-components/interaction/bds-collapsible.d.ts +7 -2
  76. package/dist/web-components/interaction/bds-collapsible.js +1 -1
  77. package/dist/web-components/interaction/bds-dialog.d.ts +11 -3
  78. package/dist/web-components/interaction/bds-dialog.js +1 -1
  79. package/dist/web-components/interaction/bds-drawer.d.ts +7 -1
  80. package/dist/web-components/interaction/bds-drawer.js +1 -1
  81. package/dist/web-components/interaction/bds-dropdown-menu-item.d.ts +51 -0
  82. package/dist/web-components/interaction/bds-dropdown-menu-item.js +7 -0
  83. package/dist/web-components/interaction/bds-dropdown-menu.d.ts +70 -0
  84. package/dist/web-components/interaction/bds-dropdown-menu.js +7 -0
  85. package/dist/web-components/interaction/bds-popover.d.ts +14 -3
  86. package/dist/web-components/interaction/bds-popover.js +1 -1
  87. package/dist/web-components/interaction/bds-skip-link.js +1 -1
  88. package/dist/web-components/interaction/bds-tab-panel.js +1 -1
  89. package/dist/web-components/interaction/bds-tab.js +1 -1
  90. package/dist/web-components/interaction/bds-tabs.d.ts +1 -0
  91. package/dist/web-components/interaction/bds-tabs.js +1 -1
  92. package/dist/web-components/interaction/bds-toast-provider.js +1 -1
  93. package/dist/web-components/interaction/bds-tooltip.d.ts +19 -3
  94. package/dist/web-components/interaction/bds-tooltip.js +1 -1
  95. package/dist/web-components/interaction/form/bds-checkbox-group.d.ts +83 -0
  96. package/dist/web-components/interaction/form/bds-checkbox-group.js +7 -0
  97. package/dist/web-components/interaction/form/bds-checkbox.d.ts +6 -0
  98. package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
  99. package/dist/web-components/interaction/form/bds-combobox.d.ts +18 -0
  100. package/dist/web-components/interaction/form/bds-combobox.js +1 -1
  101. package/dist/web-components/interaction/form/bds-field-group.d.ts +89 -0
  102. package/dist/web-components/interaction/form/bds-field-group.js +7 -0
  103. package/dist/web-components/interaction/form/bds-file-input.d.ts +1 -1
  104. package/dist/web-components/interaction/form/bds-file-input.js +1 -1
  105. package/dist/web-components/interaction/form/bds-form-input.d.ts +92 -0
  106. package/dist/web-components/interaction/form/bds-form-input.js +7 -0
  107. package/dist/web-components/interaction/form/bds-number-input.d.ts +18 -1
  108. package/dist/web-components/interaction/form/bds-number-input.js +1 -1
  109. package/dist/web-components/interaction/form/bds-radio-group.d.ts +81 -0
  110. package/dist/web-components/interaction/form/bds-radio-group.js +7 -0
  111. package/dist/web-components/interaction/form/bds-radio.d.ts +34 -6
  112. package/dist/web-components/interaction/form/bds-radio.js +1 -1
  113. package/dist/web-components/interaction/form/bds-segmented-control.d.ts +4 -4
  114. package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
  115. package/dist/web-components/interaction/form/bds-select.d.ts +22 -1
  116. package/dist/web-components/interaction/form/bds-select.js +1 -1
  117. package/dist/web-components/interaction/form/bds-slider.d.ts +42 -10
  118. package/dist/web-components/interaction/form/bds-slider.js +1 -1
  119. package/dist/web-components/interaction/form/bds-switch.d.ts +20 -0
  120. package/dist/web-components/interaction/form/bds-switch.js +1 -1
  121. package/dist/web-components/interaction/form/bds-textarea.d.ts +23 -3
  122. package/dist/web-components/interaction/form/bds-textarea.js +1 -1
  123. package/dist/web-components/layout/bds-grid-item.d.ts +63 -0
  124. package/dist/web-components/layout/bds-grid-item.js +7 -0
  125. package/dist/web-components/layout/bds-grid.d.ts +108 -0
  126. package/dist/web-components/layout/bds-grid.js +7 -0
  127. package/dist/web-components/ui/bds-alert.d.ts +16 -2
  128. package/dist/web-components/ui/bds-alert.js +1 -1
  129. package/dist/web-components/ui/bds-avatar.d.ts +2 -1
  130. package/dist/web-components/ui/bds-avatar.js +1 -1
  131. package/dist/web-components/ui/bds-badge.js +1 -1
  132. package/dist/web-components/ui/bds-breadcrumb.d.ts +3 -1
  133. package/dist/web-components/ui/bds-breadcrumb.js +1 -1
  134. package/dist/web-components/ui/bds-button-container.d.ts +52 -0
  135. package/dist/web-components/ui/bds-button-container.js +7 -0
  136. package/dist/web-components/ui/bds-button-group.d.ts +21 -0
  137. package/dist/web-components/ui/bds-button-group.js +8 -0
  138. package/dist/web-components/ui/bds-calendar.d.ts +121 -0
  139. package/dist/web-components/ui/bds-calendar.js +7 -0
  140. package/dist/web-components/ui/bds-card.d.ts +12 -3
  141. package/dist/web-components/ui/bds-card.js +1 -1
  142. package/dist/web-components/ui/bds-carousel.d.ts +98 -0
  143. package/dist/web-components/ui/bds-carousel.js +7 -0
  144. package/dist/web-components/ui/bds-description-list.js +1 -1
  145. package/dist/web-components/ui/bds-icon-wrapper.d.ts +0 -9
  146. package/dist/web-components/ui/bds-icon-wrapper.js +1 -1
  147. package/dist/web-components/ui/bds-link.js +1 -1
  148. package/dist/web-components/ui/bds-loading.js +1 -1
  149. package/dist/web-components/ui/bds-notification-banner.js +1 -1
  150. package/dist/web-components/ui/bds-pagination.d.ts +47 -0
  151. package/dist/web-components/ui/bds-pagination.js +7 -0
  152. package/dist/web-components/ui/bds-progress-circle.d.ts +3 -1
  153. package/dist/web-components/ui/bds-progress-circle.js +1 -1
  154. package/dist/web-components/ui/bds-progress.d.ts +3 -1
  155. package/dist/web-components/ui/bds-progress.js +1 -1
  156. package/dist/web-components/ui/bds-rating.js +1 -1
  157. package/dist/web-components/ui/bds-section-header.d.ts +18 -4
  158. package/dist/web-components/ui/bds-section-header.js +1 -1
  159. package/dist/web-components/ui/bds-separator.js +1 -1
  160. package/dist/web-components/ui/bds-skeleton.js +1 -1
  161. package/dist/web-components/ui/bds-table.d.ts +52 -0
  162. package/dist/web-components/ui/bds-table.js +7 -0
  163. package/dist/web-components/ui/bds-typography.d.ts +1 -0
  164. package/dist/web-components/ui/bds-typography.js +1 -1
  165. package/package.json +60 -3
  166. package/src/components/interaction/Button/Button.module.css +23 -14
  167. package/src/components/interaction/Button/Button.spec.tsx +20 -0
  168. package/src/components/interaction/Button/Button.tsx +2 -2
  169. package/src/components/interaction/Command/Command.mdx +5 -2
  170. package/src/components/interaction/Command/Command.module.css +23 -7
  171. package/src/components/interaction/Command/Command.spec.tsx +35 -0
  172. package/src/components/interaction/Command/Command.tsx +15 -4
  173. package/src/components/interaction/Command/index.ts +1 -1
  174. package/src/components/interaction/Dialog/Dialog.mdx +4 -4
  175. package/src/components/interaction/Dialog/Dialog.module.css +20 -0
  176. package/src/components/interaction/Dialog/Dialog.spec.tsx +20 -0
  177. package/src/components/interaction/Dialog/Dialog.tsx +8 -3
  178. package/src/components/interaction/Dialog/index.ts +1 -0
  179. package/src/components/interaction/Drawer/Drawer.mdx +5 -2
  180. package/src/components/interaction/Drawer/Drawer.module.css +34 -3
  181. package/src/components/interaction/Drawer/Drawer.spec.tsx +67 -1
  182. package/src/components/interaction/Drawer/Drawer.tsx +30 -12
  183. package/src/components/interaction/Drawer/index.ts +1 -0
  184. package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +2 -0
  185. package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +34 -0
  186. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +15 -5
  187. package/src/components/interaction/DropdownMenu/index.ts +1 -0
  188. package/src/components/interaction/Popover/Popover.mdx +6 -2
  189. package/src/components/interaction/Popover/Popover.module.css +26 -18
  190. package/src/components/interaction/Popover/Popover.spec.tsx +38 -0
  191. package/src/components/interaction/Popover/Popover.tsx +19 -5
  192. package/src/components/interaction/Popover/index.ts +1 -0
  193. package/src/components/interaction/Rating/Rating.mdx +1 -1
  194. package/src/components/interaction/Rating/Rating.module.css +2 -2
  195. package/src/components/interaction/Rating/Rating.tsx +1 -1
  196. package/src/components/interaction/Rating/index.ts +1 -0
  197. package/src/components/interaction/Toast/Toast.mdx +3 -0
  198. package/src/components/interaction/Toast/Toast.module.css +35 -5
  199. package/src/components/interaction/Toast/Toast.spec.tsx +69 -1
  200. package/src/components/interaction/Toast/Toast.tsx +15 -9
  201. package/src/components/interaction/form/Checkbox/Checkbox.mdx +3 -0
  202. package/src/components/interaction/form/Checkbox/Checkbox.module.css +13 -6
  203. package/src/components/interaction/form/Checkbox/Checkbox.spec.tsx +6 -0
  204. package/src/components/interaction/form/Checkbox/Checkbox.tsx +1 -1
  205. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +16 -1
  206. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.module.css +24 -8
  207. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.spec.tsx +32 -2
  208. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +14 -2
  209. package/src/components/interaction/form/Combobox/Combobox.mdx +11 -4
  210. package/src/components/interaction/form/Combobox/Combobox.module.css +6 -6
  211. package/src/components/interaction/form/Combobox/Combobox.spec.tsx +47 -0
  212. package/src/components/interaction/form/Combobox/Combobox.tsx +10 -5
  213. package/src/components/interaction/form/FieldGroup/FieldGroup.mdx +9 -10
  214. package/src/components/interaction/form/FieldGroup/FieldGroup.module.css +57 -23
  215. package/src/components/interaction/form/FieldGroup/FieldGroup.spec.tsx +129 -7
  216. package/src/components/interaction/form/FieldGroup/FieldGroup.tsx +72 -12
  217. package/src/components/interaction/form/FileInput/FileInput.mdx +9 -1
  218. package/src/components/interaction/form/FileInput/FileInput.module.css +8 -8
  219. package/src/components/interaction/form/FileInput/FileInput.spec.tsx +89 -1
  220. package/src/components/interaction/form/FileInput/FileInput.tsx +6 -2
  221. package/src/components/interaction/form/FormInput/FormInput.mdx +9 -5
  222. package/src/components/interaction/form/FormInput/FormInput.module.css +17 -8
  223. package/src/components/interaction/form/FormInput/FormInput.spec.tsx +20 -0
  224. package/src/components/interaction/form/FormInput/FormInput.tsx +7 -2
  225. package/src/components/interaction/form/NumberInput/NumberInput.mdx +5 -1
  226. package/src/components/interaction/form/NumberInput/NumberInput.module.css +6 -6
  227. package/src/components/interaction/form/NumberInput/NumberInput.spec.tsx +51 -0
  228. package/src/components/interaction/form/NumberInput/NumberInput.tsx +36 -8
  229. package/src/components/interaction/form/Radio/Radio.mdx +8 -1
  230. package/src/components/interaction/form/Radio/Radio.module.css +20 -7
  231. package/src/components/interaction/form/Radio/Radio.spec.tsx +15 -0
  232. package/src/components/interaction/form/Radio/Radio.tsx +10 -4
  233. package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +16 -1
  234. package/src/components/interaction/form/RadioGroup/RadioGroup.module.css +24 -8
  235. package/src/components/interaction/form/RadioGroup/RadioGroup.spec.tsx +32 -2
  236. package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +14 -2
  237. package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +9 -3
  238. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +25 -12
  239. package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +86 -5
  240. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +44 -4
  241. package/src/components/interaction/form/Select/Select.mdx +10 -4
  242. package/src/components/interaction/form/Select/Select.module.css +4 -4
  243. package/src/components/interaction/form/Select/Select.spec.tsx +34 -0
  244. package/src/components/interaction/form/Select/Select.tsx +21 -9
  245. package/src/components/interaction/form/Slider/Slider.mdx +4 -1
  246. package/src/components/interaction/form/Slider/Slider.module.css +32 -8
  247. package/src/components/interaction/form/Slider/Slider.spec.tsx +29 -0
  248. package/src/components/interaction/form/Slider/Slider.tsx +9 -7
  249. package/src/components/interaction/form/Switch/Switch.mdx +2 -2
  250. package/src/components/interaction/form/Switch/Switch.module.css +12 -13
  251. package/src/components/interaction/form/Switch/Switch.spec.tsx +20 -0
  252. package/src/components/interaction/form/Switch/Switch.tsx +2 -1
  253. package/src/components/interaction/form/Textarea/Textarea.mdx +5 -0
  254. package/src/components/interaction/form/Textarea/Textarea.module.css +5 -5
  255. package/src/components/interaction/form/Textarea/Textarea.spec.tsx +13 -0
  256. package/src/components/interaction/form/Textarea/Textarea.tsx +3 -1
  257. package/src/components/interaction/form/atoms/Message.module.css +1 -1
  258. package/src/components/interaction/form/atoms/Message.spec.tsx +29 -0
  259. package/src/components/interaction/form/atoms/Message.tsx +1 -1
  260. package/src/components/layout/ButtonGroup/ButtonGroup.mdx +11 -0
  261. package/src/components/layout/ButtonGroup/ButtonGroup.module.css +1 -5
  262. package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +14 -0
  263. package/src/components/layout/Card/Card.mdx +6 -1
  264. package/src/components/layout/Card/Card.module.css +26 -5
  265. package/src/components/layout/Card/Card.spec.tsx +7 -0
  266. package/src/components/layout/Card/Card.tsx +4 -3
  267. package/src/components/layout/Grid/Grid.spec.tsx +44 -0
  268. package/src/components/layout/Grid/Grid.tsx +5 -5
  269. package/src/components/layout/Grid/GridItem.tsx +6 -6
  270. package/src/components/layout/Grid/masonry.ts +31 -5
  271. package/src/components/layout/Grid/useIsomorphicLayoutEffect.ts +11 -0
  272. package/src/components/layout/IconWrapper/IconWrapper.mdx +8 -2
  273. package/src/components/layout/IconWrapper/IconWrapper.module.css +9 -6
  274. package/src/components/layout/SectionHeader/SectionHeader.mdx +4 -1
  275. package/src/components/layout/SectionHeader/SectionHeader.module.css +10 -9
  276. package/src/components/ui/Accordion/Accordion.mdx +4 -1
  277. package/src/components/ui/Accordion/Accordion.module.css +2 -1
  278. package/src/components/ui/Alert/Alert.mdx +21 -4
  279. package/src/components/ui/Alert/Alert.module.css +9 -4
  280. package/src/components/ui/Alert/Alert.spec.tsx +20 -0
  281. package/src/components/ui/Avatar/Avatar.mdx +8 -3
  282. package/src/components/ui/Avatar/Avatar.module.css +13 -8
  283. package/src/components/ui/Badge/Badge.mdx +3 -1
  284. package/src/components/ui/Breadcrumb/Breadcrumb.mdx +3 -0
  285. package/src/components/ui/Breadcrumb/Breadcrumb.module.css +4 -0
  286. package/src/components/ui/Breadcrumb/Breadcrumb.spec.tsx +12 -0
  287. package/src/components/ui/Breadcrumb/Breadcrumb.tsx +11 -3
  288. package/src/components/ui/Calendar/Calendar.mdx +6 -0
  289. package/src/components/ui/Calendar/Calendar.module.css +68 -19
  290. package/src/components/ui/Calendar/Calendar.spec.tsx +139 -24
  291. package/src/components/ui/Calendar/Calendar.stories.tsx +14 -0
  292. package/src/components/ui/Calendar/Calendar.tsx +143 -154
  293. package/src/components/ui/Calendar/CalendarRange.mdx +39 -0
  294. package/src/components/ui/Calendar/CalendarRange.spec.tsx +119 -0
  295. package/src/components/ui/Calendar/CalendarRange.stories.tsx +51 -0
  296. package/src/components/ui/Calendar/CalendarRange.tsx +213 -0
  297. package/src/components/ui/Calendar/MonthGrid.tsx +141 -0
  298. package/src/components/ui/Calendar/calendar-core.spec.ts +176 -0
  299. package/src/components/ui/Calendar/calendar-core.ts +164 -0
  300. package/src/components/ui/Calendar/index.ts +1 -0
  301. package/src/components/ui/Carousel/Carousel.mdx +8 -3
  302. package/src/components/ui/Carousel/Carousel.module.css +7 -5
  303. package/src/components/ui/Carousel/Carousel.spec.tsx +67 -0
  304. package/src/components/ui/Carousel/Carousel.tsx +19 -7
  305. package/src/components/ui/Collapsible/Collapsible.mdx +17 -6
  306. package/src/components/ui/Collapsible/Collapsible.module.css +7 -2
  307. package/src/components/ui/Collapsible/Collapsible.spec.tsx +40 -0
  308. package/src/components/ui/Collapsible/Collapsible.tsx +19 -2
  309. package/src/components/ui/DescriptionList/DescriptionList.mdx +2 -0
  310. package/src/components/ui/Link/Link.mdx +4 -2
  311. package/src/components/ui/Loading/Loading.mdx +6 -3
  312. package/src/components/ui/Loading/Loading.module.css +7 -7
  313. package/src/components/ui/Loading/Loading.spec.tsx +12 -0
  314. package/src/components/ui/Loading/Loading.tsx +8 -3
  315. package/src/components/ui/NotificationBanner/NotificationBanner.mdx +4 -0
  316. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +5 -0
  317. package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +20 -0
  318. package/src/components/ui/Pagination/Pagination.mdx +29 -7
  319. package/src/components/ui/Pagination/Pagination.module.css +15 -14
  320. package/src/components/ui/Progress/Progress.mdx +6 -2
  321. package/src/components/ui/Progress/Progress.module.css +1 -1
  322. package/src/components/ui/Progress/Progress.spec.tsx +17 -0
  323. package/src/components/ui/Progress/Progress.tsx +2 -2
  324. package/src/components/ui/ProgressCircle/ProgressCircle.mdx +8 -4
  325. package/src/components/ui/ProgressCircle/ProgressCircle.module.css +2 -2
  326. package/src/components/ui/ProgressCircle/ProgressCircle.spec.tsx +11 -1
  327. package/src/components/ui/ProgressCircle/ProgressCircle.tsx +1 -1
  328. package/src/components/ui/Separator/Separator.mdx +7 -0
  329. package/src/components/ui/Separator/Separator.module.css +1 -0
  330. package/src/components/ui/Skeleton/Skeleton.mdx +17 -0
  331. package/src/components/ui/Skeleton/Skeleton.module.css +12 -5
  332. package/src/components/ui/SkipLink/SkipLink.mdx +19 -0
  333. package/src/components/ui/SkipLink/SkipLink.module.css +8 -7
  334. package/src/components/ui/SkipLink/SkipLink.spec.tsx +28 -0
  335. package/src/components/ui/Table/Table.mdx +14 -0
  336. package/src/components/ui/Table/Table.module.css +13 -8
  337. package/src/components/ui/Table/Table.spec.tsx +56 -0
  338. package/src/components/ui/Table/Table.tsx +44 -6
  339. package/src/components/ui/Tabs/Tabs.mdx +16 -0
  340. package/src/components/ui/Tabs/Tabs.module.css +3 -3
  341. package/src/components/ui/Tabs/Tabs.spec.tsx +20 -0
  342. package/src/components/ui/Tabs/Tabs.tsx +5 -1
  343. package/src/components/ui/Tooltip/Tooltip.mdx +9 -0
  344. package/src/components/ui/Tooltip/Tooltip.module.css +32 -12
  345. package/src/components/ui/Tooltip/Tooltip.spec.tsx +56 -0
  346. package/src/components/ui/Tooltip/Tooltip.tsx +26 -7
  347. package/src/components/ui/Typography/Typography.mdx +7 -0
  348. package/src/components/ui/Typography/Typography.module.css +5 -5
  349. package/src/index.ts +7 -3
  350. package/src/stories/DesignSystem/Borders.mdx +14 -9
  351. package/src/stories/DesignSystem/Colors.mdx +43 -41
  352. package/src/stories/DesignSystem/Overview.mdx +4 -3
  353. package/src/stories/Introduction.mdx +5 -5
  354. package/src/web-components/globals.ts +7 -0
  355. package/src/web-components/index.ts +2 -0
  356. package/src/web-components/interaction/BdsAccordion.mdx +10 -1
  357. package/src/web-components/interaction/BdsButton.mdx +15 -4
  358. package/src/web-components/interaction/BdsButton.stories.tsx +1 -1
  359. package/src/web-components/interaction/BdsCollapsible.mdx +3 -3
  360. package/src/web-components/interaction/BdsDialog.mdx +12 -7
  361. package/src/web-components/interaction/BdsDialog.stories.tsx +2 -2
  362. package/src/web-components/interaction/BdsDrawer.mdx +9 -6
  363. package/src/web-components/interaction/BdsDropdownMenu.mdx +20 -1
  364. package/src/web-components/interaction/BdsPopover.mdx +7 -3
  365. package/src/web-components/interaction/BdsSkipLink.mdx +14 -1
  366. package/src/web-components/interaction/BdsTabs.mdx +18 -1
  367. package/src/web-components/interaction/BdsToastProvider.mdx +21 -3
  368. package/src/web-components/interaction/BdsTooltip.mdx +4 -4
  369. package/src/web-components/interaction/bds-accordion-item.ts +10 -0
  370. package/src/web-components/interaction/bds-accordion.spec.ts +41 -0
  371. package/src/web-components/interaction/bds-accordion.ts +28 -2
  372. package/src/web-components/interaction/bds-button.spec.ts +81 -0
  373. package/src/web-components/interaction/bds-button.ts +55 -8
  374. package/src/web-components/interaction/bds-collapsible.spec.ts +93 -2
  375. package/src/web-components/interaction/bds-collapsible.ts +49 -7
  376. package/src/web-components/interaction/bds-dialog.spec.ts +49 -0
  377. package/src/web-components/interaction/bds-dialog.ts +68 -11
  378. package/src/web-components/interaction/bds-drawer.spec.ts +93 -4
  379. package/src/web-components/interaction/bds-drawer.ts +54 -21
  380. package/src/web-components/interaction/bds-dropdown-menu-item.ts +12 -1
  381. package/src/web-components/interaction/bds-dropdown-menu.spec.ts +63 -0
  382. package/src/web-components/interaction/bds-dropdown-menu.ts +45 -7
  383. package/src/web-components/interaction/bds-popover.spec.ts +80 -6
  384. package/src/web-components/interaction/bds-popover.ts +83 -32
  385. package/src/web-components/interaction/bds-skip-link.spec.ts +18 -0
  386. package/src/web-components/interaction/bds-skip-link.ts +29 -8
  387. package/src/web-components/interaction/bds-tab-panel.ts +10 -0
  388. package/src/web-components/interaction/bds-tab.spec.ts +25 -0
  389. package/src/web-components/interaction/bds-tab.ts +20 -5
  390. package/src/web-components/interaction/bds-tabs.spec.ts +92 -5
  391. package/src/web-components/interaction/bds-tabs.ts +42 -1
  392. package/src/web-components/interaction/bds-toast-provider.spec.ts +43 -0
  393. package/src/web-components/interaction/bds-toast-provider.ts +50 -21
  394. package/src/web-components/interaction/bds-tooltip.spec.ts +71 -0
  395. package/src/web-components/interaction/bds-tooltip.ts +100 -5
  396. package/src/web-components/interaction/form/BdsCheckbox.mdx +20 -1
  397. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +8 -0
  398. package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +4 -3
  399. package/src/web-components/interaction/form/BdsCombobox.mdx +39 -2
  400. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +31 -0
  401. package/src/web-components/interaction/form/BdsFieldGroup.mdx +8 -3
  402. package/src/web-components/interaction/form/BdsFieldGroup.stories.tsx +1 -1
  403. package/src/web-components/interaction/form/BdsFileInput.mdx +26 -5
  404. package/src/web-components/interaction/form/BdsFormInput.mdx +16 -1
  405. package/src/web-components/interaction/form/BdsNumberInput.mdx +34 -2
  406. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +27 -3
  407. package/src/web-components/interaction/form/BdsRadio.mdx +39 -12
  408. package/src/web-components/interaction/form/BdsRadio.stories.tsx +26 -0
  409. package/src/web-components/interaction/form/BdsRadioGroup.mdx +9 -4
  410. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +37 -11
  411. package/src/web-components/interaction/form/BdsSelect.mdx +22 -4
  412. package/src/web-components/interaction/form/BdsSelect.stories.tsx +33 -0
  413. package/src/web-components/interaction/form/BdsSlider.mdx +36 -19
  414. package/src/web-components/interaction/form/BdsSlider.stories.tsx +24 -0
  415. package/src/web-components/interaction/form/BdsSwitch.mdx +38 -11
  416. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +16 -0
  417. package/src/web-components/interaction/form/BdsTextarea.mdx +42 -16
  418. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +21 -0
  419. package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +99 -0
  420. package/src/web-components/interaction/form/bds-checkbox-group.ts +95 -9
  421. package/src/web-components/interaction/form/bds-checkbox.spec.ts +55 -0
  422. package/src/web-components/interaction/form/bds-checkbox.ts +30 -5
  423. package/src/web-components/interaction/form/bds-combobox.spec.ts +79 -0
  424. package/src/web-components/interaction/form/bds-combobox.ts +101 -16
  425. package/src/web-components/interaction/form/bds-field-group.spec.ts +158 -0
  426. package/src/web-components/interaction/form/bds-field-group.ts +167 -23
  427. package/src/web-components/interaction/form/bds-file-input.spec.ts +73 -5
  428. package/src/web-components/interaction/form/bds-file-input.ts +71 -34
  429. package/src/web-components/interaction/form/bds-form-input.spec.ts +22 -0
  430. package/src/web-components/interaction/form/bds-form-input.ts +27 -16
  431. package/src/web-components/interaction/form/bds-number-input.spec.ts +49 -0
  432. package/src/web-components/interaction/form/bds-number-input.ts +118 -29
  433. package/src/web-components/interaction/form/bds-radio-group.spec.ts +57 -0
  434. package/src/web-components/interaction/form/bds-radio-group.ts +60 -12
  435. package/src/web-components/interaction/form/bds-radio.spec.ts +123 -0
  436. package/src/web-components/interaction/form/bds-radio.ts +135 -22
  437. package/src/web-components/interaction/form/bds-segmented-control.spec.ts +55 -0
  438. package/src/web-components/interaction/form/bds-segmented-control.ts +81 -59
  439. package/src/web-components/interaction/form/bds-select.spec.ts +57 -0
  440. package/src/web-components/interaction/form/bds-select.ts +95 -7
  441. package/src/web-components/interaction/form/bds-slider.spec.ts +83 -0
  442. package/src/web-components/interaction/form/bds-slider.ts +154 -26
  443. package/src/web-components/interaction/form/bds-switch.spec.ts +68 -0
  444. package/src/web-components/interaction/form/bds-switch.ts +87 -20
  445. package/src/web-components/interaction/form/bds-textarea.spec.ts +71 -0
  446. package/src/web-components/interaction/form/bds-textarea.ts +108 -7
  447. package/src/web-components/layout/BdsGrid.mdx +6 -2
  448. package/src/web-components/layout/BdsGrid.stories.tsx +4 -0
  449. package/src/web-components/layout/bds-grid-item.spec.ts +21 -0
  450. package/src/web-components/layout/bds-grid-item.ts +17 -3
  451. package/src/web-components/layout/bds-grid.spec.ts +98 -0
  452. package/src/web-components/layout/bds-grid.ts +139 -19
  453. package/src/web-components/ui/BdsAlert.mdx +6 -5
  454. package/src/web-components/ui/BdsAlert.stories.tsx +6 -6
  455. package/src/web-components/ui/BdsAvatar.mdx +4 -2
  456. package/src/web-components/ui/BdsBreadcrumb.mdx +3 -2
  457. package/src/web-components/ui/BdsButtonContainer.mdx +64 -0
  458. package/src/web-components/ui/BdsButtonContainer.stories.tsx +84 -0
  459. package/src/web-components/ui/BdsCalendar.mdx +29 -4
  460. package/src/web-components/ui/BdsCalendar.stories.tsx +16 -18
  461. package/src/web-components/ui/BdsCalendarRange.mdx +71 -0
  462. package/src/web-components/ui/BdsCalendarRange.stories.tsx +31 -0
  463. package/src/web-components/ui/BdsCard.mdx +7 -3
  464. package/src/web-components/ui/BdsCard.stories.tsx +17 -1
  465. package/src/web-components/ui/BdsCarousel.mdx +40 -12
  466. package/src/web-components/ui/BdsDescriptionList.mdx +6 -1
  467. package/src/web-components/ui/BdsIconWrapper.mdx +3 -2
  468. package/src/web-components/ui/BdsLink.mdx +14 -2
  469. package/src/web-components/ui/BdsNotificationBanner.mdx +18 -0
  470. package/src/web-components/ui/BdsPagination.mdx +40 -1
  471. package/src/web-components/ui/BdsProgress.mdx +8 -2
  472. package/src/web-components/ui/BdsProgressCircle.mdx +5 -2
  473. package/src/web-components/ui/BdsRating.mdx +7 -0
  474. package/src/web-components/ui/BdsSectionHeader.mdx +22 -3
  475. package/src/web-components/ui/BdsSectionHeader.stories.tsx +15 -13
  476. package/src/web-components/ui/BdsTable.mdx +23 -2
  477. package/src/web-components/ui/BdsTable.stories.tsx +8 -2
  478. package/src/web-components/ui/BdsTypography.mdx +17 -1
  479. package/src/web-components/ui/bds-alert.spec.ts +17 -2
  480. package/src/web-components/ui/bds-alert.ts +31 -5
  481. package/src/web-components/ui/bds-avatar.spec.ts +29 -0
  482. package/src/web-components/ui/bds-avatar.ts +29 -11
  483. package/src/web-components/ui/bds-badge.spec.ts +5 -0
  484. package/src/web-components/ui/bds-badge.ts +11 -1
  485. package/src/web-components/ui/bds-breadcrumb.spec.ts +30 -0
  486. package/src/web-components/ui/bds-breadcrumb.ts +26 -4
  487. package/src/web-components/ui/bds-button-container.spec.ts +39 -0
  488. package/src/web-components/ui/bds-button-container.ts +123 -0
  489. package/src/web-components/ui/bds-button-group.spec.ts +14 -20
  490. package/src/web-components/ui/bds-button-group.ts +13 -64
  491. package/src/web-components/ui/bds-calendar-range.spec.ts +123 -0
  492. package/src/web-components/ui/bds-calendar-range.ts +307 -0
  493. package/src/web-components/ui/bds-calendar.spec.ts +176 -0
  494. package/src/web-components/ui/bds-calendar.ts +186 -344
  495. package/src/web-components/ui/bds-card.spec.ts +32 -0
  496. package/src/web-components/ui/bds-card.ts +34 -9
  497. package/src/web-components/ui/bds-carousel.spec.ts +147 -0
  498. package/src/web-components/ui/bds-carousel.ts +109 -32
  499. package/src/web-components/ui/bds-description-list.spec.ts +15 -0
  500. package/src/web-components/ui/bds-description-list.ts +37 -3
  501. package/src/web-components/ui/bds-icon-wrapper.spec.ts +12 -0
  502. package/src/web-components/ui/bds-icon-wrapper.ts +15 -14
  503. package/src/web-components/ui/bds-link.spec.ts +17 -0
  504. package/src/web-components/ui/bds-link.ts +26 -11
  505. package/src/web-components/ui/bds-loading.ts +10 -0
  506. package/src/web-components/ui/bds-notification-banner.spec.ts +13 -0
  507. package/src/web-components/ui/bds-notification-banner.ts +18 -1
  508. package/src/web-components/ui/bds-pagination.spec.ts +44 -0
  509. package/src/web-components/ui/bds-pagination.ts +39 -19
  510. package/src/web-components/ui/bds-progress-circle.spec.ts +21 -0
  511. package/src/web-components/ui/bds-progress-circle.ts +17 -5
  512. package/src/web-components/ui/bds-progress.spec.ts +21 -0
  513. package/src/web-components/ui/bds-progress.ts +17 -4
  514. package/src/web-components/ui/bds-rating.spec.ts +6 -0
  515. package/src/web-components/ui/bds-rating.ts +12 -2
  516. package/src/web-components/ui/bds-section-header.spec.ts +39 -8
  517. package/src/web-components/ui/bds-section-header.ts +47 -13
  518. package/src/web-components/ui/bds-separator.ts +10 -0
  519. package/src/web-components/ui/bds-skeleton.ts +10 -0
  520. package/src/web-components/ui/bds-table.spec.ts +63 -0
  521. package/src/web-components/ui/bds-table.ts +88 -28
  522. package/src/web-components/ui/bds-typography.spec.ts +47 -0
  523. package/src/web-components/ui/bds-typography.ts +28 -10
  524. package/src/web-components/ui/calendar-styles.ts +94 -0
  525. package/dist/web-components/chunk-7YURXHTS.js +0 -147
  526. package/dist/web-components/chunk-A3RLT3AS.js +0 -49
  527. package/dist/web-components/chunk-AGKJTMJI.js +0 -56
  528. package/dist/web-components/chunk-BQLZ7I4G.js +0 -56
  529. package/dist/web-components/chunk-DZOEPVFT.js +0 -107
  530. package/dist/web-components/chunk-JYYRJS2D.js +0 -118
  531. package/dist/web-components/chunk-Y4MAXTMA.js +0 -80
  532. package/dist/web-components/chunk-Y7V7LM6R.js +0 -98
  533. package/src/web-components/ui/BdsButtonGroup.mdx +0 -69
  534. package/src/web-components/ui/BdsButtonGroup.stories.tsx +0 -66
@@ -52,4 +52,103 @@ describe('bds-checkbox-group', () => {
52
52
  expect(message?.textContent?.trim()).toBe('Select all that apply');
53
53
  cleanup(el);
54
54
  });
55
+
56
+ it('propagates disabled to slotted bds-checkbox elements', async () => {
57
+ const el = await fixture(
58
+ '<bds-checkbox-group label="Interests" disabled>' +
59
+ '<bds-checkbox value="sports">Sports</bds-checkbox>' +
60
+ '<bds-checkbox value="music">Music</bds-checkbox>' +
61
+ '</bds-checkbox-group>',
62
+ ) as BdsCheckboxGroup;
63
+ await Promise.resolve();
64
+ const checkboxes = Array.from(el.querySelectorAll('bds-checkbox'));
65
+ expect(checkboxes.every(checkbox => checkbox.hasAttribute('disabled'))).toBe(true);
66
+ cleanup(el);
67
+ });
68
+
69
+ it('removes propagated disabled from slotted bds-checkbox elements when re-enabled, keeping individually-disabled ones', async () => {
70
+ const el = await fixture(
71
+ '<bds-checkbox-group label="Interests" disabled>' +
72
+ '<bds-checkbox value="sports">Sports</bds-checkbox>' +
73
+ '<bds-checkbox value="music" disabled>Music</bds-checkbox>' +
74
+ '</bds-checkbox-group>',
75
+ ) as BdsCheckboxGroup;
76
+ await Promise.resolve();
77
+
78
+ el.disabled = false;
79
+ await el.updateComplete;
80
+ await Promise.resolve();
81
+
82
+ const [sports, music] = Array.from(el.querySelectorAll('bds-checkbox'));
83
+ expect(sports.hasAttribute('disabled')).toBe(false);
84
+ expect(music.hasAttribute('disabled')).toBe(true);
85
+ cleanup(el);
86
+ });
87
+
88
+ it('propagates disabled to a bds-checkbox slotted in after the group is already disabled', async () => {
89
+ const el = await fixture('<bds-checkbox-group label="Interests" disabled></bds-checkbox-group>') as BdsCheckboxGroup;
90
+ const checkbox = document.createElement('bds-checkbox');
91
+ checkbox.setAttribute('value', 'sports');
92
+ el.appendChild(checkbox);
93
+ // slotchange fires asynchronously; allow a microtask.
94
+ await new Promise(r => requestAnimationFrame(() => r(null)));
95
+ expect(checkbox.hasAttribute('disabled')).toBe(true);
96
+ cleanup(el);
97
+ });
98
+
99
+ it('exposes a visually-hidden "(required)" text alternative instead of aria-required on the fieldset', async () => {
100
+ const el = await fixture('<bds-checkbox-group label="Test" required></bds-checkbox-group>');
101
+ const fieldset = el.shadowRoot!.querySelector('fieldset')!;
102
+ // aria-required is not supported ARIA on role=group (which is what a bare
103
+ // <fieldset> maps to) — assert it is never set.
104
+ expect(fieldset.hasAttribute('aria-required')).toBe(false);
105
+ const requiredLabel = el.shadowRoot!.querySelector('.requiredLabel');
106
+ expect(requiredLabel?.textContent?.trim()).toBe('(required)');
107
+ cleanup(el);
108
+ });
109
+
110
+ it('omits the required text alternative when not required', async () => {
111
+ const el = await fixture('<bds-checkbox-group label="Test"></bds-checkbox-group>');
112
+ expect(el.shadowRoot!.querySelector('.requiredLabel')).toBeNull();
113
+ cleanup(el);
114
+ });
115
+
116
+ it('wires aria-describedby on the fieldset to the error message id', async () => {
117
+ const el = await fixture('<bds-checkbox-group label="Test" error="Select at least one"></bds-checkbox-group>');
118
+ const fieldset = el.shadowRoot!.querySelector('fieldset')!;
119
+ const message = el.shadowRoot!.querySelector('.message--error')!;
120
+ expect(fieldset.getAttribute('aria-describedby')).toBe(message.id);
121
+ cleanup(el);
122
+ });
123
+
124
+ it('wires aria-describedby on the fieldset to the hint message id', async () => {
125
+ const el = await fixture('<bds-checkbox-group label="Test" hint="Select all that apply"></bds-checkbox-group>');
126
+ const fieldset = el.shadowRoot!.querySelector('fieldset')!;
127
+ const message = el.shadowRoot!.querySelector('.message--hint')!;
128
+ expect(fieldset.getAttribute('aria-describedby')).toBe(message.id);
129
+ cleanup(el);
130
+ });
131
+
132
+ it('omits aria-describedby on the fieldset when there is no error or hint', async () => {
133
+ const el = await fixture('<bds-checkbox-group label="Test"></bds-checkbox-group>');
134
+ const fieldset = el.shadowRoot!.querySelector('fieldset')!;
135
+ expect(fieldset.hasAttribute('aria-describedby')).toBe(false);
136
+ cleanup(el);
137
+ });
138
+
139
+ it('uses medium font-weight token for the legend (not semibold)', () => {
140
+ const styles = BdsCheckboxGroup.styles.toString();
141
+ expect(styles).toContain('--bds-font_weight--medium');
142
+ expect(styles).not.toContain('--bds-font_weight--semibold');
143
+ });
144
+
145
+ it('uses the on-bg error color token for the error message (not the raw error token)', () => {
146
+ const styles = BdsCheckboxGroup.styles.toString();
147
+ expect(styles).toContain('--bds-color_error_on-bg');
148
+ });
149
+
150
+ it('applies :host([disabled]) visual styling for the group', () => {
151
+ const styles = BdsCheckboxGroup.styles.toString();
152
+ expect(styles).toContain(':host([disabled])');
153
+ });
55
154
  });
@@ -1,15 +1,28 @@
1
- import { LitElement, css, html } from 'lit';
1
+ import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
3
  /**
4
4
  * `<bds-checkbox-group>` — groups related checkboxes with a shared label.
5
5
  *
6
6
  * Renders a `<fieldset>` with a `<legend>` for accessible grouping.
7
+ * Propagates `disabled` to slotted `<bds-checkbox>` elements — a shadow-DOM
8
+ * `<fieldset disabled>` has no effect on slotted light-DOM content on its
9
+ * own, so the group attribute is explicitly applied to (and removed from)
10
+ * each child. A checkbox individually marked `disabled` in markup stays
11
+ * disabled even after the group re-enables.
12
+ *
13
+ * `required` is surfaced to assistive tech via a visually-hidden "(required)"
14
+ * text alternative in the legend rather than `aria-required` on the fieldset —
15
+ * `aria-required` is only a supported property on the `checkbox`, `combobox`,
16
+ * `gridcell`, `listbox`, `radiogroup`, `spinbutton`, `textbox` and `tree`
17
+ * roles; a bare `<fieldset>` maps to the generic `group` role, which does not
18
+ * support it (there is no ARIA `checkboxgroup` role), so the attribute would
19
+ * be silently ignored by assistive tech.
7
20
  *
8
21
  * Attributes:
9
22
  * label — visible group label (rendered as `<legend>`)
10
23
  * error — error message shown below items
11
24
  * hint — hint text shown below items
12
- * disabled — disables the entire fieldset
25
+ * disabled — disables the entire fieldset and all slotted `<bds-checkbox>` elements
13
26
  * required — marks the group as required
14
27
  *
15
28
  * Slots:
@@ -23,10 +36,25 @@ import { LitElement, css, html } from 'lit';
23
36
  */
24
37
  export class BdsCheckboxGroup extends LitElement {
25
38
  static styles = css`
39
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
40
+ here; otherwise elements with an explicit size + padding size as
41
+ content-box and layouts drift from the React (light-DOM) versions. */
42
+ :host,
43
+ *,
44
+ *::before,
45
+ *::after {
46
+ box-sizing: border-box;
47
+ }
48
+
26
49
  :host {
27
50
  display: block;
28
51
  }
29
52
 
53
+ :host([disabled]) .legend,
54
+ :host([disabled]) .message {
55
+ opacity: 0.5;
56
+ }
57
+
30
58
  fieldset {
31
59
  border: none;
32
60
  margin: 0;
@@ -36,7 +64,7 @@ export class BdsCheckboxGroup extends LitElement {
36
64
  .legend {
37
65
  font-size: var(--bds-font_size--body--s);
38
66
  font-family: var(--bds-font_family--body);
39
- font-weight: var(--bds-font_weight--semibold);
67
+ font-weight: var(--bds-font_weight--medium);
40
68
  color: var(--bds-color_on-bg);
41
69
  margin-block-end: var(--bds-space_xs);
42
70
  }
@@ -46,6 +74,22 @@ export class BdsCheckboxGroup extends LitElement {
46
74
  margin-inline-start: var(--bds-space_xxxs);
47
75
  }
48
76
 
77
+ /* Visually hidden but still exposed to assistive tech — carries the
78
+ "required" state into the fieldset's accessible name, since the
79
+ visible asterisk above is aria-hidden and aria-required is not
80
+ supported ARIA on a fieldset (role=group). */
81
+ .requiredLabel {
82
+ position: absolute;
83
+ inline-size: 1px;
84
+ block-size: 1px;
85
+ padding: 0;
86
+ margin: -1px;
87
+ overflow: hidden;
88
+ clip: rect(0, 0, 0, 0);
89
+ white-space: nowrap;
90
+ border-width: 0;
91
+ }
92
+
49
93
  .items {
50
94
  display: flex;
51
95
  flex-direction: column;
@@ -59,7 +103,7 @@ export class BdsCheckboxGroup extends LitElement {
59
103
  }
60
104
 
61
105
  .message--error {
62
- color: var(--bds-color_error);
106
+ color: var(--bds-color_error_on-bg);
63
107
  }
64
108
 
65
109
  .message--hint {
@@ -82,6 +126,8 @@ export class BdsCheckboxGroup extends LitElement {
82
126
  declare disabled: boolean;
83
127
  declare required: boolean;
84
128
 
129
+ private readonly _uid = Math.random().toString(36).slice(2, 8);
130
+
85
131
  constructor() {
86
132
  super();
87
133
  this.label = '';
@@ -89,20 +135,60 @@ export class BdsCheckboxGroup extends LitElement {
89
135
  this.required = false;
90
136
  }
91
137
 
138
+ /**
139
+ * Propagates `disabled` to slotted `<bds-checkbox>` elements. Only checkboxes
140
+ * that were enabled before the group disabled them are re-enabled when the
141
+ * group re-enables — a checkbox individually marked `disabled` in markup
142
+ * stays disabled.
143
+ */
144
+ private _propagateDisabled = () => {
145
+ this.querySelectorAll('bds-checkbox').forEach(checkbox => {
146
+ const el = checkbox as HTMLElement;
147
+ if (this.disabled) {
148
+ if (!el.hasAttribute('disabled')) {
149
+ el.setAttribute('data-bds-group-disabled', '');
150
+ }
151
+ el.setAttribute('disabled', '');
152
+ } else if (el.hasAttribute('data-bds-group-disabled')) {
153
+ el.removeAttribute('disabled');
154
+ el.removeAttribute('data-bds-group-disabled');
155
+ }
156
+ });
157
+ };
158
+
159
+ connectedCallback() {
160
+ super.connectedCallback();
161
+ // Propagate after slot content has been parsed
162
+ Promise.resolve().then(this._propagateDisabled);
163
+ }
164
+
165
+ updated(changed: Map<string, unknown>) {
166
+ super.updated(changed);
167
+ if (changed.has('disabled')) {
168
+ this._propagateDisabled();
169
+ }
170
+ }
171
+
92
172
  render() {
173
+ const errorId = `bds-checkbox-group-${this._uid}-error`;
174
+ const hintId = `bds-checkbox-group-${this._uid}-hint`;
175
+ const describedBy = [this.error && errorId, this.hint && hintId].filter(Boolean).join(' ') || undefined;
176
+
93
177
  return html`
94
- <fieldset ?disabled=${this.disabled}>
178
+ <fieldset ?disabled=${this.disabled} aria-describedby=${describedBy ?? nothing}>
95
179
  <legend class="legend">
96
180
  ${this.label}
97
- ${this.required ? html`<span class="required" aria-hidden="true"> *</span>` : ''}
181
+ ${this.required
182
+ ? html`<span class="required" aria-hidden="true"> *</span> <span class="requiredLabel">(required)</span>`
183
+ : ''}
98
184
  </legend>
99
185
  <div class="items">
100
- <slot></slot>
186
+ <slot @slotchange=${this._propagateDisabled}></slot>
101
187
  </div>
102
188
  ${this.error
103
- ? html`<p class="message message--error" role="alert">${this.error}</p>`
189
+ ? html`<p id=${errorId} class="message message--error" role="alert">${this.error}</p>`
104
190
  : this.hint
105
- ? html`<p class="message message--hint">${this.hint}</p>`
191
+ ? html`<p id=${hintId} class="message message--hint">${this.hint}</p>`
106
192
  : ''}
107
193
  </fieldset>
108
194
  `;
@@ -60,4 +60,59 @@ describe('bds-checkbox', () => {
60
60
  it('is form-associated', () => {
61
61
  expect(BdsCheckbox.formAssociated).toBe(true);
62
62
  });
63
+
64
+ it('recomputes required validity when checked changes (not just when required changes)', async () => {
65
+ const setValidity = vi.fn();
66
+ const spy = vi
67
+ .spyOn(HTMLElement.prototype, 'attachInternals')
68
+ .mockReturnValue({ setValidity, setFormValue: vi.fn() } as unknown as ElementInternals);
69
+
70
+ const el = await fixture('<bds-checkbox name="agree" required>Accept</bds-checkbox>') as BdsCheckbox;
71
+ // Initial connect already reports invalid (required + unchecked) — clear that call.
72
+ setValidity.mockClear();
73
+
74
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
75
+ input.checked = true;
76
+ input.dispatchEvent(new Event('change', { bubbles: true }));
77
+ await el.updateComplete;
78
+
79
+ expect(setValidity).toHaveBeenLastCalledWith({});
80
+
81
+ spy.mockRestore();
82
+ cleanup(el);
83
+ });
84
+
85
+ it('reports invalid when a required checkbox becomes unchecked again', async () => {
86
+ const setValidity = vi.fn();
87
+ const spy = vi
88
+ .spyOn(HTMLElement.prototype, 'attachInternals')
89
+ .mockReturnValue({ setValidity, setFormValue: vi.fn() } as unknown as ElementInternals);
90
+
91
+ const el = await fixture('<bds-checkbox name="agree" required checked>Accept</bds-checkbox>') as BdsCheckbox;
92
+ setValidity.mockClear();
93
+
94
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
95
+ input.checked = false;
96
+ input.dispatchEvent(new Event('change', { bubbles: true }));
97
+ await el.updateComplete;
98
+
99
+ expect(setValidity).toHaveBeenLastCalledWith({ valueMissing: true }, 'Required');
100
+
101
+ spy.mockRestore();
102
+ cleanup(el);
103
+ });
104
+
105
+ it('sets aria-invalid on the input when error attribute is set', async () => {
106
+ const el = await fixture('<bds-checkbox name="agree" error>Accept</bds-checkbox>');
107
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
108
+ expect(input.getAttribute('aria-invalid')).toBe('true');
109
+ cleanup(el);
110
+ });
111
+
112
+ it('aria-invalid is false by default', async () => {
113
+ const el = await fixture('<bds-checkbox name="agree">Accept</bds-checkbox>');
114
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
115
+ expect(input.getAttribute('aria-invalid')).toBe('false');
116
+ cleanup(el);
117
+ });
63
118
  });
@@ -13,6 +13,7 @@ import { LitElement, css, html } from 'lit';
13
13
  * checked — boolean; whether the checkbox is checked
14
14
  * required — boolean
15
15
  * disabled — boolean
16
+ * error — boolean; puts the checkbox in an error state (border colour + aria-invalid)
16
17
  *
17
18
  * Slots:
18
19
  * (default) — label text
@@ -27,10 +28,20 @@ export class BdsCheckbox extends LitElement {
27
28
  static formAssociated = true;
28
29
 
29
30
  static styles = css`
31
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
32
+ here; otherwise elements with an explicit size + padding size as
33
+ content-box and layouts drift from the React (light-DOM) versions. */
34
+ :host,
35
+ *,
36
+ *::before,
37
+ *::after {
38
+ box-sizing: border-box;
39
+ }
40
+
30
41
  :host {
31
42
  display: inline-flex;
32
43
  align-items: flex-start;
33
- gap: var(--bds-space_xs);
44
+ gap: var(--checkbox_gap, var(--bds-space_m));
34
45
  cursor: pointer;
35
46
  font-size: var(--bds-font_size--body);
36
47
  font-family: var(--bds-font_family--body);
@@ -45,16 +56,18 @@ export class BdsCheckbox extends LitElement {
45
56
 
46
57
  .input {
47
58
  --inputSize: calc(var(--bds-space_s) * 2);
48
- margin-block-start: 0.25em;
59
+ margin-block-start: var(--checkbox_offset, 0.25em);
49
60
  inline-size: var(--inputSize);
50
61
  block-size: var(--inputSize);
51
62
  flex-shrink: 0;
52
- --bdc_color: var(--checkbox_border-color, currentcolor);
63
+ /* --checkbox_border-color is a deprecated alias — prefer --checkbox_color (matches React) */
64
+ color: var(--checkbox_color, var(--checkbox_border-color, var(--bds-color_on-bg)));
65
+ --bdc_color: currentcolor;
53
66
  --bdc-outline_radius: var(--bds-border_radius--xs);
54
67
 
55
68
  border-radius: var(--checkbox_radius, var(--bdc-outline_radius));
56
69
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--checkbox_shadow, var(--bdc-outline_shadow));
57
- border: none;
70
+ border: var(--checkbox_border, none);
58
71
  appearance: none;
59
72
  background-color: var(--checkbox_color_bg, var(--bds-color_bg));
60
73
  cursor: pointer;
@@ -79,11 +92,19 @@ export class BdsCheckbox extends LitElement {
79
92
  transform: rotate(45deg);
80
93
  }
81
94
 
95
+ .input:focus {
96
+ --bdc_color: var(--bdc_color--focus);
97
+ }
98
+
82
99
  .input:focus-visible {
83
100
  outline: var(--bds-outline_default);
84
101
  outline-offset: var(--bds-outline_offset);
85
102
  }
86
103
 
104
+ :host([error]) .input {
105
+ --bdc_color: var(--bdc_color--error);
106
+ }
107
+
87
108
  label {
88
109
  cursor: pointer;
89
110
  flex: 1;
@@ -96,6 +117,7 @@ export class BdsCheckbox extends LitElement {
96
117
  checked: { type: Boolean, reflect: true },
97
118
  required: { type: Boolean, reflect: true },
98
119
  disabled: { type: Boolean, reflect: true },
120
+ error: { type: Boolean, reflect: true },
99
121
  };
100
122
 
101
123
  declare name: string;
@@ -103,6 +125,7 @@ export class BdsCheckbox extends LitElement {
103
125
  declare checked: boolean;
104
126
  declare required: boolean;
105
127
  declare disabled: boolean;
128
+ declare error: boolean;
106
129
 
107
130
  private _internals!: ElementInternals;
108
131
  private readonly _uid = Math.random().toString(36).slice(2, 8);
@@ -115,6 +138,7 @@ export class BdsCheckbox extends LitElement {
115
138
  this.checked = false;
116
139
  this.required = false;
117
140
  this.disabled = false;
141
+ this.error = false;
118
142
  }
119
143
 
120
144
  updated(changed: Map<string, unknown>) {
@@ -122,7 +146,7 @@ export class BdsCheckbox extends LitElement {
122
146
  if (changed.has('checked') || changed.has('value')) {
123
147
  this._internals.setFormValue?.(this.checked ? this.value : null);
124
148
  }
125
- if (changed.has('required')) {
149
+ if (changed.has('required') || changed.has('checked')) {
126
150
  if (this.required && !this.checked) {
127
151
  this._internals.setValidity?.({ valueMissing: true }, 'Required');
128
152
  } else {
@@ -150,6 +174,7 @@ export class BdsCheckbox extends LitElement {
150
174
  .checked=${this.checked}
151
175
  ?required=${this.required}
152
176
  ?disabled=${this.disabled}
177
+ aria-invalid=${this.error ? 'true' : 'false'}
153
178
  @change=${this._handleChange}
154
179
  />
155
180
  <label for=${id}><slot></slot></label>
@@ -114,4 +114,83 @@ describe('bds-combobox', () => {
114
114
  it('is form-associated', () => {
115
115
  expect(BdsCombobox.formAssociated).toBe(true);
116
116
  });
117
+
118
+ it('associates a visible label with the input via for/id', async () => {
119
+ const el = await fixture(`<bds-combobox name="country" label="Country" options='${OPTIONS}'></bds-combobox>`);
120
+ const label = el.shadowRoot!.querySelector<HTMLLabelElement>('label')!;
121
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
122
+ expect(label).not.toBeNull();
123
+ expect(label.textContent).toBe('Country');
124
+ expect(label.getAttribute('for')).toBe(input.id);
125
+ cleanup(el);
126
+ });
127
+
128
+ it('renders no label when the label attribute is unset', async () => {
129
+ const el = await fixture(`<bds-combobox name="country" options='${OPTIONS}'></bds-combobox>`);
130
+ expect(el.shadowRoot!.querySelector('label')).toBeNull();
131
+ cleanup(el);
132
+ });
133
+
134
+ it('sets aria-controls on the input pointing at the listbox id', async () => {
135
+ const el = await fixture(`<bds-combobox name="country" options='${OPTIONS}'></bds-combobox>`);
136
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
137
+ input.dispatchEvent(new Event('focus'));
138
+ await el.updateComplete;
139
+ const listbox = el.shadowRoot!.querySelector('[role="listbox"]')!;
140
+ expect(input.getAttribute('aria-controls')).toBe(listbox.id);
141
+ cleanup(el);
142
+ });
143
+
144
+ it('sets autocomplete="off" on the input', async () => {
145
+ const el = await fixture(`<bds-combobox name="country" options='${OPTIONS}'></bds-combobox>`);
146
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
147
+ expect(input.getAttribute('autocomplete')).toBe('off');
148
+ cleanup(el);
149
+ });
150
+
151
+ it('updates aria-activedescendant to the focused option id while navigating', async () => {
152
+ const el = await fixture(`<bds-combobox name="country" options='${OPTIONS}'></bds-combobox>`);
153
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
154
+ input.dispatchEvent(new Event('focus'));
155
+ await el.updateComplete;
156
+ expect(input.hasAttribute('aria-activedescendant')).toBe(false);
157
+
158
+ input.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
159
+ await el.updateComplete;
160
+ const options = Array.from(el.shadowRoot!.querySelectorAll('[role="option"]'));
161
+ const focusedOption = options.find(o => o.className.includes('--focused'))!;
162
+ expect(focusedOption).not.toBeUndefined();
163
+ expect(input.getAttribute('aria-activedescendant')).toBe(focusedOption.id);
164
+ cleanup(el);
165
+ });
166
+
167
+ it('gives the no-results item role="presentation" so it is not exposed as an option', async () => {
168
+ const el = await fixture(`<bds-combobox name="country" options='${OPTIONS}'></bds-combobox>`);
169
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
170
+ input.value = 'zzz';
171
+ input.dispatchEvent(new Event('input', { bubbles: true }));
172
+ await el.updateComplete;
173
+ const noResults = el.shadowRoot!.querySelector('.no-results')!;
174
+ expect(noResults.getAttribute('role')).toBe('presentation');
175
+ cleanup(el);
176
+ });
177
+
178
+ it('sets aria-invalid and wires the error message via aria-describedby', async () => {
179
+ const el = await fixture(`<bds-combobox name="country" error="Required field" options='${OPTIONS}'></bds-combobox>`);
180
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
181
+ const error = el.shadowRoot!.querySelector('.message--error')!;
182
+ expect(input.getAttribute('aria-invalid')).toBe('true');
183
+ expect(error.getAttribute('role')).toBe('alert');
184
+ expect(input.getAttribute('aria-describedby')).toBe(error.id);
185
+ cleanup(el);
186
+ });
187
+
188
+ it('wires the hint message via aria-describedby when there is no error', async () => {
189
+ const el = await fixture(`<bds-combobox name="country" hint="Pick a country" options='${OPTIONS}'></bds-combobox>`);
190
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
191
+ const hint = el.shadowRoot!.querySelector('.message--hint')!;
192
+ expect(input.getAttribute('aria-invalid')).toBe('false');
193
+ expect(input.getAttribute('aria-describedby')).toBe(hint.id);
194
+ cleanup(el);
195
+ });
117
196
  });