srcdev-nuxt-components 9.6.4 → 9.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.claude/rules/consumer/a11y-no-focus-steal.md +14 -0
  2. package/.claude/skills/component-compliance-checklist.md +14 -2
  3. package/.claude/skills/components/display-toast.md +6 -3
  4. package/.claude/skills/components/progress-tracker.md +140 -0
  5. package/.claude/skills/components/social-icons-list.md +32 -5
  6. package/.claude/skills/components/stepper-list.md +10 -3
  7. package/.claude/skills/components/tabbed-content.md +4 -0
  8. package/.claude/skills/css-dynamic-border-radius.md +114 -0
  9. package/.claude/skills/index.md +4 -2
  10. package/.claude/skills/storybook-add-story.md +12 -0
  11. package/.vscode/srcdev-component-display-toast.code-snippets +6 -8
  12. package/.vscode/srcdev-component-progress-tracker.code-snippets +45 -0
  13. package/.vscode/srcdev-component-social-icons-list.code-snippets +14 -0
  14. package/.vscode/srcdev-component-stepper-list.code-snippets +3 -2
  15. package/.vscode/srcdev-component-tabbed-content.code-snippets +1 -0
  16. package/.vscode/srcdev-utility-dynamic-border-radius.code-snippets +31 -0
  17. package/app/assets/styles/setup/06.utility-classes/_dynamic-border-radius.css +27 -0
  18. package/app/assets/styles/setup/06.utility-classes/index.css +1 -0
  19. package/app/components/01.atoms/tabbed-content/CONSUMER-STYLING.md +5 -1
  20. package/app/components/01.atoms/tabbed-content/TabbedContent.vue +2 -2
  21. package/app/components/01.atoms/tabbed-content/stories/TabbedContent.stories.ts +26 -0
  22. package/app/components/02.molecules/contact-section/tests/__snapshots__/ContactSection.spec.ts.snap +28 -28
  23. package/app/components/02.molecules/progress-tracker/CONSUMER-STYLING.md +116 -0
  24. package/app/components/02.molecules/progress-tracker/ProgressTracker.vue +275 -0
  25. package/app/components/02.molecules/progress-tracker/stories/ProgressTracker.stories.ts +424 -0
  26. package/app/components/02.molecules/progress-tracker/tests/ProgressTracker.spec.ts +253 -0
  27. package/app/components/02.molecules/progress-tracker/tests/__snapshots__/ProgressTracker.spec.ts.snap +46 -0
  28. package/app/components/02.molecules/social-icons-list/CONSUMER-STYLING.md +97 -8
  29. package/app/components/02.molecules/social-icons-list/SocialIconsList.vue +80 -14
  30. package/app/components/02.molecules/social-icons-list/stories/SocialIconsList.stories.ts +230 -2
  31. package/app/components/02.molecules/social-icons-list/stories/social-icons-list-recipes.css +108 -0
  32. package/app/components/02.molecules/social-icons-list/tests/SocialIconsList.spec.ts +123 -52
  33. package/app/components/02.molecules/social-icons-list/tests/__snapshots__/SocialIconsList.spec.ts.snap +10 -4
  34. package/app/components/02.molecules/stepper-list/CONSUMER-STYLING.md +42 -7
  35. package/app/components/02.molecules/stepper-list/StepperList.vue +42 -19
  36. package/app/components/02.molecules/stepper-list/stories/StepperList.stories.ts +288 -2
  37. package/app/components/02.molecules/stepper-list/tests/StepperList.spec.ts +161 -34
  38. package/app/components/02.molecules/stepper-list/tests/__snapshots__/StepperList.spec.ts.snap +40 -40
  39. package/app/components/02.molecules/toast/CONSUMER-STYLING.md +9 -3
  40. package/app/components/02.molecules/toast/DisplayToast.vue +10 -10
  41. package/app/components/02.molecules/toast/DisplayToastProvider.vue +12 -4
  42. package/app/components/02.molecules/toast/stories/DisplayToast.stories.ts +200 -2
  43. package/app/components/02.molecules/toast/tests/DisplayToast.spec.ts +33 -12
  44. package/app/components/02.molecules/toast/tests/DisplayToastProvider.spec.ts +20 -0
  45. package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +7 -7
  46. package/app/types/components/index.ts +1 -0
  47. package/app/types/components/progress-tracker.d.ts +6 -0
  48. package/app/types/components/social-icons-list.d.ts +9 -0
  49. package/package.json +1 -1
