@kopexa/sidebar 17.2.0 → 17.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.
@@ -34,23 +34,29 @@ var import_react4 = require("react");
34
34
  var import_button = require("@kopexa/button");
35
35
  var import_icons = require("@kopexa/icons");
36
36
  var import_shared_utils = require("@kopexa/shared-utils");
37
- var import_theme = require("@kopexa/theme");
37
+ var import_theme2 = require("@kopexa/theme");
38
38
  var import_tooltip2 = require("@kopexa/tooltip");
39
39
  var import_react2 = require("react");
40
40
 
41
41
  // src/v2/context.tsx
42
42
  var import_react_utils = require("@kopexa/react-utils");
43
+ var import_theme = require("@kopexa/theme");
43
44
  var import_tooltip = require("@kopexa/tooltip");
44
45
  var import_use_is_mobile = require("@kopexa/use-is-mobile");
45
46
  var import_react = require("react");
46
- var import_jsx_runtime = require("react/jsx-runtime");
47
- var PIN_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
48
- var [Provider, useSidebarV2] = (0, import_react_utils.createContext)({
49
- name: "SidebarV2Context",
50
- errorMessage: "useSidebarV2 must be used within <SidebarV2> (the provider component)."
51
- });
52
47
 
53
48
  // src/v2/types.ts
49
+ function normalizePath(href) {
50
+ const path = href.split("#")[0].split("?")[0].replace(/\/+$/, "");
51
+ return path === "" ? "/" : path;
52
+ }
53
+ function pathMatchLength(currentPath, href) {
54
+ const target = normalizePath(href);
55
+ if (currentPath === target) return target.length;
56
+ if (target !== "/" && currentPath.startsWith(`${target}/`))
57
+ return target.length;
58
+ return -1;
59
+ }
54
60
  function panelItemHasChildren(item) {
55
61
  return "children" in item && Array.isArray(item.children);
56
62
  }
@@ -58,27 +64,29 @@ function panelItemIsSection(item) {
58
64
  return "section" in item;
59
65
  }
60
66
 
67
+ // src/v2/context.tsx
68
+ var import_jsx_runtime = require("react/jsx-runtime");
69
+ var PIN_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
70
+ var [Provider, useSidebarV2] = (0, import_react_utils.createContext)({
71
+ name: "SidebarV2Context",
72
+ errorMessage: "useSidebarV2 must be used within <SidebarV2> (the provider component)."
73
+ });
74
+
61
75
  // src/v2/components.tsx
62
76
  var import_jsx_runtime2 = require("react/jsx-runtime");
63
77
  function SidebarV2Rail({ className, ...props }) {
64
- const { tone } = useSidebarV2();
65
- const light = tone === "light";
78
+ const { styles } = useSidebarV2();
66
79
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
67
80
  "nav",
68
81
  {
69
82
  "data-slot": "sidebar-v2-rail",
70
- className: (0, import_shared_utils.cn)(
71
- "flex w-(--kpx-rail-width) shrink-0 flex-col overflow-hidden bg-sidebar py-2 text-sidebar-foreground",
72
- // Light tone: the dark rail floats as a rounded card on the light
73
- // surround. Dark tone: full-height, flush to the edge.
74
- light ? "m-2 rounded-2xl shadow-sm" : "h-full",
75
- className
76
- ),
83
+ className: styles.rail({ className }),
77
84
  ...props
78
85
  }
79
86
  );
80
87
  }
81
88
  var SidebarV2Workspace = (0, import_react2.forwardRef)(({ name, role, logo, className, appearance = "rail", ...props }, ref) => {
89
+ const { styles } = useSidebarV2();
82
90
  if (appearance === "bar") {
83
91
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
84
92
  "button",
@@ -87,19 +95,15 @@ var SidebarV2Workspace = (0, import_react2.forwardRef)(({ name, role, logo, clas
87
95
  type: "button",
88
96
  "data-slot": "sidebar-v2-workspace",
89
97
  "aria-label": role ? `${name} \u2013 ${role}` : name,
90
- className: (0, import_shared_utils.cn)(
91
- "group/ws flex cursor-pointer items-center gap-2 rounded-lg py-1 pr-2 pl-1",
92
- "outline-hidden ring-ring transition-colors hover:bg-foreground/5 focus-visible:ring-2",
93
- className
94
- ),
98
+ className: styles.workspaceBar({ className }),
95
99
  ...props,
96
100
  children: [
97
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "flex size-7 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-semibold text-primary-foreground", children: logo != null ? logo : name.charAt(0).toUpperCase() }),
98
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "flex min-w-0 flex-col text-left leading-tight", children: [
99
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate text-sm font-semibold text-foreground", children: name }),
100
- role && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: role })
101
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.workspaceBarLogo(), children: logo != null ? logo : name.charAt(0).toUpperCase() }),
102
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: styles.workspaceBarText(), children: [
103
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.workspaceBarName(), children: name }),
104
+ role && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.workspaceBarRole(), children: role })
101
105
  ] }),
