@kushagradhawan/kookie-ui 0.1.48 → 0.1.50

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 (139) hide show
  1. package/components.css +1094 -95
  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/schemas/index.d.ts +2 -0
  23. package/dist/cjs/components/schemas/index.d.ts.map +1 -1
  24. package/dist/cjs/components/schemas/index.js +1 -1
  25. package/dist/cjs/components/schemas/index.js.map +3 -3
  26. package/dist/cjs/components/schemas/shell.schema.d.ts +1025 -0
  27. package/dist/cjs/components/schemas/shell.schema.d.ts.map +1 -0
  28. package/dist/cjs/components/schemas/shell.schema.js +2 -0
  29. package/dist/cjs/components/schemas/shell.schema.js.map +7 -0
  30. package/dist/cjs/components/shell.context.d.ts +38 -0
  31. package/dist/cjs/components/shell.context.d.ts.map +1 -0
  32. package/dist/cjs/components/shell.context.js +2 -0
  33. package/dist/cjs/components/shell.context.js.map +7 -0
  34. package/dist/cjs/components/shell.d.ts +6 -68
  35. package/dist/cjs/components/shell.d.ts.map +1 -1
  36. package/dist/cjs/components/shell.hooks.d.ts +3 -0
  37. package/dist/cjs/components/shell.hooks.d.ts.map +1 -0
  38. package/dist/cjs/components/shell.hooks.js +2 -0
  39. package/dist/cjs/components/shell.hooks.js.map +7 -0
  40. package/dist/cjs/components/shell.js +1 -1
  41. package/dist/cjs/components/shell.js.map +3 -3
  42. package/dist/cjs/components/shell.types.d.ts +20 -0
  43. package/dist/cjs/components/shell.types.d.ts.map +1 -0
  44. package/dist/cjs/components/shell.types.js +2 -0
  45. package/dist/cjs/components/shell.types.js.map +7 -0
  46. package/dist/cjs/components/sidebar.d.ts +8 -2
  47. package/dist/cjs/components/sidebar.d.ts.map +1 -1
  48. package/dist/cjs/components/sidebar.js +1 -1
  49. package/dist/cjs/components/sidebar.js.map +3 -3
  50. package/dist/esm/components/_internal/shell-bottom.d.ts +31 -0
  51. package/dist/esm/components/_internal/shell-bottom.d.ts.map +1 -0
  52. package/dist/esm/components/_internal/shell-bottom.js +2 -0
  53. package/dist/esm/components/_internal/shell-bottom.js.map +7 -0
  54. package/dist/esm/components/_internal/shell-handles.d.ts +7 -0
  55. package/dist/esm/components/_internal/shell-handles.d.ts.map +1 -0
  56. package/dist/esm/components/_internal/shell-handles.js +2 -0
  57. package/dist/esm/components/_internal/shell-handles.js.map +7 -0
  58. package/dist/esm/components/_internal/shell-inspector.d.ts +31 -0
  59. package/dist/esm/components/_internal/shell-inspector.d.ts.map +1 -0
  60. package/dist/esm/components/_internal/shell-inspector.js +2 -0
  61. package/dist/esm/components/_internal/shell-inspector.js.map +7 -0
  62. package/dist/esm/components/_internal/shell-resize.d.ts +24 -0
  63. package/dist/esm/components/_internal/shell-resize.d.ts.map +1 -0
  64. package/dist/esm/components/_internal/shell-resize.js +2 -0
  65. package/dist/esm/components/_internal/shell-resize.js.map +7 -0
  66. package/dist/esm/components/_internal/shell-sidebar.d.ts +37 -0
  67. package/dist/esm/components/_internal/shell-sidebar.d.ts.map +1 -0
  68. package/dist/esm/components/_internal/shell-sidebar.js +2 -0
  69. package/dist/esm/components/_internal/shell-sidebar.js.map +7 -0
  70. package/dist/esm/components/schemas/index.d.ts +2 -0
  71. package/dist/esm/components/schemas/index.d.ts.map +1 -1
  72. package/dist/esm/components/schemas/index.js +1 -1
  73. package/dist/esm/components/schemas/index.js.map +3 -3
  74. package/dist/esm/components/schemas/shell.schema.d.ts +1025 -0
  75. package/dist/esm/components/schemas/shell.schema.d.ts.map +1 -0
  76. package/dist/esm/components/schemas/shell.schema.js +2 -0
  77. package/dist/esm/components/schemas/shell.schema.js.map +7 -0
  78. package/dist/esm/components/shell.context.d.ts +38 -0
  79. package/dist/esm/components/shell.context.d.ts.map +1 -0
  80. package/dist/esm/components/shell.context.js +2 -0
  81. package/dist/esm/components/shell.context.js.map +7 -0
  82. package/dist/esm/components/shell.d.ts +6 -68
  83. package/dist/esm/components/shell.d.ts.map +1 -1
  84. package/dist/esm/components/shell.hooks.d.ts +3 -0
  85. package/dist/esm/components/shell.hooks.d.ts.map +1 -0
  86. package/dist/esm/components/shell.hooks.js +2 -0
  87. package/dist/esm/components/shell.hooks.js.map +7 -0
  88. package/dist/esm/components/shell.js +1 -1
  89. package/dist/esm/components/shell.js.map +3 -3
  90. package/dist/esm/components/shell.types.d.ts +20 -0
  91. package/dist/esm/components/shell.types.d.ts.map +1 -0
  92. package/dist/esm/components/shell.types.js +2 -0
  93. package/dist/esm/components/shell.types.js.map +7 -0
  94. package/dist/esm/components/sidebar.d.ts +8 -2
  95. package/dist/esm/components/sidebar.d.ts.map +1 -1
  96. package/dist/esm/components/sidebar.js +1 -1
  97. package/dist/esm/components/sidebar.js.map +3 -3
  98. package/layout/utilities.css +168 -84
  99. package/layout.css +168 -84
  100. package/package.json +2 -1
  101. package/schemas/base-button.json +1 -1
  102. package/schemas/button.json +1 -1
  103. package/schemas/icon-button.json +1 -1
  104. package/schemas/index.json +6 -6
  105. package/schemas/shell-bottom.json +168 -0
  106. package/schemas/shell-content.json +34 -0
  107. package/schemas/shell-handle.json +34 -0
  108. package/schemas/shell-header.json +42 -0
  109. package/schemas/shell-inspector.json +171 -0
  110. package/schemas/shell-panel.json +167 -0
  111. package/schemas/shell-rail.json +132 -0
  112. package/schemas/shell-root.json +54 -0
  113. package/schemas/shell-sidebar.json +182 -0
  114. package/schemas/shell-trigger.json +76 -0
  115. package/schemas/toggle-button.json +1 -1
  116. package/schemas/toggle-icon-button.json +1 -1
  117. package/src/components/_internal/base-menu.css +4 -5
  118. package/src/components/_internal/base-sidebar-menu.css +0 -1
  119. package/src/components/_internal/base-sidebar.css +7 -0
  120. package/src/components/_internal/shell-bottom.tsx +251 -0
  121. package/src/components/_internal/shell-handles.tsx +193 -0
  122. package/src/components/_internal/shell-inspector.tsx +242 -0
  123. package/src/components/_internal/shell-resize.tsx +30 -0
  124. package/src/components/_internal/shell-sidebar.tsx +370 -0
  125. package/src/components/schemas/index.ts +46 -0
  126. package/src/components/schemas/shell.schema.ts +403 -0
  127. package/src/components/shell.context.tsx +59 -0
  128. package/src/components/shell.css +33 -18
  129. package/src/components/shell.hooks.ts +31 -0
  130. package/src/components/shell.tsx +387 -1682
  131. package/src/components/shell.types.ts +27 -0
  132. package/src/components/sidebar.css +233 -33
  133. package/src/components/sidebar.tsx +248 -214
  134. package/src/styles/tokens/blur.css +2 -2
  135. package/src/styles/tokens/color.css +2 -2
  136. package/styles.css +1267 -181
  137. package/tokens/base.css +5 -2
  138. package/tokens.css +5 -2
  139. package/utilities.css +168 -84
