@boostdev/design-system-components 2.7.1 → 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 (535) 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-3AY2YKCM.js +223 -0
  15. package/dist/web-components/chunk-3WAV6MDN.js +212 -0
  16. package/dist/web-components/{chunk-CZBIVR4V.js → chunk-47AT5KZD.js} +88 -16
  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-5R6IFELV.js → chunk-AIBOHNDU.js} +11 -1
  23. package/dist/web-components/{chunk-ITHLKR7Q.js → chunk-AP4RDUL2.js} +16 -5
  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-CM3KYZ6Z.js → chunk-JH6LQKLK.js} +78 -6
  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-57TRNCWQ.js → chunk-WFVKU4GX.js} +22 -11
  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-F5E3IT7G.js → chunk-XIZWAWMJ.js} +50 -11
  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 +60 -13
  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 +102 -17
  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 +136 -23
  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 +96 -8
  441. package/src/web-components/interaction/form/bds-slider.spec.ts +83 -0
  442. package/src/web-components/interaction/form/bds-slider.ts +181 -33
  443. package/src/web-components/interaction/form/bds-switch.spec.ts +68 -0
  444. package/src/web-components/interaction/form/bds-switch.ts +142 -41
  445. package/src/web-components/interaction/form/bds-textarea.spec.ts +71 -0
  446. package/src/web-components/interaction/form/bds-textarea.ts +109 -8
  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 +30 -12
  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 +113 -36
  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 +16 -15
  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 +11 -1
  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 +19 -6
  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-5TFWOPLH.js +0 -49
  526. package/dist/web-components/chunk-7FMR53BW.js +0 -127
  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-IYGF6CD5.js +0 -118
  530. package/dist/web-components/chunk-QBB6ZX4R.js +0 -107
  531. package/dist/web-components/chunk-Y3POAKGS.js +0 -133
  532. package/dist/web-components/chunk-Y4MAXTMA.js +0 -80
  533. package/dist/web-components/chunk-Y7V7LM6R.js +0 -98
  534. package/src/web-components/ui/BdsButtonGroup.mdx +0 -69
  535. package/src/web-components/ui/BdsButtonGroup.stories.tsx +0 -66
