srcdev-nuxt-components 9.6.19 → 9.6.20

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 (135) hide show
  1. package/.claude/rules/consumer/ids-from-useid.md +3 -2
  2. package/.claude/skills/component-compliance-checklist.md +5 -0
  3. package/.claude/skills/components/auto-grid.md +3 -1
  4. package/.claude/skills/components/capture-qr-code.md +9 -5
  5. package/.claude/skills/components/carousel-flip.md +41 -30
  6. package/.claude/skills/components/column-flow-grid.md +2 -0
  7. package/.claude/skills/components/dashboard-quad-grid.md +7 -2
  8. package/.claude/skills/components/dashboard-stats-grid.md +4 -0
  9. package/.claude/skills/components/decode-qr-code.md +7 -2
  10. package/.claude/skills/components/deep-expanding-menu-classic.md +31 -30
  11. package/.claude/skills/components/deep-expanding-menu.md +22 -21
  12. package/.claude/skills/components/grid-stack.md +2 -0
  13. package/.claude/skills/components/layout-grid-by-cols.md +2 -0
  14. package/.claude/skills/components/masonry-grid.md +9 -1
  15. package/.claude/skills/components/page-row.md +3 -0
  16. package/.claude/skills/components/samaritan-prompt.md +24 -8
  17. package/.claude/skills/components/site-header.md +16 -2
  18. package/.claude/skills/index.md +12 -12
  19. package/.claude/skills/storybook-add-story.md +25 -0
  20. package/.claude/skills/testing-add-unit-test.md +26 -0
  21. package/.vscode/srcdev-component-capture-decode-qr-code.code-snippets +11 -2
  22. package/.vscode/srcdev-component-carousel-flip.code-snippets +22 -4
  23. package/.vscode/srcdev-component-deep-expanding-menu-classic.code-snippets +32 -2
  24. package/.vscode/srcdev-component-deep-expanding-menu.code-snippets +31 -1
  25. package/.vscode/srcdev-component-samaritan-prompt.code-snippets +5 -4
  26. package/.vscode/srcdev-component-site-header.code-snippets +13 -1
  27. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/CONSUMER-STYLING.md +12 -2
  28. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/DashboardQuadGrid.vue +19 -17
  29. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/stories/DashboardQuadGrid.stories.ts +42 -0
  30. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-quad-grid/tests/DashboardQuadGrid.spec.ts +31 -44
  31. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/CONSUMER-STYLING.md +13 -1
  32. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/DashboardStatsGrid.vue +40 -31
  33. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/stories/DashboardStatsGrid.stories.ts +47 -0
  34. package/app/components/01.atoms/content-wrappers/layout-grid/dashboard-stats-grid/tests/DashboardStatsGrid.spec.ts +51 -53
  35. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/CONSUMER-STYLING.md +3 -0
  36. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/LayoutGridByCols.vue +4 -0
  37. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/stories/LayoutGridByCols.stories.ts +47 -2
  38. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/tests/LayoutGridByCols.spec.ts +36 -23
  39. package/app/components/01.atoms/grids/auto-grid/AutoGrid.vue +7 -3
  40. package/app/components/01.atoms/grids/auto-grid/CONSUMER-STYLING.md +1 -1
  41. package/app/components/01.atoms/grids/auto-grid/stories/AutoGrid.stories.ts +46 -1
  42. package/app/components/01.atoms/grids/auto-grid/tests/AutoGrid.spec.ts +40 -27
  43. package/app/components/01.atoms/grids/auto-grid/tests/__snapshots__/AutoGrid.spec.ts.snap +1 -1
  44. package/app/components/01.atoms/grids/column-flow-grid/CONSUMER-STYLING.md +9 -0
  45. package/app/components/01.atoms/grids/column-flow-grid/ColumnFlowGrid.vue +3 -2
  46. package/app/components/01.atoms/grids/column-flow-grid/stories/ColumnFlowGrid.stories.ts +46 -0
  47. package/app/components/01.atoms/grids/column-flow-grid/tests/ColumnFlowGrid.spec.ts +24 -11
  48. package/app/components/01.atoms/grids/grid-stack/CONSUMER-STYLING.md +3 -0
  49. package/app/components/01.atoms/grids/grid-stack/GridStack.vue +2 -0
  50. package/app/components/01.atoms/grids/grid-stack/stories/GridStack.stories.ts +41 -0
  51. package/app/components/01.atoms/grids/grid-stack/tests/GridStack.spec.ts +26 -13
  52. package/app/components/01.atoms/grids/masonry-grid/CONSUMER-STYLING.md +15 -0
  53. package/app/components/01.atoms/grids/masonry-grid/MasonryGrid.vue +51 -31
  54. package/app/components/01.atoms/grids/masonry-grid/stories/MasonryGrid.stories.ts +48 -0
  55. package/app/components/01.atoms/grids/masonry-grid/tests/MasonryGrid.spec.ts +84 -29
  56. package/app/components/01.atoms/page-row/CONSUMER-STYLING.md +6 -1
  57. package/app/components/01.atoms/page-row/PageRow.vue +16 -15
  58. package/app/components/01.atoms/page-row/stories/PageRow.stories.ts +23 -0
  59. package/app/components/01.atoms/page-row/tests/PageRow.spec.ts +6 -5
  60. package/app/components/02.molecules/navigation/deep-expanding-menu/CONSUMER-STYLING.md +63 -44
  61. package/app/components/02.molecules/navigation/deep-expanding-menu/DeepExpandingMenu.vue +74 -37
  62. package/app/components/02.molecules/navigation/deep-expanding-menu/stories/DeepExpandingMenu.stories.ts +139 -19
  63. package/app/components/02.molecules/navigation/deep-expanding-menu/tests/DeepExpandingMenu.spec.ts +90 -27
  64. package/app/components/02.molecules/navigation/deep-expanding-menu/tests/__snapshots__/DeepExpandingMenu.spec.ts.snap +8 -8
  65. package/app/components/02.molecules/navigation/deep-expanding-menu-classic/CONSUMER-STYLING.md +58 -26
  66. package/app/components/02.molecules/navigation/deep-expanding-menu-classic/DeepExpandingMenuClassic.vue +113 -57
  67. package/app/components/02.molecules/navigation/deep-expanding-menu-classic/stories/DeepExpandingMenuClassic.stories.ts +139 -19
  68. package/app/components/02.molecules/navigation/deep-expanding-menu-classic/tests/DeepExpandingMenuClassic.spec.ts +140 -22
  69. package/app/components/02.molecules/navigation/deep-expanding-menu-classic/tests/__snapshots__/DeepExpandingMenuClassic.spec.ts.snap +9 -9
  70. package/app/components/02.molecules/qr-code/CONSUMER-STYLING.md +22 -7
  71. package/app/components/02.molecules/qr-code/CaptureQrCode.vue +63 -71
  72. package/app/components/02.molecules/qr-code/DecodeQrCode.vue +47 -10
  73. package/app/components/02.molecules/qr-code/stories/CaptureQrCode.stories.ts +114 -26
  74. package/app/components/02.molecules/qr-code/stories/DecodeQrCode.stories.ts +115 -24
  75. package/app/components/02.molecules/qr-code/tests/CaptureQrCode.spec.ts +124 -51
  76. package/app/components/02.molecules/qr-code/tests/DecodeQrCode.spec.ts +74 -25
  77. package/app/components/02.molecules/samaritan-prompt/CONSUMER-STYLING.md +22 -10
  78. package/app/components/02.molecules/samaritan-prompt/SamaritanPrompt.vue +30 -12
  79. package/app/components/02.molecules/samaritan-prompt/SamaritanPromptMixed.vue +34 -10
  80. package/app/components/02.molecules/samaritan-prompt/stories/SamaritanPrompt.stories.ts +55 -4
  81. package/app/components/02.molecules/samaritan-prompt/stories/SamaritanPromptMixed.stories.ts +67 -7
  82. package/app/components/02.molecules/samaritan-prompt/tests/SamaritanPrompt.spec.ts +113 -29
  83. package/app/components/02.molecules/samaritan-prompt/tests/SamaritanPromptMixed.spec.ts +92 -45
  84. package/app/components/03.organisms/image-galleries/carousel-flip/CONSUMER-STYLING.md +82 -29
  85. package/app/components/03.organisms/image-galleries/carousel-flip/CarouselFlip.vue +176 -113
  86. package/app/components/03.organisms/image-galleries/carousel-flip/stories/CarouselFlip.stories.ts +153 -23
  87. package/app/components/03.organisms/image-galleries/carousel-flip/tests/CarouselFlip.spec.ts +119 -63
  88. package/app/components/03.organisms/services/service-detail/tests/ServiceDetail.spec.ts +8 -8
  89. package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +4 -4
  90. package/app/components/03.organisms/site-header/CONSUMER-STYLING.md +41 -23
  91. package/app/components/03.organisms/site-header/SiteHeader.vue +16 -21
  92. package/app/components/03.organisms/site-header/stories/SiteHeader.stories.ts +138 -0
  93. package/app/components/03.organisms/site-header/tests/SiteHeader.spec.ts +53 -26
  94. package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +2 -2
  95. package/app/types/components/qr-code.d.ts +12 -0
  96. package/app/utils/graphemes.ts +8 -0
  97. package/package.json +1 -1
  98. package/app/components/01.atoms/animations/entry/.nuxt/app.config.mjs +0 -21
  99. package/app/components/01.atoms/animations/entry/.nuxt/components.d.ts +0 -66
  100. package/app/components/01.atoms/animations/entry/.nuxt/imports.d.ts +0 -30
  101. package/app/components/01.atoms/animations/entry/.nuxt/manifest/meta/test.json +0 -1
  102. package/app/components/01.atoms/animations/entry/.nuxt/types/app.config.d.ts +0 -35
  103. package/app/components/01.atoms/animations/entry/.nuxt/types/build.d.ts +0 -23
  104. package/app/components/01.atoms/animations/entry/.nuxt/types/builder-env.d.ts +0 -1
  105. package/app/components/01.atoms/animations/entry/.nuxt/types/components.d.ts +0 -71
  106. package/app/components/01.atoms/animations/entry/.nuxt/types/imports.d.ts +0 -386
  107. package/app/components/01.atoms/animations/entry/.nuxt/types/middleware.d.ts +0 -11
  108. package/app/components/01.atoms/animations/entry/.nuxt/types/modules.d.ts +0 -79
  109. package/app/components/01.atoms/animations/entry/.nuxt/types/nitro-layouts.d.ts +0 -17
  110. package/app/components/01.atoms/animations/entry/.nuxt/types/nitro-nuxt.d.ts +0 -64
  111. package/app/components/01.atoms/animations/entry/.nuxt/types/plugins.d.ts +0 -29
  112. package/app/components/01.atoms/animations/entry/.nuxt/types/runtime-config.d.ts +0 -32
  113. package/app/components/01.atoms/animations/entry/.nuxt/types/shared-imports.d.ts +0 -10
  114. package/app/components/01.atoms/animations/entry/.nuxt/types/vue-shim.d.ts +0 -0
  115. package/app/components/01.atoms/animations/entry/.nuxtrc +0 -1
  116. package/app/components/01.atoms/animations/entry/node_modules/.cache/nuxt/chrome-workspace.json +0 -1
  117. package/app/components/01.atoms/animations/entry/node_modules/.cache/vite/client/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  118. package/app/components/03.organisms/responsive-header/tests/.nuxt/app.config.mjs +0 -21
  119. package/app/components/03.organisms/responsive-header/tests/.nuxt/components.d.ts +0 -66
  120. package/app/components/03.organisms/responsive-header/tests/.nuxt/imports.d.ts +0 -30
  121. package/app/components/03.organisms/responsive-header/tests/.nuxt/manifest/meta/test.json +0 -1
  122. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/app.config.d.ts +0 -35
  123. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/build.d.ts +0 -23
  124. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/builder-env.d.ts +0 -1
  125. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/components.d.ts +0 -71
  126. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/imports.d.ts +0 -386
  127. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/middleware.d.ts +0 -11
  128. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/modules.d.ts +0 -79
  129. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/nitro-layouts.d.ts +0 -17
  130. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/nitro-nuxt.d.ts +0 -64
  131. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/plugins.d.ts +0 -29
  132. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/runtime-config.d.ts +0 -32
  133. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/shared-imports.d.ts +0 -10
  134. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/vue-shim.d.ts +0 -0
  135. package/app/components/03.organisms/responsive-header/tests/node_modules/.cache/nuxt/chrome-workspace.json +0 -1
