@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.
- package/components.css +1094 -95
- 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/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 +38 -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 +8 -2
- 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/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 +38 -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 +8 -2
- 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 +3 -3
- 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/base-menu.css +4 -5
- package/src/components/_internal/base-sidebar-menu.css +0 -1
- package/src/components/_internal/base-sidebar.css +7 -0
- 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 +370 -0
- package/src/components/schemas/index.ts +46 -0
- package/src/components/schemas/shell.schema.ts +403 -0
- package/src/components/shell.context.tsx +59 -0
- package/src/components/shell.css +33 -18
- package/src/components/shell.hooks.ts +31 -0
- package/src/components/shell.tsx +387 -1682
- package/src/components/shell.types.ts +27 -0
- package/src/components/sidebar.css +233 -33
- package/src/components/sidebar.tsx +248 -214
- package/src/styles/tokens/blur.css +2 -2
- package/src/styles/tokens/color.css +2 -2
- package/styles.css +1267 -181
- package/tokens/base.css +5 -2
- package/tokens.css +5 -2
- 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
|
+
}
|
package/src/components/shell.css
CHANGED
|
@@ -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
|
-
/*
|
|
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
|
+
}
|