@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.
Files changed (149) hide show
  1. package/components.css +858 -30
  2. package/dist/cjs/components/_internal/shell-bottom.d.ts +31 -0
  3. package/dist/cjs/components/_internal/shell-bottom.d.ts.map +1 -0
  4. package/dist/cjs/components/_internal/shell-bottom.js +2 -0
  5. package/dist/cjs/components/_internal/shell-bottom.js.map +7 -0
  6. package/dist/cjs/components/_internal/shell-handles.d.ts +7 -0
  7. package/dist/cjs/components/_internal/shell-handles.d.ts.map +1 -0
  8. package/dist/cjs/components/_internal/shell-handles.js +2 -0
  9. package/dist/cjs/components/_internal/shell-handles.js.map +7 -0
  10. package/dist/cjs/components/_internal/shell-inspector.d.ts +31 -0
  11. package/dist/cjs/components/_internal/shell-inspector.d.ts.map +1 -0
  12. package/dist/cjs/components/_internal/shell-inspector.js +2 -0
  13. package/dist/cjs/components/_internal/shell-inspector.js.map +7 -0
  14. package/dist/cjs/components/_internal/shell-resize.d.ts +24 -0
  15. package/dist/cjs/components/_internal/shell-resize.d.ts.map +1 -0
  16. package/dist/cjs/components/_internal/shell-resize.js +2 -0
  17. package/dist/cjs/components/_internal/shell-resize.js.map +7 -0
  18. package/dist/cjs/components/_internal/shell-sidebar.d.ts +37 -0
  19. package/dist/cjs/components/_internal/shell-sidebar.d.ts.map +1 -0
  20. package/dist/cjs/components/_internal/shell-sidebar.js +2 -0
  21. package/dist/cjs/components/_internal/shell-sidebar.js.map +7 -0
  22. package/dist/cjs/components/alert-dialog.d.ts.map +1 -1
  23. package/dist/cjs/components/alert-dialog.js +1 -1
  24. package/dist/cjs/components/alert-dialog.js.map +2 -2
  25. package/dist/cjs/components/dialog.d.ts.map +1 -1
  26. package/dist/cjs/components/dialog.js +1 -1
  27. package/dist/cjs/components/dialog.js.map +2 -2
  28. package/dist/cjs/components/schemas/index.d.ts +2 -0
  29. package/dist/cjs/components/schemas/index.d.ts.map +1 -1
  30. package/dist/cjs/components/schemas/index.js +1 -1
  31. package/dist/cjs/components/schemas/index.js.map +3 -3
  32. package/dist/cjs/components/schemas/shell.schema.d.ts +1025 -0
  33. package/dist/cjs/components/schemas/shell.schema.d.ts.map +1 -0
  34. package/dist/cjs/components/schemas/shell.schema.js +2 -0
  35. package/dist/cjs/components/schemas/shell.schema.js.map +7 -0
  36. package/dist/cjs/components/shell.context.d.ts +37 -0
  37. package/dist/cjs/components/shell.context.d.ts.map +1 -0
  38. package/dist/cjs/components/shell.context.js +2 -0
  39. package/dist/cjs/components/shell.context.js.map +7 -0
  40. package/dist/cjs/components/shell.d.ts +6 -68
  41. package/dist/cjs/components/shell.d.ts.map +1 -1
  42. package/dist/cjs/components/shell.hooks.d.ts +3 -0
  43. package/dist/cjs/components/shell.hooks.d.ts.map +1 -0
  44. package/dist/cjs/components/shell.hooks.js +2 -0
  45. package/dist/cjs/components/shell.hooks.js.map +7 -0
  46. package/dist/cjs/components/shell.js +1 -1
  47. package/dist/cjs/components/shell.js.map +3 -3
  48. package/dist/cjs/components/shell.types.d.ts +20 -0
  49. package/dist/cjs/components/shell.types.d.ts.map +1 -0
  50. package/dist/cjs/components/shell.types.js +2 -0
  51. package/dist/cjs/components/shell.types.js.map +7 -0
  52. package/dist/cjs/components/sidebar.d.ts +1 -1
  53. package/dist/cjs/components/sidebar.d.ts.map +1 -1
  54. package/dist/cjs/components/sidebar.js +1 -1
  55. package/dist/cjs/components/sidebar.js.map +3 -3
  56. package/dist/esm/components/_internal/shell-bottom.d.ts +31 -0
  57. package/dist/esm/components/_internal/shell-bottom.d.ts.map +1 -0
  58. package/dist/esm/components/_internal/shell-bottom.js +2 -0
  59. package/dist/esm/components/_internal/shell-bottom.js.map +7 -0
  60. package/dist/esm/components/_internal/shell-handles.d.ts +7 -0
  61. package/dist/esm/components/_internal/shell-handles.d.ts.map +1 -0
  62. package/dist/esm/components/_internal/shell-handles.js +2 -0
  63. package/dist/esm/components/_internal/shell-handles.js.map +7 -0
  64. package/dist/esm/components/_internal/shell-inspector.d.ts +31 -0
  65. package/dist/esm/components/_internal/shell-inspector.d.ts.map +1 -0
  66. package/dist/esm/components/_internal/shell-inspector.js +2 -0
  67. package/dist/esm/components/_internal/shell-inspector.js.map +7 -0
  68. package/dist/esm/components/_internal/shell-resize.d.ts +24 -0
  69. package/dist/esm/components/_internal/shell-resize.d.ts.map +1 -0
  70. package/dist/esm/components/_internal/shell-resize.js +2 -0
  71. package/dist/esm/components/_internal/shell-resize.js.map +7 -0
  72. package/dist/esm/components/_internal/shell-sidebar.d.ts +37 -0
  73. package/dist/esm/components/_internal/shell-sidebar.d.ts.map +1 -0
  74. package/dist/esm/components/_internal/shell-sidebar.js +2 -0
  75. package/dist/esm/components/_internal/shell-sidebar.js.map +7 -0
  76. package/dist/esm/components/alert-dialog.d.ts.map +1 -1
  77. package/dist/esm/components/alert-dialog.js +1 -1
  78. package/dist/esm/components/alert-dialog.js.map +2 -2
  79. package/dist/esm/components/dialog.d.ts.map +1 -1
  80. package/dist/esm/components/dialog.js +1 -1
  81. package/dist/esm/components/dialog.js.map +2 -2
  82. package/dist/esm/components/schemas/index.d.ts +2 -0
  83. package/dist/esm/components/schemas/index.d.ts.map +1 -1
  84. package/dist/esm/components/schemas/index.js +1 -1
  85. package/dist/esm/components/schemas/index.js.map +3 -3
  86. package/dist/esm/components/schemas/shell.schema.d.ts +1025 -0
  87. package/dist/esm/components/schemas/shell.schema.d.ts.map +1 -0
  88. package/dist/esm/components/schemas/shell.schema.js +2 -0
  89. package/dist/esm/components/schemas/shell.schema.js.map +7 -0
  90. package/dist/esm/components/shell.context.d.ts +37 -0
  91. package/dist/esm/components/shell.context.d.ts.map +1 -0
  92. package/dist/esm/components/shell.context.js +2 -0
  93. package/dist/esm/components/shell.context.js.map +7 -0
  94. package/dist/esm/components/shell.d.ts +6 -68
  95. package/dist/esm/components/shell.d.ts.map +1 -1
  96. package/dist/esm/components/shell.hooks.d.ts +3 -0
  97. package/dist/esm/components/shell.hooks.d.ts.map +1 -0
  98. package/dist/esm/components/shell.hooks.js +2 -0
  99. package/dist/esm/components/shell.hooks.js.map +7 -0
  100. package/dist/esm/components/shell.js +1 -1
  101. package/dist/esm/components/shell.js.map +3 -3
  102. package/dist/esm/components/shell.types.d.ts +20 -0
  103. package/dist/esm/components/shell.types.d.ts.map +1 -0
  104. package/dist/esm/components/shell.types.js +2 -0
  105. package/dist/esm/components/shell.types.js.map +7 -0
  106. package/dist/esm/components/sidebar.d.ts +1 -1
  107. package/dist/esm/components/sidebar.d.ts.map +1 -1
  108. package/dist/esm/components/sidebar.js +1 -1
  109. package/dist/esm/components/sidebar.js.map +2 -2
  110. package/layout/utilities.css +168 -84
  111. package/layout.css +168 -84
  112. package/package.json +2 -1
  113. package/schemas/base-button.json +1 -1
  114. package/schemas/button.json +1 -1
  115. package/schemas/icon-button.json +1 -1
  116. package/schemas/index.json +6 -6
  117. package/schemas/shell-bottom.json +168 -0
  118. package/schemas/shell-content.json +34 -0
  119. package/schemas/shell-handle.json +34 -0
  120. package/schemas/shell-header.json +42 -0
  121. package/schemas/shell-inspector.json +171 -0
  122. package/schemas/shell-panel.json +167 -0
  123. package/schemas/shell-rail.json +132 -0
  124. package/schemas/shell-root.json +54 -0
  125. package/schemas/shell-sidebar.json +182 -0
  126. package/schemas/shell-trigger.json +76 -0
  127. package/schemas/toggle-button.json +1 -1
  128. package/schemas/toggle-icon-button.json +1 -1
  129. package/src/components/_internal/shell-bottom.tsx +251 -0
  130. package/src/components/_internal/shell-handles.tsx +193 -0
  131. package/src/components/_internal/shell-inspector.tsx +242 -0
  132. package/src/components/_internal/shell-resize.tsx +30 -0
  133. package/src/components/_internal/shell-sidebar.tsx +347 -0
  134. package/src/components/alert-dialog.tsx +6 -0
  135. package/src/components/dialog.tsx +6 -0
  136. package/src/components/schemas/index.ts +46 -0
  137. package/src/components/schemas/shell.schema.ts +403 -0
  138. package/src/components/shell.context.tsx +56 -0
  139. package/src/components/shell.css +5 -17
  140. package/src/components/shell.hooks.ts +31 -0
  141. package/src/components/shell.tsx +368 -1684
  142. package/src/components/shell.types.ts +27 -0
  143. package/src/components/sidebar.tsx +1 -1
  144. package/src/styles/tokens/blur.css +2 -2
  145. package/src/styles/tokens/color.css +2 -2
  146. package/styles.css +1031 -116
  147. package/tokens/base.css +5 -2
  148. package/tokens.css +5 -2
  149. 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
  *