@@ -17,49 +17,62 @@ const defaultNavLinks: ResponsiveHeaderNavItem[] = [
17
17
  { name: "Contact", path: "/contact" },
18
18
  ];
19
19
 
20
+ const mounted: Awaited<ReturnType<typeof mountSuspended>>[] = [];
21
+
22
+ const mountMenu = async (options: { props?: Record<string, unknown>; attachTo?: HTMLElement } = {}) => {
23
+ const wrapper = await mountSuspended(DeepExpandingMenu, options);
24
+ mounted.push(wrapper);
25
+ return wrapper;
26
+ };
27
+
28
+ afterEach(() => {
29
+ mounted.splice(0).forEach((wrapper) => wrapper.unmount());
30
+ vi.restoreAllMocks();
31
+ });
32
+
20
33
  describe("DeepExpandingMenu", () => {
21
34
  it("mounts without error", async () => {
22
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
35
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
23
36
  expect(wrapper.vm).toBeTruthy();
24
37
  });
25
38
 
26
39
  it("renders correct HTML structure", async () => {
27
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
40
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
28
41
  expect(wrapper.html()).toMatchSnapshot();
29
42
  });
30
43
 
31
44
  it("renders a <nav> by default", async () => {
32
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
45
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
33
46
  expect(wrapper.element.tagName.toLowerCase()).toBe("nav");
34
47
  });
35
48
 
36
49
  it("renders the given tag", async () => {
37
- const wrapper = await mountSuspended(DeepExpandingMenu, {
50
+ const wrapper = await mountMenu({
38
51
  props: { navLinks: defaultNavLinks, tag: "div" },
39
52
  });
40
53
  expect(wrapper.element.tagName.toLowerCase()).toBe("div");
41
54
  });
42
55
 
43
56
  it("renders a direct link for items with a path", async () => {
44
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
45
- const links = wrapper.findAll(".navigation-link");
57
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
58
+ const links = wrapper.findAll(".deep-expanding-menu-link");
46
59
  expect(links.map((l) => l.text())).toEqual(["Home", "Contact"]);
47
60
  });
48
61
 
49
62
  it("renders a toggle group for items with childLinks", async () => {
50
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
51
- expect(wrapper.find(".navigation-group-toggle").text()).toContain("Services");
63
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
64
+ expect(wrapper.find(".deep-expanding-menu-group-toggle").text()).toContain("Services");
52
65
  });
53
66
 
54
67
  it("renders each child link inside the group panel", async () => {
55
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
56
- const childLinks = wrapper.findAll(".navigation-group-link");
68
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
69
+ const childLinks = wrapper.findAll(".deep-expanding-menu-group-link");
57
70
  expect(childLinks.map((l) => l.text())).toEqual(["Haircuts", "Colouring"]);
58
71
  });
59
72
 
60
73
  it("renders the childLinksTitle heading", async () => {
61
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
62
- expect(wrapper.find(".navigation-group-panel h4").text()).toBe("Our services");
74
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
75
+ expect(wrapper.find(".deep-expanding-menu-group-heading").text()).toBe("Our services");
63
76
  });
64
77
 
65
78
  it("gives each group toggle a unique popovertarget", async () => {
@@ -67,21 +80,21 @@ describe("DeepExpandingMenu", () => {
67
80
  { name: "A", childLinksTitle: "A", childLinks: [{ name: "A1", path: "/a1" }] },
68
81
  { name: "B", childLinksTitle: "B", childLinks: [{ name: "B1", path: "/b1" }] },
69
82
  ];
70
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks } });
71
- const toggles = wrapper.findAll(".navigation-group-toggle");
83
+ const wrapper = await mountMenu({ props: { navLinks } });
84
+ const toggles = wrapper.findAll(".deep-expanding-menu-group-toggle");
72
85
  const targets = toggles.map((t) => t.attributes("popovertarget"));
73
86
  expect(new Set(targets).size).toBe(2);
74
87
  });
75
88
 
76
89
  it("applies styleClassPassthrough classes", async () => {
77
- const wrapper = await mountSuspended(DeepExpandingMenu, {
90
+ const wrapper = await mountMenu({
78
91
  props: { navLinks: defaultNavLinks, styleClassPassthrough: ["custom-class"] },
79
92
  });
80
93
  expect(wrapper.classes()).toContain("custom-class");
81
94
  });
82
95
 
83
96
  it("resets classes when styleClassPassthrough prop changes", async () => {
84
- const wrapper = await mountSuspended(DeepExpandingMenu, {
97
+ const wrapper = await mountMenu({
85
98
  props: { navLinks: defaultNavLinks, styleClassPassthrough: ["initial-class"] },
86
99
  });
87
100
  expect(wrapper.classes()).toContain("initial-class");
@@ -91,9 +104,60 @@ describe("DeepExpandingMenu", () => {
91
104
  expect(wrapper.classes()).toContain("updated-class");
92
105
  });
93
106
 
107
+ it("labels the root when ariaLabel is set, and leaves it unlabelled otherwise", async () => {
108
+ const unlabelled = await mountMenu({ props: { navLinks: defaultNavLinks } });
109
+ expect(unlabelled.attributes("aria-label")).toBeUndefined();
110
+
111
+ const labelled = await mountMenu({
112
+ props: { navLinks: defaultNavLinks, ariaLabel: "Main" },
113
+ });
114
+ expect(labelled.attributes("aria-label")).toBe("Main");
115
+ });
116
+
117
+ it("gives the child link list a list role", async () => {
118
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
119
+ expect(wrapper.find(".deep-expanding-menu-group-list").attributes("role")).toBe("list");
120
+ });
121
+
122
+ it("omits the heading when childLinksTitle is missing or empty", async () => {
123
+ const navLinks: ResponsiveHeaderNavItem[] = [
124
+ { name: "A", childLinks: [{ name: "A1", path: "/a1" }] },
125
+ { name: "B", childLinksTitle: "", childLinks: [{ name: "B1", path: "/b1" }] },
126
+ ];
127
+ const wrapper = await mountMenu({ props: { navLinks } });
128
+ expect(wrapper.find(".deep-expanding-menu-group-heading").exists()).toBe(false);
129
+ });
130
+
131
+ it("omits the list when a group has no child links", async () => {
132
+ const navLinks: ResponsiveHeaderNavItem[] = [{ name: "Empty", childLinksTitle: "Empty", childLinks: [] }];
133
+ const wrapper = await mountMenu({ props: { navLinks } });
134
+ expect(wrapper.find(".deep-expanding-menu-group-list").exists()).toBe(false);
135
+ });
136
+
137
+ it("keeps child links with duplicate names in step when the list is reordered", async () => {
138
+ const childLinks = [
139
+ { name: "Same", path: "/one" },
140
+ { name: "Same", path: "/two" },
141
+ { name: "Other", path: "/three" },
142
+ ];
143
+ const wrapper = await mountMenu({
144
+ props: { navLinks: [{ name: "Group", childLinksTitle: "Group", childLinks }] },
145
+ });
146
+ await wrapper.setProps({
147
+ navLinks: [{ name: "Group", childLinksTitle: "Group", childLinks: [childLinks[2]!, childLinks[0]!] }],
148
+ });
149
+ const links = wrapper.findAll(".deep-expanding-menu-group-link");
150
+ expect(links.map((l) => l.attributes("href"))).toEqual(["/three", "/one"]);
151
+ });
152
+
153
+ it("hides the caret icon from assistive technology", async () => {
154
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
155
+ expect(wrapper.find(".deep-expanding-menu-group-icon").attributes("aria-hidden")).toBe("true");
156
+ });
157
+
94
158
  it("doesn't give the link panels a menu role", async () => {
95
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: defaultNavLinks } });
96
- expect(wrapper.find(".navigation-group-panel").attributes("role")).toBeUndefined();
159
+ const wrapper = await mountMenu({ props: { navLinks: defaultNavLinks } });
160
+ expect(wrapper.find(".deep-expanding-menu-group-panel").attributes("role")).toBeUndefined();
97
161
  });
98
162
 
99
163
  describe("open state", () => {
@@ -116,9 +180,9 @@ describe("DeepExpandingMenu", () => {
116
180
  });
117
181
 
118
182
  it("tracks the open group from toggle events, whichever order they arrive in", async () => {
119
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: twoGroups } });
120
- const [first, second] = wrapper.findAll(".navigation-group-panel");
121
- const toggles = wrapper.findAll(".navigation-group-toggle");
183
+ const wrapper = await mountMenu({ props: { navLinks: twoGroups } });
184
+ const [first, second] = wrapper.findAll(".deep-expanding-menu-group-panel");
185
+ const toggles = wrapper.findAll(".deep-expanding-menu-group-toggle");
122
186
 
123
187
  first!.element.dispatchEvent(toggleEvent("open"));
124
188
  await nextTick();
@@ -142,9 +206,9 @@ describe("DeepExpandingMenu", () => {
142
206
  });
143
207
 
144
208
  it("opens, switches and closes groups from their toggles", async () => {
145
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: twoGroups } });
146
- const toggles = wrapper.findAll(".navigation-group-toggle");
147
- const panels = wrapper.findAll(".navigation-group-panel");
209
+ const wrapper = await mountMenu({ props: { navLinks: twoGroups } });
210
+ const toggles = wrapper.findAll(".deep-expanding-menu-group-toggle");
211
+ const panels = wrapper.findAll(".deep-expanding-menu-group-panel");
148
212
 
149
213
  await toggles[0]!.trigger("click");
150
214
  expect(panels[0]!.classes()).toContain("deep-expanding-menu-panel-open");
@@ -160,14 +224,13 @@ describe("DeepExpandingMenu", () => {
160
224
  });
161
225
 
162
226
  it("closes the open group on Escape", async () => {
163
- const wrapper = await mountSuspended(DeepExpandingMenu, { props: { navLinks: twoGroups }, attachTo: document.body });
164
- await wrapper.findAll(".navigation-group-toggle")[0]!.trigger("click");
227
+ const wrapper = await mountMenu({ props: { navLinks: twoGroups }, attachTo: document.body });
228
+ await wrapper.findAll(".deep-expanding-menu-group-toggle")[0]!.trigger("click");
165
229
  await nextTick();
166
230
 
167
231
  document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
168
232
  await nextTick();
169
233
  expect(wrapper.find(".deep-expanding-menu-panel-open").exists()).toBe(false);
170
- wrapper.unmount();
171
234
  });
172
235
  });
173
236
  });
@@ -2,16 +2,16 @@
2
2
 
3
3
  exports[`DeepExpandingMenu > renders correct HTML structure 1`] = `
4
4
  "<nav class="deep-expanding-menu">
5
- <div class="inner"><a href="/" class="navigation-link">Home</a>
6
- <div class="navigation-group" style="--_anchor-name: --anchor-v-0-0-1;"><button type="button" popovertarget="popovertarget-v-0-0-1" class="navigation-group-toggle" aria-expanded="false"><span>Services</span><span class="iconify i-bi:caret-down-fill icon" aria-hidden="true"></span></button>
7
- <div id="popovertarget-v-0-0-1" class="navigation-group-panel" popover="">
8
- <h4 class="page-heading-4 mb-6">Our services</h4>
9
- <ul class="navigation-group-list">
10
- <li class="navigation-group-item"><a href="/services/haircuts" class="navigation-group-link">Haircuts</a></li>
11
- <li class="navigation-group-item"><a href="/services/colouring" class="navigation-group-link">Colouring</a></li>
5
+ <div class="deep-expanding-menu-inner"><a href="/" class="deep-expanding-menu-link">Home</a>
6
+ <div class="deep-expanding-menu-group" style="--_anchor-name: --anchor-v-0-0-1;"><button type="button" popovertarget="popovertarget-v-0-0-1" class="deep-expanding-menu-group-toggle" aria-expanded="false"><span class="deep-expanding-menu-group-label">Services</span><span class="iconify i-bi:caret-down-fill deep-expanding-menu-group-icon" aria-hidden="true"></span></button>
7
+ <div id="popovertarget-v-0-0-1" class="deep-expanding-menu-group-panel" popover="">
8
+ <h4 class="deep-expanding-menu-group-heading page-heading-4 mb-6">Our services</h4>
9
+ <ul class="deep-expanding-menu-group-list" role="list">
10
+ <li class="deep-expanding-menu-group-item"><a href="/services/haircuts" class="deep-expanding-menu-group-link">Haircuts</a></li>
11
+ <li class="deep-expanding-menu-group-item"><a href="/services/colouring" class="deep-expanding-menu-group-link">Colouring</a></li>
12
12
  </ul>
13
13
  </div>
14
- </div><a href="/contact" class="navigation-link">Contact</a>
14
+ </div><a href="/contact" class="deep-expanding-menu-link">Contact</a>
15
15
  </div>
16
16
  </nav>"
17
17
  `;
@@ -2,44 +2,72 @@
2
2
 
3
3
  ## Public token API
4
4
 
5
+ > Changed 2026-10-21: colour defaults now come from `--theme-*` tokens (were `--blue-10`, `white`,
6
+ > `black`, `--slate-10`), `--deep-expanding-menu-classic-panel-offset-top` defaults to
7
+ > `calc(100% + 1rem)` (was `4rem`, which overlapped a wrapped toggle label), the panel widths switch
8
+ > on the menu's own width instead of the viewport, and `--deep-expanding-menu-classic-gap` was
9
+ > removed (the root grid has one area, so it never did anything).
10
+
11
+ ### Top-level row
12
+
5
13
  | Token | Default | Controls |
6
14
  |---|---|---|
7
- | `--deep-expanding-menu-classic-gap` | `1.2rem` | Gap on the root grid |
8
- | `--deep-expanding-menu-classic-item-gap` | `2.4rem` | Gap between top-level items |
9
- | `--deep-expanding-menu-classic-link-border-width` | `0.2rem` | Bottom border width on links and group toggles |
15
+ | `--deep-expanding-menu-classic-item-gap` | `2.4rem` | Gap between top-level items (row and column, the row wraps) |
16
+ | `--deep-expanding-menu-classic-link-border-width` | `0.2rem` | Bottom border width on links, group toggles and child links |
10
17
  | `--deep-expanding-menu-classic-link-padding-block` | `0.8rem` | Vertical padding on links and group toggles |
11
- | `--deep-expanding-menu-classic-link-border-colour-hover` | `var(--blue-10)` | Bottom border colour on hover/focus |
18
+ | `--deep-expanding-menu-classic-link-border-colour-hover` | `var(--theme-border)` | Bottom border colour on hover/focus |
19
+ | `--deep-expanding-menu-classic-focus-outline-width` | `0.2rem` | Keyboard focus ring width on links and toggles |
20
+ | `--deep-expanding-menu-classic-focus-outline-colour` | `var(--theme-ring, currentcolor)` | Keyboard focus ring colour |
12
21
  | `--deep-expanding-menu-classic-icon-size` | `1.2rem` | Caret icon size |
13
- | `--deep-expanding-menu-classic-panel-offset-top` | `4rem` | Panel offset from the toggle |
14
- | `--deep-expanding-menu-classic-panel-width` | `20rem` | Panel width below the `768px` breakpoint |
15
- | `--deep-expanding-menu-classic-panel-width-tablet` | `40rem` | Panel width from `768px` |
16
- | `--deep-expanding-menu-classic-panel-width-desktop` | `60rem` | Panel width from `1024px` |
17
- | `--deep-expanding-menu-classic-panel-background-colour` | `white` | Panel background |
22
+
23
+ ### Panel
24
+
25
+ | Token | Default | Controls |
26
+ |---|---|---|
27
+ | `--deep-expanding-menu-classic-panel-offset-top` | `calc(100% + 1rem)` | Panel offset from the top of its group |
28
+ | `--deep-expanding-menu-classic-panel-width` | `20rem` | Panel width while the menu is under `768px` wide |
29
+ | `--deep-expanding-menu-classic-panel-width-tablet` | `40rem` | Panel width once the menu is `768px` wide |
30
+ | `--deep-expanding-menu-classic-panel-width-desktop` | `60rem` | Panel width once the menu is `1024px` wide |
31
+ | `--deep-expanding-menu-classic-panel-text-colour` | `var(--theme-text)` | Panel text colour |
32
+ | `--deep-expanding-menu-classic-panel-background-colour` | `var(--theme-surface-subtle)` | Panel background |
18
33
  | `--deep-expanding-menu-classic-panel-border-width` | `0.1rem` | Panel border width |
19
- | `--deep-expanding-menu-classic-panel-border-colour` | `black` | Panel border colour |
34
+ | `--deep-expanding-menu-classic-panel-border-colour` | `var(--theme-border)` | Panel border colour |
20
35
  | `--deep-expanding-menu-classic-panel-border-radius` | `1.2rem` | Panel corner radius |
21
36
  | `--deep-expanding-menu-classic-panel-shadow` | `0 0 1rem rgba(0, 0, 0, 0.1)` | Panel box-shadow |
22
37
  | `--deep-expanding-menu-classic-panel-padding` | `1.2rem` | Panel padding |
23
- | `--deep-expanding-menu-classic-panel-heading-colour` | `var(--slate-10)` | `childLinksTitle` heading colour inside the panel |
24
- | `--deep-expanding-menu-classic-panel-list-gap` | `1.2rem` | Gap between child link grid items |
25
- | `--deep-expanding-menu-classic-group-link-colour` | `var(--slate-10)` | Child link text colour |
26
- | `--deep-expanding-menu-classic-group-link-border-colour-hover` | `var(--slate-10)` | Child link bottom border colour on hover/focus |
38
+ | `--deep-expanding-menu-classic-panel-heading-colour` | `var(--theme-text)` | `childLinksTitle` heading colour |
39
+ | `--deep-expanding-menu-classic-panel-heading-line-clamp` | `none` | Lines of `childLinksTitle` before an ellipsis. `1` is single-line ellipsis, `none` shows everything |
40
+ | `--deep-expanding-menu-classic-panel-list-gap` | `1.2rem` | Gap between the panel's heading and list, and between child link grid items |
41
+ | `--deep-expanding-menu-classic-group-link-colour` | `var(--theme-text)` | Child link text colour |
42
+ | `--deep-expanding-menu-classic-group-link-border-colour-hover` | `var(--theme-text)` | Child link bottom border colour on hover/focus |
43
+
44
+ Each panel width is capped at the menu's own width (`min(<token>, 100cqi)`). Private tokens (not
45
+ public API): `--_icon-transform` (caret flip).
46
+
47
+ ## State hooks
27
48
 
