@djangocfg/ui-tools 2.1.316 → 2.1.318
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-A3J65L6F.mjs +4 -0
- package/dist/{TreeRoot-A25RIGYE.cjs.map → TreeRoot-A3J65L6F.mjs.map} +1 -1
- package/dist/TreeRoot-DSK5JILT.cjs +19 -0
- package/dist/{TreeRoot-HBRJEHBH.mjs.map → TreeRoot-DSK5JILT.cjs.map} +1 -1
- package/dist/{chunk-4CEOJDMB.cjs → chunk-3Z3A7FHA.cjs} +36 -15
- package/dist/chunk-3Z3A7FHA.cjs.map +1 -0
- package/dist/{chunk-NFIMVYJU.mjs → chunk-MOME6KYD.mjs} +36 -15
- package/dist/chunk-MOME6KYD.mjs.map +1 -0
- package/dist/file-icon/index.cjs +173 -0
- package/dist/file-icon/index.cjs.map +1 -0
- package/dist/file-icon/index.d.cts +98 -0
- package/dist/file-icon/index.d.ts +98 -0
- package/dist/file-icon/index.mjs +167 -0
- package/dist/file-icon/index.mjs.map +1 -0
- package/dist/index.cjs +122 -122
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +3 -3
- package/dist/tree/index.cjs +33 -33
- package/dist/tree/index.d.cts +10 -172
- package/dist/tree/index.d.ts +10 -172
- package/dist/tree/index.mjs +1 -1
- package/dist/types-CevSbyfD.d.cts +204 -0
- package/dist/types-CevSbyfD.d.ts +204 -0
- package/package.json +13 -7
- package/src/tools/FileIcon/FileIcon.tsx +102 -0
- package/src/tools/FileIcon/index.ts +15 -0
- package/src/tools/FileIcon/loader.ts +47 -0
- package/src/tools/FileIcon/specialFolders.ts +93 -0
- package/src/tools/FileIcon/treeAdapter.tsx +49 -0
- package/src/tools/Tree/README.md +100 -0
- package/src/tools/Tree/Tree.story.tsx +84 -0
- package/src/tools/Tree/TreeRoot.tsx +6 -1
- package/src/tools/Tree/components/TreeContent.tsx +3 -1
- package/src/tools/Tree/components/TreeRow.tsx +17 -8
- package/src/tools/Tree/context/TreeContext.tsx +14 -3
- package/src/tools/Tree/data/flatten.ts +10 -1
- package/src/tools/Tree/index.tsx +2 -0
- package/src/tools/Tree/types.ts +43 -2
- package/dist/TreeRoot-A25RIGYE.cjs +0 -19
- package/dist/TreeRoot-HBRJEHBH.mjs +0 -4
- package/dist/chunk-4CEOJDMB.cjs.map +0 -1
- package/dist/chunk-NFIMVYJU.mjs.map +0 -1
package/dist/tree/index.d.ts
CHANGED
|
@@ -1,172 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { b as TreeRootProps, f as TreeItemId, T as TreeNode, F as FlatRow, o as TreeActivateOptions, g as TreeLabels, R as ResolvedAppearance, h as TreeSelectionMode, p as TreeActivationMode, a as TreeRowSlot, e as TreeContextMenuSlot } from '../types-CevSbyfD.js';
|
|
3
|
+
export { c as DEFAULT_TREE_APPEARANCE, D as DEFAULT_TREE_LABELS, m as TreeAccentIntensity, k as TreeAppearance, l as TreeDensity, j as TreeLoadChildren, n as TreeRadius, i as TreeRowRenderProps, d as appearanceToStyle, r as resolveAppearance } from '../types-CevSbyfD.js';
|
|
2
4
|
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
5
|
|
|
171
6
|
/**
|
|
172
7
|
* High-level entry point. Wraps Provider + (optional) search bar + content.
|
|
@@ -218,13 +53,14 @@ interface TreeContextValue<T> {
|
|
|
218
53
|
setQuery: (q: string) => void;
|
|
219
54
|
refresh: (id: TreeItemId) => Promise<void>;
|
|
220
55
|
refreshAll: () => Promise<void>;
|
|
221
|
-
activate: (node: TreeNode<T
|
|
56
|
+
activate: (node: TreeNode<T>, opts?: TreeActivateOptions) => void;
|
|
222
57
|
labels: TreeLabels;
|
|
223
58
|
/** Resolved cosmetic config — never null. */
|
|
224
59
|
appearance: ResolvedAppearance;
|
|
225
60
|
/** Convenience alias for `appearance.indent`. */
|
|
226
61
|
indent: number;
|
|
227
62
|
selectionMode: TreeSelectionMode;
|
|
63
|
+
activationMode: TreeActivationMode;
|
|
228
64
|
enableSearch: boolean;
|
|
229
65
|
showIndentGuides: boolean;
|
|
230
66
|
getItemName: (node: TreeNode<T>) => string;
|
|
@@ -234,7 +70,7 @@ interface TreeContextValue<T> {
|
|
|
234
70
|
renderContextMenu?: TreeContextMenuSlot<T>;
|
|
235
71
|
}
|
|
236
72
|
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'> {
|
|
73
|
+
interface TreeProviderProps<T> extends Pick<TreeRootProps<T>, 'data' | 'getItemName' | 'loadChildren' | 'selectionMode' | 'activationMode' | 'initialExpandedIds' | 'initialSelectedIds' | 'indent' | 'appearance' | 'onSelectionChange' | 'onExpansionChange' | 'onActivate' | 'filterNode' | 'enableSearch' | 'showIndentGuides' | 'renderIcon' | 'renderLabel' | 'renderActions' | 'renderContextMenu' | 'labels' | 'persistKey' | 'persistSelection'> {
|
|
238
74
|
children: React$1.ReactNode;
|
|
239
75
|
}
|
|
240
76
|
declare function TreeProvider<T>(props: TreeProviderProps<T>): react_jsx_runtime.JSX.Element;
|
|
@@ -276,7 +112,7 @@ declare function useTreeActions<T>(): {
|
|
|
276
112
|
collapseAll: () => void;
|
|
277
113
|
refresh: (id: TreeItemId) => Promise<void>;
|
|
278
114
|
refreshAll: () => Promise<void>;
|
|
279
|
-
activate: (node: TreeNode<T
|
|
115
|
+
activate: (node: TreeNode<T>, opts?: TreeActivateOptions) => void;
|
|
280
116
|
};
|
|
281
117
|
|
|
282
118
|
interface UseTreeTypeAheadOptions<T> {
|
|
@@ -405,6 +241,8 @@ interface FlattenInput<T> {
|
|
|
405
241
|
roots: TreeNode<T>[];
|
|
406
242
|
expandedIds: ReadonlySet<TreeItemId>;
|
|
407
243
|
cache: ChildCache<T>;
|
|
244
|
+
/** Optional predicate. Nodes returning `false` (and their descendants) are excluded. */
|
|
245
|
+
filterNode?: (node: TreeNode<T>) => boolean;
|
|
408
246
|
}
|
|
409
247
|
/**
|
|
410
248
|
* Walk the tree top-to-bottom and produce a flat list of visible rows.
|
|
@@ -413,7 +251,7 @@ interface FlattenInput<T> {
|
|
|
413
251
|
* `expandedIds`. The output is ordered exactly as it should render,
|
|
414
252
|
* which keeps keyboard navigation (next/prev row) trivial.
|
|
415
253
|
*/
|
|
416
|
-
declare function flattenTree<T>({ roots, expandedIds, cache }: FlattenInput<T>): FlatRow<T>[];
|
|
254
|
+
declare function flattenTree<T>({ roots, expandedIds, cache, filterNode, }: FlattenInput<T>): FlatRow<T>[];
|
|
417
255
|
|
|
418
256
|
interface PersistedTreeState {
|
|
419
257
|
expandedItems: TreeItemId[];
|
|
@@ -439,4 +277,4 @@ declare function createDemoTree({ depth, breadth, rootPrefix, }?: {
|
|
|
439
277
|
rootPrefix?: string;
|
|
440
278
|
}): TreeNode<DemoNode>[];
|
|
441
279
|
|
|
442
|
-
export { type ChildCache, type ChildEntry, type ChildEntryStatus,
|
|
280
|
+
export { type ChildCache, type ChildEntry, type ChildEntryStatus, type DemoNode, FlatRow, type FlattenInput, type PersistedTreeState, ResolvedAppearance, TreeRoot as Tree, TreeActivateOptions, TreeActivationMode, TreeChevron, type TreeChevronProps, TreeContent, type TreeContentProps, TreeContextMenuSlot, type TreeContextValue, TreeEmpty, type TreeEmptyProps, TreeError, type TreeErrorProps, TreeIcon, type TreeIconProps, TreeIndentGuides, type TreeIndentGuidesProps, TreeItemId, TreeLabel, type TreeLabelProps, TreeLabels, TreeNode, TreeProvider, type TreeProviderProps, TreeRoot, TreeRootProps, TreeRow, type TreeRowProps, TreeRowSlot, TreeSearchInput, type TreeSearchInputProps, TreeSelectionMode, TreeSkeleton, type TreeSkeletonProps, type UseTreeKeyboardOptions, type UseTreeTypeAheadOptions, clearTreeState, createChildCache, createDemoTree, TreeRoot as default, flattenTree, loadTreeState, resolveChildren, saveTreeState, useTreeActions, useTreeContext, useTreeExpansion, useTreeFocus, useTreeKeyboard, useTreeLabels, useTreeRows, useTreeSearch, useTreeSelection, useTreeTypeAhead };
|
package/dist/tree/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { TreeError, TreeSkeleton, createDemoTree } from '../chunk-KR6B3LVY.mjs';
|
|
2
|
-
export { DEFAULT_TREE_APPEARANCE, DEFAULT_TREE_LABELS, TreeRoot as Tree, TreeChevron, TreeContent, TreeEmpty, TreeIcon, TreeIndentGuides, TreeLabel, TreeProvider, TreeRoot, TreeRow, TreeSearchInput, appearanceToStyle, clearTreeState, createChildCache, TreeRoot_default as default, flattenTree, loadTreeState, resolveAppearance, resolveChildren, saveTreeState, useTreeActions, useTreeContext, useTreeExpansion, useTreeFocus, useTreeKeyboard, useTreeLabels, useTreeRows, useTreeSearch, useTreeSelection, useTreeTypeAhead } from '../chunk-
|
|
2
|
+
export { DEFAULT_TREE_APPEARANCE, DEFAULT_TREE_LABELS, TreeRoot as Tree, TreeChevron, TreeContent, TreeEmpty, TreeIcon, TreeIndentGuides, TreeLabel, TreeProvider, TreeRoot, TreeRow, TreeSearchInput, appearanceToStyle, clearTreeState, createChildCache, TreeRoot_default as default, flattenTree, loadTreeState, resolveAppearance, resolveChildren, saveTreeState, useTreeActions, useTreeContext, useTreeExpansion, useTreeFocus, useTreeKeyboard, useTreeLabels, useTreeRows, useTreeSearch, useTreeSelection, useTreeTypeAhead } from '../chunk-MOME6KYD.mjs';
|
|
3
3
|
import '../chunk-CGILA3WO.mjs';
|
|
4
4
|
//# sourceMappingURL=index.mjs.map
|
|
5
5
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type TreeDensity = 'compact' | 'cozy' | 'comfortable';
|
|
4
|
+
type TreeAccentIntensity = 'subtle' | 'default' | 'strong';
|
|
5
|
+
type TreeRadius = 'none' | 'sm' | 'md';
|
|
6
|
+
/**
|
|
7
|
+
* Cosmetic configuration. Every field is optional; missing values fall
|
|
8
|
+
* back to the `cozy` preset (a comfortable VSCode-Explorer-like density).
|
|
9
|
+
*
|
|
10
|
+
* Customize the look without re-implementing slots.
|
|
11
|
+
*/
|
|
12
|
+
interface TreeAppearance {
|
|
13
|
+
/** Built-in size preset. Default: `'cozy'`. */
|
|
14
|
+
density?: TreeDensity;
|
|
15
|
+
/** Override row height in px (wins over density). */
|
|
16
|
+
rowHeight?: number;
|
|
17
|
+
/** Override icon + chevron size in px (wins over density). */
|
|
18
|
+
iconSize?: number;
|
|
19
|
+
/** Lucide stroke width for icon + chevron. Default: 1.5. */
|
|
20
|
+
iconStrokeWidth?: number;
|
|
21
|
+
/** Override label font size in px (wins over density). */
|
|
22
|
+
fontSize?: number;
|
|
23
|
+
/** Pixels between chevron / icon / label. Default depends on density. */
|
|
24
|
+
gap?: number;
|
|
25
|
+
/** Pixels between nesting levels. Default: 16. */
|
|
26
|
+
indent?: number;
|
|
27
|
+
/** Hover / selected highlight intensity. Default: `'default'`. */
|
|
28
|
+
accent?: TreeAccentIntensity;
|
|
29
|
+
/** Row corner radius. Default: `'sm'`. */
|
|
30
|
+
radius?: TreeRadius;
|
|
31
|
+
/** Indent-guide line opacity (0..1). Default: 0.4. */
|
|
32
|
+
indentGuideOpacity?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Show a 2px primary-tinted bar on the left of the selected row.
|
|
35
|
+
* Mimics the VSCode active-tab indicator. Default: `true`.
|
|
36
|
+
*/
|
|
37
|
+
showActiveIndicator?: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface ResolvedAppearance {
|
|
40
|
+
density: TreeDensity;
|
|
41
|
+
rowHeight: number;
|
|
42
|
+
iconSize: number;
|
|
43
|
+
iconStrokeWidth: number;
|
|
44
|
+
fontSize: number;
|
|
45
|
+
gap: number;
|
|
46
|
+
indent: number;
|
|
47
|
+
accent: TreeAccentIntensity;
|
|
48
|
+
radius: TreeRadius;
|
|
49
|
+
indentGuideOpacity: number;
|
|
50
|
+
showActiveIndicator: boolean;
|
|
51
|
+
}
|
|
52
|
+
declare const DEFAULT_TREE_APPEARANCE: ResolvedAppearance;
|
|
53
|
+
/**
|
|
54
|
+
* Merge a partial appearance with the default + density preset.
|
|
55
|
+
*
|
|
56
|
+
* Explicit numeric overrides (e.g. `rowHeight`) win over the density preset.
|
|
57
|
+
*/
|
|
58
|
+
declare function resolveAppearance(input?: TreeAppearance,
|
|
59
|
+
/** Outer `indent` prop (kept on TreeRoot for back-compat). */
|
|
60
|
+
outerIndent?: number): ResolvedAppearance;
|
|
61
|
+
/**
|
|
62
|
+
* Build the `style` object that exposes the resolved appearance to any
|
|
63
|
+
* descendant via CSS variables. Set on `<TreeRoot>`'s outer div.
|
|
64
|
+
*/
|
|
65
|
+
declare function appearanceToStyle(a: ResolvedAppearance): CSSProperties;
|
|
66
|
+
|
|
67
|
+
type TreeItemId = string;
|
|
68
|
+
/** A single node in the consumer's tree data. Generic over your payload. */
|
|
69
|
+
interface TreeNode<T = unknown> {
|
|
70
|
+
id: TreeItemId;
|
|
71
|
+
data: T;
|
|
72
|
+
/** Inline children. Omit (and provide a `loadChildren`) for async loading. */
|
|
73
|
+
children?: TreeNode<T>[];
|
|
74
|
+
/**
|
|
75
|
+
* Set to `true` to mark a node as a folder even when its `children` array
|
|
76
|
+
* is empty (e.g. an unloaded async folder). Default: derived from
|
|
77
|
+
* `Array.isArray(children)`.
|
|
78
|
+
*/
|
|
79
|
+
isFolder?: boolean;
|
|
80
|
+
/** Disable interaction. */
|
|
81
|
+
disabled?: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface TreeLabels {
|
|
84
|
+
loading: string;
|
|
85
|
+
empty: string;
|
|
86
|
+
error: string;
|
|
87
|
+
searchPlaceholder: string;
|
|
88
|
+
searchMatches: (count: number) => string;
|
|
89
|
+
ariaLabel: string;
|
|
90
|
+
}
|
|
91
|
+
declare const DEFAULT_TREE_LABELS: TreeLabels;
|
|
92
|
+
type TreeSelectionMode = 'none' | 'single' | 'multiple';
|
|
93
|
+
/**
|
|
94
|
+
* How a node becomes "activated" (i.e. opened) on pointer interaction.
|
|
95
|
+
*
|
|
96
|
+
* - `'single-click'` (default): single click activates a leaf immediately;
|
|
97
|
+
* double-click also activates. Folders always toggle on single click.
|
|
98
|
+
* - `'double-click'`: single click only selects + focuses; double-click is
|
|
99
|
+
* required to activate. Mirrors classic file-manager behaviour.
|
|
100
|
+
* - `'single-click-preview'`: VSCode Explorer / Cursor behaviour. Single
|
|
101
|
+
* click activates with `{ preview: true }` (consumer renders a preview
|
|
102
|
+
* tab); double-click activates with `{ preview: false }` (pinned tab).
|
|
103
|
+
*
|
|
104
|
+
* Folders ignore this setting — they always toggle on single click and
|
|
105
|
+
* never call `onActivate`.
|
|
106
|
+
*/
|
|
107
|
+
type TreeActivationMode = 'single-click' | 'double-click' | 'single-click-preview';
|
|
108
|
+
interface TreeActivateOptions {
|
|
109
|
+
/**
|
|
110
|
+
* `true` when the activation came from a single click in
|
|
111
|
+
* `'single-click-preview'` mode. `false` for double-click and for
|
|
112
|
+
* non-preview modes. Consumers typically map this to a
|
|
113
|
+
* preview-tab vs pinned-tab distinction.
|
|
114
|
+
*/
|
|
115
|
+
preview: boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Async loader: called the first time a folder is expanded with no inline
|
|
119
|
+
* `children`. Result is cached; concurrent expansions are de-duplicated.
|
|
120
|
+
*/
|
|
121
|
+
type TreeLoadChildren<T> = (node: TreeNode<T>) => Promise<TreeNode<T>[]>;
|
|
122
|
+
interface TreeRowRenderProps<T> {
|
|
123
|
+
node: TreeNode<T>;
|
|
124
|
+
level: number;
|
|
125
|
+
isSelected: boolean;
|
|
126
|
+
isExpanded: boolean;
|
|
127
|
+
isFocused: boolean;
|
|
128
|
+
isFolder: boolean;
|
|
129
|
+
isLoading: boolean;
|
|
130
|
+
isMatchingSearch: boolean;
|
|
131
|
+
}
|
|
132
|
+
type TreeRowSlot<T> = (props: TreeRowRenderProps<T>) => ReactNode;
|
|
133
|
+
type TreeContextMenuSlot<T> = (props: TreeRowRenderProps<T>, trigger: ReactNode) => ReactNode;
|
|
134
|
+
interface TreeRootProps<T> {
|
|
135
|
+
/** Root nodes. Top-level items are rendered directly (no synthetic root). */
|
|
136
|
+
data: TreeNode<T>[];
|
|
137
|
+
/** Returns the human-readable name for a node (used by search/type-ahead). */
|
|
138
|
+
getItemName: (node: TreeNode<T>) => string;
|
|
139
|
+
/** Async loader for folders without inline `children`. */
|
|
140
|
+
loadChildren?: TreeLoadChildren<T>;
|
|
141
|
+
/** Selection behaviour. Default: `'single'`. */
|
|
142
|
+
selectionMode?: TreeSelectionMode;
|
|
143
|
+
/** Pointer activation behaviour. Default: `'single-click'`. */
|
|
144
|
+
activationMode?: TreeActivationMode;
|
|
145
|
+
/** Initially expanded ids. */
|
|
146
|
+
initialExpandedIds?: TreeItemId[];
|
|
147
|
+
/** Initially selected ids. */
|
|
148
|
+
initialSelectedIds?: TreeItemId[];
|
|
149
|
+
/** Pixels of indent per nesting level. Default: 16. (Shortcut for `appearance.indent`.) */
|
|
150
|
+
indent?: number;
|
|
151
|
+
/** Cosmetic configuration: density, sizes, accent intensity, radius. */
|
|
152
|
+
appearance?: TreeAppearance;
|
|
153
|
+
/** Triggered when selection changes. */
|
|
154
|
+
onSelectionChange?: (selectedIds: TreeItemId[]) => void;
|
|
155
|
+
/** Triggered when expanded set changes. */
|
|
156
|
+
onExpansionChange?: (expandedIds: TreeItemId[]) => void;
|
|
157
|
+
/**
|
|
158
|
+
* Triggered when a leaf is activated (Enter / dblclick / click depending
|
|
159
|
+
* on `activationMode`). Folders never call this — they toggle instead.
|
|
160
|
+
*/
|
|
161
|
+
onActivate?: (node: TreeNode<T>, opts: TreeActivateOptions) => void;
|
|
162
|
+
/**
|
|
163
|
+
* Optional predicate. Nodes returning `false` (and their descendants) are
|
|
164
|
+
* not rendered and not searchable. Use this to hide dot-files, system
|
|
165
|
+
* entries, or anything else the consumer wants to filter out.
|
|
166
|
+
*/
|
|
167
|
+
filterNode?: (node: TreeNode<T>) => boolean;
|
|
168
|
+
/** Show built-in search input. Default: false. */
|
|
169
|
+
enableSearch?: boolean;
|
|
170
|
+
/** Type printable letters to jump to a matching name. Default: true. */
|
|
171
|
+
enableTypeAhead?: boolean;
|
|
172
|
+
/** Render vertical indent guides under expanded folders. Default: false. */
|
|
173
|
+
showIndentGuides?: boolean;
|
|
174
|
+
/** Custom row renderer. Falls back to the default <TreeRow />. */
|
|
175
|
+
renderRow?: TreeRowSlot<T>;
|
|
176
|
+
/** Replace default folder/file icon. */
|
|
177
|
+
renderIcon?: TreeRowSlot<T>;
|
|
178
|
+
/** Replace default label rendering. */
|
|
179
|
+
renderLabel?: TreeRowSlot<T>;
|
|
180
|
+
/** Right-side actions slot (per row). */
|
|
181
|
+
renderActions?: TreeRowSlot<T>;
|
|
182
|
+
/** Wrap each row in a context menu (right-click). Receives the row meta + trigger element. */
|
|
183
|
+
renderContextMenu?: TreeContextMenuSlot<T>;
|
|
184
|
+
/** Override built-in copy in your locale. */
|
|
185
|
+
labels?: Partial<TreeLabels>;
|
|
186
|
+
/** Persist expanded + (optional) selected ids in localStorage under this key. */
|
|
187
|
+
persistKey?: string;
|
|
188
|
+
/** Persist selection alongside expansion. Default: false. */
|
|
189
|
+
persistSelection?: boolean;
|
|
190
|
+
className?: string;
|
|
191
|
+
style?: React.CSSProperties;
|
|
192
|
+
}
|
|
193
|
+
/** Internal flat-row representation used by the renderer + keyboard nav. */
|
|
194
|
+
interface FlatRow<T> {
|
|
195
|
+
node: TreeNode<T>;
|
|
196
|
+
level: number;
|
|
197
|
+
parentId: TreeItemId | null;
|
|
198
|
+
isFolder: boolean;
|
|
199
|
+
isExpanded: boolean;
|
|
200
|
+
isLoading: boolean;
|
|
201
|
+
hasError: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export { DEFAULT_TREE_LABELS as D, type FlatRow as F, type ResolvedAppearance as R, type TreeNode as T, type TreeRowSlot as a, type TreeRootProps as b, DEFAULT_TREE_APPEARANCE as c, appearanceToStyle as d, type TreeContextMenuSlot as e, type TreeItemId as f, type TreeLabels as g, type TreeSelectionMode as h, type TreeRowRenderProps as i, type TreeLoadChildren as j, type TreeAppearance as k, type TreeDensity as l, type TreeAccentIntensity as m, type TreeRadius as n, type TreeActivateOptions as o, type TreeActivationMode as p, resolveAppearance as r };
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type TreeDensity = 'compact' | 'cozy' | 'comfortable';
|
|
4
|
+
type TreeAccentIntensity = 'subtle' | 'default' | 'strong';
|
|
5
|
+
type TreeRadius = 'none' | 'sm' | 'md';
|
|
6
|
+
/**
|
|
7
|
+
* Cosmetic configuration. Every field is optional; missing values fall
|
|
8
|
+
* back to the `cozy` preset (a comfortable VSCode-Explorer-like density).
|
|
9
|
+
*
|
|
10
|
+
* Customize the look without re-implementing slots.
|
|
11
|
+
*/
|
|
12
|
+
interface TreeAppearance {
|
|
13
|
+
/** Built-in size preset. Default: `'cozy'`. */
|
|
14
|
+
density?: TreeDensity;
|
|
15
|
+
/** Override row height in px (wins over density). */
|
|
16
|
+
rowHeight?: number;
|
|
17
|
+
/** Override icon + chevron size in px (wins over density). */
|
|
18
|
+
iconSize?: number;
|
|
19
|
+
/** Lucide stroke width for icon + chevron. Default: 1.5. */
|
|
20
|
+
iconStrokeWidth?: number;
|
|
21
|
+
/** Override label font size in px (wins over density). */
|
|
22
|
+
fontSize?: number;
|
|
23
|
+
/** Pixels between chevron / icon / label. Default depends on density. */
|
|
24
|
+
gap?: number;
|
|
25
|
+
/** Pixels between nesting levels. Default: 16. */
|
|
26
|
+
indent?: number;
|
|
27
|
+
/** Hover / selected highlight intensity. Default: `'default'`. */
|
|
28
|
+
accent?: TreeAccentIntensity;
|
|
29
|
+
/** Row corner radius. Default: `'sm'`. */
|
|
30
|
+
radius?: TreeRadius;
|
|
31
|
+
/** Indent-guide line opacity (0..1). Default: 0.4. */
|
|
32
|
+
indentGuideOpacity?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Show a 2px primary-tinted bar on the left of the selected row.
|
|
35
|
+
* Mimics the VSCode active-tab indicator. Default: `true`.
|
|
36
|
+
*/
|
|
37
|
+
showActiveIndicator?: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface ResolvedAppearance {
|
|
40
|
+
density: TreeDensity;
|
|
41
|
+
rowHeight: number;
|
|
42
|
+
iconSize: number;
|
|
43
|
+
iconStrokeWidth: number;
|
|
44
|
+
fontSize: number;
|
|
45
|
+
gap: number;
|
|
46
|
+
indent: number;
|
|
47
|
+
accent: TreeAccentIntensity;
|
|
48
|
+
radius: TreeRadius;
|
|
49
|
+
indentGuideOpacity: number;
|
|
50
|
+
showActiveIndicator: boolean;
|
|
51
|
+
}
|
|
52
|
+
declare const DEFAULT_TREE_APPEARANCE: ResolvedAppearance;
|
|
53
|
+
/**
|
|
54
|
+
* Merge a partial appearance with the default + density preset.
|
|
55
|
+
*
|
|
56
|
+
* Explicit numeric overrides (e.g. `rowHeight`) win over the density preset.
|
|
57
|
+
*/
|
|
58
|
+
declare function resolveAppearance(input?: TreeAppearance,
|
|
59
|
+
/** Outer `indent` prop (kept on TreeRoot for back-compat). */
|
|
60
|
+
outerIndent?: number): ResolvedAppearance;
|
|
61
|
+
/**
|
|
62
|
+
* Build the `style` object that exposes the resolved appearance to any
|
|
63
|
+
* descendant via CSS variables. Set on `<TreeRoot>`'s outer div.
|
|
64
|
+
*/
|
|
65
|
+
declare function appearanceToStyle(a: ResolvedAppearance): CSSProperties;
|
|
66
|
+
|
|
67
|
+
type TreeItemId = string;
|
|
68
|
+
/** A single node in the consumer's tree data. Generic over your payload. */
|
|
69
|
+
interface TreeNode<T = unknown> {
|
|
70
|
+
id: TreeItemId;
|
|
71
|
+
data: T;
|
|
72
|
+
/** Inline children. Omit (and provide a `loadChildren`) for async loading. */
|
|
73
|
+
children?: TreeNode<T>[];
|
|
74
|
+
/**
|
|
75
|
+
* Set to `true` to mark a node as a folder even when its `children` array
|
|
76
|
+
* is empty (e.g. an unloaded async folder). Default: derived from
|
|
77
|
+
* `Array.isArray(children)`.
|
|
78
|
+
*/
|
|
79
|
+
isFolder?: boolean;
|
|
80
|
+
/** Disable interaction. */
|
|
81
|
+
disabled?: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface TreeLabels {
|
|
84
|
+
loading: string;
|
|
85
|
+
empty: string;
|
|
86
|
+
error: string;
|
|
87
|
+
searchPlaceholder: string;
|
|
88
|
+
searchMatches: (count: number) => string;
|
|
89
|
+
ariaLabel: string;
|
|
90
|
+
}
|
|
91
|
+
declare const DEFAULT_TREE_LABELS: TreeLabels;
|
|
92
|
+
type TreeSelectionMode = 'none' | 'single' | 'multiple';
|
|
93
|
+
/**
|
|
94
|
+
* How a node becomes "activated" (i.e. opened) on pointer interaction.
|
|
95
|
+
*
|
|
96
|
+
* - `'single-click'` (default): single click activates a leaf immediately;
|
|
97
|
+
* double-click also activates. Folders always toggle on single click.
|
|
98
|
+
* - `'double-click'`: single click only selects + focuses; double-click is
|
|
99
|
+
* required to activate. Mirrors classic file-manager behaviour.
|
|
100
|
+
* - `'single-click-preview'`: VSCode Explorer / Cursor behaviour. Single
|
|
101
|
+
* click activates with `{ preview: true }` (consumer renders a preview
|
|
102
|
+
* tab); double-click activates with `{ preview: false }` (pinned tab).
|
|
103
|
+
*
|
|
104
|
+
* Folders ignore this setting — they always toggle on single click and
|
|
105
|
+
* never call `onActivate`.
|
|
106
|
+
*/
|
|
107
|
+
type TreeActivationMode = 'single-click' | 'double-click' | 'single-click-preview';
|
|
108
|
+
interface TreeActivateOptions {
|
|
109
|
+
/**
|
|
110
|
+
* `true` when the activation came from a single click in
|
|
111
|
+
* `'single-click-preview'` mode. `false` for double-click and for
|
|
112
|
+
* non-preview modes. Consumers typically map this to a
|
|
113
|
+
* preview-tab vs pinned-tab distinction.
|
|
114
|
+
*/
|
|
115
|
+
preview: boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Async loader: called the first time a folder is expanded with no inline
|
|
119
|
+
* `children`. Result is cached; concurrent expansions are de-duplicated.
|
|
120
|
+
*/
|
|
121
|
+
type TreeLoadChildren<T> = (node: TreeNode<T>) => Promise<TreeNode<T>[]>;
|
|
122
|
+
interface TreeRowRenderProps<T> {
|
|
123
|
+
node: TreeNode<T>;
|
|
124
|
+
level: number;
|
|
125
|
+
isSelected: boolean;
|
|
126
|
+
isExpanded: boolean;
|
|
127
|
+
isFocused: boolean;
|
|
128
|
+
isFolder: boolean;
|
|
129
|
+
isLoading: boolean;
|
|
130
|
+
isMatchingSearch: boolean;
|
|
131
|
+
}
|
|
132
|
+
type TreeRowSlot<T> = (props: TreeRowRenderProps<T>) => ReactNode;
|
|
133
|
+
type TreeContextMenuSlot<T> = (props: TreeRowRenderProps<T>, trigger: ReactNode) => ReactNode;
|
|
134
|
+
interface TreeRootProps<T> {
|
|
135
|
+
/** Root nodes. Top-level items are rendered directly (no synthetic root). */
|
|
136
|
+
data: TreeNode<T>[];
|
|
137
|
+
/** Returns the human-readable name for a node (used by search/type-ahead). */
|
|
138
|
+
getItemName: (node: TreeNode<T>) => string;
|
|
139
|
+
/** Async loader for folders without inline `children`. */
|
|
140
|
+
loadChildren?: TreeLoadChildren<T>;
|
|
141
|
+
/** Selection behaviour. Default: `'single'`. */
|
|
142
|
+
selectionMode?: TreeSelectionMode;
|
|
143
|
+
/** Pointer activation behaviour. Default: `'single-click'`. */
|
|
144
|
+
activationMode?: TreeActivationMode;
|
|
145
|
+
/** Initially expanded ids. */
|
|
146
|
+
initialExpandedIds?: TreeItemId[];
|
|
147
|
+
/** Initially selected ids. */
|
|
148
|
+
initialSelectedIds?: TreeItemId[];
|
|
149
|
+
/** Pixels of indent per nesting level. Default: 16. (Shortcut for `appearance.indent`.) */
|
|
150
|
+
indent?: number;
|
|
151
|
+
/** Cosmetic configuration: density, sizes, accent intensity, radius. */
|
|
152
|
+
appearance?: TreeAppearance;
|
|
153
|
+
/** Triggered when selection changes. */
|
|
154
|
+
onSelectionChange?: (selectedIds: TreeItemId[]) => void;
|
|
155
|
+
/** Triggered when expanded set changes. */
|
|
156
|
+
onExpansionChange?: (expandedIds: TreeItemId[]) => void;
|
|
157
|
+
/**
|
|
158
|
+
* Triggered when a leaf is activated (Enter / dblclick / click depending
|
|
159
|
+
* on `activationMode`). Folders never call this — they toggle instead.
|
|
160
|
+
*/
|
|
161
|
+
onActivate?: (node: TreeNode<T>, opts: TreeActivateOptions) => void;
|
|
162
|
+
/**
|
|
163
|
+
* Optional predicate. Nodes returning `false` (and their descendants) are
|
|
164
|
+
* not rendered and not searchable. Use this to hide dot-files, system
|
|
165
|
+
* entries, or anything else the consumer wants to filter out.
|
|
166
|
+
*/
|
|
167
|
+
filterNode?: (node: TreeNode<T>) => boolean;
|
|
168
|
+
/** Show built-in search input. Default: false. */
|
|
169
|
+
enableSearch?: boolean;
|
|
170
|
+
/** Type printable letters to jump to a matching name. Default: true. */
|
|
171
|
+
enableTypeAhead?: boolean;
|
|
172
|
+
/** Render vertical indent guides under expanded folders. Default: false. */
|
|
173
|
+
showIndentGuides?: boolean;
|
|
174
|
+
/** Custom row renderer. Falls back to the default <TreeRow />. */
|
|
175
|
+
renderRow?: TreeRowSlot<T>;
|
|
176
|
+
/** Replace default folder/file icon. */
|
|
177
|
+
renderIcon?: TreeRowSlot<T>;
|
|
178
|
+
/** Replace default label rendering. */
|
|
179
|
+
renderLabel?: TreeRowSlot<T>;
|
|
180
|
+
/** Right-side actions slot (per row). */
|
|
181
|
+
renderActions?: TreeRowSlot<T>;
|
|
182
|
+
/** Wrap each row in a context menu (right-click). Receives the row meta + trigger element. */
|
|
183
|
+
renderContextMenu?: TreeContextMenuSlot<T>;
|
|
184
|
+
/** Override built-in copy in your locale. */
|
|
185
|
+
labels?: Partial<TreeLabels>;
|
|
186
|
+
/** Persist expanded + (optional) selected ids in localStorage under this key. */
|
|
187
|
+
persistKey?: string;
|
|
188
|
+
/** Persist selection alongside expansion. Default: false. */
|
|
189
|
+
persistSelection?: boolean;
|
|
190
|
+
className?: string;
|
|
191
|
+
style?: React.CSSProperties;
|
|
192
|
+
}
|
|
193
|
+
/** Internal flat-row representation used by the renderer + keyboard nav. */
|
|
194
|
+
interface FlatRow<T> {
|
|
195
|
+
node: TreeNode<T>;
|
|
196
|
+
level: number;
|
|
197
|
+
parentId: TreeItemId | null;
|
|
198
|
+
isFolder: boolean;
|
|
199
|
+
isExpanded: boolean;
|
|
200
|
+
isLoading: boolean;
|
|
201
|
+
hasError: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export { DEFAULT_TREE_LABELS as D, type FlatRow as F, type ResolvedAppearance as R, type TreeNode as T, type TreeRowSlot as a, type TreeRootProps as b, DEFAULT_TREE_APPEARANCE as c, appearanceToStyle as d, type TreeContextMenuSlot as e, type TreeItemId as f, type TreeLabels as g, type TreeSelectionMode as h, type TreeRowRenderProps as i, type TreeLoadChildren as j, type TreeAppearance as k, type TreeDensity as l, type TreeAccentIntensity as m, type TreeRadius as n, type TreeActivateOptions as o, type TreeActivationMode as p, resolveAppearance as r };
|