@repobit/dex-system-design 0.25.11 → 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.
- package/CHANGELOG.md +195 -0
- package/README.md +131 -8
- package/package.json +95 -13
- package/schemas/component-manifest.json +3294 -405
- package/schemas/manifest-omissions.json +173 -0
- package/src/blog/src/breakpoints.js +6 -6
- package/src/blog/src/content/blog-atoms-showcase.js +1 -1
- package/src/blog/src/content/blog-page-layout.js +2 -2
- package/src/blog/src/lib/article-toc.js +7 -7
- package/src/blog/src/shell/blog-shell.js +1 -1
- package/src/blog/src/tokens/blog.js +2 -2
- package/src/blog/src/tokens/core.js +34 -35
- package/src/blog/src/tokens/legacy.js +0 -9
- package/src/blog/tokens/blog.js +2 -2
- package/src/blog/tokens/core.js +34 -35
- package/src/blog/tokens/legacy.js +0 -9
- package/src/blog/tokens.css +36 -46
- package/src/components/accordion/accordion-bg.css.js +83 -59
- package/src/components/accordion/accordion-bg.js +29 -10
- package/src/components/accordion/accordion-bg.stories.js +67 -67
- package/src/components/accordion/accordion-keyboard.js +80 -0
- package/src/components/accordion/accordion.css.js +142 -80
- package/src/components/accordion/accordion.js +37 -10
- package/src/components/accordion/accordion.stories.js +7 -7
- package/src/components/agent-endpoints/agent-endpoints.css.js +36 -39
- package/src/components/agent-endpoints/agent-endpoints.js +30 -20
- package/src/components/agent-endpoints/agent-endpoints.stories.js +1 -1
- package/src/components/ai-guardian-demo.stories.js +91 -91
- package/src/components/alert/alert.css.js +198 -0
- package/src/components/alert/alert.js +103 -0
- package/src/components/alert/alert.stories.js +206 -0
- package/src/components/anchor/anchor-nav.css.js +213 -101
- package/src/components/anchor/anchor-nav.js +26 -40
- package/src/components/anchor/anchor.stories.js +22 -12
- package/src/components/annotation/annotation.css.js +58 -0
- package/src/components/annotation/annotation.js +67 -0
- package/src/components/annotation/annotation.stories.js +63 -0
- package/src/components/architecture.stories.js +285 -0
- package/src/components/atoms.stories.js +342 -0
- package/src/components/avatar/avatar.css.js +67 -0
- package/src/components/avatar/avatar.js +42 -0
- package/src/components/avatar/avatar.stories.js +95 -0
- package/src/components/awards/awards-flex.css.js +209 -23
- package/src/components/awards/awards-flex.js +66 -7
- package/src/components/awards/awards-flex.stories.js +1 -1
- package/src/components/awards/{awards-light.stories.js → awards-summary.stories.js} +54 -64
- package/src/components/awards/awards.css.js +116 -58
- package/src/components/awards/awards.js +102 -28
- package/src/components/awards/awards.stories.js +1 -1
- package/src/components/back/back.css.js +51 -22
- package/src/components/back/back.js +28 -7
- package/src/components/back/back.stories.js +9 -3
- package/src/components/badge/badge.css.js +158 -46
- package/src/components/badge/badge.js +62 -74
- package/src/components/badge/badge.stories.js +176 -248
- package/src/components/bento-grid/bento-grid.css.js +21 -16
- package/src/components/bento-grid/bento-grid.js +16 -4
- package/src/components/bento-grid/bento-grid.stories.js +19 -18
- package/src/components/bento-grid/bento-item.css.js +52 -28
- package/src/components/bento-grid/bento-item.js +2 -2
- package/src/components/blockquote/blockquote.css.js +47 -0
- package/src/components/blockquote/blockquote.js +29 -0
- package/src/components/blockquote/blockquote.stories.js +62 -0
- package/src/components/breadcrumb/breadcrumb.css.js +92 -22
- package/src/components/breadcrumb/breadcrumb.js +56 -11
- package/src/components/button/button.css.js +531 -161
- package/src/components/button/button.js +206 -214
- package/src/components/button/button.stories.js +322 -174
- package/src/components/caption/caption.css.js +21 -0
- package/src/components/caption/caption.js +31 -0
- package/src/components/caption/caption.stories.js +62 -0
- package/src/components/card-features/card-features.css.js +14 -22
- package/src/components/card-features/card-features.js +68 -9
- package/src/components/card-features/card-features.stories.js +11 -11
- package/src/components/cards/card.css.js +60 -81
- package/src/components/cards/card.js +56 -25
- package/src/components/cards/card.stories.js +39 -39
- package/src/components/carousel/carousel.css.js +93 -99
- package/src/components/carousel/carousel.js +32 -4
- package/src/components/checkbox/checkbox.css.js +111 -93
- package/src/components/checkbox/checkbox.js +64 -90
- package/src/components/checkbox/checkbox.stories.js +96 -29
- package/src/components/code/code.css.js +70 -0
- package/src/components/code/code.js +40 -0
- package/src/components/code/code.stories.js +73 -0
- package/src/components/compare/compare.css.js +179 -43
- package/src/components/compare/compare.js +52 -25
- package/src/components/compare/compare.stories.js +61 -4
- package/src/components/comparison-panel/comparison-panel.css.js +38 -51
- package/src/components/comparison-panel/comparison-panel.js +5 -4
- package/src/components/comparison-panel/comparison-panel.stories.js +1 -1
- package/src/components/compatibility-table/compatibility-table.css.js +180 -80
- package/src/components/compatibility-table/compatibility-table.js +37 -9
- package/src/components/control-alignment.stories.js +393 -0
- package/src/components/cta-banner/cta-banner.css.js +41 -13
- package/src/components/cta-banner/cta-banner.js +6 -5
- package/src/components/cta-banner/cta-banner.stories.js +43 -98
- package/src/components/display/display.css.js +25 -1
- package/src/components/display/display.js +46 -13
- package/src/components/display/display.stories.js +270 -40
- package/src/components/divider/divider-horizontal.js +21 -5
- package/src/components/divider/divider-vertical.js +15 -7
- package/src/components/divider/divider.css.js +2 -2
- package/src/components/divider/divider.stories.js +38 -34
- package/src/components/dropdown/dropdown.css.js +93 -126
- package/src/components/dropdown/dropdown.js +114 -34
- package/src/components/dropdown/dropdown.stories.js +56 -24
- package/src/components/features/features.css.js +24 -11
- package/src/components/features/features.js +7 -3
- package/src/components/features/features.stories.js +37 -37
- package/src/components/features-tab/features-tab.css.js +19 -8
- package/src/components/features-tab/features-tab.js +6 -5
- package/src/components/features-tab/features-tab.stories.js +23 -23
- package/src/components/fieldset/fieldset.css.js +30 -0
- package/src/components/fieldset/fieldset.js +28 -0
- package/src/components/fieldset/fieldset.stories.js +84 -0
- package/src/components/footer/footer-links-group.css.js +10 -14
- package/src/components/footer/footer-links-group.js +4 -3
- package/src/components/footer/footer-lp.css.js +59 -30
- package/src/components/footer/footer-lp.js +17 -12
- package/src/components/footer/footer-lp.stories.js +63 -75
- package/src/components/footer/footer-nav-menu.css.js +26 -4
- package/src/components/footer/footer-nav-menu.js +3 -2
- package/src/components/footer/footer.css.js +146 -264
- package/src/components/footer/footer.js +176 -106
- package/src/components/footer/footer.stories.js +9 -9
- package/src/components/footer/localeMap.js +1 -1
- package/src/components/grid/grid.css.js +1 -1
- package/src/components/grid/grid.js +49 -7
- package/src/components/grid/grid.stories.js +111 -0
- package/src/components/header/header-code.css.js +61 -51
- package/src/components/header/header-code.js +28 -14
- package/src/components/header/header-code.stories.js +5 -5
- package/src/components/header/header.css.js +655 -176
- package/src/components/header/header.js +269 -36
- package/src/components/header/header.stories.js +841 -18
- package/src/components/heading/heading.css.js +14 -17
- package/src/components/heading/heading.js +48 -33
- package/src/components/heading/heading.stories.js +27 -25
- package/src/components/help-text/help-text.css.js +21 -0
- package/src/components/help-text/help-text.js +25 -0
- package/src/components/help-text/help-text.stories.js +66 -0
- package/src/components/highlight/highlight.css.js +86 -64
- package/src/components/highlight/highlight.js +18 -27
- package/src/components/highlight/highlight.stories.js +14 -3
- package/src/components/icons/analysis-icon.js +6 -16
- package/src/components/icons/arrow-down-icon.js +6 -19
- package/src/components/icons/arrow-icon.js +44 -0
- package/src/components/icons/arrow-right-icon.js +30 -23
- package/src/components/icons/arrow-up-icon.js +19 -18
- package/src/components/icons/bd-ai-icon.js +1 -1
- package/src/components/icons/brand-marks.stories.js +279 -0
- package/src/components/icons/brand-signature-icon.js +42 -0
- package/src/components/icons/check-icon.js +27 -0
- package/src/components/icons/circle-info-icon.js +33 -0
- package/src/components/icons/close-icon.js +6 -18
- package/src/components/icons/family-icon.js +8 -20
- package/src/components/icons/globe-icon.js +6 -18
- package/src/components/icons/guide-icon.js +6 -18
- package/src/components/icons/icon-element.js +99 -0
- package/src/components/icons/icons.js +36 -0
- package/src/components/icons/icons.stories.js +184 -52
- package/src/components/icons/individual-icon.js +6 -18
- package/src/components/icons/laurel-icon.js +9 -19
- package/src/components/icons/machine-learning-icon.js +6 -17
- package/src/components/icons/marks.js +41 -0
- package/src/components/icons/minus-icon.js +7 -21
- package/src/components/icons/missing-icon.js +52 -0
- package/src/components/icons/plus-icon.js +7 -21
- package/src/components/icons/quote-icon.js +19 -19
- package/src/components/image/image.css.js +72 -25
- package/src/components/image/image.js +11 -6
- package/src/components/image/image.stories.js +2 -2
- package/src/components/input/custom-form.stories.js +214 -62
- package/src/components/input/input-clipboard.css.js +51 -144
- package/src/components/input/input-clipboard.js +31 -15
- package/src/components/input/input.css.js +8 -146
- package/src/components/input/input.js +93 -38
- package/src/components/install-options/install-options.css.js +84 -77
- package/src/components/install-options/install-options.js +33 -30
- package/src/components/install-options/install-options.stories.js +3 -3
- package/src/components/label/label.css.js +35 -0
- package/src/components/label/label.js +38 -0
- package/src/components/label/label.stories.js +82 -0
- package/src/components/light-carousel/light-carousel.css.js +111 -63
- package/src/components/light-carousel/light-carousel.js +85 -11
- package/src/components/light-carousel/light-carousel.stories.js +126 -82
- package/src/components/link/link.css.js +150 -99
- package/src/components/link/link.js +86 -11
- package/src/components/link/link.stories.js +124 -30
- package/src/components/list/list-item/list-item.css.js +74 -22
- package/src/components/list/list-item/list-item.js +32 -10
- package/src/components/list/list-item/list-item.stories.js +23 -23
- package/src/components/list/list.css.js +8 -2
- package/src/components/list/list.js +3 -2
- package/src/components/list/list.stories.js +222 -0
- package/src/components/modal/modal.css.js +114 -24
- package/src/components/modal/modal.js +83 -7
- package/src/components/modal/modal.stories.js +9 -9
- package/src/components/overview/overview.css.js +19 -14
- package/src/components/overview/overview.js +6 -5
- package/src/components/overview/overview.stories.js +10 -10
- package/src/components/page-switcher/page-switcher.css.js +97 -40
- package/src/components/page-switcher/page-switcher.js +28 -5
- package/src/components/page-switcher/page-switcher.stories.js +95 -0
- package/src/components/paragraph/paragraph.css.js +15 -10
- package/src/components/paragraph/paragraph.js +41 -44
- package/src/components/paragraph/paragraph.stories.js +56 -21
- package/src/components/picture/picture.css.js +103 -44
- package/src/components/picture/picture.js +100 -30
- package/src/components/picture/picture.stories.js +1 -1
- package/src/components/pricing-cards/new-pricing-card.js +3 -3
- package/src/components/pricing-cards/new-pricing.css.js +24 -15
- package/src/components/pricing-cards/pricing-card-actions.css.js +1 -1
- package/src/components/pricing-cards/pricing-card-actions.js +3 -4
- package/src/components/pricing-cards/pricing-card-container.css.js +3 -3
- package/src/components/pricing-cards/pricing-card-container.js +3 -2
- package/src/components/pricing-cards/pricing-card-header.css.js +10 -8
- package/src/components/pricing-cards/pricing-card-header.js +6 -7
- package/src/components/pricing-cards/pricing-card-pricing.css.js +16 -9
- package/src/components/pricing-cards/pricing-card-pricing.js +8 -6
- package/src/components/pricing-cards/pricing-card-show-more.css.js +11 -3
- package/src/components/pricing-cards/pricing-card-show-more.js +8 -3
- package/src/components/pricing-cards/pricing-card.css.js +244 -190
- package/src/components/pricing-cards/pricing-card.js +54 -70
- package/src/components/pricing-cards/pricing-feature-item.css.js +25 -8
- package/src/components/pricing-cards/pricing-feature-item.js +8 -3
- package/src/components/process-steps/process-steps.css.js +26 -14
- package/src/components/process-steps/process-steps.js +23 -6
- package/src/components/process-steps/process-steps.stories.js +1 -1
- package/src/components/progress/progress.css.js +80 -0
- package/src/components/progress/progress.js +42 -0
- package/src/components/progress/progress.stories.js +79 -0
- package/src/components/quick-answer/quick-answer.css.js +75 -13
- package/src/components/quick-answer/quick-answer.js +8 -3
- package/src/components/radio/radio.css.js +92 -128
- package/src/components/radio/radio.js +106 -127
- package/src/components/radio/radio.stories.js +54 -19
- package/src/components/review/review-grid.css.js +5 -6
- package/src/components/review/review-grid.js +14 -11
- package/src/components/review/review.css.js +11 -6
- package/src/components/review/review.js +3 -8
- package/src/components/shared/ensemble.css.js +93 -0
- package/src/components/shared/form-field.css.js +206 -0
- package/src/components/shared/prop-vocabulary.js +48 -0
- package/src/components/shared/token-scales.js +306 -0
- package/src/components/skeleton/skeleton.css.js +34 -0
- package/src/components/skeleton/skeleton.js +32 -0
- package/src/components/skeleton/skeleton.stories.js +70 -0
- package/src/components/spinner/spinner.css.js +62 -0
- package/src/components/spinner/spinner.js +38 -0
- package/src/components/spinner/spinner.stories.js +92 -0
- package/src/components/spotlight-section/spotlight-section.css.js +14 -13
- package/src/components/spotlight-section/spotlight-section.js +42 -39
- package/src/components/switch/switch.css.js +103 -0
- package/src/components/switch/switch.js +44 -0
- package/src/components/switch/switch.stories.js +86 -0
- package/src/components/tab-list/content-switcher.stories.js +189 -0
- package/src/components/tab-list/tab-list.css.js +250 -0
- package/src/components/tab-list/tab-list.js +184 -0
- package/src/components/tab-list/tab-list.stories.js +221 -0
- package/src/components/tabs/tabs.css.js +14 -123
- package/src/components/tabs/tabs.js +16 -19
- package/src/components/tabs/tabs.stories.js +95 -95
- package/src/components/tag/tag.css.js +54 -0
- package/src/components/tag/tag.js +32 -0
- package/src/components/tag/tag.stories.js +126 -0
- package/src/components/terminal/terminal-message.css.js +164 -60
- package/src/components/terminal/terminal-message.js +5 -5
- package/src/components/terminal/terminal-message.stories.js +70 -1
- package/src/components/termsOfUse/terms.css.js +25 -20
- package/src/components/termsOfUse/terms.js +13 -9
- package/src/components/termsOfUse/terms.stories.js +1 -1
- package/src/components/textarea/textarea.css.js +51 -0
- package/src/components/textarea/textarea.js +136 -0
- package/src/components/textarea/textarea.stories.js +191 -0
- package/src/components/tooltip/tooltip.css.js +75 -0
- package/src/components/tooltip/tooltip.js +156 -0
- package/src/components/tooltip/tooltip.stories.js +161 -0
- package/src/components/trust-panel/trust-panel.css.js +85 -33
- package/src/components/trust-panel/trust-panel.js +18 -10
- package/src/components/trust-panel/trust-panel.stories.js +1 -1
- package/src/components/ultimate-security-demo.stories.js +431 -0
- package/src/components/video/video.css.js +17 -0
- package/src/components/video/video.js +40 -0
- package/src/components/video/video.stories.js +106 -0
- package/src/components/video-player/video-player.css.js +67 -11
- package/src/components/video-player/video-player.js +35 -4
- package/src/components/video-player/video-player.stories.js +1 -1
- package/src/components/visual-alignment.stories.js +411 -0
- package/src/components/visually-hidden/visually-hidden.css.js +24 -0
- package/src/components/visually-hidden/visually-hidden.js +16 -0
- package/src/components/visually-hidden/visually-hidden.stories.js +56 -0
- package/src/stories/Button.stories.js +17 -17
- package/src/stories/Header.stories.js +10 -10
- package/src/stories/Page.js +1 -1
- package/src/stories/Page.stories.js +6 -6
- package/src/tokens/borders.stories.js +339 -0
- package/src/tokens/color-responsibilities.stories.js +227 -0
- package/src/tokens/dark-derivation.js +309 -0
- package/src/tokens/dark-findings.js +197 -0
- package/src/tokens/dark-mode.stories.js +207 -0
- package/src/tokens/dimension.stories.js +251 -0
- package/src/tokens/elevation.stories.js +143 -0
- package/src/tokens/focus.stories.js +276 -0
- package/src/tokens/fonts.css +20 -20
- package/src/tokens/fonts.stories.js +354 -374
- package/src/tokens/layout.css +25 -11
- package/src/tokens/motion.stories.js +231 -0
- package/src/tokens/shape.stories.js +272 -0
- package/src/tokens/spacing-rhythm.stories.js +359 -0
- package/src/tokens/spacing.stories.js +208 -703
- package/src/tokens/story-chrome.js +503 -0
- package/src/tokens/surfaces.stories.js +224 -0
- package/src/tokens/text-on-surface.stories.js +164 -0
- package/src/tokens/token-map.js +220 -0
- package/src/tokens/token-map.stories.js +257 -0
- package/src/tokens/token-purposes.js +266 -0
- package/src/tokens/tokens-grid.stories.js +388 -900
- package/src/tokens/tokens.css +1633 -1045
- package/src/tokens/tokens.js +1130 -492
- package/src/tokens/tokens.stories.js +137 -47
- package/src/tokens/type-ceiling-words.js +299 -0
- package/src/tokens/typography.stories.js +1003 -965
- package/src/tokens/vertical-rhythm.stories.js +224 -0
- package/src/components/awards/awards-icon.js +0 -56
- package/src/components/awards/awards-light.js +0 -240
- package/src/components/banner/banner.js +0 -60
- package/src/components/banner/banner.stories.js +0 -51
- package/src/components/button/icons.js +0 -24
- package/src/components/input/index.js +0 -0
- package/src/components/light-carousel/light-carousel-simple.css.js +0 -183
- package/src/components/light-carousel/light-carousel-simple.js +0 -74
- package/src/tokens/colors.js +0 -121
- package/src/tokens/typography.css.js +0 -207
- package/src/tokens/typography.js +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
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
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The tab strip on its own — the row of buttons, the selected underline, and
|
|
7
|
+
* the WAI-ARIA tabs keyboard pattern. It owns no panel and no layout; the
|
|
8
|
+
* section that uses it decides what a panel is and how the page around it is
|
|
9
|
+
* arranged.
|
|
10
|
+
*
|
|
11
|
+
* ## Light DOM, on purpose
|
|
12
|
+
*
|
|
13
|
+
* `aria-controls` and `aria-labelledby` are IDREFs, and an IDREF does not
|
|
14
|
+
* resolve across a shadow boundary. A tab inside this element's shadow root
|
|
15
|
+
* therefore could not point at a panel living in the consumer's shadow root.
|
|
16
|
+
* Rendering into light DOM keeps the buttons in the same node tree as the
|
|
17
|
+
* panel, so the wiring is real rather than decorative.
|
|
18
|
+
*
|
|
19
|
+
* The consequence is that `static styles` would never apply. Import
|
|
20
|
+
* `tabListCSS` from ./tab-list.css.js and add it to the consuming component's
|
|
21
|
+
* own `static styles` instead.
|
|
22
|
+
*
|
|
23
|
+
* ## Two appearances, one control
|
|
24
|
+
*
|
|
25
|
+
* `appearance="switcher"` draws the Content Switcher: a pill track with the
|
|
26
|
+
* selected option on a white pill. It is a skin rather than its own element
|
|
27
|
+
* because everything below it -- role="tablist", role="tab", aria-selected,
|
|
28
|
+
* the roving tabindex and the Arrow/Home/End pattern with automatic
|
|
29
|
+
* activation -- is identical, and the light-DOM decision above is the whole
|
|
30
|
+
* reason this element exists. A separate <bd-content-switcher> would have had
|
|
31
|
+
* to re-solve the IDREF problem and keep a second copy of the keyboard
|
|
32
|
+
* pattern in step with this one.
|
|
33
|
+
*
|
|
34
|
+
* Storybook lists it as Components/Content Switcher so it is findable by the
|
|
35
|
+
* name it was designed under.
|
|
36
|
+
*/
|
|
37
|
+
export class BdTabList extends LitElement {
|
|
38
|
+
static properties = {
|
|
39
|
+
tabs : { type: Array },
|
|
40
|
+
selected : { type: Number, reflect: true },
|
|
41
|
+
label : { type: String },
|
|
42
|
+
panelId : { type: String, attribute: "panel-id" },
|
|
43
|
+
idPrefix : { type: String, attribute: "id-prefix" },
|
|
44
|
+
/**
|
|
45
|
+
* The skin. Omitted gives the underlined strip this element has always
|
|
46
|
+
* drawn; "switcher" gives the pill-track content switcher. It is an
|
|
47
|
+
* appearance and not a second element on purpose -- see the note above
|
|
48
|
+
* the class for why.
|
|
49
|
+
*/
|
|
50
|
+
appearance: { type: String, reflect: true }
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// See the note above: light DOM is what makes the ARIA wiring work.
|
|
54
|
+
createRenderRoot() {
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
constructor() {
|
|
59
|
+
super();
|
|
60
|
+
this.tabs = [];
|
|
61
|
+
this.selected = 0;
|
|
62
|
+
this.label = "";
|
|
63
|
+
this.panelId = "";
|
|
64
|
+
this.idPrefix = "bd-tab";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
tabId(index) {
|
|
68
|
+
return `${this.idPrefix}-${index}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_select(index, { focus = false } = {}) {
|
|
72
|
+
if (index === this.selected) return;
|
|
73
|
+
this.selected = index;
|
|
74
|
+
this.dispatchEvent(new CustomEvent("bd-tab-select", {
|
|
75
|
+
detail : { index },
|
|
76
|
+
bubbles : true,
|
|
77
|
+
composed: true
|
|
78
|
+
}));
|
|
79
|
+
if (focus) this.updateComplete.then(() => this._focusSelected());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The switcher's equal-width rule, which CSS alone cannot express.
|
|
84
|
+
*
|
|
85
|
+
* The design asks for every option to be as wide as the LONGEST label, so a
|
|
86
|
+
* translation cannot make one option wider than another. That needs three
|
|
87
|
+
* things at once -- the track hugs its content, the columns are equal, and
|
|
88
|
+
* the equal width is the widest option's -- and no grid declaration gives
|
|
89
|
+
* all three. Measured on the Unequal labels story: `1fr` produced 127.21 and
|
|
90
|
+
* 141.79 and wrapped both labels, and `minmax(max-content, 1fr)` produced
|
|
91
|
+
* 78.35 and 248.77. Both are correct CSS; an `fr` track needs definite free
|
|
92
|
+
* space to equalise, and a shrink-to-fit container has none -- and once the
|
|
93
|
+
* width IS definite, `fr` splits it evenly rather than matching the widest.
|
|
94
|
+
*
|
|
95
|
+
* So the widest option is measured and published as a custom property the
|
|
96
|
+
* grid reads. The property is cleared first: without that, a re-render after
|
|
97
|
+
* the labels get SHORTER would measure the widths this rule had already
|
|
98
|
+
* equalised and the track could never shrink again.
|
|
99
|
+
*/
|
|
100
|
+
_sizeSwitcherOptions() {
|
|
101
|
+
if (this.appearance !== "switcher") return;
|
|
102
|
+
const track = this.querySelector(".bd-tabs-container");
|
|
103
|
+
const options = [...this.querySelectorAll(".bd-tab-button")];
|
|
104
|
+
if (!track || !options.length) return;
|
|
105
|
+
|
|
106
|
+
track.style.removeProperty("--bd-switcher-option-width");
|
|
107
|
+
const widest = Math.max(...options.map(o => o.getBoundingClientRect().width));
|
|
108
|
+
if (widest > 0) track.style.setProperty("--bd-switcher-option-width", `${widest}px`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
updated(changed) {
|
|
112
|
+
super.updated(changed);
|
|
113
|
+
this._sizeSwitcherOptions();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
firstUpdated() {
|
|
117
|
+
/* The measurement is only as good as the font that was loaded when it ran.
|
|
118
|
+
IBM Plex arrives after first paint, and a fallback face has different
|
|
119
|
+
advance widths -- so a switcher measured on the fallback keeps a width
|
|
120
|
+
that no longer matches its own text. One re-measure once the faces are
|
|
121
|
+
in is enough; fonts.ready settles once per document. */
|
|
122
|
+
document.fonts?.ready.then(() => this._sizeSwitcherOptions());
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
_focusSelected() {
|
|
126
|
+
this.querySelector(`#${CSS.escape(this.tabId(this.selected))}`)?.focus();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Arrow keys move and activate in one step (automatic activation), which is
|
|
131
|
+
* the WAI-ARIA recommendation when revealing a panel is cheap — it is here,
|
|
132
|
+
* the panels are already in the DOM.
|
|
133
|
+
*/
|
|
134
|
+
_onKeydown(event) {
|
|
135
|
+
const last = this.tabs.length - 1;
|
|
136
|
+
if (last < 0) return;
|
|
137
|
+
|
|
138
|
+
let next;
|
|
139
|
+
switch (event.key) {
|
|
140
|
+
case "ArrowRight": next = this.selected === last ? 0 : this.selected + 1; break;
|
|
141
|
+
case "ArrowLeft": next = this.selected === 0 ? last : this.selected - 1; break;
|
|
142
|
+
case "Home": next = 0; break;
|
|
143
|
+
case "End": next = last; break;
|
|
144
|
+
default: return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
event.preventDefault();
|
|
148
|
+
this._select(next, { focus: true });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
render() {
|
|
152
|
+
return html`
|
|
153
|
+
<div
|
|
154
|
+
class="bd-tabs-container ${this.appearance === "switcher" ? "bd-tabs-container--switcher" : ""}"
|
|
155
|
+
role="tablist"
|
|
156
|
+
aria-label=${this.label || nothing}
|
|
157
|
+
@keydown=${this._onKeydown}
|
|
158
|
+
>
|
|
159
|
+
${this.tabs.map((tab, index) => {
|
|
160
|
+
const isSelected = this.selected === index;
|
|
161
|
+
return html`
|
|
162
|
+
<button
|
|
163
|
+
type="button"
|
|
164
|
+
role="tab"
|
|
165
|
+
id=${this.tabId(index)}
|
|
166
|
+
aria-selected=${isSelected ? "true" : "false"}
|
|
167
|
+
aria-controls=${this.panelId || nothing}
|
|
168
|
+
tabindex=${isSelected ? "0" : "-1"}
|
|
169
|
+
class="bd-tab-button ${isSelected ? "bd-selected" : ""}"
|
|
170
|
+
@click=${() => this._select(index)}
|
|
171
|
+
>
|
|
172
|
+
${tab.icon
|
|
173
|
+
? html`<img src=${tab.icon} alt=${tab.iconAlt || ""} class="bd-tab-icon" />`
|
|
174
|
+
: ""}
|
|
175
|
+
<span class="bd-tab-label">${tab.content ?? tab.label}</span>
|
|
176
|
+
</button>
|
|
177
|
+
`;
|
|
178
|
+
})}
|
|
179
|
+
</div>
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
customElements.define("bd-tab-list", BdTabList);
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
import "../paragraph/paragraph.js";
|
|
3
|
+
import "./tab-list.js";
|
|
4
|
+
import { tabListCSS } from "./tab-list.css.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The stories render <bd-tab-list> at document scope, where a component's
|
|
8
|
+
* `static styles` would not reach it anyway — see the note in tab-list.js on
|
|
9
|
+
* why this element is light DOM. Inside a real component you add `tabListCSS`
|
|
10
|
+
* to that component's own `static styles` instead of doing this.
|
|
11
|
+
*/
|
|
12
|
+
const withStyles = template => html`
|
|
13
|
+
<style>${tabListCSS.cssText}</style>
|
|
14
|
+
<div style="font-family: var(--typography-fontFamily-sans);">${template}</div>
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
title : "Components/Tab List",
|
|
19
|
+
tags : ["autodocs"],
|
|
20
|
+
parameters: {
|
|
21
|
+
docs: {
|
|
22
|
+
description: {
|
|
23
|
+
component: `
|
|
24
|
+
|
|
25
|
+
### This atom does not style itself
|
|
26
|
+
|
|
27
|
+
\`bd-tab-list\` renders into **light DOM**, so its stylesheet is not adopted the
|
|
28
|
+
way every other atom's is. Importing the element gets you the markup and the
|
|
29
|
+
behaviour and nothing else — a consumer has to put \`tabListCSS\` into its own
|
|
30
|
+
\`static styles\` ahead of any override:
|
|
31
|
+
|
|
32
|
+
\`\`\`js
|
|
33
|
+
import { tabListCSS } from '@repobit/dex-system-design/tab-list-css';
|
|
34
|
+
|
|
35
|
+
static styles = [tabListCSS, myComponentCSS];
|
|
36
|
+
\`\`\`
|
|
37
|
+
|
|
38
|
+
That is deliberate — a tab strip has to sit inside its host's own layout and
|
|
39
|
+
inherit its type — but it is the only atom that works this way, so it is worth
|
|
40
|
+
saying plainly rather than leaving to be discovered.
|
|
41
|
+
**BdTabList** is the tab strip on its own: the row of buttons, the selected
|
|
42
|
+
underline, and the WAI-ARIA tabs keyboard pattern. It owns no panel and no
|
|
43
|
+
surrounding layout — the section using it decides what a panel is.
|
|
44
|
+
|
|
45
|
+
It was extracted from \`<bd-tabs>\`, \`<bd-tabs-component>\` and
|
|
46
|
+
\`<bd-tabs-component-family>\`, which each hand-rolled the same strip. Those three
|
|
47
|
+
now compose this one.
|
|
48
|
+
|
|
49
|
+
### Usage
|
|
50
|
+
\`\`\`js
|
|
51
|
+
import "@repobit/dex-system-design/tab-list";
|
|
52
|
+
import { tabListCSS } from "@repobit/dex-system-design/tab-list-css";
|
|
53
|
+
|
|
54
|
+
static styles = [tabListCSS, myComponentCSS];
|
|
55
|
+
\`\`\`
|
|
56
|
+
|
|
57
|
+
\`\`\`js
|
|
58
|
+
html\`
|
|
59
|
+
<bd-tab-list
|
|
60
|
+
.tabs=\${[{ label: "Windows" }, { label: "macOS" }]}
|
|
61
|
+
.selected=\${this.selectedTab}
|
|
62
|
+
id-prefix="tab-btn"
|
|
63
|
+
panel-id="tab-panel"
|
|
64
|
+
@bd-tab-select=\${e => this.selectTab(e.detail.index)}
|
|
65
|
+
></bd-tab-list>
|
|
66
|
+
|
|
67
|
+
<div id="tab-panel" role="tabpanel" aria-labelledby="tab-btn-\${this.selectedTab}">
|
|
68
|
+
…
|
|
69
|
+
</div>
|
|
70
|
+
\`
|
|
71
|
+
\`\`\`
|
|
72
|
+
|
|
73
|
+
### Props
|
|
74
|
+
| Prop | Values | Default |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| \`tabs\` | array of \`{ label, content?, icon?, iconAlt? }\` | \`[]\` |
|
|
77
|
+
| \`selected\` | index of the active tab | \`0\` |
|
|
78
|
+
| \`label\` | \`aria-label\` for the tablist | \`''\` |
|
|
79
|
+
| \`panel-id\` | id of the panel every tab controls | \`''\` |
|
|
80
|
+
| \`id-prefix\` | prefix for generated tab ids | \`'bd-tab'\` |
|
|
81
|
+
|
|
82
|
+
\`content\` takes a Lit template and wins over \`label\` when both are set — it
|
|
83
|
+
exists for strips whose label is richer than a string.
|
|
84
|
+
|
|
85
|
+
### Events
|
|
86
|
+
\`bd-tab-select\` — fires on selection with \`detail: { index }\`. It does not fire
|
|
87
|
+
when the already-selected tab is clicked.
|
|
88
|
+
|
|
89
|
+
### Light DOM
|
|
90
|
+
\`aria-controls\` and \`aria-labelledby\` are IDREFs, and an IDREF does not resolve
|
|
91
|
+
across a shadow boundary. If the buttons lived in this element's shadow root
|
|
92
|
+
they could not point at a panel in the consuming component's shadow root, so
|
|
93
|
+
this element renders into light DOM and the styles ship as an importable
|
|
94
|
+
\`tabListCSS\` sheet.
|
|
95
|
+
|
|
96
|
+
### Accessibility
|
|
97
|
+
\`role="tablist"\` with \`role="tab"\` buttons, roving \`tabindex\` so the strip is a
|
|
98
|
+
single tab stop, and arrow keys / Home / End moving between tabs with automatic
|
|
99
|
+
activation. Every tab points at the panel via \`aria-controls\`; the panel points
|
|
100
|
+
back via \`aria-labelledby\`.
|
|
101
|
+
|
|
102
|
+
### Theming
|
|
103
|
+
Component-local custom properties, all optional:
|
|
104
|
+
\`--bd-tab-color\`, \`--bd-tab-color-selected\`, \`--bd-tab-border-color\`,
|
|
105
|
+
\`--bd-tab-underline-color\`, \`--bd-tab-underline-height\`,
|
|
106
|
+
\`--bd-tab-underline-duration\`, \`--bd-tab-padding\`, \`--bd-tab-padding-mobile\`,
|
|
107
|
+
\`--bd-tab-gap\`, \`--bd-tab-font-size\`, \`--bd-tab-font-weight\`.
|
|
108
|
+
`
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const PLATFORMS = [
|
|
115
|
+
{ label: "Windows" },
|
|
116
|
+
{ label: "macOS" },
|
|
117
|
+
{ label: "iOS" },
|
|
118
|
+
{ label: "Android" }
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
/** A strip wired to a panel, which is how it is meant to be used. */
|
|
122
|
+
export const Default = {
|
|
123
|
+
name : "Default",
|
|
124
|
+
render: () => withStyles(html`
|
|
125
|
+
<bd-tab-list
|
|
126
|
+
.tabs=${PLATFORMS}
|
|
127
|
+
.selected=${0}
|
|
128
|
+
label="Platform"
|
|
129
|
+
id-prefix="demo-tab"
|
|
130
|
+
panel-id="demo-panel"
|
|
131
|
+
@bd-tab-select=${e => {
|
|
132
|
+
const panel = document.getElementById("demo-panel");
|
|
133
|
+
panel.textContent = `${PLATFORMS[e.detail.index].label} panel`;
|
|
134
|
+
panel.setAttribute("aria-labelledby", `demo-tab-${e.detail.index}`);
|
|
135
|
+
}}
|
|
136
|
+
></bd-tab-list>
|
|
137
|
+
<div
|
|
138
|
+
id="demo-panel"
|
|
139
|
+
role="tabpanel"
|
|
140
|
+
aria-labelledby="demo-tab-0"
|
|
141
|
+
style="padding: var(--spacing-24) 0;"
|
|
142
|
+
>Windows panel</div>
|
|
143
|
+
`)
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/** Selection can start anywhere; the strip does not assume the first tab. */
|
|
147
|
+
export const PreSelected = {
|
|
148
|
+
name : "Pre-selected tab",
|
|
149
|
+
render: () => withStyles(html`
|
|
150
|
+
<bd-tab-list .tabs=${PLATFORMS} .selected=${2} id-prefix="pre-tab"></bd-tab-list>
|
|
151
|
+
`)
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/** An optional icon per tab. Sizing stays with the consuming section. */
|
|
155
|
+
export const WithIcons = {
|
|
156
|
+
name : "With icons",
|
|
157
|
+
render: () => withStyles(html`
|
|
158
|
+
<style>.bd-tab-icon { width: 28px; height: 28px; object-fit: contain; }</style>
|
|
159
|
+
<bd-tab-list
|
|
160
|
+
id-prefix="icon-tab"
|
|
161
|
+
.tabs=${[
|
|
162
|
+
{ label: "Admin", icon: "/assets/pic1.png", iconAlt: "" },
|
|
163
|
+
{ label: "Adult", icon: "/assets/pic2.png", iconAlt: "" },
|
|
164
|
+
{ label: "Teen", icon: "/assets/pic3.png", iconAlt: "" }
|
|
165
|
+
]}
|
|
166
|
+
></bd-tab-list>
|
|
167
|
+
`)
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/** `content` replaces `label` when the strip needs richer markup. */
|
|
171
|
+
export const RichLabels = {
|
|
172
|
+
name : "Rich labels (content)",
|
|
173
|
+
render: () => withStyles(html`
|
|
174
|
+
<bd-tab-list
|
|
175
|
+
id-prefix="rich-tab"
|
|
176
|
+
.tabs=${PLATFORMS.map(p => ({
|
|
177
|
+
content: html`<bd-p variant="small"><strong>${p.label}</strong></bd-p>`
|
|
178
|
+
}))}
|
|
179
|
+
></bd-tab-list>
|
|
180
|
+
`)
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/** Every knob moved off its default at once, to show what is themeable. */
|
|
184
|
+
export const Themed = {
|
|
185
|
+
name : "Themed via custom properties",
|
|
186
|
+
render: () => withStyles(html`
|
|
187
|
+
<div style="
|
|
188
|
+
--bd-tab-color: var(--color-neutral-700);
|
|
189
|
+
--bd-tab-color-selected: var(--color-green-700);
|
|
190
|
+
--bd-tab-underline-color: var(--color-green-700);
|
|
191
|
+
--bd-tab-underline-height: var(--border-width-4);
|
|
192
|
+
--bd-tab-padding: var(--spacing-12) var(--spacing-32);
|
|
193
|
+
--bd-tab-border-color: var(--color-neutral-50);
|
|
194
|
+
">
|
|
195
|
+
<bd-tab-list .tabs=${PLATFORMS} .selected=${1} id-prefix="themed-tab"></bd-tab-list>
|
|
196
|
+
</div>
|
|
197
|
+
`)
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Tab, then arrow keys. The strip is one tab stop and arrows move within it —
|
|
202
|
+
* the behaviour none of the three sections had before the extraction.
|
|
203
|
+
*/
|
|
204
|
+
export const KeyboardNavigation = {
|
|
205
|
+
name : "Keyboard navigation",
|
|
206
|
+
render: () => withStyles(html`
|
|
207
|
+
<p style="font-family: var(--typography-fontFamily-sans);">
|
|
208
|
+
Focus the strip with <kbd>Tab</kbd>, then use <kbd>←</kbd> <kbd>→</kbd>
|
|
209
|
+
<kbd>Home</kbd> <kbd>End</kbd>.
|
|
210
|
+
</p>
|
|
211
|
+
<bd-tab-list .tabs=${PLATFORMS} label="Platform" id-prefix="kbd-tab"></bd-tab-list>
|
|
212
|
+
`)
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/** A single tab still renders a valid tablist. */
|
|
216
|
+
export const SingleTab = {
|
|
217
|
+
name : "Single tab (edge case)",
|
|
218
|
+
render: () => withStyles(html`
|
|
219
|
+
<bd-tab-list .tabs=${[{ label: "Only one" }]} id-prefix="single-tab"></bd-tab-list>
|
|
220
|
+
`)
|
|
221
|
+
};
|
|
@@ -2,7 +2,6 @@ import { css } from "lit";
|
|
|
2
2
|
|
|
3
3
|
export default css`
|
|
4
4
|
:host {
|
|
5
|
-
--bd-accesibility-focus: var(--color-blue-500);
|
|
6
5
|
font-size: 100%;
|
|
7
6
|
display: block;
|
|
8
7
|
font-family: var(--typography-fontFamily-sans);
|
|
@@ -17,8 +16,6 @@ export default css`
|
|
|
17
16
|
display: flex;
|
|
18
17
|
flex-direction: column;
|
|
19
18
|
align-items: center;
|
|
20
|
-
max-width: 1290px;
|
|
21
|
-
margin-inline: auto;
|
|
22
19
|
box-sizing: border-box;
|
|
23
20
|
}
|
|
24
21
|
|
|
@@ -38,13 +35,8 @@ export default css`
|
|
|
38
35
|
margin-bottom: var(--spacing-32);
|
|
39
36
|
}
|
|
40
37
|
|
|
41
|
-
/* Tab
|
|
42
|
-
|
|
43
|
-
display: inline-flex;
|
|
44
|
-
justify-content: center;
|
|
45
|
-
flex-wrap: wrap;
|
|
46
|
-
border-bottom: 1px solid var(--color-neutral-100);
|
|
47
|
-
}
|
|
38
|
+
/* The tab strip itself lives in Components/Tab List (tabListCSS, included in
|
|
39
|
+
static styles above). Only this section's own layout stays here. */
|
|
48
40
|
|
|
49
41
|
/* Panel — full width, fara padding inline */
|
|
50
42
|
.bd-panel-wrapper {
|
|
@@ -52,118 +44,17 @@ export default css`
|
|
|
52
44
|
box-sizing: border-box;
|
|
53
45
|
}
|
|
54
46
|
|
|
55
|
-
.bd-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
cursor: pointer;
|
|
63
|
-
color: var(--color-blue-500);
|
|
64
|
-
position: relative;
|
|
65
|
-
font-family: var(--typography-fontFamily-sans);
|
|
66
|
-
font-size: var(--typography-body-large-fontSize);
|
|
67
|
-
font-weight: var(--typography-fontWeight-semibold);
|
|
68
|
-
transition: color var(--transition-duration-fast) var(--transition-easing-smooth);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.bd-tab-button::after {
|
|
72
|
-
content: "";
|
|
73
|
-
height: 3px;
|
|
74
|
-
background: var(--color-blue-500);
|
|
75
|
-
position: absolute;
|
|
76
|
-
left: 0;
|
|
77
|
-
bottom: 0;
|
|
78
|
-
width: 0;
|
|
79
|
-
transition: width var(--transition-duration-slow) var(--transition-easing-smooth);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.bd-tab-button.bd-selected::after {
|
|
83
|
-
width: 100%;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.bd-tab-button.bd-selected {
|
|
87
|
-
color: var(--color-neutral-900);
|
|
88
|
-
font-weight: var(--typography-fontWeight-semibold);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.bd-tab-button:focus-visible {
|
|
92
|
-
outline: 2px solid var(--bd-accesibility-focus);
|
|
93
|
-
outline-offset: 2px;
|
|
94
|
-
border-radius: var(--radius-sm);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.bd-tab-label {
|
|
98
|
-
pointer-events: none;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/* Columns grid */
|
|
102
|
-
.bd-columns-container {
|
|
103
|
-
display: grid;
|
|
104
|
-
gap: var(--spacing-32);
|
|
105
|
-
width: 100%;
|
|
106
|
-
justify-content: center;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/* Coloana individuala */
|
|
110
|
-
.bd-col {
|
|
111
|
-
display: flex;
|
|
112
|
-
flex-direction: column;
|
|
113
|
-
width: 300px;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/* Icon wrapper */
|
|
117
|
-
.col-icon-wrapper {
|
|
118
|
-
display: flex;
|
|
119
|
-
align-items: flex-start;
|
|
120
|
-
margin-bottom: var(--spacing-8);
|
|
121
|
-
overflow: hidden;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/* Title wrapper */
|
|
125
|
-
.col-title-wrapper {
|
|
126
|
-
display: flex;
|
|
127
|
-
align-items: flex-start;
|
|
128
|
-
margin-bottom: var(--spacing-8);
|
|
129
|
-
overflow: hidden;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.col-title {
|
|
133
|
-
font-family: var(--typography-fontFamily-sans);
|
|
134
|
-
font-size: var(--typography-fontSize-2xl);
|
|
135
|
-
font-weight: var(--typography-fontWeight-bold);
|
|
136
|
-
color: var(--color-neutral-900);
|
|
137
|
-
line-height: var(--typography-lineHeight-normal);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.col-description {
|
|
141
|
-
margin-bottom: var(--spacing-16);
|
|
142
|
-
font-family: var(--typography-fontFamily-sans);
|
|
143
|
-
font-size: var(--typography-fontSize-md);
|
|
144
|
-
color: var(--color-neutral-700);
|
|
145
|
-
line-height: var(--typography-lineHeight-normal);
|
|
146
|
-
overflow: hidden;
|
|
147
|
-
}
|
|
47
|
+
/* No column rules. A tab panel's columns are bd-features' -- every panel in
|
|
48
|
+
every story wraps its content in <bd-features>, which renders .bd-col,
|
|
49
|
+
.col-icon-wrapper, .col-title-wrapper, .col-title and .col-description
|
|
50
|
+
into its own shadow root and styles them from features.css.js. A copy of
|
|
51
|
+
six of those selectors stood here and could not reach across that
|
|
52
|
+
boundary: measured 0 matches for every one of them across 9 bd-tabs shadow
|
|
53
|
+
roots in 604 built stories.
|
|
148
54
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
@media (max-width: 600px) {
|
|
157
|
-
.bd-col {
|
|
158
|
-
width: 100%;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
.bd-tabs-container {
|
|
162
|
-
gap: var(--spacing-4);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.bd-tab-button {
|
|
166
|
-
padding: var(--spacing-8) var(--spacing-12);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
55
|
+
Two recorded findings went with them, and neither was a question about
|
|
56
|
+
tabs. The 24px/1.5 column title in scripts/typography-pairings.json was
|
|
57
|
+
this file's .col-title, so the pairing it recorded rendered nowhere; and
|
|
58
|
+
the two responsive widths were this file's entries in the lg and 600
|
|
59
|
+
column groups, where bd-features carries the live ones. */
|
|
169
60
|
`;
|
|
@@ -1,11 +1,15 @@
|
|
|
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";
|
|
2
4
|
import { keyed } from "lit/directives/keyed.js";
|
|
3
|
-
import { tokens } from "../../tokens/tokens.js";
|
|
4
5
|
import "../features/features.js";
|
|
5
6
|
import "../heading/heading.js";
|
|
6
7
|
import "../highlight/highlight.js";
|
|
7
8
|
import "../paragraph/paragraph.js";
|
|
9
|
+
import "../tab-list/tab-list.js";
|
|
10
|
+
import { tabListCSS } from "../tab-list/tab-list.css.js";
|
|
8
11
|
import tabsCSS from "./tabs.css.js";
|
|
12
|
+
import { ensembleCSS } from "../shared/ensemble.css.js";
|
|
9
13
|
|
|
10
14
|
class BdTabPanel extends LitElement {
|
|
11
15
|
static styles = [];
|
|
@@ -25,7 +29,7 @@ class BdTabs extends LitElement {
|
|
|
25
29
|
_panelMinHeight: { type: Number, state: true },
|
|
26
30
|
bgBlue : { type: Boolean, reflect: true, attribute: "bg-blue" } };
|
|
27
31
|
|
|
28
|
-
static styles = [
|
|
32
|
+
static styles = [ensembleCSS, tabListCSS, tabsCSS];
|
|
29
33
|
|
|
30
34
|
constructor() {
|
|
31
35
|
super();
|
|
@@ -78,33 +82,26 @@ class BdTabs extends LitElement {
|
|
|
78
82
|
const activePanel = panels[this.selectedTab];
|
|
79
83
|
|
|
80
84
|
return html`
|
|
81
|
-
<div class="bd-tabs-component">
|
|
85
|
+
<div class="bd-ensemble bd-tabs-component">
|
|
82
86
|
|
|
83
87
|
${this.title
|
|
84
88
|
? html`<bd-highlight highlight-text="${this.highlightText}">${this.title}</bd-highlight>`
|
|
85
89
|
: ""}
|
|
86
90
|
|
|
87
91
|
${this.subtitle
|
|
88
|
-
? html`<bd-p
|
|
92
|
+
? html`<bd-p variant="large" class="bd-tabs-subtitle">${this.subtitle}</bd-p>`
|
|
89
93
|
: ""}
|
|
90
94
|
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
class="bd-tab-button ${this.selectedTab === index ? "bd-selected" : ""}"
|
|
99
|
-
@click=${() => this.selectTab(index)}
|
|
100
|
-
>
|
|
101
|
-
<span class="bd-tab-label">${panel.getAttribute("title")}</span>
|
|
102
|
-
</button>
|
|
103
|
-
`)}
|
|
104
|
-
</div>
|
|
95
|
+
<bd-tab-list
|
|
96
|
+
.tabs=${panels.map(panel => ({ label: panel.getAttribute("title") }))}
|
|
97
|
+
.selected=${this.selectedTab}
|
|
98
|
+
id-prefix="tab-btn"
|
|
99
|
+
panel-id="tab-panel"
|
|
100
|
+
@bd-tab-select=${e => this.selectTab(e.detail.index)}
|
|
101
|
+
></bd-tab-list>
|
|
105
102
|
|
|
106
103
|
<div
|
|
107
|
-
id="tab-panel
|
|
104
|
+
id="tab-panel"
|
|
108
105
|
role="tabpanel"
|
|
109
106
|
aria-labelledby="tab-btn-${this.selectedTab}"
|
|
110
107
|
class="bd-panel-wrapper"
|