shadcn-glass-ui 2.1.2 → 2.1.5
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/README.md +5 -5
- package/context7.json +17 -2
- package/dist/cli/index.cjs +1 -1
- package/dist/components.cjs +4 -4
- package/dist/components.js +1 -1
- package/dist/hooks.cjs +2 -2
- package/dist/index.cjs +1659 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1651 -4
- package/dist/index.js.map +1 -1
- package/dist/r/registry.json +36 -0
- package/dist/r/sidebar-context.json +35 -0
- package/dist/r/sidebar-glass.json +40 -0
- package/dist/r/sidebar-menu.json +39 -0
- package/dist/r/split-layout-accordion.json +24 -0
- package/dist/r/split-layout-context.json +21 -0
- package/dist/r/split-layout-glass.json +25 -0
- package/dist/shadcn-glass-ui.css +1 -1
- package/dist/{theme-context-BHXYJ4RE.cjs → theme-context-Y98bGvcm.cjs} +2 -2
- package/dist/{theme-context-BHXYJ4RE.cjs.map → theme-context-Y98bGvcm.cjs.map} +1 -1
- package/dist/themes.cjs +1 -1
- package/dist/{trust-score-card-glass-CGXmOIfq.cjs → trust-score-card-glass-2rjz00d_.cjs} +47 -5
- package/dist/trust-score-card-glass-2rjz00d_.cjs.map +1 -0
- package/dist/{trust-score-card-glass-L9g0qamo.js → trust-score-card-glass-zjkx4OC2.js} +3 -3
- package/dist/trust-score-card-glass-zjkx4OC2.js.map +1 -0
- package/dist/{use-focus-CeNHOiBa.cjs → use-focus-DbpBEuee.cjs} +2 -2
- package/dist/{use-focus-CeNHOiBa.cjs.map → use-focus-DbpBEuee.cjs.map} +1 -1
- package/dist/{use-wallpaper-tint-Bt2G3g1v.cjs → use-wallpaper-tint-DbawS9zh.cjs} +2 -2
- package/dist/{use-wallpaper-tint-Bt2G3g1v.cjs.map → use-wallpaper-tint-DbawS9zh.cjs.map} +1 -1
- package/dist/{utils-LYxxWvUn.cjs → utils-XlyXIhuP.cjs} +2 -2
- package/dist/{utils-LYxxWvUn.cjs.map → utils-XlyXIhuP.cjs.map} +1 -1
- package/dist/utils.cjs +1 -1
- package/docs/AI_USAGE.md +5 -5
- package/docs/BEST_PRACTICES.md +1 -1
- package/docs/COMPONENTS_CATALOG.md +215 -0
- package/docs/EXPORTS_MAP.json +140 -14
- package/docs/EXPORTS_STRUCTURE.md +43 -9
- package/docs/GETTING_STARTED.md +1 -1
- package/docs/REGISTRY_USAGE.md +1 -1
- package/docs/api/README.md +1 -1
- package/docs/components/SIDEBAR_GLASS.md +555 -0
- package/docs/components/SPLIT_LAYOUT_GLASS.md +546 -0
- package/package.json +3 -3
- package/dist/trust-score-card-glass-CGXmOIfq.cjs.map +0 -1
- package/dist/trust-score-card-glass-L9g0qamo.js.map +0 -1
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
# SplitLayoutGlass
|
|
2
|
+
|
|
3
|
+
Responsive two-column layout component with sticky scroll behavior and glassmorphism styling.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`SplitLayoutGlass` provides a modern split-panel layout inspired by MDN, GitHub Docs, and Linear. It
|
|
8
|
+
features independent scrolling in each panel after sticky positioning activates, making it perfect
|
|
9
|
+
for documentation sites, dashboards, and analytics applications.
|
|
10
|
+
|
|
11
|
+
**API:** Compound component only (v2.2.0+). Legacy props API has been removed.
|
|
12
|
+
|
|
13
|
+
### Key Features
|
|
14
|
+
|
|
15
|
+
- **Compound Component API** - Provider, Root, Sidebar, Main, and nested components
|
|
16
|
+
- **Sticky Scroll Behavior** - Panels scroll together until reaching sticky offset, then scroll
|
|
17
|
+
independently
|
|
18
|
+
- **Responsive Design** - 2 columns on desktop, configurable mobile layouts
|
|
19
|
+
(stack/main-only/sidebar-only)
|
|
20
|
+
- **Master-Detail Pattern** - Built-in selection state via `selectedKey`
|
|
21
|
+
- **CSS Grid with minmax()** - Minimum sidebar width prevents squeezing
|
|
22
|
+
- **Glassmorphism Styling** - Configurable blur intensity (subtle/medium/strong)
|
|
23
|
+
- **Keyboard Shortcut** - Toggle sidebar with Cmd/Ctrl + B
|
|
24
|
+
- **URL Persistence** - Optional URL parameter sync for selection state
|
|
25
|
+
- **Theme Support** - Works with all 3 themes (glass, light, aurora)
|
|
26
|
+
|
|
27
|
+
### Browser Compatibility
|
|
28
|
+
|
|
29
|
+
- Chrome 89+ (CSS Grid minmax support)
|
|
30
|
+
- Firefox 87+
|
|
31
|
+
- Safari 14.1+
|
|
32
|
+
- Edge 89+
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
The component is part of the Glass UI library. Import it from the composite components:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { SplitLayoutGlass, useSplitLayout } from 'shadcn-glass-ui';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Compound API Reference
|
|
47
|
+
|
|
48
|
+
### Component Structure
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<SplitLayoutGlass.Provider>
|
|
52
|
+
{' '}
|
|
53
|
+
// Context provider (required)
|
|
54
|
+
<SplitLayoutGlass.Root>
|
|
55
|
+
{' '}
|
|
56
|
+
// Grid container
|
|
57
|
+
<SplitLayoutGlass.Sidebar>
|
|
58
|
+
{' '}
|
|
59
|
+
// Sidebar panel (aside element)
|
|
60
|
+
<SplitLayoutGlass.SidebarHeader /> // Sticky header
|
|
61
|
+
<SplitLayoutGlass.SidebarContent /> // Scrollable content
|
|
62
|
+
<SplitLayoutGlass.SidebarFooter /> // Sticky footer
|
|
63
|
+
</SplitLayoutGlass.Sidebar>
|
|
64
|
+
<SplitLayoutGlass.Main>
|
|
65
|
+
{' '}
|
|
66
|
+
// Main panel (main element)
|
|
67
|
+
<SplitLayoutGlass.MainHeader /> // Sticky header
|
|
68
|
+
<SplitLayoutGlass.MainContent /> // Scrollable content
|
|
69
|
+
<SplitLayoutGlass.MainFooter /> // Sticky footer
|
|
70
|
+
</SplitLayoutGlass.Main>
|
|
71
|
+
</SplitLayoutGlass.Root>
|
|
72
|
+
<SplitLayoutGlass.Trigger /> // Toggle button (optional)
|
|
73
|
+
</SplitLayoutGlass.Provider>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Props API
|
|
79
|
+
|
|
80
|
+
### Provider Props
|
|
81
|
+
|
|
82
|
+
| Prop | Type | Default | Description |
|
|
83
|
+
| --------------------- | --------------------------------------- | ---------- | ---------------------------------------- |
|
|
84
|
+
| `selectedKey` | `string \| null` | - | Controlled selected key (master-detail) |
|
|
85
|
+
| `onSelectedKeyChange` | `(key: string \| null) => void` | - | Selection change handler |
|
|
86
|
+
| `defaultSelectedKey` | `string \| null` | - | Initial selected key |
|
|
87
|
+
| `open` | `boolean` | - | Controlled sidebar open state |
|
|
88
|
+
| `onOpenChange` | `(open: boolean) => void` | - | Open state change handler |
|
|
89
|
+
| `defaultOpen` | `boolean` | `true` | Initial sidebar open state |
|
|
90
|
+
| `breakpoint` | `'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | `'md'` | Desktop layout breakpoint |
|
|
91
|
+
| `mobileMode` | `'stack' \| 'accordion' \| 'drawer'` | `'stack'` | Mobile layout behavior |
|
|
92
|
+
| `intensity` | `'subtle' \| 'medium' \| 'strong'` | `'medium'` | Glass blur intensity |
|
|
93
|
+
| `stickyOffset` | `number` | `24` | Sticky offset in pixels |
|
|
94
|
+
| `urlParamName` | `string` | - | URL param name for selection persistence |
|
|
95
|
+
| `keyboardShortcut` | `string \| false` | `'b'` | Keyboard shortcut (Cmd/Ctrl + key) |
|
|
96
|
+
|
|
97
|
+
### Root Props
|
|
98
|
+
|
|
99
|
+
| Prop | Type | Default | Description |
|
|
100
|
+
| ----------------- | ------------------------------------------------- | ----------------------------- | --------------------------------- |
|
|
101
|
+
| `ratio` | `{ sidebar: number; main: number }` | `{ sidebar: 1, main: 2 }` | Column ratio (1:2 = 33%/67%) |
|
|
102
|
+
| `minSidebarWidth` | `string` | `'300px'` | Minimum sidebar width (CSS value) |
|
|
103
|
+
| `maxSidebarWidth` | `string` | - | Maximum sidebar width (CSS value) |
|
|
104
|
+
| `gap` | `number \| { mobile?: number; desktop?: number }` | `{ mobile: 16, desktop: 24 }` | Gap between panels in pixels |
|
|
105
|
+
| `breakpoint` | `Breakpoint` | - | Overrides Provider breakpoint |
|
|
106
|
+
| `mobileLayout` | `'stack' \| 'main-only' \| 'sidebar-only'` | `'stack'` | Mobile layout mode |
|
|
107
|
+
| `className` | `string` | - | Custom className for container |
|
|
108
|
+
|
|
109
|
+
### Sidebar/Main Props
|
|
110
|
+
|
|
111
|
+
| Prop | Type | Default | Description |
|
|
112
|
+
| ----------- | -------- | ----------------------------------------- | --------------------- |
|
|
113
|
+
| `label` | `string` | `'Sidebar navigation'` / `'Main content'` | ARIA label for region |
|
|
114
|
+
| `className` | `string` | - | Custom className |
|
|
115
|
+
|
|
116
|
+
### Header/Footer Props
|
|
117
|
+
|
|
118
|
+
| Prop | Type | Default | Description |
|
|
119
|
+
| ----------- | -------- | ------- | ---------------- |
|
|
120
|
+
| `className` | `string` | - | Custom className |
|
|
121
|
+
|
|
122
|
+
### Content Props
|
|
123
|
+
|
|
124
|
+
| Prop | Type | Default | Description |
|
|
125
|
+
| ------------ | --------- | ------- | --------------------------------------------------- |
|
|
126
|
+
| `scrollable` | `boolean` | `true` | Enable ScrollArea wrapper for independent scrolling |
|
|
127
|
+
| `className` | `string` | - | Custom className |
|
|
128
|
+
|
|
129
|
+
### Trigger Props
|
|
130
|
+
|
|
131
|
+
| Prop | Type | Default | Description |
|
|
132
|
+
| --------------- | ------------------- | -------- | ------------------------------------------- |
|
|
133
|
+
| `asChild` | `boolean` | `false` | Use Radix Slot for custom trigger element |
|
|
134
|
+
| `showOnDesktop` | `boolean` | `false` | Show trigger on desktop (hidden by default) |
|
|
135
|
+
| `variant` | `'menu' \| 'panel'` | `'menu'` | Icon style (hamburger vs panel icons) |
|
|
136
|
+
| `className` | `string` | - | Custom className |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Usage Examples
|
|
141
|
+
|
|
142
|
+
### Basic Two-Column Layout
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import { SplitLayoutGlass } from 'shadcn-glass-ui';
|
|
146
|
+
|
|
147
|
+
export function DocsLayout() {
|
|
148
|
+
return (
|
|
149
|
+
<SplitLayoutGlass.Provider>
|
|
150
|
+
<SplitLayoutGlass.Root>
|
|
151
|
+
<SplitLayoutGlass.Sidebar>
|
|
152
|
+
<SplitLayoutGlass.SidebarHeader>
|
|
153
|
+
<h3 className="text-lg font-semibold">Navigation</h3>
|
|
154
|
+
</SplitLayoutGlass.SidebarHeader>
|
|
155
|
+
<SplitLayoutGlass.SidebarContent>
|
|
156
|
+
<nav className="space-y-2 p-4">
|
|
157
|
+
<a href="#section-1" className="block p-2 rounded hover:bg-muted">
|
|
158
|
+
Section 1
|
|
159
|
+
</a>
|
|
160
|
+
<a href="#section-2" className="block p-2 rounded hover:bg-muted">
|
|
161
|
+
Section 2
|
|
162
|
+
</a>
|
|
163
|
+
</nav>
|
|
164
|
+
</SplitLayoutGlass.SidebarContent>
|
|
165
|
+
</SplitLayoutGlass.Sidebar>
|
|
166
|
+
<SplitLayoutGlass.Main>
|
|
167
|
+
<SplitLayoutGlass.MainContent>
|
|
168
|
+
<article className="p-6">
|
|
169
|
+
<h1 className="text-3xl font-bold mb-4">Content Title</h1>
|
|
170
|
+
<p>Your main content here...</p>
|
|
171
|
+
</article>
|
|
172
|
+
</SplitLayoutGlass.MainContent>
|
|
173
|
+
</SplitLayoutGlass.Main>
|
|
174
|
+
</SplitLayoutGlass.Root>
|
|
175
|
+
</SplitLayoutGlass.Provider>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### Master-Detail Pattern
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
import { SplitLayoutGlass, useSplitLayout } from 'shadcn-glass-ui';
|
|
186
|
+
|
|
187
|
+
function ItemList() {
|
|
188
|
+
const { selectedKey, setSelectedKey } = useSplitLayout();
|
|
189
|
+
const items = [
|
|
190
|
+
{ id: '1', name: 'Item 1' },
|
|
191
|
+
{ id: '2', name: 'Item 2' },
|
|
192
|
+
{ id: '3', name: 'Item 3' },
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div className="space-y-2">
|
|
197
|
+
{items.map((item) => (
|
|
198
|
+
<button
|
|
199
|
+
key={item.id}
|
|
200
|
+
onClick={() => setSelectedKey(item.id)}
|
|
201
|
+
className={cn('w-full p-3 rounded text-left', selectedKey === item.id && 'bg-primary/10')}
|
|
202
|
+
>
|
|
203
|
+
{item.name}
|
|
204
|
+
</button>
|
|
205
|
+
))}
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function ItemDetail() {
|
|
211
|
+
const { selectedKey } = useSplitLayout();
|
|
212
|
+
if (!selectedKey) return <p>Select an item</p>;
|
|
213
|
+
return <div>Details for item {selectedKey}</div>;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function MasterDetailLayout() {
|
|
217
|
+
return (
|
|
218
|
+
<SplitLayoutGlass.Provider defaultSelectedKey="1" urlParamName="item">
|
|
219
|
+
<SplitLayoutGlass.Root ratio={{ sidebar: 1, main: 2 }}>
|
|
220
|
+
<SplitLayoutGlass.Sidebar>
|
|
221
|
+
<SplitLayoutGlass.SidebarHeader>
|
|
222
|
+
<h3>Items</h3>
|
|
223
|
+
<SplitLayoutGlass.Trigger variant="menu" />
|
|
224
|
+
</SplitLayoutGlass.SidebarHeader>
|
|
225
|
+
<SplitLayoutGlass.SidebarContent>
|
|
226
|
+
<ItemList />
|
|
227
|
+
</SplitLayoutGlass.SidebarContent>
|
|
228
|
+
</SplitLayoutGlass.Sidebar>
|
|
229
|
+
<SplitLayoutGlass.Main>
|
|
230
|
+
<SplitLayoutGlass.MainContent>
|
|
231
|
+
<ItemDetail />
|
|
232
|
+
</SplitLayoutGlass.MainContent>
|
|
233
|
+
</SplitLayoutGlass.Main>
|
|
234
|
+
</SplitLayoutGlass.Root>
|
|
235
|
+
</SplitLayoutGlass.Provider>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
### Custom Ratio and Width
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
<SplitLayoutGlass.Provider>
|
|
246
|
+
<SplitLayoutGlass.Root
|
|
247
|
+
ratio={{ sidebar: 1, main: 3 }} // 25% sidebar, 75% main
|
|
248
|
+
minSidebarWidth="250px"
|
|
249
|
+
maxSidebarWidth="400px"
|
|
250
|
+
>
|
|
251
|
+
{/* ... */}
|
|
252
|
+
</SplitLayoutGlass.Root>
|
|
253
|
+
</SplitLayoutGlass.Provider>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### Intensity Variants
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
// Subtle blur (8px) - minimal glass effect
|
|
262
|
+
<SplitLayoutGlass.Provider intensity="subtle">
|
|
263
|
+
{/* ... */}
|
|
264
|
+
</SplitLayoutGlass.Provider>
|
|
265
|
+
|
|
266
|
+
// Medium blur (16px) - standard glass effect (default)
|
|
267
|
+
<SplitLayoutGlass.Provider intensity="medium">
|
|
268
|
+
{/* ... */}
|
|
269
|
+
</SplitLayoutGlass.Provider>
|
|
270
|
+
|
|
271
|
+
// Strong blur (24px) - heavy glass effect
|
|
272
|
+
<SplitLayoutGlass.Provider intensity="strong">
|
|
273
|
+
{/* ... */}
|
|
274
|
+
</SplitLayoutGlass.Provider>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### Mobile Layouts
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
// Stack Layout (default) - sidebar above main
|
|
283
|
+
<SplitLayoutGlass.Root mobileLayout="stack">
|
|
284
|
+
{/* ... */}
|
|
285
|
+
</SplitLayoutGlass.Root>
|
|
286
|
+
|
|
287
|
+
// Main Only - hide sidebar on mobile
|
|
288
|
+
<SplitLayoutGlass.Root mobileLayout="main-only">
|
|
289
|
+
{/* ... */}
|
|
290
|
+
</SplitLayoutGlass.Root>
|
|
291
|
+
|
|
292
|
+
// Sidebar Only - hide main on mobile
|
|
293
|
+
<SplitLayoutGlass.Root mobileLayout="sidebar-only">
|
|
294
|
+
{/* ... */}
|
|
295
|
+
</SplitLayoutGlass.Root>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
### With Headers and Footers
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
<SplitLayoutGlass.Provider>
|
|
304
|
+
<SplitLayoutGlass.Root>
|
|
305
|
+
<SplitLayoutGlass.Sidebar>
|
|
306
|
+
<SplitLayoutGlass.SidebarHeader>
|
|
307
|
+
<Logo />
|
|
308
|
+
<SplitLayoutGlass.Trigger />
|
|
309
|
+
</SplitLayoutGlass.SidebarHeader>
|
|
310
|
+
<SplitLayoutGlass.SidebarContent scrollable>
|
|
311
|
+
<Navigation />
|
|
312
|
+
</SplitLayoutGlass.SidebarContent>
|
|
313
|
+
<SplitLayoutGlass.SidebarFooter>
|
|
314
|
+
<UserMenu />
|
|
315
|
+
</SplitLayoutGlass.SidebarFooter>
|
|
316
|
+
</SplitLayoutGlass.Sidebar>
|
|
317
|
+
<SplitLayoutGlass.Main>
|
|
318
|
+
<SplitLayoutGlass.MainHeader>
|
|
319
|
+
<Breadcrumbs />
|
|
320
|
+
<SearchBar />
|
|
321
|
+
</SplitLayoutGlass.MainHeader>
|
|
322
|
+
<SplitLayoutGlass.MainContent>
|
|
323
|
+
<PageContent />
|
|
324
|
+
</SplitLayoutGlass.MainContent>
|
|
325
|
+
<SplitLayoutGlass.MainFooter>
|
|
326
|
+
<Pagination />
|
|
327
|
+
</SplitLayoutGlass.MainFooter>
|
|
328
|
+
</SplitLayoutGlass.Main>
|
|
329
|
+
</SplitLayoutGlass.Root>
|
|
330
|
+
</SplitLayoutGlass.Provider>
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### Different Breakpoint
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
<SplitLayoutGlass.Provider breakpoint="lg">
|
|
339
|
+
<SplitLayoutGlass.Root>
|
|
340
|
+
{/* Two-column layout starts at 1024px instead of 768px */}
|
|
341
|
+
</SplitLayoutGlass.Root>
|
|
342
|
+
</SplitLayoutGlass.Provider>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Breakpoint values:**
|
|
346
|
+
|
|
347
|
+
- `sm`: 640px
|
|
348
|
+
- `md`: 768px (default)
|
|
349
|
+
- `lg`: 1024px
|
|
350
|
+
- `xl`: 1280px
|
|
351
|
+
- `2xl`: 1536px
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Hook: useSplitLayout()
|
|
356
|
+
|
|
357
|
+
Access the SplitLayoutGlass context from any child component:
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
import { useSplitLayout } from 'shadcn-glass-ui';
|
|
361
|
+
|
|
362
|
+
function MyComponent() {
|
|
363
|
+
const {
|
|
364
|
+
// Selection state (master-detail)
|
|
365
|
+
selectedKey, // Current selected key
|
|
366
|
+
setSelectedKey, // Set selected key
|
|
367
|
+
|
|
368
|
+
// Desktop state
|
|
369
|
+
isOpen, // Sidebar open state
|
|
370
|
+
setIsOpen, // Set open state
|
|
371
|
+
|
|
372
|
+
// Mobile state
|
|
373
|
+
isMobileOpen, // Mobile sidebar open
|
|
374
|
+
setMobileOpen, // Set mobile open
|
|
375
|
+
|
|
376
|
+
// Responsive
|
|
377
|
+
isMobile, // Is mobile viewport
|
|
378
|
+
breakpoint, // Current breakpoint
|
|
379
|
+
mobileMode, // Mobile layout mode
|
|
380
|
+
|
|
381
|
+
// Config
|
|
382
|
+
intensity, // Glass intensity
|
|
383
|
+
stickyOffset, // Sticky offset
|
|
384
|
+
|
|
385
|
+
// Actions
|
|
386
|
+
toggle, // Toggle sidebar
|
|
387
|
+
|
|
388
|
+
// shadcn/ui aliases
|
|
389
|
+
state, // 'expanded' | 'collapsed'
|
|
390
|
+
open, // Alias for isOpen
|
|
391
|
+
openMobile, // Alias for isMobileOpen
|
|
392
|
+
toggleSidebar, // Alias for toggle
|
|
393
|
+
} = useSplitLayout();
|
|
394
|
+
|
|
395
|
+
return <button onClick={toggle}>{isOpen ? 'Close Sidebar' : 'Open Sidebar'}</button>;
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Responsive Behavior
|
|
402
|
+
|
|
403
|
+
### Desktop (≥ breakpoint)
|
|
404
|
+
|
|
405
|
+
- **Layout:** Two columns side by side
|
|
406
|
+
- **Sticky:** Both panels become sticky after scrolling past offset
|
|
407
|
+
- **Max Height:** `calc(100vh - offset * 2)` constrains panel height
|
|
408
|
+
- **Scrolling:** Each panel scrolls independently within max-height
|
|
409
|
+
- **Grid:** Uses CSS Grid with `minmax()` for sidebar width
|
|
410
|
+
|
|
411
|
+
### Mobile (< breakpoint)
|
|
412
|
+
|
|
413
|
+
- **Layout:** Determined by `mobileLayout` prop
|
|
414
|
+
- `stack`: Single column, sidebar above main
|
|
415
|
+
- `main-only`: Hide sidebar, show only main
|
|
416
|
+
- `sidebar-only`: Hide main, show only sidebar
|
|
417
|
+
- **Sticky:** Disabled (not useful in single column)
|
|
418
|
+
- **Scrolling:** Normal document flow
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Sticky Scroll Behavior
|
|
423
|
+
|
|
424
|
+
### How It Works
|
|
425
|
+
|
|
426
|
+
1. **Initial scroll:** Both panels scroll together with page
|
|
427
|
+
2. **Reaching offset:** Panels become `position: sticky` at `top: {stickyOffset}px`
|
|
428
|
+
3. **Independent scroll:** Each panel scrolls independently within `max-height` constraint
|
|
429
|
+
4. **No sync:** Panels do NOT scroll together to end of document
|
|
430
|
+
|
|
431
|
+
### Visual Diagram
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
┌─────────────────────────────────────┐
|
|
435
|
+
│ Browser Viewport │
|
|
436
|
+
│ ┌─────────────────────────────┐ │
|
|
437
|
+
│ │ Offset (24px) │ │
|
|
438
|
+
│ ├─────────────┬───────────────┤ │ ← Sticky point
|
|
439
|
+
│ │ Sidebar │ Main │ │
|
|
440
|
+
│ │ (sticky) │ (sticky) │ │
|
|
441
|
+
│ │ │ │ │
|
|
442
|
+
│ │ [scroll] │ [scroll] │ │
|
|
443
|
+
│ │ ↕ │ ↕ │ │
|
|
444
|
+
│ └─────────────┴───────────────┘ │
|
|
445
|
+
│ Offset (24px) │
|
|
446
|
+
└─────────────────────────────────────┘
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Accessibility
|
|
452
|
+
|
|
453
|
+
### Semantic HTML
|
|
454
|
+
|
|
455
|
+
- **`<aside>`** for sidebar - Navigation landmark
|
|
456
|
+
- **`<main>`** for main content - Main landmark
|
|
457
|
+
- Screen readers announce these regions automatically
|
|
458
|
+
|
|
459
|
+
### ARIA Labels
|
|
460
|
+
|
|
461
|
+
```tsx
|
|
462
|
+
<SplitLayoutGlass.Sidebar label="Documentation navigation">
|
|
463
|
+
{/* ... */}
|
|
464
|
+
</SplitLayoutGlass.Sidebar>
|
|
465
|
+
|
|
466
|
+
<SplitLayoutGlass.Main label="Article content">
|
|
467
|
+
{/* ... */}
|
|
468
|
+
</SplitLayoutGlass.Main>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Keyboard Navigation
|
|
472
|
+
|
|
473
|
+
- **Cmd/Ctrl + B:** Toggle sidebar (configurable via `keyboardShortcut`)
|
|
474
|
+
- **Tab:** Cycles through focusable elements in document order
|
|
475
|
+
- **Arrow keys:** Scrolls within focused ScrollArea
|
|
476
|
+
- **Space/Page Down:** Scrolls down in focused panel
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Troubleshooting
|
|
481
|
+
|
|
482
|
+
### Sidebar too narrow
|
|
483
|
+
|
|
484
|
+
**Solution:** Increase `minSidebarWidth`
|
|
485
|
+
|
|
486
|
+
```tsx
|
|
487
|
+
<SplitLayoutGlass.Root minSidebarWidth="350px">
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Sidebar too wide
|
|
491
|
+
|
|
492
|
+
**Solution:** Set `maxSidebarWidth` or adjust ratio
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
<SplitLayoutGlass.Root maxSidebarWidth="400px" ratio={{ sidebar: 1, main: 3 }} />
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Content not scrolling
|
|
499
|
+
|
|
500
|
+
**Solution:** Ensure `scrollable` prop is true (default) on Content components
|
|
501
|
+
|
|
502
|
+
```tsx
|
|
503
|
+
<SplitLayoutGlass.SidebarContent scrollable>{/* Long content */}</SplitLayoutGlass.SidebarContent>
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Sticky not working
|
|
507
|
+
|
|
508
|
+
**Possible causes:**
|
|
509
|
+
|
|
510
|
+
1. **Mobile viewport** - Sticky disabled on mobile
|
|
511
|
+
2. **Parent overflow** - Parent has `overflow: hidden/auto/scroll`
|
|
512
|
+
3. **Z-index conflict** - Add `z-10` to className
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Related Components
|
|
517
|
+
|
|
518
|
+
- **[SidebarGlass](./SIDEBAR_GLASS.md)** - Traditional collapsible sidebar (shadcn/ui compatible)
|
|
519
|
+
- **[GlassCard](./GLASS_CARD.md)** - Base glass container
|
|
520
|
+
- **[ModalGlass](./MODAL_GLASS.md)** - Modal with compound API pattern
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Changelog
|
|
525
|
+
|
|
526
|
+
### v2.2.0 (2025-01-XX)
|
|
527
|
+
|
|
528
|
+
- Initial release with compound API
|
|
529
|
+
- Legacy props API removed
|
|
530
|
+
- 18 visual tests across 3 themes
|
|
531
|
+
- 20+ unit tests with 100% coverage
|
|
532
|
+
- Complete documentation
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## Support
|
|
537
|
+
|
|
538
|
+
- **GitHub Issues:** [Report bugs](https://github.com/yhooi2/shadcn-glass-ui-library/issues)
|
|
539
|
+
- **Storybook:** [View live examples](https://yhooi2.github.io/shadcn-glass-ui-library/)
|
|
540
|
+
- **Documentation:** [CLAUDE.md](../../CLAUDE.md) for AI assistants
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## License
|
|
545
|
+
|
|
546
|
+
MIT License - Part of [shadcn-glass-ui-library](https://github.com/yhooi2/shadcn-glass-ui-library)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shadcn-glass-ui",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.5",
|
|
5
5
|
"description": "Glassmorphism UI library for React - AI-friendly with 57 components, strict TypeScript, and comprehensive docs",
|
|
6
6
|
"author": "Yhooi2",
|
|
7
7
|
"license": "MIT",
|
|
@@ -97,7 +97,8 @@
|
|
|
97
97
|
"default": "./dist/themes.cjs"
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
|
-
"./styles.css": "./dist/
|
|
100
|
+
"./styles.css": "./dist/shadcn-glass-ui.css",
|
|
101
|
+
"./dist/shadcn-glass-ui.css": "./dist/shadcn-glass-ui.css"
|
|
101
102
|
},
|
|
102
103
|
"files": [
|
|
103
104
|
"dist",
|
|
@@ -188,7 +189,6 @@
|
|
|
188
189
|
"@storybook/addon-docs": "^10.1.0",
|
|
189
190
|
"@storybook/addon-links": "^10.1.4",
|
|
190
191
|
"@storybook/addon-mcp": "^0.1.3",
|
|
191
|
-
"@storybook/addon-onboarding": "^10.1.0",
|
|
192
192
|
"@storybook/addon-vitest": "^10.1.0",
|
|
193
193
|
"@storybook/react-vite": "^10.1.0",
|
|
194
194
|
"@testing-library/react": "^16.3.0",
|