28
- ```css
29
- .my-page {
30
- --deep-expanding-menu-classic-panel-background-colour: #1a1a1a;
31
- --deep-expanding-menu-classic-panel-border-colour: transparent;
32
- --deep-expanding-menu-classic-group-link-colour: white;
33
- }
34
- ```
49
+ | Hook | Meaning |
50
+ |---|---|
51
+ | `.deep-expanding-menu-classic-group[open]` | Group open (flips the caret) |
35
52
 
36
- Or scope to a single instance via `styleClassPassthrough`:
53
+ Inner elements: `.deep-expanding-menu-classic-inner` (the flex row),
54
+ `.deep-expanding-menu-classic-link` (direct link), `.deep-expanding-menu-classic-group` (the
55
+ `<details>`), `.deep-expanding-menu-classic-group-toggle` (the `<summary>`),
56
+ `.deep-expanding-menu-classic-group-label`, `.deep-expanding-menu-classic-group-icon`,
57
+ `.deep-expanding-menu-classic-group-panel`, `.deep-expanding-menu-classic-group-heading`,
58
+ `.deep-expanding-menu-classic-group-list`, `.deep-expanding-menu-classic-group-item`,
59
+ `.deep-expanding-menu-classic-group-link`.
37
60
 
38
- ```vue
39
- <DeepExpandingMenuClassic style-class-passthrough="main-nav">...</DeepExpandingMenuClassic>
40
- ```
61
+ > Changed 2026-10-21: these were `.inner`, `.navigation-link`, `.navigation-group`,
62
+ > `.navigation-group-toggle`, `.icon`, `.navigation-group-panel`, `.navigation-group-list`,
63
+ > `.navigation-group-item` and `.navigation-group-link`. The heading had no class of its own.
41
64
 
