srcdev-nuxt-components 9.1.50 → 9.1.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +8 -27
- package/.claude/settings.local.json +24 -52
- package/.claude/skills/components/action-menu.md +141 -0
- package/.claude/skills/components/stepper-list.md +52 -18
- package/.claude/skills/css-nesting-conventions.md +121 -0
- package/.claude/skills/index.md +3 -0
- package/.claude/skills/pull-request-description.md +48 -0
- package/.claude/skills/testing-add-unit-test.md +40 -2
- package/README.md +26 -5
- package/app/components/02.molecules/action-menu/ActionMenu.vue +218 -0
- package/app/components/02.molecules/action-menu/ActionMenuItemCore.vue +123 -0
- package/app/components/02.molecules/action-menu/CONSUMER-STYLING.md +125 -0
- package/app/components/02.molecules/action-menu/stories/ActionMenu.stories.ts +326 -0
- package/app/components/02.molecules/action-menu/tests/ActionMenu.spec.ts +458 -0
- package/app/components/02.molecules/action-menu/tests/ActionMenuItemCore.spec.ts +199 -0
- package/app/components/02.molecules/action-menu/tests/__snapshots__/ActionMenu.spec.ts.snap +28 -0
- package/app/components/02.molecules/action-menu/tests/__snapshots__/ActionMenuItemCore.spec.ts.snap +27 -0
- package/app/components/02.molecules/display-chip/tests/DisplayChip.spec.ts +5 -1
- package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +2 -1
- package/app/components/02.molecules/stepper-list/CONSUMER-STYLING.md +138 -0
- package/app/components/02.molecules/stepper-list/StepperList.vue +50 -24
- package/app/components/03.organisms/image-galleries/slider-gallery/tests/SliderGallery.spec.ts +5 -1
- package/app/components/05.forms/input-button/InputButtonCore.vue +1 -1
- package/app/components/carousels/tests/CarouselFlip.spec.ts +1 -0
- package/app/components/responsive-header/NavigationItems.vue +302 -81
- package/app/components/responsive-header/ResponsiveHeader.vue +360 -56
- package/app/layouts/default.vue +43 -352
- package/app/layouts/site-navigation-demo.vue +36 -34
- package/app/pages/page-hero-highlights.vue +3 -3
- package/app/pages/ui/scroll-reveal-image.vue +3 -3
- package/app/pages/ui/simple-grid.vue +9 -20
- package/modules/colour-scheme.ts +1 -1
- package/nuxt.config.ts +11 -2
- package/package.json +17 -16
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="overflow-navigation-wrapper"
|
|
4
|
+
:class="[elementClasses, { 'is-panel-animating': isPanelAnimating }]"
|
|
5
|
+
role="menu"
|
|
6
|
+
aria-label="Overflow navigation menu"
|
|
7
|
+
@mouseleave="
|
|
8
|
+
hoveredItemKey = null;
|
|
9
|
+
hoveredChildKey = null;
|
|
10
|
+
"
|
|
11
|
+
>
|
|
3
12
|
<ul
|
|
4
13
|
v-for="(navGroup, groupKey) in mainNavigationState.clonedNavLinks"
|
|
5
14
|
:key="groupKey"
|
|
@@ -12,7 +21,11 @@
|
|
|
12
21
|
<li
|
|
13
22
|
v-if="link.path"
|
|
14
23
|
class="overflow-navigation-item"
|
|
15
|
-
:class="{
|
|
24
|
+
:class="{
|
|
25
|
+
visible: !mainNavigationState.clonedNavLinks?.[groupKey]?.[localIndex]?.config?.visible,
|
|
26
|
+
'is-hovered': hoveredItemKey === `${String(groupKey)}-${localIndex}`,
|
|
27
|
+
'is-active': isActiveNavItem(link),
|
|
28
|
+
}"
|
|
16
29
|
:style="{
|
|
17
30
|
'--_main-navigation-item-width':
|
|
18
31
|
mainNavigationState.clonedNavLinks?.[groupKey]?.[localIndex]?.config?.width + 'px',
|
|
@@ -20,6 +33,7 @@
|
|
|
20
33
|
:data-group-key="groupKey"
|
|
21
34
|
:data-local-index="localIndex"
|
|
22
35
|
role="none"
|
|
36
|
+
@mouseenter="hoveredItemKey = `${String(groupKey)}-${localIndex}`"
|
|
23
37
|
>
|
|
24
38
|
<NuxtLink class="overflow-navigation-link" :to="link.path" role="menuitem">
|
|
25
39
|
<span class="overflow-navigation-text">{{ link.name }}</span>
|
|
@@ -28,7 +42,11 @@
|
|
|
28
42
|
<li
|
|
29
43
|
v-else
|
|
30
44
|
class="overflow-navigation-item"
|
|
31
|
-
:class="{
|
|
45
|
+
:class="{
|
|
46
|
+
visible: !mainNavigationState.clonedNavLinks?.[groupKey]?.[localIndex]?.config?.visible,
|
|
47
|
+
'is-hovered': hoveredItemKey === `${String(groupKey)}-${localIndex}`,
|
|
48
|
+
'is-active': isActiveNavItem(link),
|
|
49
|
+
}"
|
|
32
50
|
:style="{
|
|
33
51
|
'--_main-navigation-item-width':
|
|
34
52
|
mainNavigationState.clonedNavLinks?.[groupKey]?.[localIndex]?.config?.width + 'px',
|
|
@@ -36,8 +54,10 @@
|
|
|
36
54
|
:data-group-key="groupKey"
|
|
37
55
|
:data-local-index="localIndex"
|
|
38
56
|
role="none"
|
|
57
|
+
@mouseenter="hoveredItemKey = `${String(groupKey)}-${localIndex}`"
|
|
39
58
|
>
|
|
40
59
|
<ExpandingPanel
|
|
60
|
+
v-model="panelOpenStates[`${String(groupKey)}-${localIndex}`]"
|
|
41
61
|
name="overflow-navigation-group"
|
|
42
62
|
:animation-duration="DETAILS_ANIMATION_DURATION"
|
|
43
63
|
icon-size="medium"
|
|
@@ -58,28 +78,36 @@
|
|
|
58
78
|
</template>
|
|
59
79
|
<template #content>
|
|
60
80
|
<div class="overflow-navigation-sub-nav-inner">
|
|
61
|
-
<ul class="overflow-navigation-sub-nav-list">
|
|
81
|
+
<ul class="overflow-navigation-sub-nav-list" @mouseleave="hoveredChildKey = null">
|
|
62
82
|
<li
|
|
63
|
-
v-for="childLink in link.childLinks"
|
|
83
|
+
v-for="(childLink, childIndex) in link.childLinks"
|
|
64
84
|
:key="childLink.name"
|
|
65
85
|
class="overflow-navigation-sub-nav-item"
|
|
86
|
+
:class="{
|
|
87
|
+
'is-hovered': hoveredChildKey === `${String(groupKey)}-${localIndex}-${childIndex}`,
|
|
88
|
+
'is-active': isActiveNavItem(childLink),
|
|
89
|
+
}"
|
|
90
|
+
@mouseenter="hoveredChildKey = `${String(groupKey)}-${localIndex}-${childIndex}`"
|
|
66
91
|
>
|
|
67
92
|
<NuxtLink :to="childLink.path" class="overflow-navigation-sub-nav-link" role="menuitem">
|
|
68
93
|
<span class="overflow-navigation-sub-nav-text">{{ childLink.name }}</span>
|
|
69
94
|
</NuxtLink>
|
|
70
95
|
</li>
|
|
71
96
|
</ul>
|
|
97
|
+
<div aria-hidden="true" class="overflow-sub-nav-indicator-hovered"></div>
|
|
72
98
|
</div>
|
|
73
99
|
</template>
|
|
74
100
|
</ExpandingPanel>
|
|
75
101
|
</li>
|
|
76
102
|
</template>
|
|
77
103
|
</ul>
|
|
104
|
+
<div aria-hidden="true" class="overflow-nav-indicator-hovered"></div>
|
|
105
|
+
<div aria-hidden="true" class="overflow-nav-indicator-active"></div>
|
|
78
106
|
</div>
|
|
79
107
|
</template>
|
|
80
108
|
|
|
81
109
|
<script setup lang="ts">
|
|
82
|
-
import type { ResponsiveHeaderState } from "../../types/components";
|
|
110
|
+
import type { ResponsiveHeaderState, ResponsiveHeaderNavItem } from "../../types/components";
|
|
83
111
|
|
|
84
112
|
interface Props {
|
|
85
113
|
mainNavigationState?: ResponsiveHeaderState;
|
|
@@ -91,8 +119,38 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
91
119
|
styleClassPassthrough: () => [],
|
|
92
120
|
});
|
|
93
121
|
|
|
94
|
-
|
|
122
|
+
const hoveredItemKey = ref<string | null>(null);
|
|
123
|
+
const hoveredChildKey = ref<string | null>(null);
|
|
124
|
+
|
|
95
125
|
const DETAILS_ANIMATION_DURATION = 200 as const;
|
|
126
|
+
|
|
127
|
+
const panelOpenStates = reactive<Record<string, boolean>>({});
|
|
128
|
+
const isPanelAnimating = ref(false);
|
|
129
|
+
let panelAnimationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
130
|
+
|
|
131
|
+
watch(
|
|
132
|
+
panelOpenStates,
|
|
133
|
+
() => {
|
|
134
|
+
isPanelAnimating.value = true;
|
|
135
|
+
if (panelAnimationTimer) clearTimeout(panelAnimationTimer);
|
|
136
|
+
panelAnimationTimer = setTimeout(() => {
|
|
137
|
+
isPanelAnimating.value = false;
|
|
138
|
+
}, DETAILS_ANIMATION_DURATION);
|
|
139
|
+
},
|
|
140
|
+
{ deep: true }
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
onUnmounted(() => {
|
|
144
|
+
if (panelAnimationTimer) clearTimeout(panelAnimationTimer);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const route = useRoute();
|
|
148
|
+
|
|
149
|
+
const isActiveNavItem = (link: ResponsiveHeaderNavItem): boolean => {
|
|
150
|
+
if (link.path) return route.path === link.path;
|
|
151
|
+
if (link.childLinks) return link.childLinks.some((child) => child.path && route.path === child.path);
|
|
152
|
+
return false;
|
|
153
|
+
};
|
|
96
154
|
// const DETAILS_ANIMATION_DURATION_STRING = `${DETAILS_ANIMATION_DURATION}ms` as const;
|
|
97
155
|
|
|
98
156
|
// Performance: Memoize expensive computed with proper dependencies
|
|
@@ -122,100 +180,120 @@ watch(
|
|
|
122
180
|
|
|
123
181
|
<style lang="css">
|
|
124
182
|
@layer components {
|
|
125
|
-
.overflow-navigation-wrapper {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
flex-direction: column;
|
|
131
|
-
gap: var(--overflow-nav-items-gap);
|
|
132
|
-
|
|
133
|
-
.overflow-navigation-list {
|
|
134
|
-
display: none;
|
|
183
|
+
.overflow-navigation-wrapper {
|
|
184
|
+
/* ─── Public CSS tokens ─────────────────────────────────────────────────
|
|
185
|
+
Override on the consumer's scope class to theme the overflow nav.
|
|
186
|
+
Tokens are read via var(--token, default) — defaults are NOT declared
|
|
187
|
+
on this element to avoid cascade conflicts with ancestor overrides.
|
|
135
188
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
189
|
+
--overflow-nav-padding-inline (default: 0.8rem)
|
|
190
|
+
--overflow-nav-items-gap (default: 0px)
|
|
191
|
+
--overflow-nav-items-padding-block (default: 0.8rem)
|
|
192
|
+
|
|
193
|
+
--overflow-nav-link-color (default: inherit)
|
|
194
|
+
--overflow-nav-link-border-color (default: #efefef75)
|
|
195
|
+
--overflow-nav-sub-item-color (default: inherit)
|
|
196
|
+
--overflow-nav-sub-item-font-size (default: inherit)
|
|
142
197
|
|
|
143
|
-
|
|
198
|
+
--overflow-nav-decorator-indicator-color (default: currentColor)
|
|
199
|
+
--overflow-nav-decorator-hovered-indicator-color (default: inherits --overflow-nav-decorator-indicator-color)
|
|
200
|
+
--overflow-nav-decorator-hovered-bg (default: oklch(100% 0 0 / 6%))
|
|
201
|
+
──────────────────────────────────────────────────────────────────────── */
|
|
202
|
+
|
|
203
|
+
display: flex;
|
|
204
|
+
flex-direction: column;
|
|
205
|
+
gap: var(--overflow-nav-items-gap, 0px);
|
|
206
|
+
position: relative;
|
|
207
|
+
|
|
208
|
+
.overflow-navigation-list {
|
|
144
209
|
display: none;
|
|
145
210
|
|
|
146
211
|
&.visible {
|
|
147
|
-
display: block;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.overflow-navigation-link {
|
|
151
|
-
text-decoration: none;
|
|
152
|
-
color: inherit;
|
|
153
|
-
padding-block: var(--overflow-nav-items-padding-block);
|
|
154
|
-
padding-inline: var(--overflow-nav-padding-inline);
|
|
155
212
|
display: flex;
|
|
156
|
-
|
|
157
|
-
|
|
213
|
+
flex-direction: column;
|
|
214
|
+
gap: var(--overflow-nav-items-gap, 0px);
|
|
215
|
+
min-width: var(--_overflow-navigation-list-min-width, auto);
|
|
158
216
|
}
|
|
159
217
|
|
|
160
|
-
.overflow-navigation-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
}
|
|
218
|
+
.overflow-navigation-item {
|
|
219
|
+
display: none;
|
|
220
|
+
|
|
221
|
+
&.visible {
|
|
222
|
+
display: block;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.overflow-navigation-link {
|
|
226
|
+
text-decoration: none;
|
|
227
|
+
color: var(--overflow-nav-link-color, inherit);
|
|
228
|
+
padding-block: var(--overflow-nav-items-padding-block, 0.8rem);
|
|
229
|
+
padding-inline: var(--overflow-nav-padding-inline, 0.8rem);
|
|
230
|
+
display: flex;
|
|
231
|
+
border-bottom: 0.1rem solid var(--overflow-nav-link-border-color, #efefef75);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.overflow-navigation-details {
|
|
235
|
+
&.expanding-panel {
|
|
236
|
+
margin-block-end: 0;
|
|
181
237
|
|
|
182
|
-
|
|
238
|
+
.expanding-panel-details {
|
|
183
239
|
.expanding-panel-summary {
|
|
184
|
-
|
|
240
|
+
padding-block: var(--overflow-nav-items-padding-block, 0.8rem);
|
|
241
|
+
padding-inline: var(--overflow-nav-padding-inline, 0.8rem);
|
|
242
|
+
gap: 1rem;
|
|
243
|
+
color: var(--overflow-nav-link-color, inherit);
|
|
244
|
+
border-bottom: 0.1rem solid var(--overflow-nav-link-border-color, #efefef75);
|
|
245
|
+
|
|
246
|
+
.label-wrapper {
|
|
247
|
+
.overflow-navigation-text {
|
|
248
|
+
text-wrap: nowrap;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
.icon-wrapper {
|
|
252
|
+
padding: 0;
|
|
253
|
+
}
|
|
185
254
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
.
|
|
189
|
-
|
|
190
|
-
|
|
255
|
+
|
|
256
|
+
&[open] {
|
|
257
|
+
.expanding-panel-summary {
|
|
258
|
+
border-bottom: 0.1rem solid transparent;
|
|
259
|
+
}
|
|
260
|
+
+ .expanding-panel-content {
|
|
261
|
+
border-bottom: 0.1rem solid var(--overflow-nav-link-border-color, #efefef75);
|
|
262
|
+
.inner {
|
|
263
|
+
.overflow-navigation-sub-nav-inner {
|
|
264
|
+
margin-top: var(--overflow-nav-items-gap, 0px);
|
|
265
|
+
}
|
|
191
266
|
}
|
|
192
267
|
}
|
|
193
268
|
}
|
|
194
269
|
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
.expanding-panel-content {
|
|
198
|
-
border-bottom: 0.1rem solid transparent;
|
|
199
270
|
|
|
200
|
-
.
|
|
201
|
-
|
|
271
|
+
.expanding-panel-content {
|
|
272
|
+
border-bottom: 0.1rem solid transparent;
|
|
202
273
|
|
|
203
|
-
.
|
|
274
|
+
.inner {
|
|
204
275
|
margin-top: 0;
|
|
205
276
|
|
|
206
|
-
.overflow-navigation-sub-nav-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
gap: 2px;
|
|
277
|
+
.overflow-navigation-sub-nav-inner {
|
|
278
|
+
margin-top: 0;
|
|
279
|
+
position: relative;
|
|
210
280
|
|
|
211
|
-
.overflow-navigation-sub-nav-
|
|
212
|
-
|
|
213
|
-
|
|
281
|
+
.overflow-navigation-sub-nav-list {
|
|
282
|
+
display: flex;
|
|
283
|
+
flex-direction: column;
|
|
284
|
+
gap: 2px;
|
|
214
285
|
|
|
215
|
-
.overflow-navigation-sub-nav-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
286
|
+
.overflow-navigation-sub-nav-item {
|
|
287
|
+
padding-block: var(--overflow-nav-items-padding-block, 0.8rem);
|
|
288
|
+
padding-inline: var(--overflow-nav-padding-inline, 0.8rem);
|
|
289
|
+
font-size: var(--overflow-nav-sub-item-font-size, inherit);
|
|
290
|
+
color: var(--overflow-nav-sub-item-color, inherit);
|
|
291
|
+
|
|
292
|
+
.overflow-navigation-sub-nav-link {
|
|
293
|
+
display: block;
|
|
294
|
+
text-decoration: none;
|
|
295
|
+
color: inherit;
|
|
296
|
+
}
|
|
219
297
|
}
|
|
220
298
|
}
|
|
221
299
|
}
|
|
@@ -226,6 +304,149 @@ watch(
|
|
|
226
304
|
}
|
|
227
305
|
}
|
|
228
306
|
}
|
|
229
|
-
|
|
307
|
+
|
|
308
|
+
/* Freeze all indicator transitions for the duration of a panel open/close animation
|
|
309
|
+
so the indicators snap to position rather than sliding through intermediate states. */
|
|
310
|
+
.overflow-navigation-wrapper.is-panel-animating .overflow-nav-indicator-hovered,
|
|
311
|
+
.overflow-navigation-wrapper.is-panel-animating .overflow-nav-indicator-active,
|
|
312
|
+
.overflow-navigation-wrapper.is-panel-animating .overflow-sub-nav-indicator-hovered {
|
|
313
|
+
transition: none;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* ─── Anchor positioning for overflow-nav indicators ─────────────────────
|
|
317
|
+
Single --overflow-nav-indicator: sits on is-hovered, falls back to
|
|
318
|
+
is-active. Vertical list so indicators slide up/down rather than left/right.
|
|
319
|
+
──────────────────────────────────────────────────────────────────────── */
|
|
320
|
+
|
|
321
|
+
/* Anchor to the inner row element, not the <li>, so an open submenu panel
|
|
322
|
+
doesn't stretch the indicator down into the expanded content. */
|
|
323
|
+
|
|
324
|
+
/* Plain link — hovered */
|
|
325
|
+
.overflow-navigation-wrapper
|
|
326
|
+
.overflow-navigation-item.is-hovered:not(:has(.overflow-navigation-details))
|
|
327
|
+
.overflow-navigation-link {
|
|
328
|
+
anchor-name: --overflow-nav-indicator;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* Submenu — hovered: anchor to summary row only */
|
|
332
|
+
.overflow-navigation-wrapper
|
|
333
|
+
.overflow-navigation-item.is-hovered
|
|
334
|
+
.overflow-navigation-details
|
|
335
|
+
.expanding-panel-summary {
|
|
336
|
+
anchor-name: --overflow-nav-indicator;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* Plain link — active (no hover) */
|
|
340
|
+
.overflow-navigation-wrapper:not(:has(.overflow-navigation-item.is-hovered))
|
|
341
|
+
.overflow-navigation-item.is-active:not(:has(.overflow-navigation-details))
|
|
342
|
+
.overflow-navigation-link {
|
|
343
|
+
anchor-name: --overflow-nav-indicator;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* Submenu — active (no hover): anchor to summary row only */
|
|
347
|
+
.overflow-navigation-wrapper:not(:has(.overflow-navigation-item.is-hovered))
|
|
348
|
+
.overflow-navigation-item.is-active
|
|
349
|
+
.overflow-navigation-details
|
|
350
|
+
.expanding-panel-summary {
|
|
351
|
+
anchor-name: --overflow-nav-indicator;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.overflow-navigation-wrapper .overflow-nav-indicator-hovered,
|
|
355
|
+
.overflow-navigation-wrapper .overflow-nav-indicator-active {
|
|
356
|
+
display: none;
|
|
357
|
+
pointer-events: none;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.overflow-navigation-wrapper .overflow-nav-indicator-hovered {
|
|
361
|
+
display: block;
|
|
362
|
+
position: absolute;
|
|
363
|
+
position-anchor: --overflow-nav-indicator;
|
|
364
|
+
left: 0;
|
|
365
|
+
right: 0;
|
|
366
|
+
top: anchor(top);
|
|
367
|
+
bottom: anchor(bottom);
|
|
368
|
+
background: var(--overflow-nav-decorator-hovered-bg, oklch(100% 0 0 / 6%));
|
|
369
|
+
z-index: 1;
|
|
370
|
+
opacity: 0;
|
|
371
|
+
transition:
|
|
372
|
+
top 200ms ease-in-out,
|
|
373
|
+
bottom 200ms ease-in-out,
|
|
374
|
+
opacity 150ms ease;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.overflow-navigation-wrapper:has(.overflow-navigation-item.is-hovered) .overflow-nav-indicator-hovered {
|
|
378
|
+
opacity: 1;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.overflow-navigation-wrapper .overflow-nav-indicator-active {
|
|
382
|
+
display: block;
|
|
383
|
+
position: absolute;
|
|
384
|
+
position-anchor: --overflow-nav-indicator;
|
|
385
|
+
left: 0;
|
|
386
|
+
width: 2px;
|
|
387
|
+
top: anchor(top);
|
|
388
|
+
bottom: anchor(bottom);
|
|
389
|
+
background: var(--overflow-nav-decorator-indicator-color, currentColor);
|
|
390
|
+
z-index: 3;
|
|
391
|
+
transition:
|
|
392
|
+
top 200ms ease-in-out,
|
|
393
|
+
bottom 200ms ease-in-out;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/* When something is hovered the active bar tracks the hovered item — use hover colour. */
|
|
397
|
+
.overflow-navigation-wrapper:has(.overflow-navigation-item.is-hovered) .overflow-nav-indicator-active {
|
|
398
|
+
background: var(
|
|
399
|
+
--overflow-nav-decorator-hovered-indicator-color,
|
|
400
|
+
var(--overflow-nav-decorator-indicator-color, currentColor)
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* ─── Anchor positioning for sub-nav child indicators ────────────────────
|
|
405
|
+
Separate --overflow-sub-nav-indicator scoped to the inner wrapper so
|
|
406
|
+
parent and child indicators are fully independent.
|
|
407
|
+
──────────────────────────────────────────────────────────────────────── */
|
|
408
|
+
|
|
409
|
+
.overflow-navigation-sub-nav-item.is-hovered {
|
|
410
|
+
anchor-name: --overflow-sub-nav-indicator;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.overflow-navigation-sub-nav-list:not(:has(.overflow-navigation-sub-nav-item.is-hovered))
|
|
414
|
+
.overflow-navigation-sub-nav-item.is-active {
|
|
415
|
+
anchor-name: --overflow-sub-nav-indicator;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.overflow-navigation-sub-nav-item.is-active {
|
|
419
|
+
border-inline-start: 2px solid var(--overflow-nav-decorator-indicator-color, currentColor);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.overflow-sub-nav-indicator-hovered {
|
|
423
|
+
/* pointer-events: none is critical — without it the indicator (z-index:1) sits
|
|
424
|
+
over the list items and swallows mouse events, clearing hoveredChildKey and
|
|
425
|
+
causing a flicker loop. */
|
|
426
|
+
pointer-events: none;
|
|
427
|
+
display: block;
|
|
428
|
+
position: absolute;
|
|
429
|
+
position-anchor: --overflow-sub-nav-indicator;
|
|
430
|
+
left: 0;
|
|
431
|
+
right: 0;
|
|
432
|
+
top: anchor(top);
|
|
433
|
+
bottom: anchor(bottom);
|
|
434
|
+
background: var(--overflow-nav-decorator-hovered-bg, oklch(100% 0 0 / 6%));
|
|
435
|
+
border-inline-start: 2px solid var(
|
|
436
|
+
--overflow-nav-decorator-hovered-indicator-color,
|
|
437
|
+
var(--overflow-nav-decorator-indicator-color, currentColor)
|
|
438
|
+
);
|
|
439
|
+
z-index: 1;
|
|
440
|
+
opacity: 0;
|
|
441
|
+
transition:
|
|
442
|
+
top 200ms ease-in-out,
|
|
443
|
+
bottom 200ms ease-in-out,
|
|
444
|
+
opacity 150ms ease;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.overflow-navigation-sub-nav-inner:has(.overflow-navigation-sub-nav-item.is-hovered)
|
|
448
|
+
.overflow-sub-nav-indicator-hovered {
|
|
449
|
+
opacity: 1;
|
|
450
|
+
}
|
|
230
451
|
}
|
|
231
452
|
</style>
|