@@ -1,12 +1,56 @@
1
1
  import type { Meta, StoryFn } from "@nuxtjs/storybook";
2
- import { ref, onMounted } from "vue";
2
+ import { ref, computed, watchEffect, onMounted, onUnmounted } from "vue";
3
3
  import StorybookComponent from "../DisplayToast.vue";
4
4
 
5
+ type CanvasKey = "none" | "gradient" | "lake" | "portrait" | "dark-photo" | "stripes" | "page-text";
6
+
7
+ const busyBackdrop = [
8
+ "repeating-linear-gradient(45deg, oklch(100% 0 0 / 0.18) 0 1.2rem, transparent 1.2rem 2.4rem)",
9
+ "linear-gradient(120deg, oklch(70% 0.2 30), oklch(75% 0.18 90) 35%, oklch(65% 0.2 200) 70%, oklch(55% 0.22 300))",
10
+ ].join(", ");
11
+
12
+ const canvases: Record<CanvasKey, string> = {
13
+ none: "",
14
+ gradient: "background: linear-gradient(135deg, oklch(40% 0.15 250), oklch(25% 0.1 300));",
15
+ lake: "background: url('/images/banners/video/lake-banner.jpg') center / cover;",
16
+ portrait: "background: url('/images/page/hero/hero-blonde.jpg') center 30% / cover;",
17
+ "dark-photo": "background: url('/images/page/hero/hero-dark.jpg') center / cover;",
18
+ stripes: `background: ${busyBackdrop};`,
19
+ "page-text": "background: white;",
20
+ };
21
+
22
+ const pageText = Array.from(
23
+ { length: 6 },
24
+ () =>
25
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
26
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
27
+ "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
28
+ );
29
+
30
+ /*
31
+ * The toast teleports to <body>, so a fill override on a story wrapper never reaches it. Inject a
32
+ * rule on .display-toast instead: --theme-surface-subtle then resolves against the toast's data-theme.
33
+ */
34
+ function useMaskedFillStyle(fill: () => number) {
35
+ const styleEl = document.createElement("style");
36
+ document.head.appendChild(styleEl);
37
+ watchEffect(() => {
38
+ styleEl.textContent =
39
+ fill() === 80
40
+ ? ""
41
+ : `.display-toast { --alert-masked-content-background: color-mix(in oklab, var(--theme-surface-subtle) ${fill()}%, transparent); }`;
42
+ });
43
+ onUnmounted(() => styleEl.remove());
44
+ }
45
+
5
46
  interface ToastStoryArgs {
6
47
  theme: "info" | "success" | "warning" | "error";
7
48
  position: "top" | "bottom";
8
49
  alignment: "left" | "center" | "right";
9
50
  fullWidth: boolean;
51
+ masked: boolean;
52
+ maskedFill: number;
53
+ canvas: CanvasKey;
10
54
  autoDismiss: boolean;
11
55
  duration: number;
12
56
  revealDuration: number;
@@ -42,6 +86,24 @@ export default {
42
86
  description: "Whether toast spans full width",
43
87
  table: { category: "Appearance" },
44
88
  },
89
+ masked: {
90
+ control: { type: "boolean" },
91
+ description: "Render with AlertMaskedContent (SVG border, translucent fill) instead of AlertContent",
92
+ table: { category: "Appearance" },
93
+ },
94
+ maskedFill: {
95
+ control: { type: "range", min: 0, max: 100, step: 5 },
96
+ description:
97
+ "Story-only: opacity (%) of the masked fill, set via --alert-masked-content-background. 80 is the library default; lower values cost contrast",
98
+ if: { arg: "masked" },
99
+ table: { category: "Story canvas" },
100
+ },
101
+ canvas: {
102
+ control: { type: "select" },
103
+ options: ["none", "gradient", "lake", "portrait", "dark-photo", "stripes", "page-text"],
104
+ description: "Story-only: full-viewport backdrop behind the toast, to show what the masked variant lets through",
105
+ table: { category: "Story canvas" },
106
+ },
45
107
  autoDismiss: {
46
108
  control: { type: "boolean" },
47
109
  description: "Auto dismiss toast after duration",
@@ -80,6 +142,9 @@ export default {
80
142
  position: "top",
81
143
  alignment: "right",
82
144
  fullWidth: false,
145
+ masked: false,
146
+ maskedFill: 80,
147
+ canvas: "none",
83
148
  autoDismiss: false,
84
149
  duration: 3000,
85
150
  revealDuration: 300,
@@ -104,9 +169,21 @@ const Template: StoryFn<ToastStoryArgs> = (args) => ({
104
169
  }, 500);
105
170
  });
106
171
 
107
- return { args, isActive };
172
+ useMaskedFillStyle(() => args.maskedFill);
173
+ const canvasStyle = computed(() => canvases[args.canvas]);
174
+
175
+ return { args, isActive, canvasStyle, pageText };
108
176
  },
