@ixfx/components 0.15.5 → 0.16.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.
Files changed (76) hide show
  1. package/bundle/index.d.ts +917 -44
  2. package/bundle/index.js +702 -696
  3. package/dist/crumb-navigation-BbqfmkYs.d.ts +147 -0
  4. package/dist/crumb-navigation-YnFVFqrx.js +1290 -0
  5. package/dist/crumbs.d.ts +2 -115
  6. package/dist/crumbs.js +1 -1179
  7. package/dist/{data-grid-D7qzmMMp.d.ts → data-grid-CIG2DVip.d.ts} +45 -3
  8. package/dist/{data-grid-C1sZX6n9.js → data-grid-rMkLX2qo.js} +593 -206
  9. package/dist/data-grid.d.ts +3 -3
  10. package/dist/data-grid.js +1 -1
  11. package/dist/{detail-list-CKIKlszv.d.ts → detail-list-6iMTNP4N.d.ts} +34 -4
  12. package/dist/{detail-list-q8bs67BM.js → detail-list-C4pDSoI8.js} +218 -7
  13. package/dist/detail-list.d.ts +4 -4
  14. package/dist/detail-list.js +1 -1
  15. package/dist/{flat-list-DXMyDiSH.d.ts → flat-list-JPgQSmLW.d.ts} +27 -4
  16. package/dist/flat-list.d.ts +2 -2
  17. package/dist/flat-list.js +123 -4
  18. package/dist/{grid-list-y6dWJYu3.js → grid-list-CdEkScn-.js} +276 -75
  19. package/dist/{grid-list-0e7snW6t.d.ts → grid-list-D6n7WH8l.d.ts} +128 -22
  20. package/dist/grid-list.d.ts +3 -3
  21. package/dist/grid-list.js +1 -1
  22. package/dist/incr-search.d.ts +1 -1
  23. package/dist/index-9ttcdwlL.d.ts +71 -0
  24. package/dist/{index-DEVyVIn8.d.ts → index-Bx0BXPxI.d.ts} +52 -6
  25. package/dist/index-CYRc6Dah.d.ts +475 -0
  26. package/dist/{index-KN2MW_xD.d.ts → index-Dr80Zdl6.d.ts} +1 -1
  27. package/dist/index.d.ts +334 -23
  28. package/dist/index.js +2247 -867
  29. package/dist/{list-native-drag-controller-O2Nruqpi.d.ts → list-native-drag-controller-D_UrXipS.d.ts} +1 -1
  30. package/dist/{list-selection-controller-BeE70lbB.js → list-selection-controller-5L0Nj9tR.js} +87 -2
  31. package/dist/miller-BFRfn0ve.js +2237 -0
  32. package/dist/miller.d.ts +4 -437
  33. package/dist/miller.js +1 -1815
  34. package/dist/pending-BGidHppL.js +91 -0
  35. package/dist/scroll-hover-guard-Cjw6179Q.js +35 -0
  36. package/dist/{split-layout-JK3xWVX2.d.ts → split-layout-CophkNeU.d.ts} +41 -3
  37. package/dist/{split-layout-Deoxy47d.js → split-layout-DTY4PJRp.js} +251 -19
  38. package/dist/split-layout.d.ts +1 -1
  39. package/dist/split-layout.js +1 -1
  40. package/dist/sunburst-tree.d.ts +2 -2
  41. package/dist/sunburst-tree.js +1 -1
  42. package/dist/{sunbursttree-list-yXwS-uEI.js → sunbursttree-list-B_VxOHlo.js} +298 -79
  43. package/dist/{sunbursttree-list--Z0uyh8O.d.ts → sunbursttree-list-D6j5BxVQ.d.ts} +40 -3
  44. package/dist/tree-CftHwtEb.js +146 -0
  45. package/dist/{tree-D8VxvR9u.js → tree-Crdpl4nc.js} +275 -47
  46. package/dist/{tree-component-C6UHO-w9.d.ts → tree-component-DgfkxmVY.d.ts} +19 -8
  47. package/dist/tree.d.ts +3 -3
  48. package/dist/tree.js +1 -1
  49. package/dist/types-LU1u0CB8.d.ts +87 -0
  50. package/dist/vertical-list-1V1Vg2O5.js +1993 -0
  51. package/dist/{vertical-list-D8MksoTp.d.ts → vertical-list-BPDmZx6T.d.ts} +31 -3
  52. package/dist/vertical-list.d.ts +3 -3
  53. package/dist/vertical-list.js +1 -1789
  54. package/dist/view-state-controller-BdyXWUUM.js +305 -0
  55. package/docs-user/README.md +2 -0
  56. package/docs-user/crumbs.md +27 -0
  57. package/docs-user/data-grid.md +66 -1
  58. package/docs-user/detail-list.md +54 -0
  59. package/docs-user/dock.md +54 -12
  60. package/docs-user/flat-list.md +27 -0
  61. package/docs-user/grid-list.md +64 -11
  62. package/docs-user/hyperbolic-tree.md +31 -4
  63. package/docs-user/icicle-tree.md +36 -0
  64. package/docs-user/index.json +12 -2
  65. package/docs-user/llms.txt +2 -0
  66. package/docs-user/miller.md +52 -21
  67. package/docs-user/multicol-list.md +50 -8
  68. package/docs-user/split-layout.md +45 -17
  69. package/docs-user/sunburst-tree.md +32 -2
  70. package/docs-user/tree.md +45 -6
  71. package/docs-user/treemap.md +32 -0
  72. package/docs-user/twosplit-layout.md +22 -0
  73. package/docs-user/user-catalog.md +1 -1
  74. package/docs-user/vertical-list.md +55 -7
  75. package/llms.txt +2 -0
  76. package/package.json +1 -1