102
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.ChevronDownIcon, { className: "size-4 shrink-0 text-muted-foreground" })
106
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.ChevronDownIcon, { className: styles.workspaceBarChevron() })
103
107
  ]
104
108
  }
105
109
  );
@@ -111,48 +115,25 @@ var SidebarV2Workspace = (0, import_react2.forwardRef)(({ name, role, logo, clas
111
115
  type: "button",
112
116
  "data-slot": "sidebar-v2-workspace",
113
117
  "aria-label": role ? `${name} \u2013 ${role}` : name,
114
- className: (0, import_shared_utils.cn)(
115
- "group/ws relative mx-auto mt-1 flex cursor-pointer items-center justify-center rounded-lg p-1",
116
- "outline-hidden ring-sidebar-ring transition-colors",
117
- "hover:bg-sidebar-accent focus-visible:ring-2",
118
- className
119
- ),
118
+ className: styles.workspaceRail({ className }),
120
119
  ...props,
121
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "relative flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary text-sm font-semibold text-primary-foreground", children: [
120
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: styles.workspaceRailLogo(), children: [
122
121
  logo != null ? logo : name.charAt(0).toUpperCase(),
123
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.ChevronDownIcon, { className: "absolute -right-1 -bottom-1 size-3.5 rounded-full bg-sidebar p-px text-sidebar-foreground/60" })
122
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.ChevronDownIcon, { className: styles.workspaceRailChevron() })
124
123
  ] })
125
124
  }
126
125
  );
127
126
  });
128
127
  SidebarV2Workspace.displayName = "SidebarV2Workspace";
129
- function railButtonClasses(active) {
130
- return (0, import_shared_utils.cn)(
131
- "group/rail relative mx-auto flex size-11 shrink-0 cursor-pointer items-center justify-center rounded-xl",
132
- "outline-hidden ring-sidebar-ring transition-colors",
133
- "text-sidebar-foreground/85 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
134
- "focus-visible:ring-2",
135
- active && "bg-sidebar-accent text-sidebar-accent-foreground"
136
- );
137
- }
138
128
  function RailInner({
139
129
  icon: Icon,
140
- active,
141
130
  badge
142
131
  }) {
132
+ const { styles } = useSidebarV2();
143
133
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
144
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
145
- "span",
146
- {
147
- "aria-hidden": true,
148
- className: (0, import_shared_utils.cn)(
149
- "absolute top-1/2 left-0 h-5 w-0.5 -translate-x-[0.6rem] -translate-y-1/2 rounded-r bg-primary transition-opacity",
150
- active ? "opacity-100" : "opacity-0"
151
- )
152
- }
153
- ),
154
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { className: "size-5 shrink-0" }),
155
- badge != null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "absolute -top-0.5 -right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[0.5625rem] font-semibold text-primary-foreground", children: badge })
134
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": true, className: styles.railIndicator() }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { className: styles.railIcon() }),
136
+ badge != null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.railBadge(), children: badge })
156
137
  ] });
157
138
  }
158
139
  function SidebarV2RailLink({
@@ -161,18 +142,18 @@ function SidebarV2RailLink({
161
142
  href,
162
143
  badge
163
144
  }) {
164
- const { renderLink, isActive, resetPanelSelection } = useSidebarV2();
145
+ const { renderLink, isActive, resetPanelSelection, styles } = useSidebarV2();
165
146
  const active = isActive(href);
166
147
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_tooltip2.Tooltip, { content: label, side: "right", children: renderLink({
167
148
  href,
168
- className: railButtonClasses(active),
149
+ className: styles.railButton(),
169
150
  "data-active": active,
170
151
  "aria-current": active ? "page" : void 0,
171
152
  "aria-label": label,
172
153
  // Navigating to a destination link clears any open panel preview,
173
154
  // even when the route doesn't change (e.g. already on it).
174
155
  onClick: resetPanelSelection,
175
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RailInner, { icon, label, active, badge })
156
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RailInner, { icon, badge })
176
157
  }) });
