@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
@@ -7,8 +7,11 @@ import { LitElement, css, html } from 'lit';
7
7
  *
8
8
  * Attributes:
9
9
  * open — boolean; controlled open state
10
- * name — groups multiple collapsibles so only one is open at a time
11
- * (native <details name="…"> behaviour)
10
+ * name — groups multiple collapsibles so only one is open at a time.
11
+ * Each instance renders its own <details> in its own shadow root, so
12
+ * native <details name> grouping (tree-scoped) can't see across
13
+ * instances; the component emulates it by closing same-name siblings
14
+ * found via document.querySelectorAll() whenever one opens.
12
15
  *
13
16
  * Slots:
14
17
  * summary — the always-visible trigger text
@@ -26,6 +29,16 @@ import { LitElement, css, html } from 'lit';
26
29
  */
27
30
  export class BdsCollapsible extends LitElement {
28
31
  static styles = css`
32
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
33
+ here; otherwise elements with an explicit size + padding size as
34
+ content-box and layouts drift from the React (light-DOM) versions. */
35
+ :host,
36
+ *,
37
+ *::before,
38
+ *::after {
39
+ box-sizing: border-box;
40
+ }
41
+
29
42
  :host {
30
43
  display: block;
31
44
  }
@@ -91,7 +104,9 @@ export class BdsCollapsible extends LitElement {
91
104
 
92
105
  .content {
93
106
  padding: var(--bds-space_m);
94
- background-color: var(--collapsible_content-bg, var(--bds-color_bg));
107
+ /* React counterpart leaves the content panel transparent; keep the override
108
+ hook for consumers but default it to match, not to --bds-color_bg. */
109
+ background-color: var(--collapsible_content-bg, transparent);
95
110
  color: var(--collapsible_on-color, var(--bds-color_on-bg));
96
111
  font-size: var(--bds-font_size--body);
97
112
  line-height: var(--bds-font_line-height--body);
@@ -131,20 +146,47 @@ export class BdsCollapsible extends LitElement {
131
146
  }
132
147
  }
133
148
  }
149
+
150
+ // Emulate native <details name="…"> exclusive-open grouping ourselves: each
151
+ // bds-collapsible renders its own <details> inside its own shadow root, so the
152
+ // browser's built-in name-based grouping is tree-scoped per shadow root and never
153
+ // sees siblings. Whenever this instance opens, close any other open member of the
154
+ // same group.
155
+ if (changed.has('open') && this.open && this.name) {
156
+ this._closeOtherGroupMembers();
157
+ }
134
158
  }
135
159
 
136
- private _onToggle(e: Event) {
137
- const details = e.currentTarget as HTMLDetailsElement;
138
- this.open = details.open;
160
+ private _closeOtherGroupMembers() {
161
+ const groupName = this.name;
162
+ document.querySelectorAll('bds-collapsible').forEach((el) => {
163
+ if (el !== this && el.name === groupName && el.open) {
164
+ el._setOpen(false);
165
+ }
166
+ });
167
+ }
168
+
169
+ // State-guarded setter: returns early once already in the target state so a
170
+ // native <details> "toggle" event re-fired by the browser after a script-driven
171
+ // attribute change (see the toggle event spec's coalescing note) never dispatches
172
+ // a redundant bds-toggle.
173
+ private _setOpen(newOpen: boolean) {
174
+ if (this.open === newOpen) return;
175
+ this.open = newOpen;
139
176
  this.dispatchEvent(
140
177
  new CustomEvent('bds-toggle', {
141
178
  bubbles: true,
142
179
  composed: true,
143
- detail: { open: this.open },
180
+ detail: { open: newOpen },
144
181
  }),
145
182
  );
146
183
  }
147
184
 
185
+ private _onToggle(e: Event) {
186
+ const details = e.currentTarget as HTMLDetailsElement;
187
+ this._setOpen(details.open);
188
+ }
189
+
148
190
  render() {
149
191
  return html`
150
192
  <details
@@ -116,4 +116,53 @@ describe('bds-dialog', () => {
116
116
  expect(el.querySelector('p')!.textContent).toBe('Hello world');
117
117
  cleanup(el);
118
118
  });
119
+
120
+ it('responds to the --show-modal custom command', async () => {
121
+ const el = await fixture('<bds-dialog><p>Content</p></bds-dialog>') as BdsDialog;
122
+ expect(el.open).toBeFalsy();
123
+ el.dispatchEvent(makeCommandEvent('--show-modal'));
124
+ await el.updateComplete;
125
+ expect(el.open).toBe(true);
126
+ expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled();
127
+ cleanup(el);
128
+ });
129
+
130
+ it('responds to the --close custom command', async () => {
131
+ const el = await fixture('<bds-dialog open><p>Content</p></bds-dialog>') as BdsDialog;
132
+ el.dispatchEvent(makeCommandEvent('--close'));
133
+ await el.updateComplete;
134
+ expect(el.open).toBe(false);
135
+ expect(HTMLDialogElement.prototype.close).toHaveBeenCalled();
136
+ cleanup(el);
137
+ });
138
+
139
+ it('releases the body scroll lock when disconnected while open', async () => {
140
+ const el = await fixture('<bds-dialog open><p>Content</p></bds-dialog>') as BdsDialog;
141
+ expect(document.body.style.overflow).toBe('hidden');
142
+ el.remove();
143
+ expect(document.body.style.overflow).toBe('');
144
+ });
145
+
146
+ it('forwards host aria-label to the shadow dialog', async () => {
147
+ const el = await fixture('<bds-dialog aria-label="Confirm deletion"><p>Content</p></bds-dialog>');
148
+ const dialog = el.shadowRoot!.querySelector('dialog')!;
149
+ expect(dialog.getAttribute('aria-label')).toBe('Confirm deletion');
150
+ cleanup(el);
151
+ });
152
+
153
+ it('omits aria-label on the shadow dialog when unset', async () => {
154
+ const el = await fixture('<bds-dialog><p>Content</p></bds-dialog>');
155
+ const dialog = el.shadowRoot!.querySelector('dialog')!;
156
+ expect(dialog.hasAttribute('aria-label')).toBe(false);
157
+ cleanup(el);
158
+ });
159
+
160
+ it('lays out the dialog as a flex column so dialog-content can scroll internally', () => {
161
+ expect(BdsDialog.styles.cssText).toMatch(/\.dialog\s*{[^}]*display:\s*flex/);
162
+ expect(BdsDialog.styles.cssText).toMatch(/\.dialog\s*{[^}]*flex-direction:\s*column/);
163
+ });
164
+
165
+ it('close button has a :focus-visible outline rule', () => {
166
+ expect(BdsDialog.styles.cssText).toMatch(/\.close-button:focus-visible\s*{[^}]*outline:/);
167
+ });
119
168
  });
