srcdev-nuxt-components 9.4.10 → 9.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/.claude/commands/migrate-component.md +18 -0
  2. package/.claude/component-ledger/audit.json +1 -1
  3. package/.claude/component-ledger/output.html +1 -1
  4. package/.claude/skills/components/input-number-core.md +214 -0
  5. package/.claude/skills/components/input-select-core.md +151 -0
  6. package/.claude/skills/components/input-text-core.md +16 -0
  7. package/.claude/skills/components/input-textarea-core.md +154 -0
  8. package/.claude/skills/components/select-menu.md +195 -0
  9. package/.claude/skills/components/toggle-switch-core.md +150 -0
  10. package/.claude/skills/index.md +5 -0
  11. package/.vscode/srcdev-component-input-number.code-snippets +65 -0
  12. package/.vscode/srcdev-component-input-select.code-snippets +42 -0
  13. package/.vscode/srcdev-component-input-textarea.code-snippets +40 -0
  14. package/.vscode/srcdev-component-select-menu.code-snippets +65 -0
  15. package/.vscode/srcdev-component-toggle-switch.code-snippets +49 -0
  16. package/app/components/01.atoms/animations/container-glow/CONSUMER-STYLING.md +1 -1
  17. package/app/components/01.atoms/animations/container-glow/ContainerGlow.vue +1 -1
  18. package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +1 -1
  19. package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +1 -1
  20. package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +1 -1
  21. package/app/components/01.atoms/animations/section-parallax/CONSUMER-STYLING.md +1 -1
  22. package/app/components/01.atoms/animations/section-parallax/SectionParallax.vue +1 -1
  23. package/app/components/01.atoms/canvas-switcher/CONSUMER-STYLING.md +2 -2
  24. package/app/components/01.atoms/canvas-switcher/CanvasSwitcher.vue +2 -2
  25. package/app/components/01.atoms/card/CardCore.vue +4 -4
  26. package/app/components/01.atoms/clipped-panel/CONSUMER-STYLING.md +2 -2
  27. package/app/components/01.atoms/clipped-panel/ClippedPanel.vue +2 -2
  28. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/CONSUMER-STYLING.md +2 -2
  29. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/DashboardQuadGrid.vue +2 -2
  30. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/stories/DashboardQuadGrid.stories.ts +1 -1
  31. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/CONSUMER-STYLING.md +1 -1
  32. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/DashboardStatsGrid.vue +1 -1
  33. package/app/components/01.atoms/display-tooltip/CONSUMER-STYLING.md +8 -8
  34. package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +8 -8
  35. package/app/components/01.atoms/pop-over/CONSUMER-STYLING.md +6 -6
  36. package/app/components/01.atoms/pop-over/PopOver.vue +6 -6
  37. package/app/components/02.molecules/navigation/deep-expanding-menu/CONSUMER-STYLING.md +1 -1
  38. package/app/components/02.molecules/navigation/deep-expanding-menu/DeepExpandingMenu.vue +1 -1
  39. package/app/components/02.molecules/navigation/deep-expanding-menu-classic/CONSUMER-STYLING.md +1 -1
  40. package/app/components/02.molecules/navigation/deep-expanding-menu-classic/DeepExpandingMenuClassic.vue +1 -1
  41. package/app/components/02.molecules/pricing-card/CONSUMER-STYLING.md +11 -0
  42. package/app/components/02.molecules/pricing-card/PricingCard.vue +3 -1
  43. package/app/components/02.molecules/pricing-card/stories/PricingCard.stories.ts +2 -0
  44. package/app/components/02.molecules/pricing-card/tests/PricingCard.spec.ts +13 -0
  45. package/app/components/02.molecules/select-menu/CONSUMER-STYLING.md +168 -0
  46. package/app/components/02.molecules/select-menu/SelectMenu.vue +384 -0
  47. package/app/components/02.molecules/select-menu/stories/SelectMenu.stories.ts +359 -0
  48. package/app/components/02.molecules/select-menu/tests/SelectMenu.spec.ts +476 -0
  49. package/app/components/02.molecules/select-menu/tests/__snapshots__/SelectMenu.spec.ts.snap +42 -0
  50. package/app/components/03.organisms/image-galleries/carousel-flip/CONSUMER-STYLING.md +3 -3
  51. package/app/components/03.organisms/image-galleries/carousel-flip/CarouselFlip.vue +3 -3
  52. package/app/components/03.organisms/image-galleries/carousel-flip/stories/CarouselFlip.stories.ts +18 -18
  53. package/app/components/05.forms/input-button/CONSUMER-STYLING.md +2 -7
  54. package/app/components/05.forms/input-button/InputButtonCore.vue +1 -5
  55. package/app/components/05.forms/input-number/CONSUMER-STYLING.md +26 -6
  56. package/app/components/05.forms/input-number/InputNumberCore.vue +125 -85
  57. package/app/components/05.forms/input-number/stories/InputNumberCore.stories.ts +92 -0
  58. package/app/components/05.forms/input-number/tests/InputNumberCore.spec.ts +119 -0
  59. package/app/components/05.forms/input-number/variants/InputNumberDefault.vue +30 -22
  60. package/app/components/05.forms/input-number/variants/stories/InputNumberDefault.stories.ts +123 -0
  61. package/app/components/05.forms/input-number/variants/tests/InputNumberDefault.spec.ts +143 -0
  62. package/app/components/05.forms/input-range/CONSUMER-STYLING.md +2 -2
  63. package/app/components/05.forms/input-range/InputRangeCore.vue +2 -2
  64. package/app/components/05.forms/input-select/InputSelectCore.vue +23 -30
  65. package/app/components/05.forms/input-select/stories/InputSelectCore.stories.ts +2 -2
  66. package/app/components/05.forms/input-select/stories/InputSelectWithLabel.stories.ts +115 -0
  67. package/app/components/05.forms/input-select/tests/InputSelectCore.spec.ts +129 -0
  68. package/app/components/05.forms/input-select/variants/InputSelectWithLabel.vue +1 -1
  69. package/app/components/05.forms/input-select/variants/tests/InputSelectWithLabel.spec.ts +87 -0
  70. package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +14 -0
  71. package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +1 -1
  72. package/app/components/05.forms/input-textarea/CONSUMER-STYLING.md +55 -0
  73. package/app/components/05.forms/input-textarea/InputTextareaCore.vue +24 -16
  74. package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +1 -1
  75. package/app/components/05.forms/input-textarea/tests/InputTextareaCore.spec.ts +119 -0
  76. package/app/components/05.forms/input-textarea/variants/InputTextareaWithLabel.vue +3 -13
  77. package/app/components/05.forms/input-textarea/variants/tests/InputTextareaWithLabel.spec.ts +93 -0
  78. package/app/components/05.forms/patterns/stories/MigratedFieldsForm.stories.ts +95 -10
  79. package/app/components/05.forms/toggle-switch/CONSUMER-STYLING.md +29 -0
  80. package/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue +120 -119
  81. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchCore.stories.ts +1 -1
  82. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +1 -1
  83. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +2 -2
  84. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchCore.spec.ts +101 -0
  85. package/app/components/05.forms/toggle-switch/variants/ToggleSwitchWithLabel.vue +3 -5
  86. package/app/components/05.forms/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +1 -2
  87. package/app/components/05.forms/toggle-switch/variants/tests/ToggleSwitchWithLabel.spec.ts +77 -0
  88. package/app/components/05.forms/toggle-switch/variants/tests/ToggleSwitchWithLabelInline.spec.ts +66 -0
  89. package/app/components/05.forms/triple-toggle-switch/CONSUMER-STYLING.md +4 -4
  90. package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +6 -6
  91. package/app/types/components/index.ts +1 -0
  92. package/app/types/components/select-menu.d.ts +5 -0
  93. package/package.json +1 -1
  94. package/.vscode/srcdev-component-toggle-switch-core.code-snippets +0 -13
