@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
@@ -46,19 +46,20 @@
46
46
  white-space: nowrap;
47
47
  line-height: 1;
48
48
 
49
- /* Identity tokens — override --button_color + --button_on-color to re-theme */
50
- --button_color: var(--bds-color_interactive);
51
- --button_on-color: var(--bds-color_on-interactive);
52
-
53
- /* Text-safe variant of --button_color for use on page background (outline text/border) */
54
- --button_color--on-bg: var(--bds-color_interactive_on-bg);
55
-
56
49
  /* Layered cascade: the consumer-facing overrides (--button_bg, --button_text,
57
50
  --button_border) are read OUTERMOST so an ancestor-set value always wins
58
51
  over variant + hover defaults. Variants and hover write to the inner
59
- --button_*--variant slot, never to the public tokens. */
60
- background-color: var(--button_bg, var(--button_bg--variant, var(--button_color)));
61
- color: var(--button_text, var(--button_text--variant, var(--button_on-color)));
52
+ --button_*--variant slot, never to the public tokens.
53
+
54
+ Identity tokens (--button_color, --button_on-color, --button_color--on-bg —
55
+ "override --button_color + --button_on-color to re-theme") are intentionally
56
+ NOT declared on this rule. They only ever appear as var() fallbacks (here and
57
+ in the variant/hover rules below), so an ancestor can set them and the value
58
+ inherits through untouched instead of being shadowed by a same-element
59
+ declaration. --button_color--on-bg is the text-safe variant of --button_color
60
+ for use on page background (outline text/border). */
61
+ background-color: var(--button_bg, var(--button_bg--variant, var(--button_color, var(--bds-color_interactive))));
62
+ color: var(--button_text, var(--button_text--variant, var(--button_on-color, var(--bds-color_on-interactive))));
62
63
  --bdc_color: var(--button_border, var(--button_border--variant, transparent));
63
64
 
64
65
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
@@ -74,8 +75,8 @@
74
75
  .button.--outline,
75
76
  .button.--ghost /* @deprecated — use variant="outline" */ {
76
77
  --button_bg--variant: var(--button_bg--outline, transparent);
77
- --button_text--variant: var(--button_text--outline, var(--button_color--on-bg));
78
- --button_border--variant: var(--button_border--outline, var(--button_color--on-bg));
78
+ --button_text--variant: var(--button_text--outline, var(--button_color--on-bg, var(--bds-color_interactive_on-bg)));
79
+ --button_border--variant: var(--button_border--outline, var(--button_color--on-bg, var(--bds-color_interactive_on-bg)));
79
80
  }
80
81
 
81
82
  .button.--size_small {
@@ -180,9 +181,17 @@
180
181
  @media (hover: hover) and (pointer: fine) {
181
182
  .button.--outline:hover,
182
183
  .button.--ghost:hover {
183
- --button_bg--variant: var(--button_bg--outline-hover, var(--button_color));
184
- --button_text--variant: var(--button_text--outline-hover, var(--button_on-color));
184
+ --button_bg--variant: var(--button_bg--outline-hover, var(--button_color, var(--bds-color_interactive)));
185
+ --button_text--variant: var(--button_text--outline-hover, var(--button_on-color, var(--bds-color_on-interactive)));
185
186
  --button_border--variant: var(--button_border--outline-hover, transparent);
186
187
  }
187
188
  }
189
+
190
+ @media (prefers-reduced-motion: reduce) {
191
+ .button.--hasPulse,
192
+ .button:hover .iconStart svg,
193
+ .button:hover .iconEnd svg {
194
+ animation: none;
195
+ }
196
+ }
188
197
  }
@@ -63,4 +63,24 @@ describe('Button', () => {
63
63
  render(<Button>Click</Button>);
64
64
  expect(screen.getByRole('button').className).not.toContain('--iconOnly');
65
65
  });
66
+
67
+ it('keeps the disabled anchor non-tabbable even if a consumer passes tabIndex', () => {
68
+ const { container } = render(
69
+ <Button href="/path" disabled tabIndex={0}>
70
+ Disabled link
71
+ </Button>
72
+ );
73
+ const link = container.querySelector('a');
74
+ expect(link).toHaveAttribute('tabindex', '-1');
75
+ expect(link).toHaveAttribute('aria-disabled', 'true');
76
+ });
77
+
78
+ it('keeps aria-disabled=true on a disabled anchor even if a consumer passes aria-disabled', () => {
79
+ const { container } = render(
80
+ <Button href="/path" disabled aria-disabled={false}>
81
+ Disabled link
82
+ </Button>
83
+ );
84
+ expect(container.querySelector('a')).toHaveAttribute('aria-disabled', 'true');
85
+ });
66
86
  });
