srcdev-nuxt-components 9.4.9 → 9.4.11
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/commands/migrate-component.md +38 -6
- package/.claude/component-ledger/audit.json +1 -1
- package/.claude/component-ledger/build.mjs +26 -0
- package/.claude/component-ledger/output.html +8 -3
- package/.claude/component-ledger/template.html +7 -2
- package/.claude/skills/component-dynamic-slots.md +1 -1
- package/.claude/skills/components/alert-mask-core.md +84 -0
- package/.claude/skills/components/canvas-switcher.md +1 -1
- package/.claude/skills/components/carousel-flip.md +112 -168
- package/.claude/skills/components/container-glow.md +123 -0
- package/.claude/skills/components/dashboard-quad-grid.md +98 -0
- package/.claude/skills/components/dashboard-stats-grid.md +103 -0
- package/.claude/skills/components/display-theme-switch.md +60 -0
- package/.claude/skills/components/glowing-border.md +66 -0
- package/.claude/skills/components/input-number-core.md +214 -0
- package/.claude/skills/components/input-range-core.md +142 -0
- package/.claude/skills/components/input-select-core.md +151 -0
- package/.claude/skills/components/input-text-core.md +16 -0
- package/.claude/skills/components/input-textarea-core.md +154 -0
- package/.claude/skills/components/section-parallax.md +32 -10
- package/.claude/skills/components/select-menu.md +195 -0
- package/.claude/skills/components/toggle-switch-core.md +150 -0
- package/.claude/skills/components/ui-block-decorated.md +56 -0
- package/.claude/skills/components/wipe-away-vertical.md +98 -0
- package/.claude/skills/icon-sets.md +1 -1
- package/.claude/skills/index.md +15 -1
- package/.vscode/css-custom-data.json +38 -0
- package/.vscode/settings.json +3 -0
- package/.vscode/srcdev-component-alert-mask-core.code-snippets +31 -0
- package/.vscode/srcdev-component-carousel-flip.code-snippets +41 -0
- package/.vscode/srcdev-component-container-glow.code-snippets +33 -0
- package/.vscode/srcdev-component-dashboard-quad-grid.code-snippets +36 -0
- package/.vscode/srcdev-component-dashboard-stats-grid.code-snippets +35 -0
- package/.vscode/srcdev-component-display-theme-switch.code-snippets +27 -0
- package/.vscode/srcdev-component-glowing-border.code-snippets +23 -0
- package/.vscode/srcdev-component-input-number.code-snippets +65 -0
- package/.vscode/srcdev-component-input-range.code-snippets +85 -0
- package/.vscode/srcdev-component-input-select.code-snippets +42 -0
- package/.vscode/srcdev-component-input-textarea.code-snippets +40 -0
- package/.vscode/srcdev-component-section-parallax.code-snippets +27 -0
- package/.vscode/srcdev-component-select-menu.code-snippets +65 -0
- package/.vscode/srcdev-component-toggle-switch.code-snippets +49 -0
- package/.vscode/srcdev-component-ui-block-decorated.code-snippets +24 -0
- package/.vscode/srcdev-component-wipe-away-vertical.code-snippets +25 -0
- package/README.md +18 -37
- package/app/components/{alert-mask → 01.atoms/alert-mask}/AlertMaskCore.vue +16 -17
- package/app/components/01.atoms/alert-mask/CONSUMER-STYLING.md +46 -0
- package/app/components/01.atoms/alert-mask/stories/AlertMaskCore.stories.ts +79 -0
- package/app/components/{alert-mask → 01.atoms/alert-mask}/tests/AlertMaskCore.spec.ts +10 -10
- package/app/components/01.atoms/animations/container-glow/CONSUMER-STYLING.md +86 -0
- package/app/components/01.atoms/animations/container-glow/ContainerGlow.vue +299 -0
- package/app/components/01.atoms/animations/container-glow/stories/ContainerGlow.stories.ts +175 -0
- package/app/components/01.atoms/animations/container-glow/tests/ContainerGlow.spec.ts +131 -0
- package/app/components/01.atoms/animations/container-glow/tests/__snapshots__/ContainerGlow.spec.ts.snap +14 -0
- package/app/components/01.atoms/animations/glowing-border/CONSUMER-STYLING.md +61 -0
- package/app/components/01.atoms/animations/glowing-border/GlowingBorder.vue +132 -0
- package/app/components/01.atoms/animations/glowing-border/stories/GlowingBorder.stories.ts +165 -0
- package/app/components/01.atoms/animations/glowing-border/tests/GlowingBorder.spec.ts +94 -0
- package/app/components/01.atoms/animations/glowing-border/tests/__snapshots__/GlowingBorder.spec.ts.snap +3 -0
- package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +1 -1
- package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +1 -1
- package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +1 -1
- package/app/components/01.atoms/animations/section-parallax/CONSUMER-STYLING.md +44 -0
- package/app/components/{parallax → 01.atoms/animations/section-parallax}/SectionParallax.vue +11 -10
- package/app/components/01.atoms/animations/section-parallax/stories/SectionParallax.stories.ts +98 -0
- package/app/components/01.atoms/animations/section-parallax/tests/SectionParallax.spec.ts +102 -0
- package/app/components/01.atoms/animations/section-parallax/tests/__snapshots__/SectionParallax.spec.ts.snap +9 -0
- package/app/components/01.atoms/animations/view-timeline/CONSUMER-STYLING.md +70 -0
- package/app/components/01.atoms/animations/view-timeline/WipeAwayVertical.vue +181 -0
- package/app/components/01.atoms/animations/view-timeline/stories/WipeAwayVertical.stories.ts +269 -0
- package/app/components/01.atoms/animations/view-timeline/tests/WipeAwayVertical.spec.ts +127 -0
- package/app/components/01.atoms/canvas-switcher/CONSUMER-STYLING.md +3 -3
- package/app/components/01.atoms/canvas-switcher/CanvasSwitcher.vue +2 -2
- package/app/components/01.atoms/canvas-switcher/stories/CanvasSwitcher.stories.ts +1 -1
- package/app/components/01.atoms/card/CardCore.vue +4 -4
- package/app/components/01.atoms/clipped-panel/CONSUMER-STYLING.md +2 -2
- package/app/components/01.atoms/clipped-panel/ClippedPanel.vue +2 -2
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/CONSUMER-STYLING.md +42 -0
- package/app/components/{layout-grids/LayoutGridA.vue → 01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/DashboardQuadGrid.vue} +23 -13
- package/app/components/{layout-grids/stories/LayoutGridA.stories.ts → 01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/stories/DashboardQuadGrid.stories.ts} +151 -23
- package/app/components/{layout-grids/tests/LayoutGridA.spec.ts → 01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/tests/DashboardQuadGrid.spec.ts} +25 -25
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/CONSUMER-STYLING.md +41 -0
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/DashboardStatsGrid.vue +133 -0
- package/app/components/{layout-grids/stories/LayoutGridB.stories.ts → 01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/stories/DashboardStatsGrid.stories.ts} +24 -24
- package/app/components/{layout-grids/tests/LayoutGridB.spec.ts → 01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/tests/DashboardStatsGrid.spec.ts} +23 -23
- package/app/components/01.atoms/display-tooltip/CONSUMER-STYLING.md +8 -8
- package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +8 -8
- package/app/components/01.atoms/pop-over/CONSUMER-STYLING.md +6 -6
- package/app/components/01.atoms/pop-over/PopOver.vue +6 -6
- package/app/components/01.atoms/ui-block-decorated/CONSUMER-STYLING.md +39 -0
- package/app/components/01.atoms/ui-block-decorated/UiBlockDecorated.vue +141 -0
- package/app/components/01.atoms/ui-block-decorated/stories/UiBlockDecorated.stories.ts +148 -0
- package/app/components/01.atoms/ui-block-decorated/tests/UiBlockDecorated.spec.ts +80 -0
- package/app/components/01.atoms/ui-block-decorated/tests/__snapshots__/UiBlockDecorated.spec.ts.snap +3 -0
- package/app/components/02.molecules/alert-masked-content/tests/AlertMaskedContent.spec.ts +6 -6
- package/app/components/02.molecules/display-theme-switch/CONSUMER-STYLING.md +34 -0
- package/app/components/02.molecules/display-theme-switch/DisplayThemeSwitch.vue +102 -0
- package/app/components/02.molecules/display-theme-switch/stories/DisplayThemeSwitch.stories.ts +115 -0
- package/app/components/02.molecules/display-theme-switch/tests/DisplayThemeSwitch.spec.ts +86 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu/CONSUMER-STYLING.md +1 -1
- package/app/components/02.molecules/navigation/deep-expanding-menu/DeepExpandingMenu.vue +1 -1
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/CONSUMER-STYLING.md +1 -1
- package/app/components/02.molecules/navigation/deep-expanding-menu-classic/DeepExpandingMenuClassic.vue +1 -1
- package/app/components/02.molecules/select-menu/CONSUMER-STYLING.md +168 -0
- package/app/components/02.molecules/select-menu/SelectMenu.vue +384 -0
- package/app/components/02.molecules/select-menu/stories/SelectMenu.stories.ts +359 -0
- package/app/components/02.molecules/select-menu/tests/SelectMenu.spec.ts +476 -0
- package/app/components/02.molecules/select-menu/tests/__snapshots__/SelectMenu.spec.ts.snap +42 -0
- package/app/components/03.organisms/image-galleries/carousel-flip/CONSUMER-STYLING.md +46 -0
- package/app/components/{carousels → 03.organisms/image-galleries/carousel-flip}/CarouselFlip.vue +63 -42
- package/app/components/{carousels → 03.organisms/image-galleries/carousel-flip}/stories/CarouselFlip.stories.ts +114 -29
- package/app/components/{carousels → 03.organisms/image-galleries/carousel-flip}/tests/CarouselFlip.spec.ts +80 -0
- package/app/components/05.forms/form-field/FormField.vue +1 -1
- package/app/components/05.forms/form-wrapper/FormWrapper.vue +1 -1
- package/app/components/05.forms/input-button/CONSUMER-STYLING.md +2 -7
- package/app/components/05.forms/input-button/InputButtonCore.vue +1 -5
- package/app/components/05.forms/input-number/CONSUMER-STYLING.md +26 -6
- package/app/components/05.forms/input-number/InputNumberCore.vue +125 -85
- package/app/components/05.forms/input-number/stories/InputNumberCore.stories.ts +92 -0
- package/app/components/05.forms/input-number/tests/InputNumberCore.spec.ts +119 -0
- package/app/components/05.forms/input-number/variants/InputNumberDefault.vue +30 -22
- package/app/components/05.forms/input-number/variants/stories/InputNumberDefault.stories.ts +123 -0
- package/app/components/05.forms/input-number/variants/tests/InputNumberDefault.spec.ts +143 -0
- package/app/components/05.forms/input-range/CONSUMER-STYLING.md +45 -0
- package/app/components/05.forms/input-range/InputRangeCore.vue +79 -143
- package/app/components/05.forms/input-range/stories/InputRangeCore.stories.ts +126 -0
- package/app/components/05.forms/input-range/tests/InputRangeCore.spec.ts +124 -0
- package/app/components/05.forms/input-range/variants/InputRangeDefault.vue +9 -32
- package/app/components/05.forms/input-range/variants/stories/InputRangeDefault.stories.ts +108 -0
- package/app/components/05.forms/input-range/variants/tests/InputRangeDefault.spec.ts +140 -0
- package/app/components/05.forms/input-select/InputSelectCore.vue +23 -30
- package/app/components/05.forms/input-select/stories/InputSelectCore.stories.ts +2 -2
- package/app/components/05.forms/input-select/stories/InputSelectWithLabel.stories.ts +115 -0
- package/app/components/05.forms/input-select/tests/InputSelectCore.spec.ts +129 -0
- package/app/components/05.forms/input-select/variants/InputSelectWithLabel.vue +1 -1
- package/app/components/05.forms/input-select/variants/tests/InputSelectWithLabel.spec.ts +87 -0
- package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +14 -0
- package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +1 -1
- package/app/components/05.forms/input-textarea/CONSUMER-STYLING.md +55 -0
- package/app/components/05.forms/input-textarea/InputTextareaCore.vue +24 -16
- package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +1 -1
- package/app/components/05.forms/input-textarea/tests/InputTextareaCore.spec.ts +119 -0
- package/app/components/05.forms/input-textarea/variants/InputTextareaWithLabel.vue +3 -13
- package/app/components/05.forms/input-textarea/variants/tests/InputTextareaWithLabel.spec.ts +93 -0
- package/app/components/05.forms/patterns/stories/MigratedFieldsForm.stories.ts +220 -0
- package/app/components/05.forms/toggle-switch/CONSUMER-STYLING.md +29 -0
- package/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue +120 -119
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchCore.stories.ts +1 -1
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +1 -1
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +2 -2
- package/app/components/05.forms/toggle-switch/tests/ToggleSwitchCore.spec.ts +101 -0
- package/app/components/05.forms/toggle-switch/variants/ToggleSwitchWithLabel.vue +3 -5
- package/app/components/05.forms/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +1 -2
- package/app/components/05.forms/toggle-switch/variants/tests/ToggleSwitchWithLabel.spec.ts +77 -0
- package/app/components/05.forms/toggle-switch/variants/tests/ToggleSwitchWithLabelInline.spec.ts +66 -0
- package/app/components/05.forms/triple-toggle-switch/CONSUMER-STYLING.md +20 -6
- package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +12 -10
- package/app/types/components/container-glow.d.ts +8 -0
- package/app/types/components/index.ts +2 -1
- package/app/types/components/select-menu.d.ts +5 -0
- package/package.json +3 -2
- package/.vscode/srcdev-component-toggle-switch-core.code-snippets +0 -13
- package/app/components/05.forms/input-range-fancy/InputRangeFancyCore.vue +0 -426
- package/app/components/05.forms/input-range-fancy/InputRangeFancyWithLabel.vue +0 -94
- package/app/components/carousels/CarouselBasic.vue +0 -317
- package/app/components/carousels/CarouselInfinite.vue +0 -358
- package/app/components/container-glow/ContainerGlowCore.vue +0 -296
- package/app/components/container-glow/stories/ContainerGlowCore.stories.ts +0 -337
- package/app/components/display-theme-switch/DisplayThemeSwitch.vue +0 -189
- package/app/components/display-theme-switch/stories/DisplayThemeSwitch.stories.ts +0 -154
- package/app/components/glowing-border/GlowingBorder.vue +0 -142
- package/app/components/glowing-border/stories/GlowingBorder.stories.ts +0 -141
- package/app/components/layout-grids/LayoutGridB.vue +0 -134
- package/app/components/test-storybook/TestStorybook.vue +0 -49
- package/app/components/test-storybook/stories/TestStorybook.stories.ts +0 -28
- package/app/components/ui-block-decorated/UiBlockDecorated.vue +0 -167
- package/app/components/view-timeline/WipeAwayVertical.vue +0 -180
- package/app/types/components/carousel-basic.d.ts +0 -19
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import type { Meta, StoryObj } from "@nuxtjs/storybook";
|
|
3
|
+
import SelectMenu from "../SelectMenu.vue";
|
|
4
|
+
import type { SelectMenuOption } from "~/types/components/select-menu";
|
|
5
|
+
|
|
6
|
+
// ─── Meta ─────────────────────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
interface StoryArgs {
|
|
9
|
+
options?: SelectMenuOption[];
|
|
10
|
+
label?: string;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
showIcon?: boolean;
|
|
13
|
+
showLabel?: boolean;
|
|
14
|
+
showChevron?: boolean;
|
|
15
|
+
multiple?: boolean;
|
|
16
|
+
showSelectionInTrigger?: boolean;
|
|
17
|
+
modelValue?: string | number | (string | number)[];
|
|
18
|
+
styleClassPassthrough?: string | string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const meta: Meta<StoryArgs> = {
|
|
22
|
+
title: "Molecules/SelectMenu",
|
|
23
|
+
component: SelectMenu,
|
|
24
|
+
argTypes: {
|
|
25
|
+
label: {
|
|
26
|
+
control: { type: "text" },
|
|
27
|
+
description: "Accessible name for the trigger/listbox. Also the trigger's fallback text when nothing is selected and no placeholder is set.",
|
|
28
|
+
table: { category: "Content" },
|
|
29
|
+
},
|
|
30
|
+
placeholder: {
|
|
31
|
+
control: { type: "text" },
|
|
32
|
+
description: "Trigger text shown when nothing is selected. Falls back to `label`.",
|
|
33
|
+
table: { category: "Content" },
|
|
34
|
+
},
|
|
35
|
+
showIcon: {
|
|
36
|
+
control: { type: "boolean" },
|
|
37
|
+
description: "Show the selected option's icon in the trigger.",
|
|
38
|
+
table: { category: "Trigger content" },
|
|
39
|
+
},
|
|
40
|
+
showLabel: {
|
|
41
|
+
control: { type: "boolean" },
|
|
42
|
+
description: "Show the selected option's label text in the trigger. Turn off for an icon-only compact trigger.",
|
|
43
|
+
table: { category: "Trigger content" },
|
|
44
|
+
},
|
|
45
|
+
showChevron: {
|
|
46
|
+
control: { type: "boolean" },
|
|
47
|
+
description: "Show the trailing chevron in the trigger.",
|
|
48
|
+
table: { category: "Trigger content" },
|
|
49
|
+
},
|
|
50
|
+
multiple: {
|
|
51
|
+
control: { type: "boolean" },
|
|
52
|
+
description: "Allow selecting more than one option. Each option gets a checkbox indicator and v-model becomes an array. Selecting an option leaves the popover open.",
|
|
53
|
+
table: { category: "Content" },
|
|
54
|
+
},
|
|
55
|
+
showSelectionInTrigger: {
|
|
56
|
+
control: { type: "boolean" },
|
|
57
|
+
description: "In multiple mode, update the trigger text to a comma-separated list of the currently checked options instead of leaving it fixed on placeholder/label. No effect outside multiple mode.",
|
|
58
|
+
table: { category: "Content" },
|
|
59
|
+
},
|
|
60
|
+
styleClassPassthrough: {
|
|
61
|
+
table: { disable: true },
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
args: {
|
|
65
|
+
label: "Language",
|
|
66
|
+
showIcon: true,
|
|
67
|
+
showLabel: true,
|
|
68
|
+
showChevron: true,
|
|
69
|
+
},
|
|
70
|
+
parameters: {
|
|
71
|
+
docs: {
|
|
72
|
+
description: {
|
|
73
|
+
component:
|
|
74
|
+
"A custom listbox trigger + popover, built on the same Popover API / CSS anchor-positioning " +
|
|
75
|
+
"approach as `ActionMenu`, but for value selection rather than actions: options carry a " +
|
|
76
|
+
"value/label/icon, and `v-model` drives the current selection. By default it's single-select " +
|
|
77
|
+
"(the selected option shows a checkmark, picking one closes the menu); set `multiple` for a " +
|
|
78
|
+
"checkbox-per-option multi-select where `v-model` becomes an array and the menu stays open " +
|
|
79
|
+
"between picks. The trigger's content (icon, text, chevron) is independently togglable, so the " +
|
|
80
|
+
"same component covers an icon-only switcher, a text+chevron category filter, or a full " +
|
|
81
|
+
"icon+text+chevron select. Defaults to a look consistent with the library's other select-like " +
|
|
82
|
+
"inputs. Set shared CSS tokens globally — see `CONSUMER-STYLING.md` in the component folder.",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export default meta;
|
|
89
|
+
type Story = StoryObj<StoryArgs>;
|
|
90
|
+
|
|
91
|
+
// ─── Shared data ──────────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
const languageOptions: SelectMenuOption[] = [
|
|
94
|
+
{ value: "en", label: "English", icon: "flag:gb-4x3" },
|
|
95
|
+
{ value: "fr", label: "Français", icon: "flag:fr-4x3" },
|
|
96
|
+
{ value: "de", label: "Deutsch", icon: "flag:de-4x3" },
|
|
97
|
+
{ value: "es", label: "Español", icon: "flag:es-4x3" },
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const serviceOptions: SelectMenuOption[] = [
|
|
101
|
+
{ value: "balayage", label: "Balayage" },
|
|
102
|
+
{ value: "highlights", label: "Highlights" },
|
|
103
|
+
{ value: "full-colour", label: "Full Colour" },
|
|
104
|
+
{ value: "cut-and-finish", label: "Cut & Finish" },
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
const treatmentOptions: SelectMenuOption[] = [
|
|
108
|
+
{ value: "trim", label: "Trim" },
|
|
109
|
+
{ value: "layers", label: "Layers" },
|
|
110
|
+
{ value: "restyle", label: "Restyle" },
|
|
111
|
+
{ value: "straightening", label: "Straightening" },
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
// ─── Stories ──────────────────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Default — icon + text + chevron trigger, matching a typical language switcher.
|
|
118
|
+
*/
|
|
119
|
+
export const Default: Story = {
|
|
120
|
+
args: {
|
|
121
|
+
label: "Language",
|
|
122
|
+
},
|
|
123
|
+
render: (args) => ({
|
|
124
|
+
components: { SelectMenu },
|
|
125
|
+
setup() {
|
|
126
|
+
const value = ref("en");
|
|
127
|
+
return { args, value, languageOptions };
|
|
128
|
+
},
|
|
129
|
+
template: `
|
|
130
|
+
<div style="padding: 4rem 8rem;">
|
|
131
|
+
<SelectMenu v-bind="args" v-model="value" :options="languageOptions" />
|
|
132
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
133
|
+
modelValue: <strong>{{ value === undefined ? 'undefined' : value }}</strong>
|
|
134
|
+
</p>
|
|
135
|
+
</div>
|
|
136
|
+
`,
|
|
137
|
+
}),
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Icon-only trigger — the compact variant for tight header/nav spaces, showing
|
|
142
|
+
* only the selected option's icon (e.g. a flag) with no text or chevron.
|
|
143
|
+
*/
|
|
144
|
+
export const IconOnly: Story = {
|
|
145
|
+
name: "Icon Only — Compact Switcher",
|
|
146
|
+
args: {
|
|
147
|
+
label: "Language",
|
|
148
|
+
showLabel: false,
|
|
149
|
+
showChevron: false,
|
|
150
|
+
},
|
|
151
|
+
render: (args) => ({
|
|
152
|
+
components: { SelectMenu },
|
|
153
|
+
setup() {
|
|
154
|
+
const value = ref("en");
|
|
155
|
+
return { args, value, languageOptions };
|
|
156
|
+
},
|
|
157
|
+
template: `
|
|
158
|
+
<div style="padding: 4rem 8rem;">
|
|
159
|
+
<SelectMenu v-bind="args" v-model="value" :options="languageOptions" />
|
|
160
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
161
|
+
modelValue: <strong>{{ value === undefined ? 'undefined' : value }}</strong>
|
|
162
|
+
</p>
|
|
163
|
+
</div>
|
|
164
|
+
`,
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Icon + chevron, no text — the selected option's icon plus the dropdown
|
|
170
|
+
* chevron, with the label text hidden. Useful when the icon alone (e.g. a
|
|
171
|
+
* flag) is identifiable, but you still want the chevron affordance showing
|
|
172
|
+
* it's an interactive dropdown.
|
|
173
|
+
*/
|
|
174
|
+
export const IconWithChevron: Story = {
|
|
175
|
+
name: "Icon + Chevron — No Text",
|
|
176
|
+
args: {
|
|
177
|
+
label: "Language",
|
|
178
|
+
showLabel: false,
|
|
179
|
+
},
|
|
180
|
+
render: (args) => ({
|
|
181
|
+
components: { SelectMenu },
|
|
182
|
+
setup() {
|
|
183
|
+
const value = ref("en");
|
|
184
|
+
return { args, value, languageOptions };
|
|
185
|
+
},
|
|
186
|
+
template: `
|
|
187
|
+
<div style="padding: 4rem 8rem;">
|
|
188
|
+
<SelectMenu v-bind="args" v-model="value" :options="languageOptions" />
|
|
189
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
190
|
+
modelValue: <strong>{{ value === undefined ? 'undefined' : value }}</strong>
|
|
191
|
+
</p>
|
|
192
|
+
</div>
|
|
193
|
+
`,
|
|
194
|
+
}),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Category filter — text + chevron only (no per-option icons), with the
|
|
199
|
+
* trigger showing the category label ("Choose a service") until a value is
|
|
200
|
+
* picked. Useful for faceted filters where several SelectMenu instances sit
|
|
201
|
+
* side by side, each covering one filter category.
|
|
202
|
+
*/
|
|
203
|
+
export const CategoryFilter: Story = {
|
|
204
|
+
name: "Category Filter",
|
|
205
|
+
args: {
|
|
206
|
+
label: "Choose a service",
|
|
207
|
+
showIcon: false,
|
|
208
|
+
},
|
|
209
|
+
render: (args) => ({
|
|
210
|
+
components: { SelectMenu },
|
|
211
|
+
setup() {
|
|
212
|
+
const value = ref<string | undefined>(undefined);
|
|
213
|
+
return { args, value, serviceOptions };
|
|
214
|
+
},
|
|
215
|
+
template: `
|
|
216
|
+
<div style="padding: 4rem 8rem;">
|
|
217
|
+
<SelectMenu v-bind="args" v-model="value" :options="serviceOptions" />
|
|
218
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
219
|
+
modelValue: <strong>{{ value === undefined ? 'undefined' : value }}</strong>
|
|
220
|
+
</p>
|
|
221
|
+
</div>
|
|
222
|
+
`,
|
|
223
|
+
}),
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Multiple filter categories side by side — each SelectMenu instance is an
|
|
228
|
+
* independent single-select v-model, so a faceted filter bar is built by
|
|
229
|
+
* placing several instances next to each other.
|
|
230
|
+
*/
|
|
231
|
+
export const FilterBar: Story = {
|
|
232
|
+
name: "Filter Bar — Multiple Categories",
|
|
233
|
+
args: {},
|
|
234
|
+
render: () => ({
|
|
235
|
+
components: { SelectMenu },
|
|
236
|
+
setup() {
|
|
237
|
+
const service = ref<string | undefined>(undefined);
|
|
238
|
+
const stylist = ref<string | undefined>(undefined);
|
|
239
|
+
const stylistOptions: SelectMenuOption[] = [
|
|
240
|
+
{ value: "any", label: "Any stylist" },
|
|
241
|
+
{ value: "alex", label: "Alex Morgan" },
|
|
242
|
+
{ value: "sam", label: "Sam Patel" },
|
|
243
|
+
];
|
|
244
|
+
return { service, stylist, serviceOptions, stylistOptions };
|
|
245
|
+
},
|
|
246
|
+
template: `
|
|
247
|
+
<div style="padding: 4rem 8rem;">
|
|
248
|
+
<div style="display: flex; gap: 1.2rem; flex-wrap: wrap;">
|
|
249
|
+
<SelectMenu label="Choose a service" v-model="service" :options="serviceOptions" />
|
|
250
|
+
<SelectMenu label="Choose a stylist" v-model="stylist" :options="stylistOptions" />
|
|
251
|
+
</div>
|
|
252
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
253
|
+
service: <strong>{{ service === undefined ? 'undefined' : service }}</strong>,
|
|
254
|
+
stylist: <strong>{{ stylist === undefined ? 'undefined' : stylist }}</strong>
|
|
255
|
+
</p>
|
|
256
|
+
</div>
|
|
257
|
+
`,
|
|
258
|
+
}),
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Multi-select — `multiple` turns each option into a checkbox row and
|
|
263
|
+
* `v-model` becomes an array. Picking an option toggles it and leaves the
|
|
264
|
+
* popover open so more can be selected. The trigger text stays fixed on
|
|
265
|
+
* `label` (e.g. "Services required") as a static category tag regardless of
|
|
266
|
+
* how many options are checked — it does not update to list the selection.
|
|
267
|
+
*/
|
|
268
|
+
export const MultiSelect: Story = {
|
|
269
|
+
name: "Multi-Select — Checkboxes",
|
|
270
|
+
args: {
|
|
271
|
+
label: "Services required",
|
|
272
|
+
showIcon: false,
|
|
273
|
+
multiple: true,
|
|
274
|
+
},
|
|
275
|
+
render: (args) => ({
|
|
276
|
+
components: { SelectMenu },
|
|
277
|
+
setup() {
|
|
278
|
+
const value = ref<string[]>([]);
|
|
279
|
+
return { args, value, treatmentOptions };
|
|
280
|
+
},
|
|
281
|
+
template: `
|
|
282
|
+
<div style="padding: 4rem 8rem;">
|
|
283
|
+
<SelectMenu v-bind="args" v-model="value" :options="treatmentOptions" />
|
|
284
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
285
|
+
modelValue: <strong>{{ value.length ? value.join(', ') : '[]' }}</strong>
|
|
286
|
+
</p>
|
|
287
|
+
</div>
|
|
288
|
+
`,
|
|
289
|
+
}),
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Multi-select with the trigger showing the current selection —
|
|
294
|
+
* `showSelectionInTrigger` opts out of the static-label default, so the
|
|
295
|
+
* trigger updates to a comma-joined list of checked options as they're
|
|
296
|
+
* toggled, falling back to `label`/`placeholder` when nothing is checked.
|
|
297
|
+
*/
|
|
298
|
+
export const MultiSelectShowingSelection: Story = {
|
|
299
|
+
name: "Multi-Select — Trigger Shows Selection",
|
|
300
|
+
args: {
|
|
301
|
+
label: "Services required",
|
|
302
|
+
showIcon: false,
|
|
303
|
+
multiple: true,
|
|
304
|
+
showSelectionInTrigger: true,
|
|
305
|
+
},
|
|
306
|
+
render: (args) => ({
|
|
307
|
+
components: { SelectMenu },
|
|
308
|
+
setup() {
|
|
309
|
+
const value = ref<string[]>(["layers", "restyle"]);
|
|
310
|
+
return { args, value, treatmentOptions };
|
|
311
|
+
},
|
|
312
|
+
template: `
|
|
313
|
+
<div style="padding: 4rem 8rem;">
|
|
314
|
+
<SelectMenu v-bind="args" v-model="value" :options="treatmentOptions" />
|
|
315
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
316
|
+
modelValue: <strong>{{ value.length ? value.join(', ') : '[]' }}</strong>
|
|
317
|
+
</p>
|
|
318
|
+
</div>
|
|
319
|
+
`,
|
|
320
|
+
}),
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Custom tokens — a per-instance styleClassPassthrough overriding the public
|
|
325
|
+
* --select-menu-* tokens to demonstrate full visual customisation.
|
|
326
|
+
*/
|
|
327
|
+
export const CustomTokens: Story = {
|
|
328
|
+
name: "Custom Tokens",
|
|
329
|
+
args: {
|
|
330
|
+
label: "Language",
|
|
331
|
+
},
|
|
332
|
+
render: (args) => ({
|
|
333
|
+
components: { SelectMenu },
|
|
334
|
+
setup() {
|
|
335
|
+
const value = ref("en");
|
|
336
|
+
return { args, value, languageOptions };
|
|
337
|
+
},
|
|
338
|
+
template: `
|
|
339
|
+
<div style="padding: 4rem 8rem;">
|
|
340
|
+
<style>
|
|
341
|
+
.select-menu.dark-pill {
|
|
342
|
+
--select-menu-trigger-border-radius: 999rem;
|
|
343
|
+
--select-menu-trigger-surface: #1a1a1a;
|
|
344
|
+
--select-menu-trigger-text-color: #ffffff;
|
|
345
|
+
--select-menu-trigger-border: #333333;
|
|
346
|
+
--select-menu-popover-surface: #1a1a1a;
|
|
347
|
+
--select-menu-popover-border: #333333;
|
|
348
|
+
--select-menu-item-text-color: #ffffff;
|
|
349
|
+
--select-menu-item-surface-hover: #2a2a2a;
|
|
350
|
+
}
|
|
351
|
+
</style>
|
|
352
|
+
<SelectMenu v-bind="args" v-model="value" :options="languageOptions" :style-class-passthrough="['dark-pill']" />
|
|
353
|
+
<p style="margin: 1.6rem 0 0; font-size: 1.3rem; opacity: 0.6;">
|
|
354
|
+
modelValue: <strong>{{ value === undefined ? 'undefined' : value }}</strong>
|
|
355
|
+
</p>
|
|
356
|
+
</div>
|
|
357
|
+
`,
|
|
358
|
+
}),
|
|
359
|
+
};
|