@boostdev/design-system-components 2.15.0 → 2.17.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 (299) hide show
  1. package/AGENTS.md +22 -15
  2. package/dist/client.cjs +271 -205
  3. package/dist/client.css +813 -650
  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 +813 -650
  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-3WAV6MDN.js → chunk-3FSGP35V.js} +1 -0
  14. package/dist/web-components/{chunk-SYNLFKD3.js → chunk-3LQKFSMR.js} +6 -0
  15. package/dist/web-components/{chunk-KA3VPKMY.js → chunk-4MB2ICSK.js} +1 -0
  16. package/dist/web-components/{chunk-6G22I2CK.js → chunk-5ATTKUCP.js} +33 -3
  17. package/dist/web-components/{chunk-IDSM74LM.js → chunk-6XL5P76D.js} +3 -3
  18. package/dist/web-components/{chunk-P24JYC5V.js → chunk-7VXRMCAL.js} +10 -4
  19. package/dist/web-components/{chunk-CUKQ2L5B.js → chunk-AGI6YQRC.js} +9 -16
  20. package/dist/web-components/chunk-BDRV452N.js +51 -0
  21. package/dist/web-components/{chunk-3AY2YKCM.js → chunk-CKCPV347.js} +1 -0
  22. package/dist/web-components/{chunk-HBLJ4SLY.js → chunk-DD3OUXNG.js} +5 -5
  23. package/dist/web-components/{chunk-RVF7W653.js → chunk-DGOCPKHI.js} +30 -10
  24. package/dist/web-components/{chunk-2OLVQUBU.js → chunk-EYCW7TKB.js} +8 -15
  25. package/dist/web-components/{chunk-VANAKB6D.js → chunk-GPJWLAKU.js} +33 -16
  26. package/dist/web-components/{chunk-VED2DFJ6.js → chunk-GQNQBEYR.js} +8 -15
  27. package/dist/web-components/{chunk-WFVKU4GX.js → chunk-IKAJLROF.js} +49 -4
  28. package/dist/web-components/{chunk-RSZ3BWBK.js → chunk-KSK4RZZQ.js} +30 -7
  29. package/dist/web-components/{chunk-FEDABOR5.js → chunk-LHFUXZ52.js} +7 -15
  30. package/dist/web-components/{chunk-M3ECULRH.js → chunk-RBF7WPLI.js} +10 -8
  31. package/dist/web-components/{chunk-BPYKZVDK.js → chunk-SJLMW2VR.js} +2 -2
  32. package/dist/web-components/chunk-SRKQ6GST.js +40 -0
  33. package/dist/web-components/{chunk-5HUAFCU6.js → chunk-TJV7UIXC.js} +7 -0
  34. package/dist/web-components/{chunk-LDIPCTRN.js → chunk-WWWJCSXN.js} +50 -4
  35. package/dist/web-components/{chunk-J3HVUIUH.js → chunk-XI2U6U26.js} +8 -15
  36. package/dist/web-components/{chunk-JH6LQKLK.js → chunk-XJU7KITO.js} +8 -15
  37. package/dist/web-components/{chunk-JV5QT2OU.js → chunk-YLDQOESI.js} +27 -13
  38. package/dist/web-components/globals.js +1 -1
  39. package/dist/web-components/index.d.ts +1 -0
  40. package/dist/web-components/index.js +35 -30
  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-badge.js +1 -1
  68. package/dist/web-components/ui/bds-notification-banner.d.ts +14 -1
  69. package/dist/web-components/ui/bds-notification-banner.js +1 -1
  70. package/dist/web-components/ui/bds-rating.js +1 -1
  71. package/dist/web-components/ui/bds-section-header.d.ts +6 -0
  72. package/dist/web-components/ui/bds-section-header.js +1 -1
  73. package/dist/web-components/ui/bds-separator.js +1 -1
  74. package/dist/web-components/ui/bds-table.js +1 -1
  75. package/package.json +6 -2
  76. package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +35 -4
  77. package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +58 -10
  78. package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +114 -1
  79. package/src/components/interaction/DropdownMenu/DropdownMenu.stories.tsx +25 -0
  80. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +69 -17
  81. package/src/components/interaction/Rating/Rating.mdx +4 -1
  82. package/src/components/interaction/Rating/Rating.module.css +9 -0
  83. package/src/components/interaction/Rating/Rating.spec.tsx +9 -0
  84. package/src/components/interaction/form/Checkbox/Checkbox.module.css +1 -0
  85. package/src/components/interaction/form/Checkbox/Checkbox.spec.tsx +7 -0
  86. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +2 -1
  87. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.module.css +8 -1
  88. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.spec.tsx +27 -0
  89. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +1 -1
  90. package/src/components/interaction/form/Combobox/Combobox.module.css +1 -0
  91. package/src/components/interaction/form/Combobox/Combobox.spec.tsx +7 -0
  92. package/src/components/interaction/form/FormInput/FormInput.mdx +9 -0
  93. package/src/components/interaction/form/FormInput/FormInput.module.css +1 -0
  94. package/src/components/interaction/form/FormInput/FormInput.spec.tsx +7 -0
  95. package/src/components/interaction/form/NumberInput/NumberInput.module.css +1 -0
  96. package/src/components/interaction/form/NumberInput/NumberInput.spec.tsx +7 -0
  97. package/src/components/interaction/form/Radio/Radio.module.css +1 -0
  98. package/src/components/interaction/form/Radio/Radio.spec.tsx +7 -0
  99. package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +2 -1
  100. package/src/components/interaction/form/RadioGroup/RadioGroup.module.css +8 -1
  101. package/src/components/interaction/form/RadioGroup/RadioGroup.spec.tsx +27 -0
  102. package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +1 -1
  103. package/src/components/interaction/form/Select/Select.module.css +1 -0
  104. package/src/components/interaction/form/Select/Select.spec.tsx +7 -0
  105. package/src/components/interaction/form/Switch/Switch.module.css +1 -0
  106. package/src/components/interaction/form/Switch/Switch.spec.tsx +7 -0
  107. package/src/components/interaction/form/Textarea/Textarea.module.css +1 -0
  108. package/src/components/interaction/form/Textarea/Textarea.spec.tsx +7 -0
  109. package/src/components/interaction/form/atoms/Message.module.css +14 -3
  110. package/src/components/interaction/form/atoms/Message.spec.tsx +22 -0
  111. package/src/components/interaction/form/atoms/Message.tsx +5 -0
  112. package/src/components/layout/SectionHeader/SectionHeader.mdx +18 -5
  113. package/src/components/layout/SectionHeader/SectionHeader.module.css +35 -14
  114. package/src/components/layout/SectionHeader/SectionHeader.spec.tsx +44 -0
  115. package/src/components/layout/SectionHeader/SectionHeader.stories.tsx +5 -0
  116. package/src/components/layout/SectionHeader/SectionHeader.tsx +3 -1
  117. package/src/components/ui/Alert/Alert.mdx +12 -1
  118. package/src/components/ui/Alert/Alert.module.css +32 -3
  119. package/src/components/ui/Alert/Alert.spec.tsx +27 -0
  120. package/src/components/ui/Alert/Alert.stories.tsx +20 -0
  121. package/src/components/ui/Alert/Alert.tsx +8 -1
  122. package/src/components/ui/Avatar/Avatar.mdx +22 -2
  123. package/src/components/ui/Avatar/Avatar.module.css +29 -2
  124. package/src/components/ui/Avatar/Avatar.spec.tsx +26 -0
  125. package/src/components/ui/Avatar/Avatar.stories.tsx +23 -0
  126. package/src/components/ui/Avatar/Avatar.tsx +4 -2
  127. package/src/components/ui/Avatar/avatarTone.spec.ts +41 -0
  128. package/src/components/ui/Avatar/avatarTone.ts +22 -0
  129. package/src/components/ui/Badge/Badge.mdx +1 -1
  130. package/src/components/ui/Badge/Badge.module.css +2 -2
  131. package/src/components/ui/Badge/Badge.spec.tsx +8 -0
  132. package/src/components/ui/Collapsible/Collapsible.module.css +1 -2
  133. package/src/components/ui/NotificationBanner/NotificationBanner.mdx +27 -1
  134. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +33 -3
  135. package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +35 -0
  136. package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +25 -0
  137. package/src/components/ui/NotificationBanner/NotificationBanner.tsx +15 -1
  138. package/src/components/ui/Separator/Separator.mdx +1 -0
  139. package/src/components/ui/Separator/Separator.module.css +6 -0
  140. package/src/components/ui/Separator/Separator.spec.tsx +19 -0
  141. package/src/components/ui/Separator/Separator.stories.tsx +15 -0
  142. package/src/components/ui/Table/Table.mdx +4 -1
  143. package/src/components/ui/Table/Table.module.css +7 -7
  144. package/src/components/ui/Table/Table.spec.tsx +11 -0
  145. package/src/components/ui/Tabs/Tabs.mdx +11 -5
  146. package/src/components/ui/Tabs/Tabs.module.css +23 -5
  147. package/src/components/ui/Tabs/Tabs.spec.tsx +39 -0
  148. package/src/components/ui/Tabs/Tabs.tsx +2 -1
  149. package/src/components/ui/Tabs/getNodeText.spec.tsx +23 -0
  150. package/src/components/ui/Tabs/getNodeText.ts +13 -0
  151. package/src/components/ui/Tooltip/Tooltip.mdx +6 -3
  152. package/src/components/ui/Tooltip/Tooltip.module.css +6 -2
  153. package/src/components/ui/Tooltip/Tooltip.spec.tsx +10 -0
  154. package/src/components/ui/Tooltip/Tooltip.stories.tsx +13 -0
  155. package/src/css/bdc.css +5 -2
  156. package/src/css/bdc.spec.ts +65 -0
  157. package/src/stories/DesignSystem/Borders.mdx +17 -9
  158. package/src/test/token-contract.spec.ts +1 -0
  159. package/src/web-components/globals.ts +10 -4
  160. package/src/web-components/index.ts +1 -0
  161. package/src/web-components/interaction/BdsAccordion.mdx +1 -1
  162. package/src/web-components/interaction/BdsAccordion.stories.tsx +1 -1
  163. package/src/web-components/interaction/BdsButton.mdx +1 -1
  164. package/src/web-components/interaction/BdsButton.stories.tsx +1 -1
  165. package/src/web-components/interaction/BdsCollapsible.mdx +1 -1
  166. package/src/web-components/interaction/BdsCollapsible.stories.tsx +1 -1
  167. package/src/web-components/interaction/BdsDialog.mdx +1 -1
  168. package/src/web-components/interaction/BdsDialog.stories.tsx +1 -1
  169. package/src/web-components/interaction/BdsDrawer.mdx +1 -1
  170. package/src/web-components/interaction/BdsDrawer.stories.tsx +1 -1
  171. package/src/web-components/interaction/BdsDropdownMenu.mdx +62 -6
  172. package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +32 -7
  173. package/src/web-components/interaction/BdsPopover.mdx +1 -1
  174. package/src/web-components/interaction/BdsPopover.stories.tsx +1 -1
  175. package/src/web-components/interaction/BdsSkipLink.mdx +1 -1
  176. package/src/web-components/interaction/BdsSkipLink.stories.tsx +1 -1
  177. package/src/web-components/interaction/BdsTabs.mdx +10 -1
  178. package/src/web-components/interaction/BdsTabs.stories.tsx +1 -1
  179. package/src/web-components/interaction/BdsToastProvider.mdx +1 -1
  180. package/src/web-components/interaction/BdsToastProvider.stories.tsx +1 -1
  181. package/src/web-components/interaction/BdsTooltip.mdx +13 -5
  182. package/src/web-components/interaction/BdsTooltip.stories.tsx +12 -12
  183. package/src/web-components/interaction/bds-dropdown-menu-group.ts +72 -0
  184. package/src/web-components/interaction/bds-dropdown-menu-item.ts +65 -17
  185. package/src/web-components/interaction/bds-dropdown-menu.spec.ts +135 -0
  186. package/src/web-components/interaction/bds-dropdown-menu.ts +5 -4
  187. package/src/web-components/interaction/bds-tab.spec.ts +34 -2
  188. package/src/web-components/interaction/bds-tab.ts +31 -6
  189. package/src/web-components/interaction/bds-tooltip.spec.ts +16 -0
  190. package/src/web-components/interaction/bds-tooltip.ts +10 -8
  191. package/src/web-components/interaction/form/BdsCheckbox.mdx +5 -1
  192. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +1 -1
  193. package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +5 -1
  194. package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +1 -1
  195. package/src/web-components/interaction/form/BdsCombobox.mdx +5 -1
  196. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +1 -1
  197. package/src/web-components/interaction/form/BdsFieldGroup.stories.tsx +1 -1
  198. package/src/web-components/interaction/form/BdsFileInput.mdx +1 -1
  199. package/src/web-components/interaction/form/BdsFileInput.stories.tsx +1 -1
  200. package/src/web-components/interaction/form/BdsFormInput.mdx +8 -1
  201. package/src/web-components/interaction/form/BdsFormInput.stories.tsx +1 -1
  202. package/src/web-components/interaction/form/BdsNumberInput.mdx +5 -1
  203. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +1 -1
  204. package/src/web-components/interaction/form/BdsRadio.mdx +5 -1
  205. package/src/web-components/interaction/form/BdsRadio.stories.tsx +1 -1
  206. package/src/web-components/interaction/form/BdsRadioGroup.mdx +5 -1
  207. package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +1 -1
  208. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +1 -1
  209. package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +1 -1
  210. package/src/web-components/interaction/form/BdsSelect.mdx +5 -1
  211. package/src/web-components/interaction/form/BdsSelect.stories.tsx +1 -1
  212. package/src/web-components/interaction/form/BdsSlider.mdx +5 -1
  213. package/src/web-components/interaction/form/BdsSlider.stories.tsx +1 -1
  214. package/src/web-components/interaction/form/BdsSwitch.mdx +5 -1
  215. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +1 -1
  216. package/src/web-components/interaction/form/BdsTextarea.mdx +5 -1
  217. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +1 -1
  218. package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +32 -3
  219. package/src/web-components/interaction/form/bds-checkbox-group.ts +33 -17
  220. package/src/web-components/interaction/form/bds-checkbox.ts +1 -0
  221. package/src/web-components/interaction/form/bds-combobox.ts +6 -16
  222. package/src/web-components/interaction/form/bds-form-input.ts +6 -16
  223. package/src/web-components/interaction/form/bds-number-input.ts +6 -16
  224. package/src/web-components/interaction/form/bds-radio-group.spec.ts +32 -3
  225. package/src/web-components/interaction/form/bds-radio-group.ts +26 -14
  226. package/src/web-components/interaction/form/bds-radio.ts +1 -0
  227. package/src/web-components/interaction/form/bds-select.ts +6 -16
  228. package/src/web-components/interaction/form/bds-slider.ts +5 -16
  229. package/src/web-components/interaction/form/bds-switch.ts +1 -0
  230. package/src/web-components/interaction/form/bds-textarea.ts +6 -16
  231. package/src/web-components/interaction/form/field-message.spec.ts +62 -0
  232. package/src/web-components/interaction/form/field-message.ts +55 -0
  233. package/src/web-components/layout/BdsGrid.mdx +1 -1
  234. package/src/web-components/layout/BdsGrid.stories.tsx +1 -1
  235. package/src/web-components/layout/BdsGridItem.mdx +1 -1
  236. package/src/web-components/layout/BdsGridItem.stories.tsx +1 -1
  237. package/src/web-components/ui/BdsAlert.mdx +20 -1
  238. package/src/web-components/ui/BdsAlert.stories.tsx +29 -3
  239. package/src/web-components/ui/BdsAvatar.mdx +20 -3
  240. package/src/web-components/ui/BdsAvatar.stories.tsx +25 -2
  241. package/src/web-components/ui/BdsBadge.mdx +2 -1
  242. package/src/web-components/ui/BdsBadge.stories.tsx +1 -1
  243. package/src/web-components/ui/BdsBreadcrumb.mdx +1 -1
  244. package/src/web-components/ui/BdsBreadcrumb.stories.tsx +1 -1
  245. package/src/web-components/ui/BdsButtonContainer.mdx +1 -1
  246. package/src/web-components/ui/BdsButtonContainer.stories.tsx +1 -1
  247. package/src/web-components/ui/BdsCalendar.mdx +1 -1
  248. package/src/web-components/ui/BdsCalendar.stories.tsx +1 -1
  249. package/src/web-components/ui/BdsCalendarRange.mdx +1 -1
  250. package/src/web-components/ui/BdsCalendarRange.stories.tsx +1 -1
  251. package/src/web-components/ui/BdsCard.mdx +1 -1
  252. package/src/web-components/ui/BdsCard.stories.tsx +1 -1
  253. package/src/web-components/ui/BdsCarousel.mdx +1 -1
  254. package/src/web-components/ui/BdsCarousel.stories.tsx +1 -1
  255. package/src/web-components/ui/BdsDescriptionList.mdx +1 -1
  256. package/src/web-components/ui/BdsDescriptionList.stories.tsx +1 -1
  257. package/src/web-components/ui/BdsIconWrapper.mdx +1 -1
  258. package/src/web-components/ui/BdsIconWrapper.stories.tsx +1 -1
  259. package/src/web-components/ui/BdsLink.mdx +1 -1
  260. package/src/web-components/ui/BdsLink.stories.tsx +1 -1
  261. package/src/web-components/ui/BdsLoading.mdx +1 -1
  262. package/src/web-components/ui/BdsLoading.stories.tsx +1 -1
  263. package/src/web-components/ui/BdsNotificationBanner.mdx +11 -2
  264. package/src/web-components/ui/BdsNotificationBanner.stories.tsx +29 -2
  265. package/src/web-components/ui/BdsPagination.mdx +1 -1
  266. package/src/web-components/ui/BdsPagination.stories.tsx +1 -1
  267. package/src/web-components/ui/BdsProgress.mdx +1 -1
  268. package/src/web-components/ui/BdsProgress.stories.tsx +1 -1
  269. package/src/web-components/ui/BdsProgressCircle.mdx +1 -1
  270. package/src/web-components/ui/BdsProgressCircle.stories.tsx +1 -1
  271. package/src/web-components/ui/BdsRating.mdx +5 -2
  272. package/src/web-components/ui/BdsRating.stories.tsx +1 -1
  273. package/src/web-components/ui/BdsSectionHeader.mdx +18 -6
  274. package/src/web-components/ui/BdsSectionHeader.stories.tsx +10 -2
  275. package/src/web-components/ui/BdsSeparator.mdx +2 -1
  276. package/src/web-components/ui/BdsSeparator.stories.tsx +13 -1
  277. package/src/web-components/ui/BdsSkeleton.mdx +1 -1
  278. package/src/web-components/ui/BdsSkeleton.stories.tsx +1 -1
  279. package/src/web-components/ui/BdsTable.mdx +5 -1
  280. package/src/web-components/ui/BdsTable.stories.tsx +1 -1
  281. package/src/web-components/ui/BdsTypography.mdx +1 -1
  282. package/src/web-components/ui/BdsTypography.stories.tsx +1 -1
  283. package/src/web-components/ui/bds-alert.spec.ts +34 -0
  284. package/src/web-components/ui/bds-alert.ts +36 -3
  285. package/src/web-components/ui/bds-avatar.spec.ts +47 -0
  286. package/src/web-components/ui/bds-avatar.ts +36 -3
  287. package/src/web-components/ui/bds-badge.spec.ts +6 -0
  288. package/src/web-components/ui/bds-badge.ts +2 -2
  289. package/src/web-components/ui/bds-notification-banner.spec.ts +52 -0
  290. package/src/web-components/ui/bds-notification-banner.ts +55 -3
  291. package/src/web-components/ui/bds-rating.spec.ts +7 -0
  292. package/src/web-components/ui/bds-rating.ts +6 -0
  293. package/src/web-components/ui/bds-section-header.spec.ts +36 -3
  294. package/src/web-components/ui/bds-section-header.ts +32 -10
  295. package/src/web-components/ui/bds-separator.spec.ts +8 -0
  296. package/src/web-components/ui/bds-separator.ts +7 -0
  297. package/src/web-components/ui/bds-table.spec.ts +11 -0
  298. package/src/web-components/ui/bds-table.ts +5 -5
  299. package/dist/web-components/chunk-QZAIRJ75.js +0 -111