109
177
  template: `
178
+ <div
179
+ v-if="args.canvas !== 'none'"
180
+ :style="canvasStyle + ' position: fixed; inset: 0; overflow: hidden; padding: 6rem 2rem 2rem; font-family: sans-serif; font-size: 1.6rem; line-height: 1.5; color: #222;'"
181
+ >
182
+ <template v-if="args.canvas === 'page-text'">
183
+ <h2 style="margin: 0 0 1rem;">Article heading behind the toast</h2>
184
+ <p v-for="(para, i) in pageText" :key="i" style="margin: 0 0 1rem;">{{ para }}</p>
185
+ </template>
186
+ </div>
110
187
  <div style="position: relative; height: 200px; padding: 20px;">
111
188
  <button
112
189
  @click="isActive = true"
@@ -123,6 +200,7 @@ const Template: StoryFn<ToastStoryArgs> = (args) => ({
123
200
  position: args.position,
124
201
  alignment: args.alignment,
125
202
  fullWidth: args.fullWidth,
203
+ masked: args.masked,
126
204
  },
127
205
  behavior: {
128
206
  autoDismiss: args.autoDismiss,
@@ -220,3 +298,123 @@ StressTest.parameters = {
220
298
  },
221
299
  },
222
300
  };
301
+
302
+ export const MaskedOverGradient = Template.bind({});
303
+ MaskedOverGradient.storyName = "Masked: Over Gradient";
304
+ MaskedOverGradient.args = {
305
+ masked: true,
306
+ canvas: "gradient",
307
+ title: "Masked toast",
308
+ description: "AlertMaskedContent: the accent border is an SVG cut-out and the fill is 80% translucent.",
309
+ };
310
+ MaskedOverGradient.parameters = {
311
+ docs: {
312
+ description: {
313
+ story:
314
+ "`appearance.masked: true` swaps AlertContent for AlertMaskedContent. Over a flat gradient the effect is subtle: " +
315
+ "switch `canvas` to a photo or the stripes to see the backdrop through the fill.",
316
+ },
317
+ },
318
+ };
319
+
320
+ export const MaskedOverPhoto = Template.bind({});
321
+ MaskedOverPhoto.storyName = "Masked: Over Photo";
322
+ MaskedOverPhoto.args = {
323
+ theme: "success",
324
+ masked: true,
325
+ canvas: "portrait",
326
+ title: "Booking confirmed",
327
+ description: "We've sent the details to your inbox.",
328
+ customIcon: "akar-icons:check-box",
329
+ };
330
+ MaskedOverPhoto.parameters = {
331
+ docs: {
332
+ description: {
333
+ story:
334
+ "A photo backdrop is where the masked variant earns its place: the image stays visible through the body and around the border. " +
335
+ "Try `lake` and `dark-photo` too, and every theme.",
336
+ },
337
+ },
338
+ };
339
+
340
+ export const MaskedVsOpaque: StoryFn<ToastStoryArgs> = (args) => ({
341
+ components: { StorybookComponent },
342
+ setup() {
343
+ const isActive = ref(false);
344
+ onMounted(() => {
345
+ setTimeout(() => {
346
+ isActive.value = true;
347
+ }, 500);
348
+ });
349
+ useMaskedFillStyle(() => args.maskedFill);
350
+ const canvasStyle = computed(() => canvases[args.canvas]);
351
+ const config = (masked: boolean, alignment: "left" | "right") => ({
352
+ appearance: { theme: args.theme, position: args.position, alignment, masked },
353
+ behavior: { autoDismiss: false, revealDuration: args.revealDuration },
354
+ content: { title: masked ? "AlertMaskedContent" : "AlertContent", description: args.description },
355
+ });
356
+ return { args, isActive, canvasStyle, config };
357
+ },
358
+ template: `
359
+ <div :style="canvasStyle + ' position: fixed; inset: 0;'"></div>
360
+ <div style="position: relative; padding: 20px;">
361
+ <button
362
+ @click="isActive = true"
363
+ style="padding: 8px 16px; background: #0066cc; color: white; border: none; border-radius: 4px; cursor: pointer;"
364
+ >
365
+ Trigger Toasts
366
+ </button>
367
+ </div>
368
+ <StorybookComponent v-model="isActive" :config="config(false, 'left')" />
369
+ <StorybookComponent v-model="isActive" :config="config(true, 'right')" />
370
+ `,
371
+ });
372
+ MaskedVsOpaque.storyName = "Masked: Side by Side with Opaque";
373
+ MaskedVsOpaque.args = {
374
+ masked: true,
375
+ canvas: "lake",
376
+ description: "Same theme, same backdrop: opaque on the left, masked on the right.",
377
+ };
378
+ MaskedVsOpaque.argTypes = {
379
+ masked: { table: { disable: true } },
380
+ alignment: { table: { disable: true } },
381
+ fullWidth: { table: { disable: true } },
382
+ title: { table: { disable: true } },
383
+ customIcon: { table: { disable: true } },
384
+ autoDismiss: { table: { disable: true } },
385
+ duration: { table: { disable: true } },
386
+ };
387
+ MaskedVsOpaque.parameters = {
388
+ docs: {
389
+ description: {
390
+ story:
391
+ "Two toasts over one backdrop: AlertContent (left) and AlertMaskedContent (right). Change `canvas` and `theme` to compare, " +
392
+ "and drag `maskedFill` to see how much backdrop the masked one lets through.",
393
+ },
394
+ },
395
+ };
396
+
397
+ export const MaskedLowContrast = Template.bind({});
398
+ MaskedLowContrast.storyName = "Masked: Low Contrast Risk";
399
+ MaskedLowContrast.args = {
400
+ theme: "info",
401
+ masked: true,
402
+ maskedFill: 35,
403
+ canvas: "page-text",
404
+ alignment: "center",
405
+ title: "Hard to read",
406
+ description: "Page text shows through a 35% fill and fights with the toast's own text.",
407
+ };
408
+ MaskedLowContrast.parameters = {
409
+ docs: {
410
+ description: {
411
+ story:
412
+ "What can go wrong. The default 80% fill keeps `--theme-text` readable over most backdrops, but contrast depends on what's behind the toast, " +
413
+ "which you don't control once it's fixed to the viewport. Here the fill is lowered to 35% over body copy, so letterforms from the page " +
414
+ "show through and compete with the message. Other traps to try: `stripes` or `portrait` with a low fill (busy detail behind small text), " +
415
+ "and the `info` theme over `gradient` (the 1px accent border nearly vanishes against a backdrop of a similar hue). " +
416
+ "Drag `maskedFill` back up to 80 to see the default recover. If you lower `--alert-masked-content-background`, test it over your real imagery and content, " +
417
+ "and prefer the opaque variant for error and warning toasts that must be read.",
418
+ },
419
+ },
420
+ };
@@ -198,21 +198,35 @@ describe("DisplayToast", () => {
198
198
 
199
199
  // ─── Dismiss via Escape key ────────────────────────────────────────────────
200
200
 
201
- it("transitions to hide class when Escape is pressed", async () => {
201
+ it("transitions to hide class when Escape is pressed on the toast", async () => {
202
202
  await mountAndShow({ config: { behavior: { autoDismiss: false } } });
203
- vi.advanceTimersByTime(100); // fire the focus setTimeout
204
- await nextTick();
203
+ vi.advanceTimersByTime(1);
205
204
  toast()!.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }));
206
205
  await nextTick();
207
206
  expect(toast()!.getAttribute("data-state")).toBe("hide");
208
207
  });
209
208
 
209
+ it("dismisses on Escape pressed anywhere in the document, since it never takes focus", async () => {
210
+ await mountAndShow({ config: { behavior: { autoDismiss: false } } });
211
+ document.body.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }));
212
+ await nextTick();
213
+ expect(toast()!.getAttribute("data-state")).toBe("hide");
214
+ });
215
+
216
+ it("ignores an Escape another handler has already claimed", async () => {
217
+ await mountAndShow({ config: { behavior: { autoDismiss: false } } });
218
+ const event = new KeyboardEvent("keydown", { key: "Escape", bubbles: true, cancelable: true });
219
+ event.preventDefault();
220
+ document.body.dispatchEvent(event);
221
+ await nextTick();
222
+ expect(toast()!.getAttribute("data-state")).toBe("show");
223
+ });
224
+
210
225
  // ─── Dismiss via close button ─────────────────────────────────────────────
211
226
 
212
227
  it("transitions to hide class when the close button is clicked", async () => {
213
228
  await mountAndShow({ config: { behavior: { autoDismiss: false } } });
214
- vi.advanceTimersByTime(100);
215
- await nextTick();
229
+ vi.advanceTimersByTime(1);
216
230
  (document.querySelector("[data-test-id='alert-dismiss']") as HTMLElement).click();
217
231
  await nextTick();
218
232
  expect(toast()!.getAttribute("data-state")).toBe("hide");
@@ -282,22 +296,29 @@ describe("DisplayToast", () => {
282
296
  expect(toast()!.getAttribute("data-state")).toBe("hide");
283
297
  });
284
298
 
285
- it("does not pause when the toast takes focus after mouse input", async () => {
299
+ it("does not move focus to itself when shown", async () => {
300
+ await mountAndShow({ config: autoConfig });
301
+ vi.advanceTimersByTime(500);
302
+ await nextTick();
303
+ expect(document.activeElement).not.toBe(toast());
304
+ expect(toast()!.hasAttribute("data-paused")).toBe(false);
305
+ });
306
+
307
+ it("does not pause when focused after mouse input", async () => {
286
308
  setFocusVisible(false);
287
309
  await mountAndShow({ config: autoConfig });
288
- vi.advanceTimersByTime(100); // the toast focuses itself
310
+ (toast() as HTMLElement).focus();
289
311
  await nextTick();
290
- expect(document.activeElement).toBe(toast());
291
312
  expect(toast()!.hasAttribute("data-paused")).toBe(false);
292
- vi.advanceTimersByTime(900);
313
+ vi.advanceTimersByTime(1000);
293
314
  await nextTick();
294
315
  expect(toast()!.getAttribute("data-state")).toBe("hide");
295
316
  });
296
317
 
297
- it("pauses when the toast takes focus after keyboard input, until focus leaves", async () => {
318
+ it("pauses when a keyboard user focuses the toast, until focus leaves", async () => {
298
319
  setFocusVisible(true);
299
320
  await mountAndShow({ config: autoConfig });
300
- vi.advanceTimersByTime(100);
321
+ (toast() as HTMLElement).focus();
301
322
  await nextTick();
302
323
  expect(toast()!.hasAttribute("data-paused")).toBe(true);
303
324
  vi.advanceTimersByTime(5000);
@@ -305,7 +326,7 @@ describe("DisplayToast", () => {
305
326
  expect(toast()!.getAttribute("data-state")).toBe("show");
306
327
  (toast() as HTMLElement).blur();
307
328
  await nextTick();
308
- vi.advanceTimersByTime(900);
329
+ vi.advanceTimersByTime(1000);
309
330
  await nextTick();
310
331
  expect(toast()!.getAttribute("data-state")).toBe("hide");
311
332
  });
@@ -208,6 +208,26 @@ describe("DisplayToastProvider", () => {
208
208
  expect(items().length).toBe(0);
209
209
  });
210
210
 
211
+ it("does not move focus to a toast when it appears", async () => {
212
+ await mountProvider(DisplayToastProvider);
213
+ show({ behavior: { autoDismiss: false } });
214
+ await nextTick();
215
+ await nextTick();
216
+ expect(document.activeElement).not.toBe(item());
217
+ });
218
+
219
+ it("dismisses only the newest toast when Escape is pressed outside the toasts", async () => {
220
+ await mountProvider(DisplayToastProvider, { props: { maxVisible: 2 } });
221
+ show({ content: { text: "First" }, behavior: { autoDismiss: false } });
222
+ show({ content: { text: "Second" }, behavior: { autoDismiss: false } });
223
+ await nextTick();
224
+ expect(items().length).toBe(2);
225
+ document.body.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }));
226
+ await nextTick();
227
+ expect(items().length).toBe(1);
228
+ expect(item()!.textContent).toContain("First");
229
+ });
230
+
211
231
  // ─── Auto-dismiss timer ───────────────────────────────────────────────────
212
232
 
213
233
  it("auto-dismisses after duration", async () => {
@@ -37,22 +37,22 @@ exports[`ServiceDetail > renders correct HTML structure 1`] = `
37
37
  <h2 class="hero-text mb-20 subheading axis-horizontal">
