srcdev-nuxt-components 9.6.11 → 9.6.13
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/ids-from-useid.md +2 -1
- package/.claude/rules/consumer/vfor-keys-from-data.md +14 -0
- package/.claude/skills/component-compliance-checklist.md +24 -1
- package/.claude/skills/component-naming.md +1 -0
- package/.claude/skills/components/banner-video.md +24 -30
- package/.claude/skills/components/content-docs.md +18 -5
- package/.claude/skills/components/display-dialog.md +16 -6
- package/.claude/skills/components/{display-tooltip-defined.md → display-tooltip-rich.md} +40 -42
- package/.claude/skills/components/display-tooltip.md +17 -6
- package/.claude/skills/components/form-field.md +15 -0
- package/.claude/skills/components/form-fieldset.md +18 -2
- package/.claude/skills/components/marquee-scroller.md +51 -14
- package/.claude/skills/components/skip-links.md +16 -0
- package/.claude/skills/composable-tooltips-guide.md +4 -4
- package/.claude/skills/index.md +6 -6
- package/.claude/skills/testing-add-unit-test.md +8 -0
- package/.vscode/srcdev-component-banner-video.code-snippets +38 -25
- package/.vscode/srcdev-component-content-docs.code-snippets +69 -60
- package/.vscode/srcdev-component-display-dialog.code-snippets +7 -5
- package/.vscode/srcdev-component-display-tooltip-rich.code-snippets +50 -0
- package/.vscode/srcdev-component-display-tooltip.code-snippets +31 -0
- package/.vscode/srcdev-component-form-field.code-snippets +7 -6
- package/.vscode/srcdev-component-form-fieldset.code-snippets +12 -12
- package/.vscode/srcdev-component-marquee-scroller.code-snippets +31 -28
- package/.vscode/srcdev-component-skip-links.code-snippets +1 -1
- package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +77 -54
- package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +103 -91
- package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +132 -3
- package/app/components/01.atoms/animations/marquee-scroller/tests/MarqueeScroller.spec.ts +190 -102
- package/app/components/01.atoms/animations/marquee-scroller/tests/__snapshots__/MarqueeScroller.spec.ts.snap +17 -13
- package/app/components/01.atoms/banner-video/BannerVideo.vue +51 -19
- package/app/components/01.atoms/banner-video/CONSUMER-STYLING.md +59 -40
- package/app/components/01.atoms/banner-video/stories/BannerVideo.stories.ts +88 -1
- package/app/components/01.atoms/banner-video/tests/BannerVideo.spec.ts +127 -78
- package/app/components/01.atoms/banner-video/tests/__snapshots__/BannerVideo.spec.ts.snap +12 -4
- package/app/components/01.atoms/content-wrappers/docs-pages/CONSUMER-STYLING.md +42 -14
- package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +86 -112
- package/app/components/01.atoms/content-wrappers/docs-pages/stories/ContentDocs.stories.ts +134 -8
- package/app/components/01.atoms/content-wrappers/docs-pages/tests/ContentDocs.spec.ts +131 -65
- package/app/components/01.atoms/display-dialog/CONSUMER-STYLING.md +28 -3
- package/app/components/01.atoms/display-dialog/DisplayDialog.vue +39 -31
- package/app/components/01.atoms/display-dialog/stories/DisplayDialog.stories.ts +92 -1
- package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +87 -41
- package/app/components/01.atoms/display-dialog/tests/__snapshots__/DisplayDialog.spec.ts.snap +5 -1
- package/app/components/01.atoms/display-tooltip/CONSUMER-STYLING.md +70 -24
- package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +24 -12
- package/app/components/01.atoms/display-tooltip/stories/DisplayTooltip.stories.ts +89 -2
- package/app/components/01.atoms/display-tooltip/tests/DisplayTooltip.spec.ts +65 -18
- package/app/components/01.atoms/display-tooltip/tests/__snapshots__/DisplayTooltip.spec.ts.snap +3 -3
- package/app/components/01.atoms/navigation/skip-links/CONSUMER-STYLING.md +65 -19
- package/app/components/01.atoms/navigation/skip-links/SkipLinks.vue +20 -14
- package/app/components/01.atoms/navigation/skip-links/stories/SkipLinks.stories.ts +89 -20
- package/app/components/01.atoms/navigation/skip-links/tests/SkipLinks.spec.ts +70 -10
- package/app/components/02.molecules/display-tooltip-rich/CONSUMER-STYLING.md +110 -0
- package/app/components/02.molecules/display-tooltip-rich/DisplayTooltipRich.vue +148 -0
- package/app/components/02.molecules/display-tooltip-rich/stories/DisplayTooltipRich.stories.ts +254 -0
- package/app/components/02.molecules/display-tooltip-rich/tests/DisplayTooltipRich.spec.ts +156 -0
- package/app/components/02.molecules/display-tooltip-rich/tests/__snapshots__/DisplayTooltipRich.spec.ts.snap +22 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu/DeepExpandingMenu.vue +1 -0
- package/app/components/02.molecules/navigation/deep-expanding-menu/tests/__snapshots__/DeepExpandingMenu.spec.ts.snap +1 -1
- package/app/components/03.organisms/image-galleries/carousel-flip/CarouselFlip.vue +1 -0
- package/app/components/05.forms/form-field/CONSUMER-STYLING.md +7 -0
- package/app/components/05.forms/form-field/stories/FormField.stories.ts +116 -2
- package/app/components/05.forms/form-fieldset/CONSUMER-STYLING.md +11 -1
- package/app/components/05.forms/form-fieldset/FormFieldset.vue +4 -2
- package/app/components/05.forms/form-fieldset/stories/FormFieldset.stories.ts +68 -4
- package/app/components/05.forms/form-fieldset/tests/FormFieldset.spec.ts +10 -0
- package/app/composables/tests/useTooltips.spec.ts +3 -3
- package/app/types/components/index.ts +1 -1
- package/package.json +1 -1
- package/.vscode/srcdev-component-display-tooltip-defined.code-snippets +0 -29
- package/app/components/02.molecules/display-tooltip-defined/CONSUMER-STYLING.md +0 -53
- package/app/components/02.molecules/display-tooltip-defined/DisplayTooltipDefined.vue +0 -117
- package/app/components/02.molecules/display-tooltip-defined/stories/DisplayTooltipDefined.stories.ts +0 -129
- package/app/components/02.molecules/display-tooltip-defined/tests/DisplayTooltipDefined.spec.ts +0 -85
- package/app/components/02.molecules/display-tooltip-defined/tests/__snapshots__/DisplayTooltipDefined.spec.ts.snap +0 -17
- /package/app/types/components/{display-tooltip-defined.d.ts → display-tooltip-rich.d.ts} +0 -0
|
@@ -10,8 +10,9 @@ type: reference
|
|
|
10
10
|
|
|
11
11
|
`MarqueeScroller` renders an infinite horizontal scroller for small repeating items — client
|
|
12
12
|
logos, badges, testimonial avatars. The track is duplicated once so the loop is seamless
|
|
13
|
-
(
|
|
14
|
-
automatically on hover,
|
|
13
|
+
(`.marquee-scroller-group` renders twice: once real, once `aria-hidden="true"` and `inert`), and the
|
|
14
|
+
whole thing pauses automatically on hover, whenever focus is inside it, and when the user has
|
|
15
|
+
`prefers-reduced-motion` set.
|
|
15
16
|
|
|
16
17
|
## Props
|
|
17
18
|
|
|
@@ -24,11 +25,12 @@ automatically on hover, on keyboard focus, and when the user has `prefers-reduce
|
|
|
24
25
|
| `ariaLabel` | `string` | `"Scrolling content"` | `aria-label` on the root region — override for localisation. |
|
|
25
26
|
| `ariaDescription` | `string` | `"Use spacebar to pause or play the animation."` | Screen-reader-only instructions rendered inside the region — override for localisation. |
|
|
26
27
|
| `showControls` | `boolean` | `false` | Shows a visible pause/play button. Recommended (WCAG 2.2.2, Pause/Stop/Hide) whenever content scrolls automatically and indefinitely. |
|
|
27
|
-
| `respectReducedMotion` | `boolean` | `true` | Auto-pauses and disables the animation for users with `prefers-reduced-motion: reduce
|
|
28
|
+
| `respectReducedMotion` | `boolean` | `true` | Auto-pauses and disables the animation for users with `prefers-reduced-motion: reduce` (and keeps it paused after focus leaves). Focus-pausing no longer depends on it. |
|
|
28
29
|
| `playIcon` | `string` | `"mdi:play"` | Iconify icon name shown on the control button while paused. Ignored if the `toggle-icon` slot is used. |
|
|
29
30
|
| `pauseIcon` | `string` | `"mdi:pause"` | Iconify icon name shown on the control button while playing. Ignored if the `toggle-icon` slot is used. |
|
|
30
|
-
| `playLabel` | `string` | `"Play animation"` | Control button
|
|
31
|
-
| `pauseLabel` | `string` | `"Pause animation"` | Control button
|
|
31
|
+
| `playLabel` | `string` | `"Play animation"` | Control button text (visually hidden, its accessible name) while paused — override for localisation. |
|
|
32
|
+
| `pauseLabel` | `string` | `"Pause animation"` | Control button text (visually hidden, its accessible name) while playing — override for localisation. |
|
|
33
|
+
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes on the root `.marquee-scroller`, via `useStyleClassPassthrough` (reacts to prop changes). |
|
|
32
34
|
|
|
33
35
|
Import the item types from the library's type exports when building `marqueeData`/`itemConfig`
|
|
34
36
|
outside the component:
|
|
@@ -52,8 +54,10 @@ One dynamically-named slot per `marqueeData` entry, named after that item's `id`
|
|
|
52
54
|
</MarqueeScroller>
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
Each slot is rendered twice (once in the visible group, once in the `aria-hidden`
|
|
56
|
-
so the loop wraps seamlessly
|
|
57
|
+
Each slot is rendered twice (once in the visible group, once in the `aria-hidden`, `inert`
|
|
58
|
+
duplicate group) so the loop wraps seamlessly. Don't put anything with side effects or unique ids
|
|
59
|
+
inside a slot. Links are fine: only the real copy is focusable. Items are fixed-size boxes; text
|
|
60
|
+
wraps inside them (`overflow-wrap: anywhere`) but content taller than `itemConfig.height` overflows.
|
|
57
61
|
|
|
58
62
|
`toggle-icon` (scoped with `{ isPaused: boolean }`) replaces the control button's icon entirely —
|
|
59
63
|
use this instead of `playIcon`/`pauseIcon` when an Iconify name isn't enough (custom SVG, a
|
|
@@ -70,16 +74,25 @@ different icon set):
|
|
|
70
74
|
## Accessibility behaviour
|
|
71
75
|
|
|
72
76
|
- The root is `role="region"` with `tabindex="0"` so it's independently focusable.
|
|
73
|
-
- Spacebar toggles pause/play while the region is focused
|
|
77
|
+
- Spacebar toggles pause/play while the region itself is focused (keydown from inside, e.g. on the
|
|
78
|
+
control button or a link, is left to that element). Arrow keys do nothing — there is no
|
|
74
79
|
manual-stepping behaviour, so the default `ariaDescription` doesn't claim one (fixed 2026-09-08;
|
|
75
80
|
it previously announced "arrow keys ... for manual control" with no implementation behind it).
|
|
76
|
-
-
|
|
77
|
-
|
|
81
|
+
- Focus anywhere inside the region (the region itself, or a link in an item) pauses the animation
|
|
82
|
+
and removes `aria-hidden` from the track, so the focused content is announced. Focus moving between
|
|
83
|
+
elements inside keeps it paused. When focus leaves, it resumes only if focus caused the pause and
|
|
84
|
+
the user doesn't prefer reduced motion: a pause chosen with the button or spacebar sticks.
|
|
85
|
+
Focus landing on the control button doesn't auto-pause, so one click pauses. (Changed 2026-10-17:
|
|
86
|
+
this used to listen for `focus`/`blur` on the region only, gated on `respectReducedMotion`, so
|
|
87
|
+
tabbing to a link in an item left it moving and `aria-hidden`.)
|
|
78
88
|
- Hovering anywhere over the scroller pauses the track and applies
|
|
79
89
|
`--marquee-scroller-group-hover-filter` (default `grayscale(1)`) to every item; hovering an
|
|
80
90
|
individual item restores it via `--marquee-scroller-item-hover-filter` (default `grayscale(0)`).
|
|
81
91
|
- `aria-live` switches to `"polite"` while paused so screen readers announce the paused content.
|
|
82
|
-
- The
|
|
92
|
+
- The track is `aria-hidden="true"` while playing (attribute removed when paused). The duplicate
|
|
93
|
+
group is always `aria-hidden="true"` and `inert`, so its copies of any links can't be focused.
|
|
94
|
+
- The control button is an `InputButton` (`variant="inline"`, icon-only): `playLabel`/`pauseLabel`
|
|
95
|
+
is its visually hidden text rather than an `aria-label`.
|
|
83
96
|
- All user-visible copy (`ariaLabel`, `ariaDescription`, `playLabel`, `pauseLabel`) is a plain
|
|
84
97
|
string prop with an English default — there's no i18n framework dependency in this library, so
|
|
85
98
|
pass translated strings from the consumer's own i18n solution.
|
|
@@ -110,11 +123,11 @@ theme); only its border width is (`--marquee-scroller-control-border-width`).
|
|
|
110
123
|
|
|
111
124
|
## Seamless loop math
|
|
112
125
|
|
|
113
|
-
The track duplicates `marqueeData` into two `.marquee-group` children so the loop can wrap without
|
|
126
|
+
The track duplicates `marqueeData` into two `.marquee-scroller-group` children so the loop can wrap without
|
|
114
127
|
a visible cut. The animation must shift the track by exactly one group's width plus its connecting
|
|
115
128
|
gap — not `translateX(-50%)`, which overshoots short of the seam once the track's own `gap`
|
|
116
129
|
between the two groups is added to its total width. This is computed as a private
|
|
117
|
-
`--_track-shift: calc(itemCount * (itemWidth + gap))` token and used in the `
|
|
130
|
+
`--_track-shift: calc(itemCount * (itemWidth + gap))` token and used in the `marquee-scroller-move`
|
|
118
131
|
keyframe. Fixed 2026-09-08 — the original `-50%` version produced a small but visible gap/overlap
|
|
119
132
|
at the loop point once more than a couple of items were in `marqueeData`.
|
|
120
133
|
|
|
@@ -125,6 +138,30 @@ section on a wide viewport), the loop briefly shows empty space before snapping
|
|
|
125
138
|
the visible track only spans as wide as the content, not the container. On mount (and on
|
|
126
139
|
container resize, via `ResizeObserver`), the component measures one rendered group's `scrollWidth`
|
|
127
140
|
against the root element's `offsetWidth` and repeats `marqueeData` internally (`repeatCount`)
|
|
128
|
-
enough times per `.marquee-group` so a single group's width always covers the container. This is
|
|
141
|
+
enough times per `.marquee-scroller-group` so a single group's width always covers the container. This is
|
|
129
142
|
transparent to consumers — it doesn't change `marqueeData` or any prop, only how many times each
|
|
130
143
|
item's slot is rendered internally. Fixed 2026-09-08.
|
|
144
|
+
|
|
145
|
+
The repeat count is capped at 50 copies per group, so tiny items in a huge container can't flood
|
|
146
|
+
the DOM (added 2026-10-17).
|
|
147
|
+
|
|
148
|
+
## Storybook
|
|
149
|
+
|
|
150
|
+
`Atoms/Effects/MarqueeScroller`: `WithControls`, `FocusableItems` (links in items, for the focus
|
|
151
|
+
behaviour), and `StressTest` (24 items of hostile copy, a broken image, long localised labels, a
|
|
152
|
+
single item, tiny items hitting the repeat cap, and empty data). Stories use the `CanvasSwitcher`
|
|
153
|
+
decorator.
|
|
154
|
+
|
|
155
|
+
## History
|
|
156
|
+
|
|
157
|
+
**2026-10-17** (stress-test pass, breaking class renames):
|
|
158
|
+
|
|
159
|
+
- Structural classes prefixed (`.marquee-scroller-item`, `-control`, `-track`, `-group`,
|
|
160
|
+
`-description`); bare `.reverse`/`.paused`/`.reduced-motion` became `data-*` attributes; keyframes
|
|
161
|
+
renamed `marquee-scroller-move`. See CONSUMER-STYLING.md for the full map.
|
|
162
|
+
- Raw `<button>` replaced with `InputButton variant="inline"` (icon-only slot).
|
|
163
|
+
- Focus-pausing reworked (focusin/focusout, see Accessibility behaviour); duplicate group `inert`.
|
|
164
|
+
- `prefers-reduced-motion` change listener is now removed on unmount.
|
|
165
|
+
- New `--marquee-scroller-focus-outline-colour` token (was bare `--theme-ring`).
|
|
166
|
+
- Added `styleClassPassthrough`. Removed the redundant `aspect-ratio: 1 / 1` on items (width and
|
|
167
|
+
height are both set, and it mis-centres on old Safari). Items wrap unbroken text.
|
|
@@ -59,6 +59,17 @@ in `.skip-links__home`. Only rendered when the slot is actually used.
|
|
|
59
59
|
Each `href` must match the `id` of a real element on the page (e.g. `<main id="main-content">`) —
|
|
60
60
|
the component does not create those anchors itself.
|
|
61
61
|
|
|
62
|
+
Data handling (safe to feed straight from a CMS):
|
|
63
|
+
|
|
64
|
+
- An entry with an empty or whitespace-only `href` or `label` is dropped: an empty link has no
|
|
65
|
+
target or no accessible name.
|
|
66
|
+
- When no entry survives, the `<nav>` isn't rendered at all, so there's no empty landmark.
|
|
67
|
+
- Two entries may share an `href`; each renders (keys include the index). Before 2026-10-18 they
|
|
68
|
+
were keyed by `href` alone, and reordering such a list left a stale extra link in the DOM.
|
|
69
|
+
- Labels render as text and wrap; the panel never exceeds the viewport width.
|
|
70
|
+
|
|
71
|
+
`SiteHeader` renders `SkipLinks` as its branding row, passing its `branding` slot into `homeLink`.
|
|
72
|
+
|
|
62
73
|
## Accessibility behaviour
|
|
63
74
|
|
|
64
75
|
- Links are hidden via `opacity`/`transform`, not `display`/`visibility` — they stay in the tab
|
|
@@ -80,3 +91,8 @@ See `CONSUMER-STYLING.md` in this component's folder for the full `--skip-links-
|
|
|
80
91
|
- Migrated 2026-09-15 from the unplaced `skip-links/` folder: the link set was previously
|
|
81
92
|
hardcoded (two fixed `<a>` tags with hardcoded English copy) — now data-driven via `links` so
|
|
82
93
|
consumers can add/remove targets and localise the copy without forking the component.
|
|
94
|
+
- 2026-10-18 migration: colours moved from hardcoded black/white to `--theme-surface-inverted` and
|
|
95
|
+
`--theme-on-surface` defaults (same high contrast, follows `data-theme`); z-index default
|
|
96
|
+
`1000` → `999999` (library overlay default); links wrap instead of `nowrap`, and the panel is
|
|
97
|
+
capped at the viewport width and anchored with `inset-inline-start`; invalid entries dropped, no
|
|
98
|
+
empty landmark, index-safe keys; StressTest story and a link to the SiteHeader story.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## Prerequisites
|
|
10
10
|
|
|
11
|
-
- Built around the native Popover API (Chrome 114+, Firefox 125+, Safari 17+). With `DisplayTooltip`/`
|
|
11
|
+
- Built around the native Popover API (Chrome 114+, Firefox 125+, Safari 17+). With `DisplayTooltip`/`DisplayTooltipRich` it also works on Safari 16, because those components fall back to JS open/close (`useAnchoredPopover`) and the guide drives them through their trigger buttons. Hand-written raw `[popover]` markup like the example below still needs the Popover API.
|
|
12
12
|
- Popovers must have `id` attributes and corresponding trigger buttons with `popovertarget` and `popovertargetaction="toggle"` attributes
|
|
13
13
|
- Close buttons inside each popover must have `popovertargetaction="hide"`
|
|
14
14
|
|
|
@@ -91,13 +91,13 @@ await startGuide()
|
|
|
91
91
|
| `stopGuide()` | `() => void` | Close any open popovers and stop the guide |
|
|
92
92
|
| `initializePopovers()` | `() => void` | Re-scan the container for `[popover]` elements; call if popovers are added dynamically |
|
|
93
93
|
|
|
94
|
-
## Example with DisplayTooltip /
|
|
94
|
+
## Example with DisplayTooltip / DisplayTooltipRich
|
|
95
95
|
|
|
96
96
|
[`DisplayTooltip`](components/display-tooltip.md) and
|
|
97
|
-
[`
|
|
97
|
+
[`DisplayTooltipRich`](components/display-tooltip-rich.md) already emit the
|
|
98
98
|
`[popover]`/`popovertarget`/`popovertargetaction` markup this composable expects, so no extra
|
|
99
99
|
wiring is needed beyond passing their shared container's ref in. See the `GuidedTour` story in
|
|
100
|
-
`
|
|
100
|
+
`DisplayTooltipRich.stories.ts` for a full working example — it recreates the old
|
|
101
101
|
`app/pages/ui/tooltips.vue` demo page (removed 2026-08-23 when Storybook became the only demo
|
|
102
102
|
surface), mixing one of each component as guide steps.
|
|
103
103
|
|
package/.claude/skills/index.md
CHANGED
|
@@ -97,19 +97,19 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
97
97
|
├── service-summary.md — ServiceSummary props, summary-link slot, DisplayPill duration/price (renamed/stripped from ServicesSection — full mode is now ServiceDetail)
|
|
98
98
|
├── service-detail.md — ServiceDetail: full service detail page (hero banner, sticky sidebar booking card + related services, closing CTA), headerTag vs subheadingTag split, book-cta/sidebar-note/related-service/final-cta slots
|
|
99
99
|
├── breadcrumb.md — Breadcrumb: items (BreadcrumbItem[]) trail, link vs current-page text, CSS token API
|
|
100
|
-
├── skip-links.md — SkipLinks: focus-revealed accessibility skip-nav, links (SkipLink[]) data-driven, homeLink slot, CSS token API
|
|
100
|
+
├── skip-links.md — SkipLinks: focus-revealed accessibility skip-nav, links (SkipLink[]) data-driven, homeLink slot, empty entries dropped, index-safe keys, theme-token colours, viewport-capped wrapping panel, CSS token API
|
|
101
101
|
├── tabbed-content.md — TabbedContent (was TabsCore): tablist + panels from indexed slots (itemCount), arrow-key nav, moving hover/active/underline indicators, CSS token API
|
|
102
102
|
├── contact-section.md — ContactSection props (stepperIndicatorSize pass-through), 3-item info+form layout, slot API
|
|
103
103
|
├── stepper-list.md — StepperList dynamic slots (item-{n}/indicator-{n}), props, measured connectors (gap, dashed image tokens), per-step state recipe
|
|
104
104
|
├── progress-tracker.md — ProgressTracker: steps (ProgressTrackerStep[]) + v-model current index over StepperList, header label + progressbar, current-step #step-{n} slot for wizard forms, focus on change, CSS token API
|
|
105
105
|
├── expanding-panel.md — ExpandingPanel v-model, forceOpened, contentIsOnTop overlay mode, slots (summary/icon/content), ARIA wiring, CSS token API
|
|
106
|
-
├── content-docs.md — ContentDocs docs-page shell: prop-driven docsNav/docsPageNav (not slots), DocsNavItem icons, container-width breakpoint behaviour, shared/per-side CSS token API
|
|
106
|
+
├── content-docs.md — ContentDocs docs-page shell: prop-driven docsNav/docsPageNav (not slots), DocsNavItem icons, container-width breakpoint behaviour, shared/per-side CSS token API, content-docs-* classes, aria-current active state
|
|
107
107
|
├── glass-panel.md — GlassPanel: frosted-glass container, light-only token defaults in-component (light-dark() block removed from _default.css, no built-in dark glass), highlight behind content, section/article labelled via headingId slot prop, CSS token API
|
|
108
108
|
├── pricing-card.md — PricingCard: plan card with highlight badge, corner ribbon, feature list, #cta slot, heading-tag, line-clamp tokens
|
|
109
109
|
├── price-list.md — PriceList: service/menu price columns (dl rows), PriceListData type, headingTag/fromLabel props, CSS token API
|
|
110
110
|
├── opening-hours.md — OpeningHours: per-day data auto-grouped into ranges, split sessions, 24h/appointment, exceptions, Intl formatting, today highlight, JSON-LD, CSS token API
|
|
111
111
|
├── input-copy.md — InputCopy: readonly copy-to-clipboard input with an inline InputButton, copied state + status announcement, translatable labels/icons, container-query icon-only button, --input-copy-* tokens
|
|
112
|
-
├── banner-video.md — BannerVideo: full-width hero video banner, depth tier system, objectFit/objectPosition, playIcon/pauseIcon/toggle-icon slot, reduced-motion fallback, CSS tokens
|
|
112
|
+
├── banner-video.md — BannerVideo: full-width hero video banner, depth tier system, objectFit/objectPosition, playIcon/pauseIcon/toggle-icon slot, playLabel/pauseLabel, reduced-motion fallback, CSS tokens
|
|
113
113
|
├── grid-stack.md — GridStack: CSS Grid z-axis stacking, slot API, z-order rules, sizing, video+overlay and image+text patterns
|
|
114
114
|
├── scroll-reveal-frame.md — ScrollRevealFrame: generic parallax clipping frame, slot API, image grid pattern, public --scroll-reveal-frame-* tokens (props only write them when passed), browser support
|
|
115
115
|
├── scroll-reveal-image.md — ScrollRevealImage: single-image parallax reveal, imgWidth/imgHeight, public focal-x/focal-y crop tokens, frame tokens settable from CSS
|
|
@@ -127,7 +127,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
127
127
|
├── card-core.md — CardCore: generic card container, dynamic named slots as rows, 4 variants, blurred backdrop layer, full CSS token API
|
|
128
128
|
├── action-menu.md — ActionMenu + ActionMenuItem: ellipsis trigger + anchored popover menu, indexed item-{n} slots, link/button items, full CSS token API
|
|
129
129
|
├── select-menu.md — SelectMenu: v-model single-select listbox popover (ActionMenu's popover mechanics, InputSelect's selected-option semantics), icon/text/chevron trigger toggles, checkmark on selected option, options-array driven, full CSS token API
|
|
130
|
-
├── display-dialog.md — DisplayDialog: native <dialog> overlay, 5 variants (dialog/modal/confirm/alert/fullscreen), useDialogControls integration, CSS token API
|
|
130
|
+
├── display-dialog.md — DisplayDialog: native <dialog> overlay, 5 variants (dialog/modal/confirm/alert/fullscreen), useDialogControls integration, InputButton close button, viewport-capped panel with wrapping title/content/footer, aria-label fallthrough when untitled, CSS token API
|
|
131
131
|
├── display-chip.md — DisplayChip: status indicator chip overlay, CSS trig positioning, circle/square shapes, status colours, icon/label content
|
|
132
132
|
├── display-pill.md — DisplayPill: pill/badge label with icon slot, 6 variants, 3 sizes, reversible order, --display-pill-* tokens (variants fall back to base colour/border/ring tokens); data-size/data-variant/data-reversed hooks (2026-10-08, were bare classes), label line-clamp token, -02 ring and outlined-monochrome recipes, StressTest story
|
|
133
133
|
├── carousel-flip.md — CarouselFlip: FLIP-animated carousel, carouselDataIds slot API, buttonLayout variants (sides/controls-flanking/controls-grouped-right/overlay), CSS tokens
|
|
@@ -142,8 +142,8 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
142
142
|
├── display-banner.md — DisplayBanner: canvas/content stacked overlay banner, conditional slot wrappers, CSS token API
|
|
143
143
|
├── deep-expanding-menu.md — DeepExpandingMenu: anchor-positioned popover nav panels, browser support caveat, CSS token API
|
|
144
144
|
├── deep-expanding-menu-classic.md — DeepExpandingMenuClassic: <details>-based fallback nav, click-outside close, CSS token API
|
|
145
|
-
├── display-tooltip.md — DisplayTooltip: anchor-positioned popover trigger, browser support caveat, CSS token API
|
|
146
|
-
├── display-tooltip-
|
|
145
|
+
├── display-tooltip.md — DisplayTooltip: anchor-positioned popover trigger, browser support caveat, triggerIcon prop, type="button" trigger, hideTrigger removes it from tab order (data-hidden), CSS token API
|
|
146
|
+
├── display-tooltip-rich.md — DisplayTooltipRich (Material 3 rich tooltip, renamed from DisplayTooltipDefined 2026-10-18): structured title/body/action content with InputButton close button, per-field line-clamp tokens, composes DisplayTooltip
|
|
147
147
|
├── pop-over.md — PopOver: generic anchor-positioned disclosure panel, consumer-supplied trigger/content slots, placement prop, CSS token API
|
|
148
148
|
├── input-text.md — InputText (bare control), InputTextField, InputPasswordField, InputTextAsNumberField: renamed from Core/WithLabel, data-* state hooks, readonly/autocomplete props, leak-free digit filtering, wrapper attr-leak/empty-description/passthrough fixes, rounded+clamped stepping, min/max pass-through, CSS token API, stress stories
|
|
149
149
|
├── input-button.md — InputButton (renamed from InputButtonCore 2026-09-28): button/NuxtLink/a; primary filled, secondary outlined, tertiary text-only, inline unstyled; data-* state hooks; shadow ring + border-colour hover; wrapping labels; icon slots; readonly (aria-disabled, activation blocked); tokens
|
|
@@ -338,6 +338,14 @@ const ids = host.findAll("input").map((input) => input.attributes("id"));
|
|
|
338
338
|
expect(new Set(ids).size).toBe(ids.length);
|
|
339
339
|
```
|
|
340
340
|
|
|
341
|
+
## Testing duplicate `v-for` keys
|
|
342
|
+
|
|
343
|
+
Duplicate keys don't show on first render, and Vue only warns (and only corrupts the DOM) inside
|
|
344
|
+
the keyed diff's unsorted middle section. A reorder that keeps the first or last item in place can
|
|
345
|
+
be resolved from the ends and never reaches it. Mount with two items sharing the repeatable field,
|
|
346
|
+
then `setProps` with the first and last items swapped, and assert the rendered labels in order
|
|
347
|
+
(`SkipLinks.spec.ts`). With an `href`-only key that test rendered five links instead of four.
|
|
348
|
+
|
|
341
349
|
## Mocking browser APIs
|
|
342
350
|
|
|
343
351
|
### Global constructors (ResizeObserver, IntersectionObserver, etc.)
|
|
@@ -4,12 +4,24 @@
|
|
|
4
4
|
"scope": "vue,html",
|
|
5
5
|
"body": [
|
|
6
6
|
"<BannerVideo",
|
|
7
|
-
" src=\"$1
|
|
8
|
-
" poster=\"$2
|
|
9
|
-
" alt=\"$
|
|
10
|
-
" :img-width=\"1920\"",
|
|
11
|
-
" :img-height=\"1080\"",
|
|
12
|
-
" depth=\"$
|
|
7
|
+
" src=\"${1:/videos/hero.mp4}\"",
|
|
8
|
+
" poster=\"${2:/images/hero-poster.jpg}\"",
|
|
9
|
+
" alt=\"${3:Studio interior}\"",
|
|
10
|
+
" :img-width=\"${4:1920}\"",
|
|
11
|
+
" :img-height=\"${5:1080}\"",
|
|
12
|
+
" depth=\"${6|md,xs,sm,lg,xl|}\"",
|
|
13
|
+
"/>"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"SRCDEV BannerVideo Localised Labels": {
|
|
17
|
+
"description": "BannerVideo with translated pause/play toggle labels (the button's visually hidden accessible name)",
|
|
18
|
+
"scope": "vue,html",
|
|
19
|
+
"body": [
|
|
20
|
+
"<BannerVideo",
|
|
21
|
+
" src=\"${1:/videos/hero.mp4}\"",
|
|
22
|
+
" poster=\"${2:/images/hero-poster.jpg}\"",
|
|
23
|
+
" :play-label=\"${3:t('banner.playVideo')}\"",
|
|
24
|
+
" :pause-label=\"${4:t('banner.pauseVideo')}\"",
|
|
13
25
|
"/>"
|
|
14
26
|
]
|
|
15
27
|
},
|
|
@@ -18,10 +30,10 @@
|
|
|
18
30
|
"scope": "vue,html",
|
|
19
31
|
"body": [
|
|
20
32
|
"<BannerVideo",
|
|
21
|
-
" src=\"$1
|
|
22
|
-
" poster=\"$2
|
|
23
|
-
" play-icon=\"$
|
|
24
|
-
" pause-icon=\"$
|
|
33
|
+
" src=\"${1:/videos/hero.mp4}\"",
|
|
34
|
+
" poster=\"${2:/images/hero-poster.jpg}\"",
|
|
35
|
+
" play-icon=\"${3:mdi:play-circle}\"",
|
|
36
|
+
" pause-icon=\"${4:mdi:pause-circle}\"",
|
|
25
37
|
"/>"
|
|
26
38
|
]
|
|
27
39
|
},
|
|
@@ -29,7 +41,7 @@
|
|
|
29
41
|
"description": "BannerVideo with the toggle-icon slot fully replacing the toggle button's icon",
|
|
30
42
|
"scope": "vue,html",
|
|
31
43
|
"body": [
|
|
32
|
-
"<BannerVideo src=\"$1
|
|
44
|
+
"<BannerVideo src=\"${1:/videos/hero.mp4}\" poster=\"${2:/images/hero-poster.jpg}\">",
|
|
33
45
|
" <template #toggle-icon=\"{ isPlaying }\">",
|
|
34
46
|
" $3",
|
|
35
47
|
" </template>",
|
|
@@ -37,22 +49,23 @@
|
|
|
37
49
|
]
|
|
38
50
|
},
|
|
39
51
|
"SRCDEV BannerVideo CSS Override": {
|
|
40
|
-
"description": "CSS override scaffold for BannerVideo —
|
|
52
|
+
"description": "CSS override scaffold for BannerVideo — set tokens on a page or section class you own",
|
|
41
53
|
"scope": "css",
|
|
42
54
|
"body": [
|
|
43
|
-
".$
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
55
|
+
".${1:my-page} {",
|
|
56
|
+
" --banner-video-max-height-xs: ;",
|
|
57
|
+
" --banner-video-max-height-sm: ;",
|
|
58
|
+
" --banner-video-max-height-md: ;",
|
|
59
|
+
" --banner-video-max-height-lg: ;",
|
|
60
|
+
" --banner-video-max-height-xl: ;",
|
|
61
|
+
" --banner-video-toggle-size: ;",
|
|
62
|
+
" --banner-video-toggle-offset: ;",
|
|
63
|
+
" --banner-video-toggle-background: ;",
|
|
64
|
+
" --banner-video-toggle-background-hover: ;",
|
|
65
|
+
" --banner-video-toggle-icon-color: ;",
|
|
66
|
+
" --banner-video-toggle-focus-outline-width: ;",
|
|
67
|
+
" --banner-video-toggle-focus-outline-color: ;",
|
|
68
|
+
" --banner-video-toggle-focus-outline-offset: ;",
|
|
56
69
|
"}"
|
|
57
70
|
]
|
|
58
71
|
}
|
|
@@ -4,49 +4,51 @@
|
|
|
4
4
|
"scope": "vue,html",
|
|
5
5
|
"body": [
|
|
6
6
|
"<ContentDocs",
|
|
7
|
-
" v-model:active-nav-item=\"$
|
|
8
|
-
" v-model:active-page-nav-item=\"$
|
|
9
|
-
" :docs-nav-items=\"$
|
|
10
|
-
" :docs-page-nav-items=\"$
|
|
7
|
+
" v-model:active-nav-item=\"${1:activeNavItem}\"",
|
|
8
|
+
" v-model:active-page-nav-item=\"${2:activePageNavItem}\"",
|
|
9
|
+
" :docs-nav-items=\"${3:docsNavItems}\"",
|
|
10
|
+
" :docs-page-nav-items=\"${4:docsPageNavItems}\"",
|
|
11
11
|
">",
|
|
12
12
|
" <template #docsContent>",
|
|
13
|
-
" <p>$
|
|
13
|
+
" <p>${5:Page content goes here.}</p>",
|
|
14
14
|
" </template>",
|
|
15
15
|
"</ContentDocs>"
|
|
16
16
|
]
|
|
17
17
|
},
|
|
18
|
-
"SRCDEV ContentDocs Custom Labels"
|
|
18
|
+
"SRCDEV ContentDocs Custom Labels": {
|
|
19
19
|
"description": "ContentDocs with custom docsNav / docsPageNav panel headings",
|
|
20
20
|
"scope": "vue,html",
|
|
21
21
|
"body": [
|
|
22
22
|
"<ContentDocs",
|
|
23
|
-
" v-model:active-nav-item=\"$
|
|
24
|
-
" v-model:active-page-nav-item=\"$
|
|
25
|
-
" :docs-nav-items=\"$
|
|
26
|
-
" :docs-page-nav-items=\"$
|
|
27
|
-
" docs-nav-label=\"$
|
|
28
|
-
" docs-page-nav-label=\"$
|
|
23
|
+
" v-model:active-nav-item=\"${1:activeNavItem}\"",
|
|
24
|
+
" v-model:active-page-nav-item=\"${2:activePageNavItem}\"",
|
|
25
|
+
" :docs-nav-items=\"${3:docsNavItems}\"",
|
|
26
|
+
" :docs-page-nav-items=\"${4:docsPageNavItems}\"",
|
|
27
|
+
" docs-nav-label=\"${5:Sections}\"",
|
|
28
|
+
" docs-page-nav-label=\"${6:Contents}\"",
|
|
29
29
|
">",
|
|
30
30
|
" <template #docsContent>",
|
|
31
|
-
" <p>$
|
|
31
|
+
" <p>${7:Page content goes here.}</p>",
|
|
32
32
|
" </template>",
|
|
33
33
|
"</ContentDocs>"
|
|
34
34
|
]
|
|
35
35
|
},
|
|
36
36
|
"SRCDEV ContentDocs Localised Nav Labels": {
|
|
37
|
-
"description": "ContentDocs with localised aria-labels on the docsNav/docsPageNav <nav> landmarks",
|
|
37
|
+
"description": "ContentDocs with localised headings and aria-labels on the docsNav/docsPageNav <nav> landmarks",
|
|
38
38
|
"scope": "vue,html",
|
|
39
39
|
"body": [
|
|
40
40
|
"<ContentDocs",
|
|
41
|
-
" v-model:active-nav-item=\"$
|
|
42
|
-
" v-model:active-page-nav-item=\"$
|
|
43
|
-
" :docs-nav-items=\"$
|
|
44
|
-
" :docs-page-nav-items=\"$
|
|
45
|
-
" docs-nav-
|
|
46
|
-
" docs-page-nav-
|
|
41
|
+
" v-model:active-nav-item=\"${1:activeNavItem}\"",
|
|
42
|
+
" v-model:active-page-nav-item=\"${2:activePageNavItem}\"",
|
|
43
|
+
" :docs-nav-items=\"${3:docsNavItems}\"",
|
|
44
|
+
" :docs-page-nav-items=\"${4:docsPageNavItems}\"",
|
|
45
|
+
" :docs-nav-label=\"${5:t('docs.navLabel')}\"",
|
|
46
|
+
" :docs-page-nav-label=\"${6:t('docs.pageNavLabel')}\"",
|
|
47
|
+
" :docs-nav-aria-label=\"${7:t('docs.navAriaLabel')}\"",
|
|
48
|
+
" :docs-page-nav-aria-label=\"${8:t('docs.pageNavAriaLabel')}\"",
|
|
47
49
|
">",
|
|
48
50
|
" <template #docsContent>",
|
|
49
|
-
" <p>$
|
|
51
|
+
" <p>${9:Page content goes here.}</p>",
|
|
50
52
|
" </template>",
|
|
51
53
|
"</ContentDocs>"
|
|
52
54
|
]
|
|
@@ -56,11 +58,11 @@
|
|
|
56
58
|
"scope": "typescript,vue",
|
|
57
59
|
"body": [
|
|
58
60
|
"const docsNavItems: DocsNavItem[] = [",
|
|
59
|
-
" { label: \"$
|
|
61
|
+
" { label: \"${1:Getting started}\", to: \"${2:/docs}\" },",
|
|
60
62
|
"];",
|
|
61
63
|
"",
|
|
62
64
|
"const docsPageNavItems: DocsNavItem[] = [",
|
|
63
|
-
" { label: \"$
|
|
65
|
+
" { label: \"${3:Overview}\", to: \"${2:/docs}#overview\" },",
|
|
64
66
|
"];",
|
|
65
67
|
"",
|
|
66
68
|
"const activeNavItem = ref<string | undefined>(docsNavItems[0]?.to);",
|
|
@@ -72,11 +74,11 @@
|
|
|
72
74
|
"scope": "typescript,vue",
|
|
73
75
|
"body": [
|
|
74
76
|
"const docsNavItems: DocsNavItem[] = [",
|
|
75
|
-
" { label: \"$
|
|
77
|
+
" { label: \"${1:Getting started}\", to: \"${2:/docs}\", icon: \"${3:lucide:rocket}\" },",
|
|
76
78
|
"];",
|
|
77
79
|
"",
|
|
78
80
|
"const docsPageNavItems: DocsNavItem[] = [",
|
|
79
|
-
" { label: \"$
|
|
81
|
+
" { label: \"${4:Overview}\", to: \"${2:/docs}#overview\", icon: \"${5:lucide:list}\" },",
|
|
80
82
|
"];",
|
|
81
83
|
"",
|
|
82
84
|
"const activeNavItem = ref<string | undefined>(docsNavItems[0]?.to);",
|
|
@@ -87,13 +89,11 @@
|
|
|
87
89
|
"description": "CSS override scaffold for ContentDocs nav-link icon tokens (gap, size, and start/end order)",
|
|
88
90
|
"scope": "css",
|
|
89
91
|
"body": [
|
|
90
|
-
".$
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
" --content-docs-page-nav-link-icon-order: $5ltr; /* icon at the start (default) */",
|
|
96
|
-
" }",
|
|
92
|
+
".${1:my-content-docs} {",
|
|
93
|
+
" --content-docs-link-icon-gap: $2;",
|
|
94
|
+
" --content-docs-link-icon-size: $3;",
|
|
95
|
+
" --content-docs-nav-link-icon-order: ${4:rtl}; /* icon at the end */",
|
|
96
|
+
" --content-docs-page-nav-link-icon-order: ${5:ltr}; /* icon at the start (default) */",
|
|
97
97
|
"}"
|
|
98
98
|
]
|
|
99
99
|
},
|
|
@@ -101,27 +101,26 @@
|
|
|
101
101
|
"description": "CSS override scaffold for ContentDocs heading/panel/link tokens, applied to both docsNav and docsPageNav at once",
|
|
102
102
|
"scope": "css",
|
|
103
103
|
"body": [
|
|
104
|
-
".$
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
" --content-docs-heading-padding-block: $5;",
|
|
104
|
+
".${1:my-content-docs} {",
|
|
105
|
+
" --content-docs-heading-font-size: $2;",
|
|
106
|
+
" --content-docs-heading-color: $3;",
|
|
107
|
+
" --content-docs-heading-bg: $4;",
|
|
108
|
+
" --content-docs-heading-padding-block: $5;",
|
|
110
109
|
"",
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
110
|
+
" --content-docs-panel-bg: $6;",
|
|
111
|
+
" --content-docs-panel-padding-block: $7;",
|
|
112
|
+
" --content-docs-panel-padding-inline: $8;",
|
|
114
113
|
"",
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
114
|
+
" --content-docs-link-font-size: $9;",
|
|
115
|
+
" --content-docs-link-color: $10;",
|
|
116
|
+
" --content-docs-link-hover-bg: $11;",
|
|
117
|
+
" --content-docs-link-active-bg: $12;",
|
|
118
|
+
" --content-docs-link-active-color: $13;",
|
|
119
|
+
" --content-docs-link-focus-outline-color: $14;",
|
|
120
120
|
"",
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
" }",
|
|
121
|
+
" --content-docs-nav-column-width: $15;",
|
|
122
|
+
" --content-docs-page-nav-column-width: $16;",
|
|
123
|
+
" --content-docs-page-nav-column-width-tablet: $17;",
|
|
125
124
|
"}"
|
|
126
125
|
]
|
|
127
126
|
},
|
|
@@ -129,17 +128,27 @@
|
|
|
129
128
|
"description": "CSS override scaffold for independently theming docsNav vs docsPageNav heading/panel/link tokens",
|
|
130
129
|
"scope": "css",
|
|
131
130
|
"body": [
|
|
132
|
-
".$
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
" --content-docs-nav-link-active-bg: $4;",
|
|
131
|
+
".${1:my-content-docs} {",
|
|
132
|
+
" /* docsNav (primary) */",
|
|
133
|
+
" --content-docs-nav-heading-color: $2;",
|
|
134
|
+
" --content-docs-nav-panel-bg: $3;",
|
|
135
|
+
" --content-docs-nav-link-active-bg: $4;",
|
|
138
136
|
"",
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
137
|
+
" /* docsPageNav (on-this-page / secondary) */",
|
|
138
|
+
" --content-docs-page-nav-heading-color: $5;",
|
|
139
|
+
" --content-docs-page-nav-panel-bg: $6;",
|
|
140
|
+
" --content-docs-page-nav-link-active-bg: $7;",
|
|
141
|
+
"}"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
"SRCDEV ContentDocs CSS Override — Active Link": {
|
|
145
|
+
"description": "Style the active ContentDocs link beyond its tokens: select [aria-current=\"page\"], there is no .is-active class",
|
|
146
|
+
"scope": "css",
|
|
147
|
+
"body": [
|
|
148
|
+
".${1:my-content-docs} {",
|
|
149
|
+
" .content-docs-nav-link[aria-current=\"page\"],",
|
|
150
|
+
" .content-docs-page-nav-link[aria-current=\"page\"] {",
|
|
151
|
+
" $2",
|
|
143
152
|
" }",
|
|
144
153
|
"}"
|
|
145
154
|
]
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
]
|
|
20
20
|
},
|
|
21
21
|
"SRCDEV DisplayDialog Confirm Template": {
|
|
22
|
-
"description": "DisplayDialog confirm variant —
|
|
22
|
+
"description": "DisplayDialog confirm variant — compact (max 48rem), dismissable with Escape or outside-click",
|
|
23
23
|
"scope": "vue,html",
|
|
24
24
|
"body": [
|
|
25
25
|
"<DisplayDialog",
|
|
@@ -114,10 +114,12 @@
|
|
|
114
114
|
" --display-dialog-backdrop-blur: ;",
|
|
115
115
|
" --display-dialog-transition-duration: ;",
|
|
116
116
|
"",
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
" .
|
|
117
|
+
" --display-dialog-header-accent-color: ;",
|
|
118
|
+
"",
|
|
119
|
+
" .display-dialog-inner {",
|
|
120
|
+
" .display-dialog-header {}",
|
|
121
|
+
" .display-dialog-content {}",
|
|
122
|
+
" .display-dialog-footer {}",
|
|
121
123
|
" }",
|
|
122
124
|
" }",
|
|
123
125
|
"}"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV DisplayTooltipRich Basic": {
|
|
3
|
+
"description": "DisplayTooltipRich — structured title/body/action tooltip",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<DisplayTooltipRich",
|
|
7
|
+
" :content-text=\"{",
|
|
8
|
+
" tooltipTitle: { tag: 'h4', text: '$1' },",
|
|
9
|
+
" tooltipContent: { tag: 'p', text: '$0' },",
|
|
10
|
+
" }\"",
|
|
11
|
+
"/>"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"SRCDEV DisplayTooltipRich Localised Copy": {
|
|
15
|
+
"description": "DisplayTooltipRich with localised trigger/close-button copy and a custom trigger icon",
|
|
16
|
+
"scope": "vue,html",
|
|
17
|
+
"body": [
|
|
18
|
+
"<DisplayTooltipRich",
|
|
19
|
+
" :content-text=\"{",
|
|
20
|
+
" tooltipTitle: { tag: 'h4', text: '$1' },",
|
|
21
|
+
" tooltipContent: { tag: 'p', text: '$2' },",
|
|
22
|
+
" }\"",
|
|
23
|
+
" trigger-aria-label=\"${3:Toggle the popover}\"",
|
|
24
|
+
" close-button-text=\"${4:Close}\"",
|
|
25
|
+
" close-button-aria-label=\"${5:Close tool tip}\"",
|
|
26
|
+
" trigger-icon=\"${6:fa7-solid:circle-question}\"",
|
|
27
|
+
"/>"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"SRCDEV DisplayTooltipRich CSS Override": {
|
|
31
|
+
"description": "CSS override scaffold for DisplayTooltipRich, scoped to a page or section class",
|
|
32
|
+
"scope": "css",
|
|
33
|
+
"body": [
|
|
34
|
+
".${1:my-page} {",
|
|
35
|
+
" .display-tooltip-rich {",
|
|
36
|
+
" --display-tooltip-rich-content-gap: ;",
|
|
37
|
+
" --display-tooltip-rich-title-colour: ;",
|
|
38
|
+
" --display-tooltip-rich-title-font-size: ;",
|
|
39
|
+
" --display-tooltip-rich-title-line-clamp: ${2:none};",
|
|
40
|
+
" --display-tooltip-rich-body-font-size: ;",
|
|
41
|
+
" --display-tooltip-rich-body-line-clamp: ${3:none};",
|
|
42
|
+
" --display-tooltip-rich-action-colour: ;",
|
|
43
|
+
" --display-tooltip-rich-action-line-clamp: ${4:none};",
|
|
44
|
+
" --display-tooltip-popover-background-colour: ;",
|
|
45
|
+
" --display-tooltip-popover-text-colour: ;",
|
|
46
|
+
" }",
|
|
47
|
+
"}"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}
|