@@ -99,6 +99,7 @@ export function Button({
99
99
  if (href) {
100
100
  return (
101
101
  <a
102
+ {...rest}
102
103
  className={classNames}
103
104
  href={disabled ? undefined : href}
104
105
  target={target}
@@ -106,7 +107,6 @@ export function Button({
106
107
  aria-disabled={disabled}
107
108
  tabIndex={disabled ? -1 : undefined}
108
109
  onClick={handleAnchorClick}
109
- {...rest}
110
110
  >
111
111
  {content}
112
112
  </a>
@@ -115,11 +115,11 @@ export function Button({
115
115
 
116
116
  return (
117
117
  <button
118
+ {...rest}
118
119
  type={type}
119
120
  className={classNames}
120
121
  disabled={disabled}
121
122
  onClick={handleButtonClick}
122
- {...rest}
123
123
  >
124
124
  {content}
125
125
  </button>
@@ -32,6 +32,8 @@ Keyboard-first command palette for searching and executing actions. Commonly tri
32
32
  <tr><td>`--command_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Text and icon colour</td></tr>
33
33
  <tr><td>`--command_shadow`</td><td>`var(--bds-shadow_xl)`</td><td>Panel box shadow</td></tr>
34
34
  <tr><td>`--command_border`</td><td>`none`</td><td>Panel border</td></tr>
35
+ <tr><td>`--command_radius`</td><td>`var(--bds-border_radius--m)`</td><td>Panel corner radius</td></tr>
36
+ <tr><td>`--command_kbd-radius`</td><td>`var(--bds-border_radius--xs)`</td><td>Corner radius of the `Esc` hint and shortcut `<kbd>` chips</td></tr>
35
37
  <tr><td>`--command_item-bg--active`</td><td>`var(--bds-color_bg--subtle)`</td><td>Active/highlighted item background</td></tr>
36
38
  </tbody>
37
39
  </table>
@@ -39,8 +41,9 @@ Keyboard-first command palette for searching and executing actions. Commonly tri
39
41
 
40
42
  ## Accessibility
41
43
 
42
- - Input has `role="combobox"` with `aria-controls` pointing to the results list
44
+ - Input has `role="combobox"`, a constant `aria-label="Search commands"` (independent of the `placeholder`), and `aria-controls` pointing to the results list
43
45
  - Results list uses `role="listbox"` with `role="option"` items
44
46
  - `aria-activedescendant` tracks the highlighted option
45
- - Keyboard: `↑`/`↓` to navigate, `Enter` to execute, `Escape` to dismiss
47
+ - Keyboard: `↑`/`↓` to navigate, `Enter` to execute the highlighted result (no-op when there are no results), `Escape` to dismiss
48
+ - A permanently mounted `aria-live="polite"` region announces the no-results state so screen readers reliably pick up the change
46
49
  - Body scroll is locked while open (`overflow: hidden`) and restored on close or unmount
@@ -2,7 +2,7 @@
2
2
  .dialog {
3
3
  padding: 0;
4
4
  border: none;
5
- border-radius: var(--bds-border_radius--m);
5
+ border-radius: var(--command_radius, var(--bds-border_radius--m));
6
6
  background: transparent;
7
7
  inline-size: min(40rem, 90vw);
8
8
  max-block-size: 70vh;
@@ -20,13 +20,13 @@
20
20
  flex-direction: column;
21
21
  background-color: var(--command_color, var(--bds-color_bg));
22
22
  color: var(--command_on-color, var(--bds-color_on-bg));
23
- border-radius: var(--bds-border_radius--m);
24
23
  overflow: hidden;
25
24
  max-block-size: 70vh;
26
25
  border: var(--command_border, none);
27
26
  --bdc_color: currentcolor;
28
27
  --bdc-outline_radius: var(--bds-border_radius--m);
29
28
 
29
+ border-radius: var(--command_radius, var(--bdc-outline_radius));
30
30
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--command_shadow, var(--bds-shadow_xl));
31
31
  }
32
32
 
@@ -49,7 +49,6 @@
49
49
  .search {
50
50
  flex: 1;
51
51
  border: none;
52
- outline: none;
53
52
  font-family: var(--bds-font_family--body);
54
53
  font-size: var(--bds-font_size--body);
55
54
  color: var(--bds-color_on-bg);
@@ -57,6 +56,11 @@
57
56
  min-inline-size: 0;
58
57
  }
59
58
 
59
+ .search:focus-visible {
60
+ outline: var(--bds-outline_default);
61
+ outline-offset: var(--bds-outline_offset);
62
+ }
63
+
60
64
  .search::placeholder {
61
65
  color: var(--bds-color_on-bg);
62
66
  }
@@ -64,8 +68,8 @@
64
68
  .escHint {
65
69
  font-size: var(--bds-font_size--body--s);
66
70
  color: var(--bds-color_on-bg);
67
- border-radius: var(--bds-border_radius--xs);
68
- padding: 0.1em 0.4em;
71
+ border-radius: var(--command_kbd-radius, var(--bds-border_radius--xs));
72
+ padding: var(--bds-space_xxxs) var(--bds-space_xxs);
69
73
  flex-shrink: 0;
70
74
 
71
75
  --bdc_color: currentcolor;
@@ -123,8 +127,8 @@
123
127
  .shortcut {
124
128
  font-size: var(--bds-font_size--body--s);
125
129
  color: var(--bds-color_on-bg);
126
- border-radius: var(--bds-border_radius--xs);
127
- padding: 0.1em 0.4em;
130
+ border-radius: var(--command_kbd-radius, var(--bds-border_radius--xs));
131
+ padding: var(--bds-space_xxxs) var(--bds-space_xxs);
128
132
 
129
133
  --bdc_color: currentcolor;
130
134
 
@@ -138,4 +142,16 @@
138
142
  color: var(--bds-color_on-bg);
139
143
  font-size: var(--bds-font_size--body);
140
144
  }
145
+
146
+ /* Visually hidden but still exposed to assistive tech — used for the
147
+ permanently mounted no-results live region announcement. */
148
+ .srOnly {
149
+ position: absolute;
150
+ inline-size: 1px;
151
+ block-size: 1px;
152
+ overflow: hidden;
153
+ clip: rect(0, 0, 0, 0);
154
+ white-space: nowrap;
155
+ border: 0;
156
+ }
141
157
  }
@@ -59,6 +59,41 @@ describe('Command', () => {
59
59
  expect(screen.getByText('Save current file')).toBeInTheDocument();
60
60
  });
61
61
 
62
+ it('exposes an accessible name on the search input independent of the placeholder', () => {
63
+ render(<Command isOpen items={items} onClose={() => {}} placeholder="Type to search…" />);
64
+ expect(screen.getByRole('combobox')).toHaveAccessibleName('Search commands');
65
+ });
66
+
67
+ it('does not close on Enter when there are no matching results', async () => {
68
+ const onClose = vi.fn();
69
+ render(<Command isOpen items={items} onClose={onClose} />);
70
+ const input = screen.getByRole('combobox');
71
+ await userEvent.type(input, 'zzz');
72
+ expect(screen.getByText(/no results/i)).toBeInTheDocument();
73
+ fireEvent.keyDown(input, { key: 'Enter' });
74
+ expect(onClose).not.toHaveBeenCalled();
75
+ });
76
+
77
+ it('selects and closes on Enter when a result is highlighted', () => {
78
+ const onClose = vi.fn();
79
+ const onSelect = vi.fn();
80
+ const testItems: CommandItem[] = [{ id: 'x', label: 'Action', onSelect }];
81
+ render(<Command isOpen items={testItems} onClose={onClose} />);
82
+ fireEvent.keyDown(screen.getByRole('combobox'), { key: 'Enter' });
83
+ expect(onSelect).toHaveBeenCalledOnce();
84
+ expect(onClose).toHaveBeenCalledOnce();
85
+ });
86
+
87
+ it('announces the no-results state via a persistent live region', async () => {
88
+ render(<Command isOpen items={items} onClose={() => {}} />);
89
+ const liveRegion = document.querySelector('[aria-live="polite"]')!;
90
+ expect(liveRegion).toBeInTheDocument();
91
+ expect(liveRegion).toHaveTextContent('');
92
+
93
+ await userEvent.type(screen.getByRole('combobox'), 'zzz');
94
+ expect(liveRegion).toHaveTextContent(/nothing matches/i);
95
+ });
96
+
62
97
  it('dialog has an id for invoker targeting', () => {
63
98
  render(<Command isOpen items={items} onClose={() => {}} />);
64
99
  expect(document.querySelector('dialog')).toHaveAttribute('id');
@@ -17,7 +17,7 @@ export interface CommandItem {
17
17
  onSelect: () => void;
18
18
  }
19
19
 
20
- interface CommandProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
20
+ export interface CommandProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
21
21
  isOpen: boolean;
22
22
  onOpen?: () => void;
23
23
  onClose: () => void;
@@ -125,8 +125,11 @@ export function Command({
125
125
  setActiveIndex(i => Math.max(i - 1, 0));
126
126
  } else if (e.key === 'Enter') {
127
127
  e.preventDefault();
128
- filtered[activeIndex]?.onSelect();
129
- onClose();
128
+ const item = filtered[activeIndex];
129
+ if (item) {
130
+ item.onSelect();
131
+ onClose();
132
+ }
130
133
  } else if (e.key === 'Escape') {
131
134
  onClose();
132
135
  }
@@ -157,6 +160,7 @@ export function Command({
157
160
  ref={inputRef}
158
161
  type="search"
159
162
  role="combobox"
163
+ aria-label="Search commands"
160
164
  aria-expanded={filtered.length > 0}
161
165
  aria-controls={listboxId}
162
166
  aria-autocomplete="list"
@@ -169,6 +173,13 @@ export function Command({
169
173
  <kbd className={css.escHint}>Esc</kbd>
170
174
  </div>
171
175
 
176
+ {/* Permanently mounted so screen readers reliably announce the
177
+ transition into/out of the no-results state; only its text
178
+ content toggles rather than the region itself mounting/unmounting. */}
179
+ <div className={css.srOnly} aria-live="polite">
180
+ {filtered.length === 0 ? `Nothing matches “${query}”` : ''}
181
+ </div>
182
+
172
183
  {filtered.length > 0 ? (
173
184
  <ul id={listboxId} role="listbox" className={css.list} aria-label="Commands">
174
185
  {Array.from(groups.entries()).map(([group, groupItems]) => (
@@ -199,7 +210,7 @@ export function Command({
199
210
  ))}
200
211
  </ul>
201
212
  ) : (
202
- <div className={css.empty} aria-live="polite">No results for &ldquo;{query}&rdquo;</div>
213
+ <div className={css.empty}>No results for &ldquo;{query}&rdquo;</div>
203
214
  )}
204
215
  </div>
205
216
  </dialog>
@@ -1,2 +1,2 @@
1
1
  export { Command } from './Command';
2
- export type { CommandItem } from './Command';
2
+ export type { CommandItem, CommandProps } from './Command';
@@ -35,9 +35,9 @@ Modal overlay using the native `<dialog>` element. Traps focus inside the dialog
35
35
  <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
36
36
  </thead>
37
37
  <tbody>
38
- <tr><td>`--dialog_color`</td><td>`var(--bds-grey--subtle)`</td><td>Dialog background</td></tr>
39
- <tr><td>`--dialog_on-color`</td><td>`var(--bds-on-grey--subtle)`</td><td>Dialog text colour</td></tr>
40
- <tr><td>`--dialog_backdrop-color`</td><td>`rgb(0 0 0 / 50%)`</td><td>Backdrop overlay colour</td></tr>
38
+ <tr><td>`--dialog_color`</td><td>`var(--bds-color_grey--subtle)`</td><td>Dialog background</td></tr>
39
+ <tr><td>`--dialog_on-color`</td><td>`var(--bds-color_on-grey--subtle)`</td><td>Dialog text colour</td></tr>
40
+ <tr><td>`--color_backdrop`</td><td>`rgb(0 0 0 / 50%)`</td><td>Backdrop overlay colour (shared hook token, not `--dialog_*`-prefixed)</td></tr>
41
41
  </tbody>
42
42
  </table>
43
43
 
@@ -47,7 +47,7 @@ Modal overlay using the native `<dialog>` element. Traps focus inside the dialog
47
47
  - Opens via `showModal()` — provides native focus trapping and `Escape` key to close
48
48
  - Backdrop click calls `onClose`
49
49
  - Body scroll is locked while open (`overflow: hidden`)
50
- - `onClose` is also called on `Escape` via the native `cancel` event
50
+ - `Escape` closes the dialog via the native `cancel` event; when `onClose` is provided (controlled usage) it is called so the parent can sync `isOpen`
51
51
 
52
52
  ## Accessibility
53
53
 
@@ -5,6 +5,8 @@
5
5
  --bdc_color: currentcolor;
6
6
  --bdc-outline_radius: var(--bds-border_radius--m);
7
7
 
8
+ display: flex;
9
+ flex-direction: column;
8
10
  border-radius: var(--dialog_radius, var(--bdc-outline_radius));
9
11
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--dialog_shadow, var(--bdc-outline_shadow));
10
12
  background-color: var(--dialog_color ,var(--bds-color_grey--subtle));
@@ -12,9 +14,18 @@
12
14
  padding: var(--bds-space_l);
13
15
  max-inline-size: 90svw;
14
16
  max-block-size: 90svh;
17
+
18
+ /* visible (not hidden) so the close button, offset outside the box via
19
+ inset-*: -1em, is never clipped; .dialogContent scrolls internally. */
15
20
  overflow: visible;
16
21
  }
17
22
 
23
+ /* A native <dialog> is display:none until opened; the flex layout above
24
+ would otherwise override the UA rule and render the dialog permanently. */
25
+ .dialog:not([open]) {
26
+ display: none;
27
+ }
28
+
18
29
  .dialogContent {
19
30
  display: grid;
20
31
  gap: var(--bds-grid_gap);
@@ -43,6 +54,15 @@
43
54
  cursor: pointer;
44
55
  }
45
56
 
57
+ /* Extend the hit area to the 44x44px minimum touch target (WCAG 2.5.5)
58
+ without growing the visual 2em disc. */
59
+ .closeButton::after {
60
+ content: '';
61
+ position: absolute;
62
+ inset-block: -0.5rem;
63
+ inset-inline: -0.5rem;
64
+ }
65
+
46
66
  .closeButton:focus-visible {
47
67
  outline: var(--bds-outline_default);
48
68
  outline-offset: var(--bds-outline_offset);
@@ -103,6 +103,26 @@ describe('Dialog', () => {
103
103
  document.body.removeChild(trigger);
104
104
  });
105
105
 
106
+ describe('cancel event (Escape key)', () => {
107
+ it('does not block the native Escape close when onClose is not provided', () => {
108
+ render(<Dialog isOpen><span>Content</span></Dialog>);
109
+ const dialog = document.querySelector('dialog')!;
110
+ const event = new Event('cancel', { cancelable: true });
111
+ dialog.dispatchEvent(event);
112
+ expect(event.defaultPrevented).toBe(false);
113
+ });
114
+
115
+ it('prevents the native close and calls onClose on Escape when controlled', () => {
116
+ const onClose = vi.fn();
117
+ render(<Dialog isOpen onClose={onClose}><span>Content</span></Dialog>);
118
+ const dialog = document.querySelector('dialog')!;
119
+ const event = new Event('cancel', { cancelable: true });
120
+ dialog.dispatchEvent(event);
121
+ expect(event.defaultPrevented).toBe(true);
122
+ expect(onClose).toHaveBeenCalled();
123
+ });
124
+ });
125
+
106
126
  describe('command event (Invoker Commands API)', () => {
107
127
  function makeCommandEvent(command: string) {
108
128
  const event = new Event('command');
@@ -9,7 +9,7 @@ import css from './Dialog.module.css';
9
9
  import { cn } from '@boostdev/design-system-foundation';
10
10
  import type { WithClassName } from '../../../types';
11
11
 
12
- interface DialogProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
12
+ export interface DialogProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
13
13
  isOpen?: boolean;
14
14
  onOpen?: () => void;
15
15
  onClose?: () => void;
@@ -69,8 +69,13 @@ export function Dialog({ children, id: idProp, isOpen = false, className, onOpen
69
69
  };
70
70
 
71
71
  const handleCancel = (e: React.SyntheticEvent) => {
72
- e.preventDefault();
73
- onClose?.();
72
+ // Only suppress the native close-on-Escape when the component is actually
73
+ // controlled — otherwise preventDefault() would leave Escape permanently
74
+ // dead in uncontrolled/invoker-only usage (no onClose to sync state).
75
+ if (onClose) {
76
+ e.preventDefault();
77
+ onClose();
78
+ }
74
79
  };
75
80
 
76
81
  const handleKeyDown = (e: React.KeyboardEvent<HTMLDialogElement>) => {
@@ -1 +1,2 @@
1
1
  export { Dialog } from './Dialog';
2
+ export type { DialogProps } from './Dialog';
@@ -38,6 +38,7 @@ Slide-in panel from the left or right edge of the viewport. Use for navigation,
38
38
  <tbody>
39
39
  <tr><td>`--drawer_color`</td><td>`var(--bds-color_bg)`</td><td>Panel background colour</td></tr>
40
40
  <tr><td>`--drawer_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
41
+ <tr><td>`--drawer_shadow`</td><td>`var(--bds-shadow_xl)`</td><td>Panel drop shadow</td></tr>
41
42
  <tr><td>`--drawer_close-radius`</td><td>`var(--bds-border_radius--circle)`</td><td>Close button border radius</td></tr>
42
43
  <tr><td>`--drawer_close-bg--hover`</td><td>`var(--bds-color_bg--subtle)`</td><td>Close button background on hover</td></tr>
43
44
  </tbody>
@@ -46,6 +47,8 @@ Slide-in panel from the left or right edge of the viewport. Use for navigation,
46
47
 
47
48
  ## Accessibility
48
49
 
49
- - Uses `<dialog>` internally — provides native focus trapping and `Escape` to close
50
- - `aria-label` on the dialog describes the drawer's purpose
50
+ - Uses `<dialog>` internally — opened via `showModal()`, which sets `aria-modal="true"` and moves focus inside automatically
51
+ - `Tab`/`Shift+Tab` are explicitly trapped within the drawer's focusable elements while open
52
+ - The `title` is wired to the dialog via `aria-labelledby` automatically, giving the drawer an accessible name — unless the consumer supplies their own `aria-label`/`aria-labelledby`, which takes priority
53
+ - Backdrop click and `Escape` both call `onClose` (backdrop detection uses `event.target`, so keyboard-activated clicks on inner controls never close the drawer)
51
54
  - Body scroll locked while open
@@ -14,7 +14,7 @@
14
14
  background-color: var(--drawer_color, var(--bds-color_bg));
15
15
  color: var(--drawer_on-color, var(--bds-color_on-bg));
16
16
  border: none;
17
- box-shadow: var(--bds-shadow_xl);
17
+ box-shadow: var(--drawer_shadow, var(--bds-shadow_xl));
18
18
  overflow: hidden;
19
19
  translate: 100% 0;
20
20
  transition:
@@ -23,11 +23,34 @@
23
23
  overlay var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete;
24
24
  }
25
25
 
26
+ /* Closed native <dialog> must be display:none — the flex layout above would
27
+ otherwise keep it rendered (off-screen, focusable, causing overflow). The
28
+ display/overlay allow-discrete transitions above animate the none↔flex. */
29
+ .drawer:not([open]) {
30
+ display: none;
31
+ }
32
+
33
+ /*
34
+ * `translate` is a physical transform — it always moves along the physical
35
+ * x-axis, regardless of writing direction. Because `side="right"` is
36
+ * positioned with the logical `inset-inline-end` (which flips to the
37
+ * physical left edge in RTL), the off-screen translate direction must flip
38
+ * to match, or the panel slides the wrong way and never leaves the
39
+ * viewport. `:dir(rtl)` inverts both sides' resting translate value.
40
+ */
41
+ .drawer:dir(rtl) {
42
+ translate: -100% 0;
43
+ }
44
+
26
45
  .--side_left.drawer {
27
46
  inset-inline: 0 auto;
28
47
  translate: -100% 0;
29
48
  }
30
49
 
50
+ .--side_left.drawer:dir(rtl) {
51
+ translate: 100% 0;
52
+ }
53
+
31
54
  .drawer[open] {
32
55
  translate: 0 0;
33
56
  }
@@ -37,9 +60,17 @@
37
60
  translate: 100% 0;
38
61
  }
39
62
 
63
+ .drawer[open]:dir(rtl) {
64
+ translate: -100% 0;
65
+ }
66
+
40
67
  .--side_left.drawer[open] {
41
68
  translate: -100% 0;
42
69
  }
70
+
71
+ .--side_left.drawer[open]:dir(rtl) {
72
+ translate: 100% 0;
73
+ }
43
74
  }
44
75
 
45
76
  .drawer::backdrop {
@@ -76,8 +107,8 @@
76
107
  display: flex;
77
108
  align-items: center;
78
109
  justify-content: center;
79
- inline-size: 2rem;
80
- block-size: 2rem;
110
+ inline-size: 2.75rem;
111
+ block-size: 2.75rem;
81
112
  border-radius: var(--drawer_close-radius, var(--bds-border_radius--circle));
82
113
  cursor: pointer;
83
114
  transition: var(--bds-animation_transition);
@@ -1,4 +1,4 @@
1
- import { render, screen } from '@testing-library/react';
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import { Drawer } from './Drawer';
4
4
 
@@ -109,6 +109,72 @@ describe('Drawer', () => {
109
109
  document.body.removeChild(trigger);
110
110
  });
111
111
 
112
+ it('closes when the backdrop (the dialog element itself) is clicked', () => {
113
+ const onClose = vi.fn();
114
+ render(<Drawer isOpen title="Menu" onClose={onClose}>Content</Drawer>);
115
+ const dialog = document.querySelector('dialog')!;
116
+ fireEvent.click(dialog);
117
+ expect(onClose).toHaveBeenCalledOnce();
118
+ });
119
+
120
+ it('does not close when a keyboard-activated control inside the drawer is clicked', () => {
121
+ const onClose = vi.fn();
122
+ render(
123
+ <Drawer isOpen title="Menu" onClose={onClose}>
124
+ <button type="button">Inner action</button>
125
+ </Drawer>,
126
+ );
127
+ const innerButton = screen.getByRole('button', { name: 'Inner action' });
128
+ // Keyboard-activated clicks report clientX/clientY at 0,0 — a coordinate-based
129
+ // backdrop check would incorrectly treat this as "outside" the panel.
130
+ fireEvent.click(innerButton, { clientX: 0, clientY: 0 });
131
+ expect(onClose).not.toHaveBeenCalled();
132
+ });
133
+
134
+ it('associates the title with the dialog via aria-labelledby', () => {
135
+ render(<Drawer isOpen title="Settings" onClose={() => {}}>Content</Drawer>);
136
+ const dialog = document.querySelector('dialog')!;
137
+ const labelledBy = dialog.getAttribute('aria-labelledby');
138
+ expect(labelledBy).toBeTruthy();
139
+ expect(document.getElementById(labelledBy!)).toHaveTextContent('Settings');
140
+ });
141
+
142
+ it('does not set aria-labelledby when the consumer supplies aria-label', () => {
143
+ render(<Drawer isOpen title="Settings" aria-label="Custom label" onClose={() => {}}>Content</Drawer>);
144
+ const dialog = document.querySelector('dialog')!;
145
+ expect(dialog).not.toHaveAttribute('aria-labelledby');
146
+ });
147
+
148
+ it('wraps Tab focus from the last focusable element back to the first', () => {
149
+ render(
150
+ <Drawer isOpen title="Menu" onClose={() => {}}>
151
+ <button type="button">First</button>
152
+ <button type="button">Last</button>
153
+ </Drawer>,
154
+ );
155
+ const dialog = document.querySelector('dialog')!;
156
+ const closeButton = screen.getByRole('button', { name: 'Close drawer' });
157
+ const last = screen.getByRole('button', { name: 'Last' });
158
+ last.focus();
159
+ fireEvent.keyDown(dialog, { key: 'Tab' });
160
+ expect(document.activeElement).toBe(closeButton);
161
+ });
162
+
163
+ it('wraps Shift+Tab focus from the first focusable element to the last', () => {
164
+ render(
165
+ <Drawer isOpen title="Menu" onClose={() => {}}>
166
+ <button type="button">First</button>
167
+ <button type="button">Last</button>
168
+ </Drawer>,
169
+ );
170
+ const dialog = document.querySelector('dialog')!;
171
+ const closeButton = screen.getByRole('button', { name: 'Close drawer' });
172
+ const last = screen.getByRole('button', { name: 'Last' });
173
+ closeButton.focus();
174
+ fireEvent.keyDown(dialog, { key: 'Tab', shiftKey: true });
175
+ expect(document.activeElement).toBe(last);
176
+ });
177
+
112
178
  describe('command event (Invoker Commands API)', () => {
113
179
  function makeCommandEvent(command: string) {
114
180
  const event = new Event('command');