@techsio/ui-kit 0.41.2 → 0.43.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/internal/molecules/drawer.context.js +133 -0
- package/dist/internal/molecules/drawer.styles.js +107 -0
- package/dist/internal/organisms/sidebar.context.js +223 -0
- package/dist/internal/organisms/sidebar.focus.js +169 -0
- package/dist/internal/organisms/sidebar.styles.js +146 -0
- package/dist/molecules/drawer.js +262 -0
- package/dist/molecules/file-upload.js +369 -0
- package/dist/organisms/sidebar.js +448 -0
- package/dist/src/internal/molecules/drawer.context.d.ts +53 -0
- package/dist/src/internal/molecules/drawer.context.d.ts.map +1 -0
- package/dist/src/internal/molecules/drawer.styles.d.ts +115 -0
- package/dist/src/internal/molecules/drawer.styles.d.ts.map +1 -0
- package/dist/src/internal/organisms/sidebar.context.d.ts +83 -0
- package/dist/src/internal/organisms/sidebar.context.d.ts.map +1 -0
- package/dist/src/internal/organisms/sidebar.focus.d.ts +16 -0
- package/dist/src/internal/organisms/sidebar.focus.d.ts.map +1 -0
- package/dist/src/internal/organisms/sidebar.styles.d.ts +149 -0
- package/dist/src/internal/organisms/sidebar.styles.d.ts.map +1 -0
- package/dist/src/molecules/drawer.d.ts +112 -0
- package/dist/src/molecules/drawer.d.ts.map +1 -0
- package/dist/src/molecules/file-upload.d.ts +84 -0
- package/dist/src/molecules/file-upload.d.ts.map +1 -0
- package/dist/src/molecules/switch.d.ts +3 -3
- package/dist/src/molecules/toast.d.ts +6 -6
- package/dist/src/organisms/sidebar.d.ts +93 -0
- package/dist/src/organisms/sidebar.d.ts.map +1 -0
- package/dist/src/types/zag.d.ts +2 -0
- package/dist/src/types/zag.d.ts.map +1 -1
- package/dist/stories/changelog/changelog.stories.d.ts.map +1 -1
- package/dist/stories/molecules/drawer.stories.d.ts +158 -0
- package/dist/stories/molecules/drawer.stories.d.ts.map +1 -0
- package/dist/stories/molecules/file-upload.stories.d.ts +105 -0
- package/dist/stories/molecules/file-upload.stories.d.ts.map +1 -0
- package/dist/stories/organisms/sidebar.stories.d.ts +66 -0
- package/dist/stories/organisms/sidebar.stories.d.ts.map +1 -0
- package/dist/test/drawer.behavior.spec.d.ts +2 -0
- package/dist/test/drawer.behavior.spec.d.ts.map +1 -0
- package/dist/test/sidebar.behavior.spec.d.ts +2 -0
- package/dist/test/sidebar.behavior.spec.d.ts.map +1 -0
- package/dist/test/sidebar.ssr.bun.d.ts +2 -0
- package/dist/test/sidebar.ssr.bun.d.ts.map +1 -0
- package/package.json +26 -22
- package/src/tokens/components/components.css +3 -0
- package/src/tokens/components/molecules/_drawer.css +369 -0
- package/src/tokens/components/molecules/_file-upload.css +128 -0
- package/src/tokens/components/organisms/_sidebar.css +93 -0
- package/src/tokens/figma/brand-overrides.css +2 -2
- package/src/tokens/figma/business/variables.css +3 -2
- package/src/tokens/figma/dark/variables.css +1 -0
- package/src/tokens/figma/light/variables.css +3 -2
- package/src/tokens/figma/neo/variables.css +3 -2
- package/src/tokens/figma/neo-dark/variables.css +1 -0
- package/src/tokens/figma/variables.css +3 -2
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { normalizeProps, useMachine } from "@zag-js/react";
|
|
4
|
+
import { createContext, useContext, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { drawerVariants } from "./drawer.styles.js";
|
|
6
|
+
import * as __rspack_external__zag_js_drawer_a300f837 from "@zag-js/drawer";
|
|
7
|
+
import * as __rspack_external__zag_js_presence_229d2f05 from "@zag-js/presence";
|
|
8
|
+
const DrawerContext = /*#__PURE__*/ createContext(null);
|
|
9
|
+
const DrawerStackStoreContext = /*#__PURE__*/ createContext(void 0);
|
|
10
|
+
const DrawerStackContext = /*#__PURE__*/ createContext(null);
|
|
11
|
+
function useDrawer(props = {}) {
|
|
12
|
+
const generatedId = useId();
|
|
13
|
+
const inheritedStack = useContext(DrawerStackStoreContext);
|
|
14
|
+
const { defaultSnapPoint, id = generatedId, stack = inheritedStack, ...machineProps } = props;
|
|
15
|
+
const machineOptions = {
|
|
16
|
+
id,
|
|
17
|
+
stack,
|
|
18
|
+
...machineProps
|
|
19
|
+
};
|
|
20
|
+
if ("defaultSnapPoint" in props) Object.assign(machineOptions, {
|
|
21
|
+
defaultSnapPoint
|
|
22
|
+
});
|
|
23
|
+
const service = useMachine(__rspack_external__zag_js_drawer_a300f837.machine, machineOptions);
|
|
24
|
+
return __rspack_external__zag_js_drawer_a300f837.connect(service, normalizeProps);
|
|
25
|
+
}
|
|
26
|
+
function useDrawerContext() {
|
|
27
|
+
const context = useContext(DrawerContext);
|
|
28
|
+
if (!context) throw new Error("Drawer components must be used within Drawer.Root");
|
|
29
|
+
return context;
|
|
30
|
+
}
|
|
31
|
+
function useDrawerStackContext() {
|
|
32
|
+
const context = useContext(DrawerStackContext);
|
|
33
|
+
if (!context) throw new Error("Drawer stack components must be used within Drawer.Stack");
|
|
34
|
+
return context;
|
|
35
|
+
}
|
|
36
|
+
function useDrawerPresence({ immediate, lazyMount = true, onEnterComplete, onExitComplete, present, skipAnimationOnMount = false, unmountOnExit = true }) {
|
|
37
|
+
const wasEverPresent = useRef(false);
|
|
38
|
+
const service = useMachine(__rspack_external__zag_js_presence_229d2f05.machine, {
|
|
39
|
+
immediate,
|
|
40
|
+
onEnterComplete,
|
|
41
|
+
onExitComplete,
|
|
42
|
+
present
|
|
43
|
+
});
|
|
44
|
+
const api = __rspack_external__zag_js_presence_229d2f05.connect(service, normalizeProps);
|
|
45
|
+
const latestSetNode = useRef(api.setNode);
|
|
46
|
+
latestSetNode.current = api.setNode;
|
|
47
|
+
const presenceRef = useRef((node)=>{
|
|
48
|
+
latestSetNode.current(node);
|
|
49
|
+
return ()=>{
|
|
50
|
+
latestSetNode.current(null);
|
|
51
|
+
};
|
|
52
|
+
}).current;
|
|
53
|
+
if (api.present) wasEverPresent.current = true;
|
|
54
|
+
const unmounted = !(api.present || wasEverPresent.current) && lazyMount || !api.present && wasEverPresent.current && unmountOnExit;
|
|
55
|
+
return {
|
|
56
|
+
api,
|
|
57
|
+
ref: presenceRef,
|
|
58
|
+
skipAnimationOnMount,
|
|
59
|
+
unmounted
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function DrawerProvider({ api, children, immediate, lazyMount = true, onEnterComplete, onExitComplete, size, skipAnimationOnMount = false, unmountOnExit = true }) {
|
|
63
|
+
const presenceOptions = {
|
|
64
|
+
immediate,
|
|
65
|
+
lazyMount,
|
|
66
|
+
skipAnimationOnMount,
|
|
67
|
+
unmountOnExit
|
|
68
|
+
};
|
|
69
|
+
const contentPresence = useDrawerPresence({
|
|
70
|
+
...presenceOptions,
|
|
71
|
+
onEnterComplete,
|
|
72
|
+
onExitComplete,
|
|
73
|
+
present: api.open
|
|
74
|
+
});
|
|
75
|
+
const styles = drawerVariants({
|
|
76
|
+
size
|
|
77
|
+
});
|
|
78
|
+
return /*#__PURE__*/ jsx(DrawerContext.Provider, {
|
|
79
|
+
value: {
|
|
80
|
+
api,
|
|
81
|
+
presence: contentPresence,
|
|
82
|
+
presenceOptions,
|
|
83
|
+
styles
|
|
84
|
+
},
|
|
85
|
+
children: children
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function getDrawerPresenceProps(open, presenceState) {
|
|
89
|
+
let dataState = null;
|
|
90
|
+
if (!(presenceState.api.skip && presenceState.skipAnimationOnMount)) dataState = open ? "open" : "closed";
|
|
91
|
+
return {
|
|
92
|
+
"data-state": dataState,
|
|
93
|
+
hidden: !presenceState.api.present
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function composeRefs(...refs) {
|
|
97
|
+
return (node)=>{
|
|
98
|
+
const cleanups = [];
|
|
99
|
+
for (const ref of refs)if ("function" == typeof ref) {
|
|
100
|
+
const cleanup = ref(node);
|
|
101
|
+
cleanups.push("function" == typeof cleanup ? cleanup : ()=>ref(null));
|
|
102
|
+
} else if (ref) {
|
|
103
|
+
ref.current = node;
|
|
104
|
+
cleanups.push(()=>{
|
|
105
|
+
ref.current = null;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return ()=>{
|
|
109
|
+
for (const cleanup of cleanups)cleanup();
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function useComposedRefs(firstRef, secondRef) {
|
|
114
|
+
return useMemo(()=>composeRefs(firstRef, secondRef), [
|
|
115
|
+
firstRef,
|
|
116
|
+
secondRef
|
|
117
|
+
]);
|
|
118
|
+
}
|
|
119
|
+
function DrawerStackProvider({ children }) {
|
|
120
|
+
const [stack] = useState(()=>__rspack_external__zag_js_drawer_a300f837.createStack());
|
|
121
|
+
const snapshot = useSyncExternalStore(stack.subscribe, stack.getSnapshot, stack.getSnapshot);
|
|
122
|
+
const api = useMemo(()=>__rspack_external__zag_js_drawer_a300f837.connectStack(snapshot, normalizeProps), [
|
|
123
|
+
snapshot
|
|
124
|
+
]);
|
|
125
|
+
return /*#__PURE__*/ jsx(DrawerStackStoreContext.Provider, {
|
|
126
|
+
value: stack,
|
|
127
|
+
children: /*#__PURE__*/ jsx(DrawerStackContext.Provider, {
|
|
128
|
+
value: api,
|
|
129
|
+
children: children
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
export { DrawerProvider, DrawerStackProvider, getDrawerPresenceProps, useComposedRefs, useDrawer, useDrawerContext, useDrawerPresence, useDrawerStackContext };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { tv } from "../../utils.js";
|
|
2
|
+
const drawerVariants = tv({
|
|
3
|
+
slots: {
|
|
4
|
+
backdrop: [
|
|
5
|
+
"drawer-backdrop-layer fixed inset-0 bg-drawer-backdrop-bg",
|
|
6
|
+
"drawer-backdrop-motion"
|
|
7
|
+
],
|
|
8
|
+
positioner: [
|
|
9
|
+
"drawer-physical-axis drawer-positioner-layer pointer-events-none fixed inset-0 flex",
|
|
10
|
+
"data-[swipe-direction=up]:items-start",
|
|
11
|
+
"data-[swipe-direction=down]:items-end",
|
|
12
|
+
"data-[swipe-direction=left]:justify-start",
|
|
13
|
+
"data-[swipe-direction=right]:justify-end"
|
|
14
|
+
],
|
|
15
|
+
content: [
|
|
16
|
+
"drawer-content-layer drawer-content-bleed pointer-events-auto relative flex max-h-full max-w-full flex-col",
|
|
17
|
+
"bg-drawer-content-bg text-drawer-content-fg shadow-drawer-content",
|
|
18
|
+
"border-(length:--border-width-drawer) border-drawer-content-border",
|
|
19
|
+
"focus-visible:drawer-focus-ring",
|
|
20
|
+
"drawer-content-motion",
|
|
21
|
+
"data-[swipe-direction=up]:drawer-content-top data-[swipe-direction=up]:w-full data-[swipe-direction=up]:border-t-0",
|
|
22
|
+
"data-[swipe-direction=down]:drawer-content-bottom data-[swipe-direction=down]:w-full data-[swipe-direction=down]:border-b-0",
|
|
23
|
+
"data-[swipe-direction=left]:drawer-content-left data-[swipe-direction=left]:h-full data-[swipe-direction=left]:border-l-0",
|
|
24
|
+
"data-[swipe-direction=right]:drawer-content-right data-[swipe-direction=right]:h-full data-[swipe-direction=right]:border-r-0"
|
|
25
|
+
],
|
|
26
|
+
header: [
|
|
27
|
+
"flex shrink-0 flex-col gap-drawer-header p-drawer-header",
|
|
28
|
+
"border-b-(length:--border-width-drawer) border-drawer-content-border"
|
|
29
|
+
],
|
|
30
|
+
body: "flex min-h-0 flex-1 flex-col overflow-y-auto p-drawer-body",
|
|
31
|
+
footer: [
|
|
32
|
+
"flex shrink-0 items-center justify-end gap-drawer-footer p-drawer-footer",
|
|
33
|
+
"border-t-(length:--border-width-drawer) border-drawer-content-border"
|
|
34
|
+
],
|
|
35
|
+
title: "drawer-title-typography font-drawer-title text-drawer-title-fg",
|
|
36
|
+
description: "drawer-description-typography text-drawer-description-fg",
|
|
37
|
+
trigger: "",
|
|
38
|
+
closeTrigger: "",
|
|
39
|
+
grabber: [
|
|
40
|
+
"group absolute flex items-center justify-center p-drawer-grabber",
|
|
41
|
+
"data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:bottom-0",
|
|
42
|
+
"data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:top-0",
|
|
43
|
+
"data-[swipe-direction=start]:inset-y-0 data-[swipe-direction=start]:end-0",
|
|
44
|
+
"data-[swipe-direction=end]:inset-y-0 data-[swipe-direction=end]:start-0"
|
|
45
|
+
],
|
|
46
|
+
grabberIndicator: [
|
|
47
|
+
"rounded-drawer-grabber bg-drawer-grabber-bg",
|
|
48
|
+
"group-data-[swipe-direction=up]:h-drawer-grabber-thickness group-data-[swipe-direction=up]:w-drawer-grabber-length",
|
|
49
|
+
"group-data-[swipe-direction=down]:h-drawer-grabber-thickness group-data-[swipe-direction=down]:w-drawer-grabber-length",
|
|
50
|
+
"group-data-[swipe-direction=start]:h-drawer-grabber-length group-data-[swipe-direction=start]:w-drawer-grabber-thickness",
|
|
51
|
+
"group-data-[swipe-direction=end]:h-drawer-grabber-length group-data-[swipe-direction=end]:w-drawer-grabber-thickness"
|
|
52
|
+
],
|
|
53
|
+
swipeArea: [
|
|
54
|
+
"drawer-swipe-area-layer fixed",
|
|
55
|
+
"data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:bottom-0 data-[swipe-direction=up]:h-drawer-swipe-area",
|
|
56
|
+
"data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:top-0 data-[swipe-direction=down]:h-drawer-swipe-area",
|
|
57
|
+
"data-[swipe-direction=left]:inset-y-0 data-[swipe-direction=left]:right-0 data-[swipe-direction=left]:w-drawer-swipe-area",
|
|
58
|
+
"data-[swipe-direction=right]:inset-y-0 data-[swipe-direction=right]:left-0 data-[swipe-direction=right]:w-drawer-swipe-area"
|
|
59
|
+
],
|
|
60
|
+
indent: "drawer-indent",
|
|
61
|
+
indentBackground: "drawer-indent-background"
|
|
62
|
+
},
|
|
63
|
+
variants: {
|
|
64
|
+
size: {
|
|
65
|
+
xs: {
|
|
66
|
+
content: [
|
|
67
|
+
"data-[swipe-direction=down]:h-drawer-xs data-[swipe-direction=up]:h-drawer-xs",
|
|
68
|
+
"data-[swipe-direction=left]:w-drawer-xs data-[swipe-direction=right]:w-drawer-xs"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
sm: {
|
|
72
|
+
content: [
|
|
73
|
+
"data-[swipe-direction=down]:h-drawer-sm data-[swipe-direction=up]:h-drawer-sm",
|
|
74
|
+
"data-[swipe-direction=left]:w-drawer-sm data-[swipe-direction=right]:w-drawer-sm"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
md: {
|
|
78
|
+
content: [
|
|
79
|
+
"data-[swipe-direction=down]:h-drawer-md data-[swipe-direction=up]:h-drawer-md",
|
|
80
|
+
"data-[swipe-direction=left]:w-drawer-md data-[swipe-direction=right]:w-drawer-md"
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
lg: {
|
|
84
|
+
content: [
|
|
85
|
+
"data-[swipe-direction=down]:h-drawer-lg data-[swipe-direction=up]:h-drawer-lg",
|
|
86
|
+
"data-[swipe-direction=left]:w-drawer-lg data-[swipe-direction=right]:w-drawer-lg"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
xl: {
|
|
90
|
+
content: [
|
|
91
|
+
"data-[swipe-direction=down]:h-drawer-xl data-[swipe-direction=up]:h-drawer-xl",
|
|
92
|
+
"data-[swipe-direction=left]:w-drawer-xl data-[swipe-direction=right]:w-drawer-xl"
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
full: {
|
|
96
|
+
content: [
|
|
97
|
+
"data-[swipe-direction=down]:h-full data-[swipe-direction=up]:h-full",
|
|
98
|
+
"data-[swipe-direction=left]:w-full data-[swipe-direction=right]:w-full"
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
defaultVariants: {
|
|
104
|
+
size: "md"
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
export { drawerVariants };
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useId, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { useDrawer } from "../../molecules/drawer.js";
|
|
5
|
+
const SidebarContext = /*#__PURE__*/ createContext(null);
|
|
6
|
+
const SidebarPanelContext = /*#__PURE__*/ createContext(null);
|
|
7
|
+
const SIDES = [
|
|
8
|
+
"start",
|
|
9
|
+
"end"
|
|
10
|
+
];
|
|
11
|
+
function createSidebarFocusRegistry() {
|
|
12
|
+
const origins = {
|
|
13
|
+
end: null,
|
|
14
|
+
start: null
|
|
15
|
+
};
|
|
16
|
+
const revisions = {
|
|
17
|
+
end: 0,
|
|
18
|
+
start: 0
|
|
19
|
+
};
|
|
20
|
+
const clear = (side, revision)=>{
|
|
21
|
+
const origin = origins[side];
|
|
22
|
+
if (origin && (void 0 === revision || origin.revision === revision)) origins[side] = null;
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
blur: ({ mode, node, relatedTarget, side })=>{
|
|
26
|
+
if (relatedTarget && node.contains(relatedTarget)) return;
|
|
27
|
+
const document = node.ownerDocument;
|
|
28
|
+
const clearBlurredOrigin = ()=>{
|
|
29
|
+
const origin = origins[side];
|
|
30
|
+
if (!origin || origin.mode !== mode || origin.node !== node) return;
|
|
31
|
+
if (node.contains(document.activeElement)) return;
|
|
32
|
+
if (node.isConnected && node.getClientRects().length > 0) return void clear(side, origin.revision);
|
|
33
|
+
const expireLease = ()=>{
|
|
34
|
+
const leasedOrigin = origins[side];
|
|
35
|
+
if (leasedOrigin?.revision === origin.revision && leasedOrigin.mode === mode && (!node.isConnected || 0 === node.getClientRects().length)) origins[side] = null;
|
|
36
|
+
};
|
|
37
|
+
const view = document.defaultView;
|
|
38
|
+
if (view) view.requestAnimationFrame(expireLease);
|
|
39
|
+
else globalThis.queueMicrotask(expireLease);
|
|
40
|
+
};
|
|
41
|
+
if (relatedTarget) return void clearBlurredOrigin();
|
|
42
|
+
const view = document.defaultView;
|
|
43
|
+
if (view) view.queueMicrotask(clearBlurredOrigin);
|
|
44
|
+
else globalThis.queueMicrotask(clearBlurredOrigin);
|
|
45
|
+
},
|
|
46
|
+
capture: ({ mode, node, side, triggerValue })=>{
|
|
47
|
+
revisions[side] += 1;
|
|
48
|
+
origins[side] = {
|
|
49
|
+
document: node.ownerDocument,
|
|
50
|
+
mode,
|
|
51
|
+
node,
|
|
52
|
+
revision: revisions[side],
|
|
53
|
+
side,
|
|
54
|
+
triggerValue
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
claim: (side, fromMode)=>{
|
|
58
|
+
const origin = origins[side];
|
|
59
|
+
if (origin?.mode !== fromMode) return null;
|
|
60
|
+
origins[side] = null;
|
|
61
|
+
return origin;
|
|
62
|
+
},
|
|
63
|
+
clear,
|
|
64
|
+
getRevision: (side)=>revisions[side],
|
|
65
|
+
peek: (side)=>origins[side]
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function getDesktopServerSnapshot() {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
function createSidebarBreakpointStore() {
|
|
72
|
+
let node = null;
|
|
73
|
+
return {
|
|
74
|
+
getSnapshot: ()=>node ? "none" !== getComputedStyle(node).display : true,
|
|
75
|
+
ref: (nextNode)=>{
|
|
76
|
+
node = nextNode;
|
|
77
|
+
},
|
|
78
|
+
subscribe: (listener)=>{
|
|
79
|
+
const target = node?.ownerDocument.defaultView;
|
|
80
|
+
let subscribed = true;
|
|
81
|
+
target?.addEventListener("resize", listener);
|
|
82
|
+
target?.queueMicrotask(()=>{
|
|
83
|
+
if (subscribed) listener();
|
|
84
|
+
});
|
|
85
|
+
return ()=>{
|
|
86
|
+
subscribed = false;
|
|
87
|
+
target?.removeEventListener("resize", listener);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function useSidebarDesktopBreakpoint() {
|
|
93
|
+
const [store] = useState(createSidebarBreakpointStore);
|
|
94
|
+
const isDesktop = useSyncExternalStore(store.subscribe, store.getSnapshot, getDesktopServerSnapshot);
|
|
95
|
+
return {
|
|
96
|
+
breakpointRef: store.ref,
|
|
97
|
+
isDesktop
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function normalizeExpanded(sides) {
|
|
101
|
+
return SIDES.filter((side)=>sides.includes(side));
|
|
102
|
+
}
|
|
103
|
+
function normalizeCollapsible(policy) {
|
|
104
|
+
return {
|
|
105
|
+
start: policy?.start ?? "icon",
|
|
106
|
+
end: policy?.end ?? "icon"
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function useSidebarState({ collapsible: collapsiblePolicy, defaultExpanded = SIDES, defaultMobileOpen = null, dir, expanded: controlledExpanded, id, mobileOpen: controlledMobileOpen, onExpandedChange, onMobileOpenChange } = {}) {
|
|
110
|
+
const generatedId = useId();
|
|
111
|
+
const rootId = id ?? generatedId;
|
|
112
|
+
const resolvedDir = dir ?? "ltr";
|
|
113
|
+
const collapsible = normalizeCollapsible(collapsiblePolicy);
|
|
114
|
+
const [focus] = useState(createSidebarFocusRegistry);
|
|
115
|
+
const { breakpointRef, isDesktop } = useSidebarDesktopBreakpoint();
|
|
116
|
+
const wasDesktop = useRef(isDesktop);
|
|
117
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = useState(()=>normalizeExpanded(defaultExpanded));
|
|
118
|
+
const [uncontrolledMobileOpen, setUncontrolledMobileOpen] = useState(defaultMobileOpen);
|
|
119
|
+
const expanded = normalizeExpanded(controlledExpanded ?? uncontrolledExpanded);
|
|
120
|
+
const effectiveExpanded = normalizeExpanded([
|
|
121
|
+
...expanded,
|
|
122
|
+
...SIDES.filter((side)=>"none" === collapsible[side])
|
|
123
|
+
]);
|
|
124
|
+
const mobileOpen = void 0 === controlledMobileOpen ? uncontrolledMobileOpen : controlledMobileOpen;
|
|
125
|
+
const changeMobileOpen = (open)=>{
|
|
126
|
+
if (void 0 === controlledMobileOpen) setUncontrolledMobileOpen(open);
|
|
127
|
+
if (open !== mobileOpen) onMobileOpenChange?.({
|
|
128
|
+
open
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
const setExpanded = (side, nextExpanded)=>{
|
|
132
|
+
if ("none" === collapsible[side]) return;
|
|
133
|
+
const next = normalizeExpanded(nextExpanded ? [
|
|
134
|
+
...expanded,
|
|
135
|
+
side
|
|
136
|
+
] : expanded.filter((candidate)=>candidate !== side));
|
|
137
|
+
if (void 0 === controlledExpanded) setUncontrolledExpanded(next);
|
|
138
|
+
if (next.length !== expanded.length) onExpandedChange?.({
|
|
139
|
+
expanded: [
|
|
140
|
+
...next
|
|
141
|
+
]
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
useLayoutEffect(()=>{
|
|
145
|
+
if (isDesktop && !wasDesktop.current && null !== mobileOpen) {
|
|
146
|
+
if (void 0 === controlledMobileOpen) setUncontrolledMobileOpen(null);
|
|
147
|
+
onMobileOpenChange?.({
|
|
148
|
+
open: null
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
wasDesktop.current = isDesktop;
|
|
152
|
+
}, [
|
|
153
|
+
controlledMobileOpen,
|
|
154
|
+
isDesktop,
|
|
155
|
+
mobileOpen,
|
|
156
|
+
onMobileOpenChange
|
|
157
|
+
]);
|
|
158
|
+
const createOpenChangeHandler = (side)=>({ open })=>{
|
|
159
|
+
if (open) changeMobileOpen(side);
|
|
160
|
+
else if (mobileOpen === side) changeMobileOpen(null);
|
|
161
|
+
};
|
|
162
|
+
const startDrawer = useDrawer({
|
|
163
|
+
dir: resolvedDir,
|
|
164
|
+
id: `${rootId}-start-drawer`,
|
|
165
|
+
onOpenChange: createOpenChangeHandler("start"),
|
|
166
|
+
open: !isDesktop && "start" === mobileOpen,
|
|
167
|
+
swipeDirection: "start"
|
|
168
|
+
});
|
|
169
|
+
const endDrawer = useDrawer({
|
|
170
|
+
dir: resolvedDir,
|
|
171
|
+
id: `${rootId}-end-drawer`,
|
|
172
|
+
onOpenChange: createOpenChangeHandler("end"),
|
|
173
|
+
open: !isDesktop && "end" === mobileOpen,
|
|
174
|
+
swipeDirection: "end"
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
breakpointRef,
|
|
178
|
+
closeMobile: ()=>changeMobileOpen(null),
|
|
179
|
+
dir: resolvedDir,
|
|
180
|
+
drawer: {
|
|
181
|
+
start: startDrawer,
|
|
182
|
+
end: endDrawer
|
|
183
|
+
},
|
|
184
|
+
expanded: effectiveExpanded,
|
|
185
|
+
focus,
|
|
186
|
+
getCollapsible: (side)=>collapsible[side],
|
|
187
|
+
getPanelId: (side)=>`${rootId}-${side}-panel`,
|
|
188
|
+
isDesktop,
|
|
189
|
+
isExpanded: (side)=>effectiveExpanded.includes(side),
|
|
190
|
+
isFixed: (side)=>"none" === collapsible[side],
|
|
191
|
+
mobileOpen,
|
|
192
|
+
openMobile: (side)=>changeMobileOpen(side),
|
|
193
|
+
rootId,
|
|
194
|
+
setExpanded,
|
|
195
|
+
toggle: (side)=>{
|
|
196
|
+
if (isDesktop) setExpanded(side, !expanded.includes(side));
|
|
197
|
+
else changeMobileOpen(mobileOpen === side ? null : side);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function SidebarProvider({ children, value }) {
|
|
202
|
+
return /*#__PURE__*/ jsx(SidebarContext.Provider, {
|
|
203
|
+
value: value,
|
|
204
|
+
children: children
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function SidebarPanelProvider({ children, value }) {
|
|
208
|
+
return /*#__PURE__*/ jsx(SidebarPanelContext.Provider, {
|
|
209
|
+
value: value,
|
|
210
|
+
children: children
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function useSidebarContext() {
|
|
214
|
+
const context = useContext(SidebarContext);
|
|
215
|
+
if (!context) throw new Error("Sidebar components must be used within Sidebar.Root");
|
|
216
|
+
return context;
|
|
217
|
+
}
|
|
218
|
+
function useSidebarPanelContext() {
|
|
219
|
+
const context = useContext(SidebarPanelContext);
|
|
220
|
+
if (!context) throw new Error("Sidebar panel parts must be used within Sidebar.Panel");
|
|
221
|
+
return context;
|
|
222
|
+
}
|
|
223
|
+
export { SidebarPanelProvider, SidebarProvider, useSidebarContext, useSidebarPanelContext, useSidebarState };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useLayoutEffect, useRef } from "react";
|
|
3
|
+
function getPanelFocusRegion(document, panelId, isDesktop) {
|
|
4
|
+
const panel = document.getElementById(panelId);
|
|
5
|
+
if (isDesktop || !panel) return panel;
|
|
6
|
+
return panel.closest('[data-scope="drawer"][data-part="content"]') ?? panel;
|
|
7
|
+
}
|
|
8
|
+
function getPanelFocusTarget({ document, panelId, rootId, side, triggerValue }) {
|
|
9
|
+
const root = document.getElementById(rootId);
|
|
10
|
+
const triggers = root ? Array.from(root.querySelectorAll("button[data-sidebar-trigger]")).filter((candidate)=>candidate.closest('[data-scope="sidebar"][data-part="root"]') === root && candidate.dataset.side === side && !candidate.disabled && candidate.getClientRects().length > 0) : [];
|
|
11
|
+
const exactTrigger = triggerValue ? triggers.find((candidate)=>candidate.dataset.sidebarTriggerValue === triggerValue) : void 0;
|
|
12
|
+
const target = exactTrigger ?? triggers[0];
|
|
13
|
+
if (target) return target;
|
|
14
|
+
const panel = document.getElementById(panelId);
|
|
15
|
+
return panel && !panel.inert && panel.getClientRects().length > 0 ? panel : null;
|
|
16
|
+
}
|
|
17
|
+
function hasMeaningfulFocus(document) {
|
|
18
|
+
const activeElement = document.activeElement;
|
|
19
|
+
return Boolean(activeElement && activeElement !== document.body && activeElement !== document.documentElement && activeElement.isConnected);
|
|
20
|
+
}
|
|
21
|
+
function queueDocumentMicrotask(document, callback) {
|
|
22
|
+
const view = document.defaultView;
|
|
23
|
+
if (view) return void view.queueMicrotask(callback);
|
|
24
|
+
globalThis.queueMicrotask(callback);
|
|
25
|
+
}
|
|
26
|
+
function captureActiveFocus({ activeElement, focus, focusRegion, mode, origin, side, triggerValue }) {
|
|
27
|
+
if (activeElement && focusRegion?.contains(activeElement)) {
|
|
28
|
+
focus.capture({
|
|
29
|
+
mode,
|
|
30
|
+
node: focusRegion,
|
|
31
|
+
side,
|
|
32
|
+
triggerValue
|
|
33
|
+
});
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
if (activeElement && origin.node.contains(activeElement)) {
|
|
37
|
+
focus.capture({
|
|
38
|
+
mode,
|
|
39
|
+
node: origin.node,
|
|
40
|
+
side,
|
|
41
|
+
triggerValue: origin.triggerValue
|
|
42
|
+
});
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function captureTransferredTarget({ document, focus, mode, origin, side, target, triggerValue }) {
|
|
48
|
+
if (!target || document.activeElement !== target) return;
|
|
49
|
+
const capturedOrigin = focus.peek(side);
|
|
50
|
+
if (capturedOrigin?.mode === mode && capturedOrigin.node === target) return;
|
|
51
|
+
focus.capture({
|
|
52
|
+
mode,
|
|
53
|
+
node: target,
|
|
54
|
+
side,
|
|
55
|
+
triggerValue: target.dataset.sidebarTriggerValue ?? origin.triggerValue ?? triggerValue
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function runQueuedFocusTransfer({ document, focus, isCurrent, isDesktop, mode, origin, panelId, rootId, side, triggerValue }) {
|
|
59
|
+
const stale = !isCurrent() || focus.getRevision(side) !== origin.revision || !document.hasFocus();
|
|
60
|
+
if (stale) return;
|
|
61
|
+
const focusRegion = getPanelFocusRegion(document, panelId, isDesktop);
|
|
62
|
+
const activeElement = document.activeElement;
|
|
63
|
+
if (activeElement && focusRegion?.contains(activeElement)) return;
|
|
64
|
+
if (hasMeaningfulFocus(document)) return;
|
|
65
|
+
const target = getPanelFocusTarget({
|
|
66
|
+
document,
|
|
67
|
+
panelId,
|
|
68
|
+
rootId,
|
|
69
|
+
side,
|
|
70
|
+
triggerValue
|
|
71
|
+
});
|
|
72
|
+
target?.focus({
|
|
73
|
+
preventScroll: true
|
|
74
|
+
});
|
|
75
|
+
captureTransferredTarget({
|
|
76
|
+
document,
|
|
77
|
+
focus,
|
|
78
|
+
mode,
|
|
79
|
+
origin,
|
|
80
|
+
side,
|
|
81
|
+
target,
|
|
82
|
+
triggerValue
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function cancelFocusTransfer(transition, transitionId) {
|
|
86
|
+
if (transition.current === transitionId) transition.current += 1;
|
|
87
|
+
}
|
|
88
|
+
function getPendingFocusOrigin(focus, side, fromMode) {
|
|
89
|
+
const origin = focus.peek(side);
|
|
90
|
+
return origin?.mode === fromMode ? origin : null;
|
|
91
|
+
}
|
|
92
|
+
function useSidebarPanelFocusTransfer({ focus, isDesktop, panelId, rootId, side, triggerValue }) {
|
|
93
|
+
const wasDesktop = useRef(isDesktop);
|
|
94
|
+
const transition = useRef(0);
|
|
95
|
+
const latestTriggerValue = useRef(triggerValue);
|
|
96
|
+
useLayoutEffect(()=>{
|
|
97
|
+
latestTriggerValue.current = triggerValue;
|
|
98
|
+
}, [
|
|
99
|
+
triggerValue
|
|
100
|
+
]);
|
|
101
|
+
useLayoutEffect(()=>{
|
|
102
|
+
if (wasDesktop.current === isDesktop) return;
|
|
103
|
+
wasDesktop.current = isDesktop;
|
|
104
|
+
const transitionId = transition.current + 1;
|
|
105
|
+
transition.current = transitionId;
|
|
106
|
+
const mode = isDesktop ? "desktop" : "mobile";
|
|
107
|
+
const fromMode = isDesktop ? "mobile" : "desktop";
|
|
108
|
+
const pendingOrigin = getPendingFocusOrigin(focus, side, fromMode);
|
|
109
|
+
if (!pendingOrigin) return;
|
|
110
|
+
const { document } = pendingOrigin;
|
|
111
|
+
const focusRegion = getPanelFocusRegion(document, panelId, isDesktop);
|
|
112
|
+
const activeElement = document.activeElement;
|
|
113
|
+
const nextTriggerValue = pendingOrigin.triggerValue ?? latestTriggerValue.current;
|
|
114
|
+
if (captureActiveFocus({
|
|
115
|
+
activeElement,
|
|
116
|
+
focus,
|
|
117
|
+
focusRegion,
|
|
118
|
+
mode,
|
|
119
|
+
origin: pendingOrigin,
|
|
120
|
+
side,
|
|
121
|
+
triggerValue: nextTriggerValue
|
|
122
|
+
})) return;
|
|
123
|
+
if (hasMeaningfulFocus(document)) return void focus.clear(side, pendingOrigin.revision);
|
|
124
|
+
const origin = focus.claim(side, fromMode);
|
|
125
|
+
if (!origin) return;
|
|
126
|
+
queueDocumentMicrotask(document, ()=>{
|
|
127
|
+
runQueuedFocusTransfer({
|
|
128
|
+
document,
|
|
129
|
+
focus,
|
|
130
|
+
isCurrent: ()=>transition.current === transitionId,
|
|
131
|
+
isDesktop,
|
|
132
|
+
mode,
|
|
133
|
+
origin,
|
|
134
|
+
panelId,
|
|
135
|
+
rootId,
|
|
136
|
+
side,
|
|
137
|
+
triggerValue: origin.triggerValue ?? latestTriggerValue.current
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
return ()=>cancelFocusTransfer(transition, transitionId);
|
|
141
|
+
}, [
|
|
142
|
+
focus,
|
|
143
|
+
isDesktop,
|
|
144
|
+
panelId,
|
|
145
|
+
rootId,
|
|
146
|
+
side
|
|
147
|
+
]);
|
|
148
|
+
const onFocusCapture = (event)=>{
|
|
149
|
+
focus.capture({
|
|
150
|
+
mode: isDesktop ? "desktop" : "mobile",
|
|
151
|
+
node: event.currentTarget,
|
|
152
|
+
side,
|
|
153
|
+
triggerValue: null
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
const onBlurCapture = (event)=>{
|
|
157
|
+
focus.blur({
|
|
158
|
+
mode: isDesktop ? "desktop" : "mobile",
|
|
159
|
+
node: event.currentTarget,
|
|
160
|
+
relatedTarget: event.relatedTarget,
|
|
161
|
+
side
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
onBlurCapture,
|
|
166
|
+
onFocusCapture
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
export { useSidebarPanelFocusTransfer };
|