@repobit/dex-system-design 0.25.12 → 0.26.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 (336) hide show
  1. package/CHANGELOG.md +187 -0
  2. package/README.md +131 -8
  3. package/package.json +95 -13
  4. package/schemas/component-manifest.json +3294 -405
  5. package/schemas/manifest-omissions.json +173 -0
  6. package/src/blog/src/breakpoints.js +6 -6
  7. package/src/blog/src/content/blog-atoms-showcase.js +1 -1
  8. package/src/blog/src/content/blog-page-layout.js +2 -2
  9. package/src/blog/src/lib/article-toc.js +7 -7
  10. package/src/blog/src/shell/blog-shell.js +1 -1
  11. package/src/blog/src/tokens/blog.js +2 -2
  12. package/src/blog/src/tokens/core.js +34 -35
  13. package/src/blog/src/tokens/legacy.js +0 -9
  14. package/src/blog/tokens/blog.js +2 -2
  15. package/src/blog/tokens/core.js +34 -35
  16. package/src/blog/tokens/legacy.js +0 -9
  17. package/src/blog/tokens.css +36 -46
  18. package/src/components/accordion/accordion-bg.css.js +83 -59
  19. package/src/components/accordion/accordion-bg.js +29 -10
  20. package/src/components/accordion/accordion-bg.stories.js +67 -67
  21. package/src/components/accordion/accordion-keyboard.js +80 -0
  22. package/src/components/accordion/accordion.css.js +142 -80
  23. package/src/components/accordion/accordion.js +37 -10
  24. package/src/components/accordion/accordion.stories.js +7 -7
  25. package/src/components/agent-endpoints/agent-endpoints.css.js +36 -39
  26. package/src/components/agent-endpoints/agent-endpoints.js +30 -20
  27. package/src/components/agent-endpoints/agent-endpoints.stories.js +1 -1
  28. package/src/components/ai-guardian-demo.stories.js +91 -91
  29. package/src/components/alert/alert.css.js +198 -0
  30. package/src/components/alert/alert.js +103 -0
  31. package/src/components/alert/alert.stories.js +206 -0
  32. package/src/components/anchor/anchor-nav.css.js +213 -101
  33. package/src/components/anchor/anchor-nav.js +26 -40
  34. package/src/components/anchor/anchor.stories.js +22 -12
  35. package/src/components/annotation/annotation.css.js +58 -0
  36. package/src/components/annotation/annotation.js +67 -0
  37. package/src/components/annotation/annotation.stories.js +63 -0
  38. package/src/components/architecture.stories.js +285 -0
  39. package/src/components/atoms.stories.js +342 -0
  40. package/src/components/avatar/avatar.css.js +67 -0
  41. package/src/components/avatar/avatar.js +42 -0
  42. package/src/components/avatar/avatar.stories.js +95 -0
  43. package/src/components/awards/awards-flex.css.js +209 -23
  44. package/src/components/awards/awards-flex.js +66 -7
  45. package/src/components/awards/awards-flex.stories.js +1 -1
  46. package/src/components/awards/{awards-light.stories.js → awards-summary.stories.js} +54 -64
  47. package/src/components/awards/awards.css.js +116 -58
  48. package/src/components/awards/awards.js +102 -28
  49. package/src/components/awards/awards.stories.js +1 -1
  50. package/src/components/back/back.css.js +51 -22
  51. package/src/components/back/back.js +28 -7
  52. package/src/components/back/back.stories.js +9 -3
  53. package/src/components/badge/badge.css.js +158 -46
  54. package/src/components/badge/badge.js +62 -74
  55. package/src/components/badge/badge.stories.js +176 -248
  56. package/src/components/bento-grid/bento-grid.css.js +21 -16
  57. package/src/components/bento-grid/bento-grid.js +16 -4
  58. package/src/components/bento-grid/bento-grid.stories.js +19 -18
  59. package/src/components/bento-grid/bento-item.css.js +52 -28
  60. package/src/components/bento-grid/bento-item.js +2 -2
  61. package/src/components/blockquote/blockquote.css.js +47 -0
  62. package/src/components/blockquote/blockquote.js +29 -0
  63. package/src/components/blockquote/blockquote.stories.js +62 -0
  64. package/src/components/breadcrumb/breadcrumb.css.js +92 -22
  65. package/src/components/breadcrumb/breadcrumb.js +56 -11
  66. package/src/components/button/button.css.js +531 -161
  67. package/src/components/button/button.js +206 -214
  68. package/src/components/button/button.stories.js +322 -174
  69. package/src/components/caption/caption.css.js +21 -0
  70. package/src/components/caption/caption.js +31 -0
  71. package/src/components/caption/caption.stories.js +62 -0
  72. package/src/components/card-features/card-features.css.js +14 -22
  73. package/src/components/card-features/card-features.js +68 -9
  74. package/src/components/card-features/card-features.stories.js +11 -11
  75. package/src/components/cards/card.css.js +60 -81
  76. package/src/components/cards/card.js +56 -25
  77. package/src/components/cards/card.stories.js +39 -39
  78. package/src/components/carousel/carousel.css.js +93 -99
  79. package/src/components/carousel/carousel.js +32 -4
  80. package/src/components/checkbox/checkbox.css.js +111 -93
  81. package/src/components/checkbox/checkbox.js +64 -90
  82. package/src/components/checkbox/checkbox.stories.js +96 -29
  83. package/src/components/code/code.css.js +70 -0
  84. package/src/components/code/code.js +40 -0
  85. package/src/components/code/code.stories.js +73 -0
  86. package/src/components/compare/compare.css.js +179 -43
  87. package/src/components/compare/compare.js +52 -25
  88. package/src/components/compare/compare.stories.js +61 -4
  89. package/src/components/comparison-panel/comparison-panel.css.js +38 -51
  90. package/src/components/comparison-panel/comparison-panel.js +5 -4
  91. package/src/components/comparison-panel/comparison-panel.stories.js +1 -1
  92. package/src/components/compatibility-table/compatibility-table.css.js +180 -80
  93. package/src/components/compatibility-table/compatibility-table.js +37 -9
  94. package/src/components/control-alignment.stories.js +393 -0
  95. package/src/components/cta-banner/cta-banner.css.js +41 -13
  96. package/src/components/cta-banner/cta-banner.js +6 -5
  97. package/src/components/cta-banner/cta-banner.stories.js +43 -98
  98. package/src/components/display/display.css.js +25 -1
  99. package/src/components/display/display.js +46 -13
  100. package/src/components/display/display.stories.js +270 -40
  101. package/src/components/divider/divider-horizontal.js +21 -5
  102. package/src/components/divider/divider-vertical.js +15 -7
  103. package/src/components/divider/divider.css.js +2 -2
  104. package/src/components/divider/divider.stories.js +38 -34
  105. package/src/components/dropdown/dropdown.css.js +93 -126
  106. package/src/components/dropdown/dropdown.js +114 -34
  107. package/src/components/dropdown/dropdown.stories.js +56 -24
  108. package/src/components/features/features.css.js +24 -11
  109. package/src/components/features/features.js +7 -3
  110. package/src/components/features/features.stories.js +37 -37
  111. package/src/components/features-tab/features-tab.css.js +19 -8
  112. package/src/components/features-tab/features-tab.js +6 -5
  113. package/src/components/features-tab/features-tab.stories.js +23 -23
  114. package/src/components/fieldset/fieldset.css.js +30 -0
  115. package/src/components/fieldset/fieldset.js +28 -0
  116. package/src/components/fieldset/fieldset.stories.js +84 -0
  117. package/src/components/footer/footer-links-group.css.js +10 -14
  118. package/src/components/footer/footer-links-group.js +4 -3
  119. package/src/components/footer/footer-lp.css.js +59 -30
  120. package/src/components/footer/footer-lp.js +17 -12
  121. package/src/components/footer/footer-lp.stories.js +63 -75
  122. package/src/components/footer/footer-nav-menu.css.js +26 -4
  123. package/src/components/footer/footer-nav-menu.js +3 -2
  124. package/src/components/footer/footer.css.js +146 -264
  125. package/src/components/footer/footer.js +176 -106
  126. package/src/components/footer/footer.stories.js +9 -9
  127. package/src/components/footer/localeMap.js +1 -1
  128. package/src/components/grid/grid.css.js +1 -1
  129. package/src/components/grid/grid.js +49 -7
  130. package/src/components/grid/grid.stories.js +111 -0
  131. package/src/components/header/header-code.css.js +61 -51
  132. package/src/components/header/header-code.js +28 -14
  133. package/src/components/header/header-code.stories.js +5 -5
  134. package/src/components/header/header.css.js +655 -176
  135. package/src/components/header/header.js +269 -36
  136. package/src/components/header/header.stories.js +841 -18
  137. package/src/components/heading/heading.css.js +14 -17
  138. package/src/components/heading/heading.js +48 -33
  139. package/src/components/heading/heading.stories.js +27 -25
  140. package/src/components/help-text/help-text.css.js +21 -0
  141. package/src/components/help-text/help-text.js +25 -0
  142. package/src/components/help-text/help-text.stories.js +66 -0
  143. package/src/components/highlight/highlight.css.js +86 -64
  144. package/src/components/highlight/highlight.js +18 -27
  145. package/src/components/highlight/highlight.stories.js +14 -3
  146. package/src/components/icons/analysis-icon.js +6 -16
  147. package/src/components/icons/arrow-down-icon.js +6 -19
  148. package/src/components/icons/arrow-icon.js +44 -0
  149. package/src/components/icons/arrow-right-icon.js +30 -23
  150. package/src/components/icons/arrow-up-icon.js +19 -18
  151. package/src/components/icons/bd-ai-icon.js +1 -1
  152. package/src/components/icons/brand-marks.stories.js +279 -0
  153. package/src/components/icons/brand-signature-icon.js +42 -0
  154. package/src/components/icons/check-icon.js +27 -0
  155. package/src/components/icons/circle-info-icon.js +33 -0
  156. package/src/components/icons/close-icon.js +6 -18
  157. package/src/components/icons/family-icon.js +8 -20
  158. package/src/components/icons/globe-icon.js +6 -18
  159. package/src/components/icons/guide-icon.js +6 -18
  160. package/src/components/icons/icon-element.js +99 -0
  161. package/src/components/icons/icons.js +36 -0
  162. package/src/components/icons/icons.stories.js +184 -52
  163. package/src/components/icons/individual-icon.js +6 -18
  164. package/src/components/icons/laurel-icon.js +9 -19
  165. package/src/components/icons/machine-learning-icon.js +6 -17
  166. package/src/components/icons/marks.js +41 -0
  167. package/src/components/icons/minus-icon.js +7 -21
  168. package/src/components/icons/missing-icon.js +52 -0
  169. package/src/components/icons/plus-icon.js +7 -21
  170. package/src/components/icons/quote-icon.js +19 -19
  171. package/src/components/image/image.css.js +72 -25
  172. package/src/components/image/image.js +11 -6
  173. package/src/components/image/image.stories.js +2 -2
  174. package/src/components/input/custom-form.stories.js +214 -62
  175. package/src/components/input/input-clipboard.css.js +51 -144
  176. package/src/components/input/input-clipboard.js +31 -15
  177. package/src/components/input/input.css.js +8 -146
  178. package/src/components/input/input.js +93 -38
  179. package/src/components/install-options/install-options.css.js +84 -77
  180. package/src/components/install-options/install-options.js +33 -30
  181. package/src/components/install-options/install-options.stories.js +3 -3
  182. package/src/components/label/label.css.js +35 -0
  183. package/src/components/label/label.js +38 -0
  184. package/src/components/label/label.stories.js +82 -0
  185. package/src/components/light-carousel/light-carousel.css.js +111 -63
  186. package/src/components/light-carousel/light-carousel.js +85 -11
  187. package/src/components/light-carousel/light-carousel.stories.js +126 -82
  188. package/src/components/link/link.css.js +150 -99
  189. package/src/components/link/link.js +86 -11
  190. package/src/components/link/link.stories.js +124 -30
  191. package/src/components/list/list-item/list-item.css.js +74 -22
  192. package/src/components/list/list-item/list-item.js +32 -10
  193. package/src/components/list/list-item/list-item.stories.js +23 -23
  194. package/src/components/list/list.css.js +8 -2
  195. package/src/components/list/list.js +3 -2
  196. package/src/components/list/list.stories.js +222 -0
  197. package/src/components/modal/modal.css.js +114 -24
  198. package/src/components/modal/modal.js +83 -7
  199. package/src/components/modal/modal.stories.js +9 -9
  200. package/src/components/overview/overview.css.js +19 -14
  201. package/src/components/overview/overview.js +6 -5
  202. package/src/components/overview/overview.stories.js +10 -10
  203. package/src/components/page-switcher/page-switcher.css.js +97 -40
  204. package/src/components/page-switcher/page-switcher.js +28 -5
  205. package/src/components/page-switcher/page-switcher.stories.js +95 -0
  206. package/src/components/paragraph/paragraph.css.js +15 -10
  207. package/src/components/paragraph/paragraph.js +41 -44
  208. package/src/components/paragraph/paragraph.stories.js +56 -21
  209. package/src/components/picture/picture.css.js +103 -44
  210. package/src/components/picture/picture.js +100 -30
  211. package/src/components/picture/picture.stories.js +1 -1
  212. package/src/components/pricing-cards/new-pricing-card.js +3 -3
  213. package/src/components/pricing-cards/new-pricing.css.js +24 -15
  214. package/src/components/pricing-cards/pricing-card-actions.css.js +1 -1
  215. package/src/components/pricing-cards/pricing-card-actions.js +3 -4
  216. package/src/components/pricing-cards/pricing-card-container.css.js +3 -3
  217. package/src/components/pricing-cards/pricing-card-container.js +3 -2
  218. package/src/components/pricing-cards/pricing-card-header.css.js +10 -8
  219. package/src/components/pricing-cards/pricing-card-header.js +6 -7
  220. package/src/components/pricing-cards/pricing-card-pricing.css.js +16 -9
  221. package/src/components/pricing-cards/pricing-card-pricing.js +8 -6
  222. package/src/components/pricing-cards/pricing-card-show-more.css.js +11 -3
  223. package/src/components/pricing-cards/pricing-card-show-more.js +8 -3
  224. package/src/components/pricing-cards/pricing-card.css.js +244 -190
  225. package/src/components/pricing-cards/pricing-card.js +54 -70
  226. package/src/components/pricing-cards/pricing-feature-item.css.js +25 -8
  227. package/src/components/pricing-cards/pricing-feature-item.js +8 -3
  228. package/src/components/process-steps/process-steps.css.js +26 -14
  229. package/src/components/process-steps/process-steps.js +23 -6
  230. package/src/components/process-steps/process-steps.stories.js +1 -1
  231. package/src/components/progress/progress.css.js +80 -0
  232. package/src/components/progress/progress.js +42 -0
  233. package/src/components/progress/progress.stories.js +79 -0
  234. package/src/components/quick-answer/quick-answer.css.js +75 -13
  235. package/src/components/quick-answer/quick-answer.js +8 -3
  236. package/src/components/radio/radio.css.js +92 -128
  237. package/src/components/radio/radio.js +106 -127
  238. package/src/components/radio/radio.stories.js +54 -19
  239. package/src/components/review/review-grid.css.js +5 -6
  240. package/src/components/review/review-grid.js +14 -11
  241. package/src/components/review/review.css.js +11 -6
  242. package/src/components/review/review.js +3 -8
  243. package/src/components/shared/ensemble.css.js +93 -0
  244. package/src/components/shared/form-field.css.js +206 -0
  245. package/src/components/shared/prop-vocabulary.js +48 -0
  246. package/src/components/shared/token-scales.js +306 -0
  247. package/src/components/skeleton/skeleton.css.js +34 -0
  248. package/src/components/skeleton/skeleton.js +32 -0
  249. package/src/components/skeleton/skeleton.stories.js +70 -0
  250. package/src/components/spinner/spinner.css.js +62 -0
  251. package/src/components/spinner/spinner.js +38 -0
  252. package/src/components/spinner/spinner.stories.js +92 -0
  253. package/src/components/spotlight-section/spotlight-section.css.js +14 -13
  254. package/src/components/spotlight-section/spotlight-section.js +42 -39
  255. package/src/components/switch/switch.css.js +103 -0
  256. package/src/components/switch/switch.js +44 -0
  257. package/src/components/switch/switch.stories.js +86 -0
  258. package/src/components/tab-list/content-switcher.stories.js +189 -0
  259. package/src/components/tab-list/tab-list.css.js +250 -0
  260. package/src/components/tab-list/tab-list.js +184 -0
  261. package/src/components/tab-list/tab-list.stories.js +221 -0
  262. package/src/components/tabs/tabs.css.js +14 -123
  263. package/src/components/tabs/tabs.js +16 -19
  264. package/src/components/tabs/tabs.stories.js +95 -95
  265. package/src/components/tag/tag.css.js +54 -0
  266. package/src/components/tag/tag.js +32 -0
  267. package/src/components/tag/tag.stories.js +126 -0
  268. package/src/components/terminal/terminal-message.css.js +164 -60
  269. package/src/components/terminal/terminal-message.js +5 -5
  270. package/src/components/terminal/terminal-message.stories.js +70 -1
  271. package/src/components/termsOfUse/terms.css.js +25 -20
  272. package/src/components/termsOfUse/terms.js +13 -9
  273. package/src/components/termsOfUse/terms.stories.js +1 -1
  274. package/src/components/textarea/textarea.css.js +51 -0
  275. package/src/components/textarea/textarea.js +136 -0
  276. package/src/components/textarea/textarea.stories.js +191 -0
  277. package/src/components/tooltip/tooltip.css.js +75 -0
  278. package/src/components/tooltip/tooltip.js +156 -0
  279. package/src/components/tooltip/tooltip.stories.js +161 -0
  280. package/src/components/trust-panel/trust-panel.css.js +85 -33
  281. package/src/components/trust-panel/trust-panel.js +18 -10
  282. package/src/components/trust-panel/trust-panel.stories.js +1 -1
  283. package/src/components/ultimate-security-demo.stories.js +431 -0
  284. package/src/components/video/video.css.js +17 -0
  285. package/src/components/video/video.js +40 -0
  286. package/src/components/video/video.stories.js +106 -0
  287. package/src/components/video-player/video-player.css.js +67 -11
  288. package/src/components/video-player/video-player.js +35 -4
  289. package/src/components/video-player/video-player.stories.js +1 -1
  290. package/src/components/visual-alignment.stories.js +411 -0
  291. package/src/components/visually-hidden/visually-hidden.css.js +24 -0
  292. package/src/components/visually-hidden/visually-hidden.js +16 -0
  293. package/src/components/visually-hidden/visually-hidden.stories.js +56 -0
  294. package/src/stories/Button.stories.js +17 -17
  295. package/src/stories/Header.stories.js +10 -10
  296. package/src/stories/Page.js +1 -1
  297. package/src/stories/Page.stories.js +6 -6
  298. package/src/tokens/borders.stories.js +339 -0
  299. package/src/tokens/color-responsibilities.stories.js +227 -0
  300. package/src/tokens/dark-derivation.js +309 -0
  301. package/src/tokens/dark-findings.js +197 -0
  302. package/src/tokens/dark-mode.stories.js +207 -0
  303. package/src/tokens/dimension.stories.js +251 -0
  304. package/src/tokens/elevation.stories.js +143 -0
  305. package/src/tokens/focus.stories.js +276 -0
  306. package/src/tokens/fonts.css +20 -20
  307. package/src/tokens/fonts.stories.js +354 -374
  308. package/src/tokens/layout.css +25 -11
  309. package/src/tokens/motion.stories.js +231 -0
  310. package/src/tokens/shape.stories.js +272 -0
  311. package/src/tokens/spacing-rhythm.stories.js +359 -0
  312. package/src/tokens/spacing.stories.js +208 -703
  313. package/src/tokens/story-chrome.js +503 -0
  314. package/src/tokens/surfaces.stories.js +224 -0
  315. package/src/tokens/text-on-surface.stories.js +164 -0
  316. package/src/tokens/token-map.js +220 -0
  317. package/src/tokens/token-map.stories.js +257 -0
  318. package/src/tokens/token-purposes.js +266 -0
  319. package/src/tokens/tokens-grid.stories.js +388 -900
  320. package/src/tokens/tokens.css +1633 -1045
  321. package/src/tokens/tokens.js +1130 -492
  322. package/src/tokens/tokens.stories.js +137 -47
  323. package/src/tokens/type-ceiling-words.js +299 -0
  324. package/src/tokens/typography.stories.js +1003 -965
  325. package/src/tokens/vertical-rhythm.stories.js +224 -0
  326. package/src/components/awards/awards-icon.js +0 -56
  327. package/src/components/awards/awards-light.js +0 -240
  328. package/src/components/banner/banner.js +0 -60
  329. package/src/components/banner/banner.stories.js +0 -51
  330. package/src/components/button/icons.js +0 -24
  331. package/src/components/input/index.js +0 -0
  332. package/src/components/light-carousel/light-carousel-simple.css.js +0 -183
  333. package/src/components/light-carousel/light-carousel-simple.js +0 -74
  334. package/src/tokens/colors.js +0 -121
  335. package/src/tokens/typography.css.js +0 -207
  336. package/src/tokens/typography.js +0 -0
