srcdev-nuxt-components 9.4.11 → 9.5.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/.claude/skills/component-aria-landmark.md +1 -1
- package/.claude/skills/component-dynamic-slots.md +0 -1
- package/.claude/skills/component-export-types.md +3 -3
- package/.claude/skills/component-inline-action-button.md +7 -7
- package/.claude/skills/component-local-style-override.md +134 -50
- package/.claude/skills/component-naming.md +107 -0
- package/.claude/skills/components/action-menu.md +18 -14
- package/.claude/skills/components/alert-content.md +110 -0
- package/.claude/skills/components/alert-mask-core.md +15 -1
- package/.claude/skills/components/alert-masked-content.md +95 -0
- package/.claude/skills/components/auto-grid.md +21 -13
- package/.claude/skills/components/canvas-switcher.md +3 -3
- package/.claude/skills/components/capture-qr-code.md +19 -9
- package/.claude/skills/components/carousel-flip.md +3 -3
- package/.claude/skills/components/container-glow.md +2 -2
- package/.claude/skills/components/content-docs.md +9 -5
- package/.claude/skills/components/cookie-consent-banner.md +16 -17
- package/.claude/skills/components/dashboard-quad-grid.md +4 -4
- package/.claude/skills/components/decode-qr-code.md +15 -9
- package/.claude/skills/components/display-avatar.md +16 -31
- package/.claude/skills/components/display-chip.md +15 -10
- package/.claude/skills/components/display-dialog.md +3 -1
- package/.claude/skills/components/display-pill.md +17 -75
- package/.claude/skills/components/display-prompt.md +11 -19
- package/.claude/skills/components/display-qr-code.md +5 -0
- package/.claude/skills/components/display-theme-switch.md +7 -6
- package/.claude/skills/components/display-toast.md +5 -6
- package/.claude/skills/components/entry-animation.md +2 -5
- package/.claude/skills/components/eyebrow-text.md +6 -4
- package/.claude/skills/components/form-field.md +79 -0
- package/.claude/skills/components/form-fieldset.md +75 -0
- package/.claude/skills/components/form-wrapper.md +71 -0
- package/.claude/skills/components/glass-panel.md +60 -51
- package/.claude/skills/components/grid-stack.md +8 -2
- package/.claude/skills/components/header-block.md +1 -1
- package/.claude/skills/components/hero-text.md +8 -6
- package/.claude/skills/components/input-button.md +72 -0
- package/.claude/skills/components/input-checkbox-radio.md +149 -0
- package/.claude/skills/components/input-checkbox.md +148 -0
- package/.claude/skills/components/input-description.md +102 -0
- package/.claude/skills/components/input-error.md +105 -0
- package/.claude/skills/components/input-label.md +119 -0
- package/.claude/skills/components/{input-number-core.md → input-number.md} +41 -36
- package/.claude/skills/components/input-radio.md +95 -0
- package/.claude/skills/components/input-range-core.md +4 -4
- package/.claude/skills/components/input-select-core.md +1 -1
- package/.claude/skills/components/input-text-core.md +8 -6
- package/.claude/skills/components/input-textarea-core.md +4 -4
- package/.claude/skills/components/layout-grid-by-cols.md +31 -43
- package/.claude/skills/components/link-text.md +2 -2
- package/.claude/skills/components/opening-hours.md +116 -0
- package/.claude/skills/components/page-hero-highlights.md +35 -35
- package/.claude/skills/components/page-row.md +1 -1
- package/.claude/skills/components/pending-effect.md +63 -0
- package/.claude/skills/components/price-list.md +72 -0
- package/.claude/skills/components/pricing-card.md +3 -3
- package/.claude/skills/components/profile-section.md +6 -4
- package/.claude/skills/components/samaritan-prompt.md +140 -0
- package/.claude/skills/components/scroll-reveal-frame.md +21 -20
- package/.claude/skills/components/scroll-reveal-image.md +31 -21
- package/.claude/skills/components/service-detail.md +2 -2
- package/.claude/skills/components/services-card-grid.md +5 -4
- package/.claude/skills/components/services-card.md +12 -10
- package/.claude/skills/components/site-navigation.md +20 -6
- package/.claude/skills/components/slider-gallery.md +88 -0
- package/.claude/skills/components/social-icons-list.md +12 -6
- package/.claude/skills/components/tab-navigation.md +1 -1
- package/.claude/skills/components/text-block.md +68 -0
- package/.claude/skills/components/toggle-switch-core.md +3 -3
- package/.claude/skills/components/triple-toggle-switch.md +85 -0
- package/.claude/skills/composable-zod-validation.md +1 -1
- package/.claude/skills/consumer-styles-structure.md +153 -0
- package/.claude/skills/icon-sets.md +3 -3
- package/.claude/skills/icon-sizing.md +66 -0
- package/.claude/skills/index.md +35 -16
- package/.claude/skills/new-app-scaffold.md +45 -7
- package/.claude/skills/pull-request-description.md +1 -0
- package/.claude/skills/storybook-add-story.md +53 -5
- package/.claude/skills/testing-add-playwright.md +1 -1
- package/.claude/skills/theming-colour-ramps.md +25 -3
- package/.claude/skills/theming-component-token-pattern.md +16 -16
- package/.claude/skills/theming-override-default.md +7 -0
- package/.claude/skills/theming-partial-override.md +1 -1
- package/.claude/skills/theming-typography-tokens.md +1 -1
- package/.claude/skills/vercel-node-version.md +1 -1
- package/.vscode/srcdev-component-action-menu.code-snippets +42 -0
- package/.vscode/srcdev-component-alert-content.code-snippets +36 -0
- package/.vscode/srcdev-component-alert-masked-content.code-snippets +35 -0
- package/.vscode/srcdev-component-auto-grid.code-snippets +39 -0
- package/.vscode/srcdev-component-capture-decode-qr-code.code-snippets +28 -0
- package/.vscode/srcdev-component-content-docs.code-snippets +4 -4
- package/.vscode/srcdev-component-cookie-consent-banner.code-snippets +33 -0
- package/.vscode/srcdev-component-display-avatar.code-snippets +28 -0
- package/.vscode/srcdev-component-display-chip.code-snippets +27 -0
- package/.vscode/srcdev-component-display-pill.code-snippets +38 -0
- package/.vscode/srcdev-component-display-prompt.code-snippets +10 -54
- package/.vscode/srcdev-component-display-qr-code.code-snippets +22 -0
- package/.vscode/srcdev-component-eyebrow-text.code-snippets +19 -0
- package/.vscode/srcdev-component-form-field.code-snippets +25 -0
- package/.vscode/srcdev-component-form-fieldset.code-snippets +36 -0
- package/.vscode/srcdev-component-form-wrapper.code-snippets +30 -0
- package/.vscode/srcdev-component-glass-panel.code-snippets +38 -0
- package/.vscode/srcdev-component-grid-stack.code-snippets +49 -0
- package/.vscode/srcdev-component-input-button.code-snippets +27 -0
- package/.vscode/srcdev-component-input-checkbox-radio.code-snippets +60 -0
- package/.vscode/srcdev-component-input-checkbox.code-snippets +48 -0
- package/.vscode/srcdev-component-input-description.code-snippets +44 -0
- package/.vscode/srcdev-component-input-error.code-snippets +30 -0
- package/.vscode/srcdev-component-input-label.code-snippets +39 -0
- package/.vscode/srcdev-component-input-number.code-snippets +11 -11
- package/.vscode/srcdev-component-input-radio.code-snippets +58 -0
- package/.vscode/srcdev-component-layout-grid-by-cols.code-snippets +46 -0
- package/.vscode/srcdev-component-link-text.code-snippets +30 -0
- package/.vscode/srcdev-component-opening-hours.code-snippets +40 -0
- package/.vscode/srcdev-component-page-hero-highlights.code-snippets +37 -0
- package/.vscode/srcdev-component-page-row.code-snippets +47 -0
- package/.vscode/srcdev-component-pending-effect.code-snippets +26 -0
- package/.vscode/srcdev-component-price-list.code-snippets +37 -0
- package/.vscode/srcdev-component-pricing-card.code-snippets +2 -2
- package/.vscode/srcdev-component-profile-section.code-snippets +36 -0
- package/.vscode/srcdev-component-samaritan-prompt.code-snippets +60 -0
- package/.vscode/srcdev-component-scroll-reveal-frame.code-snippets +36 -0
- package/.vscode/srcdev-component-scroll-reveal-image.code-snippets +46 -0
- package/.vscode/srcdev-component-services-card.code-snippets +4 -4
- package/.vscode/srcdev-component-services-grids.code-snippets +36 -0
- package/.vscode/srcdev-component-site-navigation.code-snippets +26 -18
- package/.vscode/srcdev-component-slider-gallery.code-snippets +9 -0
- package/.vscode/srcdev-component-social-icons-list.code-snippets +24 -0
- package/.vscode/srcdev-component-stepper-list.code-snippets +39 -0
- package/.vscode/srcdev-component-text-block.code-snippets +31 -0
- package/.vscode/srcdev-component-triple-toggle-switch.code-snippets +30 -0
- package/README.md +2 -2
- package/app/app.config.ts +10 -0
- package/app/assets/styles/setup/02.colours/_orange.css +11 -11
- package/app/assets/styles/setup/02.colours/_theme-params.css +2 -2
- package/app/assets/styles/setup/03.theming/_default.css +1 -22
- package/app/assets/styles/setup/03.theming/_theme-slots.css +1 -1
- package/app/assets/styles/setup/03.theming/_warning.css +8 -10
- package/app/assets/styles/setup/04.elements/forms/02.typography.css +0 -14
- package/app/assets/styles/setup/04.elements/forms/06.button-geometry.css +1 -1
- package/app/assets/styles/setup/index.css +1 -1
- package/app/components/01.atoms/alert-mask/AlertMaskCore.vue +23 -5
- package/app/components/01.atoms/alert-mask/CONSUMER-STYLING.md +23 -5
- package/app/components/01.atoms/alert-mask/stories/AlertMaskCore.stories.ts +45 -19
- package/app/components/01.atoms/alert-mask/tests/AlertMaskCore.spec.ts +35 -1
- package/app/components/01.atoms/animations/animated-svg-text/CONSUMER-STYLING.md +13 -0
- package/app/components/01.atoms/animations/clip-element/CONSUMER-STYLING.md +13 -0
- package/app/components/01.atoms/animations/clip-element/ClipElement.vue +2 -2
- package/app/components/01.atoms/animations/container-glow/CONSUMER-STYLING.md +26 -5
- package/app/components/01.atoms/animations/entry/.nuxt/app.config.mjs +21 -0
- package/app/components/01.atoms/animations/entry/.nuxt/components.d.ts +66 -0
- package/app/components/01.atoms/animations/entry/.nuxt/imports.d.ts +30 -0
- package/app/components/01.atoms/animations/entry/.nuxt/manifest/meta/test.json +1 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/app.config.d.ts +35 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/build.d.ts +23 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/builder-env.d.ts +1 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/components.d.ts +71 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/imports.d.ts +386 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/middleware.d.ts +11 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/modules.d.ts +79 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/nitro-layouts.d.ts +17 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/nitro-nuxt.d.ts +64 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/plugins.d.ts +29 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/runtime-config.d.ts +32 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/shared-imports.d.ts +10 -0
- package/app/components/01.atoms/animations/entry/.nuxt/types/vue-shim.d.ts +0 -0
- package/app/components/01.atoms/animations/entry/.nuxtrc +1 -0
- package/app/components/01.atoms/animations/entry/CONSUMER-STYLING.md +65 -0
- package/app/components/01.atoms/animations/entry/EntryAnimation.vue +6 -5
- package/app/components/01.atoms/animations/entry/node_modules/.cache/nuxt/chrome-workspace.json +1 -0
- package/app/components/01.atoms/animations/entry/node_modules/.cache/vite/client/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/app/components/01.atoms/animations/entry/stories/EntryAnimation.stories.ts +1 -1
- package/app/components/01.atoms/animations/entry/tests/EntryAnimation.spec.ts +25 -0
- package/app/components/01.atoms/animations/glowing-border/CONSUMER-STYLING.md +24 -5
- package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +20 -0
- package/app/components/01.atoms/animations/rotating-carousel-image/CONSUMER-STYLING.md +17 -0
- package/app/components/01.atoms/animations/scroll-reveal-frame/CONSUMER-STYLING.md +77 -0
- package/app/components/01.atoms/animations/scroll-reveal-frame/ScrollRevealFrame.vue +37 -78
- package/app/components/01.atoms/animations/scroll-reveal-frame/stories/ScrollRevealFrame.stories.ts +48 -0
- package/app/components/01.atoms/animations/scroll-reveal-frame/tests/ScrollRevealFrame.spec.ts +40 -33
- package/app/components/01.atoms/animations/scroll-reveal-frame/tests/__snapshots__/ScrollRevealFrame.spec.ts.snap +4 -4
- package/app/components/01.atoms/animations/scroll-reveal-image/CONSUMER-STYLING.md +74 -0
- package/app/components/01.atoms/animations/scroll-reveal-image/ScrollRevealImage.vue +14 -44
- package/app/components/01.atoms/animations/scroll-reveal-image/stories/ScrollRevealImage.stories.ts +50 -1
- package/app/components/01.atoms/animations/scroll-reveal-image/tests/ScrollRevealImage.spec.ts +27 -20
- package/app/components/01.atoms/animations/scroll-reveal-image/tests/__snapshots__/ScrollRevealImage.spec.ts.snap +4 -4
- package/app/components/01.atoms/animations/section-parallax/CONSUMER-STYLING.md +21 -4
- package/app/components/01.atoms/animations/view-timeline/CONSUMER-STYLING.md +25 -0
- package/app/components/01.atoms/banner-video/CONSUMER-STYLING.md +12 -5
- package/app/components/01.atoms/canvas-switcher/CONSUMER-STYLING.md +20 -7
- package/app/components/01.atoms/canvas-switcher/CanvasSwitcher.vue +12 -7
- package/app/components/01.atoms/card/CONSUMER-STYLING.md +47 -42
- package/app/components/01.atoms/card/CardCore.vue +7 -17
- package/app/components/01.atoms/clipped-panel/CONSUMER-STYLING.md +13 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/CONSUMER-STYLING.md +127 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +44 -77
- package/app/components/01.atoms/content-wrappers/docs-pages/stories/ContentDocs.stories.ts +3 -3
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/CONSUMER-STYLING.md +14 -1
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/stories/DashboardQuadGrid.stories.ts +2 -0
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/CONSUMER-STYLING.md +13 -0
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/stories/DashboardStatsGrid.stories.ts +2 -0
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/CONSUMER-STYLING.md +72 -0
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/LayoutGridByCols.vue +26 -25
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/stories/LayoutGridByCols.stories.ts +91 -107
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/tests/LayoutGridByCols.spec.ts +50 -15
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/tests/__snapshots__/LayoutGridByCols.spec.ts.snap +5 -5
- package/app/components/01.atoms/display-banner/CONSUMER-STYLING.md +13 -0
- package/app/components/01.atoms/display-dialog/CONSUMER-STYLING.md +82 -54
- package/app/components/01.atoms/display-dialog/DisplayDialog.vue +38 -45
- package/app/components/01.atoms/display-dialog/stories/DisplayDialog.stories.ts +25 -0
- package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +21 -0
- package/app/components/01.atoms/display-pill/CONSUMER-STYLING.md +112 -0
- package/app/components/01.atoms/display-pill/DisplayPill.vue +88 -50
- package/app/components/01.atoms/display-pill/stories/DisplayPill.stories.ts +56 -3
- package/app/components/01.atoms/display-pill/tests/DisplayPill.spec.ts +104 -4
- package/app/components/01.atoms/display-pill/tests/__snapshots__/DisplayPill.spec.ts.snap +3 -3
- package/app/components/01.atoms/display-tooltip/CONSUMER-STYLING.md +22 -2
- package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +18 -26
- package/app/components/01.atoms/glass-panel/CONSUMER-STYLING.md +91 -0
- package/app/components/01.atoms/glass-panel/GlassPanel.vue +34 -30
- package/app/components/01.atoms/glass-panel/stories/GlassPanel.stories.ts +121 -0
- package/app/components/01.atoms/glass-panel/tests/GlassPanel.spec.ts +61 -0
- package/app/components/01.atoms/grids/auto-grid/AutoGrid.vue +5 -10
- package/app/components/01.atoms/grids/auto-grid/CONSUMER-STYLING.md +76 -0
- package/app/components/01.atoms/grids/auto-grid/stories/AutoGrid.stories.ts +5 -4
- package/app/components/01.atoms/grids/auto-grid/tests/AutoGrid.spec.ts +8 -0
- package/app/components/01.atoms/grids/column-flow-grid/CONSUMER-STYLING.md +11 -2
- package/app/components/01.atoms/grids/grid-stack/CONSUMER-STYLING.md +76 -0
- package/app/components/01.atoms/grids/grid-stack/GridStack.vue +6 -1
- package/app/components/01.atoms/grids/grid-stack/stories/GridStack.stories.ts +1 -1
- package/app/components/01.atoms/grids/grid-stack/tests/GridStack.spec.ts +35 -0
- package/app/components/01.atoms/grids/masonry-grid/CONSUMER-STYLING.md +11 -2
- package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +5 -10
- package/app/components/01.atoms/navigation/breadcrumb/CONSUMER-STYLING.md +15 -0
- package/app/components/01.atoms/navigation/skip-links/CONSUMER-STYLING.md +13 -0
- package/app/components/01.atoms/navigation/tabs/CONSUMER-STYLING.md +21 -0
- package/app/components/01.atoms/page-row/CONSUMER-STYLING.md +46 -8
- package/app/components/01.atoms/page-row/PageRow.vue +17 -13
- package/app/components/01.atoms/page-row/stories/PageRow.stories.ts +8 -0
- package/app/components/01.atoms/page-row/tests/PageRow.spec.ts +7 -11
- package/app/components/01.atoms/pop-over/CONSUMER-STYLING.md +13 -0
- package/app/components/01.atoms/qr-code/CONSUMER-STYLING.md +48 -0
- package/app/components/01.atoms/qr-code/DisplayQrCode.vue +5 -1
- package/app/components/01.atoms/qr-code/stories/DisplayQrCode.stories.ts +11 -3
- package/app/components/01.atoms/qr-code/tests/DisplayQrCode.spec.ts +15 -0
- package/app/components/01.atoms/text-block/CONSUMER-STYLING.md +49 -0
- package/app/components/01.atoms/text-block/TextBlock.vue +13 -5
- package/app/components/01.atoms/text-block/stories/TextBlock.stories.ts +84 -0
- package/app/components/01.atoms/text-block/tests/TextBlock.spec.ts +78 -0
- package/app/components/01.atoms/text-block/tests/__snapshots__/TextBlock.spec.ts.snap +7 -0
- package/app/components/01.atoms/text-blocks/eyebrow-text/CONSUMER-STYLING.md +56 -0
- package/app/components/01.atoms/text-blocks/eyebrow-text/EyebrowText.vue +10 -5
- package/app/components/01.atoms/text-blocks/eyebrow-text/tests/EyebrowText.spec.ts +11 -0
- package/app/components/01.atoms/text-blocks/header-block/CONSUMER-STYLING.md +16 -1
- package/app/components/01.atoms/text-blocks/hero-text/CONSUMER-STYLING.md +74 -0
- package/app/components/01.atoms/text-blocks/hero-text/HeroText.vue +14 -9
- package/app/components/01.atoms/text-blocks/hero-text/tests/HeroText.spec.ts +11 -0
- package/app/components/01.atoms/text-blocks/link-text/CONSUMER-STYLING.md +45 -0
- package/app/components/01.atoms/text-blocks/link-text/LinkText.vue +15 -8
- package/app/components/01.atoms/text-blocks/link-text/tests/LinkText.spec.ts +11 -0
- package/app/components/01.atoms/ui-block-decorated/CONSUMER-STYLING.md +13 -0
- package/app/components/02.molecules/action-menu/ActionMenu.vue +28 -30
- package/app/components/02.molecules/action-menu/{ActionMenuItemCore.vue → ActionMenuItem.vue} +12 -14
- package/app/components/02.molecules/action-menu/CONSUMER-STYLING.md +90 -76
- package/app/components/02.molecules/action-menu/stories/ActionMenu.stories.ts +48 -41
- package/app/components/02.molecules/action-menu/tests/ActionMenu.spec.ts +46 -1
- package/app/components/02.molecules/action-menu/tests/{ActionMenuItemCore.spec.ts → ActionMenuItem.spec.ts} +11 -5
- package/app/components/02.molecules/action-menu/tests/__snapshots__/ActionMenuItem.spec.ts.snap +27 -0
- package/app/components/02.molecules/alert-content/AlertContent.vue +17 -8
- package/app/components/02.molecules/alert-content/AlertContentInner.vue +57 -30
- package/app/components/02.molecules/alert-content/CONSUMER-STYLING.md +84 -0
- package/app/components/02.molecules/alert-content/stories/AlertContent.stories.ts +39 -0
- package/app/components/02.molecules/alert-content/tests/AlertContent.spec.ts +32 -0
- package/app/components/02.molecules/alert-content/tests/AlertContentInner.spec.ts +32 -0
- package/app/components/02.molecules/alert-masked-content/AlertMaskedContent.vue +9 -5
- package/app/components/02.molecules/alert-masked-content/CONSUMER-STYLING.md +73 -0
- package/app/components/02.molecules/alert-masked-content/stories/AlertMaskedContent.stories.ts +91 -10
- package/app/components/02.molecules/alert-masked-content/tests/AlertMaskedContent.spec.ts +52 -0
- package/app/components/02.molecules/cookie-consent-banner/CONSUMER-STYLING.md +95 -0
- package/app/components/02.molecules/cookie-consent-banner/CookieConsentBanner.vue +149 -0
- package/app/components/{01.atoms → 02.molecules}/cookie-consent-banner/stories/CookieConsentBanner.stories.ts +22 -3
- package/app/components/{01.atoms → 02.molecules}/cookie-consent-banner/tests/CookieConsentBanner.spec.ts +81 -4
- package/app/components/02.molecules/display-avatar/CONSUMER-STYLING.md +63 -0
- package/app/components/02.molecules/display-avatar/DisplayAvatar.vue +120 -0
- package/app/components/{01.atoms → 02.molecules}/display-avatar/stories/DisplayAvatar.stories.ts +56 -14
- package/app/components/{01.atoms → 02.molecules}/display-avatar/tests/DisplayAvatar.spec.ts +43 -11
- package/app/components/02.molecules/display-avatar/tests/__snapshots__/DisplayAvatar.spec.ts.snap +11 -0
- package/app/components/02.molecules/display-chip/CONSUMER-STYLING.md +57 -0
- package/app/components/02.molecules/display-chip/DisplayChip.vue +50 -83
- package/app/components/02.molecules/display-chip/tests/DisplayChip.spec.ts +10 -10
- package/app/components/02.molecules/display-chip/tests/__snapshots__/DisplayChip.spec.ts.snap +4 -4
- package/app/components/02.molecules/display-theme-switch/CONSUMER-STYLING.md +25 -4
- package/app/components/02.molecules/display-theme-switch/DisplayThemeSwitch.vue +9 -6
- package/app/components/02.molecules/display-theme-switch/stories/DisplayThemeSwitch.stories.ts +6 -1
- package/app/components/02.molecules/display-theme-switch/tests/DisplayThemeSwitch.spec.ts +10 -1
- package/app/components/02.molecules/display-tooltip-defined/CONSUMER-STYLING.md +11 -0
- package/app/components/02.molecules/expandable/accordian/CONSUMER-STYLING.md +11 -4
- package/app/components/02.molecules/expandable/expanding-panel/CONSUMER-STYLING.md +12 -5
- package/app/components/02.molecules/expandable/expanding-panel-classic/CONSUMER-STYLING.md +12 -5
- package/app/components/02.molecules/input-copy/CONSUMER-STYLING.md +12 -5
- package/app/components/02.molecules/input-copy/InputCopy.vue +12 -25
- package/app/components/02.molecules/input-copy/stories/InputCopy.stories.ts +1 -1
- package/app/components/02.molecules/input-copy/tests/InputCopy.spec.ts +1 -1
- package/app/components/02.molecules/navigation/deep-expanding-menu/CONSUMER-STYLING.md +13 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/CONSUMER-STYLING.md +11 -0
- package/app/components/02.molecules/navigation/site-navigation/CONSUMER-STYLING.md +109 -0
- package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +37 -55
- package/app/components/02.molecules/navigation/site-navigation/stories/SiteNavigation.stories.ts +22 -1
- package/app/components/02.molecules/navigation/site-navigation/tests/SiteNavigation.spec.ts +41 -6
- package/app/components/02.molecules/navigation/tab-navigation/CONSUMER-STYLING.md +13 -8
- package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +18 -36
- package/app/components/02.molecules/navigation/tab-navigation/stories/TabNavigation.stories.ts +1 -1
- package/app/components/02.molecules/navigation/tab-navigation/tests/TabNavigation.spec.ts +1 -1
- package/app/components/02.molecules/opening-hours/CONSUMER-STYLING.md +134 -0
- package/app/components/02.molecules/opening-hours/OpeningHours.vue +352 -0
- package/app/components/02.molecules/opening-hours/stories/OpeningHours.stories.ts +127 -0
- package/app/components/02.molecules/opening-hours/tests/OpeningHours.spec.ts +228 -0
- package/app/components/02.molecules/opening-hours/tests/OpeningHours.structuredData.spec.ts +45 -0
- package/app/components/02.molecules/opening-hours/tests/__snapshots__/OpeningHours.spec.ts.snap +23 -0
- package/app/components/02.molecules/opening-hours/tests/buildOpeningHoursSpecification.spec.ts +52 -0
- package/app/components/02.molecules/price-list/CONSUMER-STYLING.md +106 -0
- package/app/components/02.molecules/price-list/PriceList.vue +48 -40
- package/app/components/02.molecules/price-list/stories/PriceList.stories.ts +15 -2
- package/app/components/02.molecules/price-list/tests/PriceList.spec.ts +39 -2
- package/app/components/02.molecules/price-list/tests/__snapshots__/PriceList.spec.ts.snap +4 -16
- package/app/components/02.molecules/pricing-card/CONSUMER-STYLING.md +23 -5
- package/app/components/02.molecules/pricing-card/PricingCard.vue +31 -61
- package/app/components/02.molecules/pricing-card/stories/PricingCard.stories.ts +2 -0
- package/app/components/02.molecules/pricing-card/tests/PricingCard.spec.ts +14 -1
- package/app/components/02.molecules/profile-section/CONSUMER-STYLING.md +53 -0
- package/app/components/02.molecules/profile-section/ProfileSection.vue +53 -66
- package/app/components/02.molecules/profile-section/tests/ProfileSection.spec.ts +4 -4
- package/app/components/02.molecules/profile-section/tests/__snapshots__/ProfileSection.spec.ts.snap +6 -12
- package/app/components/02.molecules/prompt/CONSUMER-STYLING.md +51 -0
- package/app/components/{01.atoms → 02.molecules}/prompt/DisplayPrompt.vue +23 -8
- package/app/components/{01.atoms → 02.molecules}/prompt/stories/DisplayPrompt.stories.ts +18 -1
- package/app/components/{01.atoms → 02.molecules}/prompt/tests/DisplayPrompt.spec.ts +37 -7
- package/app/components/02.molecules/qr-code/CONSUMER-STYLING.md +66 -0
- package/app/components/02.molecules/qr-code/CaptureQrCode.vue +31 -12
- package/app/components/02.molecules/qr-code/DecodeQrCode.vue +55 -19
- package/app/components/02.molecules/qr-code/stories/CaptureQrCode.stories.ts +56 -0
- package/app/components/02.molecules/qr-code/stories/DecodeQrCode.stories.ts +53 -0
- package/app/components/02.molecules/qr-code/tests/CaptureQrCode.spec.ts +68 -20
- package/app/components/02.molecules/qr-code/tests/DecodeQrCode.spec.ts +44 -8
- package/app/components/02.molecules/samaritan-prompt/CONSUMER-STYLING.md +118 -0
- package/app/components/02.molecules/samaritan-prompt/SamaritanPrompt.vue +108 -51
- package/app/components/02.molecules/samaritan-prompt/SamaritanPromptMixed.vue +63 -62
- package/app/components/02.molecules/samaritan-prompt/stories/SamaritanPrompt.stories.ts +129 -0
- package/app/components/02.molecules/samaritan-prompt/stories/SamaritanPromptMixed.stories.ts +124 -0
- package/app/components/02.molecules/samaritan-prompt/tests/SamaritanPrompt.spec.ts +66 -0
- package/app/components/02.molecules/samaritan-prompt/tests/SamaritanPromptMixed.spec.ts +95 -17
- package/app/components/02.molecules/select-menu/CONSUMER-STYLING.md +11 -2
- package/app/components/02.molecules/social-icons-list/CONSUMER-STYLING.md +43 -0
- package/app/components/02.molecules/social-icons-list/SocialIconsList.vue +15 -15
- package/app/components/02.molecules/social-icons-list/stories/SocialIconsList.stories.ts +6 -1
- package/app/components/02.molecules/social-icons-list/tests/SocialIconsList.spec.ts +22 -1
- package/app/components/02.molecules/social-icons-list/tests/__snapshots__/SocialIconsList.spec.ts.snap +3 -3
- package/app/components/02.molecules/stepper-list/CONSUMER-STYLING.md +44 -5
- package/app/components/02.molecules/stepper-list/StepperList.vue +23 -43
- package/app/components/02.molecules/stepper-list/tests/StepperList.spec.ts +9 -0
- package/app/components/{01.atoms → 02.molecules}/toast/CONSUMER-STYLING.md +14 -0
- package/app/components/{01.atoms → 02.molecules}/toast/DisplayToast.vue +1 -2
- package/app/components/{01.atoms → 02.molecules}/toast/DisplayToastProvider.vue +1 -2
- package/app/components/{01.atoms → 02.molecules}/toast/stories/DisplayToast.stories.ts +1 -1
- package/app/components/{01.atoms → 02.molecules}/toast/stories/DisplayToastProvider.stories.ts +1 -1
- package/app/components/03.organisms/image-galleries/carousel-flip/CONSUMER-STYLING.md +13 -0
- package/app/components/03.organisms/image-galleries/slider-gallery/CONSUMER-STYLING.md +137 -0
- package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +378 -343
- package/app/components/03.organisms/image-galleries/slider-gallery/stories/SliderGallery.stories.ts +26 -1
- package/app/components/03.organisms/image-galleries/slider-gallery/tests/SliderGallery.spec.ts +102 -23
- package/app/components/03.organisms/image-galleries/slider-gallery/tests/__snapshots__/SliderGallery.spec.ts.snap +44 -44
- package/app/components/03.organisms/responsive-header/CONSUMER-STYLING.md +12 -1
- package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +0 -4
- package/app/components/03.organisms/services/service-detail/CONSUMER-STYLING.md +24 -3
- package/app/components/03.organisms/services/service-detail/ServiceDetail.vue +3 -3
- package/app/components/03.organisms/services/service-detail/stories/ServiceDetail.stories.ts +13 -13
- package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +1 -1
- package/app/components/03.organisms/services/service-summary/CONSUMER-STYLING.md +24 -7
- package/app/components/03.organisms/services/service-summary/ServiceSummary.vue +3 -3
- package/app/components/03.organisms/services/service-summary/stories/ServiceSummary.stories.ts +1 -1
- package/app/components/03.organisms/services/service-summary/tests/__snapshots__/ServiceSummary.spec.ts.snap +1 -1
- package/app/components/03.organisms/services/services-card/CONSUMER-STYLING.md +11 -2
- package/app/components/03.organisms/services/services-card/ServicesCard.vue +17 -26
- package/app/components/03.organisms/services/services-card/tests/ServicesCard.spec.ts +21 -0
- package/app/components/03.organisms/services/services-grids/CONSUMER-STYLING.md +50 -0
- package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +9 -16
- package/app/components/03.organisms/services/services-grids/stories/ServicesCardGrid.stories.ts +6 -0
- package/app/components/03.organisms/services/services-grids/tests/ServicesCardGrid.spec.ts +18 -0
- package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServiceSummaryGrid.spec.ts.snap +3 -3
- package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServicesCardGrid.spec.ts.snap +3 -3
- package/app/components/03.organisms/site-header/CONSUMER-STYLING.md +12 -1
- package/app/components/04.templates/page-hero-highlights/CONSUMER-STYLING.md +103 -0
- package/app/components/04.templates/page-hero-highlights/PageHeroHighlights.vue +144 -193
- package/app/components/04.templates/page-hero-highlights/PageHeroHighlightsHeader.vue +27 -37
- package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlights.stories.ts +56 -60
- package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlightsHeader.stories.ts +2 -2
- package/app/components/04.templates/page-hero-highlights/tests/PageHeroHighlights.spec.ts +10 -10
- package/app/components/04.templates/page-hero-highlights/tests/PageHeroHighlightsHeader.spec.ts +7 -7
- package/app/components/04.templates/page-hero-highlights/tests/__snapshots__/PageHeroHighlights.spec.ts.snap +6 -6
- package/app/components/05.forms/form-errors/CONSUMER-STYLING.md +112 -0
- package/app/components/05.forms/form-errors/InputError.vue +101 -122
- package/app/components/05.forms/form-errors/stories/InputError.stories.ts +125 -0
- package/app/components/05.forms/form-errors/tests/InputError.spec.ts +82 -31
- package/app/components/05.forms/form-field/CONSUMER-STYLING.md +91 -0
- package/app/components/05.forms/form-field/FormField.vue +26 -35
- package/app/components/05.forms/form-field/stories/FormField.stories.ts +104 -0
- package/app/components/05.forms/form-field/tests/FormField.spec.ts +75 -0
- package/app/components/05.forms/form-fieldset/CONSUMER-STYLING.md +88 -0
- package/app/components/05.forms/form-fieldset/FormFieldset.vue +34 -28
- package/app/components/05.forms/form-fieldset/stories/FormFieldset.stories.ts +84 -0
- package/app/components/05.forms/form-fieldset/tests/FormFieldset.spec.ts +111 -0
- package/app/components/05.forms/form-wrapper/CONSUMER-STYLING.md +101 -0
- package/app/components/05.forms/form-wrapper/FormWrapper.vue +32 -15
- package/app/components/05.forms/form-wrapper/stories/FormWrapper.stories.ts +75 -0
- package/app/components/05.forms/form-wrapper/tests/FormWrapper.spec.ts +57 -0
- package/app/components/05.forms/input-button/CONSUMER-STYLING.md +52 -7
- package/app/components/05.forms/input-button/{InputButtonCore.vue → InputButton.vue} +60 -18
- package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts → input-button.playwright.ts} +5 -5
- package/app/components/05.forms/input-button/stories/{InputButtonCore.stories.ts → InputButton.stories.ts} +8 -10
- package/app/components/05.forms/input-button/tests/{InputButtonCore.spec.ts → InputButton.spec.ts} +75 -19
- package/app/components/05.forms/input-button/tests/__snapshots__/{InputButtonCore.spec.ts.snap → InputButton.spec.ts.snap} +18 -18
- package/app/components/05.forms/input-checkbox/CONSUMER-STYLING.md +93 -0
- package/app/components/05.forms/input-checkbox/MultipleCheckboxes.vue +19 -25
- package/app/components/05.forms/input-checkbox/SingleCheckbox.vue +17 -43
- package/app/components/05.forms/input-checkbox/stories/MultipleCheckboxes.stories.ts +104 -0
- package/app/components/05.forms/input-checkbox/stories/SingleCheckbox.stories.ts +75 -0
- package/app/components/05.forms/input-checkbox/tests/MultipleCheckboxes.spec.ts +91 -53
- package/app/components/05.forms/input-checkbox/tests/SingleCheckbox.spec.ts +112 -0
- package/app/components/05.forms/input-checkbox-radio/CONSUMER-STYLING.md +115 -35
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadio.vue +158 -0
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue +102 -101
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioField.vue +100 -0
- package/app/components/05.forms/input-checkbox-radio/stories/{InputCheckboxRadioCore.stories.ts → InputCheckboxRadio.stories.ts} +23 -8
- package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadioButton.stories.ts +60 -16
- package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadioField.stories.ts +93 -0
- package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadio.spec.ts +174 -0
- package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadioButton.spec.ts +87 -0
- package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadioField.spec.ts +87 -0
- package/app/components/05.forms/input-description/CONSUMER-STYLING.md +177 -0
- package/app/components/05.forms/input-description/InputDescription.vue +45 -24
- package/app/components/05.forms/input-description/stories/InputDescription.stories.ts +160 -0
- package/app/components/05.forms/input-description/tests/InputDescription.spec.ts +62 -386
- package/app/components/05.forms/input-label/CONSUMER-STYLING.md +134 -0
- package/app/components/05.forms/input-label/InputLabel.vue +99 -38
- package/app/components/05.forms/input-label/stories/InputLabel.stories.ts +236 -0
- package/app/components/05.forms/input-label/tests/InputLabel.spec.ts +113 -342
- package/app/components/05.forms/input-number/CONSUMER-STYLING.md +16 -7
- package/app/components/05.forms/input-number/{InputNumberCore.vue → InputNumber.vue} +6 -6
- package/app/components/05.forms/input-number/{variants/InputNumberDefault.vue → InputNumberField.vue} +12 -15
- package/app/components/05.forms/input-number/stories/{InputNumberCore.stories.ts → InputNumber.stories.ts} +6 -6
- package/app/components/05.forms/input-number/{variants/stories/InputNumberDefault.stories.ts → stories/InputNumberField.stories.ts} +5 -5
- package/app/components/05.forms/input-number/tests/{InputNumberCore.spec.ts → InputNumber.spec.ts} +2 -2
- package/app/components/05.forms/input-number/{variants/tests/InputNumberDefault.spec.ts → tests/InputNumberField.spec.ts} +8 -8
- package/app/components/05.forms/input-radio/CONSUMER-STYLING.md +70 -0
- package/app/components/05.forms/input-radio/MultipleRadiobuttons.vue +19 -30
- package/app/components/05.forms/input-radio/stories/MultipleRadiobuttons.stories.ts +116 -0
- package/app/components/05.forms/input-radio/tests/MultipleRadioButtons.spec.ts +125 -74
- package/app/components/05.forms/input-range/CONSUMER-STYLING.md +13 -0
- package/app/components/05.forms/input-range/InputRangeCore.vue +1 -1
- package/app/components/05.forms/input-range/{variants/InputRangeDefault.vue → InputRangeDefault.vue} +7 -11
- package/app/components/05.forms/input-range/{variants/tests → tests}/InputRangeDefault.spec.ts +1 -1
- package/app/components/05.forms/input-select/CONSUMER-STYLING.md +11 -2
- package/app/components/05.forms/input-select/{variants/InputSelectWithLabel.vue → InputSelectWithLabel.vue} +6 -9
- package/app/components/05.forms/input-select/stories/InputSelectWithLabel.stories.ts +1 -1
- package/app/components/05.forms/input-text/CONSUMER-STYLING.md +12 -3
- package/app/components/05.forms/input-text/{variants/InputPasswordWithLabel.vue → InputPasswordWithLabel.vue} +3 -3
- package/app/components/05.forms/input-text/{variants/InputTextAsNumberWithLabel.vue → InputTextAsNumberWithLabel.vue} +12 -15
- package/app/components/05.forms/input-text/InputTextCore.vue +8 -11
- package/app/components/05.forms/input-text/{variants/InputTextWithLabel.vue → InputTextWithLabel.vue} +9 -10
- package/app/components/05.forms/input-text/stories/InputPasswordWithLabel.stories.ts +1 -1
- package/app/components/05.forms/input-text/stories/InputTextAsNumberWithLabel.stories.ts +1 -1
- package/app/components/05.forms/input-text/stories/InputTextWithLabel.stories.ts +1 -1
- package/app/components/05.forms/input-text/tests/InputPasswordWithLabel.spec.ts +2 -1
- package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +1 -1
- package/app/components/05.forms/input-text/tests/InputTextWithLabel.spec.ts +2 -1
- package/app/components/05.forms/input-textarea/CONSUMER-STYLING.md +11 -2
- package/app/components/05.forms/input-textarea/{variants/InputTextareaWithLabel.vue → InputTextareaWithLabel.vue} +3 -7
- package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +1 -1
- package/app/components/05.forms/patterns/stories/ContactForm.stories.ts +9 -10
- package/app/components/05.forms/patterns/stories/LoginForm.stories.ts +10 -10
- package/app/components/05.forms/patterns/stories/MigratedFieldsForm.stories.ts +246 -101
- package/app/components/05.forms/pending-effect/CONSUMER-STYLING.md +92 -0
- package/app/components/05.forms/pending-effect/PendingEffect.vue +52 -45
- package/app/components/05.forms/pending-effect/stories/PendingEffect.stories.ts +132 -0
- package/app/components/05.forms/pending-effect/tests/PendingEffect.spec.ts +67 -0
- package/app/components/05.forms/toggle-switch/CONSUMER-STYLING.md +11 -2
- package/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue +10 -29
- package/app/components/05.forms/toggle-switch/{variants/ToggleSwitchWithLabel.vue → ToggleSwitchWithLabel.vue} +5 -7
- package/app/components/05.forms/toggle-switch/{variants/ToggleSwitchWithLabelInline.vue → ToggleSwitchWithLabelInline.vue} +2 -4
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +1 -1
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +4 -1
- package/app/components/05.forms/toggle-switch/{variants/tests → tests}/ToggleSwitchWithLabel.spec.ts +26 -0
- package/app/components/05.forms/triple-toggle-switch/CONSUMER-STYLING.md +75 -62
- package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitch.vue +243 -0
- package/app/components/05.forms/triple-toggle-switch/stories/TripleToggleSwitch.stories.ts +104 -0
- package/app/components/05.forms/triple-toggle-switch/tests/TripleToggleSwitch.spec.ts +138 -0
- package/app/composables/tests/useCancellableTimer.spec.ts +48 -0
- package/app/composables/tests/useMaxChildWidth.spec.ts +67 -0
- package/app/composables/useCancellableTimer.ts +27 -7
- package/app/composables/useMaxChildWidth.ts +4 -6
- package/app/types/app-config.d.ts +10 -0
- package/app/types/components/cookie-consent-banner.d.ts +3 -0
- package/app/types/components/index.ts +6 -1
- package/app/types/components/opening-hours.d.ts +48 -0
- package/app/types/components/price-list.d.ts +11 -0
- package/app/types/components/profile-section.d.ts +6 -0
- package/app/types/components/samaritan-prompt.d.ts +13 -0
- package/app/types/components/services-card.d.ts +9 -0
- package/app/types/components/slider-gallery.d.ts +2 -0
- package/app/types/components/social-icons-list.d.ts +2 -0
- package/app/types/forms/types.forms.d.ts +3 -0
- package/app/types/forms/types.zodFormControl.d.ts +0 -3
- package/app/utils/opening-hours.ts +44 -0
- package/nuxt.config.ts +5 -1
- package/package.json +2 -2
- package/ramps.config.mjs +1 -1
- package/.claude/commands/create-commit-message.md +0 -13
- package/.claude/commands/create-release-notes.md +0 -34
- package/.claude/commands/migrate-component.md +0 -169
- package/.claude/commands/run-commit.md +0 -13
- package/.claude/component-ledger/artifact-url.txt +0 -1
- package/.claude/component-ledger/audit.json +0 -1
- package/.claude/component-ledger/build.mjs +0 -164
- package/.claude/component-ledger/output.html +0 -569
- package/.claude/component-ledger/template.html +0 -569
- package/.claude/hooks/check-component-update.sh +0 -95
- package/.claude/hooks/refresh-component-ledger.sh +0 -32
- package/.claude/settings.json +0 -134
- package/.claude/settings.local.json +0 -38
- package/.claude/skills/components/alert-content-inner.md +0 -60
- package/.claude/skills/components/navigation-horizontal.md +0 -99
- package/.claude/skills/components/samaritan-prompt-mixed.md +0 -139
- package/app/components/01.atoms/content-wrappers/content-columns-2/ContentColumns2.vue +0 -51
- package/app/components/01.atoms/content-wrappers/content-columns-2/stories/ContentColumns2.stories.ts +0 -110
- package/app/components/01.atoms/content-wrappers/content-columns-2/tests/ContentColumns2.spec.ts +0 -105
- package/app/components/01.atoms/content-wrappers/content-columns-2/tests/__snapshots__/ContentColumns2.spec.ts.snap +0 -14
- package/app/components/01.atoms/content-wrappers/content-width/ContentWidth.vue +0 -88
- package/app/components/01.atoms/content-wrappers/content-width/stories/ContentWidth.stories.ts +0 -362
- package/app/components/01.atoms/content-wrappers/content-width/tests/ContentWidth.spec.ts +0 -132
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/tests/__snapshots__/LayoutGrid.spec.ts.snap +0 -36
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/LayoutGridByWidth.vue +0 -70
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/stories/LayoutGridByWidth.stories.ts +0 -220
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/LayoutGridByWidth.spec.ts +0 -174
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/__snapshots__/LayoutGrid.spec.ts.snap +0 -36
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/__snapshots__/LayoutGridByCols.spec.ts.snap +0 -36
- package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/__snapshots__/LayoutGridByWidth.spec.ts.snap +0 -36
- package/app/components/01.atoms/cookie-consent-banner/CookieConsentBanner.vue +0 -148
- package/app/components/01.atoms/display-avatar/DisplayAvatar.vue +0 -130
- package/app/components/01.atoms/display-avatar/tests/__snapshots__/DisplayAvatar.spec.ts.snap +0 -11
- package/app/components/02.molecules/action-menu/tests/__snapshots__/ActionMenuItemCore.spec.ts.snap +0 -27
- package/app/components/02.molecules/navigation/navigation-horizontal/NavigationHorizontal.vue +0 -162
- package/app/components/02.molecules/navigation/navigation-horizontal/stories/NavigationHorizontal.stories.ts +0 -373
- package/app/components/02.molecules/navigation/navigation-horizontal/tests/NavigationHorizontal.spec.ts +0 -152
- package/app/components/02.molecules/navigation/navigation-horizontal/tests/__snapshots__/NavigationHorizontal.spec.ts.snap +0 -17
- package/app/components/02.molecules/qr-code/stories/QrCode.stories.ts +0 -101
- package/app/components/03.organisms/colour-finder/ColourFinder.vue +0 -1519
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue +0 -202
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioWithLabel.vue +0 -105
- package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadioCore.spec.ts +0 -320
- package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +0 -314
- package/app/components/05.forms/triple-toggle-switch/stories/TripleToggleSwitchCore.stories.ts +0 -63
- package/.vscode/{srcdev-component-dialog.code-snippets → srcdev-component-display-dialog.code-snippets} +0 -0
- package/app/components/{01.atoms → 02.molecules}/toast/tests/DisplayToast.spec.ts +1 -1
- /package/app/components/{01.atoms → 02.molecules}/toast/tests/DisplayToastProvider.spec.ts +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-icons-secondary-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-icons-secondary-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-icons-secondary-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-icons-tertiary-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-icons-tertiary-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-icons-tertiary-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-primary-pending-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-primary-pending-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-primary-pending-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-secondary-pill-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-secondary-pill-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-secondary-pill-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-tertiary-readonly-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-tertiary-readonly-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/combo-tertiary-readonly-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-default-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-default-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-default-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-error-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-error-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-error-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-success-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-success-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-success-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-warning-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-warning-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-theme-warning-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-primary-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-primary-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-primary-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-secondary-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-secondary-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-secondary-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-tertiary-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-tertiary-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-variant-tertiary-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/default-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/nuxt-icon-only-component-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/nuxt-icon-only-component-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/nuxt-icon-only-component-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-pending-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-pending-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-pending-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-pill-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-pill-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-pill-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-readonly-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-readonly-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/state-readonly-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/with-both-nuxt-icon-components-chromium-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/with-both-nuxt-icon-components-firefox-darwin.png +0 -0
- /package/app/components/05.forms/input-button/playwright/{input-button-core.playwright.ts-snapshots → input-button.playwright.ts-snapshots}/with-both-nuxt-icon-components-webkit-darwin.png +0 -0
- /package/app/components/05.forms/input-range/{variants/stories → stories}/InputRangeDefault.stories.ts +0 -0
- /package/app/components/05.forms/input-select/{variants/tests → tests}/InputSelectWithLabel.spec.ts +0 -0
- /package/app/components/05.forms/input-textarea/{variants/tests → tests}/InputTextareaWithLabel.spec.ts +0 -0
- /package/app/components/05.forms/toggle-switch/{variants/tests → tests}/ToggleSwitchWithLabelInline.spec.ts +0 -0
- /package/app/types/components/{navigation-horizontal.d.ts → nav-item.d.ts} +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# AlertContent — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
Covers `AlertContent` and its inner `AlertContentInner`. The inner tokens also apply inside
|
|
4
|
+
`AlertMaskedContent`, which has its own guide for its outer shape.
|
|
5
|
+
|
|
6
|
+
## Public token API
|
|
7
|
+
|
|
8
|
+
### Outer shape (`.alert-content`)
|
|
9
|
+
|
|
10
|
+
| Token | Default | Controls |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `--alert-content-accent` | `var(--theme-accent)` | Accent stripe colour (the root's background, showing at the left edge) |
|
|
13
|
+
| `--alert-content-accent-width` | `0.6rem` | Accent stripe width |
|
|
14
|
+
| `--alert-content-border` | `0.1rem solid var(--theme-border)` | Border (shorthand) |
|
|
15
|
+
| `--alert-content-border-radius-start` | `0.8rem` | Left-hand corner radii (also rounds the inner panel) |
|
|
16
|
+
| `--alert-content-border-radius-end` | `0.4rem` | Right-hand corner radii |
|
|
17
|
+
|
|
18
|
+
### Inside (`.alert-content-inner`)
|
|
19
|
+
|
|
20
|
+
| Token | Default | Controls |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `--alert-content-inner-background` | `var(--theme-surface-subtle)` | Panel background |
|
|
23
|
+
| `--alert-content-text-colour` | `var(--theme-text)` | Text colour (icon, title, message and dismiss inherit it) |
|
|
24
|
+
| `--alert-content-padding` | `1.2rem 1.5rem` | Panel padding |
|
|
25
|
+
| `--alert-content-gap` | `1.2rem` | Gap between icon, message column and dismiss button |
|
|
26
|
+
| `--alert-content-icon-colour` | `currentColor` | Theme icon colour |
|
|
27
|
+
| `--alert-content-icon-size` | `2.5rem` | Theme icon size (`font-size`) |
|
|
28
|
+
| `--alert-content-body-gap` | `0.4rem` | Gap between title and message |
|
|
29
|
+
| `--alert-content-title-font-size` | `var(--step-4)` | Title size |
|
|
30
|
+
| `--alert-content-text-font-size` | `var(--step-3)` | Message size |
|
|
31
|
+
| `--alert-content-actions-spacing` | `1.2rem` | Space between the message and the actions row |
|
|
32
|
+
| `--alert-content-actions-gap` | `0.8rem` | Gap between action controls |
|
|
33
|
+
| `--alert-content-actions-justify` | `flex-end` | Horizontal alignment of the actions row (`justify-content`) |
|
|
34
|
+
|
|
35
|
+
### Dismiss button
|
|
36
|
+
|
|
37
|
+
| Token | Default | Controls |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `--alert-content-dismiss-border-colour` | `var(--theme-border)` | Button border |
|
|
40
|
+
| `--alert-content-dismiss-icon-size` | `1.5rem` | Close icon size |
|
|
41
|
+
| `--alert-content-dismiss-background-hover` | `var(--theme-surface-hover)` | Background on hover/focus |
|
|
42
|
+
| `--alert-content-dismiss-colour-hover` | `var(--theme-on-surface)` | Icon colour on hover/focus |
|
|
43
|
+
| `--alert-content-dismiss-ring` | `var(--theme-ring)` | Focus/hover outline colour |
|
|
44
|
+
|
|
45
|
+
> **Changed 2026-09-27**: every value above except `--alert-content-inner-background` was hardcoded
|
|
46
|
+
> (or read a `--theme-*` token directly, CLAUDE.md pitfall #14). Defaults are unchanged apart from
|
|
47
|
+
> the px radii and stripe width, which are now the same sizes in rem. The icon and dismiss colours now
|
|
48
|
+
> inherit the text colour (still `--theme-text` by default) so one token recolours all of it.
|
|
49
|
+
|
|
50
|
+
Private tokens (not public API): `--_radius-start`/`--_radius-end` on `.alert-content`, resolving the
|
|
51
|
+
radius tokens once for the four corners.
|
|
52
|
+
|
|
53
|
+
## State hooks
|
|
54
|
+
|
|
55
|
+
- `data-theme` on `.alert-content`, from the required `theme` prop. It sets the `--theme-*` tokens
|
|
56
|
+
that every default above reads, so it drives all the colours, in light and dark mode.
|
|
57
|
+
- Classes: `.alert-content` > `.alert-content-inner` > `.alert-content-icon` (when `showIcon`),
|
|
58
|
+
`.alert-content-main` > (`.alert-content-body` > `.alert-content-title`, `.alert-content-text`) +
|
|
59
|
+
`.alert-content-actions` (when the `#actions` slot is used), then `.alert-content-dismiss`
|
|
60
|
+
(when `dismissible`).
|
|
61
|
+
- `data-test-id`: `alert-icon`, `alert-title`, `alert-content`, `alert-actions`, `alert-dismiss`.
|
|
62
|
+
|
|
63
|
+
> **Changed 2026-09-27**: `.title`/`.content` renamed to `.alert-content-title`/`.alert-content-text`
|
|
64
|
+
> (generic names collide with site CSS when the alert renders inline). The body and new actions row
|
|
65
|
+
> are wrapped in `.alert-content-main`.
|
|
66
|
+
|
|
67
|
+
## Local overrides
|
|
68
|
+
|
|
69
|
+
Set the tokens above on an element you own (a page or section class, or a plain `class` on the
|
|
70
|
+
component, which falls through to the root `.alert-content`): they inherit down into the component.
|
|
71
|
+
Keep the block **unlayered** (no `@layer` wrapper) so it beats the library's `@layer components`. If
|
|
72
|
+
your own file uses `<style scoped>`, tokens set on your element still work, but selectors that reach
|
|
73
|
+
inside the component need `:deep()`. Patterns and examples:
|
|
74
|
+
`.claude/skills/component-local-style-override.md`.
|
|
75
|
+
|
|
76
|
+
**Caveat:** `.alert-content` sets `data-theme` on itself, so `--theme-*` values set on an ancestor
|
|
77
|
+
don't reach it: the alert always uses its own `theme` prop's palette. Override the `--alert-content-*`
|
|
78
|
+
tokens instead. When it's rendered by `DisplayToast`/`DisplayToastProvider` it's teleported to
|
|
79
|
+
`<body>`, so set tokens globally or through the toast's own hooks rather than on a page wrapper.
|
|
80
|
+
|
|
81
|
+
## Class passthrough
|
|
82
|
+
|
|
83
|
+
No `style-class-passthrough` prop. A plain `class` attribute falls through to the root `.alert-content`
|
|
84
|
+
(`AlertContent` has a single root), which is enough for setting tokens on one instance.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@nuxtjs/storybook";
|
|
2
2
|
import AlertContent from "../AlertContent.vue";
|
|
3
|
+
import InputButton from "../../../05.forms/input-button/InputButton.vue";
|
|
3
4
|
|
|
4
5
|
const meta: Meta<typeof AlertContent> = {
|
|
5
6
|
title: "Molecules/AlertContent",
|
|
@@ -16,6 +17,11 @@ const meta: Meta<typeof AlertContent> = {
|
|
|
16
17
|
description: "Iconify icon name to override the default theme icon",
|
|
17
18
|
table: { category: "Appearance" },
|
|
18
19
|
},
|
|
20
|
+
showIcon: {
|
|
21
|
+
control: "boolean",
|
|
22
|
+
description: "Render the theme icon column",
|
|
23
|
+
table: { category: "Appearance" },
|
|
24
|
+
},
|
|
19
25
|
dismissible: {
|
|
20
26
|
control: "boolean",
|
|
21
27
|
description: "Show a close button (emits 'dismiss' on click)",
|
|
@@ -26,6 +32,7 @@ const meta: Meta<typeof AlertContent> = {
|
|
|
26
32
|
},
|
|
27
33
|
args: {
|
|
28
34
|
theme: "info",
|
|
35
|
+
showIcon: true,
|
|
29
36
|
dismissible: false,
|
|
30
37
|
},
|
|
31
38
|
};
|
|
@@ -129,3 +136,35 @@ export const AllThemes: Story = {
|
|
|
129
136
|
`,
|
|
130
137
|
}),
|
|
131
138
|
};
|
|
139
|
+
|
|
140
|
+
/** Actions — a row of buttons under the message, e.g. for a consent or confirm prompt. */
|
|
141
|
+
export const WithActions: Story = {
|
|
142
|
+
name: "With Actions",
|
|
143
|
+
args: { theme: "info", customIcon: "material-symbols:cookie-outline" },
|
|
144
|
+
render: (args) => ({
|
|
145
|
+
components: { AlertContent, InputButton },
|
|
146
|
+
setup() {
|
|
147
|
+
return { args };
|
|
148
|
+
},
|
|
149
|
+
template: `
|
|
150
|
+
<div :data-theme="args.theme" style="max-width: 600px; padding: 2rem;">
|
|
151
|
+
<AlertContent v-bind="args">
|
|
152
|
+
<template #title>Cookies</template>
|
|
153
|
+
<template #content>This site uses cookies to understand how it's used. You can accept or reject them.</template>
|
|
154
|
+
<template #actions>
|
|
155
|
+
<InputButton type="button" variant="tertiary" button-text="Reject" />
|
|
156
|
+
<InputButton type="button" variant="primary" button-text="Accept" />
|
|
157
|
+
</template>
|
|
158
|
+
</AlertContent>
|
|
159
|
+
</div>
|
|
160
|
+
`,
|
|
161
|
+
}),
|
|
162
|
+
parameters: {
|
|
163
|
+
docs: {
|
|
164
|
+
description: {
|
|
165
|
+
story:
|
|
166
|
+
"The #actions slot renders a wrapping row under the message, outside the aria-live/contentId body so the buttons aren't announced or pulled into aria-describedby. Actions are right-aligned by default (--alert-content-actions-justify). The cookie icon comes from customIcon; set showIcon to false to drop the icon column.",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
@@ -132,4 +132,36 @@ describe("AlertContent", () => {
|
|
|
132
132
|
});
|
|
133
133
|
expect(wrapper.find(".sr-only").text()).toBe("Close");
|
|
134
134
|
});
|
|
135
|
+
|
|
136
|
+
// ─── showIcon / actions (added 2026-09-27) ──────────────────────────────────
|
|
137
|
+
|
|
138
|
+
it("omits the icon region when showIcon is false", async () => {
|
|
139
|
+
const wrapper = await mountSuspended(AlertContent, { props: { theme: "info", showIcon: false } });
|
|
140
|
+
expect(wrapper.find("[data-test-id='alert-icon']").exists()).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("renders the #actions slot in its own row, outside the live/described body", async () => {
|
|
144
|
+
const wrapper = await mountSuspended(AlertContent, {
|
|
145
|
+
props: { theme: "info", contentId: "msg-1", ariaLive: "polite" },
|
|
146
|
+
slots: { content: "Body", actions: '<button type="button" class="act">Do it</button>' },
|
|
147
|
+
});
|
|
148
|
+
const actions = wrapper.find("[data-test-id='alert-actions']");
|
|
149
|
+
expect(actions.exists()).toBe(true);
|
|
150
|
+
expect(actions.find(".act").exists()).toBe(true);
|
|
151
|
+
expect(wrapper.find(".alert-content-body").find(".act").exists()).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("does not render the actions row without the #actions slot", async () => {
|
|
155
|
+
const wrapper = await mountSuspended(AlertContent, { props: { theme: "info" }, slots: { content: "Body" } });
|
|
156
|
+
expect(wrapper.find("[data-test-id='alert-actions']").exists()).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("uses component-prefixed classes for the title and text", async () => {
|
|
160
|
+
const wrapper = await mountSuspended(AlertContent, {
|
|
161
|
+
props: { theme: "info" },
|
|
162
|
+
slots: { title: "T", content: "C" },
|
|
163
|
+
});
|
|
164
|
+
expect(wrapper.find(".alert-content-title").exists()).toBe(true);
|
|
165
|
+
expect(wrapper.find(".alert-content-text").exists()).toBe(true);
|
|
166
|
+
});
|
|
135
167
|
});
|
|
@@ -132,4 +132,36 @@ describe("AlertContentInner", () => {
|
|
|
132
132
|
});
|
|
133
133
|
expect(wrapper.find(".sr-only").text()).toBe("Close");
|
|
134
134
|
});
|
|
135
|
+
|
|
136
|
+
// ─── showIcon / actions (added 2026-09-27) ──────────────────────────────────
|
|
137
|
+
|
|
138
|
+
it("omits the icon region when showIcon is false", async () => {
|
|
139
|
+
const wrapper = await mountSuspended(AlertContentInner, { props: { theme: "info", showIcon: false } });
|
|
140
|
+
expect(wrapper.find("[data-test-id='alert-icon']").exists()).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("renders the #actions slot in its own row, outside the live/described body", async () => {
|
|
144
|
+
const wrapper = await mountSuspended(AlertContentInner, {
|
|
145
|
+
props: { theme: "info", contentId: "msg-1", ariaLive: "polite" },
|
|
146
|
+
slots: { content: "Body", actions: '<button type="button" class="act">Do it</button>' },
|
|
147
|
+
});
|
|
148
|
+
const actions = wrapper.find("[data-test-id='alert-actions']");
|
|
149
|
+
expect(actions.exists()).toBe(true);
|
|
150
|
+
expect(actions.find(".act").exists()).toBe(true);
|
|
151
|
+
expect(wrapper.find(".alert-content-body").find(".act").exists()).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("does not render the actions row without the #actions slot", async () => {
|
|
155
|
+
const wrapper = await mountSuspended(AlertContentInner, { props: { theme: "info" }, slots: { content: "Body" } });
|
|
156
|
+
expect(wrapper.find("[data-test-id='alert-actions']").exists()).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("uses component-prefixed classes for the title and text", async () => {
|
|
160
|
+
const wrapper = await mountSuspended(AlertContentInner, {
|
|
161
|
+
props: { theme: "info" },
|
|
162
|
+
slots: { title: "T", content: "C" },
|
|
163
|
+
});
|
|
164
|
+
expect(wrapper.find(".alert-content-title").exists()).toBe(true);
|
|
165
|
+
expect(wrapper.find(".alert-content-text").exists()).toBe(true);
|
|
166
|
+
});
|
|
135
167
|
});
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
<AlertContentInner
|
|
5
5
|
:theme="theme"
|
|
6
6
|
:custom-icon="customIcon"
|
|
7
|
+
:show-icon="showIcon"
|
|
7
8
|
:dismissible="dismissible"
|
|
8
9
|
:content-id="contentId"
|
|
9
10
|
:aria-live="ariaLive"
|
|
@@ -18,6 +19,9 @@
|
|
|
18
19
|
<template v-if="slots.content" #content>
|
|
19
20
|
<slot name="content"></slot>
|
|
20
21
|
</template>
|
|
22
|
+
<template v-if="slots.actions" #actions>
|
|
23
|
+
<slot name="actions"></slot>
|
|
24
|
+
</template>
|
|
21
25
|
<template v-if="slots.dismissIcon" #dismissIcon>
|
|
22
26
|
<slot name="dismissIcon"></slot>
|
|
23
27
|
</template>
|
|
@@ -35,6 +39,7 @@ import type { SemanticTheme, AlertMaskConfig } from "~/types/components";
|
|
|
35
39
|
interface Props {
|
|
36
40
|
theme: SemanticTheme;
|
|
37
41
|
customIcon?: string;
|
|
42
|
+
showIcon?: boolean;
|
|
38
43
|
dismissible?: boolean;
|
|
39
44
|
contentId?: string;
|
|
40
45
|
ariaLive?: "polite" | "assertive" | "off";
|
|
@@ -43,6 +48,7 @@ interface Props {
|
|
|
43
48
|
|
|
44
49
|
const props = withDefaults(defineProps<Props>(), {
|
|
45
50
|
customIcon: undefined,
|
|
51
|
+
showIcon: true,
|
|
46
52
|
dismissible: false,
|
|
47
53
|
contentId: undefined,
|
|
48
54
|
ariaLive: undefined,
|
|
@@ -55,8 +61,8 @@ const slots = useSlots();
|
|
|
55
61
|
|
|
56
62
|
// Shape matches AlertContent: 8px left radius, 4px right, 6px accent bar on left, 1px border elsewhere
|
|
57
63
|
const resolvedMaskConfig = computed<AlertMaskConfig>(() => ({
|
|
58
|
-
borderColour: "var(--theme-accent)",
|
|
59
|
-
backgroundColour: "
|
|
64
|
+
borderColour: "var(--alert-masked-content-border-colour, var(--theme-accent))",
|
|
65
|
+
backgroundColour: "var(--alert-masked-content-background, color-mix(in oklab, var(--theme-surface-subtle) 80%, transparent))",
|
|
60
66
|
radiusLeft: 8,
|
|
61
67
|
radiusRight: 4,
|
|
62
68
|
borderLeft: 6,
|
|
@@ -70,9 +76,7 @@ const resolvedMaskConfig = computed<AlertMaskConfig>(() => ({
|
|
|
70
76
|
<style lang="css">
|
|
71
77
|
@layer components {
|
|
72
78
|
.alert-masked-content {
|
|
73
|
-
|
|
74
|
-
--_alert-content-inner-bg: transparent;
|
|
75
|
-
}
|
|
79
|
+
--alert-content-inner-background: transparent;
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
82
|
</style>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# AlertMaskedContent — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
`AlertMaskedContent` is `AlertContentInner` (icon, title, body, dismiss button) wrapped in
|
|
4
|
+
`AlertMaskCore`'s SVG mask: an accent-coloured border drawn as a cut-out, and a translucent fill,
|
|
5
|
+
so whatever sits behind the alert stays visible. It's the variant `DisplayToast`
|
|
6
|
+
(`appearance.masked`) and `DisplayPrompt` (`masked`) swap in.
|
|
7
|
+
|
|
8
|
+
## Public token API
|
|
9
|
+
|
|
10
|
+
### Mask colours
|
|
11
|
+
|
|
12
|
+
| Token | Default | Controls |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `--alert-masked-content-border-colour` | `var(--theme-accent)` | Border colour (6px accent bar on the left, 1px elsewhere). |
|
|
15
|
+
| `--alert-masked-content-background` | `color-mix(in oklab, var(--theme-surface-subtle) 80%, transparent)` | Translucent fill behind the content: the theme's own surface colour at 80%, so text contrast matches `AlertContent` in light and dark mode. |
|
|
16
|
+
|
|
17
|
+
These reach the SVG as `fill` styles, so they resolve like any inherited custom property. A
|
|
18
|
+
`maskConfig.borderColour` / `maskConfig.backgroundColour` prop value replaces the token entirely
|
|
19
|
+
for that instance.
|
|
20
|
+
|
|
21
|
+
### Mask geometry
|
|
22
|
+
|
|
23
|
+
Radius and border thickness aren't tokens: `AlertMaskCore` computes the SVG path from them in JS.
|
|
24
|
+
Set them with the `maskConfig` prop (`AlertMaskConfig`). Defaults: `radiusLeft: 8`,
|
|
25
|
+
`radiusRight: 4`, `borderLeft: 6`, `borderTop`/`borderRight`/`borderBottom: 1`.
|
|
26
|
+
|
|
27
|
+
### Content
|
|
28
|
+
|
|
29
|
+
Icon, text and dismiss button styling come from `AlertContentInner` and follow the `data-theme`
|
|
30
|
+
set on the root (`--theme-text`, `--theme-border`, etc.).
|
|
31
|
+
|
|
32
|
+
### Private tokens
|
|
33
|
+
|
|
34
|
+
None of its own. `AlertMaskCore`'s `--_height` / `--_inset-*` are measured plumbing, not public API.
|
|
35
|
+
|
|
36
|
+
## State hooks
|
|
37
|
+
|
|
38
|
+
- `data-theme="info" | "success" | "warning" | "error"` on the root `.alert-masked-content`,
|
|
39
|
+
from the `theme` prop. Drives `--theme-accent` and the content colours.
|
|
40
|
+
- Inner classes: `.alert-mask-core` > `.alert-mask-decorator` (the SVG) + `.alert-mask-content` >
|
|
41
|
+
`.alert-content-inner` > `.alert-content-icon`, `.alert-content-main` > (`.alert-content-body` >
|
|
42
|
+
`.alert-content-title`, `.alert-content-text`) + `.alert-content-actions`, then `.alert-content-dismiss`.
|
|
43
|
+
The inner content tokens (`--alert-content-gap`, `-padding`, `-text-colour`, `-icon-size`, `-title-font-size`,
|
|
44
|
+
`-actions-gap`, the dismiss-button tokens, ...) apply here too; see `AlertContent`'s CONSUMER-STYLING.md.
|
|
45
|
+
Its outer-shape tokens (`--alert-content-accent`, `-border`, `-border-radius-*`, `-accent-width`) don't:
|
|
46
|
+
the masked shape comes from `maskConfig`.
|
|
47
|
+
|
|
48
|
+
> **Changed 2026-09-27**: `.title`/`.content` renamed to `.alert-content-title`/`.alert-content-text`,
|
|
49
|
+
> and body + actions now sit in `.alert-content-main`.
|
|
50
|
+
|
|
51
|
+
## Local overrides
|
|
52
|
+
|
|
53
|
+
Set the tokens above on an element you own (a page or section class, or a plain `class` on
|
|
54
|
+
`<AlertMaskedContent>`, which falls through to the root since there's no passthrough prop): they
|
|
55
|
+
inherit down into the component. Keep the block **unlayered** (no `@layer` wrapper) so it beats the
|
|
56
|
+
library's `@layer components`. If your own file uses `<style scoped>`, tokens set on your element
|
|
57
|
+
still work, but selectors that reach inside the component need `:deep()`. Patterns and examples:
|
|
58
|
+
`.claude/skills/component-local-style-override.md`.
|
|
59
|
+
|
|
60
|
+
**Caveat:** the root sets `--alert-content-inner-background: transparent` on itself, so an
|
|
61
|
+
ancestor value of that token never reaches the masked variant. That's deliberate: an opaque inner
|
|
62
|
+
background would hide the mask. Change the fill with `--alert-masked-content-background` instead.
|
|
63
|
+
|
|
64
|
+
## Class passthrough
|
|
65
|
+
|
|
66
|
+
There's no `styleClassPassthrough` prop. A plain `class` attribute falls through to the root
|
|
67
|
+
`.alert-masked-content` element.
|
|
68
|
+
|
|
69
|
+
## Notes
|
|
70
|
+
|
|
71
|
+
- The default fill is the theme's own surface (`--theme-surface-subtle`) at 80%, matching the
|
|
72
|
+
surface `--theme-text` is designed for, so contrast holds in light and dark mode. Lowering the
|
|
73
|
+
percentage shows more backdrop but costs contrast; check it over your real imagery.
|
package/app/components/02.molecules/alert-masked-content/stories/AlertMaskedContent.stories.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@nuxtjs/storybook";
|
|
2
2
|
import AlertMaskedContent from "../AlertMaskedContent.vue";
|
|
3
|
+
import AlertContent from "../../alert-content/AlertContent.vue";
|
|
3
4
|
|
|
4
5
|
const meta: Meta<typeof AlertMaskedContent> = {
|
|
5
6
|
title: "Molecules/AlertMaskedContent",
|
|
@@ -34,22 +35,18 @@ const meta: Meta<typeof AlertMaskedContent> = {
|
|
|
34
35
|
export default meta;
|
|
35
36
|
type Story = StoryObj<typeof AlertMaskedContent>;
|
|
36
37
|
|
|
37
|
-
const wrapperStyle =
|
|
38
|
-
max-width: 600px;
|
|
39
|
-
padding: 2rem;
|
|
40
|
-
background: linear-gradient(135deg, oklch(40% 0.15 250), oklch(25% 0.1 300));
|
|
41
|
-
border-radius: 8px;
|
|
42
|
-
`;
|
|
38
|
+
const wrapperStyle =
|
|
39
|
+
"max-width: 600px; padding: 2rem; background: linear-gradient(135deg, oklch(40% 0.15 250), oklch(25% 0.1 300)); border-radius: 8px;";
|
|
43
40
|
|
|
44
41
|
/** Default — info theme over a coloured background to show the glass effect. */
|
|
45
42
|
export const Default: Story = {
|
|
46
43
|
render: (args) => ({
|
|
47
44
|
components: { AlertMaskedContent },
|
|
48
45
|
setup() {
|
|
49
|
-
return { args };
|
|
46
|
+
return { args, wrapperStyle };
|
|
50
47
|
},
|
|
51
48
|
template: `
|
|
52
|
-
<div :data-theme="args.theme" :style="
|
|
49
|
+
<div :data-theme="args.theme" :style="wrapperStyle">
|
|
53
50
|
<AlertMaskedContent v-bind="args">
|
|
54
51
|
<template #title>Alert title</template>
|
|
55
52
|
<template #content>This is the alert body. It describes what happened and what the user should do next.</template>
|
|
@@ -65,10 +62,10 @@ export const Dismissible: Story = {
|
|
|
65
62
|
render: (args) => ({
|
|
66
63
|
components: { AlertMaskedContent },
|
|
67
64
|
setup() {
|
|
68
|
-
return { args };
|
|
65
|
+
return { args, wrapperStyle };
|
|
69
66
|
},
|
|
70
67
|
template: `
|
|
71
|
-
<div :data-theme="args.theme" :style="
|
|
68
|
+
<div :data-theme="args.theme" :style="wrapperStyle">
|
|
72
69
|
<AlertMaskedContent v-bind="args">
|
|
73
70
|
<template #title>Dismissible alert</template>
|
|
74
71
|
<template #content>Click the close button to emit the dismiss event.</template>
|
|
@@ -130,3 +127,87 @@ export const BackgroundVariants: Story = {
|
|
|
130
127
|
`,
|
|
131
128
|
}),
|
|
132
129
|
};
|
|
130
|
+
|
|
131
|
+
const busyBackdrop = [
|
|
132
|
+
"repeating-linear-gradient(45deg, oklch(100% 0 0 / 0.18) 0 1.2rem, transparent 1.2rem 2.4rem)",
|
|
133
|
+
"linear-gradient(120deg, oklch(70% 0.2 30), oklch(75% 0.18 90) 35%, oklch(65% 0.2 200) 70%, oklch(55% 0.22 300))",
|
|
134
|
+
].join(", ");
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Over imagery — the mask only reads as a mask with something busy behind it. Each row pairs
|
|
138
|
+
* the plain AlertContent (opaque surface) with AlertMaskedContent over the same backdrop, so the
|
|
139
|
+
* translucent fill and the cut-out accent border are directly comparable.
|
|
140
|
+
*/
|
|
141
|
+
export const OverImagery: Story = {
|
|
142
|
+
name: "Over Imagery (mask in action)",
|
|
143
|
+
args: { theme: "info", dismissible: true },
|
|
144
|
+
render: (args) => ({
|
|
145
|
+
components: { AlertMaskedContent, AlertContent },
|
|
146
|
+
setup() {
|
|
147
|
+
const backdrops = [
|
|
148
|
+
{ label: "Photo", style: "background: url('/images/banners/video/lake-banner.jpg') center / cover;" },
|
|
149
|
+
{ label: "Photo", style: "background: url('/images/page/hero/hero-blonde.jpg') center 30% / cover;" },
|
|
150
|
+
{ label: "Striped gradient", style: `background: ${busyBackdrop};` },
|
|
151
|
+
];
|
|
152
|
+
return { args, backdrops };
|
|
153
|
+
},
|
|
154
|
+
template: `
|
|
155
|
+
<div style="display: grid; gap: 2.4rem; max-width: 110rem;">
|
|
156
|
+
<p style="margin: 0; font-family: sans-serif; font-size: 1.4rem; max-width: 70ch;">
|
|
157
|
+
Left: <strong>AlertContent</strong> (opaque surface). Right: <strong>AlertMaskedContent</strong>:
|
|
158
|
+
the SVG mask draws only the accent border and a translucent fill, so the backdrop stays visible
|
|
159
|
+
through the body and around the border's cut-out.
|
|
160
|
+
</p>
|
|
161
|
+
<div
|
|
162
|
+
v-for="(backdrop, i) in backdrops"
|
|
163
|
+
:key="i"
|
|
164
|
+
:data-theme="args.theme"
|
|
165
|
+
:style="backdrop.style + ' display: grid; grid-template-columns: repeat(auto-fit, minmax(32rem, 1fr)); gap: 2.4rem; padding: 4rem 2.4rem; border-radius: 1.2rem;'"
|
|
166
|
+
>
|
|
167
|
+
<AlertContent v-bind="args">
|
|
168
|
+
<template #title>AlertContent ({{ backdrop.label }})</template>
|
|
169
|
+
<template #content>Opaque surface: nothing behind it shows through.</template>
|
|
170
|
+
</AlertContent>
|
|
171
|
+
<AlertMaskedContent v-bind="args">
|
|
172
|
+
<template #title>AlertMaskedContent ({{ backdrop.label }})</template>
|
|
173
|
+
<template #content>Translucent fill and cut-out border: the backdrop shows through.</template>
|
|
174
|
+
</AlertMaskedContent>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
`,
|
|
178
|
+
}),
|
|
179
|
+
parameters: {
|
|
180
|
+
docs: {
|
|
181
|
+
description: {
|
|
182
|
+
story:
|
|
183
|
+
"Photos and a striped gradient behind each pair. Compare the opaque AlertContent on the left with the masked variant on the right.",
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/** Token overrides — the public colour tokens set on a wrapper you own, over the same busy backdrop. */
|
|
190
|
+
export const TokenOverrides: Story = {
|
|
191
|
+
name: "Token Overrides",
|
|
192
|
+
args: { theme: "warning", dismissible: false },
|
|
193
|
+
render: (args) => ({
|
|
194
|
+
components: { AlertMaskedContent },
|
|
195
|
+
setup() {
|
|
196
|
+
return { args, busyBackdrop };
|
|
197
|
+
},
|
|
198
|
+
template: `
|
|
199
|
+
<div :data-theme="args.theme" :style="'background: ' + busyBackdrop + '; padding: 4rem 2.4rem; border-radius: 1.2rem; display: grid; gap: 2.4rem; max-width: 60rem;'">
|
|
200
|
+
<AlertMaskedContent v-bind="args">
|
|
201
|
+
<template #title>Default tokens</template>
|
|
202
|
+
<template #content>--theme-accent border, --theme-surface-subtle fill at 80%.</template>
|
|
203
|
+
</AlertMaskedContent>
|
|
204
|
+
<div style="--alert-masked-content-border-colour: white; --alert-masked-content-background: color-mix(in oklab, var(--theme-surface-subtle) 55%, transparent);">
|
|
205
|
+
<AlertMaskedContent v-bind="args">
|
|
206
|
+
<template #title>Overridden tokens</template>
|
|
207
|
+
<template #content>White border, fill dropped to 55% so more of the backdrop shows (at some cost to contrast).</template>
|
|
208
|
+
</AlertMaskedContent>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
`,
|
|
212
|
+
}),
|
|
213
|
+
};
|
|
@@ -142,6 +142,26 @@ describe("AlertMaskedContent", () => {
|
|
|
142
142
|
expect(style.getPropertyValue("--_inset-block-end")).toBe("1px");
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
+
it("routes the default mask colours through public tokens", async () => {
|
|
146
|
+
const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
|
|
147
|
+
const paths = wrapper.findAll(".alert-mask-decorator > path");
|
|
148
|
+
expect((paths[0]!.element as unknown as SVGElement).style.fill).toBe(
|
|
149
|
+
"var(--alert-masked-content-border-colour, var(--theme-accent))"
|
|
150
|
+
);
|
|
151
|
+
expect((paths[1]!.element as unknown as SVGElement).style.fill).toBe(
|
|
152
|
+
"var(--alert-masked-content-background, color-mix(in oklab, var(--theme-surface-subtle) 80%, transparent))"
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("lets maskConfig colours replace the token defaults", async () => {
|
|
157
|
+
const wrapper = await mountSuspended(AlertMaskedContent, {
|
|
158
|
+
props: { theme: "info", maskConfig: { borderColour: "red", backgroundColour: "blue" } },
|
|
159
|
+
});
|
|
160
|
+
const paths = wrapper.findAll(".alert-mask-decorator > path");
|
|
161
|
+
expect((paths[0]!.element as unknown as SVGElement).style.fill).toBe("red");
|
|
162
|
+
expect((paths[1]!.element as unknown as SVGElement).style.fill).toBe("blue");
|
|
163
|
+
});
|
|
164
|
+
|
|
145
165
|
it("merges custom maskConfig over defaults", async () => {
|
|
146
166
|
const wrapper = await mountSuspended(AlertMaskedContent, {
|
|
147
167
|
props: { theme: "info", maskConfig: { borderLeft: 12 } },
|
|
@@ -150,4 +170,36 @@ describe("AlertMaskedContent", () => {
|
|
|
150
170
|
const style = (contentEl.element as HTMLElement).style;
|
|
151
171
|
expect(style.getPropertyValue("--_inset-inline-start")).toBe("12px");
|
|
152
172
|
});
|
|
173
|
+
|
|
174
|
+
// ─── showIcon / actions (added 2026-09-27) ──────────────────────────────────
|
|
175
|
+
|
|
176
|
+
it("omits the icon region when showIcon is false", async () => {
|
|
177
|
+
const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info", showIcon: false } });
|
|
178
|
+
expect(wrapper.find("[data-test-id='alert-icon']").exists()).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("renders the #actions slot in its own row, outside the live/described body", async () => {
|
|
182
|
+
const wrapper = await mountSuspended(AlertMaskedContent, {
|
|
183
|
+
props: { theme: "info", contentId: "msg-1", ariaLive: "polite" },
|
|
184
|
+
slots: { content: "Body", actions: '<button type="button" class="act">Do it</button>' },
|
|
185
|
+
});
|
|
186
|
+
const actions = wrapper.find("[data-test-id='alert-actions']");
|
|
187
|
+
expect(actions.exists()).toBe(true);
|
|
188
|
+
expect(actions.find(".act").exists()).toBe(true);
|
|
189
|
+
expect(wrapper.find(".alert-content-body").find(".act").exists()).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("does not render the actions row without the #actions slot", async () => {
|
|
193
|
+
const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" }, slots: { content: "Body" } });
|
|
194
|
+
expect(wrapper.find("[data-test-id='alert-actions']").exists()).toBe(false);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("uses component-prefixed classes for the title and text", async () => {
|
|
198
|
+
const wrapper = await mountSuspended(AlertMaskedContent, {
|
|
199
|
+
props: { theme: "info" },
|
|
200
|
+
slots: { title: "T", content: "C" },
|
|
201
|
+
});
|
|
202
|
+
expect(wrapper.find(".alert-content-title").exists()).toBe(true);
|
|
203
|
+
expect(wrapper.find(".alert-content-text").exists()).toBe(true);
|
|
204
|
+
});
|
|
153
205
|
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# CookieConsentBanner — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
The banner is a fixed, teleported wrapper around `AlertContent`. The panel itself (background, text
|
|
4
|
+
colour, border, radius, padding, accent stripe, icon, title and message sizes, actions alignment) is
|
|
5
|
+
`AlertContent`'s, styled with its `--alert-content-*` tokens: see
|
|
6
|
+
`app/components/02.molecules/alert-content/CONSUMER-STYLING.md`. This guide covers what the banner
|
|
7
|
+
adds: position, motion and the two buttons.
|
|
8
|
+
|
|
9
|
+
> **Changed 2026-09-27**: rebuilt on `AlertContent`. The banner's own panel tokens
|
|
10
|
+
> (`--cookie-consent-banner-padding`, `-gap`, `-border-radius`, `-border`, `-accent-border-width`,
|
|
11
|
+
> `-background`, `-text-colour`, `-actions-gap`) are gone; use the matching `--alert-content-*`
|
|
12
|
+
> tokens. The panel now follows `data-theme` in light and dark mode (a theme-tinted surface) instead
|
|
13
|
+
> of a fixed white panel, with a left accent stripe instead of a top border.
|
|
14
|
+
>
|
|
15
|
+
> Earlier the same day: classes, tokens and `data-test-id`s renamed from `privacy-notice-banner` to
|
|
16
|
+
> `cookie-consent-banner`. The consent cookie's own name (`privacy-notice-consent`, owned by
|
|
17
|
+
> `useCookieConsent`) is unchanged.
|
|
18
|
+
|
|
19
|
+
## Public token API
|
|
20
|
+
|
|
21
|
+
### Position and motion
|
|
22
|
+
|
|
23
|
+
| Token | Default | Controls |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `--cookie-consent-banner-z-index` | `999999` | Stacking order (matches `DisplayDialog`/`DisplayToast`) |
|
|
26
|
+
| `--cookie-consent-banner-gutter` | `1.6rem` | Distance from the viewport's bottom and side edges |
|
|
27
|
+
| `--cookie-consent-banner-max-width` | `64rem` | Maximum width (centred) |
|
|
28
|
+
| `--cookie-consent-banner-transition-duration` | `200ms` | Close fade and button hover transitions |
|
|
29
|
+
|
|
30
|
+
### Buttons
|
|
31
|
+
|
|
32
|
+
| Token | Default | Controls |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `--cookie-consent-banner-accent` | `var(--theme-accent)` | Accept background and reject hover border |
|
|
35
|
+
| `--cookie-consent-banner-button-padding` | `0.8rem 1.6rem` | Button padding |
|
|
36
|
+
| `--cookie-consent-banner-button-border-radius` | `0.4rem` | Button corner radius |
|
|
37
|
+
| `--cookie-consent-banner-focus-ring` | `var(--theme-border-focus)` | `:focus-visible` outline colour on both buttons |
|
|
38
|
+
| `--cookie-consent-banner-reject-border-colour` | `var(--theme-border)` | Reject button border, resting |
|
|
39
|
+
| `--cookie-consent-banner-reject-border-colour-hover` | `var(--cookie-consent-banner-accent)` | Reject button border, hover/focus |
|
|
40
|
+
| `--cookie-consent-banner-accept-background` | `var(--cookie-consent-banner-accent)` | Accept button background |
|
|
41
|
+
| `--cookie-consent-banner-accept-text-colour` | `var(--theme-on-surface)` | Accept button text |
|
|
42
|
+
|
|
43
|
+
The gap between the buttons and their alignment (right by default) are `AlertContent`'s
|
|
44
|
+
`--alert-content-actions-gap` and `--alert-content-actions-justify`.
|
|
45
|
+
|
|
46
|
+
Private tokens (not public API): `--_gutter`, `--_transition-duration`, `--_accent` on the root,
|
|
47
|
+
each resolving a public token once for reuse.
|
|
48
|
+
|
|
49
|
+
## State hooks
|
|
50
|
+
|
|
51
|
+
- `data-theme` on the root and on the inner `.alert-content`, from the `theme` prop or `app.config`
|
|
52
|
+
(default `info`). It drives every `--theme-*` default, for the panel and the buttons.
|
|
53
|
+
- `.closed` on the root once consent is granted or denied. The banner fades out and becomes
|
|
54
|
+
`visibility: hidden`, so its buttons leave the tab order and the accessibility tree.
|
|
55
|
+
- Classes: `.cookie-consent-banner` > `.cookie-consent-banner-inner` (the `role="region"`) >
|
|
56
|
+
`.alert-content` (see its guide for the inner structure); the buttons are
|
|
57
|
+
`.cookie-consent-banner-reject` and `.cookie-consent-banner-accept` inside `.alert-content-actions`.
|
|
58
|
+
- `data-test-id`: `cookie-consent-banner`, `cookie-consent-banner-reject`, `cookie-consent-banner-accept`,
|
|
59
|
+
plus `AlertContent`'s `alert-icon`, `alert-title`, `alert-content`, `alert-actions`.
|
|
60
|
+
|
|
61
|
+
## Motion
|
|
62
|
+
|
|
63
|
+
Closing fades opacity and collapses `grid-template-rows` over the transition duration. Under
|
|
64
|
+
`prefers-reduced-motion: reduce` it closes instantly.
|
|
65
|
+
|
|
66
|
+
## Local overrides
|
|
67
|
+
|
|
68
|
+
Set the tokens above on an element you own (a page or section class, or a class added with
|
|
69
|
+
`:style-class-passthrough`): they inherit down into the component. Keep the block **unlayered** (no
|
|
70
|
+
`@layer` wrapper) so it beats the library's `@layer components`. If your own file uses
|
|
71
|
+
`<style scoped>`, tokens set on your element still work, but selectors that reach inside the
|
|
72
|
+
component need `:deep()`. Patterns and examples: `.claude/skills/component-local-style-override.md`.
|
|
73
|
+
|
|
74
|
+
**Caveat:** the banner is teleported to `<body>`, so tokens set on a page or section wrapper never
|
|
75
|
+
reach it. Set them on `:root`/`html`, on `body`, or on the banner itself through
|
|
76
|
+
`style-class-passthrough`. That includes the `--alert-content-*` panel tokens; setting them on the
|
|
77
|
+
banner scopes them to the banner, leaving other alerts on the page alone.
|
|
78
|
+
|
|
79
|
+
## Recipe: neutral panel
|
|
80
|
+
|
|
81
|
+
The pre-2026-09-27 look (white panel, dark text, no tint), scoped to the banner:
|
|
82
|
+
|
|
83
|
+
```css
|
|
84
|
+
.cookie-consent-banner {
|
|
85
|
+
--alert-content-inner-background: var(--slate-00);
|
|
86
|
+
--alert-content-text-colour: var(--slate-10);
|
|
87
|
+
--alert-content-border: 0.1rem solid var(--slate-10);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Class passthrough
|
|
92
|
+
|
|
93
|
+
`style-class-passthrough` adds classes to the teleported root `.cookie-consent-banner`, next to
|
|
94
|
+
`data-theme` and `.closed`. It's reachable in normal use and is the most reliable place to set
|
|
95
|
+
tokens for this component, since ancestor wrappers don't contain it.
|