@robr0/design-system 0.8.0 → 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 +3 -3
- package/components/Accordion/Accordion.js +1 -0
- package/components/AgentPlan/AgentPlan.css +2 -2
- package/components/AgentPlan/AgentPlan.js +1 -0
- package/components/AgentStatus/AgentStatus.js +1 -0
- package/components/AiButton/AiButton.js +1 -0
- package/components/AlertDialog/AlertDialog.js +1 -0
- package/components/AnchorNav/AnchorNav.css +63 -0
- package/components/AnchorNav/AnchorNav.d.ts +33 -0
- package/components/AnchorNav/AnchorNav.js +82 -0
- package/components/AppLayout/AppLayout.js +1 -0
- package/components/AppSidebar/AppSidebar.js +1 -0
- package/components/Avatar/Avatar.js +1 -0
- package/components/Button/Button.js +1 -0
- package/components/Card/Card.js +1 -0
- package/components/Carousel/Carousel.js +1 -0
- package/components/ChatThread/ChatThread.js +1 -0
- package/components/Checkbox/Checkbox.js +1 -0
- package/components/CodeBlock/CodeBlock.js +1 -0
- package/components/CodeDiff/CodeDiff.css +175 -0
- package/components/CodeDiff/CodeDiff.d.ts +58 -0
- package/components/CodeDiff/CodeDiff.js +114 -0
- package/components/ColorPicker/ColorPicker.js +1 -0
- package/components/Combobox/Combobox.js +1 -0
- package/components/CommandPalette/CommandPalette.js +1 -0
- package/components/Composer/Composer.js +1 -0
- package/components/ContactCard/ContactCard.js +1 -0
- package/components/ContextMenu/ContextMenu.js +1 -0
- package/components/DataTable/DataTable.js +1 -0
- package/components/DateInput/DateInput.js +1 -0
- package/components/DatePicker/DatePicker.js +1 -0
- package/components/Dialog/Dialog.js +1 -0
- package/components/Drawer/Drawer.js +1 -0
- package/components/Dropdown/Dropdown.js +1 -0
- package/components/DropdownMenu/DropdownMenu.css +1 -1
- package/components/DropdownMenu/DropdownMenu.js +1 -0
- package/components/EventCalendar/EventCalendar.js +1 -0
- package/components/Field/Field.js +1 -0
- package/components/Field/FieldContext.js +1 -0
- package/components/FileInput/FileInput.js +1 -0
- package/components/Input/Input.js +1 -0
- package/components/InterruptCard/InterruptCard.css +11 -21
- package/components/InterruptCard/InterruptCard.d.ts +5 -6
- package/components/MessageCard/MessageCard.css +1 -2
- package/components/ModelPicker/ModelPicker.css +3 -1
- package/components/ModelPicker/ModelPicker.js +1 -0
- package/components/NavList/NavList.js +1 -0
- package/components/NotificationCenter/NotificationCenter.js +1 -0
- package/components/NumberInput/NumberInput.css +154 -0
- package/components/NumberInput/NumberInput.d.ts +44 -0
- package/components/NumberInput/NumberInput.js +147 -0
- package/components/Pagination/Pagination.js +1 -0
- package/components/PinInput/PinInput.css +92 -0
- package/components/PinInput/PinInput.d.ts +46 -0
- package/components/PinInput/PinInput.js +161 -0
- package/components/Popover/Popover.css +5 -6
- package/components/Popover/Popover.js +1 -0
- package/components/RadioButton/RadioButton.js +1 -0
- package/components/Reasoning/Reasoning.js +1 -0
- package/components/SegmentedControl/SegmentedControl.js +1 -0
- package/components/SelectionCard/SelectionCard.js +1 -0
- package/components/ShaderField/ShaderField.js +1 -0
- package/components/ShaderField/useShaderField.js +1 -0
- package/components/Slider/Slider.js +1 -0
- package/components/Sparkline/Sparkline.css +52 -0
- package/components/Sparkline/Sparkline.d.ts +49 -0
- package/components/Sparkline/Sparkline.js +86 -0
- package/components/Stepper/Stepper.css +207 -0
- package/components/Stepper/Stepper.d.ts +41 -0
- package/components/Stepper/Stepper.js +61 -0
- package/components/Tabs/Tabs.js +1 -0
- package/components/TagInput/TagInput.css +160 -0
- package/components/TagInput/TagInput.d.ts +43 -0
- package/components/TagInput/TagInput.js +137 -0
- package/components/Textarea/Textarea.js +1 -0
- package/components/TimePicker/TimePicker.css +230 -0
- package/components/TimePicker/TimePicker.d.ts +46 -0
- package/components/TimePicker/TimePicker.js +246 -0
- package/components/Toast/Toast.js +1 -0
- package/components/ToggleGroup/ToggleGroup.js +1 -0
- package/components/ToggleSwitch/ToggleSwitch.js +1 -0
- package/components/ToolCall/ToolCall.css +7 -11
- package/components/ToolCall/ToolCall.js +1 -0
- package/components/Tooltip/Tooltip.js +1 -0
- package/components/TreeView/TreeView.css +119 -0
- package/components/TreeView/TreeView.d.ts +45 -0
- package/components/TreeView/TreeView.js +232 -0
- package/components/registry.d.ts +22 -6
- package/components/registry.js +3 -1
- package/components/registry.json +206 -20
- package/components/registry.json.d.ts +206 -20
- package/components/registry.json.js +2 -2
- package/index.d.ts +11 -2
- package/index.js +21 -1
- package/package.json +1 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
TREEVIEW COMPONENT
|
|
3
|
+
Collapsible hierarchy for files, folders,
|
|
4
|
+
and nested structures
|
|
5
|
+
============================================ */
|
|
6
|
+
|
|
7
|
+
/* Base */
|
|
8
|
+
|
|
9
|
+
.ds-treeview {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
width: 100%;
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 0;
|
|
15
|
+
list-style: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* ============================================
|
|
19
|
+
ITEM — the focusable treeitem (roving tabindex)
|
|
20
|
+
============================================ */
|
|
21
|
+
|
|
22
|
+
.ds-treeview__item {
|
|
23
|
+
outline: none;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* The focus ring draws on the item's own row, never on the subtree */
|
|
27
|
+
.ds-treeview__item:focus-visible > .ds-treeview__row {
|
|
28
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
29
|
+
outline-offset: -2px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ============================================
|
|
33
|
+
ROW — one line of the tree
|
|
34
|
+
Indentation steps per depth via a custom
|
|
35
|
+
property the component sets inline.
|
|
36
|
+
============================================ */
|
|
37
|
+
|
|
38
|
+
.ds-treeview__row {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: var(--gap-xs);
|
|
42
|
+
padding: var(--padding-xxs) var(--padding-sm);
|
|
43
|
+
padding-left: calc(var(--padding-sm) + var(--ds-treeview-depth, 0) * var(--gap-md));
|
|
44
|
+
border-radius: var(--radius-sm);
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* States */
|
|
50
|
+
|
|
51
|
+
.ds-treeview__row:hover {
|
|
52
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ds-treeview__row--selected {
|
|
56
|
+
background-color: var(--color-action-passive-bg-active);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ds-treeview__row--selected .ds-treeview__label {
|
|
60
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* ============================================
|
|
64
|
+
CHEVRON — rotates a quarter turn on expand
|
|
65
|
+
============================================ */
|
|
66
|
+
|
|
67
|
+
.ds-treeview__chevron {
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
--icon-size: var(--icon-size-sm);
|
|
70
|
+
color: var(--color-icon-primary);
|
|
71
|
+
transition: transform var(--motion-duration-fast) var(--motion-ease-standard);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.ds-treeview__item[aria-expanded='true'] > .ds-treeview__row .ds-treeview__chevron {
|
|
75
|
+
transform: rotate(90deg);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Leaves keep the chevron column so labels align across depths */
|
|
79
|
+
.ds-treeview__chevron--spacer {
|
|
80
|
+
display: inline-block;
|
|
81
|
+
width: var(--icon-size-sm);
|
|
82
|
+
height: var(--icon-size-sm);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* ============================================
|
|
86
|
+
ICON
|
|
87
|
+
============================================ */
|
|
88
|
+
|
|
89
|
+
.ds-treeview__icon {
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
--icon-size: var(--icon-size-sm);
|
|
92
|
+
color: var(--color-icon-primary);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* ============================================
|
|
96
|
+
LABEL
|
|
97
|
+
============================================ */
|
|
98
|
+
|
|
99
|
+
.ds-treeview__label {
|
|
100
|
+
font-family: var(--font-paragraph-sm-family);
|
|
101
|
+
font-size: var(--font-paragraph-sm-size);
|
|
102
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
103
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
104
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
105
|
+
color: var(--color-text-primary);
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
white-space: nowrap;
|
|
108
|
+
text-overflow: ellipsis;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ============================================
|
|
112
|
+
GROUP — nested children
|
|
113
|
+
============================================ */
|
|
114
|
+
|
|
115
|
+
.ds-treeview__group {
|
|
116
|
+
margin: 0;
|
|
117
|
+
padding: 0;
|
|
118
|
+
list-style: none;
|
|
119
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface TreeViewNode {
|
|
3
|
+
/** Unique identifier for the node */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Text shown on the row */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Material Symbol name; defaults to `folder` for branches and `draft` for leaves */
|
|
8
|
+
icon?: string;
|
|
9
|
+
/** Child nodes; a non-empty list makes the node an expandable branch */
|
|
10
|
+
children?: TreeViewNode[];
|
|
11
|
+
}
|
|
12
|
+
/** Props owned by TreeView itself — everything else falls through to the root <ul>. */
|
|
13
|
+
type TreeViewOwnProps = {
|
|
14
|
+
/** Tree data to render */
|
|
15
|
+
nodes: TreeViewNode[];
|
|
16
|
+
/** IDs of initially expanded branches (uncontrolled) */
|
|
17
|
+
defaultExpandedIds?: string[];
|
|
18
|
+
/** Expanded branch IDs (controlled) — pair with `onExpandedChange` */
|
|
19
|
+
expandedIds?: string[];
|
|
20
|
+
/** Called with the full list of expanded branch IDs whenever a branch toggles */
|
|
21
|
+
onExpandedChange?: (ids: string[]) => void;
|
|
22
|
+
/** Selected node ID (controlled) — pair with `onSelect` */
|
|
23
|
+
selectedId?: string;
|
|
24
|
+
/** ID of the initially selected node (uncontrolled) */
|
|
25
|
+
defaultSelectedId?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Called with the node's ID when a row is selected via click, Enter, or
|
|
28
|
+
* Space. Intentionally shadows the native `select` event handler, which
|
|
29
|
+
* has no meaning on a tree widget.
|
|
30
|
+
*/
|
|
31
|
+
onSelect?: (id: string) => void;
|
|
32
|
+
/** Additional CSS classes */
|
|
33
|
+
className?: string;
|
|
34
|
+
};
|
|
35
|
+
export interface TreeViewProps extends TreeViewOwnProps, Omit<React.ComponentPropsWithoutRef<'ul'>, keyof TreeViewOwnProps> {
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* TreeView renders a collapsible hierarchy — files, folders, and other
|
|
39
|
+
* nested structures — as a WAI-ARIA tree. Branches expand and collapse,
|
|
40
|
+
* one node can be selected, and a roving tabindex gives the whole tree a
|
|
41
|
+
* single tab stop with full arrow-key navigation. Expansion and selection
|
|
42
|
+
* each work controlled or uncontrolled.
|
|
43
|
+
*/
|
|
44
|
+
export declare const TreeView: React.ForwardRefExoticComponent<TreeViewProps & React.RefAttributes<HTMLUListElement>>;
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState, useMemo, useRef, useCallback } from "react";
|
|
4
|
+
import "./TreeView.css";
|
|
5
|
+
import "../../fonts/material-symbols.css";
|
|
6
|
+
const isBranchNode = (node) => Array.isArray(node.children) && node.children.length > 0;
|
|
7
|
+
const TreeView = React.forwardRef(
|
|
8
|
+
({
|
|
9
|
+
nodes,
|
|
10
|
+
defaultExpandedIds = [],
|
|
11
|
+
expandedIds,
|
|
12
|
+
onExpandedChange,
|
|
13
|
+
selectedId,
|
|
14
|
+
defaultSelectedId,
|
|
15
|
+
onSelect,
|
|
16
|
+
className = "",
|
|
17
|
+
...rest
|
|
18
|
+
}, ref) => {
|
|
19
|
+
const baseClass = "ds-treeview";
|
|
20
|
+
const baseId = React.useId();
|
|
21
|
+
const [internalExpanded, setInternalExpanded] = useState(
|
|
22
|
+
() => new Set(defaultExpandedIds)
|
|
23
|
+
);
|
|
24
|
+
const [internalSelected, setInternalSelected] = useState(
|
|
25
|
+
defaultSelectedId
|
|
26
|
+
);
|
|
27
|
+
const [focusedId, setFocusedId] = useState(void 0);
|
|
28
|
+
const expandedSet = useMemo(
|
|
29
|
+
() => expandedIds !== void 0 ? new Set(expandedIds) : internalExpanded,
|
|
30
|
+
[expandedIds, internalExpanded]
|
|
31
|
+
);
|
|
32
|
+
const selected = selectedId !== void 0 ? selectedId : internalSelected;
|
|
33
|
+
const itemRefs = useRef(/* @__PURE__ */ new Map());
|
|
34
|
+
const indexById = useMemo(() => {
|
|
35
|
+
const map = /* @__PURE__ */ new Map();
|
|
36
|
+
let i = 0;
|
|
37
|
+
const walk = (list) => {
|
|
38
|
+
for (const node of list) {
|
|
39
|
+
map.set(node.id, i);
|
|
40
|
+
i += 1;
|
|
41
|
+
if (node.children) walk(node.children);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
walk(nodes);
|
|
45
|
+
return map;
|
|
46
|
+
}, [nodes]);
|
|
47
|
+
const parentById = useMemo(() => {
|
|
48
|
+
const map = /* @__PURE__ */ new Map();
|
|
49
|
+
const walk = (list, parent) => {
|
|
50
|
+
for (const node of list) {
|
|
51
|
+
map.set(node.id, parent);
|
|
52
|
+
if (node.children) walk(node.children, node.id);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
walk(nodes);
|
|
56
|
+
return map;
|
|
57
|
+
}, [nodes]);
|
|
58
|
+
const visibleNodes = useMemo(() => {
|
|
59
|
+
const out = [];
|
|
60
|
+
const walk = (list) => {
|
|
61
|
+
for (const node of list) {
|
|
62
|
+
out.push(node);
|
|
63
|
+
if (isBranchNode(node) && expandedSet.has(node.id)) walk(node.children);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
walk(nodes);
|
|
67
|
+
return out;
|
|
68
|
+
}, [nodes, expandedSet]);
|
|
69
|
+
const visibleIds = useMemo(
|
|
70
|
+
() => new Set(visibleNodes.map((node) => node.id)),
|
|
71
|
+
[visibleNodes]
|
|
72
|
+
);
|
|
73
|
+
const tabbableId = focusedId !== void 0 && visibleIds.has(focusedId) ? focusedId : selected !== void 0 && visibleIds.has(selected) ? selected : visibleNodes[0]?.id;
|
|
74
|
+
const commitExpanded = useCallback(
|
|
75
|
+
(next) => {
|
|
76
|
+
if (expandedIds === void 0) setInternalExpanded(next);
|
|
77
|
+
onExpandedChange?.(Array.from(next));
|
|
78
|
+
},
|
|
79
|
+
[expandedIds, onExpandedChange]
|
|
80
|
+
);
|
|
81
|
+
const toggleBranch = useCallback(
|
|
82
|
+
(id) => {
|
|
83
|
+
const next = new Set(expandedSet);
|
|
84
|
+
if (next.has(id)) {
|
|
85
|
+
next.delete(id);
|
|
86
|
+
} else {
|
|
87
|
+
next.add(id);
|
|
88
|
+
}
|
|
89
|
+
commitExpanded(next);
|
|
90
|
+
},
|
|
91
|
+
[expandedSet, commitExpanded]
|
|
92
|
+
);
|
|
93
|
+
const selectNode = useCallback(
|
|
94
|
+
(id) => {
|
|
95
|
+
if (selectedId === void 0) setInternalSelected(id);
|
|
96
|
+
onSelect?.(id);
|
|
97
|
+
},
|
|
98
|
+
[selectedId, onSelect]
|
|
99
|
+
);
|
|
100
|
+
const focusNode = useCallback((id) => {
|
|
101
|
+
if (id === void 0) return;
|
|
102
|
+
setFocusedId(id);
|
|
103
|
+
itemRefs.current.get(id)?.focus();
|
|
104
|
+
}, []);
|
|
105
|
+
const handleKeyDown = (event, node) => {
|
|
106
|
+
const branch = isBranchNode(node);
|
|
107
|
+
const expanded = expandedSet.has(node.id);
|
|
108
|
+
const index = visibleNodes.findIndex((n) => n.id === node.id);
|
|
109
|
+
let handled = true;
|
|
110
|
+
switch (event.key) {
|
|
111
|
+
case "ArrowDown":
|
|
112
|
+
focusNode(visibleNodes[index + 1]?.id);
|
|
113
|
+
break;
|
|
114
|
+
case "ArrowUp":
|
|
115
|
+
focusNode(visibleNodes[index - 1]?.id);
|
|
116
|
+
break;
|
|
117
|
+
case "ArrowRight":
|
|
118
|
+
if (branch && !expanded) {
|
|
119
|
+
toggleBranch(node.id);
|
|
120
|
+
} else if (branch && expanded) {
|
|
121
|
+
focusNode(node.children[0]?.id);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case "ArrowLeft":
|
|
125
|
+
if (branch && expanded) {
|
|
126
|
+
toggleBranch(node.id);
|
|
127
|
+
} else {
|
|
128
|
+
focusNode(parentById.get(node.id));
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
case "Home":
|
|
132
|
+
focusNode(visibleNodes[0]?.id);
|
|
133
|
+
break;
|
|
134
|
+
case "End":
|
|
135
|
+
focusNode(visibleNodes[visibleNodes.length - 1]?.id);
|
|
136
|
+
break;
|
|
137
|
+
case "Enter":
|
|
138
|
+
case " ":
|
|
139
|
+
selectNode(node.id);
|
|
140
|
+
break;
|
|
141
|
+
default:
|
|
142
|
+
handled = false;
|
|
143
|
+
}
|
|
144
|
+
if (handled) {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
event.stopPropagation();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const renderNode = (node, depth) => {
|
|
150
|
+
const branch = isBranchNode(node);
|
|
151
|
+
const expanded = branch && expandedSet.has(node.id);
|
|
152
|
+
const isSelected = selected === node.id;
|
|
153
|
+
const labelId = `${baseId}-label-${indexById.get(node.id)}`;
|
|
154
|
+
const icon = node.icon ?? (branch ? "folder" : "draft");
|
|
155
|
+
const rowClasses = [
|
|
156
|
+
`${baseClass}__row`,
|
|
157
|
+
isSelected && `${baseClass}__row--selected`
|
|
158
|
+
].filter(Boolean).join(" ");
|
|
159
|
+
return /* @__PURE__ */ jsxs(
|
|
160
|
+
"li",
|
|
161
|
+
{
|
|
162
|
+
role: "treeitem",
|
|
163
|
+
"aria-expanded": branch ? expanded : void 0,
|
|
164
|
+
"aria-selected": isSelected,
|
|
165
|
+
"aria-labelledby": labelId,
|
|
166
|
+
tabIndex: node.id === tabbableId ? 0 : -1,
|
|
167
|
+
className: `${baseClass}__item`,
|
|
168
|
+
ref: (el) => {
|
|
169
|
+
if (el) {
|
|
170
|
+
itemRefs.current.set(node.id, el);
|
|
171
|
+
} else {
|
|
172
|
+
itemRefs.current.delete(node.id);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
onKeyDown: (event) => handleKeyDown(event, node),
|
|
176
|
+
onFocus: (event) => {
|
|
177
|
+
event.stopPropagation();
|
|
178
|
+
setFocusedId(node.id);
|
|
179
|
+
},
|
|
180
|
+
onClick: (event) => {
|
|
181
|
+
event.stopPropagation();
|
|
182
|
+
if (branch) toggleBranch(node.id);
|
|
183
|
+
selectNode(node.id);
|
|
184
|
+
focusNode(node.id);
|
|
185
|
+
},
|
|
186
|
+
children: [
|
|
187
|
+
/* @__PURE__ */ jsxs(
|
|
188
|
+
"div",
|
|
189
|
+
{
|
|
190
|
+
className: rowClasses,
|
|
191
|
+
style: { "--ds-treeview-depth": depth },
|
|
192
|
+
children: [
|
|
193
|
+
branch ? /* @__PURE__ */ jsx(
|
|
194
|
+
"span",
|
|
195
|
+
{
|
|
196
|
+
className: `${baseClass}__chevron material-symbols-rounded`,
|
|
197
|
+
"aria-hidden": "true",
|
|
198
|
+
children: "chevron_right"
|
|
199
|
+
}
|
|
200
|
+
) : /* @__PURE__ */ jsx(
|
|
201
|
+
"span",
|
|
202
|
+
{
|
|
203
|
+
className: `${baseClass}__chevron ${baseClass}__chevron--spacer`,
|
|
204
|
+
"aria-hidden": "true"
|
|
205
|
+
}
|
|
206
|
+
),
|
|
207
|
+
/* @__PURE__ */ jsx(
|
|
208
|
+
"span",
|
|
209
|
+
{
|
|
210
|
+
className: `${baseClass}__icon material-symbols-rounded`,
|
|
211
|
+
"aria-hidden": "true",
|
|
212
|
+
children: icon
|
|
213
|
+
}
|
|
214
|
+
),
|
|
215
|
+
/* @__PURE__ */ jsx("span", { id: labelId, className: `${baseClass}__label`, children: node.label })
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
),
|
|
219
|
+
expanded && /* @__PURE__ */ jsx("ul", { role: "group", className: `${baseClass}__group`, children: node.children.map((child) => renderNode(child, depth + 1)) })
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
node.id
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
const classes = [baseClass, className].filter(Boolean).join(" ");
|
|
226
|
+
return /* @__PURE__ */ jsx("ul", { ...rest, ref, role: "tree", className: classes, children: nodes.map((node) => renderNode(node, 0)) });
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
TreeView.displayName = "TreeView";
|
|
230
|
+
export {
|
|
231
|
+
TreeView
|
|
232
|
+
};
|
package/components/registry.d.ts
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
* The data lives in registry.json. Each entry in `components` carries:
|
|
6
6
|
*
|
|
7
|
-
* name the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* name the exported component name; also the folder under
|
|
8
|
+
* src/components unless `folder` says otherwise
|
|
9
|
+
* label the display name — "Nav list" for the NavList folder
|
|
10
|
+
* slug the website route segment — stored, not derived, so a
|
|
11
|
+
* name-to-slug exception stays plain data rather than a
|
|
11
12
|
* special case duplicated across validators
|
|
12
13
|
* description one line, used for the page title, the sidebar search index,
|
|
13
14
|
* and anywhere the component is summarised
|
|
@@ -16,6 +17,9 @@
|
|
|
16
17
|
* uses hooks or defines handlers. Presentational components are
|
|
17
18
|
* deliberately false so consumers can render them from a React
|
|
18
19
|
* Server Component.
|
|
20
|
+
* folder set only when the implementation lives in a shared folder
|
|
21
|
+
* rather than one named after the component — the nine chart
|
|
22
|
+
* components all live in Chart/. Omitted everywhere else.
|
|
19
23
|
*
|
|
20
24
|
* `docOnlyHelpers` names the internal documentation helpers that are
|
|
21
25
|
* deliberately excluded from the public count.
|
|
@@ -31,7 +35,7 @@
|
|
|
31
35
|
export interface ComponentMeta {
|
|
32
36
|
/** Folder under src/components, and the exported component name */
|
|
33
37
|
name: string;
|
|
34
|
-
/** Display name — may differ from `name` (
|
|
38
|
+
/** Display name — may differ from `name` (NavList → "Nav list") */
|
|
35
39
|
label: string;
|
|
36
40
|
/** Website route segment under /components */
|
|
37
41
|
slug: string;
|
|
@@ -41,10 +45,22 @@ export interface ComponentMeta {
|
|
|
41
45
|
category: string;
|
|
42
46
|
/** Whether the component declares 'use client' */
|
|
43
47
|
client: boolean;
|
|
48
|
+
/** Folder under src/components when it differs from `name` (shared folders like Chart) */
|
|
49
|
+
folder?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface ComponentCategoryMeta {
|
|
52
|
+
/** Category id — the value each component's `category` field carries, and the website route segment under /components */
|
|
53
|
+
id: string;
|
|
54
|
+
/** Display name for the category, used for section headings and landing pages */
|
|
55
|
+
label: string;
|
|
56
|
+
/** One-line summary of what the category holds */
|
|
57
|
+
description: string;
|
|
44
58
|
}
|
|
45
59
|
/** Full metadata for every public component, alphabetical by name. */
|
|
46
60
|
export declare const componentMetadata: readonly ComponentMeta[];
|
|
47
|
-
/**
|
|
61
|
+
/** Full metadata for every component category, alphabetical by id. */
|
|
62
|
+
export declare const componentCategoryMetadata: readonly ComponentCategoryMeta[];
|
|
63
|
+
/** The category ids a component may belong to. */
|
|
48
64
|
export declare const componentCategories: readonly string[];
|
|
49
65
|
/**
|
|
50
66
|
* The official public component list, names only.
|
package/components/registry.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import registry from "./registry.json.js";
|
|
2
2
|
const componentMetadata = registry.components;
|
|
3
|
-
const
|
|
3
|
+
const componentCategoryMetadata = registry.categories;
|
|
4
|
+
const componentCategories = registry.categories.map((c) => c.id);
|
|
4
5
|
const componentRegistry = registry.components.map((c) => c.name);
|
|
5
6
|
const COMPONENT_COUNT = registry.components.length;
|
|
6
7
|
export {
|
|
7
8
|
COMPONENT_COUNT,
|
|
8
9
|
componentCategories,
|
|
10
|
+
componentCategoryMetadata,
|
|
9
11
|
componentMetadata,
|
|
10
12
|
componentRegistry
|
|
11
13
|
};
|