@ixfx/components 0.15.4 → 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 (101) hide show
  1. package/bundle/index.d.ts +1223 -48
  2. package/bundle/index.js +875 -700
  3. package/dist/ac-text.d.ts +1 -1
  4. package/dist/{ac-token-Cq7lsYf-.d.ts → ac-token-qEs3FsQv.d.ts} +1 -1
  5. package/dist/ac-token.d.ts +1 -1
  6. package/dist/colour-picker.d.ts +1 -1
  7. package/dist/crumb-navigation-BbqfmkYs.d.ts +147 -0
  8. package/dist/crumb-navigation-YnFVFqrx.js +1290 -0
  9. package/dist/crumbs.d.ts +2 -115
  10. package/dist/crumbs.js +1 -1179
  11. package/dist/{data-grid-CbiubdG2.d.ts → data-grid-CIG2DVip.d.ts} +58 -9
  12. package/dist/{data-grid-Dx3l3dxw.js → data-grid-rMkLX2qo.js} +630 -215
  13. package/dist/data-grid.d.ts +3 -3
  14. package/dist/data-grid.js +1 -1
  15. package/dist/{detail-list-ClkMV0SN.d.ts → detail-list-6iMTNP4N.d.ts} +35 -5
  16. package/dist/{detail-list-q8bs67BM.js → detail-list-C4pDSoI8.js} +218 -7
  17. package/dist/detail-list.d.ts +4 -4
  18. package/dist/detail-list.js +1 -1
  19. package/dist/{flat-list-0xTZdXzh.d.ts → flat-list-JPgQSmLW.d.ts} +28 -5
  20. package/dist/flat-list.d.ts +2 -2
  21. package/dist/flat-list.js +123 -4
  22. package/dist/{grid-list-y6dWJYu3.js → grid-list-CdEkScn-.js} +276 -75
  23. package/dist/{grid-list-BnWJUIBC.d.ts → grid-list-D6n7WH8l.d.ts} +128 -22
  24. package/dist/grid-list.d.ts +3 -3
  25. package/dist/grid-list.js +1 -1
  26. package/dist/{grouped-item-lister-Bhyo-dkH.d.ts → grouped-item-lister-DETte0Dh.d.ts} +1 -1
  27. package/dist/grouped-item-lister.d.ts +1 -1
  28. package/dist/{icon-DR_3rSyZ.d.ts → icon-CDGprSdE.d.ts} +1 -1
  29. package/dist/icons.d.ts +2 -2
  30. package/dist/incr-search.d.ts +1 -1
  31. package/dist/index-9ttcdwlL.d.ts +71 -0
  32. package/dist/{index-BAuqR9El.d.ts → index-Bx0BXPxI.d.ts} +52 -6
  33. package/dist/index-CYRc6Dah.d.ts +475 -0
  34. package/dist/{index-garxxqgV.d.ts → index-CYndvTWH.d.ts} +1 -1
  35. package/dist/{index-BUB5SICW.d.ts → index-CoqtMSd9.d.ts} +1 -1
  36. package/dist/{index-Bz3loIAf.d.ts → index-DN2BWctP.d.ts} +1 -1
  37. package/dist/{index-BPTuCRGb.d.ts → index-Dr80Zdl6.d.ts} +2 -2
  38. package/dist/{index-cnaRPQPp.d.ts → index-DxyyVqzA.d.ts} +2 -2
  39. package/dist/{index-CJ5fshD3.d.ts → index-UvnoZUAo.d.ts} +1 -1
  40. package/dist/index.d.ts +380 -33
  41. package/dist/index.js +2247 -866
  42. package/dist/{labelled-input-base-Dp_9KP0G.d.ts → labelled-input-base-DiTme1JO.d.ts} +1 -1
  43. package/dist/labelled-radial-input.d.ts +2 -2
  44. package/dist/labelled-range-input.d.ts +1 -1
  45. package/dist/labelled-slider-input.d.ts +1 -1
  46. package/dist/list-group-header.d.ts +1 -1
  47. package/dist/{list-native-drag-controller-O2Nruqpi.d.ts → list-native-drag-controller-D_UrXipS.d.ts} +1 -1
  48. package/dist/{list-selection-controller-BeE70lbB.js → list-selection-controller-5L0Nj9tR.js} +87 -2
  49. package/dist/{menu-item-B0zqw2xp.d.ts → menu-item-bF6narIz.d.ts} +1 -1
  50. package/dist/menu.d.ts +2 -2
  51. package/dist/miller-BFRfn0ve.js +2237 -0
  52. package/dist/miller.d.ts +4 -437
  53. package/dist/miller.js +1 -1815
  54. package/dist/panel.d.ts +1 -1
  55. package/dist/pending-BGidHppL.js +91 -0
  56. package/dist/scroll-hover-guard-Cjw6179Q.js +35 -0
  57. package/dist/{split-layout-C5SYbDrq.d.ts → split-layout-CophkNeU.d.ts} +42 -4
  58. package/dist/{split-layout-Deoxy47d.js → split-layout-DTY4PJRp.js} +251 -19
  59. package/dist/split-layout.d.ts +1 -1
  60. package/dist/split-layout.js +1 -1
  61. package/dist/sunburst-tree.d.ts +2 -0
  62. package/dist/sunburst-tree.js +2 -0
  63. package/dist/sunbursttree-list-B_VxOHlo.js +1556 -0
  64. package/dist/sunbursttree-list-D6j5BxVQ.d.ts +303 -0
  65. package/dist/{tab-list-wC0xNz1b.d.ts → tab-list-Df371rqw.d.ts} +1 -1
  66. package/dist/tabs.d.ts +1 -1
  67. package/dist/{titlebar-B5zSTZnF.d.ts → titlebar-Tqu-VvMU.d.ts} +1 -1
  68. package/dist/titlebar.d.ts +1 -1
  69. package/dist/tree-CftHwtEb.js +146 -0
  70. package/dist/{tree-D8VxvR9u.js → tree-Crdpl4nc.js} +275 -47
  71. package/dist/{tree-component-C6UHO-w9.d.ts → tree-component-DgfkxmVY.d.ts} +19 -8
  72. package/dist/tree.d.ts +3 -3
  73. package/dist/tree.js +1 -1
  74. package/dist/types-LU1u0CB8.d.ts +87 -0
  75. package/dist/vertical-list-1V1Vg2O5.js +1993 -0
  76. package/dist/{vertical-list-B8FoU-pU.d.ts → vertical-list-BPDmZx6T.d.ts} +31 -3
  77. package/dist/vertical-list.d.ts +3 -3
  78. package/dist/vertical-list.js +1 -1789
  79. package/dist/view-state-controller-BdyXWUUM.js +305 -0
  80. package/docs-user/README.md +3 -0
  81. package/docs-user/crumbs.md +27 -0
  82. package/docs-user/data-grid.md +77 -5
  83. package/docs-user/detail-list.md +54 -0
  84. package/docs-user/dock.md +54 -12
  85. package/docs-user/flat-list.md +27 -0
  86. package/docs-user/grid-list.md +64 -11
  87. package/docs-user/hyperbolic-tree.md +31 -4
  88. package/docs-user/icicle-tree.md +36 -0
  89. package/docs-user/index.json +17 -2
  90. package/docs-user/llms.txt +3 -0
  91. package/docs-user/miller.md +52 -21
  92. package/docs-user/multicol-list.md +50 -8
  93. package/docs-user/split-layout.md +45 -17
  94. package/docs-user/sunburst-tree.md +223 -0
  95. package/docs-user/tree.md +46 -7
  96. package/docs-user/treemap.md +32 -0
  97. package/docs-user/twosplit-layout.md +22 -0
  98. package/docs-user/user-catalog.md +1 -1
  99. package/docs-user/vertical-list.md +55 -7
  100. package/llms.txt +3 -0
  101. package/package.json +5 -1
