@boostdev/design-system-components 2.14.1 → 2.16.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 (290) hide show
  1. package/AGENTS.md +20 -15
  2. package/dist/client.cjs +271 -205
  3. package/dist/client.css +808 -648
  4. package/dist/client.d.cts +19 -4
  5. package/dist/client.d.ts +19 -4
  6. package/dist/client.js +206 -139
  7. package/dist/index.cjs +271 -205
  8. package/dist/index.css +808 -648
  9. package/dist/index.d.cts +19 -4
  10. package/dist/index.d.ts +19 -4
  11. package/dist/index.js +206 -139
  12. package/dist/web-components/chunk-2DHW2WJZ.js +154 -0
  13. package/dist/web-components/{chunk-LDIPCTRN.js → chunk-2MJTO2IW.js} +48 -2
  14. package/dist/web-components/{chunk-3WAV6MDN.js → chunk-3FSGP35V.js} +1 -0
  15. package/dist/web-components/{chunk-KA3VPKMY.js → chunk-4MB2ICSK.js} +1 -0
  16. package/dist/web-components/{chunk-IDSM74LM.js → chunk-6XL5P76D.js} +3 -3
  17. package/dist/web-components/{chunk-P24JYC5V.js → chunk-7VXRMCAL.js} +10 -4
  18. package/dist/web-components/{chunk-CUKQ2L5B.js → chunk-AGI6YQRC.js} +9 -16
  19. package/dist/web-components/chunk-BDRV452N.js +51 -0
  20. package/dist/web-components/{chunk-3AY2YKCM.js → chunk-CKCPV347.js} +1 -0
  21. package/dist/web-components/{chunk-HBLJ4SLY.js → chunk-DD3OUXNG.js} +5 -5
  22. package/dist/web-components/{chunk-RVF7W653.js → chunk-DGOCPKHI.js} +30 -10
  23. package/dist/web-components/{chunk-2OLVQUBU.js → chunk-EYCW7TKB.js} +8 -15
  24. package/dist/web-components/{chunk-VANAKB6D.js → chunk-GPJWLAKU.js} +33 -16
  25. package/dist/web-components/{chunk-VED2DFJ6.js → chunk-GQNQBEYR.js} +8 -15
  26. package/dist/web-components/{chunk-WFVKU4GX.js → chunk-IKAJLROF.js} +49 -4
  27. package/dist/web-components/{chunk-RSZ3BWBK.js → chunk-KSK4RZZQ.js} +30 -7
  28. package/dist/web-components/{chunk-FEDABOR5.js → chunk-LHFUXZ52.js} +7 -15
  29. package/dist/web-components/{chunk-M3ECULRH.js → chunk-RBF7WPLI.js} +10 -8
  30. package/dist/web-components/{chunk-6G22I2CK.js → chunk-RZH5IVB5.js} +31 -1
  31. package/dist/web-components/chunk-SRKQ6GST.js +40 -0
  32. package/dist/web-components/{chunk-5HUAFCU6.js → chunk-TJV7UIXC.js} +7 -0
  33. package/dist/web-components/{chunk-J3HVUIUH.js → chunk-XI2U6U26.js} +8 -15
  34. package/dist/web-components/{chunk-JH6LQKLK.js → chunk-XJU7KITO.js} +8 -15
  35. package/dist/web-components/{chunk-XIZWAWMJ.js → chunk-XTPUKUN5.js} +16 -6
  36. package/dist/web-components/{chunk-JV5QT2OU.js → chunk-YLDQOESI.js} +27 -13
  37. package/dist/web-components/globals.js +1 -1
  38. package/dist/web-components/index.d.ts +1 -0
  39. package/dist/web-components/index.js +34 -29
  40. package/dist/web-components/interaction/bds-button.js +1 -1
  41. package/dist/web-components/interaction/bds-dropdown-menu-group.d.ts +41 -0
  42. package/dist/web-components/interaction/bds-dropdown-menu-group.js +7 -0
  43. package/dist/web-components/interaction/bds-dropdown-menu-item.d.ts +14 -1
  44. package/dist/web-components/interaction/bds-dropdown-menu-item.js +1 -1
  45. package/dist/web-components/interaction/bds-dropdown-menu.d.ts +2 -1
  46. package/dist/web-components/interaction/bds-dropdown-menu.js +1 -1
  47. package/dist/web-components/interaction/bds-tab.d.ts +5 -0
  48. package/dist/web-components/interaction/bds-tab.js +1 -1
  49. package/dist/web-components/interaction/bds-tooltip.js +1 -1
  50. package/dist/web-components/interaction/form/bds-checkbox-group.d.ts +6 -0
  51. package/dist/web-components/interaction/form/bds-checkbox-group.js +2 -1
  52. package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
  53. package/dist/web-components/interaction/form/bds-combobox.js +2 -1
  54. package/dist/web-components/interaction/form/bds-form-input.js +2 -1
  55. package/dist/web-components/interaction/form/bds-number-input.js +2 -1
  56. package/dist/web-components/interaction/form/bds-radio-group.d.ts +5 -0
  57. package/dist/web-components/interaction/form/bds-radio-group.js +2 -1
  58. package/dist/web-components/interaction/form/bds-radio.js +1 -1
  59. package/dist/web-components/interaction/form/bds-select.js +2 -1
  60. package/dist/web-components/interaction/form/bds-slider.js +2 -1
  61. package/dist/web-components/interaction/form/bds-switch.js +1 -1
  62. package/dist/web-components/interaction/form/bds-textarea.js +2 -1
  63. package/dist/web-components/ui/bds-alert.d.ts +8 -1
  64. package/dist/web-components/ui/bds-alert.js +1 -1
  65. package/dist/web-components/ui/bds-avatar.d.ts +11 -0
  66. package/dist/web-components/ui/bds-avatar.js +1 -1
  67. package/dist/web-components/ui/bds-notification-banner.d.ts +14 -1
  68. package/dist/web-components/ui/bds-notification-banner.js +1 -1
  69. package/dist/web-components/ui/bds-section-header.d.ts +6 -0
  70. package/dist/web-components/ui/bds-section-header.js +1 -1
  71. package/dist/web-components/ui/bds-separator.js +1 -1
  72. package/dist/web-components/ui/bds-table.js +1 -1
  73. package/package.json +6 -2
  74. package/src/components/interaction/Button/Button.mdx +7 -0
  75. package/src/components/interaction/Button/Button.module.css +17 -9
  76. package/src/components/interaction/Button/Button.stories.tsx +28 -0
  77. package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +35 -4
  78. package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +58 -10
  79. package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +114 -1
  80. package/src/components/interaction/DropdownMenu/DropdownMenu.stories.tsx +25 -0
  81. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +69 -17
  82. package/src/components/interaction/form/Checkbox/Checkbox.module.css +1 -0
  83. package/src/components/interaction/form/Checkbox/Checkbox.spec.tsx +7 -0
  84. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +1 -0
  85. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.module.css +7 -0
  86. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.spec.tsx +22 -0
  87. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +1 -1
  88. package/src/components/interaction/form/Combobox/Combobox.module.css +1 -0
  89. package/src/components/interaction/form/Combobox/Combobox.spec.tsx +7 -0
  90. package/src/components/interaction/form/FormInput/FormInput.mdx +9 -0
  91. package/src/components/interaction/form/FormInput/FormInput.module.css +1 -0
  92. package/src/components/interaction/form/FormInput/FormInput.spec.tsx +7 -0
  93. package/src/components/interaction/form/NumberInput/NumberInput.module.css +1 -0
  94. package/src/components/interaction/form/NumberInput/NumberInput.spec.tsx +7 -0
  95. package/src/components/interaction/form/Radio/Radio.module.css +1 -0
  96. package/src/components/interaction/form/Radio/Radio.spec.tsx +7 -0
  97. package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +1 -0
  98. package/src/components/interaction/form/RadioGroup/RadioGroup.module.css +7 -0
  99. package/src/components/interaction/form/RadioGroup/RadioGroup.spec.tsx +22 -0
  100. package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +1 -1
  101. package/src/components/interaction/form/Select/Select.module.css +1 -0
  102. package/src/components/interaction/form/Select/Select.spec.tsx +7 -0
  103. package/src/components/interaction/form/Switch/Switch.module.css +1 -0
  104. package/src/components/interaction/form/Switch/Switch.spec.tsx +7 -0
  105. package/src/components/interaction/form/Textarea/Textarea.module.css +1 -0
  106. package/src/components/interaction/form/Textarea/Textarea.spec.tsx +7 -0
  107. package/src/components/interaction/form/atoms/Message.module.css +14 -3
  108. package/src/components/interaction/form/atoms/Message.spec.tsx +22 -0
  109. package/src/components/interaction/form/atoms/Message.tsx +5 -0
  110. package/src/components/layout/SectionHeader/SectionHeader.mdx +18 -5
  111. package/src/components/layout/SectionHeader/SectionHeader.module.css +35 -14
  112. package/src/components/layout/SectionHeader/SectionHeader.spec.tsx +44 -0
  113. package/src/components/layout/SectionHeader/SectionHeader.stories.tsx +5 -0
  114. package/src/components/layout/SectionHeader/SectionHeader.tsx +3 -1
  115. package/src/components/ui/Alert/Alert.mdx +11 -0
  116. package/src/components/ui/Alert/Alert.module.css +30 -1
  117. package/src/components/ui/Alert/Alert.spec.tsx +21 -0
  118. package/src/components/ui/Alert/Alert.stories.tsx +20 -0
  119. package/src/components/ui/Alert/Alert.tsx +8 -1
  120. package/src/components/ui/Avatar/Avatar.mdx +22 -2
  121. package/src/components/ui/Avatar/Avatar.module.css +29 -2
  122. package/src/components/ui/Avatar/Avatar.spec.tsx +26 -0
  123. package/src/components/ui/Avatar/Avatar.stories.tsx +23 -0
  124. package/src/components/ui/Avatar/Avatar.tsx +4 -2
  125. package/src/components/ui/Avatar/avatarTone.spec.ts +41 -0
  126. package/src/components/ui/Avatar/avatarTone.ts +22 -0
  127. package/src/components/ui/Collapsible/Collapsible.module.css +1 -2
  128. package/src/components/ui/NotificationBanner/NotificationBanner.mdx +14 -0
  129. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +31 -1
  130. package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +29 -0
  131. package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +25 -0
  132. package/src/components/ui/NotificationBanner/NotificationBanner.tsx +15 -1
  133. package/src/components/ui/Separator/Separator.mdx +1 -0
  134. package/src/components/ui/Separator/Separator.module.css +6 -0
  135. package/src/components/ui/Separator/Separator.spec.tsx +19 -0
  136. package/src/components/ui/Separator/Separator.stories.tsx +15 -0
  137. package/src/components/ui/Table/Table.mdx +4 -1
  138. package/src/components/ui/Table/Table.module.css +7 -7
  139. package/src/components/ui/Table/Table.spec.tsx +11 -0
  140. package/src/components/ui/Tabs/Tabs.mdx +11 -5
  141. package/src/components/ui/Tabs/Tabs.module.css +23 -5
  142. package/src/components/ui/Tabs/Tabs.spec.tsx +39 -0
  143. package/src/components/ui/Tabs/Tabs.tsx +2 -1
  144. package/src/components/ui/Tabs/getNodeText.spec.tsx +23 -0
  145. package/src/components/ui/Tabs/getNodeText.ts +13 -0
  146. package/src/components/ui/Tooltip/Tooltip.mdx +6 -3
  147. package/src/components/ui/Tooltip/Tooltip.module.css +6 -2
  148. package/src/components/ui/Tooltip/Tooltip.spec.tsx +10 -0
  149. package/src/components/ui/Tooltip/Tooltip.stories.tsx +13 -0
  150. package/src/css/bdc.css +5 -2
  151. package/src/css/bdc.spec.ts +65 -0
  152. package/src/stories/DesignSystem/Borders.mdx +17 -9
  153. package/src/web-components/globals.ts +10 -4
  154. package/src/web-components/index.ts +1 -0
  155. package/src/web-components/interaction/BdsAccordion.mdx +1 -1
  156. package/src/web-components/interaction/BdsAccordion.stories.tsx +1 -1
  157. package/src/web-components/interaction/BdsButton.mdx +9 -1
  158. package/src/web-components/interaction/BdsButton.stories.tsx +42 -1
  159. package/src/web-components/interaction/BdsCollapsible.mdx +1 -1
  160. package/src/web-components/interaction/BdsCollapsible.stories.tsx +1 -1
  161. package/src/web-components/interaction/BdsDialog.mdx +1 -1
  162. package/src/web-components/interaction/BdsDialog.stories.tsx +1 -1
  163. package/src/web-components/interaction/BdsDrawer.mdx +1 -1
  164. package/src/web-components/interaction/BdsDrawer.stories.tsx +1 -1
  165. package/src/web-components/interaction/BdsDropdownMenu.mdx +62 -6
  166. package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +32 -7
  167. package/src/web-components/interaction/BdsPopover.mdx +1 -1
  168. package/src/web-components/interaction/BdsPopover.stories.tsx +1 -1
  169. package/src/web-components/interaction/BdsSkipLink.mdx +1 -1
  170. package/src/web-components/interaction/BdsSkipLink.stories.tsx +1 -1
  171. package/src/web-components/interaction/BdsTabs.mdx +10 -1
  172. package/src/web-components/interaction/BdsTabs.stories.tsx +1 -1
  173. package/src/web-components/interaction/BdsToastProvider.mdx +1 -1
  174. package/src/web-components/interaction/BdsToastProvider.stories.tsx +1 -1
  175. package/src/web-components/interaction/BdsTooltip.mdx +13 -5
  176. package/src/web-components/interaction/BdsTooltip.stories.tsx +12 -12
  177. package/src/web-components/interaction/bds-button.ts +16 -6
  178. package/src/web-components/interaction/bds-dropdown-menu-group.ts +72 -0
  179. package/src/web-components/interaction/bds-dropdown-menu-item.ts +65 -17
  180. package/src/web-components/interaction/bds-dropdown-menu.spec.ts +135 -0
  181. package/src/web-components/interaction/bds-dropdown-menu.ts +5 -4
  182. package/src/web-components/interaction/bds-tab.spec.ts +34 -2
  183. package/src/web-components/interaction/bds-tab.ts +31 -6
  184. package/src/web-components/interaction/bds-tooltip.spec.ts +16 -0
  185. package/src/web-components/interaction/bds-tooltip.ts +10 -8
  186. package/src/web-components/interaction/form/BdsCheckbox.mdx +5 -1
  187. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +1 -1
  188. package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +5 -1
  189. package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +1 -1
  190. package/src/web-components/interaction/form/BdsCombobox.mdx +5 -1
  191. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +1 -1
  192. package/src/web-components/interaction/form/BdsFieldGroup.stories.tsx +1 -1
  193. package/src/web-components/interaction/form/BdsFileInput.mdx +1 -1
  194. package/src/web-components/interaction/form/BdsFileInput.stories.tsx +1 -1
  195. package/src/web-components/interaction/form/BdsFormInput.mdx +8 -1
  196. package/src/web-components/interaction/form/BdsFormInput.stories.tsx +1 -1
  197. package/src/web-components/interaction/form/BdsNumberInput.mdx +5 -1
  198. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +1 -1
  199. package/src/web-components/interaction/form/BdsRadio.mdx +5 -1
  200. package/src/web-components/interaction/form/BdsRadio.stories.tsx +1 -1
  201. package/src/web-components/interaction/form/BdsRadioGroup.mdx +5 -1
  202. package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +1 -1
  203. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +1 -1
  204. package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +1 -1
  205. package/src/web-components/interaction/form/BdsSelect.mdx +5 -1
  206. package/src/web-components/interaction/form/BdsSelect.stories.tsx +1 -1
  207. package/src/web-components/interaction/form/BdsSlider.mdx +5 -1
  208. package/src/web-components/interaction/form/BdsSlider.stories.tsx +1 -1
  209. package/src/web-components/interaction/form/BdsSwitch.mdx +5 -1
  210. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +1 -1
  211. package/src/web-components/interaction/form/BdsTextarea.mdx +5 -1
  212. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +1 -1
  213. package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +32 -3
  214. package/src/web-components/interaction/form/bds-checkbox-group.ts +33 -17
  215. package/src/web-components/interaction/form/bds-checkbox.ts +1 -0
  216. package/src/web-components/interaction/form/bds-combobox.ts +6 -16
  217. package/src/web-components/interaction/form/bds-form-input.ts +6 -16
  218. package/src/web-components/interaction/form/bds-number-input.ts +6 -16
  219. package/src/web-components/interaction/form/bds-radio-group.spec.ts +32 -3
  220. package/src/web-components/interaction/form/bds-radio-group.ts +26 -14
  221. package/src/web-components/interaction/form/bds-radio.ts +1 -0
  222. package/src/web-components/interaction/form/bds-select.ts +6 -16
  223. package/src/web-components/interaction/form/bds-slider.ts +5 -16
  224. package/src/web-components/interaction/form/bds-switch.ts +1 -0
  225. package/src/web-components/interaction/form/bds-textarea.ts +6 -16
  226. package/src/web-components/interaction/form/field-message.spec.ts +62 -0
  227. package/src/web-components/interaction/form/field-message.ts +55 -0
  228. package/src/web-components/layout/BdsGrid.mdx +1 -1
  229. package/src/web-components/layout/BdsGrid.stories.tsx +1 -1
  230. package/src/web-components/layout/BdsGridItem.mdx +1 -1
  231. package/src/web-components/layout/BdsGridItem.stories.tsx +1 -1
  232. package/src/web-components/ui/BdsAlert.mdx +19 -1
  233. package/src/web-components/ui/BdsAlert.stories.tsx +29 -3
  234. package/src/web-components/ui/BdsAvatar.mdx +20 -3
  235. package/src/web-components/ui/BdsAvatar.stories.tsx +25 -2
  236. package/src/web-components/ui/BdsBadge.mdx +1 -1
  237. package/src/web-components/ui/BdsBadge.stories.tsx +1 -1
  238. package/src/web-components/ui/BdsBreadcrumb.mdx +1 -1
  239. package/src/web-components/ui/BdsBreadcrumb.stories.tsx +1 -1
  240. package/src/web-components/ui/BdsButtonContainer.mdx +1 -1
  241. package/src/web-components/ui/BdsButtonContainer.stories.tsx +1 -1
  242. package/src/web-components/ui/BdsCalendar.mdx +1 -1
  243. package/src/web-components/ui/BdsCalendar.stories.tsx +1 -1
  244. package/src/web-components/ui/BdsCalendarRange.mdx +1 -1
  245. package/src/web-components/ui/BdsCalendarRange.stories.tsx +1 -1
  246. package/src/web-components/ui/BdsCard.mdx +1 -1
  247. package/src/web-components/ui/BdsCard.stories.tsx +1 -1
  248. package/src/web-components/ui/BdsCarousel.mdx +1 -1
  249. package/src/web-components/ui/BdsCarousel.stories.tsx +1 -1
  250. package/src/web-components/ui/BdsDescriptionList.mdx +1 -1
  251. package/src/web-components/ui/BdsDescriptionList.stories.tsx +1 -1
  252. package/src/web-components/ui/BdsIconWrapper.mdx +1 -1
  253. package/src/web-components/ui/BdsIconWrapper.stories.tsx +1 -1
  254. package/src/web-components/ui/BdsLink.mdx +1 -1
  255. package/src/web-components/ui/BdsLink.stories.tsx +1 -1
  256. package/src/web-components/ui/BdsLoading.mdx +1 -1
  257. package/src/web-components/ui/BdsLoading.stories.tsx +1 -1
  258. package/src/web-components/ui/BdsNotificationBanner.mdx +10 -1
  259. package/src/web-components/ui/BdsNotificationBanner.stories.tsx +29 -2
  260. package/src/web-components/ui/BdsPagination.mdx +1 -1
  261. package/src/web-components/ui/BdsPagination.stories.tsx +1 -1
  262. package/src/web-components/ui/BdsProgress.mdx +1 -1
  263. package/src/web-components/ui/BdsProgress.stories.tsx +1 -1
  264. package/src/web-components/ui/BdsProgressCircle.mdx +1 -1
  265. package/src/web-components/ui/BdsProgressCircle.stories.tsx +1 -1
  266. package/src/web-components/ui/BdsRating.mdx +1 -1
  267. package/src/web-components/ui/BdsRating.stories.tsx +1 -1
  268. package/src/web-components/ui/BdsSectionHeader.mdx +18 -6
  269. package/src/web-components/ui/BdsSectionHeader.stories.tsx +10 -2
  270. package/src/web-components/ui/BdsSeparator.mdx +2 -1
  271. package/src/web-components/ui/BdsSeparator.stories.tsx +13 -1
  272. package/src/web-components/ui/BdsSkeleton.mdx +1 -1
  273. package/src/web-components/ui/BdsSkeleton.stories.tsx +1 -1
  274. package/src/web-components/ui/BdsTable.mdx +5 -1
  275. package/src/web-components/ui/BdsTable.stories.tsx +1 -1
  276. package/src/web-components/ui/BdsTypography.mdx +1 -1
  277. package/src/web-components/ui/BdsTypography.stories.tsx +1 -1
  278. package/src/web-components/ui/bds-alert.spec.ts +27 -0
  279. package/src/web-components/ui/bds-alert.ts +34 -1
  280. package/src/web-components/ui/bds-avatar.spec.ts +47 -0
  281. package/src/web-components/ui/bds-avatar.ts +36 -3
  282. package/src/web-components/ui/bds-notification-banner.spec.ts +45 -0
  283. package/src/web-components/ui/bds-notification-banner.ts +53 -1
  284. package/src/web-components/ui/bds-section-header.spec.ts +36 -3
  285. package/src/web-components/ui/bds-section-header.ts +32 -10
  286. package/src/web-components/ui/bds-separator.spec.ts +8 -0
  287. package/src/web-components/ui/bds-separator.ts +7 -0
  288. package/src/web-components/ui/bds-table.spec.ts +11 -0
  289. package/src/web-components/ui/bds-table.ts +5 -5
  290. package/dist/web-components/chunk-QZAIRJ75.js +0 -111