package/dist/flat-list.js CHANGED
@@ -3,9 +3,10 @@ import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
3
3
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
4
4
  import "./icon-1gpwtPx8.js";
5
5
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
6
- import "./crumbs.js";
6
+ import { t as ViewStateController } from "./view-state-controller-BdyXWUUM.js";
7
+ import { n as resolveKeyPath } from "./crumb-navigation-YnFVFqrx.js";
7
8
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-BjcMyauw.js";
8
- import "./vertical-list.js";
9
+ import "./vertical-list-1V1Vg2O5.js";
9
10
  import { LitElement, css, html, nothing } from "lit";
10
11
  import { property, state } from "lit/decorators.js";
11
12
  //#region src/flat-list/flat-list.ts
@@ -46,6 +47,15 @@ function findKeyPath(root, target) {
46
47
  if (sub) return [child.item.key, ...sub];
47
48
  }
48
49
  }
50
+ function levelState(state) {
51
+ const { selected, focus, scroll } = state;
52
+ if (selected === void 0 && focus === void 0 && scroll === void 0) return void 0;
53
+ return {
54
+ selected,
55
+ focus,
56
+ scroll
57
+ };
58
+ }
49
59
  function orderRows(children, branchOrder, sort) {
50
60
  const rows = children.map((node) => ({
51
61
  key: node.item.key,
@@ -78,6 +88,17 @@ let FlatListElement = class FlatListElement extends LitElement {
78
88
  this.#lastPath = [];
79
89
  this.#selected = /* @__PURE__ */ new Set();
80
90
  this.#direction = `jump`;
91
+ this.#viewState = new ViewStateController(this, {
92
+ kind: `flat-list`,
93
+ capture: () => this.getViewState()
94
+ });
95
+ this.#keepFocus = false;
96
+ this.#ownPath = this.path;
97
+ this.#onInnerViewState = (e) => {
98
+ e.stopPropagation();
99
+ const reason = e.detail.reason;
100
+ if (e.target === this.list && reason !== `restore`) this.#viewState.notify(reason);
101
+ };
81
102
  this.#canDropOn = (el, dataTransfer) => {
82
103
  const node = this.#nodeForElement(el);
83
104
  return !!node && (this.canDrop?.(node, dataTransfer) ?? true);
@@ -137,6 +158,11 @@ let FlatListElement = class FlatListElement extends LitElement {
137
158
  }));
138
159
  };
139
160
  this.#onListSelect = (e) => {
161
+ if (!this.#viewState.isRestoring && this.#pendingLevel?.selected) this.#pendingLevel = {
162
+ ...this.#pendingLevel,
163
+ selected: void 0
164
+ };
165
+ this.#viewState.notify();
140
166
  const previous = this.#selected;
