@repobit/dex-system-design 0.25.12 → 1.0.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 +204 -0
  2. package/README.md +131 -8
  3. package/package.json +96 -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
@@ -1,24 +1,54 @@
1
1
  import { LitElement, html } from 'lit';
2
+ // Installs the design tokens into document scope; see src/tokens/tokens.js
3
+ import "../../tokens/tokens.js";
4
+ /* The md boundary comes from the shared breakpoint source so the CSS and the
5
+ JS cannot drift apart again: bd-footer switched at 767 while bd-footer-lp,
6
+ sharing footer-nav-menu.css.js, switched at 768 — so at exactly 768px the
7
+ LP footer rendered its mobile markup under the desktop stylesheet. */
8
+ import { matchesBelow } from '../shared/token-scales.js';
2
9
  import '../../components/divider/divider-horizontal.js';
3
10
  import '../../components/divider/divider-vertical.js';
4
11
  import '../../components/footer/footer-links-group.js';
5
12
  import '../../components/footer/footer-nav-menu.js';
6
13
  import '../../components/grid/grid.js';
7
14
  import '../../components/link/link.js';
8
- import { tokens } from "../../tokens/tokens.js";
9
15
  import "../icons/arrow-down-icon.js";
10
16
  import "../icons/arrow-up-icon.js";
11
17
  import "../icons/close-icon.js";
12
18
  import "../icons/globe-icon.js";
13
19
  import footerCSS from './footer.css.js';
20
+ import { ensembleCSS } from '../shared/ensemble.css.js';
14
21
  import { localeMap } from './localeMap.js';
15
22
 