177
158
  }
178
159
  function SidebarV2RailItem({
@@ -185,6 +166,7 @@ function SidebarV2RailItem({
185
166
  onMouseLeave,
186
167
  badge
187
168
  }) {
169
+ const { styles } = useSidebarV2();
188
170
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_tooltip2.Tooltip, { content: label, side: "right", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
189
171
  "button",
190
172
  {
@@ -195,8 +177,8 @@ function SidebarV2RailItem({
195
177
  onClick,
196
178
  onMouseEnter,
197
179
  onMouseLeave,
198
- className: railButtonClasses(active),
199
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RailInner, { icon, label, active, badge })
180
+ className: styles.railButton(),
181
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RailInner, { icon, badge })
200
182
  }
201
183
  ) });
202
184
  }
@@ -209,54 +191,18 @@ function SidebarV2Panel({
209
191
  children,
210
192
  className
211
193
  }) {
212
- const { togglePin, pinned, tone } = useSidebarV2();
213
- const light = tone === "light";
194
+ const { togglePin, pinned, styles } = useSidebarV2();
214
195
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
215
196
  "div",
216
197
  {
217
198
  "data-slot": "sidebar-v2-panel",
218
- "data-floating": floating,
219
- className: (0, import_shared_utils.cn)(
220
- "flex h-full w-(--kpx-panel-width) shrink-0 flex-col",
221
- // Surface. The flyout is a distinct floating card (white on light),
222
- // so it reads as an overlay rather than a flat full-height slab.
223
- floating ? light ? "bg-background text-foreground" : "bg-sidebar text-sidebar-foreground" : light ? "bg-muted text-foreground" : "bg-sidebar text-sidebar-foreground",
224
- floating ? (
225
- // Floating card: rounded, soft layered shadow, hairline ring.
226
- (0, import_shared_utils.cn)(
227
- "overflow-hidden rounded-2xl shadow-2xl shadow-black/20 ring-1",
228
- light ? "ring-black/5" : "ring-white/10"
229
- )
230
- ) : (
231
- // Pinned: light blends into the surround (no border); dark keeps a
232
- // hairline against the rail.
233
- light ? "" : "border-l border-sidebar-border/40"
234
- ),
235
- className
236
- ),
199
+ "data-floating": floating ? "true" : "false",
200
+ className: styles.panel({ className }),
237
201
  children: [
238
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-start gap-2 px-3 pt-3 pb-1.5", children: [
202
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: styles.panelHeader(), children: [
239
203
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "min-w-0 flex-1", children: [
240
- title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
241
- "div",
242
- {
243
- className: (0, import_shared_utils.cn)(
244
- "truncate text-sm font-semibold",
245
- light ? "text-foreground" : "text-sidebar-foreground"
246
- ),
247
- children: title
248
- }
249
- ),
250
- subtitle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
251
- "div",
252
- {
253
- className: (0, import_shared_utils.cn)(
254
- "truncate text-xs",
255
- light ? "text-muted-foreground" : "text-sidebar-foreground/70"
256
- ),
257
- children: subtitle
258
- }
259
- )
204
+ title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: styles.panelTitle(), children: title }),
205
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: styles.panelSubtitle(), children: subtitle })
260
206
  ] }),
261
207
  action != null ? action : !hidePin && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
262
208
  import_tooltip2.Tooltip,
@@ -270,41 +216,28 @@ function SidebarV2Panel({
270
216
  size: "sm",
271
217
  "aria-label": pinned ? "Panel l\xF6sen" : "Panel anheften",
272
218
  onClick: togglePin,
273
- className: (0, import_shared_utils.cn)(
274
- "-mr-1 shrink-0",
275
- light ? "text-muted-foreground hover:bg-foreground/5 hover:text-foreground" : "text-sidebar-foreground/60 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
276
- ),
219
+ className: styles.panelPin(),
277
220
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.PanelLeftIcon, { className: "size-4" })
278
221
  }
