srcdev-nuxt-components 9.4.5 → 9.4.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.
Files changed (45) hide show
  1. package/.claude/commands/migrate-component.md +40 -2
  2. package/.claude/component-ledger/audit.json +1 -1
  3. package/.claude/component-ledger/output.html +1 -1
  4. package/.claude/skills/components/breadcrumb.md +1 -0
  5. package/.claude/skills/components/content-docs.md +2 -0
  6. package/.claude/skills/components/display-tooltip-defined.md +3 -0
  7. package/.claude/skills/components/display-tooltip.md +1 -0
  8. package/.claude/skills/components/marquee-scroller.md +130 -0
  9. package/.claude/skills/components/navigation-items.md +1 -0
  10. package/.claude/skills/components/responsive-header.md +3 -0
  11. package/.claude/skills/components/site-header.md +4 -0
  12. package/.claude/skills/components/site-navigation.md +1 -0
  13. package/.claude/skills/components/tab-navigation.md +1 -0
  14. package/.claude/skills/index.md +1 -0
  15. package/.vscode/srcdev-component-breadcrumb.code-snippets +13 -0
  16. package/.vscode/srcdev-component-content-docs.code-snippets +18 -0
  17. package/.vscode/srcdev-component-display-tooltip-defined.code-snippets +15 -0
  18. package/.vscode/srcdev-component-display-tooltip.code-snippets +11 -0
  19. package/.vscode/srcdev-component-marquee-scroller.code-snippets +93 -0
  20. package/.vscode/srcdev-component-responsive-header.code-snippets +12 -0
  21. package/.vscode/srcdev-component-site-header.code-snippets +17 -0
  22. package/.vscode/srcdev-component-site-navigation.code-snippets +30 -0
  23. package/.vscode/srcdev-component-slider-gallery.code-snippets +38 -0
  24. package/.vscode/srcdev-component-tab-navigation.code-snippets +30 -0
  25. package/app/components/01.atoms/animations/marquee-scroller/CONSUMER-STYLING.md +94 -0
  26. package/app/components/01.atoms/animations/marquee-scroller/MarqueeScroller.vue +331 -0
  27. package/app/components/01.atoms/animations/marquee-scroller/stories/MarqueeScroller.stories.ts +151 -0
  28. package/app/components/01.atoms/animations/marquee-scroller/tests/MarqueeScroller.spec.ts +315 -0
  29. package/app/components/01.atoms/animations/marquee-scroller/tests/__snapshots__/MarqueeScroller.spec.ts.snap +28 -0
  30. package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +8 -2
  31. package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +4 -1
  32. package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +4 -1
  33. package/app/components/02.molecules/display-tooltip-defined/DisplayTooltipDefined.vue +16 -3
  34. package/app/components/02.molecules/display-tooltip-defined/tests/__snapshots__/DisplayTooltipDefined.spec.ts.snap +1 -1
  35. package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +4 -1
  36. package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +4 -1
  37. package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +16 -4
  38. package/app/components/03.organisms/responsive-header/NavigationItems.vue +4 -1
  39. package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +16 -3
  40. package/app/components/03.organisms/site-header/SiteHeader.vue +16 -1
  41. package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +1 -1
  42. package/app/types/components/index.ts +1 -0
  43. package/app/types/components/marquee-scroller.d.ts +10 -0
  44. package/package.json +1 -1
  45. package/app/components/marquee-scroller/MarqueeScroller.vue +0 -289
@@ -16,6 +16,7 @@ Both the horizontal list and the panel include animated active/hover indicator d
16
16
  |---|---|---|---|
17
17
  | `navItemData` | `NavItemData` | — (required) | Navigation items — see type below |
18
18
  | `navAlign` | `"left" \| "center" \| "right"` | `"left"` | Alignment of the horizontal nav list |
