@kopexa/sidebar 17.1.74 → 17.2.1

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.
@@ -0,0 +1,151 @@
1
+ "use client";
2
+
3
+ // src/v2/context.tsx
4
+ import { createContext } from "@kopexa/react-utils";
5
+ import { sidebarV2 } from "@kopexa/theme";
6
+ import { TooltipProvider } from "@kopexa/tooltip";
7
+ import { useIsMobile } from "@kopexa/use-is-mobile";
8
+ import {
9
+ useCallback,
10
+ useEffect,
11
+ useMemo,
12
+ useState
13
+ } from "react";
14
+ import { jsx } from "react/jsx-runtime";
15
+ var PIN_COOKIE = "kpx_sidebar_v2_pinned";
16
+ var PIN_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
17
+ var [Provider, useSidebarV2] = createContext({
18
+ name: "SidebarV2Context",
19
+ errorMessage: "useSidebarV2 must be used within <SidebarV2> (the provider component)."
20
+ });
21
+ var defaultRenderLink = (props) => {
22
+ const { href, className, children, ...rest } = props;
23
+ return /* @__PURE__ */ jsx("a", { href, className, ...rest, children });
24
+ };
25
+ function SidebarV2Provider({
26
+ children,
27
+ tone = "dark",
28
+ flyoutTrigger = "click",
29
+ activeHref,
30
+ renderLink = defaultRenderLink,
31
+ pinned: pinnedProp,
32
+ onPinnedChange,
33
+ defaultPinned = true
34
+ }) {
35
+ const isMobile = useIsMobile();
36
+ const [drawerOpen, setDrawerOpen] = useState(false);
37
+ const [flyoutValue, setFlyoutValue] = useState(null);
38
+ const [selectedRail, setSelectedRail] = useState(null);
39
+ const [openGroup, setOpenGroup] = useState(null);
40
+ const [pinnedUncontrolled, setPinnedUncontrolled] = useState(defaultPinned);
41
+ const pinned = pinnedProp != null ? pinnedProp : pinnedUncontrolled;
42
+ const [panelHost, setPanelHost] = useState(null);
43
+ const [overrideCount, setOverrideCount] = useState(0);
44
+ const registerPanelOverride = useCallback(() => {
45
+ setOverrideCount((c) => c + 1);
46
+ return () => setOverrideCount((c) => c - 1);
47
+ }, []);
48
+ const panelOverrideActive = overrideCount > 0;
49
+ const navPreviewActive = pinned ? selectedRail !== null : flyoutValue !== null;
50
+ const styles = useMemo(() => sidebarV2({ tone }), [tone]);
51
+ const setPinned = useCallback(
52
+ (value2) => {
53
+ onPinnedChange == null ? void 0 : onPinnedChange(value2);
54
+ if (pinnedProp === void 0) {
55
+ setPinnedUncontrolled(value2);
56
+ }
57
+ document.cookie = `${PIN_COOKIE}=${value2}; path=/; max-age=${PIN_COOKIE_MAX_AGE}`;
58
+ },
59
+ [onPinnedChange, pinnedProp]
60
+ );
61
+ const togglePin = useCallback(() => {
62
+ setPinned(!pinned);
63
+ setFlyoutValue(null);
64
+ }, [pinned, setPinned]);
65
+ const openFlyout = useCallback((value2) => {
66
+ setFlyoutValue((curr) => curr === value2 ? null : value2);
67
+ }, []);
68
+ const setFlyout = useCallback((value2) => {
69
+ setFlyoutValue(value2);
70
+ }, []);
71
+ const closeFlyout = useCallback(() => setFlyoutValue(null), []);
72
+ const resetPanelSelection = useCallback(() => {
73
+ setSelectedRail(null);
74
+ setFlyoutValue(null);
75
+ }, []);
76
+ const toggleGroup = useCallback((key) => {
77
+ setOpenGroup((curr) => curr === key ? null : key);
78
+ }, []);
79
+ const isActive = useCallback(
80
+ (href) => activeHref === href || href !== "/" && activeHref.startsWith(`${href}/`),
81
+ [activeHref]
82
+ );
83
+ const value = useMemo(
84
+ () => ({
85
+ tone,
86
+ styles,
87
+ pinned,
88
+ togglePin,
89
+ setPinned,
90
+ selectedRail,
91
+ setSelectedRail,
92
+ flyoutTrigger,
93
+ flyoutValue,
94
+ openFlyout,
95
+ setFlyout,
96
+ closeFlyout,
97
+ resetPanelSelection,
98
+ openGroup,
99
+ toggleGroup,
100
+ setOpenGroup,
101
+ activeHref,
102
+ isActive,
103
+ renderLink,
104
+ isMobile,
105
+ drawerOpen,
106
+ setDrawerOpen,
107
+ panelHost,
108
+ setPanelHost,
109
+ panelOverrideActive,
110
+ registerPanelOverride,
111
+ navPreviewActive
112
+ }),
113
+ [
114
+ tone,
115
+ styles,
116
+ pinned,
117
+ togglePin,
118
+ setPinned,
119
+ selectedRail,
120
+ flyoutTrigger,
121
+ flyoutValue,
122
+ openFlyout,
123
+ setFlyout,
124
+ closeFlyout,
125
+ resetPanelSelection,
126
+ openGroup,
127
+ toggleGroup,
128
+ activeHref,
129
+ isActive,
130
+ renderLink,
131
+ isMobile,
132
+ drawerOpen,
133
+ panelHost,
134
+ panelOverrideActive,
135
+ registerPanelOverride,
136
+ navPreviewActive
137
+ ]
138
+ );
139
+ useEffect(() => {
140
+ setDrawerOpen(false);
141
+ setFlyoutValue(null);
142
+ setSelectedRail(null);
143
+ setOpenGroup(null);
144
+ }, [activeHref]);
145
+ return /* @__PURE__ */ jsx(Provider, { value, children: /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 0, children }) });
146
+ }
147
+
148
+ export {
149
+ useSidebarV2,
150
+ SidebarV2Provider
151
+ };
@@ -0,0 +1,272 @@
1
+ "use client";
2
+ import {
3
+ SidebarV2Panel,
4
+ SidebarV2PanelItems,
5
+ SidebarV2Rail,
6
+ SidebarV2RailItem,
7
+ SidebarV2RailLink
8
+ } from "./chunk-YW3JMPRU.mjs";
9
+ import {
10
+ panelItemHasChildren,
11
+ panelItemIsSection
12
+ } from "./chunk-SDMGFB6V.mjs";
13
+ import {
14
+ useSidebarV2
15
+ } from "./chunk-AIRHHM7Z.mjs";
16
+
17
+ // src/v2/from-config.tsx
18
+ import { Drawer } from "@kopexa/drawer";
19
+ import { cn } from "@kopexa/shared-utils";
20
+ import { AnimatePresence, motion } from "motion/react";
21
+ import {
22
+ useCallback,
23
+ useEffect,
24
+ useMemo,
25
+ useRef,
26
+ useState
27
+ } from "react";
28
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
29
+ var RAIL_WIDTH = "4rem";
30
+ var PANEL_WIDTH = "15rem";
31
+ var railVars = {
32
+ "--kpx-rail-width": RAIL_WIDTH,
33
+ "--kpx-panel-width": PANEL_WIDTH
34
+ };
35
+ function entryValue(entry) {
36
+ var _a;
37
+ if (entry.type === "divider") return "divider";
38
+ return entry.type === "panel" ? (_a = entry.value) != null ? _a : entry.label : entry.label;
39
+ }
40
+ function SidebarV2FromConfig({
41
+ items,
42
+ header
43
+ }) {
44
+ var _a, _b, _c;
45
+ const {
46
+ pinned,
47
+ flyoutTrigger,
48
+ flyoutValue,
49
+ openFlyout,
50
+ setFlyout,
51
+ closeFlyout,
52
+ selectedRail,
53
+ setSelectedRail,
54
+ isActive,
55
+ isMobile,
56
+ drawerOpen,
57
+ setDrawerOpen,
58
+ setPanelHost,
59
+ panelOverrideActive,
60
+ navPreviewActive,
61
+ styles
62
+ } = useSidebarV2();
63
+ const hoverMode = flyoutTrigger === "hover" && !pinned && !isMobile;
64
+ const closeTimer = useRef(null);
65
+ const cancelClose = useCallback(() => {
66
+ if (closeTimer.current) clearTimeout(closeTimer.current);
67
+ closeTimer.current = null;
68
+ }, []);
69
+ const scheduleClose = useCallback(() => {
70
+ cancelClose();
71
+ closeTimer.current = setTimeout(() => closeFlyout(), 160);
72
+ }, [cancelClose, closeFlyout]);
73
+ useEffect(() => cancelClose, [cancelClose]);
74
+ useEffect(() => {
75
+ if (pinned || isMobile || !flyoutValue) return;
76
+ const onPointerDown = (event) => {
77
+ const t = event.target;
78
+ if (!t) return;
79
+ if (t.closest('[data-slot="sidebar-v2-rail"]')) return;
80
+ if (t.closest('[data-floating="true"]')) return;
81
+ closeFlyout();
82
+ };
83
+ const onKeyDown = (event) => {
84
+ if (event.key === "Escape") closeFlyout();
85
+ };
86
+ document.addEventListener("pointerdown", onPointerDown);
87
+ document.addEventListener("keydown", onKeyDown);
88
+ return () => {
89
+ document.removeEventListener("pointerdown", onPointerDown);
90
+ document.removeEventListener("keydown", onKeyDown);
91
+ };
92
+ }, [pinned, isMobile, flyoutValue, closeFlyout]);
93
+ const panels = useMemo(
94
+ () => items.filter(
95
+ (e) => e.type === "panel"
96
+ ),
97
+ [items]
98
+ );
99
+ const activeRailValue = useMemo(() => {
100
+ const match = panels.find(
101
+ (p) => p.items.some((item) => {
102
+ if (panelItemIsSection(item)) return false;
103
+ return panelItemHasChildren(item) ? item.children.some((c) => isActive(c.href)) : isActive(item.href);
104
+ })
105
+ );
106
+ return match ? entryValue(match) : null;
107
+ }, [panels, isActive]);
108
+ const shownValue = pinned ? selectedRail != null ? selectedRail : activeRailValue : flyoutValue;
109
+ const shownPanel = (_a = panels.find((p) => entryValue(p) === shownValue)) != null ? _a : null;
110
+ const topEntries = items.filter((e) => e.slot !== "bottom");
111
+ const bottomEntries = items.filter((e) => e.slot === "bottom");
112
+ function renderRailEntry(entry, index) {
113
+ if (entry.type === "divider") {
114
+ return /* @__PURE__ */ jsx(
115
+ "div",
116
+ {
117
+ "aria-hidden": true,
118
+ className: styles.railDivider()
119
+ },
120
+ `rail-divider-${index}`
121
+ );
122
+ }
123
+ const value = entryValue(entry);
124
+ if (entry.type === "link") {
125
+ return /* @__PURE__ */ jsx(
126
+ SidebarV2RailLink,
127
+ {
128
+ icon: entry.icon,
129
+ label: entry.label,
130
+ href: entry.href,
131
+ badge: entry.badge
132
+ },
133
+ value
134
+ );
135
+ }
136
+ if (entry.type === "action") {
137
+ return /* @__PURE__ */ jsx(
138
+ SidebarV2RailItem,
139
+ {
140
+ icon: entry.icon,
141
+ label: entry.label,
142
+ active: false,
143
+ onClick: entry.onSelect
144
+ },
145
+ value
146
+ );
147
+ }
148
+ const active = flyoutValue ? value === flyoutValue : value === (selectedRail != null ? selectedRail : activeRailValue);
149
+ return /* @__PURE__ */ jsx(
150
+ SidebarV2RailItem,
151
+ {
152
+ icon: entry.icon,
153
+ label: entry.label,
154
+ active,
155
+ hasPanel: true,
156
+ onClick: () => {
157
+ if (pinned) setSelectedRail(value);
158
+ else openFlyout(value);
159
+ },
160
+ onMouseEnter: hoverMode ? () => {
161
+ cancelClose();
162
+ setFlyout(value);
163
+ } : void 0,
164
+ onMouseLeave: hoverMode ? scheduleClose : void 0
165
+ },
166
+ value
167
+ );
168
+ }
169
+ const railContent = /* @__PURE__ */ jsxs(Fragment, { children: [
170
+ /* @__PURE__ */ jsxs("div", { className: styles.railScroll(), children: [
171
+ header && /* @__PURE__ */ jsxs(Fragment, { children: [
172
+ header,
173
+ /* @__PURE__ */ jsx("div", { className: styles.railHeaderDivider() })
174
+ ] }),
175
+ topEntries.map(renderRailEntry)
176
+ ] }),
177
+ bottomEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: styles.railBottom(), children: bottomEntries.map(renderRailEntry) })
178
+ ] });
179
+ const navData = pinned && shownPanel && (navPreviewActive || !panelOverrideActive) ? shownPanel : null;
180
+ const [bufferedPanel, setBufferedPanel] = useState(navData);
181
+ useEffect(() => {
182
+ if (navData) {
183
+ setBufferedPanel(navData);
184
+ return;
185
+ }
186
+ const t = setTimeout(() => setBufferedPanel(null), 220);
187
+ return () => clearTimeout(t);
188
+ }, [navData]);
189
+ const navToRender = navData != null ? navData : bufferedPanel;
190
+ const renderNav = (!panelOverrideActive || navPreviewActive) && navToRender;
191
+ const panelContent = navToRender && renderNav ? /* @__PURE__ */ jsx(
192
+ SidebarV2Panel,
193
+ {
194
+ title: (_b = navToRender.title) != null ? _b : navToRender.label,
195
+ subtitle: navToRender.subtitle,
196
+ children: /* @__PURE__ */ jsx(SidebarV2PanelItems, { items: navToRender.items })
197
+ },
198
+ entryValue(navToRender)
199
+ ) : null;
200
+ const docked = Boolean(navData) || panelOverrideActive;
201
+ const showFlyout = !pinned && Boolean(shownPanel);
202
+ if (isMobile) {
203
+ return /* @__PURE__ */ jsx(
204
+ Drawer.Root,
205
+ {
206
+ open: drawerOpen,
207
+ onOpenChange: setDrawerOpen,
208
+ placement: "left",
209
+ children: /* @__PURE__ */ jsxs(Drawer.Content, { className: styles.mobileDrawer(), children: [
210
+ /* @__PURE__ */ jsxs(Drawer.Header, { className: "sr-only", children: [
211
+ /* @__PURE__ */ jsx(Drawer.Title, { children: "Navigation" }),
212
+ /* @__PURE__ */ jsx(Drawer.Description, { children: "Hauptnavigation" })
213
+ ] }),
214
+ /* @__PURE__ */ jsxs("div", { className: "flex h-full", style: railVars, children: [
215
+ /* @__PURE__ */ jsx(SidebarV2Rail, { children: railContent }),
216
+ /* @__PURE__ */ jsx(
217
+ "div",
218
+ {
219
+ ref: setPanelHost,
220
+ "data-slot": "sidebar-v2-panel-zone",
221
+ className: "flex min-h-0",
222
+ children: panelContent
223
+ }
224
+ )
225
+ ] })
226
+ ] })
227
+ }
228
+ );
229
+ }
230
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
231
+ /* @__PURE__ */ jsx(SidebarV2Rail, { style: { gridArea: "rail" }, children: railContent }),
232
+ /* @__PURE__ */ jsxs(
233
+ "div",
234
+ {
235
+ ref: setPanelHost,
236
+ "data-slot": "sidebar-v2-panel-zone",
237
+ className: cn(styles.panelZone(), pinned && "overflow-hidden"),
238
+ style: { gridArea: "panel", width: docked ? PANEL_WIDTH : "0px" },
239
+ children: [
240
+ panelContent,
241
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showFlyout && shownPanel && /* @__PURE__ */ jsx(
242
+ motion.div,
243
+ {
244
+ "data-floating": "true",
245
+ className: styles.flyout(),
246
+ initial: { x: -14, opacity: 0 },
247
+ animate: { x: 0, opacity: 1 },
248
+ exit: { x: -14, opacity: 0 },
249
+ transition: { duration: 0.16, ease: "easeOut" },
250
+ onMouseEnter: hoverMode ? cancelClose : void 0,
251
+ onMouseLeave: hoverMode ? scheduleClose : void 0,
252
+ children: /* @__PURE__ */ jsx(
253
+ SidebarV2Panel,
254
+ {
255
+ floating: true,
256
+ title: (_c = shownPanel.title) != null ? _c : shownPanel.label,
257
+ subtitle: shownPanel.subtitle,
258
+ children: /* @__PURE__ */ jsx(SidebarV2PanelItems, { items: shownPanel.items })
259
+ }
260
+ )
261
+ },
262
+ "sidebar-v2-flyout"
263
+ ) })
264
+ ]
265
+ }
266
+ )
267
+ ] });
268
+ }
269
+
270
+ export {
271
+ SidebarV2FromConfig
272
+ };
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import {
3
+ SidebarV2FromConfig
4
+ } from "./chunk-KLYPP6QE.mjs";
5
+ import {
6
+ SidebarV2Inset,
7
+ SidebarV2Panel,
8
+ SidebarV2PanelGroup,
9
+ SidebarV2PanelItems,
10
+ SidebarV2PanelLabel,
11
+ SidebarV2PanelLeaf,
12
+ SidebarV2Rail,
13
+ SidebarV2RailItem,
14
+ SidebarV2RailLink,
15
+ SidebarV2RailSpacer,
16
+ SidebarV2Trigger,
17
+ SidebarV2Workspace
18
+ } from "./chunk-YW3JMPRU.mjs";
19
+ import {
20
+ SidebarV2Provider
21
+ } from "./chunk-AIRHHM7Z.mjs";
22
+
23
+ // src/v2/index.tsx
24
+ var SidebarV2 = SidebarV2Provider;
25
+ SidebarV2.FromConfig = SidebarV2FromConfig;
26
+ SidebarV2.Inset = SidebarV2Inset;
27
+ SidebarV2.Trigger = SidebarV2Trigger;
28
+ SidebarV2.Rail = SidebarV2Rail;
29
+ SidebarV2.RailItem = SidebarV2RailItem;
30
+ SidebarV2.RailLink = SidebarV2RailLink;
31
+ SidebarV2.RailSpacer = SidebarV2RailSpacer;
32
+ SidebarV2.Workspace = SidebarV2Workspace;
33
+ SidebarV2.Panel = SidebarV2Panel;
34
+ SidebarV2.PanelItems = SidebarV2PanelItems;
35
+ SidebarV2.PanelLeaf = SidebarV2PanelLeaf;
36
+ SidebarV2.PanelGroup = SidebarV2PanelGroup;
37
+ SidebarV2.PanelLabel = SidebarV2PanelLabel;
38
+
39
+ export {
40
+ SidebarV2
41
+ };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+
3
+ // src/v2/types.ts
4
+ function panelItemHasChildren(item) {
5
+ return "children" in item && Array.isArray(item.children);
6
+ }
7
+ function panelItemIsSection(item) {
8
+ return "section" in item;
9
+ }
10
+
11
+ export {
12
+ panelItemHasChildren,
13
+ panelItemIsSection
14
+ };
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import {
3
+ useSidebarV2
4
+ } from "./chunk-AIRHHM7Z.mjs";
5
+
6
+ // src/v2/app-shell.tsx
7
+ import {
8
+ useEffect
9
+ } from "react";
10
+ import { createPortal } from "react-dom";
11
+ import { jsx } from "react/jsx-runtime";
12
+ var RAIL_WIDTH = "4rem";
13
+ var PANEL_WIDTH = "15rem";
14
+ function AppShellRoot({
15
+ className,
16
+ style,
17
+ children,
18
+ ...props
19
+ }) {
20
+ const { tone, styles } = useSidebarV2();
21
+ return /* @__PURE__ */ jsx(
22
+ "div",
23
+ {
24
+ "data-slot": "app-shell",
25
+ "data-tone": tone,
26
+ className: styles.shell({ className }),
27
+ style: {
28
+ "--kpx-rail-width": RAIL_WIDTH,
29
+ "--kpx-panel-width": PANEL_WIDTH,
30
+ gridTemplateAreas: '"header header header header" "rail panel main aside"',
31
+ gridTemplateRows: "auto 1fr",
32
+ gridTemplateColumns: "auto auto 1fr auto",
33
+ ...style
34
+ },
35
+ ...props,
36
+ children
37
+ }
38
+ );
39
+ }
40
+ function AppShellHeader({
41
+ className,
42
+ style,
43
+ ...props
44
+ }) {
45
+ const { styles } = useSidebarV2();
46
+ return /* @__PURE__ */ jsx(
47
+ "header",
48
+ {
49
+ "data-slot": "app-shell-header",
50
+ className: styles.header({ className }),
51
+ style: { gridArea: "header", ...style },
52
+ ...props
53
+ }
54
+ );
55
+ }
56
+ function AppShellMain({ className, style, ...props }) {
57
+ const { styles } = useSidebarV2();
58
+ return /* @__PURE__ */ jsx(
59
+ "main",
60
+ {
61
+ "data-slot": "app-shell-main",
62
+ className: styles.main({ className }),
63
+ style: { gridArea: "main", ...style },
64
+ ...props
65
+ }
66
+ );
67
+ }
68
+ function AppShellAside({
69
+ className,
70
+ style,
71
+ ...props
72
+ }) {
73
+ const { styles } = useSidebarV2();
74
+ return /* @__PURE__ */ jsx(
75
+ "aside",
76
+ {
77
+ "data-slot": "app-shell-aside",
78
+ className: styles.aside({ className }),
79
+ style: { gridArea: "aside", ...style },
80
+ ...props
81
+ }
82
+ );
83
+ }
84
+ function AppShellPanelContent({ children }) {
85
+ const { panelHost, registerPanelOverride, navPreviewActive } = useSidebarV2();
86
+ useEffect(() => registerPanelOverride(), [registerPanelOverride]);
87
+ if (!panelHost || navPreviewActive) return null;
88
+ return createPortal(children, panelHost);
89
+ }
90
+ var AppShell = AppShellRoot;
91
+ AppShell.Header = AppShellHeader;
92
+ AppShell.Main = AppShellMain;
93
+ AppShell.Aside = AppShellAside;
94
+ AppShell.PanelContent = AppShellPanelContent;
95
+
96
+ export {
97
+ AppShellRoot,
98
+ AppShellHeader,
99
+ AppShellMain,
100
+ AppShellAside,
101
+ AppShellPanelContent,
102
+ AppShell
103
+ };