279
222
  )
280
223
  }
281
224
  )
282
225
  ] }),
283
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-auto p-2", children })
226
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: styles.panelBody(), children })
284
227
  ]
285
228
  }
286
229
  );
287
230
  }
288
- function panelRowLight(active) {
289
- return (0, import_shared_utils.cn)(
290
- "flex h-8 w-full items-center gap-2.5 rounded-md px-2 text-sm outline-hidden ring-ring transition-colors focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
291
- active ? "bg-primary/10 font-medium text-primary" : "text-foreground/80 hover:bg-foreground/5"
292
- );
293
- }
294
231
  function SidebarV2PanelLabel({
295
232
  className,
296
233
  ...props
297
234
  }) {
298
- const { tone } = useSidebarV2();
235
+ const { styles } = useSidebarV2();
299
236
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
300
237
  "div",
301
238
  {
302
239
  "data-slot": "sidebar-v2-panel-label",
303
- className: (0, import_shared_utils.cn)(
304
- "px-2 pt-3 pb-1 text-[0.6875rem] font-medium uppercase tracking-wide",
305
- tone === "light" ? "text-muted-foreground" : "text-sidebar-foreground/50",
306
- className
307
- ),
240
+ className: styles.panelLabel({ className }),
308
241
  ...props
309
242
  }
310
243
  );
@@ -313,7 +246,7 @@ function SidebarV2PanelLeaf({
313
246
  item,
314
247
  active: activeProp
315
248
  }) {
316
- const { renderLink, isActive, tone } = useSidebarV2();
249
+ const { renderLink, isActive, tone, styles } = useSidebarV2();
317
250
  const light = tone === "light";
318
251
  const Icon = item.icon;
319
252
  const active = activeProp != null ? activeProp : isActive(item.href);
@@ -321,51 +254,40 @@ function SidebarV2PanelLeaf({
321
254
  href: item.href,
322
255
  "data-active": active,
323
256
  "aria-current": active ? "page" : void 0,
324
- className: light ? panelRowLight(active) : (0, import_theme.sidebarMenuButton)({ size: "md" }),
257
+ // Light tone uses the recipe's leaf slot (group/leaf + data-active);
258
+ // dark tone reuses the existing sidebarMenuButton recipe.
259
+ className: light ? styles.panelLeaf() : (0, import_theme2.sidebarMenuButton)({ size: "md" }),
325
260
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
326
- Icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
327
- Icon,
328
- {
329
- className: (0, import_shared_utils.cn)(
330
- light ? active ? void 0 : "text-muted-foreground" : "text-sidebar-foreground/75"
331
- )
332
- }
333
- ),
334
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
335
- item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
336
- "span",
337
- {
338
- className: (0, import_shared_utils.cn)(
339
- "ml-auto rounded-full px-1.5 text-[0.625rem] font-medium",
340
- light ? "bg-foreground/10 text-foreground/70" : "bg-sidebar-accent text-sidebar-accent-foreground"
341
- ),
342
- children: item.badge
343
- }
344
- )
261
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { className: styles.panelLeafIcon() }),
262
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.panelLeafLabel(), children: item.label }),
263
+ item.tag && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.panelLeafTag(), children: item.tag }),
264
+ item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.panelLeafBadge(), children: item.badge })
345
265
  ] })
346
266
  }) });
347
267
  }