@@ -7,25 +7,28 @@ function BdsSectionHeader({
7
7
  subtitle,
8
8
  alignment = 'start',
9
9
  size = 'medium',
10
+ appearance = 'default',
10
11
  titleAs,
11
12
  }: {
12
13
  heading?: string;
13
14
  subtitle?: string;
14
15
  alignment?: 'start' | 'center' | 'end';
15
16
  size?: 'xs' | 'small' | 'medium' | 'large';
17
+ appearance?: 'default' | 'gradient';
16
18
  titleAs?: string;
17
19
  }) {
18
- return React.createElement('bds-section-header', { heading, subtitle, alignment, size, 'title-as': titleAs });
20
+ return React.createElement('bds-section-header', { heading, subtitle, alignment, size, appearance, 'title-as': titleAs });
19
21
  }
20
22
 
21
23
  const meta = {
22
24
  title: 'Web Components/Layout/SectionHeader',
23
25
  component: BdsSectionHeader,
24
- tags: ['!stable', 'experimental'],
26
+ tags: ['!stable', 'alpha'],
25
27
  parameters: { layout: 'padded' },
26
28
  argTypes: {
27
29
  alignment: { control: 'select', options: ['start', 'center', 'end'] },
28
30
  size: { control: 'select', options: ['xs', 'small', 'medium', 'large'] },
31
+ appearance: { control: 'select', options: ['default', 'gradient'] },
29
32
  titleAs: { control: 'text' },
30
33
  },
31
34
  } satisfies Meta<typeof BdsSectionHeader>;