19
+ | `ariaLabel` | `string` | `"Site navigation"` | aria-label on the root `<nav>` landmark — override for localisation |
19
20
  | `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes applied to the root `<nav>` |
20
21
 
21
22
  ## NavItemData type
@@ -40,6 +40,7 @@ interface NavItemData {
40
40
  | `nav-item-data` | `NavItemData` | required | Navigation link data — only `main` key is read |
41
41
  | `nav-align` | `"left" \| "center" \| "right"` | `"left"` | Positions the tab list within the nav container |
42
42
  | `anchor-scroll-offset` | `number \| (() => number)` | — | Pixel offset subtracted from scroll target; pass a getter so it is re-evaluated at click time |
43
+ | `aria-label` | `string` | `"Site navigation"` | aria-label on the root `<nav>` landmark — override for localisation |
43
44
  | `:style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root `<nav>` element |
44
45
 
45
46
  ---
@@ -89,6 +89,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
89
89
  ├── grid-stack.md — GridStack: CSS Grid z-axis stacking, slot API, z-order rules, sizing, video+overlay and image+text patterns
90
90
  ├── scroll-reveal-frame.md — ScrollRevealFrame: generic parallax clipping frame, slot API, image grid pattern, CSS tokens, browser support
91
91
  ├── scroll-reveal-image.md — ScrollRevealImage: single-image parallax reveal, focalX, imgWidth/imgHeight, responsive frame height
92
+ ├── marquee-scroller.md — MarqueeScroller: infinite logo/badge scroller, per-item dynamic slots (marqueeData id), hover/focus/keyboard pause, reduced-motion, CSS tokens
92
93
  ├── site-navigation.md — SiteNavigation: responsive nav with auto-collapse, burger menu, decorator indicators, CSS token API
93
94
  ├── tab-navigation.md — TabNavigation: horizontal tab nav with CSS anchor-positioning indicators, anchor scroll, burger collapse, full CSS token API
94
95
  ├── social-icons-list.md — SocialIconsList: data-driven social icon links, ISocialIcon type, logos: icon names, CSS tokens
@@ -10,5 +10,18 @@
10
10
  " ]\"",
11
11
  "/>"
12
12
  ]
13
+ },
14
+ "SRCDEV Breadcrumb Localised": {
15
+ "description": "Breadcrumb with a localised aria-label",
16
+ "scope": "vue,html",
17
+ "body": [
18
+ "<Breadcrumb",
19
+ " :items=\"[",
20
+ " { label: '$1Services', to: '$2/services' },",
21
+ " { label: '$3${TM_FILENAME_BASE}' },",
22
+ " ]\"",
23
+ " aria-label=\"${4:Breadcrumb}\"",
24
+ "/>"
25
+ ]
13
26
  }
14
27
  }
@@ -33,6 +33,24 @@
33
33
  "</ContentDocs>"
34
34
  ]
35
35
  },
36
+ "SRCDEV ContentDocs Localised Nav Labels": {
37
+ "description": "ContentDocs with localised aria-labels on the docsNav/docsPageNav <nav> landmarks",
38
+ "scope": "vue,html",
39
+ "body": [
40
+ "<ContentDocs",
41
+ " v-model:active-nav-item=\"$1activeNavItem\"",
42
+ " v-model:active-page-nav-item=\"$2activePageNavItem\"",
43
+ " :docs-nav-items=\"$3docsNavItems\"",
44
+ " :docs-page-nav-items=\"$4docsPageNavItems\"",
45
+ " docs-nav-aria-label=\"${5:Docs navigation}\"",
46
+ " docs-page-nav-aria-label=\"${6:On this page}\"",
47
+ ">",
48
+ " <template #docsContent>",
49
+ " <p>$7Page content goes here.</p>",
50
+ " </template>",
51
+ "</ContentDocs>"
52
+ ]
53
+ },
36
54
  "SRCDEV ContentDocs Items Script": {
37
55
  "description": "docsNavItems / docsPageNavItems + active-item refs for ContentDocs",
38
56
  "scope": "typescript,vue",
@@ -10,5 +10,20 @@
10
10
  " }\"",
11
11
  "/>"
12
12
  ]
13
+ },
14
+ "SRCDEV DisplayTooltipDefined Localised Copy": {
15
+ "description": "DisplayTooltipDefined with localised trigger/close-button copy",
16
+ "scope": "vue,html",
17
+ "body": [
18
+ "<DisplayTooltipDefined",
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
+ "/>"
27
+ ]
13
28
  }
14
29
  }
@@ -23,5 +23,16 @@
23
23
  " </template>",
