@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
@@ -1,7 +1,17 @@
1
1
  import { fixture, cleanup } from '../test/helpers';
2
2
  import { BdsGrid } from './bds-grid';
3
+ import type { BdsGridItem } from './bds-grid-item';
4
+ // Side-effect import: registers the `bds-grid-item` custom element. BdsGridItem
5
+ // above is used only as a type, which esbuild's isolatedModules-style transform
6
+ // would otherwise elide — silently leaving <bds-grid-item> un-upgraded (a plain
7
+ // HTMLElement) in every fixture in this file that nests one inside <bds-grid>.
3
8
  import './bds-grid-item';
4
9
 
10
+ /** Flush one requestAnimationFrame tick — the masonry polyfill's schedule/apply cycle. */
11
+ function nextFrame(): Promise<void> {
12
+ return new Promise((resolve) => requestAnimationFrame(() => resolve()));
13
+ }
14
+
5
15
  describe('bds-grid', () => {
6
16
  it('is registered as a custom element', () => {
7
17
  expect(customElements.get('bds-grid')).toBe(BdsGrid);
@@ -67,4 +77,92 @@ describe('bds-grid', () => {
67
77
  expect(el.masonryPreferredColumnSpan).toBe('half');
68
78
  cleanup(el);
69
79
  });
80
+
81
+ it('reflects masonry-row-unit-px as a number property', async () => {
82
+ const el = await fixture(
83
+ '<bds-grid is-masonry masonry-row-unit-px="8"></bds-grid>',
84
+ ) as BdsGrid;
85
+ expect(el.masonryRowUnitPx).toBe(8);
86
+ cleanup(el);
87
+ });
88
+
89
+ it('applies grid-column: 1 / -1 to the host (not the inner .grid) for variant="page", so nested page grids span the parent', () => {
90
+ const cssText = BdsGrid.styles.cssText;
91
+ expect(cssText).toMatch(/:host\(\[variant='page'\]\)\s*{[^}]*grid-column:\s*1\s*\/\s*-1/);
92
+ // The inner .grid.--page rule must not also carry grid-column — the host
93
+ // (which participates in a parent grid's tracks) owns spanning; the inner
94
+ // div only owns its own track sizing.
95
+ expect(cssText).not.toMatch(/\.grid\.--page\s*{[^}]*grid-column:/);
96
+ });
97
+
98
+ it('falls back to the --grid_columns default when the columns attribute is removed', async () => {
99
+ const el = await fixture(
100
+ '<bds-grid variant="custom" columns="6"></bds-grid>',
101
+ ) as BdsGrid;
102
+ const grid = el.shadowRoot!.querySelector('.grid') as HTMLElement;
103
+ expect(grid.getAttribute('style')).toContain('--grid_columns: 6');
104
+
105
+ el.removeAttribute('columns');
106
+ await el.updateComplete;
107
+
108
+ // Lit's Number converter yields `null` (not `undefined`) when a reflected
109
+ // attribute is removed. A strict `!== undefined` check would still match
110
+ // and emit the literal string "null", making `var(--grid_columns, 4)`
111
+ // resolve to an invalid custom property and collapse the grid to one
112
+ // column instead of falling back to the default.
113
+ expect(grid.getAttribute('style') ?? '').not.toContain('null');
114
+ cleanup(el);
115
+ });
116
+
117
+ it('does not clear a slotted grid-item row-span style when re-rendering a non-masonry grid', async () => {
118
+ const el = await fixture(
119
+ '<bds-grid><bds-grid-item row-span="3">A</bds-grid-item></bds-grid>',
120
+ ) as BdsGrid;
121
+ const item = el.querySelector('bds-grid-item') as BdsGridItem;
122
+ await item.updateComplete;
123
+ expect(item.style.gridRow).toBe('span 3');
124
+
125
+ // An unrelated property change re-renders bds-grid. Before the fix,
126
+ // updated() called clearMasonryLayout() unconditionally on every
127
+ // non-masonry update, wiping the row-span this GridItem's own render set.
128
+ el.isCentered = true;
129
+ await el.updateComplete;
130
+
131
+ expect(item.style.gridRow).toBe('span 3');
132
+ cleanup(el);
133
+ });
134
+
135
+ it('applies a masonry row-span to slotted items after mount', async () => {
136
+ const el = await fixture(
137
+ '<bds-grid is-masonry><bds-grid-item>A</bds-grid-item></bds-grid>',
138
+ ) as BdsGrid;
139
+ await nextFrame();
140
+ const item = el.querySelector('bds-grid-item') as HTMLElement;
141
+ // jsdom reports offsetHeight 0 for unlaid-out elements, so the polyfill
142
+ // assigns the 1-row floor.
143
+ expect(item.style.gridRowEnd).toBe('span 1');
144
+ cleanup(el);
145
+ });
146
+
147
+ it('re-engages masonry after being disconnected and reconnected', async () => {
148
+ const el = await fixture(
149
+ '<bds-grid is-masonry><bds-grid-item>A</bds-grid-item></bds-grid>',
150
+ ) as BdsGrid;
151
+ await nextFrame();
152
+ const item = el.querySelector('bds-grid-item') as HTMLElement;
153
+ expect(item.style.gridRowEnd).toBe('span 1');
154
+
155
+ const parent = el.parentElement!;
156
+ el.remove();
157
+ // disconnectedCallback tears down masonry synchronously.
158
+ expect(item.style.gridRowEnd).toBe('');
159
+
160
+ parent.appendChild(el);
161
+ // No property changed, so updated() won't fire — connectedCallback must
162
+ // re-arm masonry on its own for this to re-apply.
163
+ await nextFrame();
164
+ expect(item.style.gridRowEnd).toBe('span 1');
165
+
166
+ cleanup(el);
167
+ });
70
168
  });
@@ -4,6 +4,12 @@ import type { GridItemSpanValue } from '../../components/layout/Grid/GridItem';
4
4
 
5
5
  export type GridVariant = 'main' | 'page' | 'funnel' | 'custom';
6
6
 
7
+ // Mirrors masonry.ts's useMasonry hook: RO-triggered resizes of already-laid-out
8
+ // items are deferred while the user is actively scrolling, and applied once
9
+ // scroll idles for this long — avoids a compositor race where a re-pack mid-
10
+ // scroll paints over already-visible content for a frame or two.
11
+ const MASONRY_SCROLL_IDLE_MS = 150;
12
+
7
13
  /**
8
14
  * `<bds-grid>` — framework-agnostic Grid layout custom element.
9
15
  *
@@ -23,16 +29,36 @@ export type GridVariant = 'main' | 'page' | 'funnel' | 'custom';
23
29
  * across breakpoints via the foundation's responsive column
24
30
  * tokens. An item at row-end is demoted to the remaining
25
31
  * column count. Numeric values are literal and don't adapt.
32
+ * masonry-row-unit-px — number; masonry only. Manual override for the
33
+ * row-track unit (px) the polyfill uses for
34
+ * `grid-auto-rows` and as the ceil() granularity of each
35
+ * item's row span. Omit to let the polyfill auto-pick the
36
+ * smallest unit that keeps the implicit row count under
37
+ * any browser cap.
26
38
  *
27
39
  * Slots:
28
40
  * (default) — grid content; typically `<bds-grid-item>` children
29
41
  */
30
42
  export class BdsGrid extends LitElement {
31
43
  static styles = css`
44
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
45
+ here; otherwise elements with an explicit size + padding size as
46
+ content-box and layouts drift from the React (light-DOM) versions. */
47
+ :host,
48
+ *,
49
+ *::before,
50
+ *::after {
51
+ box-sizing: border-box;
52
+ }
53
+
32
54
  :host {
33
55
  display: block;
34
56
  }
35
57
 
58
+ :host([variant='page']) {
59
+ grid-column: 1 / -1;
60
+ }
61
+
36
62
  .grid {
37
63
  display: grid;
38
64
  gap: var(--grid_gap, var(--bds-grid_gap));
@@ -45,7 +71,6 @@ export class BdsGrid extends LitElement {
45
71
 
46
72
  .grid.--page {
47
73
  grid-template-columns: 1fr;
48
- grid-column: 1 / -1;
49
74
  }
50
75
 
51
76
  .grid.--funnel {
@@ -88,6 +113,7 @@ export class BdsGrid extends LitElement {
88
113
  attribute: 'masonry-preferred-column-span',
89
114
  reflect: true,
90
115
  },
116
+ masonryRowUnitPx: { type: Number, attribute: 'masonry-row-unit-px', reflect: true },
91
117
  };
92
118
 
93
119
  declare variant: GridVariant;
@@ -96,10 +122,53 @@ export class BdsGrid extends LitElement {
96
122
  declare isMasonry: boolean;
97
123
  declare autoSpanMedia: boolean;
98
124
  declare masonryPreferredColumnSpan: string | undefined;
125
+ declare masonryRowUnitPx: number | undefined;
99
126
 
100
127
  private _ro?: ResizeObserver;
101
128
  private _mo?: MutationObserver;
102
129
  private _frame = 0;
130
+ // Tracks whether the masonry observers/listeners are currently wired up.
131
+ // Guards _teardownMasonry so a grid that never engaged masonry (or already
132
+ // tore it down) never clears spans it didn't apply.
133
+ private _engaged = false;
134
+ private _scrolling = false;
135
+ private _pendingResize = false;
136
+ private _scrollTimer?: ReturnType<typeof setTimeout>;
137
+
138
+ // RO-triggered re-runs (an already-laid-out item resizing — image decode, font
139
+ // swap) apply immediately unless the user is actively scrolling, in which case
140
+ // they're deferred until scroll idles (see _onScroll) to avoid a compositor
141
+ // race where `grid-auto-flow: dense` re-packs items mid-scroll. Stable
142
+ // arrow-function references so connectedCallback/disconnectedCallback can
143
+ // add/remove the same listener.
144
+ private _onResize = () => {
145
+ if (this._scrolling) {
146
+ this._pendingResize = true;
147
+ return;
148
+ }
149
+ this._apply();
150
+ };
151
+
152
+ // MutationObserver fires when children are added/removed. Newly-added children
153
+ // (and their media descendants) need to be observed for size, and the run is
154
+ // deferred to rAF so the browser lays out the new children before measuring.
155
+ private _onMutate = () => {
156
+ for (const child of this._items()) this._observeDescendants(child);
157
+ this._scheduleMasonry();
158
+ };
159
+
160
+ private _onScroll = () => {
161
+ this._scrolling = true;
162
+ if (this._scrollTimer !== undefined) clearTimeout(this._scrollTimer);
163
+ this._scrollTimer = setTimeout(() => {
164
+ this._scrolling = false;
165
+ this._scrollTimer = undefined;
166
+ if (this._pendingResize) {
167
+ this._pendingResize = false;
168
+ this._apply();
169
+ }
170
+ }, MASONRY_SCROLL_IDLE_MS);
171
+ };
103
172
 
104
173
  constructor() {
105
174
  super();
@@ -109,6 +178,21 @@ export class BdsGrid extends LitElement {
109
178
  this.isMasonry = false;
110
179
  this.autoSpanMedia = false;
111
180
  this.masonryPreferredColumnSpan = undefined;
181
+ this.masonryRowUnitPx = undefined;
182
+ }
183
+
184
+ connectedCallback() {
185
+ super.connectedCallback();
186
+ // Re-arm masonry on reconnect (e.g. the element was moved in the DOM).
187
+ // disconnectedCallback tore down observers/listeners; updated() only fires
188
+ // again on a property change, so a reconnect with no property change would
189
+ // otherwise leave masonry permanently disengaged. No-op on first connect —
190
+ // the shadow root hasn't rendered yet, so _setupMasonry finds no container
191
+ // and updated() performs the initial setup once it has.
192
+ if (this.isMasonry && !supportsNativeMasonry() && !this._engaged) {
193
+ this._setupMasonry();
194
+ this._scheduleMasonry();
195
+ }
112
196
  }
113
197
 
114
198
  disconnectedCallback() {
@@ -121,6 +205,7 @@ export class BdsGrid extends LitElement {
121
205
  this._setupMasonry();
122
206
  this._scheduleMasonry();
123
207
  } else {
208
+ // No-op when masonry was never engaged — see the guard in _teardownMasonry.
124
209
  this._teardownMasonry();
125
210
  }
126
211
  }
@@ -133,37 +218,54 @@ export class BdsGrid extends LitElement {
133
218
  return (Array.from(this.children) as HTMLElement[]).filter((el) => el.nodeType === 1);
134
219
  }
135
220
 
221
+ private _observeDescendants(child: Element) {
222
+ if (!this._ro) return;
223
+ this._ro.observe(child);
224
+ // Also observe media descendants directly. `loading="lazy"` images decode
225
+ // asynchronously; observing the image itself means the polyfill re-runs in
226
+ // the same frame as the decode instead of one frame late.
227
+ for (const media of Array.from(child.querySelectorAll('img, video'))) {
228
+ this._ro.observe(media);
229
+ }
230
+ }
231
+
136
232
  private _setupMasonry() {
137
- if (this._ro || this._mo) return;
233
+ if (this._engaged) return;
138
234
  const container = this._gridEl();
139
235
  if (!container) return;
236
+ this._engaged = true;
140
237
 
141
238
  if (typeof ResizeObserver !== 'undefined') {
142
- this._ro = new ResizeObserver(() => this._scheduleMasonry());
143
- // Only observe children, not the container — container block-size changes when
144
- // we apply row-spans, which would loop back through the observer.
145
- for (const child of this._items()) this._ro.observe(child);
239
+ this._ro = new ResizeObserver(this._onResize);
240
+ // Only observe children (and their media), not the container — container
241
+ // block-size changes when we apply row-spans, which would loop back
242
+ // through the observer.
243
+ for (const child of this._items()) this._observeDescendants(child);
146
244
  }
147
245
 
148
246
  if (typeof MutationObserver !== 'undefined') {
149
- this._mo = new MutationObserver(() => {
150
- if (this._ro) for (const child of this._items()) this._ro.observe(child);
151
- this._scheduleMasonry();
152
- });
247
+ this._mo = new MutationObserver(this._onMutate);
153
248
  this._mo.observe(this, { childList: true });
154
249
  }
250
+
251
+ // `capture: true` catches scroll events from any nested scroll container,
252
+ // since scroll doesn't bubble. `passive: true` tells the browser we won't
253
+ // preventDefault — critical for not blocking scroll performance.
254
+ window.addEventListener('scroll', this._onScroll, { passive: true, capture: true });
255
+ }
256
+
257
+ private _apply() {
258
+ const container = this._gridEl();
259
+ if (!container) return;
260
+ applyMasonryLayout(container, this._items(), {
261
+ preferredColumnSpan: this._resolvePreferredColumnSpan(),
262
+ rowUnitPx: this.masonryRowUnitPx,
263
+ });
155
264
  }
156
265
 
157
266
  private _scheduleMasonry() {
158
267
  cancelAnimationFrame(this._frame);
159
- this._frame = requestAnimationFrame(() => {
160
- const container = this._gridEl();
161
- if (container) {
162
- applyMasonryLayout(container, this._items(), {
163
- preferredColumnSpan: this._resolvePreferredColumnSpan(),
164
- });
165
- }
166
- });
268
+ this._frame = requestAnimationFrame(() => this._apply());
167
269
  }
168
270
 
169
271
  private _resolvePreferredColumnSpan(): Exclude<GridItemSpanValue, 'auto'> | undefined {
@@ -176,11 +278,24 @@ export class BdsGrid extends LitElement {
176
278
  }
177
279
 
178
280
  private _teardownMasonry() {
281
+ // Nothing was ever wired up — skip clearMasonryLayout too, so a non-masonry
282
+ // (or not-yet-engaged) grid never has its slotted items' inline styles
283
+ // (e.g. a `row-span` a consumer set) reset on disconnect/reconnect.
284
+ if (!this._engaged) return;
285
+
179
286
  cancelAnimationFrame(this._frame);
287
+ if (this._scrollTimer !== undefined) {
288
+ clearTimeout(this._scrollTimer);
289
+ this._scrollTimer = undefined;
290
+ }
291
+ this._scrolling = false;
292
+ this._pendingResize = false;
293
+ window.removeEventListener('scroll', this._onScroll, { capture: true } as EventListenerOptions);
180
294
  this._ro?.disconnect();
181
295
  this._mo?.disconnect();
182
296
  this._ro = undefined;
183
297
  this._mo = undefined;
298
+ this._engaged = false;
184
299
  const container = this._gridEl();
185
300
  if (container) clearMasonryLayout(container, this._items());
186
301
  }
@@ -193,8 +308,13 @@ export class BdsGrid extends LitElement {
193
308
  this.isMasonry ? '--masonry' : '',
194
309
  ].filter(Boolean).join(' ');
195
310
 
311
+ // Lit's Number converter yields `null` (not `undefined`) when a reflected
312
+ // attribute is removed — a strict `!== undefined` check would still match
313
+ // and emit the literal string "null", making `var(--grid_columns, 4)`
314
+ // resolve to an invalid custom property and collapse the grid to one
315
+ // column. Loose `!= null` catches both null and undefined.
196
316
  const styleAttr =
197
- this.variant === 'custom' && this.columns !== undefined
317
+ this.variant === 'custom' && this.columns != null
198
318
  ? `--grid_columns: ${this.columns}`
199
319
  : '';
200
320
 
@@ -5,7 +5,7 @@ import * as Stories from './BdsAlert.stories';
5
5
 
6
6
  # &lt;bds-alert&gt;
7
7
 
8
- Framework-agnostic alert custom element for inline status messages. Supports four semantic variants, an optional title, and a dismissible mode.
8
+ Framework-agnostic alert custom element for inline status messages. Supports four semantic variants, an optional heading, and a dismissible mode.
9
9
 
10
10
  > **Status: experimental** — API may change before stable release.
11
11
 
@@ -32,8 +32,8 @@ import '@boostdev/design-system-components/web-components';
32
32
  ### Error
33
33
  <Canvas of={Stories.Error} />
34
34
 
35
- ### With title
36
- <Canvas of={Stories.WithTitle} />
35
+ ### With heading
36
+ <Canvas of={Stories.WithHeading} />
37
37
 
38
38
  ### Dismissible
39
39
  <Canvas of={Stories.Dismissible} />
@@ -47,7 +47,8 @@ import '@boostdev/design-system-components/web-components';
47
47
  | Attribute | Type | Default | Description |
48
48
  |-----------|------|---------|-------------|
49
49
  | `variant` | `"info" \| "success" \| "warning" \| "error"` | `"info"` | Semantic colour and icon |
50
- | `title` | string | — | Optional heading displayed above body content |
50
+ | `heading` | string | — | Optional heading displayed above body content |
51
+ | `title` | string | — | **Deprecated.** Alias for `heading`, used as a fallback when `heading` is unset. Avoid: it shares its name with the global HTML `title` attribute, which makes the browser show a native tooltip on hover. Will be removed in a later major — use `heading` instead. |
51
52
  | `dismissible` | boolean | `false` | Shows a dismiss (×) button |
52
53
 
53
54
  ## Slots
@@ -66,7 +67,7 @@ import '@boostdev/design-system-components/web-components';
66
67
  ## Usage in plain HTML
67
68
 
68
69
  ```html
69
- <bds-alert variant="success" title="Saved">
70
+ <bds-alert variant="success" heading="Saved">
70
71
  Your changes have been saved successfully.
71
72
  </bds-alert>
72
73
 
@@ -6,20 +6,20 @@ import '../index'; // auto-registers all custom elements
6
6
  // Thin React wrapper so Storybook controls work with the custom element's props
7
7
  function BdsAlert({
8
8
  variant = 'info',
9
- title,
9
+ heading,
10
10
  dismissible,
11
11
  children,
12
12
  onDismiss,
13
13
  }: {
14
14
  variant?: AlertVariant;
15
- title?: string;
15
+ heading?: string;
16
16
  dismissible?: boolean;
17
17
  children?: React.ReactNode;
18
18
  onDismiss?: () => void;
19
19
  }) {
20
20
  return React.createElement(
21
21
  'bds-alert',
22
- { variant, title, dismissible: dismissible || undefined, onbdsdismiss: onDismiss },
22
+ { variant, heading, dismissible: dismissible || undefined, onbdsdismiss: onDismiss },
23
23
  children,
24
24
  );
25
25
  }
@@ -41,8 +41,8 @@ export const Info: Story = { args: { children: 'This is an informational message
41
41
  export const Success: Story = { args: { children: 'Your changes have been saved.', variant: 'success' } };
42
42
  export const Warning: Story = { args: { children: 'Please review before continuing.', variant: 'warning' } };
43
43
  export const Error: Story = { args: { children: 'Something went wrong.', variant: 'error' } };
44
- export const WithTitle: Story = {
45
- args: { children: 'More details about the alert.', variant: 'info', title: 'Heads up' },
44
+ export const WithHeading: Story = {
45
+ args: { children: 'More details about the alert.', variant: 'info', heading: 'Heads up' },
46
46
  };
47
47
  export const Dismissible: Story = {
48
48
  args: { children: 'You can dismiss this alert.', variant: 'success', dismissible: true },
@@ -51,7 +51,7 @@ export const AllVariants: Story = {
51
51
  render: () => (
52
52
  <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', maxWidth: 500 }}>
53
53
  {(['info', 'success', 'warning', 'error'] as const).map(v => (
54
- <BdsAlert key={v} variant={v} title={v.charAt(0).toUpperCase() + v.slice(1)}>
54
+ <BdsAlert key={v} variant={v} heading={v.charAt(0).toUpperCase() + v.slice(1)}>
55
55
  This is a {v} alert.
56
56
  </BdsAlert>
57
57
  ))}
@@ -46,7 +46,7 @@ import '@boostdev/design-system-components/web-components';
46
46
  | Attribute | Type | Default | Description |
47
47
  |-----------|------|---------|-------------|
48
48
  | `src` | string | — | Photo URL; when set the image is shown |
49
- | `alt` | string | `name` or `"User avatar"` | Alt text for the `<img>` element |
49
+ | `alt` | string | `name` or `"User avatar"` | Alt text for the `<img>` element. Pass `alt=""` explicitly to mark a decorative image — an empty attribute is preserved as-is and is not replaced by `name`/`"User avatar"`. |
50
50
  | `name` | string | — | Full name; used to compute up to two initials and as `aria-label` |
51
51
  | `size` | `"small" \| "medium" \| "large"` | `"medium"` | Diameter scale |
52
52
 
@@ -54,6 +54,8 @@ import '@boostdev/design-system-components/web-components';
54
54
 
55
55
  | Property | Description |
56
56
  |----------|-------------|
57
+ | `--avatar_size` | Diameter override (wins over the `size` attribute's preset); defaults to `3em` |
58
+ | `--avatar_radius` | Corner radius; defaults to `var(--bds-border_radius--circle)` |
57
59
  | `--avatar_bg` | Background colour of the fallback initials circle |
58
60
  | `--avatar_text` | Text colour of the initials |
59
61
 
@@ -73,4 +75,4 @@ import '@boostdev/design-system-components/web-components';
73
75
  ## Accessibility
74
76
 
75
77
  - Without `src`: renders `role="img"` with `aria-label` set to `name` (or "User avatar")
76
- - With `src`: renders `<img>` with `alt` set to `alt`, `name`, or "User avatar"
78
+ - With `src`: renders `<img>` with `alt` set to the explicit `alt` attribute when provided (including `alt=""` for a decorative image), otherwise falling back to `name`, or "User avatar"
@@ -5,7 +5,7 @@ import * as Stories from './BdsBreadcrumb.stories';
5
5
 
6
6
  # &lt;bds-breadcrumb&gt;
7
7
 
8
- Framework-agnostic Breadcrumb custom element. Renders a horizontal navigation trail from a JSON array of `{ label, href? }` items. The last item is treated as the current page and rendered without a link.
8
+ Framework-agnostic Breadcrumb custom element. Renders a horizontal navigation trail from a JSON array of `{ label, href? }` items. The last item is treated as the current page and rendered without a link. Non-last items without an `href` render as plain (non-interactive) text instead of an unusable link.
9
9
 
10
10
  > **Status: experimental** — API may change before stable release.
11
11
 
@@ -39,7 +39,7 @@ import '@boostdev/design-system-components/web-components';
39
39
 
40
40
  | Attribute | Type | Default | Description |
41
41
  |-----------|------|---------|-------------|
42
- | `items` | `Array<{ label: string; href?: string }>` | `[]` | Breadcrumb items as a JSON-serialisable array. The last item is always the current page. |
42
+ | `items` | `Array<{ label: string; href?: string }>` | `[]` | Breadcrumb items as a JSON-serialisable array. The last item is always the current page. Malformed JSON (or a removed attribute) falls back to an empty list rather than crashing the render. |
43
43
 
44
44
  ## Usage in plain HTML
45
45
 
@@ -64,3 +64,4 @@ document.querySelector('bds-breadcrumb').items = [
64
64
  - Wrapped in `<nav aria-label="Breadcrumb">` with an `<ol>` list structure
65
65
  - The current page item carries `aria-current="page"`
66
66
  - Separator characters are `aria-hidden="true"` to avoid screen reader noise
67
+ - Non-last items without an `href` render as plain text rather than a link with `href="#"` — this avoids an interactive-looking element that scrolls to top and pushes a history entry when activated
@@ -0,0 +1,64 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsButtonContainer.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # &lt;bds-button-container&gt;
7
+
8
+ Framework-agnostic layout wrapper for a row of action buttons (Cancel / Confirm, Back / Next). Web-component port of the React `ButtonContainer`.
9
+
10
+ > **Status: experimental** — API may change before stable release.
11
+
12
+ Buttons stack vertically (primary on top, via `column-reverse`) on narrow containers and lay out in a row once the container is at least `30rem` wide. The `variant` controls alignment: `flow` (multi-step navigation), `card` (single-form submit), `modal` (dialog actions, aligned end), `content` (inline actions, aligned start).
13
+
14
+ ## Installation
15
+
16
+ ```js
17
+ import '@boostdev/design-system-components/web-components';
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### Two buttons
23
+ <Canvas of={Stories.TwoButtons} />
24
+
25
+ ### Three buttons
26
+ <Canvas of={Stories.ThreeButtons} />
27
+
28
+ ### Variants
29
+ <Canvas of={Stories.Variants} />
30
+
31
+ ## Props
32
+
33
+ <ArgTypes of={Stories} />
34
+
35
+ ## Attributes
36
+
37
+ | Attribute | Type | Default | Description |
38
+ |-----------|------|---------|-------------|
39
+ | `variant` | `"flow" \| "card" \| "modal" \| "content"` | — | Alignment of the button row |
40
+ | `aria-label` | string | — | Accessible label for the group container |
41
+
42
+ ## Slots
43
+
44
+ | Slot | Description |
45
+ |------|-------------|
46
+ | `(default)` | `<bds-button>` elements |
47
+
48
+ ## Usage in plain HTML
49
+
50
+ ```html
51
+ <bds-button-container variant="modal" aria-label="Dialog actions">
52
+ <bds-button variant="outline">Cancel</bds-button>
53
+ <bds-button>Confirm</bds-button>
54
+ </bds-button-container>
55
+ ```
56
+
57
+ ## Deprecated: `<bds-button-group>`
58
+
59
+ `<bds-button-group>` is a **deprecated alias** of `<bds-button-container>` and behaves identically. Migrate to `<bds-button-container>`; the alias (and its `./web-components/ui/bds-button-group` deep import) will be removed in a future major version.
60
+
61
+ ## Accessibility
62
+
63
+ - Renders a `<div role="group">` with the provided `aria-label`; the attribute is omitted entirely (not an empty string) when unset
64
+ - Always set `aria-label` to describe the purpose of the group
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import type { ButtonContainerVariant } from './bds-button-container';
4
+ import '../index'; // auto-registers all custom elements
5
+
6
+ function BdsButtonContainer({
7
+ variant,
8
+ ariaLabel,
9
+ children,
10
+ }: {
11
+ variant?: ButtonContainerVariant;
12
+ ariaLabel?: string;
13
+ children?: React.ReactNode;
14
+ }) {
15
+ return React.createElement('bds-button-container', { variant, 'aria-label': ariaLabel }, children);
16
+ }
17
+
18
+ const meta = {
19
+ title: 'Web Components/Layout/ButtonContainer',
20
+ component: BdsButtonContainer,
21
+ tags: ['!stable', 'experimental'],
22
+ parameters: { layout: 'padded' },
23
+ argTypes: {
24
+ variant: { control: 'radio', options: ['flow', 'card', 'modal', 'content'] },
25
+ ariaLabel: { control: 'text' },
26
+ },
27
+ } satisfies Meta<typeof BdsButtonContainer>;
28
+
29
+ export default meta;
30
+ type Story = StoryObj<typeof meta>;
31
+
32
+ const btn = (label: string, variant?: string) =>
33
+ React.createElement('bds-button', variant ? { variant } : null, label);
34
+
35
+ /** Two actions — the common Cancel / Confirm dialog row. */
36
+ export const TwoButtons: Story = {
37
+ render: () =>
38
+ React.createElement(
39
+ 'bds-button-container',
40
+ { variant: 'modal', 'aria-label': 'Dialog actions' },
41
+ btn('Cancel', 'outline'),
42
+ btn('Confirm'),
43
+ ),
44
+ };
45
+
46
+ /** Three actions. */
47
+ export const ThreeButtons: Story = {
48
+ render: () =>
49
+ React.createElement(
50
+ 'bds-button-container',
51
+ { variant: 'content', 'aria-label': 'Actions' },
52
+ btn('Back', 'outline'),
53
+ btn('Save draft', 'outline'),
54
+ btn('Publish'),
55
+ ),
56
+ };
57
+
58
+ /** All four alignment variants (resize the viewport to see the row/stack switch at 30rem). */
59
+ export const Variants: Story = {
60
+ render: () =>
61
+ React.createElement(
62
+ 'div',
63
+ { style: { display: 'flex', flexDirection: 'column', gap: '2rem' } },
64
+ ...(['flow', 'card', 'modal', 'content'] as const).map((v) =>
65
+ React.createElement(
66
+ 'bds-button-container',
67
+ { key: v, variant: v, 'aria-label': v },
68
+ btn('Cancel', 'outline'),
69
+ btn('Confirm'),
70
+ ),
71
+ ),
72
+ ),
73
+ };
74
+
75
+ /** `<bds-button-group>` is a deprecated alias and behaves identically — prefer `<bds-button-container>`. */
76
+ export const DeprecatedButtonGroupAlias: Story = {
77
+ render: () =>
78
+ React.createElement(
79
+ 'bds-button-group',
80
+ { variant: 'modal', 'aria-label': 'Legacy alias' },
81
+ btn('Cancel', 'outline'),
82
+ btn('Confirm'),
83
+ ),
84
+ };