@kopexa/sidebar 17.2.0 → 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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  // src/v2/context.tsx
4
4
  import { createContext } from "@kopexa/react-utils";
5
+ import { sidebarV2 } from "@kopexa/theme";
5
6
  import { TooltipProvider } from "@kopexa/tooltip";
6
7
  import { useIsMobile } from "@kopexa/use-is-mobile";
7
8
  import {
@@ -46,6 +47,7 @@ function SidebarV2Provider({
46
47
  }, []);
47
48
  const panelOverrideActive = overrideCount > 0;
48
49
  const navPreviewActive = pinned ? selectedRail !== null : flyoutValue !== null;
50
+ const styles = useMemo(() => sidebarV2({ tone }), [tone]);
49
51
  const setPinned = useCallback(
50
52
  (value2) => {
51
53
  onPinnedChange == null ? void 0 : onPinnedChange(value2);
@@ -81,6 +83,7 @@ function SidebarV2Provider({
81
83
  const value = useMemo(
82
84
  () => ({
83
85
  tone,
86
+ styles,
84
87
  pinned,
85
88
  togglePin,
86
89
  setPinned,
@@ -109,6 +112,7 @@ function SidebarV2Provider({
109
112
  }),
110
113
  [
111
114
  tone,
115
+ styles,
112
116
  pinned,
113
117
  togglePin,
114
118
  setPinned,
@@ -5,14 +5,14 @@ import {
5
5
  SidebarV2Rail,
6
6
  SidebarV2RailItem,
7
7
  SidebarV2RailLink
8
- } from "./chunk-EIXUCY5M.mjs";
8
+ } from "./chunk-YW3JMPRU.mjs";
9
9
  import {
10
10
  panelItemHasChildren,
11
11
  panelItemIsSection
12
12
  } from "./chunk-SDMGFB6V.mjs";
13
13
  import {
14
14
  useSidebarV2
15
- } from "./chunk-3L2F566G.mjs";
15
+ } from "./chunk-AIRHHM7Z.mjs";
16
16
 
17
17
  // src/v2/from-config.tsx
18
18
  import { Drawer } from "@kopexa/drawer";
@@ -57,7 +57,8 @@ function SidebarV2FromConfig({
57
57
  setDrawerOpen,
58
58
  setPanelHost,
59
59
  panelOverrideActive,
60
- navPreviewActive
60
+ navPreviewActive,
61
+ styles
61
62
  } = useSidebarV2();
62
63
  const hoverMode = flyoutTrigger === "hover" && !pinned && !isMobile;
63
64
  const closeTimer = useRef(null);
@@ -114,7 +115,7 @@ function SidebarV2FromConfig({
114
115
  "div",
115
116
  {
116
117
  "aria-hidden": true,
117
- className: "mx-3 my-1.5 h-px shrink-0 bg-sidebar-border/70"
118
+ className: styles.railDivider()
118
119
  },
119
120
  `rail-divider-${index}`
120
121
  );
@@ -166,14 +167,14 @@ function SidebarV2FromConfig({
166
167
  );
167
168
  }
168
169
  const railContent = /* @__PURE__ */ jsxs(Fragment, { children: [
169
- /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: [
170
+ /* @__PURE__ */ jsxs("div", { className: styles.railScroll(), children: [
170
171
  header && /* @__PURE__ */ jsxs(Fragment, { children: [
171
172
  header,
172
- /* @__PURE__ */ jsx("div", { className: "mx-3 my-1 h-px shrink-0 bg-sidebar-border/60" })
173
+ /* @__PURE__ */ jsx("div", { className: styles.railHeaderDivider() })
173
174
  ] }),
174
175
  topEntries.map(renderRailEntry)
175
176
  ] }),
176
- bottomEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-col gap-1 pt-1", children: bottomEntries.map(renderRailEntry) })
177
+ bottomEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: styles.railBottom(), children: bottomEntries.map(renderRailEntry) })
177
178
  ] });
178
179
  const navData = pinned && shownPanel && (navPreviewActive || !panelOverrideActive) ? shownPanel : null;
179
180
  const [bufferedPanel, setBufferedPanel] = useState(navData);
@@ -205,7 +206,7 @@ function SidebarV2FromConfig({
205
206
  open: drawerOpen,
206
207
  onOpenChange: setDrawerOpen,
207
208
  placement: "left",
208
- children: /* @__PURE__ */ jsxs(Drawer.Content, { className: "w-auto max-w-[85vw] border-0 bg-sidebar p-0 [&>button]:hidden", children: [
209
+ children: /* @__PURE__ */ jsxs(Drawer.Content, { className: styles.mobileDrawer(), children: [
209
210
  /* @__PURE__ */ jsxs(Drawer.Header, { className: "sr-only", children: [
210
211
  /* @__PURE__ */ jsx(Drawer.Title, { children: "Navigation" }),
211
212
  /* @__PURE__ */ jsx(Drawer.Description, { children: "Hauptnavigation" })
@@ -233,10 +234,7 @@ function SidebarV2FromConfig({
233
234
  {
234
235
  ref: setPanelHost,
235
236
  "data-slot": "sidebar-v2-panel-zone",
236
- className: cn(
237
- "relative shrink-0 transition-[width] duration-200 ease-out motion-reduce:transition-none",
238
- pinned && "overflow-hidden"
239
- ),
237
+ className: cn(styles.panelZone(), pinned && "overflow-hidden"),
240
238
  style: { gridArea: "panel", width: docked ? PANEL_WIDTH : "0px" },
241
239
  children: [
242
240
  panelContent,
@@ -244,7 +242,7 @@ function SidebarV2FromConfig({
244
242
  motion.div,
245
243
  {
246
244
  "data-floating": "true",
247
- className: "absolute inset-y-2 left-1 z-30",
245
+ className: styles.flyout(),
248
246
  initial: { x: -14, opacity: 0 },
249
247
  animate: { x: 0, opacity: 1 },
250
248
  exit: { x: -14, opacity: 0 },
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  SidebarV2FromConfig
4
- } from "./chunk-CMYTESJM.mjs";
4
+ } from "./chunk-KLYPP6QE.mjs";
5
5
  import {
6
6
  SidebarV2Inset,
7
7
  SidebarV2Panel,
@@ -15,10 +15,10 @@ import {
15
15
  SidebarV2RailSpacer,
16
16
  SidebarV2Trigger,
17
17
  SidebarV2Workspace
18
- } from "./chunk-EIXUCY5M.mjs";
18
+ } from "./chunk-YW3JMPRU.mjs";
19
19
  import {
20
20
  SidebarV2Provider
21
- } from "./chunk-3L2F566G.mjs";
21
+ } from "./chunk-AIRHHM7Z.mjs";
22
22
 
23
23
  // src/v2/index.tsx
24
24
  var SidebarV2 = SidebarV2Provider;
@@ -1,10 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  useSidebarV2
4
- } from "./chunk-3L2F566G.mjs";
4
+ } from "./chunk-AIRHHM7Z.mjs";
5
5
 
6
6
  // src/v2/app-shell.tsx
7
- import { cn } from "@kopexa/shared-utils";
8
7
  import {
9
8
  useEffect
10
9
  } from "react";
@@ -18,17 +17,13 @@ function AppShellRoot({
18
17
  children,
19
18
  ...props
20
19
  }) {
21
- const { tone } = useSidebarV2();
20
+ const { tone, styles } = useSidebarV2();
22
21
  return /* @__PURE__ */ jsx(
23
22
  "div",
24
23
  {
25
24
  "data-slot": "app-shell",
26
25
  "data-tone": tone,
27
- className: cn(
28
- "relative isolate grid h-svh w-full overflow-hidden antialiased",
29
- tone === "light" ? "bg-muted text-foreground" : "bg-sidebar text-sidebar-foreground",
30
- className
31
- ),
26
+ className: styles.shell({ className }),
32
27
  style: {
33
28
  "--kpx-rail-width": RAIL_WIDTH,
34
29
  "--kpx-panel-width": PANEL_WIDTH,
@@ -47,26 +42,24 @@ function AppShellHeader({
47
42
  style,
48
43
  ...props
49
44
  }) {
45
+ const { styles } = useSidebarV2();
50
46
  return /* @__PURE__ */ jsx(
51
47
  "header",
52
48
  {
53
49
  "data-slot": "app-shell-header",
54
- className: cn("z-20 flex h-14 items-center gap-3 px-2", className),
50
+ className: styles.header({ className }),
55
51
  style: { gridArea: "header", ...style },
56
52
  ...props
57
53
  }
58
54
  );
59
55
  }
60
56
  function AppShellMain({ className, style, ...props }) {
57
+ const { styles } = useSidebarV2();
61
58
  return /* @__PURE__ */ jsx(
62
59
  "main",
63
60
  {
64
61
  "data-slot": "app-shell-main",
65
- className: cn(
66
- "relative flex min-h-0 min-w-0 flex-col overflow-hidden bg-background",
67
- "m-2 rounded-xl shadow-sm",
68
- className
69
- ),
62
+ className: styles.main({ className }),
70
63
  style: { gridArea: "main", ...style },
71
64
  ...props
72
65
  }
@@ -77,11 +70,12 @@ function AppShellAside({
77
70
  style,
78
71
  ...props
79
72
  }) {
73
+ const { styles } = useSidebarV2();
80
74
  return /* @__PURE__ */ jsx(
81
75
  "aside",
82
76
  {
83
77
  "data-slot": "app-shell-aside",
84
- className: cn("min-h-0 min-w-0 overflow-hidden", className),
78
+ className: styles.aside({ className }),
85
79
  style: { gridArea: "aside", ...style },
86
80
  ...props
87
81
  }
@@ -0,0 +1,329 @@
1
+ "use client";
2
+ import {
3
+ panelItemHasChildren,
4
+ panelItemIsSection
5
+ } from "./chunk-SDMGFB6V.mjs";
6
+ import {
7
+ useSidebarV2
8
+ } from "./chunk-AIRHHM7Z.mjs";
9
+
10
+ // src/v2/components.tsx
11
+ import { IconButton } from "@kopexa/button";
12
+ import {
13
+ ChevronDownIcon,
14
+ ChevronRightIcon,
15
+ PanelLeftIcon
16
+ } from "@kopexa/icons";
17
+ import { cn } from "@kopexa/shared-utils";
18
+ import { sidebarMenuButton } from "@kopexa/theme";
19
+ import { Tooltip } from "@kopexa/tooltip";
20
+ import { forwardRef } from "react";
21
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
22
+ function SidebarV2Inset({
23
+ className,
24
+ ...props
25
+ }) {
26
+ const { styles } = useSidebarV2();
27
+ return /* @__PURE__ */ jsx(
28
+ "main",
29
+ {
30
+ "data-slot": "sidebar-v2-inset",
31
+ className: styles.inset({ className }),
32
+ ...props
33
+ }
34
+ );
35
+ }
36
+ function SidebarV2Rail({ className, ...props }) {
37
+ const { styles } = useSidebarV2();
38
+ return /* @__PURE__ */ jsx(
39
+ "nav",
40
+ {
41
+ "data-slot": "sidebar-v2-rail",
42
+ className: styles.rail({ className }),
43
+ ...props
44
+ }
45
+ );
46
+ }
47
+ function SidebarV2RailSpacer() {
48
+ return /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "flex-1" });
49
+ }
50
+ var SidebarV2Workspace = forwardRef(({ name, role, logo, className, appearance = "rail", ...props }, ref) => {
51
+ const { styles } = useSidebarV2();
52
+ if (appearance === "bar") {
53
+ return /* @__PURE__ */ jsxs(
54
+ "button",
55
+ {
56
+ ref,
57
+ type: "button",
58
+ "data-slot": "sidebar-v2-workspace",
59
+ "aria-label": role ? `${name} \u2013 ${role}` : name,
60
+ className: styles.workspaceBar({ className }),
61
+ ...props,
62
+ children: [
63
+ /* @__PURE__ */ jsx("span", { className: styles.workspaceBarLogo(), children: logo != null ? logo : name.charAt(0).toUpperCase() }),
64
+ /* @__PURE__ */ jsxs("span", { className: styles.workspaceBarText(), children: [
65
+ /* @__PURE__ */ jsx("span", { className: styles.workspaceBarName(), children: name }),
66
+ role && /* @__PURE__ */ jsx("span", { className: styles.workspaceBarRole(), children: role })
67
+ ] }),
68
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: styles.workspaceBarChevron() })
69
+ ]
70
+ }
71
+ );
72
+ }
73
+ return /* @__PURE__ */ jsx(
74
+ "button",
75
+ {
76
+ ref,
77
+ type: "button",
78
+ "data-slot": "sidebar-v2-workspace",
79
+ "aria-label": role ? `${name} \u2013 ${role}` : name,
80
+ className: styles.workspaceRail({ className }),
81
+ ...props,
82
+ children: /* @__PURE__ */ jsxs("span", { className: styles.workspaceRailLogo(), children: [
83
+ logo != null ? logo : name.charAt(0).toUpperCase(),
84
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: styles.workspaceRailChevron() })
85
+ ] })
86
+ }
87
+ );
88
+ });
89
+ SidebarV2Workspace.displayName = "SidebarV2Workspace";
90
+ function RailInner({
91
+ icon: Icon,
92
+ badge
93
+ }) {
94
+ const { styles } = useSidebarV2();
95
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: styles.railIndicator() }),
97
+ /* @__PURE__ */ jsx(Icon, { className: styles.railIcon() }),
98
+ badge != null && /* @__PURE__ */ jsx("span", { className: styles.railBadge(), children: badge })
99
+ ] });
100
+ }
101
+ function SidebarV2RailLink({
102
+ icon,
103
+ label,
104
+ href,
105
+ badge
106
+ }) {
107
+ const { renderLink, isActive, resetPanelSelection, styles } = useSidebarV2();
108
+ const active = isActive(href);
109
+ return /* @__PURE__ */ jsx(Tooltip, { content: label, side: "right", children: renderLink({
110
+ href,
111
+ className: styles.railButton(),
112
+ "data-active": active,
113
+ "aria-current": active ? "page" : void 0,
114
+ "aria-label": label,
115
+ // Navigating to a destination link clears any open panel preview,
116
+ // even when the route doesn't change (e.g. already on it).
117
+ onClick: resetPanelSelection,
118
+ children: /* @__PURE__ */ jsx(RailInner, { icon, badge })
119
+ }) });
120
+ }
121
+ function SidebarV2RailItem({
122
+ icon,
123
+ label,
124
+ active,
125
+ hasPanel,
126
+ onClick,
127
+ onMouseEnter,
128
+ onMouseLeave,
129
+ badge
130
+ }) {
131
+ const { styles } = useSidebarV2();
132
+ return /* @__PURE__ */ jsx(Tooltip, { content: label, side: "right", children: /* @__PURE__ */ jsx(
133
+ "button",
134
+ {
135
+ type: "button",
136
+ "data-active": active,
137
+ "aria-label": label,
138
+ "aria-expanded": hasPanel ? active : void 0,
139
+ onClick,
140
+ onMouseEnter,
141
+ onMouseLeave,
142
+ className: styles.railButton(),
143
+ children: /* @__PURE__ */ jsx(RailInner, { icon, badge })
144
+ }
145
+ ) });
146
+ }
147
+ function SidebarV2Panel({
148
+ title,
149
+ subtitle,
150
+ floating,
151
+ hidePin,
152
+ action,
153
+ children,
154
+ className
155
+ }) {
156
+ const { togglePin, pinned, styles } = useSidebarV2();
157
+ return /* @__PURE__ */ jsxs(
158
+ "div",
159
+ {
160
+ "data-slot": "sidebar-v2-panel",
161
+ "data-floating": floating ? "true" : "false",
162
+ className: styles.panel({ className }),
163
+ children: [
164
+ /* @__PURE__ */ jsxs("div", { className: styles.panelHeader(), children: [
165
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
166
+ title && /* @__PURE__ */ jsx("div", { className: styles.panelTitle(), children: title }),
167
+ subtitle && /* @__PURE__ */ jsx("div", { className: styles.panelSubtitle(), children: subtitle })
168
+ ] }),
169
+ action != null ? action : !hidePin && /* @__PURE__ */ jsx(
170
+ Tooltip,
171
+ {
172
+ content: pinned ? "Panel l\xF6sen" : "Panel anheften",
173
+ side: "bottom",
174
+ children: /* @__PURE__ */ jsx(
175
+ IconButton,
176
+ {
177
+ variant: "ghost",
178
+ size: "sm",
179
+ "aria-label": pinned ? "Panel l\xF6sen" : "Panel anheften",
180
+ onClick: togglePin,
181
+ className: styles.panelPin(),
182
+ children: /* @__PURE__ */ jsx(PanelLeftIcon, { className: "size-4" })
183
+ }
184
+ )
185
+ }
186
+ )
187
+ ] }),
188
+ /* @__PURE__ */ jsx("div", { className: styles.panelBody(), children })
189
+ ]
190
+ }
191
+ );
192
+ }
193
+ function SidebarV2PanelLabel({
194
+ className,
195
+ ...props
196
+ }) {
197
+ const { styles } = useSidebarV2();
198
+ return /* @__PURE__ */ jsx(
199
+ "div",
200
+ {
201
+ "data-slot": "sidebar-v2-panel-label",
202
+ className: styles.panelLabel({ className }),
203
+ ...props
204
+ }
205
+ );
206
+ }
207
+ function SidebarV2PanelLeaf({
208
+ item,
209
+ active: activeProp
210
+ }) {
211
+ const { renderLink, isActive, tone, styles } = useSidebarV2();
212
+ const light = tone === "light";
213
+ const Icon = item.icon;
214
+ const active = activeProp != null ? activeProp : isActive(item.href);
215
+ return /* @__PURE__ */ jsx(Fragment, { children: renderLink({
216
+ href: item.href,
217
+ "data-active": active,
218
+ "aria-current": active ? "page" : void 0,
219
+ // Light tone uses the recipe's leaf slot (group/leaf + data-active);
220
+ // dark tone reuses the existing sidebarMenuButton recipe.
221
+ className: light ? styles.panelLeaf() : sidebarMenuButton({ size: "md" }),
222
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
223
+ Icon && /* @__PURE__ */ jsx(Icon, { className: styles.panelLeafIcon() }),
224
+ /* @__PURE__ */ jsx("span", { className: styles.panelLeafLabel(), children: item.label }),
225
+ item.badge != null && /* @__PURE__ */ jsx("span", { className: styles.panelLeafBadge(), children: item.badge })
226
+ ] })
227
+ }) });
228
+ }
229
+ function SidebarV2PanelGroup({
230
+ item
231
+ }) {
232
+ var _a;
233
+ const { openGroup, toggleGroup, activeHref, renderLink, tone, styles } = useSidebarV2();
234
+ const light = tone === "light";
235
+ const Icon = item.icon;
236
+ const key = (_a = item.value) != null ? _a : item.label;
237
+ let bestChildHref = null;
238
+ let bestLen = -1;
239
+ for (const c of item.children) {
240
+ if (activeHref === c.href) {
241
+ bestChildHref = c.href;
242
+ break;
243
+ }
244
+ if (activeHref.startsWith(`${c.href}/`) && c.href.length > bestLen) {
245
+ bestChildHref = c.href;
246
+ bestLen = c.href.length;
247
+ }
248
+ }
249
+ const containsActive = bestChildHref !== null;
250
+ const open = openGroup === key || openGroup === null && containsActive;
251
+ return /* @__PURE__ */ jsxs("div", { children: [
252
+ /* @__PURE__ */ jsxs(
253
+ "button",
254
+ {
255
+ type: "button",
256
+ "data-state": open ? "open" : "closed",
257
+ "data-contains-active": containsActive,
258
+ "aria-expanded": open,
259
+ onClick: () => toggleGroup(key),
260
+ className: cn(
261
+ light ? styles.panelLeaf() : sidebarMenuButton({ size: "md" }),
262
+ styles.panelGroupButton()
263
+ ),
264
+ children: [
265
+ Icon && /* @__PURE__ */ jsx(Icon, { className: styles.panelGroupIcon() }),
266
+ /* @__PURE__ */ jsx("span", { className: styles.panelGroupLabel(), children: item.label }),
267
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: styles.panelGroupChevron() })
268
+ ]
269
+ }
270
+ ),
271
+ open && /* @__PURE__ */ jsx("div", { className: styles.panelTree(), children: item.children.map((child) => {
272
+ const active = child.href === bestChildHref;
273
+ return /* @__PURE__ */ jsx("span", { children: renderLink({
274
+ href: child.href,
275
+ "data-active": active,
276
+ "aria-current": active ? "page" : void 0,
277
+ className: styles.subItem(),
278
+ children: child.label
279
+ }) }, child.href);
280
+ }) })
281
+ ] });
282
+ }
283
+ function SidebarV2PanelItems({
284
+ items
285
+ }) {
286
+ return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, idx) => {
287
+ var _a;
288
+ if (panelItemIsSection(item)) {
289
+ return /* @__PURE__ */ jsx(SidebarV2PanelLabel, { children: item.section }, `section-${item.section}-${idx}`);
290
+ }
291
+ if (panelItemHasChildren(item)) {
292
+ return /* @__PURE__ */ jsx(SidebarV2PanelGroup, { item }, (_a = item.value) != null ? _a : item.label);
293
+ }
294
+ return /* @__PURE__ */ jsx(SidebarV2PanelLeaf, { item }, item.href);
295
+ }) });
296
+ }
297
+ function SidebarV2Trigger({
298
+ className,
299
+ ...props
300
+ }) {
301
+ const { setDrawerOpen, drawerOpen } = useSidebarV2();
302
+ return /* @__PURE__ */ jsx(
303
+ IconButton,
304
+ {
305
+ variant: "ghost",
306
+ size: "md",
307
+ "aria-label": "Navigation \xF6ffnen",
308
+ onClick: () => setDrawerOpen(!drawerOpen),
309
+ className,
310
+ ...props,
311
+ children: /* @__PURE__ */ jsx(PanelLeftIcon, { className: "size-5" })
312
+ }
313
+ );
314
+ }
315
+
316
+ export {
317
+ SidebarV2Inset,
318
+ SidebarV2Rail,
319
+ SidebarV2RailSpacer,
320
+ SidebarV2Workspace,
321
+ SidebarV2RailLink,
322
+ SidebarV2RailItem,
323
+ SidebarV2Panel,
324
+ SidebarV2PanelLabel,
325
+ SidebarV2PanelLeaf,
326
+ SidebarV2PanelGroup,
327
+ SidebarV2PanelItems,
328
+ SidebarV2Trigger
329
+ };