@burtson-labs/ui 0.8.1 → 0.9.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/README.md +1 -1
- package/dist/components/context-menu.d.ts +30 -0
- package/dist/components/context-menu.js +131 -0
- package/dist/components/context-menu.js.map +1 -0
- package/dist/components/dropdown-menu.js +5 -6
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editor-tabs.d.ts +43 -0
- package/dist/components/editor-tabs.js +178 -0
- package/dist/components/editor-tabs.js.map +1 -0
- package/dist/components/menubar.d.ts +30 -0
- package/dist/components/menubar.js +140 -0
- package/dist/components/menubar.js.map +1 -0
- package/dist/components/onboarding-checklist.d.ts +26 -0
- package/dist/components/onboarding-checklist.js +106 -0
- package/dist/components/onboarding-checklist.js.map +1 -0
- package/dist/components/popover.d.ts +2 -0
- package/dist/components/popover.js +3 -1
- package/dist/components/popover.js.map +1 -1
- package/dist/components/resizable.d.ts +33 -0
- package/dist/components/resizable.js +54 -0
- package/dist/components/resizable.js.map +1 -0
- package/dist/components/tour.d.ts +96 -0
- package/dist/components/tour.js +367 -0
- package/dist/components/tour.js.map +1 -0
- package/dist/components/tree-view.d.ts +61 -0
- package/dist/components/tree-view.js +278 -0
- package/dist/components/tree-view.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +10 -3
- package/dist/styles.css +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Spinner } from "./spinner.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import ChevronRight from "@burtson-labs/icons/react/chevron-right";
|
|
6
|
+
//#region src/components/tree-view.tsx
|
|
7
|
+
var isExpandable = (n) => (n.children?.length ?? 0) > 0 || Boolean(n.hasChildren);
|
|
8
|
+
/** The rows a person can see, in order, with the ARIA position data for each. */
|
|
9
|
+
function flattenTree(nodes, expanded) {
|
|
10
|
+
const rows = [];
|
|
11
|
+
const walk = (list, level, parentId) => {
|
|
12
|
+
list.forEach((node, i) => {
|
|
13
|
+
const expandable = isExpandable(node);
|
|
14
|
+
const open = expandable && expanded.has(node.id);
|
|
15
|
+
rows.push({
|
|
16
|
+
node,
|
|
17
|
+
level,
|
|
18
|
+
parentId,
|
|
19
|
+
setSize: list.length,
|
|
20
|
+
posInSet: i + 1,
|
|
21
|
+
expandable,
|
|
22
|
+
expanded: open
|
|
23
|
+
});
|
|
24
|
+
if (open && node.children) walk(node.children, level + 1, node.id);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
walk(nodes, 1, null);
|
|
28
|
+
return rows;
|
|
29
|
+
}
|
|
30
|
+
var isTypingTarget = (target) => target instanceof HTMLElement && (target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName));
|
|
31
|
+
/**
|
|
32
|
+
* A file-explorer style tree. Everything is controlled: the app owns which
|
|
33
|
+
* nodes are expanded and selected, and file operations are callbacks. Rows
|
|
34
|
+
* render flat (role="treeitem" with aria-level), one tab stop for the tree,
|
|
35
|
+
* arrows to move, Right/Left to open and close, Home/End, typeahead.
|
|
36
|
+
*/
|
|
37
|
+
function TreeView({ nodes, expanded, onExpandedChange, selected, onSelectedChange, selectionMode = "single", selectionFollowsFocus = false, onAction, onLoadChildren, renderLabel, density = "default", empty, onRowContextMenu, className, ...props }) {
|
|
38
|
+
const expandedSet = React.useMemo(() => new Set(expanded), [expanded]);
|
|
39
|
+
const selectedSet = React.useMemo(() => new Set(selected), [selected]);
|
|
40
|
+
const rows = React.useMemo(() => flattenTree(nodes, expandedSet), [nodes, expandedSet]);
|
|
41
|
+
const index = React.useMemo(() => new Map(rows.map((r, i) => [r.node.id, i])), [rows]);
|
|
42
|
+
const [focusedId, setFocusedId] = React.useState(null);
|
|
43
|
+
const anchorId = React.useRef(null);
|
|
44
|
+
const rowRefs = React.useRef(/* @__PURE__ */ new Map());
|
|
45
|
+
const treeRef = React.useRef(null);
|
|
46
|
+
const hadFocus = React.useRef(false);
|
|
47
|
+
const lastIds = React.useRef([]);
|
|
48
|
+
const lastParents = React.useRef(/* @__PURE__ */ new Map());
|
|
49
|
+
const typeahead = React.useRef({
|
|
50
|
+
text: "",
|
|
51
|
+
at: 0
|
|
52
|
+
});
|
|
53
|
+
const tabStopId = (focusedId && index.has(focusedId) ? focusedId : null) ?? rows.find((r) => selectedSet.has(r.node.id))?.node.id ?? rows[0]?.node.id ?? null;
|
|
54
|
+
const focusRow = React.useCallback((id) => {
|
|
55
|
+
setFocusedId(id);
|
|
56
|
+
rowRefs.current.get(id)?.focus();
|
|
57
|
+
rowRefs.current.get(id)?.scrollIntoView?.({ block: "nearest" });
|
|
58
|
+
}, []);
|
|
59
|
+
React.useLayoutEffect(() => {
|
|
60
|
+
if (focusedId && !index.has(focusedId)) {
|
|
61
|
+
let next = null;
|
|
62
|
+
let parent = lastParents.current.get(focusedId) ?? null;
|
|
63
|
+
while (parent && !index.has(parent)) parent = lastParents.current.get(parent) ?? null;
|
|
64
|
+
const was = Math.max(0, lastIds.current.indexOf(focusedId));
|
|
65
|
+
next = parent ?? rows[Math.min(was, rows.length - 1)]?.node.id ?? null;
|
|
66
|
+
setFocusedId(next);
|
|
67
|
+
const active = document.activeElement;
|
|
68
|
+
if (next && hadFocus.current && (!active || active === document.body)) rowRefs.current.get(next)?.focus();
|
|
69
|
+
}
|
|
70
|
+
lastIds.current = rows.map((r) => r.node.id);
|
|
71
|
+
lastParents.current = new Map(rows.map((r) => [r.node.id, r.parentId]));
|
|
72
|
+
}, [
|
|
73
|
+
rows,
|
|
74
|
+
index,
|
|
75
|
+
focusedId
|
|
76
|
+
]);
|
|
77
|
+
const setExpanded = (row, open) => {
|
|
78
|
+
if (!row.expandable || row.expanded === open) return;
|
|
79
|
+
const id = row.node.id;
|
|
80
|
+
onExpandedChange(open ? [...expanded, id] : expanded.filter((e) => e !== id));
|
|
81
|
+
if (open && !row.node.children && row.node.hasChildren) onLoadChildren?.(id);
|
|
82
|
+
};
|
|
83
|
+
const selectRange = (toId) => {
|
|
84
|
+
const from = index.get(anchorId.current ?? toId) ?? 0;
|
|
85
|
+
const to = index.get(toId) ?? 0;
|
|
86
|
+
const [a, b] = from < to ? [from, to] : [to, from];
|
|
87
|
+
onSelectedChange(rows.slice(a, b + 1).filter((r) => !r.node.disabled).map((r) => r.node.id));
|
|
88
|
+
};
|
|
89
|
+
const select = (id, mode) => {
|
|
90
|
+
if (rows[index.get(id) ?? -1]?.node.disabled) return;
|
|
91
|
+
if (selectionMode === "single" || mode === "replace") {
|
|
92
|
+
anchorId.current = id;
|
|
93
|
+
onSelectedChange([id]);
|
|
94
|
+
} else if (mode === "toggle") {
|
|
95
|
+
anchorId.current = id;
|
|
96
|
+
onSelectedChange(selectedSet.has(id) ? selected.filter((s) => s !== id) : [...selected, id]);
|
|
97
|
+
} else selectRange(id);
|
|
98
|
+
};
|
|
99
|
+
const moveTo = (i, extend) => {
|
|
100
|
+
const row = rows[Math.max(0, Math.min(rows.length - 1, i))];
|
|
101
|
+
if (!row) return;
|
|
102
|
+
focusRow(row.node.id);
|
|
103
|
+
if (selectionMode === "multiple" && extend) selectRange(row.node.id);
|
|
104
|
+
else if (selectionFollowsFocus && !row.node.disabled) select(row.node.id, "replace");
|
|
105
|
+
};
|
|
106
|
+
const onKeyDown = (event) => {
|
|
107
|
+
props.onKeyDown?.(event);
|
|
108
|
+
if (event.defaultPrevented || isTypingTarget(event.target)) return;
|
|
109
|
+
const id = tabStopId;
|
|
110
|
+
if (!id) return;
|
|
111
|
+
const i = index.get(id) ?? 0;
|
|
112
|
+
const row = rows[i];
|
|
113
|
+
if (!row) return;
|
|
114
|
+
const mod = event.metaKey || event.ctrlKey;
|
|
115
|
+
let handled = true;
|
|
116
|
+
switch (event.key) {
|
|
117
|
+
case "ArrowDown":
|
|
118
|
+
moveTo(i + 1, event.shiftKey);
|
|
119
|
+
break;
|
|
120
|
+
case "ArrowUp":
|
|
121
|
+
moveTo(i - 1, event.shiftKey);
|
|
122
|
+
break;
|
|
123
|
+
case "Home":
|
|
124
|
+
moveTo(0, event.shiftKey);
|
|
125
|
+
break;
|
|
126
|
+
case "End":
|
|
127
|
+
moveTo(rows.length - 1, event.shiftKey);
|
|
128
|
+
break;
|
|
129
|
+
case "ArrowRight":
|
|
130
|
+
if (row.expandable && !row.expanded) setExpanded(row, true);
|
|
131
|
+
else if (row.expanded && rows[i + 1]?.parentId === row.node.id) moveTo(i + 1, event.shiftKey);
|
|
132
|
+
break;
|
|
133
|
+
case "ArrowLeft":
|
|
134
|
+
if (row.expanded) setExpanded(row, false);
|
|
135
|
+
else if (row.parentId) moveTo(index.get(row.parentId) ?? i, event.shiftKey);
|
|
136
|
+
break;
|
|
137
|
+
case "Enter":
|
|
138
|
+
if (row.node.disabled) break;
|
|
139
|
+
select(row.node.id, "replace");
|
|
140
|
+
onAction?.(row.node.id);
|
|
141
|
+
break;
|
|
142
|
+
case " ":
|
|
143
|
+
select(row.node.id, selectionMode === "multiple" ? event.shiftKey ? "range" : "toggle" : "replace");
|
|
144
|
+
break;
|
|
145
|
+
case "a":
|
|
146
|
+
if (mod && selectionMode === "multiple") onSelectedChange(rows.filter((r) => !r.node.disabled).map((r) => r.node.id));
|
|
147
|
+
else handled = false;
|
|
148
|
+
break;
|
|
149
|
+
case "ContextMenu":
|
|
150
|
+
onRowContextMenu?.(row.node.id, event);
|
|
151
|
+
break;
|
|
152
|
+
default: handled = false;
|
|
153
|
+
}
|
|
154
|
+
if (!handled && event.key.length === 1 && !mod && !event.altKey) {
|
|
155
|
+
const now = event.timeStamp;
|
|
156
|
+
const t = typeahead.current;
|
|
157
|
+
t.text = now - t.at > 600 ? event.key : t.text + event.key;
|
|
158
|
+
t.at = now;
|
|
159
|
+
const query = t.text.toLowerCase();
|
|
160
|
+
const start = t.text.length === 1 ? i + 1 : i;
|
|
161
|
+
for (let k = 0; k < rows.length; k++) {
|
|
162
|
+
const r = rows[(start + k) % rows.length];
|
|
163
|
+
if (r && r.node.label.toLowerCase().startsWith(query)) {
|
|
164
|
+
moveTo(index.get(r.node.id) ?? 0, false);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
handled = true;
|
|
169
|
+
}
|
|
170
|
+
if (handled) {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
event.stopPropagation();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
if (rows.length === 0 && empty) return /* @__PURE__ */ jsx("div", {
|
|
176
|
+
"data-slot": "tree-view",
|
|
177
|
+
"data-empty": true,
|
|
178
|
+
className: cn("text-[13px]", className),
|
|
179
|
+
...props,
|
|
180
|
+
children: empty
|
|
181
|
+
});
|
|
182
|
+
return /* @__PURE__ */ jsx("div", {
|
|
183
|
+
ref: treeRef,
|
|
184
|
+
role: "tree",
|
|
185
|
+
tabIndex: -1,
|
|
186
|
+
"data-slot": "tree-view",
|
|
187
|
+
"data-density": density,
|
|
188
|
+
"aria-multiselectable": selectionMode === "multiple" || void 0,
|
|
189
|
+
className: cn("group/tree flex flex-col py-1 text-[13px] select-none", className),
|
|
190
|
+
...props,
|
|
191
|
+
onKeyDown,
|
|
192
|
+
onFocus: (event) => {
|
|
193
|
+
hadFocus.current = true;
|
|
194
|
+
if (event.target === event.currentTarget && tabStopId) rowRefs.current.get(tabStopId)?.focus();
|
|
195
|
+
props.onFocus?.(event);
|
|
196
|
+
},
|
|
197
|
+
onBlur: (event) => {
|
|
198
|
+
if (!treeRef.current?.contains(event.relatedTarget)) hadFocus.current = false;
|
|
199
|
+
props.onBlur?.(event);
|
|
200
|
+
},
|
|
201
|
+
children: rows.map((row) => {
|
|
202
|
+
const { node } = row;
|
|
203
|
+
const isSelected = selectedSet.has(node.id);
|
|
204
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
205
|
+
ref: (el) => {
|
|
206
|
+
if (el) rowRefs.current.set(node.id, el);
|
|
207
|
+
else rowRefs.current.delete(node.id);
|
|
208
|
+
},
|
|
209
|
+
role: "treeitem",
|
|
210
|
+
"data-slot": "tree-item",
|
|
211
|
+
"data-id": node.id,
|
|
212
|
+
"aria-level": row.level,
|
|
213
|
+
"aria-setsize": row.setSize,
|
|
214
|
+
"aria-posinset": row.posInSet,
|
|
215
|
+
"aria-expanded": row.expandable ? row.expanded : void 0,
|
|
216
|
+
"aria-selected": isSelected,
|
|
217
|
+
"aria-disabled": node.disabled || void 0,
|
|
218
|
+
"aria-busy": row.expanded && node.loading || void 0,
|
|
219
|
+
"aria-label": node.label,
|
|
220
|
+
tabIndex: node.id === tabStopId ? 0 : -1,
|
|
221
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
222
|
+
style: { paddingInlineStart: `${(row.level - 1) * 12 + 4}px` },
|
|
223
|
+
className: cn("flex h-7 shrink-0 cursor-default items-center gap-1 rounded-sm pe-2 outline-none group-data-[density=compact]/tree:h-6", "hover:bg-muted/70 data-[state=selected]:bg-brand-soft/70 data-[state=selected]:text-foreground", "focus-visible:shadow-[inset_0_0_0_1px_var(--ring)] aria-disabled:opacity-50"),
|
|
224
|
+
onFocus: () => setFocusedId(node.id),
|
|
225
|
+
onClick: (event) => {
|
|
226
|
+
if (isTypingTarget(event.target)) return;
|
|
227
|
+
select(node.id, event.shiftKey ? "range" : event.metaKey || event.ctrlKey ? "toggle" : "replace");
|
|
228
|
+
if (!event.shiftKey && !event.metaKey && !event.ctrlKey && row.expandable && selectionMode === "single") setExpanded(row, !row.expanded);
|
|
229
|
+
},
|
|
230
|
+
onDoubleClick: (event) => {
|
|
231
|
+
if (!isTypingTarget(event.target) && !node.disabled) onAction?.(node.id);
|
|
232
|
+
},
|
|
233
|
+
onContextMenu: onRowContextMenu ? (event) => onRowContextMenu(node.id, event) : void 0,
|
|
234
|
+
children: [
|
|
235
|
+
/* @__PURE__ */ jsx("span", {
|
|
236
|
+
"aria-hidden": true,
|
|
237
|
+
className: "flex size-4 shrink-0 items-center justify-center text-muted-foreground",
|
|
238
|
+
onClick: (event) => {
|
|
239
|
+
if (!row.expandable) return;
|
|
240
|
+
event.stopPropagation();
|
|
241
|
+
setExpanded(row, !row.expanded);
|
|
242
|
+
},
|
|
243
|
+
children: row.expandable && /* @__PURE__ */ jsx(ChevronRight, { className: cn("size-3.5 motion-safe:transition-transform", row.expanded && "rotate-90") })
|
|
244
|
+
}),
|
|
245
|
+
node.icon && /* @__PURE__ */ jsx("span", {
|
|
246
|
+
"aria-hidden": true,
|
|
247
|
+
className: "flex shrink-0 text-muted-foreground [&_svg]:size-4",
|
|
248
|
+
children: node.icon
|
|
249
|
+
}),
|
|
250
|
+
/* @__PURE__ */ jsx("span", {
|
|
251
|
+
className: "min-w-0 flex-1 truncate",
|
|
252
|
+
children: renderLabel ? renderLabel(node) : node.label
|
|
253
|
+
}),
|
|
254
|
+
node.meta && /* @__PURE__ */ jsx("span", {
|
|
255
|
+
className: "shrink-0 text-xs text-muted-foreground",
|
|
256
|
+
children: node.meta
|
|
257
|
+
})
|
|
258
|
+
]
|
|
259
|
+
}), row.expanded && node.loading && !node.children?.length && /* @__PURE__ */ jsxs("div", {
|
|
260
|
+
role: "presentation",
|
|
261
|
+
"data-slot": "tree-loading",
|
|
262
|
+
style: { paddingInlineStart: `${row.level * 12 + 8}px` },
|
|
263
|
+
className: "flex h-7 items-center gap-2 text-muted-foreground group-data-[density=compact]/tree:h-6",
|
|
264
|
+
children: [/* @__PURE__ */ jsx(Spinner, {
|
|
265
|
+
className: "size-3.5",
|
|
266
|
+
label: `Loading ${node.label}`
|
|
267
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
268
|
+
"aria-hidden": true,
|
|
269
|
+
children: "Loading…"
|
|
270
|
+
})]
|
|
271
|
+
})] }, node.id);
|
|
272
|
+
})
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
//#endregion
|
|
276
|
+
export { TreeView, flattenTree };
|
|
277
|
+
|
|
278
|
+
//# sourceMappingURL=tree-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-view.js","names":[],"sources":["../../src/components/tree-view.tsx"],"sourcesContent":["import ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Spinner } from './spinner';\n\nexport interface TreeNode {\n /** Stable identity. Keep it across renders (a path, a database id). */\n id: string;\n /** Plain text: the accessible name and the typeahead key. */\n label: string;\n icon?: React.ReactNode;\n /** Undefined: a leaf, unless `hasChildren` says the children load later. */\n children?: TreeNode[];\n /** Expandable before its children are known; expanding calls onLoadChildren. */\n hasChildren?: boolean;\n /** Children are being fetched; shows a loading row while expanded. */\n loading?: boolean;\n disabled?: boolean;\n /** Trailing detail, such as a git status letter or a count. */\n meta?: React.ReactNode;\n}\n\nexport interface TreeViewProps extends Omit<\n React.ComponentProps<'div'>,\n 'children' | 'onSelect' | 'aria-label'\n> {\n nodes: TreeNode[];\n /** Required: what the tree holds, e.g. \"Files\". */\n 'aria-label': string;\n expanded: string[];\n onExpandedChange: (ids: string[]) => void;\n selected: string[];\n onSelectedChange: (ids: string[]) => void;\n /** `multiple`: Shift extends a range, Ctrl/⌘ toggles, Space toggles. */\n selectionMode?: 'single' | 'multiple';\n /** Move selection with focus on arrow keys (a file explorer); default off. */\n selectionFollowsFocus?: boolean;\n /** Enter or double-click: open the file, run the item. */\n onAction?: (id: string) => void;\n /** Called once when a node with `hasChildren` and no children expands. */\n onLoadChildren?: (id: string) => void;\n /** Replace the label, e.g. with a rename input. Keys typed in an input never move focus. */\n renderLabel?: (node: TreeNode) => React.ReactNode;\n /** `compact` 24px rows for desktop explorers, `default` 28px. */\n density?: 'compact' | 'default';\n /** Shown when `nodes` is empty. */\n empty?: React.ReactNode;\n /** Right-click or the context-menu key on a row. */\n onRowContextMenu?: (id: string, event: React.MouseEvent | React.KeyboardEvent) => void;\n}\n\ninterface Row {\n node: TreeNode;\n level: number;\n parentId: string | null;\n setSize: number;\n posInSet: number;\n expandable: boolean;\n expanded: boolean;\n}\n\nconst isExpandable = (n: TreeNode) => (n.children?.length ?? 0) > 0 || Boolean(n.hasChildren);\n\n/** The rows a person can see, in order, with the ARIA position data for each. */\nexport function flattenTree(nodes: TreeNode[], expanded: ReadonlySet<string>): Row[] {\n const rows: Row[] = [];\n const walk = (list: TreeNode[], level: number, parentId: string | null) => {\n list.forEach((node, i) => {\n const expandable = isExpandable(node);\n const open = expandable && expanded.has(node.id);\n rows.push({\n node,\n level,\n parentId,\n setSize: list.length,\n posInSet: i + 1,\n expandable,\n expanded: open,\n });\n if (open && node.children) walk(node.children, level + 1, node.id);\n });\n };\n walk(nodes, 1, null);\n return rows;\n}\n\nconst isTypingTarget = (target: EventTarget | null) =>\n target instanceof HTMLElement &&\n (target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName));\n\n/**\n * A file-explorer style tree. Everything is controlled: the app owns which\n * nodes are expanded and selected, and file operations are callbacks. Rows\n * render flat (role=\"treeitem\" with aria-level), one tab stop for the tree,\n * arrows to move, Right/Left to open and close, Home/End, typeahead.\n */\nfunction TreeView({\n nodes,\n expanded,\n onExpandedChange,\n selected,\n onSelectedChange,\n selectionMode = 'single',\n selectionFollowsFocus = false,\n onAction,\n onLoadChildren,\n renderLabel,\n density = 'default',\n empty,\n onRowContextMenu,\n className,\n ...props\n}: TreeViewProps) {\n const expandedSet = React.useMemo(() => new Set(expanded), [expanded]);\n const selectedSet = React.useMemo(() => new Set(selected), [selected]);\n const rows = React.useMemo(() => flattenTree(nodes, expandedSet), [nodes, expandedSet]);\n const index = React.useMemo(() => new Map(rows.map((r, i) => [r.node.id, i])), [rows]);\n\n const [focusedId, setFocusedId] = React.useState<string | null>(null);\n const anchorId = React.useRef<string | null>(null);\n const rowRefs = React.useRef(new Map<string, HTMLDivElement>());\n const treeRef = React.useRef<HTMLDivElement>(null);\n const hadFocus = React.useRef(false);\n const lastIds = React.useRef<string[]>([]);\n const lastParents = React.useRef(new Map<string, string | null>());\n const typeahead = React.useRef({ text: '', at: 0 });\n\n // The tab stop: the focused row if it is still visible, else the first\n // selected visible row, else the first row.\n const tabStopId =\n (focusedId && index.has(focusedId) ? focusedId : null) ??\n rows.find((r) => selectedSet.has(r.node.id))?.node.id ??\n rows[0]?.node.id ??\n null;\n\n const focusRow = React.useCallback((id: string) => {\n setFocusedId(id);\n rowRefs.current.get(id)?.focus();\n rowRefs.current.get(id)?.scrollIntoView?.({ block: 'nearest' });\n }, []);\n\n // Focus recovery: when the focused row disappears (deleted, or a parent\n // collapsed), move to its nearest visible ancestor, else the row now at its\n // old position. Only takes DOM focus if the tree had it.\n React.useLayoutEffect(() => {\n if (focusedId && !index.has(focusedId)) {\n let next: string | null = null;\n let parent = lastParents.current.get(focusedId) ?? null;\n while (parent && !index.has(parent)) parent = lastParents.current.get(parent) ?? null;\n const was = Math.max(0, lastIds.current.indexOf(focusedId));\n next = parent ?? rows[Math.min(was, rows.length - 1)]?.node.id ?? null;\n setFocusedId(next);\n const active = document.activeElement;\n if (next && hadFocus.current && (!active || active === document.body))\n rowRefs.current.get(next)?.focus();\n }\n lastIds.current = rows.map((r) => r.node.id);\n lastParents.current = new Map(rows.map((r) => [r.node.id, r.parentId]));\n }, [rows, index, focusedId]);\n\n const setExpanded = (row: Row, open: boolean) => {\n if (!row.expandable || row.expanded === open) return;\n const id = row.node.id;\n onExpandedChange(open ? [...expanded, id] : expanded.filter((e) => e !== id));\n if (open && !row.node.children && row.node.hasChildren) onLoadChildren?.(id);\n };\n\n const selectRange = (toId: string) => {\n const from = index.get(anchorId.current ?? toId) ?? 0;\n const to = index.get(toId) ?? 0;\n const [a, b] = from < to ? [from, to] : [to, from];\n onSelectedChange(\n rows\n .slice(a, b + 1)\n .filter((r) => !r.node.disabled)\n .map((r) => r.node.id),\n );\n };\n\n const select = (id: string, mode: 'replace' | 'toggle' | 'range') => {\n if (rows[index.get(id) ?? -1]?.node.disabled) return;\n if (selectionMode === 'single' || mode === 'replace') {\n anchorId.current = id;\n onSelectedChange([id]);\n } else if (mode === 'toggle') {\n anchorId.current = id;\n onSelectedChange(selectedSet.has(id) ? selected.filter((s) => s !== id) : [...selected, id]);\n } else selectRange(id);\n };\n\n const moveTo = (i: number, extend: boolean) => {\n const row = rows[Math.max(0, Math.min(rows.length - 1, i))];\n if (!row) return;\n focusRow(row.node.id);\n if (selectionMode === 'multiple' && extend) selectRange(row.node.id);\n else if (selectionFollowsFocus && !row.node.disabled) select(row.node.id, 'replace');\n };\n\n const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n props.onKeyDown?.(event);\n if (event.defaultPrevented || isTypingTarget(event.target)) return;\n const id = tabStopId;\n if (!id) return;\n const i = index.get(id) ?? 0;\n const row = rows[i];\n if (!row) return;\n const mod = event.metaKey || event.ctrlKey;\n let handled = true;\n switch (event.key) {\n case 'ArrowDown':\n moveTo(i + 1, event.shiftKey);\n break;\n case 'ArrowUp':\n moveTo(i - 1, event.shiftKey);\n break;\n case 'Home':\n moveTo(0, event.shiftKey);\n break;\n case 'End':\n moveTo(rows.length - 1, event.shiftKey);\n break;\n case 'ArrowRight':\n if (row.expandable && !row.expanded) setExpanded(row, true);\n else if (row.expanded && rows[i + 1]?.parentId === row.node.id)\n moveTo(i + 1, event.shiftKey);\n break;\n case 'ArrowLeft':\n if (row.expanded) setExpanded(row, false);\n else if (row.parentId) moveTo(index.get(row.parentId) ?? i, event.shiftKey);\n break;\n case 'Enter':\n if (row.node.disabled) break;\n select(row.node.id, 'replace');\n onAction?.(row.node.id);\n break;\n case ' ':\n select(\n row.node.id,\n selectionMode === 'multiple' ? (event.shiftKey ? 'range' : 'toggle') : 'replace',\n );\n break;\n case 'a':\n if (mod && selectionMode === 'multiple') {\n onSelectedChange(rows.filter((r) => !r.node.disabled).map((r) => r.node.id));\n } else handled = false;\n break;\n case 'ContextMenu':\n onRowContextMenu?.(row.node.id, event);\n break;\n default:\n handled = false;\n }\n if (!handled && event.key.length === 1 && !mod && !event.altKey) {\n // Typeahead: jump to the next row whose label starts with what was typed.\n const now = event.timeStamp;\n const t = typeahead.current;\n t.text = now - t.at > 600 ? event.key : t.text + event.key;\n t.at = now;\n const query = t.text.toLowerCase();\n const start = t.text.length === 1 ? i + 1 : i;\n for (let k = 0; k < rows.length; k++) {\n const r = rows[(start + k) % rows.length];\n if (r && r.node.label.toLowerCase().startsWith(query)) {\n moveTo(index.get(r.node.id) ?? 0, false);\n break;\n }\n }\n handled = true;\n }\n if (handled) {\n event.preventDefault();\n event.stopPropagation();\n }\n };\n\n if (rows.length === 0 && empty) {\n return (\n <div data-slot=\"tree-view\" data-empty className={cn('text-[13px]', className)} {...props}>\n {empty}\n </div>\n );\n }\n\n return (\n <div\n ref={treeRef}\n role=\"tree\"\n tabIndex={-1}\n data-slot=\"tree-view\"\n data-density={density}\n aria-multiselectable={selectionMode === 'multiple' || undefined}\n className={cn('group/tree flex flex-col py-1 text-[13px] select-none', className)}\n {...props}\n onKeyDown={onKeyDown}\n onFocus={(event) => {\n hadFocus.current = true;\n // Focus landing on the tree itself (a click on empty space) goes to the tab stop.\n if (event.target === event.currentTarget && tabStopId)\n rowRefs.current.get(tabStopId)?.focus();\n props.onFocus?.(event);\n }}\n onBlur={(event) => {\n if (!treeRef.current?.contains(event.relatedTarget)) hadFocus.current = false;\n props.onBlur?.(event);\n }}\n >\n {rows.map((row) => {\n const { node } = row;\n const isSelected = selectedSet.has(node.id);\n return (\n <React.Fragment key={node.id}>\n {/* Keys are handled once on the tree, for whichever row has focus. */}\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}\n <div\n ref={(el) => {\n if (el) rowRefs.current.set(node.id, el);\n else rowRefs.current.delete(node.id);\n }}\n role=\"treeitem\"\n data-slot=\"tree-item\"\n data-id={node.id}\n aria-level={row.level}\n aria-setsize={row.setSize}\n aria-posinset={row.posInSet}\n aria-expanded={row.expandable ? row.expanded : undefined}\n aria-selected={isSelected}\n aria-disabled={node.disabled || undefined}\n aria-busy={(row.expanded && node.loading) || undefined}\n aria-label={node.label}\n tabIndex={node.id === tabStopId ? 0 : -1}\n data-state={isSelected ? 'selected' : undefined}\n style={{ paddingInlineStart: `${(row.level - 1) * 12 + 4}px` }}\n className={cn(\n 'flex h-7 shrink-0 cursor-default items-center gap-1 rounded-sm pe-2 outline-none group-data-[density=compact]/tree:h-6',\n 'hover:bg-muted/70 data-[state=selected]:bg-brand-soft/70 data-[state=selected]:text-foreground',\n 'focus-visible:shadow-[inset_0_0_0_1px_var(--ring)] aria-disabled:opacity-50',\n )}\n onFocus={() => setFocusedId(node.id)}\n onClick={(event) => {\n if (isTypingTarget(event.target)) return;\n select(\n node.id,\n event.shiftKey ? 'range' : event.metaKey || event.ctrlKey ? 'toggle' : 'replace',\n );\n if (\n !event.shiftKey &&\n !event.metaKey &&\n !event.ctrlKey &&\n row.expandable &&\n selectionMode === 'single'\n )\n setExpanded(row, !row.expanded);\n }}\n onDoubleClick={(event) => {\n if (!isTypingTarget(event.target) && !node.disabled) onAction?.(node.id);\n }}\n onContextMenu={\n onRowContextMenu ? (event) => onRowContextMenu(node.id, event) : undefined\n }\n >\n {/* A pointer shortcut only: Right and Left expand and collapse from the keyboard. */}\n <span\n aria-hidden\n className=\"flex size-4 shrink-0 items-center justify-center text-muted-foreground\"\n onClick={(event) => {\n if (!row.expandable) return;\n event.stopPropagation();\n setExpanded(row, !row.expanded);\n }}\n >\n {row.expandable && (\n <ChevronRight\n className={cn(\n 'size-3.5 motion-safe:transition-transform',\n row.expanded && 'rotate-90',\n )}\n />\n )}\n </span>\n {node.icon && (\n <span aria-hidden className=\"flex shrink-0 text-muted-foreground [&_svg]:size-4\">\n {node.icon}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate\">\n {renderLabel ? renderLabel(node) : node.label}\n </span>\n {node.meta && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">{node.meta}</span>\n )}\n </div>\n {row.expanded && node.loading && !node.children?.length && (\n <div\n role=\"presentation\"\n data-slot=\"tree-loading\"\n style={{ paddingInlineStart: `${row.level * 12 + 8}px` }}\n className=\"flex h-7 items-center gap-2 text-muted-foreground group-data-[density=compact]/tree:h-6\"\n >\n <Spinner className=\"size-3.5\" label={`Loading ${node.label}`} />\n <span aria-hidden>Loading…</span>\n </div>\n )}\n </React.Fragment>\n );\n })}\n </div>\n );\n}\n\nexport { TreeView };\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,10 +15,12 @@ export * from './components/collapsible';
|
|
|
15
15
|
export * from './components/combobox';
|
|
16
16
|
export * from './components/command';
|
|
17
17
|
export * from './components/composer';
|
|
18
|
+
export * from './components/context-menu';
|
|
18
19
|
export * from './components/conversation';
|
|
19
20
|
export * from './components/copy-button';
|
|
20
21
|
export * from './components/dialog';
|
|
21
22
|
export * from './components/dropdown-menu';
|
|
23
|
+
export * from './components/editor-tabs';
|
|
22
24
|
export * from './components/empty-state';
|
|
23
25
|
export * from './components/field';
|
|
24
26
|
export * from './components/icon-button';
|
|
@@ -26,14 +28,17 @@ export * from './components/input';
|
|
|
26
28
|
export * from './components/kbd';
|
|
27
29
|
export * from './components/label';
|
|
28
30
|
export * from './components/markdown';
|
|
31
|
+
export * from './components/menubar';
|
|
29
32
|
export * from './components/message';
|
|
30
33
|
export * from './components/navigation-menu';
|
|
34
|
+
export * from './components/onboarding-checklist';
|
|
31
35
|
export * from './components/page-header';
|
|
32
36
|
export * from './components/pagination';
|
|
33
37
|
export * from './components/popover';
|
|
34
38
|
export * from './components/progress';
|
|
35
39
|
export * from './components/radio-group';
|
|
36
40
|
export * from './components/reasoning';
|
|
41
|
+
export * from './components/resizable';
|
|
37
42
|
export * from './components/scroll-area';
|
|
38
43
|
export * from './components/secret-input';
|
|
39
44
|
export * from './components/select';
|
|
@@ -54,3 +59,5 @@ export * from './components/toaster';
|
|
|
54
59
|
export * from './components/tool-call';
|
|
55
60
|
export * from './components/toolbar';
|
|
56
61
|
export * from './components/tooltip';
|
|
62
|
+
export * from './components/tour';
|
|
63
|
+
export * from './components/tree-view';
|
package/dist/index.js
CHANGED
|
@@ -15,28 +15,33 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./component
|
|
|
15
15
|
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from "./components/dialog.js";
|
|
16
16
|
import { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from "./components/command.js";
|
|
17
17
|
import { Input, fieldClasses } from "./components/input.js";
|
|
18
|
-
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, surfaceClasses } from "./components/popover.js";
|
|
18
|
+
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, menuItemClasses, surfaceClasses } from "./components/popover.js";
|
|
19
19
|
import { Spinner } from "./components/spinner.js";
|
|
20
20
|
import { Combobox } from "./components/combobox.js";
|
|
21
21
|
import { Composer, Suggestions } from "./components/composer.js";
|
|
22
|
+
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "./components/context-menu.js";
|
|
22
23
|
import { Conversation } from "./components/conversation.js";
|
|
23
24
|
import { IconButton } from "./components/icon-button.js";
|
|
24
25
|
import { Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, toastVariants } from "./components/toast.js";
|
|
25
26
|
import { Toaster, toast } from "./components/toaster.js";
|
|
26
27
|
import { CopyButton } from "./components/copy-button.js";
|
|
27
28
|
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "./components/dropdown-menu.js";
|
|
29
|
+
import { EditorTabs } from "./components/editor-tabs.js";
|
|
28
30
|
import { EmptyState, EmptyStateActions, EmptyStateDescription, EmptyStateIcon, EmptyStateTitle } from "./components/empty-state.js";
|
|
29
31
|
import { Field, FieldDescription, FieldError, FieldHeader, FieldHint, FieldLabel } from "./components/field.js";
|
|
30
32
|
import { Kbd, KbdGroup } from "./components/kbd.js";
|
|
31
33
|
import { Label } from "./components/label.js";
|
|
32
34
|
import { CodeBlock, Markdown, parseMarkdown } from "./components/markdown.js";
|
|
35
|
+
import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from "./components/menubar.js";
|
|
33
36
|
import { Message } from "./components/message.js";
|
|
34
37
|
import { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, navigationMenuTriggerStyle } from "./components/navigation-menu.js";
|
|
38
|
+
import { Progress } from "./components/progress.js";
|
|
39
|
+
import { OnboardingChecklist } from "./components/onboarding-checklist.js";
|
|
35
40
|
import { PageHeader, PageHeaderActions, PageHeaderDescription, PageHeaderEyebrow, PageHeaderMain, PageHeaderTitle } from "./components/page-header.js";
|
|
36
41
|
import { Pagination, paginationRange } from "./components/pagination.js";
|
|
37
|
-
import { Progress } from "./components/progress.js";
|
|
38
42
|
import { RadioGroup, RadioGroupItem } from "./components/radio-group.js";
|
|
39
43
|
import { Reasoning, StreamingIndicator } from "./components/reasoning.js";
|
|
44
|
+
import { ResizablePanel, ResizablePanelGroup, ResizeHandle, useGroupRef, usePanelRef } from "./components/resizable.js";
|
|
40
45
|
import { ScrollArea, ScrollBar } from "./components/scroll-area.js";
|
|
41
46
|
import { SecretInput } from "./components/secret-input.js";
|
|
42
47
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from "./components/select.js";
|
|
@@ -54,4 +59,6 @@ import { Textarea } from "./components/textarea.js";
|
|
|
54
59
|
import { ToolApproval, ToolCall } from "./components/tool-call.js";
|
|
55
60
|
import { Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarSpacer } from "./components/toolbar.js";
|
|
56
61
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./components/tooltip.js";
|
|
57
|
-
|
|
62
|
+
import { Spotlight, Tour, TourAnchor, findTourTarget, tourTarget, waitForTourTarget } from "./components/tour.js";
|
|
63
|
+
import { TreeView, flattenTree } from "./components/tree-view.js";
|
|
64
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, AppShellBody, AppShellContent, AppShellHeader, AppShellMain, AppShellSidebar, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Card, CardAction, CardContent, CardDescription, CardEyebrow, CardFooter, CardHeader, CardTitle, Checkbox, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Composer, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, Conversation, CopyButton, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EditorTabs, EmptyState, EmptyStateActions, EmptyStateDescription, EmptyStateIcon, EmptyStateTitle, Field, FieldDescription, FieldError, FieldHeader, FieldHint, FieldLabel, IconButton, Input, Kbd, KbdGroup, Label, Markdown, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Message, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, OnboardingChecklist, PageHeader, PageHeaderActions, PageHeaderDescription, PageHeaderEyebrow, PageHeaderMain, PageHeaderTitle, Pagination, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, Reasoning, ResizablePanel, ResizablePanelGroup, ResizeHandle, ScrollArea, ScrollBar, SecretInput, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Skeleton, Slider, Spinner, Spotlight, StatCard, Status, StatusDot, Steps, StreamingIndicator, Suggestions, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, ToolApproval, ToolCall, Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarSpacer, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Tour, TourAnchor, TreeView, alertVariants, badgeVariants, brand, buttonVariants, cardVariants, cn, dark, fieldClasses, findTourTarget, flattenTree, fontMono, fontSans, isApplePlatform, light, menuItemClasses, modKeyLabel, motion, navigationMenuTriggerStyle, paginationRange, parseMarkdown, radius, shadow, shortcutLabel, statusDotVariants, surfaceClasses, toast, toastVariants, tokens, tourTarget, useGroupRef, usePanelRef, waitForTourTarget };
|