@@ -7,7 +7,7 @@ import * as Stories from './BdsToastProvider.stories';
7
7
 
8
8
  Framework-agnostic toast notification provider. Wrap your page content in `<bds-toast-provider>` to enable toast notifications that render in the browser top layer (above fixed/sticky elements). Auto-dismisses after 5 seconds.
9
9
 
10
- > **Status: experimental** — API may change before stable release.
10
+ > **Status: alpha** — API may change before stable release.
11
11
 
12
12
  ## Installation
13
13
 
@@ -37,7 +37,7 @@ function ToastDemo() {
37
37
  const meta = {
38
38
  title: 'Web Components/Interaction/ToastProvider',
39
39
  component: ToastDemo,
40
- tags: ['!stable', 'experimental'],
40
+ tags: ['!stable', 'alpha'],
41
41
  parameters: { layout: 'centered' },
42
42
  } satisfies Meta<typeof ToastDemo>;
43
43
 
@@ -7,7 +7,7 @@ import * as Stories from './BdsTooltip.stories';
7
7
 
8
8
  Framework-agnostic Tooltip custom element. Displays a small informational label on hover and keyboard focus using CSS-only visibility — no JavaScript positioning required.
9
9
 
10
- > **Status: experimental** — API may change before stable release.
10
+ > **Status: alpha** — API may change before stable release.
11
11
 
12
12
  ## Installation
13
13
 
@@ -52,6 +52,9 @@ Or in HTML without a bundler:
52
52
  ### Right placement
53
53
  <Canvas of={Stories.Right} />
54
54
 
55
+ ### Long text
56
+ <Canvas of={Stories.LongText} />
57
+
55
58
  ### All placements
56
59
  <Canvas of={Stories.AllPlacements} />
57
60
 
@@ -74,10 +77,15 @@ Or in HTML without a bundler:
74
77
 
75
78
  ## CSS Custom Properties
76
79
 
77
- | Property | Description |
78
- |----------|-------------|
79
- | `--tooltip_bg` | Tooltip background colour (default: `var(--bds-color_on-bg)`) |
80
- | `--tooltip_text` | Tooltip text colour (default: `var(--bds-color_bg)`) |
80
+ | Property | Default | Description |
81
+ |----------|---------|-------------|
82
+ | `--tooltip_bg` | `var(--bds-color_on-bg)` | Tooltip background colour |
83
+ | `--tooltip_text` | `var(--bds-color_bg)` | Tooltip text colour |
84
+ | `--tooltip_radius` | `var(--bds-border_radius--xs)` | Tooltip corner radius |
85
+ | `--tooltip_padding` | `var(--bds-space_xxs) var(--bds-space_s)` | Tooltip padding |
86
+ | `--tooltip_font-size` | `var(--bds-font_size--body--s)` | Tooltip text size |
87
+ | `--tooltip_offset` | `var(--bds-space_xs)` | Gap between the trigger and the tooltip |
88
+ | `--tooltip_max-inline-size` | `20rem` | Maximum inline size before content wraps. The tooltip is as wide as its text (`max-content`) up to this value |
81
89
 
82
90
  ## Usage in plain HTML
83
91
 
@@ -16,14 +16,14 @@ function BdsTooltip({
16
16
  return React.createElement(
17
17
  'bds-tooltip',
18
18
  { content, placement },
19
- children ?? React.createElement('button', { type: 'button' }, 'Hover me'),
19
+ children ?? React.createElement('bds-button', null, 'Hover me'),
20
20
  );
21
21
  }
22
22
 
23
23
  const meta = {
24
24
  title: 'Web Components/UI/Tooltip',
25
25
  component: BdsTooltip,
26
- tags: ['!stable', 'experimental'],
26
+ tags: ['!stable', 'alpha'],
27
27
  parameters: { layout: 'centered' },
28
28
  argTypes: {
29
29
  content: { control: 'text' },
@@ -44,11 +44,7 @@ export const OnButton: Story = {
44
44
  React.createElement(
45
45
  'bds-tooltip',
46
46
  { content: args.content, placement: args.placement },
47
- React.createElement(
48
- 'button',
49
- { type: 'button', style: { padding: '0.5rem 1rem', cursor: 'pointer' } },
50
- 'Save',
51
- ),
47
+ React.createElement('bds-button', null, 'Save'),
52
48
  ),
53
49
  };
54
50
 
@@ -64,6 +60,14 @@ export const Right: Story = {
64
60
  args: { content: 'Appears to the right', placement: 'right' },
65
61
  };
66
62
 
63
+ export const LongText: Story = {
64
+ args: {
65
+ content:
66
+ 'Longer explanation that wraps onto a second line once it reaches the maximum width of the tooltip.',
67
+ placement: 'bottom',
68
+ },
69
+ };
70
+
67
71
  export const AllPlacements: Story = {
68
72
  render: () => (
69
73
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, auto)', gap: '4rem', padding: '3rem' }}>
@@ -74,11 +78,7 @@ export const AllPlacements: Story = {
74
78
  React.createElement(
75
79
  'bds-tooltip',
76
80
  { content: `Placement: ${placement}`, placement },
77
- React.createElement(
78
- 'button',
79
- { type: 'button', style: { padding: '0.5rem 1rem', cursor: 'pointer' } },
80
- placement,
81
- ),
81
+ React.createElement('bds-button', null, placement),
82
82
  ),
83
83
  ),
84
84
  )}
@@ -70,7 +70,9 @@ export class BdsButton extends LitElement {
70
70
  all: unset;
71
71
  position: relative;
72
72
  font: inherit;
73
- padding-inline: var(--bds-space_l);
73
+ --button_padding-inline--size: var(--bds-space_l);
74
+
75
+ padding-inline: var(--button_padding-inline--size);
74
76
  display: inline-flex;
75
77
  gap: var(--bds-space_xs);
76
78
  border-radius: var(--button_radius, var(--bds-border_radius--full));
@@ -120,17 +122,17 @@ export class BdsButton extends LitElement {
120
122
  .button.small {
121
123
  --button_height: 2.25em;
122
124
  --button_font-size: var(--bds-font_size--body--s);
123
- padding-inline: var(--bds-space_m);
125
+ --button_padding-inline--size: var(--bds-space_m);
124
126
  }
125
127
 
126
128
  .button.medium {
127
129
  --button_height: 3em;
128
- padding-inline: var(--bds-space_l);
130
+ --button_padding-inline--size: var(--bds-space_l);
129
131
  }
130
132
 
131
133
  .button.large {
132
134
  --button_font-size: var(--bds-font_size--heading-3);
133
- padding-inline: var(--bds-space_xl);
135
+ --button_padding-inline--size: var(--bds-space_xl);
134
136
  }
135
137
 
136
138
  /* Pulse */
@@ -173,15 +175,23 @@ export class BdsButton extends LitElement {
173
175
  align-items: center;
174
176
  }
175
177
 
178
+ /* Icon offset — pulls the icon into the padding so the optical gap between
179
+ icon and edge matches the gap between label and edge. Defaults to half
180
+ the size's inline padding (--button_padding-inline--size, set above per
181
+ size), so it scales automatically with size and with the responsive
182
+ space tokens. --button_icon-offset is the public override; it is read
183
+ only as a var() fallback here, never declared on .button, so a value
184
+ set on the host or an ancestor inherits through the shadow boundary
185
+ instead of being shadowed by a same-element declaration. */
176
186
  .icon-start.has-content {
177
187
  display: flex;
178
- margin-inline-start: calc(var(--bds-space_s) * -1);
188
+ margin-inline-start: calc(var(--button_icon-offset, calc(var(--button_padding-inline--size) / 2)) * -1);
179
189
  transition: var(--bds-animation_transition);
180
190
  }
181
191
 
182
192
  .icon-end.has-content {
183
193
  display: flex;
184
- margin-inline-end: calc(var(--bds-space_s) * -1);
194
+ margin-inline-end: calc(var(--button_icon-offset, calc(var(--button_padding-inline--size) / 2)) * -1);
185
195
  transition: var(--bds-animation_transition);
186
196
  }
187
197
 
@@ -0,0 +1,72 @@
1
+ import { LitElement, css, html, nothing } from 'lit';
2
+
3
+ /**
4
+ * `<bds-dropdown-menu-group>` — a labelled group of `<bds-dropdown-menu-item>`
5
+ * elements inside a `<bds-dropdown-menu>`.
6
+ *
7
+ * The shadow root renders a `role="group"` element named by the visible label
8
+ * (`aria-labelledby` inside the same shadow root). The label is not focusable;
9
+ * keyboard navigation in the menu only visits the items.
10
+ *
11
+ * Attributes:
12
+ * label — visible group label, also the accessible name of the group
13
+ *
14
+ * Slots:
15
+ * (default) — `<bds-dropdown-menu-item>` elements
16
+ *
17
+ * @example
18
+ * <bds-dropdown-menu-group label="Edit">
19
+ * <bds-dropdown-menu-item value="edit">Edit</bds-dropdown-menu-item>
20
+ * </bds-dropdown-menu-group>
21
+ */
22
+ export class BdsDropdownMenuGroup extends LitElement {
23
+ static styles = css`
24
+ /* Shadow DOM does not inherit the global box-sizing reset, so set it here. */
25
+ :host,
26
+ *,
27
+ *::before,
28
+ *::after {
29
+ box-sizing: border-box;
30
+ }
31
+
32
+ :host {
33
+ display: block;
34
+ }
35
+
36
+ .label {
37
+ padding: var(--dropdown_group-label-padding, var(--bds-space_xs) var(--bds-space_s) var(--bds-space_xxs));
38
+ font-family: var(--bds-font_family--body);
39
+ font-size: var(--dropdown_group-label-font-size, var(--bds-font_size--body--s));
40
+ font-weight: var(--dropdown_group-label-font-weight, var(--bds-font_weight--bold));
41
+ color: var(--dropdown_group-label-color, var(--bds-color_on-bg--muted, var(--bds-color_on-bg)));
42
+ }
43
+ `;
44
+
45
+ static properties = {
46
+ label: { type: String, reflect: true },
47
+ };
48
+
49
+ declare label: string;
50
+
51
+ constructor() {
52
+ super();
53
+ this.label = '';
54
+ }
55
+
56
+ render() {
57
+ return html`
58
+ <div role="group" aria-labelledby=${this.label ? 'label' : nothing}>
59
+ ${this.label ? html`<div id="label" class="label">${this.label}</div>` : nothing}
60
+ <slot></slot>
61
+ </div>
62
+ `;
63
+ }
64
+ }
65
+
66
+ customElements.define('bds-dropdown-menu-group', BdsDropdownMenuGroup);
67
+
68
+ declare global {
69
+ interface HTMLElementTagNameMap {
70
+ 'bds-dropdown-menu-group': BdsDropdownMenuGroup;
71
+ }
72
+ }
@@ -1,4 +1,4 @@
1
- import { LitElement, css, html } from 'lit';
1
+ import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
3
  /**
4
4
  * `<bds-dropdown-menu-item>` — a single item inside a `<bds-dropdown-menu>`.
@@ -6,9 +6,12 @@ import { LitElement, css, html } from 'lit';
6
6
  * Attributes:
7
7
  * value — value associated with this item
8
8
  * disabled — disables this item
9
- * destructive — renders the item in a destructive (red) style
9
+ * destructive — renders the item in a destructive (error colour) style
10
+ * shortcut — keyboard shortcut as display text (decorative, `aria-hidden`);
11
+ * the consumer wires the actual key
10
12
  *
11
13
  * Slots:
14
+ * icon — optional icon shown before the label (decorative)
12
15
  * (default) — item label text
13
16
  *
14
17
  * Events:
@@ -34,7 +37,7 @@ export class BdsDropdownMenuItem extends LitElement {
34
37
  }
35
38
 
36
39
  :host([disabled]) {
37
- opacity: 0.5;
40
+ opacity: var(--dropdown_item-opacity--disabled, 0.4);
38
41
  pointer-events: none;
39
42
  }
40
43
 
@@ -43,36 +46,67 @@ export class BdsDropdownMenuItem extends LitElement {
43
46
  align-items: center;
44
47
  gap: var(--bds-space_xs);
45
48
  inline-size: 100%;
46
- padding: var(--bds-space_xs) var(--bds-space_s);
47
- font-size: var(--bds-font_size--body);
49
+ padding: var(--dropdown_item-padding, var(--bds-space_xs) var(--bds-space_s));
50
+ font-size: var(--dropdown_item-font-size, var(--bds-font_size--body));
48
51
  font-family: var(--bds-font_family--body);
49
- color: var(--bds-color_on-bg);
52
+ color: inherit;
50
53
  background: none;
51
54
  border: none;
52
55
  text-align: start;
53
56
  cursor: pointer;
54
- border-radius: var(--bds-border_radius--xs);
57
+ border-radius: var(--dropdown_item-radius, var(--bds-border_radius--xs));
55
58
  transition: var(--bds-animation_transition);
56
59
  }
57
60
 
58
61
  :host([destructive]) .item {
59
- color: var(--bds-color_error);
62
+ color: var(--dropdown_item-color--destructive, var(--bds-color_error_on-bg));
63
+ }
64
+
65
+ .item:focus-visible {
66
+ outline: var(--bds-outline_default);
67
+ outline-offset: calc(var(--bds-outline_offset) * -1);
68
+ }
69
+
70
+ .item:not(:disabled):focus-visible {
71
+ background-color: var(--dropdown_item-bg--hover, var(--bds-color_primary--subtle, var(--bds-color_blue--subtle)));
72
+ color: var(--dropdown_item-color--hover, var(--bds-color_on-primary--subtle, var(--bds-color_on-blue--subtle)));
73
+ }
74
+
75
+ :host([destructive]) .item:not(:disabled):focus-visible {
76
+ background-color: var(--dropdown_item-bg--destructive-hover, var(--bds-color_error--subtle));
77
+ color: var(--dropdown_item-color--destructive-hover, var(--bds-color_on-error--subtle));
60
78
  }
61
79
 
62
80
  @media (hover: hover) and (pointer: fine) {
63
- .item:hover {
64
- background-color: var(--dropdown_item-bg--hover, var(--bds-color_bg--subtle));
65
- color: var(--dropdown_item-color--hover, var(--bds-color_interactive_on-bg));
81
+ .item:not(:disabled):hover {
82
+ background-color: var(--dropdown_item-bg--hover, var(--bds-color_primary--subtle, var(--bds-color_blue--subtle)));
83
+ color: var(--dropdown_item-color--hover, var(--bds-color_on-primary--subtle, var(--bds-color_on-blue--subtle)));
66
84
  }
67
85
 
68
- :host([destructive]) .item:hover {
69
- background-color: color-mix(in srgb, var(--bds-color_error) 10%, transparent);
86
+ :host([destructive]) .item:not(:disabled):hover {
87
+ background-color: var(--dropdown_item-bg--destructive-hover, var(--bds-color_error--subtle));
88
+ color: var(--dropdown_item-color--destructive-hover, var(--bds-color_on-error--subtle));
70
89
  }
71
90
  }
72
91
 
73
- .item:focus-visible {
74
- outline: var(--bds-outline_default);
75
- outline-offset: var(--bds-outline_offset);
92
+ .icon[hidden] {
93
+ display: none;
94
+ }
95
+
96
+ .icon {
97
+ display: flex;
98
+ align-items: center;
99
+ flex-shrink: 0;
100
+ }
101
+
102
+ .label {
103
+ flex: 1;
104
+ }
105
+
106
+ .shortcut {
107
+ flex-shrink: 0;
108
+ color: var(--dropdown_shortcut-color, var(--bds-color_on-bg--muted, var(--bds-color_on-bg)));
109
+ font-size: var(--dropdown_shortcut-font-size, var(--bds-font_size--body--s));
76
110
  }
77
111
  `;
78
112
 
@@ -80,17 +114,27 @@ export class BdsDropdownMenuItem extends LitElement {
80
114
  value: { type: String, reflect: true },
81
115
  disabled: { type: Boolean, reflect: true },
82
116
  destructive: { type: Boolean, reflect: true },
117
+ shortcut: { type: String, reflect: true },
118
+ _hasIcon: { state: true },
83
119
  };
84
120
 
85
121
  declare value: string;
86
122
  declare disabled: boolean;
87
123
  declare destructive: boolean;
124
+ declare shortcut: string;
125
+ declare _hasIcon: boolean;
88
126
 
89
127
  constructor() {
90
128
  super();
91
129
  this.value = '';
92
130
  this.disabled = false;
93
131
  this.destructive = false;
132
+ this.shortcut = '';
133
+ this._hasIcon = false;
134
+ }
135
+
136
+ private _onIconSlotChange(e: Event) {
137
+ this._hasIcon = (e.target as HTMLSlotElement).assignedNodes().length > 0;
94
138
  }
95
139
 
96
140
  private _handleClick() {
@@ -120,7 +164,11 @@ export class BdsDropdownMenuItem extends LitElement {
120
164
  @click=${this._handleClick}
121
165
  @keydown=${this._handleKeydown}
122
166
  >
123
- <slot></slot>
167
+ <span class="icon" aria-hidden="true" ?hidden=${!this._hasIcon}>
168
+ <slot name="icon" @slotchange=${this._onIconSlotChange}></slot>
169
+ </span>
170
+ <span class="label"><slot></slot></span>
171
+ ${this.shortcut ? html`<span class="shortcut" aria-hidden="true">${this.shortcut}</span>` : nothing}
124
172
  </button>
125
173
  `;
126
174
  }
@@ -1,6 +1,13 @@
1
1
  import { fixture, cleanup } from '../test/helpers';
2
2
  import { BdsDropdownMenu } from './bds-dropdown-menu';
3
3
  import { BdsDropdownMenuItem } from './bds-dropdown-menu-item';
4
+ import { BdsDropdownMenuGroup } from './bds-dropdown-menu-group';
5
+ import { readFileSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+
8
+ const itemSource = readFileSync(resolve(process.cwd(), 'src/web-components/interaction/bds-dropdown-menu-item.ts'), 'utf8');
9
+ const groupSource = readFileSync(resolve(process.cwd(), 'src/web-components/interaction/bds-dropdown-menu-group.ts'), 'utf8');
10
+ const menuSource = readFileSync(resolve(process.cwd(), 'src/web-components/interaction/bds-dropdown-menu.ts'), 'utf8');
4
11
 
5
12
  describe('bds-dropdown-menu', () => {
6
13
  it('is registered as a custom element', () => {
@@ -163,3 +170,131 @@ describe('bds-dropdown-menu-item', () => {
163
170
  cleanup(el);
164
171
  });
165
172
  });
173
+
174
+ describe('bds-dropdown-menu-item colour', () => {
175
+ it('inherits the colour from the menu panel so --dropdown_on-color applies', () => {
176
+ expect(String(BdsDropdownMenuItem.styles)).toMatch(/\.item \{[^}]*color:\s*inherit/);
177
+ expect(String(BdsDropdownMenuItem.styles)).not.toMatch(/\.item \{[^}]*color:\s*var\(--bds-color_on-bg\)/);
178
+ expect(itemSource).toContain(':host([destructive]) .item {');
179
+ });
180
+ });
181
+
182
+ describe('bds-dropdown-menu-item shortcut, icon and destructive', () => {
183
+ it('renders the shortcut aria-hidden and reflects the attribute', async () => {
184
+ const el = await fixture('<bds-dropdown-menu-item value="edit" shortcut="⌘E">Edit</bds-dropdown-menu-item>') as BdsDropdownMenuItem;
185
+ const shortcut = el.shadowRoot!.querySelector('.shortcut')!;
186
+ expect(shortcut.textContent).toBe('⌘E');
187
+ expect(shortcut.getAttribute('aria-hidden')).toBe('true');
188
+ expect(el.getAttribute('shortcut')).toBe('⌘E');
189
+ cleanup(el);
190
+ });
191
+
192
+ it('omits the shortcut element when no shortcut is set', async () => {
193
+ const el = await fixture('<bds-dropdown-menu-item value="edit">Edit</bds-dropdown-menu-item>');
194
+ expect(el.shadowRoot!.querySelector('.shortcut')).toBeNull();
195
+ cleanup(el);
196
+ });
197
+
198
+ it('offers an icon slot before the label, hidden until filled', async () => {
199
+ const el = await fixture('<bds-dropdown-menu-item value="edit">Edit</bds-dropdown-menu-item>') as BdsDropdownMenuItem;
200
+ const icon = el.shadowRoot!.querySelector('.icon')!;
201
+ expect(icon.querySelector('slot[name="icon"]')).toBeTruthy();
202
+ expect(icon.hasAttribute('hidden')).toBe(true);
203
+ expect(icon.compareDocumentPosition(el.shadowRoot!.querySelector('.label')!) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
204
+ cleanup(el);
205
+ });
206
+
207
+ it('reflects the destructive attribute', async () => {
208
+ const el = await fixture('<bds-dropdown-menu-item value="delete" destructive>Delete</bds-dropdown-menu-item>') as BdsDropdownMenuItem;
209
+ expect(el.destructive).toBe(true);
210
+ expect(el.hasAttribute('destructive')).toBe(true);
211
+ cleanup(el);
212
+ });
213
+
214
+ it.each([
215
+ '--dropdown_item-padding',
216
+ '--dropdown_item-radius',
217
+ '--dropdown_item-font-size',
218
+ '--dropdown_item-bg--hover',
219
+ '--dropdown_item-color--hover',
220
+ '--dropdown_item-opacity--disabled',
221
+ '--dropdown_item-color--destructive',
222
+ '--dropdown_item-bg--destructive-hover',
223
+ '--dropdown_item-color--destructive-hover',
224
+ '--dropdown_shortcut-color',
225
+ '--dropdown_shortcut-font-size',
226
+ ])('reads %s through var() in the item stylesheet', hook => {
227
+ expect(itemSource).toContain(`var(${hook},`);
228
+ });
229
+ });
230
+
231
+ describe('bds-dropdown-menu-group', () => {
232
+ it('is registered as a custom element', () => {
233
+ expect(customElements.get('bds-dropdown-menu-group')).toBe(BdsDropdownMenuGroup);
234
+ });
235
+
236
+ it('renders a role="group" named by its visible label', async () => {
237
+ const el = await fixture('<bds-dropdown-menu-group label="Edit"></bds-dropdown-menu-group>') as BdsDropdownMenuGroup;
238
+ const group = el.shadowRoot!.querySelector('[role="group"]')!;
239
+ const labelId = group.getAttribute('aria-labelledby')!;
240
+ const label = el.shadowRoot!.getElementById(labelId)!;
241
+ expect(label.textContent?.trim()).toBe('Edit');
242
+ cleanup(el);
243
+ });
244
+
245
+ it('renders no label element and no aria-labelledby without a label', async () => {
246
+ const el = await fixture('<bds-dropdown-menu-group></bds-dropdown-menu-group>') as BdsDropdownMenuGroup;
247
+ const group = el.shadowRoot!.querySelector('[role="group"]')!;
248
+ expect(group.hasAttribute('aria-labelledby')).toBe(false);
249
+ expect(el.shadowRoot!.querySelector('.label')).toBeNull();
250
+ cleanup(el);
251
+ });
252
+
253
+ it('updates the label when the attribute changes', async () => {
254
+ const el = await fixture('<bds-dropdown-menu-group label="Edit"></bds-dropdown-menu-group>') as BdsDropdownMenuGroup;
255
+ el.setAttribute('label', 'Danger');
256
+ await el.updateComplete;
257
+ expect(el.shadowRoot!.querySelector('.label')!.textContent?.trim()).toBe('Danger');
258
+ cleanup(el);
259
+ });
260
+
261
+ it.each([
262
+ '--dropdown_group-label-font-size',
263
+ '--dropdown_group-label-font-weight',
264
+ '--dropdown_group-label-color',
265
+ '--dropdown_group-label-padding',
266
+ ])('reads %s through var() in the group stylesheet', hook => {
267
+ expect(groupSource).toContain(`var(${hook},`);
268
+ });
269
+
270
+ it('moves focus from the last item of one group to the first of the next', async () => {
271
+ const el = await fixture(`
272
+ <bds-dropdown-menu>
273
+ <button slot="trigger" type="button">Options</button>
274
+ <bds-dropdown-menu-group label="Edit">
275
+ <bds-dropdown-menu-item value="a">A</bds-dropdown-menu-item>
276
+ <bds-dropdown-menu-item value="b">B</bds-dropdown-menu-item>
277
+ </bds-dropdown-menu-group>
278
+ <bds-dropdown-menu-group label="Danger">
279
+ <bds-dropdown-menu-item value="c" destructive>C</bds-dropdown-menu-item>
280
+ </bds-dropdown-menu-group>
281
+ </bds-dropdown-menu>
282
+ `) as BdsDropdownMenu;
283
+ const items = [...el.querySelectorAll('bds-dropdown-menu-item')] as BdsDropdownMenuItem[];
284
+ await Promise.all(items.map(item => item.updateComplete));
285
+ el._open();
286
+ await el.updateComplete;
287
+ const buttons = items.map(item => item.shadowRoot!.querySelector<HTMLButtonElement>('button')!);
288
+ const spy = vi.spyOn(buttons[2], 'focus');
289
+ buttons[1].focus();
290
+ el.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
291
+ expect(spy).toHaveBeenCalled();
292
+ cleanup(el);
293
+ });
294
+ });
295
+
296
+ describe('bds-dropdown-menu panel hooks', () => {
297
+ it.each(['--dropdown_padding', '--dropdown_border-color'])('reads %s through var()', hook => {
298
+ expect(menuSource).toContain(`var(${hook},`);
299
+ });
300
+ });
@@ -19,7 +19,8 @@ export type DropdownMenuPlacement = 'bottom-start' | 'bottom-end' | 'top-start'
19
19
  *
20
20
  * Slots:
21
21
  * trigger — the activating element (button or similar)
22
- * (default) — `<bds-dropdown-menu-item>` elements
22
+ * (default) — `<bds-dropdown-menu-item>` elements, optionally wrapped in
23
+ * `<bds-dropdown-menu-group label="...">`
23
24
  *
24
25
  * Events:
25
26
  * bds-open — fired when the menu opens
@@ -55,15 +56,15 @@ export class BdsDropdownMenu extends LitElement {
55
56
  inset-inline-start: 0;
56
57
  min-inline-size: 10rem;
57
58
  border: var(--dropdown_border, none);
58
- --bdc_color: currentcolor;
59
+ --bdc_color: var(--dropdown_border-color, var(--bds-color_on-bg--as-surface, var(--bds-color_on-bg--border, var(--bds-color_on-bg))));
59
60
  --bdc-outline_radius: var(--bds-border_radius--s);
60
61
 
61
62
  border-radius: var(--dropdown_radius, var(--bdc-outline_radius));
62
63
  background-color: var(--dropdown_color, var(--bds-color_bg--strong, var(--bds-color_bg)));
63
64
  color: var(--dropdown_on-color, var(--bds-color_on-bg));
64
65
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color),
65
- var(--dropdown_shadow, var(--bds-shadow_m));
66
- padding: var(--bds-space_xxs);
66
+ var(--dropdown_shadow, var(--bds-shadow_l));
67
+ padding: var(--dropdown_padding, var(--bds-space_xxs));
67
68
  z-index: var(--bds-z-index_dropdown);
68
69
  display: none;
69
70
  flex-direction: column;
@@ -14,6 +14,22 @@ describe('bds-tab', () => {
14
14
  cleanup(el);
15
15
  });
16
16
 
17
+ it('copies the slotted label into data-label to reserve the bold width', async () => {
18
+ const el = await fixture('<bds-tab>Overview</bds-tab>') as BdsTab;
19
+ const slot = el.shadowRoot!.querySelector('slot')!;
20
+ slot.dispatchEvent(new Event('slotchange'));
21
+ await el.updateComplete;
22
+ expect(el.shadowRoot!.querySelector('.label')!.getAttribute('data-label')).toBe('Overview');
23
+ cleanup(el);
24
+ });
25
+
26
+ it('styles a hidden ::after at the active weight', () => {
27
+ const css = BdsTab.styles.toString();
28
+ expect(css).toMatch(/\.label::after\s*\{[^}]*content:\s*attr\(data-label\)/);
29
+ expect(css).toMatch(/\.label::after\s*\{[^}]*font-weight:\s*var\(--tab_font-weight,\s*var\(--tab_font-weight--active,\s*var\(--bds-font_weight--bold\)\)\)/);
30
+ expect(css).toMatch(/\.label::after\s*\{[^}]*visibility:\s*hidden/);
31
+ });
32
+
17
33
  it('is not selected by default', async () => {
18
34
  const el = await fixture('<bds-tab>Label</bds-tab>') as BdsTab;
19
35
  expect(el.selected).toBe(false);
@@ -72,10 +88,10 @@ describe('bds-tab', () => {
72
88
  it('lets the public --tab_color/--tab_border-color tokens win over selected/hover-state defaults', () => {
73
89
  const cssText = BdsTab.styles.cssText;
74
90
  expect(cssText).toMatch(
75
- /\.tab\s*{[^}]*color:\s*var\(--tab_color,\s*var\(--tab_color--state,\s*var\(--bds-color_on-bg\)\)\)/,
91
+ /\.tab\s*{[^}]*color:\s*var\(--tab_color,\s*var\(--tab_color--state,\s*var\(--tab_color--inactive,\s*var\(--bds-color_on-bg--muted,\s*var\(--bds-color_on-bg\)\)\)\)\)/,
76
92
  );
77
93
  expect(cssText).toMatch(
78
- /\.tab\s*{[^}]*border-block-end:\s*2px solid var\(--tab_border-color,\s*var\(--tab_border-color--state,\s*transparent\)\)/,
94
+ /\.tab\s*{[^}]*border-block-end:\s*var\(--tab_indicator-width,\s*3px\) solid var\(--tab_border-color,\s*var\(--tab_border-color--state,\s*transparent\)\)/,
79
95
  );
80
96
  });
81
97
 
@@ -93,4 +109,20 @@ describe('bds-tab', () => {
93
109
  /--tab_color--state:\s*var\(--tab_color--hover,/,
94
110
  );
95
111
  });
112
+
113
+ it('styles the resting tab muted and medium, the selected tab strong and bold, and hover in the full text colour', () => {
114
+ const cssText = BdsTab.styles.cssText;
115
+ expect(cssText).toMatch(
116
+ /\.tab\s*{[^}]*font-weight:\s*var\(--tab_font-weight,\s*var\(--tab_font-weight--state,\s*var\(--tab_font-weight--inactive,\s*var\(--bds-font_weight--medium\)\)\)\)/,
117
+ );
118
+ expect(cssText).toMatch(
119
+ /:host\(\[selected\]\)\s*\.tab\s*{[^}]*--tab_color--state:\s*var\(--tab_color--active,\s*var\(--bds-color_on-bg\)\)/,
120
+ );
121
+ expect(cssText).toMatch(
122
+ /:host\(\[selected\]\)\s*\.tab\s*{[^}]*--tab_font-weight--state:\s*var\(--tab_font-weight--active,\s*var\(--bds-font_weight--bold\)\)/,
123
+ );
124
+ expect(cssText).toMatch(
125
+ /--tab_color--state:\s*var\(--tab_color--hover,\s*var\(--bds-color_on-bg\)\)/,
126
+ );
127
+ });
96
128
  });