srcdev-nuxt-components 9.5.7 → 9.6.1

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 (159) hide show
  1. package/.claude/skills/component-compliance-checklist.md +8 -2
  2. package/.claude/skills/component-dynamic-slots.md +3 -3
  3. package/.claude/skills/component-export-types.md +10 -16
  4. package/.claude/skills/component-naming.md +1 -1
  5. package/.claude/skills/components/alert-content.md +9 -1
  6. package/.claude/skills/components/breadcrumb.md +5 -0
  7. package/.claude/skills/components/container-glow.md +21 -8
  8. package/.claude/skills/components/display-avatar.md +13 -7
  9. package/.claude/skills/components/display-chip.md +37 -24
  10. package/.claude/skills/components/display-pill.md +58 -8
  11. package/.claude/skills/components/display-prompt.md +8 -5
  12. package/.claude/skills/components/display-toast.md +21 -4
  13. package/.claude/skills/components/glowing-border.md +20 -2
  14. package/.claude/skills/components/input-button.md +3 -0
  15. package/.claude/skills/components/responsive-header.md +59 -0
  16. package/.claude/skills/components/select-menu.md +54 -5
  17. package/.claude/skills/components/service-detail.md +32 -0
  18. package/.claude/skills/components/service-summary.md +8 -0
  19. package/.claude/skills/components/services-card-grid.md +5 -3
  20. package/.claude/skills/components/services-card.md +22 -12
  21. package/.claude/skills/components/site-header.md +2 -2
  22. package/.claude/skills/components/slider-gallery.md +10 -4
  23. package/.claude/skills/components/tabbed-content.md +300 -0
  24. package/.claude/skills/composable-anchor-scroll.md +16 -15
  25. package/.claude/skills/index.md +4 -5
  26. package/.claude/skills/storybook-add-story.md +53 -0
  27. package/.claude/skills/theming-status-tokens.md +60 -0
  28. package/.vscode/srcdev-component-display-avatar.code-snippets +2 -1
  29. package/.vscode/srcdev-component-display-chip.code-snippets +3 -2
  30. package/.vscode/srcdev-component-display-pill.code-snippets +10 -0
  31. package/.vscode/srcdev-component-responsive-header.code-snippets +16 -0
  32. package/.vscode/srcdev-component-select-menu.code-snippets +28 -0
  33. package/.vscode/srcdev-component-service-detail.code-snippets +1 -0
  34. package/.vscode/srcdev-component-service-summary.code-snippets +3 -1
  35. package/.vscode/srcdev-component-services-card.code-snippets +38 -36
  36. package/.vscode/srcdev-component-services-grids.code-snippets +2 -1
  37. package/.vscode/{srcdev-component-tabs-core.code-snippets → srcdev-component-tabbed-content.code-snippets} +35 -16
  38. package/app/assets/styles/setup/03.theming/_status.css +24 -0
  39. package/app/assets/styles/setup/03.theming/index.css +1 -0
  40. package/app/components/01.atoms/animations/container-glow/CONSUMER-STYLING.md +39 -35
  41. package/app/components/01.atoms/animations/container-glow/ContainerGlow.vue +25 -15
  42. package/app/components/01.atoms/animations/container-glow/stories/ContainerGlow.stories.ts +130 -24
  43. package/app/components/01.atoms/animations/container-glow/tests/ContainerGlow.spec.ts +45 -0
  44. package/app/components/01.atoms/animations/container-glow/tests/__snapshots__/ContainerGlow.spec.ts.snap +2 -2
  45. package/app/components/01.atoms/animations/glowing-border/CONSUMER-STYLING.md +76 -19
  46. package/app/components/01.atoms/animations/glowing-border/GlowingBorder.vue +12 -10
  47. package/app/components/01.atoms/animations/glowing-border/stories/GlowingBorder.stories.ts +201 -42
  48. package/app/components/01.atoms/animations/glowing-border/tests/GlowingBorder.spec.ts +15 -4
  49. package/app/components/01.atoms/animations/glowing-border/tests/__snapshots__/GlowingBorder.spec.ts.snap +1 -1
  50. package/app/components/01.atoms/display-pill/CONSUMER-STYLING.md +78 -9
  51. package/app/components/01.atoms/display-pill/DisplayPill.vue +59 -23
  52. package/app/components/01.atoms/display-pill/stories/DisplayPill.stories.ts +240 -16
  53. package/app/components/01.atoms/display-pill/tests/DisplayPill.spec.ts +43 -14
  54. package/app/components/01.atoms/display-pill/tests/__snapshots__/DisplayPill.spec.ts.snap +3 -3
  55. package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +16 -4
  56. package/app/components/01.atoms/navigation/breadcrumb/CONSUMER-STYLING.md +28 -5
  57. package/app/components/01.atoms/navigation/breadcrumb/stories/Breadcrumb.stories.ts +94 -0
  58. package/app/components/01.atoms/navigation/breadcrumb/tests/Breadcrumb.spec.ts +27 -0
  59. package/app/components/01.atoms/tabbed-content/CONSUMER-STYLING.md +201 -0
  60. package/app/components/01.atoms/tabbed-content/TabbedContent.vue +750 -0
  61. package/app/components/01.atoms/tabbed-content/stories/TabbedContent.stories.ts +279 -0
  62. package/app/components/01.atoms/tabbed-content/tests/TabbedContent.spec.ts +816 -0
  63. package/app/components/02.molecules/alert-content/AlertContent.vue +11 -2
  64. package/app/components/02.molecules/alert-content/AlertContentInner.vue +19 -0
  65. package/app/components/02.molecules/alert-content/CONSUMER-STYLING.md +17 -4
  66. package/app/components/02.molecules/alert-content/stories/AlertContent.stories.ts +200 -17
  67. package/app/components/02.molecules/alert-content/tests/AlertContent.spec.ts +33 -0
  68. package/app/components/02.molecules/display-avatar/CONSUMER-STYLING.md +7 -5
  69. package/app/components/02.molecules/display-avatar/DisplayAvatar.vue +6 -2
  70. package/app/components/02.molecules/display-avatar/stories/DisplayAvatar.stories.ts +24 -3
  71. package/app/components/02.molecules/display-avatar/tests/DisplayAvatar.spec.ts +19 -0
  72. package/app/components/02.molecules/display-avatar/tests/__snapshots__/DisplayAvatar.spec.ts.snap +2 -1
  73. package/app/components/02.molecules/display-chip/CONSUMER-STYLING.md +52 -19
  74. package/app/components/02.molecules/display-chip/DisplayChip.vue +72 -54
  75. package/app/components/02.molecules/display-chip/stories/DisplayChip.stories.ts +103 -6
  76. package/app/components/02.molecules/display-chip/tests/DisplayChip.spec.ts +98 -29
  77. package/app/components/02.molecules/display-chip/tests/__snapshots__/DisplayChip.spec.ts.snap +8 -4
  78. package/app/components/02.molecules/prompt/CONSUMER-STYLING.md +9 -1
  79. package/app/components/02.molecules/prompt/DisplayPrompt.vue +2 -2
  80. package/app/components/02.molecules/prompt/stories/DisplayPrompt.stories.ts +208 -71
  81. package/app/components/02.molecules/prompt/tests/DisplayPrompt.spec.ts +19 -6
  82. package/app/components/02.molecules/select-menu/CONSUMER-STYLING.md +66 -8
  83. package/app/components/02.molecules/select-menu/SelectMenu.vue +141 -18
  84. package/app/components/02.molecules/select-menu/stories/SelectMenu.stories.ts +232 -2
  85. package/app/components/02.molecules/select-menu/tests/SelectMenu.spec.ts +151 -0
  86. package/app/components/02.molecules/select-menu/tests/__snapshots__/SelectMenu.spec.ts.snap +6 -2
  87. package/app/components/02.molecules/toast/CONSUMER-STYLING.md +91 -27
  88. package/app/components/02.molecules/toast/DisplayToast.vue +109 -50
  89. package/app/components/02.molecules/toast/DisplayToastProvider.vue +109 -45
  90. package/app/components/02.molecules/toast/stories/DisplayToast.stories.ts +23 -0
  91. package/app/components/02.molecules/toast/stories/DisplayToastProvider.stories.ts +73 -0
  92. package/app/components/02.molecules/toast/tests/DisplayToast.spec.ts +132 -18
  93. package/app/components/02.molecules/toast/tests/DisplayToastProvider.spec.ts +105 -39
  94. package/app/components/03.organisms/image-galleries/slider-gallery/CONSUMER-STYLING.md +19 -1
  95. package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +65 -7
  96. package/app/components/03.organisms/image-galleries/slider-gallery/stories/SliderGallery.stories.ts +201 -63
  97. package/app/components/03.organisms/image-galleries/slider-gallery/tests/SliderGallery.spec.ts +41 -2
  98. package/app/components/03.organisms/image-galleries/slider-gallery/tests/__snapshots__/SliderGallery.spec.ts.snap +6 -6
  99. package/app/components/03.organisms/responsive-header/CONSUMER-STYLING.md +42 -11
  100. package/app/components/03.organisms/responsive-header/NavigationItems.vue +60 -16
  101. package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +86 -24
  102. package/app/components/03.organisms/responsive-header/stories/ResponsiveHeader.stories.ts +52 -0
  103. package/app/components/03.organisms/responsive-header/tests/NavigationItems.spec.ts +20 -0
  104. package/app/components/03.organisms/responsive-header/tests/ResponsiveHeader.spec.ts +40 -0
  105. package/app/components/03.organisms/services/service-detail/CONSUMER-STYLING.md +92 -41
  106. package/app/components/03.organisms/services/service-detail/ServiceDetail.vue +198 -73
  107. package/app/components/03.organisms/services/service-detail/stories/ServiceDetail.stories.ts +157 -9
  108. package/app/components/03.organisms/services/service-detail/tests/ServiceDetail.spec.ts +58 -0
  109. package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +5 -4
  110. package/app/components/03.organisms/services/service-summary/CONSUMER-STYLING.md +30 -0
  111. package/app/components/03.organisms/services/service-summary/ServiceSummary.vue +32 -8
  112. package/app/components/03.organisms/services/service-summary/stories/ServiceSummary.stories.ts +147 -0
  113. package/app/components/03.organisms/services/service-summary/tests/ServiceSummary.spec.ts +26 -0
  114. package/app/components/03.organisms/services/service-summary/tests/__snapshots__/ServiceSummary.spec.ts.snap +2 -2
  115. package/app/components/03.organisms/services/services-card/CONSUMER-STYLING.md +104 -63
  116. package/app/components/03.organisms/services/services-card/ServicesCard.vue +92 -66
  117. package/app/components/03.organisms/services/services-card/stories/ServicesCard.stories.ts +194 -27
  118. package/app/components/03.organisms/services/services-card/tests/ServicesCard.spec.ts +34 -8
  119. package/app/components/03.organisms/services/services-card/tests/__snapshots__/ServicesCard.spec.ts.snap +8 -8
  120. package/app/components/03.organisms/services/services-grids/CONSUMER-STYLING.md +9 -0
  121. package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +2 -1
  122. package/app/components/03.organisms/services/services-grids/stories/ServiceSummaryGrid.stories.ts +46 -6
  123. package/app/components/03.organisms/services/services-grids/stories/ServicesCardGrid.stories.ts +89 -11
  124. package/app/components/03.organisms/services/services-grids/tests/ServicesCardGrid.spec.ts +8 -0
  125. package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServiceSummaryGrid.spec.ts.snap +6 -6
  126. package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServicesCardGrid.spec.ts.snap +24 -24
  127. package/app/components/05.forms/input-button/CONSUMER-STYLING.md +8 -0
  128. package/app/components/05.forms/input-button/InputButton.vue +3 -1
  129. package/app/composables/tests/useAnchorScroll.spec.ts +8 -0
  130. package/app/composables/useAnchorScroll.ts +1 -1
  131. package/app/composables/useTabs.ts +148 -206
  132. package/app/types/components/display-chip.d.ts +8 -4
  133. package/app/types/components/display-toast.d.ts +2 -0
  134. package/app/types/components/index.ts +0 -1
  135. package/app/types/components/select-menu.d.ts +2 -0
  136. package/app/utils/pausableTimeout.ts +41 -0
  137. package/nuxt.config.ts +1 -1
  138. package/package.json +1 -1
  139. package/.claude/skills/components/site-navigation.md +0 -145
  140. package/.claude/skills/components/tab-navigation.md +0 -272
  141. package/.claude/skills/components/tabs-core.md +0 -187
  142. package/.vscode/srcdev-component-site-navigation.code-snippets +0 -38
  143. package/.vscode/srcdev-component-tab-navigation.code-snippets +0 -30
  144. package/app/components/01.atoms/navigation/tabs/CONSUMER-STYLING.md +0 -120
  145. package/app/components/01.atoms/navigation/tabs/TabsCore.vue +0 -272
  146. package/app/components/01.atoms/navigation/tabs/stories/TabsCore.stories.ts +0 -199
  147. package/app/components/01.atoms/navigation/tabs/tests/TabsCore.spec.ts +0 -274
  148. package/app/components/02.molecules/navigation/site-navigation/CONSUMER-STYLING.md +0 -109
  149. package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +0 -751
  150. package/app/components/02.molecules/navigation/site-navigation/stories/SiteNavigation.stories.ts +0 -356
  151. package/app/components/02.molecules/navigation/site-navigation/tests/SiteNavigation.spec.ts +0 -367
  152. package/app/components/02.molecules/navigation/site-navigation/tests/__snapshots__/SiteNavigation.spec.ts.snap +0 -30
  153. package/app/components/02.molecules/navigation/tab-navigation/CONSUMER-STYLING.md +0 -150
  154. package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +0 -518
  155. package/app/components/02.molecules/navigation/tab-navigation/stories/TabNavigation.stories.ts +0 -340
  156. package/app/components/02.molecules/navigation/tab-navigation/tests/TabNavigation.spec.ts +0 -339
  157. package/app/components/02.molecules/navigation/tab-navigation/tests/__snapshots__/TabNavigation.spec.ts.snap +0 -33
  158. package/app/composables/useNavCollapse.ts +0 -86
  159. package/app/types/components/nav-item.d.ts +0 -11
