@neuronection/assistant-ui 0.14.0 → 0.15.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.
- package/CHANGELOG.md +42 -0
- package/README.md +2 -0
- package/dist/chip-input.d.ts +2 -0
- package/dist/chip-input.js +1 -1
- package/dist/chunk-535TM7SK.js +119 -0
- package/dist/chunk-535TM7SK.js.map +1 -0
- package/dist/chunk-EZTQMJ5I.js +428 -0
- package/dist/chunk-EZTQMJ5I.js.map +1 -0
- package/dist/{chunk-TPLQL62V.js → chunk-HIRR2F4R.js} +42 -5
- package/dist/chunk-HIRR2F4R.js.map +1 -0
- package/dist/{chunk-UIUALJNR.js → chunk-PSFJN7WH.js} +12 -7
- package/dist/chunk-PSFJN7WH.js.map +1 -0
- package/dist/{chunk-JWAX2AOO.js → chunk-XSJ3TWWZ.js} +43 -3
- package/dist/chunk-XSJ3TWWZ.js.map +1 -0
- package/dist/{chunk-WA7Q4TTA.js → chunk-YIGLULRG.js} +3 -3
- package/dist/{chunk-WA7Q4TTA.js.map → chunk-YIGLULRG.js.map} +1 -1
- package/dist/context-menu.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/menu.d.ts +7 -1
- package/dist/menu.js +1 -1
- package/dist/scale-slider.js +1 -1
- package/dist/sidebar-nav.d.ts +62 -0
- package/dist/sidebar-nav.js +3 -0
- package/dist/sidebar-nav.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/user-menu.d.ts +30 -0
- package/dist/user-menu.js +3 -0
- package/dist/user-menu.js.map +1 -0
- package/package.json +9 -1
- package/dist/chunk-JWAX2AOO.js.map +0 -1
- package/dist/chunk-TPLQL62V.js.map +0 -1
- package/dist/chunk-UIUALJNR.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @neuronection/assistant-ui
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`e7a75e3`](https://github.com/neuronection/assistant-ui/commit/e7a75e3a3970e01f7bdcaf9060f54abe145d5a27) Thanks [@constLiakos](https://github.com/constLiakos)! - ChipInput: the typed draft now renders as a dashed pending chip
|
|
8
|
+
(`data-pending` on the container while a draft exists) so it is visually
|
|
9
|
+
explicit that each entry is its own separate item, and a new `hint` prop
|
|
10
|
+
renders helper text below the field wired to the input via
|
|
11
|
+
`aria-describedby` — use it to spell out the "press Enter or Add after each
|
|
12
|
+
one" contract.
|
|
13
|
+
|
|
14
|
+
- [`163e5e4`](https://github.com/neuronection/assistant-ui/commit/163e5e4f13d5a097dea56727447fe7e1070e3395) Thanks [@constLiakos](https://github.com/constLiakos)! - ScaleSlider: modern track + thumb (filled progress, larger thumb, visible
|
|
15
|
+
focus ring) via new `styles.css` range rules scoped to
|
|
16
|
+
`[data-as='scale-slider']`; low/high labels are larger and readable
|
|
17
|
+
(text-xs, medium weight, muted color) instead of 9px uppercase.
|
|
18
|
+
|
|
19
|
+
ChipInput: new `addLabel` prop renders an explicit add button that commits
|
|
20
|
+
the draft (disabled while empty, re-focuses the input) — makes the
|
|
21
|
+
multi-entry affordance discoverable without keyboard knowledge.
|
|
22
|
+
|
|
23
|
+
- [`3826518`](https://github.com/neuronection/assistant-ui/commit/3826518fd86f03cbef56344bec9b34b2234086c9) Thanks [@constLiakos](https://github.com/constLiakos)! - New `SidebarNav` component: the family-standard vertical navigation panel
|
|
24
|
+
(groups + section dividers, icons, badges, controlled `activeId`, optional
|
|
25
|
+
collapsed icon rail with hover flyouts, header/footer slots). Fully
|
|
26
|
+
presentational + controlled per ADR-006 — routing, role filtering and i18n
|
|
27
|
+
stay app-side. Ships with keyboard-nav + axe assertions, Ladle stories and
|
|
28
|
+
a docs page; adoption across the family apps is tracked in the nav
|
|
29
|
+
primitives program (family ADR-0007).
|
|
30
|
+
|
|
31
|
+
- [`3df9ac1`](https://github.com/neuronection/assistant-ui/commit/3df9ac1dbc90079cf1910e34bd213f63e700688b) Thanks [@constLiakos](https://github.com/constLiakos)! - `SidebarNav`: top-level `NavItem` entries now accept `section` — a divider
|
|
32
|
+
label rendered above the item (first occurrence only) so flat sidebars can
|
|
33
|
+
group their entries visually without nested expand/collapse. Sections are
|
|
34
|
+
ignored in the collapsed rail. (Career's sidebar adoption is the first
|
|
35
|
+
consumer; matches the existing child-level `section` dividers.)
|
|
36
|
+
|
|
37
|
+
- [`3826518`](https://github.com/neuronection/assistant-ui/commit/3826518fd86f03cbef56344bec9b34b2234086c9) Thanks [@constLiakos](https://github.com/constLiakos)! - New `UserMenu` component: the family-standard user menu (avatar or
|
|
38
|
+
initials-disc trigger with name/email, identity header in the panel, item
|
|
39
|
+
model with `tone: 'danger'`, `pending`, and checkable items for
|
|
40
|
+
theme/language toggles). Built on the `Menu` primitives; also adds
|
|
41
|
+
`MenuCheckboxItem` (Radix checkbox menu item with an indicator) to the
|
|
42
|
+
menu module. Health's hand-rolled header dropdown and career's plain
|
|
43
|
+
sign-out button are the adoption targets (family ADR-0007 program).
|
|
44
|
+
|
|
3
45
|
## 0.14.0
|
|
4
46
|
|
|
5
47
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -86,6 +86,8 @@ Visual reference: [gallery](https://neuronection.github.io/assistant-ui/).
|
|
|
86
86
|
| [`info-button`](./docs/components/info-button.md) / [`field-label`](./docs/components/field-label.md) / [`copy-button`](./docs/components/copy-button.md) / [`breadcrumbs`](./docs/components/breadcrumbs.md) | `InfoButton` · `FieldLabel` · `CopyButton` (clipboard + copied state) · `Breadcrumbs` (SPA links via `linkComponent`) | [stories](https://neuronection.github.io/assistant-ui/?story=phase2--copy-buttons) |
|
|
87
87
|
| [`ai-button`](./docs/components/ai-button.md) / [`ai-actions-dropdown`](./docs/components/ai-actions-dropdown.md) / [`ai-magic-fill`](./docs/components/ai-magic-fill.md) | AI affordances: ask-with-suggestions (controlled open, icon-only mode) · action menu + custom prompt · describe-in-words fill modal — API calls stay app-side | [stories](https://neuronection.github.io/assistant-ui/?story=ai-patterns--ai-buttons) |
|
|
88
88
|
| [`settings-shell`](./docs/components/settings-shell.md) / [`provider-form`](./docs/components/provider-form.md) / [`connection-test-row`](./docs/components/connection-test-row.md) | `SettingsShell` (controlled two-pane nav) · `ProviderForm` (write-only API-key field) · `ConnectionTestRow` (idle/testing/ok/fail + latency, `inline` variant + meta slot) | [stories](https://neuronection.github.io/assistant-ui/?story=settings-trio--provider-form-story) |
|
|
89
|
+
| [`sidebar-nav`](./docs/components/sidebar-nav.md) | `SidebarNav` (family-standard vertical nav: groups + sections, badges, controlled active id, optional collapsed icon rail with hover flyouts, header/footer slots) | [stories](https://neuronection.github.io/assistant-ui/?story=sidebar-nav--groups-story) |
|
|
90
|
+
| [`user-menu`](./docs/components/user-menu.md) | `UserMenu` (avatar/identity trigger + action menu incl. checkable items; composed over `Menu`) | [stories](https://neuronection.github.io/assistant-ui/?story=user-menu--checkable-items-story) |
|
|
89
91
|
| [`model-picker`](./docs/components/model-picker.md) / [`task-assignment-picker`](./docs/components/task-assignment-picker.md) / [`capability-chips`](./docs/components/capability-chips.md) | `ModelPicker` (grouped provider→model combobox, capability chips) · `TaskAssignmentPicker` (task → model mapping rows, capability-filtered, sections + fallback assignment, meta slot) · `CapabilityChips` (cap toggle group / badges, min-selected) | [stories](https://neuronection.github.io/assistant-ui/?story=model-assignment--task-assignment-v2-story) |
|
|
90
92
|
| [`model-registry`](./docs/components/model-registry.md) | `ModelRegistry` (provider cards → registered model rows; add/edit in one catalog modal fed by app-fetched remote models; manual id entry; add-all of pending ids) | [stories](https://neuronection.github.io/assistant-ui/?story=model-registry--model-registry-story) |
|
|
91
93
|
| [`upload-dropzone`](./docs/components/upload-dropzone.md) / [`file-card`](./docs/components/file-card.md) / [`file-queue`](./docs/components/file-queue.md) | file attachment surface: dropzone (block/row) · card (status, include toggle) · queue (summary + reorder) | [stories](https://neuronection.github.io/assistant-ui/?story=file-surface--dropzones) |
|
package/dist/chip-input.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ interface ChipInputProps extends Omit<React.ComponentProps<'div'>, 'onChange'> {
|
|
|
7
7
|
separators?: string[];
|
|
8
8
|
inputLabel?: string;
|
|
9
9
|
removeLabel?: string;
|
|
10
|
+
addLabel?: string;
|
|
11
|
+
hint?: string;
|
|
10
12
|
disabled?: boolean;
|
|
11
13
|
}
|
|
12
14
|
declare const ChipInput: React.ForwardRefExoticComponent<Omit<ChipInputProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
package/dist/chip-input.js
CHANGED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Menu, MenuTrigger, MenuContent, MenuSeparator, MenuCheckboxItem, MenuItem } from './chunk-XSJ3TWWZ.js';
|
|
2
|
+
import { cn } from './chunk-BLJWR4ZV.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function deriveInitials(name) {
|
|
7
|
+
if (!name) return "";
|
|
8
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
9
|
+
if (parts.length === 0) return "";
|
|
10
|
+
const first = parts[0]?.charAt(0) ?? "";
|
|
11
|
+
const last = parts.length > 1 ? parts[parts.length - 1]?.charAt(0) ?? "" : "";
|
|
12
|
+
return (first + last).toUpperCase();
|
|
13
|
+
}
|
|
14
|
+
function UserGlyph() {
|
|
15
|
+
return /* @__PURE__ */ jsxs(
|
|
16
|
+
"svg",
|
|
17
|
+
{
|
|
18
|
+
viewBox: "0 0 24 24",
|
|
19
|
+
fill: "none",
|
|
20
|
+
stroke: "currentColor",
|
|
21
|
+
strokeWidth: "2",
|
|
22
|
+
strokeLinecap: "round",
|
|
23
|
+
strokeLinejoin: "round",
|
|
24
|
+
className: "size-4",
|
|
25
|
+
"aria-hidden": true,
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "8", r: "4" }),
|
|
28
|
+
/* @__PURE__ */ jsx("path", { d: "M4 21c0-4 3.6-6 8-6s8 2 8 6" })
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
var UserMenu = React.forwardRef(
|
|
34
|
+
function UserMenu2({
|
|
35
|
+
name,
|
|
36
|
+
email,
|
|
37
|
+
avatarUrl,
|
|
38
|
+
initials,
|
|
39
|
+
items,
|
|
40
|
+
onItemSelect,
|
|
41
|
+
align = "end",
|
|
42
|
+
labels,
|
|
43
|
+
className
|
|
44
|
+
}, ref) {
|
|
45
|
+
const disc = initials ?? deriveInitials(name);
|
|
46
|
+
const hasIdentity = name !== void 0 || email !== void 0;
|
|
47
|
+
return /* @__PURE__ */ jsx("div", { ref, "data-as": "user-menu", className: cn("inline-flex", className), children: /* @__PURE__ */ jsxs(Menu, { children: [
|
|
48
|
+
/* @__PURE__ */ jsxs(
|
|
49
|
+
MenuTrigger,
|
|
50
|
+
{
|
|
51
|
+
type: "button",
|
|
52
|
+
"aria-label": labels?.openMenu ?? "Open user menu",
|
|
53
|
+
"aria-haspopup": "menu",
|
|
54
|
+
className: "flex cursor-pointer items-center gap-2.5 rounded-full p-1 pr-3 transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]",
|
|
55
|
+
children: [
|
|
56
|
+
avatarUrl ? /* @__PURE__ */ jsx(
|
|
57
|
+
"img",
|
|
58
|
+
{
|
|
59
|
+
src: avatarUrl,
|
|
60
|
+
alt: "",
|
|
61
|
+
className: "size-8 shrink-0 rounded-full object-cover"
|
|
62
|
+
}
|
|
63
|
+
) : /* @__PURE__ */ jsx(
|
|
64
|
+
"span",
|
|
65
|
+
{
|
|
66
|
+
"aria-hidden": true,
|
|
67
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-full bg-[var(--as-primary)] text-xs font-bold text-[var(--as-primary-fg)]",
|
|
68
|
+
children: disc || /* @__PURE__ */ jsx(UserGlyph, {})
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
name || email ? /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col text-left leading-tight", children: [
|
|
72
|
+
name ? /* @__PURE__ */ jsx("span", { className: "max-w-40 truncate text-sm font-medium text-[var(--as-fg)]", children: name }) : null,
|
|
73
|
+
email ? /* @__PURE__ */ jsx("span", { className: "max-w-40 truncate text-xs text-[var(--as-muted-fg)]", children: email }) : null
|
|
74
|
+
] }) : null
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
/* @__PURE__ */ jsxs(MenuContent, { align, sideOffset: 8, className: "min-w-48", children: [
|
|
79
|
+
hasIdentity ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
80
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col px-2 py-1.5", children: [
|
|
81
|
+
name ? /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-bold text-[var(--as-fg)]", children: name }) : null,
|
|
82
|
+
email ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-[var(--as-muted-fg)]", children: email }) : null
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ jsx(MenuSeparator, {})
|
|
85
|
+
] }) : null,
|
|
86
|
+
items.map(
|
|
87
|
+
(item) => item.checked !== void 0 ? /* @__PURE__ */ jsx(
|
|
88
|
+
MenuCheckboxItem,
|
|
89
|
+
{
|
|
90
|
+
icon: item.icon,
|
|
91
|
+
danger: item.tone === "danger",
|
|
92
|
+
disabled: item.disabled,
|
|
93
|
+
pending: item.pending,
|
|
94
|
+
checked: item.checked,
|
|
95
|
+
onSelect: () => onItemSelect(item.id),
|
|
96
|
+
children: item.label
|
|
97
|
+
},
|
|
98
|
+
item.id
|
|
99
|
+
) : /* @__PURE__ */ jsx(
|
|
100
|
+
MenuItem,
|
|
101
|
+
{
|
|
102
|
+
icon: item.icon,
|
|
103
|
+
danger: item.tone === "danger",
|
|
104
|
+
disabled: item.disabled,
|
|
105
|
+
pending: item.pending,
|
|
106
|
+
onSelect: () => onItemSelect(item.id),
|
|
107
|
+
children: item.label
|
|
108
|
+
},
|
|
109
|
+
item.id
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
] })
|
|
113
|
+
] }) });
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
export { UserMenu };
|
|
118
|
+
//# sourceMappingURL=chunk-535TM7SK.js.map
|
|
119
|
+
//# sourceMappingURL=chunk-535TM7SK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/user-menu/UserMenu.tsx"],"names":["UserMenu"],"mappings":"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","file":"chunk-535TM7SK.js","sourcesContent":["import * as React from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport {\n Menu,\n MenuCheckboxItem,\n MenuContent,\n MenuItem,\n MenuSeparator,\n MenuTrigger,\n} from '../menu/Menu'\nimport { cn } from '../../lib/utils'\n\nexport interface UserMenuItem {\n id: string\n label: string\n icon?: LucideIcon\n tone?: 'default' | 'danger'\n disabled?: boolean\n pending?: boolean\n /** Renders as a checkable item (aria-checked) — e.g. theme/language toggles. */\n checked?: boolean\n}\n\nexport interface UserMenuProps {\n name?: string\n email?: string\n avatarUrl?: string\n /** Fallback disc text when no avatarUrl; derived from `name` when omitted. */\n initials?: string\n items: UserMenuItem[]\n onItemSelect: (id: string) => void\n align?: 'start' | 'end'\n labels?: { openMenu?: string }\n className?: string\n}\n\nfunction deriveInitials(name?: string): string {\n if (!name) return ''\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n if (parts.length === 0) return ''\n const first = parts[0]?.charAt(0) ?? ''\n const last = parts.length > 1 ? (parts[parts.length - 1]?.charAt(0) ?? '') : ''\n return (first + last).toUpperCase()\n}\n\nfunction UserGlyph() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"size-4\"\n aria-hidden\n >\n <circle cx=\"12\" cy=\"8\" r=\"4\" />\n <path d=\"M4 21c0-4 3.6-6 8-6s8 2 8 6\" />\n </svg>\n )\n}\n\nexport const UserMenu = React.forwardRef<HTMLDivElement, UserMenuProps>(\n function UserMenu(\n {\n name,\n email,\n avatarUrl,\n initials,\n items,\n onItemSelect,\n align = 'end',\n labels,\n className,\n },\n ref,\n ) {\n const disc = initials ?? deriveInitials(name)\n const hasIdentity = name !== undefined || email !== undefined\n\n return (\n <div ref={ref} data-as=\"user-menu\" className={cn('inline-flex', className)}>\n <Menu>\n <MenuTrigger\n type=\"button\"\n aria-label={labels?.openMenu ?? 'Open user menu'}\n aria-haspopup=\"menu\"\n className=\"flex cursor-pointer items-center gap-2.5 rounded-full p-1 pr-3 transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n {avatarUrl ? (\n <img\n src={avatarUrl}\n alt=\"\"\n className=\"size-8 shrink-0 rounded-full object-cover\"\n />\n ) : (\n <span\n aria-hidden\n className=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-[var(--as-primary)] text-xs font-bold text-[var(--as-primary-fg)]\"\n >\n {disc || <UserGlyph />}\n </span>\n )}\n {name || email ? (\n <span className=\"flex min-w-0 flex-col text-left leading-tight\">\n {name ? (\n <span className=\"max-w-40 truncate text-sm font-medium text-[var(--as-fg)]\">\n {name}\n </span>\n ) : null}\n {email ? (\n <span className=\"max-w-40 truncate text-xs text-[var(--as-muted-fg)]\">\n {email}\n </span>\n ) : null}\n </span>\n ) : null}\n </MenuTrigger>\n <MenuContent align={align} sideOffset={8} className=\"min-w-48\">\n {hasIdentity ? (\n <>\n <div className=\"flex flex-col px-2 py-1.5\">\n {name ? (\n <span className=\"truncate text-sm font-bold text-[var(--as-fg)]\">\n {name}\n </span>\n ) : null}\n {email ? (\n <span className=\"truncate text-xs text-[var(--as-muted-fg)]\">\n {email}\n </span>\n ) : null}\n </div>\n <MenuSeparator />\n </>\n ) : null}\n {items.map((item) =>\n item.checked !== undefined ? (\n <MenuCheckboxItem\n key={item.id}\n icon={item.icon}\n danger={item.tone === 'danger'}\n disabled={item.disabled}\n pending={item.pending}\n checked={item.checked}\n onSelect={() => onItemSelect(item.id)}\n >\n {item.label}\n </MenuCheckboxItem>\n ) : (\n <MenuItem\n key={item.id}\n icon={item.icon}\n danger={item.tone === 'danger'}\n disabled={item.disabled}\n pending={item.pending}\n onSelect={() => onItemSelect(item.id)}\n >\n {item.label}\n </MenuItem>\n ),\n )}\n </MenuContent>\n </Menu>\n </div>\n )\n },\n)\n"]}
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import { cn } from './chunk-BLJWR4ZV.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
4
|
+
import { ChevronRight, ChevronLeft, ChevronDown } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var FLYOUT_DELAY_MS = 150;
|
|
8
|
+
var itemButtonClass = (active) => cn(
|
|
9
|
+
"flex w-full cursor-pointer items-center gap-3 rounded-[var(--as-radius)] px-3 py-2.5 text-left text-sm transition-colors focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)] disabled:pointer-events-none disabled:opacity-50",
|
|
10
|
+
active ? "bg-[color-mix(in_srgb,var(--as-primary)_12%,transparent)] font-bold text-[var(--as-primary)]" : "font-medium text-[var(--as-fg)] hover:bg-[var(--as-muted)]"
|
|
11
|
+
);
|
|
12
|
+
var flyoutContentClass = "as-anim-pop z-[var(--as-z-popover)] min-w-44 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-1 text-[var(--as-fg)] shadow-[var(--as-shadow-3)] focus:outline-none";
|
|
13
|
+
function Badge({ value, active }) {
|
|
14
|
+
return /* @__PURE__ */ jsx(
|
|
15
|
+
"span",
|
|
16
|
+
{
|
|
17
|
+
className: cn(
|
|
18
|
+
"inline-flex min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 py-0.5 text-[11px] font-bold leading-none",
|
|
19
|
+
active ? "bg-[var(--as-primary)] text-[var(--as-primary-fg)]" : "bg-[var(--as-muted)] text-[var(--as-muted-fg)]"
|
|
20
|
+
),
|
|
21
|
+
children: value
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
function ItemBadge({ badge, active }) {
|
|
26
|
+
if (badge === void 0) return null;
|
|
27
|
+
return /* @__PURE__ */ jsx("span", { className: "ml-auto", children: /* @__PURE__ */ jsx(Badge, { value: badge, active }) });
|
|
28
|
+
}
|
|
29
|
+
var SidebarNav = React.forwardRef(
|
|
30
|
+
function SidebarNav2({
|
|
31
|
+
items,
|
|
32
|
+
activeId,
|
|
33
|
+
onNavigate,
|
|
34
|
+
collapsed = false,
|
|
35
|
+
onCollapsedChange,
|
|
36
|
+
collapsible = false,
|
|
37
|
+
expandedIds,
|
|
38
|
+
onExpandedIdsChange,
|
|
39
|
+
header,
|
|
40
|
+
footer,
|
|
41
|
+
labels,
|
|
42
|
+
className,
|
|
43
|
+
navClassName
|
|
44
|
+
}, ref) {
|
|
45
|
+
const baseId = React.useId();
|
|
46
|
+
const listRef = React.useRef(null);
|
|
47
|
+
const flyoutTimer = React.useRef(null);
|
|
48
|
+
const [openFlyout, setOpenFlyout] = React.useState(null);
|
|
49
|
+
const [internalExpanded, setInternalExpanded] = React.useState([]);
|
|
50
|
+
const controlledExpanded = expandedIds !== void 0 && onExpandedIdsChange !== void 0;
|
|
51
|
+
const expanded = controlledExpanded ? expandedIds : internalExpanded;
|
|
52
|
+
const setExpandedList = React.useCallback(
|
|
53
|
+
(next) => {
|
|
54
|
+
if (controlledExpanded) onExpandedIdsChange?.(next);
|
|
55
|
+
else setInternalExpanded(next);
|
|
56
|
+
},
|
|
57
|
+
[controlledExpanded, onExpandedIdsChange]
|
|
58
|
+
);
|
|
59
|
+
const toggleGroup = React.useCallback(
|
|
60
|
+
(id) => {
|
|
61
|
+
setExpandedList(
|
|
62
|
+
expanded.includes(id) ? expanded.filter((g) => g !== id) : [...expanded, id]
|
|
63
|
+
);
|
|
64
|
+
},
|
|
65
|
+
[expanded, setExpandedList]
|
|
66
|
+
);
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
if (controlledExpanded || activeId == null) return;
|
|
69
|
+
const owner = items.find((it) => it.children?.some((c) => c.id === activeId));
|
|
70
|
+
if (owner && !expanded.includes(owner.id)) {
|
|
71
|
+
setExpandedList([...expanded, owner.id]);
|
|
72
|
+
}
|
|
73
|
+
}, [activeId, items, controlledExpanded]);
|
|
74
|
+
React.useEffect(() => {
|
|
75
|
+
return () => {
|
|
76
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
77
|
+
};
|
|
78
|
+
}, []);
|
|
79
|
+
const flyoutEnter = (id) => {
|
|
80
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
81
|
+
flyoutTimer.current = setTimeout(() => setOpenFlyout(id), FLYOUT_DELAY_MS);
|
|
82
|
+
};
|
|
83
|
+
const flyoutLeave = () => {
|
|
84
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
85
|
+
flyoutTimer.current = setTimeout(() => setOpenFlyout(null), FLYOUT_DELAY_MS);
|
|
86
|
+
};
|
|
87
|
+
const flyoutEnterCancel = () => {
|
|
88
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
89
|
+
};
|
|
90
|
+
const navigate = (id) => {
|
|
91
|
+
setOpenFlyout(null);
|
|
92
|
+
onNavigate?.(id);
|
|
93
|
+
};
|
|
94
|
+
const visibleItems = () => {
|
|
95
|
+
const list = listRef.current;
|
|
96
|
+
if (!list) return [];
|
|
97
|
+
return Array.from(
|
|
98
|
+
list.querySelectorAll("[data-as-nav-item]")
|
|
99
|
+
).filter((el) => el.closest("[hidden]") === null);
|
|
100
|
+
};
|
|
101
|
+
const focusSibling = (current, offset) => {
|
|
102
|
+
const all = visibleItems();
|
|
103
|
+
const index = all.indexOf(current);
|
|
104
|
+
if (index === -1) return;
|
|
105
|
+
const next = all[Math.min(Math.max(index + offset, 0), all.length - 1)];
|
|
106
|
+
next?.focus();
|
|
107
|
+
};
|
|
108
|
+
const handleFlyoutArrowKeys = (e) => {
|
|
109
|
+
if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
const buttons = Array.from(
|
|
112
|
+
e.currentTarget.querySelectorAll(
|
|
113
|
+
"button[data-as-flyout-item]:not([disabled])"
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
const index = buttons.indexOf(document.activeElement);
|
|
117
|
+
const step = e.key === "ArrowDown" ? 1 : buttons.length - 1;
|
|
118
|
+
buttons[(index + step) % buttons.length]?.focus();
|
|
119
|
+
};
|
|
120
|
+
const groupTriggerFor = (id) => Array.from(
|
|
121
|
+
listRef.current?.querySelectorAll(
|
|
122
|
+
"[data-as-nav-group-id]"
|
|
123
|
+
) ?? []
|
|
124
|
+
).find((b) => b.dataset.asNavGroupId === id);
|
|
125
|
+
const firstChildFor = (id) => Array.from(
|
|
126
|
+
listRef.current?.querySelectorAll(
|
|
127
|
+
"[data-as-nav-parent-id]"
|
|
128
|
+
) ?? []
|
|
129
|
+
).find((b) => b.dataset.asNavParentId === id && !b.disabled);
|
|
130
|
+
const handleListKeyDown = (e) => {
|
|
131
|
+
const button = e.target.closest(
|
|
132
|
+
"[data-as-nav-item]"
|
|
133
|
+
);
|
|
134
|
+
if (!button) return;
|
|
135
|
+
const groupId = button.dataset.asNavGroupId;
|
|
136
|
+
const parentId = button.dataset.asNavParentId;
|
|
137
|
+
switch (e.key) {
|
|
138
|
+
case "ArrowDown":
|
|
139
|
+
e.preventDefault();
|
|
140
|
+
focusSibling(button, 1);
|
|
141
|
+
break;
|
|
142
|
+
case "ArrowUp":
|
|
143
|
+
e.preventDefault();
|
|
144
|
+
focusSibling(button, -1);
|
|
145
|
+
break;
|
|
146
|
+
case "Home": {
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
visibleItems()[0]?.focus();
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case "End": {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
const all = visibleItems();
|
|
154
|
+
all[all.length - 1]?.focus();
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case "ArrowRight":
|
|
158
|
+
if (groupId) {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
if (!expanded.includes(groupId)) {
|
|
161
|
+
setExpandedList([...expanded, groupId]);
|
|
162
|
+
} else {
|
|
163
|
+
firstChildFor(groupId)?.focus();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
case "ArrowLeft":
|
|
168
|
+
if (parentId) {
|
|
169
|
+
e.preventDefault();
|
|
170
|
+
groupTriggerFor(parentId)?.focus();
|
|
171
|
+
} else if (groupId && expanded.includes(groupId)) {
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
toggleGroup(groupId);
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
const navAria = labels?.navAria ?? "Main navigation";
|
|
179
|
+
const rail = collapsed;
|
|
180
|
+
const flyoutHeader = (text) => /* @__PURE__ */ jsx("div", { className: "border-b border-[var(--as-border)] px-2 py-1.5 text-xs font-bold text-[var(--as-muted-fg)]", children: text });
|
|
181
|
+
return /* @__PURE__ */ jsxs(
|
|
182
|
+
"nav",
|
|
183
|
+
{
|
|
184
|
+
ref,
|
|
185
|
+
"data-as": "sidebar-nav",
|
|
186
|
+
"aria-label": navAria,
|
|
187
|
+
className: cn(
|
|
188
|
+
"relative flex h-full flex-col border-r border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] transition-[width] duration-200",
|
|
189
|
+
rail ? "w-20" : "w-64",
|
|
190
|
+
className
|
|
191
|
+
),
|
|
192
|
+
children: [
|
|
193
|
+
collapsible ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 -right-3 z-10 hidden flex-col justify-center lg:flex", children: /* @__PURE__ */ jsx(
|
|
194
|
+
"button",
|
|
195
|
+
{
|
|
196
|
+
type: "button",
|
|
197
|
+
onClick: () => onCollapsedChange?.(!collapsed),
|
|
198
|
+
title: collapsed ? labels?.expand ?? "Expand sidebar" : labels?.collapse ?? "Collapse sidebar",
|
|
199
|
+
"aria-label": collapsed ? labels?.expand ?? "Expand sidebar" : labels?.collapse ?? "Collapse sidebar",
|
|
200
|
+
className: "pointer-events-auto flex size-6 items-center justify-center rounded-lg border border-[var(--as-border)] bg-[var(--as-surface-raised)] text-[var(--as-muted-fg)] shadow-[var(--as-shadow-2)] transition-colors hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
|
|
201
|
+
children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5", "aria-hidden": true })
|
|
202
|
+
}
|
|
203
|
+
) }) : null,
|
|
204
|
+
header ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: header }) : null,
|
|
205
|
+
/* @__PURE__ */ jsx(
|
|
206
|
+
"div",
|
|
207
|
+
{
|
|
208
|
+
ref: listRef,
|
|
209
|
+
onKeyDown: handleListKeyDown,
|
|
210
|
+
className: cn("min-h-0 flex-1 overflow-y-auto px-3 py-3", navClassName),
|
|
211
|
+
children: /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: items.map((item, index) => {
|
|
212
|
+
if (item.children !== void 0 && item.children.length === 0) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const sectionSeen = !rail && item.section !== void 0 && items.findIndex((i) => i.section === item.section) === index;
|
|
216
|
+
const sectionDivider = sectionSeen ? /* @__PURE__ */ jsx(
|
|
217
|
+
"div",
|
|
218
|
+
{
|
|
219
|
+
role: "presentation",
|
|
220
|
+
className: "mt-2 border-t border-[var(--as-border)] px-3 pb-1 pt-3 text-[11px] font-bold uppercase tracking-wide text-[var(--as-muted-fg)]",
|
|
221
|
+
children: item.section
|
|
222
|
+
}
|
|
223
|
+
) : null;
|
|
224
|
+
const active = item.id === activeId;
|
|
225
|
+
const childActive = item.children?.some((c) => c.id === activeId) ?? false;
|
|
226
|
+
const isExpanded = expanded.includes(item.id);
|
|
227
|
+
const Icon = item.icon;
|
|
228
|
+
const groupId = `${baseId}-group-${item.id}`;
|
|
229
|
+
if (item.children && item.children.length > 0 && rail) {
|
|
230
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
231
|
+
sectionDivider,
|
|
232
|
+
/* @__PURE__ */ jsxs(
|
|
233
|
+
PopoverPrimitive.Root,
|
|
234
|
+
{
|
|
235
|
+
open: openFlyout === item.id,
|
|
236
|
+
onOpenChange: (open) => {
|
|
237
|
+
if (!open) setOpenFlyout(null);
|
|
238
|
+
},
|
|
239
|
+
children: [
|
|
240
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
241
|
+
"button",
|
|
242
|
+
{
|
|
243
|
+
type: "button",
|
|
244
|
+
"data-as-nav-item": true,
|
|
245
|
+
"data-as-nav-group-id": item.id,
|
|
246
|
+
disabled: item.disabled,
|
|
247
|
+
"aria-label": labels?.openGroup ?? `Open ${item.label} menu`,
|
|
248
|
+
"aria-haspopup": "true",
|
|
249
|
+
"aria-expanded": openFlyout === item.id,
|
|
250
|
+
onClick: () => setOpenFlyout(item.id),
|
|
251
|
+
onKeyDown: (e) => {
|
|
252
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
253
|
+
e.preventDefault();
|
|
254
|
+
setOpenFlyout(item.id);
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
onMouseEnter: () => flyoutEnter(item.id),
|
|
258
|
+
onMouseLeave: flyoutLeave,
|
|
259
|
+
className: cn(itemButtonClass(active || childActive), "justify-center px-0"),
|
|
260
|
+
children: Icon ? /* @__PURE__ */ jsx(
|
|
261
|
+
Icon,
|
|
262
|
+
{
|
|
263
|
+
className: cn(
|
|
264
|
+
"size-5 shrink-0",
|
|
265
|
+
active || childActive ? "text-[var(--as-primary)]" : "text-[var(--as-muted-fg)]"
|
|
266
|
+
),
|
|
267
|
+
"aria-hidden": true
|
|
268
|
+
}
|
|
269
|
+
) : null
|
|
270
|
+
}
|
|
271
|
+
) }),
|
|
272
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
273
|
+
PopoverPrimitive.Content,
|
|
274
|
+
{
|
|
275
|
+
side: "right",
|
|
276
|
+
sideOffset: 8,
|
|
277
|
+
"aria-label": item.label,
|
|
278
|
+
onCloseAutoFocus: (e) => {
|
|
279
|
+
e.preventDefault();
|
|
280
|
+
groupTriggerFor(item.id)?.focus();
|
|
281
|
+
},
|
|
282
|
+
onMouseEnter: flyoutEnterCancel,
|
|
283
|
+
onMouseLeave: flyoutLeave,
|
|
284
|
+
onKeyDown: handleFlyoutArrowKeys,
|
|
285
|
+
className: flyoutContentClass,
|
|
286
|
+
children: [
|
|
287
|
+
flyoutHeader(item.label),
|
|
288
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-1 space-y-0.5", children: item.children.map((child) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
289
|
+
"button",
|
|
290
|
+
{
|
|
291
|
+
type: "button",
|
|
292
|
+
"data-as-flyout-item": true,
|
|
293
|
+
disabled: child.disabled,
|
|
294
|
+
onClick: () => navigate(child.id),
|
|
295
|
+
"aria-current": child.id === activeId ? "page" : void 0,
|
|
296
|
+
className: cn(
|
|
297
|
+
"flex w-full cursor-pointer items-center gap-2 rounded-[calc(var(--as-radius-sm)-2px)] px-2 py-1.5 text-left text-sm outline-none transition-colors focus:bg-[var(--as-secondary)] disabled:pointer-events-none disabled:opacity-50",
|
|
298
|
+
child.id === activeId && "font-bold text-[var(--as-primary)]"
|
|
299
|
+
),
|
|
300
|
+
children: [
|
|
301
|
+
child.icon ? /* @__PURE__ */ jsx(child.icon, { "aria-hidden": true }) : null,
|
|
302
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: child.label }),
|
|
303
|
+
/* @__PURE__ */ jsx(ItemBadge, { badge: child.badge, active: child.id === activeId })
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
) }, child.id)) })
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
) })
|
|
310
|
+
]
|
|
311
|
+
}
|
|
312
|
+
)
|
|
313
|
+
] }, item.id);
|
|
314
|
+
}
|
|
315
|
+
if (item.children && item.children.length > 0) {
|
|
316
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
317
|
+
sectionDivider,
|
|
318
|
+
/* @__PURE__ */ jsxs(
|
|
319
|
+
"button",
|
|
320
|
+
{
|
|
321
|
+
type: "button",
|
|
322
|
+
"data-as-nav-item": true,
|
|
323
|
+
"data-as-nav-group-id": item.id,
|
|
324
|
+
disabled: item.disabled,
|
|
325
|
+
"aria-expanded": isExpanded,
|
|
326
|
+
"aria-controls": groupId,
|
|
327
|
+
onClick: () => toggleGroup(item.id),
|
|
328
|
+
className: itemButtonClass(active || childActive),
|
|
329
|
+
children: [
|
|
330
|
+
Icon ? /* @__PURE__ */ jsx(
|
|
331
|
+
Icon,
|
|
332
|
+
{
|
|
333
|
+
className: cn(
|
|
334
|
+
"size-4 shrink-0",
|
|
335
|
+
active || childActive ? "text-[var(--as-primary)]" : "text-[var(--as-muted-fg)]"
|
|
336
|
+
),
|
|
337
|
+
"aria-hidden": true
|
|
338
|
+
}
|
|
339
|
+
) : null,
|
|
340
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
|
|
341
|
+
/* @__PURE__ */ jsx(ItemBadge, { badge: item.badge, active: active || childActive }),
|
|
342
|
+
isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 shrink-0 text-[var(--as-muted-fg)]", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4 shrink-0 text-[var(--as-muted-fg)]", "aria-hidden": true })
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
),
|
|
346
|
+
/* @__PURE__ */ jsx("ul", { id: groupId, hidden: !isExpanded, className: "mt-1 space-y-0.5 pl-6", children: item.children.map((child) => {
|
|
347
|
+
const childActiveItem = child.id === activeId;
|
|
348
|
+
const ChildIcon = child.icon;
|
|
349
|
+
const sectionSeen2 = child.section !== void 0 && item.children.findIndex(
|
|
350
|
+
(c) => c.section === child.section
|
|
351
|
+
) === item.children.indexOf(child);
|
|
352
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
353
|
+
sectionSeen2 ? /* @__PURE__ */ jsx(
|
|
354
|
+
"div",
|
|
355
|
+
{
|
|
356
|
+
role: "presentation",
|
|
357
|
+
className: "mt-2 border-t border-[var(--as-border)] px-3 pb-1 pt-3 text-[11px] font-bold uppercase tracking-wide text-[var(--as-muted-fg)]",
|
|
358
|
+
children: child.section
|
|
359
|
+
}
|
|
360
|
+
) : null,
|
|
361
|
+
/* @__PURE__ */ jsxs(
|
|
362
|
+
"button",
|
|
363
|
+
{
|
|
364
|
+
type: "button",
|
|
365
|
+
"data-as-nav-item": true,
|
|
366
|
+
"data-as-nav-parent-id": item.id,
|
|
367
|
+
disabled: child.disabled,
|
|
368
|
+
"aria-current": childActiveItem ? "page" : void 0,
|
|
369
|
+
onClick: () => navigate(child.id),
|
|
370
|
+
className: cn(
|
|
371
|
+
itemButtonClass(childActiveItem),
|
|
372
|
+
"py-2 pl-3 pr-2"
|
|
373
|
+
),
|
|
374
|
+
children: [
|
|
375
|
+
ChildIcon ? /* @__PURE__ */ jsx(ChildIcon, { className: "size-4 shrink-0", "aria-hidden": true }) : null,
|
|
376
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: child.label }),
|
|
377
|
+
/* @__PURE__ */ jsx(ItemBadge, { badge: child.badge, active: childActiveItem })
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
] }, child.id);
|
|
382
|
+
}) })
|
|
383
|
+
] }, item.id);
|
|
384
|
+
}
|
|
385
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
386
|
+
sectionDivider,
|
|
387
|
+
/* @__PURE__ */ jsxs(
|
|
388
|
+
"button",
|
|
389
|
+
{
|
|
390
|
+
type: "button",
|
|
391
|
+
"data-as-nav-item": true,
|
|
392
|
+
disabled: item.disabled,
|
|
393
|
+
title: rail ? item.label : void 0,
|
|
394
|
+
"aria-label": rail ? item.label : void 0,
|
|
395
|
+
"aria-current": active ? "page" : void 0,
|
|
396
|
+
onClick: () => navigate(item.id),
|
|
397
|
+
className: cn(itemButtonClass(active), rail && "justify-center px-0"),
|
|
398
|
+
children: [
|
|
399
|
+
Icon ? /* @__PURE__ */ jsx(
|
|
400
|
+
Icon,
|
|
401
|
+
{
|
|
402
|
+
className: cn(
|
|
403
|
+
"shrink-0",
|
|
404
|
+
rail ? "size-5" : "size-4",
|
|
405
|
+
active ? "text-[var(--as-primary)]" : "text-[var(--as-muted-fg)]"
|
|
406
|
+
),
|
|
407
|
+
"aria-hidden": true
|
|
408
|
+
}
|
|
409
|
+
) : null,
|
|
410
|
+
!rail ? /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }) : null,
|
|
411
|
+
!rail ? /* @__PURE__ */ jsx(ItemBadge, { badge: item.badge, active }) : null
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
)
|
|
415
|
+
] }, item.id);
|
|
416
|
+
}) })
|
|
417
|
+
}
|
|
418
|
+
),
|
|
419
|
+
footer ? /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-[var(--as-border)] p-3", children: footer }) : null
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
export { SidebarNav };
|
|
427
|
+
//# sourceMappingURL=chunk-EZTQMJ5I.js.map
|
|
428
|
+
//# sourceMappingURL=chunk-EZTQMJ5I.js.map
|