23
+ /* The locale a footer shows when neither the page nor the URL says otherwise. */
24
+ const DEFAULT_LOCALE = 'en';
25
+
16
26
  export class BdFooter extends LitElement {
17
27
  static properties = {
18
28
  _countriesOpen : { state: true },
19
29
  selectedCountry : { state: true },
20
- currentLocale : { type: String },
21
- maxColumnsPerRow : { type: Number },
30
+ /* `current-locale` and `max-columns-per-row`, both documented dash-cased
31
+ and both previously inert for the same reason as bd-header above: Lit
32
+ lowercases a property name to get its observed attribute, so these were
33
+ listening for `currentlocale` and `maxcolumnsperrow`.
34
+
35
+ current-locale is the consequential one, and it did not merely fail --
36
+ it failed into nonsense. The attribute was ignored, so the locale fell
37
+ through to URL detection, and under Storybook the path is /iframe.html:
38
+ measured on Components/Footer Default, Romanian Locale and German
39
+ Locale, all three reported currentLocale "iframe.html" while their
40
+ markup asked for "en", "ro" and "de". Twelve usages in footer.stories.js
41
+ write it, including the documented usage example.
42
+
43
+ max-columns-per-row has a single usage, in the playground, and it passes
44
+ 2 -- which is already the default -- so repairing it changes no rendered
45
+ output today. It is fixed with the other one because it is the same
46
+ defect in the same declaration block, not because it was visible.
47
+
48
+ Zero consumers of either working lowercase spelling across src, schemas
49
+ and docs, and no property bindings, so naming the attributes is safe. */
50
+ currentLocale : { type: String, attribute: "current-locale" },
51
+ maxColumnsPerRow : { type: Number, attribute: "max-columns-per-row" },
22
52
  _isMobile : { state: true },
23
53
  _countriesContainer: { state: true }
24
54
  };
@@ -27,14 +57,21 @@ export class BdFooter extends LitElement {
27
57
  super();
28
58
  this._countriesOpen = false;
29
59
  this.maxColumnsPerRow = 2;
30
- this.currentLocale = 'en';
60
+ this.currentLocale = DEFAULT_LOCALE;
31
61
  this.selectedCountry = 'Choose your country';
32
- this._isMobile = window.innerWidth <= 767;
62
+ this._isMobile = matchesBelow('md');
33
63
  this._countriesContainer = null;
34
64
  }
35
65
 
36
66
  connectedCallback() {
37
67
  super.connectedCallback();
68
+ /* Whether the consuming page asked for a locale, captured before inference
69
+ runs. An attribute in the markup counts, and so does a property assigned
70
+ before the element connects -- both are the page stating its intent. A
71
+ page that explicitly asks for 'en' is indistinguishable from one that
72
+ said nothing, and that costs nothing: it asked for the value it gets. */
73
+ this._localeExplicit =
74
+ this.hasAttribute('current-locale') || this.currentLocale !== DEFAULT_LOCALE;
38
75
  this._initLocaleFromUrl();
39
76
  window.addEventListener('resize', this._handleResize.bind(this));
40
77
  }
@@ -46,12 +83,10 @@ export class BdFooter extends LitElement {
46
83
 
47
84
  firstUpdated() {
48
85
  super.firstUpdated();
49
- this._updateNavLinks();
50
86
  }
51
87
 
52
88
  updated(changedProps) {
53
89
  if (changedProps.has('currentLocale')) {
54
- this._updateNavLinks();
55
90
  this._toggleImpressumVisibility();
56
91
  }
57
92
 
@@ -61,6 +96,30 @@ export class BdFooter extends LitElement {
61
96
  }
62
97
  }
63
98
 
99
+ /* maxColumnsPerRow, finally read. The property has been declared here with
100
+ a default of 2 since it was written, the manifest claims it, and
101
+ footer.stories.js documents it as "Max columns per row in the quick-links
102
+ grid" -- and nothing ever looked at it. P7H.1 made the attribute reach the
103
+ property; this makes the property reach the layout.
104
+
105
+ It drives the grid the documentation names, through the cols-* attributes
106
+ bd-grid observes since P7H. Mobile and sm stay at one column because the
107
+ footer stacks there regardless of the cap, and md is capped at 2 because
108
+ that is what md has always shown -- the property raises the ceiling at the
109
+ widest breakpoint rather than redesigning the ladder.
110
+
111
+ The default therefore renders exactly what it rendered before:
112
+ min(2, 2) = 2 at md and 2 at lg, which is the pair that was hard-coded.
113
+ Verified by measurement, not by reading.
114
+
115
+ Clamped because the attribute is public: a 0, a negative or a fractional
116
+ value would otherwise reach grid-template-columns as
117
+ `repeat(0, 1fr)`. */
118
+ get _maxColumns() {
119
+ const n = Math.floor(Number(this.maxColumnsPerRow));
120
+ return Number.isFinite(n) && n >= 1 ? n : 2;
121
+ }
122
+
64
123
  _toggleImpressumVisibility() {
65
124
  const showImpressum = this.locale === 'de-de' || this.locale === 'de';
66
125
  const slot = this.shadowRoot.querySelector('slot[name="secondary-nav"]');
@@ -101,75 +160,80 @@ export class BdFooter extends LitElement {
101
160
  }
102
161
 
103
162
  _handleResize() {
104
- this._isMobile = window.innerWidth <= 767;
105
- const newIsMobile = window.innerWidth <= 767;
163
+ this._isMobile = matchesBelow('md');
164
+ const newIsMobile = matchesBelow('md');
106
165
 
107
166
  if (this._isMobile !== newIsMobile) {
108
167
  this._isMobile = newIsMobile;
109
168
  }
110
169
  }
111
170
 
171
+ /* Locale precedence, and it is a precedence rather than a sequence of
172
+ assignments -- which is what went wrong.
173
+
174
+ 1. the country selector, when a reader picks one (see _selectCountry)
175
+ 2. an explicit current-locale attribute or currentLocale property
176
+ 3. a locale inferred from the first path segment, IF it resolves to a
177
+ supported locale
178
+ 4. DEFAULT_LOCALE
179
+
180
+ Two defects sat in the old version, both in its closing lines. It ended
181
+ with an unconditional `this.currentLocale = originalKey || urlLocale`,
182
+ so:
183
+
184
+ - an explicit input was silently overwritten by the environment. Measured:
185
+ <bd-footer current-locale="ro"> served from /de/ reported "de".
186
+ - any first path segment became the locale verbatim, supported or not.
187
+ Measured: /iframe.html reported currentLocale "iframe.html", and /zz-zz/
188
+ reported "zz-zz".
189
+
190
+ The second is why Storybook showed "iframe.html" as a locale, and the fix
191
+ is not a Storybook exception -- there is none here. A segment that does
192
+ not resolve against localeMap is simply not a locale, on any host. The
193
+ resolution itself (exact key, then language with a matching region, then
194
+ any key sharing the language) is unchanged; only its authority is. */
112
195
  _initLocaleFromUrl() {
113
- const urlLocale = window.location.pathname.split('/')[1]?.toLowerCase();
196
+ if (this._localeExplicit) return;
114
197
 
115
- if (!urlLocale) {
116
- this._updateNavLinks();
117
- return;
118
- }
198
+ const urlLocale = window.location.pathname.split('/')[1]?.toLowerCase();
199
+ if (!urlLocale) return;
119
200
 
120
- const normalizedLocaleMap = {};
201
+ const normalized = {};
121
202
  Object.entries(localeMap).forEach(([key, value]) => {
122
- normalizedLocaleMap[key.toLowerCase()] = value;
203
+ normalized[key.toLowerCase()] = value;
123
204
  });
124
-
125
- let country = normalizedLocaleMap[urlLocale];
126
-
127
- if (!country && urlLocale) {
128
- const localeParts = urlLocale.split('-');
129
- const language = localeParts[0];
130
- const region = localeParts[1];
131
-
132
- const possibleMatches = Object.entries(normalizedLocaleMap)
205
+ const originalKeyFor = lower =>
206
+ Object.keys(localeMap).find(k => k.toLowerCase() === lower);
207
+
208
+ let resolvedKey = null;
209
+ let country = null;
210
+
211
+ if (normalized[urlLocale]) {
212
+ resolvedKey = originalKeyFor(urlLocale) || urlLocale;
213
+ country = normalized[urlLocale];
214
+ } else {
215
+ const [language, region] = urlLocale.split('-');
216
+ const sameLanguage = Object.entries(normalized)
133
217
  .filter(([key]) => key.startsWith(language));
134
218
 
135
- if (possibleMatches.length > 0) {
136
- const exactRegionMatch = possibleMatches.find(([key]) => {
137
- const keyParts = key.split('-');
138
- const keyRegion = keyParts[1];
139
- const regionMatch = region && keyRegion === region;
140
- const languageOnlyMatch = !region && keyParts.length === 1;
141
-
142
- return regionMatch || languageOnlyMatch;
219
+ if (sameLanguage.length) {
220
+ const exactRegion = sameLanguage.find(([key]) => {
221
+ const keyRegion = key.split('-')[1];
222
+ return (region && keyRegion === region) || (!region && !keyRegion);
143
223
  });
144
-
145
- if (exactRegionMatch) {
146
- country = exactRegionMatch[1];
147
- const originalKey = Object.keys(localeMap).find(k =>
148
- k.toLowerCase() === exactRegionMatch[0]
149
- );
150
- this.currentLocale = originalKey || exactRegionMatch[0];
151
- } else {
152
- country = possibleMatches[0][1];
153
- const originalKey = Object.keys(localeMap).find(k =>
154
- k.toLowerCase() === possibleMatches[0][0]
155
- );
156
- this.currentLocale = originalKey || possibleMatches[0][0];
157
- }
224
+ const [matchKey, matchCountry] = exactRegion || sameLanguage[0];
225
+ resolvedKey = originalKeyFor(matchKey) || matchKey;
226
+ country = matchCountry;
158
227
  }
159
228
  }
160
229
 
161
- if (country) {
162
- this.selectedCountry = country;
163
- }
164
-
165
- if (this.currentLocale !== urlLocale) {
166
- const originalKey = Object.keys(localeMap).find(k =>
167
- k.toLowerCase() === urlLocale
168
- );
169
- this.currentLocale = originalKey || urlLocale;
170
- }
230
+ /* Nothing resolved: the segment is not a locale, so neither the locale nor
231
+ the country is touched. This is the line that used to assign the raw
232
+ path segment. */
233
+ if (!resolvedKey) return;
171
234
 
172
- this._updateNavLinks();
235
+ this.currentLocale = resolvedKey;
236
+ this.selectedCountry = country;
173
237
  }
174
238
 
175
239
  _toggleCountries() {
@@ -208,7 +272,6 @@ export class BdFooter extends LitElement {
208
272
  this.currentLocale = localeEntry[0];
209
273
  }
210
274
 
211
- this._updateNavLinks();
212
275
  this._scrollToTop();
213
276
  }
214
277
 
@@ -225,14 +288,14 @@ export class BdFooter extends LitElement {
225
288
  }
226
289
 
227
290
  _updateSlotStyles() {
228
- const isMobile = window.innerWidth <= 767;
291
+ const isMobile = matchesBelow('md');
229
292
  const slot = this.shadowRoot.querySelector('slot[name="nav"]');
230
293
  const assignedElements = slot.assignedElements();
231
294
 
232
295
  assignedElements.forEach(element => {
233
296
  if (isMobile) {
234
- element.style.color = '#151719';
235
- element.style.setProperty('color', '#151719', 'important');
297
+ element.style.color = 'var(--color-neutral-900)';
298
+ element.style.setProperty('color', 'var(--color-neutral-900)', 'important');
236
299
  } else {
237
300
  element.style.color = '';
238
301
  element.style.removeProperty('color');
@@ -240,21 +303,19 @@ export class BdFooter extends LitElement {
240
303
  });
241
304
  }
242
305
 
243
- _updateNavLinks() {
244
- // Fixed: the wrapping div in render() below is class
245
- // "footer-nav-main-container", not "footer-nav-main" — the old
246
- // selector never matched anything, so link hrefs were never updated
247
- // when the locale changed.
248
- const links = this.shadowRoot.querySelectorAll('.footer-nav-main-container bd-link');
249
- const linkPaths = ['consumer', 'small-business', 'business', 'partners'];
250
- const currentLocale = this.locale;
251
-
252
- links.forEach((link, index) => {
253
- if (index < linkPaths.length) {
254
- link.href = `/${currentLocale}/${linkPaths[index]}/`;
255
- }
256
- });
257
- }
306
+ /* No _updateNavLinks. It queried '.footer-nav-main bd-link' inside this
307
+ shadow root and wrote a locale into the href of everything it found, and it
308
+ could never find anything: .footer-nav-main is rendered by bd-footer-nav
309
+ into bd-footer-nav's own shadow root, and this template has only
310
+ .footer-nav-main-container, the box its slot sits in. Measured 0 matches
311
+ across the 22 built footer stories.
312
+
313
+ So the four locale-aware nav hrefs it promised -- consumer,
314
+ small-business, business, partners -- were never written, and no story
315
+ depended on them. Localising slotted navigation is real work with a real
316
+ API question (whose hrefs are they, and does a component rewrite markup it
317
+ does not own); it is not this, and leaving this here made it look
318
+ answered. */
258
319
 
259
320
  render() {
260
321
  const year = new Date().getFullYear();
@@ -292,7 +353,7 @@ export class BdFooter extends LitElement {
292
353
 
293
354
  return html`
294
355
  <div class="footer-top-bleed">
295
- <div class="container">
356
+ <div class="bd-ensemble container">
296
357
  <div class="footer-top">
297
358
  <div class="footer-logo">
298
359
  <slot name="logo">
@@ -312,19 +373,19 @@ export class BdFooter extends LitElement {
312
373
  </div>
313
374
  </div>
314
375
 
315
- <footer class="container">
376
+ <footer class="bd-ensemble container">
316
377
  <div class="footer-nav-main-container">
317
378
  <slot name="nav"></slot>
318
379
  </div>
319
- <bd-divider-horizontal width="100%" color="white" opacity="0.25"></bd-divider-horizontal>
380
+ <bd-divider-horizontal width="100%" color="inverse" opacity="0.25"></bd-divider-horizontal>
320
381
 
321
382
  <div class="footer-links">
322
383
  <div class="footer-links-left">
323
- <bd-grid
324
- cols="1"
325
- cols-sm="1"
326
- cols-md="2"
327
- cols-lg="2"
384
+ <bd-grid
385
+ cols="1"
386
+ cols-sm="1"
387
+ cols-md="${Math.min(2, this._maxColumns)}"
388
+ cols-lg="${this._maxColumns}"
328
389
  gap="lg"
329
390
  align="start"
330
391
  justify="start"
@@ -333,32 +394,32 @@ export class BdFooter extends LitElement {
333
394
  <slot name="quick-links"></slot>
334
395
  </bd-grid>
335
396
  </div>
336
- <bd-divider-horizontal class="tablet-divider" width="100%" color="white" opacity="0.25"></bd-divider-horizontal>
397
+ <bd-divider-horizontal class="tablet-divider" width="100%" color="inverse" opacity="0.25"></bd-divider-horizontal>
337
398
  ${this._isMobile
338
- ? html`<bd-divider-horizontal width="100%" color="white" opacity="0.25"></bd-divider-horizontal>`
399
+ ? html`<bd-divider-horizontal width="100%" color="inverse" opacity="0.25"></bd-divider-horizontal>`
339
400
  : ''}
340
-
401
+
341
402
  <div class="footer-links-right social-icons">
342
403
  <slot name="social-links">
343
- <bd-link href="https://www.facebook.com/bitdefender" target="_blank" kind="secondary" class="bd-facebook">Facebook</bd-link>
344
- <bd-link href="https://twitter.com/bitdefender" target="_blank" kind="secondary" class="bd-twitter">Twitter</bd-link>
345
- <bd-link href="https://www.linkedin.com/company/bitdefender" target="_blank" kind="secondary" class="bd-linkedin">LinkedIn</bd-link>
346
- <bd-link href="https://www.youtube.com/c/Bitdefender" target="_blank" kind="secondary" class="bd-youtube">YouTube</bd-link>
347
- <bd-link href="https://www.instagram.com/bitdefender/" target="_blank" kind="secondary" class="bd-instagram">Instagram</bd-link>
348
- <bd-link href="https://www.tiktok.com/@bitdefender" target="_blank" kind="secondary" class="bd-tiktok">TikTok</bd-link>
404
+ <bd-link href="https://www.facebook.com/bitdefender" target="_blank" variant="secondary" class="bd-facebook">Facebook</bd-link>
405
+ <bd-link href="https://twitter.com/bitdefender" target="_blank" variant="secondary" class="bd-twitter">Twitter</bd-link>
406
+ <bd-link href="https://www.linkedin.com/company/bitdefender" target="_blank" variant="secondary" class="bd-linkedin">LinkedIn</bd-link>
407
+ <bd-link href="https://www.youtube.com/c/Bitdefender" target="_blank" variant="secondary" class="bd-youtube">YouTube</bd-link>
408
+ <bd-link href="https://www.instagram.com/bitdefender/" target="_blank" variant="secondary" class="bd-instagram">Instagram</bd-link>
409
+ <bd-link href="https://www.tiktok.com/@bitdefender" target="_blank" variant="secondary" class="bd-tiktok">TikTok</bd-link>
349
410
  </slot>
350
411
  </div>
351
412
  </div>
352
413
 
353
414
  ${!this._isMobile
354
- ? html`<bd-divider-horizontal width="100%" color="white" opacity="0.25"></bd-divider-horizontal>`
415
+ ? html`<bd-divider-horizontal width="100%" color="inverse" opacity="0.25"></bd-divider-horizontal>`
355
416
  : ''}
356
417
 
357
418
  <div class="footer-middle-line">
358
419
  <div class="secondary-nav-container">
359
420
  <slot name="secondary-nav"></slot>
360
421
  ${this._isMobile
361
- ? html`<bd-divider-horizontal width="100%" color="white" opacity="0.25"></bd-divider-horizontal>`
422
+ ? html`<bd-divider-horizontal width="100%" color="inverse" opacity="0.25"></bd-divider-horizontal>`
362
423
  : ''}
363
424
  </div>
364
425
  <div class="footer-address">
@@ -371,7 +432,7 @@ export class BdFooter extends LitElement {
371
432
  </div>
372
433
  </div>
373
434
 
374
- <bd-divider-horizontal width="100%" color="white" opacity="0.25"></bd-divider-horizontal>
435
+ <bd-divider-horizontal width="100%" color="inverse" opacity="0.25"></bd-divider-horizontal>
375
436
 
376
437
  <div class="footer-extra">
377
438
  <div class="footer-copy">
@@ -379,7 +440,7 @@ export class BdFooter extends LitElement {
379
440
  Copyright © 1997 - ${year} Bitdefender
380
441
  </slot>
381
442
  </div>
382
-
443
+
383
444
  ${showAnpc
384
445
  ? html`
385
446
  <div class="footer-anpc">
@@ -389,7 +450,7 @@ export class BdFooter extends LitElement {
389
450
  </div>
390
451
  `
391
452
  : null}
392
-
453
+
393
454
  <div class="footer-countries-toggle">
394
455
  <button class="country-toggle" @click="${this._toggleCountries}">
395
456
  <bd-globe-icon size="20" color="white"></bd-globe-icon>
@@ -405,17 +466,26 @@ export class BdFooter extends LitElement {
405
466
  ${this._countriesOpen
406
467
  ? html`
407
468
  <div class="footer-countries-container">
408
- <button class="close-countries-button" @click="${this._closeCountries}">
469
+ <!-- The icon is the only content and bd-close-icon's svg is aria-hidden,
470
+ so without a label this button had no accessible name at all: a
471
+ screen reader announced "button" and nothing else. WCAG 2.2 SC
472
+ 4.1.2. The name goes on the control, never on the icon -- naming
473
+ both makes it announce twice. -->
474
+ <button
475
+ class="close-countries-button"
476
+ aria-label="Close country list"
477
+ @click="${this._closeCountries}"
478
+ >
409
479
  <bd-close-icon size="18" color="white"></bd-close-icon>
410
480
  </button>
411
481
  ${countryChunks.map(chunk => html`
412
482
  <bd-footer-links-group slot="countries" title="${chunk === countryChunks[0] ? 'Choose your country' : ''}">
413
483
  ${chunk.map(c => html`
414
- <bd-link
415
- href="/${c.locale.toLowerCase()}/"
416
- data-locale="${c.locale}"
417
- kind="light"
418
- class="${this.selectedCountry === c.label ? 'selected' : ''}"
484
+ <bd-link
485
+ href="/${c.locale.toLowerCase()}/"
486
+ data-locale="${c.locale}"
487
+ variant="light"
488
+ class="${this.selectedCountry === c.label ? 'selected' : ''}"
419
489
  @click="${(e) => this._handleCountryClick(e, c.label, c.locale)}">
420
490
  ${c.label}
421
491
  </bd-link>
@@ -429,7 +499,7 @@ export class BdFooter extends LitElement {
429
499
  `;
430
500
  }
431
501
 
432
- static styles = [tokens, footerCSS];
502
+ static styles = [ensembleCSS, footerCSS];
433
503
  }
434
504
 
435
505
  customElements.define('bd-footer', BdFooter);
@@ -69,14 +69,14 @@ export default {
69
69
 
70
70
  const quickLinks = html`
71
71
  <bd-footer-links-group slot="quick-links" title="Products">
72
- <bd-link href="/antivirus" kind="light">Antivirus</bd-link>
73
- <bd-link href="/total-security" kind="light">Total Security</bd-link>
74
- <bd-link href="/vpn" kind="light">VPN</bd-link>
72
+ <bd-link href="/antivirus" variant="light">Antivirus</bd-link>
73
+ <bd-link href="/total-security" variant="light">Total Security</bd-link>
74
+ <bd-link href="/vpn" variant="light">VPN</bd-link>
75
75
  </bd-footer-links-group>
76
76
  <bd-footer-links-group slot="quick-links" title="Support">
77
- <bd-link href="/support" kind="light">Help Center</bd-link>
78
- <bd-link href="/contact" kind="light">Contact Us</bd-link>
79
- <bd-link href="/community" kind="light">Community</bd-link>
77
+ <bd-link href="/support" variant="light">Help Center</bd-link>
78
+ <bd-link href="/contact" variant="light">Contact Us</bd-link>
79
+ <bd-link href="/community" variant="light">Community</bd-link>
80
80
  </bd-footer-links-group>
81
81
  `;
82
82
 
@@ -108,11 +108,11 @@ export const GermanLocale = {
108
108
  <bd-footer current-locale="de">
109
109
  ${quickLinks}
110
110
  <div slot="secondary-nav">
111
- <bd-link href="/privacy" kind="secondary">Privacy Policy</bd-link>
111
+ <bd-link href="/privacy" variant="secondary">Privacy Policy</bd-link>
112
112
  <bd-divider-vertical></bd-divider-vertical>
113
- <bd-link href="/terms" kind="secondary">Terms</bd-link>
113
+ <bd-link href="/terms" variant="secondary">Terms</bd-link>
114
114
  <bd-divider-vertical class="impressum-link"></bd-divider-vertical>
115
- <bd-link href="/impressum" kind="secondary" class="impressum-link">Impressum</bd-link>
115
+ <bd-link href="/impressum" variant="secondary" class="impressum-link">Impressum</bd-link>
116
116
  </div>
117
117
  </bd-footer>
118
118
  `,
@@ -1 +1 @@
1
- export const localeMap = { "en-AU": "Australia - English", "nl-BE": "België - Nederlands", "fr-BE": "Belgique - Français", "en-BZ": "Belize - English", "pt-BR": "Brasil - Português", "en-BG": "Bulgaria - English", "en-CA": "Canada - English", "es-CL": "Chile - Español", "es-CO": "Colombia - Español", "en-CZ": "Czechia - English", "en-DK": "Denmark - English", "de-DE": "Deutschland - Deutsch", "es-ES": "España - Español", "fr-FR": "France - Français", "zh-HK": "Hong Kong - China", "hu-HU": "Hungary - Magyar", "en-IN": "India - English", "en-ID": "Indonesia - English", "en-IL": "Israel - English", "it-IT": "Italia - Italiano", "en-JM": "Jamaica - English", "en-LV": "Latvia - English", "en-MY": "Malaysia - English", "en-MT": "Malta - English", "es-MX": "México - Español", "nl-NL": "Nederland - Nederlands", "en-NZ": "New Zealand - English", "en-NO": "Norway - English", "de-AT": "Österreich - Deutsch", "es-PE": "Perú - Español", "en-PH": "Philippines - English", "en-PL": "Poland - English", "pt-PT": "Portugal - Português", "ro-RO": "România - Română", "en-SA": "Saudi Arabia - English", "de-CH": "Schweiz - Deutsch", "en-SG": "Singapore - English", "en-ZA": "South Africa - English", "en-KR": "South Korea - English", "sv-SE": "Sverige - Svenska", "zh-TW": "Taiwan - 台灣", "en-TH": "Thailand - English", "en-AE": "United Arab Emirates - English", "en-GB": "United Kingdom - English", "en-US": "United States - English", "ja-JP": "日本 - 日本語" };
1
+ export const localeMap = { "en-AU": "Australia - English", "nl-BE": "België - Nederlands", "fr-BE": "Belgique - Français", "en-BZ": "Belize - English", "pt-BR": "Brasil - Português", "en-BG": "Bulgaria - English", "en-CA": "Canada - English", "es-CL": "Chile - Español", "es-CO": "Colombia - Español", "en-CZ": "Czechia - English", "en-DK": "Denmark - English", "de-DE": "Deutschland - Deutsch", "es-ES": "España - Español", "fr-FR": "France - Français", "zh-HK": "Hong Kong - China", "en-HU": "Hungary - English", "en-IN": "India - English", "en-ID": "Indonesia - English", "en-IL": "Israel - English", "it-IT": "Italia - Italiano", "en-JM": "Jamaica - English", "en-LV": "Latvia - English", "en-MY": "Malaysia - English", "en-MT": "Malta - English", "es-MX": "México - Español", "nl-NL": "Nederland - Nederlands", "en-NZ": "New Zealand - English", "en-NO": "Norway - English", "de-AT": "Österreich - Deutsch", "es-PE": "Perú - Español", "en-PH": "Philippines - English", "en-PL": "Poland - English", "pt-PT": "Portugal - Português", "ro-RO": "România - Română", "en-SA": "Saudi Arabia - English", "de-CH": "Schweiz - Deutsch", "en-SG": "Singapore - English", "en-ZA": "South Africa - English", "en-KR": "South Korea - English", "sv-SE": "Sverige - Svenska", "zh-TW": "Taiwan - 台灣", "en-TH": "Thailand - English", "en-AE": "United Arab Emirates - English", "en-GB": "United Kingdom - English", "en-US": "United States - English", "ja-JP": "日本 - 日本語" };
@@ -7,7 +7,7 @@ export default css`
7
7
 
8
8
  .grid {
9
9
  display: grid;
10
- gap: var(--space-md);
10
+ gap: var(--spacing-24);
11
11
  align-items: stretch;
12
12
  justify-items: start;
13
13
  }
@@ -1,13 +1,55 @@
1
1
  import { LitElement, html } from "lit";
2
- import { tokens } from "../../tokens/tokens.js";
2
+ // Installs the design tokens into document scope; see src/tokens/tokens.js
3
+ import "../../tokens/tokens.js";
3
4
  import gridCSS from "../grid/grid.css.js";
5
+ import { space } from "../shared/token-scales.js";
4
6
 
5
7
  class BdGrid extends LitElement {
8
+ /* The three responsive properties name their attribute, and that is the
9
+ whole fix. Lit derives an observed attribute by LOWERCASING the property
10
+ name -- not by dash-casing it -- so `colsSm` observed `colssm` and the
11
+ `cols-sm` this component documents was not an attribute it had ever been
12
+ listening for. observedAttributes read
13
+ ["cols","colssm","colsmd","colslg","gap","align","justify","padding"];
14
+ `cols` worked because it is one word, which is why the failure looked like
15
+ a responsive bug rather than a naming one.
16
+
17
+ So every dash-cased column attribute in the package was inert and the
18
+ properties kept their constructor defaults 1/1/2/3. Those defaults sit one
19
+ step under the 2/3/4 the Responsive columns story asks for, which is why
20
+ the rendered grid looked merely one breakpoint late instead of ignoring
21
+ the markup entirely. Measured across five stories x six viewports, 25 of
22
+ 66 readings rendered a column count nobody had asked for:
23
+
24
+ Layout/Grid "Single column" cols-lg="1" -> 3 columns at 992 and 1440
25
+ Layout/Grid "Gap scale" cols-sm="3" -> 1 column at 576-767
26
+ Layout/Grid "Alignment" cols-sm="3" -> 1 column at 576-767
27
+ bd-footer quick links cols-lg="2" -> 3 columns at 992 and 1440
28
+
29
+ The last one is not a story: footer.js writes cols-md/cols-lg in its own
30
+ shadow root, so a shipped component's layout was running on the defaults
31
+ too.
32
+
33
+ Naming the attribute is what this package already does everywhere else --
34
+ 94 explicit dash-cased mappings across 40 files, `heading-level`,
35
+ `visual-level`, `max-columns`, `min-card-width` -- and it is what the
36
+ component's own documentation promises: grid.stories.js reads "`cols`
37
+ below 576, then `cols-sm`, `cols-md` at 768 and `cols-lg` at 992", and its
38
+ argTypes map colsSm to the control name "cols-sm". The code was the only
39
+ part that disagreed.
40
+
41
+ An explicit name replaces the lowercase one rather than adding to it, so
42
+ `colssm` stops being observed. Nothing reads it: grepped for colssm,
43
+ colsmd, colslg and fallbacksrc across src, schemas and docs -- zero
44
+ occurrences outside these declarations. The responsive behaviour itself is
45
+ untouched; the media queries in grid.css.js and the 576/768/992 steps are
46
+ the ones that were already there, and this adds no smartness to a layout
47
+ primitive -- it only lets the primitive hear what it is told. */
6
48
  static properties = {
7
49
  cols : { type: Number }, // default cols
8
- colsSm : { type: Number }, // optional cols on small screens
9
- colsMd : { type: Number }, // optional cols on medium
10
- colsLg : { type: Number }, // optional cols on large
50
+ colsSm : { type: Number, attribute: "cols-sm" }, // optional cols on small screens
51
+ colsMd : { type: Number, attribute: "cols-md" }, // optional cols on medium
52
+ colsLg : { type: Number, attribute: "cols-lg" }, // optional cols on large
11
53
  gap : { type: String }, // e.g., 'sm', 'md'
12
54
  align : { type: String }, // start, center, end, stretch
13
55
  justify: { type: String }, // start, center, end, space-between
@@ -38,10 +80,10 @@ class BdGrid extends LitElement {
38
80
  --grid-cols-sm: ${this.colsSm};
39
81
  --grid-cols-md: ${this.colsMd};
40
82
  --grid-cols-lg: ${this.colsLg};
41
- gap: var(--space-${this.gap});
83
+ gap: ${space(this.gap)};
42
84
  align-items: ${this.align};
43
85
  justify-items: ${this.justify};
44
- padding: var(--space-${this.padding});
86
+ padding: ${space(this.padding)};
45
87
 
46
88
  "
47
89
  >
@@ -50,6 +92,6 @@ class BdGrid extends LitElement {
50
92
  `;
51
93
  }
52
94
  }
53
- BdGrid.styles = [tokens, gridCSS];
95
+ BdGrid.styles = [gridCSS];
54
96
 
55
97
  customElements.define("bd-grid", BdGrid);