@ixfx/components 0.14.1 → 0.14.3

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.
Files changed (31) hide show
  1. package/bundle/index.d.ts +22 -6
  2. package/bundle/index.js +27 -15
  3. package/dist/crumbs.d.ts +2 -2
  4. package/dist/{data-grid-D7RxYISt.d.ts → data-grid-DmkId8bu.d.ts} +3 -3
  5. package/dist/data-grid.d.ts +2 -2
  6. package/dist/{detail-list-w32XZEgH.d.ts → detail-list-CmQqeXvp.d.ts} +3 -3
  7. package/dist/detail-list.d.ts +3 -3
  8. package/dist/{flat-list-CkRIZCuR.d.ts → flat-list-BmQBB3ZC.d.ts} +3 -3
  9. package/dist/flat-list.d.ts +1 -1
  10. package/dist/{grid-list-DUvhSoT2.d.ts → grid-list-BVsUEvgd.d.ts} +3 -3
  11. package/dist/grid-list.d.ts +2 -2
  12. package/dist/incr-search.d.ts +1 -1
  13. package/dist/{index-CO6m-YC0.d.ts → index-BvoXLnBf.d.ts} +2 -2
  14. package/dist/{index-CSCrK0hR.d.ts → index-DuhzWWTr.d.ts} +10 -4
  15. package/dist/{index-B-hzcIP0.d.ts → index-DxyyVqzA.d.ts} +1 -1
  16. package/dist/index.d.ts +13 -11
  17. package/dist/index.js +12 -5
  18. package/dist/{list-native-drag-controller-CvXN3NB7.d.ts → list-native-drag-controller-NMspr0E1.d.ts} +1 -1
  19. package/dist/menu.d.ts +1 -1
  20. package/dist/miller.d.ts +3 -3
  21. package/dist/{tree-9Hs7VxuX.js → tree-BFoN2Z_P.js} +41 -10
  22. package/dist/{tree-component-Tslymyyl.d.ts → tree-component-CDsYTBDi.d.ts} +1 -1
  23. package/dist/tree.d.ts +3 -3
  24. package/dist/tree.js +1 -1
  25. package/dist/{types-DQ7KOUIj.d.ts → types-Jky6oNAp.d.ts} +8 -0
  26. package/dist/{vertical-list-B1Fq06xr.d.ts → vertical-list-ztrdFvyT.d.ts} +2 -2
  27. package/dist/vertical-list.d.ts +2 -2
  28. package/dist/vertical-list.js +4 -1
  29. package/docs-user/index.json +2 -2
  30. package/docs-user/tree.md +56 -3
  31. package/package.json +1 -1