42
- ---
65
+ ## Sizing model
66
+
67
+ The root is an inline-size container named `deep-expanding-menu-classic`, so it can't size itself
68
+ from its content: give it a width from its parent (it fills a block or grid cell by default). A
69
+ panel opens from its toggle's left edge, so a group near the menu's right edge can still overrun it
70
+ by up to the panel's width; `DeepExpandingMenu` flips its panel instead.
43
71
 
44
72
  ## Local overrides
45
73
 
@@ -49,3 +77,7 @@ Set the tokens above on an element you own (a page or section class, or a class
49
77
  `<style scoped>`, tokens set on your element still work, but selectors that reach inside the component need
50
78
  `:deep()`. Patterns and examples: `.claude/skills/component-local-style-override.md`.
51
79
 
80
+ ## Class passthrough
81
+
82
+ `style-class-passthrough` adds classes to the root element (the `<nav>` by default). It's the
83
+ usual place to scope token overrides to one instance.
@@ -1,18 +1,34 @@
1
1
  <template>
2
- <component :is="tag" class="deep-expanding-menu-classic" :class="[elementClasses]">
3
- <div class="inner">
2
+ <component
3
+ :is="tag"
4
+ ref="rootRef"
5
+ class="deep-expanding-menu-classic"
6
+ :class="[elementClasses]"
7
+ :aria-label="ariaLabel"
8
+ @click="closeOtherGroups"
9
+ @keydown.esc="closeOnEscape"
10
+ >
11
+ <div class="deep-expanding-menu-classic-inner">
4
12
  <template v-for="(link, key) in navLinks" :key="key">
5
- <NuxtLink v-if="link.path" :to="link.path" class="navigation-link">{{ link.name }}</NuxtLink>
6
- <details v-else ref="navigationGroupRef" class="navigation-group" name="navigation-group">
7
- <summary class="navigation-group-toggle">
8
- <span>{{ link.name }}</span>
9
- <Icon name="bi:caret-down-fill" class="icon" />
13
+ <NuxtLink v-if="link.path" :to="link.path" class="deep-expanding-menu-classic-link">{{ link.name }}</NuxtLink>
14
+ <details v-else class="deep-expanding-menu-classic-group" :name="groupName">
15
+ <summary class="deep-expanding-menu-classic-group-toggle">
16
+ <span class="deep-expanding-menu-classic-group-label">{{ link.name }}</span>
17
+ <Icon name="bi:caret-down-fill" class="deep-expanding-menu-classic-group-icon" aria-hidden="true" />
10
18
  </summary>
11
- <div class="navigation-group-panel">
12
- <h4 class="page-heading-4 mb-6">{{ link.childLinksTitle }}</h4>
13
- <ul class="navigation-group-list">
14
- <li v-for="childLink in link.childLinks" :key="childLink.name" class="navigation-group-item">
15
- <NuxtLink :to="childLink.path" class="navigation-group-link">{{ childLink.name }}</NuxtLink>
19
+ <div class="deep-expanding-menu-classic-group-panel">
20
+ <h4 v-if="link.childLinksTitle" class="deep-expanding-menu-classic-group-heading page-heading-4 mb-6">
21
+ {{ link.childLinksTitle }}
22
+ </h4>
23
+ <ul v-if="link.childLinks?.length" class="deep-expanding-menu-classic-group-list" role="list">
24
+ <li
25
+ v-for="(childLink, childIndex) in link.childLinks"
26
+ :key="`${childIndex}-${childLink.name}`"
27
+ class="deep-expanding-menu-classic-group-item"
28
+ >
29
+ <NuxtLink :to="childLink.path" class="deep-expanding-menu-classic-group-link">
30
+ {{ childLink.name }}
31
+ </NuxtLink>
16
32
  </li>
17
33
  </ul>
18
34
  </div>
@@ -27,20 +43,48 @@ import { onClickOutside } from "@vueuse/core";
27
43
  import type { ResponsiveHeaderNavItem } from "~/types/components";
28
44
 
29
45
  interface Props {
30
- tag?: "div" | "section" | "nav" | "ul" | "ol";
46
+ tag?: "div" | "section" | "nav";
31
47
  navLinks?: ResponsiveHeaderNavItem[];
48
+ ariaLabel?: string;
32
49
  styleClassPassthrough?: string | string[];
33
50
  }
34
51
 
35
52
  const props = withDefaults(defineProps<Props>(), {
36
53
  tag: "nav",
37
54
  navLinks: () => [],
55
+ ariaLabel: undefined,
38
56
  styleClassPassthrough: () => [],
39
57
  });
40
58
 
41
59
  const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
42
60
 
43
- const navigationGroupRef = useTemplateRef<HTMLElement[]>("navigationGroupRef");
61
+ // Per-instance so groups are exclusive within one menu but not across menus.
62
+ const groupName = `deep-expanding-menu-classic-${useId()}`;
63
+
64
+ const rootRef = ref<HTMLElement | null>(null);
65
+
66
+ const openGroups = () =>
67
+ Array.from(rootRef.value?.querySelectorAll<HTMLDetailsElement>("details[open]") ?? []);
68
+
69
+ const closeOtherGroups = (event: Event) => {
70
+ const target = event.target as Element | null;
71
+ const followedLink = !!target?.closest?.("a");
72
+ openGroups().forEach((group) => {
73
+ if (followedLink || !target || !group.contains(target)) group.open = false;
74
+ });
75
+ };
76
+
77
+ const closeOnEscape = (event: KeyboardEvent) => {
78
+ const target = event.target as Node | null;
79
+ const group = openGroups().find((details) => target && details.contains(target));
80
+ if (!group) return;
81
+ group.open = false;
82
+ group.querySelector<HTMLElement>("summary")?.focus();
83
+ };
84
+
85
+ onClickOutside(rootRef, () => {
86
+ openGroups().forEach((group) => (group.open = false));
87
+ });
44
88
 
45
89
  watch(
46
90
  () => props.styleClassPassthrough,
@@ -48,36 +92,31 @@ watch(
48
92
  resetElementClasses(props.styleClassPassthrough);
49
93
  }
50
94
  );
51
-
52
- onMounted(() => {
53
- navigationGroupRef.value?.forEach((element, index) => {
54
- onClickOutside(element, () => {
55
- navigationGroupRef.value?.[index]?.removeAttribute("open");
56
- });
57
- });
58
- });
59
95
  </script>
60
96
 
61
97
  <style lang="css">
62
98
  @layer components {
63
99
  @layer popover-setup {
64
100
  .deep-expanding-menu-classic {
65
- container-type: inline-size;
101
+ container: deep-expanding-menu-classic / inline-size;
66
102
  display: grid;
67
103
  grid-template-areas: "element-stack";
68
104
  align-items: center;
69
- gap: var(--deep-expanding-menu-classic-gap, 1.2rem);
70
105
 
71
- .inner {
106
+ .deep-expanding-menu-classic-inner {
72
107
  grid-area: element-stack;
73
108
  display: flex;
109
+ flex-wrap: wrap;
74
110
  gap: var(--deep-expanding-menu-classic-item-gap, 2.4rem);
75
111
  align-items: center;
112
+ min-inline-size: 0;
76
113
  z-index: 1;
77
114
 
78
- .navigation-link,
79
- .navigation-group-toggle {
115
+ .deep-expanding-menu-classic-link,
116
+ .deep-expanding-menu-classic-group-toggle {
80
117
  all: unset;
118
+ min-inline-size: 0;
119
+ overflow-wrap: anywhere;
81
120
  border-bottom: var(--deep-expanding-menu-classic-link-border-width, 0.2rem) solid transparent;
82
121
  padding-block: var(--deep-expanding-menu-classic-link-padding-block, 0.8rem);
83
122
 
@@ -87,18 +126,22 @@ onMounted(() => {
87
126
  &:focus,
88
127
  &:focus-visible {
89
128
  cursor: pointer;
90
- border-color: var(
91
- --deep-expanding-menu-classic-link-border-colour-hover,
92
- var(--blue-10)
93
- );
129
+ border-color: var(--deep-expanding-menu-classic-link-border-colour-hover, var(--theme-border));
130
+ }
131
+
132
+ &:focus-visible {
133
+ outline: var(--deep-expanding-menu-classic-focus-outline-width, 0.2rem) solid
134
+ var(--deep-expanding-menu-classic-focus-outline-colour, var(--theme-ring, currentcolor));
135
+ outline-offset: 0.2rem;
94
136
  }
95
137
  }
96
138
 
97
- .navigation-group {
139
+ .deep-expanding-menu-classic-group {
98
140
  --_icon-transform: scaleY(1);
99
141
 
100
142
  display: grid;
101
143
  grid-template-areas: "details-stack";
144
+ min-inline-size: 0;
102
145
  z-index: 1;
103
146
  position: relative;
104
147
 
@@ -111,16 +154,21 @@ onMounted(() => {
111
154
  --_icon-transform: scaleY(-1);
112
155
  }
113
156
 
114
- .navigation-group-toggle {
157
+ .deep-expanding-menu-classic-group-toggle {
115
158
  grid-area: details-stack;
116
159
 
117
- display: flex !important;
160
+ display: flex;
118
161
  align-items: center;
119
162
  gap: 1.2rem;
120
163
  list-style: none;
121
164
 
122
- .icon {
165
+ .deep-expanding-menu-classic-group-label {
166
+ min-inline-size: 0;
167
+ }
168
+
169
+ .deep-expanding-menu-classic-group-icon {
123
170
  display: block;
171
+ flex-shrink: 0;
124
172
  font-size: var(--deep-expanding-menu-classic-icon-size, 1.2rem);
125
173
 
126
174
  transform: var(--_icon-transform);
@@ -128,51 +176,62 @@ onMounted(() => {
128
176
  }
129
177
  }
130
178
 
131
- .navigation-group-panel {
179
+ .deep-expanding-menu-classic-group-panel {
132
180
  display: grid;
133
181
  grid-area: details-stack;
134
182
  z-index: 2;
135
183
  position: absolute;
136
184
  inset: auto;
137
- top: var(--deep-expanding-menu-classic-panel-offset-top, 4rem);
138
- left: 0rem;
185
+ top: var(--deep-expanding-menu-classic-panel-offset-top, calc(100% + 1rem));
186
+ left: 0;
139
187
  gap: var(--deep-expanding-menu-classic-panel-list-gap, 1.2rem);
140
188
 
141
- width: var(--deep-expanding-menu-classic-panel-width, 20rem);
189
+ width: min(var(--deep-expanding-menu-classic-panel-width, 20rem), 100cqi);
142
190
 
143
- @media screen and (min-width: 768px) {
144
- width: var(--deep-expanding-menu-classic-panel-width-tablet, 40rem);
191
+ @container deep-expanding-menu-classic (min-width: 768px) {
192
+ width: min(var(--deep-expanding-menu-classic-panel-width-tablet, 40rem), 100cqi);
145
193
  }
146
194
 
147
- @media screen and (min-width: 1024px) {
148
- width: var(--deep-expanding-menu-classic-panel-width-desktop, 60rem);
195
+ @container deep-expanding-menu-classic (min-width: 1024px) {
196
+ width: min(var(--deep-expanding-menu-classic-panel-width-desktop, 60rem), 100cqi);
149
197
  }
150
198
 
151
- background-color: var(--deep-expanding-menu-classic-panel-background-colour, white);
199
+ color: var(--deep-expanding-menu-classic-panel-text-colour, var(--theme-text));
200
+ background-color: var(--deep-expanding-menu-classic-panel-background-colour, var(--theme-surface-subtle));
152
201
  border: var(--deep-expanding-menu-classic-panel-border-width, 0.1rem) solid
153
- var(--deep-expanding-menu-classic-panel-border-colour, black);
202
+ var(--deep-expanding-menu-classic-panel-border-colour, var(--theme-border));
154
203
  border-radius: var(--deep-expanding-menu-classic-panel-border-radius, 1.2rem);
155
204
  box-shadow: var(--deep-expanding-menu-classic-panel-shadow, 0 0 1rem rgba(0, 0, 0, 0.1));
156
205
  padding: var(--deep-expanding-menu-classic-panel-padding, 1.2rem);
157
206
  overflow: clip;
158
207
 
159
- h4 {
160
- color: var(--deep-expanding-menu-classic-panel-heading-colour, var(--slate-10));
208
+ .deep-expanding-menu-classic-group-heading {
209
+ color: var(--deep-expanding-menu-classic-panel-heading-colour, var(--theme-text));
210
+ overflow-wrap: anywhere;
211
+ display: -webkit-box;
212
+ -webkit-box-orient: vertical;
213
+ overflow: hidden;
214
+ -webkit-line-clamp: var(--deep-expanding-menu-classic-panel-heading-line-clamp, none);
215
+ line-clamp: var(--deep-expanding-menu-classic-panel-heading-line-clamp, none);
161
216
  }
162
217
 
163
- .navigation-group-list {
218
+ .deep-expanding-menu-classic-group-list {
164
219
  display: grid;
165
- grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
220
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr));
166
221
  gap: var(--deep-expanding-menu-classic-panel-list-gap, 1.2rem);
222
+ list-style: none;
167
223
  padding-inline-start: 0;
168
- margin-block-end: 0.8rem;
224
+ margin-block: 0 0.8rem;
169
225
 
170
- .navigation-group-item {
226
+ .deep-expanding-menu-classic-group-item {
171
227
  display: block;
228
+ min-inline-size: 0;
172
229
 
173
- a.navigation-group-link {
230
+ a.deep-expanding-menu-classic-group-link {
174
231
  display: inline-block;
175
- color: var(--deep-expanding-menu-classic-group-link-colour, var(--slate-10));
232
+ max-inline-size: 100%;
233
+ overflow-wrap: anywhere;
234
+ color: var(--deep-expanding-menu-classic-group-link-colour, var(--theme-text));
176
235
  text-decoration: none;
177
236
  padding-block: 0.8rem;
178
237
 
@@ -183,10 +242,7 @@ onMounted(() => {
183
242
  &:hover,
184
243
  &:focus-visible {
185
244
  cursor: pointer;
186
- border-color: var(
187
- --deep-expanding-menu-classic-group-link-border-colour-hover,
188
- var(--slate-10)
189
- );
245
+ border-color: var(--deep-expanding-menu-classic-group-link-border-colour-hover, var(--theme-text));
190
246
  }
191
247
  }
192
248
  }