@@ -54,3 +57,8 @@ export const AllSizes: Story = {
54
57
  </div>
55
58
  ),
56
59
  };
60
+
61
+ export const Gradient: Story = { args: { heading: 'Gradient Header', subtitle: 'Gradient title', appearance: 'gradient' } };
62
+ export const GradientExtraSmall: Story = { args: { heading: 'Gradient Extra Small', subtitle: 'Gradient title', appearance: 'gradient', size: 'xs' } };
63
+ export const GradientSmall: Story = { args: { heading: 'Gradient Small', subtitle: 'Gradient title', appearance: 'gradient', size: 'small' } };
64
+ export const GradientLarge: Story = { args: { heading: 'Gradient Large', subtitle: 'Gradient title', appearance: 'gradient', size: 'large' } };
@@ -7,7 +7,7 @@ import * as Stories from './BdsSeparator.stories';
7
7
 
8
8
  Framework-agnostic Separator custom element. Renders a thin decorative line to visually divide content. Supports both horizontal and vertical orientations.
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
 
@@ -56,6 +56,7 @@ Or in HTML without a bundler:
56
56
  |----------|-------------|
57
57
  | `--separator_color` | Line colour (defaults to `--bds-color_on-bg--as-surface`, the non-text member of the set — a rule is not text, so it needs 3:1, not 4.5:1) |