348
268
  function SidebarV2PanelGroup({
349
- item
269
+ item,
270
+ winningHref
350
271
  }) {
351
272
  var _a;
352
- const { openGroup, toggleGroup, activeHref, renderLink, tone } = useSidebarV2();
273
+ const { openGroup, toggleGroup, activeHref, renderLink, tone, styles } = useSidebarV2();
353
274
  const light = tone === "light";
354
275
  const Icon = item.icon;
355
276
  const key = (_a = item.value) != null ? _a : item.label;
356
- let bestChildHref = null;
357
- let bestLen = -1;
358
- for (const c of item.children) {
359
- if (activeHref === c.href) {
360
- bestChildHref = c.href;
361
- break;
362
- }
363
- if (activeHref.startsWith(`${c.href}/`) && c.href.length > bestLen) {
364
- bestChildHref = c.href;
365
- bestLen = c.href.length;
277
+ let winner = winningHref;
278
+ if (winner === void 0) {
279
+ const current = normalizePath(activeHref);
280
+ let len = -1;
281
+ winner = null;
282
+ for (const c of item.children) {
283
+ const l = pathMatchLength(current, c.href);
284
+ if (l > len) {
285
+ len = l;
286
+ winner = normalizePath(c.href);
287
+ }
366
288
  }
367
289
  }
368
- const containsActive = bestChildHref !== null;
290
+ const containsActive = winner != null && item.children.some((c) => normalizePath(c.href) === winner);
369
291
  const open = openGroup === key || openGroup === null && containsActive;
370
292
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
371
293
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
@@ -373,71 +295,76 @@ function SidebarV2PanelGroup({
373
295
  {
374
296
  type: "button",
375
297
  "data-state": open ? "open" : "closed",
298
+ "data-contains-active": containsActive,
376
299
  "aria-expanded": open,
377
300
  onClick: () => toggleGroup(key),
378
301
  className: (0, import_shared_utils.cn)(
379
- light ? panelRowLight(false) : (0, import_theme.sidebarMenuButton)({ size: "md" }),
380
- "cursor-pointer",
381
- containsActive && (light ? "font-medium text-foreground" : "font-medium")
302
+ light ? styles.panelLeaf() : (0, import_theme2.sidebarMenuButton)({ size: "md" }),
303
+ styles.panelGroupButton()
382
304
  ),
383
305
  children: [
384
- Icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
385
- Icon,
386
- {
387
- className: light ? "text-muted-foreground" : "text-sidebar-foreground/75"
388
- }
389
- ),
390
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label }),
391
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
392
- import_icons.ChevronRightIcon,
393
- {
394
- className: (0, import_shared_utils.cn)(
395
- "size-3.5! shrink-0 transition-transform",
396
- light ? "text-muted-foreground" : "text-sidebar-foreground/60",
397
- open && "rotate-90"
398
- )
399
- }
400
- )
306
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { className: styles.panelGroupIcon() }),
307
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.panelGroupLabel(), children: item.label }),
308
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.ChevronRightIcon, { className: styles.panelGroupChevron() })
401
309
  ]
402
310
  }
403
311
  ),
404
- open && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
405
- "div",
406
- {
407
- className: (0, import_shared_utils.cn)(
408
- "my-0.5 ml-[1.05rem] flex flex-col border-l pl-3",
409
- light ? "border-border" : "border-sidebar-border"
410
- ),
411
- children: item.children.map((child) => {
412
- const active = child.href === bestChildHref;
413
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: renderLink({
414
- href: child.href,
415
- "data-active": active,
416
- "aria-current": active ? "page" : void 0,
417
- className: (0, import_shared_utils.cn)(
418
- "relative block rounded-md px-2 py-1.5 text-[0.8125rem] outline-hidden transition-colors focus-visible:ring-2",
419
- "before:absolute before:top-1/2 before:-left-3 before:h-px before:w-2.5",
420
- light ? active ? "bg-primary/10 font-medium text-primary ring-ring before:bg-primary" : "text-muted-foreground ring-ring hover:bg-foreground/5 hover:text-foreground before:bg-border" : active ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground ring-sidebar-ring before:bg-primary" : "text-sidebar-foreground/80 ring-sidebar-ring hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground before:bg-sidebar-foreground/30"
421
- ),
422
- children: child.label
423
- }) }, child.href);
424
- })
425
- }
426
- )
312
+ open && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: styles.panelTree(), children: item.children.map((child) => {
313
+ const active = normalizePath(child.href) === winner;
314
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: renderLink({
315
+ href: child.href,
316
+ "data-active": active,
317
+ "aria-current": active ? "page" : void 0,
318
+ className: styles.subItem(),
319
+ children: child.label
320
+ }) }, child.href);
321
+ }) })
427
322
  ] });
428
323
  }
