laif-ds 1.0.0 → 1.0.2

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.
@@ -1,92 +1,218 @@
1
1
  "use client";
2
- import { jsx as t, jsxs as s, Fragment as E } from "react/jsx-runtime";
3
- import * as o from "react";
4
- import { designTokens as l } from "../design-tokens.js";
5
- import { AppSidebarMobile as de } from "./app-sidebar-mobile.js";
6
- import { DropdownMenu as q, DropdownMenuTrigger as J, DropdownMenuContent as Q, DropdownMenuRadioGroup as ue, DropdownMenuRadioItem as he, DropdownMenuItem as pe } from "./dropdown-menu.js";
7
- import { Icon as k } from "./icon.js";
8
- import { useSidebar as fe, Sidebar as W, SidebarHeader as me, SidebarContent as be, SidebarRail as ge, SidebarGroup as z, SidebarSeparator as ve, SidebarGroupLabel as xe, SidebarGroupContent as Se, SidebarMenu as Ne, SidebarMenuItem as D, SidebarMenuButton as _, SidebarMenuSub as Ae, SidebarMenuSubItem as we, SidebarMenuSubButton as X } from "./sidebar.js";
9
- import { Tabs as ye, TabsList as Me, TabsContent as Te, TabsTrigger as Ce } from "./tabs.js";
10
- import { Tooltip as j, TooltipTrigger as K, TooltipContent as O } from "./tooltip.js";
11
- import { cn as d } from "../../lib/utils.js";
12
- const Z = (i, a) => `${i.title} ${a.url} ${a.title}`, P = (i) => `${i.url} ${i.title}`, Ie = { xs: "size-4", sm: "size-5" }, T = (i, a, b) => {
13
- if (i.icon) {
14
- const h = i.icon;
15
- return /* @__PURE__ */ t(h, { className: d(Ie[a], "shrink-0", b) });
2
+ import { jsx as t, jsxs as c, Fragment as W } from "react/jsx-runtime";
3
+ import * as i from "react";
4
+ import { designTokens as f } from "../design-tokens.js";
5
+ import { navTokens as _e } from "../nav-tokens.js";
6
+ import { AppSidebarMobile as mn } from "./app-sidebar-mobile.js";
7
+ import { DropdownMenu as $e, DropdownMenuTrigger as Ge, DropdownMenuContent as De, DropdownMenuRadioGroup as pn, DropdownMenuRadioItem as bn, DropdownMenuItem as vn } from "./dropdown-menu.js";
8
+ import { Icon as ne } from "./icon.js";
9
+ import { someRowBadged as Y, NavBadgeDot as me, normalizeNavBadge as M, renderInlineNavBadge as P, NavBadgeSrLabel as B } from "./nav-badge.js";
10
+ import { useSidebar as gn, Sidebar as Fe, SidebarContent as wn, SidebarRail as xn, SidebarHeader as ze, SidebarGroup as pe, SidebarSeparator as Nn, SidebarGroupLabel as Sn, SidebarGroupContent as En, SidebarMenu as yn, SidebarMenuItem as be, SidebarMenuButton as ve, SidebarMenuSub as Rn, SidebarMenuSubItem as Tn, SidebarMenuSubButton as je } from "./sidebar.js";
11
+ import { Tabs as Mn, TabsList as Cn, TabsContent as kn, TabsTrigger as An } from "./tabs.js";
12
+ import { Tooltip as J, TooltipTrigger as Q, TooltipContent as X } from "./tooltip.js";
13
+ import { cn as h } from "../../lib/utils.js";
14
+ const He = (o, l) => `${o.title} ${l.url} ${l.title}`, Ke = (o) => `${o.url} ${o.title}`, In = { xs: "size-4", sm: "size-5" }, Ve = "absolute top-0 -right-[5px]", Z = (o, l, x) => {
15
+ if (o.icon) {
16
+ const v = o.icon;
17
+ return /* @__PURE__ */ t(v, { className: h(In[l], "shrink-0", x) });
16
18
  }
17
- return i.iconName ? /* @__PURE__ */ t(k, { name: i.iconName, size: a, className: b }) : null;
18
- }, C = "__group-selector";
19
- function Oe({
20
- navigation: i,
21
- navigationFooter: a,
22
- navigationDisplay: b = "list",
23
- headerContent: h,
24
- footerContent: B,
25
- showRail: L = !0,
26
- collapsible: g,
27
- linkComponent: u,
28
- linkProps: v = {},
29
- ...F
19
+ return o.iconName ? /* @__PURE__ */ t(ne, { name: o.iconName, size: l, className: x }) : null;
20
+ }, ee = "__group-selector", qe = 300, Ue = 300, On = 120, b = (o) => {
21
+ o.current !== null && (window.clearTimeout(o.current), o.current = null);
22
+ }, Pn = (o, l) => l instanceof Node ? o?.contains(l) ? !0 : l instanceof Element && !!l.closest("[data-radix-popper-content-wrapper]") : !1;
23
+ function Bn() {
24
+ const [o, l] = i.useState(!1);
25
+ return i.useEffect(() => {
26
+ if (typeof window > "u" || !window.matchMedia) return;
27
+ const x = window.matchMedia("(hover: hover) and (pointer: fine)"), v = () => l(x.matches);
28
+ return v(), x.addEventListener("change", v), () => x.removeEventListener("change", v);
29
+ }, []), o;
30
+ }
31
+ function Un({
32
+ navigation: o,
33
+ navigationFooter: l,
34
+ navigationDisplay: x = "list",
35
+ headerContent: v,
36
+ footerContent: ge,
37
+ showRail: We = !0,
38
+ collapsible: N,
39
+ side: te = "left",
40
+ expandOnHover: re,
41
+ pinned: C,
42
+ defaultPinned: Ye,
43
+ onPinnedChange: we,
44
+ linkComponent: y,
45
+ linkProps: j = {},
46
+ ...k
30
47
  }) {
31
- const { state: ee, isMobile: V } = fe(), re = o.useId(), x = g === "icon" && ee === "collapsed" && !V, [te, H] = o.useState({}), I = o.useMemo(
32
- () => [...i, ...a ?? []].flatMap(
48
+ const { state: Je, isMobile: ie, open: a, setOpen: H, peek: A, setPeek: m } = gn(), Qe = i.useId(), u = N === "icon" && Je === "collapsed" && !ie, Xe = Bn(), p = !!re && N === "icon" && !ie && Xe;
49
+ i.useEffect(() => {
50
+ !re || N === "icon" || console.warn(
51
+ `AppSidebar: \`expandOnHover\` requires \`collapsible="icon"\` — got "${N ?? "offcanvas"}", so the prop is ignored.`
52
+ );
53
+ }, [re, N]);
54
+ const I = i.useRef(null), R = i.useRef(null), S = i.useRef(null), L = i.useRef(null), T = i.useRef(!1), _ = i.useRef(!1), se = i.useCallback(
55
+ () => !!I.current?.contains(document.activeElement),
56
+ []
57
+ ), $ = i.useCallback(() => {
58
+ const e = document.activeElement;
59
+ return !(e instanceof HTMLElement) || !I.current?.contains(e) ? !1 : e.matches(":focus-visible");
60
+ }, []), G = i.useCallback(
61
+ () => !!I.current?.querySelector(
62
+ '[aria-expanded="true"][data-state="open"]'
63
+ ),
64
+ []
65
+ ), g = i.useCallback(() => {
66
+ b(R), b(S), b(L);
67
+ }, []), D = i.useCallback(() => {
68
+ g(), m(!1);
69
+ }, [g, m]), oe = i.useCallback(() => {
70
+ b(S);
71
+ const e = () => {
72
+ if (S.current = null, !(T.current || $())) {
73
+ if (G()) {
74
+ S.current = window.setTimeout(e, Ue);
75
+ return;
76
+ }
77
+ m(!1);
78
+ }
79
+ };
80
+ S.current = window.setTimeout(e, Ue);
81
+ }, [$, G, m]), Ze = () => {
82
+ T.current = !0, p && (b(S), !(a || A || _.current) && (b(R), R.current = window.setTimeout(function e() {
83
+ if (R.current = null, G()) {
84
+ R.current = window.setTimeout(e, qe);
85
+ return;
86
+ }
87
+ m(!0);
88
+ }, qe)));
89
+ }, en = () => {
90
+ T.current = !1, p && (_.current = !1, b(R), A && oe());
91
+ }, nn = () => {
92
+ b(L), !(!p || a || A || _.current) && (G() || (b(R), m(!0)));
93
+ }, tn = () => {
94
+ p && (b(L), L.current = window.setTimeout(() => {
95
+ L.current = null, document.activeElement !== document.body && (se() || (_.current = !1, !($() || T.current) && (G() || m(!1))));
96
+ }, On));
97
+ };
98
+ i.useEffect(() => {
99
+ if (!p || !A) return;
100
+ const e = (w) => {
101
+ const O = Pn(I.current, w.target);
102
+ if (T.current = O, O) {
103
+ b(S);
104
+ return;
105
+ }
106
+ S.current === null && oe();
107
+ }, n = () => {
108
+ T.current = !1, D();
109
+ }, r = () => D(), s = () => {
110
+ document.visibilityState === "hidden" && D();
111
+ }, d = (w) => {
112
+ w.key === "Escape" && ($() || D());
113
+ };
114
+ return document.addEventListener("mouseover", e), document.addEventListener("mouseleave", n), document.addEventListener("visibilitychange", s), window.addEventListener("blur", r), window.addEventListener("keydown", d), () => {
115
+ document.removeEventListener("mouseover", e), document.removeEventListener("mouseleave", n), document.removeEventListener("visibilitychange", s), window.removeEventListener("blur", r), window.removeEventListener("keydown", d);
116
+ };
117
+ }, [p, A, oe, D, $]), i.useEffect(() => g, [g]), i.useEffect(() => {
118
+ p || (g(), m(!1));
119
+ }, [p, g, m]);
120
+ const xe = i.useRef(a);
121
+ i.useEffect(() => {
122
+ const e = xe.current;
123
+ if (xe.current = a, !p) return;
124
+ if (a) {
125
+ g(), m(!1);
126
+ return;
127
+ }
128
+ if (!e) return;
129
+ _.current = T.current || se(), g(), m(!1);
130
+ const n = I.current, r = document.activeElement, s = r === document.body || r instanceof HTMLElement && r.dataset.sidebar === "pin";
131
+ n && s && n.querySelector(
132
+ '[data-sidebar="menu-button"], [data-sidebar="menu-sub-button"]'
133
+ )?.focus();
134
+ }, [a, p, g, se, m]);
135
+ const Ne = i.useRef(a), rn = i.useRef(Ye);
136
+ i.useEffect(() => {
137
+ const e = rn.current;
138
+ e === void 0 || e === a || H(e);
139
+ }, []), i.useEffect(() => {
140
+ Ne.current !== a && (Ne.current = a, we?.(a));
141
+ }, [a, we]);
142
+ const Se = i.useRef(null);
143
+ i.useEffect(() => {
144
+ const e = Se.current;
145
+ Se.current = C, C !== void 0 && C !== e && C !== a && H(C);
146
+ }, [C, a, H]);
147
+ const ce = i.useRef(null), Ee = i.useRef(0), ye = i.useRef(u);
148
+ ye.current !== u && (ye.current = u, Ee.current = ce.current?.scrollTop ?? 0), i.useLayoutEffect(() => {
149
+ const e = ce.current;
150
+ e && (e.scrollTop = Ee.current);
151
+ }, [u]);
152
+ const [sn, Re] = i.useState({}), ae = i.useMemo(
153
+ () => [...o, ...l ?? []].flatMap(
33
154
  (e) => e.items.filter(
34
- (r) => r.subItems?.length && (r.isActive || r.subItems.some((n) => n.isActive))
35
- ).map((r) => Z(e, r))
155
+ (n) => n.subItems?.length && (n.isActive || n.subItems.some((r) => r.isActive))
156
+ ).map((n) => He(e, n))
36
157
  ).join("|"),
37
- [i, a]
158
+ [o, l]
38
159
  );
39
- o.useEffect(() => {
40
- I && H((e) => {
41
- const r = I.split("|").filter((n) => e[n] === void 0);
42
- return r.length ? { ...e, ...Object.fromEntries(r.map((n) => [n, !0])) } : e;
160
+ i.useEffect(() => {
161
+ ae && Re((e) => {
162
+ const n = ae.split("|").filter((r) => e[r] === void 0);
163
+ return n.length ? { ...e, ...Object.fromEntries(n.map((r) => [r, !0])) } : e;
43
164
  });
44
- }, [I]);
45
- const $ = o.useRef(/* @__PURE__ */ new Map()), p = o.useRef(null), S = (e) => (r) => {
46
- r ? $.current.set(e, r) : $.current.delete(e);
165
+ }, [ae]);
166
+ const le = i.useRef(/* @__PURE__ */ new Map()), F = i.useRef(null), K = (e) => (n) => {
167
+ n ? le.current.set(e, n) : le.current.delete(e);
47
168
  };
48
- o.useLayoutEffect(() => {
49
- const e = p.current;
50
- !e || document.activeElement !== document.body || $.current.get(e)?.focus();
51
- }, [x]);
52
- const ne = b === "tab" && i.length > 1, N = o.useMemo(() => {
53
- const e = i.findIndex(
54
- (r) => r.items.some(
55
- (n) => n.isActive || n.subItems?.some((c) => c.isActive)
169
+ i.useLayoutEffect(() => {
170
+ const e = F.current;
171
+ !e || document.activeElement !== document.body || le.current.get(e)?.focus();
172
+ }, [u]);
173
+ const on = x === "tab" && o.length > 1, V = i.useMemo(() => {
174
+ const e = o.findIndex(
175
+ (n) => n.items.some(
176
+ (r) => r.isActive || r.subItems?.some((s) => s.isActive)
56
177
  )
57
178
  );
58
179
  return e === -1 ? null : e;
59
- }, [i]), [U, G] = o.useState(
60
- N ?? 0
180
+ }, [o]), [Te, de] = i.useState(
181
+ V ?? 0
61
182
  );
62
- o.useEffect(() => {
63
- N !== null && G(N);
64
- }, [N]);
65
- const A = U < i.length ? U : 0, w = (e) => {
66
- const r = T(e, "sm");
67
- return r || (g !== "icon" ? null : /* @__PURE__ */ t(
183
+ i.useEffect(() => {
184
+ V !== null && de(V);
185
+ }, [V]);
186
+ const z = Te < o.length ? Te : 0, ue = (e) => {
187
+ const n = Z(e, "sm");
188
+ return n || (N !== "icon" ? null : /* @__PURE__ */ t(
68
189
  "span",
69
190
  {
70
191
  "aria-hidden": "true",
71
- className: "flex size-4 shrink-0 items-center justify-center text-xs font-semibold uppercase opacity-0 transition-opacity group-data-[collapsible=icon]:opacity-100",
192
+ className: h(
193
+ "flex shrink-0 items-center justify-center text-xs font-semibold uppercase opacity-0 transition-opacity group-data-[collapsible=icon]:opacity-100",
194
+ _e.rail.fallbackGlyph
195
+ ),
72
196
  children: e.title.charAt(0)
73
197
  }
74
198
  ));
75
- }, ie = (e) => {
76
- const r = /* @__PURE__ */ s(E, { children: [
77
- T(e, "xs"),
78
- /* @__PURE__ */ t("span", { children: e.title })
199
+ }, cn = (e) => {
200
+ const n = M(e.badge, "full", e.title), r = /* @__PURE__ */ c(W, { children: [
201
+ Z(e, "xs"),
202
+ /* @__PURE__ */ t("span", { className: "min-w-0 flex-1 truncate", children: e.title }),
203
+ /* @__PURE__ */ t(B, { row: e, badge: n }),
204
+ P(n)
79
205
  ] });
80
- return u ? /* @__PURE__ */ t(X, { isActive: e.isActive, asChild: !0, children: /* @__PURE__ */ t(
81
- u,
206
+ return y ? /* @__PURE__ */ t(je, { isActive: e.isActive, asChild: !0, children: /* @__PURE__ */ t(
207
+ y,
82
208
  {
83
209
  href: e.url,
84
210
  className: "flex w-full items-center gap-2",
85
211
  "aria-current": e.isActive ? "page" : void 0,
86
- ...v,
212
+ ...j,
87
213
  children: r
88
214
  }
89
- ) }) : /* @__PURE__ */ t(X, { isActive: e.isActive, asChild: !0, children: /* @__PURE__ */ t(
215
+ ) }) : /* @__PURE__ */ t(je, { isActive: e.isActive, asChild: !0, children: /* @__PURE__ */ t(
90
216
  "a",
91
217
  {
92
218
  href: e.url,
@@ -95,294 +221,317 @@ function Oe({
95
221
  children: r
96
222
  }
97
223
  ) });
98
- }, se = (e) => {
99
- const r = /* @__PURE__ */ s(E, { children: [
100
- T(e, "xs"),
101
- /* @__PURE__ */ t("span", { children: e.title })
102
- ] }), n = d(
224
+ }, an = (e) => {
225
+ const n = M(e.badge, "full", e.title), r = /* @__PURE__ */ c(W, { children: [
226
+ Z(e, "xs"),
227
+ /* @__PURE__ */ t("span", { className: "min-w-0 flex-1 truncate", children: e.title }),
228
+ /* @__PURE__ */ t(B, { row: e, badge: n }),
229
+ P(n)
230
+ ] }), s = h(
103
231
  "flex w-full items-center gap-2",
104
- e.isActive && l.dropdownItem.selected
232
+ e.isActive && f.dropdownItem.selected
105
233
  );
106
- return /* @__PURE__ */ t(pe, { asChild: !0, children: u ? /* @__PURE__ */ t(
107
- u,
234
+ return /* @__PURE__ */ t(vn, { asChild: !0, children: y ? /* @__PURE__ */ t(
235
+ y,
108
236
  {
109
237
  href: e.url,
110
- className: n,
238
+ className: s,
111
239
  "aria-current": e.isActive ? "page" : void 0,
112
- ...v,
240
+ ...j,
113
241
  children: r
114
242
  }
115
243
  ) : /* @__PURE__ */ t(
116
244
  "a",
117
245
  {
118
246
  href: e.url,
119
- className: n,
247
+ className: s,
120
248
  "aria-current": e.isActive ? "page" : void 0,
121
249
  children: r
122
250
  }
123
- ) }, P(e));
124
- }, ce = (e, r) => {
125
- const n = Z(e, r), c = r.subItems ?? [], f = te[n] ?? !1, Y = `${re}-${n.replace(/[^\w-]+/g, "-")}-submenu`, M = /* @__PURE__ */ t("span", { className: "truncate", children: r.title });
126
- return c.length === 0 ? /* @__PURE__ */ t(D, { children: /* @__PURE__ */ t(
127
- _,
128
- {
129
- asChild: !0,
130
- isActive: r.isActive,
131
- tooltip: r.title,
132
- children: u ? /* @__PURE__ */ s(
133
- u,
251
+ ) }, Ke(e));
252
+ }, ln = (e, n) => {
253
+ const r = He(e, n), s = n.subItems ?? [], d = sn[r] ?? !1, w = `${Qe}-${r.replace(/[^\w-]+/g, "-")}-submenu`, O = u ? "dot" : "full", Ae = M(n.badge, O, n.title), Ie = Ae ?? ((u || !d) && Y(s) ? { kind: "dot" } : null), Oe = u ? M(n.badge, "full", n.title) : null, Pe = Oe?.kind === "text" ? `${n.title} · ${Oe.text}` : n.title, fe = /* @__PURE__ */ t("span", { className: "min-w-0 flex-1 truncate", children: n.title }), he = /* @__PURE__ */ t(B, { row: n, badge: Ae }), Be = u ? null : P(Ie), Le = u && Ie ? /* @__PURE__ */ t(me, { className: Ve }) : null;
254
+ if (s.length === 0) {
255
+ const E = /* @__PURE__ */ c(W, { children: [
256
+ ue(n),
257
+ fe,
258
+ he,
259
+ Be
260
+ ] });
261
+ return /* @__PURE__ */ c(be, { children: [
262
+ /* @__PURE__ */ t(ve, { asChild: !0, isActive: n.isActive, tooltip: Pe, children: y ? /* @__PURE__ */ t(
263
+ y,
134
264
  {
135
- href: r.url,
136
- "aria-current": r.isActive ? "page" : void 0,
137
- ...v,
138
- children: [
139
- w(r),
140
- M
141
- ]
265
+ href: n.url,
266
+ "aria-current": n.isActive ? "page" : void 0,
267
+ ...j,
268
+ children: E
142
269
  }
143
- ) : /* @__PURE__ */ s(
270
+ ) : /* @__PURE__ */ t(
144
271
  "a",
145
272
  {
146
- href: r.url,
147
- "aria-current": r.isActive ? "page" : void 0,
148
- children: [
149
- w(r),
150
- M
151
- ]
152
- }
153
- )
154
- }
155
- ) }, n) : x ? /* @__PURE__ */ t(D, { children: /* @__PURE__ */ s(j, { children: [
156
- /* @__PURE__ */ s(q, { modal: !1, children: [
157
- /* @__PURE__ */ t(J, { asChild: !0, children: /* @__PURE__ */ t(K, { asChild: !0, children: /* @__PURE__ */ s(
158
- _,
159
- {
160
- ref: S(n),
161
- type: "button",
162
- isActive: r.isActive,
163
- onFocus: () => {
164
- p.current = n;
165
- },
166
- children: [
167
- w(r),
168
- M
169
- ]
273
+ href: n.url,
274
+ "aria-current": n.isActive ? "page" : void 0,
275
+ children: E
170
276
  }
171
- ) }) }),
277
+ ) }),
278
+ Le
279
+ ] }, r);
280
+ }
281
+ return u ? /* @__PURE__ */ c(be, { children: [
282
+ /* @__PURE__ */ c(J, { children: [
283
+ /* @__PURE__ */ c($e, { modal: !1, children: [
284
+ /* @__PURE__ */ t(Ge, { asChild: !0, children: /* @__PURE__ */ t(Q, { asChild: !0, children: /* @__PURE__ */ c(
285
+ ve,
286
+ {
287
+ ref: K(r),
288
+ type: "button",
289
+ isActive: n.isActive,
290
+ onFocus: () => {
291
+ F.current = r;
292
+ },
293
+ children: [
294
+ ue(n),
295
+ fe,
296
+ he
297
+ ]
298
+ }
299
+ ) }) }),
300
+ /* @__PURE__ */ t(
301
+ De,
302
+ {
303
+ side: "right",
304
+ align: "start",
305
+ sideOffset: 8,
306
+ className: "min-w-48",
307
+ children: s.map(an)
308
+ }
309
+ )
310
+ ] }),
172
311
  /* @__PURE__ */ t(
173
- Q,
312
+ X,
174
313
  {
175
314
  side: "right",
176
- align: "start",
177
- sideOffset: 8,
178
- className: "min-w-48",
179
- children: c.map(se)
315
+ align: "center",
316
+ hidden: !u,
317
+ children: Pe
180
318
  }
181
319
  )
182
320
  ] }),
183
- /* @__PURE__ */ t(
184
- O,
185
- {
186
- side: "right",
187
- align: "center",
188
- hidden: !x,
189
- children: r.title
190
- }
191
- )
192
- ] }) }, n) : /* @__PURE__ */ s(D, { children: [
193
- /* @__PURE__ */ s(
194
- _,
321
+ Le
322
+ ] }, r) : /* @__PURE__ */ c(be, { children: [
323
+ /* @__PURE__ */ c(
324
+ ve,
195
325
  {
196
- ref: S(n),
326
+ ref: K(r),
197
327
  type: "button",
198
- isActive: r.isActive,
199
- tooltip: r.title,
200
- "aria-expanded": f,
201
- "aria-controls": Y,
328
+ isActive: n.isActive,
329
+ tooltip: n.title,
330
+ "aria-expanded": d,
331
+ "aria-controls": w,
202
332
  onFocus: () => {
203
- p.current = n;
333
+ F.current = r;
204
334
  },
205
- onClick: () => H((m) => ({ ...m, [n]: !m[n] })),
335
+ onClick: () => Re((E) => ({ ...E, [r]: !E[r] })),
206
336
  children: [
207
- w(r),
208
- M,
337
+ ue(n),
338
+ fe,
339
+ he,
340
+ Be,
209
341
  /* @__PURE__ */ t(
210
- k,
342
+ ne,
211
343
  {
212
- name: f ? "ChevronDown" : "ChevronRight",
213
- className: "text-d-muted-foreground ml-auto size-4 shrink-0 group-data-[collapsible=icon]:hidden"
344
+ name: "ChevronRight",
345
+ className: h(
346
+ "text-d-muted-foreground size-4 shrink-0 group-data-[collapsible=icon]:hidden",
347
+ "transition-transform motion-reduce:transition-none",
348
+ f.motion.duration,
349
+ f.motion.ease,
350
+ d && "rotate-90"
351
+ )
214
352
  }
215
353
  )
216
354
  ]
217
355
  }
218
356
  ),
219
- f && /* @__PURE__ */ t(Ae, { id: Y, children: c.map((m) => /* @__PURE__ */ t(we, { children: ie(m) }, P(m))) })
220
- ] }, n);
221
- }, y = (e, r = !0, n) => /* @__PURE__ */ s(
222
- z,
223
- {
224
- role: n ? "group" : void 0,
225
- "aria-label": n,
226
- children: [
227
- r && e.title && /* @__PURE__ */ t(xe, { children: e.title }),
228
- /* @__PURE__ */ t(Se, { children: /* @__PURE__ */ t(Ne, { children: e.items.map((c) => ce(e, c)) }) })
229
- ]
230
- },
231
- e.title
232
- ), R = (e) => {
233
- const r = T(e, "sm");
234
- return r || /* @__PURE__ */ t(
357
+ /* @__PURE__ */ t(
358
+ "div",
359
+ {
360
+ className: h(
361
+ "grid transition-[grid-template-rows,visibility] motion-reduce:transition-none",
362
+ f.motion.duration,
363
+ f.motion.ease,
364
+ d ? "visible grid-rows-[1fr]" : "invisible grid-rows-[0fr]"
365
+ ),
366
+ children: /* @__PURE__ */ t("div", { className: "overflow-hidden", children: /* @__PURE__ */ t(Rn, { id: w, children: s.map((E) => /* @__PURE__ */ t(Tn, { children: cn(E) }, Ke(E))) }) })
367
+ }
368
+ )
369
+ ] }, r);
370
+ }, q = (e, n = !0, r) => {
371
+ const s = u ? null : M(e.badge, "full", e.title);
372
+ return /* @__PURE__ */ c(
373
+ pe,
374
+ {
375
+ role: r ? "group" : void 0,
376
+ "aria-label": r,
377
+ children: [
378
+ n && e.title && /* @__PURE__ */ c(Sn, { children: [
379
+ /* @__PURE__ */ t("span", { className: "min-w-0 flex-1 truncate", children: e.title }),
380
+ /* @__PURE__ */ t(B, { row: e, badge: s }),
381
+ P(s)
382
+ ] }),
383
+ /* @__PURE__ */ t(En, { children: /* @__PURE__ */ t(yn, { children: e.items.map((d) => ln(e, d)) }) })
384
+ ]
385
+ },
386
+ e.title
387
+ );
388
+ }, U = (e) => {
389
+ const n = Z(e, "sm");
390
+ return n || /* @__PURE__ */ t(
235
391
  "span",
236
392
  {
237
393
  "aria-hidden": "true",
238
- className: "flex size-4 shrink-0 items-center justify-center text-xs font-semibold uppercase",
394
+ className: h(
395
+ "flex shrink-0 items-center justify-center text-xs font-semibold uppercase",
396
+ _e.rail.fallbackGlyph
397
+ ),
239
398
  children: e.title.charAt(0)
240
399
  }
241
400
  );
242
- }, ae = (e, r) => {
243
- const n = `${r} ${e.title}`, c = r === A, f = /* @__PURE__ */ s(
244
- Ce,
401
+ }, Me = (e) => e.items.some(
402
+ (n) => Y([n]) || Y(n.subItems)
403
+ ), dn = (e, n) => {
404
+ const r = `${n} ${e.title}`, s = n === z, d = M(
405
+ e.badge,
406
+ s ? "full" : "dot",
407
+ e.title
408
+ ), w = d ?? (!s && Me(e) ? { kind: "dot" } : null), O = /* @__PURE__ */ c(
409
+ An,
245
410
  {
246
- value: String(r),
247
- ref: c ? S(C) : void 0,
248
- onFocus: c ? () => {
249
- p.current = C;
411
+ value: String(n),
412
+ ref: s ? K(ee) : void 0,
413
+ onFocus: s ? () => {
414
+ F.current = ee;
250
415
  } : void 0,
251
- className: d(
416
+ className: h(
252
417
  "text-d-sidebar-foreground/70 h-8 min-w-0 flex-initial justify-start gap-0 p-2",
253
- // Overrides the `transition-all duration-200` the primitive inherits
254
- // from `focusRing`: `all` would also pick up the width the label
255
- // animation drives from the child, and 200ms/`ease-out` is not the
256
- // house curve.
257
- //
258
- // No `interaction.active` here. These tabs are styled as sidebar rows,
259
- // and no row in the sidebar squashes — `SidebarMenuButton` has no
260
- // press state at all, and `app-sidebar-mobile.tsx` turns the token
261
- // down in as many words ("that is the button squash, wrong on a list
262
- // row"). A tab that squashed above nav rows that do not would break
263
- // the rail's homogeneity, which is the same reason the icon-mode
264
- // selector button below refuses it.
418
+ // Overrides the `transition-all` inherited from `focusRing`: `all`
419
+ // would also pick up the width the label animation drives from the
420
+ // child. No `interaction.active` either — no sidebar row squashes.
265
421
  "transition-[box-shadow,background-color,border-color,color]",
266
- l.motion.duration,
267
- l.motion.ease,
268
- // Only the *unselected* tabs take a hover tint.
269
- // `hover:bg-d-sidebar-accent/50` has specificity 0-2-0 and so beat the
270
- // selected tab's own background, halving its alpha (0.4 -> 0.2): the
271
- // hover *lightened* the selected tab instead of darkening it. The
272
- // pointer query is the second half of the same fix — without it a tap
273
- // on a tablet (>= 768px, where this bar is rendered) leaves the hover
274
- // tint stuck on the tab it opened.
275
- !c && "[@media(hover:hover)_and_(pointer:fine)]:hover:bg-d-sidebar-accent/50 [@media(hover:hover)_and_(pointer:fine)]:hover:text-d-sidebar-accent-foreground",
276
- c && "bg-d-sidebar-accent text-d-sidebar-accent-foreground font-semibold shadow-none"
422
+ f.motion.duration,
423
+ f.motion.ease,
424
+ // Only the *unselected* tabs take a hover tint: unguarded it beat the
425
+ // selected tab's own background and *lightened* it. The pointer query
426
+ // keeps a tap on a tablet from leaving the tint stuck.
427
+ !s && "[@media(hover:hover)_and_(pointer:fine)]:hover:bg-d-sidebar-accent/50 [@media(hover:hover)_and_(pointer:fine)]:hover:text-d-sidebar-accent-foreground",
428
+ s && "bg-d-sidebar-accent text-d-sidebar-accent-foreground font-semibold shadow-none"
277
429
  ),
278
430
  children: [
279
- R(e),
431
+ w && !s ? /* @__PURE__ */ c("span", { className: "relative inline-flex shrink-0", children: [
432
+ U(e),
433
+ /* @__PURE__ */ t(me, { className: "absolute -top-0.5 -right-0.5" })
434
+ ] }) : U(e),
435
+ /* @__PURE__ */ t(B, { row: e, badge: d }),
280
436
  /* @__PURE__ */ t(
281
437
  "span",
282
438
  {
283
- className: d(
284
- // Deliberate exception: `grid-template-columns` is a layout
285
- // property, so this animation runs on the main thread and cannot be
286
- // composited. It is kept on purpose — it is the only CSS-only way to
287
- // animate to the *content's* width (`width: auto` is not
288
- // animatable), and the alternative is a JS measurement or a
289
- // `max-width` guess to keep in sync with the longest title. The cost
290
- // is bounded by there being a handful of tabs, each reflowing a
291
- // single text node. Do not "fix" this into a transform.
439
+ className: h(
440
+ // Deliberate exception: this animates a layout property on the
441
+ // main thread. It is the only CSS-only way to reach the *content's*
442
+ // width, and the cost is bounded by a handful of tabs. Do not
443
+ // "fix" it into a transform.
292
444
  "grid grid-cols-[0fr] transition-[grid-template-columns] motion-reduce:transition-none",
293
- l.motion.duration,
294
- l.motion.ease,
295
- c && "grid-cols-[1fr]"
445
+ f.motion.duration,
446
+ f.motion.ease,
447
+ s && "grid-cols-[1fr]"
296
448
  ),
297
- children: /* @__PURE__ */ t(
449
+ children: /* @__PURE__ */ c(
298
450
  "span",
299
451
  {
300
- className: d(
301
- // `text-ellipsis` needs all three of overflow/nowrap/ellipsis on
302
- // this box: it is the grid item, so the 0fr/1fr column is what
303
- // gives it the definite width the text overflows.
452
+ className: h(
453
+ // On this box because it is the grid item: the 0fr/1fr column is
454
+ // what gives it the definite width the text overflows.
304
455
  "overflow-hidden text-ellipsis whitespace-nowrap",
305
- // Clipping alone let the text slide out from under the icon with a
306
- // hard edge, so it fades. Asymmetric on purpose, and both halves
307
- // are timed against the *same* front-loaded curve the width uses —
308
- // which covers ~90% of its travel in the first quarter of its
309
- // 160ms, so "half the duration" would not have been half the
310
- // distance.
311
- // Exit: 60ms, no delay. Measured, the tab is ~91% shut 43ms in,
312
- // so anything slower leaves the text visibly under the closing
313
- // edge; at 60ms on this curve it is at ~2% opacity by then.
314
- // Entry: delayed 70ms, by which point the box is already ~88%
315
- // open. That delay doubles as the ellipsis mitigation — the
316
- // narrow "A…"/"Am…" intermediate states play out while the text
317
- // is still transparent.
456
+ // Asymmetric on purpose: the entry delay doubles as the ellipsis
457
+ // mitigation — the narrow "A…"/"Am…" intermediate states play out
458
+ // while the text is still transparent.
318
459
  "transition-opacity motion-reduce:transition-none",
319
- l.motion.ease,
320
- c ? "opacity-100 delay-[70ms] duration-[140ms]" : "opacity-0 delay-0 duration-[60ms]"
460
+ f.motion.ease,
461
+ s ? "opacity-100 delay-[70ms] duration-[140ms]" : "opacity-0 delay-0 duration-[60ms]"
321
462
  ),
322
- children: /* @__PURE__ */ t("span", { className: "pl-2", children: e.title })
463
+ children: [
464
+ /* @__PURE__ */ t("span", { className: "pl-2", children: e.title }),
465
+ s && P(w, "ml-1 align-middle")
466
+ ]
323
467
  }
324
468
  )
325
469
  }
326
470
  )
327
471
  ]
328
472
  },
329
- n
473
+ r
330
474
  );
331
- return /* @__PURE__ */ s(j, { children: [
332
- /* @__PURE__ */ t(K, { asChild: !0, children: f }),
333
- /* @__PURE__ */ t(O, { side: "right", align: "center", hidden: c, children: e.title })
334
- ] }, n);
335
- }, oe = () => {
336
- const e = i[A];
337
- return /* @__PURE__ */ s(E, { children: [
338
- /* @__PURE__ */ t(z, { className: "pb-0", children: /* @__PURE__ */ s(j, { children: [
339
- /* @__PURE__ */ s(q, { modal: !1, children: [
340
- /* @__PURE__ */ t(J, { asChild: !0, children: /* @__PURE__ */ t(K, { asChild: !0, children: /* @__PURE__ */ s(
475
+ return /* @__PURE__ */ c(J, { children: [
476
+ /* @__PURE__ */ t(Q, { asChild: !0, children: O }),
477
+ /* @__PURE__ */ t(X, { side: "right", align: "center", hidden: s, children: e.title })
478
+ ] }, r);
479
+ }, un = () => {
480
+ const e = o[z], n = o.some(
481
+ (r, s) => s !== z && (Y([r]) || Me(r))
482
+ );
483
+ return /* @__PURE__ */ c(W, { children: [
484
+ /* @__PURE__ */ t(pe, { className: "pb-0", children: /* @__PURE__ */ c(J, { children: [
485
+ /* @__PURE__ */ c($e, { modal: !1, children: [
486
+ /* @__PURE__ */ t(Ge, { asChild: !0, children: /* @__PURE__ */ t(Q, { asChild: !0, children: /* @__PURE__ */ c(
341
487
  "button",
342
488
  {
343
489
  type: "button",
344
- ref: S(C),
490
+ ref: K(ee),
345
491
  onFocus: () => {
346
- p.current = C;
492
+ F.current = ee;
347
493
  },
348
494
  "aria-label": `Navigation group: ${e.title}`,
349
- className: d(
495
+ className: h(
496
+ // The glyph's centre stays where the expanded
497
+ // `TabsTrigger` puts it, which is what makes the swap
498
+ // read as a change of shape instead of a jump.
499
+ // `relative` only anchors the badge dot — this button is
500
+ // not `overflow-hidden`.
501
+ "group/tab-selector relative flex h-10 w-8 cursor-pointer flex-col items-center gap-0 pt-1.5 pb-0.5",
350
502
  // Not `SidebarMenuButton`: in icon mode the primitive
351
- // forces `!size-8 !p-2`, which would flatten the
352
- // icon-over-chevron stack this button is.
353
- "group/tab-selector flex h-10 w-8 cursor-pointer flex-col items-center gap-0.5 pt-2 pb-0.5",
354
- // `renderGroupTabIcon` asks for `size="sm"` (20px) and
355
- // relies on the host to bring it down; expanded, that host
356
- // is `TabsTrigger`. Without the same rule here the icon
357
- // rendered 20px wide and was squashed to 16 tall by the
358
- // column — measured, and visibly distorted. `:not([class*='size-'])`
359
- // is what keeps it off the chevron's own `size-3`.
360
- "[&_svg:not([class*='size-'])]:size-4",
503
+ // forces a `!size-8` square, which would flatten the
504
+ // icon-over-chevron stack this button is — so the rail's
505
+ // 20px glyph is restated here rather than inherited from
506
+ // `navTokens.rail.button`. `:not([class*='size-'])` is
507
+ // what keeps the rule off the chevron's own `size-3`.
508
+ "[&_svg:not([class*='size-'])]:size-5",
361
509
  // Same surface as the selected tab when expanded, so the
362
510
  // swap reads as a change of shape, not of state.
363
511
  "bg-d-sidebar-accent text-d-sidebar-accent-foreground font-semibold",
364
- l.radius.default,
365
- l.focusRing
512
+ f.radius.default,
513
+ f.focusRing
366
514
  ),
367
515
  children: [
368
- R(e),
516
+ U(e),
369
517
  /* @__PURE__ */ t(
370
- k,
518
+ ne,
371
519
  {
372
520
  name: "ChevronDown",
373
- className: d(
521
+ className: h(
374
522
  "text-d-sidebar-foreground/70 size-3 shrink-0 transition-colors",
375
523
  "group-hover/tab-selector:text-d-sidebar-accent-foreground",
376
524
  "group-data-[state=open]/tab-selector:text-d-sidebar-accent-foreground",
377
525
  "animate-in fade-in motion-reduce:animate-none motion-reduce:transition-none"
378
526
  )
379
527
  }
380
- )
528
+ ),
529
+ n && /* @__PURE__ */ t(me, { className: Ve })
381
530
  ]
382
531
  }
383
532
  ) }) }),
384
533
  /* @__PURE__ */ t(
385
- Q,
534
+ De,
386
535
  {
387
536
  side: "right",
388
537
  align: "start",
@@ -390,78 +539,132 @@ function Oe({
390
539
  "aria-label": "Navigation groups",
391
540
  className: "max-w-64 min-w-48",
392
541
  children: /* @__PURE__ */ t(
393
- ue,
542
+ pn,
394
543
  {
395
- value: String(A),
396
- onValueChange: (r) => G(Number(r)),
397
- children: i.map((r, n) => /* @__PURE__ */ s(
398
- he,
399
- {
400
- value: String(n),
401
- className: "cursor-pointer gap-2 [&>svg]:size-4",
402
- children: [
403
- R(r),
404
- /* @__PURE__ */ t("span", { className: "truncate", children: r.title })
405
- ]
406
- },
407
- `${n} ${r.title}`
408
- ))
544
+ value: String(z),
545
+ onValueChange: (r) => de(Number(r)),
546
+ children: o.map((r, s) => {
547
+ const d = M(
548
+ r.badge,
549
+ "full",
550
+ r.title
551
+ );
552
+ return /* @__PURE__ */ c(
553
+ bn,
554
+ {
555
+ value: String(s),
556
+ className: "cursor-pointer gap-2 [&>svg]:size-4",
557
+ children: [
558
+ U(r),
559
+ /* @__PURE__ */ t("span", { className: "min-w-0 flex-1 truncate", children: r.title }),
560
+ /* @__PURE__ */ t(B, { row: r, badge: d }),
561
+ P(d)
562
+ ]
563
+ },
564
+ `${s} ${r.title}`
565
+ );
566
+ })
409
567
  }
410
568
  )
411
569
  }
412
570
  )
413
571
  ] }),
414
- /* @__PURE__ */ t(O, { side: "right", align: "center", children: e.title })
572
+ /* @__PURE__ */ t(X, { side: "right", align: "center", children: e.title })
415
573
  ] }) }),
416
- /* @__PURE__ */ t(ve, {}),
417
- y(e, !1, e.title)
574
+ /* @__PURE__ */ t(Nn, {}),
575
+ q(e, !1, e.title)
418
576
  ] });
419
- }, le = () => /* @__PURE__ */ s(
420
- ye,
577
+ }, fn = () => /* @__PURE__ */ c(
578
+ Mn,
421
579
  {
422
- value: String(A),
423
- onValueChange: (e) => G(Number(e)),
580
+ value: String(z),
581
+ onValueChange: (e) => de(Number(e)),
424
582
  className: "gap-0",
425
583
  children: [
426
- /* @__PURE__ */ t(z, { className: "pb-0", children: /* @__PURE__ */ t(
427
- Me,
584
+ /* @__PURE__ */ t(pe, { className: "pb-0", children: /* @__PURE__ */ t(
585
+ Cn,
428
586
  {
429
- className: d(
430
- // `justify-start`: tabs are sized by their content now, not stretched
431
- // to equal widths, so the row packs to the left and the space the
432
- // selected tab does not need stays empty.
587
+ className: h(
588
+ // Tabs are sized by their content, not stretched to equal widths.
433
589
  "h-auto w-full justify-start gap-1 bg-transparent p-0"
434
- // 3rem of rail leaves no room for a row of tabs: they stack into an
435
- // icon-only strip instead of falling back to a flat list, so the
436
- // "one group at a time" model survives the collapse.
437
590
  ),
438
- children: i.map((e, r) => ae(e, r))
591
+ children: o.map((e, n) => dn(e, n))
439
592
  }
440
593
  ) }),
441
- i.map((e, r) => /* @__PURE__ */ t(Te, { value: String(r), children: y(e, !1) }, `${r} ${e.title}`))
594
+ o.map((e, n) => /* @__PURE__ */ t(kn, { value: String(n), children: q(e, !1) }, `${n} ${e.title}`))
442
595
  ]
443
596
  }
444
- );
445
- return V ? /* @__PURE__ */ t(W, { collapsible: g, ...F, children: /* @__PURE__ */ t(
446
- de,
597
+ ), Ce = a ? "Collapse sidebar to icons" : "Keep sidebar open", ke = (e) => /* @__PURE__ */ c(J, { children: [
598
+ /* @__PURE__ */ t(Q, { asChild: !0, children: /* @__PURE__ */ t(
599
+ "button",
600
+ {
601
+ type: "button",
602
+ "data-sidebar": "pin",
603
+ "aria-label": Ce,
604
+ "aria-hidden": e ? void 0 : !0,
605
+ tabIndex: e ? void 0 : -1,
606
+ onClick: () => H(!a),
607
+ className: h(
608
+ "text-d-sidebar-foreground/70 hover:bg-d-sidebar-accent hover:text-d-sidebar-accent-foreground flex size-8 shrink-0 cursor-pointer items-center justify-center",
609
+ f.radius.default,
610
+ f.focusRing,
611
+ !e && "pointer-events-none opacity-0"
612
+ ),
613
+ children: /* @__PURE__ */ t(ne, { name: a ? "PinOff" : "Pin", size: "xs" })
614
+ }
615
+ ) }),
616
+ /* @__PURE__ */ t(X, { side: "bottom", align: "end", children: Ce })
617
+ ] }), hn = () => {
618
+ if (!p)
619
+ return v ? /* @__PURE__ */ t(ze, { children: v }) : null;
620
+ const e = A || a, n = te === "right";
621
+ return /* @__PURE__ */ t(ze, { children: /* @__PURE__ */ c("div", { className: "flex items-center gap-2", children: [
622
+ n && ke(e),
623
+ /* @__PURE__ */ t("div", { className: "min-w-0 flex-1", children: v }),
624
+ !n && ke(e)
625
+ ] }) });
626
+ };
627
+ return ie ? /* @__PURE__ */ t(Fe, { collapsible: N, side: te, ...k, children: /* @__PURE__ */ t(
628
+ mn,
447
629
  {
448
- navigation: i,
449
- navigationFooter: a,
450
- headerContent: h,
451
- footerContent: B,
452
- linkComponent: u,
453
- linkProps: v
630
+ navigation: o,
631
+ navigationFooter: l,
632
+ headerContent: v,
633
+ footerContent: ge,
634
+ linkComponent: y,
635
+ linkProps: j
454
636
  }
455
- ) }) : /* @__PURE__ */ s(W, { collapsible: g, ...F, children: [
456
- h && /* @__PURE__ */ t(me, { children: h }),
457
- /* @__PURE__ */ t(be, { children: ne ? x ? oe() : le() : i.map(
458
- (e) => y(e, i.length > 1)
459
- ) }),
460
- a?.map((e) => y(e)),
461
- B,
462
- L && /* @__PURE__ */ t(ge, {})
463
- ] });
637
+ ) }) : /* @__PURE__ */ c(
638
+ Fe,
639
+ {
640
+ ref: I,
641
+ collapsible: N,
642
+ side: te,
643
+ ...k,
644
+ onMouseEnter: (e) => {
645
+ k.onMouseEnter?.(e), Ze();
646
+ },
647
+ onMouseLeave: (e) => {
648
+ k.onMouseLeave?.(e), en();
649
+ },
650
+ onFocus: (e) => {
651
+ k.onFocus?.(e), nn();
652
+ },
653
+ onBlur: (e) => {
654
+ k.onBlur?.(e), tn();
655
+ },
656
+ children: [
657
+ hn(),
658
+ /* @__PURE__ */ t(wn, { ref: ce, children: on ? u ? un() : fn() : o.map(
659
+ (e) => q(e, o.length > 1)
660
+ ) }),
661
+ l?.map((e) => q(e)),
662
+ ge,
663
+ We && /* @__PURE__ */ t(xn, {})
664
+ ]
665
+ }
666
+ );
464
667
  }
465
668
  export {
466
- Oe as AppSidebar
669
+ Un as AppSidebar
467
670
  };