srcdev-nuxt-components 9.6.4 → 9.6.6
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/a11y-no-focus-steal.md +14 -0
- package/.claude/skills/component-compliance-checklist.md +14 -2
- package/.claude/skills/components/display-toast.md +6 -3
- package/.claude/skills/components/progress-tracker.md +140 -0
- package/.claude/skills/components/social-icons-list.md +32 -5
- package/.claude/skills/components/stepper-list.md +10 -3
- package/.claude/skills/components/tabbed-content.md +4 -0
- package/.claude/skills/css-dynamic-border-radius.md +114 -0
- package/.claude/skills/index.md +4 -2
- package/.claude/skills/storybook-add-story.md +12 -0
- package/.vscode/srcdev-component-display-toast.code-snippets +6 -8
- package/.vscode/srcdev-component-progress-tracker.code-snippets +45 -0
- package/.vscode/srcdev-component-social-icons-list.code-snippets +14 -0
- package/.vscode/srcdev-component-stepper-list.code-snippets +3 -2
- package/.vscode/srcdev-component-tabbed-content.code-snippets +1 -0
- package/.vscode/srcdev-utility-dynamic-border-radius.code-snippets +31 -0
- package/app/assets/styles/setup/06.utility-classes/_dynamic-border-radius.css +27 -0
- package/app/assets/styles/setup/06.utility-classes/index.css +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/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/social-icons-list/CONSUMER-STYLING.md +97 -8
- package/app/components/02.molecules/social-icons-list/SocialIconsList.vue +80 -14
- package/app/components/02.molecules/social-icons-list/stories/SocialIconsList.stories.ts +230 -2
- package/app/components/02.molecules/social-icons-list/stories/social-icons-list-recipes.css +108 -0
- package/app/components/02.molecules/social-icons-list/tests/SocialIconsList.spec.ts +123 -52
- package/app/components/02.molecules/social-icons-list/tests/__snapshots__/SocialIconsList.spec.ts.snap +10 -4
- 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/02.molecules/toast/CONSUMER-STYLING.md +9 -3
- package/app/components/02.molecules/toast/DisplayToast.vue +10 -10
- package/app/components/02.molecules/toast/DisplayToastProvider.vue +12 -4
- package/app/components/02.molecules/toast/stories/DisplayToast.stories.ts +200 -2
- package/app/components/02.molecules/toast/tests/DisplayToast.spec.ts +33 -12
- package/app/components/02.molecules/toast/tests/DisplayToastProvider.spec.ts +20 -0
- package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +7 -7
- package/app/types/components/index.ts +1 -0
- package/app/types/components/progress-tracker.d.ts +6 -0
- package/app/types/components/social-icons-list.d.ts +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV ProgressTracker": {
|
|
3
|
+
"description": "ProgressTracker showing progress through steps (v-model is the 0-based current step)",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<ProgressTracker v-model=\"${1:currentStep}\" :steps=\"${2:steps}\" />"
|
|
7
|
+
]
|
|
8
|
+
},
|
|
9
|
+
"SRCDEV ProgressTracker Wizard": {
|
|
10
|
+
"description": "ProgressTracker as a wizard: each step's form lives in its #step-{n} slot and drives the model",
|
|
11
|
+
"scope": "vue,html",
|
|
12
|
+
"body": [
|
|
13
|
+
"<ProgressTracker v-model=\"${1:currentStep}\" :steps=\"${2:steps}\">",
|
|
14
|
+
" <template #step-0=\"{ headingId }\">",
|
|
15
|
+
" <form :aria-labelledby=\"headingId\" @submit.prevent=\"$1++\">",
|
|
16
|
+
" $3",
|
|
17
|
+
" <InputButton type=\"submit\" button-text=\"Continue\" />",
|
|
18
|
+
" </form>",
|
|
19
|
+
" </template>",
|
|
20
|
+
" <template #step-1=\"{ headingId }\">",
|
|
21
|
+
" <form :aria-labelledby=\"headingId\" @submit.prevent=\"$1 = $2.length\">",
|
|
22
|
+
" $4",
|
|
23
|
+
" <InputButton button-text=\"Back\" variant=\"secondary\" @click=\"$1--\" />",
|
|
24
|
+
" <InputButton type=\"submit\" button-text=\"Submit\" />",
|
|
25
|
+
" </form>",
|
|
26
|
+
" </template>",
|
|
27
|
+
"</ProgressTracker>"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"SRCDEV ProgressTracker CSS Override": {
|
|
31
|
+
"description": "CSS override scaffold for ProgressTracker tokens",
|
|
32
|
+
"scope": "css",
|
|
33
|
+
"body": [
|
|
34
|
+
".$1my-page {",
|
|
35
|
+
" --progress-tracker-accent: $2;",
|
|
36
|
+
" --progress-tracker-track: $3;",
|
|
37
|
+
" --progress-tracker-card-surface: $4;",
|
|
38
|
+
" --progress-tracker-card-shadow: $5;",
|
|
39
|
+
" --progress-tracker-label-font-family: $6;",
|
|
40
|
+
" --progress-tracker-title-line-clamp: $7;",
|
|
41
|
+
" --progress-tracker-body-line-clamp: $8;",
|
|
42
|
+
"}"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -11,6 +11,19 @@
|
|
|
11
11
|
"/>"
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
|
+
"SRCDEV SocialIconsList Labelled": {
|
|
15
|
+
"description": "SocialIconsList with visible labels and brand colours (mono icons, for the pill or tile recipes)",
|
|
16
|
+
"scope": "vue,html",
|
|
17
|
+
"body": [
|
|
18
|
+
"<SocialIconsList",
|
|
19
|
+
" :items=\"[",
|
|
20
|
+
" { networkName: '${1:Instagram}', iconName: '${2:bi:instagram}', baseHref: '${3:https://www.instagram.com/}', profileId: '$4', brandColour: '${5:#e1306c}' },",
|
|
21
|
+
" ]\"",
|
|
22
|
+
" show-label",
|
|
23
|
+
" :style-class-passthrough=\"['${6:my-social-pills}']\"",
|
|
24
|
+
"/>"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
14
27
|
"SRCDEV SocialIconsList CSS Override": {
|
|
15
28
|
"description": "CSS override scaffold for SocialIconsList tokens",
|
|
16
29
|
"scope": "css",
|
|
@@ -18,6 +31,7 @@
|
|
|
18
31
|
".$1my-page {",
|
|
19
32
|
" --social-icons-list-icon-size: $2;",
|
|
20
33
|
" --social-icons-list-gap: $3;",
|
|
34
|
+
" --social-icons-list-icon-colour: $4;",
|
|
21
35
|
"}"
|
|
22
36
|
]
|
|
23
37
|
}
|
|
@@ -31,8 +31,9 @@
|
|
|
31
31
|
".$1my-page {",
|
|
32
32
|
" --stepper-list-gap: $2;",
|
|
33
33
|
" --stepper-list-connector-color: $3;",
|
|
34
|
-
" --stepper-list-
|
|
35
|
-
" --stepper-list-counter-disc-
|
|
34
|
+
" --stepper-list-connector-gap: $4;",
|
|
35
|
+
" --stepper-list-counter-disc-background: $5;",
|
|
36
|
+
" --stepper-list-counter-disc-text: $6;",
|
|
36
37
|
"}"
|
|
37
38
|
]
|
|
38
39
|
}
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
" --tabs-underline-indicator-height: ;",
|
|
59
59
|
" --tabs-hover-underline-indicator-colour: ;",
|
|
60
60
|
" --tabs-hover-underline-indicator-height: ;",
|
|
61
|
+
" --tabs-hover-indicator-stretch: ;",
|
|
61
62
|
" --tabs-list-item-opacity: ;",
|
|
62
63
|
" --tabs-list-item-colour: ;",
|
|
63
64
|
" --tabs-list-item-colour-selected: ;",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV Dynamic Border Radius Markup": {
|
|
3
|
+
"prefix": "srcdev-dynamic-border-radius",
|
|
4
|
+
"description": ".dynamic-border-radius: rounded until the image fills its container, then square (wrapper needs container-type: inline-size)",
|
|
5
|
+
"scope": "vue,html",
|
|
6
|
+
"body": [
|
|
7
|
+
"<div class=\"$1media-wrapper\">",
|
|
8
|
+
" <img class=\"dynamic-border-radius${6:-transition}\" src=\"$2\" alt=\"$3\" width=\"$4\" height=\"$5\">",
|
|
9
|
+
"</div>"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"SRCDEV Dynamic Border Radius CSS": {
|
|
13
|
+
"prefix": "srcdev-dynamic-border-radius-css",
|
|
14
|
+
"description": "Container wrapper and image rules for .dynamic-border-radius (max width via the token, so the -transition class can read it)",
|
|
15
|
+
"scope": "css",
|
|
16
|
+
"body": [
|
|
17
|
+
".$1media-wrapper {",
|
|
18
|
+
" container-type: inline-size;",
|
|
19
|
+
"",
|
|
20
|
+
" img {",
|
|
21
|
+
" display: block;",
|
|
22
|
+
" inline-size: 100%;",
|
|
23
|
+
" --dynamic-border-radius-max-width: ${2:50rem};",
|
|
24
|
+
" max-inline-size: var(--dynamic-border-radius-max-width);",
|
|
25
|
+
" margin-inline: auto;",
|
|
26
|
+
" --dynamic-border-radius: ${3:5rem};",
|
|
27
|
+
" }",
|
|
28
|
+
"}"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* ===========================================
|
|
2
|
+
DYNAMIC BORDER RADIUS
|
|
3
|
+
Rounded corners while the element is narrower than its
|
|
4
|
+
container; square once it spans the full container width.
|
|
5
|
+
Needs an ancestor with container-type: inline-size.
|
|
6
|
+
=========================================== */
|
|
7
|
+
|
|
8
|
+
.dynamic-border-radius {
|
|
9
|
+
border-radius: clamp(0px, (100cqi - 100%) * 1e5, var(--dynamic-border-radius, 5rem));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* Transition variant: compares against a max-width token instead of 100%, so the computed value is a plain length.
|
|
14
|
+
* A % stays unresolved until layout, which makes a transition start from a stale value and flicker on every resize frame.
|
|
15
|
+
*/
|
|
16
|
+
.dynamic-border-radius-transition {
|
|
17
|
+
max-inline-size: var(--dynamic-border-radius-max-width, 100%);
|
|
18
|
+
border-radius: clamp(
|
|
19
|
+
0px,
|
|
20
|
+
(100cqi - var(--dynamic-border-radius-max-width, 100%)) * 1e5,
|
|
21
|
+
var(--dynamic-border-radius, 5rem)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
25
|
+
transition: border-radius var(--dynamic-border-radius-duration, 300ms) var(--dynamic-border-radius-easing, ease-out);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -58,6 +58,7 @@ box.
|
|
|
58
58
|
| `--tabs-underline-indicator-height` | `0.4rem` | Thickness of the underline (`axis="x"`), also its width on `axis="y"` |
|
|
59
59
|
| `--tabs-hover-underline-indicator-colour` | `--tabs-underline-indicator-colour` | Colour of the thin underline/sideline that follows the hovered tab (`trackHover` and `trackIndicator`) |
|
|
60
60
|
| `--tabs-hover-underline-indicator-height` | `0.1rem` | Its thickness; `0` hides it. Sits under the active underline where they overlap |
|
|
61
|
+
| `--tabs-hover-indicator-stretch` | `1` | Stretch of the hover highlight and hover underline as they move: `1` stretches (leading edge first, trailing edge catches up), `0` slides both edges together. Values in between shorten the stretch |
|
|
61
62
|
|
|
62
63
|
### More menu (`overflowMode="menu"`, `axis="x"`)
|
|
63
64
|
|
|
@@ -98,7 +99,10 @@ measured layout, per indicator (`active` / `hovered`): `--_{kind}-start` / `--_{
|
|
|
98
99
|
insets from the bar's start and end along the axis), `--_{kind}-duration`,
|
|
99
100
|
`--_{kind}-start-delay` / `--_{kind}-end-delay`; each indicator reads them through its own
|
|
100
101
|
`--_start` / `--_end` / `--_duration` / `--_start-delay` / `--_end-delay`. Not public API; use the
|
|
101
|
-
`transitionDuration` prop for indicator speed (one edge moves for that long, then the other)
|
|
102
|
+
`transitionDuration` prop for indicator speed (one edge moves for that long, then the other), and
|
|
103
|
+
`--tabs-hover-indicator-stretch` to turn the hover stretch off. The More menu also uses
|
|
104
|
+
`--_anchor-name` (a per-instance anchor name) and the `--_anchor-*` position values
|
|
105
|
+
`useAnchoredPopover` writes for browsers without CSS anchor positioning.
|
|
102
106
|
|
|
103
107
|
> **Changed 2026-10-08**: indicators were a bar-wide box moved with `translate` and sized with
|
|
104
108
|
> `scale` (`--_x-*`, `--_width-*`, `--_y-*`, a shared `--_transition-duration`), with a timer
|
|
@@ -354,8 +354,8 @@ watch(
|
|
|
354
354
|
--_start: var(--_hovered-start, 0px);
|
|
355
355
|
--_end: var(--_hovered-end, 100%);
|
|
356
356
|
--_duration: var(--_hovered-duration, 0ms);
|
|
357
|
-
--_start-delay: var(--_hovered-start-delay, 0ms);
|
|
358
|
-
--_end-delay: var(--_hovered-end-delay, 0ms);
|
|
357
|
+
--_start-delay: calc(var(--_hovered-start-delay, 0ms) * var(--tabs-hover-indicator-stretch, 1));
|
|
358
|
+
--_end-delay: calc(var(--_hovered-end-delay, 0ms) * var(--tabs-hover-indicator-stretch, 1));
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
.tabbed-content-indicator-active,
|
|
@@ -219,6 +219,32 @@ export const IndicatorColours: Story = {
|
|
|
219
219
|
}),
|
|
220
220
|
};
|
|
221
221
|
|
|
222
|
+
export const HoverWithoutStretch: Story = {
|
|
223
|
+
name: "Hover Without Stretch",
|
|
224
|
+
args: { itemCount: 5 },
|
|
225
|
+
parameters: {
|
|
226
|
+
docs: {
|
|
227
|
+
description: {
|
|
228
|
+
story:
|
|
229
|
+
"--tabs-hover-indicator-stretch: 0 makes the hover highlight slide between tabs instead of stretching across and catching up. Clicking a tab still stretches the active indicator.",
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
render: (args) => ({
|
|
234
|
+
components: { TabbedContent },
|
|
235
|
+
setup() {
|
|
236
|
+
return { args };
|
|
237
|
+
},
|
|
238
|
+
template: `
|
|
239
|
+
<div style="--tabs-hover-indicator-stretch: 0">
|
|
240
|
+
<TabbedContent v-bind="args">
|
|
241
|
+
${tabSlots}
|
|
242
|
+
</TabbedContent>
|
|
243
|
+
</div>
|
|
244
|
+
`,
|
|
245
|
+
}),
|
|
246
|
+
};
|
|
247
|
+
|
|
222
248
|
// ─── Stress test ──────────────────────────────────────────────────────────────
|
|
223
249
|
|
|
224
250
|
const stressTabs = [
|
package/app/components/02.molecules/contact-section/tests/__snapshots__/ContactSection.spec.ts.snap
CHANGED
|
@@ -4,22 +4,22 @@ exports[`ContactSection > renders correct HTML structure with default props 1`]
|
|
|
4
4
|
"<div class="contact-section">
|
|
5
5
|
<div class="contact-section-inner">
|
|
6
6
|
<div class="contact-section-info">
|
|
7
|
-
<ul class="stepper-list">
|
|
8
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
7
|
+
<ul role="list" class="stepper-list">
|
|
8
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
9
9
|
<div class="stepper-list__indicator-custom"></div>
|
|
10
|
-
<div>
|
|
10
|
+
<div class="stepper-list-content">
|
|
11
11
|
<p class="page-body-normal">Default slot content for item 1</p>
|
|
12
12
|
</div>
|
|
13
13
|
</li>
|
|
14
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
14
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
15
15
|
<div class="stepper-list__indicator-custom"></div>
|
|
16
|
-
<div>
|
|
16
|
+
<div class="stepper-list-content">
|
|
17
17
|
<p class="page-body-normal">Default slot content for item 2</p>
|
|
18
18
|
</div>
|
|
19
19
|
</li>
|
|
20
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
20
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
21
21
|
<div class="stepper-list__indicator-custom"></div>
|
|
22
|
-
<div>
|
|
22
|
+
<div class="stepper-list-content">
|
|
23
23
|
<p class="page-body-normal">Default slot content for item 3</p>
|
|
24
24
|
</div>
|
|
25
25
|
</li>
|
|
@@ -34,22 +34,22 @@ exports[`ContactSection > renders correct HTML structure with form slot 1`] = `
|
|
|
34
34
|
"<div class="contact-section">
|
|
35
35
|
<div class="contact-section-inner">
|
|
36
36
|
<div class="contact-section-info">
|
|
37
|
-
<ul class="stepper-list">
|
|
38
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
37
|
+
<ul role="list" class="stepper-list">
|
|
38
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
39
39
|
<div class="stepper-list__indicator-custom"></div>
|
|
40
|
-
<div>
|
|
40
|
+
<div class="stepper-list-content">
|
|
41
41
|
<p class="page-body-normal">Default slot content for item 1</p>
|
|
42
42
|
</div>
|
|
43
43
|
</li>
|
|
44
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
44
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
45
45
|
<div class="stepper-list__indicator-custom"></div>
|
|
46
|
-
<div>
|
|
46
|
+
<div class="stepper-list-content">
|
|
47
47
|
<p class="page-body-normal">Default slot content for item 2</p>
|
|
48
48
|
</div>
|
|
49
49
|
</li>
|
|
50
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
50
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
51
51
|
<div class="stepper-list__indicator-custom"></div>
|
|
52
|
-
<div>
|
|
52
|
+
<div class="stepper-list-content">
|
|
53
53
|
<p class="page-body-normal">Default slot content for item 3</p>
|
|
54
54
|
</div>
|
|
55
55
|
</li>
|
|
@@ -66,22 +66,22 @@ exports[`ContactSection > renders correct HTML structure with styleClassPassthro
|
|
|
66
66
|
"<div class="contact-section custom-class another-class">
|
|
67
67
|
<div class="contact-section-inner">
|
|
68
68
|
<div class="contact-section-info">
|
|
69
|
-
<ul class="stepper-list">
|
|
70
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
69
|
+
<ul role="list" class="stepper-list">
|
|
70
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
71
71
|
<div class="stepper-list__indicator-custom"></div>
|
|
72
|
-
<div>
|
|
72
|
+
<div class="stepper-list-content">
|
|
73
73
|
<p class="page-body-normal">Default slot content for item 1</p>
|
|
74
74
|
</div>
|
|
75
75
|
</li>
|
|
76
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
76
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
77
77
|
<div class="stepper-list__indicator-custom"></div>
|
|
78
|
-
<div>
|
|
78
|
+
<div class="stepper-list-content">
|
|
79
79
|
<p class="page-body-normal">Default slot content for item 2</p>
|
|
80
80
|
</div>
|
|
81
81
|
</li>
|
|
82
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
82
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
83
83
|
<div class="stepper-list__indicator-custom"></div>
|
|
84
|
-
<div>
|
|
84
|
+
<div class="stepper-list-content">
|
|
85
85
|
<p class="page-body-normal">Default slot content for item 3</p>
|
|
86
86
|
</div>
|
|
87
87
|
</li>
|
|
@@ -96,18 +96,18 @@ exports[`ContactSection > renders correctly with all props and slots combined 1`
|
|
|
96
96
|
"<section class="contact-section combined-class">
|
|
97
97
|
<div class="contact-section-inner">
|
|
98
98
|
<div class="contact-section-info">
|
|
99
|
-
<ul class="stepper-list">
|
|
100
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
99
|
+
<ul role="list" class="stepper-list">
|
|
100
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
101
101
|
<div class="stepper-list__indicator-custom"><span class="icon">✓</span></div>
|
|
102
|
-
<div><span>Step one</span></div>
|
|
102
|
+
<div class="stepper-list-content"><span>Step one</span></div>
|
|
103
103
|
</li>
|
|
104
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
104
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
105
105
|
<div class="stepper-list__indicator-custom"></div>
|
|
106
|
-
<div><span>Step two</span></div>
|
|
106
|
+
<div class="stepper-list-content"><span>Step two</span></div>
|
|
107
107
|
</li>
|
|
108
|
-
<li class="has-indicator indicator-top indicator-disc">
|
|
108
|
+
<li class="stepper-list-item has-indicator indicator-top indicator-disc">
|
|
109
109
|
<div class="stepper-list__indicator-custom"></div>
|
|
110
|
-
<div><span>Step three</span></div>
|
|
110
|
+
<div class="stepper-list-content"><span>Step three</span></div>
|
|
111
111
|
</li>
|
|
112
112
|
</ul>
|
|
113
113
|
</div>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# ProgressTracker — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
## Public token API
|
|
4
|
+
|
|
5
|
+
All `--progress-tracker-*` tokens are the stable override surface. Set them on an ancestor you
|
|
6
|
+
own, or on a class added with `:style-class-passthrough`.
|
|
7
|
+
|
|
8
|
+
### Colours
|
|
9
|
+
|
|
10
|
+
| Token | Default | Controls |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `--progress-tracker-accent` | `var(--theme-accent)` | Done indicator fill, current indicator outline and number, connectors below done steps, progress bar fill |
|
|
13
|
+
| `--progress-tracker-on-accent` | `var(--theme-on-surface)` | Tick colour on the done indicator; keep it in contrast with the accent |
|
|
14
|
+
| `--progress-tracker-track` | `--theme-text` mixed to 15% | Progress bar track, upcoming indicator outline, connectors below current and upcoming steps |
|
|
15
|
+
| `--progress-tracker-ring-colour` | `--theme-accent` mixed to 20% | Halo around the current indicator |
|
|
16
|
+
| `--progress-tracker-upcoming-text` | `--theme-text` mixed to 60% | Upcoming step numbers, titles and bodies |
|
|
17
|
+
| `--progress-tracker-title-colour` | `var(--theme-text)` | Done and current step titles |
|
|
18
|
+
| `--progress-tracker-body-colour` | `--theme-text` mixed to 80% | Done and current step bodies |
|
|
19
|
+
| `--progress-tracker-label-colour` | `--theme-text` mixed to 70% | Header label |
|
|
20
|
+
|
|
21
|
+
### Header
|
|
22
|
+
|
|
23
|
+
| Token | Default | Controls |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `--progress-tracker-header-gap` | `2.4rem` | Space between the header and the first step |
|
|
26
|
+
| `--progress-tracker-label-font-family` | `inherit` | Header label font (e.g. a monospace stack) |
|
|
27
|
+
| `--progress-tracker-label-font-size` | `var(--step-4)` | Header label size |
|
|
28
|
+
| `--progress-tracker-label-font-weight` | `600` | Header label weight |
|
|
29
|
+
| `--progress-tracker-label-letter-spacing` | `0.12em` | Header label tracking |
|
|
30
|
+
| `--progress-tracker-label-text-transform` | `uppercase` | Header label case; `none` keeps the prop's casing |
|
|
31
|
+
| `--progress-tracker-bar-inline-size` | `16rem` | Preferred bar width; it shrinks first and wraps below the label when space runs out |
|
|
32
|
+
| `--progress-tracker-bar-height` | `0.6rem` | Bar thickness |
|
|
33
|
+
| `--progress-tracker-bar-radius` | `99rem` | Bar corner rounding |
|
|
34
|
+
|
|
35
|
+
### Steps and indicators
|
|
36
|
+
|
|
37
|
+
| Token | Default | Controls |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `--progress-tracker-gap` | `4rem` | Space between the indicator column and the step content |
|
|
40
|
+
| `--progress-tracker-step-padding-block` | `1.2rem` | Vertical padding of each step row |
|
|
41
|
+
| `--progress-tracker-connector-width` | `0.2rem` | Connector line thickness |
|
|
42
|
+
| `--progress-tracker-indicator-size` | `4.4rem` | Indicator width and height; titles are centred against it |
|
|
43
|
+
| `--progress-tracker-indicator-border-width` | `0.2rem` | Indicator outline width |
|
|
44
|
+
| `--progress-tracker-indicator-radius` | `50%` | Indicator shape; `0.8rem` gives rounded squares |
|
|
45
|
+
| `--progress-tracker-indicator-font-size` | `var(--step-4)` | Step number size |
|
|
46
|
+
| `--progress-tracker-ring-width` | `0.6rem` | Halo width around the current indicator |
|
|
47
|
+
| `--progress-tracker-content-gap` | `0.8rem` | Space between title, body and slot content in a step |
|
|
48
|
+
| `--progress-tracker-slot-gap` | `0.8rem` | Extra space above the `#step-{n}` slot content |
|
|
49
|
+
| `--progress-tracker-title-font-size` | `var(--step-5)` | Step title size |
|
|
50
|
+
| `--progress-tracker-title-font-weight` | `600` | Step title weight |
|
|
51
|
+
| `--progress-tracker-title-line-clamp` | `none` | Lines before a title is cut off with an ellipsis (`1` is single-line) |
|
|
52
|
+
| `--progress-tracker-body-font-size` | `var(--step-4)` | Step body size |
|
|
53
|
+
| `--progress-tracker-body-line-clamp` | `none` | Lines before a body is cut off with an ellipsis |
|
|
54
|
+
|
|
55
|
+
### Focus card (current step)
|
|
56
|
+
|
|
57
|
+
| Token | Default | Controls |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `--progress-tracker-card-surface` | `var(--theme-surface-subtle)` | Card background; set `#ffffff` (or similar) to lift it off a grey panel |
|
|
60
|
+
| `--progress-tracker-card-shadow` | soft two-layer shadow | Card shadow; `none` for a flat card |
|
|
61
|
+
| `--progress-tracker-card-radius` | `1.6rem` | Card corner rounding |
|
|
62
|
+
| `--progress-tracker-card-padding-block` | `1.6rem` | Card top and bottom padding; the current indicator moves down by the same amount to stay level with the title |
|
|
63
|
+
| `--progress-tracker-card-padding-inline` | `2rem` | Card side padding; the card bleeds left by the same amount so its text lines up with the other steps. Clearance between the current ring and the card is `--progress-tracker-gap` minus this minus `--progress-tracker-ring-width` (1.4rem by default), so raise the gap with it |
|
|
64
|
+
|
|
65
|
+
### Motion
|
|
66
|
+
|
|
67
|
+
| Token | Default | Controls |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `--progress-tracker-transition-duration` | `200ms` | Bar fill and state colour transitions. Off under `prefers-reduced-motion: reduce` |
|
|
70
|
+
|
|
71
|
+
Private (not public API): `--_progress-tracker-progress`, the done fraction the component sets
|
|
72
|
+
inline on the bar.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## State hooks
|
|
77
|
+
|
|
78
|
+
| Hook | Element | When |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `.is-complete` | root | The model equals `steps.length` |
|
|
81
|
+
| `.is-done`, `.is-current`, `.is-upcoming` | `.progress-tracker-step` and `.progress-tracker-indicator` | That step's state |
|
|
82
|
+
| `aria-current="step"` | `.progress-tracker-title` | The current step |
|
|
83
|
+
|
|
84
|
+
Inner classes: `.progress-tracker-header`, `.progress-tracker-label`, `.progress-tracker-bar`,
|
|
85
|
+
`.progress-tracker-bar-fill`, `.progress-tracker-list` (the StepperList root),
|
|
86
|
+
`.progress-tracker-indicator`, `.progress-tracker-indicator-icon`, `.progress-tracker-step`,
|
|
87
|
+
`.progress-tracker-title`, `.progress-tracker-body`, `.progress-tracker-slot`.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Local overrides
|
|
92
|
+
|
|
93
|
+
Set the tokens above on an element you own (a page or section class, or a class added with
|
|
94
|
+
`:style-class-passthrough`): they inherit down into the component. Keep the block **unlayered** (no
|
|
95
|
+
`@layer` wrapper) so it beats the library's `@layer components`. If your own file uses
|
|
96
|
+
`<style scoped>`, tokens set on your element still work, but selectors that reach inside the component need
|
|
97
|
+
`:deep()`. Patterns and examples: `.claude/skills/component-local-style-override.md`.
|
|
98
|
+
|
|
99
|
+
**Caveat: StepperList tokens.** The list is a `StepperList`, and ProgressTracker sets its
|
|
100
|
+
`--stepper-list-*` tokens on `.progress-tracker-list` from its own tokens. A `--stepper-list-*`
|
|
101
|
+
value set on an ancestor never reaches it; use the `--progress-tracker-*` equivalents
|
|
102
|
+
(`-gap`, `-step-padding-block`, `-connector-width`, `-accent`, `-track`).
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Class passthrough
|
|
107
|
+
|
|
108
|
+
`style-class-passthrough` adds classes to the root `div`. Tokens set on a passthrough class apply to
|
|
109
|
+
the whole tracker. Reactive after mount.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Notes
|
|
114
|
+
|
|
115
|
+
- Title centring against the indicator uses the `lh` unit. Safari before 16.4 ignores it and the
|
|
116
|
+
title sits level with the top of the indicator instead.
|