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,149 @@
|
|
|
1
|
+
# InputCheckboxRadio Component
|
|
2
|
+
|
|
3
|
+
> **Renamed 2026-09-27**: `InputCheckboxRadioCore` → `InputCheckboxRadio`,
|
|
4
|
+
> `InputCheckboxRadioWithLabel` → `InputCheckboxRadioField`; `InputCheckboxRadioButton` kept its
|
|
5
|
+
> name. Root classes: `.input-checkbox-radio-wrapper` → `.input-checkbox-radio`,
|
|
6
|
+
> `.input-checkbox-radio-with-label` → `.input-checkbox-radio-field`,
|
|
7
|
+
> `.input-checkbox-radio-options-button` → `.input-checkbox-radio-button` (full list in
|
|
8
|
+
> CONSUMER-STYLING.md). Tokens unchanged.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
The single checkbox or radio control that every checkbox and radio in `05.forms` is built from.
|
|
13
|
+
Consumers normally use the group components instead:
|
|
14
|
+
|
|
15
|
+
- `MultipleCheckboxes` / `SingleCheckbox` (`input-checkbox.md`)
|
|
16
|
+
- `MultipleRadiobuttons` (`input-radio.md`)
|
|
17
|
+
|
|
18
|
+
Use these three directly only for a custom group or layout:
|
|
19
|
+
|
|
20
|
+
| Component | Renders | Used by |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `InputCheckboxRadio` | The visual square/circle stacked over a hidden native `<input>`. No label. | The other two |
|
|
23
|
+
| `InputCheckboxRadioField` | `<label>` with the control and a text label | `SingleCheckbox`, non-button `MultipleCheckboxes`/`MultipleRadiobuttons` |
|
|
24
|
+
| `InputCheckboxRadioButton` | `<label>` drawn as a button/pill: control, centred label, decorator icon | `is-button` mode of the group components |
|
|
25
|
+
|
|
26
|
+
```vue
|
|
27
|
+
<InputCheckboxRadioField v-model="state.rememberMe" type="checkbox" name="rememberMe" label="Remember me" />
|
|
28
|
+
|
|
29
|
+
<InputCheckboxRadioButton
|
|
30
|
+
v-for="option in options"
|
|
31
|
+
:id="`service-${option.value}`"
|
|
32
|
+
:key="option.value"
|
|
33
|
+
v-model="state.services"
|
|
34
|
+
type="checkbox"
|
|
35
|
+
name="services"
|
|
36
|
+
:label="option.label"
|
|
37
|
+
:true-value="option.value"
|
|
38
|
+
:multiple-options="true"
|
|
39
|
+
:is-pill="true"
|
|
40
|
+
/>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## InputCheckboxRadio (the control)
|
|
46
|
+
|
|
47
|
+
> **Hyphenation rule**: write camelCase props hyphenated: `:true-value`, `:false-value`, `:multiple-options`, `:field-has-error`, `:aria-describedby`, `:display-as-disc`, `:is-button`, `:input-variant`, `:style-class-passthrough`.
|
|
48
|
+
|
|
49
|
+
| Prop | Type | Default | Notes |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| `type` | `"checkbox" \| "radio"` | required | Can change at runtime: the input is keyed on it, so it's recreated with the right v-model handling. |
|
|
52
|
+
| `id` | `string` | required | Native input id; pair it with a `label[for]`. |
|
|
53
|
+
| `name` | `string` | required | Share one `name` across a radio group. |
|
|
54
|
+
| `:true-value` / `:false-value` | `string \| number \| boolean` | `true` / `false` | Checked / unchecked value. `trueValue` is also the native `value`. |
|
|
55
|
+
| `:multiple-options` | `boolean` | `false` | Part of a checkbox group (array model). Also drops native `required` (a group can't require every box). |
|
|
56
|
+
| `:required` | `boolean` | `false` | Native `required` (unless `multiple-options`). |
|
|
57
|
+
| `:field-has-error` | `boolean` | `false` | `aria-invalid="true"` on the input, `data-invalid` on the root. |
|
|
58
|
+
| `:aria-describedby` | `string` | `""` | On the input, omitted when empty. |
|
|
59
|
+
| `theme` | `FormUiTheme` | `"default"` | `data-theme`. |
|
|
60
|
+
| `:input-variant` | `InputUiVariant` | `"normal"` | `data-input-variant`; `underlined` squares off a checkbox. |
|
|
61
|
+
| `:is-button` | `boolean` | `false` | Set by `InputCheckboxRadioButton`: no focus outline of its own, enables `display-as-disc`. |
|
|
62
|
+
| `:display-as-disc` | `boolean` | `false` | Rounds a checkbox, button mode only. |
|
|
63
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | On the root, reacts to changes. |
|
|
64
|
+
|
|
65
|
+
`v-model` (**required**): a single value, or an array for a checkbox group (the control toggles its
|
|
66
|
+
`trueValue` in and out of the array).
|
|
67
|
+
|
|
68
|
+
Slot: `checkedIcon` replaces the default icon (`material-symbols:check-small`, or
|
|
69
|
+
`material-symbols:circle` for radios) shown when checked.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Variants
|
|
74
|
+
|
|
75
|
+
### InputCheckboxRadioField
|
|
76
|
+
|
|
77
|
+
Same props as the control minus `id`, `isButton`; plus `label?: string` (`""`). Generates its own
|
|
78
|
+
id with `useId()` and links the `<label for>` to it. Slots: `checkedIcon` (forwarded),
|
|
79
|
+
`labelContent` (replaces the `label` text, e.g. a label containing a terms link). Root
|
|
80
|
+
`<label class="input-checkbox-radio-field">` with `data-invalid`.
|
|
81
|
+
|
|
82
|
+
### InputCheckboxRadioButton
|
|
83
|
+
|
|
84
|
+
Same props as the control minus `isButton` (always on), plus:
|
|
85
|
+
|
|
86
|
+
| Prop | Type | Default | Notes |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| `id` | `string` | required | Used for both the input and `label[for]`. |
|
|
89
|
+
| `label` | `string` | `""` | Replaced by the `labelContent` slot when given. |
|
|
90
|
+
| `:options-layout` | `OptionsLayout` | `"equal-widths"` | `data-options-layout`; `inline` stops the label wrapping. |
|
|
91
|
+
| `direction` | `"row" \| "row-reverse"` | `"row"` | `data-direction`; `row-reverse` puts the control on the right. Reacts to changes. |
|
|
92
|
+
| `:is-pill` | `boolean` | `false` | `data-pill`, fully rounded. |
|
|
93
|
+
| `:item-icon` | `string` | `"material-symbols:add-2"` | Decorator icon name. The `itemIcon` slot replaces it entirely. |
|
|
94
|
+
|
|
95
|
+
Slots: `checkedIcon`, `labelContent`, `itemIcon`.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Accessibility
|
|
100
|
+
|
|
101
|
+
- A real native `<input type="checkbox|radio">` does the work: native checked state, keyboard
|
|
102
|
+
(Space; arrow keys within a same-`name` radio group), form validation. It's visually hidden with
|
|
103
|
+
`opacity: 0` and sized to the visible box, so it's still what gets clicked and focused.
|
|
104
|
+
- No `aria-checked` on the input: it's a native checkbox/radio, and ARIA in HTML forbids
|
|
105
|
+
`aria-checked` there (the native state is what's announced).
|
|
106
|
+
- Focus: the control draws an outline on `:has(input:focus-visible)`; the button draws its own
|
|
107
|
+
background and outline change instead.
|
|
108
|
+
- The Field and Button are `<label>` elements, so the whole row is clickable and labels the input.
|
|
109
|
+
The decorator icon is `aria-hidden`.
|
|
110
|
+
- Transitions are off under `prefers-reduced-motion: reduce`.
|
|
111
|
+
- No hardcoded copy; the icon names are props or slots.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Styling
|
|
116
|
+
|
|
117
|
+
Full detail in `app/components/05.forms/input-checkbox-radio/CONSUMER-STYLING.md`. Tokens:
|
|
118
|
+
`--input-checkbox-*` (control colours, label colour/padding, transition duration) and
|
|
119
|
+
`--input-checkbox-button-*` (button colours, radius, pill radius, gap, paddings); shared geometry
|
|
120
|
+
`--input-checked-element-size`, `--input-checked-icon-size`, `--input-checked-icon-gap`,
|
|
121
|
+
`--input-checkbox-decorator-icon-size`. Hooks: `data-type`, `data-input-variant`, `data-theme`,
|
|
122
|
+
`data-button`, `data-display-as-disc`, `data-invalid`, `data-pill`, `data-direction`,
|
|
123
|
+
`data-options-layout`.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## History
|
|
128
|
+
|
|
129
|
+
**Migrated 2026-09-27** (3/5 → full compliance):
|
|
130
|
+
|
|
131
|
+
- Renamed (see top). Every state class became a data attribute (`.error`, `.button`, `.checkbox`,
|
|
132
|
+
`.inline` etc. collided with common consumer CSS).
|
|
133
|
+
- A runtime `type` switch left the checkbox v-model handler attached to the input, so a radio kept
|
|
134
|
+
toggling values in the old array; the input is now keyed on `type`.
|
|
135
|
+
- Removed `aria-checked` from the native input (and the `isChecked` computed that only fed it) and
|
|
136
|
+
the `is-button` input class, which nothing styled.
|
|
137
|
+
- `direction` on the button was copied into a plain `ref` at setup, so changing it did nothing; now
|
|
138
|
+
`data-direction`.
|
|
139
|
+
- The decorator icon and the button's checked icon were sized with `width`/`height` (ignored,
|
|
140
|
+
pitfall #24); now `font-size`, so they change size for the first time.
|
|
141
|
+
- The Field no longer takes `id` or `optionsLayout` (its id is always generated; the layout class
|
|
142
|
+
set a variable nothing read); the group components stopped passing them, so the id no longer
|
|
143
|
+
falls through onto the `<label>`. Removed its non-existent `body-normal*` utility classes.
|
|
144
|
+
`label` is optional on both Field and Button.
|
|
145
|
+
- The button forwards `inputVariant` (the group components already passed it, but it fell through
|
|
146
|
+
as an attribute). New `itemIcon` prop.
|
|
147
|
+
- Button radius, gap, paddings and the Field label colour became tokens; label colour default moved
|
|
148
|
+
from `--colour-text-default` to `--theme-text`. Removed an undeclared `--_box-shadow` and an
|
|
149
|
+
invalid unitless `min-height`.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# MultipleCheckboxes / SingleCheckbox Components
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `input-checkbox` folder holds two ready-to-use checkbox fields. Each renders a `FormFieldset`
|
|
6
|
+
(with `<legend>`), an optional description, the checkbox control(s), and an `InputError` message,
|
|
7
|
+
with `aria-describedby` wired up via `useAriaDescribedById`.
|
|
8
|
+
|
|
9
|
+
- **MultipleCheckboxes**: a group of checkboxes built from a data list (`v-model:field-data`).
|
|
10
|
+
The model is an array of the checked items' values. Each option renders as either a pill/button
|
|
11
|
+
(`InputCheckboxRadioButton`, `:is-button="true"`) or a plain labelled checkbox
|
|
12
|
+
(`InputCheckboxRadioField`, the default).
|
|
13
|
+
- **SingleCheckbox**: one labelled checkbox (e.g. "I agree to the terms"). The model toggles
|
|
14
|
+
between `trueValue` and `falseValue`.
|
|
15
|
+
|
|
16
|
+
For a group where only one option can be chosen, use `MultipleRadiobuttons` (`input-radio`)
|
|
17
|
+
instead.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## MultipleCheckboxes
|
|
22
|
+
|
|
23
|
+
> **Hyphenation rule**: always write camelCase props hyphenated in templates: `:field-has-error`, `:is-button`, `:options-layout`.
|
|
24
|
+
|
|
25
|
+
| Prop (template form) | Type | Default | Notes |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| `name` | `string` | (required) | Shared `name` on every checkbox; also used to build each checkbox `id` (`${name}-${item.value}`) and the error/description ids. |
|
|
28
|
+
| `legend` | `string` | (required) | Fieldset `<legend>` text. |
|
|
29
|
+
| `:error-message` | `string \| object` | (required) | Shown by `InputError` when `fieldHasError` is true. Pass `""` when there's no error. An array renders as a list. |
|
|
30
|
+
| `:field-has-error` | `boolean` | `false` | Shows the error, sets `aria-invalid` on the fieldset and points each checkbox's `aria-describedby` at the error. |
|
|
31
|
+
| `:required` | `boolean` | `false` | No ARIA output: `aria-required` isn't valid on a checkbox group (`role="group"`), so it was dropped from the fieldset 2026-09-26. Signal "required" in the legend text instead (e.g. "Interests (required)"). Native `required` is deliberately **not** put on the individual checkboxes, since that would force every box to be ticked. Validate "at least N selected" in the consuming app. |
|
|
32
|
+
| `:is-button` | `boolean` | `false` | Pill/button presentation (`InputCheckboxRadioButton`) instead of labelled checkboxes. |
|
|
33
|
+
| `:is-pill` | `boolean` | `false` | With `is-button`, fully rounded pills. |
|
|
34
|
+
| `:options-layout` | `OptionsLayout` | `"equal-widths"` | `"equal-widths"` (auto-fit grid, columns sized to the longest label), `"inline"` (wrapping row) or `"block"` (column). Rendered as `data-options-layout` on the items container (was a bare class until 2026-09-27). |
|
|
35
|
+
| `:direction` | `"row" \| "row-reverse"` | `"row"` | Button presentation only: icon/label order. |
|
|
36
|
+
| `:display-as-disc` | `boolean` | `false` | Round checkbox symbol. |
|
|
37
|
+
| `:theme` | `FormUiTheme` | `"default"` | Forwarded to each control. |
|
|
38
|
+
| `:input-variant` | `InputUiVariant` | `"normal"` | Forwarded to each control and the error message. |
|
|
39
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Classes on the root `<fieldset>`. Read once at mount. |
|
|
40
|
+
| `data-testid` | `string` | `"multiple-checkboxes"` | On the root `<fieldset>`. |
|
|
41
|
+
| `label` | `string` | `""` | **Ignored.** Kept only so existing call sites that pass it don't break; it has never rendered. Use `legend` or the description slots. |
|
|
42
|
+
|
|
43
|
+
### v-models
|
|
44
|
+
|
|
45
|
+
- `v-model`: `(string | number | boolean)[]`, **required**. Bind an array (start with `[]`); checked values are added and removed from it.
|
|
46
|
+
- `v-model:field-data`: `IFormMultipleOptions` (`{ data: IOptionsConfig[]; total; skip; limit }`), **required**. Each `data` item's `value` is the checkbox value and `label` its text.
|
|
47
|
+
|
|
48
|
+
### Slots
|
|
49
|
+
|
|
50
|
+
| Slot | Notes |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `descriptionText` / `descriptionHtml` | Description under the legend (via `InputDescription`). |
|
|
53
|
+
| `checkedIcon` | Replaces the checked-state icon in every control. |
|
|
54
|
+
| `itemIcon` | Button presentation only: the trailing decorator icon (default `material-symbols:add-2`). |
|
|
55
|
+
|
|
56
|
+
### Example
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<MultipleCheckboxes
|
|
60
|
+
v-model="state.services"
|
|
61
|
+
v-model:field-data="servicesData"
|
|
62
|
+
name="services"
|
|
63
|
+
legend="Services of interest"
|
|
64
|
+
:error-message="errors.services"
|
|
65
|
+
:field-has-error="!!errors.services"
|
|
66
|
+
options-layout="inline"
|
|
67
|
+
:is-button="true"
|
|
68
|
+
/>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## SingleCheckbox
|
|
74
|
+
|
|
75
|
+
| Prop (template form) | Type | Default | Notes |
|
|
76
|
+
|---|---|---|---|
|
|
77
|
+
| `name` | `string` | (required) | Checkbox `name`; also used for the error/description ids. |
|
|
78
|
+
| `legend` | `string` | (required) | Fieldset `<legend>` text. |
|
|
79
|
+
| `label` | `string` | `""` | Text next to the checkbox. Replaced by the `labelContent` slot when given. |
|
|
80
|
+
| `:error-message` | `string \| object` | (required) | Pass `""` when there's no error. |
|
|
81
|
+
| `:field-has-error` | `boolean` | `false` | Shows the error, sets `aria-invalid` on the fieldset and the checkbox's `aria-describedby`. |
|
|
82
|
+
| `:required` | `boolean` | `false` | Native `required` on the checkbox. (The fieldset no longer gets `aria-required`, see above.) |
|
|
83
|
+
| `:true-value` / `:false-value` | `string \| number \| boolean` | `true` / `false` | Model values for checked/unchecked. |
|
|
84
|
+
| `:options-layout` | `OptionsLayout` | `"equal-widths"` | Rendered as `data-options-layout` on the items container. |
|
|
85
|
+
| `:theme` | `FormUiTheme` | `"default"` | |
|
|
86
|
+
| `:input-variant` | `InputUiVariant` | `"normal"` | |
|
|
87
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Classes on the root `<fieldset>`. Read once at mount. |
|
|
88
|
+
| `data-testid` | `string` | `"single-checkbox"` | On the root `<fieldset>`. |
|
|
89
|
+
|
|
90
|
+
### v-model
|
|
91
|
+
|
|
92
|
+
- `v-model`: `string | number | boolean`, **required**. Toggles between `trueValue` and `falseValue`. Works with `@update:model-value` for save-on-change settings toggles.
|
|
93
|
+
|
|
94
|
+
### Slots
|
|
95
|
+
|
|
96
|
+
`descriptionText` / `descriptionHtml`, `checkedIcon`, and `labelContent` (rich label, e.g. a
|
|
97
|
+
terms link).
|
|
98
|
+
|
|
99
|
+
### Example
|
|
100
|
+
|
|
101
|
+
```vue
|
|
102
|
+
<SingleCheckbox
|
|
103
|
+
v-model="state.terms"
|
|
104
|
+
name="terms"
|
|
105
|
+
legend="Terms and conditions"
|
|
106
|
+
label="I agree to the terms"
|
|
107
|
+
:required="true"
|
|
108
|
+
:error-message="errors.terms"
|
|
109
|
+
:field-has-error="!!errors.terms"
|
|
110
|
+
/>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## CSS token API
|
|
116
|
+
|
|
117
|
+
See [CONSUMER-STYLING.md](../../../app/components/05.forms/input-checkbox/CONSUMER-STYLING.md).
|
|
118
|
+
These components own only the items-container spacing (`--multiple-checkboxes-gap`,
|
|
119
|
+
`--multiple-checkboxes-margin-block-start`, `--single-checkbox-gap`,
|
|
120
|
+
`--single-checkbox-margin-block-start`, `--single-checkbox-column-min-width`). The checkbox
|
|
121
|
+
controls' own colours are the `--input-checkbox-*` tokens in `input-checkbox-radio`.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Migration notes (2026-09-25)
|
|
126
|
+
|
|
127
|
+
Brought to full compliance. Behaviour changes a consumer could notice:
|
|
128
|
+
|
|
129
|
+
- **MultipleCheckboxes no longer puts native `required` on every checkbox.** Previously each box
|
|
130
|
+
got `required`, so a form without `novalidate` would refuse to submit until every option was
|
|
131
|
+
ticked. `InputCheckboxRadioField`/`InputCheckboxRadioButton` now forward `multipleOptions`
|
|
132
|
+
to `InputCheckboxRadio` (they declared it but dropped it), and `MultipleCheckboxes` passes
|
|
133
|
+
`true`.
|
|
134
|
+
- **SingleCheckbox `styleClassPassthrough` now lands on the root `<fieldset>`**, matching
|
|
135
|
+
`MultipleCheckboxes`. It was being applied to the error message.
|
|
136
|
+
- **SingleCheckbox default `data-testid` is now `"single-checkbox"`** (was a copy-paste
|
|
137
|
+
`"multiple-radio-buttons"`).
|
|
138
|
+
- Removed never-used props: `placeholder`, `multipleOptions`, `equalCols` (MultipleCheckboxes);
|
|
139
|
+
`multipleOptions`, `equalCols` (SingleCheckbox). MultipleCheckboxes' `label` became optional
|
|
140
|
+
and stays ignored.
|
|
141
|
+
- Removed SingleCheckbox's dead `watchEffect` that tried to add `mbs-12` to the error message (it
|
|
142
|
+
never reached the DOM, since `InputError` reads its classes once at mount).
|
|
143
|
+
- Both `v-model`s (and `v-model:field-data`) are now `defineModel({ required: true })`.
|
|
144
|
+
- Items-container spacing is now overridable via the public tokens above (defaults unchanged).
|
|
145
|
+
|
|
146
|
+
Fixed 2026-09-26 (FormFieldset migration): the shared `FormFieldset` used to hardcode
|
|
147
|
+
`role="radiogroup"`, so screen readers announced checkbox groups as radio groups. It now defaults
|
|
148
|
+
to the native fieldset `group` role; only `MultipleRadiobuttons` opts into `radiogroup`.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# InputDescription Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`InputDescription` renders a form field's help text. Every `*Field` wrapper in `05.forms`
|
|
6
|
+
(`InputTextWithLabel`, `InputNumberField`, `InputSelectWithLabel`, `InputTextareaWithLabel`,
|
|
7
|
+
`InputRangeDefault`, `InputTextAsNumberWithLabel`, `SingleCheckbox`, `MultipleCheckboxes`,
|
|
8
|
+
`MultipleRadiobuttons`) already renders one and forwards its own `descriptionText` /
|
|
9
|
+
`descriptionHtml` slots into it, so consumers normally just pass those slots to the wrapper:
|
|
10
|
+
|
|
11
|
+
```vue
|
|
12
|
+
<InputTextWithLabel v-model="email" name="email" label="Email" :field-has-error :error-message>
|
|
13
|
+
<template #descriptionText>We'll only use this for your booking confirmation</template>
|
|
14
|
+
</InputTextWithLabel>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use `InputDescription` directly only when building a custom field wrapper.
|
|
18
|
+
|
|
19
|
+
With neither slot provided it renders nothing (no empty element, no dangling id).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Props reference
|
|
24
|
+
|
|
25
|
+
> **Hyphenation rule**: write camelCase props hyphenated in templates: `:description-id`, `:field-has-error`, `:input-variant`, `:style-class-passthrough`.
|
|
26
|
+
|
|
27
|
+
| Prop (template form) | Type | Default | Notes |
|
|
28
|
+
|------|------|---------|-------|
|
|
29
|
+
| `:description-id` | `string` | `""` | Rendered as the root `id`, omitted when empty. Must match the id in the control's `aria-describedby`; wrappers get it from `useAriaDescribedById(...).descriptionId`, which only adds it to `aria-describedby` when a description slot is present. |
|
|
30
|
+
| `:field-has-error` | `boolean` | `false` | Rendered as `data-invalid`. Styling hook only. |
|
|
31
|
+
| `:input-variant` | `"normal" \| "outlined" \| "underlined"` | `"normal"` | Rendered as `data-input-variant`. Styling hook only. |
|
|
32
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root, reacts to prop changes. |
|
|
33
|
+
|
|
34
|
+
## Slots
|
|
35
|
+
|
|
36
|
+
| Slot | Rendered in | Notes |
|
|
37
|
+
|------|-------------|-------|
|
|
38
|
+
| `descriptionHtml` | `<div class="input-description-html">` | Rich markup (lists, links). Rendered first. |
|
|
39
|
+
| `descriptionText` | `<p class="input-description-text">` | Plain text only (it's inside a `<p>`, so no block elements). |
|
|
40
|
+
|
|
41
|
+
**Forwarding slots from a wrapper**: only forward a slot when your own consumer provided it,
|
|
42
|
+
otherwise `InputDescription` sees an (empty) slot and renders an empty element:
|
|
43
|
+
|
|
44
|
+
```vue
|
|
45
|
+
<InputDescription :description-id :input-variant :field-has-error>
|
|
46
|
+
<template v-if="slots.descriptionHtml" #descriptionHtml><slot name="descriptionHtml"></slot></template>
|
|
47
|
+
<template v-if="slots.descriptionText" #descriptionText><slot name="descriptionText"></slot></template>
|
|
48
|
+
</InputDescription>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Accessibility
|
|
54
|
+
|
|
55
|
+
- It's a plain description, not a live region: link it with `aria-describedby` on the control
|
|
56
|
+
(`useAriaDescribedById` does this in every wrapper).
|
|
57
|
+
- `InputTextWithLabel`, `InputSelectWithLabel` and `InputTextareaWithLabel` render it **after**
|
|
58
|
+
the control for the `outlined` variant and before it otherwise; both positions carry the same id.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Styling
|
|
63
|
+
|
|
64
|
+
Full token table in `app/components/05.forms/input-description/CONSUMER-STYLING.md`. Public
|
|
65
|
+
tokens: `--input-description-color`, `--input-description-font-size`,
|
|
66
|
+
`--input-description-line-height`, `--input-description-slot-margin-block-start|end`,
|
|
67
|
+
`--input-description-slot-margin-inline`; panel tokens on the root (matching `FormFieldset`):
|
|
68
|
+
`--input-description-background-color`, `--input-description-margin-block|inline`,
|
|
69
|
+
`--input-description-padding-block|inline`, `--input-description-border`,
|
|
70
|
+
`--input-description-border-radius`, `--input-description-outline|outline-offset`. For a callout
|
|
71
|
+
look, zero the slot margins and space it with the root margins (example in CONSUMER-STYLING.md). Hooks:
|
|
72
|
+
`data-input-variant`, `data-invalid`.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## History
|
|
78
|
+
|
|
79
|
+
**Migrated 2026-09-26** (1/5 → full compliance):
|
|
80
|
+
|
|
81
|
+
- Wrappers forwarded both description slots unconditionally, so every field rendered an empty
|
|
82
|
+
description element (with its id) even when no description was given. Each wrapper now forwards
|
|
83
|
+
a slot only when its own consumer supplied it.
|
|
84
|
+
- `InputTextWithLabel` and `InputSelectWithLabel` rendered the description **twice** for the
|
|
85
|
+
`outlined` variant (before and after the control); the first copy now has
|
|
86
|
+
`v-if="inputVariant !== 'outlined'"`, matching `InputTextareaWithLabel`.
|
|
87
|
+
- The outlined-variant copies had no `description-id`, so the control's `aria-describedby`
|
|
88
|
+
pointed at an id that didn't exist. They now pass it.
|
|
89
|
+
- Removed props that were never read: `id` (a leftover from a commented-out id computation) and
|
|
90
|
+
`theme`. Wrappers also stopped passing `name`, which wasn't a prop and fell through as an
|
|
91
|
+
invalid `name` attribute on the `<div>`.
|
|
92
|
+
- `inputVariant` and `fieldHasError` (previously accepted but unused) now render as
|
|
93
|
+
`data-input-variant` / `data-invalid` styling hooks.
|
|
94
|
+
- Colour read `--form-description-color`, which was never declared anywhere; replaced by
|
|
95
|
+
`--input-description-color` (defaults to `inherit`, same visual result). Font size, line height
|
|
96
|
+
and margins promoted to public tokens with the old values as defaults.
|
|
97
|
+
- Added root panel tokens (background, margin, padding, border, radius, outline) matching
|
|
98
|
+
`FormFieldset`. Removed `InputLabel`'s `.input-label + .input-description { margin-block-end: 0.2rem }`
|
|
99
|
+
rule, which overrode the root margin token (no visual change by default: the slot's `0.8rem`
|
|
100
|
+
bottom margin collapsed through and won anyway).
|
|
101
|
+
- An empty `descriptionId` no longer renders `id=""`. `styleClassPassthrough` now reacts to prop
|
|
102
|
+
changes.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# InputError Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`InputError` renders the red error message strip under a form control. Every `*Field` wrapper in
|
|
6
|
+
`05.forms` (`InputTextWithLabel`, `InputNumberField`, `InputSelectWithLabel`, `InputTextareaWithLabel`,
|
|
7
|
+
`InputRangeDefault`, `ToggleSwitchWithLabel`, `SingleCheckbox`, `MultipleCheckboxes`,
|
|
8
|
+
`MultipleRadiobuttons`, `InputTextAsNumberWithLabel`) already renders one, so consumers rarely use
|
|
9
|
+
it directly. Use it yourself only when building a custom field wrapper.
|
|
10
|
+
|
|
11
|
+
It is designed to sit in **grid row 2** of the wrapper, directly under the control in row 1: it is
|
|
12
|
+
translated up by the control's border width + radius so an attached error tucks under the
|
|
13
|
+
control's bottom edge. It opens with a `grid-template-rows: 0fr → 1fr` + opacity transition.
|
|
14
|
+
|
|
15
|
+
Its root carries `data-theme="error"`, so the red `--theme-*` ramp applies inside it regardless of
|
|
16
|
+
the surrounding theme.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Props reference
|
|
21
|
+
|
|
22
|
+
> **Hyphenation rule**: write camelCase props hyphenated in templates: `:error-message`, `:show-error`, `:is-detached`, `:input-variant`, `:style-class-passthrough`.
|
|
23
|
+
|
|
24
|
+
| Prop (template form) | Type | Default | Notes |
|
|
25
|
+
|------|------|---------|-------|
|
|
26
|
+
| `:id` | `string` | (required) | Must match an id in the control's `aria-describedby` while in error. Wrappers get it from `useAriaDescribedById(...).errorId`, which only adds it to `aria-describedby` when `fieldHasError` is true. |
|
|
27
|
+
| `:error-message` | `string \| string[] \| object` | (required) | A string renders as one message; an array renders as a `<ul>` list. |
|
|
28
|
+
| `:show-error` | `boolean` | (required) | Opens the strip. Rendered as `data-visible`; when `false` the root gets `aria-hidden="true"`. |
|
|
29
|
+
| `:is-detached` | `boolean` | (required) | `true`: sits below the control with a `2rem` gap, fully rounded. `false`: tucked under the control's bottom edge. Rendered as `data-detached`. |
|
|
30
|
+
| `:input-variant` | `"normal" \| "outlined" \| "underlined"` | `"normal"` | Match the control's variant. Rendered as `data-input-variant`. `underlined` drops the rounded corners and (when attached) the outline. |
|
|
31
|
+
| `icon` | `string` | `"radix-icons:circle-backslash"` | Iconify name for the decorative icon (`aria-hidden`). |
|
|
32
|
+
| `data-testid` | `string` | `"inputError"` | |
|
|
33
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root, reacts to prop changes. |
|
|
34
|
+
|
|
35
|
+
No slots.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Usage (inside a custom field wrapper)
|
|
40
|
+
|
|
41
|
+
```vue
|
|
42
|
+
<template>
|
|
43
|
+
<div class="my-field">
|
|
44
|
+
<input :id :aria-describedby :aria-invalid="fieldHasError" />
|
|
45
|
+
<InputError :id="errorId" :error-message :show-error="fieldHasError" :is-detached="false" :input-variant />
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script setup lang="ts">
|
|
50
|
+
const { id, errorId, ariaDescribedby } = useAriaDescribedById(props.name, toRef(props, "fieldHasError"), useSlots());
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<style>
|
|
54
|
+
.my-field {
|
|
55
|
+
display: grid;
|
|
56
|
+
grid-template-rows: auto auto;
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Accessibility
|
|
64
|
+
|
|
65
|
+
- The message is exposed through the control's `aria-describedby`, not a live region, so it's
|
|
66
|
+
read when the control is focused. Moving focus to the first invalid field on submit is the
|
|
67
|
+
form's job (see `FormWrapper` / pattern forms).
|
|
68
|
+
- Hidden errors are `aria-hidden="true"`; the icon is always `aria-hidden`.
|
|
69
|
+
- The open/close transition is disabled under `prefers-reduced-motion: reduce`.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Styling
|
|
74
|
+
|
|
75
|
+
Full token table in `app/components/05.forms/form-errors/CONSUMER-STYLING.md`. Public tokens:
|
|
76
|
+
`--input-error-text-color`, `--input-error-icon-color`, `--input-error-icon-size`,
|
|
77
|
+
`--input-error-background-color`, `--input-error-border-color`, `--input-error-outline-color`,
|
|
78
|
+
`--input-error-border-radius`, `--input-error-font-family|size|weight`,
|
|
79
|
+
`--input-error-padding-inline`, `--input-error-padding-block-start|end`, `--input-error-list-gap`,
|
|
80
|
+
`--input-error-detached-offset`, `--input-error-margin-block-start`,
|
|
81
|
+
`--input-error-transition-duration`.
|
|
82
|
+
|
|
83
|
+
Set them on an ancestor, not the global `--theme-error-*` tokens: the root's `data-theme="error"`
|
|
84
|
+
re-declares those on the element itself, so ancestor overrides of them never land.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## History
|
|
89
|
+
|
|
90
|
+
**Migrated 2026-09-26** (1/5 → full compliance):
|
|
91
|
+
|
|
92
|
+
- State moved from bare classes (`.show`, `.detached`, `.normal`/`.outlined`/`.underlined`) to
|
|
93
|
+
`data-visible`, `data-detached`, `data-input-variant`; inner elements renamed from generic
|
|
94
|
+
`.inner`/`.inner-content`/`.inner-icon`/`.icon`/`.message`/`.message-*` to
|
|
95
|
+
`.input-error-message-*`. It renders inline in the consumer's DOM, so those names collided with
|
|
96
|
+
consumer CSS (pitfall #16).
|
|
97
|
+
- Removed the unused `compact` prop (declared, never read, never passed).
|
|
98
|
+
- Added the `icon` prop.
|
|
99
|
+
- Removed dead CSS: detached-state border colours (including a hardcoded `--red-08` bottom border)
|
|
100
|
+
only applied while hidden at `opacity: 0` and were overridden by the visible-state border, and a
|
|
101
|
+
top-level `.underlined` outline rule that the visible state always overrode.
|
|
102
|
+
- Hardcoded `white` on the icon and list items replaced by the text-colour token (same default).
|
|
103
|
+
Hardcoded font size/weight, padding, list gap and detached gap promoted to public tokens.
|
|
104
|
+
- `aria-hidden` now omitted when visible (was `"false"`); icon marked `aria-hidden`;
|
|
105
|
+
`prefers-reduced-motion` respected; `styleClassPassthrough` now reacts to prop changes.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# InputLabel Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`InputLabel` renders a form field's `<label>`. Every labelled wrapper in `05.forms`
|
|
6
|
+
(`InputTextWithLabel`, `InputTextAsNumberWithLabel`, `InputNumberField`, `InputSelectWithLabel`,
|
|
7
|
+
`InputTextareaWithLabel`, `InputRangeDefault`, `ToggleSwitchWithLabel`,
|
|
8
|
+
`ToggleSwitchWithLabelInline`) already renders one from its `label` prop, so consumers normally
|
|
9
|
+
never use it directly.
|
|
10
|
+
|
|
11
|
+
Use `InputLabel` directly only when building a custom field wrapper:
|
|
12
|
+
|
|
13
|
+
```vue
|
|
14
|
+
<InputLabel :id="inputId" :input-variant :field-has-error>
|
|
15
|
+
<template #textLabel>{{ label }}</template>
|
|
16
|
+
</InputLabel>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Props reference
|
|
22
|
+
|
|
23
|
+
> **Hyphenation rule**: write camelCase props hyphenated in templates: `:required-text`, `:optional-icon`, `:field-has-error`, `:input-variant`, `:style-class-passthrough`.
|
|
24
|
+
|
|
25
|
+
| Prop (template form) | Type | Default | Notes |
|
|
26
|
+
|------|------|---------|-------|
|
|
27
|
+
| `:id` | `string` | required | The **control's** id, rendered as the label's `for`. The label itself gets no id. Must match the id actually on the `<input>`/`<select>`/`<textarea>` (e.g. `ToggleSwitchCore` prefixes its input id with `toggle-switch-`, so its wrappers pass `toggleSwitchId`). |
|
|
28
|
+
| `:required` | `boolean` | `false` | Whether the field is required. Only decides which fields the indicator marks; it doesn't set `required` on the control. Wrappers forward their own `required`. |
|
|
29
|
+
| `:indicator` | `"none" \| "required" \| "optional"` | `undefined` → app.config → `"none"` | Which fields get a marker. |
|
|
30
|
+
| `:required-text` | `string` | `undefined` → app.config → `"*"` | Required marker text. |
|
|
31
|
+
| `:optional-text` | `string` | `undefined` → app.config → `"(optional)"` | Optional marker text (translatable). |
|
|
32
|
+
| `:required-icon` | `string` | `undefined` → app.config → none | Iconify name that replaces the required text. |
|
|
33
|
+
| `:optional-icon` | `string` | `undefined` → app.config → none | Iconify name that replaces the visible optional text (the text stays as `.sr-only`). |
|
|
34
|
+
| `:field-has-error` | `boolean` | `false` | Rendered as `data-invalid`. Styling hook only. |
|
|
35
|
+
| `:input-variant` | `"normal" \| "outlined" \| "underlined"` | `"normal"` | Rendered as `data-input-variant`. Styling hook only. |
|
|
36
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the `<label>`, reacts to prop changes. |
|
|
37
|
+
|
|
38
|
+
## Slots
|
|
39
|
+
|
|
40
|
+
| Slot | Notes |
|
|
41
|
+
|------|-------|
|
|
42
|
+
| `htmlLabel` | Rich markup (e.g. a required marker). Rendered first. Phrasing content only: it's inside a `<label>`, so no interactive elements. |
|
|
43
|
+
| `textLabel` | Plain label text. |
|
|
44
|
+
|
|
45
|
+
Both render directly inside the `<label>`, no wrapper elements. Don't hardcode a required
|
|
46
|
+
asterisk in a slot: use the indicator below.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Required / optional indicator
|
|
51
|
+
|
|
52
|
+
Resolution for every indicator prop: **explicit prop → `app.config` `srcdev.inputLabel.*` → fallback**.
|
|
53
|
+
Consumers normally set it once site-wide and never touch the props:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
// consumer app.config.ts
|
|
57
|
+
export default defineAppConfig({
|
|
58
|
+
srcdev: { inputLabel: { indicator: "required", requiredIcon: "mdi:asterisk" } },
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- `"required"` mode: a marker on fields with `required`; `"optional"` mode: a marker on fields
|
|
63
|
+
without it; `"none"`: nothing (default, so existing sites are unchanged).
|
|
64
|
+
- `InputTextWithLabel`, `InputTextAsNumberWithLabel`, `InputNumberField`, `InputSelectWithLabel`,
|
|
65
|
+
`InputTextareaWithLabel` and `InputRangeDefault` forward `:required`.
|
|
66
|
+
`ToggleSwitchWithLabel`/`ToggleSwitchWithLabelInline` pass `indicator="none"`: a switch always
|
|
67
|
+
has a value, so neither marker means anything there.
|
|
68
|
+
- The wrappers don't expose the indicator props per field; use `app.config`.
|
|
69
|
+
- Text props are the i18n hook: pass translated `optionalText`/`requiredText` (or set them in
|
|
70
|
+
`app.config`).
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Accessibility
|
|
75
|
+
|
|
76
|
+
- The `for`/`id` pairing is the accessible name for the control. If the ids don't match, the
|
|
77
|
+
control has no name and clicking the label does nothing; check this whenever the control
|
|
78
|
+
component derives its own id from the one you pass it.
|
|
79
|
+
- The required marker is `aria-hidden`: the control's own `required` attribute is what screen
|
|
80
|
+
readers announce, so the control must actually carry it. The optional marker is announced, and
|
|
81
|
+
keeps its text as `.sr-only` when an icon replaces it.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Styling
|
|
86
|
+
|
|
87
|
+
Full token table in `app/components/05.forms/input-label/CONSUMER-STYLING.md`. Public tokens:
|
|
88
|
+
`--input-label-color` (defaults to `inherit`),
|
|
89
|
+
`--input-label-font-size`, `--input-label-font-weight`, `--input-label-line-height`,
|
|
90
|
+
`--input-label-margin-block`, `--input-label-margin-inline`; indicator:
|
|
91
|
+
`--input-label-indicator-color[-required|-optional]`, `--input-label-indicator-font-size[-required|-optional]`,
|
|
92
|
+
`--input-label-indicator-font-weight`, `--input-label-indicator-gap`, `--input-label-indicator-icon-size`.
|
|
93
|
+
Hooks: `data-input-variant`, `data-invalid`, `.input-label-indicator[data-indicator]`.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## History
|
|
98
|
+
|
|
99
|
+
**Migrated 2026-09-26** (1/5 → full compliance):
|
|
100
|
+
|
|
101
|
+
- Removed props that were never read: `name` and `theme`. Wrappers stopped passing them.
|
|
102
|
+
- Wrappers also passed a non-prop `:for`, which fell through and overrode the `for` built from
|
|
103
|
+
`id`. For the text/number/select/textarea/range wrappers it was the same value (dropped). For
|
|
104
|
+
`ToggleSwitchWithLabel`/`ToggleSwitchWithLabelInline` it was the only thing pointing the label
|
|
105
|
+
at the real input (`toggle-switch-<id>`); they now pass `:id="toggleSwitchId"` explicitly.
|
|
106
|
+
- `inputVariant` moved from a bare class (`.normal`/`.underlined`, whose rules were duplicates of
|
|
107
|
+
the base rule) to `data-input-variant`. `fieldHasError` (accepted but unused) now renders
|
|
108
|
+
`data-invalid`.
|
|
109
|
+
- Colour, font size, font weight, line height and margins are public tokens with the old values
|
|
110
|
+
as defaults. The colour used to read `--form-label-color`, never declared in this library;
|
|
111
|
+
replaced by `--input-label-color` (defaults to `inherit`, same visual result).
|
|
112
|
+
- Removed the unused `--field-label-*`, `--field-description-*`, `--field-error-*` and
|
|
113
|
+
`--input-line-height` globals from `04.elements/forms/02.typography.css`, left over from before
|
|
114
|
+
the per-component token pattern.
|
|
115
|
+
- `styleClassPassthrough` now reacts to prop changes.
|
|
116
|
+
|
|
117
|
+
**2026-09-27**: added the required/optional indicator (`required`, `indicator`, `requiredText`,
|
|
118
|
+
`optionalText`, `requiredIcon`, `optionalIcon`, all app.config-backed under `srcdev.inputLabel`),
|
|
119
|
+
with wrappers forwarding `:required`.
|