429
324
  function SidebarV2PanelItems({
430
325
  items
431
326
  }) {
327
+ const { activeHref } = useSidebarV2();
328
+ const winningHref = (0, import_react2.useMemo)(() => {
329
+ const current = normalizePath(activeHref);
330
+ let href = null;
331
+ let len = -1;
332
+ for (const item of items) {
333
+ if (panelItemIsSection(item)) continue;
334
+ const hrefs = panelItemHasChildren(item) ? item.children.map((c) => c.href) : [item.href];
335
+ for (const h of hrefs) {
336
+ const l = pathMatchLength(current, h);
337
+ if (l > len) {
338
+ len = l;
339
+ href = normalizePath(h);
340
+ }
341
+ }
342
+ }
343
+ return href;
344
+ }, [items, activeHref]);
432
345
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: items.map((item, idx) => {
433
346
  var _a;
434
347
  if (panelItemIsSection(item)) {
435
348
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SidebarV2PanelLabel, { children: item.section }, `section-${item.section}-${idx}`);
436
349
  }
437
350
  if (panelItemHasChildren(item)) {
438
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SidebarV2PanelGroup, { item }, (_a = item.value) != null ? _a : item.label);
351
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
352
+ SidebarV2PanelGroup,
353
+ {
354
+ item,
355
+ winningHref
356
+ },
357
+ (_a = item.value) != null ? _a : item.label
358
+ );
439
359
  }
440
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SidebarV2PanelLeaf, { item }, item.href);
360
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
361
+ SidebarV2PanelLeaf,
362
+ {
363
+ item,
364
+ active: winningHref != null && normalizePath(item.href) === winningHref
365
+ },
366
+ item.href
367
+ );
441
368
  }) });
442
369
  }
443
370
 
@@ -468,13 +395,14 @@ function SidebarV2FromConfig({
468
395
  closeFlyout,
469
396
  selectedRail,
470
397
  setSelectedRail,
471
- isActive,
398
+ activeHref,
472
399
  isMobile,
473
400
  drawerOpen,
474
401
  setDrawerOpen,
475
402
  setPanelHost,
476
403
  panelOverrideActive,
477
- navPreviewActive
404
+ navPreviewActive,
405
+ styles
478
406
  } = useSidebarV2();
479
407
  const hoverMode = flyoutTrigger === "hover" && !pinned && !isMobile;
480
408
  const closeTimer = (0, import_react4.useRef)(null);
@@ -513,14 +441,21 @@ function SidebarV2FromConfig({
513
441
  [items]
514
442
  );
515
443
  const activeRailValue = (0, import_react4.useMemo)(() => {
516
- const match = panels.find(
517
- (p) => p.items.some((item) => {
518
- if (panelItemIsSection(item)) return false;
519
- return panelItemHasChildren(item) ? item.children.some((c) => isActive(c.href)) : isActive(item.href);
520
- })
521
- );
522
- return match ? entryValue(match) : null;
523
- }, [panels, isActive]);
444
+ var _a2, _b2;
445
+ const current = normalizePath(activeHref);
446
+ let best = null;
447
+ for (const p of panels) {
448
+ for (const item of p.items) {
449
+ if (panelItemIsSection(item)) continue;
450
+ const hrefs = panelItemHasChildren(item) ? item.children.map((c) => c.href) : [item.href];
451
+ for (const href of hrefs) {
452
+ const len = pathMatchLength(current, href);
453
+ if (len > ((_a2 = best == null ? void 0 : best.len) != null ? _a2 : -1)) best = { value: entryValue(p), len };
454
+ }
455
+ }
456
+ }
457
+ return (_b2 = best == null ? void 0 : best.value) != null ? _b2 : null;
458
+ }, [panels, activeHref]);
524
459
  const shownValue = pinned ? selectedRail != null ? selectedRail : activeRailValue : flyoutValue;
525
460
  const shownPanel = (_a = panels.find((p) => entryValue(p) === shownValue)) != null ? _a : null;
526
461
  const topEntries = items.filter((e) => e.slot !== "bottom");
@@ -531,7 +466,7 @@ function SidebarV2FromConfig({
531
466
  "div",
532
467
  {
533
468
  "aria-hidden": true,
534
- className: "mx-3 my-1.5 h-px shrink-0 bg-sidebar-border/70"
469
+ className: styles.railDivider()
535
470
  },
536
471
  `rail-divider-${index}`
537
472
  );
@@ -583,14 +518,14 @@ function SidebarV2FromConfig({
583
518
  );
584
519
  }
585
520
  const railContent = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
586
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: [
521
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: styles.railScroll(), children: [
587
522
  header && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
588
523
  header,
589
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mx-3 my-1 h-px shrink-0 bg-sidebar-border/60" })
524
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: styles.railHeaderDivider() })
590
525
  ] }),
