@kushagradhawan/kookie-ui 0.1.125 → 0.1.126
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/components.css +93 -0
- package/dist/cjs/components/_internal/base-menu.props.d.ts +52 -1
- package/dist/cjs/components/_internal/base-menu.props.d.ts.map +1 -1
- package/dist/cjs/components/_internal/base-menu.props.js +1 -1
- package/dist/cjs/components/_internal/base-menu.props.js.map +3 -3
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.d.ts +60 -0
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.d.ts.map +1 -0
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.js +2 -0
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.js.map +7 -0
- package/dist/cjs/components/dropdown-menu.d.ts +28 -7
- package/dist/cjs/components/dropdown-menu.d.ts.map +1 -1
- package/dist/cjs/components/dropdown-menu.js +1 -1
- package/dist/cjs/components/dropdown-menu.js.map +3 -3
- package/dist/cjs/components/dropdown-menu.props.d.ts +1 -1
- package/dist/cjs/components/dropdown-menu.props.d.ts.map +1 -1
- package/dist/cjs/components/dropdown-menu.props.js +1 -1
- package/dist/cjs/components/dropdown-menu.props.js.map +2 -2
- package/dist/cjs/components/icons.d.ts +2 -1
- package/dist/cjs/components/icons.d.ts.map +1 -1
- package/dist/cjs/components/icons.js +1 -1
- package/dist/cjs/components/icons.js.map +3 -3
- package/dist/cjs/components/schemas/shell.schema.d.ts +2 -2
- package/dist/esm/components/_internal/base-menu.props.d.ts +52 -1
- package/dist/esm/components/_internal/base-menu.props.d.ts.map +1 -1
- package/dist/esm/components/_internal/base-menu.props.js +1 -1
- package/dist/esm/components/_internal/base-menu.props.js.map +3 -3
- package/dist/esm/components/_internal/dropdown-menu-drill-down.d.ts +60 -0
- package/dist/esm/components/_internal/dropdown-menu-drill-down.d.ts.map +1 -0
- package/dist/esm/components/_internal/dropdown-menu-drill-down.js +2 -0
- package/dist/esm/components/_internal/dropdown-menu-drill-down.js.map +7 -0
- package/dist/esm/components/dropdown-menu.d.ts +28 -7
- package/dist/esm/components/dropdown-menu.d.ts.map +1 -1
- package/dist/esm/components/dropdown-menu.js +1 -1
- package/dist/esm/components/dropdown-menu.js.map +3 -3
- package/dist/esm/components/dropdown-menu.props.d.ts +1 -1
- package/dist/esm/components/dropdown-menu.props.d.ts.map +1 -1
- package/dist/esm/components/dropdown-menu.props.js +1 -1
- package/dist/esm/components/dropdown-menu.props.js.map +3 -3
- package/dist/esm/components/icons.d.ts +2 -1
- package/dist/esm/components/icons.d.ts.map +1 -1
- package/dist/esm/components/icons.js +1 -1
- package/dist/esm/components/icons.js.map +3 -3
- package/dist/esm/components/schemas/shell.schema.d.ts +2 -2
- package/package.json +1 -1
- package/schemas/base-button.json +1 -1
- package/schemas/button.json +1 -1
- package/schemas/icon-button.json +1 -1
- package/schemas/index.json +6 -6
- package/schemas/toggle-button.json +1 -1
- package/schemas/toggle-icon-button.json +1 -1
- package/src/components/_internal/base-menu.props.ts +31 -1
- package/src/components/_internal/dropdown-menu-drill-down.tsx +242 -0
- package/src/components/dropdown-menu.css +119 -0
- package/src/components/dropdown-menu.props.tsx +2 -0
- package/src/components/dropdown-menu.tsx +217 -27
- package/src/components/icons.tsx +14 -1
- package/styles.css +93 -0
|
@@ -8,8 +8,10 @@ const contentSizes = ['1', '2'] as const;
|
|
|
8
8
|
const contentVariants = ['solid', 'soft'] as const;
|
|
9
9
|
const panelBackgrounds = ['solid', 'translucent'] as const;
|
|
10
10
|
const materials = ['solid', 'translucent'] as const;
|
|
11
|
+
const submenuBehaviors = ['cascade', 'drill-down'] as const;
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
// Base props shared between Content and SubContent
|
|
14
|
+
const baseMenuSharedPropDefs = {
|
|
13
15
|
size: {
|
|
14
16
|
type: 'enum',
|
|
15
17
|
className: 'rt-r-size',
|
|
@@ -45,6 +47,32 @@ const baseMenuContentPropDefs = {
|
|
|
45
47
|
panelBackground: PropDef<(typeof panelBackgrounds)[number] | undefined>;
|
|
46
48
|
};
|
|
47
49
|
|
|
50
|
+
// Content-specific props (includes submenuBehavior)
|
|
51
|
+
const baseMenuContentPropDefs = {
|
|
52
|
+
...baseMenuSharedPropDefs,
|
|
53
|
+
/**
|
|
54
|
+
* Controls how submenus behave.
|
|
55
|
+
* - `cascade`: Default cascading behavior where submenus open to the side (portal-based)
|
|
56
|
+
* - `drill-down`: Mobile-friendly behavior where submenus replace the content inline
|
|
57
|
+
* Supports responsive values: `{ initial: 'drill-down', md: 'cascade' }`
|
|
58
|
+
*/
|
|
59
|
+
submenuBehavior: {
|
|
60
|
+
type: 'enum',
|
|
61
|
+
values: submenuBehaviors,
|
|
62
|
+
default: 'cascade',
|
|
63
|
+
responsive: true,
|
|
64
|
+
},
|
|
65
|
+
} satisfies {
|
|
66
|
+
size: PropDef<(typeof contentSizes)[number]>;
|
|
67
|
+
variant: PropDef<(typeof contentVariants)[number]>;
|
|
68
|
+
material: PropDef<(typeof materials)[number] | undefined>;
|
|
69
|
+
panelBackground: PropDef<(typeof panelBackgrounds)[number] | undefined>;
|
|
70
|
+
submenuBehavior: PropDef<(typeof submenuBehaviors)[number]>;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// SubContent props (no submenuBehavior)
|
|
74
|
+
const baseMenuSubContentPropDefs = baseMenuSharedPropDefs;
|
|
75
|
+
|
|
48
76
|
const baseMenuItemPropDefs = {
|
|
49
77
|
...asChildPropDef,
|
|
50
78
|
...colorPropDef,
|
|
@@ -66,7 +94,9 @@ const baseMenuRadioItemPropDefs = {
|
|
|
66
94
|
|
|
67
95
|
export {
|
|
68
96
|
baseMenuContentPropDefs,
|
|
97
|
+
baseMenuSubContentPropDefs,
|
|
69
98
|
baseMenuItemPropDefs,
|
|
70
99
|
baseMenuCheckboxItemPropDefs,
|
|
71
100
|
baseMenuRadioItemPropDefs,
|
|
101
|
+
submenuBehaviors,
|
|
72
102
|
};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import type { Breakpoint, Responsive } from '../../props/prop-def.js';
|
|
5
|
+
import type { submenuBehaviors } from './base-menu.props.js';
|
|
6
|
+
import { _BREAKPOINTS } from '../shell.types.js';
|
|
7
|
+
|
|
8
|
+
type SubmenuBehavior = (typeof submenuBehaviors)[number];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Hook to get the current breakpoint based on window width.
|
|
12
|
+
* Returns 'initial' on the server and during initial hydration.
|
|
13
|
+
* Uses shared breakpoint values from shell.types.js.
|
|
14
|
+
*/
|
|
15
|
+
function useBreakpoint(): { breakpoint: Breakpoint; ready: boolean } {
|
|
16
|
+
const [currentBp, setCurrentBp] = React.useState<Breakpoint>('initial');
|
|
17
|
+
const [ready, setReady] = React.useState(false);
|
|
18
|
+
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
if (typeof window === 'undefined') return;
|
|
21
|
+
|
|
22
|
+
// Use shared breakpoint media queries from shell.types
|
|
23
|
+
const queries = Object.entries(_BREAKPOINTS) as [keyof typeof _BREAKPOINTS, string][];
|
|
24
|
+
const mqls = queries.map(([k, q]) => [k, window.matchMedia(q)] as const);
|
|
25
|
+
|
|
26
|
+
const compute = () => {
|
|
27
|
+
// Highest matched breakpoint wins
|
|
28
|
+
const matched = mqls.filter(([, m]) => m.matches).map(([k]) => k);
|
|
29
|
+
const next = (matched[matched.length - 1] as Breakpoint | undefined) ?? 'initial';
|
|
30
|
+
setCurrentBp(next);
|
|
31
|
+
setReady(true);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
compute();
|
|
35
|
+
|
|
36
|
+
const cleanups: Array<() => void> = [];
|
|
37
|
+
mqls.forEach(([, m]) => {
|
|
38
|
+
const mm = m as MediaQueryList & {
|
|
39
|
+
addEventListener?: (type: 'change', listener: () => void) => void;
|
|
40
|
+
removeEventListener?: (type: 'change', listener: () => void) => void;
|
|
41
|
+
addListener?: (listener: () => void) => void;
|
|
42
|
+
removeListener?: (listener: () => void) => void;
|
|
43
|
+
};
|
|
44
|
+
if (typeof mm.addEventListener === 'function') {
|
|
45
|
+
mm.addEventListener('change', compute);
|
|
46
|
+
cleanups.push(() => mm.removeEventListener?.('change', compute));
|
|
47
|
+
} else if (typeof mm.addListener === 'function') {
|
|
48
|
+
mm.addListener(compute);
|
|
49
|
+
cleanups.push(() => mm.removeListener?.(compute));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return () => {
|
|
54
|
+
cleanups.forEach((fn) => {
|
|
55
|
+
try {
|
|
56
|
+
fn();
|
|
57
|
+
} catch (e) {
|
|
58
|
+
// MediaQueryList cleanup can fail in edge cases (e.g., already removed)
|
|
59
|
+
// Log in development to aid debugging
|
|
60
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
61
|
+
console.warn('[DropdownMenu] MediaQueryList cleanup warning:', e);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
return { breakpoint: currentBp, ready };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Resolves a responsive value to its current value based on the breakpoint.
|
|
73
|
+
* Falls back through smaller breakpoints if the current one isn't defined.
|
|
74
|
+
*/
|
|
75
|
+
function resolveResponsiveValue<T>(
|
|
76
|
+
value: T | Partial<Record<Breakpoint, T>> | undefined,
|
|
77
|
+
currentBreakpoint: Breakpoint,
|
|
78
|
+
defaultValue: T
|
|
79
|
+
): T {
|
|
80
|
+
if (value === undefined || value === null) {
|
|
81
|
+
return defaultValue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Non-object values are returned directly
|
|
85
|
+
if (typeof value !== 'object') {
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const map = value as Partial<Record<Breakpoint, T>>;
|
|
90
|
+
|
|
91
|
+
// Check if current breakpoint has a value
|
|
92
|
+
if (map[currentBreakpoint] !== undefined) {
|
|
93
|
+
return map[currentBreakpoint] as T;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Fall back through smaller breakpoints
|
|
97
|
+
const bpOrder: Breakpoint[] = ['xl', 'lg', 'md', 'sm', 'xs', 'initial'];
|
|
98
|
+
const startIdx = bpOrder.indexOf(currentBreakpoint);
|
|
99
|
+
|
|
100
|
+
for (let i = startIdx + 1; i < bpOrder.length; i++) {
|
|
101
|
+
const bp = bpOrder[i];
|
|
102
|
+
if (map[bp] !== undefined) {
|
|
103
|
+
return map[bp] as T;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return defaultValue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// DrillDown Context
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
interface DrillDownContextValue {
|
|
115
|
+
/** Current submenu behavior mode */
|
|
116
|
+
behavior: SubmenuBehavior;
|
|
117
|
+
/** Whether the breakpoint has been resolved (client-side only) */
|
|
118
|
+
ready: boolean;
|
|
119
|
+
/** Stack of active submenu IDs. Empty means root menu is shown. */
|
|
120
|
+
stack: string[];
|
|
121
|
+
/** Navigate into a submenu */
|
|
122
|
+
push: (id: string) => void;
|
|
123
|
+
/** Navigate back to parent menu */
|
|
124
|
+
pop: () => void;
|
|
125
|
+
/** Reset to root menu */
|
|
126
|
+
reset: () => void;
|
|
127
|
+
/** Check if a specific submenu is the currently active one */
|
|
128
|
+
isActive: (id: string) => boolean;
|
|
129
|
+
/** Check if we're at root level (no submenus open) */
|
|
130
|
+
isRoot: boolean;
|
|
131
|
+
/** The currently active submenu ID (or null if at root) */
|
|
132
|
+
currentId: string | null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const DrillDownContext = React.createContext<DrillDownContextValue | null>(null);
|
|
136
|
+
|
|
137
|
+
interface DrillDownProviderProps {
|
|
138
|
+
children: React.ReactNode;
|
|
139
|
+
submenuBehavior: Responsive<SubmenuBehavior> | undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function DrillDownProvider({ children, submenuBehavior }: DrillDownProviderProps) {
|
|
143
|
+
const { breakpoint, ready } = useBreakpoint();
|
|
144
|
+
const [stack, setStack] = React.useState<string[]>([]);
|
|
145
|
+
|
|
146
|
+
// Resolve the current behavior based on breakpoint
|
|
147
|
+
const behavior = React.useMemo(
|
|
148
|
+
() => resolveResponsiveValue(submenuBehavior, breakpoint, 'cascade'),
|
|
149
|
+
[submenuBehavior, breakpoint]
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Reset stack when behavior changes from drill-down to cascade
|
|
153
|
+
const prevBehaviorRef = React.useRef(behavior);
|
|
154
|
+
React.useEffect(() => {
|
|
155
|
+
if (prevBehaviorRef.current === 'drill-down' && behavior === 'cascade') {
|
|
156
|
+
setStack([]);
|
|
157
|
+
}
|
|
158
|
+
prevBehaviorRef.current = behavior;
|
|
159
|
+
}, [behavior]);
|
|
160
|
+
|
|
161
|
+
const push = React.useCallback((id: string) => {
|
|
162
|
+
setStack((prev) => [...prev, id]);
|
|
163
|
+
}, []);
|
|
164
|
+
|
|
165
|
+
const pop = React.useCallback(() => {
|
|
166
|
+
setStack((prev) => prev.slice(0, -1));
|
|
167
|
+
}, []);
|
|
168
|
+
|
|
169
|
+
const reset = React.useCallback(() => {
|
|
170
|
+
setStack([]);
|
|
171
|
+
}, []);
|
|
172
|
+
|
|
173
|
+
const isActive = React.useCallback(
|
|
174
|
+
(id: string) => {
|
|
175
|
+
if (stack.length === 0) return false;
|
|
176
|
+
return stack[stack.length - 1] === id;
|
|
177
|
+
},
|
|
178
|
+
[stack]
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const value = React.useMemo(
|
|
182
|
+
(): DrillDownContextValue => ({
|
|
183
|
+
behavior,
|
|
184
|
+
ready,
|
|
185
|
+
stack,
|
|
186
|
+
push,
|
|
187
|
+
pop,
|
|
188
|
+
reset,
|
|
189
|
+
isActive,
|
|
190
|
+
isRoot: stack.length === 0,
|
|
191
|
+
currentId: stack.length > 0 ? stack[stack.length - 1] : null,
|
|
192
|
+
}),
|
|
193
|
+
[behavior, ready, stack, push, pop, reset, isActive]
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
return <DrillDownContext.Provider value={value}>{children}</DrillDownContext.Provider>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function useDrillDown() {
|
|
200
|
+
const ctx = React.useContext(DrillDownContext);
|
|
201
|
+
if (!ctx) {
|
|
202
|
+
throw new Error('useDrillDown must be used within a DropdownMenu.Content');
|
|
203
|
+
}
|
|
204
|
+
return ctx;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Hook to check if drill-down context is available (i.e., we're inside Content)
|
|
209
|
+
*/
|
|
210
|
+
function useDrillDownOptional() {
|
|
211
|
+
return React.useContext(DrillDownContext);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ============================================================================
|
|
215
|
+
// Sub Context (for individual submenu instances)
|
|
216
|
+
// ============================================================================
|
|
217
|
+
|
|
218
|
+
interface SubContextValue {
|
|
219
|
+
/** Unique ID for this submenu */
|
|
220
|
+
id: string;
|
|
221
|
+
/** Label for the back button */
|
|
222
|
+
label: React.ReactNode;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const SubContext = React.createContext<SubContextValue | null>(null);
|
|
226
|
+
|
|
227
|
+
function useSubContext() {
|
|
228
|
+
return React.useContext(SubContext);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export {
|
|
232
|
+
DrillDownProvider,
|
|
233
|
+
DrillDownContext,
|
|
234
|
+
SubContext,
|
|
235
|
+
useDrillDown,
|
|
236
|
+
useDrillDownOptional,
|
|
237
|
+
useSubContext,
|
|
238
|
+
useBreakpoint,
|
|
239
|
+
resolveResponsiveValue,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
export type { SubmenuBehavior, DrillDownContextValue, SubContextValue };
|
|
@@ -44,3 +44,122 @@
|
|
|
44
44
|
height: var(--trigger-icon-size-4);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
/***************************************************************************************************
|
|
49
|
+
* *
|
|
50
|
+
* DRILL-DOWN MODE *
|
|
51
|
+
* *
|
|
52
|
+
***************************************************************************************************/
|
|
53
|
+
|
|
54
|
+
/* Root container that holds the main menu items */
|
|
55
|
+
.rt-DropdownMenuDrillDownRoot {
|
|
56
|
+
display: contents;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* When a submenu is active, hide the ROOT's direct children (but not nested panels) */
|
|
60
|
+
.rt-DropdownMenuDrillDownRoot:where([data-drill-down-active]) > * {
|
|
61
|
+
display: none !important;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Keep nested panels visible (they use display: contents) */
|
|
65
|
+
.rt-DropdownMenuDrillDownRoot:where([data-drill-down-active]) > :where(.rt-DropdownMenuDrillDownPanel) {
|
|
66
|
+
display: contents !important;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Submenu panel in drill-down mode */
|
|
70
|
+
.rt-DropdownMenuDrillDownPanel {
|
|
71
|
+
display: contents;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Hide children of INACTIVE drill-down panels */
|
|
75
|
+
.rt-DropdownMenuDrillDownPanel:where(:not([data-drill-down-active])) > * {
|
|
76
|
+
display: none !important;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* But keep nested panels visible (they use display: contents) */
|
|
80
|
+
.rt-DropdownMenuDrillDownPanel:where(:not([data-drill-down-active])) > :where(.rt-DropdownMenuDrillDownPanel) {
|
|
81
|
+
display: contents !important;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Back button item */
|
|
85
|
+
.rt-DropdownMenuDrillDownBackItem {
|
|
86
|
+
display: flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
gap: var(--space-2);
|
|
89
|
+
min-height: var(--base-menu-item-height);
|
|
90
|
+
padding-top: var(--base-menu-item-padding-y);
|
|
91
|
+
padding-bottom: var(--base-menu-item-padding-y);
|
|
92
|
+
padding-inline-start: var(--base-menu-item-padding-left);
|
|
93
|
+
padding-inline-end: var(--base-menu-item-padding-right);
|
|
94
|
+
box-sizing: border-box;
|
|
95
|
+
outline: none;
|
|
96
|
+
cursor: var(--cursor-menu-item);
|
|
97
|
+
user-select: none;
|
|
98
|
+
transition: var(--transition-menu);
|
|
99
|
+
font-weight: 500;
|
|
100
|
+
|
|
101
|
+
&:where(:focus-visible) {
|
|
102
|
+
outline: 2px solid var(--focus-8);
|
|
103
|
+
outline-offset: -2px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Enhanced reduced motion support */
|
|
107
|
+
@media (prefers-reduced-motion: reduce) {
|
|
108
|
+
transition: none;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Back icon */
|
|
113
|
+
.rt-DropdownMenuDrillDownBackIcon {
|
|
114
|
+
width: var(--indicator-icon-size-2);
|
|
115
|
+
height: var(--indicator-icon-size-2);
|
|
116
|
+
flex-shrink: 0;
|
|
117
|
+
color: var(--gray-12);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Back label */
|
|
121
|
+
.rt-DropdownMenuDrillDownBackLabel {
|
|
122
|
+
color: var(--gray-12);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Solid variant - drill-down items hover (matches menu item [data-highlighted]) */
|
|
126
|
+
.rt-BaseMenuContent:where(.rt-variant-solid) {
|
|
127
|
+
& :where(.rt-DropdownMenuDrillDownBackItem:hover),
|
|
128
|
+
& :where(.rt-DropdownMenuDrillDownBackItem:focus-visible),
|
|
129
|
+
& :where(.rt-DropdownMenuDrillDownSubTrigger:hover),
|
|
130
|
+
& :where(.rt-DropdownMenuDrillDownSubTrigger:focus-visible) {
|
|
131
|
+
background-color: var(--accent-9);
|
|
132
|
+
color: var(--accent-contrast);
|
|
133
|
+
|
|
134
|
+
& :where(.rt-DropdownMenuDrillDownBackIcon),
|
|
135
|
+
& :where(.rt-DropdownMenuDrillDownBackLabel),
|
|
136
|
+
& :where(.rt-BaseMenuSubTriggerIcon) {
|
|
137
|
+
color: var(--accent-contrast);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Soft variant - drill-down items hover (matches menu item [data-highlighted]) */
|
|
143
|
+
.rt-BaseMenuContent:where(.rt-variant-soft) {
|
|
144
|
+
& :where(.rt-DropdownMenuDrillDownBackItem:hover),
|
|
145
|
+
& :where(.rt-DropdownMenuDrillDownBackItem:focus-visible),
|
|
146
|
+
& :where(.rt-DropdownMenuDrillDownSubTrigger:hover),
|
|
147
|
+
& :where(.rt-DropdownMenuDrillDownSubTrigger:focus-visible) {
|
|
148
|
+
background-color: var(--accent-4);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
:where([data-panel-background='translucent']) & :where(.rt-DropdownMenuDrillDownBackItem:hover),
|
|
152
|
+
:where([data-panel-background='translucent']) & :where(.rt-DropdownMenuDrillDownBackItem:focus-visible),
|
|
153
|
+
:where([data-panel-background='translucent']) & :where(.rt-DropdownMenuDrillDownSubTrigger:hover),
|
|
154
|
+
:where([data-panel-background='translucent']) & :where(.rt-DropdownMenuDrillDownSubTrigger:focus-visible) {
|
|
155
|
+
background-color: var(--accent-a4);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Forced colors support */
|
|
160
|
+
@media (forced-colors: active) {
|
|
161
|
+
.rt-DropdownMenuDrillDownBackItem:where(:focus-visible) {
|
|
162
|
+
outline: 2px solid Highlight;
|
|
163
|
+
outline-offset: 2px;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export {
|
|
2
2
|
baseMenuContentPropDefs as dropdownMenuContentPropDefs,
|
|
3
|
+
baseMenuSubContentPropDefs as dropdownMenuSubContentPropDefs,
|
|
3
4
|
baseMenuItemPropDefs as dropdownMenuItemPropDefs,
|
|
4
5
|
baseMenuCheckboxItemPropDefs as dropdownMenuCheckboxItemPropDefs,
|
|
5
6
|
baseMenuRadioItemPropDefs as dropdownMenuRadioItemPropDefs,
|
|
7
|
+
submenuBehaviors,
|
|
6
8
|
} from './_internal/base-menu.props.js';
|