@@ -7,6 +7,7 @@
7
7
  " :service-data=\"$1service\"",
8
8
  " location=\"$2Mobile — across Bath\"",
9
9
  " :related-services=\"$3relatedServices\"",
10
+ " price-prefix=\"${7:From}\"",
10
11
  ">",
11
12
  " <template #book-cta>",
12
13
  " <button type=\"button\">$4Book Now</button>",
@@ -18,7 +18,7 @@
18
18
  "description": "ServiceSummary with image/content columns swapped",
19
19
  "scope": "vue,html",
20
20
  "body": [
21
- "<ServiceSummary :service-data=\"$1service\" :reverse=\"$2true\">",
21
+ "<ServiceSummary :service-data=\"$1service\" :reverse=\"$2true\" price-prefix=\"${3:From}\">",
22
22
  " <template #summary-link=\"{ serviceData }\">",
23
23
  " <NuxtLink :to=\"`/services/${serviceData.slug}`\">$3More about {{ serviceData.title }} →</NuxtLink>",
24
24
  " </template>",
@@ -55,6 +55,8 @@
55
55
  " --service-summary-image-padding-block-mobile: ;",
56
56
  " --service-summary-image-padding-inline-mobile: ;",
57
57
  " --service-summary-pills-gap: ;",
58
+ " --service-summary-column-min-width: ;",
59
+ " --service-summary-body-line-clamp: ;",
58
60
  " --service-summary-pill-border-colour: ;",
59
61
  "",
60
62
  " .service-summary__image-wrapper {}",
@@ -85,6 +85,7 @@
85
85
  " --services-card-outline-width: ;",
86
86
  " --services-card-outline-colour: ;",
87
87
  " --services-card-outline-colour-hover: ;",
88
+ " --services-card-outline-colour-focus: ;",
88
89
  " --services-card-outline-offset: ;",
89
90
  " --services-card-outline-offset-hover: ;",
90
91
  " --services-card-background-color-hover: ;",
@@ -94,44 +95,45 @@
94
95
  " --services-card-background-color: ;",
95
96
  " --services-card-padding-block: ;",
96
97
  " --services-card-padding-inline: ;",
97
- " --image-wrapper-aspect-ratio: ;",
98
- " --image-wrapper-border-radius: ;",
99
- " --image-wrapper-padding-block: ;",
100
- " --image-wrapper-padding-inline: ;",
101
- " --image-wrapper-border-image-zoom-transform: ;",
102
- " --details-wrapper-grid-gap: ;",
103
- " --details-wrapper-padding-block: ;",
104
- " --details-wrapper-padding-inline: ;",
105
- " --eyebrow-text-padding-block: ;",
106
- " --hero-text-padding-block: ;",
107
- " --description-text-colour: ;",
108
- " --description-padding-block: ;",
109
- " --description-line-height: ;",
110
- " --description-font-weight: ;",
111
- " --description-line-clamp: ;",
112
- " --meta-padding-block: ;",
113
- " --meta-border-colour: ;",
114
- " --meta-text-colour: ;",
115
- " --meta-duration-text-colour: ;",
116
- " --meta-price-text-colour: ;",
117
- " --meta-duration-font-weight: ;",
118
- " --meta-price-font-weight: ;",
119
- " --meta-letter-spacing: ;",
120
- " --meta-font-size: ;",
121
- " --meta-text-transform: ;",
122
- " --footer-padding-block: ;",
123
- " --footer-wrapper-grid-gap: ;",
98
+ " --services-card-image-aspect-ratio: ;",
99
+ " --services-card-image-border-radius: ;",
100
+ " --services-card-image-padding-block: ;",
101
+ " --services-card-image-padding-inline: ;",
102
+ " --services-card-image-zoom-transform: ;",
103
+ " --services-card-details-gap: ;",
104
+ " --services-card-details-padding-block: ;",
105
+ " --services-card-details-padding-inline: ;",
106
+ " --services-card-eyebrow-padding-block: ;",
107
+ " --services-card-title-padding-block: ;",
108
+ " --services-card-description-text-colour: ;",
109
+ " --services-card-description-padding-block: ;",
110
+ " --services-card-description-line-height: ;",
111
+ " --services-card-description-font-weight: ;",
112
+ " --services-card-description-line-clamp: ;",
113
+ " --services-card-meta-padding-block: ;",
114
+ " --services-card-meta-border-colour: ;",
115
+ " --services-card-meta-text-colour: ;",
116
+ " --services-card-meta-duration-text-colour: ;",
117
+ " --services-card-meta-price-text-colour: ;",
118
+ " --services-card-meta-duration-font-weight: ;",
119
+ " --services-card-meta-price-font-weight: ;",
120
+ " --services-card-meta-letter-spacing: ;",
121
+ " --services-card-meta-font-size: ;",
122
+ " --services-card-meta-text-transform: ;",
123
+ " --services-card-meta-gap: ;",
124
+ " --services-card-footer-padding-block: ;",
125
+ " --services-card-footer-gap: ;",
124
126
  "",
125
127
  " /* Titles over the image (titlesWithinImageWrapper) */",
126
- " --image-wrapper-details-scrim-colour: ;",
127
- " --image-wrapper-details-scrim: ;",
128
- " --image-wrapper-details-text-colour: ;",
129
- " --image-wrapper-details-eyebrow-text-colour: ;",
130
- " --image-wrapper-details-gap: ;",
131
- " --image-wrapper-details-eyebrow-text-padding-block: ;",
132
- " --image-wrapper-details-eyebrow-text-padding-inline: ;",
133
- " --image-wrapper-details-hero-text-padding-block: ;",
134
- " --image-wrapper-details-hero-text-padding-inline: ;",
128
+ " --services-card-image-details-scrim-colour: ;",
129
+ " --services-card-image-details-scrim: ;",
130
+ " --services-card-image-details-text-colour: ;",
131
+ " --services-card-image-details-eyebrow-colour: ;",
132
+ " --services-card-image-details-gap: ;",
133
+ " --services-card-image-details-eyebrow-padding-block: ;",
134
+ " --services-card-image-details-eyebrow-padding-inline: ;",
135
+ " --services-card-image-details-title-padding-block: ;",
136
+ " --services-card-image-details-title-padding-inline: ;",
135
137
  " }",
136
138
  "}"
137
139
  ]