58
58
  | `--separator_thickness` | Line thickness (default: `1px`) |
59
+ | `--separator_spacing` | Space around the line: inline for vertical (default: `var(--bds-space_s)`), block for horizontal (default: `0`) |
59
60
 
60
61
  ## Usage in plain HTML
61
62
 
@@ -13,7 +13,7 @@ function BdsSeparator({
13
13
  const meta = {
14
14
  title: 'Web Components/UI/Separator',
15
15
  component: BdsSeparator,
16
- tags: ['!stable', 'experimental'],
16
+ tags: ['!stable', 'alpha'],
17
17
  parameters: { layout: 'centered' },
18
18
  argTypes: {
19
19
  orientation: { control: 'radio', options: ['horizontal', 'vertical'] },
@@ -53,3 +53,15 @@ export const Vertical: Story = {
53
53
  </div>
54
54
  ),
55
55
  };
56
+
57
+ export const BetweenLinks: Story = {
58
+ render: () => (
59
+ <nav aria-label="Example" style={{ display: 'flex', alignItems: 'center' }}>
60
+ <a href="#one">Home</a>
61
+ {React.createElement('bds-separator', { orientation: 'vertical' })}
62
+ <a href="#two">Pricing</a>
63
+ {React.createElement('bds-separator', { orientation: 'vertical' })}
64
+ <a href="#three">Contact</a>
65
+ </nav>
66
+ ),
67
+ };
@@ -7,7 +7,7 @@ import * as Stories from './BdsSkeleton.stories';
7
7
 
8
8
  Framework-agnostic Skeleton loading placeholder custom element. Displays an animated shimmer while real content is loading. Size is set via inline styles or CSS on the host element.
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
 
@@ -10,7 +10,7 @@ function BdsSkeleton({ width = '200px', height = '1rem' }: { width?: string; hei
10
10
  const meta = {
11
11
  title: 'Web Components/UI/Skeleton',
12
12
  component: BdsSkeleton,
13
- tags: ['!stable', 'experimental'],
13
+ tags: ['!stable', 'alpha'],
14
14
  parameters: { layout: 'centered' },
15
15
  argTypes: {
16
16
  width: { control: 'text' },
@@ -7,7 +7,7 @@ import * as Stories from './BdsTable.stories';
7
7
 
8
8
  Framework-agnostic scrollable Table wrapper custom element. Apply design-system styles to a standard `<table>` element by nesting it in the default slot.
9
9
 
10
- > **Status: experimental** — API may change before stable release.
10
+ > **Status: alpha** — API may change before stable release.
11
11
 
12
12
  > **Light-DOM styling contract:** `::slotted()` can only match the node placed directly into
13
13
  > the slot (the `<table>` itself), never its descendants. `<thead>`/`<th>`/`<td>` styling is
@@ -57,6 +57,10 @@ import '@boostdev/design-system-components/web-components';
57
57
  | Property | Description |
58
58
  |----------|-------------|
59
59
  | `--table_divider-color` | Colour of the header underline and row rules (default: `--bds-color_on-bg--as-surface`, the non-text member of the set — ≥ 3:1, not a ground colour) |
60
+ | `--table_header-font-size` | Header cell font size (default: `var(--bds-font_size--body)`) |
61
+ | `--table_header-font-weight` | Header cell font weight (default: `var(--bds-font_weight--bold)`) |
62
+ | `--table_header-color` | Header cell text colour (default: `var(--bds-color_on-bg--subtle)`) |
63
+ | `--table_header-bg` | Header row background (default: `var(--bds-color_bg--subtle)`) |
60
64
  | `--table_border` | Wrapper border (default: `none`) |
61
65
  | `--table_radius` | Wrapper corner radius (default: `var(--bdc-outline_radius)`, itself set to `var(--bds-border_radius--s)` on the wrapper) |
62
66
  | `--table_row-bg--hover` | Row background on hover, pointer devices only (default: `var(--bds-color_bg--subtle)`) |
@@ -58,7 +58,7 @@ const sampleTable = () =>
58
58
  const meta = {
59
59
  title: 'Web Components/UI/Table',
60
60
  component: BdsTable,
61
- tags: ['!stable', 'experimental'],
61
+ tags: ['!stable', 'alpha'],
62
62
  parameters: { layout: 'fullscreen' },
63
63
  argTypes: {
64
64
  stickyHeader: { control: 'boolean' },
@@ -7,7 +7,7 @@ import * as Stories from './BdsTypography.stories';
7
7
 
8
8
  Framework-agnostic Typography custom element. Renders slotted text inside the appropriate semantic HTML element (`h1`–`h3`, `p`) based on the `variant` attribute, with optional tag override via `component`.
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
 
@@ -18,7 +18,7 @@ function BdsTypography({
18
18
  const meta = {
19
19
  title: 'Web Components/UI/Typography',
20
20
  component: BdsTypography,
21
- tags: ['!stable', 'experimental'],
21
+ tags: ['!stable', 'alpha'],
22
22
  parameters: { layout: 'centered' },
23
23
  argTypes: {
24
24
  variant: { control: 'select', options: ['h1', 'h2', 'h3', 'body', 'body_s'] },
@@ -121,4 +121,38 @@ describe('bds-alert', () => {
121
121
  expect(div!.getAttribute('role')).toBe('alert');
122
122
  cleanup(el);
123
123
  });
124
+
125
+ it('defaults to appearance="default"', async () => {
126
+ const el = await fixture('<bds-alert>Message</bds-alert>');
127
+ expect(el.getAttribute('appearance')).toBe('default');
128
+ cleanup(el);
129
+ });
130
+
131
+ it('reflects appearance="gradient"', async () => {
132
+ const el = await fixture('<bds-alert appearance="gradient">Message</bds-alert>') as BdsAlert;
133
+ expect(el.appearance).toBe('gradient');
134
+ el.appearance = 'default';
135
+ await el.updateComplete;
136
+ expect(el.getAttribute('appearance')).toBe('default');
137
+ cleanup(el);
138
+ });
139
+
140
+ it('wires the gradient hooks in the styles', () => {
141
+ const styles = String(BdsAlert.styles);
142
+ expect(styles).toContain(":host([appearance='gradient']) .alert");
143
+ expect(styles).toMatch(/background-image:\s*var\(--alert_gradient,\s*linear-gradient\(100deg/);
144
+ expect(styles).toMatch(/box-shadow:\s*var\(--alert_shadow,\s*var\(--bds-shadow_s\)\)/);
145
+ expect(styles).toContain('--alert_border-width--variant: 3px');
146
+ expect(styles).toMatch(/\.alert \{[^}]*--alert_border-width--variant:\s*initial/);
147
+ ['info', 'success', 'warning', 'error'].forEach(v => {
148
+ expect(styles).toContain(`--alert_accent--${v}`);
149
+ });
150
+ });
151
+
152
+ it('paints the error variant with the error subtle pair, matching the React counterpart', () => {
153
+ const styles = String(BdsAlert.styles);
154
+ expect(styles).toMatch(/--alert_bg--variant:\s*var\(--alert_bg--error,\s*var\(--bds-color_error--subtle\)\)/);
155
+ expect(styles).toMatch(/--alert_text--variant:\s*var\(--alert_text--error,\s*var\(--bds-color_on-error--subtle\)\)/);
156
+ expect(styles).not.toContain('rgb(from var(--bds-color_error)');
157
+ });
124
158
  });
@@ -1,12 +1,14 @@
1
1
  import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
3
  export type AlertVariant = 'info' | 'success' | 'warning' | 'error';
4
+ export type AlertAppearance = 'default' | 'gradient';
4
5
 
5
6
  /**
6
7
  * `<bds-alert>` — framework-agnostic Alert custom element.
7
8
  *
8
9
  * Attributes:
9
10
  * variant — "info" (default) | "success" | "warning" | "error"
11
+ * appearance — "default" | "gradient" (fades the tint to the surface, 3px accent line, shadow)
10
12
  * heading — optional heading above the body text
11
13
  * title — deprecated alias for `heading`. Collides with the global HTML
12
14
  * `title` attribute, which triggers a native browser tooltip on
@@ -60,9 +62,12 @@ export class BdsAlert extends LitElement {
60
62
  defaults. Variants write to the inner --alert_*--variant slot. */
61
63
  background-color: var(--alert_bg, var(--alert_bg--variant, var(--bds-color_blue--subtle)));
62
64
  color: var(--alert_text, var(--alert_text--variant, var(--bds-color_on-blue--subtle)));
63
- border-inline-start: var(--bds-space_s) solid var(--alert_border, var(--alert_border--variant, var(--bds-color_blue)));
65
+ border-inline-start: var(--alert_border-width, var(--alert_border-width--variant, var(--bds-space_s))) solid var(--alert_border, var(--alert_border--variant, var(--bds-color_blue)));
64
66
  font-size: var(--bds-font_size--body);
65
67
  line-height: var(--bds-font_line-height--body);
68
+
69
+ /* Reset the slot so a nested default alert does not inherit a parent's gradient width. */
70
+ --alert_border-width--variant: initial;
66
71
  }
67
72
 
68
73
  /* Per-variant resting overrides — consumers can theme per-variant via
@@ -86,11 +91,36 @@ export class BdsAlert extends LitElement {
86
91
  }
87
92
 
88
93
  :host([variant='error']) .alert {
89
- --alert_bg--variant: var(--alert_bg--error, rgb(from var(--bds-color_error) r g b / 12%));
90
- --alert_text--variant: var(--alert_text--error, var(--bds-color_on-bg));
94
+ --alert_bg--variant: var(--alert_bg--error, var(--bds-color_error--subtle));
95
+ --alert_text--variant: var(--alert_text--error, var(--bds-color_on-error--subtle));
91
96
  --alert_border--variant: var(--alert_border--error, var(--bds-color_error));
92
97
  }
93
98
 
99
+ /* Gradient appearance: the variant background stays the base colour and a
100
+ gradient fades it to the surface. The accent line is thinner and uses a
101
+ per-variant accent slot; --alert_border still wins over it. */
102
+ :host([appearance='gradient']) .alert {
103
+ --alert_border-width--variant: 3px;
104
+ background-image: var(--alert_gradient, linear-gradient(100deg, transparent 35%, var(--bds-color_bg--strong, var(--bds-color_bg)) 100%));
105
+ box-shadow: var(--alert_shadow, var(--bds-shadow_s));
106
+ }
107
+
108
+ :host([appearance='gradient'][variant='info']) .alert {
109
+ --alert_border--variant: var(--alert_border--info, var(--alert_accent--info, var(--bds-color_on-blue--subtle)));
110
+ }
111
+
112
+ :host([appearance='gradient'][variant='success']) .alert {
113
+ --alert_border--variant: var(--alert_border--success, var(--alert_accent--success, var(--bds-color_on-success--subtle)));
114
+ }
115
+
116
+ :host([appearance='gradient'][variant='warning']) .alert {
117
+ --alert_border--variant: var(--alert_border--warning, var(--alert_accent--warning, var(--bds-color_warning)));
118
+ }
119
+
120
+ :host([appearance='gradient'][variant='error']) .alert {
121
+ --alert_border--variant: var(--alert_border--error, var(--alert_accent--error, var(--bds-color_error)));
122
+ }
123
+
94
124
  /* Icon slot wrapper — hidden unless slot has content */
95
125
  .icon {
96
126
  display: none;
@@ -151,6 +181,7 @@ export class BdsAlert extends LitElement {
151
181
 
152
182
  static properties = {
153
183
  variant: { type: String, reflect: true },
184
+ appearance: { type: String, reflect: true },
154
185
  heading: { type: String },
155
186
  title: { type: String },
156
187
  dismissible: { type: Boolean, reflect: true },
@@ -160,6 +191,7 @@ export class BdsAlert extends LitElement {
160
191
  // `declare` annotates the type without emitting a class field initializer
161
192
  // that would shadow Lit's reactive accessors on the prototype.
162
193
  declare variant: AlertVariant;
194
+ declare appearance: AlertAppearance;
163
195
  declare heading: string;
164
196
  /**
165
197
  * @deprecated Use `heading` instead. Sharing the name with the global HTML
@@ -173,6 +205,7 @@ export class BdsAlert extends LitElement {
173
205
  constructor() {
174
206
  super();
175
207
  this.variant = 'info';
208
+ this.appearance = 'default';
176
209
  this.heading = '';
177
210
  this.title = '';
178
211
  this.dismissible = false;
@@ -1,5 +1,6 @@
1
1
  import { fixture, cleanup } from '../test/helpers';
2
2
  import { BdsAvatar } from './bds-avatar';
3
+ import { toneFromName } from '../../components/ui/Avatar/avatarTone';
3
4
 
4
5
  describe('bds-avatar', () => {
5
6
  it('is registered as a custom element', () => {
@@ -101,4 +102,50 @@ describe('bds-avatar', () => {
101
102
  // The public --avatar_size token itself must never be set directly by a size selector.
102
103
  expect(cssText).not.toMatch(/:host\(\[size=[^)]*\]\)\s*\{\s*--avatar_size:/);
103
104
  });
105
+
106
+ it('defaults to tone="auto"', async () => {
107
+ const el = await fixture('<bds-avatar name="Jane Doe"></bds-avatar>');
108
+ expect(el.getAttribute('tone')).toBe('auto');
109
+ cleanup(el);
110
+ });
111
+
112
+ it('picks the same tone as the React Avatar for the same name', async () => {
113
+ const el = await fixture('<bds-avatar name="Jane Doe"></bds-avatar>');
114
+ const fallback = el.shadowRoot!.querySelector('.fallback');
115
+ expect(fallback!.classList.contains(`tone_${toneFromName('Jane Doe')}`)).toBe(true);
116
+ cleanup(el);
117
+ });
118
+
119
+ it('uses primary when there is no name', async () => {
120
+ const el = await fixture('<bds-avatar></bds-avatar>');
121
+ expect(el.shadowRoot!.querySelector('.fallback')!.classList.contains('tone_primary')).toBe(true);
122
+ cleanup(el);
123
+ });
124
+
125
+ it('falls back to the name tone for an unknown tone attribute', async () => {
126
+ const el = await fixture('<bds-avatar name="Jane Doe" tone="foo"></bds-avatar>');
127
+ expect(el.shadowRoot!.querySelector('.fallback')!.classList.contains(`tone_${toneFromName('Jane Doe')}`)).toBe(true);
128
+ });
129
+
130
+ it('lets an explicit tone win over auto', async () => {
131
+ const el = await fixture('<bds-avatar name="Jane Doe" tone="accent-2"></bds-avatar>');
132
+ expect(el.shadowRoot!.querySelector('.fallback')!.classList.contains('tone_accent-2')).toBe(true);
133
+ cleanup(el);
134
+ });
135
+
136
+ it('does not render a tone for image avatars', async () => {
137
+ const el = await fixture('<bds-avatar src="/photo.jpg" name="Jane Doe" tone="accent-1"></bds-avatar>');
138
+ expect(el.shadowRoot!.querySelector('.fallback')).toBeNull();
139
+ cleanup(el);
140
+ });
141
+
142
+ it('exposes a hook per tone and lets --avatar_bg and --avatar_text win', () => {
143
+ const cssText = BdsAvatar.styles.cssText;
144
+ expect(cssText).toMatch(/background-color:\s*var\(--avatar_bg,\s*var\(--avatar_bg--variant\)\)/);
145
+ expect(cssText).toMatch(/color:\s*var\(--avatar_text,\s*var\(--avatar_text--variant\)\)/);
146
+ ['primary', 'secondary', 'accent-1', 'accent-2', 'accent-3'].forEach(tone => {
147
+ expect(cssText).toContain(`--avatar_bg--${tone}`);
148
+ expect(cssText).toContain(`--avatar_text--${tone}`);
149
+ });
150
+ });
104
151
  });
@@ -1,4 +1,5 @@
1
1
  import { LitElement, css, html, nothing } from 'lit';
2
+ import { resolveAvatarTone, type AvatarTone } from '../../components/ui/Avatar/avatarTone';
2
3
 
3
4
  /**
4
5
  * `<bds-avatar>` — framework-agnostic Avatar custom element.
@@ -11,6 +12,8 @@ import { LitElement, css, html, nothing } from 'lit';
11
12
  * explicitly to mark the image as decorative (silences the accessible name).
12
13
  * name — full name; used to compute initials and as fallback aria-label
13
14
  * size — "small" | "medium" (default) | "large"
15
+ * tone — "auto" (default, picked from `name`) | "primary" | "secondary" |
16
+ * "accent-1" | "accent-2" | "accent-3"; colours the initials fallback
14
17
  *
15
18
  * @example
16
19
  * <bds-avatar src="/photo.jpg" name="Jane Doe"></bds-avatar>
@@ -53,11 +56,38 @@ export class BdsAvatar extends LitElement {
53
56
  justify-content: center;
54
57
  inline-size: 100%;
55
58
  block-size: 100%;
56
- background-color: var(--avatar_bg, var(--bds-color_blue));
57
- color: var(--avatar_text, var(--bds-color_on-blue));
59
+ background-color: var(--avatar_bg, var(--avatar_bg--variant));
60
+ color: var(--avatar_text, var(--avatar_text--variant));
58
61
  font-weight: var(--bds-font_weight--semibold);
59
62
  }
60
63
 
64
+ /* Tone slots (mirrors the React Avatar): outer --avatar_bg / --avatar_text
65
+ still win, each tone has its own public hook. */
66
+ .fallback.tone_primary {
67
+ --avatar_bg--variant: var(--avatar_bg--primary, var(--bds-color_primary--subtle, var(--bds-color_blue--subtle)));
68
+ --avatar_text--variant: var(--avatar_text--primary, var(--bds-color_on-primary--subtle, var(--bds-color_on-blue--subtle)));
69
+ }
70
+
71
+ .fallback.tone_secondary {
72
+ --avatar_bg--variant: var(--avatar_bg--secondary, var(--bds-color_secondary--subtle, var(--bds-color_blue--subtle)));
73
+ --avatar_text--variant: var(--avatar_text--secondary, var(--bds-color_on-secondary--subtle, var(--bds-color_on-blue--subtle)));
74
+ }
75
+
76
+ .fallback.tone_accent-1 {
77
+ --avatar_bg--variant: var(--avatar_bg--accent-1, var(--bds-color_accent-1--subtle, var(--bds-color_green--subtle)));
78
+ --avatar_text--variant: var(--avatar_text--accent-1, var(--bds-color_on-accent-1--subtle, var(--bds-color_on-green--subtle)));
79
+ }
80
+
81
+ .fallback.tone_accent-2 {
82
+ --avatar_bg--variant: var(--avatar_bg--accent-2, var(--bds-color_accent-2--subtle, var(--bds-color_orange--subtle)));
83
+ --avatar_text--variant: var(--avatar_text--accent-2, var(--bds-color_on-accent-2--subtle, var(--bds-color_on-orange--subtle)));
84
+ }
85
+
86
+ .fallback.tone_accent-3 {
87
+ --avatar_bg--variant: var(--avatar_bg--accent-3, var(--bds-color_accent-3--subtle, var(--bds-color_blue--subtle)));
88
+ --avatar_text--variant: var(--avatar_text--accent-3, var(--bds-color_on-accent-3--subtle, var(--bds-color_on-blue--subtle)));
89
+ }
90
+
61
91
  .initials {
62
92
  line-height: 1;
63
93
  user-select: none;
@@ -80,12 +110,14 @@ export class BdsAvatar extends LitElement {
80
110
  alt: { type: String },
81
111
  name: { type: String },
82
112
  size: { type: String, reflect: true },
113
+ tone: { type: String, reflect: true },
83
114
  };
84
115
 
85
116
  declare src: string;
86
117
  declare alt: string;
87
118
  declare name: string;
88
119
  declare size: 'small' | 'medium' | 'large';
120
+ declare tone: AvatarTone;
89
121
 
90
122
  constructor() {
91
123
  super();
@@ -93,6 +125,7 @@ export class BdsAvatar extends LitElement {
93
125
  this.alt = '';
94
126
  this.name = '';
95
127
  this.size = 'medium';
128
+ this.tone = 'auto';
96
129
  }
97
130
 
98
131
  private get _initials(): string {
@@ -119,7 +152,7 @@ export class BdsAvatar extends LitElement {
119
152
 
120
153
  return html`
121
154
  <span
122
- class="fallback"
155
+ class="fallback tone_${resolveAvatarTone(this.tone, this.name)}"
123
156
  role="img"
124
157
  aria-label=${this.name || 'User avatar'}
125
158
  >
@@ -53,4 +53,10 @@ describe('bds-badge', () => {
53
53
  const cssText = BdsBadge.styles.cssText;
54
54
  expect(cssText).toMatch(/border-radius:\s*var\(--badge_radius,\s*var\(--bds-border_radius--full\)\)/);
55
55
  });
56
+
57
+ it('gives the secondary variant a solid neutral surface, matching the React counterpart', () => {
58
+ const cssText = BdsBadge.styles.cssText;
59
+ expect(cssText).toMatch(/:host\(\[variant='secondary'\]\) \.badge \{[^}]*--badge_bg--variant:\s*var\(--badge_bg--secondary,\s*var\(--bds-color_grey\)\)/);
60
+ expect(cssText).toMatch(/:host\(\[variant='secondary'\]\) \.badge \{[^}]*--badge_text--variant:\s*var\(--badge_text--secondary,\s*var\(--bds-color_on-grey\)\)/);
61
+ });
56
62
  });
@@ -54,8 +54,8 @@ export class BdsBadge extends LitElement {
54
54
  }
55
55
 
56
56
  :host([variant='secondary']) .badge {
57
- --badge_bg--variant: var(--badge_bg--secondary, var(--bds-color_bg));
58
- --badge_text--variant: var(--badge_text--secondary, var(--bds-color_on-bg));
57
+ --badge_bg--variant: var(--badge_bg--secondary, var(--bds-color_grey));
58
+ --badge_text--variant: var(--badge_text--secondary, var(--bds-color_on-grey));
59
59
  }
60
60
 
61
61
  :host([variant='success']) .badge {
@@ -92,4 +92,56 @@ describe('bds-notification-banner', () => {
92
92
  /--bdc_color:\s*var\(--banner_dismiss-border-color,\s*var\(--notification-banner_dismiss-border-color,\s*currentcolor\)\)/,
93
93
  );
94
94
  });
95
+
96
+ it('defaults to appearance="default"', async () => {
97
+ const el = await fixture('<bds-notification-banner>Message</bds-notification-banner>');
98
+ expect(el.getAttribute('appearance')).toBe('default');
99
+ cleanup(el);
100
+ });
101
+
102
+ it('reflects appearance="gradient"', async () => {
103
+ const el = await fixture('<bds-notification-banner appearance="gradient">Message</bds-notification-banner>') as BdsNotificationBanner;
104
+ expect(el.appearance).toBe('gradient');
105
+ el.appearance = 'default';
106
+ await el.updateComplete;
107
+ expect(el.getAttribute('appearance')).toBe('default');
108
+ cleanup(el);
109
+ });
110
+
111
+ it('wires the gradient hooks in the styles', () => {
112
+ const styles = String(BdsNotificationBanner.styles);
113
+ expect(styles).toContain(":host([appearance='gradient']) .banner");
114
+ expect(styles).toMatch(/background-image:\s*var\(--banner_gradient,\s*linear-gradient\(100deg/);
115
+ expect(styles).toMatch(/box-shadow:\s*var\(--banner_shadow,\s*var\(--bds-shadow_s\)\)/);
116
+ expect(styles).toMatch(/border-block-end:\s*var\(--banner_border-width,\s*3px\)/);
117
+ ['info', 'success', 'warning', 'error'].forEach(v => {
118
+ expect(styles).toContain(`--banner_accent--${v}`);
119
+ });
120
+ });
121
+
122
+ it('renders an aria-hidden icon wrapper around the icon slot', async () => {
123
+ const el = await fixture('<bds-notification-banner>Message<svg slot="icon"></svg></bds-notification-banner>');
124
+ const icon = el.shadowRoot!.querySelector('.icon');
125
+ expect(icon).not.toBeNull();
126
+ expect(icon!.getAttribute('aria-hidden')).toBe('true');
127
+ expect(icon!.querySelector('slot[name="icon"]')).not.toBeNull();
128
+ cleanup(el);
129
+ });
130
+
131
+ it('shows the icon wrapper only when the icon slot has content', async () => {
132
+ const el = await fixture('<bds-notification-banner>Message<svg slot="icon"></svg></bds-notification-banner>') as BdsNotificationBanner;
133
+ await el.updateComplete;
134
+ expect(el.shadowRoot!.querySelector('.icon')!.classList.contains('has-content')).toBe(true);
135
+ cleanup(el);
136
+ const plain = await fixture('<bds-notification-banner>Message</bds-notification-banner>') as BdsNotificationBanner;
137
+ expect(plain.shadowRoot!.querySelector('.icon')!.classList.contains('has-content')).toBe(false);
138
+ cleanup(plain);
139
+ });
140
+
141
+ it('paints the error variant with the error subtle pair, matching the React counterpart', () => {
142
+ const styles = String(BdsNotificationBanner.styles);
143
+ expect(styles).toMatch(/--banner_bg--variant:\s*var\(--banner_bg--error,\s*var\(--bds-color_error--subtle\)\)/);
144
+ expect(styles).toMatch(/--banner_text--variant:\s*var\(--banner_text--error,\s*var\(--bds-color_on-error--subtle\)\)/);
145
+ expect(styles).not.toContain('rgb(from var(--bds-color_error)');
146
+ });
95
147
  });
@@ -1,17 +1,20 @@
1
1
  import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
3
  export type NotificationBannerVariant = 'info' | 'success' | 'warning' | 'error';
4
+ export type NotificationBannerAppearance = 'default' | 'gradient';
4
5
 
5
6
  /**
6
7
  * `<bds-notification-banner>` — framework-agnostic Notification Banner custom element.
7
8
  *
8
9
  * Attributes:
9
10
  * variant — "info" (default) | "success" | "warning" | "error"
11
+ * appearance — "default" | "gradient" (fades the tint to the surface, accent line, shadow)
10
12
  * dismissible — boolean; shows a dismiss button when present
11
13
  * dismiss-label — aria-label for the dismiss button (default: "Dismiss notification")
12
14
  *
13
15
  * Slots:
14
16
  * (default) — banner body content
17
+ * icon — optional icon displayed before the content
15
18
  * action — optional action area (e.g. a button)
16
19
  *
17
20
  * Events:
@@ -46,7 +49,7 @@ export class BdsNotificationBanner extends LitElement {
46
49
  padding: var(--bds-space_s) var(--bds-space_m);
47
50
  background-color: var(--banner_bg, var(--banner_bg--variant, var(--bds-color_blue--subtle)));
48
51
  color: var(--banner_text, var(--banner_text--variant, var(--bds-color_on-blue--subtle)));
49
- border-block-end: 3px solid var(--banner_border, var(--banner_border--variant, var(--bds-color_blue)));
52
+ border-block-end: var(--banner_border-width, 3px) solid var(--banner_border, var(--banner_border--variant, var(--bds-color_blue)));
50
53
  font-size: var(--bds-font_size--body);
51
54
  line-height: var(--bds-font_line-height--body);
52
55
  inline-size: 100%;
@@ -72,11 +75,46 @@ export class BdsNotificationBanner extends LitElement {
72
75
  }
73
76
 
74
77
  :host([variant='error']) .banner {
75
- --banner_bg--variant: var(--banner_bg--error, rgb(from var(--bds-color_error) r g b / 12%));
76
- --banner_text--variant: var(--banner_text--error, var(--bds-color_on-bg));
78
+ --banner_bg--variant: var(--banner_bg--error, var(--bds-color_error--subtle));
79
+ --banner_text--variant: var(--banner_text--error, var(--bds-color_on-error--subtle));
77
80
  --banner_border--variant: var(--banner_border--error, var(--bds-color_error));
78
81
  }
79
82
 
83
+ /* Gradient appearance: the variant background stays the base colour and a
84
+ gradient fades it to the surface. The accent line uses a per-variant
85
+ accent slot; --banner_border still wins over it. */
86
+ :host([appearance='gradient']) .banner {
87
+ background-image: var(--banner_gradient, linear-gradient(100deg, transparent 35%, var(--bds-color_bg--strong, var(--bds-color_bg)) 100%));
88
+ box-shadow: var(--banner_shadow, var(--bds-shadow_s));
89
+ }
90
+
91
+ :host([appearance='gradient'][variant='info']) .banner {
92
+ --banner_border--variant: var(--banner_border--info, var(--banner_accent--info, var(--bds-color_on-blue--subtle)));
93
+ }
94
+
95
+ :host([appearance='gradient'][variant='success']) .banner {
96
+ --banner_border--variant: var(--banner_border--success, var(--banner_accent--success, var(--bds-color_on-success--subtle)));
97
+ }
98
+
99
+ :host([appearance='gradient'][variant='warning']) .banner {
100
+ --banner_border--variant: var(--banner_border--warning, var(--banner_accent--warning, var(--bds-color_warning)));
101
+ }
102
+
103
+ :host([appearance='gradient'][variant='error']) .banner {
104
+ --banner_border--variant: var(--banner_border--error, var(--banner_accent--error, var(--bds-color_error)));
105
+ }
106
+
107
+ /* Icon slot wrapper — hidden unless slot has content */
108
+ .icon {
109
+ display: none;
110
+ align-items: center;
111
+ flex-shrink: 0;
112
+ }
113
+
114
+ .icon.has-content {
115
+ display: flex;
116
+ }
117
+
80
118
  .content {
81
119
  flex: 1;
82
120
  }
@@ -131,22 +169,33 @@ export class BdsNotificationBanner extends LitElement {
131
169
 
132
170
  static properties = {
133
171
  variant: { type: String, reflect: true },
172
+ appearance: { type: String, reflect: true },
134
173
  dismissible: { type: Boolean, reflect: true },
135
174
  dismissLabel: { type: String, attribute: 'dismiss-label' },
136
175
  _actionFilled: { state: true },
176
+ _iconFilled: { state: true },
137
177
  };
138
178
 
139
179
  declare variant: NotificationBannerVariant;
180
+ declare appearance: NotificationBannerAppearance;
140
181
  declare dismissible: boolean;
141
182
  declare dismissLabel: string;
142
183
  declare private _actionFilled: boolean;
184
+ declare private _iconFilled: boolean;
143
185
 
144
186
  constructor() {
145
187
  super();
146
188
  this.variant = 'info';
189
+ this.appearance = 'default';
147
190
  this.dismissible = false;
148
191
  this.dismissLabel = 'Dismiss notification';
149
192
  this._actionFilled = false;
193
+ this._iconFilled = false;
194
+ }
195
+
196
+ private _onIconSlotChange(e: Event) {
197
+ const slot = e.target as HTMLSlotElement;
198
+ this._iconFilled = slot.assignedNodes({ flatten: true }).length > 0;
150
199
  }
151
200
 
152
201
  private _onActionSlotChange(e: Event) {
@@ -170,6 +219,9 @@ export class BdsNotificationBanner extends LitElement {
170
219
  aria-live=${this._isUrgent ? 'assertive' : 'polite'}
171
220
  aria-atomic="true"
172
221
  >
222
+ <span class="icon ${this._iconFilled ? 'has-content' : ''}" aria-hidden="true">
223
+ <slot name="icon" @slotchange=${this._onIconSlotChange}></slot>
224
+ </span>
173
225
  <div class="content"><slot></slot></div>
174
226
  <div class="action ${this._actionFilled ? 'has-content' : ''}">
175
227
  <slot name="action" @slotchange=${this._onActionSlotChange}></slot>
@@ -73,4 +73,11 @@ describe('bds-rating', () => {
73
73
  expect(cssText).toMatch(/color:\s*var\(--rating_color,\s*var\(--bds-color_bg\)\)/);
74
74
  expect(cssText).toMatch(/color:\s*var\(--rating_color--filled,\s*var\(--bds-color_warning\)\)/);
75
75
  });
76
+
77
+ it('outlines empty stars through the same stroke hooks as the React counterpart', () => {
78
+ const cssText = BdsRating.styles.cssText;
79
+ expect(cssText).toMatch(/\.star \{[^}]*stroke:\s*var\(--rating_stroke-color,\s*var\(--bds-color_on-bg--as-surface,\s*var\(--bds-color_on-bg--border,\s*var\(--bds-color_on-bg\)\)\)\)/);
80
+ expect(cssText).toMatch(/\.star \{[^}]*stroke-width:\s*var\(--rating_stroke-width,\s*var\(--bdc-outline_width\)\)/);
81
+ expect(cssText).toMatch(/\.star\.--filled \{[^}]*stroke:\s*var\(--rating_stroke-color--filled,\s*currentcolor\)/);
82
+ });
76
83
  });