38
38
  <!--v-if--><span class="text-block-0 normal">The Process</span>
39
39
  </h2>
40
- <ol class="stepper-list has-connectors service-detail__process">
41
- <li class="indicator-top indicator-circle" style="--_connector-top: 0px; --_connector-height: 0px;">
40
+ <ol role="list" class="stepper-list has-connectors service-detail__process">
41
+ <li class="stepper-list-item indicator-top indicator-circle" style="--_connector-left: 0px; --_connector-top: 0px; --_connector-height: 0px;">
42
42
  <div class="stepper-list__indicator-counter"></div>
43
- <div>
43
+ <div class="stepper-list-content">
44
44
  <p class="page-body-normal">Consultation</p>
45
45
  </div>
46
46
  </li>
47
- <li class="indicator-top indicator-circle" style="--_connector-top: 0px; --_connector-height: 0px;">
47
+ <li class="stepper-list-item indicator-top indicator-circle" style="--_connector-left: 0px; --_connector-top: 0px; --_connector-height: 0px;">
48
48
  <div class="stepper-list__indicator-counter"></div>
49
- <div>
49
+ <div class="stepper-list-content">
50
50
  <p class="page-body-normal">Sectioning</p>
51
51
  </div>
52
52
  </li>
53
- <li class="indicator-top indicator-circle">
53
+ <li class="stepper-list-item indicator-top indicator-circle">
54
54
  <div class="stepper-list__indicator-counter"></div>
