@hyphen/hyphen-components 7.2.0 → 7.3.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/components/Sidebar/Sidebar.d.ts +20 -13
- package/dist/components/Sidebar/Sidebar.stories.d.ts +2 -0
- package/dist/hyphen-components.cjs.development.js +241 -146
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +1 -1
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +241 -146
- package/dist/hyphen-components.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Sidebar/Sidebar.stories.tsx +104 -1
- package/src/components/Sidebar/Sidebar.test.tsx +63 -2
- package/src/components/Sidebar/Sidebar.tsx +335 -160
|
@@ -25,33 +25,183 @@ const SIDEBAR_WIDTH = '16rem';
|
|
|
25
25
|
const SIDEBAR_WIDTH_ICON = '44px';
|
|
26
26
|
const SIDEBAR_KEYBOARD_SHORTCUT = '[';
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
type SidebarSide = 'left' | 'right';
|
|
29
|
+
|
|
30
|
+
type SidebarOpenState = Record<SidebarSide, boolean>;
|
|
31
|
+
|
|
32
|
+
type SidebarOpenValue = boolean | Partial<SidebarOpenState>;
|
|
33
|
+
|
|
34
|
+
type SidebarStorageKey = string | Partial<Record<SidebarSide, string>>;
|
|
35
|
+
|
|
36
|
+
interface SidebarContextSideState {
|
|
29
37
|
state: 'expanded' | 'collapsed';
|
|
30
38
|
open: boolean;
|
|
31
|
-
setOpen: (open: boolean) => void;
|
|
39
|
+
setOpen: (open: boolean | ((open: boolean) => boolean)) => void;
|
|
32
40
|
openMobile: boolean;
|
|
33
|
-
setOpenMobile: (open: boolean) => void;
|
|
34
|
-
isMobile: boolean;
|
|
41
|
+
setOpenMobile: (open: boolean | ((open: boolean) => boolean)) => void;
|
|
35
42
|
toggleSidebar: () => void;
|
|
36
43
|
}
|
|
37
44
|
|
|
45
|
+
interface SidebarContextProps {
|
|
46
|
+
isMobile: boolean;
|
|
47
|
+
sides: Record<SidebarSide, SidebarContextSideState>;
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
const SidebarContext = React.createContext<SidebarContextProps | null>(null);
|
|
51
|
+
const SidebarSideContext = React.createContext<SidebarSide>('left');
|
|
52
|
+
|
|
53
|
+
const resolveSideValue = (
|
|
54
|
+
value: SidebarOpenValue | undefined,
|
|
55
|
+
side: SidebarSide,
|
|
56
|
+
fallback: boolean
|
|
57
|
+
) => {
|
|
58
|
+
if (typeof value === 'boolean') {
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (value && typeof value === 'object' && typeof value[side] === 'boolean') {
|
|
63
|
+
return value[side] as boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return fallback;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const resolveControlledOpen = (
|
|
70
|
+
value: SidebarOpenValue | undefined,
|
|
71
|
+
side: SidebarSide
|
|
72
|
+
) => {
|
|
73
|
+
if (typeof value === 'boolean') {
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (value && typeof value === 'object' && typeof value[side] === 'boolean') {
|
|
78
|
+
return value[side] as boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return undefined;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const resolveStorageKey = (
|
|
85
|
+
storageKey: SidebarStorageKey,
|
|
86
|
+
side: SidebarSide
|
|
87
|
+
) => {
|
|
88
|
+
if (typeof storageKey === 'string') {
|
|
89
|
+
return side === 'left' ? storageKey : `${storageKey}_right`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (storageKey && typeof storageKey === 'object') {
|
|
93
|
+
return (
|
|
94
|
+
storageKey[side] ??
|
|
95
|
+
(side === 'left' ? 'sidebar_expanded' : 'sidebar_expanded_right')
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return side === 'left' ? 'sidebar_expanded' : 'sidebar_expanded_right';
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const useSidebarSideState = ({
|
|
103
|
+
side,
|
|
104
|
+
isMobile,
|
|
105
|
+
defaultOpen,
|
|
106
|
+
openProp,
|
|
107
|
+
onOpenChange,
|
|
108
|
+
storageKey,
|
|
109
|
+
lastToggledSideRef,
|
|
110
|
+
}: {
|
|
111
|
+
side: SidebarSide;
|
|
112
|
+
isMobile: boolean;
|
|
113
|
+
defaultOpen: SidebarOpenValue | undefined;
|
|
114
|
+
openProp: SidebarOpenValue | undefined;
|
|
115
|
+
onOpenChange?: (open: boolean, side?: SidebarSide) => void;
|
|
116
|
+
storageKey: SidebarStorageKey;
|
|
117
|
+
lastToggledSideRef: React.MutableRefObject<SidebarSide>;
|
|
118
|
+
}): SidebarContextSideState => {
|
|
119
|
+
const defaultFallback = typeof defaultOpen === 'boolean' ? defaultOpen : true;
|
|
120
|
+
const initialDefaultOpen = resolveSideValue(
|
|
121
|
+
defaultOpen,
|
|
122
|
+
side,
|
|
123
|
+
defaultFallback
|
|
124
|
+
);
|
|
125
|
+
const controlledOpen = resolveControlledOpen(openProp, side);
|
|
126
|
+
const isControlled = typeof controlledOpen === 'boolean';
|
|
127
|
+
|
|
128
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(
|
|
129
|
+
controlledOpen ?? initialDefaultOpen
|
|
130
|
+
);
|
|
131
|
+
const [openMobile, setOpenMobile] = useState(() =>
|
|
132
|
+
isMobile ? false : controlledOpen ?? initialDefaultOpen
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const open = controlledOpen ?? uncontrolledOpen;
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (isMobile) {
|
|
139
|
+
setOpenMobile(false);
|
|
140
|
+
} else {
|
|
141
|
+
setUncontrolledOpen(controlledOpen ?? initialDefaultOpen);
|
|
142
|
+
}
|
|
143
|
+
}, [isMobile, controlledOpen, initialDefaultOpen]);
|
|
144
|
+
|
|
145
|
+
const setOpen = useCallback(
|
|
146
|
+
(value: boolean | ((value: boolean) => boolean)) => {
|
|
147
|
+
const newOpenState = typeof value === 'function' ? value(open) : value;
|
|
148
|
+
if (newOpenState === open) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!isControlled) {
|
|
153
|
+
setUncontrolledOpen(newOpenState);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
onOpenChange?.(newOpenState, side);
|
|
157
|
+
|
|
158
|
+
const key = resolveStorageKey(storageKey, side);
|
|
159
|
+
localStorage.setItem(key, `${newOpenState}`);
|
|
160
|
+
},
|
|
161
|
+
[open, isControlled, onOpenChange, side, storageKey]
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const toggleSidebar = useCallback(() => {
|
|
165
|
+
lastToggledSideRef.current = side;
|
|
166
|
+
isMobile ? setOpenMobile((value) => !value) : setOpen((value) => !value);
|
|
167
|
+
}, [isMobile, setOpen, side, lastToggledSideRef]);
|
|
168
|
+
|
|
169
|
+
const state = open ? 'expanded' : 'collapsed';
|
|
170
|
+
|
|
171
|
+
return useMemo(
|
|
172
|
+
() => ({
|
|
173
|
+
state,
|
|
174
|
+
open,
|
|
175
|
+
setOpen,
|
|
176
|
+
openMobile,
|
|
177
|
+
setOpenMobile,
|
|
178
|
+
toggleSidebar,
|
|
179
|
+
}),
|
|
180
|
+
[state, open, setOpen, openMobile, setOpenMobile, toggleSidebar]
|
|
181
|
+
);
|
|
182
|
+
};
|
|
39
183
|
|
|
40
|
-
function useSidebar() {
|
|
184
|
+
function useSidebar(sideOverride?: SidebarSide) {
|
|
41
185
|
const context = React.useContext(SidebarContext);
|
|
42
186
|
if (!context) {
|
|
43
187
|
throw new Error('useSidebar must be used within a SidebarProvider.');
|
|
44
188
|
}
|
|
45
|
-
|
|
189
|
+
const contextSide = React.useContext(SidebarSideContext);
|
|
190
|
+
const side = sideOverride ?? contextSide;
|
|
191
|
+
return {
|
|
192
|
+
...context.sides[side],
|
|
193
|
+
isMobile: context.isMobile,
|
|
194
|
+
side,
|
|
195
|
+
};
|
|
46
196
|
}
|
|
47
197
|
|
|
48
198
|
const SidebarProvider = forwardRef<
|
|
49
199
|
HTMLDivElement,
|
|
50
200
|
React.ComponentProps<'div'> & {
|
|
51
|
-
defaultOpen?:
|
|
52
|
-
open?:
|
|
53
|
-
storageKey?:
|
|
54
|
-
onOpenChange?: (open: boolean) => void;
|
|
201
|
+
defaultOpen?: SidebarOpenValue;
|
|
202
|
+
open?: SidebarOpenValue;
|
|
203
|
+
storageKey?: SidebarStorageKey;
|
|
204
|
+
onOpenChange?: (open: boolean, side?: SidebarSide) => void;
|
|
55
205
|
}
|
|
56
206
|
>(
|
|
57
207
|
(
|
|
@@ -68,72 +218,49 @@ const SidebarProvider = forwardRef<
|
|
|
68
218
|
ref
|
|
69
219
|
) => {
|
|
70
220
|
const isMobile = useIsMobile();
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const newOpenState = typeof value === 'function' ? value(open) : value;
|
|
91
|
-
|
|
92
|
-
if (newOpenState !== open) {
|
|
93
|
-
if (setOpenProp) {
|
|
94
|
-
setOpenProp(newOpenState);
|
|
95
|
-
} else {
|
|
96
|
-
_setOpen(newOpenState);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
localStorage.setItem(storageKey, `${newOpenState}`);
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
[setOpenProp, open, storageKey]
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
// Toggle sidebar based on screen type
|
|
106
|
-
const toggleSidebar = useCallback(() => {
|
|
107
|
-
isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
|
108
|
-
}, [isMobile, setOpen, setOpenMobile]);
|
|
221
|
+
const lastToggledSideRef = React.useRef<SidebarSide>('left');
|
|
222
|
+
const leftState = useSidebarSideState({
|
|
223
|
+
side: 'left',
|
|
224
|
+
isMobile,
|
|
225
|
+
defaultOpen,
|
|
226
|
+
openProp,
|
|
227
|
+
onOpenChange: setOpenProp,
|
|
228
|
+
storageKey,
|
|
229
|
+
lastToggledSideRef,
|
|
230
|
+
});
|
|
231
|
+
const rightState = useSidebarSideState({
|
|
232
|
+
side: 'right',
|
|
233
|
+
isMobile,
|
|
234
|
+
defaultOpen,
|
|
235
|
+
openProp,
|
|
236
|
+
onOpenChange: setOpenProp,
|
|
237
|
+
storageKey,
|
|
238
|
+
lastToggledSideRef,
|
|
239
|
+
});
|
|
109
240
|
|
|
110
241
|
// Keydown event handler for toggling sidebar
|
|
111
242
|
useEffect(() => {
|
|
112
243
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
113
244
|
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT) {
|
|
114
245
|
event.preventDefault();
|
|
115
|
-
|
|
246
|
+
const sideToToggle = lastToggledSideRef.current;
|
|
247
|
+
(sideToToggle === 'left' ? leftState : rightState).toggleSidebar();
|
|
116
248
|
}
|
|
117
249
|
};
|
|
118
250
|
|
|
119
251
|
window.addEventListener('keydown', handleKeyDown);
|
|
120
252
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
121
|
-
}, [
|
|
122
|
-
|
|
123
|
-
// Assign state for data attributes
|
|
124
|
-
const state = open ? 'expanded' : 'collapsed';
|
|
253
|
+
}, [leftState, rightState]);
|
|
125
254
|
|
|
126
255
|
const contextValue = useMemo<SidebarContextProps>(
|
|
127
256
|
() => ({
|
|
128
|
-
state,
|
|
129
|
-
open,
|
|
130
|
-
setOpen,
|
|
131
257
|
isMobile,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
258
|
+
sides: {
|
|
259
|
+
left: leftState,
|
|
260
|
+
right: rightState,
|
|
261
|
+
},
|
|
135
262
|
}),
|
|
136
|
-
[
|
|
263
|
+
[isMobile, leftState, rightState]
|
|
137
264
|
);
|
|
138
265
|
|
|
139
266
|
return (
|
|
@@ -167,7 +294,7 @@ SidebarProvider.displayName = 'SidebarProvider';
|
|
|
167
294
|
const Sidebar = React.forwardRef<
|
|
168
295
|
HTMLDivElement,
|
|
169
296
|
React.ComponentProps<'div'> & {
|
|
170
|
-
side?: 'left'
|
|
297
|
+
side?: 'left' | 'right';
|
|
171
298
|
collapsible?: 'offcanvas' | 'icon' | 'none';
|
|
172
299
|
}
|
|
173
300
|
>(
|
|
@@ -175,106 +302,134 @@ const Sidebar = React.forwardRef<
|
|
|
175
302
|
{ side = 'left', collapsible = 'offcanvas', className, children, ...props },
|
|
176
303
|
ref
|
|
177
304
|
) => {
|
|
178
|
-
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
|
305
|
+
const { isMobile, state, openMobile, setOpenMobile } = useSidebar(side);
|
|
179
306
|
|
|
180
307
|
if (isMobile) {
|
|
181
308
|
return (
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
309
|
+
<SidebarSideContext.Provider value={side}>
|
|
310
|
+
<Drawer
|
|
311
|
+
isOpen={openMobile}
|
|
312
|
+
onDismiss={() => setOpenMobile(false)}
|
|
313
|
+
placement={side}
|
|
314
|
+
>
|
|
315
|
+
<Box data-sidebar="sidebar" data-mobile="true" height="100">
|
|
316
|
+
{children}
|
|
317
|
+
</Box>
|
|
318
|
+
</Drawer>
|
|
319
|
+
</SidebarSideContext.Provider>
|
|
191
320
|
);
|
|
192
321
|
}
|
|
193
322
|
|
|
194
323
|
if (collapsible === 'none') {
|
|
195
324
|
return (
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
325
|
+
<SidebarSideContext.Provider value={side}>
|
|
326
|
+
<div
|
|
327
|
+
className={classNames(
|
|
328
|
+
'group display-flex h-100 font-size-xs flex-direction-column background-color-secondary font-color-base',
|
|
329
|
+
className
|
|
330
|
+
)}
|
|
331
|
+
style={{
|
|
332
|
+
width: 'var(--sidebar-width)',
|
|
333
|
+
}}
|
|
334
|
+
ref={ref}
|
|
335
|
+
{...props}
|
|
336
|
+
>
|
|
337
|
+
{children}
|
|
338
|
+
</div>
|
|
339
|
+
</SidebarSideContext.Provider>
|
|
209
340
|
);
|
|
210
341
|
}
|
|
211
342
|
|
|
212
343
|
return (
|
|
213
|
-
<
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
transitionDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
231
|
-
animationDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
232
|
-
transitionProperty: 'width',
|
|
233
|
-
width:
|
|
234
|
-
state === 'collapsed' && collapsible === 'icon'
|
|
235
|
-
? 'var(--sidebar-width-icon)'
|
|
236
|
-
: state === 'collapsed'
|
|
237
|
-
? '0'
|
|
238
|
-
: 'var(--sidebar-width)',
|
|
239
|
-
height: '100svh',
|
|
240
|
-
}}
|
|
241
|
-
className={classNames('position-relative', className)}
|
|
242
|
-
/>
|
|
243
|
-
<div
|
|
244
|
-
className={classNames(
|
|
245
|
-
'position-absolute display-none display-flex-desktop ',
|
|
246
|
-
className
|
|
247
|
-
)}
|
|
248
|
-
style={{
|
|
249
|
-
left:
|
|
250
|
-
state === 'expanded' || collapsible === 'icon'
|
|
251
|
-
? '0'
|
|
252
|
-
: 'calc(var(--sidebar-width)*-1)',
|
|
253
|
-
top: '0',
|
|
254
|
-
bottom: '0',
|
|
255
|
-
zIndex: 'var(--size-z-index-drawer)',
|
|
256
|
-
animationTimingFunction: 'var(--sidebar-transition-timing, linear)',
|
|
257
|
-
transitionTimingFunction:
|
|
258
|
-
'var(--sidebar-transition-timing, linear)',
|
|
259
|
-
transitionDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
260
|
-
animationDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
261
|
-
transitionProperty: 'left, right, width',
|
|
262
|
-
width:
|
|
263
|
-
state === 'collapsed' && collapsible === 'icon'
|
|
264
|
-
? 'var(--sidebar-width-icon)'
|
|
265
|
-
: 'var(--sidebar-width)',
|
|
266
|
-
height: '100svh',
|
|
267
|
-
}}
|
|
268
|
-
{...props}
|
|
344
|
+
<SidebarSideContext.Provider value={side}>
|
|
345
|
+
<Box
|
|
346
|
+
ref={ref}
|
|
347
|
+
background="primary"
|
|
348
|
+
display={{ base: 'none', desktop: 'block' }}
|
|
349
|
+
color="base"
|
|
350
|
+
fontSize="sm"
|
|
351
|
+
position="relative"
|
|
352
|
+
style={
|
|
353
|
+
side === 'right' && collapsible === 'offcanvas'
|
|
354
|
+
? { overflowX: 'hidden' }
|
|
355
|
+
: undefined
|
|
356
|
+
}
|
|
357
|
+
data-state={state}
|
|
358
|
+
data-collapsible={collapsible}
|
|
359
|
+
data-side={side}
|
|
360
|
+
className="group"
|
|
269
361
|
>
|
|
270
362
|
<div
|
|
271
|
-
|
|
272
|
-
|
|
363
|
+
style={{
|
|
364
|
+
animationTimingFunction:
|
|
365
|
+
'var(--sidebar-transition-timing, linear)',
|
|
366
|
+
transitionTimingFunction:
|
|
367
|
+
'var(--sidebar-transition-timing, linear)',
|
|
368
|
+
transitionDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
369
|
+
animationDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
370
|
+
transitionProperty: 'width',
|
|
371
|
+
width:
|
|
372
|
+
state === 'collapsed' && collapsible === 'icon'
|
|
373
|
+
? 'var(--sidebar-width-icon)'
|
|
374
|
+
: state === 'collapsed'
|
|
375
|
+
? '0'
|
|
376
|
+
: 'var(--sidebar-width)',
|
|
377
|
+
height: '100svh',
|
|
378
|
+
}}
|
|
379
|
+
className={classNames('position-relative', className)}
|
|
380
|
+
/>
|
|
381
|
+
<div
|
|
382
|
+
className={classNames(
|
|
383
|
+
'position-absolute display-none display-flex-desktop ',
|
|
384
|
+
className
|
|
385
|
+
)}
|
|
386
|
+
style={{
|
|
387
|
+
left:
|
|
388
|
+
side === 'left' &&
|
|
389
|
+
(state === 'expanded' || collapsible === 'icon')
|
|
390
|
+
? '0'
|
|
391
|
+
: side === 'left'
|
|
392
|
+
? 'calc(var(--sidebar-width)*-1)'
|
|
393
|
+
: undefined,
|
|
394
|
+
right:
|
|
395
|
+
side === 'right' &&
|
|
396
|
+
(state === 'expanded' || collapsible === 'icon')
|
|
397
|
+
? '0'
|
|
398
|
+
: side === 'right'
|
|
399
|
+
? 'calc(var(--sidebar-width)*-1)'
|
|
400
|
+
: undefined,
|
|
401
|
+
top: '0',
|
|
402
|
+
bottom: '0',
|
|
403
|
+
zIndex: 'var(--size-z-index-drawer)',
|
|
404
|
+
animationTimingFunction:
|
|
405
|
+
'var(--sidebar-transition-timing, linear)',
|
|
406
|
+
transitionTimingFunction:
|
|
407
|
+
'var(--sidebar-transition-timing, linear)',
|
|
408
|
+
transitionDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
409
|
+
animationDuration: 'var(--sidebar-transition-duration, 200ms)',
|
|
410
|
+
transitionProperty: 'left, right, width',
|
|
411
|
+
width:
|
|
412
|
+
state === 'collapsed' && collapsible === 'icon'
|
|
413
|
+
? 'var(--sidebar-width-icon)'
|
|
414
|
+
: 'var(--sidebar-width)',
|
|
415
|
+
height: '100svh',
|
|
416
|
+
}}
|
|
417
|
+
{...props}
|
|
273
418
|
>
|
|
274
|
-
|
|
419
|
+
<div
|
|
420
|
+
data-sidebar="sidebar"
|
|
421
|
+
className={classNames(
|
|
422
|
+
'display-flex h-100 w-100 flex-direction-column background-color-secondary font-color-base',
|
|
423
|
+
{
|
|
424
|
+
'p-right-lg-desktop': side === 'right',
|
|
425
|
+
}
|
|
426
|
+
)}
|
|
427
|
+
>
|
|
428
|
+
{children}
|
|
429
|
+
</div>
|
|
275
430
|
</div>
|
|
276
|
-
</
|
|
277
|
-
</
|
|
431
|
+
</Box>
|
|
432
|
+
</SidebarSideContext.Provider>
|
|
278
433
|
);
|
|
279
434
|
}
|
|
280
435
|
);
|
|
@@ -282,9 +437,12 @@ Sidebar.displayName = 'Sidebar';
|
|
|
282
437
|
|
|
283
438
|
const SidebarTrigger = React.forwardRef<
|
|
284
439
|
React.ElementRef<typeof Button>,
|
|
285
|
-
React.ComponentProps<typeof Button>
|
|
286
|
-
|
|
287
|
-
|
|
440
|
+
React.ComponentProps<typeof Button> & {
|
|
441
|
+
side?: SidebarSide;
|
|
442
|
+
iconName?: IconName;
|
|
443
|
+
}
|
|
444
|
+
>(({ className, onClick, side, iconName = 'dock-left', ...props }, ref) => {
|
|
445
|
+
const { toggleSidebar, side: contextSide } = useSidebar(side);
|
|
288
446
|
|
|
289
447
|
return (
|
|
290
448
|
<Button
|
|
@@ -292,13 +450,19 @@ const SidebarTrigger = React.forwardRef<
|
|
|
292
450
|
data-sidebar="trigger"
|
|
293
451
|
variant="tertiary"
|
|
294
452
|
size="sm"
|
|
295
|
-
iconPrefix=
|
|
296
|
-
className={classNames(
|
|
453
|
+
iconPrefix={iconName}
|
|
454
|
+
className={classNames(
|
|
455
|
+
{
|
|
456
|
+
'm-left-sm m-left-0-tablet': contextSide === 'left',
|
|
457
|
+
'm-right-sm m-right-0-tablet': contextSide === 'right',
|
|
458
|
+
},
|
|
459
|
+
className
|
|
460
|
+
)}
|
|
297
461
|
onClick={(event) => {
|
|
298
462
|
onClick?.(event);
|
|
299
463
|
toggleSidebar();
|
|
300
464
|
}}
|
|
301
|
-
aria-label=
|
|
465
|
+
aria-label={`Toggle ${contextSide} sidebar`}
|
|
302
466
|
{...props}
|
|
303
467
|
/>
|
|
304
468
|
);
|
|
@@ -429,7 +593,7 @@ const SidebarMenuButton = React.forwardRef<
|
|
|
429
593
|
ref
|
|
430
594
|
) => {
|
|
431
595
|
const Comp = asChild ? Slot : 'button';
|
|
432
|
-
const { isMobile, state } = useSidebar();
|
|
596
|
+
const { isMobile, state, side } = useSidebar();
|
|
433
597
|
|
|
434
598
|
const button = (
|
|
435
599
|
<Comp
|
|
@@ -464,7 +628,7 @@ const SidebarMenuButton = React.forwardRef<
|
|
|
464
628
|
<Tooltip>
|
|
465
629
|
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
|
466
630
|
<TooltipContent
|
|
467
|
-
side=
|
|
631
|
+
side={side === 'right' ? 'left' : 'right'}
|
|
468
632
|
align="center"
|
|
469
633
|
hidden={state !== 'collapsed' || isMobile}
|
|
470
634
|
{...tooltip}
|
|
@@ -594,9 +758,15 @@ const SidebarRail = React.forwardRef<
|
|
|
594
758
|
HTMLButtonElement,
|
|
595
759
|
React.ComponentProps<'button'>
|
|
596
760
|
>(({ className, ...props }, ref) => {
|
|
597
|
-
const { open, toggleSidebar } = useSidebar();
|
|
761
|
+
const { open, toggleSidebar, side } = useSidebar();
|
|
598
762
|
|
|
599
|
-
const caretIcon = open
|
|
763
|
+
const caretIcon = open
|
|
764
|
+
? side === 'right'
|
|
765
|
+
? 'caret-sm-right'
|
|
766
|
+
: 'caret-sm-left'
|
|
767
|
+
: side === 'right'
|
|
768
|
+
? 'caret-sm-left'
|
|
769
|
+
: 'caret-sm-right';
|
|
600
770
|
|
|
601
771
|
return (
|
|
602
772
|
<button
|
|
@@ -610,15 +780,18 @@ const SidebarRail = React.forwardRef<
|
|
|
610
780
|
styles.rail,
|
|
611
781
|
'hover-show-child background-color-transparent display-flex p-top-5xl p-left-xl p-right-0 justify-content-center position-absolute',
|
|
612
782
|
{
|
|
613
|
-
'cursor-w-resize':
|
|
614
|
-
|
|
783
|
+
'cursor-w-resize':
|
|
784
|
+
(open && side === 'left') || (!open && side === 'right'),
|
|
785
|
+
'cursor-e-resize':
|
|
786
|
+
(!open && side === 'left') || (open && side === 'right'),
|
|
615
787
|
},
|
|
616
788
|
className
|
|
617
789
|
)}
|
|
618
790
|
style={{
|
|
619
791
|
top: '20px',
|
|
620
792
|
bottom: '20px',
|
|
621
|
-
right: '-14px',
|
|
793
|
+
right: side === 'left' ? '-14px' : undefined,
|
|
794
|
+
left: side === 'right' ? '-14px' : undefined,
|
|
622
795
|
width: '10px',
|
|
623
796
|
}}
|
|
624
797
|
{...props}
|
|
@@ -638,8 +811,10 @@ const SidebarRail = React.forwardRef<
|
|
|
638
811
|
className={classNames(
|
|
639
812
|
'hover-child',
|
|
640
813
|
{
|
|
641
|
-
'cursor-w-resize':
|
|
642
|
-
|
|
814
|
+
'cursor-w-resize':
|
|
815
|
+
(open && side === 'left') || (!open && side === 'right'),
|
|
816
|
+
'cursor-e-resize':
|
|
817
|
+
(!open && side === 'left') || (open && side === 'right'),
|
|
643
818
|
},
|
|
644
819
|
className
|
|
645
820
|
)}
|