@@ -1,3 +1,3 @@
1
- import { B as ListNativeDragStartEvent, F as ListDragPreviewContext, I as ListDragPreviewRenderer, N as ListDragEntry, P as ListDragPreview, R as ListDragSource, z as ListNativeDragStartDetail } from "./tree-component-C6UHO-w9.js";
2
- import { A as DataGridEditorFactory, B as GlobalFormatter, C as BuiltInFormatterName, D as DataGridDataType, E as DataGridColumnMenu, F as DataGridInteractionMode, I as DataGridRowLook, L as DataGridSelectionMode, M as DataGridGetRowKey, N as DataGridGroupBy, O as DataGridEditability, P as DataGridGroupLabel, R as DataGridSortDirection, S as DataGridViewportChangeEvent, T as DataGridColumn, _ as DataGridSelectDetail, a as DataGridColumnReorderDetail, b as DataGridSortEvent, c as DataGridColumnResizeEvent, d as DataGridElement, f as DataGridElementEventMap, g as DataGridRowActivateEvent, h as DataGridRowActivateDetail, i as DataGridCellEditEvent, j as DataGridEditorType, k as DataGridEditorContext, l as DataGridColumnVisibilityDetail, m as DataGridGroupChangeEvent, n as DataGridCellClickEvent, o as DataGridColumnReorderEvent, p as DataGridGroupChangeDetail, r as DataGridCellEditDetail, s as DataGridColumnResizeDetail, t as DataGridCellClickDetail, u as DataGridColumnVisibilityEvent, v as DataGridSelectEvent, w as BuiltInFormatterOptions, x as DataGridViewportChangeDetail, y as DataGridSortDetail, z as DataGridSortState } from "./data-grid-CbiubdG2.js";
3
- export { type BuiltInFormatterName, type BuiltInFormatterOptions, DataGridCellClickDetail, DataGridCellClickEvent, DataGridCellEditDetail, DataGridCellEditEvent, type DataGridColumn, type DataGridColumnMenu, DataGridColumnReorderDetail, DataGridColumnReorderEvent, DataGridColumnResizeDetail, DataGridColumnResizeEvent, DataGridColumnVisibilityDetail, DataGridColumnVisibilityEvent, type DataGridDataType, type DataGridEditability, type DataGridEditorContext, type DataGridEditorFactory, type DataGridEditorType, DataGridElement, DataGridElementEventMap, type DataGridGetRowKey, type DataGridGroupBy, DataGridGroupChangeDetail, DataGridGroupChangeEvent, type DataGridGroupLabel, type DataGridInteractionMode, DataGridRowActivateDetail, DataGridRowActivateEvent, type DataGridRowLook, DataGridSelectDetail, DataGridSelectEvent, type DataGridSelectionMode, DataGridSortDetail, type DataGridSortDirection, DataGridSortEvent, type DataGridSortState, DataGridViewportChangeDetail, DataGridViewportChangeEvent, type GlobalFormatter, type ListDragEntry, type ListDragPreview, type ListDragPreviewContext, type ListDragPreviewRenderer, type ListDragSource, type ListNativeDragStartDetail, type ListNativeDragStartEvent };
1
+ import { B as ListNativeDragStartDetail, F as ListDragPreview, I as ListDragPreviewContext, L as ListDragPreviewRenderer, P as ListDragEntry, V as ListNativeDragStartEvent, z as ListDragSource } from "./tree-component-DgfkxmVY.js";
2
+ import { A as DataGridEditability, B as DataGridSortDirection, C as DataGridColumnViewState, D as DataGridColumn, E as BuiltInFormatterOptions, F as DataGridGroupBy, H as GlobalFormatter, I as DataGridGroupLabel, L as DataGridInteractionMode, M as DataGridEditorFactory, N as DataGridEditorType, O as DataGridColumnMenu, P as DataGridGetRowKey, R as DataGridRowLook, S as DataGridViewportChangeEvent, T as BuiltInFormatterName, V as DataGridSortState, _ as DataGridSelectDetail, a as DataGridColumnReorderDetail, b as DataGridSortEvent, c as DataGridColumnResizeEvent, d as DataGridElement, f as DataGridElementEventMap, g as DataGridRowActivateEvent, h as DataGridRowActivateDetail, i as DataGridCellEditEvent, j as DataGridEditorContext, k as DataGridDataType, l as DataGridColumnVisibilityDetail, m as DataGridGroupChangeEvent, n as DataGridCellClickEvent, o as DataGridColumnReorderEvent, p as DataGridGroupChangeDetail, r as DataGridCellEditDetail, s as DataGridColumnResizeDetail, t as DataGridCellClickDetail, u as DataGridColumnVisibilityEvent, v as DataGridSelectEvent, w as DataGridViewState, x as DataGridViewportChangeDetail, y as DataGridSortDetail, z as DataGridSelectionMode } from "./data-grid-CIG2DVip.js";
3
+ export { type BuiltInFormatterName, type BuiltInFormatterOptions, DataGridCellClickDetail, DataGridCellClickEvent, DataGridCellEditDetail, DataGridCellEditEvent, type DataGridColumn, type DataGridColumnMenu, DataGridColumnReorderDetail, DataGridColumnReorderEvent, DataGridColumnResizeDetail, DataGridColumnResizeEvent, type DataGridColumnViewState, DataGridColumnVisibilityDetail, DataGridColumnVisibilityEvent, type DataGridDataType, type DataGridEditability, type DataGridEditorContext, type DataGridEditorFactory, type DataGridEditorType, DataGridElement, DataGridElementEventMap, type DataGridGetRowKey, type DataGridGroupBy, DataGridGroupChangeDetail, DataGridGroupChangeEvent, type DataGridGroupLabel, type DataGridInteractionMode, DataGridRowActivateDetail, DataGridRowActivateEvent, type DataGridRowLook, DataGridSelectDetail, DataGridSelectEvent, type DataGridSelectionMode, DataGridSortDetail, type DataGridSortDirection, DataGridSortEvent, type DataGridSortState, type DataGridViewState, DataGridViewportChangeDetail, DataGridViewportChangeEvent, type GlobalFormatter, type ListDragEntry, type ListDragPreview, type ListDragPreviewContext, type ListDragPreviewRenderer, type ListDragSource, type ListNativeDragStartDetail, type ListNativeDragStartEvent };
package/dist/data-grid.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as DataGridElement } from "./data-grid-Dx3l3dxw.js";
1
+ import { t as DataGridElement } from "./data-grid-rMkLX2qo.js";
2
2
  export { DataGridElement };