55
- <div>
55
+ <div class="stepper-list-content">
56
56
  <p class="page-body-normal">Painting</p>
57
57
  </div>
58
58
  </li>
@@ -26,3 +26,4 @@ export * from "./samaritan-prompt.d"
26
26
  export * from "./profile-section.d"
27
27
  export * from "./services-card.d"
28
28
  export * from "./google-reviews.d"
29
+ export * from "./progress-tracker.d"
@@ -0,0 +1,6 @@
1
+ export interface ProgressTrackerStep {
2
+ title: string;
3
+ body?: string;
4
+ }
5
+
6
+ export type ProgressTrackerStepState = "done" | "current" | "upcoming";
@@ -1,3 +1,5 @@
1
+ import type { VNode } from "vue";
2
+
1
3
  export interface ISocialIcon {
2
4
  networkName: string;
3
5
  iconName: string;
@@ -5,4 +7,11 @@ export interface ISocialIcon {
5
7
  profileId: string;
6
8
  /** Accessible name for the link; overrides the list's linkLabelTemplate. */
7
9
  label?: string;
10
+ /** Brand colour, exposed as --social-icons-list-brand-colour on this item for recipes to use. */
11
+ brandColour?: string;
12
+ }
13
+
14
+ export interface SocialIconsListSlots {
15
+ icon?(props: { item: ISocialIcon }): VNode[];
16
+ label?(props: { item: ISocialIcon }): VNode[];
8
17
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.6.4",
4
+ "version": "9.6.6",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",