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.
- package/dist/CHANGELOG.md +25 -0
- package/dist/_virtual/index3.js +5 -5
- package/dist/_virtual/index4.js +5 -5
- package/dist/_virtual/index5.js +4 -4
- package/dist/agent-docs/adoption-report.json +26 -24
- package/dist/agent-docs/components/AppBottomNav.md +180 -49
- package/dist/agent-docs/components/AppSidebar.md +504 -11
- package/dist/agent-docs/components/Sidebar.md +72 -1
- package/dist/agent-docs/components-list.md +3 -2
- package/dist/agent-docs/manifest.json +52 -15
- package/dist/components/design-tokens.js +0 -64
- package/dist/components/nav-tokens.js +41 -0
- package/dist/components/ui/app-bottom-nav.js +125 -130
- package/dist/components/ui/app-sidebar-mobile.js +119 -104
- package/dist/components/ui/app-sidebar.js +516 -313
- package/dist/components/ui/nav-badge.js +66 -0
- package/dist/components/ui/sidebar.js +272 -207
- package/dist/index.d.ts +122 -29
- package/dist/node_modules/eventemitter3/index.js +1 -1
- package/dist/node_modules/hast-util-to-jsx-runtime/lib/index.js +1 -1
- package/dist/node_modules/recharts/es6/util/Events.js +1 -1
- package/dist/node_modules/unified/lib/index.js +1 -1
- package/dist/styles.v3.css +1 -1
- package/package.json +1 -1
|
@@ -1,159 +1,154 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import * as
|
|
4
|
-
import { designTokens as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
import { jsxs as d, jsx as n, Fragment as J } from "react/jsx-runtime";
|
|
3
|
+
import * as Q from "react";
|
|
4
|
+
import { designTokens as U } from "../design-tokens.js";
|
|
5
|
+
import { navTokens as T } from "../nav-tokens.js";
|
|
6
|
+
import { Icon as V } from "./icon.js";
|
|
7
|
+
import { warnOnce as i, someRowBadged as _, normalizeNavBadge as W, NavBadgeOverlay as Y, NavBadgeDot as w, NavBadgeSrLabel as Z } from "./nav-badge.js";
|
|
8
|
+
import { useSidebar as ee } from "./sidebar.js";
|
|
9
|
+
import { cn as r } from "../../lib/utils.js";
|
|
10
|
+
const O = 6, $ = (a) => `${a.url} ${a.title}`, A = (a) => !!a.isActive || !!a.subItems?.some((o) => o.isActive), te = "md:hidden shrink-0 overflow-hidden bg-d-card border-d-border rounded-t-lg border-t pb-[env(safe-area-inset-bottom)]", ae = "flex items-stretch p-1", g = r(
|
|
11
11
|
// `min-h-11` (44px) written out rather than `sizes.touch`: that token also
|
|
12
|
-
// carries `px-4`, and 16px of horizontal padding inside a ~61px
|
|
13
|
-
// leave 29px for the label. `min-h-`, never `h-`: a cell must be
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
// `py-1.5` when the icon dropped to 16px, deliberately: `py-2` would have held
|
|
18
|
-
// the bar at the 59px it had with a 20px glyph, and a lower bar was the point
|
|
19
|
-
// of the smaller glyph, not a side effect of it. 12px of vertical padding
|
|
20
|
-
// around 34px of content (16 + 2 + 16) puts the pill at 46px.
|
|
12
|
+
// carries `px-4` and `text-sm`, and 16px of horizontal padding inside a ~61px
|
|
13
|
+
// cell would leave 29px for the label. `min-h-`, never `h-`: a cell must be
|
|
14
|
+
// able to grow. `cursor-pointer` because v4's preflight sets
|
|
15
|
+
// `cursor: default` on `<button>`, so without it the Menu cell would feel
|
|
16
|
+
// inert next to the `<a>` cells.
|
|
21
17
|
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
// bearing. `flex-1` alone is `1 1 0%`, which distributes the row evenly only
|
|
34
|
-
// as long as no cell's content forces it wider: a flex item's automatic
|
|
35
|
-
// minimum size is its min-content width, so a cell whose contents cannot
|
|
36
|
-
// shrink below the fair share silently takes more than it and every other
|
|
37
|
-
// cell takes less. Here that floor is 24px — a `shrink-0` 16px icon plus
|
|
38
|
-
// `px-1` — and the narrowest cell the budget produces is 52px (six cells at
|
|
39
|
-
// 320px), so today the row is even by arithmetic. `min-w-0` makes it even by
|
|
40
|
-
// construction instead, at any width and whatever a cell holds, which is what
|
|
41
|
-
// the row's rhythm actually depends on. The label shrinks in exchange
|
|
42
|
-
// (`w-full truncate`, whose `overflow-hidden` already floors its own
|
|
43
|
-
// min-content size at 0) — the label is the right thing to spend.
|
|
44
|
-
"flex min-h-11 min-w-0 flex-1 cursor-pointer flex-col items-center justify-center gap-0.5 px-1 py-1.5 text-xs",
|
|
45
|
-
// The radius goes on every cell, not only the marked one: it costs nothing
|
|
46
|
-
// while the fill is transparent, and it keeps the hover and press surfaces of
|
|
47
|
-
// an inactive cell the same shape as the pill they can become.
|
|
48
|
-
u.navItem.basePill,
|
|
49
|
-
u.focusRing,
|
|
50
|
-
// `ring-inset` is still right, for a new reason: the cells now touch each
|
|
51
|
-
// other, not the dock's clipped corners, so a 3px outset ring would not be
|
|
52
|
-
// shaved — it would spill over the neighbouring cell and read as if two cells
|
|
53
|
-
// were focused.
|
|
18
|
+
// `min-w-0` beside `flex-1` is the equal-width guarantee: a flex item's
|
|
19
|
+
// automatic minimum size is its min-content width, so without it a cell whose
|
|
20
|
+
// contents cannot shrink below the fair share takes more than it and every
|
|
21
|
+
// other cell takes less. The label is what gives way instead.
|
|
22
|
+
"flex min-h-11 min-w-0 flex-1 cursor-pointer flex-col items-center justify-center gap-0.5 px-1 py-2.5 text-xs",
|
|
23
|
+
// On every cell, not only the marked one: it keeps the hover and press
|
|
24
|
+
// surfaces of an inactive cell the same shape as the pill they can become.
|
|
25
|
+
T.item.basePill,
|
|
26
|
+
U.focusRing,
|
|
27
|
+
// `ring-inset` because the cells touch each other: an outset ring would spill
|
|
28
|
+
// over the neighbour and read as if two cells were focused.
|
|
54
29
|
"focus-visible:ring-inset"
|
|
55
|
-
),
|
|
30
|
+
), h = r(
|
|
56
31
|
"text-d-foreground font-medium",
|
|
57
32
|
"[@media(hover:hover)_and_(pointer:fine)]:hover:bg-d-sidebar-accent [@media(hover:hover)_and_(pointer:fine)]:hover:text-d-sidebar-accent-foreground",
|
|
58
33
|
"active:bg-d-sidebar-accent active:text-d-sidebar-accent-foreground"
|
|
59
|
-
),
|
|
60
|
-
/* @__PURE__ */
|
|
61
|
-
|
|
34
|
+
), M = T.item.selectedPill, P = "relative flex size-5 shrink-0 items-center justify-center", c = (a, o) => /* @__PURE__ */ d("span", { className: P, children: [
|
|
35
|
+
/* @__PURE__ */ n(V, { name: a, size: "sm", className: "shrink-0" }),
|
|
36
|
+
o
|
|
37
|
+
] }), ne = (a, o) => /* @__PURE__ */ d("span", { className: r(P, "[&>svg]:size-full"), children: [
|
|
38
|
+
a,
|
|
39
|
+
o
|
|
40
|
+
] }), oe = "-top-1 -right-1.5", S = "absolute -top-1 -right-1", N = (a, o, m) => /* @__PURE__ */ d(J, { children: [
|
|
41
|
+
a,
|
|
42
|
+
/* @__PURE__ */ n("span", { className: "w-full truncate text-center", children: o }),
|
|
43
|
+
m
|
|
62
44
|
] });
|
|
63
|
-
function
|
|
64
|
-
items:
|
|
65
|
-
showMenu:
|
|
66
|
-
menuLabel:
|
|
67
|
-
ariaLabel:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
45
|
+
function pe({
|
|
46
|
+
items: a,
|
|
47
|
+
showMenu: o = !0,
|
|
48
|
+
menuLabel: m = "Menu",
|
|
49
|
+
ariaLabel: j = "Main navigation",
|
|
50
|
+
menuIcon: p = "Menu",
|
|
51
|
+
menuBadge: D = !1,
|
|
52
|
+
linkComponent: x,
|
|
53
|
+
linkProps: z = {},
|
|
54
|
+
className: E,
|
|
55
|
+
...R
|
|
73
56
|
}) {
|
|
74
|
-
const { openMobile:
|
|
75
|
-
if (
|
|
76
|
-
const e =
|
|
77
|
-
|
|
78
|
-
`AppBottomNav: ${
|
|
57
|
+
const { openMobile: I, setOpenMobile: B, mobileNavTarget: F, setMobileNavTarget: C } = ee(), u = o ? O - 1 : O, l = a.slice(0, u), v = a.slice(u);
|
|
58
|
+
if (v.length > 0) {
|
|
59
|
+
const e = v.map((t) => `"${t.title}"`).join(", ");
|
|
60
|
+
i(
|
|
61
|
+
`AppBottomNav: ${a.length} items passed, ${u} slots available. Dropped: ${e}.`
|
|
79
62
|
);
|
|
80
63
|
}
|
|
81
|
-
const
|
|
82
|
-
for (const e of
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
`AppBottomNav: duplicate item "${
|
|
86
|
-
),
|
|
64
|
+
const L = /* @__PURE__ */ new Set();
|
|
65
|
+
for (const e of l) {
|
|
66
|
+
const t = $(e);
|
|
67
|
+
L.has(t) && i(
|
|
68
|
+
`AppBottomNav: duplicate item "${t}" — one of them is ignored.`
|
|
69
|
+
), L.add(t);
|
|
87
70
|
}
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
`AppBottomNav: more than one active item — "${
|
|
71
|
+
const b = l.findIndex(A);
|
|
72
|
+
l.filter(A).length > 1 && i(
|
|
73
|
+
`AppBottomNav: more than one active item — "${l[b].title}" wins.`
|
|
91
74
|
);
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
75
|
+
const K = D || _(v), G = (() => {
|
|
76
|
+
const e = K ? /* @__PURE__ */ n(w, { className: S }) : null;
|
|
77
|
+
if (typeof p == "string") return c(p, e);
|
|
78
|
+
const t = p();
|
|
79
|
+
return t == null ? c("Menu", e) : ne(t, e);
|
|
80
|
+
})(), k = (e) => {
|
|
81
|
+
const t = W(e.badge, "compact", e.title), s = /* @__PURE__ */ n(Z, { row: e, badge: t });
|
|
82
|
+
return t?.kind === "text" ? {
|
|
83
|
+
visual: /* @__PURE__ */ n(Y, { text: t.text, className: oe }),
|
|
84
|
+
srLabel: s
|
|
85
|
+
} : t?.kind === "dot" || _(e.subItems) ? { visual: /* @__PURE__ */ n(w, { className: S }), srLabel: s } : { visual: null, srLabel: s };
|
|
86
|
+
}, X = (e, t) => {
|
|
87
|
+
const s = {
|
|
88
|
+
className: r(
|
|
89
|
+
g,
|
|
90
|
+
t ? M : h
|
|
97
91
|
),
|
|
98
92
|
"data-slot": "app-bottom-nav-item",
|
|
99
|
-
"data-active":
|
|
93
|
+
"data-active": t ? "true" : void 0,
|
|
100
94
|
// Not set unconditionally: `truncate` does not alter the text node, so
|
|
101
|
-
// the full title is already in the accessibility tree
|
|
102
|
-
// `aria-label` is dead weight.
|
|
95
|
+
// the full title is already in the accessibility tree.
|
|
103
96
|
"aria-label": e.ariaLabel,
|
|
104
|
-
"aria-current":
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
"
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
97
|
+
"aria-current": t ? "page" : void 0
|
|
98
|
+
}, { visual: f, srLabel: H } = k(e), y = N(
|
|
99
|
+
c(e.iconName, f),
|
|
100
|
+
e.title,
|
|
101
|
+
H
|
|
102
|
+
);
|
|
103
|
+
return x ? /* @__PURE__ */ n(x, { href: e.url, ...s, ...z, children: y }) : /* @__PURE__ */ n("a", { href: e.url, ...s, children: y });
|
|
104
|
+
}, q = (e, t) => {
|
|
105
|
+
const { visual: s, srLabel: f } = k(e);
|
|
106
|
+
return (
|
|
107
|
+
// A button is not a page, so no `aria-current` even when the indicator is
|
|
108
|
+
// here. No `aria-controls` — the drill panel's id is Radix-generated and
|
|
109
|
+
// unreachable from the bar — and no `aria-haspopup`, which would promise
|
|
110
|
+
// arrow-key menu semantics the drill-down does not implement.
|
|
111
|
+
/* @__PURE__ */ n(
|
|
112
|
+
"button",
|
|
113
|
+
{
|
|
114
|
+
type: "button",
|
|
115
|
+
"data-slot": "app-bottom-nav-item",
|
|
116
|
+
"data-active": t ? "true" : void 0,
|
|
117
|
+
"aria-label": e.ariaLabel,
|
|
118
|
+
"aria-expanded": I && F === e.title,
|
|
119
|
+
className: r(
|
|
120
|
+
g,
|
|
121
|
+
t ? M : h
|
|
122
|
+
),
|
|
123
|
+
onClick: () => {
|
|
124
|
+
C(e.title), B(!0);
|
|
125
|
+
},
|
|
126
|
+
children: N(c(e.iconName, s), e.title, f)
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
return l.length === 0 && !o ? (i(
|
|
133
132
|
"AppBottomNav: no items and showMenu={false} — nothing to render, the bar is omitted."
|
|
134
|
-
), null) : /* @__PURE__ */
|
|
133
|
+
), null) : /* @__PURE__ */ n(
|
|
135
134
|
"div",
|
|
136
135
|
{
|
|
137
136
|
"data-slot": "app-bottom-nav",
|
|
138
|
-
className:
|
|
139
|
-
...
|
|
140
|
-
children: /* @__PURE__ */
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
className: r(te, E),
|
|
138
|
+
...R,
|
|
139
|
+
children: /* @__PURE__ */ d("nav", { "aria-label": j, className: ae, children: [
|
|
140
|
+
l.map((e, t) => /* @__PURE__ */ n(Q.Fragment, { children: e.subItems?.length ? q(e, t === b) : X(e, t === b) }, $(e))),
|
|
141
|
+
o && /* @__PURE__ */ n(
|
|
143
142
|
"button",
|
|
144
143
|
{
|
|
145
144
|
type: "button",
|
|
146
145
|
"data-slot": "app-bottom-nav-item",
|
|
147
|
-
"
|
|
148
|
-
|
|
149
|
-
className: i(
|
|
150
|
-
m,
|
|
151
|
-
x ? v : p
|
|
152
|
-
),
|
|
146
|
+
"aria-expanded": I,
|
|
147
|
+
className: r(g, h),
|
|
153
148
|
onClick: () => {
|
|
154
|
-
|
|
149
|
+
C(null), B(!0);
|
|
155
150
|
},
|
|
156
|
-
children:
|
|
151
|
+
children: N(G, m)
|
|
157
152
|
}
|
|
158
153
|
)
|
|
159
154
|
] })
|
|
@@ -161,5 +156,5 @@ function J({
|
|
|
161
156
|
);
|
|
162
157
|
}
|
|
163
158
|
export {
|
|
164
|
-
|
|
159
|
+
pe as AppBottomNav
|
|
165
160
|
};
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as n, jsxs as
|
|
3
|
-
import * as
|
|
4
|
-
import { designTokens as
|
|
2
|
+
import { jsx as n, jsxs as u, Fragment as L } from "react/jsx-runtime";
|
|
3
|
+
import * as i from "react";
|
|
4
|
+
import { designTokens as h } from "../design-tokens.js";
|
|
5
|
+
import { navTokens as j } from "../nav-tokens.js";
|
|
5
6
|
import { Icon as R } from "./icon.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import { normalizeNavBadge as D, renderInlineNavBadge as G, NavBadgeSrLabel as O, someRowBadged as Y } from "./nav-badge.js";
|
|
8
|
+
import { useSidebar as Z } from "./sidebar.js";
|
|
9
|
+
import { cn as f } from "../../lib/utils.js";
|
|
10
|
+
const v = (t, l) => `${t} ${l.url} ${l.title}`, _ = (t, l, a) => {
|
|
9
11
|
if (!t) return null;
|
|
10
|
-
for (const
|
|
11
|
-
const
|
|
12
|
-
(
|
|
12
|
+
for (const d of [...l, ...a ?? []]) {
|
|
13
|
+
const c = d.items.find(
|
|
14
|
+
(p) => p.title === t && p.subItems?.length
|
|
13
15
|
);
|
|
14
|
-
if (
|
|
16
|
+
if (c) return { key: v(d.title, c), item: c };
|
|
15
17
|
}
|
|
16
18
|
return console.warn(
|
|
17
19
|
`AppSidebarMobile: no navigation item with sub-items titled "${t}" — opening at level 0.`
|
|
18
20
|
), null;
|
|
19
|
-
},
|
|
21
|
+
}, ee = (t) => t.defaultPrevented || t.metaKey || t.ctrlKey || t.shiftKey || t.altKey || t.button !== 0, M = f(
|
|
20
22
|
"flex w-full items-center gap-3 text-left",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
h.sizes.touch,
|
|
24
|
+
j.item.base,
|
|
25
|
+
h.focusRing,
|
|
24
26
|
// The card clips its children (`overflow-hidden` is what keeps the rounded
|
|
25
27
|
// corners on the first and last row), so an outset ring would be cut off.
|
|
26
28
|
"focus-visible:ring-inset",
|
|
@@ -28,134 +30,143 @@ const v = (t, i) => `${t} ${i.url} ${i.title}`, V = (t, i, a) => {
|
|
|
28
30
|
// state is the only immediate feedback a finger gets. Not
|
|
29
31
|
// `interaction.active` — that is the button squash, wrong on a list row.
|
|
30
32
|
"active:bg-d-accent"
|
|
31
|
-
),
|
|
33
|
+
), T = (t) => t ? j.item.selected : h.interaction.hover, te = "text-d-foreground flex items-center px-4 pb-2 text-xs font-semibold tracking-wide uppercase", $ = f(
|
|
32
34
|
"divide-d-border border-d-border bg-d-card divide-y overflow-hidden border",
|
|
33
|
-
|
|
34
|
-
),
|
|
35
|
+
h.radius.lg
|
|
36
|
+
), ne = (t) => {
|
|
35
37
|
if (t.icon) {
|
|
36
|
-
const
|
|
37
|
-
return /* @__PURE__ */ n(
|
|
38
|
+
const l = t.icon;
|
|
39
|
+
return /* @__PURE__ */ n(l, { className: "size-5 shrink-0" });
|
|
38
40
|
}
|
|
39
41
|
return t.iconName ? /* @__PURE__ */ n(R, { name: t.iconName, size: "sm", className: "shrink-0" }) : null;
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
}, E = (t) => !!t.iconName || !!t.icon, y = (t, { showIconColumn: l, hasChildren: a }) => {
|
|
43
|
+
const d = D(t.badge, "full", t.title), c = d ?? (a && Y("subItems" in t ? t.subItems : void 0) ? { kind: "dot" } : null);
|
|
44
|
+
return /* @__PURE__ */ u(L, { children: [
|
|
45
|
+
l && (ne(t) ?? // Empty placeholder, not an initial: on a wide row the label is right
|
|
46
|
+
// there, so an initial would only add noise. Desktop icon mode needs
|
|
47
|
+
// the fallback because there the icon is the only affordance.
|
|
48
|
+
/* @__PURE__ */ n("span", { "aria-hidden": "true", className: "size-5 shrink-0" })),
|
|
49
|
+
/* @__PURE__ */ n("span", { className: "flex-1", children: t.title }),
|
|
50
|
+
/* @__PURE__ */ n(O, { row: t, badge: d }),
|
|
51
|
+
G(c),
|
|
52
|
+
a && /* @__PURE__ */ n(
|
|
53
|
+
R,
|
|
54
|
+
{
|
|
55
|
+
name: "ChevronRight",
|
|
56
|
+
size: "sm",
|
|
57
|
+
className: "text-d-muted-foreground shrink-0"
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
] });
|
|
61
|
+
};
|
|
62
|
+
function de({
|
|
56
63
|
navigation: t,
|
|
57
|
-
navigationFooter:
|
|
64
|
+
navigationFooter: l,
|
|
58
65
|
headerContent: a,
|
|
59
|
-
footerContent:
|
|
60
|
-
linkComponent:
|
|
61
|
-
linkProps:
|
|
66
|
+
footerContent: d,
|
|
67
|
+
linkComponent: c,
|
|
68
|
+
linkProps: p = {}
|
|
62
69
|
}) {
|
|
63
|
-
const { openMobile:
|
|
64
|
-
() =>
|
|
65
|
-
), [
|
|
66
|
-
|
|
70
|
+
const { openMobile: B, setOpenMobile: P, mobileNavTarget: q } = Z(), [r, x] = i.useState(
|
|
71
|
+
() => _(q, t, l)
|
|
72
|
+
), [F, N] = i.useState(!1), g = i.useRef(!0), C = (!!r || F) && !(g.current && r);
|
|
73
|
+
i.useEffect(() => {
|
|
67
74
|
g.current = !1;
|
|
68
|
-
}, []),
|
|
69
|
-
|
|
70
|
-
}, [
|
|
71
|
-
const
|
|
75
|
+
}, []), i.useEffect(() => {
|
|
76
|
+
B || (x(null), N(!1));
|
|
77
|
+
}, [B]);
|
|
78
|
+
const w = i.useRef(null), k = i.useRef(/* @__PURE__ */ new Map()), I = i.useRef(null), H = (e) => (s) => {
|
|
72
79
|
s ? k.current.set(e, s) : k.current.delete(e);
|
|
73
80
|
};
|
|
74
|
-
|
|
81
|
+
i.useLayoutEffect(() => {
|
|
75
82
|
if (r) {
|
|
76
83
|
if (g.current) return;
|
|
77
|
-
|
|
84
|
+
w.current?.focus();
|
|
78
85
|
return;
|
|
79
86
|
}
|
|
80
|
-
const e =
|
|
81
|
-
e && (
|
|
87
|
+
const e = I.current;
|
|
88
|
+
e && (I.current = null, k.current.get(e)?.focus());
|
|
82
89
|
}, [r]);
|
|
83
|
-
const
|
|
90
|
+
const J = (e) => {
|
|
84
91
|
N(!1), x(e);
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
},
|
|
88
|
-
const
|
|
89
|
-
|
|
92
|
+
}, Q = () => {
|
|
93
|
+
I.current = r?.key ?? null, N(!0), x(null);
|
|
94
|
+
}, S = (e, s) => {
|
|
95
|
+
const b = f(M, T(e.isActive)), o = (m) => {
|
|
96
|
+
ee(m) || P(!1);
|
|
90
97
|
};
|
|
91
|
-
return
|
|
92
|
-
|
|
98
|
+
return c ? /* @__PURE__ */ n(
|
|
99
|
+
c,
|
|
93
100
|
{
|
|
94
101
|
href: e.url,
|
|
95
|
-
className:
|
|
102
|
+
className: b,
|
|
96
103
|
"aria-current": e.isActive ? "page" : void 0,
|
|
97
104
|
onClick: o,
|
|
98
|
-
...
|
|
99
|
-
children:
|
|
105
|
+
...p,
|
|
106
|
+
children: y(e, s)
|
|
100
107
|
}
|
|
101
108
|
) : /* @__PURE__ */ n(
|
|
102
109
|
"a",
|
|
103
110
|
{
|
|
104
111
|
href: e.url,
|
|
105
|
-
className:
|
|
112
|
+
className: b,
|
|
106
113
|
"aria-current": e.isActive ? "page" : void 0,
|
|
107
114
|
onClick: o,
|
|
108
|
-
children:
|
|
115
|
+
children: y(e, s)
|
|
109
116
|
}
|
|
110
117
|
);
|
|
111
|
-
},
|
|
112
|
-
const o = v(e.title, s),
|
|
113
|
-
return
|
|
118
|
+
}, U = (e, s, b) => {
|
|
119
|
+
const o = v(e.title, s), m = !!s.subItems?.length, K = { showIconColumn: b, hasChildren: m }, W = s.isActive || !!s.subItems?.some((X) => X.isActive);
|
|
120
|
+
return m ? /* @__PURE__ */ n(
|
|
114
121
|
"button",
|
|
115
122
|
{
|
|
116
|
-
ref:
|
|
123
|
+
ref: H(o),
|
|
117
124
|
type: "button",
|
|
118
|
-
className:
|
|
119
|
-
onClick: () =>
|
|
120
|
-
children:
|
|
125
|
+
className: f(M, T(W)),
|
|
126
|
+
onClick: () => J({ key: o, item: s }),
|
|
127
|
+
children: y(s, K)
|
|
121
128
|
}
|
|
122
|
-
) :
|
|
123
|
-
},
|
|
124
|
-
const
|
|
125
|
-
return /* @__PURE__ */
|
|
126
|
-
s && e.title && /* @__PURE__ */
|
|
127
|
-
|
|
129
|
+
) : S(s, K);
|
|
130
|
+
}, A = (e, s = !0) => {
|
|
131
|
+
const b = e.items.some(E), o = D(e.badge, "full", e.title);
|
|
132
|
+
return /* @__PURE__ */ u("section", { children: [
|
|
133
|
+
s && e.title && /* @__PURE__ */ u("h3", { className: te, children: [
|
|
134
|
+
/* @__PURE__ */ n("span", { className: "min-w-0 flex-1", children: e.title }),
|
|
135
|
+
/* @__PURE__ */ n(O, { row: e, badge: o }),
|
|
136
|
+
G(o)
|
|
137
|
+
] }),
|
|
138
|
+
/* @__PURE__ */ n("ul", { className: $, children: e.items.map((m) => /* @__PURE__ */ n("li", { children: U(e, m, b) }, v(e.title, m))) })
|
|
128
139
|
] }, e.title);
|
|
129
|
-
}, z = r?.item.subItems ?? [],
|
|
140
|
+
}, z = r?.item.subItems ?? [], V = z.some(E);
|
|
130
141
|
return /* @__PURE__ */ n(
|
|
131
142
|
"div",
|
|
132
143
|
{
|
|
133
144
|
"data-slot": "app-sidebar-mobile",
|
|
134
|
-
className:
|
|
145
|
+
className: f(
|
|
135
146
|
"bg-d-muted text-d-foreground flex min-h-0 flex-1 flex-col",
|
|
136
147
|
// The home indicator overlaps the bottom of the viewport, and
|
|
137
148
|
// `footerContent` is the last thing in the panel — so the reserve lives
|
|
138
149
|
// here, not on the scroll area above it.
|
|
139
150
|
"pb-[max(1rem,env(safe-area-inset-bottom))]"
|
|
140
151
|
),
|
|
141
|
-
children: /* @__PURE__ */
|
|
142
|
-
r ? /* @__PURE__ */
|
|
152
|
+
children: /* @__PURE__ */ u("div", { className: "flex min-h-0 w-full flex-1 flex-col sm:mx-auto sm:max-w-md", children: [
|
|
153
|
+
r ? /* @__PURE__ */ u(
|
|
143
154
|
"div",
|
|
144
155
|
{
|
|
145
156
|
"data-sidebar": "header",
|
|
146
|
-
className: "border-d-border shrink-0 border-b pb-2",
|
|
157
|
+
className: "border-d-border shrink-0 border-b pr-12 pb-2",
|
|
147
158
|
children: [
|
|
148
|
-
/* @__PURE__ */ n("div", { className: "p-2", children: /* @__PURE__ */
|
|
159
|
+
/* @__PURE__ */ n("div", { className: "p-2", children: /* @__PURE__ */ u(
|
|
149
160
|
"button",
|
|
150
161
|
{
|
|
151
162
|
type: "button",
|
|
152
163
|
"aria-label": "Back to menu",
|
|
153
|
-
onClick:
|
|
154
|
-
className:
|
|
164
|
+
onClick: Q,
|
|
165
|
+
className: f(
|
|
155
166
|
"flex min-h-11 items-center gap-1 pr-3 pl-2",
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
167
|
+
h.radius.default,
|
|
168
|
+
h.focusRing,
|
|
169
|
+
h.interaction.hover,
|
|
159
170
|
"active:bg-d-accent"
|
|
160
171
|
),
|
|
161
172
|
children: [
|
|
@@ -167,7 +178,7 @@ function se({
|
|
|
167
178
|
/* @__PURE__ */ n(
|
|
168
179
|
"h2",
|
|
169
180
|
{
|
|
170
|
-
ref:
|
|
181
|
+
ref: w,
|
|
171
182
|
tabIndex: -1,
|
|
172
183
|
className: "px-4 text-base font-semibold outline-none",
|
|
173
184
|
children: r.item.title
|
|
@@ -175,46 +186,50 @@ function se({
|
|
|
175
186
|
)
|
|
176
187
|
]
|
|
177
188
|
}
|
|
178
|
-
) : a &&
|
|
179
|
-
/* @__PURE__ */ n("div", { "data-sidebar": "header", className: "shrink-0 px-4 py-2", children: a }),
|
|
189
|
+
) : a && /* @__PURE__ */ n("div", { "data-sidebar": "header", className: "shrink-0 px-12 py-2", children: a }),
|
|
180
190
|
/* @__PURE__ */ n(
|
|
181
191
|
"nav",
|
|
182
192
|
{
|
|
183
|
-
className:
|
|
184
|
-
|
|
193
|
+
className: f(
|
|
194
|
+
// A column, so the footer block can claim the leftover space with
|
|
195
|
+
// `mt-auto` and sit at the bottom the way the desktop panel's does.
|
|
196
|
+
"flex min-h-0 flex-1 flex-col space-y-6 overflow-y-auto overscroll-contain px-4 pb-4",
|
|
185
197
|
// The sheet's close button floats over the top-right corner. A
|
|
186
198
|
// header (or the back bar) sits under it and gets `pr-12`; with
|
|
187
199
|
// neither, the list itself has to clear its 52px.
|
|
188
200
|
r || a ? "pt-3" : "pt-14",
|
|
189
|
-
|
|
190
|
-
|
|
201
|
+
C && "animate-in fade-in-0 duration-200 motion-reduce:animate-none",
|
|
202
|
+
C && (r ? "slide-in-from-right-4" : "slide-in-from-left-4")
|
|
191
203
|
),
|
|
192
204
|
children: r ? (
|
|
193
205
|
// One card, no group heading: the level's title is already in the
|
|
194
206
|
// back bar.
|
|
195
|
-
/* @__PURE__ */ n("ul", { className:
|
|
196
|
-
showIconColumn:
|
|
207
|
+
/* @__PURE__ */ n("ul", { className: $, children: z.map((e) => /* @__PURE__ */ n("li", { children: S(e, {
|
|
208
|
+
showIconColumn: V,
|
|
197
209
|
hasChildren: !1
|
|
198
210
|
}) }, v(r.key, e))) })
|
|
199
|
-
) : /* @__PURE__ */
|
|
211
|
+
) : /* @__PURE__ */ u(L, { children: [
|
|
200
212
|
t.map(
|
|
201
|
-
(e) =>
|
|
213
|
+
(e) => A(e, t.length > 1)
|
|
202
214
|
),
|
|
203
|
-
|
|
215
|
+
l?.length ? (
|
|
204
216
|
// Detached by a wider gap: the "system" block at the bottom of a
|
|
205
217
|
// native Settings list. `pt-6` on top of the `space-y-6` — 8px
|
|
206
|
-
// read as an accident, not as a separation.
|
|
207
|
-
|
|
218
|
+
// read as an accident, not as a separation. `mt-auto` eats the
|
|
219
|
+
// leftover height when the list is short, so the block lands at
|
|
220
|
+
// the bottom of the panel; with a long list it resolves to 0 and
|
|
221
|
+
// the block just scrolls after the last group.
|
|
222
|
+
/* @__PURE__ */ n("div", { className: "mt-auto space-y-6 pt-6", children: l.map((e) => A(e)) })
|
|
208
223
|
) : null
|
|
209
224
|
] })
|
|
210
225
|
},
|
|
211
226
|
r ? `level-1 ${r.key}` : "level-0"
|
|
212
227
|
),
|
|
213
|
-
|
|
228
|
+
d
|
|
214
229
|
] })
|
|
215
230
|
}
|
|
216
231
|
);
|
|
217
232
|
}
|
|
218
233
|
export {
|
|
219
|
-
|
|
234
|
+
de as AppSidebarMobile
|
|
220
235
|
};
|