@@ -1,14 +1,31 @@
1
- import "./icon-DR_3rSyZ.js";
1
+ import "./icon-CDGprSdE.js";
2
2
  import { r as IDataProvider } from "./data-provider-BAn_-oR1.js";
3
- import { B as ListNativeDragStartEvent, I as ListDragPreviewRenderer, L as ListDragPreviewSourceResolver } from "./tree-component-C6UHO-w9.js";
3
+ import { L as ListDragPreviewRenderer, R as ListDragPreviewSourceResolver, V as ListNativeDragStartEvent } from "./tree-component-DgfkxmVY.js";
4
+ import { a as ViewStateBase, s as ViewStateChangeEvent, t as GetViewStateOptions } from "./types-LU1u0CB8.js";
5
+ import "./index-9ttcdwlL.js";
4
6
  import { n as ListViewportChangeEvent } from "./list-viewport-types-BRZsLcvp.js";
5
- import { S as ListSearchController } from "./index-BPTuCRGb.js";
7
+ import { S as ListSearchController } from "./index-Dr80Zdl6.js";
6
8
  import { a as ListGroupEventMap, o as ListGroupInfo, s as ListGroupLabel } from "./grouping-CUKgmkMm.js";
7
9
  import { i as ListInteractionMode, l as ListSelectionMode, r as ListElementEventMap } from "./list-selection-types-PjKdhF-a.js";
8
- import { n as CustomCheckboxOptions, t as AddItemOptions } from "./vertical-list-B8FoU-pU.js";
10
+ import { n as CustomCheckboxOptions, t as AddItemOptions } from "./vertical-list-BPDmZx6T.js";
9
11
  import "./list-group-header.js";
10
12
  import { LitElement, PropertyValues } from "lit";
11
13
  import { CommandId, CommandRegistry } from "@clinth/ui-commands";
14
+ //#region src/detail-list/detail-list-view-state.d.ts
15
+ /**
16
+ * Pure helpers behind `ixfx-detail-list`'s view state (see
17
+ * `docs/infra-view-state.md`). The component keeps only the wiring.
18
+ *
19
+ * - `selected` — selected item keys (in `checked` mode, the checked set:
20
+ * `data-checked` is derived from the selection, not stored separately).
21
+ * - `expanded` — `{ [groupKey]: false }` for collapsed groups. Groups default
22
+ * open, so only collapses are recorded; `true` re-opens.
23
+ * - `focus` — keyboard-cursor key.
24
+ * - `scroll` — horizontal: `left` plus an anchor on the top item of the first
25
+ * visible column.
26
+ */
27
+ type DetailListViewState = ViewStateBase;
28
+ //#endregion
12
29
  //#region src/detail-list/types.d.ts
13
30
  /** Sort direction applied to the item columns. */
14
31
  type DetailSortMode = `none` | `ascending` | `descending`;
