@hex-core/components 1.3.0 → 1.4.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 +183 -9
- package/dist/accordion.d.ts +13 -0
- package/dist/accordion.js +62 -0
- package/dist/accordion.js.map +1 -0
- package/dist/alert-dialog.d.ts +34 -0
- package/dist/alert-dialog.js +125 -0
- package/dist/alert-dialog.js.map +1 -0
- package/dist/alert.d.ts +17 -0
- package/dist/alert.js +54 -0
- package/dist/alert.js.map +1 -0
- package/dist/aspect-ratio.d.ts +7 -0
- package/dist/aspect-ratio.js +8 -0
- package/dist/aspect-ratio.js.map +1 -0
- package/dist/avatar.d.ts +11 -0
- package/dist/avatar.js +44 -0
- package/dist/avatar.js.map +1 -0
- package/dist/badge.d.ts +22 -0
- package/dist/badge.js +36 -0
- package/dist/badge.js.map +1 -0
- package/dist/breadcrumb.d.ts +27 -0
- package/dist/breadcrumb.js +120 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/button-variants-Bx6gCUFp.d.ts +19 -0
- package/dist/button.d.ts +13 -0
- package/dist/button.js +113 -0
- package/dist/button.js.map +1 -0
- package/dist/calendar.d.ts +17 -0
- package/dist/calendar.js +126 -0
- package/dist/calendar.js.map +1 -0
- package/dist/card.d.ts +16 -0
- package/dist/card.js +68 -0
- package/dist/card.js.map +1 -0
- package/dist/checkbox.d.ts +11 -0
- package/dist/checkbox.js +65 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/cluster.d.ts +34 -0
- package/dist/cluster.js +50 -0
- package/dist/cluster.js.map +1 -0
- package/dist/collapsible.d.ts +11 -0
- package/dist/collapsible.js +10 -0
- package/dist/collapsible.js.map +1 -0
- package/dist/color-picker.d.ts +44 -0
- package/dist/color-picker.js +321 -0
- package/dist/color-picker.js.map +1 -0
- package/dist/combobox.d.ts +45 -0
- package/dist/combobox.js +226 -0
- package/dist/combobox.js.map +1 -0
- package/dist/command.d.ts +111 -0
- package/dist/command.js +232 -0
- package/dist/command.js.map +1 -0
- package/dist/container.d.ts +41 -0
- package/dist/container.js +39 -0
- package/dist/container.js.map +1 -0
- package/dist/context-menu.d.ts +37 -0
- package/dist/context-menu.js +130 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/data-table.d.ts +33 -0
- package/dist/data-table.js +103 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-picker.d.ts +43 -0
- package/dist/date-picker.js +221 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/dialog.d.ts +46 -0
- package/dist/dialog.js +125 -0
- package/dist/dialog.js.map +1 -0
- package/dist/drawer.d.ts +41 -0
- package/dist/drawer.js +82 -0
- package/dist/drawer.js.map +1 -0
- package/dist/dropdown-menu.d.ts +39 -0
- package/dist/dropdown-menu.js +133 -0
- package/dist/dropdown-menu.js.map +1 -0
- package/dist/dropzone.d.ts +54 -0
- package/dist/dropzone.js +194 -0
- package/dist/dropzone.js.map +1 -0
- package/dist/file-tree.d.ts +53 -0
- package/dist/file-tree.js +322 -0
- package/dist/file-tree.js.map +1 -0
- package/dist/form.d.ts +45 -0
- package/dist/form.js +114 -0
- package/dist/form.js.map +1 -0
- package/dist/grid.d.ts +50 -0
- package/dist/grid.js +58 -0
- package/dist/grid.js.map +1 -0
- package/dist/hover-card.d.ts +11 -0
- package/dist/hover-card.js +34 -0
- package/dist/hover-card.js.map +1 -0
- package/dist/index.d.ts +98 -1564
- package/dist/index.js +527 -5536
- package/dist/index.js.map +1 -1
- package/dist/input-otp.d.ts +19 -0
- package/dist/input-otp.js +71 -0
- package/dist/input-otp.js.map +1 -0
- package/dist/input.d.ts +6 -0
- package/dist/input.js +40 -0
- package/dist/input.js.map +1 -0
- package/dist/label.d.ts +11 -0
- package/dist/label.js +22 -0
- package/dist/label.js.map +1 -0
- package/dist/menubar.d.ts +35 -0
- package/dist/menubar.js +106 -0
- package/dist/menubar.js.map +1 -0
- package/dist/multi-combobox.d.ts +51 -0
- package/dist/multi-combobox.js +258 -0
- package/dist/multi-combobox.js.map +1 -0
- package/dist/navigation-menu.d.ts +23 -0
- package/dist/navigation-menu.js +108 -0
- package/dist/navigation-menu.js.map +1 -0
- package/dist/pagination.d.ts +40 -0
- package/dist/pagination.js +195 -0
- package/dist/pagination.js.map +1 -0
- package/dist/popover.d.ts +13 -0
- package/dist/popover.js +35 -0
- package/dist/popover.js.map +1 -0
- package/dist/progress.d.ts +10 -0
- package/dist/progress.js +38 -0
- package/dist/progress.js.map +1 -0
- package/dist/radio-group.d.ts +9 -0
- package/dist/radio-group.js +44 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/resizable.d.ts +28 -0
- package/dist/resizable.js +66 -0
- package/dist/resizable.js.map +1 -0
- package/dist/schemas.d.ts +121 -0
- package/dist/schemas.js +4643 -0
- package/dist/schemas.js.map +1 -0
- package/dist/scroll-area.d.ts +18 -0
- package/dist/scroll-area.js +55 -0
- package/dist/scroll-area.js.map +1 -0
- package/dist/select.d.ts +21 -0
- package/dist/select.js +136 -0
- package/dist/select.js.map +1 -0
- package/dist/separator.d.ts +11 -0
- package/dist/separator.js +29 -0
- package/dist/separator.js.map +1 -0
- package/dist/sheet.d.ts +39 -0
- package/dist/sheet.js +140 -0
- package/dist/sheet.js.map +1 -0
- package/dist/sidebar.d.ts +75 -0
- package/dist/sidebar.js +201 -0
- package/dist/sidebar.js.map +1 -0
- package/dist/skeleton.d.ts +11 -0
- package/dist/skeleton.js +21 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/slider.d.ts +20 -0
- package/dist/slider.js +55 -0
- package/dist/slider.js.map +1 -0
- package/dist/sonner.d.ts +14 -0
- package/dist/sonner.js +27 -0
- package/dist/sonner.js.map +1 -0
- package/dist/spacer.d.ts +38 -0
- package/dist/spacer.js +43 -0
- package/dist/spacer.js.map +1 -0
- package/dist/stack.d.ts +34 -0
- package/dist/stack.js +49 -0
- package/dist/stack.js.map +1 -0
- package/dist/stepper.d.ts +48 -0
- package/dist/stepper.js +226 -0
- package/dist/stepper.js.map +1 -0
- package/dist/switch.d.ts +11 -0
- package/dist/switch.js +47 -0
- package/dist/switch.js.map +1 -0
- package/dist/table.d.ts +24 -0
- package/dist/table.js +85 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.d.ts +13 -0
- package/dist/tabs.js +57 -0
- package/dist/tabs.js.map +1 -0
- package/dist/textarea.d.ts +10 -0
- package/dist/textarea.js +36 -0
- package/dist/textarea.js.map +1 -0
- package/dist/time-picker.d.ts +34 -0
- package/dist/time-picker.js +50 -0
- package/dist/time-picker.js.map +1 -0
- package/dist/timeline.d.ts +42 -0
- package/dist/timeline.js +84 -0
- package/dist/timeline.js.map +1 -0
- package/dist/toggle-group.d.ts +17 -0
- package/dist/toggle-group.js +83 -0
- package/dist/toggle-group.js.map +1 -0
- package/dist/toggle.d.ts +19 -0
- package/dist/toggle.js +49 -0
- package/dist/toggle.js.map +1 -0
- package/dist/tooltip.d.ts +13 -0
- package/dist/tooltip.js +33 -0
- package/dist/tooltip.js.map +1 -0
- package/package.json +68 -16
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
interface FileTreeNode {
|
|
5
|
+
/** Stable unique id used as React key + ARIA target. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Display name (file or folder). */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Nested children. Presence (even if empty array) marks the node as a folder. */
|
|
10
|
+
children?: FileTreeNode[];
|
|
11
|
+
/** Optional icon override. Default chooses folder/file based on `children`. */
|
|
12
|
+
icon?: React.ReactNode;
|
|
13
|
+
/** Disable selection + expand toggle. */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface FileTreeProps {
|
|
17
|
+
/** Root nodes. */
|
|
18
|
+
nodes: FileTreeNode[];
|
|
19
|
+
/** Uncontrolled initial expanded ids. */
|
|
20
|
+
defaultExpanded?: string[];
|
|
21
|
+
/** Controlled expanded ids. */
|
|
22
|
+
expanded?: string[];
|
|
23
|
+
/** Fired when expanded set changes (array of ids). */
|
|
24
|
+
onExpandedChange?: (ids: string[]) => void;
|
|
25
|
+
/** Controlled selected node id. */
|
|
26
|
+
selected?: string;
|
|
27
|
+
/** Fired when the user activates a node (click, Enter, or Space). */
|
|
28
|
+
onSelect?: (id: string) => void;
|
|
29
|
+
/** Required accessible name for the tree container. */
|
|
30
|
+
"aria-label": string;
|
|
31
|
+
/** Extra class names on the root tree element. */
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Hierarchical tree view for files, folders, settings sections, or any nested
|
|
36
|
+
* navigation. Built on the WAI-ARIA tree pattern: `role="tree"` root,
|
|
37
|
+
* `role="treeitem"` per node, `role="group"` per child group, with
|
|
38
|
+
* `aria-level` / `aria-expanded` / `aria-selected` reflecting state.
|
|
39
|
+
*
|
|
40
|
+
* Keyboard: Up/Down move between visible items; Right expands a folder or
|
|
41
|
+
* moves to the first child; Left collapses or moves to the parent;
|
|
42
|
+
* Enter/Space activate the focused node; Home/End jump to the first/last.
|
|
43
|
+
*
|
|
44
|
+
* Expanded state is uncontrolled by default (`defaultExpanded`). Pass
|
|
45
|
+
* `expanded` + `onExpandedChange` for controlled mode.
|
|
46
|
+
* @returns A keyboard-accessible nested tree.
|
|
47
|
+
*/
|
|
48
|
+
declare function FileTree({ nodes, defaultExpanded, expanded: expandedProp, onExpandedChange, selected, onSelect, "aria-label": ariaLabel, className, }: FileTreeProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
declare namespace FileTree {
|
|
50
|
+
var displayName: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { FileTree, type FileTreeNode, type FileTreeProps };
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { clsx } from 'clsx';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function cn(...inputs) {
|
|
8
|
+
return twMerge(clsx(inputs));
|
|
9
|
+
}
|
|
10
|
+
function flatten(nodes, expandedSet, level = 1, parentId = null) {
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const node of nodes) {
|
|
13
|
+
const hasChildren = Array.isArray(node.children);
|
|
14
|
+
out.push({
|
|
15
|
+
id: node.id,
|
|
16
|
+
name: node.name,
|
|
17
|
+
level,
|
|
18
|
+
hasChildren,
|
|
19
|
+
disabled: !!node.disabled,
|
|
20
|
+
parentId,
|
|
21
|
+
icon: node.icon
|
|
22
|
+
});
|
|
23
|
+
if (hasChildren && expandedSet.has(node.id) && node.children) {
|
|
24
|
+
out.push(...flatten(node.children, expandedSet, level + 1, node.id));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
function FolderIcon({ open }) {
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
"svg",
|
|
32
|
+
{
|
|
33
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
34
|
+
viewBox: "0 0 24 24",
|
|
35
|
+
fill: "none",
|
|
36
|
+
stroke: "currentColor",
|
|
37
|
+
strokeWidth: "2",
|
|
38
|
+
strokeLinecap: "round",
|
|
39
|
+
strokeLinejoin: "round",
|
|
40
|
+
className: "h-4 w-4 shrink-0",
|
|
41
|
+
"aria-hidden": "true",
|
|
42
|
+
children: open ? /* @__PURE__ */ jsx("path", { d: "M3 7v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-7l-2-2H5a2 2 0 0 0-2 2z" }) : /* @__PURE__ */ jsx("path", { d: "M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" })
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function FileIcon() {
|
|
47
|
+
return /* @__PURE__ */ jsxs(
|
|
48
|
+
"svg",
|
|
49
|
+
{
|
|
50
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
51
|
+
viewBox: "0 0 24 24",
|
|
52
|
+
fill: "none",
|
|
53
|
+
stroke: "currentColor",
|
|
54
|
+
strokeWidth: "2",
|
|
55
|
+
strokeLinecap: "round",
|
|
56
|
+
strokeLinejoin: "round",
|
|
57
|
+
className: "h-4 w-4 shrink-0",
|
|
58
|
+
"aria-hidden": "true",
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
61
|
+
/* @__PURE__ */ jsx("polyline", { points: "14 2 14 8 20 8" })
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function Chevron({ expanded }) {
|
|
67
|
+
return /* @__PURE__ */ jsx(
|
|
68
|
+
"svg",
|
|
69
|
+
{
|
|
70
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
71
|
+
viewBox: "0 0 24 24",
|
|
72
|
+
fill: "none",
|
|
73
|
+
stroke: "currentColor",
|
|
74
|
+
strokeWidth: "2",
|
|
75
|
+
strokeLinecap: "round",
|
|
76
|
+
strokeLinejoin: "round",
|
|
77
|
+
className: cn(
|
|
78
|
+
"h-3 w-3 shrink-0 text-muted-foreground transition-transform duration-[var(--duration-normal,200ms)] ease-out",
|
|
79
|
+
expanded ? "rotate-90" : ""
|
|
80
|
+
),
|
|
81
|
+
"aria-hidden": "true",
|
|
82
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" })
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
function TreeItem({
|
|
87
|
+
node,
|
|
88
|
+
level,
|
|
89
|
+
expandedSet,
|
|
90
|
+
selected,
|
|
91
|
+
onToggle,
|
|
92
|
+
onSelect,
|
|
93
|
+
onKeyDown,
|
|
94
|
+
registerRef,
|
|
95
|
+
tabbableId
|
|
96
|
+
}) {
|
|
97
|
+
const hasChildren = Array.isArray(node.children);
|
|
98
|
+
const isExpanded = hasChildren && expandedSet.has(node.id);
|
|
99
|
+
const isSelected = selected === node.id;
|
|
100
|
+
return /* @__PURE__ */ jsxs("li", { role: "none", children: [
|
|
101
|
+
/* @__PURE__ */ jsxs(
|
|
102
|
+
"div",
|
|
103
|
+
{
|
|
104
|
+
role: "treeitem",
|
|
105
|
+
"aria-level": level,
|
|
106
|
+
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
107
|
+
"aria-selected": isSelected,
|
|
108
|
+
"aria-disabled": node.disabled || void 0,
|
|
109
|
+
tabIndex: tabbableId === node.id ? 0 : -1,
|
|
110
|
+
ref: (el) => registerRef(node.id, el),
|
|
111
|
+
onClick: (e) => {
|
|
112
|
+
if (node.disabled) return;
|
|
113
|
+
e.stopPropagation();
|
|
114
|
+
onSelect(node.id);
|
|
115
|
+
},
|
|
116
|
+
onKeyDown: (e) => onKeyDown(e, node.id),
|
|
117
|
+
className: cn(
|
|
118
|
+
"flex items-center gap-[var(--space-2,0.5rem)] rounded-md px-[var(--space-2,0.5rem)] py-[var(--space-1,0.25rem)] text-sm cursor-pointer select-none transition-colors duration-[var(--duration-normal,200ms)] ease-out",
|
|
119
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
120
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
121
|
+
isSelected && "bg-accent text-accent-foreground",
|
|
122
|
+
node.disabled && "opacity-50 cursor-not-allowed pointer-events-none"
|
|
123
|
+
),
|
|
124
|
+
style: { paddingInlineStart: `calc(${level - 1} * 1rem + var(--space-2, 0.5rem))` },
|
|
125
|
+
children: [
|
|
126
|
+
hasChildren ? /* @__PURE__ */ jsx(
|
|
127
|
+
"button",
|
|
128
|
+
{
|
|
129
|
+
type: "button",
|
|
130
|
+
tabIndex: -1,
|
|
131
|
+
"aria-hidden": "true",
|
|
132
|
+
onClick: (e) => {
|
|
133
|
+
e.stopPropagation();
|
|
134
|
+
if (node.disabled) return;
|
|
135
|
+
onToggle(node.id);
|
|
136
|
+
},
|
|
137
|
+
className: "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-sm hover:bg-accent-foreground/10",
|
|
138
|
+
children: /* @__PURE__ */ jsx(Chevron, { expanded: isExpanded })
|
|
139
|
+
}
|
|
140
|
+
) : /* @__PURE__ */ jsx("span", { className: "w-3 shrink-0", "aria-hidden": "true" }),
|
|
141
|
+
node.icon ?? (hasChildren ? /* @__PURE__ */ jsx(FolderIcon, { open: isExpanded }) : /* @__PURE__ */ jsx(FileIcon, {})),
|
|
142
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: node.name })
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
),
|
|
146
|
+
hasChildren && isExpanded && node.children ? /* @__PURE__ */ jsx("ul", { role: "group", className: "m-0 list-none p-0", children: node.children.map((child) => /* @__PURE__ */ jsx(
|
|
147
|
+
TreeItem,
|
|
148
|
+
{
|
|
149
|
+
node: child,
|
|
150
|
+
level: level + 1,
|
|
151
|
+
expandedSet,
|
|
152
|
+
selected,
|
|
153
|
+
onToggle,
|
|
154
|
+
onSelect,
|
|
155
|
+
onKeyDown,
|
|
156
|
+
registerRef,
|
|
157
|
+
tabbableId
|
|
158
|
+
},
|
|
159
|
+
child.id
|
|
160
|
+
)) }) : null
|
|
161
|
+
] });
|
|
162
|
+
}
|
|
163
|
+
function FileTree({
|
|
164
|
+
nodes,
|
|
165
|
+
defaultExpanded,
|
|
166
|
+
expanded: expandedProp,
|
|
167
|
+
onExpandedChange,
|
|
168
|
+
selected,
|
|
169
|
+
onSelect,
|
|
170
|
+
"aria-label": ariaLabel,
|
|
171
|
+
className
|
|
172
|
+
}) {
|
|
173
|
+
const isControlled = expandedProp !== void 0;
|
|
174
|
+
const [internalExpanded, setInternalExpanded] = React.useState(
|
|
175
|
+
defaultExpanded ?? []
|
|
176
|
+
);
|
|
177
|
+
const expanded = isControlled ? expandedProp : internalExpanded;
|
|
178
|
+
const expandedSet = React.useMemo(() => new Set(expanded), [expanded]);
|
|
179
|
+
const itemRefs = React.useRef(/* @__PURE__ */ new Map());
|
|
180
|
+
const registerRef = React.useCallback(
|
|
181
|
+
(id, el) => {
|
|
182
|
+
if (el) itemRefs.current.set(id, el);
|
|
183
|
+
else itemRefs.current.delete(id);
|
|
184
|
+
},
|
|
185
|
+
[]
|
|
186
|
+
);
|
|
187
|
+
const flat = React.useMemo(
|
|
188
|
+
() => flatten(nodes, expandedSet),
|
|
189
|
+
[nodes, expandedSet]
|
|
190
|
+
);
|
|
191
|
+
const firstId = flat[0]?.id ?? null;
|
|
192
|
+
const [focusedId, setFocusedId] = React.useState(null);
|
|
193
|
+
const visibleIds = React.useMemo(
|
|
194
|
+
() => new Set(flat.map((n) => n.id)),
|
|
195
|
+
[flat]
|
|
196
|
+
);
|
|
197
|
+
const candidate = focusedId ?? selected ?? firstId;
|
|
198
|
+
const tabbableId = candidate && visibleIds.has(candidate) ? candidate : firstId;
|
|
199
|
+
const setExpanded = React.useCallback(
|
|
200
|
+
(next) => {
|
|
201
|
+
if (!isControlled) setInternalExpanded(next);
|
|
202
|
+
onExpandedChange?.(next);
|
|
203
|
+
},
|
|
204
|
+
[isControlled, onExpandedChange]
|
|
205
|
+
);
|
|
206
|
+
const toggle = React.useCallback(
|
|
207
|
+
(id) => {
|
|
208
|
+
const set = new Set(expanded);
|
|
209
|
+
if (set.has(id)) set.delete(id);
|
|
210
|
+
else set.add(id);
|
|
211
|
+
setExpanded(Array.from(set));
|
|
212
|
+
},
|
|
213
|
+
[expanded, setExpanded]
|
|
214
|
+
);
|
|
215
|
+
const handleSelect = React.useCallback(
|
|
216
|
+
(id) => {
|
|
217
|
+
onSelect?.(id);
|
|
218
|
+
setFocusedId(id);
|
|
219
|
+
},
|
|
220
|
+
[onSelect]
|
|
221
|
+
);
|
|
222
|
+
const focusNode = (id) => {
|
|
223
|
+
setFocusedId(id);
|
|
224
|
+
requestAnimationFrame(() => itemRefs.current.get(id)?.focus());
|
|
225
|
+
};
|
|
226
|
+
const handleKeyDown = (e, id) => {
|
|
227
|
+
const flatNodes = flat;
|
|
228
|
+
const idx = flatNodes.findIndex((n) => n.id === id);
|
|
229
|
+
const node = flatNodes[idx];
|
|
230
|
+
if (!node) return;
|
|
231
|
+
const findEnabled = (start, dir) => {
|
|
232
|
+
let i = start;
|
|
233
|
+
while (i >= 0 && i < flatNodes.length) {
|
|
234
|
+
if (!flatNodes[i].disabled) return flatNodes[i];
|
|
235
|
+
i += dir;
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
};
|
|
239
|
+
switch (e.key) {
|
|
240
|
+
case "ArrowDown": {
|
|
241
|
+
e.preventDefault();
|
|
242
|
+
const next = findEnabled(idx + 1, 1);
|
|
243
|
+
if (next) focusNode(next.id);
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case "ArrowUp": {
|
|
247
|
+
e.preventDefault();
|
|
248
|
+
const prev = findEnabled(idx - 1, -1);
|
|
249
|
+
if (prev) focusNode(prev.id);
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case "ArrowRight": {
|
|
253
|
+
e.preventDefault();
|
|
254
|
+
if (node.hasChildren && !expandedSet.has(node.id)) {
|
|
255
|
+
toggle(node.id);
|
|
256
|
+
} else if (node.hasChildren) {
|
|
257
|
+
const firstChild = flatNodes[idx + 1];
|
|
258
|
+
if (firstChild && firstChild.parentId === node.id)
|
|
259
|
+
focusNode(firstChild.id);
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
case "ArrowLeft": {
|
|
264
|
+
e.preventDefault();
|
|
265
|
+
if (node.hasChildren && expandedSet.has(node.id)) {
|
|
266
|
+
toggle(node.id);
|
|
267
|
+
} else if (node.parentId) {
|
|
268
|
+
focusNode(node.parentId);
|
|
269
|
+
}
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
case "Home": {
|
|
273
|
+
e.preventDefault();
|
|
274
|
+
if (flatNodes[0]) focusNode(flatNodes[0].id);
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
case "End": {
|
|
278
|
+
e.preventDefault();
|
|
279
|
+
const last = flatNodes[flatNodes.length - 1];
|
|
280
|
+
if (last) focusNode(last.id);
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case "Enter":
|
|
284
|
+
case " ": {
|
|
285
|
+
e.preventDefault();
|
|
286
|
+
if (!node.disabled) {
|
|
287
|
+
if (node.hasChildren) toggle(node.id);
|
|
288
|
+
handleSelect(node.id);
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
return /* @__PURE__ */ jsx(
|
|
295
|
+
"ul",
|
|
296
|
+
{
|
|
297
|
+
role: "tree",
|
|
298
|
+
"aria-label": ariaLabel,
|
|
299
|
+
className: cn("list-none p-0 m-0", className),
|
|
300
|
+
children: nodes.map((node) => /* @__PURE__ */ jsx(
|
|
301
|
+
TreeItem,
|
|
302
|
+
{
|
|
303
|
+
node,
|
|
304
|
+
level: 1,
|
|
305
|
+
expandedSet,
|
|
306
|
+
selected,
|
|
307
|
+
onToggle: toggle,
|
|
308
|
+
onSelect: handleSelect,
|
|
309
|
+
onKeyDown: handleKeyDown,
|
|
310
|
+
registerRef,
|
|
311
|
+
tabbableId
|
|
312
|
+
},
|
|
313
|
+
node.id
|
|
314
|
+
))
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
FileTree.displayName = "FileTree";
|
|
319
|
+
|
|
320
|
+
export { FileTree };
|
|
321
|
+
//# sourceMappingURL=file-tree.js.map
|
|
322
|
+
//# sourceMappingURL=file-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/file-tree/file-tree.tsx"],"names":[],"mappings":"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","file":"file-tree.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\ninterface FileTreeNode {\n\t/** Stable unique id used as React key + ARIA target. */\n\tid: string;\n\t/** Display name (file or folder). */\n\tname: string;\n\t/** Nested children. Presence (even if empty array) marks the node as a folder. */\n\tchildren?: FileTreeNode[];\n\t/** Optional icon override. Default chooses folder/file based on `children`. */\n\ticon?: React.ReactNode;\n\t/** Disable selection + expand toggle. */\n\tdisabled?: boolean;\n}\n\ninterface FileTreeProps {\n\t/** Root nodes. */\n\tnodes: FileTreeNode[];\n\t/** Uncontrolled initial expanded ids. */\n\tdefaultExpanded?: string[];\n\t/** Controlled expanded ids. */\n\texpanded?: string[];\n\t/** Fired when expanded set changes (array of ids). */\n\tonExpandedChange?: (ids: string[]) => void;\n\t/** Controlled selected node id. */\n\tselected?: string;\n\t/** Fired when the user activates a node (click, Enter, or Space). */\n\tonSelect?: (id: string) => void;\n\t/** Required accessible name for the tree container. */\n\t\"aria-label\": string;\n\t/** Extra class names on the root tree element. */\n\tclassName?: string;\n}\n\ninterface FlatNode {\n\tid: string;\n\tname: string;\n\tlevel: number;\n\thasChildren: boolean;\n\tdisabled: boolean;\n\tparentId: string | null;\n\ticon: React.ReactNode | undefined;\n}\n\n/** Walk the tree once, emitting every visible node in document order. */\nfunction flatten(\n\tnodes: FileTreeNode[],\n\texpandedSet: Set<string>,\n\tlevel = 1,\n\tparentId: string | null = null,\n): FlatNode[] {\n\tconst out: FlatNode[] = [];\n\tfor (const node of nodes) {\n\t\tconst hasChildren = Array.isArray(node.children);\n\t\tout.push({\n\t\t\tid: node.id,\n\t\t\tname: node.name,\n\t\t\tlevel,\n\t\t\thasChildren,\n\t\t\tdisabled: !!node.disabled,\n\t\t\tparentId,\n\t\t\ticon: node.icon,\n\t\t});\n\t\tif (hasChildren && expandedSet.has(node.id) && node.children) {\n\t\t\tout.push(...flatten(node.children, expandedSet, level + 1, node.id));\n\t\t}\n\t}\n\treturn out;\n}\n\n/** Default folder glyph; flips between open and closed shapes via `open`. */\nfunction FolderIcon({ open }: { open: boolean }) {\n\treturn (\n\t\t<svg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"h-4 w-4 shrink-0\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t{open ? (\n\t\t\t\t<path d=\"M3 7v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-7l-2-2H5a2 2 0 0 0-2 2z\" />\n\t\t\t) : (\n\t\t\t\t<path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\n\t\t\t)}\n\t\t</svg>\n\t);\n}\n\n/** Default leaf-node glyph (generic file icon). */\nfunction FileIcon() {\n\treturn (\n\t\t<svg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"h-4 w-4 shrink-0\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n\t\t\t<polyline points=\"14 2 14 8 20 8\" />\n\t\t</svg>\n\t);\n}\n\n/** Disclosure chevron — rotates 90° when the folder is expanded. */\nfunction Chevron({ expanded }: { expanded: boolean }) {\n\treturn (\n\t\t<svg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName={cn(\n\t\t\t\t\"h-3 w-3 shrink-0 text-muted-foreground transition-transform duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\texpanded ? \"rotate-90\" : \"\",\n\t\t\t)}\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<polyline points=\"9 18 15 12 9 6\" />\n\t\t</svg>\n\t);\n}\n\ninterface TreeItemProps {\n\tnode: FileTreeNode;\n\tlevel: number;\n\texpandedSet: Set<string>;\n\tselected?: string;\n\tonToggle: (id: string) => void;\n\tonSelect: (id: string) => void;\n\tonKeyDown: (e: React.KeyboardEvent<HTMLDivElement>, id: string) => void;\n\tregisterRef: (id: string, el: HTMLDivElement | null) => void;\n\ttabbableId: string | null;\n}\n\n/** Recursive single-node renderer; chevron toggles, row body selects. */\nfunction TreeItem({\n\tnode,\n\tlevel,\n\texpandedSet,\n\tselected,\n\tonToggle,\n\tonSelect,\n\tonKeyDown,\n\tregisterRef,\n\ttabbableId,\n}: TreeItemProps) {\n\tconst hasChildren = Array.isArray(node.children);\n\tconst isExpanded = hasChildren && expandedSet.has(node.id);\n\tconst isSelected = selected === node.id;\n\n\treturn (\n\t\t<li role=\"none\">\n\t\t\t<div\n\t\t\t\trole=\"treeitem\"\n\t\t\t\taria-level={level}\n\t\t\t\taria-expanded={hasChildren ? isExpanded : undefined}\n\t\t\t\taria-selected={isSelected}\n\t\t\t\taria-disabled={node.disabled || undefined}\n\t\t\t\ttabIndex={tabbableId === node.id ? 0 : -1}\n\t\t\t\tref={(el) => registerRef(node.id, el)}\n\t\t\t\tonClick={(e) => {\n\t\t\t\t\tif (node.disabled) return;\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t/*\n\t\t\t\t\t * WAI-ARIA tree pattern: row click selects only. Toggling\n\t\t\t\t\t * a folder is the chevron's job (or ArrowRight/Left, or\n\t\t\t\t\t * Enter/Space when the row is focused).\n\t\t\t\t\t */\n\t\t\t\t\tonSelect(node.id);\n\t\t\t\t}}\n\t\t\t\tonKeyDown={(e) => onKeyDown(e, node.id)}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex items-center gap-[var(--space-2,0.5rem)] rounded-md px-[var(--space-2,0.5rem)] py-[var(--space-1,0.25rem)] text-sm cursor-pointer select-none transition-colors duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"hover:bg-accent hover:text-accent-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\",\n\t\t\t\t\tisSelected && \"bg-accent text-accent-foreground\",\n\t\t\t\t\tnode.disabled && \"opacity-50 cursor-not-allowed pointer-events-none\",\n\t\t\t\t)}\n\t\t\t\tstyle={{ paddingInlineStart: `calc(${level - 1} * 1rem + var(--space-2, 0.5rem))` }}\n\t\t\t>\n\t\t\t\t{hasChildren ? (\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * Decorative button — toggling is also reachable via\n\t\t\t\t\t\t * Enter/Space on the treeitem and ArrowRight/Left, so\n\t\t\t\t\t\t * we don't add this to the keyboard tour.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\tif (node.disabled) return;\n\t\t\t\t\t\t\tonToggle(node.id);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName=\"inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-sm hover:bg-accent-foreground/10\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Chevron expanded={isExpanded} />\n\t\t\t\t\t</button>\n\t\t\t\t) : (\n\t\t\t\t\t<span className=\"w-3 shrink-0\" aria-hidden=\"true\" />\n\t\t\t\t)}\n\t\t\t\t{node.icon ?? (hasChildren ? <FolderIcon open={isExpanded} /> : <FileIcon />)}\n\t\t\t\t<span className=\"truncate\">{node.name}</span>\n\t\t\t</div>\n\t\t\t{hasChildren && isExpanded && node.children ? (\n\t\t\t\t<ul role=\"group\" className=\"m-0 list-none p-0\">\n\t\t\t\t\t{node.children.map((child) => (\n\t\t\t\t\t\t<TreeItem\n\t\t\t\t\t\t\tkey={child.id}\n\t\t\t\t\t\t\tnode={child}\n\t\t\t\t\t\t\tlevel={level + 1}\n\t\t\t\t\t\t\texpandedSet={expandedSet}\n\t\t\t\t\t\t\tselected={selected}\n\t\t\t\t\t\t\tonToggle={onToggle}\n\t\t\t\t\t\t\tonSelect={onSelect}\n\t\t\t\t\t\t\tonKeyDown={onKeyDown}\n\t\t\t\t\t\t\tregisterRef={registerRef}\n\t\t\t\t\t\t\ttabbableId={tabbableId}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t) : null}\n\t\t</li>\n\t);\n}\n\n/**\n * Hierarchical tree view for files, folders, settings sections, or any nested\n * navigation. Built on the WAI-ARIA tree pattern: `role=\"tree\"` root,\n * `role=\"treeitem\"` per node, `role=\"group\"` per child group, with\n * `aria-level` / `aria-expanded` / `aria-selected` reflecting state.\n *\n * Keyboard: Up/Down move between visible items; Right expands a folder or\n * moves to the first child; Left collapses or moves to the parent;\n * Enter/Space activate the focused node; Home/End jump to the first/last.\n *\n * Expanded state is uncontrolled by default (`defaultExpanded`). Pass\n * `expanded` + `onExpandedChange` for controlled mode.\n * @returns A keyboard-accessible nested tree.\n */\nfunction FileTree({\n\tnodes,\n\tdefaultExpanded,\n\texpanded: expandedProp,\n\tonExpandedChange,\n\tselected,\n\tonSelect,\n\t\"aria-label\": ariaLabel,\n\tclassName,\n}: FileTreeProps) {\n\tconst isControlled = expandedProp !== undefined;\n\tconst [internalExpanded, setInternalExpanded] = React.useState<string[]>(\n\t\tdefaultExpanded ?? [],\n\t);\n\tconst expanded = isControlled ? expandedProp : internalExpanded;\n\tconst expandedSet = React.useMemo(() => new Set(expanded), [expanded]);\n\n\tconst itemRefs = React.useRef(new Map<string, HTMLDivElement>());\n\tconst registerRef = React.useCallback(\n\t\t(id: string, el: HTMLDivElement | null) => {\n\t\t\tif (el) itemRefs.current.set(id, el);\n\t\t\telse itemRefs.current.delete(id);\n\t\t},\n\t\t[],\n\t);\n\n\tconst flat = React.useMemo(\n\t\t() => flatten(nodes, expandedSet),\n\t\t[nodes, expandedSet],\n\t);\n\n\tconst firstId = flat[0]?.id ?? null;\n\tconst [focusedId, setFocusedId] = React.useState<string | null>(null);\n\t/*\n\t * Resolve the roving-tabindex target against the *visible* (flattened)\n\t * node set. If `selected` lives inside a collapsed branch its <treeitem>\n\t * doesn't render, and pointing tabIndex=0 at it would silently skip the\n\t * whole tree from Tab navigation.\n\t */\n\tconst visibleIds = React.useMemo(\n\t\t() => new Set(flat.map((n) => n.id)),\n\t\t[flat],\n\t);\n\tconst candidate = focusedId ?? selected ?? firstId;\n\tconst tabbableId =\n\t\tcandidate && visibleIds.has(candidate) ? candidate : firstId;\n\n\tconst setExpanded = React.useCallback(\n\t\t(next: string[]) => {\n\t\t\tif (!isControlled) setInternalExpanded(next);\n\t\t\tonExpandedChange?.(next);\n\t\t},\n\t\t[isControlled, onExpandedChange],\n\t);\n\n\tconst toggle = React.useCallback(\n\t\t(id: string) => {\n\t\t\tconst set = new Set(expanded);\n\t\t\tif (set.has(id)) set.delete(id);\n\t\t\telse set.add(id);\n\t\t\tsetExpanded(Array.from(set));\n\t\t},\n\t\t[expanded, setExpanded],\n\t);\n\n\tconst handleSelect = React.useCallback(\n\t\t(id: string) => {\n\t\t\tonSelect?.(id);\n\t\t\tsetFocusedId(id);\n\t\t},\n\t\t[onSelect],\n\t);\n\n\tconst focusNode = (id: string) => {\n\t\tsetFocusedId(id);\n\t\t// Defer to next paint so the new tabbable element is in the DOM.\n\t\trequestAnimationFrame(() => itemRefs.current.get(id)?.focus());\n\t};\n\n\tconst handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>, id: string) => {\n\t\tconst flatNodes = flat;\n\t\tconst idx = flatNodes.findIndex((n) => n.id === id);\n\t\tconst node = flatNodes[idx];\n\t\tif (!node) return;\n\n\t\t// Walk past disabled neighbours so arrow keys never park focus on a\n\t\t// non-actionable node — matches the convention used elsewhere in the\n\t\t// repo (see <Select> / <Combobox> disabled item handling in cmdk).\n\t\tconst findEnabled = (start: number, dir: 1 | -1) => {\n\t\t\tlet i = start;\n\t\t\twhile (i >= 0 && i < flatNodes.length) {\n\t\t\t\tif (!flatNodes[i].disabled) return flatNodes[i];\n\t\t\t\ti += dir;\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\n\t\tswitch (e.key) {\n\t\t\tcase \"ArrowDown\": {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next = findEnabled(idx + 1, 1);\n\t\t\t\tif (next) focusNode(next.id);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"ArrowUp\": {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev = findEnabled(idx - 1, -1);\n\t\t\t\tif (prev) focusNode(prev.id);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"ArrowRight\": {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (node.hasChildren && !expandedSet.has(node.id)) {\n\t\t\t\t\ttoggle(node.id);\n\t\t\t\t} else if (node.hasChildren) {\n\t\t\t\t\tconst firstChild = flatNodes[idx + 1];\n\t\t\t\t\tif (firstChild && firstChild.parentId === node.id)\n\t\t\t\t\t\tfocusNode(firstChild.id);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"ArrowLeft\": {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (node.hasChildren && expandedSet.has(node.id)) {\n\t\t\t\t\ttoggle(node.id);\n\t\t\t\t} else if (node.parentId) {\n\t\t\t\t\tfocusNode(node.parentId);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"Home\": {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (flatNodes[0]) focusNode(flatNodes[0].id);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"End\": {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst last = flatNodes[flatNodes.length - 1];\n\t\t\t\tif (last) focusNode(last.id);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"Enter\":\n\t\t\tcase \" \": {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (!node.disabled) {\n\t\t\t\t\tif (node.hasChildren) toggle(node.id);\n\t\t\t\t\thandleSelect(node.id);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<ul\n\t\t\trole=\"tree\"\n\t\t\taria-label={ariaLabel}\n\t\t\tclassName={cn(\"list-none p-0 m-0\", className)}\n\t\t>\n\t\t\t{nodes.map((node) => (\n\t\t\t\t<TreeItem\n\t\t\t\t\tkey={node.id}\n\t\t\t\t\tnode={node}\n\t\t\t\t\tlevel={1}\n\t\t\t\t\texpandedSet={expandedSet}\n\t\t\t\t\tselected={selected}\n\t\t\t\t\tonToggle={toggle}\n\t\t\t\t\tonSelect={handleSelect}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tregisterRef={registerRef}\n\t\t\t\t\ttabbableId={tabbableId}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\nFileTree.displayName = \"FileTree\";\n\nexport { FileTree };\nexport type { FileTreeNode, FileTreeProps };\n"]}
|
package/dist/form.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as _radix_ui_react_slot from '@radix-ui/react-slot';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import * as react_hook_form from 'react-hook-form';
|
|
4
|
+
import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
|
|
5
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
|
|
8
|
+
/** Root form provider. Wraps react-hook-form's FormProvider. */
|
|
9
|
+
declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransformedValues = TFieldValues>(props: react_hook_form.FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React.JSX.Element;
|
|
10
|
+
/**
|
|
11
|
+
* Binds a field name to a react-hook-form Controller.
|
|
12
|
+
* Provides context so FormItem children can access field state.
|
|
13
|
+
* @param props - Controller props including name, control, render
|
|
14
|
+
* @returns A Controller with FormFieldContext
|
|
15
|
+
*/
|
|
16
|
+
declare const FormField: <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({ ...props }: ControllerProps<TFieldValues, TName>) => react_jsx_runtime.JSX.Element;
|
|
17
|
+
/**
|
|
18
|
+
* Hook that returns the current field's id, name, error, and derived aria ids.
|
|
19
|
+
* Must be called inside a FormField + FormItem subtree.
|
|
20
|
+
* @returns Field state + aria descriptors
|
|
21
|
+
*/
|
|
22
|
+
declare function useFormField(): {
|
|
23
|
+
invalid: boolean;
|
|
24
|
+
isDirty: boolean;
|
|
25
|
+
isTouched: boolean;
|
|
26
|
+
isValidating: boolean;
|
|
27
|
+
error?: react_hook_form.FieldError;
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
formItemId: string;
|
|
31
|
+
formDescriptionId: string;
|
|
32
|
+
formMessageId: string;
|
|
33
|
+
};
|
|
34
|
+
/** Wraps a single form field (label + control + description + message). */
|
|
35
|
+
declare const FormItem: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
36
|
+
/** Accessible label wired to the FormItem's control. Turns red on error. */
|
|
37
|
+
declare const FormLabel: React.ForwardRefExoticComponent<Omit<LabelPrimitive.LabelProps & React.RefAttributes<HTMLLabelElement>, "ref"> & React.RefAttributes<HTMLLabelElement>>;
|
|
38
|
+
/** Wraps the form control and wires id + aria-describedby + aria-invalid. */
|
|
39
|
+
declare const FormControl: React.ForwardRefExoticComponent<Omit<_radix_ui_react_slot.SlotProps & React.RefAttributes<HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
40
|
+
/** Optional helper text below the control. */
|
|
41
|
+
declare const FormDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
42
|
+
/** Validation error message. Renders the error string when the field is invalid. */
|
|
43
|
+
declare const FormMessage: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
44
|
+
|
|
45
|
+
export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField };
|
package/dist/form.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import * as React2 from 'react';
|
|
4
|
+
import { useFormContext, useFormState, FormProvider, Controller } from 'react-hook-form';
|
|
5
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
6
|
+
import { cva } from 'class-variance-authority';
|
|
7
|
+
import { clsx } from 'clsx';
|
|
8
|
+
import { twMerge } from 'tailwind-merge';
|
|
9
|
+
import { jsx } from 'react/jsx-runtime';
|
|
10
|
+
|
|
11
|
+
function cn(...inputs) {
|
|
12
|
+
return twMerge(clsx(inputs));
|
|
13
|
+
}
|
|
14
|
+
var labelVariants = cva(
|
|
15
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
16
|
+
);
|
|
17
|
+
var Label = React2.forwardRef(
|
|
18
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props })
|
|
19
|
+
);
|
|
20
|
+
Label.displayName = "Label";
|
|
21
|
+
var Form = FormProvider;
|
|
22
|
+
var FormFieldContext = React2.createContext({});
|
|
23
|
+
var FormField = ({
|
|
24
|
+
...props
|
|
25
|
+
}) => {
|
|
26
|
+
return /* @__PURE__ */ jsx(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx(Controller, { ...props }) });
|
|
27
|
+
};
|
|
28
|
+
var FormItemContext = React2.createContext({});
|
|
29
|
+
function useFormField() {
|
|
30
|
+
const fieldContext = React2.useContext(FormFieldContext);
|
|
31
|
+
const itemContext = React2.useContext(FormItemContext);
|
|
32
|
+
if (!fieldContext?.name) {
|
|
33
|
+
throw new Error("useFormField should be used within <FormField>");
|
|
34
|
+
}
|
|
35
|
+
const { getFieldState } = useFormContext();
|
|
36
|
+
const formState = useFormState({ name: fieldContext.name });
|
|
37
|
+
const fieldState = getFieldState(fieldContext.name, formState);
|
|
38
|
+
const { id } = itemContext;
|
|
39
|
+
return {
|
|
40
|
+
id,
|
|
41
|
+
name: fieldContext.name,
|
|
42
|
+
formItemId: `${id}-form-item`,
|
|
43
|
+
formDescriptionId: `${id}-form-item-description`,
|
|
44
|
+
formMessageId: `${id}-form-item-message`,
|
|
45
|
+
...fieldState
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
var FormItem = React2.forwardRef(
|
|
49
|
+
({ className, ...props }, ref) => {
|
|
50
|
+
const id = React2.useId();
|
|
51
|
+
return /* @__PURE__ */ jsx(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx("div", { ref, className: cn("space-y-2", className), ...props }) });
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
FormItem.displayName = "FormItem";
|
|
55
|
+
var FormLabel = React2.forwardRef(({ className, ...props }, ref) => {
|
|
56
|
+
const { error, formItemId } = useFormField();
|
|
57
|
+
return /* @__PURE__ */ jsx(
|
|
58
|
+
Label,
|
|
59
|
+
{
|
|
60
|
+
ref,
|
|
61
|
+
className: cn(error && "text-destructive", className),
|
|
62
|
+
htmlFor: formItemId,
|
|
63
|
+
...props
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
FormLabel.displayName = "FormLabel";
|
|
68
|
+
var FormControl = React2.forwardRef(({ ...props }, ref) => {
|
|
69
|
+
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
|
70
|
+
return /* @__PURE__ */ jsx(
|
|
71
|
+
Slot,
|
|
72
|
+
{
|
|
73
|
+
ref,
|
|
74
|
+
id: formItemId,
|
|
75
|
+
"aria-describedby": error ? `${formDescriptionId} ${formMessageId}` : `${formDescriptionId}`,
|
|
76
|
+
"aria-invalid": !!error,
|
|
77
|
+
...props
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
FormControl.displayName = "FormControl";
|
|
82
|
+
var FormDescription = React2.forwardRef(({ className, ...props }, ref) => {
|
|
83
|
+
const { formDescriptionId } = useFormField();
|
|
84
|
+
return /* @__PURE__ */ jsx(
|
|
85
|
+
"p",
|
|
86
|
+
{
|
|
87
|
+
ref,
|
|
88
|
+
id: formDescriptionId,
|
|
89
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
90
|
+
...props
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
FormDescription.displayName = "FormDescription";
|
|
95
|
+
var FormMessage = React2.forwardRef(({ className, children, ...props }, ref) => {
|
|
96
|
+
const { error, formMessageId } = useFormField();
|
|
97
|
+
const body = error?.message ? String(error.message) : children;
|
|
98
|
+
if (!body) return null;
|
|
99
|
+
return /* @__PURE__ */ jsx(
|
|
100
|
+
"p",
|
|
101
|
+
{
|
|
102
|
+
ref,
|
|
103
|
+
id: formMessageId,
|
|
104
|
+
className: cn("text-sm font-medium text-destructive", className),
|
|
105
|
+
...props,
|
|
106
|
+
children: body
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
FormMessage.displayName = "FormMessage";
|
|
111
|
+
|
|
112
|
+
export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField };
|
|
113
|
+
//# sourceMappingURL=form.js.map
|
|
114
|
+
//# sourceMappingURL=form.js.map
|
package/dist/form.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/primitives/label/label.tsx","../src/components/form/form.tsx"],"names":["React","jsx"],"mappings":"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","file":"form.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nconst labelVariants = cva(\n\t\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n);\n\nexport interface LabelProps\n\textends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>,\n\t\tVariantProps<typeof labelVariants> {}\n\nconst Label = React.forwardRef<React.ComponentRef<typeof LabelPrimitive.Root>, LabelProps>(\n\t({ className, ...props }, ref) => (\n\t\t<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n\t),\n);\nLabel.displayName = \"Label\";\n\nexport { Label };\n","\"use client\";\n\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport {\n\tController,\n\ttype ControllerProps,\n\ttype FieldPath,\n\ttype FieldValues,\n\tFormProvider,\n\tuseFormContext,\n\tuseFormState,\n} from \"react-hook-form\";\nimport { Label } from \"../../primitives/label/label.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root form provider. Wraps react-hook-form's FormProvider. */\nconst Form = FormProvider;\n\ninterface FormFieldContextValue<\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n\tname: TName;\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);\n\n/**\n * Binds a field name to a react-hook-form Controller.\n * Provides context so FormItem children can access field state.\n * @param props - Controller props including name, control, render\n * @returns A Controller with FormFieldContext\n */\nconst FormField = <\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n\t...props\n}: ControllerProps<TFieldValues, TName>) => {\n\treturn (\n\t\t<FormFieldContext.Provider value={{ name: props.name }}>\n\t\t\t<Controller {...props} />\n\t\t</FormFieldContext.Provider>\n\t);\n};\n\ninterface FormItemContextValue {\n\tid: string;\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);\n\n/**\n * Hook that returns the current field's id, name, error, and derived aria ids.\n * Must be called inside a FormField + FormItem subtree.\n * @returns Field state + aria descriptors\n */\nfunction useFormField() {\n\tconst fieldContext = React.useContext(FormFieldContext);\n\tconst itemContext = React.useContext(FormItemContext);\n\tif (!fieldContext?.name) {\n\t\tthrow new Error(\"useFormField should be used within <FormField>\");\n\t}\n\n\tconst { getFieldState } = useFormContext();\n\tconst formState = useFormState({ name: fieldContext.name });\n\tconst fieldState = getFieldState(fieldContext.name, formState);\n\n\tconst { id } = itemContext;\n\treturn {\n\t\tid,\n\t\tname: fieldContext.name,\n\t\tformItemId: `${id}-form-item`,\n\t\tformDescriptionId: `${id}-form-item-description`,\n\t\tformMessageId: `${id}-form-item-message`,\n\t\t...fieldState,\n\t};\n}\n\n/** Wraps a single form field (label + control + description + message). */\nconst FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, ...props }, ref) => {\n\t\tconst id = React.useId();\n\t\treturn (\n\t\t\t<FormItemContext.Provider value={{ id }}>\n\t\t\t\t<div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n\t\t\t</FormItemContext.Provider>\n\t\t);\n\t},\n);\nFormItem.displayName = \"FormItem\";\n\n/** Accessible label wired to the FormItem's control. Turns red on error. */\nconst FormLabel = React.forwardRef<\n\tReact.ComponentRef<typeof LabelPrimitive.Root>,\n\tReact.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n\tconst { error, formItemId } = useFormField();\n\treturn (\n\t\t<Label\n\t\t\tref={ref}\n\t\t\tclassName={cn(error && \"text-destructive\", className)}\n\t\t\thtmlFor={formItemId}\n\t\t\t{...props}\n\t\t/>\n\t);\n});\nFormLabel.displayName = \"FormLabel\";\n\n/** Wraps the form control and wires id + aria-describedby + aria-invalid. */\nconst FormControl = React.forwardRef<\n\tReact.ComponentRef<typeof Slot>,\n\tReact.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n\tconst { error, formItemId, formDescriptionId, formMessageId } = useFormField();\n\treturn (\n\t\t<Slot\n\t\t\tref={ref}\n\t\t\tid={formItemId}\n\t\t\taria-describedby={\n\t\t\t\terror ? `${formDescriptionId} ${formMessageId}` : `${formDescriptionId}`\n\t\t\t}\n\t\t\taria-invalid={!!error}\n\t\t\t{...props}\n\t\t/>\n\t);\n});\nFormControl.displayName = \"FormControl\";\n\n/** Optional helper text below the control. */\nconst FormDescription = React.forwardRef<\n\tHTMLParagraphElement,\n\tReact.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n\tconst { formDescriptionId } = useFormField();\n\treturn (\n\t\t<p\n\t\t\tref={ref}\n\t\t\tid={formDescriptionId}\n\t\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n});\nFormDescription.displayName = \"FormDescription\";\n\n/** Validation error message. Renders the error string when the field is invalid. */\nconst FormMessage = React.forwardRef<\n\tHTMLParagraphElement,\n\tReact.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n\tconst { error, formMessageId } = useFormField();\n\tconst body = error?.message ? String(error.message) : children;\n\tif (!body) return null;\n\treturn (\n\t\t<p\n\t\t\tref={ref}\n\t\t\tid={formMessageId}\n\t\t\tclassName={cn(\"text-sm font-medium text-destructive\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{body}\n\t\t</p>\n\t);\n});\nFormMessage.displayName = \"FormMessage\";\n\nexport {\n\tuseFormField,\n\tForm,\n\tFormItem,\n\tFormLabel,\n\tFormControl,\n\tFormDescription,\n\tFormMessage,\n\tFormField,\n};\n"]}
|
package/dist/grid.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* CVA variants for Grid — CSS grid with column-count presets and shared `gap`.
|
|
8
|
+
* `cols` accepts 1/2/3/4/6 fixed columns or `"auto-fit"` for responsive auto-sizing
|
|
9
|
+
* (in which case the consumer should pass `minColWidth` for the min track size).
|
|
10
|
+
*
|
|
11
|
+
* `cols` keys are TypeScript numeric literals (`cols={3}`) at the type level;
|
|
12
|
+
* the schema's `enumValues` serializes them as strings for JSON-shape parity.
|
|
13
|
+
*/
|
|
14
|
+
declare const gridVariants: (props?: ({
|
|
15
|
+
cols?: 1 | 2 | 3 | 4 | 6 | "auto-fit" | null | undefined;
|
|
16
|
+
gap?: "sm" | "lg" | "md" | "xl" | "xs" | null | undefined;
|
|
17
|
+
align?: "center" | "start" | "end" | "stretch" | null | undefined;
|
|
18
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
19
|
+
/** Props for the Grid component. */
|
|
20
|
+
interface GridProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof gridVariants> {
|
|
21
|
+
/**
|
|
22
|
+
* Minimum column width for `cols="auto-fit"`. Tracks repeat to fill the container,
|
|
23
|
+
* never shrinking below this value. Ignored when `cols` is a fixed integer.
|
|
24
|
+
* @default "16rem"
|
|
25
|
+
*/
|
|
26
|
+
minColWidth?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* CSS grid with column-count presets and consistent gap. Use for card grids,
|
|
30
|
+
* dashboards, image galleries, and any layout where children should align to
|
|
31
|
+
* shared row/column tracks.
|
|
32
|
+
*
|
|
33
|
+
* Pass `cols="auto-fit"` and `minColWidth` for responsive grids that fit as
|
|
34
|
+
* many columns as the viewport allows without media queries.
|
|
35
|
+
*
|
|
36
|
+
* @param props - Grid props including `cols`, `gap`, `align`, and `minColWidth`.
|
|
37
|
+
* @returns A CSS grid container.
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <Grid cols={3} gap="md">
|
|
41
|
+
* {items.map((i) => <Card key={i.id}>{i.title}</Card>)}
|
|
42
|
+
* </Grid>
|
|
43
|
+
* <Grid cols="auto-fit" minColWidth="20rem" gap="lg">
|
|
44
|
+
* {responsiveItems.map(...)}
|
|
45
|
+
* </Grid>
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare function Grid({ className, cols, gap, align, minColWidth, style, ...props }: GridProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
|
|
50
|
+
export { Grid, type GridProps, gridVariants };
|