24
24
  "</DisplayTooltip>"
25
25
  ]
26
+ },
27
+ "SRCDEV DisplayTooltip Localised Trigger Label": {
28
+ "description": "DisplayTooltip with a localised triggerAriaLabel",
29
+ "scope": "vue,html",
30
+ "body": [
31
+ "<DisplayTooltip trigger-aria-label=\"${1:Toggle the popover}\">",
32
+ " <template #tooltipContent>",
33
+ " <p>$0</p>",
34
+ " </template>",
35
+ "</DisplayTooltip>"
36
+ ]
26
37
  }
27
38
  }
@@ -0,0 +1,93 @@
1
+ {
2
+ "SRCDEV MarqueeScroller Basic": {
3
+ "description": "MarqueeScroller — infinite horizontal logo/badge scroller with per-item slots",
4
+ "scope": "vue,html",
5
+ "body": [
6
+ "<MarqueeScroller",
7
+ " :marquee-data=\"[",
8
+ " { id: 1, content: '$1logo-a' },",
9
+ " { id: 2, content: '$2logo-b' },",
10
+ " ]\"",
11
+ " :item-config=\"{ width: '${3:120px}', height: '${4:60px}', gap: '${5:24px}' }\"",
12
+ ">",
13
+ " <template #1>",
14
+ " $6",
15
+ " </template>",
16
+ " <template #2>",
17
+ " $7",
18
+ " </template>",
19
+ "</MarqueeScroller>"
20
+ ]
21
+ },
22
+ "SRCDEV MarqueeScroller With Controls": {
23
+ "description": "MarqueeScroller with the visible pause/play control button (WCAG 2.2.2)",
24
+ "scope": "vue,html",
25
+ "body": [
26
+ "<MarqueeScroller",
27
+ " :marquee-data=\"$1items\"",
28
+ " show-controls",
29
+ " aria-label=\"$2Scrolling client logos\"",
30
+ ">",
31
+ " <template v-for=\"item in $1items\" #[item.id] :key=\"item.id\">",
32
+ " $3",
33
+ " </template>",
34
+ "</MarqueeScroller>"
35
+ ]
36
+ },
37
+ "SRCDEV MarqueeScroller Custom Control Icon/Copy": {
38
+ "description": "MarqueeScroller control button with custom icons and localised aria-labels",
39
+ "scope": "vue,html",
40
+ "body": [
41
+ "<MarqueeScroller",
42
+ " :marquee-data=\"$1items\"",
43
+ " show-controls",
44
+ " play-icon=\"${2:mdi:play-circle}\"",
45
+ " pause-icon=\"${3:mdi:pause-circle}\"",
46
+ " play-label=\"${4:Play}\"",
47
+ " pause-label=\"${5:Pause}\"",
48
+ ">",
49
+ " <template v-for=\"item in $1items\" #[item.id] :key=\"item.id\">",
50
+ " $6",
51
+ " </template>",
52
+ "</MarqueeScroller>"
53
+ ]
54
+ },
55
+ "SRCDEV MarqueeScroller Custom Toggle Icon Slot": {
56
+ "description": "MarqueeScroller with the toggle-icon slot fully replacing the control button's icon",
57
+ "scope": "vue,html",
58
+ "body": [
59
+ "<MarqueeScroller :marquee-data=\"$1items\" show-controls>",
60
+ " <template #toggle-icon=\"{ isPaused }\">",
61
+ " $2",
62
+ " </template>",
63
+ "</MarqueeScroller>"
64
+ ]
65
+ },
66
+ "SRCDEV MarqueeScroller CSS Override": {
67
+ "description": "CSS override scaffold for MarqueeScroller — scope to a page or section class",
68
+ "scope": "css",
69
+ "body": [
70
+ ".$1my-page {",
71
+ " .marquee-scroller {",
72
+ " --marquee-scroller-fade-width: ;",
73
+ " --marquee-scroller-focus-outline-width: ;",
74
+ " --marquee-scroller-focus-outline-offset: ;",
75
+ " --marquee-scroller-item-border-colour: ;",
76
+ " --marquee-scroller-item-border-width: ;",
77
+ " --marquee-scroller-item-border-radius: ;",
78
+ " --marquee-scroller-item-transition-duration: ;",
79
+ " --marquee-scroller-group-hover-filter: ;",
80
+ " --marquee-scroller-item-hover-filter: ;",
81
+ " --marquee-scroller-control-offset: ;",
82
+ " --marquee-scroller-control-background-colour: ;",
83
+ " --marquee-scroller-control-background-colour-hover: ;",
84
+ " --marquee-scroller-control-text-colour: ;",
85
+ " --marquee-scroller-control-border-radius: ;",
86
+ " --marquee-scroller-control-border-width: ;",
87
+ " --marquee-scroller-control-padding: ;",
88
+ " --marquee-scroller-control-font-size: ;",
89
+ " }",
90
+ "}"
91
+ ]
92
+ }
93
+ }
@@ -15,6 +15,18 @@
15
15
  "</ResponsiveHeader>"
