@ixfx/components 0.3.2 → 0.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/bundle/index.d.ts +1086 -603
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +16153 -15296
- package/bundle/index.js.map +1 -1
- package/bundle/style.css +14 -4
- package/dist/ac-text.d.ts.map +1 -1
- package/dist/ac-text.js +11 -6
- package/dist/ac-text.js.map +1 -1
- package/dist/{button-DMt5XWUK.js → button-C3fLMKUv.js} +4 -4
- package/dist/{button-DMt5XWUK.js.map → button-C3fLMKUv.js.map} +1 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.d.ts.map +1 -1
- package/dist/button.js +1 -1
- package/dist/checkbox.d.ts +2 -2
- package/dist/checkbox.d.ts.map +1 -1
- package/dist/checkbox.js +14 -8
- package/dist/checkbox.js.map +1 -1
- package/dist/{colour-C3MQIjFJ-BLXg8W3U.js → colour-C3MQIjFJ-vRCdr8W-.js} +146 -552
- package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +1 -0
- package/dist/{colour-picker-K6zu82lm.js → colour-picker-0sgAha1T.js} +14 -9
- package/dist/colour-picker-0sgAha1T.js.map +1 -0
- package/dist/colour-picker.d.ts +1 -1
- package/dist/colour-picker.js +1 -1
- package/dist/crumbs.d.ts +1 -1
- package/dist/crumbs.d.ts.map +1 -1
- package/dist/crumbs.js +11 -6
- package/dist/crumbs.js.map +1 -1
- package/dist/data-display.d.ts +9 -4
- package/dist/data-display.d.ts.map +1 -1
- package/dist/data-display.js +270 -43
- package/dist/data-display.js.map +1 -1
- package/dist/data-provider-DgI909FP.js +23 -0
- package/dist/data-provider-DgI909FP.js.map +1 -0
- package/dist/{decorate-D7rC1gLP.js → decorate-DdjvVHS-.js} +2 -2
- package/dist/{decorate-D7rC1gLP.js.map → decorate-DdjvVHS-.js.map} +1 -1
- package/dist/{defaults-C7elhuyJ.js → defaults-C3b9OWJD.js} +2 -2
- package/dist/{defaults-C7elhuyJ.js.map → defaults-C3b9OWJD.js.map} +1 -1
- package/dist/{dist-TAGYwaju.js → dist-CA13FvMn.js} +7 -66
- package/dist/dist-CA13FvMn.js.map +1 -0
- package/dist/editable-label.d.ts.map +1 -1
- package/dist/editable-label.js +3 -2
- package/dist/editable-label.js.map +1 -1
- package/dist/fallbacks-pNMOMx38.js +168 -0
- package/dist/fallbacks-pNMOMx38.js.map +1 -0
- package/dist/{hex-editor-DlfoA65y.d.ts → hex-editor-CMIxtNgT.d.ts} +1 -1
- package/dist/hex-editor-CMIxtNgT.d.ts.map +1 -0
- package/dist/{hex-editor-CsN_ySkH.js → hex-editor-WZrjRtvL.js} +3 -3
- package/dist/{hex-editor-CsN_ySkH.js.map → hex-editor-WZrjRtvL.js.map} +1 -1
- package/dist/hex.d.ts +1 -1
- package/dist/hex.js +1 -1
- package/dist/{highlight-TPbSHruI.js → highlight-B-eQrhhb.js} +1 -1
- package/dist/{highlight-TPbSHruI.js.map → highlight-B-eQrhhb.js.map} +1 -1
- package/dist/{icon-Dm_DHDz6.d.ts → icon-Bd5BiU4b.d.ts} +3 -3
- package/dist/icon-Bd5BiU4b.d.ts.map +1 -0
- package/dist/{icon-9NWTXtE1.js → icon-Ndo40kNO.js} +6 -5
- package/dist/icon-Ndo40kNO.js.map +1 -0
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +3 -3
- package/dist/{incr-search-DSKKsk6w.js → incr-search-CeERfijK.js} +2 -2
- package/dist/{incr-search-DSKKsk6w.js.map → incr-search-CeERfijK.js.map} +1 -1
- package/dist/incr-search.d.ts +1 -1
- package/dist/incr-search.js +2 -2
- package/dist/{index-hXFn14tM.d.ts → index-BMjri2-S.d.ts} +2 -2
- package/dist/{index-hXFn14tM.d.ts.map → index-BMjri2-S.d.ts.map} +1 -1
- package/dist/{index-DSlPeWLK.d.ts → index-CWpNcQKE.d.ts} +5 -5
- package/dist/index-CWpNcQKE.d.ts.map +1 -0
- package/dist/{index-DLkSKL4T.d.ts → index-CowKi2mo.d.ts} +1 -1
- package/dist/index-CowKi2mo.d.ts.map +1 -0
- package/dist/{index-B1hNR7Z9.d.ts → index-D87kRcEs.d.ts} +1 -1
- package/dist/{index-B1hNR7Z9.d.ts.map → index-D87kRcEs.d.ts.map} +1 -1
- package/dist/{index-CnL9krsH.d.ts → index-DgXpCg_G.d.ts} +32 -26
- package/dist/index-DgXpCg_G.d.ts.map +1 -0
- package/dist/{index-iZLld8Ca.d.ts → index-s_IhSnwc.d.ts} +2 -2
- package/dist/index-s_IhSnwc.d.ts.map +1 -0
- package/dist/index.d.ts +432 -121
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2369 -1706
- package/dist/index.js.map +1 -1
- package/dist/interaction-D6efrBLo.js +1 -0
- package/dist/{keyboard-De_vOHLg.js → keyboard-CimiEskD.js} +1 -1
- package/dist/{keyboard-De_vOHLg.js.map → keyboard-CimiEskD.js.map} +1 -1
- package/dist/{labelled-input-base-CqPL5rKm.js → labelled-input-base-9K_w3oLj.js} +2 -2
- package/dist/{labelled-input-base-CqPL5rKm.js.map → labelled-input-base-9K_w3oLj.js.map} +1 -1
- package/dist/{labelled-input-base-BVvNeb5R.d.ts → labelled-input-base-ORb1rGq6.d.ts} +2 -2
- package/dist/labelled-input-base-ORb1rGq6.d.ts.map +1 -0
- package/dist/labelled-radial-input.d.ts +3 -3
- package/dist/labelled-radial-input.d.ts.map +1 -1
- package/dist/labelled-radial-input.js +7 -6
- package/dist/labelled-radial-input.js.map +1 -1
- package/dist/labelled-range-input.d.ts +1 -1
- package/dist/labelled-range-input.js +2 -2
- package/dist/led.d.ts +1 -1
- package/dist/led.d.ts.map +1 -1
- package/dist/led.js +2 -2
- package/dist/led.js.map +1 -1
- package/dist/{menu-item-CKRfP0pN.js → menu-item-BrIuORYD.js} +20 -10
- package/dist/menu-item-BrIuORYD.js.map +1 -0
- package/dist/{menu-item-ClQF2DKN.d.ts → menu-item-COx-Azgj.d.ts} +1 -1
- package/dist/menu-item-COx-Azgj.d.ts.map +1 -0
- package/dist/{menu-DJJuCm-5.js → menu-vjoiHZ13.js} +30 -17
- package/dist/menu-vjoiHZ13.js.map +1 -0
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +2 -2
- package/dist/miller.d.ts +2 -2
- package/dist/miller.d.ts.map +1 -1
- package/dist/miller.js +18 -11
- package/dist/miller.js.map +1 -1
- package/dist/narrowed-text.d.ts.map +1 -1
- package/dist/narrowed-text.js +7 -5
- package/dist/narrowed-text.js.map +1 -1
- package/dist/panel.d.ts +1 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +5 -4
- package/dist/panel.js.map +1 -1
- package/dist/plots.d.ts +2 -2
- package/dist/plots.js +2 -2
- package/dist/polar-pad.d.ts +1 -1
- package/dist/polar-pad.d.ts.map +1 -1
- package/dist/polar-pad.js +10 -4
- package/dist/polar-pad.js.map +1 -1
- package/dist/{popup-ImtS9KnS.js → popup-DiWMxsWj.js} +1 -1
- package/dist/{popup-ImtS9KnS.js.map → popup-DiWMxsWj.js.map} +1 -1
- package/dist/prominence-DlFShic3.js +104 -0
- package/dist/prominence-DlFShic3.js.map +1 -0
- package/dist/{radial-input-LUSBEycd.d.ts → radial-input-CpQPs1Mp.d.ts} +1 -1
- package/dist/radial-input-CpQPs1Mp.d.ts.map +1 -0
- package/dist/{radial-input-DZA6WaFu.js → radial-input-DZ7eQCcM.js} +11 -6
- package/dist/radial-input-DZ7eQCcM.js.map +1 -0
- package/dist/radial-input.d.ts +1 -1
- package/dist/radial-input.js +1 -1
- package/dist/range-input.d.ts +1 -1
- package/dist/range-input.d.ts.map +1 -1
- package/dist/range-input.js +9 -4
- package/dist/range-input.js.map +1 -1
- package/dist/range.d.ts +1 -1
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js +5 -3
- package/dist/range.js.map +1 -1
- package/dist/{registry-Q2gYQCHM.js → registry-CkW7q09Q.js} +1 -1
- package/dist/{registry-Q2gYQCHM.js.map → registry-CkW7q09Q.js.map} +1 -1
- package/dist/selecthorizontal.d.ts +1 -1
- package/dist/selecthorizontal.d.ts.map +1 -1
- package/dist/selecthorizontal.js +4 -3
- package/dist/selecthorizontal.js.map +1 -1
- package/dist/snap-container.d.ts.map +1 -1
- package/dist/snap-container.js +1 -1
- package/dist/split-layout.d.ts +1 -1
- package/dist/split-layout.d.ts.map +1 -1
- package/dist/split-layout.js +6 -5
- package/dist/split-layout.js.map +1 -1
- package/dist/style.css +14 -4
- package/dist/swipe.d.ts.map +1 -1
- package/dist/swipe.js +9 -4
- package/dist/swipe.js.map +1 -1
- package/dist/{tab-list-BnqISNvO.d.ts → tab-list-DLzb-m-I.d.ts} +2 -2
- package/dist/tab-list-DLzb-m-I.d.ts.map +1 -0
- package/dist/tabs.d.ts +1 -1
- package/dist/tabs.js +10 -4
- package/dist/tabs.js.map +1 -1
- package/dist/{tickled-controller-Cq1Va0rR.d.ts → tickled-controller-BjYCzGrU.d.ts} +2 -2
- package/dist/tickled-controller-BjYCzGrU.d.ts.map +1 -0
- package/dist/{tickled-styles-Bg3QbcrD.js → tickled-styles-fNDdqf6l.js} +1 -17
- package/dist/{tickled-styles-Bg3QbcrD.js.map → tickled-styles-fNDdqf6l.js.map} +1 -1
- package/dist/{timeline-Bh0PhlKW.js → timeline-2OFtN4Ta.js} +2 -2
- package/dist/{timeline-Bh0PhlKW.js.map → timeline-2OFtN4Ta.js.map} +1 -1
- package/dist/timeline.d.ts +1 -1
- package/dist/timeline.js +1 -1
- package/dist/{tooltip-DMxmBNky.js → tooltip-CJt3WLmN.js} +1 -1
- package/dist/{tooltip-DMxmBNky.js.map → tooltip-CJt3WLmN.js.map} +1 -1
- package/dist/{tooltip-CwGfb4lp.d.ts → tooltip-RGVIwHrZ.d.ts} +1 -1
- package/dist/{tooltip-CwGfb4lp.d.ts.map → tooltip-RGVIwHrZ.d.ts.map} +1 -1
- package/dist/{tree-CvvKbO-f.js → tree-CJWpMUvD.js} +113 -103
- package/dist/tree-CJWpMUvD.js.map +1 -0
- package/dist/{tree-component-D8Bg48tt.d.ts → tree-component-BcO26Xvt.d.ts} +65 -3
- package/dist/tree-component-BcO26Xvt.d.ts.map +1 -0
- package/dist/tree.d.ts +15 -15
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +1 -1
- package/dist/{types-BKaqnpwx.d.ts → types-DSfbtHs3.d.ts} +1 -1
- package/dist/types-DSfbtHs3.d.ts.map +1 -0
- package/dist/{xy-axis-DL0tfJDr.js → xy-axis-CK64haaK.js} +1831 -359
- package/dist/xy-axis-CK64haaK.js.map +1 -0
- package/dist/{xy-axis-D9uwpGTT.d.ts → xy-axis-McdUpcYr.d.ts} +102 -3
- package/dist/xy-axis-McdUpcYr.d.ts.map +1 -0
- package/dist/xy-pad.d.ts +1 -1
- package/dist/xy-pad.d.ts.map +1 -1
- package/dist/xy-pad.js +11 -6
- package/dist/xy-pad.js.map +1 -1
- package/docs-user/README.md +45 -0
- package/docs-user/ac-text.md +67 -0
- package/docs-user/ac-token.md +187 -0
- package/docs-user/button.md +355 -0
- package/docs-user/checkbox.md +62 -0
- package/docs-user/colour-picker.md +237 -0
- package/docs-user/crumbs.md +66 -0
- package/docs-user/data-display.md +98 -0
- package/docs-user/editable-label.md +244 -0
- package/docs-user/grouped-item-lister.md +424 -0
- package/docs-user/icons.md +191 -0
- package/docs-user/incr-search.md +94 -0
- package/docs-user/labelled-radial-input.md +204 -0
- package/docs-user/labelled-range-input.md +194 -0
- package/docs-user/led.md +40 -0
- package/docs-user/menu.md +319 -0
- package/docs-user/miller.md +453 -0
- package/docs-user/narrowed-text.md +72 -0
- package/docs-user/panel.md +250 -0
- package/docs-user/plots.md +361 -0
- package/docs-user/polar-pad.md +228 -0
- package/docs-user/radial-input.md +559 -0
- package/docs-user/range-input.md +264 -0
- package/docs-user/range.md +12 -0
- package/docs-user/selecthorizontal.md +32 -0
- package/docs-user/snap-container.md +132 -0
- package/docs-user/split-layout.md +232 -0
- package/docs-user/swipe.md +44 -0
- package/docs-user/tabs.md +217 -0
- package/docs-user/timeline.md +116 -0
- package/docs-user/transitory-label.md +120 -0
- package/docs-user/tree.md +592 -0
- package/docs-user/user-catalog.md +165 -0
- package/docs-user/user-theming.md +379 -0
- package/docs-user/util.md +122 -0
- package/docs-user/vertical-list.md +351 -0
- package/docs-user/xy-pad.md +94 -0
- package/package.json +18 -17
- package/dist/colour-C3MQIjFJ-BLXg8W3U.js.map +0 -1
- package/dist/colour-picker-K6zu82lm.js.map +0 -1
- package/dist/dist-BX0OVIm7.js +0 -1290
- package/dist/dist-BX0OVIm7.js.map +0 -1
- package/dist/dist-TAGYwaju.js.map +0 -1
- package/dist/hex-editor-DlfoA65y.d.ts.map +0 -1
- package/dist/icon-9NWTXtE1.js.map +0 -1
- package/dist/icon-Dm_DHDz6.d.ts.map +0 -1
- package/dist/index-CnL9krsH.d.ts.map +0 -1
- package/dist/index-DLkSKL4T.d.ts.map +0 -1
- package/dist/index-DSlPeWLK.d.ts.map +0 -1
- package/dist/index-iZLld8Ca.d.ts.map +0 -1
- package/dist/interaction-DG7X1rhI.js +0 -1
- package/dist/labelled-input-base-BVvNeb5R.d.ts.map +0 -1
- package/dist/menu-DJJuCm-5.js.map +0 -1
- package/dist/menu-item-CKRfP0pN.js.map +0 -1
- package/dist/menu-item-ClQF2DKN.d.ts.map +0 -1
- package/dist/prominence--ic9uWBl.js +0 -98
- package/dist/prominence--ic9uWBl.js.map +0 -1
- package/dist/radial-input-DZA6WaFu.js.map +0 -1
- package/dist/radial-input-LUSBEycd.d.ts.map +0 -1
- package/dist/tab-list-BnqISNvO.d.ts.map +0 -1
- package/dist/tickled-controller-Cq1Va0rR.d.ts.map +0 -1
- package/dist/tree-CvvKbO-f.js.map +0 -1
- package/dist/tree-component-D8Bg48tt.d.ts.map +0 -1
- package/dist/types-BKaqnpwx.d.ts.map +0 -1
- package/dist/xy-axis-D9uwpGTT.d.ts.map +0 -1
- package/dist/xy-axis-DL0tfJDr.js.map +0 -1
- /package/bundle/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
- /package/dist/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
# Tree Components — Common API Reference
|
|
2
|
+
|
|
3
|
+
Three components share a common `TreeComponent` interface: **`ixfx-tree-list`**, **`ixfx-miller-list`**, and **`ixfx-crumb-navigation`**. This document describes the shared API, plus component-specific behaviour where noted.
|
|
4
|
+
|
|
5
|
+
`ixfx-crumb-path` uses a fundamentally different string-based model and is not covered here.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
1. [Data model](#data-model)
|
|
12
|
+
2. [Properties](#properties)
|
|
13
|
+
3. [Selection](#selection)
|
|
14
|
+
4. [Events](#events)
|
|
15
|
+
5. [Keyboard navigation](#keyboard-navigation)
|
|
16
|
+
6. [Incremental search](#incremental-search)
|
|
17
|
+
7. [ARIA](#aria)
|
|
18
|
+
8. [CSS variables](#css-variables)
|
|
19
|
+
9. [Controller authoring guide](#controller-authoring-guide)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Data model
|
|
24
|
+
|
|
25
|
+
### Core types
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
type TreeItem = {
|
|
29
|
+
key: string; // Unique identifier across the whole tree
|
|
30
|
+
label: string; // Display text
|
|
31
|
+
isLeaf?: boolean; // true = never expandable; undefined/false = branch
|
|
32
|
+
data?: unknown; // Arbitrary user payload
|
|
33
|
+
icon?: string; // Icon name (passed to <ixfx-icon>)
|
|
34
|
+
tooltip?: string; // Tooltip content
|
|
35
|
+
value?: string; // Optional machine-readable value
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type TreeNode = {
|
|
39
|
+
item: TreeItem;
|
|
40
|
+
children?: TreeNode[]; // undefined = unloaded; [] = confirmed empty
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`TreeNode` is **immutable** — structural changes always produce a new root. Never mutate a node in place; use `TreeDataModel` convenience methods or replace `root` directly.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### Static trees
|
|
49
|
+
|
|
50
|
+
Set `root` directly when the tree data is available up-front:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
el.root = {
|
|
54
|
+
item: { key: 'root', label: 'My Files' },
|
|
55
|
+
children: [
|
|
56
|
+
{ item: { key: 'docs', label: 'Documents' }, children: [] },
|
|
57
|
+
{ item: { key: 'img', label: 'Images', isLeaf: true } },
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### Lazy loading via `loadChildren`
|
|
65
|
+
|
|
66
|
+
Set `loadChildren` to fetch children on demand (called when a branch is expanded):
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
el.loadChildren = async ({ node, depth }, signal) => {
|
|
70
|
+
const res = await fetch(`/api/children/${node.item.key}`, { signal });
|
|
71
|
+
return res.json(); // TreeNode[]
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The callback receives an `AbortSignal`; honour it to avoid races when the user collapses quickly. It may return `TreeNode[]`, `Promise<TreeNode[]>`, or `AsyncIterable<DataBatch<TreeNode>>` for streaming children.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### `TreeDataModel` — shared, cached data layer
|
|
80
|
+
|
|
81
|
+
`TreeDataModel` is an optional shared data layer that owns child-loading and caching. It is useful when:
|
|
82
|
+
|
|
83
|
+
- Multiple components display the same dataset (e.g. a tree-list and a miller-list side-by-side).
|
|
84
|
+
- You need programmatic tree mutation without tracking the root yourself.
|
|
85
|
+
- You need to invalidate (refresh) individual branches without a full re-render.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { TreeDataModel } from '@ixfx/components';
|
|
89
|
+
|
|
90
|
+
const model = new TreeDataModel({
|
|
91
|
+
root: { item: { key: 'root', label: 'Root' }, children: undefined },
|
|
92
|
+
loadChildren: async ({ node }, signal) => {
|
|
93
|
+
const res = await fetch(`/api/children/${node.item.key}`, { signal });
|
|
94
|
+
return res.json();
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
treeEl.model = model;
|
|
99
|
+
millerEl.model = model; // Both components share the same cache
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### Model API
|
|
103
|
+
|
|
104
|
+
| Member | Signature | Description |
|
|
105
|
+
|--------|-----------|-------------|
|
|
106
|
+
| `root` | `get root(): TreeNode` | Current immutable root snapshot |
|
|
107
|
+
| `setRoot` | `(root: TreeNode): void` | Replace the root; notifies all connected components |
|
|
108
|
+
| `getChildren` | `(node, depth, signal): Promise<TreeNode[]>` | Returns cached children or calls `loadChildren`; cache keyed by `node.item.key` |
|
|
109
|
+
| `invalidate` | `(nodeKey: string): void` | Clears cached children for `nodeKey`; connected components collapse that branch so the next expand triggers a fresh fetch |
|
|
110
|
+
| `addNode` | `(parentKey, node): TreeNode` | Appends a child; returns new root |
|
|
111
|
+
| `removeNode` | `(key): TreeNode` | Removes node and all descendants; returns new root |
|
|
112
|
+
| `updateItem` | `(key, patch): TreeNode` | Merges `patch` into the item at `key`; returns new root |
|
|
113
|
+
| `moveNode` | `(key, newParentKey): TreeNode` | Moves a node under a new parent; returns new root |
|
|
114
|
+
| `_subscribe` | `(cb): () => void` | Internal subscription used by components; returns unsubscribe |
|
|
115
|
+
|
|
116
|
+
#### How caching works
|
|
117
|
+
|
|
118
|
+
`getChildren()` stores results in a `Map<string, TreeNode[]>` keyed by `node.item.key`. A cache hit returns the stored array synchronously (wrapped in a resolved `Promise`). `invalidate(key)` deletes the cache entry and emits an `invalidate` event; connected components collapse the branch so the next expand triggers a fresh load.
|
|
119
|
+
|
|
120
|
+
Mutator methods (`addNode`, `removeNode`, `updateItem`, `moveNode`) apply pure transformations to produce a new immutable root, then emit a `root` event so all connected components re-render.
|
|
121
|
+
|
|
122
|
+
#### Model vs `loadChildren`
|
|
123
|
+
|
|
124
|
+
When both `model` and `loadChildren` are set, `model` takes precedence. `loadChildren` remains available for simple cases that do not need sharing or programmatic mutation.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Properties
|
|
129
|
+
|
|
130
|
+
These properties are present on all three components (`ixfx-tree-list`, `ixfx-miller-list`, `ixfx-crumb-navigation`).
|
|
131
|
+
|
|
132
|
+
| Property / Attribute | Type | Default | Description |
|
|
133
|
+
|----------------------|------|---------|-------------|
|
|
134
|
+
| `root` | `TreeNode \| undefined` | `undefined` | Root node of the tree |
|
|
135
|
+
| `model` | `TreeDataModel \| undefined` | `undefined` | Shared data model; takes precedence over `loadChildren` |
|
|
136
|
+
| `loadChildren` | `LoadChildrenCallback \| undefined` | `undefined` | Callback for lazy child loading |
|
|
137
|
+
| `selectedNode` | `TreeNode \| undefined` | `undefined` | Primary (most recent) selected node |
|
|
138
|
+
| `selectedNodes` | `ReadonlySet<TreeNode>` | `{}` | Full selection set (read-only) |
|
|
139
|
+
| `interactionMode` | `TreeInteractionMode` | `'standard'` | How gestures map to selection changes (`ixfx-tree-list` / `ixfx-miller-list` only) |
|
|
140
|
+
| `selectionFilter` | `'none' \| 'leaf' \| 'branch'` | `'leaf'` | Which node kinds can be selected (reflected attribute) |
|
|
141
|
+
| `filterPredicate` | `TreeFilterPredicate \| undefined` | `undefined` | Filter; only nodes returning `true` are shown |
|
|
142
|
+
| `exclusivity` | `'none' \| 'depth' \| 'global'` | `'none'` | Expansion exclusivity (reflected attribute) |
|
|
143
|
+
|
|
144
|
+
### `interactionMode` (`ixfx-tree-list` / `ixfx-miller-list`)
|
|
145
|
+
|
|
146
|
+
Controls how pointer and keyboard gestures translate to selection changes.
|
|
147
|
+
|
|
148
|
+
| Value | Behaviour |
|
|
149
|
+
|-------|-----------|
|
|
150
|
+
| `'implicit'` | Single selection follows every click; click also toggles expand/collapse |
|
|
151
|
+
| `'standard'` | Plain click selects + toggles expand; Ctrl/Cmd+click toggles item; Shift+click range-selects |
|
|
152
|
+
| `'manual'` | Component never auto-selects; use `select()` / `deselect()` / `clearSelection()` to drive state |
|
|
153
|
+
| `'checked'` | Checkboxes on every row; checkbox click recursively selects/deselects loaded descendants; row click only expands/collapses |
|
|
154
|
+
| `'vscode'` | Like `standard` for clicks; Shift+Up/Down uses snapshot-based toggle-range (VS Code file-explorer style) |
|
|
155
|
+
|
|
156
|
+
Switching `interactionMode` clears the current selection.
|
|
157
|
+
|
|
158
|
+
### `selectionFilter`
|
|
159
|
+
|
|
160
|
+
| Value | Behaviour |
|
|
161
|
+
|-------|-----------|
|
|
162
|
+
| `'none'` | No nodes can be selected |
|
|
163
|
+
| `'leaf'` | Only leaf nodes (`isLeaf: true` or `children: []`) can be selected |
|
|
164
|
+
| `'branch'` | Only branch nodes can be selected |
|
|
165
|
+
|
|
166
|
+
### `exclusivity`
|
|
167
|
+
|
|
168
|
+
Controls how expansion of one branch affects others.
|
|
169
|
+
|
|
170
|
+
| Value | Behaviour |
|
|
171
|
+
|-------|-----------|
|
|
172
|
+
| `'none'` | Any number of branches can be open simultaneously |
|
|
173
|
+
| `'depth'` | Opening a branch collapses its siblings at the same depth (accordion) |
|
|
174
|
+
| `'global'` | Opening any branch collapses all other open branches in the tree |
|
|
175
|
+
|
|
176
|
+
`exclusivity="depth"` replaces the old `accordion` boolean attribute. To migrate: `accordion` → `exclusivity="depth"`.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Selection
|
|
181
|
+
|
|
182
|
+
### Programmatic selection
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// Select a node (respects selectionFilter; always replaces selection)
|
|
186
|
+
el.select(node);
|
|
187
|
+
|
|
188
|
+
// Remove a specific node from the selection
|
|
189
|
+
el.deselect(node);
|
|
190
|
+
|
|
191
|
+
// Clear the entire selection
|
|
192
|
+
el.clearSelection();
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Reading the selection
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Primary (most-recent) selected node
|
|
199
|
+
console.log(el.selectedNode?.item.label);
|
|
200
|
+
|
|
201
|
+
// Full selection set (for multi-select)
|
|
202
|
+
for (const node of el.selectedNodes) {
|
|
203
|
+
console.log(node.item.label);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Listening for selection changes
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
el.addEventListener('select', ({ detail }) => {
|
|
211
|
+
const { selected, previous } = detail;
|
|
212
|
+
console.log('Selected:', [...selected].map(n => n.item.label));
|
|
213
|
+
console.log('Previously:', [...previous].map(n => n.item.label));
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Events
|
|
220
|
+
|
|
221
|
+
All events **bubble** and are **composed** (cross shadow-DOM boundaries).
|
|
222
|
+
|
|
223
|
+
| Event | Detail type | When fired |
|
|
224
|
+
|-------|-------------|------------|
|
|
225
|
+
| `select` | `TreeSelectDetail` | Selection set changes by any means (click, keyboard, programmatic) |
|
|
226
|
+
| `tickle` | `TreeTickleDetail` | An item enters cursor focus: pointer hover OR keyboard navigation cursor |
|
|
227
|
+
| `activate` | `TreeActivateDetail` | User explicitly activates an item (Enter key or double-click) |
|
|
228
|
+
| `item-click` | `{ node: TreeNode; depth: number }` | Raw pointer click on any item |
|
|
229
|
+
| `expand` | `{ node: TreeNode; depth: number }` | A branch expands |
|
|
230
|
+
| `collapse` | `{ node: TreeNode; depth: number }` | A branch collapses |
|
|
231
|
+
|
|
232
|
+
### Detail types
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
type TreeSelectDetail = {
|
|
236
|
+
readonly selected: ReadonlySet<TreeNode>; // Current full selection
|
|
237
|
+
readonly previous: ReadonlySet<TreeNode>; // Selection before this change
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
type TreeTickleDetail = {
|
|
241
|
+
readonly node: TreeNode;
|
|
242
|
+
readonly depth: number;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
type TreeActivateDetail = {
|
|
246
|
+
readonly node: TreeNode;
|
|
247
|
+
readonly depth: number;
|
|
248
|
+
};
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Usage example
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
el.addEventListener('select', ({ detail }) => {
|
|
255
|
+
// Works for both single and multi-select
|
|
256
|
+
const first = [...detail.selected][0];
|
|
257
|
+
if (first) console.log('Primary selection:', first.item.label);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
el.addEventListener('tickle', ({ detail }) => {
|
|
261
|
+
// Show a preview pane as the user hovers
|
|
262
|
+
preview.setNode(detail.node);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
el.addEventListener('activate', ({ detail }) => {
|
|
266
|
+
// Open the item (e.g. navigate to a route)
|
|
267
|
+
router.navigate(detail.node.item.key);
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Migration from old event shapes
|
|
272
|
+
|
|
273
|
+
| Old | New |
|
|
274
|
+
|-----|-----|
|
|
275
|
+
| `select` → `{ selected: TreeNode, previous: TreeNode \| undefined }` | `select` → `TreeSelectDetail` (set-based) |
|
|
276
|
+
| `change` (Miller) | `select` (set-based) |
|
|
277
|
+
| Miller `select` (Enter key) | `activate` |
|
|
278
|
+
| no tickle event | `tickle` |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Keyboard navigation
|
|
283
|
+
|
|
284
|
+
The element must be focused (click it or tab to it) before keyboard navigation works.
|
|
285
|
+
|
|
286
|
+
### `ixfx-tree-list`
|
|
287
|
+
|
|
288
|
+
| Key | Action |
|
|
289
|
+
|-----|--------|
|
|
290
|
+
| `Arrow Up` | Move cursor to previous visible item |
|
|
291
|
+
| `Arrow Down` | Move cursor to next visible item |
|
|
292
|
+
| `Arrow Right` (on collapsed branch) | Expand and move into first child |
|
|
293
|
+
| `Arrow Right` (on expanded branch) | Move into first child |
|
|
294
|
+
| `Arrow Right` (on leaf) | No-op |
|
|
295
|
+
| `Arrow Left` (on expanded branch) | Collapse branch |
|
|
296
|
+
| `Arrow Left` (on leaf or collapsed branch) | Move to parent |
|
|
297
|
+
| `Enter` | Select and activate focused item |
|
|
298
|
+
| `Escape` | Cancel in-flight lazy load |
|
|
299
|
+
|
|
300
|
+
Moving the cursor fires a `tickle` event. Pressing Enter fires `select` then `activate`.
|
|
301
|
+
|
|
302
|
+
### `ixfx-miller-list`
|
|
303
|
+
|
|
304
|
+
| Key | Action |
|
|
305
|
+
|-----|--------|
|
|
306
|
+
| `Arrow Up / Down` | Move within the active column |
|
|
307
|
+
| `Arrow Right` | Expand (open next column for) highlighted branch |
|
|
308
|
+
| `Arrow Left` | Go back to the parent column |
|
|
309
|
+
| `Enter` | Activate the highlighted item (`activate` event) |
|
|
310
|
+
| `Escape` | Cancel pending operations |
|
|
311
|
+
|
|
312
|
+
### `ixfx-crumb-navigation`
|
|
313
|
+
|
|
314
|
+
Keyboard navigation follows the crumb path. Arrow keys move between breadcrumb segments; clicking or Enter expands the next level.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Incremental search
|
|
319
|
+
|
|
320
|
+
Wire up a text input to filter and highlight matching nodes using `IncrSearchTreeController`:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { IncrSearchTreeController } from '@ixfx/components';
|
|
324
|
+
|
|
325
|
+
const ctrl = new IncrSearchTreeController(el, {
|
|
326
|
+
selector: item => item.node.item.label, // Text to search against
|
|
327
|
+
input: document.querySelector('#search'), // Optional: auto-wires input/keydown
|
|
328
|
+
});
|
|
329
|
+
ctrl.connect();
|
|
330
|
+
|
|
331
|
+
// Clean up when done
|
|
332
|
+
ctrl.disconnect();
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Options
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
type IncrSearchTreeOptions = {
|
|
339
|
+
/** How to extract searchable text from each node */
|
|
340
|
+
selector: (item: { node: TreeNode; depth: number }) => string;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* CSS selector for label elements inside the shadow root.
|
|
344
|
+
* Default: '.tree-label' (ixfx-tree-list)
|
|
345
|
+
* Use '.label' for ixfx-miller-list
|
|
346
|
+
*/
|
|
347
|
+
labelSelector?: string;
|
|
348
|
+
|
|
349
|
+
/** Input element to auto-wire. Esc clears the query. */
|
|
350
|
+
input?: HTMLInputElement;
|
|
351
|
+
|
|
352
|
+
/** fzf matching options */
|
|
353
|
+
fzf?: Partial<FzfOptions<{ node: TreeNode; depth: number }>>;
|
|
354
|
+
};
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Manual control
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
await ctrl.setQuery('search text');
|
|
361
|
+
await ctrl.clearQuery();
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Using with miller-list
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
const ctrl = new IncrSearchTreeController(millerEl, {
|
|
368
|
+
selector: item => item.node.item.label,
|
|
369
|
+
labelSelector: '.label', // Miller uses .label, not .tree-label
|
|
370
|
+
input: searchInput,
|
|
371
|
+
});
|
|
372
|
+
ctrl.connect();
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### How it works
|
|
376
|
+
|
|
377
|
+
1. `connect()` calls `el.getNodes()` to snapshot the full item list.
|
|
378
|
+
2. On each query change the controller runs fzf fuzzy matching and sets `el.filterPredicate` to a function that returns `true` only for matching nodes.
|
|
379
|
+
3. Matched label text is highlighted in the shadow DOM using the CSS Highlight API via `applyHighlights()`.
|
|
380
|
+
4. `disconnect()` clears `filterPredicate` and all highlights.
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## ARIA
|
|
385
|
+
|
|
386
|
+
Each tree-like component must implement the following. These are enforced by the shared `TreeComponent` interface and implemented in `TreeBaseElement` / `MillerBaseElement` / `CrumbNavigationElement`.
|
|
387
|
+
|
|
388
|
+
**Container element**
|
|
389
|
+
|
|
390
|
+
- [ ] `role="tree"` on the outermost interactive container
|
|
391
|
+
- [ ] `aria-label` or `aria-labelledby` to name the tree
|
|
392
|
+
|
|
393
|
+
**Each item element**
|
|
394
|
+
|
|
395
|
+
- [ ] `role="treeitem"`
|
|
396
|
+
- [ ] `aria-level` (1-based depth)
|
|
397
|
+
- [ ] `aria-setsize` (total siblings in the same group)
|
|
398
|
+
- [ ] `aria-posinset` (1-based position among siblings)
|
|
399
|
+
- [ ] `aria-selected="true|false"`
|
|
400
|
+
|
|
401
|
+
**Expandable items**
|
|
402
|
+
|
|
403
|
+
- [ ] `aria-expanded="true"` when open, `"false"` when closed
|
|
404
|
+
- [ ] Omit `aria-expanded` on leaf nodes
|
|
405
|
+
|
|
406
|
+
**Child groups**
|
|
407
|
+
|
|
408
|
+
- [ ] Wrap children in `<ul role="group">` (or equivalent `role="group"` container)
|
|
409
|
+
|
|
410
|
+
**Miller columns specifically**
|
|
411
|
+
|
|
412
|
+
Each column is a separate `role="listbox"` with `aria-label` showing the parent node label. Items use `role="option"` and `aria-selected`.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## CSS variables
|
|
417
|
+
|
|
418
|
+
### Shared / themed
|
|
419
|
+
|
|
420
|
+
These are set by the global theme and inherited by all tree components.
|
|
421
|
+
|
|
422
|
+
| Variable | Description |
|
|
423
|
+
|----------|-------------|
|
|
424
|
+
| `--accent` | Selected item background |
|
|
425
|
+
| `--accent-text` | Selected item text |
|
|
426
|
+
| `--surface-3` | Panel background |
|
|
427
|
+
| `--surface-3-text` | Default item text |
|
|
428
|
+
| `--surface-muted-text` | Muted text (carets, secondary info) |
|
|
429
|
+
| `--surface-h` | Hover background |
|
|
430
|
+
| `--radius-s` | Small border radius |
|
|
431
|
+
| `--transition` | Default transition timing |
|
|
432
|
+
| `--space-xs` | Extra-small spacing |
|
|
433
|
+
| `--space-s` | Small spacing |
|
|
434
|
+
| `--space-m` | Medium spacing |
|
|
435
|
+
| `--font-family` | Font family |
|
|
436
|
+
| `--text-m` | Base text size |
|
|
437
|
+
| `--text-l` | Large text size |
|
|
438
|
+
|
|
439
|
+
### `ixfx-tree-list` specific
|
|
440
|
+
|
|
441
|
+
| Variable | Default | Description |
|
|
442
|
+
|----------|---------|-------------|
|
|
443
|
+
| `--tree-indent` | `20px` | Indentation per depth level |
|
|
444
|
+
| `--tree-item-height` | `28px` | Height of each row |
|
|
445
|
+
| `--tree-caret-size` | `10px` | Expand/collapse caret size |
|
|
446
|
+
|
|
447
|
+
### `ixfx-miller-list` specific
|
|
448
|
+
|
|
449
|
+
| Variable | Default | Description |
|
|
450
|
+
|----------|---------|-------------|
|
|
451
|
+
| `--miller-column-width` | `180px` | Width of each column |
|
|
452
|
+
| `--miller-column-max-height` | `320px` | Maximum column height before scroll |
|
|
453
|
+
| `--item-hover-bg` | `var(--surface-h)` | Hover background |
|
|
454
|
+
| `--item-selected-bg` | `var(--accent)` | Selected item background |
|
|
455
|
+
| `--item-selected-text` | `#fff` | Selected item text |
|
|
456
|
+
| `--item-open-bg` | (theme) | Background for items on the open path |
|
|
457
|
+
| `--icon-size` | `1em` | Icon dimensions |
|
|
458
|
+
| `--icon-spacing` | `0.3em` | Gap between icon and label |
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Controller authoring guide
|
|
463
|
+
|
|
464
|
+
A controller operates against the `TreeComponent` interface. This means the same controller works with any of the three components.
|
|
465
|
+
|
|
466
|
+
### Minimal controller
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
import type { TreeComponent, TreeNode } from '@ixfx/components';
|
|
470
|
+
|
|
471
|
+
export class MyController {
|
|
472
|
+
#el: TreeComponent;
|
|
473
|
+
#unsub?: () => void;
|
|
474
|
+
|
|
475
|
+
constructor(el: TreeComponent) {
|
|
476
|
+
this.#el = el;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
connect(): void {
|
|
480
|
+
this.disconnect();
|
|
481
|
+
this.#el.addEventListener('select', this.#onSelect);
|
|
482
|
+
this.#el.addEventListener('tickle', this.#onTickle);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
disconnect(): void {
|
|
486
|
+
this.#el.removeEventListener('select', this.#onSelect);
|
|
487
|
+
this.#el.removeEventListener('tickle', this.#onTickle);
|
|
488
|
+
this.#unsub?.();
|
|
489
|
+
this.#unsub = undefined;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
#onSelect = (e: CustomEvent) => {
|
|
493
|
+
const { selected } = e.detail;
|
|
494
|
+
for (const node of selected as ReadonlySet<TreeNode>) {
|
|
495
|
+
console.log('selected:', node.item.label);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
#onTickle = (e: CustomEvent) => {
|
|
500
|
+
const { node, depth } = e.detail;
|
|
501
|
+
console.log('tickled:', node.item.label, 'at depth', depth);
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Querying all nodes
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
// Snapshot of all visible nodes with their depth
|
|
510
|
+
const nodes = el.getNodes(); // ReadonlyArray<{ node: TreeNode; depth: number }>
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Filtering
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
// Only show nodes matching a predicate
|
|
517
|
+
el.filterPredicate = (node, depth) => node.item.label.startsWith('A');
|
|
518
|
+
|
|
519
|
+
// Clear filter
|
|
520
|
+
el.filterPredicate = undefined;
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Selecting programmatically
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
// Honour selectionMode and selectionFilter automatically
|
|
527
|
+
el.select(someNode);
|
|
528
|
+
|
|
529
|
+
// Or navigate to a node by key path and select it
|
|
530
|
+
el.navigateTo(['root', 'documents', 'readme.md']);
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Using `TreeSearchHost` for shadow-DOM access
|
|
534
|
+
|
|
535
|
+
Controllers that need to touch the shadow DOM (e.g. for highlight injection) should type the host as `TreeSearchHost` rather than `TreeComponent`:
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
import type { TreeSearchHost } from '@ixfx/components';
|
|
539
|
+
|
|
540
|
+
export class HighlightController {
|
|
541
|
+
#el: TreeSearchHost;
|
|
542
|
+
|
|
543
|
+
constructor(el: TreeSearchHost) {
|
|
544
|
+
this.#el = el;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async highlight(selector: string): Promise<void> {
|
|
548
|
+
await this.#el.updateComplete;
|
|
549
|
+
const labels = this.#el.shadowRoot?.querySelectorAll(selector);
|
|
550
|
+
// ...
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## Types reference
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
type LoadChildrenCallback = (
|
|
561
|
+
query: { node: TreeNode; depth: number },
|
|
562
|
+
signal: AbortSignal
|
|
563
|
+
) => TreeNode[] | Promise<TreeNode[]> | AsyncIterable<DataBatch<TreeNode>>;
|
|
564
|
+
|
|
565
|
+
type TreeFilterPredicate = (node: TreeNode, depth: number) => boolean;
|
|
566
|
+
|
|
567
|
+
type TreeExclusivity = 'none' | 'depth' | 'global';
|
|
568
|
+
type TreeSelectionFilter = 'none' | 'leaf' | 'branch';
|
|
569
|
+
type TreeInteractionMode = 'implicit' | 'standard' | 'manual' | 'checked' | 'vscode';
|
|
570
|
+
|
|
571
|
+
interface TreeComponent extends EventTarget {
|
|
572
|
+
root: TreeNode | undefined;
|
|
573
|
+
model: TreeDataModel | undefined;
|
|
574
|
+
loadChildren: LoadChildrenCallback | undefined;
|
|
575
|
+
selectedNode: TreeNode | undefined;
|
|
576
|
+
readonly selectedNodes: ReadonlySet<TreeNode>;
|
|
577
|
+
selectionFilter: TreeSelectionFilter;
|
|
578
|
+
filterPredicate: TreeFilterPredicate | undefined;
|
|
579
|
+
exclusivity: TreeExclusivity;
|
|
580
|
+
select(node: TreeNode): void;
|
|
581
|
+
deselect(node: TreeNode): void;
|
|
582
|
+
clearSelection(): void;
|
|
583
|
+
navigateTo(keys: readonly string[]): boolean;
|
|
584
|
+
navigateToNode(predicate: (node: TreeNode) => boolean): boolean;
|
|
585
|
+
getNodes(): ReadonlyArray<{ node: TreeNode; depth: number }>;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
interface TreeSearchHost extends TreeComponent {
|
|
589
|
+
readonly shadowRoot: ShadowRoot | null;
|
|
590
|
+
readonly updateComplete: Promise<boolean>;
|
|
591
|
+
}
|
|
592
|
+
```
|