@fragments-sdk/ui 0.15.1 → 0.16.0
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/dist/assets/ui.css +42 -34
- package/dist/components/AppShell/AppShell.module.scss.cjs +15 -21
- package/dist/components/AppShell/AppShell.module.scss.js +15 -21
- package/dist/components/AppShell/index.cjs +52 -13
- package/dist/components/AppShell/index.d.ts +55 -27
- package/dist/components/AppShell/index.d.ts.map +1 -1
- package/dist/components/AppShell/index.js +52 -13
- package/dist/components/CodeBlock/index.d.ts.map +1 -1
- package/dist/components/DatePicker/index.d.ts.map +1 -1
- package/dist/components/Form/index.cjs +1 -1
- package/dist/components/Form/index.d.ts +1 -1
- package/dist/components/Form/index.d.ts.map +1 -1
- package/dist/components/Form/index.js +1 -1
- package/dist/components/Menu/index.d.ts +1 -2
- package/dist/components/Menu/index.d.ts.map +1 -1
- package/dist/components/NavigationMenu/useNavigationMenu.cjs +6 -3
- package/dist/components/NavigationMenu/useNavigationMenu.d.ts.map +1 -1
- package/dist/components/NavigationMenu/useNavigationMenu.js +6 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/seed-derivation.d.ts.map +1 -1
- package/dist/utils/theme-presets.d.ts.map +1 -1
- package/fragments.json +1 -1
- package/package.json +2 -2
- package/src/components/AppShell/AppShell.module.scss +29 -20
- package/src/components/AppShell/index.tsx +123 -36
- package/src/components/CodeBlock/index.tsx +0 -1
- package/src/components/DatePicker/index.tsx +1 -1
- package/src/components/Form/index.tsx +1 -1
- package/src/components/Menu/index.tsx +1 -1
- package/src/components/NavigationMenu/useNavigationMenu.ts +6 -3
- package/src/index.ts +1 -0
- package/src/utils/seed-derivation.ts +0 -9
- package/src/utils/theme-presets.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragments-sdk/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Customizable UI components built on Base UI headless primitives",
|
|
6
6
|
"author": "Conan McNicholl",
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
"vite": "^6.0.0",
|
|
231
231
|
"vitest": "^2.1.8",
|
|
232
232
|
"vitest-axe": "^0.1.0",
|
|
233
|
-
"@fragments-sdk/core": "0.
|
|
233
|
+
"@fragments-sdk/core": "1.0.0"
|
|
234
234
|
},
|
|
235
235
|
"files": [
|
|
236
236
|
"src",
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
// ============================================
|
|
7
7
|
// Grid areas: header, sidebar, main, aside
|
|
8
8
|
//
|
|
9
|
-
// 'default'
|
|
10
|
-
//
|
|
11
|
-
// 'sidebar-floating': like sidebar, but main floats with rounded corners
|
|
9
|
+
// Structure is controlled by the `layout` prop ('default' | 'sidebar').
|
|
10
|
+
// Visual treatment (floating) is controlled per-slot via `variant` props.
|
|
12
11
|
|
|
13
12
|
.root {
|
|
14
13
|
display: grid;
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
// Sidebar
|
|
50
|
+
// Sidebar structure: sidebar spans full height
|
|
52
51
|
// sidebar header header
|
|
53
52
|
// sidebar main aside
|
|
54
53
|
.sidebarLayout {
|
|
@@ -65,11 +64,6 @@
|
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
// Sidebar-floating layout: shell background frames the floating main area
|
|
69
|
-
.sidebarFloatingLayout {
|
|
70
|
-
background-color: var(--fui-bg-primary, $fui-bg-primary);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
67
|
// ============================================
|
|
74
68
|
// Header
|
|
75
69
|
// ============================================
|
|
@@ -83,11 +77,6 @@
|
|
|
83
77
|
background-color: var(--fui-bg-primary, $fui-bg-primary);
|
|
84
78
|
}
|
|
85
79
|
|
|
86
|
-
// Header in sidebar-floating layout — matches shell bg
|
|
87
|
-
.headerFloating {
|
|
88
|
-
background-color: var(--fui-bg-primary, $fui-bg-primary);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
80
|
// ============================================
|
|
92
81
|
// Sidebar
|
|
93
82
|
// ============================================
|
|
@@ -129,7 +118,7 @@
|
|
|
129
118
|
}
|
|
130
119
|
}
|
|
131
120
|
|
|
132
|
-
// Sidebar in sidebar
|
|
121
|
+
// Sidebar in sidebar structure: full height
|
|
133
122
|
.sidebarFullHeight {
|
|
134
123
|
top: 0;
|
|
135
124
|
height: 100vh;
|
|
@@ -141,11 +130,9 @@
|
|
|
141
130
|
}
|
|
142
131
|
}
|
|
143
132
|
|
|
144
|
-
// Sidebar
|
|
133
|
+
// Sidebar variant="floating": blends with shell background (bg applied via inline style on Sidebar)
|
|
145
134
|
.sidebarFloating {
|
|
146
|
-
|
|
147
|
-
background-color: var(--fui-bg-primary, $fui-bg-primary);
|
|
148
|
-
}
|
|
135
|
+
// No additional styles needed — bg prop is passed directly to the Sidebar component
|
|
149
136
|
}
|
|
150
137
|
|
|
151
138
|
// ============================================
|
|
@@ -159,13 +146,15 @@
|
|
|
159
146
|
background-color: var(--fui-bg-primary, $fui-bg-primary);
|
|
160
147
|
}
|
|
161
148
|
|
|
162
|
-
// Main
|
|
149
|
+
// Main variant="floating": elevated card effect with inset from edges
|
|
163
150
|
.mainFloating {
|
|
151
|
+
margin: var(--fui-space-2, $fui-space-2) var(--fui-space-2, $fui-space-2) var(--fui-space-2, $fui-space-2) 0;
|
|
164
152
|
border-radius: var(--fui-radius-xl, $fui-radius-xl);
|
|
165
153
|
background-color: var(--fui-bg-secondary, $fui-bg-secondary);
|
|
166
154
|
overflow: hidden;
|
|
167
155
|
|
|
168
156
|
@include below-md {
|
|
157
|
+
margin: var(--fui-space-2, $fui-space-2) 0;
|
|
169
158
|
border-radius: var(--fui-radius-lg, $fui-radius-lg);
|
|
170
159
|
width: 100%;
|
|
171
160
|
}
|
|
@@ -216,3 +205,23 @@
|
|
|
216
205
|
border-top: 1px solid var(--fui-border, $fui-border);
|
|
217
206
|
}
|
|
218
207
|
}
|
|
208
|
+
|
|
209
|
+
// Aside variant="floating": elevated card effect with inset from edges
|
|
210
|
+
.asideFloating {
|
|
211
|
+
// Override the explicit width so the aside fills its grid cell
|
|
212
|
+
// and the margin creates visible inset space from the viewport edge.
|
|
213
|
+
width: auto;
|
|
214
|
+
height: calc(100vh - var(--appshell-header-height, 56px) - var(--fui-space-2, $fui-space-2) * 2);
|
|
215
|
+
height: calc(100dvh - var(--appshell-header-height, 56px) - var(--fui-space-2, $fui-space-2) * 2);
|
|
216
|
+
margin: var(--fui-space-2, $fui-space-2) var(--fui-space-2, $fui-space-2) var(--fui-space-2, $fui-space-2) 0;
|
|
217
|
+
border-radius: var(--fui-radius-xl, $fui-radius-xl);
|
|
218
|
+
background-color: var(--fui-bg-secondary, $fui-bg-secondary);
|
|
219
|
+
overflow: hidden;
|
|
220
|
+
|
|
221
|
+
@include below-md {
|
|
222
|
+
margin: var(--fui-space-2, $fui-space-2) 0;
|
|
223
|
+
border-radius: var(--fui-radius-lg, $fui-radius-lg);
|
|
224
|
+
width: 100%;
|
|
225
|
+
height: auto;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -14,46 +14,62 @@ import {
|
|
|
14
14
|
// ============================================
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
+
* Structural layout — controls CSS grid areas.
|
|
18
|
+
*
|
|
17
19
|
* ```
|
|
18
|
-
* 'default' 'sidebar'
|
|
19
|
-
* ┌──────────────┐ ┌────┬─────────┐
|
|
20
|
-
* │ Header │ │ │ Header │
|
|
21
|
-
* ├────┬─────────┤ │Side├─────────┤
|
|
22
|
-
* │ │ │ │bar │ │
|
|
23
|
-
* │Side│ Main │ │ │ Main │
|
|
24
|
-
* │bar │ │ │ │ │
|
|
25
|
-
* └────┴─────────┘ └────┴─────────┘
|
|
20
|
+
* 'default' 'sidebar'
|
|
21
|
+
* ┌──────────────┐ ┌────┬─────────┐
|
|
22
|
+
* │ Header │ │ │ Header │
|
|
23
|
+
* ├────┬─────────┤ │Side├─────────┤
|
|
24
|
+
* │ │ │ │bar │ │
|
|
25
|
+
* │Side│ Main │ │ │ Main │
|
|
26
|
+
* │bar │ │ │ │ │
|
|
27
|
+
* └────┴─────────┘ └────┴─────────┘
|
|
26
28
|
* ```
|
|
29
|
+
*
|
|
30
|
+
* Combine with `variant="floating"` on individual slots for floating effects:
|
|
31
|
+
*
|
|
32
|
+
* ```tsx
|
|
33
|
+
* <AppShell layout="sidebar">
|
|
34
|
+
* <AppShell.Sidebar variant="floating" />
|
|
35
|
+
* <AppShell.Main variant="floating" />
|
|
36
|
+
* <AppShell.Aside variant="floating" />
|
|
37
|
+
* </AppShell>
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* Legacy values `'sidebar-floating'` and `'floating'` are still accepted
|
|
41
|
+
* for backwards compatibility and internally expand to the appropriate
|
|
42
|
+
* per-slot variants.
|
|
27
43
|
*/
|
|
28
|
-
export type AppShellLayout = 'default' | 'sidebar' | 'sidebar-floating';
|
|
44
|
+
export type AppShellLayout = 'default' | 'sidebar' | 'sidebar-floating' | 'floating';
|
|
45
|
+
|
|
46
|
+
/** Visual treatment for individual layout slots. */
|
|
47
|
+
export type AppShellSlotVariant = 'default' | 'floating';
|
|
29
48
|
|
|
30
49
|
export interface AppShellProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
31
50
|
children: React.ReactNode;
|
|
32
51
|
/**
|
|
33
|
-
* Layout
|
|
34
|
-
*
|
|
35
|
-
* ```
|
|
36
|
-
* 'default' 'sidebar' 'sidebar-floating'
|
|
37
|
-
* ┌──────────────┐ ┌────┬─────────┐ ┌────┬─────────┐
|
|
38
|
-
* │ Header │ │ │ Header │ │ │ Header │
|
|
39
|
-
* ├────┬─────────┤ │Side├─────────┤ │Side├╌╌╌╌╌╌╌╌╌┤
|
|
40
|
-
* │ │ │ │bar │ │ │bar │┌───────┐│
|
|
41
|
-
* │Side│ Main │ │ │ Main │ │ ││ Main ││
|
|
42
|
-
* │bar │ │ │ │ │ │ │└───────┘│
|
|
43
|
-
* └────┴─────────┘ └────┴─────────┘ └────┴─────────┘
|
|
44
|
-
* ```
|
|
52
|
+
* Layout structure:
|
|
45
53
|
*
|
|
46
54
|
* - `'default'`: Header spans full width, sidebar below (default)
|
|
47
55
|
* - `'sidebar'`: Sidebar is full height, header sits beside it
|
|
48
|
-
*
|
|
56
|
+
*
|
|
57
|
+
* Legacy presets (still work, prefer per-slot `variant` props instead):
|
|
58
|
+
*
|
|
59
|
+
* - `'sidebar-floating'`: Expands to `layout="sidebar"` with floating sidebar + main
|
|
60
|
+
* - `'floating'`: Expands to `layout="sidebar"` with floating sidebar + main + aside
|
|
49
61
|
*/
|
|
50
62
|
layout?: AppShellLayout;
|
|
63
|
+
/** Background color for the shell container (accepts any CSS color value or token) */
|
|
64
|
+
bg?: string;
|
|
51
65
|
}
|
|
52
66
|
|
|
53
67
|
export interface AppShellHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
54
68
|
children: React.ReactNode;
|
|
55
69
|
/** Header height (default: '56px') */
|
|
56
70
|
height?: string;
|
|
71
|
+
/** Background color override (accepts any CSS color value or token) */
|
|
72
|
+
bg?: string;
|
|
57
73
|
}
|
|
58
74
|
|
|
59
75
|
export interface AppShellSidebarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
@@ -68,12 +84,20 @@ export interface AppShellSidebarProps extends React.HTMLAttributes<HTMLDivElemen
|
|
|
68
84
|
position?: 'left' | 'right';
|
|
69
85
|
/** Default collapsed state */
|
|
70
86
|
defaultCollapsed?: boolean;
|
|
87
|
+
/** Visual treatment: `'floating'` blends sidebar with the shell background */
|
|
88
|
+
variant?: AppShellSlotVariant;
|
|
89
|
+
/** Background color override (accepts any CSS color value or token) */
|
|
90
|
+
bg?: string;
|
|
71
91
|
}
|
|
72
92
|
|
|
73
93
|
export interface AppShellMainProps extends React.HTMLAttributes<HTMLElement> {
|
|
74
94
|
children: React.ReactNode;
|
|
75
95
|
/** Content padding */
|
|
76
96
|
padding?: 'none' | 'sm' | 'md' | 'lg';
|
|
97
|
+
/** Visual treatment: `'floating'` adds rounded corners and elevated background */
|
|
98
|
+
variant?: AppShellSlotVariant;
|
|
99
|
+
/** Background color override (accepts any CSS color value or token) */
|
|
100
|
+
bg?: string;
|
|
77
101
|
}
|
|
78
102
|
|
|
79
103
|
export interface AppShellAsideProps extends React.HTMLAttributes<HTMLElement> {
|
|
@@ -82,6 +106,35 @@ export interface AppShellAsideProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
82
106
|
width?: string;
|
|
83
107
|
/** Control visibility */
|
|
84
108
|
visible?: boolean;
|
|
109
|
+
/** Visual treatment: `'floating'` adds rounded corners and elevated background */
|
|
110
|
+
variant?: AppShellSlotVariant;
|
|
111
|
+
/** Background color override (accepts any CSS color value or token) */
|
|
112
|
+
bg?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ============================================
|
|
116
|
+
// Layout resolution helpers
|
|
117
|
+
// ============================================
|
|
118
|
+
|
|
119
|
+
/** Resolve a layout value to its structural grid mode. */
|
|
120
|
+
function resolveStructure(layout: AppShellLayout): 'default' | 'sidebar' {
|
|
121
|
+
if (layout === 'sidebar' || layout === 'sidebar-floating' || layout === 'floating') return 'sidebar';
|
|
122
|
+
return 'default';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Resolve a slot's visual variant.
|
|
127
|
+
* Explicit `variant` prop always wins. Otherwise, infer from legacy layout values.
|
|
128
|
+
*/
|
|
129
|
+
function resolveSlotVariant(
|
|
130
|
+
explicit: AppShellSlotVariant | undefined,
|
|
131
|
+
layout: AppShellLayout,
|
|
132
|
+
slot: 'main' | 'aside' | 'sidebar',
|
|
133
|
+
): AppShellSlotVariant {
|
|
134
|
+
if (explicit !== undefined) return explicit;
|
|
135
|
+
if ((layout === 'sidebar-floating' || layout === 'floating') && (slot === 'main' || slot === 'sidebar')) return 'floating';
|
|
136
|
+
if (layout === 'floating' && slot === 'aside') return 'floating';
|
|
137
|
+
return 'default';
|
|
85
138
|
}
|
|
86
139
|
|
|
87
140
|
// ============================================
|
|
@@ -90,6 +143,7 @@ export interface AppShellAsideProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
90
143
|
|
|
91
144
|
interface AppShellContextValue {
|
|
92
145
|
layout: AppShellLayout;
|
|
146
|
+
structure: 'default' | 'sidebar';
|
|
93
147
|
headerHeight: string;
|
|
94
148
|
sidebarWidth: string;
|
|
95
149
|
sidebarCollapsedWidth: string;
|
|
@@ -99,6 +153,7 @@ interface AppShellContextValue {
|
|
|
99
153
|
|
|
100
154
|
const AppShellContext = React.createContext<AppShellContextValue>({
|
|
101
155
|
layout: 'default',
|
|
156
|
+
structure: 'default',
|
|
102
157
|
headerHeight: '56px',
|
|
103
158
|
sidebarWidth: '240px',
|
|
104
159
|
sidebarCollapsedWidth: '64px',
|
|
@@ -190,20 +245,21 @@ function AppShellInner({
|
|
|
190
245
|
children,
|
|
191
246
|
className,
|
|
192
247
|
layout,
|
|
248
|
+
structure,
|
|
193
249
|
style: styleProp,
|
|
194
250
|
...htmlProps
|
|
195
251
|
}: {
|
|
196
252
|
children: React.ReactNode;
|
|
197
253
|
className?: string;
|
|
198
254
|
layout: AppShellLayout;
|
|
255
|
+
structure: 'default' | 'sidebar';
|
|
199
256
|
} & React.HTMLAttributes<HTMLDivElement>) {
|
|
200
257
|
const appShell = useAppShell();
|
|
201
258
|
const { collapsed, isMobile, collapsible } = useSidebar();
|
|
202
259
|
|
|
203
260
|
const classes = [
|
|
204
261
|
styles.root,
|
|
205
|
-
|
|
206
|
-
layout === 'sidebar-floating' && styles.sidebarFloatingLayout,
|
|
262
|
+
structure === 'sidebar' && styles.sidebarLayout,
|
|
207
263
|
className,
|
|
208
264
|
].filter(Boolean).join(' ');
|
|
209
265
|
|
|
@@ -243,14 +299,19 @@ function AppShellInner({
|
|
|
243
299
|
function AppShellRoot({
|
|
244
300
|
children,
|
|
245
301
|
layout = 'default',
|
|
302
|
+
bg,
|
|
246
303
|
className,
|
|
304
|
+
style: styleProp,
|
|
247
305
|
...htmlProps
|
|
248
306
|
}: AppShellProps) {
|
|
307
|
+
const structure = resolveStructure(layout);
|
|
308
|
+
|
|
249
309
|
// Extract config from children using useMemo to avoid re-renders
|
|
250
310
|
const config = React.useMemo(() => extractConfigFromChildren(children), [children]);
|
|
251
311
|
|
|
252
312
|
const contextValue: AppShellContextValue = {
|
|
253
313
|
layout,
|
|
314
|
+
structure,
|
|
254
315
|
headerHeight: config.headerHeight,
|
|
255
316
|
sidebarWidth: config.sidebarWidth,
|
|
256
317
|
sidebarCollapsedWidth: config.sidebarCollapsedWidth,
|
|
@@ -266,7 +327,7 @@ function AppShellRoot({
|
|
|
266
327
|
collapsible={config.sidebarCollapsible}
|
|
267
328
|
defaultCollapsed={config.sidebarDefaultCollapsed}
|
|
268
329
|
>
|
|
269
|
-
<AppShellInner className={className} layout={layout} {...htmlProps}>
|
|
330
|
+
<AppShellInner className={className} layout={layout} structure={structure} style={{ ...(bg ? { backgroundColor: bg } : {}), ...styleProp }} {...htmlProps}>
|
|
270
331
|
{children}
|
|
271
332
|
</AppShellInner>
|
|
272
333
|
</SidebarProvider>
|
|
@@ -280,21 +341,19 @@ function AppShellRoot({
|
|
|
280
341
|
function AppShellHeader({
|
|
281
342
|
children,
|
|
282
343
|
height = '56px',
|
|
344
|
+
bg,
|
|
283
345
|
className,
|
|
284
346
|
style: styleProp,
|
|
285
347
|
...htmlProps
|
|
286
348
|
}: AppShellHeaderProps) {
|
|
287
|
-
const { layout } = useAppShell();
|
|
288
|
-
|
|
289
349
|
const classes = [
|
|
290
350
|
styles.header,
|
|
291
|
-
(layout === 'sidebar' || layout === 'sidebar-floating') && styles.headerSidebar,
|
|
292
|
-
layout === 'sidebar-floating' && styles.headerFloating,
|
|
293
351
|
className,
|
|
294
352
|
].filter(Boolean).join(' ');
|
|
295
353
|
|
|
296
354
|
const style: React.CSSProperties = {
|
|
297
355
|
'--header-height': height,
|
|
356
|
+
...(bg ? { backgroundColor: bg } : {}),
|
|
298
357
|
...styleProp,
|
|
299
358
|
} as React.CSSProperties;
|
|
300
359
|
|
|
@@ -315,22 +374,30 @@ function AppShellSidebar({
|
|
|
315
374
|
collapsible = 'icon',
|
|
316
375
|
position = 'left',
|
|
317
376
|
defaultCollapsed = false,
|
|
377
|
+
variant,
|
|
378
|
+
bg,
|
|
318
379
|
'aria-label': ariaLabel,
|
|
319
380
|
className,
|
|
381
|
+
style: styleProp,
|
|
320
382
|
...htmlProps
|
|
321
383
|
}: AppShellSidebarProps) {
|
|
322
384
|
const isMobile = useIsMobile();
|
|
323
|
-
const { layout } = useAppShell();
|
|
385
|
+
const { layout, structure } = useAppShell();
|
|
386
|
+
const resolvedVariant = resolveSlotVariant(variant, layout, 'sidebar');
|
|
324
387
|
|
|
325
388
|
const classes = [
|
|
326
389
|
styles.sidebar,
|
|
327
|
-
|
|
328
|
-
|
|
390
|
+
structure === 'sidebar' && styles.sidebarFullHeight,
|
|
391
|
+
resolvedVariant === 'floating' && styles.sidebarFloating,
|
|
329
392
|
className,
|
|
330
393
|
].filter(Boolean).join(' ');
|
|
331
394
|
|
|
395
|
+
const style: React.CSSProperties = {
|
|
396
|
+
...styleProp,
|
|
397
|
+
} as React.CSSProperties;
|
|
398
|
+
|
|
332
399
|
return (
|
|
333
|
-
<div {...htmlProps} className={classes}>
|
|
400
|
+
<div {...htmlProps} className={classes} style={style}>
|
|
334
401
|
<Sidebar
|
|
335
402
|
width={width}
|
|
336
403
|
collapsedWidth={collapsedWidth}
|
|
@@ -338,6 +405,7 @@ function AppShellSidebar({
|
|
|
338
405
|
collapsible={collapsible}
|
|
339
406
|
defaultCollapsed={defaultCollapsed}
|
|
340
407
|
aria-label={ariaLabel}
|
|
408
|
+
style={bg ? { backgroundColor: bg } : undefined}
|
|
341
409
|
>
|
|
342
410
|
{children}
|
|
343
411
|
</Sidebar>
|
|
@@ -352,21 +420,30 @@ function AppShellSidebar({
|
|
|
352
420
|
function AppShellMain({
|
|
353
421
|
children,
|
|
354
422
|
padding = 'md',
|
|
423
|
+
variant,
|
|
424
|
+
bg,
|
|
355
425
|
className,
|
|
426
|
+
style: styleProp,
|
|
356
427
|
id = 'main-content',
|
|
357
428
|
...htmlProps
|
|
358
429
|
}: AppShellMainProps) {
|
|
359
430
|
const { layout } = useAppShell();
|
|
431
|
+
const resolvedVariant = resolveSlotVariant(variant, layout, 'main');
|
|
360
432
|
|
|
361
433
|
const classes = [
|
|
362
434
|
styles.main,
|
|
363
435
|
padding !== 'none' && styles[`padding${padding.charAt(0).toUpperCase() + padding.slice(1)}`],
|
|
364
|
-
|
|
436
|
+
resolvedVariant === 'floating' && styles.mainFloating,
|
|
365
437
|
className,
|
|
366
438
|
].filter(Boolean).join(' ');
|
|
367
439
|
|
|
440
|
+
const style: React.CSSProperties = {
|
|
441
|
+
...(bg ? { backgroundColor: bg } : {}),
|
|
442
|
+
...styleProp,
|
|
443
|
+
} as React.CSSProperties;
|
|
444
|
+
|
|
368
445
|
return (
|
|
369
|
-
<main {...htmlProps} className={classes} id={id}>
|
|
446
|
+
<main {...htmlProps} className={classes} style={style} id={id}>
|
|
370
447
|
{children}
|
|
371
448
|
</main>
|
|
372
449
|
);
|
|
@@ -379,18 +456,28 @@ function AppShellAside({
|
|
|
379
456
|
children,
|
|
380
457
|
width = '280px',
|
|
381
458
|
visible = true,
|
|
459
|
+
variant,
|
|
460
|
+
bg,
|
|
382
461
|
className,
|
|
383
462
|
style: styleProp,
|
|
384
463
|
...htmlProps
|
|
385
464
|
}: AppShellAsideProps) {
|
|
465
|
+
const { layout } = useAppShell();
|
|
466
|
+
const resolvedVariant = resolveSlotVariant(variant, layout, 'aside');
|
|
467
|
+
|
|
386
468
|
if (!visible) {
|
|
387
469
|
return null;
|
|
388
470
|
}
|
|
389
471
|
|
|
390
|
-
const classes = [
|
|
472
|
+
const classes = [
|
|
473
|
+
styles.aside,
|
|
474
|
+
resolvedVariant === 'floating' && styles.asideFloating,
|
|
475
|
+
className,
|
|
476
|
+
].filter(Boolean).join(' ');
|
|
391
477
|
|
|
392
478
|
const style: React.CSSProperties = {
|
|
393
479
|
'--aside-width': width,
|
|
480
|
+
...(bg ? { backgroundColor: bg } : {}),
|
|
394
481
|
...styleProp,
|
|
395
482
|
} as React.CSSProperties;
|
|
396
483
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { Popover as BasePopover } from '@base-ui/react/popover';
|
|
5
|
-
import {
|
|
5
|
+
import { useFormFieldIds, type FormFieldProps } from '../../utils/aria';
|
|
6
6
|
import styles from './DatePicker.module.scss';
|
|
7
7
|
// Import globals to ensure CSS variables are defined
|
|
8
8
|
import '../../styles/globals.scss';
|
|
@@ -73,7 +73,7 @@ export interface MenuGroupLabelProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
73
73
|
children: React.ReactNode;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
export
|
|
76
|
+
export type MenuSeparatorProps = React.HTMLAttributes<HTMLElement>;
|
|
77
77
|
|
|
78
78
|
export interface MenuSubmenuProps {
|
|
79
79
|
children: React.ReactNode;
|
|
@@ -64,10 +64,13 @@ export function useNavigationMenu({
|
|
|
64
64
|
|
|
65
65
|
// Clean up timers on unmount
|
|
66
66
|
React.useEffect(() => {
|
|
67
|
+
const openTimer = openTimerRef.current;
|
|
68
|
+
const closeTimer = closeTimerRef.current;
|
|
69
|
+
const skipDelayTimer = skipDelayTimerRef.current;
|
|
67
70
|
return () => {
|
|
68
|
-
if (
|
|
69
|
-
if (
|
|
70
|
-
if (
|
|
71
|
+
if (openTimer) clearTimeout(openTimer);
|
|
72
|
+
if (closeTimer) clearTimeout(closeTimer);
|
|
73
|
+
if (skipDelayTimer) clearTimeout(skipDelayTimer);
|
|
71
74
|
};
|
|
72
75
|
}, []);
|
|
73
76
|
|
package/src/index.ts
CHANGED
|
@@ -266,15 +266,6 @@ function rgbToHex(r: number, g: number, b: number): string {
|
|
|
266
266
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
/**
|
|
270
|
-
* Check if a color is considered "dark" (luminance < 0.5)
|
|
271
|
-
*/
|
|
272
|
-
function isDarkColor(hex: string): boolean {
|
|
273
|
-
const { r, g, b } = hexToRgb(hex);
|
|
274
|
-
const luminance = 0.2126 * (r / 255) + 0.7152 * (g / 255) + 0.0722 * (b / 255);
|
|
275
|
-
return luminance < 0.5;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
269
|
/**
|
|
279
270
|
* Lighten a color by a percentage
|
|
280
271
|
*/
|