@@ -0,0 +1,403 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Shell Zod schema - Single source of truth for Shell component props
5
+ *
6
+ * The Shell component is a layout engine that provides structural patterns for building
7
+ * application interfaces. It manages layout state, composition rules, and responsive
8
+ * behavior across seven core slots.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // Basic shell validation
13
+ * const props = ShellRootSchema.parse({ height: 'full' });
14
+ *
15
+ * // Shell with responsive sidebar
16
+ * const sidebarProps = ShellSidebarSchema.parse({
17
+ * defaultMode: { initial: 'collapsed', md: 'expanded' },
18
+ * presentation: { initial: 'overlay', lg: 'fixed' }
19
+ * });
20
+ * ```
21
+ */
22
+
23
+ // Common types
24
+ const PaneModeSchema = z.enum(['expanded', 'collapsed']).describe('Pane state mode');
25
+ const SidebarModeSchema = z.enum(['collapsed', 'thin', 'expanded']).describe('Sidebar state mode');
26
+ const PresentationValueSchema = z
27
+ .enum(['fixed', 'overlay', 'stacked'])
28
+ .describe('Presentation mode');
29
+ const BreakpointSchema = z
30
+ .enum(['initial', 'xs', 'sm', 'md', 'lg', 'xl'])
31
+ .describe('Responsive breakpoint');
32
+ const PaneTargetSchema = z
33
+ .enum(['left', 'rail', 'panel', 'sidebar', 'inspector', 'bottom'])
34
+ .describe('Pane target');
35
+ const TriggerActionSchema = z.enum(['toggle', 'expand', 'collapse']).describe('Trigger action');
36
+
37
+ // Responsive schemas
38
+ const ResponsiveModeSchema = z
39
+ .union([
40
+ PaneModeSchema,
41
+ z.object({
42
+ initial: PaneModeSchema.optional(),
43
+ xs: PaneModeSchema.optional(),
44
+ sm: PaneModeSchema.optional(),
45
+ md: PaneModeSchema.optional(),
46
+ lg: PaneModeSchema.optional(),
47
+ xl: PaneModeSchema.optional(),
48
+ }),
49
+ ])
50
+ .describe('Responsive pane mode configuration');
51
+
52
+ const ResponsiveSidebarModeSchema = z
53
+ .union([
54
+ SidebarModeSchema,
55
+ z.object({
56
+ initial: SidebarModeSchema.optional(),
57
+ xs: SidebarModeSchema.optional(),
58
+ sm: SidebarModeSchema.optional(),
59
+ md: SidebarModeSchema.optional(),
60
+ lg: SidebarModeSchema.optional(),
61
+ xl: SidebarModeSchema.optional(),
62
+ }),
63
+ ])
64
+ .describe('Responsive sidebar mode configuration');
65
+
66
+ const ResponsivePresentationSchema = z
67
+ .union([
68
+ PresentationValueSchema,
69
+ z.object({
70
+ initial: PresentationValueSchema.optional(),
71
+ xs: PresentationValueSchema.optional(),
72
+ sm: PresentationValueSchema.optional(),
73
+ md: PresentationValueSchema.optional(),
74
+ lg: PresentationValueSchema.optional(),
75
+ xl: PresentationValueSchema.optional(),
76
+ }),
77
+ ])
78
+ .describe('Responsive presentation configuration');
79
+
80
+ // Size persistence adapter
81
+ const PaneSizePersistenceSchema = z
82
+ .object({
83
+ load: z
84
+ .function()
85
+ .returns(z.union([z.number(), z.promise(z.number()), z.undefined()]))
86
+ .optional(),
87
+ save: z
88
+ .function()
89
+ .args(z.number())
90
+ .returns(z.union([z.void(), z.promise(z.void())]))
91
+ .optional(),
92
+ })
93
+ .describe('Size persistence adapter');
94
+
95
+ // Common pane props
96
+ const PanePropsSchema = z
97
+ .object({
98
+ presentation: ResponsivePresentationSchema.optional(),
99
+ mode: PaneModeSchema.optional(),
100
+ defaultMode: ResponsiveModeSchema.optional(),
101
+ onModeChange: z.function().args(PaneModeSchema).returns(z.void()).optional(),
102
+ expandedSize: z.number().optional(),
103
+ minSize: z.number().optional(),
104
+ maxSize: z.number().optional(),
105
+ resizable: z.boolean().optional(),
106
+ collapsible: z.boolean().optional(),
107
+ onExpand: z.function().returns(z.void()).optional(),
108
+ onCollapse: z.function().returns(z.void()).optional(),
109
+ onResize: z.function().args(z.number()).returns(z.void()).optional(),
110
+ resizer: z.any().optional(),
111
+ onResizeStart: z.function().args(z.number()).returns(z.void()).optional(),
112
+ onResizeEnd: z.function().args(z.number()).returns(z.void()).optional(),
113
+ snapPoints: z.array(z.number()).optional(),
114
+ snapTolerance: z.number().optional(),
115
+ collapseThreshold: z.number().optional(),
116
+ paneId: z.string().optional(),
117
+ persistence: PaneSizePersistenceSchema.optional(),
118
+ className: z.string().optional(),
119
+ style: z.record(z.string(), z.union([z.string(), z.number()])).optional(),
120
+ children: z.any().optional(),
121
+ })
122
+ .strict();
123
+
124
+ /**
125
+ * Shell.Root component schema
126
+ */
127
+ export const ShellRootSchema = z
128
+ .object({
129
+ height: z
130
+ .union([z.literal('full'), z.literal('auto'), z.string(), z.number()])
131
+ .default('full')
132
+ .describe('Height of the shell container'),
133
+ className: z.string().optional().describe('Additional CSS class name'),
134
+ style: z
135
+ .record(z.string(), z.union([z.string(), z.number()]))
136
+ .optional()
137
+ .describe('Inline styles'),
138
+ children: z.any().optional().describe('Shell components'),
139
+ })
140
+ .strict();
141
+
142
+ /**
143
+ * Shell.Header component schema
144
+ */
145
+ export const ShellHeaderSchema = z
146
+ .object({
147
+ height: z.union([z.string(), z.number()]).default(64).describe('Height of the header'),
148
+ className: z.string().optional().describe('Additional CSS class name'),
149
+ style: z
150
+ .record(z.string(), z.union([z.string(), z.number()]))
151
+ .optional()
152
+ .describe('Inline styles'),
153
+ children: z.any().optional().describe('Header content'),
154
+ })
155
+ .strict();
156
+
157
+ /**
158
+ * Shell.Rail component schema
159
+ */
160
+ export const ShellRailSchema = z
161
+ .object({
162
+ presentation: ResponsivePresentationSchema.optional(),
163
+ mode: PaneModeSchema.optional(),
164
+ defaultMode: ResponsiveModeSchema.optional(),
165
+ onModeChange: z.function().args(PaneModeSchema).returns(z.void()).optional(),
166
+ expandedSize: z.number().default(64).describe('Default width in pixels'),
167
+ collapsible: z.boolean().optional(),
168
+ onExpand: z.function().returns(z.void()).optional(),
169
+ onCollapse: z.function().returns(z.void()).optional(),
170
+ className: z.string().optional().describe('Additional CSS class name'),
171
+ style: z
172
+ .record(z.string(), z.union([z.string(), z.number()]))
173
+ .optional()
174
+ .describe('Inline styles'),
175
+ children: z.any().optional().describe('Rail content'),
176
+ })
177
+ .strict();
178
+
179
+ /**
180
+ * Shell.Panel component schema
181
+ */
182
+ export const ShellPanelSchema = PanePropsSchema.extend({
183
+ expandedSize: z.number().default(288).describe('Default width in pixels'),
184
+ minSize: z.number().default(200).describe('Minimum width when resizing'),
185
+ maxSize: z.number().default(800).describe('Maximum width when resizing'),
186
+ resizable: z.boolean().default(false).describe('Whether the panel can be resized'),
187
+ collapsible: z
188
+ .boolean()
189
+ .default(true)
190
+ .describe('Whether the panel can be collapsed via resize handle'),
191
+ }).strict();
192
+
193
+ /**
194
+ * Shell.Sidebar component schema
195
+ */
196
+ export const ShellSidebarSchema = PanePropsSchema.extend({
197
+ mode: SidebarModeSchema.optional(),
198
+ defaultMode: ResponsiveSidebarModeSchema.default('expanded').describe('Initial sidebar mode'),
199
+ expandedSize: z.number().default(288).describe('Default width in pixels'),
200
+ minSize: z.number().default(200).describe('Minimum width when resizing'),
201
+ maxSize: z.number().default(400).describe('Maximum width when resizing'),
202
+ thinSize: z.number().default(64).describe('Width in thin mode'),
203
+ toggleModes: z.enum(['both', 'single']).optional().describe('Available modes in toggle sequence'),
204
+ resizable: z.boolean().default(false).describe('Whether the sidebar can be resized'),
205
+ collapsible: z
206
+ .boolean()
207
+ .default(true)
208
+ .describe('Whether the sidebar can be collapsed via resize handle'),
209
+ }).strict();
210
+
211
+ /**
212
+ * Shell.Content component schema
213
+ */
214
+ export const ShellContentSchema = z
215
+ .object({
216
+ className: z.string().optional().describe('Additional CSS class name'),
217
+ style: z
218
+ .record(z.string(), z.union([z.string(), z.number()]))
219
+ .optional()
220
+ .describe('Inline styles'),
221
+ children: z.any().optional().describe('Main content'),
222
+ })
223
+ .strict();
224
+
225
+ /**
226
+ * Shell.Inspector component schema
227
+ */
228
+ export const ShellInspectorSchema = PanePropsSchema.extend({
229
+ presentation: ResponsivePresentationSchema.default({ initial: 'overlay', lg: 'fixed' }).describe(
230
+ 'Presentation mode',
231
+ ),
232
+ expandedSize: z.number().default(320).describe('Default width in pixels'),
233
+ minSize: z.number().default(200).describe('Minimum width when resizing'),
234
+ maxSize: z.number().default(500).describe('Maximum width when resizing'),
235
+ resizable: z.boolean().default(false).describe('Whether the inspector can be resized'),
236
+ collapsible: z
237
+ .boolean()
238
+ .default(true)
239
+ .describe('Whether the inspector can be collapsed via resize handle'),
240
+ }).strict();
241
+
242
+ /**
243
+ * Shell.Bottom component schema
244
+ */
245
+ export const ShellBottomSchema = PanePropsSchema.extend({
246
+ presentation: ResponsivePresentationSchema.default('fixed').describe('Presentation mode'),
247
+ expandedSize: z.number().default(200).describe('Default height in pixels'),
248
+ minSize: z.number().default(100).describe('Minimum height when resizing'),
249
+ maxSize: z.number().default(400).describe('Maximum height when resizing'),
250
+ resizable: z.boolean().default(false).describe('Whether the bottom panel can be resized'),
251
+ collapsible: z
252
+ .boolean()
253
+ .default(true)
254
+ .describe('Whether the bottom panel can be collapsed via resize handle'),
255
+ }).strict();
256
+
257
+ /**
258
+ * Shell.Trigger component schema
259
+ */
260
+ export const ShellTriggerSchema = z
261
+ .object({
262
+ target: PaneTargetSchema.describe('Which pane to control'),
263
+ action: TriggerActionSchema.default('toggle').describe('Action to perform'),
264
+ peekOnHover: z
265
+ .boolean()
266
+ .default(false)
267
+ .describe('Whether to show peek preview on hover when collapsed'),
268
+ className: z.string().optional().describe('Additional CSS class name'),
269
+ style: z
270
+ .record(z.string(), z.union([z.string(), z.number()]))
271
+ .optional()
272
+ .describe('Inline styles'),
273
+ children: z.any().optional().describe('Trigger content'),
274
+ onClick: z.function().optional().describe('Click handler'),
275
+ onMouseEnter: z.function().optional().describe('Mouse enter handler'),
276
+ onMouseLeave: z.function().optional().describe('Mouse leave handler'),
277
+ 'aria-label': z.string().optional().describe('ARIA label for accessibility'),
278
+ 'aria-labelledby': z.string().optional().describe('ARIA labelled by reference'),
279
+ 'aria-describedby': z.string().optional().describe('ARIA described by reference'),
280
+ })
281
+ .strict();
282
+
283
+ /**
284
+ * Shell.Handle component schema (for resize handles)
285
+ */
286
+ export const ShellHandleSchema = z
287
+ .object({
288
+ className: z.string().optional().describe('Additional CSS class name'),
289
+ style: z
290
+ .record(z.string(), z.union([z.string(), z.number()]))
291
+ .optional()
292
+ .describe('Inline styles'),
293
+ children: z.any().optional().describe('Handle content'),
294
+ })
295
+ .strict();
296
+
297
+ // Type exports
298
+ export type ShellRootProps = z.infer<typeof ShellRootSchema>;
299
+ export type ShellHeaderProps = z.infer<typeof ShellHeaderSchema>;
300
+ export type ShellRailProps = z.infer<typeof ShellRailSchema>;
301
+ export type ShellPanelProps = z.infer<typeof ShellPanelSchema>;
302
+ export type ShellSidebarProps = z.infer<typeof ShellSidebarSchema>;
303
+ export type ShellContentProps = z.infer<typeof ShellContentSchema>;
304
+ export type ShellInspectorProps = z.infer<typeof ShellInspectorSchema>;
305
+ export type ShellBottomProps = z.infer<typeof ShellBottomSchema>;
306
+ export type ShellTriggerProps = z.infer<typeof ShellTriggerSchema>;
307
+ export type ShellHandleProps = z.infer<typeof ShellHandleSchema>;
308
+
309
+ // Common type exports
310
+ export type PaneMode = z.infer<typeof PaneModeSchema>;
311
+ export type SidebarMode = z.infer<typeof SidebarModeSchema>;
312
+ export type PresentationValue = z.infer<typeof PresentationValueSchema>;
313
+ export type Breakpoint = z.infer<typeof BreakpointSchema>;
314
+ export type PaneTarget = z.infer<typeof PaneTargetSchema>;
315
+ export type TriggerAction = z.infer<typeof TriggerActionSchema>;
316
+ export type ResponsiveMode = z.infer<typeof ResponsiveModeSchema>;
317
+ export type ResponsiveSidebarMode = z.infer<typeof ResponsiveSidebarModeSchema>;
318
+ export type ResponsivePresentation = z.infer<typeof ResponsivePresentationSchema>;
319
+ export type PaneSizePersistence = z.infer<typeof PaneSizePersistenceSchema>;
320
+
321
+ /**
322
+ * Development-only helper to validate and normalize Shell props
323
+ * This function should only be used in development mode
324
+ *
325
+ * @param props - Props to validate and normalize
326
+ * @returns Validated and normalized props
327
+ *
328
+ * @example
329
+ * ```tsx
330
+ * // In development, this will validate props and show helpful errors
331
+ * const validatedProps = parseShellRootProps({ height: 'invalid' });
332
+ * // Throws validation errors for invalid values
333
+ * ```
334
+ */
335
+ export function parseShellRootProps(props: unknown): ShellRootProps {
336
+ if (process.env.NODE_ENV === 'development') {
337
+ return ShellRootSchema.parse(props);
338
+ }
339
+ return props as ShellRootProps;
340
+ }
341
+
342
+ export function parseShellHeaderProps(props: unknown): ShellHeaderProps {
343
+ if (process.env.NODE_ENV === 'development') {
344
+ return ShellHeaderSchema.parse(props);
345
+ }
346
+ return props as ShellHeaderProps;
347
+ }
348
+
349
+ export function parseShellRailProps(props: unknown): ShellRailProps {
350
+ if (process.env.NODE_ENV === 'development') {
351
+ return ShellRailSchema.parse(props);
352
+ }
353
+ return props as ShellRailProps;
354
+ }
355
+
356
+ export function parseShellPanelProps(props: unknown): ShellPanelProps {
357
+ if (process.env.NODE_ENV === 'development') {
358
+ return ShellPanelSchema.parse(props);
359
+ }
360
+ return props as ShellPanelProps;
361
+ }
362
+
363
+ export function parseShellSidebarProps(props: unknown): ShellSidebarProps {
364
+ if (process.env.NODE_ENV === 'development') {
365
+ return ShellSidebarSchema.parse(props);
366
+ }
367
+ return props as ShellSidebarProps;
368
+ }
369
+
370
+ export function parseShellContentProps(props: unknown): ShellContentProps {
371
+ if (process.env.NODE_ENV === 'development') {
372
+ return ShellContentSchema.parse(props);
373
+ }
374
+ return props as ShellContentProps;
375
+ }
376
+
377
+ export function parseShellInspectorProps(props: unknown): ShellInspectorProps {
378
+ if (process.env.NODE_ENV === 'development') {
379
+ return ShellInspectorSchema.parse(props);
380
+ }
381
+ return props as ShellInspectorProps;
382
+ }
383
+
384
+ export function parseShellBottomProps(props: unknown): ShellBottomProps {
385
+ if (process.env.NODE_ENV === 'development') {
386
+ return ShellBottomSchema.parse(props);
387
+ }
388
+ return props as ShellBottomProps;
389
+ }
390
+
391
+ export function parseShellTriggerProps(props: unknown): ShellTriggerProps {
392
+ if (process.env.NODE_ENV === 'development') {
393
+ return ShellTriggerSchema.parse(props);
394
+ }
395
+ return props as ShellTriggerProps;
396
+ }
397
+
398
+ export function parseShellHandleProps(props: unknown): ShellHandleProps {
399
+ if (process.env.NODE_ENV === 'development') {
400
+ return ShellHandleSchema.parse(props);
401
+ }
402
+ return props as ShellHandleProps;
403
+ }
@@ -0,0 +1,59 @@
1
+ import * as React from 'react';
2
+ import type { Breakpoint, PresentationValue, SidebarMode, PaneMode, PaneTarget } from './shell.types.js';
3
+
4
+ export interface ShellContextValue {
5
+ // Pane states
6
+ leftMode: PaneMode;
7
+ setLeftMode: (mode: PaneMode) => void;
8
+ panelMode: PaneMode; // Panel state within left container
9
+ setPanelMode: (mode: PaneMode) => void;
10
+ sidebarMode: SidebarMode;
11
+ setSidebarMode: (mode: SidebarMode) => void;
12
+ inspectorMode: PaneMode;
13
+ setInspectorMode: (mode: PaneMode) => void;
14
+ bottomMode: PaneMode;
15
+ setBottomMode: (mode: PaneMode) => void;
16
+
17
+ // Peek state (layout-only, ephemeral)
18
+ peekTarget: PaneTarget | null;
19
+ setPeekTarget: (target: PaneTarget | null) => void;
20
+ peekPane: (target: PaneTarget) => void;
21
+ clearPeek: () => void;
22
+
23
+ // Sidebar presentation sequencing phase (library-managed)
24
+ sidebarPhase?: 'idle' | 'hiding' | 'resizing' | 'showing';
25
+
26
+ // Composition detection
27
+ hasLeft: boolean;
28
+ setHasLeft: (has: boolean) => void;
29
+ hasSidebar: boolean;
30
+ setHasSidebar: (has: boolean) => void;
31
+
32
+ // Presentation resolution
33
+ currentBreakpoint: Breakpoint;
34
+ currentBreakpointReady: boolean;
35
+ leftResolvedPresentation?: PresentationValue;
36
+
37
+ // Actions
38
+ togglePane: (target: PaneTarget) => void;
39
+ expandPane: (target: PaneTarget) => void;
40
+ collapsePane: (target: PaneTarget) => void;
41
+ // Toggle customization
42
+ setSidebarToggleComputer?: (fn: (current: SidebarMode) => SidebarMode) => void;
43
+ // Dev-only hooks for presentation warnings
44
+ onLeftPres?: (p: PresentationValue) => void;
45
+ // Sizing info for overlay grouping
46
+ onLeftDefaults?: (size: number) => void;
47
+ }
48
+
49
+ const ShellContext = React.createContext<ShellContextValue | null>(null);
50
+
51
+ export function useShell() {
52
+ const ctx = React.useContext(ShellContext);
53
+ if (!ctx) throw new Error('Shell components must be used within <Shell.Root>');
54
+ return ctx;
55
+ }
56
+
57
+ export function ShellProvider({ value, children }: { value: ShellContextValue; children: React.ReactNode }) {
58
+ return <ShellContext.Provider value={value}>{children}</ShellContext.Provider>;
59
+ }
@@ -33,7 +33,6 @@
33
33
  z-index: 50;
34
34
  height: var(--shell-header-height, 64px);
35
35
  min-height: var(--shell-header-height, 64px);
36
- background-color: var(--color-panel);
37
36
  display: flex;
38
37
  align-items: center;
39
38
  flex-shrink: 0;
@@ -63,7 +62,6 @@
63
62
  display: flex;
64
63
  flex-direction: column;
65
64
  height: 100%;
66
- background-color: var(--color-surface);
67
65
  overflow: hidden;
68
66
 
69
67
  /* Animation setup */
@@ -76,6 +74,8 @@
76
74
 
77
75
  .rt-ShellRail[data-mode='collapsed'] {
78
76
  width: 0px;
77
+ /* Delay container collapse until content fade completes */
78
+ transition-delay: var(--motion-duration-small);
79
79
  }
80
80
 
81
81
  /* Keep collapsed panes out of flow to avoid layout blips when exiting peek */
@@ -97,8 +97,7 @@
97
97
 
98
98
  /* Content animation: fade out first, then fade in after width settles */
99
99
  opacity: 0;
100
- transition: opacity var(--motion-duration-small) var(--motion-ease-standard)
101
- var(--motion-duration-small);
100
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard) var(--motion-duration-small);
102
101
  }
103
102
 
104
103
  .rt-ShellRailContent[data-visible] {
@@ -116,7 +115,6 @@
116
115
  display: flex;
117
116
  flex-direction: column;
118
117
  height: 100%;
119
- background-color: var(--color-panel);
120
118
  /* Allow handle to bleed across boundary */
121
119
  overflow: visible;
122
120
  position: relative;
@@ -132,6 +130,8 @@
132
130
 
133
131
  .rt-ShellPanel:not([data-visible]) {
134
132
  width: 0px;
133
+ /* Delay container collapse until content fade completes */
134
+ transition-delay: var(--motion-duration-small);
135
135
  }
136
136
 
137
137
  /* Keep collapsed panel out of flow to avoid layout blips when exiting peek */
@@ -150,8 +150,7 @@
150
150
 
151
151
  /* Content animation */
152
152
  opacity: 0;
153
- transition: opacity var(--motion-duration-small) var(--motion-ease-standard)
154
- var(--motion-duration-small);
153
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard) var(--motion-duration-small);
155
154
  }
156
155
 
157
156
  .rt-ShellPanelContent[data-visible] {
@@ -169,7 +168,6 @@
169
168
  display: flex;
170
169
  flex-direction: column;
171
170
  height: 100%;
172
- background-color: var(--color-panel);
173
171
  /* Allow handle to bleed across boundary */
174
172
  overflow: visible;
175
173
  position: relative;
@@ -194,6 +192,8 @@
194
192
 
195
193
  .rt-ShellSidebar[data-mode='collapsed'] {
196
194
  width: 0px;
195
+ /* Delay container collapse until content fade completes */
196
+ transition-delay: var(--motion-duration-small);
197
197
  }
198
198
 
199
199
  /* Keep collapsed sidebar out of flow to avoid layout blips when exiting peek */
@@ -212,8 +212,7 @@
212
212
 
213
213
  /* Content animation */
214
214
  opacity: 0;
215
- transition: opacity var(--motion-duration-small) var(--motion-ease-standard)
216
- var(--motion-duration-small);
215
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard) var(--motion-duration-small);
217
216
  }
218
217
 
219
218
  /* Hide resizer in thin mode */
@@ -225,6 +224,22 @@
225
224
  opacity: 1;
226
225
  }
227
226
 
227
+ /* Sidebar presentation switch sequencing (thin ↔ expanded) */
228
+ .rt-ShellSidebarContent[data-phase='hiding'] {
229
+ /* Immediately fade out */
230
+ opacity: 0;
231
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard);
232
+ }
233
+ .rt-ShellSidebarContent[data-phase='resizing'] {
234
+ /* Keep hidden during width transition */
235
+ opacity: 0;
236
+ }
237
+ .rt-ShellSidebarContent[data-phase='showing'] {
238
+ /* Fade back in after width settles */
239
+ opacity: 1;
240
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard);
241
+ }
242
+
228
243
  .rt-ShellSidebar[data-mode='collapsed'] .rt-ShellSidebarContent {
229
244
  /* Exit animation: fade out content first */
230
245
  opacity: 0;
@@ -259,7 +274,6 @@
259
274
  min-width: 0;
260
275
  height: 100%;
261
276
  overflow: auto;
262
- background-color: var(--color-surface);
263
277
  }
264
278
 
265
279
  /* Inspector - right-side panel */
@@ -267,7 +281,6 @@
267
281
  display: flex;
268
282
  flex-direction: column;
269
283
  height: 100%;
270
- background-color: var(--color-panel);
271
284
  /* Allow handle to bleed across boundary */
272
285
  overflow: visible;
273
286
  position: relative;
@@ -283,6 +296,8 @@
283
296
 
284
297
  .rt-ShellInspector[data-mode='collapsed'] {
285
298
  width: 0px;
299
+ /* Delay container collapse until content fade completes */
300
+ transition-delay: var(--motion-duration-small);
286
301
  }
287
302
 
288
303
  .rt-ShellInspector[data-mode='collapsed'] {
@@ -300,8 +315,7 @@
300
315
 
301
316
  /* Content animation */
302
317
  opacity: 0;
303
- transition: opacity var(--motion-duration-small) var(--motion-ease-standard)
304
- var(--motion-duration-small);
318
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard) var(--motion-duration-small);
305
319
  }
306
320
 
307
321
  .rt-ShellInspectorContent[data-visible] {
@@ -319,7 +333,6 @@
319
333
  display: flex;
320
334
  flex-direction: column;
321
335
  width: 100%;
322
- background-color: var(--color-panel);
323
336
  /* Allow handle to bleed across boundary */
324
337
  overflow: visible;
325
338
  flex-shrink: 0;
@@ -338,6 +351,8 @@
338
351
  position: absolute;
339
352
  inset-inline: 0;
340
353
  inset-block-end: 0;
354
+ /* Delay container collapse until content fade completes */
355
+ transition-delay: var(--motion-duration-small);
341
356
  }
342
357
 
343
358
  .rt-ShellBottomContent {
@@ -349,8 +364,7 @@
349
364
 
350
365
  /* Content animation */
351
366
  opacity: 0;
352
- transition: opacity var(--motion-duration-small) var(--motion-ease-standard)
353
- var(--motion-duration-small);
367
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard) var(--motion-duration-small);
354
368
  }
355
369
 
356
370
  .rt-ShellBottomContent[data-visible] {
@@ -549,13 +563,14 @@
549
563
  box-shadow: 0 -4px 8px -4px rgba(0, 0, 0, 0.15);
550
564
  }
551
565
 
552
- /* Force content visible during peek */
566
+ /* Peek: expand container first, then fade content in */
553
567
  .rt-ShellRail[data-peek] .rt-ShellRailContent,
554
568
  .rt-ShellPanel[data-peek] .rt-ShellPanelContent,
555
569
  .rt-ShellSidebar[data-peek] .rt-ShellSidebarContent,
556
570
  .rt-ShellInspector[data-peek] .rt-ShellInspectorContent,
557
571
  .rt-ShellBottom[data-peek] .rt-ShellBottomContent {
558
572
  opacity: 1;
573
+ transition-delay: var(--motion-duration-small);
559
574
  }
560
575
 
561
576
  /* Rail peek: left edge */
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ import type { Breakpoint, PresentationValue, ResponsivePresentation } from './shell.types.js';
3
+ import { BREAKPOINTS } from './shell.types.js';
4
+ import { useShell } from './shell.context.js';
5
+
6
+ export function useResponsivePresentation(presentation: ResponsivePresentation): PresentationValue {
7
+ const { currentBreakpoint } = useShell();
8
+
9
+ return React.useMemo(() => {
10
+ if (typeof presentation === 'string') {
11
+ return presentation;
12
+ }
13
+
14
+ if (presentation[currentBreakpoint]) {
15
+ return presentation[currentBreakpoint]!;
16
+ }
17
+
18
+ const bpKeys = Object.keys(BREAKPOINTS) as Array<keyof typeof BREAKPOINTS>;
19
+ const order: Breakpoint[] = ([...bpKeys].reverse() as Breakpoint[]).concat('initial' as Breakpoint);
20
+ const startIdx = order.indexOf(currentBreakpoint as Breakpoint);
21
+
22
+ for (let i = startIdx + 1; i < order.length; i++) {
23
+ const bp = order[i];
24
+ if (presentation[bp]) {
25
+ return presentation[bp]!;
26
+ }
27
+ }
28
+
29
+ return 'fixed';
30
+ }, [presentation, currentBreakpoint]);
31
+ }