@@ -29,7 +29,8 @@
29
29
  ".$1my-page {",
30
30
  " --services-card-grid-column-min-width: $2;",
31
31
  " --services-card-grid-gap: $3;",
32
- " --service-summary-grid-row-gap: $4;",
32
+ " --services-card-grid-button-text-white-space: $4;",
33
+ " --service-summary-grid-row-gap: $5;",
33
34
  "}"
34
35
  ]
35
36
  }
@@ -1,9 +1,9 @@
1
1
  {
2
- "SRCDEV TabsCore Basic": {
3
- "description": "TabsCore — horizontal tablist with indexed trigger/content slots",
2
+ "SRCDEV TabbedContent Basic": {
3
+ "description": "TabbedContent — horizontal tablist with indexed trigger/content slots",
4
4
  "scope": "vue,html",
5
5
  "body": [
6
- "<TabsCore :item-count=\"${1:3}\">",
6
+ "<TabbedContent :item-count=\"${1:3}\" aria-label=\"${8:Product details}\">",
7
7
  " <template #tab-0-trigger>${2:Overview}</template>",
8
8
  " <template #tab-0-content>",
9
9
  " $3",
@@ -16,39 +16,39 @@
16
16
  " <template #tab-2-content>",
17
17
  " $7",
18
18
  " </template>",
19
- "</TabsCore>"
19
+ "</TabbedContent>"
20
20
  ]
21
21
  },
22
- "SRCDEV TabsCore Vertical": {
23
- "description": "TabsCore with axis=\"y\" for a vertical tab column",
22
+ "SRCDEV TabbedContent Vertical": {
23
+ "description": "TabbedContent with axis=\"y\" for a vertical tab column",
24
24
  "scope": "vue,html",
25
25
  "body": [
26
- "<TabsCore axis=\"y\" :item-count=\"${1:3}\" aria-label=\"${2:Settings}\">",
26
+ "<TabbedContent axis=\"y\" :item-count=\"${1:3}\" aria-label=\"${2:Settings}\">",
27
27
  " <template #tab-0-trigger>$3</template>",
28
28
  " <template #tab-0-content>$4</template>",
29
- "</TabsCore>"
29
+ "</TabbedContent>"
30
30
  ]
31
31
  },
32
- "SRCDEV TabsCore Indicators Off": {
33
- "description": "TabsCore with the moving hover/active/underline decorators all disabled",
32
+ "SRCDEV TabbedContent Indicators Off": {
33
+ "description": "TabbedContent with the moving hover/active/underline decorators all disabled",
34
34
  "scope": "vue,html",
35
35
  "body": [
36
- "<TabsCore",
36
+ "<TabbedContent",
37
37
  " :item-count=\"${1:3}\"",
38
38
  " :track-hover=\"false\"",
39
39
  " :track-active=\"false\"",
40
40
  " :track-indicator=\"false\"",
41
41
  ">",
42
42
  " $2",
43
- "</TabsCore>"
43
+ "</TabbedContent>"
44
44
  ]
45
45
  },
46
- "SRCDEV TabsCore CSS Override": {
47
- "description": "CSS override scaffold for TabsCore — scope to a page or section class",
46
+ "SRCDEV TabbedContent CSS Override": {
47
+ "description": "CSS override scaffold for TabbedContent — scope to a page or section class",
48
48
  "scope": "css",
49
49
  "body": [
50
50
  ".$1my-page {",
51
- " .tabs-core {",
51
+ " .tabbed-content {",
52
52
  " --tabs-nav-border: ;",
53
53
  " --tabs-hover-indicator-colour: ;",
54
54
  " --tabs-hover-indicator-text-colour: ;",
@@ -56,6 +56,8 @@
56
56
  " --tabs-active-indicator-text-colour: ;",
57
57
  " --tabs-underline-indicator-colour: ;",
58
58
  " --tabs-underline-indicator-height: ;",
59
+ " --tabs-hover-underline-indicator-colour: ;",
60
+ " --tabs-hover-underline-indicator-height: ;",
59
61
  " --tabs-list-item-opacity: ;",
60
62
  " --tabs-list-item-colour: ;",
61
63
  " --tabs-list-item-colour-selected: ;",
@@ -63,16 +65,33 @@
63
65
  " --tabs-list-item-font-weight: ;",
64
66
  " --tabs-list-item-padding-block: ;",
65
67
  " --tabs-list-item-padding-inline: ;",
68
+ " --tabs-list-item-max-inline-size: ;",
66
69
  " --tabs-list-item-colour-transition-duration: ;",
67
- " --tabs-list-item-focus-outline-width: ;",
70
+ " --tabs-focus-ring-width: ;",
71
+ " --tabs-focus-ring-colour: ;",
68
72
  " --tabs-list-item-focus-outline-offset: ;",
73
+ " --tabs-more-popover-surface: ;",
74
+ " --tabs-more-popover-border: ;",
75
+ " --tabs-more-item-surface-hover: ;",
76
+ " --tabs-more-item-colour-selected: ;",
69
77
  " --tabs-content-background-colour: ;",
78
+ " --tabs-content-text-colour: ;",
70
79
  " --tabs-content-border-width: ;",
71
80
  " --tabs-content-border-colour: ;",
72
81
  " --tabs-content-border-radius: ;",
73
82
  " --tabs-axis-y-gap: ;",
83
+ " --tabs-axis-y-list-max-inline-size: ;",
74
84
  " }",
75
85
  "}"
76
86
  ]
87
+ },
88
+ "SRCDEV TabbedContent Scrolling Row": {
89
+ "description": "TabbedContent whose tab row scrolls sideways instead of collapsing into a More menu",
90
+ "scope": "vue,html",
91
+ "body": [
92
+ "<TabbedContent :item-count=\"${1:3}\" overflow-mode=\"scroll\" aria-label=\"${2:Product details}\">",
93
+ " $3",
94
+ "</TabbedContent>"
95
+ ]
77
96
  }
78
97
  }
@@ -0,0 +1,24 @@
1
+ /* Shared status colours. Each status has a solid colour (dots, markers) plus a tinted
2
+ surface/text pair (badges, pills). Component tokens fall back to these, so overriding
3
+ one here restyles that status across every component. */
4
+ :root {
5
+ --status-success: var(--green-06);
6
+ --status-success-surface: var(--green-01);
7
+ --status-success-text: var(--green-10);
8
+
9
+ --status-warning: var(--orange-05);
10
+ --status-warning-surface: var(--orange-01);
11
+ --status-warning-text: var(--orange-10);
12
+
13
+ --status-danger: var(--red-06);
14
+ --status-danger-surface: var(--red-01);
15
+ --status-danger-text: var(--red-10);
16
+
17
+ --status-info: var(--blue-06);
18
+ --status-info-surface: var(--blue-01);
19
+ --status-info-text: var(--blue-09);
20
+
21
+ --status-neutral: var(--slate-05);
22
+ --status-neutral-surface: var(--slate-01);
23
+ --status-neutral-text: var(--slate-09);
24
+ }
@@ -4,3 +4,4 @@
4
4
  @import "./_error.css";
5
5
  @import "./_success.css";
6
6
  @import "./_warning.css";
7
+ @import "./_status.css";
@@ -1,17 +1,18 @@
1
1
  # ContainerGlow — Consumer Styling Guide
2
2
 
3
- ## Public CSS custom properties
3
+ ## Public token API
4
4
 
5
- These are static, per-card visual tokens — override them with a `style` attribute or from a
6
- consuming page's own stylesheet:
5
+ Static, per-card visual tokens. Set them on an element you own (see Local overrides) or with a
6
+ `style` attribute:
7
7
 
8
8
  | Token | Default | Description |
9
9
  |---|---|---|
10
- | `--container-glow-background` | `white` | Card background colour. |
10
+ | `--container-glow-background` | `var(--theme-surface-subtle)` | Card background colour. |
11
+ | `--container-glow-text-colour` | `var(--theme-text)` | Card text colour. |
11
12
  | `--container-glow-padding` | `2rem` | Card inner padding. |
12
- | `--container-glow-aspect-ratio` | `330 / 400` | Card aspect ratio. |
13
+ | `--container-glow-aspect-ratio` | `330 / 400` | Card aspect ratio. Content taller than this grows the card. |
13
14
  | `--container-glow-border-radius` | `12px` | Card and glow-effect corner radius (shared by the card and every glow layer). |
14
- | `--container-glow-min-width` | `280px` | Card minimum width. |
15
+ | `--container-glow-min-width` | `280px` | Card minimum width, capped at the wrapper's width so a narrow viewport never overflows. |
15
16
  | `--container-glow-max-width` | `280px` | Card maximum width. |
16
17
  | `--container-glow-content-gap` | `0.25rem` | Gap between a card's own slotted children. |
17
18
  | `--container-glow-highlight-colour` | `hsl(280 10% 50% / 1)` | Tint of the thin proximity-tracking ring drawn under the coloured glow. |
@@ -19,9 +20,14 @@ consuming page's own stylesheet:
19
20
  | `--container-glow-transition-duration` | `1s` | Fade duration when the glow's opacity changes (also disabled under `prefers-reduced-motion: reduce`). |
20
21
  | `--container-glow-gradient` | 5-stop conic rainbow gradient | The glow's colour gradient. Override with any valid `background` value (a `conic-gradient(...)`, a flat colour, etc). |
21
22
 
23
+ > Changed 2026-10-08: `--container-glow-background` defaulted to `white` and the card set no text
24
+ > colour. It now defaults to `var(--theme-surface-subtle)`, with the new
25
+ > `--container-glow-text-colour` defaulting to `var(--theme-text)`. Set
26
+ > `--container-glow-background: white` to keep the old look.
27
+
22
28
  ```vue
23
29
  <ContainerGlow
24
- style="--container-glow-background: #111; --container-glow-border-radius: 4px; --container-glow-gradient: conic-gradient(from 180deg, #22d3ee, #a855f7, #22d3ee);"
30
+ style="--container-glow-background: #111; --container-glow-text-colour: #eee; --container-glow-gradient: conic-gradient(from 180deg, #22d3ee, #a855f7, #22d3ee);"
25
31
  >
26
32
  <template #cta>
27
33
  <p>Custom-coloured glow card</p>
@@ -29,25 +35,40 @@ consuming page's own stylesheet:
29
35
  </ContainerGlow>
30
36
  ```
31
37
 
32
- ---
38
+ Private tokens, not public API: `--_start`, `--_opacity-active`, `--_gap`, `--_blur`, `--_spread`,
39
+ `--_direction` and `--_gradient`. They're driven by pointer events and the `config` prop; use
40
+ `config` (gap/blur/spread/direction/opacity) or the public tokens above (colour/geometry) instead.
41
+
42
+ ## State hooks
43
+
44
+ | Selector | Element |
45
+ |---|---|
46
+ | `.container-glow-wrapper` | Root. A `<ul>` when `tag="li"`, otherwise a `<div>`. Flex row (column with `config.vertical`) that wraps onto new lines. |
47
+ | `.container-glow` | One card per named slot, rendered as the `tag` element. |
48
+ | `.container-glow-glows` | Decorative blurred glow layer inside each card (`aria-hidden`). |
49
+
50
+ > Changed 2026-10-08: the glow layer class was `.glows`; renamed to `.container-glow-glows` so a
51
+ > consumer's own `.glows` class can't collide with it. The wrapper also gained `flex-wrap: wrap`
52
+ > (many cards used to overflow sideways) and renders as a `<ul>` when `tag="li"` (previously an
53
+ > invalid `<li>` inside a `<div>`), with list margin, padding and bullets reset.
33
54
 
34
55
  ## The `config` prop (layout and interaction behaviour)
35
56
 
36
57
  Proximity distance, glow spread/blur, wrapper gap, wrapper direction, and the inactive-state
37
- opacity are **not** CSS tokens — they're computed per-pointer-move in JavaScript and applied as
38
- private custom properties, so they're driven entirely by the `config` prop instead
39
- (`ContainerGlowConfig`, importable from `srcdev-nuxt-components`):
58
+ opacity are **not** CSS tokens. They're computed in JavaScript and applied as private custom
59
+ properties, so they're driven entirely by the `config` prop (`ContainerGlowConfig`, importable
60
+ from `srcdev-nuxt-components`):
40
61
 
41
62
  | Field | Type | Default | Description |
42
63
  |---|---|---|---|
43
- | `proximity` | `number` | `40` | Pointer distance (px) at which a card starts glowing. |
44
- | `spread` | `number` | `80` | Angular spread of the glow (degrees). |
45
- | `blur` | `number` | `20` | Blur applied to the glow layer (px). |
46
- | `gap` | `number` | `32` | Gap between cards in the wrapper (px). |
64
+ | `proximity` | `number` | `40` | Pointer distance (px) at which a card starts glowing. Minimum `0`. |
65
+ | `spread` | `number` | `80` | Angular spread of the glow (degrees). Clamped to `0`–`360`. |
66
+ | `blur` | `number` | `20` | Blur applied to the glow layer (px). Minimum `0`. |
67
+ | `gap` | `number` | `32` | Gap between cards in the wrapper (px). Minimum `0`. |
47
68
  | `vertical` | `boolean` | `false` | Stack cards vertically instead of horizontally. |
48
- | `inactiveOpacity` | `number` | `0` | Glow opacity when the pointer isn't nearby. |
69
+ | `inactiveOpacity` | `number` | `0` | Glow opacity when the pointer isn't nearby. Clamped to `0`–`1`. |
49
70
 
50
- All fields are optional — pass only the ones you want to change:
71
+ Non-finite values (`NaN`, `Infinity`) fall back to the default. All fields are optional:
51
72
 
52
73
  ```vue
53
74
  <ContainerGlow :config="{ blur: 40, vertical: true }">
@@ -56,11 +77,9 @@ All fields are optional — pass only the ones you want to change:
56
77
  </ContainerGlow>
57
78
  ```
58
79
 
59
- ---
60
-
61
80
  ## Named dynamic slots
62
81
 
63
- Each named slot renders as one glow card — the consumer controls the slot names, there's no
82
+ Each named slot renders as one glow card. The consumer controls the slot names; there's no
64
83
  `itemCount`-style prop:
65
84
 
66
85
  ```vue
@@ -70,23 +89,11 @@ Each named slot renders as one glow card — the consumer controls the slot name
70
89
  </ContainerGlow>
71
90
  ```
72
91
 
73
- ---
74
-
75
92
  ## Motion
76
93
 
77
94
  The glow's opacity fade (`--container-glow-transition-duration`) is disabled under
78
95
  `prefers-reduced-motion: reduce`, so proximity changes are instant rather than animated.
79
96
 
80
- ---
81
-
82
- ## Internal (non-overridable) custom properties
83
-
84
- `--_start`, `--_opacity-active`, `--_gap`, `--_blur`, `--_spread`, `--_direction`, and `--_gradient`
85
- are internal plumbing driven by pointer events and the `config` prop — use `config` (for
86
- gap/blur/spread/direction/opacity) or the public tokens above (for colour/geometry) instead.
87
-
88
- ---
89
-
90
97
  ## Local overrides
91
98
 
92
99
  Set the tokens above on an element you own (a page or section class, or a class added with
@@ -95,8 +102,6 @@ Set the tokens above on an element you own (a page or section class, or a class
95
102
  `<style scoped>`, tokens set on your element still work, but selectors that reach inside the component need
96
103
  `:deep()`. Patterns and examples: `.claude/skills/component-local-style-override.md`.
97
104
 
98
- ---
99
-
100
105
  ## Class passthrough
101
106
 
102
107
  Use `styleClassPassthrough` to add classes to the root `.container-glow-wrapper` element.
@@ -104,4 +109,3 @@ Use `styleClassPassthrough` to add classes to the root `.container-glow-wrapper`
104
109
  ```vue
105
110
  <ContainerGlow style-class-passthrough="my-container-glow">...</ContainerGlow>
106
111
  ```
107
-
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div ref="containerGlowWrapper" class="container-glow-wrapper" :class="elementClasses">
2
+ <component :is="wrapperTag" ref="containerGlowWrapper" class="container-glow-wrapper" :class="elementClasses">
3
3
  <component
4
4
  :is="tag"
5
5
  v-for="(_, name) in $slots"
@@ -7,10 +7,10 @@
7
7
  ref="containerGlowItem"
8
8
  class="container-glow"
9
9
  >
10
- <div class="glows"></div>
10
+ <div class="container-glow-glows" aria-hidden="true"></div>
11
11
  <slot :name="name"></slot>
12
12
  </component>
13
- </div>
13
+ </component>
14
14
  </template>
15
15
 
16
16
  <script setup lang="ts">
@@ -37,18 +37,22 @@ watch(
37
37
  }
38
38
  );
39
39
 
40
+ const wrapperTag = computed(() => (props.tag === "li" ? "ul" : "div"));
41
+
40
42
  const controller = new AbortController();
41
43
 
42
44
  const containerGlowWrapper = ref<HTMLElement>();
43
45
  const containerGlowItem = ref<HTMLElement[]>([]);
44
46
 
45
- // Cache frequently used values to avoid repeated access
47
+ const clampConfig = (value: number | undefined, fallback: number, min: number, max: number) =>
48
+ typeof value === "number" && Number.isFinite(value) ? Math.min(Math.max(value, min), max) : fallback;
49
+
46
50
  const configCache = computed(() => ({
47
- proximity: props.config.proximity ?? 40,
48
- inactiveOpacityStr: String(props.config.inactiveOpacity ?? 0),
49
- gapStr: String(props.config.gap ?? 32),
50
- blurStr: String(props.config.blur ?? 20),
51
- spreadStr: String(props.config.spread ?? 80),
51
+ proximity: clampConfig(props.config.proximity, 40, 0, Infinity),
52
+ inactiveOpacityStr: String(clampConfig(props.config.inactiveOpacity, 0, 0, 1)),
53
+ gapStr: String(clampConfig(props.config.gap, 32, 0, Infinity)),
54
+ blurStr: String(clampConfig(props.config.blur, 20, 0, Infinity)),
55
+ spreadStr: String(clampConfig(props.config.spread, 80, 0, 360)),
52
56
  direction: props.config.vertical ? "column" : "row",
53
57
  }));
54
58
 
@@ -164,7 +168,11 @@ onBeforeUnmount(() => {
164
168
  .container-glow-wrapper {
165
169
  display: flex;
166
170
  flex-direction: var(--_direction, row);
171
+ flex-wrap: wrap;
167
172
  gap: calc(var(--_gap, 32) * 1px);
173
+ margin: 0;
174
+ padding: 0;
175
+ list-style: none;
168
176
 
169
177
  .container-glow {
170
178
  & *,
@@ -185,18 +193,20 @@ onBeforeUnmount(() => {
185
193
  hsla(0, 0%, 98%, 1) 1turn
186
194
  )
187
195
  );
188
- --_opacity-active: v-bind("props.config.inactiveOpacity ?? 0");
196
+ --_opacity-active: v-bind("configCache.inactiveOpacityStr");
189
197
  --_start: 0;
190
198
 
191
199
  position: relative;
192
200
 
193
201
  height: 100%;
194
- background: var(--container-glow-background, white);
202
+ background: var(--container-glow-background, var(--theme-surface-subtle));
203
+ color: var(--container-glow-text-colour, var(--theme-text));
195
204
  padding: var(--container-glow-padding, 2rem);
196
205
  aspect-ratio: var(--container-glow-aspect-ratio, 330 / 400);
197
206
  border-radius: var(--container-glow-border-radius, 12px);
198
- min-width: var(--container-glow-min-width, 280px);
207
+ min-width: min(var(--container-glow-min-width, 280px), 100%);
199
208
  max-width: var(--container-glow-max-width, 280px);
209
+ overflow-wrap: anywhere;
200
210
  display: flex;
201
211
  flex-direction: column;
202
212
  gap: var(--container-glow-content-gap, 0.25rem);
@@ -255,7 +265,7 @@ onBeforeUnmount(() => {
255
265
  mask-composite: intersect;
256
266
  }
257
267
 
258
- .glows {
268
+ .container-glow-glows {
259
269
  pointer-events: none;
260
270
  position: absolute;
261
271
  inset: 0;
@@ -288,8 +298,8 @@ onBeforeUnmount(() => {
288
298
  @media (prefers-reduced-motion: reduce) {
289
299
  &::before,
290
300
  &::after,
291
- .glows::before,
292
- .glows::after {
301
+ .container-glow-glows::before,
302
+ .container-glow-glows::after {
293
303
  transition: none;
294
304
  }
295
305
  }