@kushagradhawan/kookie-ui 0.1.47 → 0.1.49
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 +858 -30
- package/dist/cjs/components/_internal/shell-bottom.d.ts +31 -0
- package/dist/cjs/components/_internal/shell-bottom.d.ts.map +1 -0
- package/dist/cjs/components/_internal/shell-bottom.js +2 -0
- package/dist/cjs/components/_internal/shell-bottom.js.map +7 -0
- package/dist/cjs/components/_internal/shell-handles.d.ts +7 -0
- package/dist/cjs/components/_internal/shell-handles.d.ts.map +1 -0
- package/dist/cjs/components/_internal/shell-handles.js +2 -0
- package/dist/cjs/components/_internal/shell-handles.js.map +7 -0
- package/dist/cjs/components/_internal/shell-inspector.d.ts +31 -0
- package/dist/cjs/components/_internal/shell-inspector.d.ts.map +1 -0
- package/dist/cjs/components/_internal/shell-inspector.js +2 -0
- package/dist/cjs/components/_internal/shell-inspector.js.map +7 -0
- package/dist/cjs/components/_internal/shell-resize.d.ts +24 -0
- package/dist/cjs/components/_internal/shell-resize.d.ts.map +1 -0
- package/dist/cjs/components/_internal/shell-resize.js +2 -0
- package/dist/cjs/components/_internal/shell-resize.js.map +7 -0
- package/dist/cjs/components/_internal/shell-sidebar.d.ts +37 -0
- package/dist/cjs/components/_internal/shell-sidebar.d.ts.map +1 -0
- package/dist/cjs/components/_internal/shell-sidebar.js +2 -0
- package/dist/cjs/components/_internal/shell-sidebar.js.map +7 -0
- package/dist/cjs/components/alert-dialog.d.ts.map +1 -1
- package/dist/cjs/components/alert-dialog.js +1 -1
- package/dist/cjs/components/alert-dialog.js.map +2 -2
- package/dist/cjs/components/dialog.d.ts.map +1 -1
- package/dist/cjs/components/dialog.js +1 -1
- package/dist/cjs/components/dialog.js.map +2 -2
- package/dist/cjs/components/schemas/index.d.ts +2 -0
- package/dist/cjs/components/schemas/index.d.ts.map +1 -1
- package/dist/cjs/components/schemas/index.js +1 -1
- package/dist/cjs/components/schemas/index.js.map +3 -3
- package/dist/cjs/components/schemas/shell.schema.d.ts +1025 -0
- package/dist/cjs/components/schemas/shell.schema.d.ts.map +1 -0
- package/dist/cjs/components/schemas/shell.schema.js +2 -0
- package/dist/cjs/components/schemas/shell.schema.js.map +7 -0
- package/dist/cjs/components/shell.context.d.ts +37 -0
- package/dist/cjs/components/shell.context.d.ts.map +1 -0
- package/dist/cjs/components/shell.context.js +2 -0
- package/dist/cjs/components/shell.context.js.map +7 -0
- package/dist/cjs/components/shell.d.ts +6 -68
- package/dist/cjs/components/shell.d.ts.map +1 -1
- package/dist/cjs/components/shell.hooks.d.ts +3 -0
- package/dist/cjs/components/shell.hooks.d.ts.map +1 -0
- package/dist/cjs/components/shell.hooks.js +2 -0
- package/dist/cjs/components/shell.hooks.js.map +7 -0
- package/dist/cjs/components/shell.js +1 -1
- package/dist/cjs/components/shell.js.map +3 -3
- package/dist/cjs/components/shell.types.d.ts +20 -0
- package/dist/cjs/components/shell.types.d.ts.map +1 -0
- package/dist/cjs/components/shell.types.js +2 -0
- package/dist/cjs/components/shell.types.js.map +7 -0
- package/dist/cjs/components/sidebar.d.ts +1 -1
- package/dist/cjs/components/sidebar.d.ts.map +1 -1
- package/dist/cjs/components/sidebar.js +1 -1
- package/dist/cjs/components/sidebar.js.map +3 -3
- package/dist/esm/components/_internal/shell-bottom.d.ts +31 -0
- package/dist/esm/components/_internal/shell-bottom.d.ts.map +1 -0
- package/dist/esm/components/_internal/shell-bottom.js +2 -0
- package/dist/esm/components/_internal/shell-bottom.js.map +7 -0
- package/dist/esm/components/_internal/shell-handles.d.ts +7 -0
- package/dist/esm/components/_internal/shell-handles.d.ts.map +1 -0
- package/dist/esm/components/_internal/shell-handles.js +2 -0
- package/dist/esm/components/_internal/shell-handles.js.map +7 -0
- package/dist/esm/components/_internal/shell-inspector.d.ts +31 -0
- package/dist/esm/components/_internal/shell-inspector.d.ts.map +1 -0
- package/dist/esm/components/_internal/shell-inspector.js +2 -0
- package/dist/esm/components/_internal/shell-inspector.js.map +7 -0
- package/dist/esm/components/_internal/shell-resize.d.ts +24 -0
- package/dist/esm/components/_internal/shell-resize.d.ts.map +1 -0
- package/dist/esm/components/_internal/shell-resize.js +2 -0
- package/dist/esm/components/_internal/shell-resize.js.map +7 -0
- package/dist/esm/components/_internal/shell-sidebar.d.ts +37 -0
- package/dist/esm/components/_internal/shell-sidebar.d.ts.map +1 -0
- package/dist/esm/components/_internal/shell-sidebar.js +2 -0
- package/dist/esm/components/_internal/shell-sidebar.js.map +7 -0
- package/dist/esm/components/alert-dialog.d.ts.map +1 -1
- package/dist/esm/components/alert-dialog.js +1 -1
- package/dist/esm/components/alert-dialog.js.map +2 -2
- package/dist/esm/components/dialog.d.ts.map +1 -1
- package/dist/esm/components/dialog.js +1 -1
- package/dist/esm/components/dialog.js.map +2 -2
- package/dist/esm/components/schemas/index.d.ts +2 -0
- package/dist/esm/components/schemas/index.d.ts.map +1 -1
- package/dist/esm/components/schemas/index.js +1 -1
- package/dist/esm/components/schemas/index.js.map +3 -3
- package/dist/esm/components/schemas/shell.schema.d.ts +1025 -0
- package/dist/esm/components/schemas/shell.schema.d.ts.map +1 -0
- package/dist/esm/components/schemas/shell.schema.js +2 -0
- package/dist/esm/components/schemas/shell.schema.js.map +7 -0
- package/dist/esm/components/shell.context.d.ts +37 -0
- package/dist/esm/components/shell.context.d.ts.map +1 -0
- package/dist/esm/components/shell.context.js +2 -0
- package/dist/esm/components/shell.context.js.map +7 -0
- package/dist/esm/components/shell.d.ts +6 -68
- package/dist/esm/components/shell.d.ts.map +1 -1
- package/dist/esm/components/shell.hooks.d.ts +3 -0
- package/dist/esm/components/shell.hooks.d.ts.map +1 -0
- package/dist/esm/components/shell.hooks.js +2 -0
- package/dist/esm/components/shell.hooks.js.map +7 -0
- package/dist/esm/components/shell.js +1 -1
- package/dist/esm/components/shell.js.map +3 -3
- package/dist/esm/components/shell.types.d.ts +20 -0
- package/dist/esm/components/shell.types.d.ts.map +1 -0
- package/dist/esm/components/shell.types.js +2 -0
- package/dist/esm/components/shell.types.js.map +7 -0
- package/dist/esm/components/sidebar.d.ts +1 -1
- package/dist/esm/components/sidebar.d.ts.map +1 -1
- package/dist/esm/components/sidebar.js +1 -1
- package/dist/esm/components/sidebar.js.map +2 -2
- package/layout/utilities.css +168 -84
- package/layout.css +168 -84
- package/package.json +2 -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/shell-bottom.json +168 -0
- package/schemas/shell-content.json +34 -0
- package/schemas/shell-handle.json +34 -0
- package/schemas/shell-header.json +42 -0
- package/schemas/shell-inspector.json +171 -0
- package/schemas/shell-panel.json +167 -0
- package/schemas/shell-rail.json +132 -0
- package/schemas/shell-root.json +54 -0
- package/schemas/shell-sidebar.json +182 -0
- package/schemas/shell-trigger.json +76 -0
- package/schemas/toggle-button.json +1 -1
- package/schemas/toggle-icon-button.json +1 -1
- package/src/components/_internal/shell-bottom.tsx +251 -0
- package/src/components/_internal/shell-handles.tsx +193 -0
- package/src/components/_internal/shell-inspector.tsx +242 -0
- package/src/components/_internal/shell-resize.tsx +30 -0
- package/src/components/_internal/shell-sidebar.tsx +347 -0
- package/src/components/alert-dialog.tsx +6 -0
- package/src/components/dialog.tsx +6 -0
- package/src/components/schemas/index.ts +46 -0
- package/src/components/schemas/shell.schema.ts +403 -0
- package/src/components/shell.context.tsx +56 -0
- package/src/components/shell.css +5 -17
- package/src/components/shell.hooks.ts +31 -0
- package/src/components/shell.tsx +368 -1684
- package/src/components/shell.types.ts +27 -0
- package/src/components/sidebar.tsx +1 -1
- package/src/styles/tokens/blur.css +2 -2
- package/src/styles/tokens/color.css +2 -2
- package/styles.css +1031 -116
- package/tokens/base.css +5 -2
- package/tokens.css +5 -2
- package/utilities.css +168 -84
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface PaneResizeContextValue {
|
|
4
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
5
|
+
cssVarName: string;
|
|
6
|
+
minSize: number;
|
|
7
|
+
maxSize: number;
|
|
8
|
+
defaultSize: number;
|
|
9
|
+
orientation: 'vertical' | 'horizontal';
|
|
10
|
+
edge: 'start' | 'end';
|
|
11
|
+
computeNext: (clientPos: number, startClientPos: number, startSize: number) => number;
|
|
12
|
+
onResize?: (size: number) => void;
|
|
13
|
+
onResizeStart?: (size: number) => void;
|
|
14
|
+
onResizeEnd?: (size: number) => void;
|
|
15
|
+
target: 'left' | 'rail' | 'panel' | 'sidebar' | 'inspector' | 'bottom';
|
|
16
|
+
collapsible: boolean;
|
|
17
|
+
snapPoints?: number[];
|
|
18
|
+
snapTolerance: number;
|
|
19
|
+
collapseThreshold?: number;
|
|
20
|
+
requestCollapse?: () => void;
|
|
21
|
+
requestToggle?: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const PaneResizeContext = React.createContext<PaneResizeContextValue | null>(null);
|
|
25
|
+
|
|
26
|
+
export function usePaneResize() {
|
|
27
|
+
const ctx = React.useContext(PaneResizeContext);
|
|
28
|
+
if (!ctx) throw new Error('Shell.Handle must be used within a resizable pane');
|
|
29
|
+
return ctx;
|
|
30
|
+
}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import * as Sheet from '../sheet.js';
|
|
4
|
+
import { VisuallyHidden } from '../visually-hidden.js';
|
|
5
|
+
import { useShell } from '../shell.context.js';
|
|
6
|
+
import { useResponsivePresentation } from '../shell.hooks.js';
|
|
7
|
+
import { PaneResizeContext } from './shell-resize.js';
|
|
8
|
+
import { SidebarHandle, PaneHandle } from './shell-handles.js';
|
|
9
|
+
import type { Breakpoint, PaneMode, PaneSizePersistence, PresentationValue, ResponsivePresentation, ResponsiveSidebarMode, SidebarMode } from '../shell.types.js';
|
|
10
|
+
import { BREAKPOINTS } from '../shell.types.js';
|
|
11
|
+
|
|
12
|
+
interface PaneProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
13
|
+
presentation?: ResponsivePresentation;
|
|
14
|
+
mode?: PaneMode;
|
|
15
|
+
defaultMode?: any;
|
|
16
|
+
onModeChange?: (mode: PaneMode | SidebarMode) => void;
|
|
17
|
+
expandedSize?: number;
|
|
18
|
+
minSize?: number;
|
|
19
|
+
maxSize?: number;
|
|
20
|
+
resizable?: boolean;
|
|
21
|
+
collapsible?: boolean;
|
|
22
|
+
onExpand?: () => void;
|
|
23
|
+
onCollapse?: () => void;
|
|
24
|
+
onResize?: (size: number) => void;
|
|
25
|
+
resizer?: React.ReactNode;
|
|
26
|
+
onResizeStart?: (size: number) => void;
|
|
27
|
+
onResizeEnd?: (size: number) => void;
|
|
28
|
+
snapPoints?: number[];
|
|
29
|
+
snapTolerance?: number;
|
|
30
|
+
collapseThreshold?: number;
|
|
31
|
+
paneId?: string;
|
|
32
|
+
persistence?: PaneSizePersistence;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type SidebarComponent = React.ForwardRefExoticComponent<
|
|
36
|
+
Omit<PaneProps, 'mode' | 'defaultMode' | 'onModeChange'> & {
|
|
37
|
+
mode?: SidebarMode;
|
|
38
|
+
defaultMode?: ResponsiveSidebarMode;
|
|
39
|
+
onModeChange?: (mode: SidebarMode) => void;
|
|
40
|
+
thinSize?: number;
|
|
41
|
+
toggleModes?: 'both' | 'single';
|
|
42
|
+
} & React.RefAttributes<HTMLDivElement>
|
|
43
|
+
> & { Handle: typeof SidebarHandle };
|
|
44
|
+
|
|
45
|
+
export const Sidebar = React.forwardRef<
|
|
46
|
+
HTMLDivElement,
|
|
47
|
+
Omit<PaneProps, 'mode' | 'defaultMode' | 'onModeChange'> & {
|
|
48
|
+
mode?: SidebarMode;
|
|
49
|
+
defaultMode?: ResponsiveSidebarMode;
|
|
50
|
+
onModeChange?: (mode: SidebarMode) => void;
|
|
51
|
+
thinSize?: number;
|
|
52
|
+
toggleModes?: 'both' | 'single';
|
|
53
|
+
}
|
|
54
|
+
>(
|
|
55
|
+
(
|
|
56
|
+
{
|
|
57
|
+
className,
|
|
58
|
+
presentation = { initial: 'overlay', md: 'fixed' },
|
|
59
|
+
mode,
|
|
60
|
+
defaultMode = 'expanded',
|
|
61
|
+
onModeChange,
|
|
62
|
+
expandedSize = 288,
|
|
63
|
+
minSize = 200,
|
|
64
|
+
maxSize = 400,
|
|
65
|
+
resizable = false,
|
|
66
|
+
collapsible = true,
|
|
67
|
+
onExpand,
|
|
68
|
+
onCollapse,
|
|
69
|
+
onResize,
|
|
70
|
+
onResizeStart,
|
|
71
|
+
onResizeEnd,
|
|
72
|
+
snapPoints,
|
|
73
|
+
snapTolerance,
|
|
74
|
+
collapseThreshold,
|
|
75
|
+
paneId,
|
|
76
|
+
persistence,
|
|
77
|
+
children,
|
|
78
|
+
style,
|
|
79
|
+
thinSize = 64,
|
|
80
|
+
toggleModes,
|
|
81
|
+
...props
|
|
82
|
+
},
|
|
83
|
+
ref,
|
|
84
|
+
) => {
|
|
85
|
+
const shell = useShell();
|
|
86
|
+
const resolvedPresentation = useResponsivePresentation(presentation);
|
|
87
|
+
const isOverlay = resolvedPresentation === 'overlay';
|
|
88
|
+
const isStacked = resolvedPresentation === 'stacked';
|
|
89
|
+
const localRef = React.useRef<HTMLDivElement | null>(null);
|
|
90
|
+
const setRef = React.useCallback(
|
|
91
|
+
(node: HTMLDivElement | null) => {
|
|
92
|
+
localRef.current = node;
|
|
93
|
+
if (typeof ref === 'function') ref(node);
|
|
94
|
+
else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
95
|
+
},
|
|
96
|
+
[ref],
|
|
97
|
+
);
|
|
98
|
+
const childArray = React.Children.toArray(children) as React.ReactElement[];
|
|
99
|
+
const handleChildren = childArray.filter((el: React.ReactElement) => React.isValidElement(el) && el.type === SidebarHandle);
|
|
100
|
+
const contentChildren = childArray.filter((el: React.ReactElement) => !(React.isValidElement(el) && el.type === SidebarHandle));
|
|
101
|
+
|
|
102
|
+
// Register with shell
|
|
103
|
+
const sidebarId = React.useId();
|
|
104
|
+
React.useEffect(() => {
|
|
105
|
+
shell.setHasSidebar(true);
|
|
106
|
+
return () => {
|
|
107
|
+
shell.setHasSidebar(false);
|
|
108
|
+
};
|
|
109
|
+
}, [shell, sidebarId]);
|
|
110
|
+
|
|
111
|
+
// Honor defaultMode on mount when uncontrolled
|
|
112
|
+
const didInitRef = React.useRef(false);
|
|
113
|
+
React.useEffect(() => {
|
|
114
|
+
if (didInitRef.current) return;
|
|
115
|
+
didInitRef.current = true;
|
|
116
|
+
if (mode === undefined && shell.sidebarMode !== (defaultMode as SidebarMode)) {
|
|
117
|
+
shell.setSidebarMode(defaultMode as SidebarMode);
|
|
118
|
+
}
|
|
119
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
120
|
+
}, []);
|
|
121
|
+
|
|
122
|
+
// Sync controlled mode
|
|
123
|
+
React.useEffect(() => {
|
|
124
|
+
if (mode !== undefined && shell.sidebarMode !== mode) {
|
|
125
|
+
shell.setSidebarMode(mode);
|
|
126
|
+
}
|
|
127
|
+
}, [mode, shell]);
|
|
128
|
+
|
|
129
|
+
// Emit mode changes
|
|
130
|
+
React.useEffect(() => {
|
|
131
|
+
if (mode === undefined) {
|
|
132
|
+
onModeChange?.(shell.sidebarMode);
|
|
133
|
+
}
|
|
134
|
+
}, [shell.sidebarMode, mode, onModeChange]);
|
|
135
|
+
|
|
136
|
+
// Emit expand/collapse events
|
|
137
|
+
React.useEffect(() => {
|
|
138
|
+
if (shell.sidebarMode === 'expanded') {
|
|
139
|
+
onExpand?.();
|
|
140
|
+
} else {
|
|
141
|
+
onCollapse?.();
|
|
142
|
+
}
|
|
143
|
+
}, [shell.sidebarMode, onExpand, onCollapse]);
|
|
144
|
+
|
|
145
|
+
// Option A: thin is width-only; content remains visible whenever not collapsed
|
|
146
|
+
const isContentVisible = shell.sidebarMode !== 'collapsed';
|
|
147
|
+
|
|
148
|
+
// Default persistence if paneId provided and none supplied (fixed only)
|
|
149
|
+
const persistenceAdapter = React.useMemo(() => {
|
|
150
|
+
if (!paneId || persistence) return persistence;
|
|
151
|
+
const key = `kookie-ui:shell:sidebar:${paneId}`;
|
|
152
|
+
const adapter: PaneSizePersistence = {
|
|
153
|
+
load: () => {
|
|
154
|
+
if (typeof window === 'undefined') return undefined;
|
|
155
|
+
const v = window.localStorage.getItem(key);
|
|
156
|
+
return v ? Number(v) : undefined;
|
|
157
|
+
},
|
|
158
|
+
save: (size: number) => {
|
|
159
|
+
if (typeof window === 'undefined') return;
|
|
160
|
+
window.localStorage.setItem(key, String(size));
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
return adapter;
|
|
164
|
+
}, [paneId, persistence]);
|
|
165
|
+
|
|
166
|
+
React.useEffect(() => {
|
|
167
|
+
let mounted = true;
|
|
168
|
+
(async () => {
|
|
169
|
+
if (!resizable || !persistenceAdapter?.load || isOverlay) return;
|
|
170
|
+
const loaded = await persistenceAdapter.load();
|
|
171
|
+
if (mounted && typeof loaded === 'number' && localRef.current) {
|
|
172
|
+
localRef.current.style.setProperty('--sidebar-size', `${loaded}px`);
|
|
173
|
+
onResize?.(loaded);
|
|
174
|
+
}
|
|
175
|
+
})();
|
|
176
|
+
return () => {
|
|
177
|
+
mounted = false;
|
|
178
|
+
};
|
|
179
|
+
}, [resizable, persistenceAdapter, onResize, isOverlay]);
|
|
180
|
+
|
|
181
|
+
// Always-follow responsive defaultMode for uncontrolled Sidebar (on breakpoint change only)
|
|
182
|
+
const resolveResponsiveMode = React.useCallback((): SidebarMode => {
|
|
183
|
+
if (typeof defaultMode === 'string') return defaultMode as SidebarMode;
|
|
184
|
+
const dm = defaultMode as Partial<Record<Breakpoint, SidebarMode>> | undefined;
|
|
185
|
+
if (dm && dm[shell.currentBreakpoint as Breakpoint]) {
|
|
186
|
+
return dm[shell.currentBreakpoint as Breakpoint] as SidebarMode;
|
|
187
|
+
}
|
|
188
|
+
const bpKeys = Object.keys(BREAKPOINTS) as Array<keyof typeof BREAKPOINTS>;
|
|
189
|
+
const order: Breakpoint[] = ([...bpKeys].reverse() as Breakpoint[]).concat('initial' as Breakpoint);
|
|
190
|
+
const startIdx = order.indexOf(shell.currentBreakpoint as Breakpoint);
|
|
191
|
+
for (let i = startIdx + 1; i < order.length; i++) {
|
|
192
|
+
const bp = order[i];
|
|
193
|
+
if (dm && dm[bp]) return dm[bp] as SidebarMode;
|
|
194
|
+
}
|
|
195
|
+
return 'collapsed';
|
|
196
|
+
}, [defaultMode, shell.currentBreakpoint]);
|
|
197
|
+
|
|
198
|
+
// Register custom toggle behavior based on toggleModes (both|single)
|
|
199
|
+
const shellForToggle = useShell();
|
|
200
|
+
const resolveDefaultSidebarMode = React.useCallback((): SidebarMode => {
|
|
201
|
+
const resolved = resolveResponsiveMode();
|
|
202
|
+
return resolved === 'thin' || resolved === 'expanded' ? resolved : 'expanded';
|
|
203
|
+
}, [resolveResponsiveMode]);
|
|
204
|
+
|
|
205
|
+
React.useEffect(() => {
|
|
206
|
+
if (!shellForToggle.setSidebarToggleComputer) return;
|
|
207
|
+
const strategy: 'both' | 'single' = toggleModes ?? 'both';
|
|
208
|
+
const compute = (current: SidebarMode): SidebarMode => {
|
|
209
|
+
if (strategy === 'both') {
|
|
210
|
+
if (current === 'collapsed') return 'thin';
|
|
211
|
+
if (current === 'thin') return 'expanded';
|
|
212
|
+
return 'collapsed';
|
|
213
|
+
}
|
|
214
|
+
const target = resolveDefaultSidebarMode();
|
|
215
|
+
if (current === 'collapsed') return target;
|
|
216
|
+
if (current === target) return 'collapsed';
|
|
217
|
+
return target;
|
|
218
|
+
};
|
|
219
|
+
shellForToggle.setSidebarToggleComputer(compute);
|
|
220
|
+
return () => {
|
|
221
|
+
shellForToggle.setSidebarToggleComputer?.((cur) => (cur === 'collapsed' ? 'thin' : cur === 'thin' ? 'expanded' : 'collapsed'));
|
|
222
|
+
};
|
|
223
|
+
}, [shellForToggle, toggleModes, resolveDefaultSidebarMode]);
|
|
224
|
+
|
|
225
|
+
const lastOverlayWidthRef = React.useRef<number>(expandedSize);
|
|
226
|
+
const lastOverlayModeRef = React.useRef<SidebarMode>('expanded');
|
|
227
|
+
React.useEffect(() => {
|
|
228
|
+
if (shell.sidebarMode !== 'collapsed') {
|
|
229
|
+
lastOverlayModeRef.current = shell.sidebarMode as SidebarMode;
|
|
230
|
+
lastOverlayWidthRef.current = shell.sidebarMode === 'thin' ? thinSize : expandedSize;
|
|
231
|
+
}
|
|
232
|
+
}, [shell.sidebarMode, thinSize, expandedSize]);
|
|
233
|
+
|
|
234
|
+
const lastSidebarBpRef = React.useRef<Breakpoint | null>(null);
|
|
235
|
+
React.useEffect(() => {
|
|
236
|
+
if (mode !== undefined) return;
|
|
237
|
+
if (!shell.currentBreakpointReady) return;
|
|
238
|
+
if (lastSidebarBpRef.current === shell.currentBreakpoint) return;
|
|
239
|
+
lastSidebarBpRef.current = shell.currentBreakpoint as Breakpoint;
|
|
240
|
+
const next = resolveResponsiveMode();
|
|
241
|
+
if (next !== shell.sidebarMode) shell.setSidebarMode(next);
|
|
242
|
+
}, [mode, shell.currentBreakpoint, shell.currentBreakpointReady, resolveResponsiveMode, shell.sidebarMode, shell.setSidebarMode]);
|
|
243
|
+
|
|
244
|
+
const handleEl =
|
|
245
|
+
resizable && !isOverlay && shell.sidebarMode === 'expanded' ? (
|
|
246
|
+
<PaneResizeContext.Provider
|
|
247
|
+
value={{
|
|
248
|
+
containerRef: localRef,
|
|
249
|
+
cssVarName: '--sidebar-size',
|
|
250
|
+
minSize,
|
|
251
|
+
maxSize,
|
|
252
|
+
defaultSize: expandedSize,
|
|
253
|
+
orientation: 'vertical',
|
|
254
|
+
edge: 'end',
|
|
255
|
+
computeNext: (client, startClient, startSize) => {
|
|
256
|
+
const isRtl = getComputedStyle(localRef.current!).direction === 'rtl';
|
|
257
|
+
const delta = client - startClient;
|
|
258
|
+
return startSize + (isRtl ? -delta : delta);
|
|
259
|
+
},
|
|
260
|
+
onResize,
|
|
261
|
+
onResizeStart,
|
|
262
|
+
onResizeEnd: (size) => {
|
|
263
|
+
onResizeEnd?.(size);
|
|
264
|
+
persistenceAdapter?.save?.(size);
|
|
265
|
+
},
|
|
266
|
+
target: 'sidebar',
|
|
267
|
+
collapsible,
|
|
268
|
+
snapPoints,
|
|
269
|
+
snapTolerance: snapTolerance ?? 8,
|
|
270
|
+
collapseThreshold,
|
|
271
|
+
requestCollapse: () => shell.setSidebarMode('collapsed'),
|
|
272
|
+
requestToggle: () => shell.togglePane('sidebar'),
|
|
273
|
+
}}
|
|
274
|
+
>
|
|
275
|
+
{handleChildren.length > 0 ? handleChildren.map((el, i) => React.cloneElement(el, { key: el.key ?? i })) : <PaneHandle />}
|
|
276
|
+
</PaneResizeContext.Provider>
|
|
277
|
+
) : null;
|
|
278
|
+
|
|
279
|
+
if (isOverlay) {
|
|
280
|
+
const open = shell.sidebarMode !== 'collapsed';
|
|
281
|
+
return (
|
|
282
|
+
<Sheet.Root open={open} onOpenChange={(o) => shell.setSidebarMode(o ? 'expanded' : 'collapsed')}>
|
|
283
|
+
<Sheet.Content
|
|
284
|
+
side="start"
|
|
285
|
+
style={{ padding: 0 }}
|
|
286
|
+
width={{
|
|
287
|
+
initial: `${open ? (shell.sidebarMode === 'thin' ? thinSize : expandedSize) : lastOverlayWidthRef.current}px`,
|
|
288
|
+
}}
|
|
289
|
+
>
|
|
290
|
+
<VisuallyHidden>
|
|
291
|
+
<Sheet.Title>Sidebar</Sheet.Title>
|
|
292
|
+
</VisuallyHidden>
|
|
293
|
+
{contentChildren}
|
|
294
|
+
</Sheet.Content>
|
|
295
|
+
</Sheet.Root>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return (
|
|
300
|
+
<div
|
|
301
|
+
{...props}
|
|
302
|
+
ref={setRef}
|
|
303
|
+
className={classNames('rt-ShellSidebar', className)}
|
|
304
|
+
data-mode={shell.sidebarMode}
|
|
305
|
+
data-peek={shell.peekTarget === 'sidebar' || undefined}
|
|
306
|
+
data-presentation={resolvedPresentation}
|
|
307
|
+
data-open={(isStacked && isContentVisible) || undefined}
|
|
308
|
+
style={{
|
|
309
|
+
...style,
|
|
310
|
+
['--sidebar-size' as any]: `${expandedSize}px`,
|
|
311
|
+
['--sidebar-thin-size' as any]: `${thinSize}px`,
|
|
312
|
+
['--sidebar-min-size' as any]: `${minSize}px`,
|
|
313
|
+
['--sidebar-max-size' as any]: `${maxSize}px`,
|
|
314
|
+
...(shell.peekTarget === 'sidebar' && shell.sidebarMode === 'collapsed' && !isOverlay
|
|
315
|
+
? (() => {
|
|
316
|
+
const strategy: 'both' | 'single' = toggleModes ?? 'both';
|
|
317
|
+
const current = shell.sidebarMode as SidebarMode;
|
|
318
|
+
let next: SidebarMode;
|
|
319
|
+
if (strategy === 'both') {
|
|
320
|
+
next = current === 'collapsed' ? 'thin' : current === 'thin' ? 'expanded' : 'collapsed';
|
|
321
|
+
} else {
|
|
322
|
+
const target = resolveDefaultSidebarMode();
|
|
323
|
+
next = current === 'collapsed' ? target : 'collapsed';
|
|
324
|
+
}
|
|
325
|
+
if (next === 'thin') {
|
|
326
|
+
return {
|
|
327
|
+
['--peek-sidebar-width' as any]: `${thinSize}px`,
|
|
328
|
+
} as React.CSSProperties;
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
['--peek-sidebar-width' as any]: `var(--sidebar-size, ${expandedSize}px)`,
|
|
332
|
+
} as React.CSSProperties;
|
|
333
|
+
})()
|
|
334
|
+
: {}),
|
|
335
|
+
}}
|
|
336
|
+
>
|
|
337
|
+
<div className="rt-ShellSidebarContent" data-visible={isContentVisible || undefined}>
|
|
338
|
+
{contentChildren}
|
|
339
|
+
</div>
|
|
340
|
+
{handleEl}
|
|
341
|
+
</div>
|
|
342
|
+
);
|
|
343
|
+
},
|
|
344
|
+
) as SidebarComponent;
|
|
345
|
+
|
|
346
|
+
Sidebar.displayName = 'Shell.Sidebar';
|
|
347
|
+
Sidebar.Handle = SidebarHandle;
|
|
@@ -157,6 +157,12 @@ const AlertDialogContent = React.forwardRef<AlertDialogContentElement, AlertDial
|
|
|
157
157
|
role="alertdialog"
|
|
158
158
|
aria-modal="true"
|
|
159
159
|
aria-describedby="alert-dialog-description"
|
|
160
|
+
onCloseAutoFocus={(event) => {
|
|
161
|
+
// Prevent default focus behavior
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
// Restore pointer-events to body (Radix UI fix for issue #1241)
|
|
164
|
+
document.body.style.pointerEvents = '';
|
|
165
|
+
}}
|
|
160
166
|
/>
|
|
161
167
|
{/* ARIA live region for screen reader announcements */}
|
|
162
168
|
<div
|
|
@@ -157,6 +157,12 @@ const DialogContent = React.forwardRef<DialogContentElement, DialogContentProps>
|
|
|
157
157
|
tabIndex={-1}
|
|
158
158
|
role="dialog"
|
|
159
159
|
aria-modal="true"
|
|
160
|
+
onCloseAutoFocus={(event) => {
|
|
161
|
+
// Prevent default focus behavior
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
// Restore pointer-events to body (Radix UI fix for issue #1241)
|
|
164
|
+
document.body.style.pointerEvents = '';
|
|
165
|
+
}}
|
|
160
166
|
/>
|
|
161
167
|
{/* ARIA live region for screen reader announcements */}
|
|
162
168
|
<div
|
|
@@ -39,6 +39,52 @@ export type { ToggleButtonProps } from './toggle-button.schema.js';
|
|
|
39
39
|
export { ToggleIconButtonSchema, parseToggleIconButtonProps } from './toggle-icon-button.schema.js';
|
|
40
40
|
export type { ToggleIconButtonProps } from './toggle-icon-button.schema.js';
|
|
41
41
|
|
|
42
|
+
// Shell schemas
|
|
43
|
+
export {
|
|
44
|
+
ShellRootSchema,
|
|
45
|
+
ShellHeaderSchema,
|
|
46
|
+
ShellRailSchema,
|
|
47
|
+
ShellPanelSchema,
|
|
48
|
+
ShellSidebarSchema,
|
|
49
|
+
ShellContentSchema,
|
|
50
|
+
ShellInspectorSchema,
|
|
51
|
+
ShellBottomSchema,
|
|
52
|
+
ShellTriggerSchema,
|
|
53
|
+
ShellHandleSchema,
|
|
54
|
+
parseShellRootProps,
|
|
55
|
+
parseShellHeaderProps,
|
|
56
|
+
parseShellRailProps,
|
|
57
|
+
parseShellPanelProps,
|
|
58
|
+
parseShellSidebarProps,
|
|
59
|
+
parseShellContentProps,
|
|
60
|
+
parseShellInspectorProps,
|
|
61
|
+
parseShellBottomProps,
|
|
62
|
+
parseShellTriggerProps,
|
|
63
|
+
parseShellHandleProps,
|
|
64
|
+
} from './shell.schema.js';
|
|
65
|
+
export type {
|
|
66
|
+
ShellRootProps,
|
|
67
|
+
ShellHeaderProps,
|
|
68
|
+
ShellRailProps,
|
|
69
|
+
ShellPanelProps,
|
|
70
|
+
ShellSidebarProps,
|
|
71
|
+
ShellContentProps,
|
|
72
|
+
ShellInspectorProps,
|
|
73
|
+
ShellBottomProps,
|
|
74
|
+
ShellTriggerProps,
|
|
75
|
+
ShellHandleProps,
|
|
76
|
+
PaneMode,
|
|
77
|
+
SidebarMode,
|
|
78
|
+
PresentationValue,
|
|
79
|
+
Breakpoint,
|
|
80
|
+
PaneTarget,
|
|
81
|
+
TriggerAction,
|
|
82
|
+
ResponsiveMode,
|
|
83
|
+
ResponsiveSidebarMode,
|
|
84
|
+
ResponsivePresentation,
|
|
85
|
+
PaneSizePersistence,
|
|
86
|
+
} from './shell.schema.js';
|
|
87
|
+
|
|
42
88
|
/**
|
|
43
89
|
* Generic parseProps helper for development-time validation
|
|
44
90
|
*
|