591
526
  topEntries.map(renderRailEntry)
592
527
  ] }),
593
- bottomEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex shrink-0 flex-col gap-1 pt-1", children: bottomEntries.map(renderRailEntry) })
528
+ bottomEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: styles.railBottom(), children: bottomEntries.map(renderRailEntry) })
594
529
  ] });
595
530
  const navData = pinned && shownPanel && (navPreviewActive || !panelOverrideActive) ? shownPanel : null;
596
531
  const [bufferedPanel, setBufferedPanel] = (0, import_react4.useState)(navData);
@@ -622,7 +557,7 @@ function SidebarV2FromConfig({
622
557
  open: drawerOpen,
623
558
  onOpenChange: setDrawerOpen,
624
559
  placement: "left",
625
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_drawer.Drawer.Content, { className: "w-auto max-w-[85vw] border-0 bg-sidebar p-0 [&>button]:hidden", children: [
560
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_drawer.Drawer.Content, { className: styles.mobileDrawer(), children: [
626
561
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_drawer.Drawer.Header, { className: "sr-only", children: [
627
562
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_drawer.Drawer.Title, { children: "Navigation" }),
628
563
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_drawer.Drawer.Description, { children: "Hauptnavigation" })
@@ -650,10 +585,7 @@ function SidebarV2FromConfig({
650
585
  {
651
586
  ref: setPanelHost,
652
587
  "data-slot": "sidebar-v2-panel-zone",
653
- className: (0, import_shared_utils2.cn)(
654
- "relative shrink-0 transition-[width] duration-200 ease-out motion-reduce:transition-none",
655
- pinned && "overflow-hidden"
656
- ),
588
+ className: (0, import_shared_utils2.cn)(styles.panelZone(), pinned && "overflow-hidden"),
657
589
  style: { gridArea: "panel", width: docked ? PANEL_WIDTH : "0px" },
658
590
  children: [
659
591
  panelContent,
@@ -661,7 +593,7 @@ function SidebarV2FromConfig({
661
593
  import_react3.motion.div,
662
594
  {
663
595
  "data-floating": "true",
664
- className: "absolute inset-y-2 left-1 z-30",
596
+ className: styles.flyout(),
665
597
  initial: { x: -14, opacity: 0 },
666
598
  animate: { x: 0, opacity: 1 },
667
599
  exit: { x: -14, opacity: 0 },
@@ -2,10 +2,10 @@
2
2
  "use client";
3
3
  import {
4
4
  SidebarV2FromConfig
5
- } from "../chunk-CMYTESJM.mjs";
6
- import "../chunk-EIXUCY5M.mjs";
7
- import "../chunk-SDMGFB6V.mjs";
8
- import "../chunk-3L2F566G.mjs";
5
+ } from "../chunk-G2J7EJQ6.mjs";
6
+ import "../chunk-5VE25P3M.mjs";
7
+ import "../chunk-XBTONQ3L.mjs";
8
+ import "../chunk-BFZFZSUC.mjs";
9
9
  export {
10
10
  SidebarV2FromConfig
11
11
  };
@@ -9,6 +9,7 @@ export { SidebarV2Icon, SidebarV2LinkProps, SidebarV2Nav, SidebarV2PanelItem, Si
9
9
  import 'react';
10
10
  import 'react/jsx-runtime';
11
11
  import '@kopexa/button';
12
+ import '@kopexa/theme';
12
13
 
13
14
  /**
14
15
  * SidebarV2 — icon rail + expandable panel navigation context + primitives.
@@ -9,6 +9,7 @@ export { SidebarV2Icon, SidebarV2LinkProps, SidebarV2Nav, SidebarV2PanelItem, Si
9
9
  import 'react';
10
10
  import 'react/jsx-runtime';
11
11
  import '@kopexa/button';
12
+ import '@kopexa/theme';
12
13
 
13
14
  /**
14
15
  * SidebarV2 — icon rail + expandable panel navigation context + primitives.