package/docs-user/tree.md CHANGED
@@ -11,6 +11,7 @@ Three components share a common `TreeComponent` interface: **`ixfx-tree-list`**,
11
11
  1. [Data model](#data-model)
12
12
  2. [Properties](#properties)
13
13
  - [Custom checkbox (`checkboxRenderer`)](#custom-checkbox-ixfx-tree-list-only--checkboxrenderer)
14
+ - [Unselectable items (`selectable`, `alignCheckboxes`)](#unselectable-items-selectable-aligncheckboxes)
14
15
  - [Virtualisation](#virtualisation-ixfx-tree-list)
15
16
  3. [Selection](#selection)
16
17
  4. [Events](#events)
@@ -31,6 +32,7 @@ type TreeItem = {
31
32
  key: string; // Unique identifier across the whole tree
32
33
  label: string; // Display text
33
34
  isLeaf?: boolean; // true = never expandable; undefined/false = branch
35
+ selectable?: boolean; // false = can never be selected (and gets no checkbox in `checked` mode)
34
36
  data?: unknown; // Arbitrary user payload
35
37
  icon?: string; // Icon name (passed to <ixfx-icon>)
36
38
  tooltip?: string; // Tooltip content
@@ -138,19 +140,33 @@ These properties are present on all three components (`ixfx-tree-list`, `ixfx-mi
138
140
 
139
141
  | Property / Attribute | Type | Default | Description |
140
142
  |----------------------|------|---------|-------------|
141
- | `root` | `TreeNode \| undefined` | `undefined` | Root node of the tree |
143
+ | `root` | `TreeNode \| undefined` | `undefined` | Root node of the tree. Replacing it keeps expansion for every `item.key` still present (see [Replacing `root`](#replacing-root)); selection and focus are reset |
142
144
  | `model` | `TreeDataModel \| undefined` | `undefined` | Shared data model; takes precedence over `loadChildren` |
143
145
  | `loadChildren` | `LoadChildrenCallback \| undefined` | `undefined` | Callback for lazy child loading |
144
146
  | `selectedNode` | `TreeNode \| undefined` | `undefined` | Primary (most recent) selected node |
145
147
  | `selectedNodes` | `ReadonlySet<TreeNode>` | `{}` | Full selection set (read-only) |
146
148
  | `interactionMode` | `TreeInteractionMode` | `'standard'` | How gestures map to selection changes (`ixfx-tree-list` / `ixfx-miller-list` only) |
147
149
  | `selectionFilter` | `'none' \| 'leaf' \| 'branch'` | `'leaf'` | Which node kinds can be selected (reflected attribute) |
150
+ | `alignCheckboxes` (`align-checkboxes`) | `boolean` | `false` | In `checked` mode, unselectable rows keep the space their checkbox would take so they line up with selectable siblings (`ixfx-tree-list` only). See [Unselectable items](#unselectable-items-selectable-aligncheckboxes) |
148
151
  | `filterPredicate` | `TreeFilterPredicate \| undefined` | `undefined` | Filter; only matching nodes and their ancestors are rendered (non-matching rows are not in the DOM, keyboard navigation, `selectAll` and Shift-range skip them) |
149
152
  | `exclusivity` | `'none' \| 'depth' \| 'global'` | `'none'` | Expansion exclusivity (reflected attribute) |
150
153
  | `stickyHeaders` (`sticky-headers`) | `boolean` | `true` | VS Code-style sticky headers; set `sticky-headers="false"` to opt out (`ixfx-tree-list` only) |
151
154
  | `virtualize` | `'auto' \| 'on' \| 'off'` | `'auto'` | Render only the rows near the viewport; `auto` switches on above `virtualizeThreshold` visible rows (`ixfx-tree-list` only). See [Virtualisation](#virtualisation-ixfx-tree-list) |
152
155
  | `virtualizeThreshold` (`virtualize-threshold`) | `number` | `200` | Visible-row count above which `virtualize="auto"` windows the list |
153
156
 
157
+ ### Replacing `root`
158
+
159
+ Because `TreeNode` is immutable, any structural change means assigning a new `root`. When you do:
160
+
161
+ - **Expansion is kept** for every branch whose `item.key` still exists in the new root, and dropped for keys that are gone. A key that disappears and later returns comes back collapsed. Call `collapseAll()` if you want a fresh tree.
162
+ - **Selection, focus and any pending lazy load are reset**, since they may refer to nodes that no longer exist.
163
+ - The reconciliation happens before the render, so assigning `root` and then calling `expandAll()` (or `navigateTo()`) synchronously works as you'd expect:
164
+
165
+ ```ts
166
+ tree.root = rebuild();
167
+ tree.expandAll(); // stays expanded after the update
168
+ ```
169
+
154
170
  ### `interactionMode` (`ixfx-tree-list` / `ixfx-miller-list`)
155
171
 
156
172
  Controls how pointer and keyboard gestures translate to selection changes.
@@ -160,7 +176,7 @@ Controls how pointer and keyboard gestures translate to selection changes.
160
176
  | `'implicit'` | Single selection follows every click; click also toggles expand/collapse |
161
177
  | `'standard'` | Plain click selects + toggles expand; Ctrl/Cmd+click toggles item; Shift+click range-selects |
162
178
  | `'manual'` | Component never auto-selects; use `select()` / `deselect()` / `clearSelection()` to drive state |
163
- | `'checked'` | Checkboxes on every row; checkbox click recursively selects/deselects loaded descendants; row click only expands/collapses |
179
+ | `'checked'` | Checkboxes on every row; clicking the checkbox — or anywhere left of the label (indent, caret, icon) — recursively selects/deselects loaded descendants; label click only expands/collapses |
164
180
  | `'vscode'` | Like `standard` for clicks; Shift+Up/Down uses snapshot-based toggle-range (VS Code file-explorer style) |
165
181
 
166
182
  Switching `interactionMode` clears the current selection.
@@ -190,6 +206,8 @@ tree.checkboxRenderer = (state) => state === `unchecked`
190
206
 
191
207
  When `checkboxRenderer` is set, the checkbox becomes a `<span class="tree-checkbox" role="checkbox" part="checkbox">` holding your template, with `aria-checked` set to `"true"`, `"false"`, or `"mixed"` to match the tri-state. The span owns the click (same as the native input), so clicking anywhere in it — including empty space when you render nothing for `unchecked` — toggles the row.
192
208
 
209
+ To keep the checkbox easy to aim at, the entire row region left of the label — indent gutter, checkbox, caret and icon — acts as one checkbox hit target in `checked` mode. Only clicks on the label itself expand/collapse.
210
+
193
211
  Both the native input and the custom span expose the `checkbox` CSS part for external styling:
194
212
 
195
213
  ```css
@@ -199,12 +217,47 @@ ixfx-tree-list::part(checkbox) {
199
217
  }
200
218
  ```
201
219
 
220
+ ### Unselectable items (`ixfx-tree-list`) — `selectable`, `alignCheckboxes`
221
+
222
+ Set `selectable: false` on a `TreeItem` to stop that one node being selected, independent of `selectionFilter` and of the interaction mode. Selection APIs (`selectNode`, `selectAll`, `Shift`-range, search "select" mode) skip it.
223
+
224
+ ```typescript
225
+ const root: TreeNode = {
226
+ item: { key: 'root', label: 'root' },
227
+ children: [
228
+ {
229
+ item: { key: 'fruit', label: 'Fruit', selectable: false }, // heading only
230
+ children: [
231
+ { item: { key: 'apple', label: 'Apple', isLeaf: true } }, // selectable
232
+ { item: { key: 'pear', label: 'Pear', isLeaf: true } },
233
+ ],
234
+ },
235
+ ],
236
+ };
237
+ ```
238
+
239
+ In `checked` mode:
240
+
241
+ - An unselectable row is drawn **without a checkbox**, and clicks in its leading region (indent, caret, icon) expand/collapse it like a normal row instead of toggling a checkbox.
242
+ - Its selectable descendants behave as normal. Unselectable leaves are ignored when working out a parent's `checked` / `indeterminate` state, so a branch whose only selectable children are all checked shows as checked.
243
+ - Only the item's own flag decides whether a checkbox is drawn. A branch that `selectionFilter="leaf"` stops being selected itself still gets a checkbox, because that checkbox toggles its descendants.
244
+
245
+ **Alignment.** By default an unselectable row reserves no space where the checkbox would be, so its caret and label sit further left than its selectable siblings. Set the `align-checkboxes` attribute (or `alignCheckboxes = true`) to keep that space:
246
+
247
+ ```html
248
+ <ixfx-tree-list interaction-mode="checked" align-checkboxes></ixfx-tree-list>
249
+ ```
250
+
251
+ The reserved space is an empty `<span class="tree-checkbox-spacer" aria-hidden="true">` the same size as a checkbox (`--tree-checkbox-size`, default `14px`, plus a `--space-xs` right margin). The native checkbox uses the same size, so rows line up exactly.
252
+
253
+ `alignCheckboxes` has no effect outside `checked` mode. `selectable: false` is honoured by the other tree components for selection, but only `ixfx-tree-list` draws checkboxes. See the "Unselectable items" section of `demo/tree-list.html` for a live example with a toggle.
254
+
202
255
  ### `selectionFilter`
203
256
 
204
257
  | Value | Behaviour |
205
258
  |-------|-----------|
206
259
  | `'none'` | No nodes can be selected |
207
- | `'leaf'` | Only leaf nodes (`isLeaf: true` or `children: []`) can be selected |
260
+ | `'leaf'` | Only leaf nodes can be selected: `isLeaf: true`, or a loaded node with `children: []` (unless `isLeaf: false`). A node whose `children` are not loaded yet is not a leaf |
208
261
  | `'branch'` | Only branch nodes can be selected |
209
262
 
210
263
  ### `exclusivity`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ixfx/components",
3
3
  "type": "module",
4
- "version": "0.14.1",
4
+ "version": "0.14.3",
5
5
  "packageManager": "pnpm@10.0.0",
6
6
  "description": "Web components for ixfx — Lit-based UI toolkit",
7
7
  "author": "Clint Heyer",