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.
- package/.claude/commands/migrate-component.md +18 -0
- package/.claude/component-ledger/audit.json +1 -1
- package/.claude/component-ledger/output.html +1 -1
- package/.claude/skills/components/input-number-core.md +214 -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/select-menu.md +195 -0
- package/.claude/skills/components/toggle-switch-core.md +150 -0
- package/.claude/skills/index.md +5 -0
- package/.vscode/srcdev-component-input-number.code-snippets +65 -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-select-menu.code-snippets +65 -0
- package/.vscode/srcdev-component-toggle-switch.code-snippets +49 -0
- package/app/components/01.atoms/animations/container-glow/CONSUMER-STYLING.md +1 -1
- package/app/components/01.atoms/animations/container-glow/ContainerGlow.vue +1 -1
- 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 +1 -1
- package/app/components/01.atoms/animations/section-parallax/SectionParallax.vue +1 -1
- package/app/components/01.atoms/canvas-switcher/CONSUMER-STYLING.md +2 -2
- package/app/components/01.atoms/canvas-switcher/CanvasSwitcher.vue +2 -2
- 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 +2 -2
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/DashboardQuadGrid.vue +2 -2
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/stories/DashboardQuadGrid.stories.ts +1 -1
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/CONSUMER-STYLING.md +1 -1
- package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/DashboardStatsGrid.vue +1 -1
- 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/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/pricing-card/CONSUMER-STYLING.md +11 -0
- package/app/components/02.molecules/pricing-card/PricingCard.vue +3 -1
- package/app/components/02.molecules/pricing-card/stories/PricingCard.stories.ts +2 -0
- package/app/components/02.molecules/pricing-card/tests/PricingCard.spec.ts +13 -0
- 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 +3 -3
- package/app/components/03.organisms/image-galleries/carousel-flip/CarouselFlip.vue +3 -3
- package/app/components/03.organisms/image-galleries/carousel-flip/stories/CarouselFlip.stories.ts +18 -18
- 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 +2 -2
- package/app/components/05.forms/input-range/InputRangeCore.vue +2 -2
- 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 +95 -10
- 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 +4 -4
- package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +6 -6
- package/app/types/components/index.ts +1 -0
- package/app/types/components/select-menu.d.ts +5 -0
- package/package.json +1 -1
- package/.vscode/srcdev-component-toggle-switch-core.code-snippets +0 -13
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# SelectMenu
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`SelectMenu` is a trigger-and-popover component for selecting from a list of options — a custom,
|
|
6
|
+
fully token-styled alternative to a native `<select>` or `InputSelectCore`, built for non-form
|
|
7
|
+
contexts (language switchers, category filters, faceted filter bars, multi-pick treatment lists).
|
|
8
|
+
It reuses the same Popover API + CSS anchor-positioning mechanism as `ActionMenu` (see that skill
|
|
9
|
+
doc), but its items carry a `value`/`label`/optional `icon`, and the whole thing is driven by
|
|
10
|
+
`v-model` instead of slotted actions. Defaults to single-select (checkmark, closes on pick); set
|
|
11
|
+
`multiple` for a checkbox-per-option multi-select where `v-model` is an array and the popover stays
|
|
12
|
+
open between picks.
|
|
13
|
+
|
|
14
|
+
**Location**: `app/components/02.molecules/select-menu/`
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Components
|
|
19
|
+
|
|
20
|
+
### SelectMenu
|
|
21
|
+
|
|
22
|
+
| Prop | Type | Default | Notes |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `options` | `SelectMenuOption[]` | — | **Required.** `{ value: string \| number; label: string; icon?: string }[]`. |
|
|
25
|
+
| `label` | `string` | — | **Required.** Accessible name for the trigger + listbox (`aria-label`). Also the trigger's fallback text when nothing is selected and no `placeholder` is set — this doubles as a visible category tag, e.g. `"Choose a service"`. |
|
|
26
|
+
| `placeholder` | `string` | `undefined` | Trigger text shown when nothing is selected. Falls back to `label` when omitted. |
|
|
27
|
+
| `showIcon` | `boolean` | `true` | Show the selected option's icon in the trigger. |
|
|
28
|
+
| `showLabel` | `boolean` | `true` | Show the selected option's label (or placeholder/label fallback) text in the trigger. Set `false` for an icon-only compact trigger. |
|
|
29
|
+
| `showChevron` | `boolean` | `true` | Show the trailing chevron in the trigger. |
|
|
30
|
+
| `multiple` | `boolean` | `false` | Allow selecting more than one option. Each option gets a checkbox indicator, `v-model` becomes an array, and picking an option leaves the popover open so more can be toggled. Trigger icon is not shown when `true` (no single option to represent). |
|
|
31
|
+
| `showSelectionInTrigger` | `boolean` | `false` | Multiple mode only. When `true`, the trigger text updates to a comma-separated list of the currently checked options instead of staying fixed on `placeholder`/`label`. No effect outside `multiple`. |
|
|
32
|
+
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes on the root `<div>`. |
|
|
33
|
+
|
|
34
|
+
**v-model**
|
|
35
|
+
|
|
36
|
+
`defineModel<string | number | (string | number)[] | undefined>({ default: undefined })` — the
|
|
37
|
+
selected value(s). In single-select mode (default) it's the one selected option's `value`, or
|
|
38
|
+
`undefined` if nothing is selected — a valid, expected state that renders the placeholder. With
|
|
39
|
+
`multiple`, it's an array of selected values (`[]` when nothing is selected). `{ default: undefined }`
|
|
40
|
+
is this repo's fix for the `vue/require-default-prop` false positive on `defineModel`-declared
|
|
41
|
+
props that are legitimately optional — unlike `InputSelectCore`'s `modelValue`, which uses
|
|
42
|
+
`{ required: true }` because a native form field genuinely can't be meaningfully empty, this model
|
|
43
|
+
is optional by design (see that rule's `defineModel` gap noted in the repo's ledger `eslint_issues`
|
|
44
|
+
docs). For several independent single-select categories, place multiple `SelectMenu` instances
|
|
45
|
+
side by side rather than using `multiple` on one instance — see the "Filter bar" section below.
|
|
46
|
+
|
|
47
|
+
**Type import**
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import type { SelectMenuOption } from "~/types/components/select-menu";
|
|
51
|
+
// consuming apps: import type { SelectMenuOption } from "srcdev-nuxt-components";
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Basic usage
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<script setup lang="ts">
|
|
60
|
+
import type { SelectMenuOption } from "~/types/components/select-menu";
|
|
61
|
+
|
|
62
|
+
const language = ref<string>("en");
|
|
63
|
+
const languageOptions: SelectMenuOption[] = [
|
|
64
|
+
{ value: "en", label: "English", icon: "flag:gb-4x3" },
|
|
65
|
+
{ value: "fr", label: "Français", icon: "flag:fr-4x3" },
|
|
66
|
+
];
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<SelectMenu v-model="language" :options="languageOptions" label="Language" />
|
|
71
|
+
</template>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Trigger content variants
|
|
77
|
+
|
|
78
|
+
| Variant | Usage |
|
|
79
|
+
|---|---|
|
|
80
|
+
| Icon-only (compact switcher, e.g. a flag in a tight header) | `:show-label="false" :show-chevron="false"` |
|
|
81
|
+
| Icon + chevron, no text (flag with a visible dropdown affordance) | `:show-label="false"` |
|
|
82
|
+
| Text + chevron (category filter, no per-option icons) | `:show-icon="false"` |
|
|
83
|
+
| Icon + text + chevron (full select) | Defaults — no overrides needed |
|
|
84
|
+
|
|
85
|
+
When nothing is selected, the trigger shows `placeholder` (or `label` if no placeholder is given)
|
|
86
|
+
— this is what makes it work as a filter-category tag, e.g. a `SelectMenu` with
|
|
87
|
+
`label="Choose a service"` and no `placeholder` shows "Choose a service" until an option is
|
|
88
|
+
picked, then swaps to the selected option's label.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Multi-select (checkboxes)
|
|
93
|
+
|
|
94
|
+
Set `multiple` to turn every option into a checkbox row. `v-model` becomes an array, and clicking
|
|
95
|
+
an option toggles it without closing the popover:
|
|
96
|
+
|
|
97
|
+
```vue
|
|
98
|
+
<script setup lang="ts">
|
|
99
|
+
const treatments = ref<string[]>([]);
|
|
100
|
+
const treatmentOptions = [
|
|
101
|
+
{ value: "trim", label: "Trim" },
|
|
102
|
+
{ value: "layers", label: "Layers" },
|
|
103
|
+
{ value: "restyle", label: "Restyle" },
|
|
104
|
+
{ value: "straightening", label: "Straightening" },
|
|
105
|
+
];
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<template>
|
|
109
|
+
<SelectMenu v-model="treatments" :options="treatmentOptions" label="Services required" multiple />
|
|
110
|
+
</template>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Unlike single-select, the trigger text stays fixed by default on `placeholder`/`label` as a static
|
|
114
|
+
category tag regardless of the current selection — it doesn't update to list checked options, so
|
|
115
|
+
`label="Services required"` remains visible in the trigger the whole time. Use the checkboxes
|
|
116
|
+
inside the open popover to see what's currently selected.
|
|
117
|
+
|
|
118
|
+
Set `showSelectionInTrigger` to opt out of that and have the trigger update instead:
|
|
119
|
+
|
|
120
|
+
```vue
|
|
121
|
+
<SelectMenu
|
|
122
|
+
v-model="treatments"
|
|
123
|
+
:options="treatmentOptions"
|
|
124
|
+
label="Services required"
|
|
125
|
+
multiple
|
|
126
|
+
show-selection-in-trigger
|
|
127
|
+
/>
|
|
128
|
+
<!-- Trigger reads e.g. "Layers, Restyle" once those two are checked, falling back to
|
|
129
|
+
"Services required" again if everything is unchecked. -->
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Filter bar (multiple categories)
|
|
135
|
+
|
|
136
|
+
`SelectMenu` is single-select per instance — a faceted filter bar is built by placing one instance
|
|
137
|
+
per category, each with its own `v-model`:
|
|
138
|
+
|
|
139
|
+
```vue
|
|
140
|
+
<template>
|
|
141
|
+
<div style="display: flex; gap: 1.2rem;">
|
|
142
|
+
<SelectMenu label="Choose a service" v-model="service" :options="serviceOptions" />
|
|
143
|
+
<SelectMenu label="Choose a stylist" v-model="stylist" :options="stylistOptions" />
|
|
144
|
+
</div>
|
|
145
|
+
</template>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## CSS token API
|
|
151
|
+
|
|
152
|
+
See `CONSUMER-STYLING.md` in the component folder for the full token reference. Default styling
|
|
153
|
+
targets the same visual language as the library's other select-like controls (border, background,
|
|
154
|
+
radius, focus ring drawn from `--theme-*` tokens).
|
|
155
|
+
|
|
156
|
+
Quick reference:
|
|
157
|
+
|
|
158
|
+
```css
|
|
159
|
+
/* assets/styles/setup/07.components/select-menu.css */
|
|
160
|
+
:root {
|
|
161
|
+
--select-menu-trigger-border-radius: 999rem;
|
|
162
|
+
--select-menu-trigger-surface: var(--brand-surface);
|
|
163
|
+
--select-menu-popover-surface: var(--brand-surface);
|
|
164
|
+
--select-menu-item-surface-hover: var(--brand-surface-subtle);
|
|
165
|
+
--select-menu-item-check-color: var(--brand-accent);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Notes
|
|
172
|
+
|
|
173
|
+
- **Popover API + CSS anchor positioning** — same mechanism as `ActionMenu`. Broadly supported
|
|
174
|
+
(Chrome 114+, Firefox 125+, Safari 17+). No polyfill is included.
|
|
175
|
+
- **Left-aligned popover** (`left: anchor(left)`) — unlike `ActionMenu` which right-aligns. Matches
|
|
176
|
+
native `<select>` dropdown behaviour. Flips above the trigger near the bottom of the viewport.
|
|
177
|
+
- **Keyboard navigation** follows the WAI-ARIA listbox pattern: `ArrowDown`/`ArrowUp` move between
|
|
178
|
+
options (wraps around), `Home`/`End` jump to first/last, `Enter`/`Space` select the focused
|
|
179
|
+
option, `Tab` closes without stealing focus back to the trigger (matches `ActionMenu`'s
|
|
180
|
+
`handleKeydown` convention — see that skill doc's note on the `currentIndex === -1` guard, which
|
|
181
|
+
applies identically here). `Enter`/`Space` close the popover in single-select mode but only
|
|
182
|
+
toggle the checkbox (leaving it open) when `multiple` is set.
|
|
183
|
+
- **Opens focused on the current selection** — `handleToggle` focuses the first selected
|
|
184
|
+
`[role="option"]` if one exists (in `multiple` mode, the first checked item), otherwise the first
|
|
185
|
+
option (unlike `ActionMenu`, which always focuses the first item since it has no selection state).
|
|
186
|
+
- **`aria-multiselectable="true"`** is set on the listbox only when `multiple` is `true`.
|
|
187
|
+
- **Chevron rotation is pure CSS** via `:has(.select-menu-popover:popover-open)` on the root — no
|
|
188
|
+
JS state drives the visual. `isOpen` is still tracked internally, but only to set `aria-expanded`
|
|
189
|
+
on the trigger.
|
|
190
|
+
- **No native `<select>`/`appearance: base-select` involved** — this is a from-scratch popover
|
|
191
|
+
listbox, not a styled native select, so it doesn't inherit `InputSelectCore`'s WebKit
|
|
192
|
+
`appearance: base-select` constraints.
|
|
193
|
+
- **Not a form field** — `SelectMenu` has no `fieldHasError`/`theme`/`inputVariant` props like the
|
|
194
|
+
`05.forms` inputs. Use `InputSelectCore` instead for an actual form field that needs validation
|
|
195
|
+
state and native `<select>` semantics.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# ToggleSwitchCore Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`ToggleSwitchCore` is the low-level pill-shaped (or square, via `round`) toggle switch primitive
|
|
6
|
+
for the `05.forms` toggle family. It renders a visually-hidden native `<input type="checkbox">`
|
|
7
|
+
(kept in the DOM for real keyboard/checkbox semantics) plus a styled track/thumb visual, with
|
|
8
|
+
optional icon slots shown inside the thumb for the on/off states. It has no label, description, or
|
|
9
|
+
error-message rendering of its own — that's composed by the `ToggleSwitchWithLabel` and
|
|
10
|
+
`ToggleSwitchWithLabelInline` variants below.
|
|
11
|
+
|
|
12
|
+
Most consumers should reach for **ToggleSwitchWithLabel** or **ToggleSwitchWithLabelInline** rather
|
|
13
|
+
than `ToggleSwitchCore` directly.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Props reference
|
|
18
|
+
|
|
19
|
+
> **Hyphenation rule**: Vue's ESLint config enforces `vue/attribute-hyphenation`. Always write camelCase prop names hyphenated in templates: `:field-has-error`, `:style-class-passthrough`, `:aria-describedby`, `:true-value`, `:false-value`.
|
|
20
|
+
|
|
21
|
+
| Prop (template form) | Type | Default | Notes |
|
|
22
|
+
|------|------|---------|-------|
|
|
23
|
+
| `:id` | `string` | (required) | Combined with a fixed prefix to build the native input's `id` (`toggle-switch-${id}`). |
|
|
24
|
+
| `:name` | `string` | (required) | Applied to the native checkbox. |
|
|
25
|
+
| `:required` | `boolean` | `false` | Native `required`. |
|
|
26
|
+
| `:field-has-error` | `boolean` | `false` | Drives `aria-invalid` on the checkbox, and switches `data-theme` to `"error"` regardless of the `theme` prop's own value. |
|
|
27
|
+
| `:true-value` / `:false-value` | `string \| number \| boolean` | `true` / `false` | The two values `v-model` toggles between. |
|
|
28
|
+
| `:style-class-passthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the root element. |
|
|
29
|
+
| `:theme` | `FormUiTheme` | `"default"` | Sets `data-theme` on the root (superseded by `"error"` when `field-has-error` is true — see above). |
|
|
30
|
+
| `:round` | `boolean` | `true` | `true` renders a pill-shaped track/thumb (`border-radius: 100vw`); `false` renders a rounded-square shape (`border-radius: 0.4rem`). See the `--toggle-switch-border-radius` token in CONSUMER-STYLING.md to override the exact value either state produces. |
|
|
31
|
+
| `:aria-describedby` | `string` | `""` | Forwarded to the native checkbox. |
|
|
32
|
+
|
|
33
|
+
### v-model
|
|
34
|
+
|
|
35
|
+
- `v-model` — `string | number | boolean`, **required** (`defineModel({ required: true })`, satisfying `vue/require-default-prop` — see `project_ledger_eslint_issues_column` in memory).
|
|
36
|
+
|
|
37
|
+
### Slots
|
|
38
|
+
|
|
39
|
+
- `iconOn` / `iconOff` — replace the default `material-symbols:circle-outline` icon shown inside the thumb for each state. Providing either slot switches off the `use-default-icons` wrapper class (checked via `useSlots()`, so this only reacts to slot *presence*, not conditional slot content).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## CSS token API
|
|
44
|
+
|
|
45
|
+
See [CONSUMER-STYLING.md](../../app/components/05.forms/toggle-switch/CONSUMER-STYLING.md) for the
|
|
46
|
+
full table with defaults.
|
|
47
|
+
|
|
48
|
+
**Common tokens:**
|
|
49
|
+
- `--toggle-switch-surface` / `-surface-hover` — track background resting/hover, fall back to `--theme-checkbox-symbol-surface`/`--theme-surface-subtle`
|
|
50
|
+
- `--toggle-switch-border` / `-border-focus` — track border colour, and `:focus-visible` outline colour, fall back to `--theme-border`/`--theme-border-focus`
|
|
51
|
+
- `--toggle-switch-symbol-surface-off` / `-symbol-surface-on` — thumb background unchecked/checked
|
|
52
|
+
- `--toggle-switch-border-radius` — track and thumb shape; see the `round` prop above
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Fixed 2026-09-23: dead functionality and story bugs
|
|
57
|
+
|
|
58
|
+
`ToggleSwitchCore` (and its two variants) migrated to full compliance from a `variants:true`,
|
|
59
|
+
`eslint_issues:true`, score-3/5 state (no tests, no skill doc).
|
|
60
|
+
|
|
61
|
+
- **`round` prop was completely dead** — both variants declared and forwarded it to
|
|
62
|
+
`ToggleSwitchCore`, and Storybook's `SquareShape` story existed specifically to demonstrate
|
|
63
|
+
`round: false`, but `ToggleSwitchCore` never declared the prop at all, so it silently fell
|
|
64
|
+
through as an inert `round` DOM attribute on the root `<div>` and the track/thumb stayed pill-shaped
|
|
65
|
+
regardless. Fixed by adding `round` to `ToggleSwitchCore` and wiring it to a new
|
|
66
|
+
`--toggle-switch-border-radius` token (100vw when round, 0.4rem when square).
|
|
67
|
+
- **`fieldHasError` didn't switch the component's theme** — `ToggleSwitchCore` and
|
|
68
|
+
`ToggleSwitchWithLabel` both computed an error-aware theme value but bound `data-theme` to the
|
|
69
|
+
raw `theme` prop instead of that computed, so this library's `[data-theme="error"]` global
|
|
70
|
+
token overrides never applied when a consumer set `fieldHasError`. Fixed by binding `data-theme`
|
|
71
|
+
to the computed value in both files.
|
|
72
|
+
- **An invalid `for` attribute on a `<div>`** (`.toggle-switch-wrapper`) was removed — `for` is
|
|
73
|
+
only a valid HTML attribute on `<label>`/`<output>`, so it was inert dead markup; the real
|
|
74
|
+
label association is via `InputLabel`'s own `for`/`id` wiring in the variants.
|
|
75
|
+
- **`defineModel` had no default**, tripping `vue/require-default-prop` (a known false-positive
|
|
76
|
+
for `defineModel` — see `project_ledger_eslint_issues_column` in memory) — fixed with
|
|
77
|
+
`{ required: true }` across `ToggleSwitchCore` and both variants, since a checkbox genuinely
|
|
78
|
+
can't be meaningfully empty.
|
|
79
|
+
- **Two dead, unread `--_transition-duration` private tokens** (one per variant) were removed —
|
|
80
|
+
nothing in either variant's own CSS or `ToggleSwitchCore`'s ever read them; the actual
|
|
81
|
+
transition durations are hardcoded `0.4s` literals inside `ToggleSwitchCore`.
|
|
82
|
+
- **Custom `iconOn`/`iconOff` slot content could render as a non-square box, throwing off
|
|
83
|
+
centering** — `.symbol-icon` is `display: grid; place-content: center;`, and its single
|
|
84
|
+
auto-sized track shrink-wraps to the slotted content's own box. A plain inline element (e.g. a
|
|
85
|
+
`<span>` wrapping a 16×16 SVG, as in the `WithCustomIcons` stories) sizes to its line box's
|
|
86
|
+
leading rather than its intrinsic height, rendering as ~16×20 instead of 16×16. Fixed by adding
|
|
87
|
+
`line-height: 0` to `.symbol-icon`, which collapses that leading for whatever markup a consumer
|
|
88
|
+
slots in. The default icon (`@nuxt/icon`'s `Icon` component) wasn't affected, since iconify sets
|
|
89
|
+
its own sizing/`vertical-align` internally.
|
|
90
|
+
- **All three story files' `theme` control listed the wrong option set**
|
|
91
|
+
(`["primary", "secondary", "tertiary", "ghost", "error", "success", "warning"]`, none of which
|
|
92
|
+
match `FormUiTheme`) — fixed to the real `["default", "success", "error", "warning"]`.
|
|
93
|
+
`ToggleSwitchWithLabelInline.stories.ts`'s `InlineFormExample` story also passed the now-invalid
|
|
94
|
+
`theme="secondary"` directly — fixed to `"default"`.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Variants
|
|
99
|
+
|
|
100
|
+
### ToggleSwitchWithLabel
|
|
101
|
+
|
|
102
|
+
`ToggleSwitchWithLabel` (`variants/ToggleSwitchWithLabel.vue`) composes `ToggleSwitchCore` with
|
|
103
|
+
`InputLabel`, an optional `description` slot, and `InputError`.
|
|
104
|
+
|
|
105
|
+
**Additional props over ToggleSwitchCore:**
|
|
106
|
+
|
|
107
|
+
| Prop (template form) | Type | Default | Notes |
|
|
108
|
+
|------|------|---------|-------|
|
|
109
|
+
| `:label` | `string` | (required) | Rendered via `InputLabel`. |
|
|
110
|
+
| `:error-message` | `object \| string` | `""` | Rendered via `InputError` when `field-has-error` is true. |
|
|
111
|
+
|
|
112
|
+
Note this wrapper passes `id`/`name`/`required`/`field-has-error`/`true-value`/`false-value`/
|
|
113
|
+
`theme`/`round`/`aria-describedby` straight through to `ToggleSwitchCore`; `id` is a self-generated
|
|
114
|
+
`useId()` value, not a prop — consumers don't set it directly.
|
|
115
|
+
|
|
116
|
+
**Slots**: `description`, `iconOn`, `iconOff` (the latter two forwarded to `ToggleSwitchCore`).
|
|
117
|
+
|
|
118
|
+
```vue
|
|
119
|
+
<ToggleSwitchWithLabel
|
|
120
|
+
name="notifications"
|
|
121
|
+
label="Enable notifications"
|
|
122
|
+
v-model="notificationsEnabled"
|
|
123
|
+
:error-message="errors.notifications"
|
|
124
|
+
:field-has-error="!!errors.notifications"
|
|
125
|
+
>
|
|
126
|
+
<template #description>Turn this on to receive notifications</template>
|
|
127
|
+
</ToggleSwitchWithLabel>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### ToggleSwitchWithLabelInline
|
|
131
|
+
|
|
132
|
+
`ToggleSwitchWithLabelInline` (`variants/ToggleSwitchWithLabelInline.vue`) composes
|
|
133
|
+
`ToggleSwitchCore` with `InputLabel` laid out inline (label and switch side by side, no
|
|
134
|
+
description/error-message support — this variant is for compact settings-row usage).
|
|
135
|
+
|
|
136
|
+
**Additional props over ToggleSwitchCore:**
|
|
137
|
+
|
|
138
|
+
| Prop (template form) | Type | Default | Notes |
|
|
139
|
+
|------|------|---------|-------|
|
|
140
|
+
| `:label` | `string` | (required) | Rendered via `InputLabel`. |
|
|
141
|
+
| `:label-weight` | `LabelWeight` (`"normal" \| "semi-bold" \| "bold"`) | `"normal"` | Maps to a `body-normal`/`body-normal-semibold`/`body-normal-bold` class on the label. |
|
|
142
|
+
|
|
143
|
+
This variant has no `required`/`field-has-error`/`error-message` props — it never claimed error-state
|
|
144
|
+
support, unlike `ToggleSwitchWithLabel`.
|
|
145
|
+
|
|
146
|
+
**Slots**: `iconOn`, `iconOff` (forwarded to `ToggleSwitchCore`).
|
|
147
|
+
|
|
148
|
+
```vue
|
|
149
|
+
<ToggleSwitchWithLabelInline name="darkMode" label="Dark mode" v-model="darkModeEnabled" />
|
|
150
|
+
```
|
package/.claude/skills/index.md
CHANGED
|
@@ -107,6 +107,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
107
107
|
├── display-theme-switch.md — DisplayThemeSwitch: system/light/dark picker wrapping TripleToggleSwitchCore, wired to useSettingsStore, labels/icons props, small sizing variant
|
|
108
108
|
├── card-core.md — CardCore: generic card container, dynamic named slots as rows, 4 variants, blurred backdrop layer, full CSS token API
|
|
109
109
|
├── action-menu.md — ActionMenu + ActionMenuItemCore: ellipsis trigger + anchored popover menu, indexed item-{n} slots, link/button items, full CSS token API
|
|
110
|
+
├── select-menu.md — SelectMenu: v-model single-select listbox popover (ActionMenu's popover mechanics, InputSelectCore's selected-option semantics), icon/text/chevron trigger toggles, checkmark on selected option, options-array driven, full CSS token API
|
|
110
111
|
├── display-dialog.md — DisplayDialog: native <dialog> overlay, 5 variants (dialog/modal/confirm/alert/fullscreen), useDialogControls integration, CSS token API
|
|
111
112
|
├── display-chip.md — DisplayChip: status indicator chip overlay, CSS trig positioning, circle/square shapes, status colours, icon/label content
|
|
112
113
|
├── display-pill.md — DisplayPill: pill/badge label with icon slot, 6 variants, 3 sizes, reversible order, full CSS token API for border/outline/colour
|
|
@@ -127,6 +128,10 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
127
128
|
├── pop-over.md — PopOver: generic anchor-positioned disclosure panel, consumer-supplied trigger/content slots, placement prop, CSS token API
|
|
128
129
|
├── input-text-core.md — InputTextCore: native text/date/number input primitive, min/max pass-through (date-picker range), CSS token API; Variants section covers InputTextWithLabel/InputPasswordWithLabel/InputTextAsNumberWithLabel
|
|
129
130
|
├── input-range-core.md — InputRangeCore: native range-slider primitive, markers/datalist slots, dead --theme-form-range-accent-color token fixed, CSS token API; Variants section covers InputRangeDefault
|
|
131
|
+
├── input-number-core.md — InputNumberCore: native number-input primitive, left/right step-button slots, missing base class/placeholder/mismatched slot-selector bugs fixed, CSS token API; Variants section covers InputNumberDefault
|
|
132
|
+
├── input-textarea-core.md — InputTextareaCore: native textarea primitive, left/right decorative slots, undefined-token/dead-code/label-leak bugs fixed, CSS token API; Variants section covers InputTextareaWithLabel
|
|
133
|
+
├── input-select-core.md — InputSelectCore: native select primitive, data-driven options with icon decorator, dead required/styleClassPassthrough/isDirty-isActive functionality fixed, appearance:base-select browser-support note, CSS token API; Variants section covers InputSelectWithLabel
|
|
134
|
+
├── toggle-switch-core.md — ToggleSwitchCore: pill/square checkbox-backed toggle primitive, dead round-prop/data-theme-error functionality and story theme-options bugs fixed, CSS token API; Variants section covers ToggleSwitchWithLabel/ToggleSwitchWithLabelInline
|
|
130
135
|
├── entry-animation.md — EntryAnimation: scroll-driven entry animation wrapper (slide-in/zoom-reveal/exit-blur utility classes), skipAnimation for above-the-fold loop items, reduced-motion handled at the CSS layer
|
|
131
136
|
├── column-flow-grid.md — ColumnFlowGrid (renamed from MasonryGrid): CSS multi-column text-flow layout, named dynamic slots (no count/data prop), itemMinWidth/gap/unit sizing, CSS token API; not a true masonry, see "which one do I want?"
|
|
132
137
|
├── masonry-grid.md — MasonryGrid: real measured-height masonry (greedy shortest-column packing, animated resize) absorbed from the now-retired MasonryGridOrdered; named dynamic slots, fixedWidth/justify, CSS token API
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV InputNumberCore Basic": {
|
|
3
|
+
"description": "Basic InputNumberCore native number input (no label/error wrapper)",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<InputNumberCore",
|
|
7
|
+
" id=\"$1fieldId\"",
|
|
8
|
+
" name=\"$2fieldName\"",
|
|
9
|
+
" v-model=\"$3fieldValue\"",
|
|
10
|
+
" :min=\"$40\"",
|
|
11
|
+
" :max=\"$5100\"",
|
|
12
|
+
" :step=\"$61\"",
|
|
13
|
+
"/>"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"SRCDEV InputNumberDefault Basic": {
|
|
17
|
+
"description": "InputNumberDefault: labelled number input with error/description support",
|
|
18
|
+
"scope": "vue,html",
|
|
19
|
+
"body": [
|
|
20
|
+
"<InputNumberDefault",
|
|
21
|
+
" v-model=\"$1fieldValue\"",
|
|
22
|
+
" name=\"$2fieldName\"",
|
|
23
|
+
" label=\"$3Field label\"",
|
|
24
|
+
" :min=\"$40\"",
|
|
25
|
+
" :max=\"$5100\"",
|
|
26
|
+
" :step=\"$61\"",
|
|
27
|
+
" :error-message=\"$7errors.fieldName\"",
|
|
28
|
+
" :field-has-error=\"!!$7errors.fieldName\"",
|
|
29
|
+
"/>"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"SRCDEV InputNumberDefault With Step Buttons": {
|
|
33
|
+
"description": "InputNumberDefault with step-down/step-up buttons wired into the left/right slots",
|
|
34
|
+
"scope": "vue,html",
|
|
35
|
+
"body": [
|
|
36
|
+
"<InputNumberDefault",
|
|
37
|
+
" v-model=\"$1fieldValue\"",
|
|
38
|
+
" name=\"$2fieldName\"",
|
|
39
|
+
" label=\"$3Field label\"",
|
|
40
|
+
" :min=\"$40\"",
|
|
41
|
+
" :max=\"$5100\"",
|
|
42
|
+
" :step=\"$61\"",
|
|
43
|
+
" :error-message=\"$7errors.fieldName\"",
|
|
44
|
+
" :field-has-error=\"!!$7errors.fieldName\"",
|
|
45
|
+
">",
|
|
46
|
+
" <template #left>\\u2212</template>",
|
|
47
|
+
" <template #right>+</template>",
|
|
48
|
+
"</InputNumberDefault>"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"SRCDEV InputNumber CSS Override": {
|
|
52
|
+
"description": "CSS override scaffold for InputNumberCore tokens",
|
|
53
|
+
"scope": "css",
|
|
54
|
+
"body": [
|
|
55
|
+
".$1my-page {",
|
|
56
|
+
" .input-number-wrapper {",
|
|
57
|
+
" --input-number-surface: $2;",
|
|
58
|
+
" --input-number-border: $3;",
|
|
59
|
+
" --input-number-border-hover: $4;",
|
|
60
|
+
" --input-number-border-focus: $5;",
|
|
61
|
+
" }",
|
|
62
|
+
"}"
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV InputSelectCore Basic": {
|
|
3
|
+
"description": "Basic InputSelectCore native select (no label/error wrapper)",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<InputSelectCore",
|
|
7
|
+
" id=\"$1fieldId\"",
|
|
8
|
+
" name=\"$2fieldName\"",
|
|
9
|
+
" v-model=\"$3fieldValue\"",
|
|
10
|
+
" v-model:field-data=\"$4fieldOptions\"",
|
|
11
|
+
" placeholder=\"$5Choose an option\"",
|
|
12
|
+
"/>"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"SRCDEV InputSelectWithLabel Basic": {
|
|
16
|
+
"description": "InputSelectWithLabel: labelled select with error/description support",
|
|
17
|
+
"scope": "vue,html",
|
|
18
|
+
"body": [
|
|
19
|
+
"<InputSelectWithLabel",
|
|
20
|
+
" v-model=\"$1fieldValue\"",
|
|
21
|
+
" v-model:field-data=\"$2fieldOptions\"",
|
|
22
|
+
" name=\"$3fieldName\"",
|
|
23
|
+
" label=\"$4Field label\"",
|
|
24
|
+
" placeholder=\"$5Choose an option\"",
|
|
25
|
+
" :error-message=\"$6errors.fieldName\"",
|
|
26
|
+
" :field-has-error=\"!!$6errors.fieldName\"",
|
|
27
|
+
"/>"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"SRCDEV InputSelect CSS Override": {
|
|
31
|
+
"description": "CSS override scaffold for InputSelectCore tokens",
|
|
32
|
+
"scope": "css",
|
|
33
|
+
"body": [
|
|
34
|
+
".$1my-page {",
|
|
35
|
+
" .input-select-wrapper {",
|
|
36
|
+
" --input-select-surface: $2;",
|
|
37
|
+
" --input-select-border: $3;",
|
|
38
|
+
" }",
|
|
39
|
+
"}"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV InputTextareaCore Basic": {
|
|
3
|
+
"description": "Basic InputTextareaCore native textarea (no label/error wrapper)",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<InputTextareaCore",
|
|
7
|
+
" id=\"$1fieldId\"",
|
|
8
|
+
" name=\"$2fieldName\"",
|
|
9
|
+
" v-model=\"$3fieldValue\"",
|
|
10
|
+
" placeholder=\"$4Placeholder text\"",
|
|
11
|
+
"/>"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"SRCDEV InputTextareaWithLabel Basic": {
|
|
15
|
+
"description": "InputTextareaWithLabel: labelled textarea with error/description support",
|
|
16
|
+
"scope": "vue,html",
|
|
17
|
+
"body": [
|
|
18
|
+
"<InputTextareaWithLabel",
|
|
19
|
+
" v-model=\"$1fieldValue\"",
|
|
20
|
+
" name=\"$2fieldName\"",
|
|
21
|
+
" label=\"$3Field label\"",
|
|
22
|
+
" placeholder=\"$4Placeholder text\"",
|
|
23
|
+
" :error-message=\"$5errors.fieldName\"",
|
|
24
|
+
" :field-has-error=\"!!$5errors.fieldName\"",
|
|
25
|
+
"/>"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"SRCDEV InputTextarea CSS Override": {
|
|
29
|
+
"description": "CSS override scaffold for InputTextareaCore tokens",
|
|
30
|
+
"scope": "css",
|
|
31
|
+
"body": [
|
|
32
|
+
".$1my-page {",
|
|
33
|
+
" .input-textarea-wrapper {",
|
|
34
|
+
" --input-textarea-surface: $2;",
|
|
35
|
+
" --input-textarea-border: $3;",
|
|
36
|
+
" }",
|
|
37
|
+
"}"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV SelectMenu Basic": {
|
|
3
|
+
"description": "SelectMenu — v-model single-select popover listbox",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<SelectMenu",
|
|
7
|
+
" v-model=\"${1:selectedValue}\"",
|
|
8
|
+
" :options=\"${2:options}\"",
|
|
9
|
+
" label=\"${3:Choose an option}\"",
|
|
10
|
+
"/>"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"SRCDEV SelectMenu Icon Only": {
|
|
14
|
+
"description": "SelectMenu — icon-only compact trigger (e.g. language switcher)",
|
|
15
|
+
"scope": "vue,html",
|
|
16
|
+
"body": [
|
|
17
|
+
"<SelectMenu",
|
|
18
|
+
" v-model=\"${1:language}\"",
|
|
19
|
+
" :options=\"${2:languageOptions}\"",
|
|
20
|
+
" label=\"${3:Language}\"",
|
|
21
|
+
" :show-label=\"false\"",
|
|
22
|
+
" :show-chevron=\"false\"",
|
|
23
|
+
"/>"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"SRCDEV SelectMenu Category Filter": {
|
|
27
|
+
"description": "SelectMenu — text + chevron category filter, no per-option icons",
|
|
28
|
+
"scope": "vue,html",
|
|
29
|
+
"body": [
|
|
30
|
+
"<SelectMenu",
|
|
31
|
+
" v-model=\"${1:filterValue}\"",
|
|
32
|
+
" :options=\"${2:filterOptions}\"",
|
|
33
|
+
" label=\"${3:Choose a service}\"",
|
|
34
|
+
" :show-icon=\"false\"",
|
|
35
|
+
"/>"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"SRCDEV SelectMenu Multi-Select": {
|
|
39
|
+
"description": "SelectMenu — checkbox-per-option multi-select, v-model is an array",
|
|
40
|
+
"scope": "vue,html",
|
|
41
|
+
"body": [
|
|
42
|
+
"<SelectMenu",
|
|
43
|
+
" v-model=\"${1:selectedValues}\"",
|
|
44
|
+
" :options=\"${2:options}\"",
|
|
45
|
+
" label=\"${3:Services required}\"",
|
|
46
|
+
" :show-icon=\"false\"",
|
|
47
|
+
" multiple",
|
|
48
|
+
"/>"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"SRCDEV SelectMenu Multi-Select Showing Selection": {
|
|
52
|
+
"description": "SelectMenu — multi-select where the trigger updates to list checked options",
|
|
53
|
+
"scope": "vue,html",
|
|
54
|
+
"body": [
|
|
55
|
+
"<SelectMenu",
|
|
56
|
+
" v-model=\"${1:selectedValues}\"",
|
|
57
|
+
" :options=\"${2:options}\"",
|
|
58
|
+
" label=\"${3:Services required}\"",
|
|
59
|
+
" :show-icon=\"false\"",
|
|
60
|
+
" multiple",
|
|
61
|
+
" show-selection-in-trigger",
|
|
62
|
+
"/>"
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV ToggleSwitchCore": {
|
|
3
|
+
"description": "ToggleSwitchCore — bare toggle switch (no label, use ToggleSwitchWithLabel for that)",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<ToggleSwitchCore",
|
|
7
|
+
" v-model=\"$1modelValue\"",
|
|
8
|
+
" id=\"$2toggle-id\"",
|
|
9
|
+
" name=\"$3toggleName\"",
|
|
10
|
+
"/>"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"SRCDEV ToggleSwitchWithLabel": {
|
|
14
|
+
"description": "ToggleSwitchWithLabel: labelled toggle switch with description/error support",
|
|
15
|
+
"scope": "vue,html",
|
|
16
|
+
"body": [
|
|
17
|
+
"<ToggleSwitchWithLabel",
|
|
18
|
+
" v-model=\"$1fieldValue\"",
|
|
19
|
+
" name=\"$2fieldName\"",
|
|
20
|
+
" label=\"$3Field label\"",
|
|
21
|
+
" :error-message=\"$4errors.fieldName\"",
|
|
22
|
+
" :field-has-error=\"!!$4errors.fieldName\"",
|
|
23
|
+
"/>"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"SRCDEV ToggleSwitchWithLabelInline": {
|
|
27
|
+
"description": "ToggleSwitchWithLabelInline: compact label + toggle switch side by side, no error support",
|
|
28
|
+
"scope": "vue,html",
|
|
29
|
+
"body": [
|
|
30
|
+
"<ToggleSwitchWithLabelInline",
|
|
31
|
+
" v-model=\"$1fieldValue\"",
|
|
32
|
+
" name=\"$2fieldName\"",
|
|
33
|
+
" label=\"$3Field label\"",
|
|
34
|
+
"/>"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"SRCDEV ToggleSwitch CSS Override": {
|
|
38
|
+
"description": "CSS override scaffold for ToggleSwitchCore tokens",
|
|
39
|
+
"scope": "css",
|
|
40
|
+
"body": [
|
|
41
|
+
".$1my-page {",
|
|
42
|
+
" .toggle-switch-wrapper {",
|
|
43
|
+
" --toggle-switch-surface: $2;",
|
|
44
|
+
" --toggle-switch-symbol-surface-on: $3;",
|
|
45
|
+
" }",
|
|
46
|
+
"}"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -7,7 +7,7 @@ consuming page's own stylesheet:
|
|
|
7
7
|
|
|
8
8
|
| Token | Default | Description |
|
|
9
9
|
|---|---|---|
|
|
10
|
-
| `--container-glow-background` | `
|
|
10
|
+
| `--container-glow-background` | `white` | Card background colour. |
|
|
11
11
|
| `--container-glow-padding` | `2rem` | Card inner padding. |
|
|
12
12
|
| `--container-glow-aspect-ratio` | `330 / 400` | Card aspect ratio. |
|
|
13
13
|
| `--container-glow-border-radius` | `12px` | Card and glow-effect corner radius (shared by the card and every glow layer). |
|
|
@@ -191,7 +191,7 @@ onBeforeUnmount(() => {
|
|
|
191
191
|
position: relative;
|
|
192
192
|
|
|
193
193
|
height: 100%;
|
|
194
|
-
background: var(--container-glow-background,
|
|
194
|
+
background: var(--container-glow-background, white);
|
|
195
195
|
padding: var(--container-glow-padding, 2rem);
|
|
196
196
|
aspect-ratio: var(--container-glow-aspect-ratio, 330 / 400);
|
|
197
197
|
border-radius: var(--container-glow-border-radius, 12px);
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
| `--marquee-scroller-item-hover-filter` | `grayscale(0)` | Filter applied to a single item when it is individually hovered (overrides the group filter for that item) |
|
|
12
12
|
| `--marquee-scroller-item-transition-duration` | `0.5s` | Transition duration for the item hover filter change |
|
|
13
13
|
| `--marquee-scroller-item-border-width` | `1px` | Item border width |
|
|
14
|
-
| `--marquee-scroller-item-border-colour` | `
|
|
14
|
+
| `--marquee-scroller-item-border-colour` | `var(--slate-10)` | Item border colour |
|
|
15
15
|
| `--marquee-scroller-item-border-radius` | `4px` | Item border radius |
|
|
16
16
|
| `--marquee-scroller-control-offset` | `8px` | Distance of the pause/play button from the top and end edges |
|
|
17
17
|
| `--marquee-scroller-control-background-colour` | `rgba(0, 0, 0, 0.7)` | Pause/play button background |
|