@ixfx/components 0.7.4 → 0.8.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 +787 -190
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +2770 -592
- package/bundle/index.js.map +1 -1
- package/dist/ac-token.js +1 -1
- package/dist/crumbs.d.ts +5 -1
- package/dist/crumbs.d.ts.map +1 -1
- package/dist/crumbs.js +10 -0
- package/dist/crumbs.js.map +1 -1
- package/dist/{data-grid-BddUjAti.d.ts → data-grid-D-z7bx5-.d.ts} +26 -1
- package/dist/data-grid-D-z7bx5-.d.ts.map +1 -0
- package/dist/data-grid.d.ts +1 -1
- package/dist/data-grid.js +88 -7
- package/dist/data-grid.js.map +1 -1
- package/dist/{detail-list-Br0WAnry.d.ts → detail-list-_ZJHYEBr.d.ts} +20 -12
- package/dist/detail-list-_ZJHYEBr.d.ts.map +1 -0
- package/dist/detail-list.d.ts +2 -2
- package/dist/detail-list.js +51 -135
- package/dist/detail-list.js.map +1 -1
- package/dist/grid-list-nRUQOcEL.js +1537 -0
- package/dist/grid-list-nRUQOcEL.js.map +1 -0
- package/dist/{grid-list-B_orPsot.d.ts → grid-list-u33vmKzb.d.ts} +128 -10
- package/dist/grid-list-u33vmKzb.d.ts.map +1 -0
- package/dist/grid-list.d.ts +1 -1
- package/dist/grid-list.js +1 -932
- package/dist/incr-search-C05WjbZh.js +999 -0
- package/dist/incr-search-C05WjbZh.js.map +1 -0
- package/dist/incr-search.d.ts +2 -2
- package/dist/incr-search.js +2 -3
- package/dist/index-h6gxtfHH.d.ts +397 -0
- package/dist/index-h6gxtfHH.d.ts.map +1 -0
- package/dist/index.d.ts +62 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +343 -17
- package/dist/index.js.map +1 -1
- package/dist/led.d.ts +33 -1
- package/dist/led.d.ts.map +1 -1
- package/dist/led.js +157 -13
- package/dist/led.js.map +1 -1
- package/dist/{list-selection-controller-CUo-Hhcm.js → list-selection-controller-DTFI40li.js} +2 -76
- package/dist/list-selection-controller-DTFI40li.js.map +1 -0
- package/dist/miller.d.ts +81 -3
- package/dist/miller.d.ts.map +1 -1
- package/dist/miller.js +327 -68
- package/dist/miller.js.map +1 -1
- package/dist/narrowed-text.js +1 -2
- package/dist/narrowed-text.js.map +1 -1
- package/dist/panel.d.ts +3 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +31 -1
- package/dist/panel.js.map +1 -1
- package/dist/plots.d.ts +2 -2
- package/dist/plots.js +1 -1
- package/dist/{titlebar-Bj5pfdw_.d.ts → titlebar-YQ-jVQoS.d.ts} +2 -2
- package/dist/{titlebar-Bj5pfdw_.d.ts.map → titlebar-YQ-jVQoS.d.ts.map} +1 -1
- package/dist/titlebar.d.ts +1 -1
- package/dist/titlebar.js +83 -1
- package/dist/titlebar.js.map +1 -1
- package/dist/{tree-B74zdI60.js → tree-Chptss7I.js} +77 -15
- package/dist/tree-Chptss7I.js.map +1 -0
- package/dist/{tree-component-BvV4muxx.d.ts → tree-component-F6qZ0Gdv.d.ts} +9 -1
- package/dist/{tree-component-BvV4muxx.d.ts.map → tree-component-F6qZ0Gdv.d.ts.map} +1 -1
- package/dist/tree.d.ts +22 -1
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +1 -1
- package/dist/{vertical-list-CQSEVeOT.d.ts → vertical-list-CFuFDygi.d.ts} +17 -14
- package/dist/vertical-list-CFuFDygi.d.ts.map +1 -0
- package/dist/vertical-list.d.ts +1 -1
- package/dist/vertical-list.js +59 -127
- package/dist/vertical-list.js.map +1 -1
- package/dist/{xy-axis-5KhVTNoX.d.ts → xy-axis-BfP9hKLj.d.ts} +25 -2
- package/dist/{xy-axis-5KhVTNoX.d.ts.map → xy-axis-BfP9hKLj.d.ts.map} +1 -1
- package/dist/{xy-axis-VrX8dmvS.js → xy-axis-DzM1brBZ.js} +141 -8
- package/dist/xy-axis-DzM1brBZ.js.map +1 -0
- package/docs-user/data-grid.md +19 -0
- package/docs-user/detail-list.md +1 -1
- package/docs-user/grid-list.md +120 -11
- package/docs-user/incr-search.md +12 -2
- package/docs-user/index.json +3 -3
- package/docs-user/led.md +37 -7
- package/docs-user/llms.txt +1 -1
- package/docs-user/panel.md +68 -13
- package/docs-user/titlebar.md +3 -4
- package/docs-user/tree.md +22 -1
- package/docs-user/vertical-list.md +7 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/dist/data-grid-BddUjAti.d.ts.map +0 -1
- package/dist/detail-list-Br0WAnry.d.ts.map +0 -1
- package/dist/element-search-Y8SRfPGM.js +0 -185
- package/dist/element-search-Y8SRfPGM.js.map +0 -1
- package/dist/grid-list-B_orPsot.d.ts.map +0 -1
- package/dist/grid-list.js.map +0 -1
- package/dist/incr-search-vCzuao-2.js +0 -137
- package/dist/incr-search-vCzuao-2.js.map +0 -1
- package/dist/index-Cu5i8zZY.d.ts +0 -160
- package/dist/index-Cu5i8zZY.d.ts.map +0 -1
- package/dist/list-selection-controller-CUo-Hhcm.js.map +0 -1
- package/dist/tree-B74zdI60.js.map +0 -1
- package/dist/vertical-list-CQSEVeOT.d.ts.map +0 -1
- package/dist/xy-axis-VrX8dmvS.js.map +0 -1
package/dist/miller.js
CHANGED
|
@@ -2,16 +2,19 @@ import { t as TickledController } from "./tickled-controller-C66DgJHl.js";
|
|
|
2
2
|
import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
|
|
3
3
|
import { t as themeFallbacks } from "./fallbacks-DNI9xt0F.js";
|
|
4
4
|
import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
|
|
5
|
+
import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-C05WjbZh.js";
|
|
5
6
|
import "./interaction-Cr13azbM.js";
|
|
6
7
|
import { t as collectDataResult } from "./data-provider-35TyWclX.js";
|
|
7
8
|
import { LitElement, css, html, nothing } from "lit";
|
|
8
9
|
import { property, state } from "lit/decorators.js";
|
|
10
|
+
import { createCommandRegistry } from "@clinth/ui-commands";
|
|
9
11
|
//#region src/miller/miller-base.ts
|
|
10
12
|
const EXPAND_DEBOUNCE_MS = 150;
|
|
11
13
|
let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
12
14
|
constructor(..._args) {
|
|
13
15
|
super(..._args);
|
|
14
16
|
this.headers = false;
|
|
17
|
+
this.stretchLastColumn = false;
|
|
15
18
|
this.interactionMode = `standard`;
|
|
16
19
|
this.selectionFilter = `leaf`;
|
|
17
20
|
this.exclusivity = `none`;
|
|
@@ -23,6 +26,10 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
23
26
|
this.#resizingDepth = -1;
|
|
24
27
|
this.#resizeStartX = 0;
|
|
25
28
|
this.#resizeStartWidth = 0;
|
|
29
|
+
this.search = new ListSearchController(this, { adapter: createTreeListSearchAdapter(this, {
|
|
30
|
+
labelSelector: `.label`,
|
|
31
|
+
highlightKey: `incr-search-highlight`
|
|
32
|
+
}) });
|
|
26
33
|
this.tickled = new TickledController(this, { getItems: () => {
|
|
27
34
|
const items = [];
|
|
28
35
|
for (let depth = 0; depth < this._columns.length; depth++) {
|
|
@@ -32,6 +39,7 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
32
39
|
return items;
|
|
33
40
|
} });
|
|
34
41
|
this.#onKeyDown = (event) => {
|
|
42
|
+
if (this.search.isOpen) return;
|
|
35
43
|
const currentDepth = this.#getTickledDepthOrDefault();
|
|
36
44
|
const col = this._columns[currentDepth];
|
|
37
45
|
if (!col || col.length === 0) {
|
|
@@ -238,9 +246,31 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
238
246
|
#resizeStartX;
|
|
239
247
|
#resizeStartWidth;
|
|
240
248
|
#modelUnsubscribe;
|
|
249
|
+
#searchRegistry;
|
|
250
|
+
#unregisterSearchCommands;
|
|
251
|
+
/** Command registry carrying this component's `list.search.*` commands. */
|
|
252
|
+
get registry() {
|
|
253
|
+
return this.#searchRegistry;
|
|
254
|
+
}
|
|
255
|
+
#effectiveSearchModes() {
|
|
256
|
+
const raw = this.searchModes?.trim();
|
|
257
|
+
if (raw === void 0) return [...LIST_SEARCH_MODES];
|
|
258
|
+
const requested = new Set(raw.split(/\s+/));
|
|
259
|
+
return LIST_SEARCH_MODES.filter((m) => requested.has(m));
|
|
260
|
+
}
|
|
261
|
+
#syncSearchCommands() {
|
|
262
|
+
if (!this.#searchRegistry) return;
|
|
263
|
+
this.search.setModes(this.#effectiveSearchModes());
|
|
264
|
+
this.#unregisterSearchCommands?.();
|
|
265
|
+
this.#unregisterSearchCommands = registerListSearchCommands(this.#searchRegistry, this.search);
|
|
266
|
+
}
|
|
241
267
|
#buildTickledId(node, depth) {
|
|
242
268
|
return `${depth}:${node.item.key}`;
|
|
243
269
|
}
|
|
270
|
+
/** The node column 0 renders the children of: `viewRoot` when rebased, else `root`. */
|
|
271
|
+
get #displayRoot() {
|
|
272
|
+
return this.viewRoot ?? this.root;
|
|
273
|
+
}
|
|
244
274
|
#getTickledDepth() {
|
|
245
275
|
const id = this.tickled.tickledId;
|
|
246
276
|
if (!id) return void 0;
|
|
@@ -249,16 +279,20 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
249
279
|
return Number(id.substring(0, colonIndex));
|
|
250
280
|
}
|
|
251
281
|
updated(changedProps) {
|
|
282
|
+
if (changedProps.has(`searchModes`)) this.#syncSearchCommands();
|
|
252
283
|
if (changedProps.has(`root`) && this.root) {
|
|
253
284
|
this.#abortPending();
|
|
254
|
-
this.
|
|
285
|
+
if (this.viewRoot !== void 0) this.viewRoot = void 0;
|
|
255
286
|
this._selectedByDepth.clear();
|
|
256
287
|
this._selectedKeys = /* @__PURE__ */ new Set();
|
|
257
288
|
this._selectedNodes.clear();
|
|
258
289
|
this.#lastSelectedNode = void 0;
|
|
259
290
|
this.#anchor = void 0;
|
|
260
291
|
this.tickled.clearTickled();
|
|
292
|
+
const display = this.#displayRoot;
|
|
293
|
+
this._columns = display?.children ? [display.children] : [];
|
|
261
294
|
}
|
|
295
|
+
if (changedProps.has(`viewRoot`)) this.#applyViewRoot();
|
|
262
296
|
if (changedProps.has(`model`)) {
|
|
263
297
|
this.#modelUnsubscribe?.();
|
|
264
298
|
this.#modelUnsubscribe = void 0;
|
|
@@ -300,10 +334,18 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
300
334
|
});
|
|
301
335
|
}
|
|
302
336
|
}
|
|
337
|
+
connectedCallback() {
|
|
338
|
+
super.connectedCallback();
|
|
339
|
+
this.#searchRegistry ??= createCommandRegistry();
|
|
340
|
+
this.#syncSearchCommands();
|
|
341
|
+
}
|
|
303
342
|
disconnectedCallback() {
|
|
304
343
|
super.disconnectedCallback();
|
|
305
344
|
this.#modelUnsubscribe?.();
|
|
306
345
|
this.#modelUnsubscribe = void 0;
|
|
346
|
+
this.#unregisterSearchCommands?.();
|
|
347
|
+
this.#unregisterSearchCommands = void 0;
|
|
348
|
+
this.#searchRegistry = void 0;
|
|
307
349
|
}
|
|
308
350
|
getConfig() {
|
|
309
351
|
const columnWidths = {};
|
|
@@ -399,15 +441,17 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
399
441
|
return results;
|
|
400
442
|
}
|
|
401
443
|
/**
|
|
402
|
-
* Programmatically navigate to a node by key path
|
|
444
|
+
* Programmatically navigate to a node by key path, relative to the current
|
|
445
|
+
* view root (rebased or full tree).
|
|
403
446
|
*/
|
|
404
447
|
navigateTo(keys) {
|
|
405
|
-
|
|
448
|
+
const display = this.#displayRoot;
|
|
449
|
+
if (!display?.children) return false;
|
|
406
450
|
this.#abortPending();
|
|
407
451
|
this._selectedByDepth.clear();
|
|
408
452
|
this.tickled.clearTickled();
|
|
409
|
-
const newColumns = [
|
|
410
|
-
let currentColumn =
|
|
453
|
+
const newColumns = [display.children];
|
|
454
|
+
let currentColumn = display.children;
|
|
411
455
|
let success = true;
|
|
412
456
|
let lastNode;
|
|
413
457
|
let lastDepth = 0;
|
|
@@ -442,13 +486,51 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
442
486
|
* Programmatically navigate to the first node (breadth-first) matching a predicate.
|
|
443
487
|
*/
|
|
444
488
|
navigateToNode(predicate) {
|
|
445
|
-
|
|
446
|
-
|
|
489
|
+
const display = this.#displayRoot;
|
|
490
|
+
if (!display?.children) return false;
|
|
491
|
+
const keyPath = this.#findNodePath(display.children, predicate);
|
|
447
492
|
if (!keyPath) return false;
|
|
448
493
|
return this.navigateTo(keyPath);
|
|
449
494
|
}
|
|
495
|
+
/** Open the columns down to `key` and move the cursor to it, without changing the selection (search "navigate" mode). */
|
|
496
|
+
revealKey(key) {
|
|
497
|
+
const display = this.#displayRoot;
|
|
498
|
+
if (!display?.children) return false;
|
|
499
|
+
const path = this.#findNodePath(display.children, (n) => n.item.key === key);
|
|
500
|
+
if (!path) return false;
|
|
501
|
+
const columns = [display.children];
|
|
502
|
+
let current = display.children;
|
|
503
|
+
let lastNode;
|
|
504
|
+
let lastDepth = 0;
|
|
505
|
+
for (let depth = 0; depth < path.length; depth++) {
|
|
506
|
+
const node = current.find((n) => n.item.key === path[depth]);
|
|
507
|
+
if (!node) return false;
|
|
508
|
+
lastNode = node;
|
|
509
|
+
lastDepth = depth;
|
|
510
|
+
if (node.children && node.children.length > 0) {
|
|
511
|
+
columns.push(node.children);
|
|
512
|
+
current = node.children;
|
|
513
|
+
} else break;
|
|
514
|
+
}
|
|
515
|
+
this._columns = columns;
|
|
516
|
+
if (lastNode) this.tickled.setTickled(this.#buildTickledId(lastNode, lastDepth));
|
|
517
|
+
this.requestUpdate();
|
|
518
|
+
this.#scrollNavigatedItemIntoView();
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
/** Replace the selection with `nodes` (search "select" mode). */
|
|
522
|
+
selectMany(nodes) {
|
|
523
|
+
const arr = this.selectionFilter === `none` ? [] : [...nodes];
|
|
524
|
+
const prev = new Set(this._selectedNodes);
|
|
525
|
+
this._selectedNodes = new Set(arr);
|
|
526
|
+
this._selectedKeys = new Set(arr.map((n) => n.item.key));
|
|
527
|
+
this.#lastSelectedNode = arr.at(-1);
|
|
528
|
+
this.#dispatchSelectEvent(prev);
|
|
529
|
+
this.requestUpdate();
|
|
530
|
+
}
|
|
450
531
|
getNodes() {
|
|
451
|
-
|
|
532
|
+
const display = this.#displayRoot;
|
|
533
|
+
if (!display?.children) return [];
|
|
452
534
|
const result = [];
|
|
453
535
|
const visit = (node, depth) => {
|
|
454
536
|
result.push({
|
|
@@ -457,7 +539,7 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
457
539
|
});
|
|
458
540
|
if (node.children) for (const child of node.children) visit(child, depth + 1);
|
|
459
541
|
};
|
|
460
|
-
for (const child of
|
|
542
|
+
for (const child of display.children) visit(child, 0);
|
|
461
543
|
return result;
|
|
462
544
|
}
|
|
463
545
|
#findNodePath(nodes, predicate, prefix = []) {
|
|
@@ -470,6 +552,124 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
470
552
|
}
|
|
471
553
|
}
|
|
472
554
|
}
|
|
555
|
+
/**
|
|
556
|
+
* Re-render the columns for the current `#displayRoot`, clearing selection.
|
|
557
|
+
* Runs on every `viewRoot` change.
|
|
558
|
+
*/
|
|
559
|
+
#applyViewRoot() {
|
|
560
|
+
this.#abortPending();
|
|
561
|
+
const prev = new Set(this._selectedNodes);
|
|
562
|
+
this._selectedByDepth.clear();
|
|
563
|
+
this._selectedKeys = /* @__PURE__ */ new Set();
|
|
564
|
+
this._selectedNodes.clear();
|
|
565
|
+
this.#lastSelectedNode = void 0;
|
|
566
|
+
this.#anchor = void 0;
|
|
567
|
+
this.tickled.clearTickled();
|
|
568
|
+
const display = this.#displayRoot;
|
|
569
|
+
if (display?.children !== void 0) {
|
|
570
|
+
this._columns = display.children ? [display.children] : [];
|
|
571
|
+
this._loadingDepth = void 0;
|
|
572
|
+
} else if (display) {
|
|
573
|
+
this._columns = [];
|
|
574
|
+
this.#loadUnloadedChildren(display, -1, false);
|
|
575
|
+
} else {
|
|
576
|
+
this._columns = [];
|
|
577
|
+
this._loadingDepth = void 0;
|
|
578
|
+
}
|
|
579
|
+
if (prev.size > 0) this.#dispatchSelectEvent(prev);
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Rebase the view to show `target`'s children in column 0 (Finder column-view
|
|
583
|
+
* behavior on double-click), keeping the full tree in `root`.
|
|
584
|
+
*
|
|
585
|
+
* - Pass a `MillerNode` (used as-is) or a key (looked up in the full tree).
|
|
586
|
+
* - Pass `undefined` to restore the full-tree view.
|
|
587
|
+
* - Rebasing to the true root is equivalent to restoring the full view.
|
|
588
|
+
* - Leaves are refused (returns `false`).
|
|
589
|
+
*
|
|
590
|
+
* Selection is cleared; all depths, headers, and key paths are relative to
|
|
591
|
+
* the new view root. Fires a `rebase` event when the view actually changes.
|
|
592
|
+
* Returns `false` when nothing changed (unknown key, leaf, or same view).
|
|
593
|
+
*/
|
|
594
|
+
rebaseTo(target) {
|
|
595
|
+
if (target === void 0) return this.#clearViewRoot();
|
|
596
|
+
const node = typeof target === `string` ? this.#findNodeByKey(target) : target;
|
|
597
|
+
if (!node || node.item.isLeaf === true) return false;
|
|
598
|
+
if (node === this.viewRoot || node.item.key === this.viewRoot?.item.key) return false;
|
|
599
|
+
if (node === this.root || !this.viewRoot && node.item.key === this.root?.item.key) return this.#clearViewRoot();
|
|
600
|
+
this.viewRoot = node;
|
|
601
|
+
this.#dispatchRebaseEvent();
|
|
602
|
+
return true;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Rebase one level up from the current view root (no-op at the full tree).
|
|
606
|
+
* Fires a `rebase` event when the view actually changes.
|
|
607
|
+
*/
|
|
608
|
+
rebaseUp() {
|
|
609
|
+
if (!this.viewRoot) return false;
|
|
610
|
+
const parent = this.#findParentOf(this.viewRoot);
|
|
611
|
+
if (!parent) return false;
|
|
612
|
+
if (parent === this.root) return this.#clearViewRoot();
|
|
613
|
+
this.viewRoot = parent;
|
|
614
|
+
this.#dispatchRebaseEvent();
|
|
615
|
+
return true;
|
|
616
|
+
}
|
|
617
|
+
#clearViewRoot() {
|
|
618
|
+
if (this.viewRoot === void 0) return false;
|
|
619
|
+
this.viewRoot = void 0;
|
|
620
|
+
this.#dispatchRebaseEvent();
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
#dispatchRebaseEvent() {
|
|
624
|
+
const viewRoot = this.viewRoot;
|
|
625
|
+
const detail = {
|
|
626
|
+
viewRoot,
|
|
627
|
+
path: viewRoot ? this.#pathToRoot(viewRoot) : []
|
|
628
|
+
};
|
|
629
|
+
this.dispatchEvent(new CustomEvent(`rebase`, {
|
|
630
|
+
detail,
|
|
631
|
+
bubbles: true,
|
|
632
|
+
composed: true
|
|
633
|
+
}));
|
|
634
|
+
}
|
|
635
|
+
#findNodeByKey(key) {
|
|
636
|
+
if (!this.root) return void 0;
|
|
637
|
+
if (this.root.item.key === key) return this.root;
|
|
638
|
+
return this.#findNodeIn(this.root.children ?? [], key);
|
|
639
|
+
}
|
|
640
|
+
#findNodeIn(nodes, key) {
|
|
641
|
+
for (const node of nodes) {
|
|
642
|
+
if (node.item.key === key) return node;
|
|
643
|
+
if (node.children) {
|
|
644
|
+
const found = this.#findNodeIn(node.children, key);
|
|
645
|
+
if (found) return found;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/** Find the parent of `target` (by reference, falling back to key) in the full tree. */
|
|
650
|
+
#findParentOf(target) {
|
|
651
|
+
if (!this.root || target === this.root) return void 0;
|
|
652
|
+
return this.#findParentIn(this.root, target);
|
|
653
|
+
}
|
|
654
|
+
#findParentIn(node, target) {
|
|
655
|
+
if (!node.children) return void 0;
|
|
656
|
+
for (const child of node.children) {
|
|
657
|
+
if (child === target || child.item.key === target.item.key) return node;
|
|
658
|
+
const found = this.#findParentIn(child, target);
|
|
659
|
+
if (found) return found;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/** Ancestry chain from the true root down to and including `target`. */
|
|
663
|
+
#pathToRoot(target) {
|
|
664
|
+
const chain = [target];
|
|
665
|
+
let current = this.#findParentOf(target);
|
|
666
|
+
while (current) {
|
|
667
|
+
chain.unshift(current);
|
|
668
|
+
if (current === this.root) break;
|
|
669
|
+
current = this.#findParentOf(current);
|
|
670
|
+
}
|
|
671
|
+
return chain;
|
|
672
|
+
}
|
|
473
673
|
renderColumnContent(nodes, depth) {
|
|
474
674
|
console.warn(`ixfx-miller-base: renderColumnContent not overridden. depth=${depth}, nodes=${nodes.length}`);
|
|
475
675
|
return nothing;
|
|
@@ -596,7 +796,7 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
596
796
|
*/
|
|
597
797
|
#buildPath(depth) {
|
|
598
798
|
const path = [];
|
|
599
|
-
if (this
|
|
799
|
+
if (this.#displayRoot) path.push(this.#displayRoot);
|
|
600
800
|
for (let d = 0; d < depth; d++) {
|
|
601
801
|
const sel = this._selectedByDepth.get(d);
|
|
602
802
|
if (sel) path.push(sel);
|
|
@@ -699,57 +899,8 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
699
899
|
this.requestUpdate();
|
|
700
900
|
return;
|
|
701
901
|
}
|
|
702
|
-
if (node.children === void 0)
|
|
703
|
-
|
|
704
|
-
this._loadingDepth = depth + 1;
|
|
705
|
-
this.#pendingNode = node;
|
|
706
|
-
const controller = new AbortController();
|
|
707
|
-
this.#pendingController = controller;
|
|
708
|
-
this.dispatchEvent(new CustomEvent(`expand`, {
|
|
709
|
-
detail: {
|
|
710
|
-
node,
|
|
711
|
-
depth
|
|
712
|
-
},
|
|
713
|
-
bubbles: true,
|
|
714
|
-
composed: true
|
|
715
|
-
}));
|
|
716
|
-
const applyChildren = (children) => {
|
|
717
|
-
if (controller.signal.aborted) return;
|
|
718
|
-
node.children = children;
|
|
719
|
-
this.#pendingNode = void 0;
|
|
720
|
-
this.#pendingController = void 0;
|
|
721
|
-
this._loadingDepth = void 0;
|
|
722
|
-
const cols = this._columns.slice(0, depth + 1);
|
|
723
|
-
if (children.length > 0) cols.push(children);
|
|
724
|
-
this._columns = cols;
|
|
725
|
-
};
|
|
726
|
-
const handleError = (err) => {
|
|
727
|
-
if (err.name !== `AbortError`) console.error(err);
|
|
728
|
-
node.children = [];
|
|
729
|
-
this.#pendingNode = void 0;
|
|
730
|
-
this.#pendingController = void 0;
|
|
731
|
-
this._loadingDepth = void 0;
|
|
732
|
-
this.requestUpdate();
|
|
733
|
-
};
|
|
734
|
-
if (this.model || this.loadChildren) {
|
|
735
|
-
if (this.#expandTimer !== void 0) clearTimeout(this.#expandTimer);
|
|
736
|
-
this.#expandTimer = setTimeout(() => {
|
|
737
|
-
this.#expandTimer = void 0;
|
|
738
|
-
if (this.#pendingNode !== node) return;
|
|
739
|
-
(this.model ? this.model.getChildren(node, depth, controller.signal) : collectDataResult(this.loadChildren({
|
|
740
|
-
node,
|
|
741
|
-
depth
|
|
742
|
-
}, controller.signal), controller.signal)).then((children) => applyChildren([...children])).catch(handleError);
|
|
743
|
-
}, EXPAND_DEBOUNCE_MS);
|
|
744
|
-
} else {
|
|
745
|
-
this._loadingDepth = void 0;
|
|
746
|
-
this.#pendingNode = void 0;
|
|
747
|
-
this.#pendingController = void 0;
|
|
748
|
-
const newColumns = this._columns.slice(0, depth + 1);
|
|
749
|
-
newColumns.push([]);
|
|
750
|
-
this._columns = newColumns;
|
|
751
|
-
}
|
|
752
|
-
} else {
|
|
902
|
+
if (node.children === void 0) this.#loadUnloadedChildren(node, depth, true);
|
|
903
|
+
else {
|
|
753
904
|
const newColumns = this._columns.slice(0, depth + 1);
|
|
754
905
|
newColumns.push(node.children);
|
|
755
906
|
this._columns = newColumns;
|
|
@@ -763,6 +914,68 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
763
914
|
}));
|
|
764
915
|
}
|
|
765
916
|
}
|
|
917
|
+
/**
|
|
918
|
+
* Fetch children for a node whose `children === undefined` and show them as
|
|
919
|
+
* the column after `parentDepth` (with the loading placeholder meanwhile).
|
|
920
|
+
* Shared by branch expansion (`parentDepth` = the branch's column) and view
|
|
921
|
+
* rebasing (`parentDepth` = -1, so the children become column 0).
|
|
922
|
+
*
|
|
923
|
+
* The `depth` reported to `loadChildren`/`model.getChildren` is the node's
|
|
924
|
+
* own depth: its column for expansions, -1 for a view root (it sits above
|
|
925
|
+
* column 0, so loaders computing child depth as `depth + 1` stay correct).
|
|
926
|
+
*/
|
|
927
|
+
#loadUnloadedChildren(node, parentDepth, fireExpandEvent) {
|
|
928
|
+
const nodeDepth = parentDepth + 1;
|
|
929
|
+
this._columns = this._columns.slice(0, nodeDepth);
|
|
930
|
+
this._loadingDepth = nodeDepth;
|
|
931
|
+
this.#pendingNode = node;
|
|
932
|
+
const controller = new AbortController();
|
|
933
|
+
this.#pendingController = controller;
|
|
934
|
+
if (fireExpandEvent) this.dispatchEvent(new CustomEvent(`expand`, {
|
|
935
|
+
detail: {
|
|
936
|
+
node,
|
|
937
|
+
depth: parentDepth
|
|
938
|
+
},
|
|
939
|
+
bubbles: true,
|
|
940
|
+
composed: true
|
|
941
|
+
}));
|
|
942
|
+
const applyChildren = (children) => {
|
|
943
|
+
if (controller.signal.aborted) return;
|
|
944
|
+
node.children = children;
|
|
945
|
+
this.#pendingNode = void 0;
|
|
946
|
+
this.#pendingController = void 0;
|
|
947
|
+
this._loadingDepth = void 0;
|
|
948
|
+
const cols = this._columns.slice(0, nodeDepth);
|
|
949
|
+
if (children.length > 0) cols.push(children);
|
|
950
|
+
this._columns = cols;
|
|
951
|
+
};
|
|
952
|
+
const handleError = (err) => {
|
|
953
|
+
if (err.name !== `AbortError`) console.error(err);
|
|
954
|
+
node.children = [];
|
|
955
|
+
this.#pendingNode = void 0;
|
|
956
|
+
this.#pendingController = void 0;
|
|
957
|
+
this._loadingDepth = void 0;
|
|
958
|
+
this.requestUpdate();
|
|
959
|
+
};
|
|
960
|
+
if (this.model || this.loadChildren) {
|
|
961
|
+
if (this.#expandTimer !== void 0) clearTimeout(this.#expandTimer);
|
|
962
|
+
this.#expandTimer = setTimeout(() => {
|
|
963
|
+
this.#expandTimer = void 0;
|
|
964
|
+
if (this.#pendingNode !== node) return;
|
|
965
|
+
(this.model ? this.model.getChildren(node, nodeDepth - 1, controller.signal) : collectDataResult(this.loadChildren({
|
|
966
|
+
node,
|
|
967
|
+
depth: nodeDepth - 1
|
|
968
|
+
}, controller.signal), controller.signal)).then((children) => applyChildren([...children])).catch(handleError);
|
|
969
|
+
}, EXPAND_DEBOUNCE_MS);
|
|
970
|
+
} else {
|
|
971
|
+
this._loadingDepth = void 0;
|
|
972
|
+
this.#pendingNode = void 0;
|
|
973
|
+
this.#pendingController = void 0;
|
|
974
|
+
const newColumns = this._columns.slice(0, nodeDepth);
|
|
975
|
+
newColumns.push([]);
|
|
976
|
+
this._columns = newColumns;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
766
979
|
#onCheckboxClick(node) {
|
|
767
980
|
const currentlySelected = this._selectedKeys.has(node.item.key);
|
|
768
981
|
if (!!node.children?.length ? this.#allDescendantsSelected(node) : currentlySelected) this.#applyCheckedToggle(node, false);
|
|
@@ -832,7 +1045,7 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
832
1045
|
#onResizeMove;
|
|
833
1046
|
#onResizeEnd;
|
|
834
1047
|
#getColumnHeader(depth) {
|
|
835
|
-
if (depth === 0) return this
|
|
1048
|
+
if (depth === 0) return this.#displayRoot?.item.label ?? ``;
|
|
836
1049
|
const explicit = this._selectedByDepth.get(depth - 1);
|
|
837
1050
|
if (explicit) return explicit.item.label;
|
|
838
1051
|
const prevCol = this._columns[depth - 1];
|
|
@@ -843,9 +1056,11 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
843
1056
|
}
|
|
844
1057
|
return ``;
|
|
845
1058
|
}
|
|
846
|
-
#columnStyle(depth) {
|
|
1059
|
+
#columnStyle(depth, isLast) {
|
|
847
1060
|
const w = this.#columnWidths.get(depth);
|
|
848
|
-
|
|
1061
|
+
if (w !== void 0) return `width:${w}px;flex-grow:0;flex-shrink:0;flex-basis:auto;max-width:none`;
|
|
1062
|
+
if (this.stretchLastColumn && isLast) return `width:max-content;flex-grow:1;flex-shrink:0;flex-basis:auto;min-width:0`;
|
|
1063
|
+
return `width:max-content;flex-grow:0;flex-shrink:0;flex-basis:auto`;
|
|
849
1064
|
}
|
|
850
1065
|
#isFocused(node, depth) {
|
|
851
1066
|
return this.tickled.isTickled(this.#buildTickledId(node, depth));
|
|
@@ -858,8 +1073,9 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
858
1073
|
}
|
|
859
1074
|
#renderLoadingColumn() {
|
|
860
1075
|
const depth = this._loadingDepth;
|
|
1076
|
+
const stretched = this.stretchLastColumn && this.#columnWidths.get(depth) === void 0;
|
|
861
1077
|
return html`
|
|
862
|
-
<div class="column loading-column" style=${this.#columnStyle(depth)}>
|
|
1078
|
+
<div class="column loading-column ${stretched ? `stretch-last` : ``}" style=${this.#columnStyle(depth, true)}>
|
|
863
1079
|
${this.headers ? html`
|
|
864
1080
|
<div class="column-header">${this.#getColumnHeader(depth)}</div>
|
|
865
1081
|
` : nothing}
|
|
@@ -874,8 +1090,10 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
874
1090
|
<div id="container" @keydown=${this.#onKeyDown} tabindex="0">
|
|
875
1091
|
${this._columns.map((nodes, depth) => {
|
|
876
1092
|
const visibleNodes = this.filterPredicate ? nodes.filter((n) => this.filterPredicate(n, depth)) : nodes;
|
|
1093
|
+
const isLast = depth === this._columns.length - 1 && this._loadingDepth === void 0;
|
|
1094
|
+
const stretched = this.stretchLastColumn && isLast && this.#columnWidths.get(depth) === void 0;
|
|
877
1095
|
return html`
|
|
878
|
-
<div class="column" style=${this.#columnStyle(depth)}>
|
|
1096
|
+
<div class="column ${stretched ? `stretch-last` : ``}" style=${this.#columnStyle(depth, isLast)}>
|
|
879
1097
|
${this.headers ? html`
|
|
880
1098
|
<div class="column-header"
|
|
881
1099
|
@click=${() => this.#onHeaderClick(depth)}
|
|
@@ -894,6 +1112,7 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
894
1112
|
})}
|
|
895
1113
|
${this._loadingDepth !== void 0 ? this.#renderLoadingColumn() : nothing}
|
|
896
1114
|
</div>
|
|
1115
|
+
${this.search.renderField()}
|
|
897
1116
|
`;
|
|
898
1117
|
}
|
|
899
1118
|
_getFocusedIndex(depth) {
|
|
@@ -929,6 +1148,7 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
929
1148
|
this.styles = [
|
|
930
1149
|
themeFallbacks,
|
|
931
1150
|
tickledStyles,
|
|
1151
|
+
listSearchStyles,
|
|
932
1152
|
css`
|
|
933
1153
|
:host {
|
|
934
1154
|
--column-bg: var(--surface-3);
|
|
@@ -963,6 +1183,20 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
963
1183
|
background: var(--column-bg);
|
|
964
1184
|
border-right: 1px solid var(--column-separator);
|
|
965
1185
|
flex-shrink: 0;
|
|
1186
|
+
/* Content-sized columns never grow wider than 80% of the available
|
|
1187
|
+
width — pathological labels truncate with ellipsis instead of
|
|
1188
|
+
pushing every other column out of view */
|
|
1189
|
+
max-width: 80%;
|
|
1190
|
+
/* Smoothly animate the last column stretching to fill remaining
|
|
1191
|
+
space and shrinking back to content width when it stops being last */
|
|
1192
|
+
transition: flex-grow var(--transition, 0.2s ease-out);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
.column.stretch-last {
|
|
1196
|
+
min-width: 0;
|
|
1197
|
+
/* Stretching fills remaining space by definition, so it is exempt
|
|
1198
|
+
from the 80% auto-size cap */
|
|
1199
|
+
max-width: none;
|
|
966
1200
|
}
|
|
967
1201
|
|
|
968
1202
|
.column-header {
|
|
@@ -1046,6 +1280,12 @@ let MillerBaseElement = class MillerBaseElement extends LitElement {
|
|
|
1046
1280
|
__decorate([property({ type: Object })], MillerBaseElement.prototype, "root", void 0);
|
|
1047
1281
|
__decorate([property({ attribute: false })], MillerBaseElement.prototype, "model", void 0);
|
|
1048
1282
|
__decorate([property({ type: Boolean })], MillerBaseElement.prototype, "headers", void 0);
|
|
1283
|
+
__decorate([property({
|
|
1284
|
+
type: Boolean,
|
|
1285
|
+
attribute: `stretch-last-column`,
|
|
1286
|
+
reflect: true
|
|
1287
|
+
})], MillerBaseElement.prototype, "stretchLastColumn", void 0);
|
|
1288
|
+
__decorate([property({ attribute: false })], MillerBaseElement.prototype, "viewRoot", void 0);
|
|
1049
1289
|
__decorate([property({ type: String })], MillerBaseElement.prototype, "interactionMode", void 0);
|
|
1050
1290
|
__decorate([property({
|
|
1051
1291
|
reflect: true,
|
|
@@ -1057,6 +1297,11 @@ __decorate([property({
|
|
|
1057
1297
|
})], MillerBaseElement.prototype, "exclusivity", void 0);
|
|
1058
1298
|
__decorate([property({ type: Object })], MillerBaseElement.prototype, "loadChildren", void 0);
|
|
1059
1299
|
__decorate([property({ attribute: false })], MillerBaseElement.prototype, "filterPredicate", void 0);
|
|
1300
|
+
__decorate([property({
|
|
1301
|
+
type: String,
|
|
1302
|
+
attribute: `search-modes`,
|
|
1303
|
+
reflect: true
|
|
1304
|
+
})], MillerBaseElement.prototype, "searchModes", void 0);
|
|
1060
1305
|
__decorate([state()], MillerBaseElement.prototype, "_columns", void 0);
|
|
1061
1306
|
__decorate([state()], MillerBaseElement.prototype, "_loadingDepth", void 0);
|
|
1062
1307
|
__decorate([state()], MillerBaseElement.prototype, "_selectedNodes", void 0);
|
|
@@ -1294,14 +1539,28 @@ var MillerTreeController = class {
|
|
|
1294
1539
|
* Any ancestor `MillerNode`s with unloaded children are populated
|
|
1295
1540
|
* synchronously before calling `element.navigateTo()`.
|
|
1296
1541
|
*
|
|
1542
|
+
* Key paths are relative to the element's current view root: when the view
|
|
1543
|
+
* is rebased, only matches at or below the view root can be reached.
|
|
1544
|
+
*
|
|
1297
1545
|
* Returns `false` if no matching node is found.
|
|
1298
1546
|
*/
|
|
1299
1547
|
navigateToValue(predicate) {
|
|
1300
1548
|
const treePath = this.#findTreePath(this.#root, predicate);
|
|
1301
1549
|
if (!treePath) return false;
|
|
1302
|
-
|
|
1550
|
+
const base = this.#element.viewRoot ?? this.#element.root;
|
|
1551
|
+
if (!base) return false;
|
|
1552
|
+
let startIndex = 1;
|
|
1553
|
+
if (this.#element.viewRoot) {
|
|
1554
|
+
const mappedBase = this.#nodeToTree.get(base);
|
|
1555
|
+
if (!mappedBase) return false;
|
|
1556
|
+
const baseIndex = treePath.indexOf(mappedBase);
|
|
1557
|
+
if (baseIndex < 0) return false;
|
|
1558
|
+
startIndex = baseIndex + 1;
|
|
1559
|
+
if (base.children === void 0) base.children = this.#childrenOf(mappedBase);
|
|
1560
|
+
}
|
|
1561
|
+
let currentColumn = base.children ?? [];
|
|
1303
1562
|
const keys = [];
|
|
1304
|
-
for (let i =
|
|
1563
|
+
for (let i = startIndex; i < treePath.length; i++) {
|
|
1305
1564
|
const treeNode = treePath[i];
|
|
1306
1565
|
const key = this.#options.valueToItem(treeNode.getValue(), treeNode).key;
|
|
1307
1566
|
keys.push(key);
|