@neuronection/assistant-ui 0.14.0 → 0.16.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 +56 -0
- package/README.md +2 -0
- package/dist/about.d.ts +4 -0
- package/dist/about.js +1 -1
- package/dist/chip-input.d.ts +2 -0
- package/dist/chip-input.js +1 -1
- package/dist/chunk-3IXMZ6KG.js +439 -0
- package/dist/chunk-3IXMZ6KG.js.map +1 -0
- package/dist/chunk-535TM7SK.js +119 -0
- package/dist/chunk-535TM7SK.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-7RTSSBBR.js → chunk-INMAUGBK.js} +39 -63
- package/dist/chunk-INMAUGBK.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 +9 -7
- 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 +66 -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-7RTSSBBR.js.map +0 -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,61 @@
|
|
|
1
1
|
# @neuronection/assistant-ui
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`d0d648b`](https://github.com/neuronection/assistant-ui/commit/d0d648b3a5142badd32de81fdd992fdff803127c) Thanks [@constLiakos](https://github.com/constLiakos)! - SidebarNav: add `secondaryItems` — flat nav items pinned below the scroll area, above `footer` (the Settings/About pattern). Pinned items share the main list's rendering, active state, collapsed-rail behavior and keyboard traversal order (arrows and Home/End cross between regions).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [`d0d648b`](https://github.com/neuronection/assistant-ui/commit/d0d648b3a5142badd32de81fdd992fdff803127c) Thanks [@constLiakos](https://github.com/constLiakos)! - SponsorCard: compact redesign — the decorative primary glow blob, large icon chip and tinted highlight block are gone. The title is bolder with a small inline heart, the footnote renders as a plain second line under the description, and the highlighted channel is emphasized with a primary border and primary name instead of a filled background. The channel list is a responsive grid — one column below the `sm` viewport breakpoint, two above — with a new `columns` prop (`'auto'` default, `1`, `2`) for narrow surfaces like modals.
|
|
12
|
+
|
|
13
|
+
FamilyBadge: the current app's card is now clickable to its own hub page (it was rendered as a non-interactive div; the ring and "Current app" badge still mark it).
|
|
14
|
+
|
|
15
|
+
- [`d0d648b`](https://github.com/neuronection/assistant-ui/commit/d0d648b3a5142badd32de81fdd992fdff803127c) Thanks [@constLiakos](https://github.com/constLiakos)! - SponsorCard: the highlighted channel renders as a soft primary tint (8–12% color-mix fill, primary-mix border, primary text/icon) instead of a solid primary block, with slightly tighter row padding — calmer, more modern hierarchy.
|
|
16
|
+
|
|
17
|
+
## 0.15.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- [`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
|
|
22
|
+
(`data-pending` on the container while a draft exists) so it is visually
|
|
23
|
+
explicit that each entry is its own separate item, and a new `hint` prop
|
|
24
|
+
renders helper text below the field wired to the input via
|
|
25
|
+
`aria-describedby` — use it to spell out the "press Enter or Add after each
|
|
26
|
+
one" contract.
|
|
27
|
+
|
|
28
|
+
- [`163e5e4`](https://github.com/neuronection/assistant-ui/commit/163e5e4f13d5a097dea56727447fe7e1070e3395) Thanks [@constLiakos](https://github.com/constLiakos)! - ScaleSlider: modern track + thumb (filled progress, larger thumb, visible
|
|
29
|
+
focus ring) via new `styles.css` range rules scoped to
|
|
30
|
+
`[data-as='scale-slider']`; low/high labels are larger and readable
|
|
31
|
+
(text-xs, medium weight, muted color) instead of 9px uppercase.
|
|
32
|
+
|
|
33
|
+
ChipInput: new `addLabel` prop renders an explicit add button that commits
|
|
34
|
+
the draft (disabled while empty, re-focuses the input) — makes the
|
|
35
|
+
multi-entry affordance discoverable without keyboard knowledge.
|
|
36
|
+
|
|
37
|
+
- [`3826518`](https://github.com/neuronection/assistant-ui/commit/3826518fd86f03cbef56344bec9b34b2234086c9) Thanks [@constLiakos](https://github.com/constLiakos)! - New `SidebarNav` component: the family-standard vertical navigation panel
|
|
38
|
+
(groups + section dividers, icons, badges, controlled `activeId`, optional
|
|
39
|
+
collapsed icon rail with hover flyouts, header/footer slots). Fully
|
|
40
|
+
presentational + controlled per ADR-006 — routing, role filtering and i18n
|
|
41
|
+
stay app-side. Ships with keyboard-nav + axe assertions, Ladle stories and
|
|
42
|
+
a docs page; adoption across the family apps is tracked in the nav
|
|
43
|
+
primitives program (family ADR-0007).
|
|
44
|
+
|
|
45
|
+
- [`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
|
|
46
|
+
label rendered above the item (first occurrence only) so flat sidebars can
|
|
47
|
+
group their entries visually without nested expand/collapse. Sections are
|
|
48
|
+
ignored in the collapsed rail. (Career's sidebar adoption is the first
|
|
49
|
+
consumer; matches the existing child-level `section` dividers.)
|
|
50
|
+
|
|
51
|
+
- [`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
|
|
52
|
+
initials-disc trigger with name/email, identity header in the panel, item
|
|
53
|
+
model with `tone: 'danger'`, `pending`, and checkable items for
|
|
54
|
+
theme/language toggles). Built on the `Menu` primitives; also adds
|
|
55
|
+
`MenuCheckboxItem` (Radix checkbox menu item with an indicator) to the
|
|
56
|
+
menu module. Health's hand-rolled header dropdown and career's plain
|
|
57
|
+
sign-out button are the adoption targets (family ADR-0007 program).
|
|
58
|
+
|
|
3
59
|
## 0.14.0
|
|
4
60
|
|
|
5
61
|
### 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, pinned secondary items, 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/about.d.ts
CHANGED
|
@@ -95,6 +95,10 @@ interface SponsorCardProps extends Omit<React.ComponentProps<'section'>, 'title'
|
|
|
95
95
|
description?: React.ReactNode;
|
|
96
96
|
footnote?: React.ReactNode;
|
|
97
97
|
channelsLabel?: string;
|
|
98
|
+
/** Channel list columns. `auto` = one column below the `sm` viewport
|
|
99
|
+
* breakpoint, two above; `1`/`2` force a count (use `1` inside narrow
|
|
100
|
+
* surfaces like modals — breakpoints track the viewport, not the card). */
|
|
101
|
+
columns?: 'auto' | 1 | 2;
|
|
98
102
|
icon?: React.ReactNode;
|
|
99
103
|
heading?: 'h2' | 'h3' | 'h4';
|
|
100
104
|
}
|
package/dist/about.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { AboutCard, AboutFooterLine, AboutLinkList, AboutNote, AboutPanel, FamilyBadge, SponsorCard, TechChips } from './chunk-
|
|
1
|
+
export { AboutCard, AboutFooterLine, AboutLinkList, AboutNote, AboutPanel, FamilyBadge, SponsorCard, TechChips } from './chunk-INMAUGBK.js';
|
|
2
2
|
//# sourceMappingURL=about.js.map
|
|
3
3
|
//# sourceMappingURL=about.js.map
|
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,439 @@
|
|
|
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
|
+
secondaryItems,
|
|
33
|
+
activeId,
|
|
34
|
+
onNavigate,
|
|
35
|
+
collapsed = false,
|
|
36
|
+
onCollapsedChange,
|
|
37
|
+
collapsible = false,
|
|
38
|
+
expandedIds,
|
|
39
|
+
onExpandedIdsChange,
|
|
40
|
+
header,
|
|
41
|
+
footer,
|
|
42
|
+
labels,
|
|
43
|
+
className,
|
|
44
|
+
navClassName
|
|
45
|
+
}, ref) {
|
|
46
|
+
const baseId = React.useId();
|
|
47
|
+
const listRef = React.useRef(null);
|
|
48
|
+
const secondaryRef = React.useRef(null);
|
|
49
|
+
const flyoutTimer = React.useRef(null);
|
|
50
|
+
const [openFlyout, setOpenFlyout] = React.useState(null);
|
|
51
|
+
const [internalExpanded, setInternalExpanded] = React.useState([]);
|
|
52
|
+
const controlledExpanded = expandedIds !== void 0 && onExpandedIdsChange !== void 0;
|
|
53
|
+
const expanded = controlledExpanded ? expandedIds : internalExpanded;
|
|
54
|
+
const setExpandedList = React.useCallback(
|
|
55
|
+
(next) => {
|
|
56
|
+
if (controlledExpanded) onExpandedIdsChange?.(next);
|
|
57
|
+
else setInternalExpanded(next);
|
|
58
|
+
},
|
|
59
|
+
[controlledExpanded, onExpandedIdsChange]
|
|
60
|
+
);
|
|
61
|
+
const toggleGroup = React.useCallback(
|
|
62
|
+
(id) => {
|
|
63
|
+
setExpandedList(
|
|
64
|
+
expanded.includes(id) ? expanded.filter((g) => g !== id) : [...expanded, id]
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
[expanded, setExpandedList]
|
|
68
|
+
);
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
if (controlledExpanded || activeId == null) return;
|
|
71
|
+
const owner = items.find((it) => it.children?.some((c) => c.id === activeId)) ?? secondaryItems?.find((it) => it.children?.some((c) => c.id === activeId));
|
|
72
|
+
if (owner && !expanded.includes(owner.id)) {
|
|
73
|
+
setExpandedList([...expanded, owner.id]);
|
|
74
|
+
}
|
|
75
|
+
}, [activeId, items, secondaryItems, controlledExpanded]);
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
return () => {
|
|
78
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
const flyoutEnter = (id) => {
|
|
82
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
83
|
+
flyoutTimer.current = setTimeout(() => setOpenFlyout(id), FLYOUT_DELAY_MS);
|
|
84
|
+
};
|
|
85
|
+
const flyoutLeave = () => {
|
|
86
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
87
|
+
flyoutTimer.current = setTimeout(() => setOpenFlyout(null), FLYOUT_DELAY_MS);
|
|
88
|
+
};
|
|
89
|
+
const flyoutEnterCancel = () => {
|
|
90
|
+
if (flyoutTimer.current) clearTimeout(flyoutTimer.current);
|
|
91
|
+
};
|
|
92
|
+
const navigate = (id) => {
|
|
93
|
+
setOpenFlyout(null);
|
|
94
|
+
onNavigate?.(id);
|
|
95
|
+
};
|
|
96
|
+
const navRegions = () => [listRef.current, secondaryRef.current].filter(
|
|
97
|
+
(r) => r !== null
|
|
98
|
+
);
|
|
99
|
+
const visibleItems = () => {
|
|
100
|
+
return navRegions().flatMap(
|
|
101
|
+
(region) => Array.from(
|
|
102
|
+
region.querySelectorAll("[data-as-nav-item]")
|
|
103
|
+
).filter((el) => el.closest("[hidden]") === null)
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
const focusSibling = (current, offset) => {
|
|
107
|
+
const all = visibleItems();
|
|
108
|
+
const index = all.indexOf(current);
|
|
109
|
+
if (index === -1) return;
|
|
110
|
+
const next = all[Math.min(Math.max(index + offset, 0), all.length - 1)];
|
|
111
|
+
next?.focus();
|
|
112
|
+
};
|
|
113
|
+
const handleFlyoutArrowKeys = (e) => {
|
|
114
|
+
if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
const buttons = Array.from(
|
|
117
|
+
e.currentTarget.querySelectorAll(
|
|
118
|
+
"button[data-as-flyout-item]:not([disabled])"
|
|
119
|
+
)
|
|
120
|
+
);
|
|
121
|
+
const index = buttons.indexOf(document.activeElement);
|
|
122
|
+
const step = e.key === "ArrowDown" ? 1 : buttons.length - 1;
|
|
123
|
+
buttons[(index + step) % buttons.length]?.focus();
|
|
124
|
+
};
|
|
125
|
+
const groupTriggerFor = (id) => navRegions().flatMap(
|
|
126
|
+
(r) => Array.from(r.querySelectorAll("[data-as-nav-group-id]"))
|
|
127
|
+
).find((b) => b.dataset.asNavGroupId === id);
|
|
128
|
+
const firstChildFor = (id) => navRegions().flatMap(
|
|
129
|
+
(r) => Array.from(r.querySelectorAll("[data-as-nav-parent-id]"))
|
|
130
|
+
).find((b) => b.dataset.asNavParentId === id && !b.disabled);
|
|
131
|
+
const handleListKeyDown = (e) => {
|
|
132
|
+
const button = e.target.closest(
|
|
133
|
+
"[data-as-nav-item]"
|
|
134
|
+
);
|
|
135
|
+
if (!button) return;
|
|
136
|
+
const groupId = button.dataset.asNavGroupId;
|
|
137
|
+
const parentId = button.dataset.asNavParentId;
|
|
138
|
+
switch (e.key) {
|
|
139
|
+
case "ArrowDown":
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
focusSibling(button, 1);
|
|
142
|
+
break;
|
|
143
|
+
case "ArrowUp":
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
focusSibling(button, -1);
|
|
146
|
+
break;
|
|
147
|
+
case "Home": {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
visibleItems()[0]?.focus();
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "End": {
|
|
153
|
+
e.preventDefault();
|
|
154
|
+
const all = visibleItems();
|
|
155
|
+
all[all.length - 1]?.focus();
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case "ArrowRight":
|
|
159
|
+
if (groupId) {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
if (!expanded.includes(groupId)) {
|
|
162
|
+
setExpandedList([...expanded, groupId]);
|
|
163
|
+
} else {
|
|
164
|
+
firstChildFor(groupId)?.focus();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
case "ArrowLeft":
|
|
169
|
+
if (parentId) {
|
|
170
|
+
e.preventDefault();
|
|
171
|
+
groupTriggerFor(parentId)?.focus();
|
|
172
|
+
} else if (groupId && expanded.includes(groupId)) {
|
|
173
|
+
e.preventDefault();
|
|
174
|
+
toggleGroup(groupId);
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const navAria = labels?.navAria ?? "Main navigation";
|
|
180
|
+
const rail = collapsed;
|
|
181
|
+
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 });
|
|
182
|
+
const renderItem = (item, index, list) => {
|
|
183
|
+
if (item.children !== void 0 && item.children.length === 0) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const sectionSeen = !rail && item.section !== void 0 && list.findIndex((i) => i.section === item.section) === index;
|
|
187
|
+
const sectionDivider = sectionSeen ? /* @__PURE__ */ jsx(
|
|
188
|
+
"div",
|
|
189
|
+
{
|
|
190
|
+
role: "presentation",
|
|
191
|
+
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)]",
|
|
192
|
+
children: item.section
|
|
193
|
+
}
|
|
194
|
+
) : null;
|
|
195
|
+
const active = item.id === activeId;
|
|
196
|
+
const childActive = item.children?.some((c) => c.id === activeId) ?? false;
|
|
197
|
+
const isExpanded = expanded.includes(item.id);
|
|
198
|
+
const Icon = item.icon;
|
|
199
|
+
const groupId = `${baseId}-group-${item.id}`;
|
|
200
|
+
if (item.children && item.children.length > 0 && rail) {
|
|
201
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
202
|
+
sectionDivider,
|
|
203
|
+
/* @__PURE__ */ jsxs(
|
|
204
|
+
PopoverPrimitive.Root,
|
|
205
|
+
{
|
|
206
|
+
open: openFlyout === item.id,
|
|
207
|
+
onOpenChange: (open) => {
|
|
208
|
+
if (!open) setOpenFlyout(null);
|
|
209
|
+
},
|
|
210
|
+
children: [
|
|
211
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
212
|
+
"button",
|
|
213
|
+
{
|
|
214
|
+
type: "button",
|
|
215
|
+
"data-as-nav-item": true,
|
|
216
|
+
"data-as-nav-group-id": item.id,
|
|
217
|
+
disabled: item.disabled,
|
|
218
|
+
"aria-label": labels?.openGroup ?? `Open ${item.label} menu`,
|
|
219
|
+
"aria-haspopup": "true",
|
|
220
|
+
"aria-expanded": openFlyout === item.id,
|
|
221
|
+
onClick: () => setOpenFlyout(item.id),
|
|
222
|
+
onKeyDown: (e) => {
|
|
223
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
224
|
+
e.preventDefault();
|
|
225
|
+
setOpenFlyout(item.id);
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
onMouseEnter: () => flyoutEnter(item.id),
|
|
229
|
+
onMouseLeave: flyoutLeave,
|
|
230
|
+
className: cn(itemButtonClass(active || childActive), "justify-center px-0"),
|
|
231
|
+
children: Icon ? /* @__PURE__ */ jsx(
|
|
232
|
+
Icon,
|
|
233
|
+
{
|
|
234
|
+
className: cn(
|
|
235
|
+
"size-5 shrink-0",
|
|
236
|
+
active || childActive ? "text-[var(--as-primary)]" : "text-[var(--as-muted-fg)]"
|
|
237
|
+
),
|
|
238
|
+
"aria-hidden": true
|
|
239
|
+
}
|
|
240
|
+
) : null
|
|
241
|
+
}
|
|
242
|
+
) }),
|
|
243
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
244
|
+
PopoverPrimitive.Content,
|
|
245
|
+
{
|
|
246
|
+
side: "right",
|
|
247
|
+
sideOffset: 8,
|
|
248
|
+
"aria-label": item.label,
|
|
249
|
+
onCloseAutoFocus: (e) => {
|
|
250
|
+
e.preventDefault();
|
|
251
|
+
groupTriggerFor(item.id)?.focus();
|
|
252
|
+
},
|
|
253
|
+
onMouseEnter: flyoutEnterCancel,
|
|
254
|
+
onMouseLeave: flyoutLeave,
|
|
255
|
+
onKeyDown: handleFlyoutArrowKeys,
|
|
256
|
+
className: flyoutContentClass,
|
|
257
|
+
children: [
|
|
258
|
+
flyoutHeader(item.label),
|
|
259
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-1 space-y-0.5", children: item.children.map((child) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
260
|
+
"button",
|
|
261
|
+
{
|
|
262
|
+
type: "button",
|
|
263
|
+
"data-as-flyout-item": true,
|
|
264
|
+
disabled: child.disabled,
|
|
265
|
+
onClick: () => navigate(child.id),
|
|
266
|
+
"aria-current": child.id === activeId ? "page" : void 0,
|
|
267
|
+
className: cn(
|
|
268
|
+
"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",
|
|
269
|
+
child.id === activeId && "font-bold text-[var(--as-primary)]"
|
|
270
|
+
),
|
|
271
|
+
children: [
|
|
272
|
+
child.icon ? /* @__PURE__ */ jsx(child.icon, { "aria-hidden": true }) : null,
|
|
273
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: child.label }),
|
|
274
|
+
/* @__PURE__ */ jsx(ItemBadge, { badge: child.badge, active: child.id === activeId })
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
) }, child.id)) })
|
|
278
|
+
]
|
|
279
|
+
}
|
|
280
|
+
) })
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
)
|
|
284
|
+
] }, item.id);
|
|
285
|
+
}
|
|
286
|
+
if (item.children && item.children.length > 0) {
|
|
287
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
288
|
+
sectionDivider,
|
|
289
|
+
/* @__PURE__ */ jsxs(
|
|
290
|
+
"button",
|
|
291
|
+
{
|
|
292
|
+
type: "button",
|
|
293
|
+
"data-as-nav-item": true,
|
|
294
|
+
"data-as-nav-group-id": item.id,
|
|
295
|
+
disabled: item.disabled,
|
|
296
|
+
"aria-expanded": isExpanded,
|
|
297
|
+
"aria-controls": groupId,
|
|
298
|
+
onClick: () => toggleGroup(item.id),
|
|
299
|
+
className: itemButtonClass(active || childActive),
|
|
300
|
+
children: [
|
|
301
|
+
Icon ? /* @__PURE__ */ jsx(
|
|
302
|
+
Icon,
|
|
303
|
+
{
|
|
304
|
+
className: cn(
|
|
305
|
+
"size-4 shrink-0",
|
|
306
|
+
active || childActive ? "text-[var(--as-primary)]" : "text-[var(--as-muted-fg)]"
|
|
307
|
+
),
|
|
308
|
+
"aria-hidden": true
|
|
309
|
+
}
|
|
310
|
+
) : null,
|
|
311
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
|
|
312
|
+
/* @__PURE__ */ jsx(ItemBadge, { badge: item.badge, active: active || childActive }),
|
|
313
|
+
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 })
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
),
|
|
317
|
+
/* @__PURE__ */ jsx("ul", { id: groupId, hidden: !isExpanded, className: "mt-1 space-y-0.5 pl-6", children: item.children.map((child) => {
|
|
318
|
+
const childActiveItem = child.id === activeId;
|
|
319
|
+
const ChildIcon = child.icon;
|
|
320
|
+
const sectionSeen2 = child.section !== void 0 && item.children.findIndex(
|
|
321
|
+
(c) => c.section === child.section
|
|
322
|
+
) === item.children.indexOf(child);
|
|
323
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
324
|
+
sectionSeen2 ? /* @__PURE__ */ jsx(
|
|
325
|
+
"div",
|
|
326
|
+
{
|
|
327
|
+
role: "presentation",
|
|
328
|
+
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)]",
|
|
329
|
+
children: child.section
|
|
330
|
+
}
|
|
331
|
+
) : null,
|
|
332
|
+
/* @__PURE__ */ jsxs(
|
|
333
|
+
"button",
|
|
334
|
+
{
|
|
335
|
+
type: "button",
|
|
336
|
+
"data-as-nav-item": true,
|
|
337
|
+
"data-as-nav-parent-id": item.id,
|
|
338
|
+
disabled: child.disabled,
|
|
339
|
+
"aria-current": childActiveItem ? "page" : void 0,
|
|
340
|
+
onClick: () => navigate(child.id),
|
|
341
|
+
className: cn(
|
|
342
|
+
itemButtonClass(childActiveItem),
|
|
343
|
+
"py-2 pl-3 pr-2"
|
|
344
|
+
),
|
|
345
|
+
children: [
|
|
346
|
+
ChildIcon ? /* @__PURE__ */ jsx(ChildIcon, { className: "size-4 shrink-0", "aria-hidden": true }) : null,
|
|
347
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: child.label }),
|
|
348
|
+
/* @__PURE__ */ jsx(ItemBadge, { badge: child.badge, active: childActiveItem })
|
|
349
|
+
]
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
] }, child.id);
|
|
353
|
+
}) })
|
|
354
|
+
] }, item.id);
|
|
355
|
+
}
|
|
356
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
357
|
+
sectionDivider,
|
|
358
|
+
/* @__PURE__ */ jsxs(
|
|
359
|
+
"button",
|
|
360
|
+
{
|
|
361
|
+
type: "button",
|
|
362
|
+
"data-as-nav-item": true,
|
|
363
|
+
disabled: item.disabled,
|
|
364
|
+
title: rail ? item.label : void 0,
|
|
365
|
+
"aria-label": rail ? item.label : void 0,
|
|
366
|
+
"aria-current": active ? "page" : void 0,
|
|
367
|
+
onClick: () => navigate(item.id),
|
|
368
|
+
className: cn(itemButtonClass(active), rail && "justify-center px-0"),
|
|
369
|
+
children: [
|
|
370
|
+
Icon ? /* @__PURE__ */ jsx(
|
|
371
|
+
Icon,
|
|
372
|
+
{
|
|
373
|
+
className: cn(
|
|
374
|
+
"shrink-0",
|
|
375
|
+
rail ? "size-5" : "size-4",
|
|
376
|
+
active ? "text-[var(--as-primary)]" : "text-[var(--as-muted-fg)]"
|
|
377
|
+
),
|
|
378
|
+
"aria-hidden": true
|
|
379
|
+
}
|
|
380
|
+
) : null,
|
|
381
|
+
!rail ? /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }) : null,
|
|
382
|
+
!rail ? /* @__PURE__ */ jsx(ItemBadge, { badge: item.badge, active }) : null
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
)
|
|
386
|
+
] }, item.id);
|
|
387
|
+
};
|
|
388
|
+
return /* @__PURE__ */ jsxs(
|
|
389
|
+
"nav",
|
|
390
|
+
{
|
|
391
|
+
ref,
|
|
392
|
+
"data-as": "sidebar-nav",
|
|
393
|
+
"aria-label": navAria,
|
|
394
|
+
className: cn(
|
|
395
|
+
"relative flex h-full flex-col border-r border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] transition-[width] duration-200",
|
|
396
|
+
rail ? "w-20" : "w-64",
|
|
397
|
+
className
|
|
398
|
+
),
|
|
399
|
+
children: [
|
|
400
|
+
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(
|
|
401
|
+
"button",
|
|
402
|
+
{
|
|
403
|
+
type: "button",
|
|
404
|
+
onClick: () => onCollapsedChange?.(!collapsed),
|
|
405
|
+
title: collapsed ? labels?.expand ?? "Expand sidebar" : labels?.collapse ?? "Collapse sidebar",
|
|
406
|
+
"aria-label": collapsed ? labels?.expand ?? "Expand sidebar" : labels?.collapse ?? "Collapse sidebar",
|
|
407
|
+
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)]",
|
|
408
|
+
children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5", "aria-hidden": true })
|
|
409
|
+
}
|
|
410
|
+
) }) : null,
|
|
411
|
+
header ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: header }) : null,
|
|
412
|
+
/* @__PURE__ */ jsx(
|
|
413
|
+
"div",
|
|
414
|
+
{
|
|
415
|
+
ref: listRef,
|
|
416
|
+
onKeyDown: handleListKeyDown,
|
|
417
|
+
className: cn("min-h-0 flex-1 overflow-y-auto px-3 py-3", navClassName),
|
|
418
|
+
children: /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: items.map((item, index) => renderItem(item, index, items)) })
|
|
419
|
+
}
|
|
420
|
+
),
|
|
421
|
+
secondaryItems && secondaryItems.length > 0 ? /* @__PURE__ */ jsx(
|
|
422
|
+
"div",
|
|
423
|
+
{
|
|
424
|
+
ref: secondaryRef,
|
|
425
|
+
onKeyDown: handleListKeyDown,
|
|
426
|
+
className: "shrink-0 border-t border-[var(--as-border)] px-3 py-3",
|
|
427
|
+
children: /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: secondaryItems.map((item, index) => renderItem(item, index, secondaryItems)) })
|
|
428
|
+
}
|
|
429
|
+
) : null,
|
|
430
|
+
footer ? /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-[var(--as-border)] p-3", children: footer }) : null
|
|
431
|
+
]
|
|
432
|
+
}
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
export { SidebarNav };
|
|
438
|
+
//# sourceMappingURL=chunk-3IXMZ6KG.js.map
|
|
439
|
+
//# sourceMappingURL=chunk-3IXMZ6KG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/sidebar-nav/SidebarNav.tsx"],"names":["SidebarNav","sectionSeen"],"mappings":"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","file":"chunk-3IXMZ6KG.js","sourcesContent":["import * as React from 'react'\nimport * as PopoverPrimitive from '@radix-ui/react-popover'\nimport {\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n type LucideIcon,\n} from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport interface NavChild {\n id: string\n label: string\n icon?: LucideIcon\n badge?: string | number\n /** Divider label rendered above this child (first occurrence only). */\n section?: string\n disabled?: boolean\n}\n\nexport interface NavItem {\n id: string\n label: string\n icon?: LucideIcon\n badge?: string | number\n /** One nesting level; deeper trees stay app-side. */\n children?: NavChild[]\n disabled?: boolean\n /** Divider label rendered above this item (first occurrence only) —\n * for flat sidebars with visual groups. Ignored in the collapsed rail. */\n section?: string\n}\n\nexport interface SidebarNavLabels {\n /** aria-label on the <nav> element. */\n navAria?: string\n /** Collapsed-rail toggle title when collapsed. */\n expand?: string\n /** Collapsed-rail toggle title when expanded. */\n collapse?: string\n /** aria-label for a collapsed group's flyout trigger. */\n openGroup?: string\n}\n\nexport interface SidebarNavProps {\n /** Pre-filtered by the app (roles, feature flags); order = render order. */\n items: NavItem[]\n /** Flat items pinned below the scroll area, above `footer` (the\n * Settings/About pattern). Same rendering, active state, rail behavior\n * and keyboard traversal order as `items`. */\n secondaryItems?: NavItem[]\n /** The app resolves route → id; matching logic stays app-side. */\n activeId?: string | null\n /** Fires for leaves only; group triggers toggle expansion instead. */\n onNavigate?: (id: string) => void\n /** Controlled icon rail. */\n collapsed?: boolean\n onCollapsedChange?: (collapsed: boolean) => void\n /** Renders the rail collapse/expand toggle handle (desktop only). */\n collapsible?: boolean\n /** Controlled group expansion; uncontrolled defaults to internal\n * state + auto-expand when activeId enters a group. */\n expandedIds?: string[]\n onExpandedIdsChange?: (ids: string[]) => void\n /** Slot above the list (brand, logo). */\n header?: React.ReactNode\n /** Slot below the list and pinned items (version, legal links). */\n footer?: React.ReactNode\n labels?: SidebarNavLabels\n className?: string\n /** Targets the scrollable list region. */\n navClassName?: string\n}\n\nconst FLYOUT_DELAY_MS = 150\n\nconst itemButtonClass = (active: boolean) =>\n cn(\n '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',\n active\n ? 'bg-[color-mix(in_srgb,var(--as-primary)_12%,transparent)] font-bold text-[var(--as-primary)]'\n : 'font-medium text-[var(--as-fg)] hover:bg-[var(--as-muted)]',\n )\n\nconst flyoutContentClass =\n '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'\n\nfunction Badge({ value, active }: { value: string | number; active: boolean }) {\n return (\n <span\n className={cn(\n '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',\n active\n ? 'bg-[var(--as-primary)] text-[var(--as-primary-fg)]'\n : 'bg-[var(--as-muted)] text-[var(--as-muted-fg)]',\n )}\n >\n {value}\n </span>\n )\n}\n\nfunction ItemBadge({ badge, active }: { badge?: string | number; active: boolean }) {\n if (badge === undefined) return null\n return (\n <span className=\"ml-auto\">\n <Badge value={badge} active={active} />\n </span>\n )\n}\n\nexport const SidebarNav = React.forwardRef<HTMLElement, SidebarNavProps>(\n function SidebarNav(\n {\n items,\n secondaryItems,\n activeId,\n onNavigate,\n collapsed = false,\n onCollapsedChange,\n collapsible = false,\n expandedIds,\n onExpandedIdsChange,\n header,\n footer,\n labels,\n className,\n navClassName,\n },\n ref,\n ) {\n const baseId = React.useId()\n const listRef = React.useRef<HTMLDivElement>(null)\n const secondaryRef = React.useRef<HTMLDivElement>(null)\n const flyoutTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n const [openFlyout, setOpenFlyout] = React.useState<string | null>(null)\n const [internalExpanded, setInternalExpanded] = React.useState<string[]>([])\n\n const controlledExpanded =\n expandedIds !== undefined && onExpandedIdsChange !== undefined\n const expanded = controlledExpanded ? (expandedIds as string[]) : internalExpanded\n\n const setExpandedList = React.useCallback(\n (next: string[]) => {\n if (controlledExpanded) onExpandedIdsChange?.(next)\n else setInternalExpanded(next)\n },\n [controlledExpanded, onExpandedIdsChange],\n )\n\n const toggleGroup = React.useCallback(\n (id: string) => {\n setExpandedList(\n expanded.includes(id)\n ? expanded.filter((g) => g !== id)\n : [...expanded, id],\n )\n },\n [expanded, setExpandedList],\n )\n\n // Auto-expand the group containing the active item so the highlighted\n // entry is always visible (uncontrolled mode only — the app owns\n // expansion when controlled).\n React.useEffect(() => {\n if (controlledExpanded || activeId == null) return\n const owner =\n items.find((it) => it.children?.some((c) => c.id === activeId)) ??\n secondaryItems?.find((it) => it.children?.some((c) => c.id === activeId))\n if (owner && !expanded.includes(owner.id)) {\n setExpandedList([...expanded, owner.id])\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeId, items, secondaryItems, controlledExpanded])\n\n React.useEffect(() => {\n return () => {\n if (flyoutTimer.current) clearTimeout(flyoutTimer.current)\n }\n }, [])\n\n const flyoutEnter = (id: string) => {\n if (flyoutTimer.current) clearTimeout(flyoutTimer.current)\n flyoutTimer.current = setTimeout(() => setOpenFlyout(id), FLYOUT_DELAY_MS)\n }\n const flyoutLeave = () => {\n if (flyoutTimer.current) clearTimeout(flyoutTimer.current)\n flyoutTimer.current = setTimeout(() => setOpenFlyout(null), FLYOUT_DELAY_MS)\n }\n const flyoutEnterCancel = () => {\n if (flyoutTimer.current) clearTimeout(flyoutTimer.current)\n }\n\n const navigate = (id: string) => {\n setOpenFlyout(null)\n onNavigate?.(id)\n }\n\n // ---- keyboard navigation over the visible list ----\n const navRegions = () =>\n [listRef.current, secondaryRef.current].filter(\n (r): r is HTMLDivElement => r !== null,\n )\n\n const visibleItems = (): HTMLButtonElement[] => {\n return navRegions().flatMap((region) =>\n Array.from(\n region.querySelectorAll<HTMLButtonElement>('[data-as-nav-item]'),\n ).filter((el) => el.closest('[hidden]') === null),\n )\n }\n\n const focusSibling = (current: HTMLElement, offset: number) => {\n const all = visibleItems()\n const index = all.indexOf(current as HTMLButtonElement)\n if (index === -1) return\n const next = all[Math.min(Math.max(index + offset, 0), all.length - 1)]\n next?.focus()\n }\n\n const handleFlyoutArrowKeys = (e: React.KeyboardEvent) => {\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return\n e.preventDefault()\n const buttons = Array.from(\n (e.currentTarget as HTMLElement).querySelectorAll<HTMLButtonElement>(\n 'button[data-as-flyout-item]:not([disabled])',\n ),\n )\n const index = buttons.indexOf(document.activeElement as HTMLButtonElement)\n const step = e.key === 'ArrowDown' ? 1 : buttons.length - 1\n buttons[(index + step) % buttons.length]?.focus()\n }\n\n const groupTriggerFor = (id: string) =>\n navRegions()\n .flatMap((r) =>\n Array.from(r.querySelectorAll<HTMLButtonElement>('[data-as-nav-group-id]')),\n )\n .find((b) => b.dataset.asNavGroupId === id)\n\n const firstChildFor = (id: string) =>\n navRegions()\n .flatMap((r) =>\n Array.from(r.querySelectorAll<HTMLButtonElement>('[data-as-nav-parent-id]')),\n )\n .find((b) => b.dataset.asNavParentId === id && !b.disabled)\n\n const handleListKeyDown = (e: React.KeyboardEvent) => {\n const button = (e.target as HTMLElement).closest<HTMLButtonElement>(\n '[data-as-nav-item]',\n )\n if (!button) return\n const groupId = button.dataset.asNavGroupId\n const parentId = button.dataset.asNavParentId\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n focusSibling(button, 1)\n break\n case 'ArrowUp':\n e.preventDefault()\n focusSibling(button, -1)\n break\n case 'Home': {\n e.preventDefault()\n visibleItems()[0]?.focus()\n break\n }\n case 'End': {\n e.preventDefault()\n const all = visibleItems()\n all[all.length - 1]?.focus()\n break\n }\n case 'ArrowRight':\n if (groupId) {\n e.preventDefault()\n if (!expanded.includes(groupId)) {\n setExpandedList([...expanded, groupId])\n } else {\n firstChildFor(groupId)?.focus()\n }\n }\n break\n case 'ArrowLeft':\n if (parentId) {\n e.preventDefault()\n groupTriggerFor(parentId)?.focus()\n } else if (groupId && expanded.includes(groupId)) {\n e.preventDefault()\n toggleGroup(groupId)\n }\n break\n }\n }\n\n const navAria = labels?.navAria ?? 'Main navigation'\n const rail = collapsed\n\n const flyoutHeader = (text: string) => (\n <div className=\"border-b border-[var(--as-border)] px-2 py-1.5 text-xs font-bold text-[var(--as-muted-fg)]\">\n {text}\n </div>\n )\n\n const renderItem = (item: NavItem, index: number, list: NavItem[]) => {\n // Group whose children were all filtered out app-side renders\n // nothing (presentational).\n if (item.children !== undefined && item.children.length === 0) {\n return null\n }\n const sectionSeen =\n !rail &&\n item.section !== undefined &&\n list.findIndex((i) => i.section === item.section) === index\n const sectionDivider = sectionSeen ? (\n <div\n role=\"presentation\"\n 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)]\"\n >\n {item.section}\n </div>\n ) : null\n const active = item.id === activeId\n const childActive = item.children?.some((c) => c.id === activeId) ?? false\n const isExpanded = expanded.includes(item.id)\n const Icon = item.icon\n const groupId = `${baseId}-group-${item.id}`\n\n if (item.children && item.children.length > 0 && rail) {\n return (\n <li key={item.id}>\n {sectionDivider}\n <PopoverPrimitive.Root\n open={openFlyout === item.id}\n onOpenChange={(open) => {\n if (!open) setOpenFlyout(null)\n }}\n >\n <PopoverPrimitive.Anchor asChild>\n <button\n type=\"button\"\n data-as-nav-item\n data-as-nav-group-id={item.id}\n disabled={item.disabled}\n aria-label={labels?.openGroup ?? `Open ${item.label} menu`}\n aria-haspopup=\"true\"\n aria-expanded={openFlyout === item.id}\n onClick={() => setOpenFlyout(item.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setOpenFlyout(item.id)\n }\n }}\n onMouseEnter={() => flyoutEnter(item.id)}\n onMouseLeave={flyoutLeave}\n className={cn(itemButtonClass(active || childActive), 'justify-center px-0')}\n >\n {Icon ? (\n <Icon\n className={cn(\n 'size-5 shrink-0',\n active || childActive\n ? 'text-[var(--as-primary)]'\n : 'text-[var(--as-muted-fg)]',\n )}\n aria-hidden\n />\n ) : null}\n </button>\n </PopoverPrimitive.Anchor>\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n side=\"right\"\n sideOffset={8}\n aria-label={item.label}\n onCloseAutoFocus={(e) => {\n // Menu-standard: focus returns to the trigger.\n e.preventDefault()\n groupTriggerFor(item.id)?.focus()\n }}\n onMouseEnter={flyoutEnterCancel}\n onMouseLeave={flyoutLeave}\n onKeyDown={handleFlyoutArrowKeys}\n className={flyoutContentClass}\n >\n {flyoutHeader(item.label)}\n <ul className=\"mt-1 space-y-0.5\">\n {item.children.map((child) => (\n <li key={child.id}>\n <button\n type=\"button\"\n data-as-flyout-item\n disabled={child.disabled}\n onClick={() => navigate(child.id)}\n aria-current={child.id === activeId ? 'page' : undefined}\n className={cn(\n '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',\n child.id === activeId && 'font-bold text-[var(--as-primary)]',\n )}\n >\n {child.icon ? <child.icon aria-hidden /> : null}\n <span className=\"min-w-0 flex-1 truncate\">{child.label}</span>\n <ItemBadge badge={child.badge} active={child.id === activeId} />\n </button>\n </li>\n ))}\n </ul>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n </li>\n )\n }\n\n if (item.children && item.children.length > 0) {\n return (\n <li key={item.id}>\n {sectionDivider}\n <button\n type=\"button\"\n data-as-nav-item\n data-as-nav-group-id={item.id}\n disabled={item.disabled}\n aria-expanded={isExpanded}\n aria-controls={groupId}\n onClick={() => toggleGroup(item.id)}\n className={itemButtonClass(active || childActive)}\n >\n {Icon ? (\n <Icon\n className={cn(\n 'size-4 shrink-0',\n active || childActive\n ? 'text-[var(--as-primary)]'\n : 'text-[var(--as-muted-fg)]',\n )}\n aria-hidden\n />\n ) : null}\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n <ItemBadge badge={item.badge} active={active || childActive} />\n {isExpanded ? (\n <ChevronDown className=\"size-4 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden />\n ) : (\n <ChevronRight className=\"size-4 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden />\n )}\n </button>\n <ul id={groupId} hidden={!isExpanded} className=\"mt-1 space-y-0.5 pl-6\">\n {item.children.map((child) => {\n const childActiveItem = child.id === activeId\n const ChildIcon = child.icon\n const sectionSeen =\n child.section !== undefined &&\n item.children!.findIndex(\n (c) => c.section === child.section,\n ) === item.children!.indexOf(child)\n return (\n <li key={child.id}>\n {sectionSeen ? (\n <div\n role=\"presentation\"\n 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)]\"\n >\n {child.section}\n </div>\n ) : null}\n <button\n type=\"button\"\n data-as-nav-item\n data-as-nav-parent-id={item.id}\n disabled={child.disabled}\n aria-current={childActiveItem ? 'page' : undefined}\n onClick={() => navigate(child.id)}\n className={cn(\n itemButtonClass(childActiveItem),\n 'py-2 pl-3 pr-2',\n )}\n >\n {ChildIcon ? (\n <ChildIcon className=\"size-4 shrink-0\" aria-hidden />\n ) : null}\n <span className=\"min-w-0 flex-1 truncate\">{child.label}</span>\n <ItemBadge badge={child.badge} active={childActiveItem} />\n </button>\n </li>\n )\n })}\n </ul>\n </li>\n )\n }\n\n return (\n <li key={item.id}>\n {sectionDivider}\n <button\n type=\"button\"\n data-as-nav-item\n disabled={item.disabled}\n title={rail ? item.label : undefined}\n aria-label={rail ? item.label : undefined}\n aria-current={active ? 'page' : undefined}\n onClick={() => navigate(item.id)}\n className={cn(itemButtonClass(active), rail && 'justify-center px-0')}\n >\n {Icon ? (\n <Icon\n className={cn(\n 'shrink-0',\n rail ? 'size-5' : 'size-4',\n active ? 'text-[var(--as-primary)]' : 'text-[var(--as-muted-fg)]',\n )}\n aria-hidden\n />\n ) : null}\n {!rail ? <span className=\"min-w-0 flex-1 truncate\">{item.label}</span> : null}\n {!rail ? <ItemBadge badge={item.badge} active={active} /> : null}\n </button>\n </li>\n )\n }\n\n return (\n <nav\n ref={ref}\n data-as=\"sidebar-nav\"\n aria-label={navAria}\n className={cn(\n 'relative flex h-full flex-col border-r border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] transition-[width] duration-200',\n rail ? 'w-20' : 'w-64',\n className,\n )}\n >\n {collapsible ? (\n <div className=\"pointer-events-none absolute inset-y-0 -right-3 z-10 hidden flex-col justify-center lg:flex\">\n <button\n type=\"button\"\n onClick={() => onCollapsedChange?.(!collapsed)}\n title={\n collapsed\n ? (labels?.expand ?? 'Expand sidebar')\n : (labels?.collapse ?? 'Collapse sidebar')\n }\n aria-label={\n collapsed\n ? (labels?.expand ?? 'Expand sidebar')\n : (labels?.collapse ?? 'Collapse sidebar')\n }\n 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)]\"\n >\n {collapsed ? (\n <ChevronRight className=\"size-3.5\" aria-hidden />\n ) : (\n <ChevronLeft className=\"size-3.5\" aria-hidden />\n )}\n </button>\n </div>\n ) : null}\n\n {header ? <div className=\"shrink-0\">{header}</div> : null}\n\n <div\n ref={listRef}\n onKeyDown={handleListKeyDown}\n className={cn('min-h-0 flex-1 overflow-y-auto px-3 py-3', navClassName)}\n >\n <ul className=\"space-y-1\">\n {items.map((item, index) => renderItem(item, index, items))}\n </ul>\n </div>\n\n {secondaryItems && secondaryItems.length > 0 ? (\n <div\n ref={secondaryRef}\n onKeyDown={handleListKeyDown}\n className=\"shrink-0 border-t border-[var(--as-border)] px-3 py-3\"\n >\n <ul className=\"space-y-1\">\n {secondaryItems.map((item, index) => renderItem(item, index, secondaryItems))}\n </ul>\n </div>\n ) : null}\n\n {footer ? (\n <div className=\"shrink-0 border-t border-[var(--as-border)] p-3\">{footer}</div>\n ) : null}\n </nav>\n )\n },\n)\n"]}
|