@@ -23,7 +23,8 @@ export interface SegmentedOption {
23
23
  * variant — "outline" (inset border on active item, default) | "filled" (sliding thumb)
24
24
  *
25
25
  * Events:
26
- * change — fired when a new segment is selected (radio mode only)
26
+ * bds-change — fired when a new segment is selected (radio mode only); detail: { value }
27
+ * change — deprecated alias for bds-change, kept for backward compatibility (radio mode only)
27
28
  *
28
29
  * @example
29
30
  * <bds-segmented-control
@@ -43,6 +44,16 @@ export class BdsSegmentedControl extends LitElement {
43
44
  static formAssociated = true;
44
45
 
45
46
  static styles = css`
47
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it
48
+ here; otherwise elements with an explicit size + padding size as
49
+ content-box and layouts drift from the React (light-DOM) versions. */
50
+ :host,
51
+ *,
52
+ *::before,
53
+ *::after {
54
+ box-sizing: border-box;
55
+ }
56
+
46
57
  :host {
47
58
  display: inline-flex;
48
59
  }
@@ -53,25 +64,35 @@ export class BdsSegmentedControl extends LitElement {
53
64
  }
54
65
 
55
66
  .control {
56
- display: inline-flex;
57
67
  position: relative;
58
- border-radius: var(--bds-border_radius--s);
59
- background-color: var(--segmented_color_bg, var(--bds-color_bg--subtle));
60
- padding: 0.25rem;
68
+ display: inline-grid;
69
+ grid-auto-flow: column;
70
+ grid-auto-columns: 1fr;
71
+ padding: var(--control_track-pad, var(--bds-space_xxs));
72
+ background-color: var(--control_track-bg, var(--segmented_color_bg, var(--bds-color_bg--subtle)));
73
+ border-radius: var(--control_radius, var(--bds-border_radius--full));
61
74
  gap: 0;
75
+ --control_dir: 1;
76
+ }
77
+
78
+ :host(:dir(rtl)) .control {
79
+ --control_dir: -1;
62
80
  }
63
81
 
64
- /* Sliding thumb */
82
+ /* Sliding thumb (filled variant) — positioned entirely via CSS custom properties
83
+ (--control_count / --control_selected-index, set inline from render()) so it
84
+ stays correct across RTL and resize without any JS measurement. */
65
85
  .thumb {
66
86
  position: absolute;
67
- inset-block: 0.25rem;
68
- border-radius: calc(var(--bds-border_radius--s) - 2px);
69
- background-color: var(--segmented_thumb-color, var(--bds-color_interactive));
70
- box-shadow: var(--bds-shadow_m);
71
- transition: inset-inline-start var(--bds-animation_transition-duration) var(--bds-animation_easing),
72
- inline-size var(--bds-animation_transition-duration) var(--bds-animation_easing);
87
+ inset-block: var(--control_track-pad, var(--bds-space_xxs));
88
+ inset-inline-start: var(--control_track-pad, var(--bds-space_xxs));
89
+ inline-size: calc((100% - 2 * var(--control_track-pad, var(--bds-space_xxs))) / var(--control_count, 1));
90
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--full));
91
+ background-color: var(--control_thumb-bg, var(--segmented_thumb-color, var(--bds-color_interactive)));
92
+ box-shadow: var(--control_thumb-shadow, var(--bds-shadow_s));
73
93
  pointer-events: none;
74
- /* Position set via JS in updated() */
94
+ transform: translateX(calc(var(--control_selected-index, 0) * var(--control_dir, 1) * 100%));
95
+ transition: transform var(--bds-animation_transition-duration) var(--bds-animation_easing);
75
96
  }
76
97
 
77
98
  .radio {
@@ -84,6 +105,7 @@ export class BdsSegmentedControl extends LitElement {
84
105
 
85
106
  .item {
86
107
  position: relative;
108
+ z-index: 1;
87
109
  display: inline-flex;
88
110
  align-items: center;
89
111
  justify-content: center;
@@ -91,9 +113,9 @@ export class BdsSegmentedControl extends LitElement {
91
113
  font-size: var(--bds-font_size--body--s);
92
114
  font-family: var(--bds-font_family--body);
93
115
  font-weight: var(--bds-font_weight--semibold);
94
- color: var(--segmented_color, var(--bds-color_on-bg));
116
+ color: var(--control_label-color, var(--segmented_color, var(--bds-color_on-bg)));
95
117
  cursor: pointer;
96
- border-radius: calc(var(--bds-border_radius--s) - 2px);
118
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--full));
97
119
  transition: color var(--bds-animation_transition-duration) var(--bds-animation_easing);
98
120
  user-select: none;
99
121
  white-space: nowrap;
@@ -101,7 +123,7 @@ export class BdsSegmentedControl extends LitElement {
101
123
  }
102
124
 
103
125
  .item.--active {
104
- color: var(--segmented_color--active, var(--bds-color_on-interactive));
126
+ color: var(--control_label-color--active, var(--segmented_color--active, var(--bds-color_on-interactive)));
105
127
  }
106
128
 
107
129
  .item.--disabled {
@@ -109,21 +131,34 @@ export class BdsSegmentedControl extends LitElement {
109
131
  cursor: not-allowed;
110
132
  }
111
133
 
112
- .radio:focus-visible + .item-label {
134
+ /* Radio-mode items aren't directly focusable (the input is visually hidden inside
135
+ the label), so match focus-visible on the input itself via :has(); link-mode
136
+ items are focusable directly. */
137
+ .item:focus-visible,
138
+ .item:has(> .radio:focus-visible) {
113
139
  outline: var(--bds-outline_default);
114
- outline-offset: var(--bds-outline_offset);
140
+ outline-offset: calc(var(--bds-outline_offset) * -1);
141
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--full));
115
142
  }
116
143
 
117
- /* Outline variant: sliding inset-border indicator (positioned via JS like .thumb) */
144
+ @media (hover: hover) and (pointer: fine) {
145
+ .item:not(.--active, .--disabled):hover {
146
+ color: var(--control_label-color--hover, var(--bds-color_on-bg));
147
+ }
148
+ }
149
+
150
+ /* Outline variant: sliding inset-border indicator (positioned like .thumb) */
118
151
  .indicator {
119
152
  position: absolute;
120
- inset-block: 0.25rem;
121
- border-radius: calc(var(--bds-border_radius--s) - 2px);
153
+ inset-block: var(--control_track-pad, var(--bds-space_xxs));
154
+ inset-inline-start: var(--control_track-pad, var(--bds-space_xxs));
155
+ inline-size: calc((100% - 2 * var(--control_track-pad, var(--bds-space_xxs))) / var(--control_count, 1));
156
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--full));
122
157
  pointer-events: none;
123
158
  z-index: 2;
124
159
  display: none;
125
- transition: inset-inline-start var(--bds-animation_transition-duration) var(--bds-animation_easing),
126
- inline-size var(--bds-animation_transition-duration) var(--bds-animation_easing);
160
+ transform: translateX(calc(var(--control_selected-index, 0) * var(--control_dir, 1) * 100%));
161
+ transition: transform var(--bds-animation_transition-duration) var(--bds-animation_easing);
127
162
  }
128
163
 
129
164
  /* Outline variant — no thumb, sliding inset-border indicator, interactive active color */
@@ -132,17 +167,17 @@ export class BdsSegmentedControl extends LitElement {
132
167
  }
133
168
 
134
169
  :host([variant='outline']) .item {
135
- background-color: var(--segmented_item-bg, transparent);
170
+ background-color: var(--control_item-bg, var(--segmented_item-bg, transparent));
136
171
  }
137
172
 
138
173
  :host([variant='outline']) .item.--active {
139
- color: var(--segmented_color--active, var(--bds-color_interactive));
140
- background-color: var(--segmented_item-bg--active, var(--bds-color_bg));
174
+ color: var(--control_label-color--active, var(--segmented_color--active, var(--bds-color_interactive)));
175
+ background-color: var(--control_item-bg--active, var(--segmented_item-bg--active, var(--bds-color_bg)));
141
176
  }
142
177
 
143
178
  :host([variant='outline']) .indicator {
144
179
  display: block;
145
- box-shadow: inset 0 0 0 2px var(--bds-color_interactive);
180
+ box-shadow: inset 0 0 0 var(--control_indicator-width, 2px) var(--control_indicator-color, var(--bds-color_interactive));
146
181
  }
147
182
 
148
183
  @media (prefers-reduced-motion: reduce) {
@@ -169,6 +204,7 @@ export class BdsSegmentedControl extends LitElement {
169
204
 
170
205
  private _internals!: ElementInternals;
171
206
  private readonly _uid = Math.random().toString(36).slice(2, 8);
207
+ private _initialValue = '';
172
208
 
173
209
  constructor() {
174
210
  super();
@@ -180,6 +216,11 @@ export class BdsSegmentedControl extends LitElement {
180
216
  this.variant = 'outline';
181
217
  }
182
218
 
219
+ connectedCallback() {
220
+ super.connectedCallback();
221
+ this._initialValue = this.value;
222
+ }
223
+
183
224
  private get _options(): SegmentedOption[] {
184
225
  try {
185
226
  return JSON.parse(this.options) as SegmentedOption[];
@@ -192,52 +233,33 @@ export class BdsSegmentedControl extends LitElement {
192
233
  super.updated(changed);
193
234
  if (changed.has('value') || changed.has('options')) {
194
235
  this._internals.setFormValue?.(this.value || null);
195
- if (this.variant === 'filled') this._updateThumb();
196
- if (this.variant === 'outline') this._updateIndicator();
197
- }
198
- if (changed.has('variant')) {
199
- if (this.variant === 'filled') this._updateThumb();
200
- if (this.variant === 'outline') this._updateIndicator();
201
236
  }
202
237
  }
203
238
 
204
- private _positionSlider(el: HTMLElement | null | undefined, items: NodeListOf<HTMLElement>, selectedIndex: number) {
205
- if (!el || items.length === 0) return;
206
- const item = items[selectedIndex];
207
- if (!item) return;
208
- const controlRect = (item.parentElement as HTMLElement).getBoundingClientRect();
209
- const itemRect = item.getBoundingClientRect();
210
- el.style.insetInlineStart = `${itemRect.left - controlRect.left}px`;
211
- el.style.inlineSize = `${itemRect.width}px`;
212
- }
213
-
214
- private _updateThumb() {
215
- const selectedIndex = Math.max(0, this._options.findIndex(o => o.value === this.value));
216
- const items = this.shadowRoot?.querySelectorAll<HTMLElement>('.item');
217
- this._positionSlider(this.shadowRoot?.querySelector<HTMLElement>('.thumb'), items!, selectedIndex);
218
- }
219
-
220
- private _updateIndicator() {
221
- const selectedIndex = Math.max(0, this._options.findIndex(o => o.value === this.value));
222
- const items = this.shadowRoot?.querySelectorAll<HTMLElement>('.item');
223
- this._positionSlider(this.shadowRoot?.querySelector<HTMLElement>('.indicator'), items!, selectedIndex);
224
- }
225
-
226
239
  formResetCallback() {
227
- const firstOption = this._options[0];
228
- this.value = firstOption?.value ?? '';
240
+ const fallback = this._options[0]?.value ?? '';
241
+ this.value = this._initialValue || fallback;
229
242
  this._internals.setFormValue?.(this.value || null);
230
243
  }
231
244
 
232
245
  private _handleChange(optionValue: string) {
233
246
  this.value = optionValue;
247
+ this.dispatchEvent(new CustomEvent('bds-change', {
248
+ detail: { value: optionValue },
249
+ bubbles: true,
250
+ composed: true,
251
+ }));
252
+ // Deprecated: kept for backward compatibility, prefer 'bds-change'.
234
253
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
235
254
  }
236
255
 
237
256
  render() {
238
257
  const opts = this._options;
258
+ const selectedIndex = Math.max(0, opts.findIndex(o => o.value === this.value));
259
+ const controlStyle = `--control_count: ${Math.max(opts.length, 1)}; --control_selected-index: ${selectedIndex}`;
260
+
239
261
  return html`
240
- <div class="control" role="group">
262
+ <div class="control" role="group" style=${controlStyle}>
241
263
  <span class="thumb" aria-hidden="true"></span>
242
264
  <span class="indicator" aria-hidden="true"></span>
243
265
  ${opts.map((opt, i) => {
@@ -251,7 +273,7 @@ export class BdsSegmentedControl extends LitElement {
251
273
  class=${itemClass}
252
274
  href=${isDisabled ? nothing : opt.href}
253
275
  aria-current=${isActive ? 'page' : nothing}
254
- ?aria-disabled=${isDisabled}
276
+ aria-disabled=${isDisabled ? 'true' : nothing}
255
277
  >${opt.label}</a>
256
278
  `;
257
279
  }
@@ -71,4 +71,61 @@ describe('bds-select', () => {
71
71
  it('is form-associated', () => {
72
72
  expect(BdsSelect.formAssociated).toBe(true);
73
73
  });
74
+
75
+ it('fires a composed bds-change event that reaches a host-level listener', async () => {
76
+ const el = await fixture(`<bds-select name="country" options='${OPTIONS}'></bds-select>`);
77
+ const values: string[] = [];
78
+ let composed = false;
79
+ el.addEventListener('bds-change', (e: Event) => {
80
+ composed = (e as CustomEvent).composed;
81
+ values.push((e as CustomEvent).detail.value);
82
+ });
83
+ const select = el.shadowRoot!.querySelector<HTMLSelectElement>('select')!;
84
+ select.value = 'be';
85
+ select.dispatchEvent(new Event('change', { bubbles: true }));
86
+ expect(values).toEqual(['be']);
87
+ expect(composed).toBe(true);
88
+ cleanup(el);
89
+ });
90
+
91
+ it('renders a label when label attribute is set, associated via for/id', async () => {
92
+ const el = await fixture(`<bds-select name="country" label="Country" options='${OPTIONS}'></bds-select>`);
93
+ const label = el.shadowRoot!.querySelector('label')!;
94
+ const select = el.shadowRoot!.querySelector('select')!;
95
+ expect(label.textContent?.trim()).toContain('Country');
96
+ expect(select.id).toBeTruthy();
97
+ expect(label.getAttribute('for')).toBe(select.id);
98
+ cleanup(el);
99
+ });
100
+
101
+ it('forwards a host aria-label to the inner select when no label attribute is set', async () => {
102
+ const el = await fixture(`<bds-select name="country" aria-label="Country" options='${OPTIONS}'></bds-select>`);
103
+ const select = el.shadowRoot!.querySelector('select')!;
104
+ expect(select.getAttribute('aria-label')).toBe('Country');
105
+ cleanup(el);
106
+ });
107
+
108
+ it('does not set aria-label on the inner select when a label attribute is present', async () => {
109
+ const el = await fixture(`<bds-select name="country" label="Country" aria-label="Ignored" options='${OPTIONS}'></bds-select>`);
110
+ const select = el.shadowRoot!.querySelector('select')!;
111
+ expect(select.hasAttribute('aria-label')).toBe(false);
112
+ cleanup(el);
113
+ });
114
+
115
+ it('renders error message and sets aria-invalid/aria-describedby when error is set', async () => {
116
+ const el = await fixture(`<bds-select name="country" error="Please choose a country" options='${OPTIONS}'></bds-select>`);
117
+ const select = el.shadowRoot!.querySelector('select')!;
118
+ const errorMsg = el.shadowRoot!.querySelector('.message--error');
119
+ expect(select.getAttribute('aria-invalid')).toBe('true');
120
+ expect(errorMsg?.textContent?.trim()).toBe('Please choose a country');
121
+ expect(select.getAttribute('aria-describedby')).toContain('-error');
122
+ cleanup(el);
123
+ });
124
+
125
+ it('renders hint message when hint is set (no error)', async () => {
126
+ const el = await fixture(`<bds-select name="country" hint="Pick your country" options='${OPTIONS}'></bds-select>`);
127
+ const hint = el.shadowRoot!.querySelector('.message--hint');
128
+ expect(hint?.textContent?.trim()).toBe('Pick your country');
129
+ cleanup(el);
130
+ });
74
131
  });
@@ -1,4 +1,4 @@
1
- import { LitElement, css, html } from 'lit';
1
+ import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
3
  export interface SelectOption {
4
4
  value: string;
@@ -17,15 +17,22 @@ export interface SelectOption {
17
17
  * value — currently selected value
18
18
  * options — JSON array of `{ value, label, disabled? }` option objects
19
19
  * placeholder — placeholder option label (disabled, empty value)
20
+ * label — visible label text (rendered as a shadow <label for>)
21
+ * hint — helper text shown below the select
22
+ * error — error message; when set the select enters error state
20
23
  * required — boolean
21
24
  * disabled — boolean
22
25
  *
26
+ * When `label` is not provided, a host `aria-label` attribute (if present) is
27
+ * forwarded to the inner `<select>` so the control always has an accessible name.
28
+ *
23
29
  * Events:
24
- * change — native change event (forwarded from inner select)
30
+ * bds-change — fired when the selected value changes; `detail: { value: string }`
25
31
  *
26
32
  * @example
27
33
  * <bds-select
28
34
  * name="country"
35
+ * label="Country"
29
36
  * placeholder="Choose…"
30
37
  * options='[{"value":"nl","label":"Netherlands"},{"value":"be","label":"Belgium"}]'
31
38
  * ></bds-select>
@@ -34,6 +41,16 @@ export class BdsSelect extends LitElement {
34
41
  static formAssociated = true;
35
42
 
36
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
+
37
54
  :host {
38
55
  display: block;
39
56
  }
@@ -43,6 +60,20 @@ export class BdsSelect extends LitElement {
43
60
  pointer-events: none;
44
61
  }
45
62
 
63
+ .label {
64
+ display: block;
65
+ font-size: var(--bds-font_size--body--s);
66
+ font-family: var(--bds-font_family--body);
67
+ font-weight: var(--bds-font_weight--semibold);
68
+ color: var(--bds-color_on-bg);
69
+ margin-block-end: var(--bds-space_xxs);
70
+ }
71
+
72
+ .required {
73
+ color: var(--bds-color_error);
74
+ margin-inline-start: var(--bds-space_xxxs);
75
+ }
76
+
46
77
  .wrapper {
47
78
  position: relative;
48
79
  display: block;
@@ -52,11 +83,11 @@ export class BdsSelect extends LitElement {
52
83
  inline-size: 100%;
53
84
  font-family: var(--bds-font_family--body);
54
85
  font-size: var(--bds-font_size--body);
55
- padding: var(--bds-space_s);
56
- padding-inline-end: var(--bds-space_xl);
57
- border: none;
58
- --bdc_color: var(--select_border-color, currentcolor);
59
- --bdc-outline_radius: var(--bds-border_radius--xs);
86
+ padding: var(--select_padding, var(--bds-space_s));
87
+ padding-inline-end: var(--select_padding-end, var(--bds-space_xxl));
88
+ border: var(--select_border, none);
89
+ --bdc_color: currentcolor;
90
+ --bdc-outline_radius: var(--bds-border_radius--full);
60
91
 
61
92
  border-radius: var(--select_radius, var(--bdc-outline_radius));
62
93
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--select_shadow, var(--bdc-outline_shadow));
@@ -64,7 +95,8 @@ export class BdsSelect extends LitElement {
64
95
  color: var(--select_color, var(--bds-color_on-bg));
65
96
  appearance: none;
66
97
  cursor: pointer;
67
- transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing);
98
+ transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing),
99
+ background-color var(--bds-animation_transition-duration) var(--bds-animation_easing);
68
100
  }
69
101
 
70
102
  .select:focus {
@@ -76,6 +108,25 @@ export class BdsSelect extends LitElement {
76
108
  outline-offset: var(--bds-outline_offset);
77
109
  }
78
110
 
111
+ :host([error]) .select {
112
+ --bdc_color: var(--bdc_color--error);
113
+ }
114
+
115
+ .message {
116
+ margin-block-start: var(--bds-space_xxs);
117
+ font-size: var(--bds-font_size--body--s);
118
+ font-family: var(--bds-font_family--body);
119
+ }
120
+
121
+ .message--error {
122
+ color: var(--bds-color_error);
123
+ }
124
+
125
+ .message--hint {
126
+ color: var(--bds-color_on-bg--subtle);
127
+ font-style: italic;
128
+ }
129
+
79
130
  .chevron {
80
131
  position: absolute;
81
132
  inset-inline-end: var(--bds-space_s);
@@ -98,6 +149,9 @@ export class BdsSelect extends LitElement {
98
149
  value: { type: String },
99
150
  options: { type: String },
100
151
  placeholder: { type: String },
152
+ label: { type: String },
153
+ hint: { type: String },
154
+ error: { type: String, reflect: true },
101
155
  required: { type: Boolean, reflect: true },
102
156
  disabled: { type: Boolean, reflect: true },
103
157
  };
@@ -106,10 +160,14 @@ export class BdsSelect extends LitElement {
106
160
  declare value: string;
107
161
  declare options: string;
108
162
  declare placeholder: string;
163
+ declare label: string;
164
+ declare hint: string | undefined;
165
+ declare error: string | undefined;
109
166
  declare required: boolean;
110
167
  declare disabled: boolean;
111
168
 
112
169
  private _internals!: ElementInternals;
170
+ private readonly _uid = Math.random().toString(36).slice(2, 8);
113
171
 
114
172
  constructor() {
115
173
  super();
@@ -118,6 +176,7 @@ export class BdsSelect extends LitElement {
118
176
  this.value = '';
119
177
  this.options = '[]';
120
178
  this.placeholder = '';
179
+ this.label = '';
121
180
  this.required = false;
122
181
  this.disabled = false;
123
182
  }
@@ -144,18 +203,42 @@ export class BdsSelect extends LitElement {
144
203
 
145
204
  private _handleChange(e: Event) {
146
205
  this.value = (e.target as HTMLSelectElement).value;
206
+ this.dispatchEvent(new CustomEvent('bds-change', {
207
+ detail: { value: this.value },
208
+ bubbles: true,
209
+ composed: true,
210
+ }));
147
211
  }
148
212
 
149
213
  render() {
150
214
  const opts = this._options;
215
+ const id = `bds-select-${this._uid}`;
216
+ const hintId = `${id}-hint`;
217
+ const errorId = `${id}-error`;
218
+ const describedBy = [this.error && errorId, this.hint && hintId].filter(Boolean).join(' ') || undefined;
219
+ const hostAriaLabel = this.getAttribute('aria-label');
220
+
151
221
  return html`
222
+ ${this.label
223
+ ? html`
224
+ <label class="label" for=${id}>
225
+ ${this.label}
226
+ ${this.required ? html`<span class="required" aria-hidden="true">*</span>` : ''}
227
+ </label>
228
+ `
229
+ : ''}
152
230
  <div class="wrapper">
153
231
  <select
232
+ id=${id}
154
233
  class="select"
155
234
  name=${this.name}
156
235
  .value=${this.value}
157
236
  ?required=${this.required}
158
237
  ?disabled=${this.disabled}
238
+ aria-invalid=${this.error ? 'true' : 'false'}
239
+ aria-required=${this.required ? 'true' : 'false'}
240
+ aria-describedby=${describedBy ?? ''}
241
+ aria-label=${this.label ? nothing : (hostAriaLabel ?? nothing)}
159
242
  @change=${this._handleChange}
160
243
  >
161
244
  ${this.placeholder ? html`
@@ -175,6 +258,11 @@ export class BdsSelect extends LitElement {
175
258
  </svg>
176
259
  </span>
177
260
  </div>
261
+ ${this.error
262
+ ? html`<p id=${errorId} class="message message--error" role="alert">${this.error}</p>`
263
+ : this.hint
264
+ ? html`<p id=${hintId} class="message message--hint">${this.hint}</p>`
265
+ : ''}
178
266
  `;
179
267
  }
180
268
  }
@@ -38,4 +38,87 @@ describe('bds-slider', () => {
38
38
  it('is form-associated', () => {
39
39
  expect(BdsSlider.formAssociated).toBe(true);
40
40
  });
41
+
42
+ it('renders a label wired to the input via for/id', async () => {
43
+ const el = await fixture('<bds-slider name="volume" label="Volume"></bds-slider>');
44
+ const label = el.shadowRoot!.querySelector<HTMLLabelElement>('label')!;
45
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
46
+ expect(label).not.toBeNull();
47
+ expect(label.textContent?.trim()).toBe('Volume');
48
+ expect(label.getAttribute('for')).toBe(input.id);
49
+ expect(input.id).not.toBe('');
50
+ cleanup(el);
51
+ });
52
+
53
+ it('renders no label element when label is unset', async () => {
54
+ const el = await fixture('<bds-slider name="volume"></bds-slider>');
55
+ expect(el.shadowRoot!.querySelector('label')).toBeNull();
56
+ cleanup(el);
57
+ });
58
+
59
+ it('shows the current value next to the label when show-value is set', async () => {
60
+ const el = await fixture('<bds-slider name="volume" label="Volume" value="42" show-value></bds-slider>');
61
+ const value = el.shadowRoot!.querySelector('.value');
62
+ expect(value?.textContent?.trim()).toBe('42');
63
+ cleanup(el);
64
+ });
65
+
66
+ it('does not render a value element when show-value is unset', async () => {
67
+ const el = await fixture('<bds-slider name="volume" label="Volume" value="42"></bds-slider>');
68
+ expect(el.shadowRoot!.querySelector('.value')).toBeNull();
69
+ cleanup(el);
70
+ });
71
+
72
+ it('sets aria-invalid and aria-describedby and renders an error message when error is set', async () => {
73
+ const el = await fixture('<bds-slider name="volume" error="Too loud"></bds-slider>');
74
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
75
+ const message = el.shadowRoot!.querySelector<HTMLParagraphElement>('.message--error')!;
76
+ expect(input.getAttribute('aria-invalid')).toBe('true');
77
+ expect(input.getAttribute('aria-describedby')).toBe(message.id);
78
+ expect(message.textContent).toBe('Too loud');
79
+ expect(message.getAttribute('role')).toBe('alert');
80
+ cleanup(el);
81
+ });
82
+
83
+ it('renders a hint message and wires aria-describedby when hint is set (no error)', async () => {
84
+ const el = await fixture('<bds-slider name="volume" hint="Adjust to taste"></bds-slider>');
85
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
86
+ const message = el.shadowRoot!.querySelector<HTMLParagraphElement>('.message--hint')!;
87
+ expect(message).not.toBeNull();
88
+ expect(message.textContent).toBe('Adjust to taste');
89
+ expect(input.getAttribute('aria-invalid')).toBe('false');
90
+ expect(input.getAttribute('aria-describedby')).toBe(message.id);
91
+ cleanup(el);
92
+ });
93
+
94
+ it('fires a composed bds-change event that crosses the shadow boundary on release', async () => {
95
+ const el = await fixture('<bds-slider name="volume"></bds-slider>');
96
+ const values: number[] = [];
97
+ // A native `change` on the inner range input does not reliably cross the
98
+ // shadow boundary; `bds-change` is re-dispatched from the host so it does.
99
+ el.addEventListener('bds-change', (e: Event) => {
100
+ values.push((e as CustomEvent).detail.value);
101
+ });
102
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
103
+ input.value = '80';
104
+ input.dispatchEvent(new Event('change', { bubbles: true }));
105
+ expect(values).toEqual([80]);
106
+ cleanup(el);
107
+ });
108
+
109
+ it('restores the initial value attribute (not 0) on form reset', async () => {
110
+ const el = await fixture('<bds-slider name="volume" value="30" min="0" max="100"></bds-slider>') as BdsSlider;
111
+ el.value = 90;
112
+ el.formResetCallback();
113
+ expect(el.value).toBe(30);
114
+ cleanup(el);
115
+ });
116
+
117
+ it('clamps the restored reset value to min/max', async () => {
118
+ const el = await fixture('<bds-slider name="rating" value="3" min="1" max="5"></bds-slider>') as BdsSlider;
119
+ el.value = 5;
120
+ el.formResetCallback();
121
+ expect(el.value).toBe(3);
122
+ cleanup(el);
123
+ });
41
124
  });