@@ -291,7 +291,7 @@ onUnmounted(() => {
291
291
  flex-shrink: 0;
292
292
 
293
293
  border: var(--marquee-scroller-item-border-width, 1px) solid
294
- var(--marquee-scroller-item-border-colour, light-dark(var(--slate-10), var(--slate-00)));
294
+ var(--marquee-scroller-item-border-colour, var(--slate-10));
295
295
  border-radius: var(--marquee-scroller-item-border-radius, 4px);
296
296
 
297
297
  &:hover {
@@ -33,7 +33,7 @@ const logoSlots = logoData
33
33
  .map(
34
34
  (item) => `
35
35
  <template #${item.id}>
36
- <div style="display: grid; place-items: center; width: 100%; height: 100%; background: light-dark(#eee, #333); font-weight: 600;">
36
+ <div style="display: grid; place-items: center; width: 100%; height: 100%; background: #eee; font-weight: 600;">
37
37
  ${item.content}
38
38
  </div>
39
39
  </template>`
@@ -8,7 +8,7 @@
8
8
  | `--section-parallax-min-height-fixed` | `120vh` | Section height once the parallax effect is active — taller than the base height to give enough scroll travel to see the motion. |
9
9
  | `--section-parallax-background-position` | `center` | `background-position` of the image. |
10
10
  | `--section-parallax-background-size` | `cover` | `background-size` of the image. |
11
- | `--section-parallax-background-colour` | `light-dark(var(--slate-01), var(--slate-08))` | Fallback colour visible if the image fails to load or hasn't loaded yet. |
11
+ | `--section-parallax-background-colour` | `var(--slate-01)` | Fallback colour visible if the image fails to load or hasn't loaded yet. |
12
12
 
13
13
  ```vue
14
14
  <SectionParallax
@@ -38,7 +38,7 @@ watch(
38
38
  background-size: var(--section-parallax-background-size, cover);
39
39
  position: relative;
40
40
 
41
- background-color: var(--section-parallax-background-colour, light-dark(var(--slate-01), var(--slate-08)));
41
+ background-color: var(--section-parallax-background-colour, var(--slate-01));
42
42
  width: 100%;
43
43
 
44
44
  @media (hover: hover) and (pointer: fine) {
@@ -9,8 +9,8 @@ CanvasSwitcher itself exposes the following public tokens:
9
9
  | `--canvas-switcher-gap` | `2rem` | Gap between the switcher's own children (currently just the list) |
10
10
  | `--canvas-switcher-item-gap` | `1rem` | Gap between each button in the list |
11
11
  | `--canvas-switcher-icon-size` | `2.4rem` | Width/height of each icon |
12
- | `--canvas-switcher-icon-colour` | `light-dark(var(--slate-10), var(--slate-02))` | Icon colour, resting state |
13
- | `--canvas-switcher-icon-colour-current` | `light-dark(var(--green-10), var(--green-04))` | Icon colour when that button's canvas is selected (`aria-pressed="true"`) |
12
+ | `--canvas-switcher-icon-colour` | `var(--slate-10)` | Icon colour, resting state |
13
+ | `--canvas-switcher-icon-colour-current` | `var(--green-10)` | Icon colour when that button's canvas is selected (`aria-pressed="true"`) |
14
14
 
15
15
  ## Class passthrough
16
16
 
@@ -78,10 +78,10 @@ watch(
78
78
  }
79
79
 
80
80
  .canvas-switcher-button.input-button-core {
81
- color: var(--canvas-switcher-icon-colour, light-dark(var(--slate-10), var(--slate-02)));
81
+ color: var(--canvas-switcher-icon-colour, var(--slate-10));
82
82
 
83
83
  &[aria-pressed="true"] {
84
- color: var(--canvas-switcher-icon-colour-current, light-dark(var(--green-10), var(--green-04)));
84
+ color: var(--canvas-switcher-icon-colour-current, var(--green-10));
85
85
  }
86
86
 
87
87
  .icon {
@@ -90,18 +90,18 @@ watch(
90
90
  }
91
91
 
92
92
  &.solid {
93
- --_card-background-color: light-dark(var(--slate-00), var(--slate-10));
93
+ --_card-background-color: var(--slate-00);
94
94
  --_card-border: 0.2rem solid var(--slate-08);
95
95
  }
96
96
 
97
97
  &.subtle {
98
- --_card-background-color: color-mix(in oklab, light-dark(var(--slate-01), var(--slate-08)) 50%, transparent);
98
+ --_card-background-color: color-mix(in oklab, var(--slate-01) 50%, transparent);
99
99
  --_card-border: 0.2rem solid var(--slate-08);
100
100
  }
101
101
 
102
102
  &.soft {
103
- --_card-background-color: color-mix(in oklab, light-dark(var(--slate-01), var(--slate-08)) 20%, transparent);
104
- --_card-box-shadow-color: color-mix(in oklab, light-dark(var(--slate-02), var(--slate-08)) 80%, transparent);
103
+ --_card-background-color: color-mix(in oklab, var(--slate-01) 20%, transparent);
104
+ --_card-box-shadow-color: color-mix(in oklab, var(--slate-02) 80%, transparent);
105
105
  }
106
106
 
107
107
  &.outline {
@@ -4,8 +4,8 @@
4
4
 
5
5
  | Token | Default | Controls |
6
6
  |---|---|---|
7
- | `--clipped-panel-background-colour` | `light-dark(hsl(0, 0%, 96%), hsl(0, 0%, 12%))` | Panel background |
8
- | `--clipped-panel-outline-colour` | `light-dark(hsl(0, 29%, 3%), hsl(0, 0%, 92%))` | Outline colour, and the panel's text/icon colour (`color`) |
7
+ | `--clipped-panel-background-colour` | `hsl(0, 0%, 96%)` | Panel background |
8
+ | `--clipped-panel-outline-colour` | `hsl(0, 29%, 3%)` | Outline colour, and the panel's text/icon colour (`color`) |
9
9
  | `--clipped-panel-outline-width` | `1px` | Outline width |
10
10
 
11
11
  ```css
@@ -30,9 +30,9 @@ watch(
30
30
  <style lang="css">
31
31
  @layer components {
32
32
  .clipped-panel {
33
- --_outline-colour: var(--clipped-panel-outline-colour, light-dark(hsl(0, 29%, 3%), hsl(0, 0%, 92%)));
33
+ --_outline-colour: var(--clipped-panel-outline-colour, hsl(0, 29%, 3%));
34
34
 
35
- background-color: var(--clipped-panel-background-colour, light-dark(hsl(0, 0%, 96%), hsl(0, 0%, 12%)));
35
+ background-color: var(--clipped-panel-background-colour, hsl(0, 0%, 96%));
36
36
  color: var(--_outline-colour);
37
37
  outline: var(--clipped-panel-outline-width, 1px) solid var(--_outline-colour);
38
38
 
@@ -7,10 +7,10 @@
7
7
  | `--dashboard-quad-grid-gap` | `2rem` | Gap between the four slot panels |
8
8
  | `--dashboard-quad-grid-padding` | `2rem` | Padding inside each slot panel |
9
9
  | `--dashboard-quad-grid-outline-width` | `0.1rem` | Slot panel outline width |
10
- | `--dashboard-quad-grid-outline-colour` | `light-dark(black, white)` | Slot panel outline colour |
10
+ | `--dashboard-quad-grid-outline-colour` | `black` | Slot panel outline colour |
11
11
  | `--dashboard-quad-grid-outline-offset` | `0` | Slot panel outline offset |
12
12
  | `--dashboard-quad-grid-border-width` | `0` | Slot panel border width (off by default — the panel edge is drawn by the outline) |
13
- | `--dashboard-quad-grid-border-colour` | `light-dark(black, white)` | Slot panel border colour, only visible once `--dashboard-quad-grid-border-width` is set |
13
+ | `--dashboard-quad-grid-border-colour` | `black` | Slot panel border colour, only visible once `--dashboard-quad-grid-border-width` is set |
14
14
  | `--dashboard-quad-grid-border-radius` | `0.5rem` | Slot panel corner radius |
15
15
  | `--dashboard-quad-grid-rule-width` | `0.1rem` | Width of the grid gap rule line (CSS Gap Decorations — see Notes) |
16
16
  | `--dashboard-quad-grid-rule-colour` | `transparent` | Colour of the grid gap rule line, invisible by default |
@@ -53,10 +53,10 @@ watch(
53
53
  & > div {
54
54
  padding: var(--dashboard-quad-grid-padding, 2rem);
55
55
  outline: var(--dashboard-quad-grid-outline-width, 0.1rem) solid
56
- var(--dashboard-quad-grid-outline-colour, light-dark(black, white));
56
+ var(--dashboard-quad-grid-outline-colour, black);
57
57
  outline-offset: var(--dashboard-quad-grid-outline-offset, 0);
58
58
  border: var(--dashboard-quad-grid-border-width, 0) solid
59
- var(--dashboard-quad-grid-border-colour, light-dark(black, white));
59
+ var(--dashboard-quad-grid-border-colour, black);
60
60
  border-radius: var(--dashboard-quad-grid-border-radius, 0.5rem);
61
61
  }
62
62
 
@@ -282,7 +282,7 @@ const RuleDecorationsTemplate: StoryFn<DashboardQuadGridArgs> = (args) => ({
282
282
  "--dashboard-quad-grid-border-width: 0",
283
283
  "--dashboard-quad-grid-border-radius: 0",
284
284
  "--dashboard-quad-grid-rule-width: 0.2rem",
285
- "--dashboard-quad-grid-rule-colour: light-dark(#cbd5e1, #475569)",
285
+ "--dashboard-quad-grid-rule-colour: #cbd5e1",
286
286
  "--dashboard-quad-grid-rule-inset: 0",
287
287
  ].join("; ");
288
288
 
@@ -7,7 +7,7 @@
7
7
  | `--dashboard-stats-grid-gap` | `1.2rem` | Gap between panels, in every row |
8
8
  | `--dashboard-stats-grid-panel-padding` | `1.2rem` | Padding inside each panel |
9
9
  | `--dashboard-stats-grid-border-width` | `0.1rem` | Panel border width |
10
- | `--dashboard-stats-grid-border-colour` | `light-dark(hsl(0, 29%, 3%), hsl(0, 0%, 92%))` | Panel border colour |
10
+ | `--dashboard-stats-grid-border-colour` | `hsl(0, 29%, 3%)` | Panel border colour |
11
11
  | `--dashboard-stats-grid-border-radius` | `1.2rem` | Panel corner radius |
12
12
  | `--dashboard-stats-grid-rule-width` | `0.1rem` | Width of the grid gap rule line (CSS Gap Decorations — see Notes) |
13
13
  | `--dashboard-stats-grid-rule-colour` | `transparent` | Colour of the grid gap rule line, invisible by default |
@@ -57,7 +57,7 @@ watch(
57
57
  .dashboard-stats-grid {
58
58
  .panel {
59
59
  border: var(--dashboard-stats-grid-border-width, 0.1rem) solid
60
- var(--dashboard-stats-grid-border-colour, light-dark(hsl(0, 29%, 3%), hsl(0, 0%, 92%)));
60
+ var(--dashboard-stats-grid-border-colour, hsl(0, 29%, 3%));
61
61
  border-radius: var(--dashboard-stats-grid-border-radius, 1.2rem);
62
62
  padding: var(--dashboard-stats-grid-panel-padding, 1.2rem);
63
63
  height: auto;
@@ -15,19 +15,19 @@
15
15
  | `--display-tooltip-popover-padding` | `1.2rem` | Popover panel content padding |
16
16
  | `--display-tooltip-popover-content-gap` | `1.2rem` | Gap between stacked children in the `tooltipContent` slot |
17
17
  | `--display-tooltip-popover-outline-width` | `0.1rem` | Popover panel outline (border) width |
18
- | `--display-tooltip-popover-outline-colour` | `light-dark(var(--slate-02), var(--slate-06))` | Popover panel outline (border) colour |
19
- | `--display-tooltip-popover-text-colour` | `light-dark(var(--slate-09), var(--slate-01))` | Popover panel text colour |
20
- | `--display-tooltip-popover-background-colour` | `light-dark(var(--slate-00), var(--slate-07))` | Popover panel background |
18
+ | `--display-tooltip-popover-outline-colour` | `var(--slate-02)` | Popover panel outline (border) colour |
19
+ | `--display-tooltip-popover-text-colour` | `var(--slate-09)` | Popover panel text colour |
20
+ | `--display-tooltip-popover-background-colour` | `var(--slate-00)` | Popover panel background |
21
21
  | `--display-tooltip-popover-border-radius` | `0.8rem` | Popover panel corner radius |
22
- | `--display-tooltip-popover-shadow` | `light-dark(0 0.4rem 1.6rem rgba(0,0,0,.12), 0 0.4rem 1.6rem rgba(0,0,0,.5))` | Popover panel elevation shadow |
22
+ | `--display-tooltip-popover-shadow` | `0 0.4rem 1.6rem rgba(0,0,0,.12)` | Popover panel elevation shadow |
23
23
  | `--display-tooltip-popover-offset` | `0.1rem` | Gap between the trigger and the popover panel |
24
- | `--display-tooltip-close-button-colour` | `light-dark(var(--slate-09), var(--slate-01))` | Close button text colour (used by `DisplayTooltipDefined`) |
24
+ | `--display-tooltip-close-button-colour` | `var(--slate-09)` | Close button text colour (used by `DisplayTooltipDefined`) |
25
25
  | `--display-tooltip-close-button-border-width` | `0.1rem` | Close button border width |
26
- | `--display-tooltip-close-button-border-colour` | `light-dark(var(--slate-03), var(--slate-06))` | Close button border colour |
26
+ | `--display-tooltip-close-button-border-colour` | `var(--slate-03)` | Close button border colour |
27
27
  | `--display-tooltip-close-button-outline-width` | `0.1rem` | Close button outline width |
28
28
  | `--display-tooltip-close-button-outline-colour` | `transparent` | Close button outline colour at rest (no permanent ring) |
29
- | `--display-tooltip-close-button-border-colour-hover` | `light-dark(var(--slate-06), var(--slate-03))` | Close button border colour on hover/focus |
30
- | `--display-tooltip-close-button-outline-colour-hover` | `light-dark(var(--slate-06), var(--slate-03))` | Close button outline colour on hover/focus |
29
+ | `--display-tooltip-close-button-border-colour-hover` | `var(--slate-06)` | Close button border colour on hover/focus |
30
+ | `--display-tooltip-close-button-outline-colour-hover` | `var(--slate-06)` | Close button outline colour on hover/focus |
31
31
  | `--display-tooltip-close-button-padding` | `0.4rem 1rem` | Close button padding |
32
32
 
33
33
  ```css
@@ -115,13 +115,13 @@ watch(
115
115
  width: var(--display-tooltip-popover-width, 30rem);
116
116
 
117
117
  outline: var(--display-tooltip-popover-outline-width, 0.1rem) solid
118
- var(--display-tooltip-popover-outline-colour, light-dark(var(--slate-02), var(--slate-06)));
119
- color: var(--display-tooltip-popover-text-colour, light-dark(var(--slate-09), var(--slate-01)));
120
- background-color: var(--display-tooltip-popover-background-colour, light-dark(var(--slate-00), var(--slate-07)));
118
+ var(--display-tooltip-popover-outline-colour, var(--slate-02));
119
+ color: var(--display-tooltip-popover-text-colour, var(--slate-09));
120
+ background-color: var(--display-tooltip-popover-background-colour, var(--slate-00));
121
121
  border-radius: var(--display-tooltip-popover-border-radius, 0.8rem);
122
122
  box-shadow: var(
123
123
  --display-tooltip-popover-shadow,
124
- light-dark(0 0.4rem 1.6rem rgba(0, 0, 0, 0.12), 0 0.4rem 1.6rem rgba(0, 0, 0, 0.5))
124
+ 0 0.4rem 1.6rem rgba(0, 0, 0, 0.12)
125
125
  );
126
126
 
127
127
  position-anchor: var(--_anchor-name);
@@ -147,9 +147,9 @@ watch(
147
147
  .display-tooltip-close-button {
148
148
  all: unset;
149
149
  cursor: pointer;
150
- color: var(--display-tooltip-close-button-colour, light-dark(var(--slate-09), var(--slate-01)));
150
+ color: var(--display-tooltip-close-button-colour, var(--slate-09));
151
151
  border: var(--display-tooltip-close-button-border-width, 0.1rem) solid
152
- var(--display-tooltip-close-button-border-colour, light-dark(var(--slate-03), var(--slate-06)));
152
+ var(--display-tooltip-close-button-border-colour, var(--slate-03));
153
153
  outline: var(--display-tooltip-close-button-outline-width, 0.1rem) solid transparent;
154
154
 
155
155
  font-weight: 600;
@@ -160,11 +160,11 @@ watch(
160
160
  text-decoration: underline;
161
161
  border-color: var(
162
162
  --display-tooltip-close-button-border-colour-hover,
163
- light-dark(var(--slate-06), var(--slate-03))
163
+ var(--slate-06)
164
164
  );
165
165
  outline-color: var(
166
166
  --display-tooltip-close-button-outline-colour-hover,
167
- light-dark(var(--slate-06), var(--slate-03))
167
+ var(--slate-06)
168
168
  );
169
169
  outline-offset: 0.2rem;
170
170
  }
@@ -9,21 +9,21 @@
9
9
  | `--pop-over-trigger-outline-colour-hover` | `var(--theme-ring)` | Trigger outline colour on focus-visible |
10
10
  | `--pop-over-width` | `30rem` | Popover panel width |
11
11
  | `--pop-over-border-width` | `0.1rem` | Popover panel border width |
12
- | `--pop-over-border-colour` | `light-dark(var(--slate-02), var(--slate-06))` | Popover panel border colour |
12
+ | `--pop-over-border-colour` | `var(--slate-02)` | Popover panel border colour |
13
13
  | `--pop-over-border-radius` | `0.8rem` | Popover panel corner radius |
14
- | `--pop-over-background-colour` | `light-dark(var(--slate-00), var(--slate-07))` | Popover panel background |
15
- | `--pop-over-text-colour` | `light-dark(var(--slate-09), var(--slate-01))` | Popover panel text colour |
16
- | `--pop-over-shadow` | `light-dark(0 0.4rem 1.6rem rgba(0,0,0,.12), 0 0.4rem 1.6rem rgba(0,0,0,.5))` | Popover panel elevation shadow |
14
+ | `--pop-over-background-colour` | `var(--slate-00)` | Popover panel background |
15
+ | `--pop-over-text-colour` | `var(--slate-09)` | Popover panel text colour |
16
+ | `--pop-over-shadow` | `0 0.4rem 1.6rem rgba(0,0,0,.12)` | Popover panel elevation shadow |
17
17
  | `--pop-over-transition-duration` | `200ms` | Open/close fade duration |
18
18
  | `--pop-over-content-padding` | `1.6rem` | Padding around the `content` slot |
19
19
  | `--pop-over-content-padding-block-start` | `3.2rem` | Extra top padding so content clears the close button |
20
20
  | `--pop-over-close-button-offset` | `0.8rem` | Distance of the close button from the panel's top/right edges |
21
21
  | `--pop-over-close-button-size` | `2.4rem` | Close button box width/height |
22
22
  | `--pop-over-close-button-border-radius` | `50%` | Close button corner radius |
23
- | `--pop-over-close-button-colour` | `light-dark(var(--slate-06), var(--slate-03))` | Close button icon colour |
23
+ | `--pop-over-close-button-colour` | `var(--slate-06)` | Close button icon colour |
24
24
  | `--pop-over-close-button-icon-size` | `1.4rem` | Close button icon glyph size |
25
25
  | `--pop-over-close-button-outline-width` | `0.1rem` | Close button focus/hover outline width |
26
- | `--pop-over-close-button-surface-hover` | `light-dark(var(--slate-01), var(--slate-06))` | Close button background on hover/focus-visible |
26
+ | `--pop-over-close-button-surface-hover` | `var(--slate-01)` | Close button background on hover/focus-visible |
27
27
  | `--pop-over-close-button-outline-colour-hover` | `var(--theme-ring)` | Close button outline colour on hover/focus-visible |
28
28
 
29
29
  ```css
@@ -102,13 +102,13 @@ watch(
102
102
  margin: 0;
103
103
  inset: auto;
104
104
  border: var(--pop-over-border-width, 0.1rem) solid
105
- var(--pop-over-border-colour, light-dark(var(--slate-02), var(--slate-06)));
105
+ var(--pop-over-border-colour, var(--slate-02));
106
106
  border-radius: var(--pop-over-border-radius, 0.8rem);
107
- background-color: var(--pop-over-background-colour, light-dark(var(--slate-00), var(--slate-07)));
108
- color: var(--pop-over-text-colour, light-dark(var(--slate-09), var(--slate-01)));
107
+ background-color: var(--pop-over-background-colour, var(--slate-00));
108
+ color: var(--pop-over-text-colour, var(--slate-09));
109
109
  box-shadow: var(
110
110
  --pop-over-shadow,
111
- light-dark(0 0.4rem 1.6rem rgba(0, 0, 0, 0.12), 0 0.4rem 1.6rem rgba(0, 0, 0, 0.5))
111
+ 0 0.4rem 1.6rem rgba(0, 0, 0, 0.12)
112
112
  );
113
113
  width: var(--pop-over-width, 30rem);
114
114
 
@@ -139,12 +139,12 @@ watch(
139
139
  width: var(--pop-over-close-button-size, 2.4rem);
140
140
  height: var(--pop-over-close-button-size, 2.4rem);
141
141
  border-radius: var(--pop-over-close-button-border-radius, 50%);
142
- color: var(--pop-over-close-button-colour, light-dark(var(--slate-06), var(--slate-03)));
142
+ color: var(--pop-over-close-button-colour, var(--slate-06));
143
143
  outline: var(--pop-over-close-button-outline-width, 0.1rem) solid transparent;
144
144
 
145
145
  &:hover,
146
146
  &:focus-visible {
147
- background-color: var(--pop-over-close-button-surface-hover, light-dark(var(--slate-01), var(--slate-06)));
147
+ background-color: var(--pop-over-close-button-surface-hover, var(--slate-01));
148
148
  outline-color: var(--pop-over-close-button-outline-colour-hover, var(--theme-ring));
149
149
  outline-offset: 0.1rem;
150
150
  }
@@ -7,7 +7,7 @@
7
7
  | `--deep-expanding-menu-gap` | `2.4rem` | Gap between top-level items |
8
8
  | `--deep-expanding-menu-link-border-width` | `0.2rem` | Bottom border width on links and group toggles |
9
9
  | `--deep-expanding-menu-link-padding-block` | `0.8rem` | Vertical padding on links and group toggles |
10
- | `--deep-expanding-menu-link-border-colour-hover` | `light-dark(var(--blue-10), var(--slate-00))` | Bottom border colour on hover/focus |
10
+ | `--deep-expanding-menu-link-border-colour-hover` | `var(--blue-10)` | Bottom border colour on hover/focus |
11
11
  | `--deep-expanding-menu-icon-size` | `1.2rem` | Caret icon size |
12
12
  | `--deep-expanding-menu-panel-width` | `min(100%, 50vw)` | Popover panel width |
13
13
  | `--deep-expanding-menu-panel-background-colour` | `white` | Popover panel background |
@@ -92,7 +92,7 @@ watch(
92
92
  cursor: pointer;
93
93
  border-color: var(
94
94
  --deep-expanding-menu-link-border-colour-hover,
95
- light-dark(var(--blue-10), var(--slate-00))
95
+ var(--blue-10)
96
96
  );
97
97
  }
98
98
  }
@@ -8,7 +8,7 @@
8
8
  | `--deep-expanding-menu-classic-item-gap` | `2.4rem` | Gap between top-level items |
9
9
  | `--deep-expanding-menu-classic-link-border-width` | `0.2rem` | Bottom border width on links and group toggles |
10
10
  | `--deep-expanding-menu-classic-link-padding-block` | `0.8rem` | Vertical padding on links and group toggles |
11
- | `--deep-expanding-menu-classic-link-border-colour-hover` | `light-dark(var(--blue-10), var(--slate-00))` | Bottom border colour on hover/focus |
11
+ | `--deep-expanding-menu-classic-link-border-colour-hover` | `var(--blue-10)` | Bottom border colour on hover/focus |
12
12
  | `--deep-expanding-menu-classic-icon-size` | `1.2rem` | Caret icon size |
13
13
  | `--deep-expanding-menu-classic-panel-offset-top` | `4rem` | Panel offset from the toggle |
14
14
  | `--deep-expanding-menu-classic-panel-width` | `20rem` | Panel width below the `768px` breakpoint |
@@ -89,7 +89,7 @@ onMounted(() => {
89
89
  cursor: pointer;
90
90
  border-color: var(
91
91
  --deep-expanding-menu-classic-link-border-colour-hover,
92
- light-dark(var(--blue-10), var(--slate-00))
92
+ var(--blue-10)
93
93
  );
94
94
  }
95
95
  }
@@ -131,6 +131,17 @@ When displaying multiple cards side-by-side (common in pricing pages), wrap in a
131
131
 
132
132
  ---
133
133
 
134
+ ## Highlight badge text
135
+
136
+ `isHighlighted` shows a top-centred badge reading "Most Popular". Pass `badge-text` to change it,
137
+ e.g. for localisation:
138
+
139
+ ```vue
140
+ <PricingCard planName="Standard" :price="99" is-highlighted :badge-text="t('pricing.mostPopular')" />
141
+ ```
142
+
143
+ ---
144
+
134
145
  ## Discount ribbon
135
146
 
136
147
  Pass `ribbon-text` to render a diagonal corner ribbon (top-right, 45°) for marketing callouts —
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component :is="tag" class="pricing-card" :class="[elementClasses, { 'is-highlighted': isHighlighted }]">
3
- <div v-if="isHighlighted" class="pricing-card__badge">Most Popular</div>
3
+ <div v-if="isHighlighted" class="pricing-card__badge">{{ badgeText }}</div>
4
4
 
5
5
  <div v-if="ribbonText" class="pricing-card__ribbon-clip">
6
6
  <span class="pricing-card__ribbon">{{ ribbonText }}</span>
@@ -41,6 +41,7 @@ interface Props {
41
41
  description?: string;
42
42
  features?: string[];
43
43
  isHighlighted?: boolean;
44
+ badgeText?: string;
44
45
  ctaText?: string;
45
46
  ctaDisabled?: boolean;
46
47
  ribbonText?: string;
@@ -54,6 +55,7 @@ const props = withDefaults(defineProps<Props>(), {
54
55
  description: undefined,
55
56
  features: () => [],
56
57
  isHighlighted: false,
58
+ badgeText: "Most Popular",
57
59
  ctaText: "Get started",
58
60
  ctaDisabled: false,
59
61
  ribbonText: undefined,
@@ -11,6 +11,7 @@ const meta: Meta<typeof PricingCard> = {
11
11
  billingPeriod: { control: "text" },
12
12
  description: { control: "text" },
13
13
  isHighlighted: { control: "boolean" },
14
+ badgeText: { control: "text" },
14
15
  ctaText: { control: "text" },
15
16
  ctaDisabled: { control: "boolean" },
16
17
  ribbonText: { control: "text" },
@@ -22,6 +23,7 @@ const meta: Meta<typeof PricingCard> = {
22
23
  description: "Perfect for freelancers and solo practitioners.",
23
24
  features: ["Embed on one domain", "Unlimited consultations", "Email support", "Monthly updates"],
24
25
  isHighlighted: false,
26
+ badgeText: "Most Popular",
25
27
  ctaText: "Get started",
26
28
  ctaDisabled: false,
27
29
  ribbonText: undefined,
@@ -84,6 +84,19 @@ describe("PricingCard", () => {
84
84
  expect(wrapper.text()).toContain("Most Popular");
85
85
  });
86
86
 
87
+ it("renders custom badge text when highlighted", () => {
88
+ const wrapper = mount(PricingCard, {
89
+ props: {
90
+ planName: "Test Plan",
91
+ price: 100,
92
+ isHighlighted: true,
93
+ badgeText: "Le plus populaire",
94
+ },
95
+ });
96
+
97
+ expect(wrapper.find(".pricing-card__badge").text()).toBe("Le plus populaire");
98
+ });
99
+
87
100
  it("emits select event with plan name on CTA click", async () => {
88
101
  const wrapper = mount(PricingCard, {
89
102
  props: {
@@ -0,0 +1,168 @@
1
+ # SelectMenu — Consumer Styling Guide
2
+
3
+ ## Public token API
4
+
5
+ All `--select-menu-*` tokens are the stable override surface, each falling back to a `--theme-*`
6
+ global token so it matches the rest of the design system out of the box.
7
+
8
+ ### Trigger button
9
+
10
+ | Token | Default | Controls |
11
+ |---|---|---|
12
+ | `--select-menu-trigger-gap` | `0.8rem` | Gap between icon / label / chevron |
13
+ | `--select-menu-trigger-min-height` | `4.4rem` | Trigger minimum height |
14
+ | `--select-menu-trigger-padding-block` | `0.8rem` | Trigger vertical padding |
15
+ | `--select-menu-trigger-padding-inline` | `1.2rem` | Trigger horizontal padding |
16
+ | `--select-menu-trigger-border-width` | `0.1rem` | Trigger border thickness |
17
+ | `--select-menu-trigger-border` | `var(--theme-border)` | Trigger border colour (rest state) |
18
+ | `--select-menu-trigger-border-focus` | `var(--theme-border-focus)` | Trigger border colour on hover/focus |
19
+ | `--select-menu-trigger-border-radius` | `0.5rem` | Trigger corner rounding |
20
+ | `--select-menu-trigger-surface` | `var(--theme-input-surface)` | Trigger background |
21
+ | `--select-menu-trigger-text-color` | `var(--theme-text)` | Trigger label text colour |
22
+ | `--select-menu-trigger-font-size` | `1.6rem` | Trigger label font size |
23
+ | `--select-menu-trigger-outline-width` | `0.2rem` | Focus-visible outline width (trigger and items) |
24
+ | `--select-menu-trigger-icon-size` | `2rem` | Selected option's icon size in the trigger |
25
+ | `--select-menu-trigger-chevron-size` | `1.6rem` | Chevron icon size |
26
+
27
+ ### Menu popover
28
+
29
+ | Token | Default | Controls |
30
+ |---|---|---|
31
+ | `--select-menu-block-distance` | `0.4rem` | Gap between trigger bottom and menu top |
32
+ | `--select-menu-popover-border-width` | `0.1rem` | Popover border thickness |
33
+ | `--select-menu-popover-border` | `var(--theme-border)` | Popover border colour |
34
+ | `--select-menu-popover-surface` | `var(--theme-input-surface)` | Popover background |
35
+ | `--select-menu-popover-border-radius` | `0.5rem` | Popover corner rounding |
36
+ | `--select-menu-popover-min-width` | `18rem` | Minimum popover width |
37
+ | `--select-menu-popover-max-height` | `32rem` | Maximum popover height before scrolling |
38
+ | `--select-menu-popover-shadow` | `0 0.4rem 1.6rem rgb(0 0 0 / 12%)` | Popover drop shadow |
39
+ | `--select-menu-transition-duration` | `200ms` | Open/close fade and chevron-rotate duration |
40
+
41
+ ### Options
42
+
43
+ | Token | Default | Controls |
44
+ |---|---|---|
45
+ | `--select-menu-item-gap` | `0.8rem` | Gap between checkmark / icon / label in a row |
46
+ | `--select-menu-item-padding-block` | `1rem` | Option row vertical padding |
47
+ | `--select-menu-item-padding-inline` | `1.2rem` | Option row horizontal padding |
48
+ | `--select-menu-item-text-color` | `var(--theme-text)` | Option label colour |
49
+ | `--select-menu-item-font-size` | `1.5rem` | Option label font size |
50
+ | `--select-menu-item-surface-hover` | `var(--theme-input-surface-hover)` | Option row background on hover/focus |
51
+ | `--select-menu-item-check-size` | `1.6rem` | Checkmark icon box size |
52
+ | `--select-menu-item-check-color` | `currentcolor` | Checkmark icon colour |
53
+ | `--select-menu-item-icon-size` | `1.8rem` | Per-option icon size |
54
+
55
+ ---
56
+
57
+ ## Global theming — recommended approach
58
+
59
+ Create `assets/styles/setup/07.components/select-menu.css` in the consuming app and set tokens
60
+ on `:root`. This applies to every `SelectMenu` across the site.
61
+
62
+ ```css
63
+ /* assets/styles/setup/07.components/select-menu.css */
64
+ :root {
65
+ --select-menu-trigger-border-radius: 999rem;
66
+ --select-menu-trigger-surface: var(--brand-surface);
67
+ --select-menu-trigger-border: var(--brand-border);
68
+
69
+ --select-menu-popover-surface: var(--brand-surface);
70
+ --select-menu-popover-border: var(--brand-border);
71
+ --select-menu-popover-shadow: 0 0.8rem 2.4rem rgba(0, 0, 0, 0.15);
72
+
73
+ --select-menu-item-surface-hover: var(--brand-surface-subtle);
74
+ --select-menu-item-check-color: var(--brand-accent);
75
+ }
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Per-instance overrides via styleClassPassthrough
81
+
82
+ ```vue
83
+ <SelectMenu
84
+ v-model="language"
85
+ :options="languageOptions"
86
+ label="Language"
87
+ :style-class-passthrough="['compact-switcher']"
88
+ />
89
+ ```
90
+
91
+ ```css
92
+ .select-menu.compact-switcher {
93
+ --select-menu-trigger-min-height: 3.2rem;
94
+ --select-menu-trigger-padding-inline: 0.8rem;
95
+ --select-menu-trigger-border-radius: 50%;
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Trigger content variants
102
+
103
+ `showIcon` / `showLabel` / `showChevron` control what renders in the trigger — combine them for
104
+ the three common shapes:
105
+
106
+ | Variant | Props |
107
+ |---|---|
108
+ | Icon-only (e.g. flag switcher in a tight header) | `:show-label="false" :show-chevron="false"` |
109
+ | Text + chevron (e.g. a category filter with no per-option icons) | `:show-icon="false"` (default `showLabel`/`showChevron`) |
110
+ | Icon + text + chevron (full select) | Defaults — no overrides needed |
111
+
112
+ ---
113
+
114
+ ## Single-select vs multi-select
115
+
116
+ By default `SelectMenu` is single-select: `v-model` is `string | number | undefined`, the selected
117
+ option shows a checkmark, and picking one closes the popover.
118
+
119
+ Set `multiple` for a checkbox-per-option multi-select instead: `v-model` becomes
120
+ `(string | number)[]`, every option shows a checkbox (checked/unchecked), and picking an option
121
+ toggles it in the array without closing the popover — so several can be picked in one open/close
122
+ cycle. By default the trigger text stays fixed on `placeholder`/`label` as a static category tag
123
+ (e.g. `"Services required"`) regardless of how many options are checked, since a comma-joined list
124
+ of checked options would grow unpredictably long. Set `showSelectionInTrigger` to opt into that
125
+ comma-joined list instead (falling back to `placeholder`/`label` when nothing is checked). The
126
+ trigger icon is not shown in multi-select mode (`showIcon` has no effect), since there's no single
127
+ selected option to represent.
128
+
129
+ ```vue
130
+ <script setup lang="ts">
131
+ const treatments = ref<string[]>([]);
132
+ const treatmentOptions = [
133
+ { value: "trim", label: "Trim" },
134
+ { value: "layers", label: "Layers" },
135
+ { value: "restyle", label: "Restyle" },
136
+ { value: "straightening", label: "Straightening" },
137
+ ];
138
+ </script>
139
+
140
+ <template>
141
+ <SelectMenu v-model="treatments" :options="treatmentOptions" label="Services required" multiple />
142
+
143
+ <!-- Trigger updates to "Layers, Restyle" etc. as options are checked -->
144
+ <SelectMenu
145
+ v-model="treatments"
146
+ :options="treatmentOptions"
147
+ label="Services required"
148
+ multiple
149
+ show-selection-in-trigger
150
+ />
151
+ </template>
152
+ ```
153
+
154
+ For several independent single-select filter categories (rather than one multi-select category),
155
+ place multiple single-select `SelectMenu` instances side by side instead — see the "Filter Bar"
156
+ story.
157
+
158
+ ---
159
+
160
+ ## Notes
161
+
162
+ - **Popover API + CSS anchor positioning** — same mechanism as `ActionMenu`. Broadly supported
163
+ (Chrome 114+, Firefox 125+, Safari 17+). No polyfill is included.
164
+ - **Popover left-aligns with the trigger** by default (`left: anchor(left)`), unlike `ActionMenu`
165
+ which right-aligns — matches native `<select>` dropdown behaviour. Flips above the trigger near
166
+ the bottom of the viewport (`position-try-fallbacks: flip-block`).
167
+ - **Chevron rotation** is pure CSS via `:has(.select-menu-popover:popover-open)` — no JS state
168
+ needed for the visual, though `isOpen` is still tracked internally to drive `aria-expanded`.