16
16
  ]
17
17
  },
18
+ "SRCDEV ResponsiveHeader Localised Nav Labels": {
19
+ "description": "ResponsiveHeader with localised aria-labels on the main/secondary nav landmarks and overflow menu",
20
+ "scope": "vue,html",
21
+ "body": [
22
+ "<ResponsiveHeader",
23
+ " :responsive-nav-links=\"$1responsiveNavLinks\"",
24
+ " main-nav-aria-label=\"${2:Main navigation}\"",
25
+ " secondary-nav-aria-label=\"${3:Secondary navigation}\"",
26
+ " overflow-menu-aria-label=\"${4:Overflow navigation menu}\"",
27
+ "/>"
28
+ ]
29
+ },
18
30
  "SRCDEV ResponsiveHeader Nav Data (with dropdown)": {
19
31
  "description": "responsiveNavLinks data with a dropdown group",
20
32
  "scope": "typescript,vue",
@@ -30,6 +30,23 @@
30
30
  "</SiteHeader>"
31
31
  ]
32
32
  },
33
+ "SRCDEV SiteHeader Localised Nav Labels": {
34
+ "description": "SiteHeader with localised aria-labels on all its nav landmarks (home, main, secondary, overflow)",
35
+ "scope": "vue,html",
36
+ "body": [
37
+ "<SiteHeader",
38
+ " :responsive-nav-links=\"$1responsiveNavLinks\"",
39
+ " home-nav-aria-label=\"${2:Home Navigation}\"",
40
+ " main-nav-aria-label=\"${3:Main navigation}\"",
41
+ " secondary-nav-aria-label=\"${4:Secondary navigation}\"",
42
+ " overflow-menu-aria-label=\"${5:Overflow navigation menu}\"",
43
+ ">",
44
+ " <template #branding>",
45
+ " <NuxtLink to=\"/\" class=\"home-link\">$6Brand</NuxtLink>",
46
+ " </template>",
47
+ "</SiteHeader>"
48
+ ]
49
+ },
33
50
  "SRCDEV SiteHeader Nav Data (flat)": {
34
51
  "description": "Simple flat responsiveNavLinks data with no dropdowns, for a few-page site",
35
52
  "scope": "typescript,vue",
@@ -0,0 +1,30 @@
1
+ {
2
+ "SRCDEV SiteNavigation Basic": {
3
+ "description": "SiteNavigation horizontal nav with sliding active/hover indicator",
4
+ "scope": "vue,html",
5
+ "body": [
6
+ "<SiteNavigation :nav-item-data=\"$1navData\" nav-align=\"${2:left}\" />"
7
+ ]
8
+ },
9
+ "SRCDEV SiteNavigation Localised": {
10
+ "description": "SiteNavigation with a localised aria-label",
11
+ "scope": "vue,html",
12
+ "body": [
13
+ "<SiteNavigation :nav-item-data=\"$1navData\" aria-label=\"${2:Site navigation}\" />"
14
+ ]
15
+ },
16
+ "SRCDEV SiteNavigation Nav Data Script": {
17
+ "description": "navItemData for SiteNavigation",
18
+ "scope": "typescript,vue",
19
+ "body": [
20
+ "import type { NavItemData } from \"srcdev-nuxt-components\";",
21
+ "",
22
+ "const $1navData: NavItemData = {",
23
+ " main: [",
24
+ " { text: \"$2Home\", href: \"$3/\" },",
25
+ " { text: \"$4About\", href: \"$5/about\" },",
26
+ " ],",
27
+ "};"
28
+ ]
29
+ }
30
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "SRCDEV SliderGallery Basic": {
3
+ "description": "SliderGallery full-screen image slider with thumbnails and prev/next arrows",
4
+ "scope": "vue,html",
5
+ "body": [
6
+ "<SliderGallery v-model:gallery-data=\"$1galleryData\" />"
7
+ ]
8
+ },
9
+ "SRCDEV SliderGallery Localised": {
10
+ "description": "SliderGallery with localised loading/CTA/arrow copy",
11
+ "scope": "vue,html",
12
+ "body": [
13
+ "<SliderGallery",
14
+ " v-model:gallery-data=\"$1galleryData\"",
15
+ " loading-text=\"${2:Loading gallery...}\"",
16
+ " see-more-text=\"${3:SEE MORE}\"",
17
+ " prev-aria-label=\"${4:Previous image}\"",
18
+ " next-aria-label=\"${5:Next image}\"",
19
+ "/>"
20
+ ]
21
+ },
22
+ "SRCDEV SliderGallery Data Script": {
23
+ "description": "galleryData ref for SliderGallery",
24
+ "scope": "typescript,vue",
25
+ "body": [
26
+ "import type { IGalleryData } from \"srcdev-nuxt-components\";",
27
+ "",
28
+ "const $1galleryData = ref<IGalleryData[]>([",
29
+ " {",
30
+ " src: \"$2/images/slide-1.jpg\",",
31
+ " alt: \"$3\",",
32
+ " title: \"$4\",",
33
+ " textBrightness: \"${5:light}\",",
34
+ " },",
35
+ "]);"
36
+ ]
37
+ }
38
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "SRCDEV TabNavigation Basic": {
3
+ "description": "TabNavigation with route/hash links",
4
+ "scope": "vue,html",
5
+ "body": [
6
+ "<TabNavigation :nav-item-data=\"$1navData\" nav-align=\"${2:center}\" />"
7
+ ]
8
+ },
9
+ "SRCDEV TabNavigation Localised": {
10
+ "description": "TabNavigation with a localised aria-label",
11
+ "scope": "vue,html",
12
+ "body": [
13
+ "<TabNavigation :nav-item-data=\"$1navData\" aria-label=\"${2:Site navigation}\" />"
14
+ ]
15
+ },
16
+ "SRCDEV TabNavigation Nav Data Script": {
17
+ "description": "navItemData for TabNavigation",
18
+ "scope": "typescript,vue",
19
+ "body": [
20
+ "import type { NavItemData } from \"srcdev-nuxt-components\";",
21
+ "",
22
+ "const $1navData: NavItemData = {",
23
+ " main: [",
24
+ " { text: \"$2Home\", href: \"$3/\" },",
25
+ " { text: \"$4Overview\", href: \"$5#overview\" },",
26
+ " ],",
27
+ "};"
28
+ ]
29
+ }
30
+ }
@@ -0,0 +1,94 @@
1
+ # MarqueeScroller — Consumer Styling Guide
2
+
3
+ ## Public token API
4
+
5
+ | Token | Default | Controls |
6
+ |---|---|---|
7
+ | `--marquee-scroller-fade-width` | `10%` | Width of the transparent fade at each edge of the track (`mask-image`) |
8
+ | `--marquee-scroller-focus-outline-width` | `2px` | Outline width on the root region and the control button when keyboard-focused (colour is `--theme-ring`) |
9
+ | `--marquee-scroller-focus-outline-offset` | `2px` | Outline offset on the same two focus states |
10
+ | `--marquee-scroller-group-hover-filter` | `grayscale(1)` | Filter applied to every item when the pointer hovers anywhere over the scroller |
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
+ | `--marquee-scroller-item-transition-duration` | `0.5s` | Transition duration for the item hover filter change |
13
+ | `--marquee-scroller-item-border-width` | `1px` | Item border width |
14
+ | `--marquee-scroller-item-border-colour` | `light-dark(var(--slate-10), var(--slate-00))` | Item border colour |
15
+ | `--marquee-scroller-item-border-radius` | `4px` | Item border radius |
16
+ | `--marquee-scroller-control-offset` | `8px` | Distance of the pause/play button from the top and end edges |
17
+ | `--marquee-scroller-control-background-colour` | `rgba(0, 0, 0, 0.7)` | Pause/play button background |
18
+ | `--marquee-scroller-control-background-colour-hover` | `rgba(0, 0, 0, 0.9)` | Pause/play button background on hover |
19
+ | `--marquee-scroller-control-text-colour` | `white` | Pause/play button icon colour |
20
+ | `--marquee-scroller-control-border-radius` | `4px` | Pause/play button border radius |
21
+ | `--marquee-scroller-control-padding` | `8px` | Pause/play button padding |
22
+ | `--marquee-scroller-control-font-size` | `14px` | Pause/play button icon font size |
23
+ | `--marquee-scroller-control-transition-duration` | `0.2s` | Pause/play button background-colour transition duration |
24
+ | `--marquee-scroller-control-border-width` | `1px` | Pause/play button border width in forced-colors/high-contrast mode (`prefers-contrast: high`). The border colour itself stays the system `ButtonText` keyword — see note below. |
25
+
26
+ ```css
27
+ .my-page {
28
+ --marquee-scroller-item-border-colour: #b5651d;
29
+ --marquee-scroller-control-background-colour: #1a1a1a;
30
+ --marquee-scroller-fade-width: 20%;
31
+ }
32
+ ```
33
+
34
+ ## High-contrast mode colours are not tokenised
35
+
36
+ Under `prefers-contrast: high`, the control button switches to the system colour keywords
37
+ `ButtonFace`/`ButtonText` rather than the component's own background/text tokens. These aren't
38
+ exposed as overridable tokens on purpose — they're meant to track the user's OS-level high-contrast
39
+ theme, which a component-level override would defeat. Only the border *width* in that mode is a
40
+ token (`--marquee-scroller-control-border-width`), since it's a plain dimension with no such
41
+ constraint.
42
+
43
+ ## Item size and spacing are prop-driven, not tokens
44
+
45
+ Item `width`/`height`/`gap` and the animation duration are set via the `itemConfig` and
46
+ `animationRuntime` props (not CSS custom properties), since they also drive the component's own
47
+ layout math (`aspect-ratio`, track width). Override those through props:
48
+
49
+ ```vue
50
+ <MarqueeScroller
51
+ :item-config="{ width: '80px', height: '80px', gap: '24px' }"
52
+ animation-runtime="60s"
53
+ />
54
+ ```
55
+
56
+ ## Item content via slots
57
+
58
+ Each entry in `marqueeData` (`{ id, content }`) renders a slot named after its `id`. Provide the
59
+ markup for each item via that dynamically-named slot:
60
+
61
+ ```vue
62
+ <MarqueeScroller :marquee-data="[{ id: 1, content: 'logo-a' }, { id: 2, content: 'logo-b' }]">
63
+ <template #1>
64
+ <img src="/logos/a.svg" alt="Logo A" />
65
+ </template>
66
+ <template #2>
67
+ <img src="/logos/b.svg" alt="Logo B" />
68
+ </template>
69
+ </MarqueeScroller>
70
+ ```
71
+
72
+ ## Control button icon and copy
73
+
74
+ The pause/play button's icon and its `aria-label` copy are all overridable — see `playIcon`/
75
+ `pauseIcon`/`playLabel`/`pauseLabel` props, or the `toggle-icon` slot for a fully custom icon
76
+ (scoped with `isPaused`):
77
+
78
+ ```vue
79
+ <MarqueeScroller
80
+ show-controls
81
+ play-icon="mdi:play-circle"
82
+ pause-icon="mdi:pause-circle"
83
+ play-label="Reproduire"
84
+ pause-label="Suspendre"
85
+ />
86
+ ```
87
+
88
+ ```vue
89
+ <MarqueeScroller show-controls>
90
+ <template #toggle-icon="{ isPaused }">
91
+ <Icon :name="isPaused ? 'lucide:play' : 'lucide:pause'" />
92
+ </template>
93
+ </MarqueeScroller>
94
+ ```