@@ -1,4 +1,4 @@
1
- import { LitElement, css, html } from 'lit';
1
+ import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
3
  const FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
4
4
 
@@ -7,10 +7,13 @@ const FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabi
7
7
  *
8
8
  * Wraps a native `<dialog>` element with `showModal()` / `close()` lifecycle,
9
9
  * backdrop-click to dismiss, Escape key handling, Tab focus trapping, and
10
- * the Invoker Commands API (`command="show-modal"` / `command="close"`).
10
+ * the Invoker Commands API (custom commands `--show-modal` / `--close`; the
11
+ * unprefixed `show-modal` / `close` values are still accepted for
12
+ * compatibility with polyfilled/legacy environments).
11
13
  *
12
14
  * Attributes:
13
15
  * open — boolean; controlled open state (syncs to native showModal/close)
16
+ * aria-label — accessible name forwarded to the inner shadow <dialog>
14
17
  *
15
18
  * Slots:
16
19
  * (default) — dialog content
@@ -20,13 +23,23 @@ const FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabi
20
23
  * bds-close — fired (bubbles, composed) when the dialog closes
21
24
  *
22
25
  * @example
23
- * <bds-dialog id="my-dialog">
26
+ * <bds-dialog id="my-dialog" aria-label="Confirm deletion">
24
27
  * <p>Dialog content</p>
