@djangocfg/ui-tools 2.1.314 → 2.1.316
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/dist/TreeRoot-A25RIGYE.cjs +19 -0
- package/dist/TreeRoot-A25RIGYE.cjs.map +1 -0
- package/dist/TreeRoot-HBRJEHBH.mjs +4 -0
- package/dist/TreeRoot-HBRJEHBH.mjs.map +1 -0
- package/dist/chunk-4CEOJDMB.cjs +1300 -0
- package/dist/chunk-4CEOJDMB.cjs.map +1 -0
- package/dist/chunk-KR6B3LVY.mjs +59 -0
- package/dist/chunk-KR6B3LVY.mjs.map +1 -0
- package/dist/chunk-NFIMVYJU.mjs +1249 -0
- package/dist/chunk-NFIMVYJU.mjs.map +1 -0
- package/dist/chunk-YXBOAGIM.cjs +63 -0
- package/dist/chunk-YXBOAGIM.cjs.map +1 -0
- package/dist/index.cjs +151 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.mjs +11 -2
- package/dist/index.mjs.map +1 -1
- package/dist/tree/index.cjs +152 -0
- package/dist/tree/index.cjs.map +1 -0
- package/dist/tree/index.d.cts +442 -0
- package/dist/tree/index.d.ts +442 -0
- package/dist/tree/index.mjs +5 -0
- package/dist/tree/index.mjs.map +1 -0
- package/package.json +11 -6
- package/src/index.ts +4 -0
- package/src/tools/Tree/README.md +220 -0
- package/src/tools/Tree/Tree.story.tsx +536 -0
- package/src/tools/Tree/TreeRoot.tsx +164 -0
- package/src/tools/Tree/components/TreeChevron.tsx +39 -0
- package/src/tools/Tree/components/TreeContent.tsx +48 -0
- package/src/tools/Tree/components/TreeEmpty.tsx +21 -0
- package/src/tools/Tree/components/TreeError.tsx +24 -0
- package/src/tools/Tree/components/TreeIcon.tsx +29 -0
- package/src/tools/Tree/components/TreeIndentGuides.tsx +33 -0
- package/src/tools/Tree/components/TreeLabel.tsx +24 -0
- package/src/tools/Tree/components/TreeRow.tsx +163 -0
- package/src/tools/Tree/components/TreeSearchInput.tsx +50 -0
- package/src/tools/Tree/components/TreeSkeleton.tsx +22 -0
- package/src/tools/Tree/components/index.ts +22 -0
- package/src/tools/Tree/context/TreeContext.tsx +538 -0
- package/src/tools/Tree/context/hooks.ts +110 -0
- package/src/tools/Tree/context/index.ts +13 -0
- package/src/tools/Tree/data/appearance.ts +175 -0
- package/src/tools/Tree/data/childCache.ts +43 -0
- package/src/tools/Tree/data/createDemoTree.ts +42 -0
- package/src/tools/Tree/data/flatten.ts +51 -0
- package/src/tools/Tree/data/index.ts +24 -0
- package/src/tools/Tree/data/persist.ts +62 -0
- package/src/tools/Tree/hooks/index.ts +6 -0
- package/src/tools/Tree/hooks/useTreeKeyboard.ts +171 -0
- package/src/tools/Tree/hooks/useTreeTypeAhead.ts +100 -0
- package/src/tools/Tree/index.tsx +99 -0
- package/src/tools/Tree/lazy.tsx +14 -0
- package/src/tools/Tree/types.ts +136 -0
- package/src/tools/index.ts +75 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var chunkYXBOAGIM_cjs = require('../chunk-YXBOAGIM.cjs');
|
|
6
|
+
var chunk4CEOJDMB_cjs = require('../chunk-4CEOJDMB.cjs');
|
|
7
|
+
require('../chunk-WGEGR3DF.cjs');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
Object.defineProperty(exports, "TreeError", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkYXBOAGIM_cjs.TreeError; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "TreeSkeleton", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkYXBOAGIM_cjs.TreeSkeleton; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, "createDemoTree", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return chunkYXBOAGIM_cjs.createDemoTree; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, "DEFAULT_TREE_APPEARANCE", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return chunk4CEOJDMB_cjs.DEFAULT_TREE_APPEARANCE; }
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "DEFAULT_TREE_LABELS", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () { return chunk4CEOJDMB_cjs.DEFAULT_TREE_LABELS; }
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(exports, "Tree", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeRoot; }
|
|
34
|
+
});
|
|
35
|
+
Object.defineProperty(exports, "TreeChevron", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeChevron; }
|
|
38
|
+
});
|
|
39
|
+
Object.defineProperty(exports, "TreeContent", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeContent; }
|
|
42
|
+
});
|
|
43
|
+
Object.defineProperty(exports, "TreeEmpty", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeEmpty; }
|
|
46
|
+
});
|
|
47
|
+
Object.defineProperty(exports, "TreeIcon", {
|
|
48
|
+
enumerable: true,
|
|
49
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeIcon; }
|
|
50
|
+
});
|
|
51
|
+
Object.defineProperty(exports, "TreeIndentGuides", {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeIndentGuides; }
|
|
54
|
+
});
|
|
55
|
+
Object.defineProperty(exports, "TreeLabel", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeLabel; }
|
|
58
|
+
});
|
|
59
|
+
Object.defineProperty(exports, "TreeProvider", {
|
|
60
|
+
enumerable: true,
|
|
61
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeProvider; }
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(exports, "TreeRoot", {
|
|
64
|
+
enumerable: true,
|
|
65
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeRoot; }
|
|
66
|
+
});
|
|
67
|
+
Object.defineProperty(exports, "TreeRow", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeRow; }
|
|
70
|
+
});
|
|
71
|
+
Object.defineProperty(exports, "TreeSearchInput", {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeSearchInput; }
|
|
74
|
+
});
|
|
75
|
+
Object.defineProperty(exports, "appearanceToStyle", {
|
|
76
|
+
enumerable: true,
|
|
77
|
+
get: function () { return chunk4CEOJDMB_cjs.appearanceToStyle; }
|
|
78
|
+
});
|
|
79
|
+
Object.defineProperty(exports, "clearTreeState", {
|
|
80
|
+
enumerable: true,
|
|
81
|
+
get: function () { return chunk4CEOJDMB_cjs.clearTreeState; }
|
|
82
|
+
});
|
|
83
|
+
Object.defineProperty(exports, "createChildCache", {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
get: function () { return chunk4CEOJDMB_cjs.createChildCache; }
|
|
86
|
+
});
|
|
87
|
+
Object.defineProperty(exports, "default", {
|
|
88
|
+
enumerable: true,
|
|
89
|
+
get: function () { return chunk4CEOJDMB_cjs.TreeRoot_default; }
|
|
90
|
+
});
|
|
91
|
+
Object.defineProperty(exports, "flattenTree", {
|
|
92
|
+
enumerable: true,
|
|
93
|
+
get: function () { return chunk4CEOJDMB_cjs.flattenTree; }
|
|
94
|
+
});
|
|
95
|
+
Object.defineProperty(exports, "loadTreeState", {
|
|
96
|
+
enumerable: true,
|
|
97
|
+
get: function () { return chunk4CEOJDMB_cjs.loadTreeState; }
|
|
98
|
+
});
|
|
99
|
+
Object.defineProperty(exports, "resolveAppearance", {
|
|
100
|
+
enumerable: true,
|
|
101
|
+
get: function () { return chunk4CEOJDMB_cjs.resolveAppearance; }
|
|
102
|
+
});
|
|
103
|
+
Object.defineProperty(exports, "resolveChildren", {
|
|
104
|
+
enumerable: true,
|
|
105
|
+
get: function () { return chunk4CEOJDMB_cjs.resolveChildren; }
|
|
106
|
+
});
|
|
107
|
+
Object.defineProperty(exports, "saveTreeState", {
|
|
108
|
+
enumerable: true,
|
|
109
|
+
get: function () { return chunk4CEOJDMB_cjs.saveTreeState; }
|
|
110
|
+
});
|
|
111
|
+
Object.defineProperty(exports, "useTreeActions", {
|
|
112
|
+
enumerable: true,
|
|
113
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeActions; }
|
|
114
|
+
});
|
|
115
|
+
Object.defineProperty(exports, "useTreeContext", {
|
|
116
|
+
enumerable: true,
|
|
117
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeContext; }
|
|
118
|
+
});
|
|
119
|
+
Object.defineProperty(exports, "useTreeExpansion", {
|
|
120
|
+
enumerable: true,
|
|
121
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeExpansion; }
|
|
122
|
+
});
|
|
123
|
+
Object.defineProperty(exports, "useTreeFocus", {
|
|
124
|
+
enumerable: true,
|
|
125
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeFocus; }
|
|
126
|
+
});
|
|
127
|
+
Object.defineProperty(exports, "useTreeKeyboard", {
|
|
128
|
+
enumerable: true,
|
|
129
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeKeyboard; }
|
|
130
|
+
});
|
|
131
|
+
Object.defineProperty(exports, "useTreeLabels", {
|
|
132
|
+
enumerable: true,
|
|
133
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeLabels; }
|
|
134
|
+
});
|
|
135
|
+
Object.defineProperty(exports, "useTreeRows", {
|
|
136
|
+
enumerable: true,
|
|
137
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeRows; }
|
|
138
|
+
});
|
|
139
|
+
Object.defineProperty(exports, "useTreeSearch", {
|
|
140
|
+
enumerable: true,
|
|
141
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeSearch; }
|
|
142
|
+
});
|
|
143
|
+
Object.defineProperty(exports, "useTreeSelection", {
|
|
144
|
+
enumerable: true,
|
|
145
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeSelection; }
|
|
146
|
+
});
|
|
147
|
+
Object.defineProperty(exports, "useTreeTypeAhead", {
|
|
148
|
+
enumerable: true,
|
|
149
|
+
get: function () { return chunk4CEOJDMB_cjs.useTreeTypeAhead; }
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=index.cjs.map
|
|
152
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React$1 from 'react';
|
|
3
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
type TreeDensity = 'compact' | 'cozy' | 'comfortable';
|
|
6
|
+
type TreeAccentIntensity = 'subtle' | 'default' | 'strong';
|
|
7
|
+
type TreeRadius = 'none' | 'sm' | 'md';
|
|
8
|
+
/**
|
|
9
|
+
* Cosmetic configuration. Every field is optional; missing values fall
|
|
10
|
+
* back to the `cozy` preset (a comfortable VSCode-Explorer-like density).
|
|
11
|
+
*
|
|
12
|
+
* Customize the look without re-implementing slots.
|
|
13
|
+
*/
|
|
14
|
+
interface TreeAppearance {
|
|
15
|
+
/** Built-in size preset. Default: `'cozy'`. */
|
|
16
|
+
density?: TreeDensity;
|
|
17
|
+
/** Override row height in px (wins over density). */
|
|
18
|
+
rowHeight?: number;
|
|
19
|
+
/** Override icon + chevron size in px (wins over density). */
|
|
20
|
+
iconSize?: number;
|
|
21
|
+
/** Lucide stroke width for icon + chevron. Default: 1.5. */
|
|
22
|
+
iconStrokeWidth?: number;
|
|
23
|
+
/** Override label font size in px (wins over density). */
|
|
24
|
+
fontSize?: number;
|
|
25
|
+
/** Pixels between chevron / icon / label. Default depends on density. */
|
|
26
|
+
gap?: number;
|
|
27
|
+
/** Pixels between nesting levels. Default: 16. */
|
|
28
|
+
indent?: number;
|
|
29
|
+
/** Hover / selected highlight intensity. Default: `'default'`. */
|
|
30
|
+
accent?: TreeAccentIntensity;
|
|
31
|
+
/** Row corner radius. Default: `'sm'`. */
|
|
32
|
+
radius?: TreeRadius;
|
|
33
|
+
/** Indent-guide line opacity (0..1). Default: 0.4. */
|
|
34
|
+
indentGuideOpacity?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Show a 2px primary-tinted bar on the left of the selected row.
|
|
37
|
+
* Mimics the VSCode active-tab indicator. Default: `true`.
|
|
38
|
+
*/
|
|
39
|
+
showActiveIndicator?: boolean;
|
|
40
|
+
}
|
|
41
|
+
interface ResolvedAppearance {
|
|
42
|
+
density: TreeDensity;
|
|
43
|
+
rowHeight: number;
|
|
44
|
+
iconSize: number;
|
|
45
|
+
iconStrokeWidth: number;
|
|
46
|
+
fontSize: number;
|
|
47
|
+
gap: number;
|
|
48
|
+
indent: number;
|
|
49
|
+
accent: TreeAccentIntensity;
|
|
50
|
+
radius: TreeRadius;
|
|
51
|
+
indentGuideOpacity: number;
|
|
52
|
+
showActiveIndicator: boolean;
|
|
53
|
+
}
|
|
54
|
+
declare const DEFAULT_TREE_APPEARANCE: ResolvedAppearance;
|
|
55
|
+
/**
|
|
56
|
+
* Merge a partial appearance with the default + density preset.
|
|
57
|
+
*
|
|
58
|
+
* Explicit numeric overrides (e.g. `rowHeight`) win over the density preset.
|
|
59
|
+
*/
|
|
60
|
+
declare function resolveAppearance(input?: TreeAppearance,
|
|
61
|
+
/** Outer `indent` prop (kept on TreeRoot for back-compat). */
|
|
62
|
+
outerIndent?: number): ResolvedAppearance;
|
|
63
|
+
/**
|
|
64
|
+
* Build the `style` object that exposes the resolved appearance to any
|
|
65
|
+
* descendant via CSS variables. Set on `<TreeRoot>`'s outer div.
|
|
66
|
+
*/
|
|
67
|
+
declare function appearanceToStyle(a: ResolvedAppearance): CSSProperties;
|
|
68
|
+
|
|
69
|
+
type TreeItemId = string;
|
|
70
|
+
/** A single node in the consumer's tree data. Generic over your payload. */
|
|
71
|
+
interface TreeNode<T = unknown> {
|
|
72
|
+
id: TreeItemId;
|
|
73
|
+
data: T;
|
|
74
|
+
/** Inline children. Omit (and provide a `loadChildren`) for async loading. */
|
|
75
|
+
children?: TreeNode<T>[];
|
|
76
|
+
/**
|
|
77
|
+
* Set to `true` to mark a node as a folder even when its `children` array
|
|
78
|
+
* is empty (e.g. an unloaded async folder). Default: derived from
|
|
79
|
+
* `Array.isArray(children)`.
|
|
80
|
+
*/
|
|
81
|
+
isFolder?: boolean;
|
|
82
|
+
/** Disable interaction. */
|
|
83
|
+
disabled?: boolean;
|
|
84
|
+
}
|
|
85
|
+
interface TreeLabels {
|
|
86
|
+
loading: string;
|
|
87
|
+
empty: string;
|
|
88
|
+
error: string;
|
|
89
|
+
searchPlaceholder: string;
|
|
90
|
+
searchMatches: (count: number) => string;
|
|
91
|
+
ariaLabel: string;
|
|
92
|
+
}
|
|
93
|
+
declare const DEFAULT_TREE_LABELS: TreeLabels;
|
|
94
|
+
type TreeSelectionMode = 'none' | 'single' | 'multiple';
|
|
95
|
+
/**
|
|
96
|
+
* Async loader: called the first time a folder is expanded with no inline
|
|
97
|
+
* `children`. Result is cached; concurrent expansions are de-duplicated.
|
|
98
|
+
*/
|
|
99
|
+
type TreeLoadChildren<T> = (node: TreeNode<T>) => Promise<TreeNode<T>[]>;
|
|
100
|
+
interface TreeRowRenderProps<T> {
|
|
101
|
+
node: TreeNode<T>;
|
|
102
|
+
level: number;
|
|
103
|
+
isSelected: boolean;
|
|
104
|
+
isExpanded: boolean;
|
|
105
|
+
isFocused: boolean;
|
|
106
|
+
isFolder: boolean;
|
|
107
|
+
isLoading: boolean;
|
|
108
|
+
isMatchingSearch: boolean;
|
|
109
|
+
}
|
|
110
|
+
type TreeRowSlot<T> = (props: TreeRowRenderProps<T>) => ReactNode;
|
|
111
|
+
type TreeContextMenuSlot<T> = (props: TreeRowRenderProps<T>, trigger: ReactNode) => ReactNode;
|
|
112
|
+
interface TreeRootProps<T> {
|
|
113
|
+
/** Root nodes. Top-level items are rendered directly (no synthetic root). */
|
|
114
|
+
data: TreeNode<T>[];
|
|
115
|
+
/** Returns the human-readable name for a node (used by search/type-ahead). */
|
|
116
|
+
getItemName: (node: TreeNode<T>) => string;
|
|
117
|
+
/** Async loader for folders without inline `children`. */
|
|
118
|
+
loadChildren?: TreeLoadChildren<T>;
|
|
119
|
+
/** Selection behaviour. Default: `'single'`. */
|
|
120
|
+
selectionMode?: TreeSelectionMode;
|
|
121
|
+
/** Initially expanded ids. */
|
|
122
|
+
initialExpandedIds?: TreeItemId[];
|
|
123
|
+
/** Initially selected ids. */
|
|
124
|
+
initialSelectedIds?: TreeItemId[];
|
|
125
|
+
/** Pixels of indent per nesting level. Default: 16. (Shortcut for `appearance.indent`.) */
|
|
126
|
+
indent?: number;
|
|
127
|
+
/** Cosmetic configuration: density, sizes, accent intensity, radius. */
|
|
128
|
+
appearance?: TreeAppearance;
|
|
129
|
+
/** Triggered when selection changes. */
|
|
130
|
+
onSelectionChange?: (selectedIds: TreeItemId[]) => void;
|
|
131
|
+
/** Triggered when expanded set changes. */
|
|
132
|
+
onExpansionChange?: (expandedIds: TreeItemId[]) => void;
|
|
133
|
+
/** Enter / dblclick on a node. */
|
|
134
|
+
onActivate?: (node: TreeNode<T>) => void;
|
|
135
|
+
/** Show built-in search input. Default: false. */
|
|
136
|
+
enableSearch?: boolean;
|
|
137
|
+
/** Type printable letters to jump to a matching name. Default: true. */
|
|
138
|
+
enableTypeAhead?: boolean;
|
|
139
|
+
/** Render vertical indent guides under expanded folders. Default: false. */
|
|
140
|
+
showIndentGuides?: boolean;
|
|
141
|
+
/** Custom row renderer. Falls back to the default <TreeRow />. */
|
|
142
|
+
renderRow?: TreeRowSlot<T>;
|
|
143
|
+
/** Replace default folder/file icon. */
|
|
144
|
+
renderIcon?: TreeRowSlot<T>;
|
|
145
|
+
/** Replace default label rendering. */
|
|
146
|
+
renderLabel?: TreeRowSlot<T>;
|
|
147
|
+
/** Right-side actions slot (per row). */
|
|
148
|
+
renderActions?: TreeRowSlot<T>;
|
|
149
|
+
/** Wrap each row in a context menu (right-click). Receives the row meta + trigger element. */
|
|
150
|
+
renderContextMenu?: TreeContextMenuSlot<T>;
|
|
151
|
+
/** Override built-in copy in your locale. */
|
|
152
|
+
labels?: Partial<TreeLabels>;
|
|
153
|
+
/** Persist expanded + (optional) selected ids in localStorage under this key. */
|
|
154
|
+
persistKey?: string;
|
|
155
|
+
/** Persist selection alongside expansion. Default: false. */
|
|
156
|
+
persistSelection?: boolean;
|
|
157
|
+
className?: string;
|
|
158
|
+
style?: React.CSSProperties;
|
|
159
|
+
}
|
|
160
|
+
/** Internal flat-row representation used by the renderer + keyboard nav. */
|
|
161
|
+
interface FlatRow<T> {
|
|
162
|
+
node: TreeNode<T>;
|
|
163
|
+
level: number;
|
|
164
|
+
parentId: TreeItemId | null;
|
|
165
|
+
isFolder: boolean;
|
|
166
|
+
isExpanded: boolean;
|
|
167
|
+
isLoading: boolean;
|
|
168
|
+
hasError: boolean;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* High-level entry point. Wraps Provider + (optional) search bar + content.
|
|
173
|
+
*
|
|
174
|
+
* For full control, compose with <TreeProvider>, <TreeContent>,
|
|
175
|
+
* <TreeSearchInput>, <TreeRow>, etc. directly from `@djangocfg/ui-tools/tree`.
|
|
176
|
+
*/
|
|
177
|
+
declare function TreeRoot<T>(props: TreeRootProps<T>): react_jsx_runtime.JSX.Element;
|
|
178
|
+
|
|
179
|
+
type ChildEntryStatus = 'idle' | 'loading' | 'loaded' | 'error';
|
|
180
|
+
interface ChildEntry<T> {
|
|
181
|
+
status: ChildEntryStatus;
|
|
182
|
+
children: TreeNode<T>[];
|
|
183
|
+
error?: string;
|
|
184
|
+
}
|
|
185
|
+
type ChildCache<T> = Map<TreeItemId, ChildEntry<T>>;
|
|
186
|
+
declare const createChildCache: <T>() => ChildCache<T>;
|
|
187
|
+
/**
|
|
188
|
+
* Resolve a node's children for the current render.
|
|
189
|
+
*
|
|
190
|
+
* - If the node carries inline `children`, those win (no async fetch).
|
|
191
|
+
* - Otherwise we look in the cache.
|
|
192
|
+
*
|
|
193
|
+
* Returns `null` when nothing is loaded yet (caller may show a skeleton).
|
|
194
|
+
*/
|
|
195
|
+
declare const resolveChildren: <T>(cache: ChildCache<T>, node: TreeNode<T>) => {
|
|
196
|
+
children: TreeNode<T>[] | null;
|
|
197
|
+
status: ChildEntryStatus;
|
|
198
|
+
error?: string;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
interface TreeContextValue<T> {
|
|
202
|
+
expanded: ReadonlySet<TreeItemId>;
|
|
203
|
+
selected: ReadonlySet<TreeItemId>;
|
|
204
|
+
focused: TreeItemId | null;
|
|
205
|
+
query: string;
|
|
206
|
+
flatRows: FlatRow<T>[];
|
|
207
|
+
/** Search-matching node ids (subset of all flatRows). */
|
|
208
|
+
matchingIds: ReadonlySet<TreeItemId>;
|
|
209
|
+
expand: (id: TreeItemId) => void;
|
|
210
|
+
collapse: (id: TreeItemId) => void;
|
|
211
|
+
toggle: (id: TreeItemId) => void;
|
|
212
|
+
expandAll: () => void;
|
|
213
|
+
collapseAll: () => void;
|
|
214
|
+
select: (id: TreeItemId) => void;
|
|
215
|
+
setSelectedIds: (ids: TreeItemId[]) => void;
|
|
216
|
+
clearSelection: () => void;
|
|
217
|
+
setFocus: (id: TreeItemId | null) => void;
|
|
218
|
+
setQuery: (q: string) => void;
|
|
219
|
+
refresh: (id: TreeItemId) => Promise<void>;
|
|
220
|
+
refreshAll: () => Promise<void>;
|
|
221
|
+
activate: (node: TreeNode<T>) => void;
|
|
222
|
+
labels: TreeLabels;
|
|
223
|
+
/** Resolved cosmetic config — never null. */
|
|
224
|
+
appearance: ResolvedAppearance;
|
|
225
|
+
/** Convenience alias for `appearance.indent`. */
|
|
226
|
+
indent: number;
|
|
227
|
+
selectionMode: TreeSelectionMode;
|
|
228
|
+
enableSearch: boolean;
|
|
229
|
+
showIndentGuides: boolean;
|
|
230
|
+
getItemName: (node: TreeNode<T>) => string;
|
|
231
|
+
renderIcon?: TreeRowSlot<T>;
|
|
232
|
+
renderLabel?: TreeRowSlot<T>;
|
|
233
|
+
renderActions?: TreeRowSlot<T>;
|
|
234
|
+
renderContextMenu?: TreeContextMenuSlot<T>;
|
|
235
|
+
}
|
|
236
|
+
declare function useTreeContext<T>(): TreeContextValue<T>;
|
|
237
|
+
interface TreeProviderProps<T> extends Pick<TreeRootProps<T>, 'data' | 'getItemName' | 'loadChildren' | 'selectionMode' | 'initialExpandedIds' | 'initialSelectedIds' | 'indent' | 'appearance' | 'onSelectionChange' | 'onExpansionChange' | 'onActivate' | 'enableSearch' | 'showIndentGuides' | 'renderIcon' | 'renderLabel' | 'renderActions' | 'renderContextMenu' | 'labels' | 'persistKey' | 'persistSelection'> {
|
|
238
|
+
children: React$1.ReactNode;
|
|
239
|
+
}
|
|
240
|
+
declare function TreeProvider<T>(props: TreeProviderProps<T>): react_jsx_runtime.JSX.Element;
|
|
241
|
+
|
|
242
|
+
declare function useTreeLabels(): TreeLabels;
|
|
243
|
+
declare function useTreeRows<T>(): FlatRow<T>[];
|
|
244
|
+
declare function useTreeSelection<T>(): {
|
|
245
|
+
selectedIds: string[];
|
|
246
|
+
select: (id: TreeItemId) => void;
|
|
247
|
+
setSelectedIds: (ids: TreeItemId[]) => void;
|
|
248
|
+
clear: () => void;
|
|
249
|
+
isSelected: (id: TreeItemId) => boolean;
|
|
250
|
+
};
|
|
251
|
+
declare function useTreeExpansion<T>(): {
|
|
252
|
+
expandedIds: string[];
|
|
253
|
+
expand: (id: TreeItemId) => void;
|
|
254
|
+
collapse: (id: TreeItemId) => void;
|
|
255
|
+
toggle: (id: TreeItemId) => void;
|
|
256
|
+
expandAll: () => void;
|
|
257
|
+
collapseAll: () => void;
|
|
258
|
+
isExpanded: (id: TreeItemId) => boolean;
|
|
259
|
+
};
|
|
260
|
+
declare function useTreeFocus<T>(): {
|
|
261
|
+
focusedId: string;
|
|
262
|
+
setFocus: (id: TreeItemId | null) => void;
|
|
263
|
+
};
|
|
264
|
+
declare function useTreeSearch<T>(): {
|
|
265
|
+
isOpen: boolean;
|
|
266
|
+
query: string;
|
|
267
|
+
setQuery: (q: string) => void;
|
|
268
|
+
matchingIds: ReadonlySet<string>;
|
|
269
|
+
matchCount: number;
|
|
270
|
+
};
|
|
271
|
+
declare function useTreeActions<T>(): {
|
|
272
|
+
expand: (id: TreeItemId) => void;
|
|
273
|
+
collapse: (id: TreeItemId) => void;
|
|
274
|
+
toggle: (id: TreeItemId) => void;
|
|
275
|
+
expandAll: () => void;
|
|
276
|
+
collapseAll: () => void;
|
|
277
|
+
refresh: (id: TreeItemId) => Promise<void>;
|
|
278
|
+
refreshAll: () => Promise<void>;
|
|
279
|
+
activate: (node: TreeNode<T>) => void;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
interface UseTreeTypeAheadOptions<T> {
|
|
283
|
+
/** Visible flat rows in render order. */
|
|
284
|
+
rows: FlatRow<T>[];
|
|
285
|
+
/** How to read the displayed name of a node (matched case-insensitively). */
|
|
286
|
+
getItemName: (node: TreeNode<T>) => string;
|
|
287
|
+
/** Element receiving keydown events. */
|
|
288
|
+
containerRef: React.RefObject<HTMLElement | null>;
|
|
289
|
+
/** Called with the matched node id so the consumer can focus / scroll. */
|
|
290
|
+
onMatch: (id: string) => void;
|
|
291
|
+
/** Disable without removing the call site. */
|
|
292
|
+
enabled?: boolean;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Type-ahead jump (Finder / VSCode style).
|
|
296
|
+
*
|
|
297
|
+
* Builds a rolling buffer of printable keys (within ~600 ms of each other)
|
|
298
|
+
* and notifies the consumer of the first row whose name starts with that
|
|
299
|
+
* prefix. Resets on Esc / Enter / navigation keys / timeout.
|
|
300
|
+
*/
|
|
301
|
+
declare function useTreeTypeAhead<T>({ rows, getItemName, containerRef, onMatch, enabled, }: UseTreeTypeAheadOptions<T>): void;
|
|
302
|
+
|
|
303
|
+
interface UseTreeKeyboardOptions<T> {
|
|
304
|
+
rows: FlatRow<T>[];
|
|
305
|
+
focusedId: TreeItemId | null;
|
|
306
|
+
enabled?: boolean;
|
|
307
|
+
onFocus: (id: TreeItemId) => void;
|
|
308
|
+
onSelect: (id: TreeItemId) => void;
|
|
309
|
+
onActivate: (id: TreeItemId) => void;
|
|
310
|
+
onExpand: (id: TreeItemId) => void;
|
|
311
|
+
onCollapse: (id: TreeItemId) => void;
|
|
312
|
+
onClearSelection: () => void;
|
|
313
|
+
}
|
|
314
|
+
interface UseTreeKeyboardReturn {
|
|
315
|
+
/** Attach to the tree container. Hotkeys only fire when focus is inside. */
|
|
316
|
+
ref: (instance: HTMLElement | null) => void;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Standard tree keyboard navigation, scoped to the container ref.
|
|
320
|
+
*
|
|
321
|
+
* - ↑ / ↓ : prev / next visible row
|
|
322
|
+
* - Home / End : first / last visible row
|
|
323
|
+
* - → : expand folder; if already expanded, jump to first child
|
|
324
|
+
* - ← : collapse folder; if already collapsed (or leaf), jump to parent
|
|
325
|
+
* - Enter / Space : activate (folder => toggle, leaf => onActivate)
|
|
326
|
+
* - Esc : clear selection
|
|
327
|
+
*
|
|
328
|
+
* Built on `useHotkey` (react-hotkeys-hook) — focus gating is automatic; no
|
|
329
|
+
* manual `addEventListener` or `data-scope` juggling.
|
|
330
|
+
*/
|
|
331
|
+
declare function useTreeKeyboard<T>({ rows, focusedId, enabled, onFocus, onSelect, onActivate, onExpand, onCollapse, onClearSelection, }: UseTreeKeyboardOptions<T>): UseTreeKeyboardReturn;
|
|
332
|
+
|
|
333
|
+
interface TreeChevronProps {
|
|
334
|
+
isExpanded: boolean;
|
|
335
|
+
isFolder: boolean;
|
|
336
|
+
className?: string;
|
|
337
|
+
}
|
|
338
|
+
declare function TreeChevron({ isExpanded, isFolder, className }: TreeChevronProps): react_jsx_runtime.JSX.Element;
|
|
339
|
+
|
|
340
|
+
interface TreeIconProps {
|
|
341
|
+
isFolder: boolean;
|
|
342
|
+
isExpanded: boolean;
|
|
343
|
+
className?: string;
|
|
344
|
+
}
|
|
345
|
+
declare function TreeIcon({ isFolder, isExpanded, className }: TreeIconProps): react_jsx_runtime.JSX.Element;
|
|
346
|
+
|
|
347
|
+
interface TreeLabelProps {
|
|
348
|
+
children: React.ReactNode;
|
|
349
|
+
isMatchingSearch?: boolean;
|
|
350
|
+
className?: string;
|
|
351
|
+
}
|
|
352
|
+
declare function TreeLabel({ children, isMatchingSearch, className }: TreeLabelProps): react_jsx_runtime.JSX.Element;
|
|
353
|
+
|
|
354
|
+
interface TreeRowProps<T> {
|
|
355
|
+
row: FlatRow<T>;
|
|
356
|
+
className?: string;
|
|
357
|
+
}
|
|
358
|
+
declare function TreeRow<T>({ row, className }: TreeRowProps<T>): react_jsx_runtime.JSX.Element;
|
|
359
|
+
|
|
360
|
+
interface TreeContentProps<T> {
|
|
361
|
+
/** Custom row renderer; falls back to <TreeRow />. */
|
|
362
|
+
children?: TreeRowSlot<T>;
|
|
363
|
+
className?: string;
|
|
364
|
+
/** Override aria-label for the container. */
|
|
365
|
+
ariaLabel?: string;
|
|
366
|
+
}
|
|
367
|
+
declare function TreeContent<T>({ children, className, ariaLabel }: TreeContentProps<T>): react_jsx_runtime.JSX.Element;
|
|
368
|
+
|
|
369
|
+
interface TreeSearchInputProps {
|
|
370
|
+
className?: string;
|
|
371
|
+
showMatches?: boolean;
|
|
372
|
+
}
|
|
373
|
+
declare function TreeSearchInput({ className, showMatches }: TreeSearchInputProps): react_jsx_runtime.JSX.Element;
|
|
374
|
+
|
|
375
|
+
interface TreeEmptyProps {
|
|
376
|
+
children: React.ReactNode;
|
|
377
|
+
className?: string;
|
|
378
|
+
}
|
|
379
|
+
declare function TreeEmpty({ children, className }: TreeEmptyProps): react_jsx_runtime.JSX.Element;
|
|
380
|
+
|
|
381
|
+
interface TreeSkeletonProps {
|
|
382
|
+
rows?: number;
|
|
383
|
+
className?: string;
|
|
384
|
+
}
|
|
385
|
+
declare function TreeSkeleton({ rows, className }: TreeSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
386
|
+
|
|
387
|
+
interface TreeErrorProps {
|
|
388
|
+
children: React.ReactNode;
|
|
389
|
+
className?: string;
|
|
390
|
+
}
|
|
391
|
+
declare function TreeError({ children, className }: TreeErrorProps): react_jsx_runtime.JSX.Element;
|
|
392
|
+
|
|
393
|
+
interface TreeIndentGuidesProps {
|
|
394
|
+
level: number;
|
|
395
|
+
indent: number;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Vertical guide lines under nested rows. Renders one absolute-positioned
|
|
399
|
+
* 1px column per ancestor level. Decorative — `aria-hidden` and
|
|
400
|
+
* pointer-events disabled. Opacity comes from the tree appearance.
|
|
401
|
+
*/
|
|
402
|
+
declare function TreeIndentGuides({ level, indent }: TreeIndentGuidesProps): react_jsx_runtime.JSX.Element;
|
|
403
|
+
|
|
404
|
+
interface FlattenInput<T> {
|
|
405
|
+
roots: TreeNode<T>[];
|
|
406
|
+
expandedIds: ReadonlySet<TreeItemId>;
|
|
407
|
+
cache: ChildCache<T>;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Walk the tree top-to-bottom and produce a flat list of visible rows.
|
|
411
|
+
*
|
|
412
|
+
* Visibility rule: a child row appears only when every ancestor is in
|
|
413
|
+
* `expandedIds`. The output is ordered exactly as it should render,
|
|
414
|
+
* which keeps keyboard navigation (next/prev row) trivial.
|
|
415
|
+
*/
|
|
416
|
+
declare function flattenTree<T>({ roots, expandedIds, cache }: FlattenInput<T>): FlatRow<T>[];
|
|
417
|
+
|
|
418
|
+
interface PersistedTreeState {
|
|
419
|
+
expandedItems: TreeItemId[];
|
|
420
|
+
selectedItems: TreeItemId[];
|
|
421
|
+
}
|
|
422
|
+
declare function loadTreeState(key: string): PersistedTreeState | null;
|
|
423
|
+
declare function saveTreeState(key: string, state: PersistedTreeState): void;
|
|
424
|
+
declare function clearTreeState(key: string): void;
|
|
425
|
+
|
|
426
|
+
interface DemoNode {
|
|
427
|
+
name: string;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Build a deterministic synthetic tree for stories and tests.
|
|
431
|
+
*
|
|
432
|
+
* @example
|
|
433
|
+
* const data = createDemoTree({ depth: 4, breadth: 3 });
|
|
434
|
+
* <TreeRoot data={data} getItemName={(n) => n.data.name} />
|
|
435
|
+
*/
|
|
436
|
+
declare function createDemoTree({ depth, breadth, rootPrefix, }?: {
|
|
437
|
+
depth?: number;
|
|
438
|
+
breadth?: number;
|
|
439
|
+
rootPrefix?: string;
|
|
440
|
+
}): TreeNode<DemoNode>[];
|
|
441
|
+
|
|
442
|
+
export { type ChildCache, type ChildEntry, type ChildEntryStatus, DEFAULT_TREE_APPEARANCE, DEFAULT_TREE_LABELS, type DemoNode, type FlatRow, type FlattenInput, type PersistedTreeState, type ResolvedAppearance, TreeRoot as Tree, type TreeAccentIntensity, type TreeAppearance, TreeChevron, type TreeChevronProps, TreeContent, type TreeContentProps, type TreeContextMenuSlot, type TreeContextValue, type TreeDensity, TreeEmpty, type TreeEmptyProps, TreeError, type TreeErrorProps, TreeIcon, type TreeIconProps, TreeIndentGuides, type TreeIndentGuidesProps, type TreeItemId, TreeLabel, type TreeLabelProps, type TreeLabels, type TreeLoadChildren, type TreeNode, TreeProvider, type TreeProviderProps, type TreeRadius, TreeRoot, type TreeRootProps, TreeRow, type TreeRowProps, type TreeRowRenderProps, type TreeRowSlot, TreeSearchInput, type TreeSearchInputProps, type TreeSelectionMode, TreeSkeleton, type TreeSkeletonProps, type UseTreeKeyboardOptions, type UseTreeTypeAheadOptions, appearanceToStyle, clearTreeState, createChildCache, createDemoTree, TreeRoot as default, flattenTree, loadTreeState, resolveAppearance, resolveChildren, saveTreeState, useTreeActions, useTreeContext, useTreeExpansion, useTreeFocus, useTreeKeyboard, useTreeLabels, useTreeRows, useTreeSearch, useTreeSelection, useTreeTypeAhead };
|