141
167
  const nodes = [...e.detail.selectedKeys].map((k) => this.#nodeForKey(k)).filter((n) => n !== void 0);
142
168
  this.#selected = new Set(nodes);
@@ -174,6 +200,7 @@ let FlatListElement = class FlatListElement extends LitElement {
174
200
  if (e.defaultPrevented || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return;
175
201
  const origin = e.composedPath()[0];
176
202
  if (origin instanceof HTMLInputElement || origin instanceof HTMLTextAreaElement) return;
203
+ this.#keepFocus = false;
177
204
  if (e.key === `ArrowRight` || e.key === `ArrowLeft` || e.key === `Backspace`) TickledController.ignoreHoverUntilPointerMoves();
178
205
  if (e.key === `ArrowRight`) {
179
206
  const node = this.#nodeForKey(this.list?.tickledKey);
@@ -232,6 +259,15 @@ let FlatListElement = class FlatListElement extends LitElement {
232
259
  #direction;
233
260
  /** Leaf key to select once the list shows its level (set when a leaf crumb is chosen). */
234
261
  #pendingSelectKey;
262
+ #viewState;
263
+ /** Saved level still being reached (keys not loaded yet). */
264
+ #pendingPath;
265
+ /** Saved `selected` / `focus` / `scroll` for the saved level, handed to the inner list once it is shown. */
266
+ #pendingLevel;
267
+ /** A restored cursor was handed to the inner list: don't park the cursor on the first row. */
268
+ #keepFocus;
269
+ /** The last `path` this component set itself — anything else came from the host. */
270
+ #ownPath;
235
271
  /** The inner list, for registry / search commands and other advanced use. */
236
272
  get list() {
237
273
  return this.renderRoot.querySelector(`ixfx-vertical-list`) ?? void 0;
@@ -287,12 +323,82 @@ let FlatListElement = class FlatListElement extends LitElement {
287
323
  }
288
324
  #setPath(path, direction) {
289
325
  if (sameKeys(path, this.path)) return;
326
+ if (!this.#viewState.isRestoring) {
327
+ this.#pendingPath = void 0;
328
+ this.#pendingLevel = void 0;
329
+ this.#keepFocus = false;
330
+ }
331
+ this.#viewState.notify();
332
+ this.#ownPath = path;
290
333
  this.#lastPath = this.path;
291
334
  this.#direction = direction;
292
335
  this.list?.search.close();
293
336
  this.list?.clearSelection();
294
337
  this.path = path;
295
338
  }
339
+ /**
340
+ * Snapshot the level shown (`path`) and, from the inner list, its selection,
341
+ * cursor and scroll. Includes a saved level not reached yet.
342
+ */
343
+ getViewState(options) {
344
+ const withPending = options?.includePending ?? true;
345
+ const level = (withPending ? this.#pendingLevel : void 0) ?? this.#captureLevel(withPending);
346
+ return this.#viewState.shape({
347
+ path: [...(withPending ? this.#pendingPath : void 0) ?? this.path],
348
+ ...level
349
+ }, options);
350
+ }
351
+ /**
352
+ * Go to a saved level. Keys not loaded yet are reached as they load (the
353
+ * level shown is always loaded); `selected` / `focus` / `scroll` apply once
354
+ * that level is shown.
355
+ */
356
+ setViewState(state) {
357
+ if (!this.#viewState.accepts(state)) return;
358
+ const level = levelState(state);
359
+ if (state.path) this.#pendingPath = [...state.path];
360
+ if (level) this.#pendingLevel = {
361
+ ...this.#pendingLevel,
362
+ ...level
363
+ };
364
+ this.#reconcilePath();
365
+ this.requestUpdate();
366
+ }
367
+ clearPendingViewState() {
368
+ this.#pendingPath = void 0;
369
+ this.#pendingLevel = void 0;
370
+ this.list?.clearPendingViewState();
371
+ }
372
+ /** Show the deepest loaded level of the pending path; loading it brings the next key in. */
373
+ #reconcilePath() {
374
+ const keys = this.#pendingPath;
375
+ const root = this.#root;
376
+ if (!keys || !root) return;
377
+ const r = resolveKeyPath(root, keys);
378
+ if (r.done) this.#pendingPath = void 0;
379
+ const reach = keys.slice(0, r.nodes.length - 1);
380
+ if (!sameKeys(reach, this.path)) this.#viewState.restoring(() => this.#setPath(reach, `jump`));
381
+ }
382
+ /** The inner list's selection / cursor / scroll. */
383
+ #captureLevel(withPending) {
384
+ const inner = this.list?.getViewState({ includePending: withPending });
385
+ return inner && {
386
+ selected: inner.selected,
387
+ focus: inner.focus,
388
+ scroll: inner.scroll
389
+ };
390
+ }
391
+ /** The saved level is shown: give it its selection, cursor and scroll. */
392
+ #handOffLevel() {
393
+ const list = this.list;
394
+ const level = this.#pendingLevel;
395
+ if (!list || !level) return;
396
+ this.#pendingLevel = void 0;
397
+ if (level.focus !== void 0) this.#keepFocus = true;
398
+ this.#viewState.restoring(() => list.setViewState(level));
399
+ }
400
+ /** The inner parts' own view-state events must not pass for this element's. */
401
+ #onInnerViewState;
296
402
  disconnectedCallback() {
297
403
  super.disconnectedCallback();
298
404
  this.#modelUnsubscribe?.();
@@ -312,8 +418,18 @@ let FlatListElement = class FlatListElement extends LitElement {
312
418
  this.#refreshRows(true);
313
419
  });
314
420
  }
421
+ if (changed.has(`path`) && this.path !== this.#ownPath) {
422
+ this.#ownPath = this.path;
423
+ this.#pendingPath = void 0;
424
+ this.#viewState.notify();
425
+ }
315
426
  const valid = resolvePath(this.#root, this.path).length - 1;
316
- if (this.#root && valid < this.path.length) this.path = this.path.slice(0, valid);
427
+ if (this.#root && valid < this.path.length) {
428
+ this.#pendingPath ??= this.path;
429
+ this.#pendingLevel ??= this.#captureLevel(true);
430
+ this.path = this.#ownPath = this.path.slice(0, valid);
431
+ }
432
+ this.#reconcilePath();
317
433
  if ([
318
434
  `root`,
319
435
  `model`,
@@ -325,6 +441,7 @@ let FlatListElement = class FlatListElement extends LitElement {
325
441
  ].some((p) => changed.has(p))) this.#refreshRows(changed.has(`root`) || changed.has(`model`) || changed.has(`loadChildren`));
326
442
  }
327
443
  updated(changed) {
444
+ if (this.#pendingLevel && !this.#pendingPath) this.#handOffLevel();
328
445
  if (changed.has(`path`) && !sameKeys(this.path, this.#lastPath) && this.#root) {
329
446
  const node = this.currentNode;
330
447
  if (node) {
@@ -436,7 +553,7 @@ let FlatListElement = class FlatListElement extends LitElement {
436
553
  this.#pendingSelectKey = void 0;
437
554
  this.#pendingFocusKey = void 0;
438
555
  if (select) list.selectKeys([select]);
439
- if (focusKey !== void 0) list.focusKey(focusKey);
556
+ if (focusKey !== void 0 && !this.#keepFocus) list.focusKey(focusKey);
440
557
  if (hadFocus) list.focus();
441
558
  }
442
559
  /** Two stable formatters, so toggling `validateEdit` rebuilds the rows with or without edit hooks. */
@@ -464,6 +581,7 @@ let FlatListElement = class FlatListElement extends LitElement {
464
581
  ?with-up=${this.withUp}
465
582
  ?hide-root=${this.hideRoot}
466
583
  @select=${this.#onCrumbSelect}
584
+ @view-state-change=${this.#onInnerViewState}
467
585
  ></ixfx-crumb-navigation>
468
586
  <div class="toolbar" part="toolbar" ?hidden=${!this._hasToolbar}>
469
587
  <slot @slotchange=${this.#onToolbarSlotChange}></slot>
@@ -494,6 +612,7 @@ let FlatListElement = class FlatListElement extends LitElement {
494
612
  @list-edit-cancel=${this.#onListEditCancel}
495
613
  @list-select=${this.#onListSelect}
496
614
  @list-activate=${this.#onListActivate}
615
+ @view-state-change=${this.#onInnerViewState}
497
616
  @keydown=${this.#onKeyDown}
498
617
  @focusin=${this.#syncFocusVisible}
499
618
  @focusout=${this.#syncFocusVisible}