@@ -0,0 +1,198 @@
1
+ import { css } from 'lit';
2
+
3
+ /**
4
+ * Styled entirely from design tokens -- see npm run lint:tokens.
5
+ *
6
+ * Reshaped 2026-09-14 to the Eclipse Alert banner (Figma yzCimjlQG7RzokkgVpjfnZ
7
+ * node 5021:11630), using this package's roles rather than that file's
8
+ * variables. The two systems turn out to share ancestry: three of the five
9
+ * tints matched byte-for-byte (blue f0f7ff, green edfdf1, red fff0f0), the type
10
+ * size matched at 14px, and the radius, gaps and padding all landed on our
11
+ * existing scales -- radius/small 8px IS --radius-lg, and 16/12/8 are
12
+ * --spacing-16/12/8.
13
+ *
14
+ * Two places the design and this package disagree, both resolved our way
15
+ * because our tokens are the brief:
16
+ *
17
+ * warning tint the design is fff6f0, an orange; --status-warning-surface is
18
+ * fffbf0, a yellow. Ours. Worth knowing that warning is the
19
+ * tightest of the six: its accent reads 3.49:1 on its own
20
+ * tint where every other tone clears 4.2, so a future change
21
+ * to either half has least room here.
22
+ * actions ink the design is 0045ad; --color-text-brand is blue-600
23
+ * 0059d6. Ours, and blue-600 is the documented choice for ink
24
+ * on a tint -- CLAUDE.md records blue-500 as failing there.
25
+ *
26
+ * THE LEFT ACCENT RULE IS GONE. This atom carried a 4px border-left in the
27
+ * tone's accent colour; the design is tint-only, with a full border on the
28
+ * outline variant instead. That is a visible change to a shipped atom and it
29
+ * was asked for. The invariant the old rule existed to keep -- that an alert
30
+ * and a bd-badge of the same tone are the same colour by construction, because
31
+ * both read --status-<tone>-accent -- survives, because the icon now carries
32
+ * it.
33
+ *
34
+ * EVERY COMBINATION WAS MEASURED, not assumed: title and description
35
+ * (--color-text-primary) run 16.03 to 17.97:1 across the six grounds, the
36
+ * actions ink 5.51 to 6.18, and the tone accents 3.49 to 8.39 against the 3:1
37
+ * non-text bar. No pair needed a compromise.
38
+ */
39
+ export const alertCSS = css`
40
+ :host {
41
+ display: block;
42
+ }
43
+
44
+ /* The native hidden attribute has to beat the display above, or a consumer
45
+ writing <bd-alert hidden> gets a visible alert. Same fix as
46
+ icons/icon-element.js. */
47
+ :host([hidden]) {
48
+ display: none;
49
+ }
50
+
51
+ .alert {
52
+ display: flex;
53
+ align-items: flex-start;
54
+ gap: var(--spacing-12);
55
+ padding: var(--spacing-16);
56
+ border-radius: var(--radius-lg);
57
+ font-family: var(--typography-fontFamily-sans);
58
+ /* Set ONCE, here. The title differs from the description by weight only,
59
+ which is what the design does too -- Body/medium/semibold over
60
+ Body/medium/regular, both 14px -- so nothing below re-declares a size.
61
+ .
62
+ THE LEADING IS DELIBERATELY NOT THE DESIGN'S. The design specifies 20px;
63
+ this resolves to 1.45, which computes to 20.3px at 14px. Confirmed 2026-09-14
64
+ to stay as it is: a unitless ratio is the first rule of this package's
65
+ typography contract, because an absolute 20px stops scaling when a reader
66
+ enlarges their text, which is the defect the rule exists to prevent. The
67
+ 0.3px is the price of keeping it. 1.45 also clears the Plex leading floor
68
+ that Romanian diacritics need, so there is no clipping risk in dropping
69
+ toward the design's figure -- but there is no reason to. */
70
+ font-size: var(--typography-body-small-fontSize);
71
+ line-height: var(--typography-body-small-lineHeight);
72
+ color: var(--color-text-primary);
73
+ background: var(--status-info-surface);
74
+ }
75
+
76
+ /* The tone sets the ground and the icon's ink in one place, so the two cannot
77
+ drift apart. The icon reads currentColor from .icon, which is the rule the
78
+ icon atoms already follow. */
79
+ .icon {
80
+ flex: none;
81
+ display: flex;
82
+ color: var(--status-info-accent);
83
+ }
84
+
85
+ :host([tone='success']) .alert {
86
+ background: var(--status-success-surface);
87
+ }
88
+
89
+ :host([tone='success']) .icon {
90
+ color: var(--status-success-accent);
91
+ }
92
+
93
+ :host([tone='warning']) .alert {
94
+ background: var(--status-warning-surface);
95
+ }
96
+
97
+ :host([tone='warning']) .icon {
98
+ color: var(--status-warning-accent);
99
+ }
100
+
101
+ :host([tone='error']) .alert {
102
+ background: var(--status-error-surface);
103
+ }
104
+
105
+ :host([tone='error']) .icon {
106
+ color: var(--status-error-accent);
107
+ }
108
+
109
+ :host([tone='neutral']) .alert {
110
+ background: var(--status-neutral-surface);
111
+ }
112
+
113
+ :host([tone='neutral']) .icon {
114
+ color: var(--status-neutral-accent);
115
+ }
116
+
117
+ /* The outline variant is a SURFACE treatment, not a tone: it keeps whichever
118
+ tone's icon is set and drops the tint for the page ground plus an edge.
119
+ That is why it is its own attribute rather than a sixth tone -- the design
120
+ models both axes in one enum, and folding a surface choice into the status
121
+ vocabulary is the category error CLAUDE.md names.
122
+ .
123
+ The edge takes --color-border-container, the role for a self-contained
124
+ object's boundary, which is what this is. The design spells it
125
+ rgba(0,0,0,0.1); the role is neutral-100 and within a shade of it. */
126
+ :host([variant='outline']) .alert {
127
+ background: var(--color-surface-default);
128
+ border: var(--border-width-1) solid var(--color-border-container);
129
+ }
130
+
131
+ .content {
132
+ flex: 1 1 auto;
133
+ min-width: 0;
134
+ display: flex;
135
+ flex-direction: column;
136
+ gap: var(--spacing-8);
137
+ overflow-wrap: break-word;
138
+ }
139
+
140
+ /* no role: the title's weight. Semibold at 14px is not a role this package
141
+ has -- body-small is 400, label-default and control-label-default are 500 --
142
+ and the element is doing the work a role would name. It stays a strong so
143
+ the emphasis is in the markup rather than in a class, which is the same
144
+ argument button.css.js's .button--bold makes.
145
+ .
146
+ The value is deliberate and not the UA default: strong renders at bolder
147
+ (700), and semibold keeps an alert title from shouting inside a status
148
+ strip. The design agrees -- Body/medium/semibold. */
149
+ .title { font-weight: var(--typography-fontWeight-semibold); }
150
+
151
+ /* The design gives the description a 24px floor so a one-line alert has the
152
+ same height as the icon beside it and the row does not look top-heavy. */
153
+ .body {
154
+ min-height: var(--icon-lg-size);
155
+ }
156
+
157
+ /* Each action is its own flex item, so the gap needs each one slotted
158
+ separately -- wrapping several in one span makes them a single item and
159
+ they run together with no space. The stories show the right shape.
160
+ .
161
+ The colour here is a DEFAULT, not the source of the action ink: bd-link
162
+ and bd-button both set their own, so in normal use this never paints. It
163
+ is kept so a bare anchor or a run of text slotted here gets brand ink
164
+ rather than the UA's blue, which is the only case it applies to. Do not go
165
+ looking here for why an action is the colour it is -- look at the atom. */
166
+ .actions {
167
+ display: flex;
168
+ flex-wrap: wrap;
169
+ align-items: center;
170
+ gap: var(--spacing-12);
171
+ color: var(--color-text-brand);
172
+ }
173
+
174
+ /* Rendered only when something is slotted in, so an alert without actions
175
+ does not carry an empty row and the gap above it. */
176
+ .actions[hidden] {
177
+ display: none;
178
+ }
179
+
180
+ .dismiss {
181
+ flex: none;
182
+ display: flex;
183
+ padding: var(--spacing-0);
184
+ border: none;
185
+ background: none;
186
+ color: var(--color-text-muted);
187
+ border-radius: var(--focus-outline-radius);
188
+ cursor: pointer;
189
+ }
190
+
191
+ /* One token, one painter -- the same invariant accordion.css.js records. */
192
+ .dismiss:focus-visible {
193
+ outline: none;
194
+ box-shadow: var(--focus-outline-primary);
195
+ }
196
+ `;
197
+
198
+ export default alertCSS;
@@ -0,0 +1,103 @@
1
+ import { LitElement, html, nothing } from 'lit';
2
+ // Installs the design tokens into document scope; see src/tokens/tokens.js
3
+ import '../../tokens/tokens.js';
4
+ import '../icons/circle-info-icon.js';
5
+ import '../icons/close-icon.js';
6
+ import { alertCSS } from './alert.css.js';
7
+
8
+ /**
9
+ * A status banner: an icon, a title, a description, optional actions, and an
10
+ * optional dismiss.
11
+ *
12
+ * Shaped to the Eclipse Alert banner (Figma yzCimjlQG7RzokkgVpjfnZ node
13
+ * 5021:11630) with this package's roles. See alert.css.js for what the two
14
+ * systems agreed on and the two places they did not.
15
+ *
16
+ * TWO AXES, NOT ONE. The design models six values of a single `type` enum:
17
+ * Information, Success, Danger, Warning, Neutral and Outline. Five of those are
18
+ * statuses and one is a surface treatment, so this element keeps them apart --
19
+ * `tone` for the status, `variant` for the treatment. An outline alert still
20
+ * has a tone, and folding the two into one attribute would mean
21
+ * tone="outline", which says nothing about what the alert is telling you.
22
+ *
23
+ * THE LEADING ICON. bd-circle-info-icon, the glyph the design asked for. It
24
+ * was a bd-missing-icon placeholder from the day this component was built --
25
+ * a visible dashed box that check:icons reported as owed -- which is the
26
+ * recorded process for an icon we need and have not drawn: no font glyph, no
27
+ * inline path, no silent omission. The artwork arrived from Eclipse and the
28
+ * placeholder is gone. Pass your own through the icon slot to override it.
29
+ */
30
+ export class BdAlert extends LitElement {
31
+ static styles = [alertCSS];
32
+
33
+ static properties = {
34
+ /** info | success | warning | error | neutral */
35
+ tone : { type: String, reflect: true },
36
+ /** tint (default) | outline */
37
+ variant : { type: String, reflect: true },
38
+ heading : { type: String },
39
+ dismissible : { type: Boolean, reflect: true },
40
+ /** The dismiss button's accessible name, overridable per context. */
41
+ dismisslabel: { type: String },
42
+ _hasActions : { state: true }
43
+ };
44
+
45
+ constructor() {
46
+ super();
47
+ this.tone = 'info';
48
+ this.variant = 'tint';
49
+ this.heading = '';
50
+ this.dismissible = false;
51
+ this.dismisslabel = 'Dismiss alert';
52
+ this._hasActions = false;
53
+ }
54
+
55
+ /* The actions row is only rendered when something is slotted into it, so an
56
+ alert without actions does not carry an empty row and the gap above it.
57
+ Read from the slot rather than from a querySelector at render time, so it
58
+ stays right when a consumer adds or removes actions later. */
59
+ _onActionsSlotChange(event) {
60
+ this._hasActions = event.target.assignedNodes({ flatten: true })
61
+ .some(n => n.nodeType === Node.ELEMENT_NODE || n.textContent.trim());
62
+ }
63
+
64
+ _onDismiss() {
65
+ /* The element does not remove itself: what should happen to the space it
66
+ occupied is the page's decision, not the atom's. */
67
+ this.dispatchEvent(new CustomEvent('bd-dismiss', { bubbles: true, composed: true }));
68
+ }
69
+
70
+ render() {
71
+ return html`
72
+ <div class="alert" role=${this.tone === 'error' ? 'alert' : 'status'}>
73
+ <span class="icon">
74
+ <slot name="icon">
75
+ <bd-circle-info-icon size="lg"></bd-circle-info-icon>
76
+ </slot>
77
+ </span>
78
+
79
+ <div class="content">
80
+ ${this.heading ? html`<strong class="title">${this.heading}</strong>` : nothing}
81
+ <div class="body"><slot></slot></div>
82
+ <div class="actions" ?hidden=${!this._hasActions}>
83
+ <slot name="actions" @slotchange=${this._onActionsSlotChange}></slot>
84
+ </div>
85
+ </div>
86
+
87
+ ${this.dismissible
88
+ ? html`
89
+ <button
90
+ class="dismiss"
91
+ type="button"
92
+ aria-label=${this.dismisslabel}
93
+ @click=${this._onDismiss}
94
+ >
95
+ <bd-close-icon size="sm"></bd-close-icon>
96
+ </button>`
97
+ : nothing}
98
+ </div>
99
+ `;
100
+ }
101
+ }
102
+
103
+ customElements.define('bd-alert', BdAlert);
@@ -0,0 +1,206 @@
1
+ import { html } from 'lit';
2
+ import './alert.js';
3
+ import '../link/link.js';
4
+
5
+ export default {
6
+ title : 'Atoms/Alert',
7
+ tags : ['autodocs'],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: `
12
+ **BdAlert** is an inline message about the state of something on the page. It
13
+ belongs in the flow, next to whatever it describes — it is not a toast or a
14
+ dialog.
15
+
16
+ ### Usage
17
+ \`\`\`html
18
+ <bd-alert>Your subscription renews on 12 March.</bd-alert>
19
+ <bd-alert tone="success" heading="Payment received">A receipt is on its way.</bd-alert>
20
+ <bd-alert tone="error" heading="Card declined">Check the expiry date and try again.</bd-alert>
21
+
22
+ <bd-alert variant="outline" heading="On a tinted page">
23
+ Drops the tint for the page ground and an edge.
24
+ </bd-alert>
25
+
26
+ <bd-alert tone="warning" heading="Two devices are out of date." dismissible>
27
+ Windows Defender is still handling protection on them.
28
+ <bd-link inline slot="actions" href="#">Review devices</bd-link>
29
+ </bd-alert>
30
+ \`\`\`
31
+
32
+ ### Props
33
+ | Prop | Values | Default |
34
+ |---|---|---|
35
+ | \`tone\` | \`info\`, \`success\`, \`warning\`, \`error\`, \`neutral\` | \`info\` |
36
+ | \`variant\` | \`tint\`, \`outline\` | \`tint\` |
37
+ | \`heading\` | any string — omit for a description-only alert | \`''\` |
38
+ | \`dismissible\` | boolean — adds a close button | \`false\` |
39
+ | \`dismisslabel\` | the close button's accessible name | \`Dismiss alert\` |
40
+
41
+ ### Slots
42
+ | Slot | For |
43
+ |---|---|
44
+ | *(default)* | the description. Carries markup, such as a link |
45
+ | \`icon\` | replaces the leading icon |
46
+ | \`actions\` | one or more actions under the description. Collapses when empty. **Each action is its own slotted element** — wrapping several in one span makes them a single flex item and they lose the gap between them |
47
+
48
+ ### Slotted links need \`inline\`
49
+ A \`bd-link\` without \`inline\` is a **standalone** link and sets its own size:
50
+ \`--typography-link-standalone-fontSize\` is \`1rem\`, where this alert's prose is
51
+ \`body-small\` at \`0.875rem\`. Dropped into an alert it renders 16px inside 14px
52
+ text, with a taller line box that pushes the surrounding line apart.
53
+
54
+ \`inline\` selects \`--typography-link-default-*\`, which is \`inherit\` for both
55
+ size and leading — deliberately, per typography rule 10 in CLAUDE.md: a link
56
+ inside a sentence sits in that sentence's line box. The same applies to an
57
+ action, which should match the alert it belongs to rather than assert a size of
58
+ its own.
59
+
60
+ The alert **cannot** fix this for you. \`::slotted(bd-link)\` sets properties on
61
+ the host, and the link's own shadow rule sets \`font-size\` on the element
62
+ inside it, so the host never wins. The attribute is the only lever.
63
+
64
+ ### Two axes, not one
65
+ The Figma source models six values of a single \`type\`: five statuses plus
66
+ \`Outline\`. Outline is a **surface treatment**, not a status — an outline alert
67
+ still needs to say whether it is an error — so the two are separate attributes
68
+ here. \`tone="outline"\` would tell a reader nothing about what the alert means.
69
+
70
+ ### The leading icon is a placeholder
71
+ The design's glyph is a circle-info, which this package has not drawn. The
72
+ default is therefore \`bd-missing-icon\` — a visible dashed box that
73
+ \`npm run check:icons\` reports as owed. Pass real artwork through the \`icon\`
74
+ slot to override it.
75
+
76
+ ### Accessibility
77
+ Only \`error\` gets \`role="alert"\`, which interrupts a screen reader. Every other
78
+ tone gets \`role="status"\`, announced politely when the user is idle.
79
+
80
+ That means **\`warning\` is announced politely, not urgently.** If a warning in
81
+ your context is time-critical, that is worth revisiting — the split is
82
+ currently error-only.
83
+
84
+ The tone is never the only signal: the heading and the description carry the
85
+ meaning too, so the alert still works for anyone who cannot distinguish the
86
+ tint. Every pairing was measured rather than assumed — the ink runs 16.03 to
87
+ 17.97:1 across the six grounds, the actions ink 5.51 to 6.18, and the tone
88
+ accents 3.49 to 8.39 against the 3:1 non-text bar.
89
+
90
+ \`dismissible\` emits \`bd-dismiss\` and does **not** remove the element: what
91
+ happens to the space it occupied is the page's decision, not the atom's.
92
+ `
93
+ }
94
+ }
95
+ },
96
+ argTypes: {
97
+ tone: {
98
+ control : { type: 'select' },
99
+ options : ['info', 'success', 'warning', 'error', 'neutral'],
100
+ description: 'Which kind of message this is. Only `error` announces urgently.',
101
+ table : { type: { summary: 'string' }, defaultValue: { summary: 'info' }, category: 'Appearance' }
102
+ },
103
+ variant: {
104
+ control : { type: 'select' },
105
+ options : ['tint', 'outline'],
106
+ description: 'A surface treatment, independent of the tone. `outline` drops the tint for the page ground and an edge.',
107
+ table : { type: { summary: 'string' }, defaultValue: { summary: 'tint' }, category: 'Appearance' }
108
+ },
109
+ heading: {
110
+ control : 'text',
111
+ description: 'Optional title, on its own line above the description.',
112
+ table : { type: { summary: 'string' }, defaultValue: { summary: '' }, category: 'Content' }
113
+ },
114
+ dismissible: {
115
+ control : 'boolean',
116
+ description: 'Adds a close button that emits `bd-dismiss`. The element does not remove itself.',
117
+ table : { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, category: 'Behaviour' }
118
+ },
119
+ dismisslabel: {
120
+ control : 'text',
121
+ description: "The close button's accessible name.",
122
+ table : { type: { summary: 'string' }, defaultValue: { summary: 'Dismiss alert' }, category: 'Accessibility' }
123
+ }
124
+ }
125
+ };
126
+
127
+ export const Tones = () => html`
128
+ <div style="display:grid; gap:1rem">
129
+ <bd-alert heading="Heads up.">Your licence renews in 14 days.</bd-alert>
130
+ <bd-alert tone="success" heading="Done.">Your device is protected.</bd-alert>
131
+ <bd-alert tone="warning" heading="Check this.">Two devices are out of date.</bd-alert>
132
+ <bd-alert tone="error" heading="Blocked.">We could not reach the update server.</bd-alert>
133
+ <bd-alert tone="neutral" heading="For reference.">Scans run weekly on this plan.</bd-alert>
134
+ </div>
135
+ `;
136
+
137
+ /**
138
+ * The `outline` variant is a surface treatment and keeps its tone. Both alerts
139
+ * below are still `info` and `error` respectively — the icon says so, and the
140
+ * error one still carries `role="alert"`. Use it where the page already has a
141
+ * tint of its own and a second one would read as dirt.
142
+ */
143
+ export const Outline = () => html`
144
+ <div style="display:grid; gap:1rem">
145
+ <bd-alert variant="outline" heading="Heads up.">Your licence renews in 14 days.</bd-alert>
146
+ <bd-alert variant="outline" tone="error" heading="Blocked.">We could not reach the update server.</bd-alert>
147
+ </div>
148
+ `;
149
+
150
+ /**
151
+ * `heading` is optional, and without it the alert is description only. Worth
152
+ * its own snapshot because it is the shape most inline alerts actually take.
153
+ */
154
+ export const WithoutHeading = () => html`
155
+ <div style="display:grid; gap:1rem">
156
+ <bd-alert>Your licence renews in 14 days.</bd-alert>
157
+ <bd-alert tone="success">Your device is protected.</bd-alert>
158
+ <bd-alert tone="error">We could not reach the update server.</bd-alert>
159
+ </div>
160
+ `;
161
+
162
+ /**
163
+ * The `actions` slot takes one or more actions under the description. It
164
+ * collapses entirely when nothing is slotted into it, so the three alerts above
165
+ * carry no empty row — compare their heights with these.
166
+ */
167
+ export const WithActions = () => html`
168
+ <bd-alert tone="warning" heading="Two devices are out of date.">
169
+ Windows Defender is still handling real-time protection on them.
170
+ <bd-link inline slot="actions" href="#">Review devices</bd-link>
171
+ <bd-link inline slot="actions" href="#">Remind me later</bd-link>
172
+ </bd-alert>
173
+ `;
174
+
175
+ /**
176
+ * `dismissible` adds the close button. It emits `bd-dismiss` and deliberately
177
+ * does not remove the element — whether the space collapses, animates out, or
178
+ * is replaced is the page's call. This story logs the event rather than acting
179
+ * on it, which is the honest demonstration.
180
+ */
181
+ export const Dismissible = () => html`
182
+ <bd-alert
183
+ tone="success"
184
+ heading="Payment received."
185
+ dismissible
186
+ @bd-dismiss=${e => e.target.setAttribute('hidden', '')}
187
+ >
188
+ A receipt is on its way. This story hides the alert on dismiss, which is
189
+ one of several things a page might reasonably do.
190
+ </bd-alert>
191
+ `;
192
+
193
+ /**
194
+ * The description is slotted, so it can carry markup — and it wraps. This is
195
+ * the story that shows the icon staying pinned to the first line while the
196
+ * text runs on, which is what `align-items: flex-start` on the row is for.
197
+ */
198
+ export const LongMessage = () => html`
199
+ <div style="max-width: 46ch">
200
+ <bd-alert tone="warning" heading="Two devices are out of date." dismissible>
201
+ Windows Defender is still handling real-time protection on them. Open
202
+ <bd-link inline href="#">Device overview</bd-link> to finish setting up, or
203
+ remove the devices you no longer use.
204
+ </bd-alert>
205
+ </div>
206
+ `;