srcdev-nuxt-components 9.6.3 → 9.6.5
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/rules/consumer/vue-no-self-closing.md +3 -2
- package/.claude/skills/component-compliance-checklist.md +17 -3
- package/.claude/skills/component-inline-action-button.md +33 -2
- package/.claude/skills/components/cookie-consent-banner.md +9 -6
- package/.claude/skills/components/input-copy.md +47 -100
- package/.claude/skills/components/progress-tracker.md +140 -0
- package/.claude/skills/components/stepper-list.md +10 -3
- package/.claude/skills/components/tabbed-content.md +4 -0
- package/.claude/skills/composable-cookie-consent.md +1 -1
- package/.claude/skills/index.md +4 -3
- package/.claude/skills/storybook-add-story.md +14 -0
- package/.claude/skills/testing-add-unit-test.md +19 -0
- package/.claude/skills/theming-component-token-pattern.md +1 -1
- package/.vscode/srcdev-component-cookie-consent-banner.code-snippets +7 -5
- package/.vscode/srcdev-component-input-copy.code-snippets +24 -42
- package/.vscode/srcdev-component-progress-tracker.code-snippets +45 -0
- package/.vscode/srcdev-component-stepper-list.code-snippets +3 -2
- package/.vscode/srcdev-component-tabbed-content.code-snippets +1 -0
- package/app/components/01.atoms/tabbed-content/CONSUMER-STYLING.md +5 -1
- package/app/components/01.atoms/tabbed-content/TabbedContent.vue +2 -2
- package/app/components/01.atoms/tabbed-content/stories/TabbedContent.stories.ts +26 -0
- package/app/components/02.molecules/contact-section/tests/__snapshots__/ContactSection.spec.ts.snap +28 -28
- package/app/components/02.molecules/cookie-consent-banner/CONSUMER-STYLING.md +13 -4
- package/app/components/02.molecules/cookie-consent-banner/CookieConsentBanner.vue +23 -14
- package/app/components/02.molecules/cookie-consent-banner/stories/CookieConsentBanner.stories.ts +106 -5
- package/app/components/02.molecules/cookie-consent-banner/tests/CookieConsentBanner.spec.ts +33 -11
- package/app/components/02.molecules/input-copy/CONSUMER-STYLING.md +82 -124
- package/app/components/02.molecules/input-copy/InputCopy.vue +110 -85
- package/app/components/02.molecules/input-copy/stories/InputCopy.stories.ts +204 -47
- package/app/components/02.molecules/input-copy/tests/InputCopy.spec.ts +147 -171
- package/app/components/02.molecules/progress-tracker/CONSUMER-STYLING.md +116 -0
- package/app/components/02.molecules/progress-tracker/ProgressTracker.vue +275 -0
- package/app/components/02.molecules/progress-tracker/stories/ProgressTracker.stories.ts +424 -0
- package/app/components/02.molecules/progress-tracker/tests/ProgressTracker.spec.ts +253 -0
- package/app/components/02.molecules/progress-tracker/tests/__snapshots__/ProgressTracker.spec.ts.snap +46 -0
- package/app/components/02.molecules/stepper-list/CONSUMER-STYLING.md +42 -7
- package/app/components/02.molecules/stepper-list/StepperList.vue +42 -19
- package/app/components/02.molecules/stepper-list/stories/StepperList.stories.ts +288 -2
- package/app/components/02.molecules/stepper-list/tests/StepperList.spec.ts +161 -34
- package/app/components/02.molecules/stepper-list/tests/__snapshots__/StepperList.spec.ts.snap +40 -40
- package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +7 -7
- package/app/types/components/cookie-consent-banner.d.ts +2 -0
- package/app/types/components/index.ts +1 -0
- package/app/types/components/progress-tracker.d.ts +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`ProgressTracker > renders correct HTML structure 1`] = `
|
|
4
|
+
"<div class="progress-tracker">
|
|
5
|
+
<div class="progress-tracker-header">
|
|
6
|
+
<p class="progress-tracker-label" aria-live="polite" tabindex="-1">Step 2 of 3</p>
|
|
7
|
+
<div class="progress-tracker-bar" role="progressbar" aria-valuemin="0" aria-valuemax="3" aria-valuenow="1" aria-valuetext="Step 2 of 3" style="--_progress-tracker-progress: 0.3333333333333333;"><span class="progress-tracker-bar-fill"></span></div>
|
|
8
|
+
</div>
|
|
9
|
+
<ol role="list" class="stepper-list has-connectors progress-tracker-list">
|
|
10
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc" style="--_connector-left: 0px; --_connector-top: 0px; --_connector-height: 0px;">
|
|
11
|
+
<div class="stepper-list__indicator-custom"><span class="progress-tracker-indicator is-done" aria-hidden="true"><span class="iconify i-lucide:check progress-tracker-indicator-icon" aria-hidden="true"></span></span></div>
|
|
12
|
+
<div class="stepper-list-content">
|
|
13
|
+
<div class="progress-tracker-step is-done">
|
|
14
|
+
<h3 id="v-0-0-step-0" class="progress-tracker-title" tabindex="-1">Create your account<span class="sr-only">, Completed</span></h3>
|
|
15
|
+
<p class="progress-tracker-body">Enter your email and choose a password.</p>
|
|
16
|
+
<!--v-if-->
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</li>
|
|
20
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc" style="--_connector-left: 0px; --_connector-top: 0px; --_connector-height: 0px;">
|
|
21
|
+
<div class="stepper-list__indicator-custom"><span class="progress-tracker-indicator is-current" aria-hidden="true">2</span></div>
|
|
22
|
+
<div class="stepper-list-content">
|
|
23
|
+
<div class="progress-tracker-step is-current">
|
|
24
|
+
<h3 id="v-0-0-step-1" class="progress-tracker-title" tabindex="-1" aria-current="step">Verify your email
|
|
25
|
+
<!--v-if-->
|
|
26
|
+
</h3>
|
|
27
|
+
<p class="progress-tracker-body">Click the link we sent to your inbox.</p>
|
|
28
|
+
<!--v-if-->
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</li>
|
|
32
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
33
|
+
<div class="stepper-list__indicator-custom"><span class="progress-tracker-indicator is-upcoming" aria-hidden="true">3</span></div>
|
|
34
|
+
<div class="stepper-list-content">
|
|
35
|
+
<div class="progress-tracker-step is-upcoming">
|
|
36
|
+
<h3 id="v-0-0-step-2" class="progress-tracker-title" tabindex="-1">Choose a plan
|
|
37
|
+
<!--v-if-->
|
|
38
|
+
</h3>
|
|
39
|
+
<!--v-if-->
|
|
40
|
+
<!--v-if-->
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</li>
|
|
44
|
+
</ol>
|
|
45
|
+
</div>"
|
|
46
|
+
`;
|
|
@@ -15,12 +15,14 @@ file, scoped to a page wrapper, or per-instance via `styleClassPassthrough`.
|
|
|
15
15
|
| `--stepper-list-counter-font-size` | `1.4rem` | Counter number font size |
|
|
16
16
|
| `--stepper-list-counter-font-weight` | `600` | Counter number font weight |
|
|
17
17
|
| `--stepper-list-connector-width` | `0.2rem` | Connector line thickness |
|
|
18
|
+
| `--stepper-list-connector-gap` | `0` | Space between each end of the connector line and the indicators it joins. A gap larger than half the space between two indicators hides that line |
|
|
18
19
|
|
|
19
20
|
### Colours
|
|
20
21
|
|
|
21
22
|
| Token | Default | Controls |
|
|
22
23
|
|---|---|---|
|
|
23
24
|
| `--stepper-list-connector-color` | `currentColor` | Connector line colour |
|
|
25
|
+
| `--stepper-list-connector-image` | `none` | Image painted over the connector colour, e.g. a `repeating-linear-gradient()` for a dashed or dotted line (set the colour to `transparent` underneath) |
|
|
24
26
|
| `--stepper-list-icon-color` | `currentColor` | Icon colour for custom `indicator-icon` elements |
|
|
25
27
|
|
|
26
28
|
### Circle indicator
|
|
@@ -58,8 +60,8 @@ The defaults above are the component's own fallbacks. The library's default them
|
|
|
58
60
|
> reads, so custom indicator icons fell back to `currentColor`. It now sets
|
|
59
61
|
> `--stepper-list-icon-color`.
|
|
60
62
|
|
|
61
|
-
Private (not public API): `--
|
|
62
|
-
`--_connector-height`, which script measures and sets inline on each `<li>`.
|
|
63
|
+
Private (not public API): `--_counter-size` and `--_padding-block`, plus `--_connector-left`,
|
|
64
|
+
`--_connector-top` and `--_connector-height`, which script measures and sets inline on each `<li>`.
|
|
63
65
|
|
|
64
66
|
---
|
|
65
67
|
|
|
@@ -72,8 +74,14 @@ Private (not public API): `--_gap`, `--_counter-size` and `--_padding-block`, pl
|
|
|
72
74
|
| `.indicator-top`, `.indicator-center` | `<li>` | `indicator-alignment` |
|
|
73
75
|
| `.indicator-disc`, `.indicator-square`, `.indicator-circle` | `<li>` | `indicator-variant` |
|
|
74
76
|
|
|
75
|
-
Inner classes: `.stepper-
|
|
76
|
-
`.stepper-list__indicator-custom` (wraps a custom `indicator-{n}` slot)
|
|
77
|
+
Inner classes: `.stepper-list-item` (each `<li>`), `.stepper-list__indicator-counter`
|
|
78
|
+
(auto-numbered bubble) or `.stepper-list__indicator-custom` (wraps a custom `indicator-{n}` slot),
|
|
79
|
+
and `.stepper-list-content` (wraps the `item-{n}` slot).
|
|
80
|
+
|
|
81
|
+
> Changed 2026-10-15: `<li>` gained `.stepper-list-item` and the content wrapper gained
|
|
82
|
+
> `.stepper-list-content` (it had no class). The content column is now `minmax(0, 1fr)` with
|
|
83
|
+
> `overflow-wrap: anywhere`, so an unbroken string or long URL wraps instead of widening the list.
|
|
84
|
+
> The root carries `role="list"`, since `list-style: none` drops list semantics in Safari.
|
|
77
85
|
|
|
78
86
|
---
|
|
79
87
|
|
|
@@ -156,6 +164,29 @@ visual style, pass a modifier class:
|
|
|
156
164
|
|
|
157
165
|
---
|
|
158
166
|
|
|
167
|
+
## Recipe: per-step states and dashed connectors
|
|
168
|
+
|
|
169
|
+
The component has no "done / current / upcoming" prop. Put a state class on the content you pass
|
|
170
|
+
to each `#indicator-{n}` slot, then set tokens on the matching `.stepper-list-item` with `:has()`.
|
|
171
|
+
Each connector belongs to the item above it, so it takes that item's state.
|
|
172
|
+
|
|
173
|
+
```css
|
|
174
|
+
.onboarding-steps {
|
|
175
|
+
--stepper-list-connector-color: transparent;
|
|
176
|
+
--stepper-list-connector-image: repeating-linear-gradient(to bottom, #3a3d45 0 0.2rem, transparent 0.2rem 0.6rem);
|
|
177
|
+
|
|
178
|
+
.stepper-list-item:has(.step-marker.is-done) {
|
|
179
|
+
--stepper-list-connector-image: repeating-linear-gradient(to bottom, #00c8d7 0 0.4rem, transparent 0.4rem 0.7rem);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Shapes such as diamonds go in the indicator slot (a rotated square). The connector is centred on
|
|
185
|
+
whatever the slot renders, so it needs no adjustment. The "Timeline (styled demo)" story shows the
|
|
186
|
+
full pattern.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
159
190
|
## Class passthrough
|
|
160
191
|
|
|
161
192
|
`style-class-passthrough` adds classes to the root `<ul>`/`<ol>`. Tokens set on a passthrough class
|
|
@@ -167,11 +198,15 @@ land for the whole list. Reactive after mount.
|
|
|
167
198
|
|
|
168
199
|
- `--stepper-list-counter-size` takes precedence over the `indicatorSize` prop. Use the prop
|
|
169
200
|
for programmatic/template control; use the CSS token for pure-CSS theme overrides.
|
|
170
|
-
- The connector line is positioned by JS
|
|
171
|
-
`--_connector-top` and `--_connector-height
|
|
201
|
+
- The connector line is positioned by JS on each `<li>` as `--_connector-left`,
|
|
202
|
+
`--_connector-top` and `--_connector-height`, centred on the measured indicator, so it lines up
|
|
203
|
+
under a custom indicator wider than `--stepper-list-counter-size`. These are internal — do not
|
|
204
|
+
set them. They are re-measured when the list or any item resizes, and when a `class` or the
|
|
205
|
+
content changes inside the list, so per-step state styling (the recipe above) keeps the lines
|
|
206
|
+
in place. A change made only through an inline `style` attribute isn't seen; toggle a class
|
|
207
|
+
instead.
|
|
172
208
|
- `--stepper-list-connector-color` defaults to `currentColor`, inheriting from the nearest
|
|
173
209
|
ancestor's text colour. Set it explicitly when that behaviour is undesirable.
|
|
174
210
|
- All border tokens (`--stepper-list-counter-*-border`) control the **colour** only — the
|
|
175
211
|
border is always `2px solid`. Override the border shorthand directly on `.stepper-list li
|
|
176
212
|
.stepper-list__indicator-counter::before` if you need a different width.
|
|
177
|
-
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
<component
|
|
3
3
|
:is="tag"
|
|
4
4
|
ref="listEl"
|
|
5
|
+
role="list"
|
|
5
6
|
class="stepper-list"
|
|
6
7
|
:class="[elementClasses, { 'has-connectors': props.connected }]"
|
|
7
8
|
>
|
|
8
9
|
<li
|
|
9
|
-
v-for="index in
|
|
10
|
+
v-for="index in itemTotal"
|
|
10
11
|
:key="index"
|
|
11
12
|
:class="[
|
|
13
|
+
'stepper-list-item',
|
|
12
14
|
{ 'has-indicator': $slots[`indicator-${index - 1}`] },
|
|
13
15
|
`indicator-${props.indicatorAlignment}`,
|
|
14
16
|
`indicator-${props.indicatorVariant}`,
|
|
@@ -19,7 +21,7 @@
|
|
|
19
21
|
>
|
|
20
22
|
<slot :name="`indicator-${index - 1}`"></slot>
|
|
21
23
|
</div>
|
|
22
|
-
<div>
|
|
24
|
+
<div class="stepper-list-content">
|
|
23
25
|
<slot :name="`item-${index - 1}`"></slot>
|
|
24
26
|
</div>
|
|
25
27
|
</li>
|
|
@@ -53,6 +55,8 @@ watch(
|
|
|
53
55
|
() => resetElementClasses(props.styleClassPassthrough)
|
|
54
56
|
);
|
|
55
57
|
|
|
58
|
+
const itemTotal = computed(() => Math.max(0, Math.floor(Number(props.itemCount)) || 0));
|
|
59
|
+
|
|
56
60
|
const listEl = ref<HTMLElement | null>(null);
|
|
57
61
|
let resizeObserver: ResizeObserver | null = null;
|
|
58
62
|
|
|
@@ -76,27 +80,50 @@ function updateConnectors() {
|
|
|
76
80
|
const indicatorRect = indicator.getBoundingClientRect();
|
|
77
81
|
const nextIndicatorRect = nextIndicator.getBoundingClientRect();
|
|
78
82
|
|
|
79
|
-
li.style.setProperty("--_connector-
|
|
83
|
+
li.style.setProperty("--_connector-left", `${indicatorRect.left - liRect.left + indicatorRect.width / 2}px`);
|
|
84
|
+
li.style.setProperty("--_connector-top",`${indicatorRect.bottom - liRect.top}px`);
|
|
80
85
|
li.style.setProperty("--_connector-height", `${Math.max(0, nextIndicatorRect.top - indicatorRect.bottom)}px`);
|
|
81
86
|
});
|
|
82
87
|
}
|
|
83
88
|
|
|
89
|
+
let mutationObserver: MutationObserver | null = null;
|
|
90
|
+
|
|
91
|
+
// Items can resize or restyle without the list changing size (e.g. a card moving from one step to the next).
|
|
92
|
+
function observeItems() {
|
|
93
|
+
if (!resizeObserver || !listEl.value) return;
|
|
94
|
+
resizeObserver.disconnect();
|
|
95
|
+
resizeObserver.observe(listEl.value);
|
|
96
|
+
listEl.value.querySelectorAll(":scope > li").forEach((li) => resizeObserver?.observe(li));
|
|
97
|
+
}
|
|
98
|
+
|
|
84
99
|
onMounted(() => {
|
|
85
100
|
updateConnectors();
|
|
86
|
-
if (
|
|
101
|
+
if (!listEl.value) return;
|
|
102
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
87
103
|
resizeObserver = new ResizeObserver(updateConnectors);
|
|
88
|
-
|
|
104
|
+
observeItems();
|
|
105
|
+
}
|
|
106
|
+
if (typeof MutationObserver !== "undefined") {
|
|
107
|
+
mutationObserver = new MutationObserver(updateConnectors);
|
|
108
|
+
mutationObserver.observe(listEl.value, {
|
|
109
|
+
subtree: true,
|
|
110
|
+
childList: true,
|
|
111
|
+
attributes: true,
|
|
112
|
+
attributeFilter: ["class"],
|
|
113
|
+
});
|
|
89
114
|
}
|
|
90
115
|
});
|
|
91
116
|
|
|
92
117
|
onBeforeUnmount(() => {
|
|
93
118
|
resizeObserver?.disconnect();
|
|
119
|
+
mutationObserver?.disconnect();
|
|
94
120
|
});
|
|
95
121
|
|
|
96
122
|
watch(
|
|
97
|
-
() => [
|
|
123
|
+
() => [itemTotal.value, props.connected, props.indicatorAlignment],
|
|
98
124
|
async () => {
|
|
99
125
|
await nextTick();
|
|
126
|
+
observeItems();
|
|
100
127
|
updateConnectors();
|
|
101
128
|
}
|
|
102
129
|
);
|
|
@@ -107,7 +134,6 @@ watch(
|
|
|
107
134
|
.stepper-list {
|
|
108
135
|
/* Layout */
|
|
109
136
|
--_padding-block: var(--stepper-list-padding-block, 1.2rem);
|
|
110
|
-
--_gap: var(--stepper-list-gap, 2.2rem);
|
|
111
137
|
--_counter-size: var(--stepper-list-counter-size, v-bind(indicatorSize));
|
|
112
138
|
|
|
113
139
|
list-style: none;
|
|
@@ -116,8 +142,8 @@ watch(
|
|
|
116
142
|
|
|
117
143
|
li {
|
|
118
144
|
display: grid;
|
|
119
|
-
grid-template-columns: auto 1fr;
|
|
120
|
-
gap: var(--
|
|
145
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
146
|
+
gap: var(--stepper-list-gap, 2.2rem);
|
|
121
147
|
counter-increment: stepper-list;
|
|
122
148
|
padding-inline-start: 0rem;
|
|
123
149
|
padding-block: var(--_padding-block);
|
|
@@ -163,13 +189,8 @@ watch(
|
|
|
163
189
|
border-radius: var(--stepper-list-counter-square-border-radius, 0.25rem);
|
|
164
190
|
}
|
|
165
191
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
.stepper-list__indicator-custom,
|
|
171
|
-
.stepper-list__indicator-counter {
|
|
172
|
-
anchor-name: --indicator-bubble;
|
|
192
|
+
.stepper-list-content {
|
|
193
|
+
overflow-wrap: anywhere;
|
|
173
194
|
}
|
|
174
195
|
|
|
175
196
|
.stepper-list__indicator-custom {
|
|
@@ -189,15 +210,17 @@ watch(
|
|
|
189
210
|
.stepper-list.has-connectors li:not(:last-child)::after {
|
|
190
211
|
content: "";
|
|
191
212
|
position: absolute;
|
|
192
|
-
left: calc(var(--_counter-size) / 2);
|
|
213
|
+
left: var(--_connector-left, calc(var(--_counter-size) / 2));
|
|
193
214
|
transform: translateX(-50%);
|
|
194
|
-
/* JS sets --_connector-top and --_connector-height from measured indicator
|
|
195
|
-
The fallback values handle the indicator-top case before JS runs. */
|
|
215
|
+
/* JS sets --_connector-left, --_connector-top and --_connector-height from measured indicator
|
|
216
|
+
positions. The fallback values handle the indicator-top case before JS runs. */
|
|
196
217
|
top: var(--_connector-top, calc(var(--_padding-block) + var(--_counter-size)));
|
|
197
218
|
height: var(--_connector-height, auto);
|
|
198
219
|
bottom: calc(-1 * var(--_padding-block));
|
|
199
220
|
width: var(--stepper-list-connector-width, 0.2rem);
|
|
221
|
+
clip-path: inset(var(--stepper-list-connector-gap, 0) 0);
|
|
200
222
|
background-color: var(--stepper-list-connector-color, currentColor);
|
|
223
|
+
background-image: var(--stepper-list-connector-image, none);
|
|
201
224
|
}
|
|
202
225
|
}
|
|
203
226
|
</style>
|