25
28
  * </bds-dialog>
26
- * <button commandfor="my-dialog" command="show-modal">Open</button>
29
+ * <button commandfor="my-dialog" command="--show-modal">Open</button>
27
30
  */
28
31
  export class BdsDialog extends LitElement {
29
32
  static styles = css`
33
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
34
+ here; otherwise elements with an explicit size + padding size as
35
+ content-box and layouts drift from the React (light-DOM) versions. */
36
+ :host,
37
+ *,
38
+ *::before,
39
+ *::after {
40
+ box-sizing: border-box;
41
+ }
42
+
30
43
  :host {
31
44
  display: contents;
32
45
  }
@@ -34,9 +47,11 @@ export class BdsDialog extends LitElement {
34
47
  .dialog {
35
48
  font-size: var(--bds-font_size--body--s);
36
49
  border: var(--dialog_border, none);
37
- --bdc_color: var(--dialog_border-color, currentcolor);
50
+ --bdc_color: currentcolor;
38
51
  --bdc-outline_radius: var(--bds-border_radius--m);
39
52
 
53
+ display: flex;
54
+ flex-direction: column;
40
55
  border-radius: var(--dialog_radius, var(--bdc-outline_radius));
41
56
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--dialog_shadow, var(--bdc-outline_shadow));
42
57
  background-color: var(--dialog_color, var(--bds-color_grey--subtle));
@@ -44,10 +59,19 @@ export class BdsDialog extends LitElement {
44
59
  padding: var(--bds-space_l);
45
60
  max-inline-size: 90svw;
46
61
  max-block-size: 90svh;
62
+
63
+ /* visible (not hidden) so the close button, offset outside the box via
64
+ inset-*: -1em, is never clipped; .dialog-content scrolls internally. */
47
65
  overflow: visible;
48
66
  position: relative;
49
67
  }
50
68
 
69
+ /* A native <dialog> is display:none until opened; the flex layout above
70
+ would otherwise override the UA rule and render the dialog permanently. */
71
+ .dialog:not([open]) {
72
+ display: none;
73
+ }
74
+
51
75
  .dialog-content {
52
76
  display: grid;
53
77
  gap: var(--bds-grid_gap);
@@ -70,12 +94,26 @@ export class BdsDialog extends LitElement {
70
94
  background-color: var(--bds-color_bg);
71
95
  color: currentcolor;
72
96
  border: var(--dialog_close-border, none);
73
- --bdc_color: var(--dialog_close-border-color, currentcolor);
97
+ --bdc_color: currentcolor;
74
98
 
75
99
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
76
100
  cursor: pointer;
77
101
  }
78
102
 
103
+ /* Extend the hit area to the 44x44px minimum touch target (WCAG 2.5.5)
104
+ without growing the visual 2em disc. */
105
+ .close-button::after {
106
+ content: '';
107
+ position: absolute;
108
+ inset-block: -0.5rem;
109
+ inset-inline: -0.5rem;
110
+ }
111
+
112
+ .close-button:focus-visible {
113
+ outline: var(--bds-outline_default);
114
+ outline-offset: var(--bds-outline_offset);
115
+ }
116
+
79
117
  .close-button svg {
80
118
  inline-size: 1.25em;
81
119
  block-size: 1.25em;
@@ -88,16 +126,19 @@ export class BdsDialog extends LitElement {
88
126
  `;
89
127
 
90
128
  static properties = {
91
- open: { type: Boolean, reflect: true },
129
+ open: { type: Boolean, reflect: true },
130
+ ariaLabel: { type: String, attribute: 'aria-label' },
92
131
  };
93
132
 
94
133
  declare open: boolean;
134
+ declare ariaLabel: string | null;
95
135
 
96
136
  private _triggerEl: Element | null = null;
97
137
 
98
138
  constructor() {
99
139
  super();
100
140
  this.open = false;
141
+ this.ariaLabel = null;
101
142
  }
102
143
 
103
144
  connectedCallback() {
@@ -108,6 +149,13 @@ export class BdsDialog extends LitElement {
108
149
  disconnectedCallback() {
109
150
  super.disconnectedCallback();
110
151
  this.removeEventListener('command', this._onCommand);
152
+ // Release the body scroll-lock if the dialog is removed from the DOM
153
+ // while still open — otherwise the lock leaks and the page stays
154
+ // non-scrollable forever.
155
+ if (this.open) {
156
+ document.body.style.overflow = '';
157
+ this._triggerEl = null;
158
+ }
111
159
  }
112
160
 
113
161
  updated(changed: Map<string, unknown>) {
@@ -134,8 +182,12 @@ export class BdsDialog extends LitElement {
134
182
 
135
183
  private _onCommand = (e: Event) => {
136
184
  const command = (e as CommandEvent).command;
137
- if (command === 'show-modal') this._openDialog();
138
- else if (command === 'close') this._closeDialog();
185
+ // Custom (`--`-prefixed) commands are what the Invoker Commands API
186
+ // actually dispatches on a non-<dialog> custom-element target — the
187
+ // unprefixed "show-modal"/"close" keywords are still accepted so
188
+ // programmatic dispatches and polyfilled environments keep working.
189
+ if (command === '--show-modal' || command === 'show-modal') this._openDialog();
190
+ else if (command === '--close' || command === 'close') this._closeDialog();
139
191
  };
140
192
 
141
193
  private _openDialog() {
@@ -178,10 +230,14 @@ export class BdsDialog extends LitElement {
178
230
  if (all.length === 0) return;
179
231
  const first = all[0];
180
232
  const last = all[all.length - 1];
233
+ // Focus inside the shadow tree (e.g. the close button) resolves via
234
+ // shadowRoot.activeElement — document.activeElement only ever reports
235
+ // the host element for shadow-internal focus.
236
+ const active = this.shadowRoot?.activeElement ?? document.activeElement;
181
237
  if (e.shiftKey) {
182
- if (document.activeElement === first) { e.preventDefault(); last.focus(); }
238
+ if (active === first) { e.preventDefault(); last.focus(); }
183
239
  } else {
184
- if (document.activeElement === last) { e.preventDefault(); first.focus(); }
240
+ if (active === last) { e.preventDefault(); first.focus(); }
185
241
  }
186
242
  }
187
243
 
@@ -190,6 +246,7 @@ export class BdsDialog extends LitElement {
190
246
  <dialog
191
247
  class="dialog"
192
248
  aria-modal="true"
249
+ aria-label=${this.ariaLabel ?? nothing}
193
250
  @click=${this._handleBackdropClick}
194
251
  @cancel=${this._handleCancel}
195
252
  @keydown=${this._handleKeydown}
@@ -71,24 +71,33 @@ describe('bds-drawer', () => {
71
71
  cleanup(el);
72
72
  });
73
73
 
74
- it('fires bds-open on show-modal command', async () => {
74
+ it('fires bds-open on --show-modal command', async () => {
75
75
  const el = await fixture('<bds-drawer><p>Content</p></bds-drawer>');
76
76
  const handler = vi.fn();
77
77
  el.addEventListener('bds-open', handler);
78
- el.dispatchEvent(makeCommandEvent('show-modal'));
78
+ el.dispatchEvent(makeCommandEvent('--show-modal'));
79
79
  expect(handler).toHaveBeenCalledOnce();
80
80
  cleanup(el);
81
81
  });
82
82
 
83
- it('fires bds-close on close command', async () => {
83
+ it('fires bds-close on --close command', async () => {
84
84
  const el = await fixture('<bds-drawer open><p>Content</p></bds-drawer>');
85
85
  const handler = vi.fn();
86
86
  el.addEventListener('bds-close', handler);
87
- el.dispatchEvent(makeCommandEvent('close'));
87
+ el.dispatchEvent(makeCommandEvent('--close'));
88
88
  expect(handler).toHaveBeenCalledOnce();
89
89
  cleanup(el);
90
90
  });
91
91
 
92
+ it('ignores the reserved built-in "show-modal"/"close" command values (never fire on custom elements)', async () => {
93
+ const el = await fixture('<bds-drawer><p>Content</p></bds-drawer>');
94
+ const openHandler = vi.fn();
95
+ el.addEventListener('bds-open', openHandler);
96
+ el.dispatchEvent(makeCommandEvent('show-modal'));
97
+ expect(openHandler).not.toHaveBeenCalled();
98
+ cleanup(el);
99
+ });
100
+
92
101
  it('close button click fires bds-close', async () => {
93
102
  const el = await fixture('<bds-drawer open><p>Content</p></bds-drawer>');
94
103
  const handler = vi.fn();
@@ -110,4 +119,84 @@ describe('bds-drawer', () => {
110
119
  expect(el.querySelector('p')!.textContent).toBe('Body content');
111
120
  cleanup(el);
112
121
  });
122
+
123
+ it('releases body scroll lock when disconnected while open', async () => {
124
+ const el = await fixture('<bds-drawer open><p>Content</p></bds-drawer>');
125
+ expect(document.body.style.overflow).toBe('hidden');
126
+ cleanup(el);
127
+ expect(document.body.style.overflow).toBe('');
128
+ });
129
+
130
+ it('does not touch body scroll when disconnected while closed', async () => {
131
+ const el = await fixture('<bds-drawer><p>Content</p></bds-drawer>');
132
+ document.body.style.overflow = 'hidden';
133
+ cleanup(el);
134
+ expect(document.body.style.overflow).toBe('hidden');
135
+ document.body.style.overflow = '';
136
+ });
137
+
138
+ it('wires aria-labelledby to the title element by default', async () => {
139
+ const el = await fixture('<bds-drawer><span slot="title">Settings</span></bds-drawer>');
140
+ const dialog = el.shadowRoot!.querySelector('dialog')!;
141
+ expect(dialog.getAttribute('aria-labelledby')).toBe('title');
142
+ expect(dialog.hasAttribute('aria-label')).toBe(false);
143
+ const titleEl = el.shadowRoot!.querySelector('#title');
144
+ expect(titleEl).not.toBeNull();
145
+ cleanup(el);
146
+ });
147
+
148
+ it('forwards a host aria-label as an override, dropping aria-labelledby', async () => {
149
+ const el = await fixture('<bds-drawer aria-label="Custom name"><span slot="title">Settings</span></bds-drawer>');
150
+ const dialog = el.shadowRoot!.querySelector('dialog')!;
151
+ expect(dialog.getAttribute('aria-label')).toBe('Custom name');
152
+ expect(dialog.hasAttribute('aria-labelledby')).toBe(false);
153
+ cleanup(el);
154
+ });
155
+
156
+ it('closes when the backdrop (dialog element itself) is clicked', async () => {
157
+ const el = await fixture('<bds-drawer open><p>Content</p></bds-drawer>');
158
+ const handler = vi.fn();
159
+ el.addEventListener('bds-close', handler);
160
+ const dialog = el.shadowRoot!.querySelector('dialog')!;
161
+ dialog.dispatchEvent(new MouseEvent('click', { bubbles: true }));
162
+ expect(handler).toHaveBeenCalledOnce();
163
+ cleanup(el);
164
+ });
165
+
166
+ it('does not close when an inner control is clicked, including a synthetic keyboard-activation click at 0,0 (target !== dialog)', async () => {
167
+ // Regression test: the previous implementation compared e.clientX/clientY
168
+ // against the panel's bounding rect, so a keyboard-activated synthetic
169
+ // click (dispatched at 0,0) on an inner control was misclassified as an
170
+ // "outside" backdrop click and closed the drawer. Coordinates must no
171
+ // longer matter — only event.target identity.
172
+ const el = await fixture('<bds-drawer open><p>Content</p></bds-drawer>');
173
+ const handler = vi.fn();
174
+ el.addEventListener('bds-close', handler);
175
+ const header = el.shadowRoot!.querySelector('.header')!;
176
+ header.dispatchEvent(new MouseEvent('click', { bubbles: true, clientX: 0, clientY: 0 }));
177
+ expect(handler).not.toHaveBeenCalled();
178
+ cleanup(el);
179
+ });
180
+
181
+ it('Tab focus trap treats slotted body elements as part of the trap boundary', async () => {
182
+ // Regression test: previously the trap only queried the shadow tree, so
183
+ // `all` was just [close-button] and slotted light-DOM buttons were never
184
+ // reachable as the wrap boundary.
185
+ const el = await fixture(
186
+ '<bds-drawer open><button id="a">A</button><button id="b">B</button></bds-drawer>',
187
+ ) as BdsDrawer;
188
+ const dialog = el.shadowRoot!.querySelector('dialog')!;
189
+ const closeBtn = el.shadowRoot!.querySelector<HTMLButtonElement>('button.close-button')!;
190
+ const btnB = el.querySelector<HTMLButtonElement>('#b')!;
191
+ const focusSpy = vi.spyOn(btnB, 'focus');
192
+ // Stub shadowRoot.activeElement (jsdom doesn't implement shadow-DOM focus
193
+ // retargeting) to simulate focus currently sitting on the close button —
194
+ // the "first" stop in the merged [close-button, ...slotted] boundary list.
195
+ Object.defineProperty(el.shadowRoot, 'activeElement', { value: closeBtn, configurable: true });
196
+ const event = new KeyboardEvent('keydown', { key: 'Tab', shiftKey: true, bubbles: true, cancelable: true });
197
+ dialog.dispatchEvent(event);
198
+ // Shift+Tab from "first" must wrap to "last" — the last slotted button (#b).
199
+ expect(focusSpy).toHaveBeenCalled();
200
+ cleanup(el);
201
+ });
113
202
  });
@@ -1,4 +1,4 @@
1
- import { LitElement, css, html } from 'lit';
1
+ import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
3
  const FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
4
4
 
@@ -13,6 +13,7 @@ export type DrawerSide = 'left' | 'right';
13
13
  * Attributes:
14
14
  * open — boolean; controlled open state
15
15
  * side — "left" | "right" (default: "right")
16
+ * aria-label — optional; overrides the default accessible name (the title slot)
16
17
  *
17
18
  * Slots:
18
19
  * title — drawer title text
@@ -27,10 +28,20 @@ export type DrawerSide = 'left' | 'right';
27
28
  * <span slot="title">Settings</span>
28
29
  * <p>Drawer content</p>
29
30
  * </bds-drawer>
30
- * <button commandfor="my-drawer" command="show-modal">Open</button>
31
+ * <button commandfor="my-drawer" command="--show-modal">Open</button>
31
32
  */
32
33
  export class BdsDrawer extends LitElement {
33
34
  static styles = css`
35
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
36
+ here; otherwise elements with an explicit size + padding size as
37
+ content-box and layouts drift from the React (light-DOM) versions. */
38
+ :host,
39
+ *,
40
+ *::before,
41
+ *::after {
42
+ box-sizing: border-box;
43
+ }
44
+
34
45
  :host {
35
46
  display: contents;
36
47
  }
@@ -59,6 +70,13 @@ export class BdsDrawer extends LitElement {
59
70
  overlay var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete;
60
71
  }
61
72
 
73
+ /* Closed native <dialog> must be display:none — the flex layout above would
74
+ otherwise keep it rendered (off-screen, focusable, causing overflow). The
75
+ display/overlay allow-discrete transitions above animate the none↔flex. */
76
+ .drawer:not([open]) {
77
+ display: none;
78
+ }
79
+
62
80
  :host([side='left']) .drawer {
63
81
  inset-inline: 0 auto;
64
82
  translate: -100% 0;
@@ -84,8 +102,8 @@ export class BdsDrawer extends LitElement {
84
102
  opacity: 0;
85
103
  transition:
86
104
  opacity var(--bds-animation_transition-duration) var(--bds-animation_easing),
87
- display var(--bds-animation_transition-duration) allow-discrete,
88
- overlay var(--bds-animation_transition-duration) allow-discrete;
105
+ display var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete,
106
+ overlay var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete;
89
107
  }
90
108
 
91
109
  .drawer[open]::backdrop {
@@ -117,8 +135,8 @@ export class BdsDrawer extends LitElement {
117
135
  display: flex;
118
136
  align-items: center;
119
137
  justify-content: center;
120
- inline-size: 2rem;
121
- block-size: 2rem;
138
+ inline-size: 2.75rem;
139
+ block-size: 2.75rem;
122
140
  border-radius: var(--drawer_close-radius, var(--bds-border_radius--circle));
123
141
  cursor: pointer;
124
142
  transition: var(--bds-animation_transition);
@@ -159,10 +177,12 @@ export class BdsDrawer extends LitElement {
159
177
  static properties = {
160
178
  open: { type: Boolean, reflect: true },
161
179
  side: { type: String, reflect: true },
180
+ ariaLabel: { type: String, attribute: 'aria-label' },
162
181
  };
163
182
 
164
183
  declare open: boolean;
165
184
  declare side: DrawerSide;
185
+ declare ariaLabel: string | null;
166
186
 
167
187
  private _triggerEl: Element | null = null;
168
188
 
@@ -170,6 +190,7 @@ export class BdsDrawer extends LitElement {
170
190
  super();
171
191
  this.open = false;
172
192
  this.side = 'right';
193
+ this.ariaLabel = null;
173
194
  }
174
195
 
175
196
  connectedCallback() {
@@ -180,6 +201,7 @@ export class BdsDrawer extends LitElement {
180
201
  disconnectedCallback() {
181
202
  super.disconnectedCallback();
182
203
  this.removeEventListener('command', this._onCommand);
204
+ if (this.open) document.body.style.overflow = '';
183
205
  }
184
206
 
185
207
  updated(changed: Map<string, unknown>) {
@@ -206,8 +228,8 @@ export class BdsDrawer extends LitElement {
206
228
 
207
229
  private _onCommand = (e: Event) => {
208
230
  const command = (e as CommandEvent).command;
209
- if (command === 'show-modal') this._openDrawer();
210
- else if (command === 'close') this._closeDrawer();
231
+ if (command === '--show-modal') this._openDrawer();
232
+ else if (command === '--close') this._closeDrawer();
211
233
  };
212
234
 
213
235
  private _openDrawer() {
@@ -223,14 +245,12 @@ export class BdsDrawer extends LitElement {
223
245
  this.dispatchEvent(new CustomEvent('bds-close', { bubbles: true, composed: true }));
224
246
  }
225
247
 
248
+ // Close on backdrop click. The dialog element's own box is only the visible
249
+ // panel — clicking the ::backdrop dispatches with e.target === the dialog
250
+ // itself, so this correctly ignores clicks (including keyboard-activated
251
+ // synthetic clicks at 0,0) on controls inside the panel.
226
252
  private _handleBackdropClick(e: MouseEvent) {
227
- const dialog = this._dialog;
228
- if (!dialog) return;
229
- const rect = dialog.getBoundingClientRect();
230
- const outside =
231
- e.clientX < rect.left || e.clientX > rect.right ||
232
- e.clientY < rect.top || e.clientY > rect.bottom;
233
- if (outside) this._closeDrawer();
253
+ if (e.target === this._dialog) this._closeDrawer();
234
254
  }
235
255
 
236
256
  private _handleCancel(e: Event) {
@@ -243,13 +263,24 @@ export class BdsDrawer extends LitElement {
243
263
  const dialog = this._dialog;
244
264
  if (!dialog) return;
245
265
  const focusable = Array.from(dialog.querySelectorAll<HTMLElement>(FOCUSABLE));
246
- if (focusable.length === 0) return;
247
- const first = focusable[0];
248
- const last = focusable[focusable.length - 1];
266
+ // Also include slotted elements from light DOM via the title + default slots
267
+ const slots = Array.from(dialog.querySelectorAll<HTMLSlotElement>('slot'));
268
+ const slottedFocusable = slots.flatMap(slot =>
269
+ slot.assignedElements({ flatten: true })
270
+ .flatMap(el => [
271
+ ...(el.matches(FOCUSABLE) ? [el as HTMLElement] : []),
272
+ ...Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE)),
273
+ ]),
274
+ );
275
+ const all = [...focusable, ...slottedFocusable];
276
+ if (all.length === 0) return;
277
+ const first = all[0];
278
+ const last = all[all.length - 1];
279
+ const active = this.shadowRoot?.activeElement ?? document.activeElement;
249
280
  if (e.shiftKey) {
250
- if (document.activeElement === first) { e.preventDefault(); last.focus(); }
281
+ if (active === first) { e.preventDefault(); last.focus(); }
251
282
  } else {
252
- if (document.activeElement === last) { e.preventDefault(); first.focus(); }
283
+ if (active === last) { e.preventDefault(); first.focus(); }
253
284
  }
254
285
  }
255
286
 
@@ -258,12 +289,14 @@ export class BdsDrawer extends LitElement {
258
289
  <dialog
259
290
  class="drawer"
260
291
  aria-modal="true"
292
+ aria-label=${this.ariaLabel ?? nothing}
293
+ aria-labelledby=${this.ariaLabel ? nothing : 'title'}
261
294
  @click=${this._handleBackdropClick}
262
295
  @cancel=${this._handleCancel}
263
296
  @keydown=${this._handleKeydown}
264
297
  >
265
298
  <div class="header">
266
- <span class="title"><slot name="title"></slot></span>
299
+ <span class="title" id="title"><slot name="title"></slot></span>
267
300
  <button
268
301
  type="button"
269
302
  class="close-button"
@@ -19,6 +19,16 @@ import { LitElement, css, html } from 'lit';
19
19
  */
20
20
  export class BdsDropdownMenuItem extends LitElement {
21
21
  static styles = css`
22
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
23
+ here; otherwise elements with an explicit size + padding size as
24
+ content-box and layouts drift from the React (light-DOM) versions. */
25
+ :host,
26
+ *,
27
+ *::before,
28
+ *::after {
29
+ box-sizing: border-box;
30
+ }
31
+
22
32
  :host {
23
33
  display: block;
24
34
  }
@@ -51,7 +61,8 @@ export class BdsDropdownMenuItem extends LitElement {
51
61
 
52
62
  @media (hover: hover) and (pointer: fine) {
53
63
  .item:hover {
54
- background-color: var(--bds-color_bg--subtle);
64
+ background-color: var(--dropdown_item-bg--hover, var(--bds-color_bg--subtle));
65
+ color: var(--dropdown_item-color--hover, var(--bds-color_interactive_on-bg));
55
66
  }
56
67
 
57
68
  :host([destructive]) .item:hover {