@@ -194,6 +211,18 @@ declare class DetailListElement extends LitElement {
194
211
  /** Move the cursor to the item with this key and scroll it into view. */
195
212
  focusKey(key: string): void;
196
213
  selectedFilter(kind: `selected` | `checked` | `either`): Generator<Element>;
214
+ /**
215
+ * Snapshot selection, collapsed groups, cursor and scroll as plain JSON,
216
+ * keyed by item / group key. Includes pending state for keys not present.
217
+ */
218
+ getViewState(options?: GetViewStateOptions<DetailListViewState>): DetailListViewState;
219
+ /**
220
+ * Apply saved view state. Fields present replace the current ones; keys not
221
+ * in the data are applied as matching items arrive (rebuilds, provider
222
+ * batches, `addItem`, light-DOM appends).
223
+ */
224
+ setViewState(state: Partial<DetailListViewState>): void;
225
+ clearPendingViewState(): void;
197
226
  /** Groups in display order (empty when ungrouped). */
198
227
  get groups(): readonly ListGroupInfo[];
199
228
  /** Collapse or expand one group. Fires `list-group-toggle` when the state changes. */
@@ -258,6 +287,7 @@ declare global {
258
287
  interface DetailListElementEventMap extends ListElementEventMap, ListGroupEventMap {
259
288
  'detail-list-viewport-change': ListViewportChangeEvent;
260
289
  'list-native-drag-start': ListNativeDragStartEvent<Element>;
290
+ 'view-state-change': ViewStateChangeEvent<DetailListViewState>;
261
291
  }
262
292
  //#endregion
263
- export { DetailSortComparator as a, DetailGroupBy as i, DetailListElementEventMap as n, DetailSortItem as o, DetailFormatter as r, DetailSortMode as s, DetailListElement as t };
293
+ export { DetailSortComparator as a, DetailListViewState as c, DetailGroupBy as i, DetailListElementEventMap as n, DetailSortItem as o, DetailFormatter as r, DetailSortMode as s, DetailListElement as t };
@@ -6,7 +6,9 @@ import { t as DataController } from "./data-controller-DOlmqNKb.js";
6
6
  import { c as createElementListSearchAdapter, i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, u as keyForElement } from "./incr-search-JIhwB49y.js";
7
7
  import { a as toGroupKey, r as partitionByGroup } from "./grouping-RYPnHkrS.js";
8
8
  import { i as animateListItemOut, r as animateListItemIn, t as ListNativeDragController } from "./list-native-drag-controller-CcXoS0YX.js";
9
- import { r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-BeE70lbB.js";
9
+ import { r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-5L0Nj9tR.js";
10
+ import { a as capKeys, d as partitionKeys, l as keysToArray, o as flagsFromRecord } from "./pending-BGidHppL.js";
11
+ import { a as restoreElementScroll, o as scrollToOffset, r as captureElementScroll, t as ViewStateController } from "./view-state-controller-BdyXWUUM.js";
10
12
  import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
11
13
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-BjcMyauw.js";
12
14
  import "./list-group-header.js";
@@ -130,6 +132,62 @@ function itemsInSpanByOrder(items, origin, start, end) {
130
132
  return items.slice(from, to);
131
133
  }
132
134
  //#endregion
135
+ //#region src/detail-list/detail-list-view-state.ts
136
+ const DETAIL_LIST_VIEW_STATE_KIND = `detail-list`;
137
+ /**
138
+ * Collapsed group keys as an `expanded` record. Collapsed keys whose group
139
+ * isn't currently present are pending; `includePending` decides whether they
140
+ * are written.
141
+ */
142
+ function collapsedToRecord(collapsed, present, includePending) {
143
+ const out = {};
144
+ for (const key of collapsed) if (includePending || present.has(key)) out[key] = false;
145
+ return out;
146
+ }
147
+ /** `expanded` record → collapsed group keys (only `false` entries collapse). */
148
+ function collapsedFromRecord(record) {
149
+ const out = /* @__PURE__ */ new Set();
150
+ for (const [key, open] of flagsFromRecord(record)) if (!open) out.add(key);
151
+ return capKeys(out);
152
+ }
153
+ /**
154
+ * The collapsed keys whose group isn't present (pending) — what survives a
155
+ * `groupBy` change: the user's collapses belong to the old grouping, but
156
+ * restored keys that never matched are still waiting for theirs.
157
+ */
158
+ function pendingCollapsed(collapsed, present) {
159
+ const { missing } = partitionKeys(collapsed, (key) => present.has(key));
160
+ return missing;
161
+ }
162
+ /** Key → element over a slice of items (first wins), for O(slice) pending resolution. */
163
+ function indexByKey(items) {
164
+ const out = /* @__PURE__ */ new Map();
165
+ for (const el of items) {
166
+ const key = keyForElement(el);
167
+ if (key !== void 0 && !out.has(key)) out.set(key, el);
168
+ }
169
+ return out;
170
+ }
171
+ /**
172
+ * Snapshot the horizontal scroll of the column flow. `visible` must be the
173
+ * visible items in DOM (= column) order.
174
+ */
175
+ function captureListScroll(viewport, visible) {
176
+ return captureElementScroll(viewport, visible, keyForElement, `horizontal`);
177
+ }
178
+ /**
179
+ * Apply a saved scroll. With an anchor, `resolve` must return the anchor item
180
+ * only while it is laid out (present and visible); until then this returns
181
+ * `false` so it is retried. Returns `true` once the position was reached.
182
+ */
183
+ function applyListScroll(viewport, scroll, resolve) {
184
+ if (scroll.anchor) {
185
+ const el = resolve(scroll.anchor.key);
186
+ return el === void 0 ? false : restoreElementScroll(viewport, el, scroll.anchor.offset, `horizontal`);
187
+ }
188
+ return scrollToOffset(viewport, scroll.left ?? 0, `horizontal`);
189
+ }
190
+ //#endregion
133
191
  //#region src/detail-list/detail-list.ts
134
192
  const ITEM_SELECTOR = `:scope > li`;
135
193
  const GROUP_HEADER_ATTR = `data-ixfx-group-header`;
@@ -262,6 +320,10 @@ let DetailListElement = class DetailListElement extends LitElement {
262
320
  this.#groupByChanged = false;
263
321
  this.#providerBuilt = 0;
264
322
  this.#data = new DataController(this);
323
+ this.#viewState = new ViewStateController(this, {
324
+ kind: DETAIL_LIST_VIEW_STATE_KIND,
325
+ capture: () => this.getViewState()
326
+ });
265
327
  this.selection = new ListSelectionController({
266
328
  getOrderedItems: () => this._getVisibleItems(),
267
329
  isSelectable: (el) => this._isCheckable(el),
@@ -283,6 +345,7 @@ let DetailListElement = class DetailListElement extends LitElement {
283
345
  previous,
284
346
  selectedKeys: this.selection.selectedKeys
285
347
  });
348
+ this.#viewState.notify();
286
349
  }
287
350
  });
288
351
  this.tickled = new TickledController(this, {
@@ -296,6 +359,8 @@ let DetailListElement = class DetailListElement extends LitElement {
296
359
  },
297
360
  onTickle: (id) => {
298
361
  if (id !== void 0) this._dispatch(`list-tickle`, { item: id });
362
+ if (!this.#viewState.isRestoring) this.#pendingFocus = void 0;
363
+ if (this.tickled.inputMode === `keyboard`) this.#viewState.notify();
299
364
  },
300
365
  onStateChange: () => this._syncItemStates(),
301
366
  itemWrap: this.itemWrap,
@@ -372,6 +437,7 @@ let DetailListElement = class DetailListElement extends LitElement {
372
437
  highlightKey: SEARCH_HIGHLIGHT_KEY
373
438
  }) });
374
439
  this.#onListScroll = () => {
440
+ if (!this.#viewState.pendingScroll) this.#viewState.notify();
375
441
  if (this.#viewportScrollRaf !== 0) return;
376
442
  this.#viewportScrollRaf = requestAnimationFrame(() => {
377
443
  this.#viewportScrollRaf = 0;
@@ -525,6 +591,11 @@ let DetailListElement = class DetailListElement extends LitElement {
525
591
  #groupObserver;
526
592
  #providerBuilt;
527
593
  #data;
594
+ #viewState;
595
+ /** Saved cursor key not (yet) present. Pending selection lives in `selection`. */
596
+ #pendingFocus;
597
+ /** The pending scroll's anchor item, once it exists. */
598
+ #scrollAnchorEl;
528
599
  #nativeDragging;
529
600
  #postDragSuppressTimer;
530
601
  #blankItemPressPending;
@@ -639,6 +710,7 @@ let DetailListElement = class DetailListElement extends LitElement {
639
710
  this.#resizeObserver.observe(this);
640
711
  this.#mutationObserver = new MutationObserver((records) => {
641
712
  this.#processAddedChildren(records);
713
+ this.#reconcileMutations(records);
642
714
  this.#animateChildMutations(records);
643
715
  this.#scheduleGeometry();
644
716
  this.#scheduleGroups();
@@ -662,6 +734,7 @@ let DetailListElement = class DetailListElement extends LitElement {
662
734
  this.#searchRegistry ??= createCommandRegistry();
663
735
  this.#syncSearchCommands();
664
736
  this.#scheduleGroups();
737
+ this.#viewState.observeScrollTarget(this);
665
738
  }
666
739
  /**
667
740
  * Collapse-in items appended to the light DOM (however they got there). A bulk
@@ -726,7 +799,8 @@ let DetailListElement = class DetailListElement extends LitElement {
726
799
  willUpdate(changed) {
727
800
  super.willUpdate(changed);
728
801
  if (changed.has(`groupBy`) && this.hasUpdated) {
729
- if (this._collapsedGroups.size > 0) this._collapsedGroups = /* @__PURE__ */ new Set();
802
+ const keep = pendingCollapsed(this._collapsedGroups, this.#presentGroupKeys());
803
+ if (keep !== this._collapsedGroups) this._collapsedGroups = keep;
730
804
  this.#groupByChanged = true;
731
805
  }
732
806
  }
@@ -799,6 +873,7 @@ let DetailListElement = class DetailListElement extends LitElement {
799
873
  if (this.sort !== `none`) this.#applySort();
800
874
  if (this.interactionMode === `checked`) this._syncCheckboxes();
801
875
  this.#scheduleGroups();
876
+ this.#adoptItems([el]);
802
877
  }
803
878
  /**
804
879
  * Collapse + fade `item` out, then detach it; the rows after it slide up to
@@ -839,6 +914,7 @@ let DetailListElement = class DetailListElement extends LitElement {
839
914
  if (this.sort !== `none`) this.#applySort();
840
915
  if (this.interactionMode === `checked`) this._syncCheckboxes();
841
916
  this.#scheduleGroups();
917
+ this.#adoptItems(items);
842
918
  }
843
919
  /**
844
920
  * Get the source object behind an `<li>` built from an `items` array or
@@ -946,20 +1022,151 @@ let DetailListElement = class DetailListElement extends LitElement {
946
1022
  if (wanted(el)) yield el;
947
1023
  }
948
1024
  }
1025
+ /**
1026
+ * Snapshot selection, collapsed groups, cursor and scroll as plain JSON,
1027
+ * keyed by item / group key. Includes pending state for keys not present.
1028
+ */
1029
+ getViewState(options) {
1030
+ const withPending = options?.includePending ?? true;
1031
+ const focus = this.tickled.inputMode === `keyboard` ? this.tickledKey : void 0;
1032
+ return this.#viewState.shape({
1033
+ selected: keysToArray(this.selection.selectedKeys, withPending ? this.selection.pendingKeys : []),
1034
+ expanded: collapsedToRecord(this._collapsedGroups, this.#presentGroupKeys(), withPending),
1035
+ focus: focus ?? (withPending ? this.#pendingFocus : void 0),
1036
+ scroll: (withPending ? this.#viewState.pendingScroll : void 0) ?? this.#captureScroll()
1037
+ }, options);
1038
+ }
1039
+ /**
1040
+ * Apply saved view state. Fields present replace the current ones; keys not
1041
+ * in the data are applied as matching items arrive (rebuilds, provider
1042
+ * batches, `addItem`, light-DOM appends).
1043
+ */
1044
+ setViewState(state) {
1045
+ if (!this.#viewState.accepts(state)) return;
1046
+ const index = indexByKey(this.#allItems());
1047
+ const resolve = (key) => index.get(key);
1048
+ this.#viewState.restoring(() => {
1049
+ if (state.expanded) this.#restoreCollapsed(collapsedFromRecord(state.expanded));
1050
+ if (state.selected) this.selection.restoreKeys(state.selected, resolve);
1051
+ if (state.focus !== void 0) {
1052
+ this.#pendingFocus = state.focus;
1053
+ this.#resolveFocus(resolve);
1054
+ }
1055
+ if (state.scroll) {
1056
+ this.#viewState.pendingScroll = state.scroll;
1057
+ this.#scrollAnchorEl = state.scroll.anchor ? resolve(state.scroll.anchor.key) : void 0;
1058
+ this.#scheduleGeometry();
1059
+ }
1060
+ this.#viewState.notify();
1061
+ });
1062
+ }
1063
+ clearPendingViewState() {
1064
+ this.selection.clearPending();
1065
+ this.#pendingFocus = void 0;
1066
+ this.#viewState.pendingScroll = void 0;
1067
+ this.#scrollAnchorEl = void 0;
1068
+ const present = this.#presentGroupKeys();
1069
+ if ([...this._collapsedGroups].some((key) => !present.has(key))) this._collapsedGroups = new Set([...this._collapsedGroups].filter((key) => present.has(key)));
1070
+ }
1071
+ /** Group keys currently shown (empty while ungrouped). */
1072
+ #presentGroupKeys() {
1073
+ return new Set(this.#groupList.map((g) => g.key));
1074
+ }
1075
+ /** Replace the collapsed set; fires `list-group-toggle` for present groups that change. */
1076
+ #restoreCollapsed(next) {
1077
+ const prev = this._collapsedGroups;
1078
+ this._collapsedGroups = next;
1079
+ for (const { key } of this.#groupList) if (prev.has(key) !== next.has(key)) this._dispatch(`list-group-toggle`, {
1080
+ groupKey: key,
1081
+ collapsed: next.has(key)
1082
+ });
1083
+ }
1084
+ /**
1085
+ * Apply pending state to items that just arrived. Only `items` is searched,
1086
+ * so a provider batch costs O(batch), not O(list).
1087
+ */
1088
+ #adoptItems(items) {
1089
+ const anchorKey = this.#viewState.pendingScroll?.anchor?.key;
1090
+ if (this.selection.pendingKeys.size === 0 && this.#pendingFocus === void 0 && anchorKey === void 0) return;
1091
+ const index = indexByKey(items);
1092
+ if (index.size === 0) return;
1093
+ const resolve = (key) => index.get(key);
1094
+ this.#viewState.restoring(() => {
1095
+ this.selection.resolvePending(resolve);
1096
+ this.#resolveFocus(resolve);
1097
+ });
1098
+ if (anchorKey !== void 0 && index.has(anchorKey)) this.#scrollAnchorEl = index.get(anchorKey);
1099
+ }
1100
+ /** Light-DOM changes: removed items go pending (silently), added items pick up pending state. */
1101
+ #reconcileMutations(records) {
1102
+ const gone = [];
1103
+ const added = [];
1104
+ const tickled = this.tickled.tickledId;
1105
+ let tickledGone = false;
1106
+ for (const record of records) {
1107
+ for (const node of record.removedNodes) {
1108
+ if (!(node instanceof Element) || node.parentElement === this) continue;
1109
+ if (this.selection.selected.has(node)) gone.push(node);
1110
+ if (node === tickled) tickledGone = true;
1111
+ }
1112
+ for (const node of record.addedNodes) if (node instanceof HTMLLIElement && node.parentElement === this) added.push(node);
1113
+ }
1114
+ if (gone.length > 0 && this.selection.demote(gone)) this._syncItemStates();
1115
+ if (tickledGone && tickled) {
1116
+ const key = keyForElement(tickled);
1117
+ this.#viewState.restoring(() => {
1118
+ if (key !== void 0 && this.tickled.inputMode === `keyboard`) this.#pendingFocus ??= key;
1119
+ this.tickled.setTickled(void 0);
1120
+ });
1121
+ }
1122
+ if (added.length > 0) this.#adoptItems(added);
1123
+ }
1124
+ /** Whether `el` is in the list and laid out (not hidden, filtered or collapsed). */
1125
+ #isLaidOut(el) {
1126
+ return el !== void 0 && el.parentElement === this && this.#isItemVisible(el) && !el.hasAttribute(GROUP_COLLAPSED_ATTR);
1127
+ }
1128
+ #resolveFocus(resolve) {
1129
+ const key = this.#pendingFocus;
1130
+ if (key === void 0) return;
1131
+ const el = resolve(key);
1132
+ if (!this.#isLaidOut(el)) return;
1133
+ this.#pendingFocus = void 0;
1134
+ this.tickled.setInputMode(`keyboard`);
1135
+ this.tickled.setTickled(el);
1136
+ }
1137
+ #captureScroll() {
1138
+ return this._listEl ? captureListScroll(this._listEl, this._getVisibleItems()) : void 0;
1139
+ }
1140
+ /** Try the pending scroll; kept until its anchor is laid out and the columns are wide enough. */
1141
+ #applyPendingScroll() {
1142
+ const viewport = this._listEl;
1143
+ if (!viewport || !this.isConnected || !this.#viewState.pendingScroll) return;
1144
+ this.#viewState.applyPendingScroll((scroll) => applyListScroll(viewport, scroll, () => this.#isLaidOut(this.#scrollAnchorEl) ? this.#scrollAnchorEl : void 0));
1145
+ if (!this.#viewState.pendingScroll) this.#scrollAnchorEl = void 0;
1146
+ }
949
1147
  #rebuildFromObjects(items, reuseRows = false) {
950
1148
  const keyOf = (el) => el.getAttribute(`data-key`) ?? el.getAttribute(`data-search-label`) ?? null;
951
- const previousKeys = new Set([...this.selection.selected].map(keyOf).filter((k) => k !== null));
1149
+ const previous = [...this.selection.selected];
1150
+ const previousKeys = new Set(previous.map(keyOf).filter((k) => k !== null));
952
1151
  const anchorKey = this.selection.anchor ? keyOf(this.selection.anchor) : null;
953
1152
  if (reuseRows) this.#reconcileObjectRows(items);
954
1153
  else this.replaceChildren(...items.map((item, index) => this.#createItemEl(item, index)));
955
- if (previousKeys.size > 0 || anchorKey !== null) {
1154
+ if (previous.length > 0 || anchorKey !== null) {
956
1155
  const next = [];
1156
+ const matched = /* @__PURE__ */ new Set();
957
1157
  let anchor;
958
1158
  for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
959
1159
  const key = keyOf(el);
960
- if (key !== null && previousKeys.has(key)) next.push(el);
1160
+ if (key !== null && previousKeys.has(key)) {
1161
+ next.push(el);
1162
+ matched.add(key);
1163
+ }
961
1164
  if (key !== null && key === anchorKey) anchor = el;
962
1165
  }
1166
+ this.selection.demote(previous.filter((el) => {
1167
+ const key = keyOf(el);
1168
+ return key === null || !matched.has(key);
1169
+ }));
963
1170
  this.selection.seed(next, anchor);
964
1171
  }
965
1172
  if (this.sort !== `none`) this.#applySort();
@@ -967,6 +1174,7 @@ let DetailListElement = class DetailListElement extends LitElement {
967
1174
  this._syncItemStates();
968
1175
  this.#scheduleGeometry();
969
1176
  this.#scheduleGroups();
1177
+ this.#adoptItems(this.#allItems());
970
1178
  }
971
1179
  /**
972
1180
  * Update the rows to match `items`, keeping the `<li>` of every object that
@@ -1038,8 +1246,8 @@ let DetailListElement = class DetailListElement extends LitElement {
1038
1246
  let prefix = 0;
1039
1247
  while (prefix < this.#builtFromProvider.length && prefix < items.length && this.#builtFromProvider[prefix] === items[prefix]) prefix++;
1040
1248
  if (prefix === this.#builtFromProvider.length && prefix <= items.length) {
1041
- const tail = items.slice(prefix);
1042
- for (const item of tail) this.appendChild(this.#createItemEl(item, this.#providerBuilt++));
1249
+ const tail = items.slice(prefix).map((item) => this.#createItemEl(item, this.#providerBuilt++));
1250
+ for (const li of tail) this.appendChild(li);
1043
1251
  if (this.sort !== `none`) {
1044
1252
  cancelAnimationFrame(this.#sortRaf);
1045
1253
  this.#sortRaf = requestAnimationFrame(() => this.#applySort());
@@ -1048,6 +1256,7 @@ let DetailListElement = class DetailListElement extends LitElement {
1048
1256
  this._syncItemStates();
1049
1257
  this.#scheduleGeometry();
1050
1258
  this.#scheduleGroups();
1259
+ this.#adoptItems(tail);
1051
1260
  } else {
1052
1261
  this.#providerBuilt = 0;
1053
1262
  this.#rebuildFromObjects(items);
@@ -1227,6 +1436,7 @@ let DetailListElement = class DetailListElement extends LitElement {
1227
1436
  groupKey,
1228
1437
  collapsed
1229
1438
  });
1439
+ this.#viewState.notify();
1230
1440
  }
1231
1441
  toggleGroup(groupKey) {
1232
1442
  this.setGroupCollapsed(groupKey, !this._collapsedGroups.has(groupKey));
@@ -1255,6 +1465,7 @@ let DetailListElement = class DetailListElement extends LitElement {
1255
1465
  this.#geometryScheduled = true;
1256
1466
  requestAnimationFrame(() => {
1257
1467
  this.#geometryScheduled = false;
1468
+ this.#applyPendingScroll();
1258
1469
  this.#emitViewportChangeIfChanged();
1259
1470
  });
1260
1471
  }
@@ -1,6 +1,6 @@
1
- import { B as ListNativeDragStartEvent, F as ListDragPreviewContext, I as ListDragPreviewRenderer, N as ListDragEntry, P as ListDragPreview, R as ListDragSource, z as ListNativeDragStartDetail } from "./tree-component-C6UHO-w9.js";
1
+ import { B as ListNativeDragStartDetail, F as ListDragPreview, I as ListDragPreviewContext, L as ListDragPreviewRenderer, P as ListDragEntry, V as ListNativeDragStartEvent, z as ListDragSource } from "./tree-component-DgfkxmVY.js";
2
2
  import { n as ListViewportChangeEvent, t as ListViewportChangeDetail } from "./list-viewport-types-BRZsLcvp.js";
3
3
  import { i as ListGroupChangeEvent, l as ListGroupToggleDetail, n as ListGroupBy, o as ListGroupInfo, r as ListGroupChangeDetail, s as ListGroupLabel, u as ListGroupToggleEvent } from "./grouping-CUKgmkMm.js";
4
- import { n as CustomCheckboxOptions, t as AddItemOptions } from "./vertical-list-B8FoU-pU.js";
5
- import { a as DetailSortComparator, i as DetailGroupBy, n as DetailListElementEventMap, o as DetailSortItem, r as DetailFormatter, s as DetailSortMode, t as DetailListElement } from "./detail-list-ClkMV0SN.js";
6
- export { type AddItemOptions, type CustomCheckboxOptions, type DetailFormatter, type DetailGroupBy, DetailListElement, DetailListElementEventMap, type DetailSortComparator, type DetailSortItem, type DetailSortMode, type ListDragEntry, type ListDragPreview, type ListDragPreviewContext, type ListDragPreviewRenderer, type ListDragSource, type ListGroupBy, type ListGroupChangeDetail, type ListGroupChangeEvent, type ListGroupInfo, type ListGroupLabel, type ListGroupToggleDetail, type ListGroupToggleEvent, type ListNativeDragStartDetail, type ListNativeDragStartEvent, type ListViewportChangeDetail, type ListViewportChangeEvent };
4
+ import { a as DetailSortComparator, c as DetailListViewState, i as DetailGroupBy, n as DetailListElementEventMap, o as DetailSortItem, r as DetailFormatter, s as DetailSortMode, t as DetailListElement } from "./detail-list-6iMTNP4N.js";
5
+ import { n as CustomCheckboxOptions, t as AddItemOptions } from "./vertical-list-BPDmZx6T.js";
6
+ export { type AddItemOptions, type CustomCheckboxOptions, type DetailFormatter, type DetailGroupBy, DetailListElement, DetailListElementEventMap, type DetailListViewState, type DetailSortComparator, type DetailSortItem, type DetailSortMode, type ListDragEntry, type ListDragPreview, type ListDragPreviewContext, type ListDragPreviewRenderer, type ListDragSource, type ListGroupBy, type ListGroupChangeDetail, type ListGroupChangeEvent, type ListGroupInfo, type ListGroupLabel, type ListGroupToggleDetail, type ListGroupToggleEvent, type ListNativeDragStartDetail, type ListNativeDragStartEvent, type ListViewportChangeDetail, type ListViewportChangeEvent };
@@ -1,3 +1,3 @@
1
- import { t as DetailListElement } from "./detail-list-q8bs67BM.js";
1
+ import { t as DetailListElement } from "./detail-list-C4pDSoI8.js";
2
2
  import "./list-group-header.js";
3
3
  export { DetailListElement };
@@ -1,9 +1,11 @@
1
- import "./icon-DR_3rSyZ.js";
2
- import { j as TreeDataModel } from "./tree-component-C6UHO-w9.js";
1
+ import "./icon-CDGprSdE.js";
2
+ import { M as TreeDataModel } from "./tree-component-DgfkxmVY.js";
3
3
  import { o as TreeNode, r as TreeFilterPredicate, t as LoadChildrenCallback } from "./types-Jky6oNAp.js";
4
- import "./crumbs.js";
4
+ import { a as ViewStateBase, t as GetViewStateOptions } from "./types-LU1u0CB8.js";
5
+ import "./index-9ttcdwlL.js";
6
+ import "./crumb-navigation-BbqfmkYs.js";
5
7
  import { i as ListInteractionMode, l as ListSelectionMode } from "./list-selection-types-PjKdhF-a.js";
6
- import { r as VerticalListElement } from "./vertical-list-B8FoU-pU.js";
8
+ import { r as VerticalListElement } from "./vertical-list-BPDmZx6T.js";
7
9
  import { LitElement, PropertyValues } from "lit";
8
10
  //#region src/flat-list/types.d.ts
9
11
  /** How branches and leaves are ordered within one level. */
@@ -46,6 +48,15 @@ type FlatListEditCommitDetail = {
46
48
  type FlatListEditCancelDetail = {
47
49
  readonly node: TreeNode;
48
50
  };
51
+ /**
52
+ * `ixfx-flat-list` view state. `selected`, `focus` and `scroll` belong to the
53
+ * level at `path`; they are held until that level is shown, then handed to
54
+ * the inner list.
55
+ */
56
+ type FlatListViewState = ViewStateBase & {
57
+ /** Keys from the root (excluded) to the level shown — the `path` property. */
58
+ readonly path?: readonly string[];
59
+ };
49
60
  type FlatListNavigateEvent = CustomEvent<FlatListNavigateDetail>;
50
61
  type FlatListSelectEvent = CustomEvent<FlatListSelectDetail>;
51
62
  type FlatListActivateEvent = CustomEvent<FlatListActivateDetail>;
@@ -164,6 +175,18 @@ declare class FlatListElement extends LitElement {
164
175
  navigateInto(key: string): boolean;
165
176
  /** Move to the parent level. Returns false at the root. */
166
177
  navigateUp(): boolean;
178
+ /**
179
+ * Snapshot the level shown (`path`) and, from the inner list, its selection,
180
+ * cursor and scroll. Includes a saved level not reached yet.
181
+ */
182
+ getViewState(options?: GetViewStateOptions<FlatListViewState>): FlatListViewState;
183
+ /**
184
+ * Go to a saved level. Keys not loaded yet are reached as they load (the
185
+ * level shown is always loaded); `selected` / `focus` / `scroll` apply once
186
+ * that level is shown.
187
+ */
188
+ setViewState(state: Partial<FlatListViewState>): void;
189
+ clearPendingViewState(): void;
167
190
  disconnectedCallback(): void;
168
191
  protected willUpdate(changed: PropertyValues): void;
169
192
  protected updated(changed: PropertyValues): void;
@@ -180,4 +203,4 @@ interface FlatListElement {
180
203
  addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
181
204
  }
182
205
  //#endregion
183
- export { FlatListSelectEvent as _, FlatListContextMenuDetail as a, FlatListDropEvent as c, FlatListEditCommitDetail as d, FlatListEditCommitEvent as f, FlatListSelectDetail as g, FlatListNavigateEvent as h, FlatListBranchOrder as i, FlatListEditCancelDetail as l, FlatListNavigateDetail as m, FlatListActivateDetail as n, FlatListContextMenuEvent as o, FlatListElementEventMap as p, FlatListActivateEvent as r, FlatListDropDetail as s, FlatListElement as t, FlatListEditCancelEvent as u };
206
+ export { FlatListSelectEvent as _, FlatListContextMenuDetail as a, FlatListDropEvent as c, FlatListEditCommitDetail as d, FlatListEditCommitEvent as f, FlatListSelectDetail as g, FlatListNavigateEvent as h, FlatListBranchOrder as i, FlatListEditCancelDetail as l, FlatListNavigateDetail as m, FlatListActivateDetail as n, FlatListContextMenuEvent as o, FlatListElementEventMap as p, FlatListActivateEvent as r, FlatListDropDetail as s, FlatListElement as t, FlatListEditCancelEvent as u, FlatListViewState as v };
@@ -1,2 +1,2 @@
1
- import { _ as FlatListSelectEvent, a as FlatListContextMenuDetail, c as FlatListDropEvent, d as FlatListEditCommitDetail, f as FlatListEditCommitEvent, g as FlatListSelectDetail, h as FlatListNavigateEvent, i as FlatListBranchOrder, l as FlatListEditCancelDetail, m as FlatListNavigateDetail, n as FlatListActivateDetail, o as FlatListContextMenuEvent, p as FlatListElementEventMap, r as FlatListActivateEvent, s as FlatListDropDetail, t as FlatListElement, u as FlatListEditCancelEvent } from "./flat-list-0xTZdXzh.js";
2
- export { type FlatListActivateDetail, type FlatListActivateEvent, type FlatListBranchOrder, type FlatListContextMenuDetail, type FlatListContextMenuEvent, type FlatListDropDetail, type FlatListDropEvent, type FlatListEditCancelDetail, type FlatListEditCancelEvent, type FlatListEditCommitDetail, type FlatListEditCommitEvent, FlatListElement, type FlatListElementEventMap, type FlatListNavigateDetail, type FlatListNavigateEvent, type FlatListSelectDetail, type FlatListSelectEvent };
1
+ import { _ as FlatListSelectEvent, a as FlatListContextMenuDetail, c as FlatListDropEvent, d as FlatListEditCommitDetail, f as FlatListEditCommitEvent, g as FlatListSelectDetail, h as FlatListNavigateEvent, i as FlatListBranchOrder, l as FlatListEditCancelDetail, m as FlatListNavigateDetail, n as FlatListActivateDetail, o as FlatListContextMenuEvent, p as FlatListElementEventMap, r as FlatListActivateEvent, s as FlatListDropDetail, t as FlatListElement, u as FlatListEditCancelEvent, v as FlatListViewState } from "./flat-list-JPgQSmLW.js";
2
+ export { type FlatListActivateDetail, type FlatListActivateEvent, type FlatListBranchOrder, type FlatListContextMenuDetail, type FlatListContextMenuEvent, type FlatListDropDetail, type FlatListDropEvent, type FlatListEditCancelDetail, type FlatListEditCancelEvent, type FlatListEditCommitDetail, type FlatListEditCommitEvent, FlatListElement, type FlatListElementEventMap, type FlatListNavigateDetail, type FlatListNavigateEvent, type FlatListSelectDetail, type FlatListSelectEvent, type FlatListViewState };