@ixfx/components 0.13.1 → 0.13.2

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.
@@ -91,6 +91,7 @@ interface FlatListElementEventMap {
91
91
  * --flat-list-radius: var(--list-radius, var(--radius-s));
92
92
  * --flat-list-crumb-padding: var(--space-xs);
93
93
  * --flat-list-crumb-font-size: var(--text-s);
94
+ * --flat-list-toolbar-gap: var(--space-xs); // between the crumbs and slotted toolbar items
94
95
  * --flat-list-chevron-gap: 0.4em; // space after the branch chevron
95
96
  * --flat-list-marked-bg / --flat-list-marked-bar: the `marked-key` row
96
97
  * --flat-list-empty-text: var(--surface-muted-text);
@@ -137,6 +138,8 @@ declare class FlatListElement extends LitElement {
137
138
  emptyText: string;
138
139
  /** Mirrors the inner list's `:focus-visible`, so the ring can go round the whole component. */
139
140
  private _focusVisible;
141
+ /** Whether anything is slotted into the toolbar; an empty toolbar takes no space. */
142
+ private _hasToolbar;
140
143
  private _rows;
141
144
  private _loading;
142
145
  /** The inner list, for registry / search commands and other advanced use. */
@@ -178,4 +181,4 @@ interface FlatListElement {
178
181
  }
179
182
  //#endregion
180
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 };
181
- //# sourceMappingURL=flat-list-DEDG6epz.d.ts.map
184
+ //# sourceMappingURL=flat-list-Ohxqsy0g.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flat-list-Ohxqsy0g.d.ts","names":[],"sources":["../src/flat-list/types.ts","../src/flat-list/flat-list.ts"],"mappings":";;;;;;;;;KAGY;KAEA;;WAED;;WAEA;;WAEA,MAAM;;WAEN;;KAGC;WACD,UAAU,YAAY;WACtB,cAAc;WACd,UAAU,YAAY;;KAGrB;WACD,MAAM;;KAGL;;WAED,MAAM;WACN,cAAc;;KAGb;;WAED,MAAM;;WAEN,gBAAgB;WAChB;WACA;;KAGC;WACD,MAAM;WACN;;KAGC;WACD,MAAM;;KAGL,wBAAwB,YAAY;KACpC,sBAAsB,YAAY;KAClC,wBAAwB,YAAY;KAEpC,oBAAoB,YAAY;KAChC,2BAA2B,YAAY;KACvC,0BAA0B,YAAY;KACtC,0BAA0B,YAAY;UAEjC;EACf,sBAAsB;EACtB,oBAAoB;EACpB,sBAAsB;EACtB,kBAAkB;EAClB,0BAA0B;EAC1B,yBAAyB;EACzB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCkFd,wBAAwB;;EAEnC,MAAM;EAGN,OAAO;;EAIP;;EAIA,cAAc;EAGd,iBAAiB;;EAIjB,QAAQ,GAAG,UAAU,GAAG;EAGxB,aAAa;EAGb,eAAe;EAGf,iBAAiB;EAGjB;EAGA;EAGA;;EAIA;;;;;EAOA,WAAW,MAAM,UAAU,cAAc;;;;;;EAQzC,gBAAgB,eAAe,MAAM;;EAIrC;;EAIA;;EAIA;EAGA;EAGA;;EAIA;;UAIQ;;UAGS;UAEA;UACA;;MAcb,QAAQ;;MAKR,YAAY;;EAKhB,SAAS,mBAAmB,OAAO;;;;;;;EAUnC,UAAU;;MAQN,eAAe;MAIf,iBAAiB,YAAY;;EAWjC,WAAW;;EASX,aAAa;;EASb;EAqBS;YAQU,WAAW,SAAS;YAyBpB,QAAQ,SAAS;YAySjB,wBAAM;SAuDT,sBAAM;;QAqGhB;YACI;IACR,kBAAkB;;;UAIL;EACf,iBAAiB,gBAAgB,yBAC/B,MAAM,GACN,WAAW,MAAM,iBAAiB,OAAO,wBAAwB,aACjE,oBAAoB;EAEtB,iBACE,cACA,UAAU,oCACV,oBAAoB"}
@@ -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-DEDG6epz.js";
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-Ohxqsy0g.js";
2
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 };
package/dist/flat-list.js CHANGED
@@ -72,6 +72,7 @@ let FlatListElement = class FlatListElement extends LitElement {
72
72
  this.hideRoot = false;
73
73
  this.emptyText = `Empty`;
74
74
  this._focusVisible = false;
75
+ this._hasToolbar = false;
75
76
  this._rows = [];
76
77
  this._loading = false;
77
78
  this.#lastPath = [];
@@ -163,6 +164,9 @@ let FlatListElement = class FlatListElement extends LitElement {
163
164
  composed: true
164
165
  }));
165
166
  };
167
+ this.#onToolbarSlotChange = (e) => {
168
+ this._hasToolbar = e.target.assignedNodes({ flatten: true }).some((n) => n.nodeType === Node.ELEMENT_NODE || !!n.textContent?.trim());
169
+ };
166
170
  this.#syncFocusVisible = () => {
167
171
  this._focusVisible = this.list?.matches(`:focus-visible`) ?? false;
168
172
  };
@@ -405,6 +409,7 @@ let FlatListElement = class FlatListElement extends LitElement {
405
409
  #onListEditCancel;
406
410
  #onListSelect;
407
411
  #onListActivate;
412
+ #onToolbarSlotChange;
408
413
  #syncFocusVisible;
409
414
  #onKeyDown;
410
415
  /** A crumb was chosen (or the Up button used): go to that node, or to its parent and select it if it is a leaf. */
@@ -456,6 +461,9 @@ let FlatListElement = class FlatListElement extends LitElement {
456
461
  ?hide-root=${this.hideRoot}
457
462
  @select=${this.#onCrumbSelect}
458
463
  ></ixfx-crumb-navigation>
464
+ <div class="toolbar" part="toolbar" ?hidden=${!this._hasToolbar}>
465
+ <slot @slotchange=${this.#onToolbarSlotChange}></slot>
466
+ </div>
459
467
  </div>
460
468
  <div class="body">
461
469
  <ixfx-vertical-list
@@ -506,12 +514,31 @@ let FlatListElement = class FlatListElement extends LitElement {
506
514
  }
507
515
 
508
516
  .crumbs {
517
+ display: flex;
518
+ align-items: center;
519
+ gap: var(--flat-list-toolbar-gap, var(--space-xs));
509
520
  flex: none;
510
521
  font-size: var(--flat-list-crumb-font-size, var(--text-s));
511
522
  padding: var(--flat-list-crumb-padding, var(--space-xs));
512
523
  border-bottom: 1px solid var(--flat-list-border, var(--list-border, var(--border)));
513
524
  }
514
525
 
526
+ .crumbs ixfx-crumb-navigation {
527
+ flex: 1 1 0;
528
+ min-width: 0;
529
+ }
530
+
531
+ .toolbar {
532
+ display: flex;
533
+ flex: none;
534
+ align-items: center;
535
+ gap: var(--flat-list-toolbar-gap, var(--space-xs));
536
+ }
537
+
538
+ .toolbar[hidden] {
539
+ display: none;
540
+ }
541
+
515
542
  .body {
516
543
  position: relative;
517
544
  flex: 1 1 auto;
@@ -645,6 +672,7 @@ __decorate([property({
645
672
  reflect: true,
646
673
  attribute: `data-focus-visible`
647
674
  })], FlatListElement.prototype, "_focusVisible", void 0);
675
+ __decorate([state()], FlatListElement.prototype, "_hasToolbar", void 0);
648
676
  __decorate([state()], FlatListElement.prototype, "_rows", void 0);
649
677
  __decorate([state()], FlatListElement.prototype, "_loading", void 0);
650
678
  FlatListElement = __decorate([safeCustomElement(`ixfx-flat-list`)], FlatListElement);
@@ -1 +1 @@
1
- {"version":3,"file":"flat-list.js","names":["#nodeForElement","#nodeForKey","#selected","#root","#setPath","#pendingSelectKey","#settleList","#renderRow","#onChevronClick","#pendingFocusKey","#lastPath","#direction","#modelUnsubscribe","#loadController","#loadingNode","#refreshRows","#applyMarked","#load","#applyRows","#onCrumbSelect","#renderEditableRow","#renderPlainRow","#renderIcon","#renderBadge","#canDropOn","#validateEditKey","#onListDragOver","#onListDrop","#onListContextMenu","#onListEditCommit","#onListEditCancel","#onListSelect","#onListActivate","#onKeyDown","#syncFocusVisible","customElement"],"sources":["../src/flat-list/flat-list.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\nimport type { PropertyValues } from 'lit';\nimport type { TreeDataModel } from '../common/tree-data-model.js';\nimport type { LoadChildrenCallback, TreeFilterPredicate, TreeNode } from '../common/types.js';\nimport type { ListInteractionMode, ListSelectDetail, ListSelectionMode } from '../interaction/list-selection-types.js';\nimport type { ListContextMenuDetail, ListDropDetail, ListEditCancelDetail, ListEditCommitDetail } from '../vertical-list/types.js';\nimport type { VerticalListElement } from '../vertical-list/vertical-list.js';\nimport type {\n FlatListActivateDetail,\n FlatListBranchOrder,\n FlatListContextMenuDetail,\n FlatListDropDetail,\n FlatListEditCancelDetail,\n FlatListEditCommitDetail,\n FlatListElementEventMap,\n FlatListNavigateDetail,\n FlatListSelectDetail,\n} from './types.js';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { collectDataResult } from '../common/data-provider.js';\nimport { appearanceAbsent, appearanceColor } from '../common/item-appearance.js';\nimport { TickledController } from '../interaction/tickled-controller.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport '../crumbs/crumb-navigation.js';\nimport '../icons/icon.js';\nimport '../vertical-list/vertical-list.js';\n\nexport type {\n FlatListActivateDetail,\n FlatListActivateEvent,\n FlatListBranchOrder,\n FlatListContextMenuDetail,\n FlatListContextMenuEvent,\n FlatListDropDetail,\n FlatListDropEvent,\n FlatListEditCancelDetail,\n FlatListEditCancelEvent,\n FlatListEditCommitDetail,\n FlatListEditCommitEvent,\n FlatListElementEventMap,\n FlatListNavigateDetail,\n FlatListNavigateEvent,\n FlatListSelectDetail,\n FlatListSelectEvent,\n} from './types.js';\n\n/** One row handed to the inner list: the node plus its (cached) branch-ness. */\ntype FlatRow = {\n readonly key: string;\n readonly node: TreeNode;\n readonly branch: boolean;\n};\n\n/**\n * A node with children, or whose children are still to be loaded.\n * `isLeaf: false` forces a branch even when `children` is `[]` (an empty\n * folder that can still be entered); `isLeaf: true` forces a leaf.\n */\nfunction isBranch(node: TreeNode): boolean {\n return node.item.isLeaf === false || (node.item.isLeaf !== true && node.children?.length !== 0);\n}\n\nfunction sameKeys(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((k, i) => k === b[i]);\n}\n\nfunction sameNodes(a: readonly FlatRow[], b: readonly FlatRow[]): boolean {\n return a.length === b.length && a.every((row, i) => row.node === b[i]!.node && row.branch === b[i]!.branch);\n}\n\n/**\n * Walk `keys` down from `root`, stopping at the first key that no longer\n * resolves. Returns the nodes visited (root first), so the valid path is\n * `nodes.length - 1` keys long.\n */\nfunction resolvePath(root: TreeNode | undefined, keys: readonly string[]): TreeNode[] {\n if (!root)\n return [];\n const nodes = [root];\n for (const key of keys) {\n const next = nodes.at(-1)!.children?.find(n => n.item.key === key);\n if (!next)\n break;\n nodes.push(next);\n }\n return nodes;\n}\n\n/** Key path (excluding root) to `target`, or `undefined` if it is not in the loaded tree. */\nfunction findKeyPath(root: TreeNode, target: TreeNode): string[] | undefined {\n if (root === target)\n return [];\n for (const child of root.children ?? []) {\n const sub = findKeyPath(child, target);\n if (sub)\n return [child.item.key, ...sub];\n }\n return undefined;\n}\n\nfunction orderRows(\n children: readonly TreeNode[],\n branchOrder: FlatListBranchOrder,\n sort: ((a: TreeNode, b: TreeNode) => number) | undefined,\n): FlatRow[] {\n const rows = children.map(node => ({ key: node.item.key, node, branch: isBranch(node) }));\n const sorted = sort ? [...rows].sort((a, b) => sort(a.node, b.node)) : rows;\n if (branchOrder === `mixed`)\n return sorted;\n // Array.prototype.filter is stable, so the sort/source order holds within each half.\n return [...sorted.filter(r => r.branch), ...sorted.filter(r => !r.branch)];\n}\n\n/**\n * Navigates a tree inside one flat list. Each level shows its branches and\n * leaves together in an `ixfx-vertical-list`; entering a branch swaps the list\n * for that branch's children, and an `ixfx-crumb-navigation` pinned above the\n * scroll area shows the path and jumps back up.\n *\n * Uses the same `TreeNode` / `TreeDataModel` data as `ixfx-crumb-navigation`\n * and `ixfx-tree-list`. As in crumb-navigation, lazily loaded children are\n * written back to `node.children`.\n *\n * Selection and keyboard behaviour is the inner list's. On top of that:\n * double-click / Enter / ArrowRight enter the cursor branch;\n * ArrowLeft / Backspace go up. Selection is cleared on every level change.\n *\n * Events (all bubble, composed)\n * - `flat-list-navigate` `{ path, previousPath, node, direction }`\n * - `flat-list-select` `{ selected: Set<TreeNode>, selectedKeys, previous }`\n * - `flat-list-activate` `{ node }` — a leaf was double-clicked / Enter pressed\n * The inner list's own `list-*` events also cross the shadow boundary.\n *\n * CSS variables (others, e.g. `--list-item-height`, pass through to the list)\n * --flat-list-bg: var(--list-bg, var(--surface-3));\n * --flat-list-text: var(--list-text, var(--surface-3-text));\n * --flat-list-border: var(--list-border, var(--border));\n * --flat-list-radius: var(--list-radius, var(--radius-s));\n * --flat-list-crumb-padding: var(--space-xs);\n * --flat-list-crumb-font-size: var(--text-s);\n * --flat-list-chevron-gap: 0.4em; // space after the branch chevron\n * --flat-list-marked-bg / --flat-list-marked-bar: the `marked-key` row\n * --flat-list-empty-text: var(--surface-muted-text);\n */\n@customElement(`ixfx-flat-list`)\nexport class FlatListElement extends LitElement {\n @property({ attribute: false })\n root: TreeNode | undefined;\n\n @property({ attribute: false })\n model: TreeDataModel | undefined;\n\n /** Keys from the root (excluded) to the level being shown. */\n @property({ attribute: false })\n path: readonly string[] = [];\n\n /** Lazily loads a branch's children when `node.children` is `undefined`. */\n @property({ attribute: false })\n loadChildren: LoadChildrenCallback | undefined;\n\n @property({ attribute: false })\n filterPredicate: TreeFilterPredicate | undefined;\n\n /** Orders nodes within the level (within each half when `branchOrder` is `first`). */\n @property({ attribute: false })\n sort: ((a: TreeNode, b: TreeNode) => number) | undefined;\n\n @property({ type: String, attribute: `branch-order`, reflect: true })\n branchOrder: FlatListBranchOrder = `first`;\n\n @property({ type: String, attribute: `selection-mode` })\n selectionMode: ListSelectionMode = `single`;\n\n @property({ type: String, attribute: `interaction-mode` })\n interactionMode: ListInteractionMode = `standard`;\n\n @property({ type: String, attribute: `item-wrap` })\n itemWrap: `stop` | `wrap` = `stop`;\n\n @property({ type: String, attribute: `search-modes`, reflect: true })\n searchModes: string | undefined;\n\n @property({ type: Boolean, attribute: `items-draggable`, reflect: true })\n itemsDraggable = false;\n\n /** Rows (and empty space) accept native drops. See `flat-list-drop`. */\n @property({ type: Boolean, attribute: `items-droppable`, reflect: true })\n itemsDroppable = false;\n\n /**\n * Refuse a drop before it is highlighted or reported. `node` is the row under\n * the drag, or the current level's node over empty space.\n */\n @property({ attribute: false })\n canDrop: ((node: TreeNode, dataTransfer: DataTransfer) => boolean) | undefined;\n\n /**\n * Opt in to in-place rename. Called with the typed text and the node when\n * the user commits; return `false` to reject it. Without it nothing can be\n * renamed and rows are plain text. Rows must also have `item.editable`.\n */\n @property({ attribute: false })\n validateEdit: ((value: string, node: TreeNode) => boolean) | undefined;\n\n /** Key of a node to keep visibly marked across level changes (unlike selection). */\n @property({ type: String, attribute: `marked-key`, reflect: true })\n markedKey: string | undefined;\n\n /** Only render the visible rows. Needs `itemHeight`. See `ixfx-vertical-list`. */\n @property({ type: Boolean, reflect: true })\n virtualize = false;\n\n /** Fixed row height in px, required for `virtualize`. */\n @property({ type: Number, attribute: `item-height` })\n itemHeight = 0;\n\n @property({ type: Boolean, attribute: `with-up`, reflect: true })\n withUp = true;\n\n @property({ type: Boolean, attribute: `hide-root`, reflect: true })\n hideRoot = false;\n\n /** Shown when the current level has no children. */\n @property({ type: String, attribute: `empty-text` })\n emptyText = `Empty`;\n\n /** Mirrors the inner list's `:focus-visible`, so the ring can go round the whole component. */\n @property({ type: Boolean, reflect: true, attribute: `data-focus-visible` })\n private _focusVisible = false;\n\n @state() private _rows: readonly FlatRow[] = [];\n @state() private _loading = false;\n\n #modelUnsubscribe: (() => void) | undefined;\n #loadController: AbortController | undefined;\n #loadingNode: TreeNode | undefined;\n #lastPath: readonly string[] = [];\n /** Branch key to put the cursor on after the next rows arrive (set when going up). */\n #pendingFocusKey: string | undefined;\n #selected: ReadonlySet<TreeNode> = new Set();\n #direction: FlatListNavigateDetail[`direction`] = `jump`;\n /** Leaf key to select once the list shows its level (set when a leaf crumb is chosen). */\n #pendingSelectKey: string | undefined;\n\n /** The inner list, for registry / search commands and other advanced use. */\n get list(): VerticalListElement | undefined {\n return this.renderRoot.querySelector(`ixfx-vertical-list`) ?? undefined;\n }\n\n /** Command registry carrying the inner list's `list.search.*` commands. */\n get registry(): VerticalListElement[`registry`] {\n return this.list?.registry;\n }\n\n /** Run a command on the inner list, e.g. `dispatch('list.search.filter')`. */\n dispatch(commandId: string, args?: Record<string, unknown>): void {\n this.list?.dispatch(commandId, args);\n }\n\n /**\n * Rename a row in place. Needs `validateEdit`, and only rows whose\n * `item.editable` is true can be edited. Ends with `flat-list-edit-commit` or `flat-list-edit-cancel`; the\n * label is not rewritten — update the tree in response. Returns false if\n * the row is unknown, not editable, or not on screen.\n */\n beginEdit(key: string): boolean {\n const node = this.#nodeForKey(key);\n if (!this.validateEdit || !node?.item.editable)\n return false;\n return this.list?.beginEdit(key) ?? false;\n }\n\n /** The node whose children are listed. */\n get currentNode(): TreeNode | undefined {\n return resolvePath(this.#root, this.path).at(-1);\n }\n\n get selectedNodes(): ReadonlySet<TreeNode> {\n return this.#selected;\n }\n\n get #root(): TreeNode | undefined {\n return this.model?.root ?? this.root;\n }\n\n // --- Navigation API ---\n\n /** Show the children of the node at this key path. Returns false if the path does not resolve. */\n navigateTo(keys: readonly string[]): boolean {\n const nodes = resolvePath(this.#root, keys);\n if (nodes.length !== keys.length + 1)\n return false;\n this.#setPath(keys, `jump`);\n return true;\n }\n\n /** Enter the child branch with this key. */\n navigateInto(key: string): boolean {\n const node = this.currentNode?.children?.find(n => n.item.key === key);\n if (!node || !isBranch(node))\n return false;\n this.#setPath([...this.path, key], `into`);\n return true;\n }\n\n /** Move to the parent level. Returns false at the root. */\n navigateUp(): boolean {\n if (this.path.length === 0)\n return false;\n this.#pendingFocusKey = this.path.at(-1);\n this.#setPath(this.path.slice(0, -1), `up`);\n return true;\n }\n\n #setPath(path: readonly string[], direction: FlatListNavigateDetail[`direction`]): void {\n if (sameKeys(path, this.path))\n return;\n this.#lastPath = this.path;\n this.#direction = direction;\n // A search over the old level makes no sense on the new one.\n this.list?.search.close();\n this.list?.clearSelection();\n this.path = path;\n }\n\n // --- Lifecycle ---\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n this.#loadController?.abort();\n this.#loadingNode = undefined;\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n if (changed.has(`model`)) {\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = this.model?._subscribe((event) => {\n if (event.type === `invalidate` && event.key === this.currentNode?.item.key) {\n const node = this.currentNode;\n if (node)\n node.children = undefined;\n }\n this.requestUpdate();\n // Model data changed in place; recompute rows even though no property did.\n this.#refreshRows(true);\n });\n }\n\n // Keep `path` valid if the tree changed underneath it.\n const valid = resolvePath(this.#root, this.path).length - 1;\n if (this.#root && valid < this.path.length)\n this.path = this.path.slice(0, valid);\n\n const rowInputs = [`root`, `model`, `path`, `branchOrder`, `sort`, `filterPredicate`, `loadChildren`] as const;\n if (rowInputs.some(p => changed.has(p)))\n this.#refreshRows(changed.has(`root`) || changed.has(`model`) || changed.has(`loadChildren`));\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(`path`) && !sameKeys(this.path, this.#lastPath) && this.#root) {\n const node = this.currentNode;\n if (node) {\n const previousPath = this.#lastPath;\n this.#lastPath = this.path;\n this.dispatchEvent(new CustomEvent<FlatListNavigateDetail>(`flat-list-navigate`, {\n detail: { path: this.path, previousPath, node, direction: this.#direction },\n bubbles: true,\n composed: true,\n }));\n this.#direction = `jump`;\n }\n }\n if (changed.has(`_rows`))\n void this.#settleList();\n if (changed.has(`_rows`) || changed.has(`markedKey`))\n void this.#applyMarked();\n }\n\n /** Recompute the level's rows, loading children first when they are not yet known. */\n #refreshRows(reload: boolean): void {\n const node = this.currentNode;\n if (!node) {\n this._rows = [];\n return;\n }\n if (node.children === undefined && (this.model || this.loadChildren) && (reload || this.#loadingNode !== node)) {\n void this.#load(node);\n return;\n }\n this.#applyRows(node);\n }\n\n #applyRows(node: TreeNode): void {\n const filter = this.filterPredicate;\n const depth = this.path.length;\n const children = (node.children ?? []).filter(c => !filter || filter(c, depth));\n const rows = orderRows(children, this.branchOrder, this.sort);\n if (!sameNodes(rows, this._rows))\n this._rows = rows;\n }\n\n async #load(node: TreeNode): Promise<void> {\n this.#loadController?.abort();\n const controller = new AbortController();\n this.#loadController = controller;\n this.#loadingNode = node;\n this._loading = true;\n this._rows = [];\n try {\n const depth = this.path.length;\n const children = this.model\n ? await this.model.getChildren(node, depth, controller.signal)\n : [...await collectDataResult(this.loadChildren!({ node, depth }, controller.signal), controller.signal)];\n if (controller.signal.aborted)\n return;\n node.children = [...children];\n } catch {\n if (controller.signal.aborted)\n return;\n node.children = [];\n }\n this.#loadingNode = undefined;\n this._loading = false;\n if (node === this.currentNode)\n this.#applyRows(node);\n }\n\n // --- Interaction ---\n\n #nodeForKey(key: string | undefined): TreeNode | undefined {\n return key === undefined ? undefined : this._rows.find(r => r.key === key)?.node;\n }\n\n /** A single click on a branch's chevron enters it, without selecting the row. */\n #onChevronClick(e: Event, node: TreeNode): void {\n e.stopPropagation();\n this.navigateInto(node.item.key);\n }\n\n #nodeForElement(el: Element | undefined): TreeNode | undefined {\n return el ? this.#nodeForKey(el.getAttribute(`data-key`) ?? undefined) : this.currentNode;\n }\n\n #canDropOn = (el: Element | undefined, dataTransfer: DataTransfer): boolean => {\n const node = this.#nodeForElement(el);\n return !!node && (this.canDrop?.(node, dataTransfer) ?? true);\n };\n\n /** Accept every drag that got past `canDrop`; the consumer only hears about the drop. */\n #onListDragOver = (e: CustomEvent<ListDropDetail>): void => {\n if (this.itemsDroppable)\n e.preventDefault();\n };\n\n #onListDrop = (e: CustomEvent<ListDropDetail>): void => {\n const node = this.#nodeForKey(e.detail.key) ?? this.currentNode;\n if (!node)\n return;\n this.dispatchEvent(new CustomEvent<FlatListDropDetail>(`flat-list-drop`, {\n detail: { node, dataTransfer: e.detail.dataTransfer },\n bubbles: true,\n composed: true,\n }));\n };\n\n #onListContextMenu = (e: CustomEvent<ListContextMenuDetail>): void => {\n const node = this.#nodeForKey(e.detail.key);\n if (!node)\n return;\n const nodes = [...e.detail.selectedKeys].map(k => this.#nodeForKey(k)).filter((n): n is TreeNode => n !== undefined);\n const proceed = this.dispatchEvent(new CustomEvent<FlatListContextMenuDetail>(`flat-list-context-menu`, {\n detail: { node, nodes, x: e.detail.x, y: e.detail.y },\n bubbles: true,\n composed: true,\n cancelable: true,\n }));\n if (!proceed)\n e.preventDefault();\n };\n\n #validateEditKey = (value: string, key: string | undefined): boolean => {\n const node = this.#nodeForKey(key);\n return !!node && (this.validateEdit?.(value, node) ?? false);\n };\n\n #onListEditCommit = (e: CustomEvent<ListEditCommitDetail>): void => {\n const node = this.#nodeForKey(e.detail.key);\n if (node) {\n this.dispatchEvent(new CustomEvent<FlatListEditCommitDetail>(`flat-list-edit-commit`, {\n detail: { node, value: e.detail.value },\n bubbles: true,\n composed: true,\n }));\n }\n };\n\n #onListEditCancel = (e: CustomEvent<ListEditCancelDetail>): void => {\n const node = this.#nodeForKey(e.detail.key);\n if (node) {\n this.dispatchEvent(new CustomEvent<FlatListEditCancelDetail>(`flat-list-edit-cancel`, {\n detail: { node },\n bubbles: true,\n composed: true,\n }));\n }\n };\n\n #onListSelect = (e: CustomEvent<ListSelectDetail>): void => {\n const previous = this.#selected;\n const nodes = [...e.detail.selectedKeys]\n .map(k => this.#nodeForKey(k))\n .filter((n): n is TreeNode => n !== undefined);\n this.#selected = new Set(nodes);\n this.dispatchEvent(new CustomEvent<FlatListSelectDetail>(`flat-list-select`, {\n detail: { selected: this.#selected, selectedKeys: e.detail.selectedKeys, previous },\n bubbles: true,\n composed: true,\n }));\n };\n\n #onListActivate = (e: CustomEvent<{ item: Element }>): void => {\n const key = e.detail.item.getAttribute(`data-key`) ?? undefined;\n const node = this.#nodeForKey(key);\n if (!node)\n return;\n if (isBranch(node)) {\n this.navigateInto(node.item.key);\n return;\n }\n this.dispatchEvent(new CustomEvent<FlatListActivateDetail>(`flat-list-activate`, {\n detail: { node },\n bubbles: true,\n composed: true,\n }));\n };\n\n #syncFocusVisible = (): void => {\n this._focusVisible = this.list?.matches(`:focus-visible`) ?? false;\n };\n\n #onKeyDown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey)\n return;\n // Leave the search overlay's text field alone.\n const origin = e.composedPath()[0];\n if (origin instanceof HTMLInputElement || origin instanceof HTMLTextAreaElement)\n return;\n\n if (e.key === `ArrowRight` || e.key === `ArrowLeft` || e.key === `Backspace`) {\n // The level is about to change under a resting pointer; hover must not steal the cursor.\n TickledController.ignoreHoverUntilPointerMoves();\n }\n\n if (e.key === `ArrowRight`) {\n const node = this.#nodeForKey(this.list?.tickledKey);\n if (node && isBranch(node)) {\n e.preventDefault();\n this.navigateInto(node.item.key);\n }\n } else if (e.key === `ArrowLeft` || e.key === `Backspace`) {\n if (this.navigateUp())\n e.preventDefault();\n }\n };\n\n /** A crumb was chosen (or the Up button used): go to that node, or to its parent and select it if it is a leaf. */\n #onCrumbSelect = (e: CustomEvent<{ selected: ReadonlySet<TreeNode> }>): void => {\n e.stopPropagation();\n const target = [...e.detail.selected].at(-1);\n const root = this.#root;\n if (!target || !root)\n return;\n const keys = findKeyPath(root, target);\n if (!keys)\n return;\n if (isBranch(target)) {\n const direction = keys.length < this.path.length && keys.every((k, i) => k === this.path[i]) ? `up` : `jump`;\n this.#setPath(keys, direction);\n } else {\n const levelPath = keys.slice(0, -1);\n const sameLevel = sameKeys(levelPath, this.path);\n this.#setPath(levelPath, `jump`);\n this.#pendingSelectKey = target.item.key;\n // Rows will not change when the leaf is already on this level.\n if (sameLevel)\n void this.#settleList();\n }\n };\n\n /** Flag the marked row. Rows are rebuilt with the level, so this runs after each rebuild. */\n async #applyMarked(): Promise<void> {\n const list = this.list;\n if (!list)\n return;\n await list.updateComplete;\n for (const row of list.querySelectorAll(`li[data-key]`))\n row.toggleAttribute(`data-marked`, row.getAttribute(`data-key`) === this.markedKey);\n }\n\n /** After the inner list has rebuilt, place the cursor / selection / focus. */\n async #settleList(): Promise<void> {\n const list = this.list;\n if (!list)\n return;\n const hadFocus = this.matches(`:focus-within`);\n await list.updateComplete;\n const select = this.#pendingSelectKey;\n const focusKey = this.#pendingFocusKey ?? select ?? this._rows[0]?.key;\n this.#pendingSelectKey = undefined;\n this.#pendingFocusKey = undefined;\n if (select)\n list.selectKeys([select]);\n if (focusKey !== undefined)\n list.focusKey(focusKey);\n if (hadFocus)\n list.focus();\n }\n\n // --- Rendering ---\n\n /** Two stable formatters, so toggling `validateEdit` rebuilds the rows with or without edit hooks. */\n #renderPlainRow = (row: unknown) => this.#renderRow(row, false);\n #renderEditableRow = (row: unknown) => this.#renderRow(row, true);\n\n #renderRow(row: unknown, editingEnabled: boolean) {\n const { node } = row as FlatRow;\n const textColor = appearanceColor(node.item.textColor);\n const editable = editingEnabled && node.item.editable === true;\n return html`<span class=\"label\" data-edit-label=${editable ? `` : nothing} data-edit-value=${editable ? node.item.label : nothing} style=${textColor ? `color:${textColor}` : nothing}>${node.item.label}</span>`;\n }\n\n #renderIcon = (row: unknown) => {\n const { node } = row as FlatRow;\n return node.item.icon ? html`<ixfx-icon name=${node.item.icon}></ixfx-icon>` : undefined;\n };\n\n #renderBadge = (row: unknown) => {\n const { node, branch } = row as FlatRow;\n const badge = appearanceAbsent(node.item.badge) ? nothing : node.item.badge;\n const textColor = appearanceColor(node.item.textColor);\n return html`${badge}${branch\n ? html`<span\n class=\"chevron\"\n aria-hidden=\"true\"\n style=${textColor ? `color:${textColor}` : nothing}\n @pointerdown=${(e: Event) => e.stopPropagation()}\n @click=${(e: Event) => this.#onChevronClick(e, node)}\n >›</span>`\n : nothing}`;\n };\n\n protected override render() {\n const root = this.#root;\n return html`\n <div class=\"crumbs\" part=\"crumbs\">\n <ixfx-crumb-navigation\n .root=${root}\n .selectedNode=${this.currentNode}\n .loadChildren=${this.loadChildren}\n selection-filter=\"all\"\n pad-ending\n leading-caret\n ?with-up=${this.withUp}\n ?hide-root=${this.hideRoot}\n @select=${this.#onCrumbSelect}\n ></ixfx-crumb-navigation>\n </div>\n <div class=\"body\">\n <ixfx-vertical-list\n .items=${this._rows}\n .formatter=${this.validateEdit ? this.#renderEditableRow : this.#renderPlainRow}\n .icon=${this.#renderIcon}\n .iconColor=${(row: unknown) => appearanceColor((row as FlatRow).node.item.iconColor)}\n .badge=${this.#renderBadge}\n key-property=\"key\"\n .selectionMode=${this.selectionMode}\n .interactionMode=${this.interactionMode}\n .itemWrap=${this.itemWrap}\n .searchModes=${this.searchModes}\n ?items-draggable=${this.itemsDraggable}\n ?items-droppable=${this.itemsDroppable}\n .canDrop=${this.#canDropOn}\n .editValidator=${this.#validateEditKey}\n .virtualize=${this.virtualize}\n .itemHeight=${this.itemHeight}\n @list-drag-over=${this.#onListDragOver}\n @list-drop=${this.#onListDrop}\n @list-context-menu=${this.#onListContextMenu}\n @list-edit-commit=${this.#onListEditCommit}\n @list-edit-cancel=${this.#onListEditCancel}\n @list-select=${this.#onListSelect}\n @list-activate=${this.#onListActivate}\n @keydown=${this.#onKeyDown}\n @focusin=${this.#syncFocusVisible}\n @focusout=${this.#syncFocusVisible}\n ></ixfx-vertical-list>\n ${this._rows.length === 0\n ? html`<div class=\"empty\" part=\"empty\">${this._loading ? `Loading…` : this.emptyText}</div>`\n : nothing}\n </div>\n `;\n }\n\n static override styles = [themeFallbacks, css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n overflow: hidden;\n background: var(--flat-list-bg, var(--list-bg, var(--surface-3)));\n color: var(--flat-list-text, var(--list-text, var(--surface-3-text)));\n border: 1px solid var(--flat-list-border, var(--list-border, var(--border)));\n border-radius: var(--flat-list-radius, var(--list-radius, var(--radius-s)));\n }\n\n .crumbs {\n flex: none;\n font-size: var(--flat-list-crumb-font-size, var(--text-s));\n padding: var(--flat-list-crumb-padding, var(--space-xs));\n border-bottom: 1px solid var(--flat-list-border, var(--list-border, var(--border)));\n }\n\n .body {\n position: relative;\n flex: 1 1 auto;\n min-height: 0;\n }\n\n :host([data-focus-visible]) {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n }\n\n ixfx-vertical-list {\n /* The ring is drawn round the whole component instead. */\n outline: none;\n /* Fill .body absolutely: a percentage height does not reliably resolve\n inside a flex item, and an unbounded list never scrolls the cursor into view. */\n position: absolute;\n inset: 0;\n --list-bg: transparent;\n --list-border: none;\n --list-radius: 0;\n }\n\n .empty {\n position: absolute;\n inset: 0;\n display: grid;\n place-items: center;\n pointer-events: none;\n color: var(--flat-list-empty-text, var(--surface-muted-text));\n }\n\n li[data-marked] {\n background: var(--flat-list-marked-bg, color-mix(in srgb, var(--accent) 18%, transparent));\n box-shadow: inset 3px 0 0 var(--flat-list-marked-bar, var(--accent));\n }\n\n .label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* Highlight rule for incremental search: the rows live in this shadow root,\n so the page-level ::highlight() rule cannot reach them. */\n ::highlight(vertical-list-search) {\n background: var(--accent);\n color: var(--accent-text, #fff);\n }\n\n .chevron {\n margin-inline-start: auto;\n padding-inline-start: 0.5em;\n padding-inline-end: var(--flat-list-chevron-gap, 0.4em);\n /* Inherit the row's text colour, so it follows selected / tickled states. */\n color: inherit;\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-flat-list': FlatListElement;\n }\n}\n\nexport interface FlatListElement {\n addEventListener<K extends keyof FlatListElementEventMap>(\n type: K,\n listener: (this: FlatListElement, event: FlatListElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions\n ): void;\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions\n ): void;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flat-list.js","names":["#nodeForElement","#nodeForKey","#selected","#root","#setPath","#pendingSelectKey","#settleList","#renderRow","#onChevronClick","#pendingFocusKey","#lastPath","#direction","#modelUnsubscribe","#loadController","#loadingNode","#refreshRows","#applyMarked","#load","#applyRows","#onCrumbSelect","#onToolbarSlotChange","#renderEditableRow","#renderPlainRow","#renderIcon","#renderBadge","#canDropOn","#validateEditKey","#onListDragOver","#onListDrop","#onListContextMenu","#onListEditCommit","#onListEditCancel","#onListSelect","#onListActivate","#onKeyDown","#syncFocusVisible","customElement"],"sources":["../src/flat-list/flat-list.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\nimport type { PropertyValues } from 'lit';\nimport type { TreeDataModel } from '../common/tree-data-model.js';\nimport type { LoadChildrenCallback, TreeFilterPredicate, TreeNode } from '../common/types.js';\nimport type { ListInteractionMode, ListSelectDetail, ListSelectionMode } from '../interaction/list-selection-types.js';\nimport type { ListContextMenuDetail, ListDropDetail, ListEditCancelDetail, ListEditCommitDetail } from '../vertical-list/types.js';\nimport type { VerticalListElement } from '../vertical-list/vertical-list.js';\nimport type {\n FlatListActivateDetail,\n FlatListBranchOrder,\n FlatListContextMenuDetail,\n FlatListDropDetail,\n FlatListEditCancelDetail,\n FlatListEditCommitDetail,\n FlatListElementEventMap,\n FlatListNavigateDetail,\n FlatListSelectDetail,\n} from './types.js';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { collectDataResult } from '../common/data-provider.js';\nimport { appearanceAbsent, appearanceColor } from '../common/item-appearance.js';\nimport { TickledController } from '../interaction/tickled-controller.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport '../crumbs/crumb-navigation.js';\nimport '../icons/icon.js';\nimport '../vertical-list/vertical-list.js';\n\nexport type {\n FlatListActivateDetail,\n FlatListActivateEvent,\n FlatListBranchOrder,\n FlatListContextMenuDetail,\n FlatListContextMenuEvent,\n FlatListDropDetail,\n FlatListDropEvent,\n FlatListEditCancelDetail,\n FlatListEditCancelEvent,\n FlatListEditCommitDetail,\n FlatListEditCommitEvent,\n FlatListElementEventMap,\n FlatListNavigateDetail,\n FlatListNavigateEvent,\n FlatListSelectDetail,\n FlatListSelectEvent,\n} from './types.js';\n\n/** One row handed to the inner list: the node plus its (cached) branch-ness. */\ntype FlatRow = {\n readonly key: string;\n readonly node: TreeNode;\n readonly branch: boolean;\n};\n\n/**\n * A node with children, or whose children are still to be loaded.\n * `isLeaf: false` forces a branch even when `children` is `[]` (an empty\n * folder that can still be entered); `isLeaf: true` forces a leaf.\n */\nfunction isBranch(node: TreeNode): boolean {\n return node.item.isLeaf === false || (node.item.isLeaf !== true && node.children?.length !== 0);\n}\n\nfunction sameKeys(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((k, i) => k === b[i]);\n}\n\nfunction sameNodes(a: readonly FlatRow[], b: readonly FlatRow[]): boolean {\n return a.length === b.length && a.every((row, i) => row.node === b[i]!.node && row.branch === b[i]!.branch);\n}\n\n/**\n * Walk `keys` down from `root`, stopping at the first key that no longer\n * resolves. Returns the nodes visited (root first), so the valid path is\n * `nodes.length - 1` keys long.\n */\nfunction resolvePath(root: TreeNode | undefined, keys: readonly string[]): TreeNode[] {\n if (!root)\n return [];\n const nodes = [root];\n for (const key of keys) {\n const next = nodes.at(-1)!.children?.find(n => n.item.key === key);\n if (!next)\n break;\n nodes.push(next);\n }\n return nodes;\n}\n\n/** Key path (excluding root) to `target`, or `undefined` if it is not in the loaded tree. */\nfunction findKeyPath(root: TreeNode, target: TreeNode): string[] | undefined {\n if (root === target)\n return [];\n for (const child of root.children ?? []) {\n const sub = findKeyPath(child, target);\n if (sub)\n return [child.item.key, ...sub];\n }\n return undefined;\n}\n\nfunction orderRows(\n children: readonly TreeNode[],\n branchOrder: FlatListBranchOrder,\n sort: ((a: TreeNode, b: TreeNode) => number) | undefined,\n): FlatRow[] {\n const rows = children.map(node => ({ key: node.item.key, node, branch: isBranch(node) }));\n const sorted = sort ? [...rows].sort((a, b) => sort(a.node, b.node)) : rows;\n if (branchOrder === `mixed`)\n return sorted;\n // Array.prototype.filter is stable, so the sort/source order holds within each half.\n return [...sorted.filter(r => r.branch), ...sorted.filter(r => !r.branch)];\n}\n\n/**\n * Navigates a tree inside one flat list. Each level shows its branches and\n * leaves together in an `ixfx-vertical-list`; entering a branch swaps the list\n * for that branch's children, and an `ixfx-crumb-navigation` pinned above the\n * scroll area shows the path and jumps back up.\n *\n * Uses the same `TreeNode` / `TreeDataModel` data as `ixfx-crumb-navigation`\n * and `ixfx-tree-list`. As in crumb-navigation, lazily loaded children are\n * written back to `node.children`.\n *\n * Selection and keyboard behaviour is the inner list's. On top of that:\n * double-click / Enter / ArrowRight enter the cursor branch;\n * ArrowLeft / Backspace go up. Selection is cleared on every level change.\n *\n * Events (all bubble, composed)\n * - `flat-list-navigate` `{ path, previousPath, node, direction }`\n * - `flat-list-select` `{ selected: Set<TreeNode>, selectedKeys, previous }`\n * - `flat-list-activate` `{ node }` — a leaf was double-clicked / Enter pressed\n * The inner list's own `list-*` events also cross the shadow boundary.\n *\n * CSS variables (others, e.g. `--list-item-height`, pass through to the list)\n * --flat-list-bg: var(--list-bg, var(--surface-3));\n * --flat-list-text: var(--list-text, var(--surface-3-text));\n * --flat-list-border: var(--list-border, var(--border));\n * --flat-list-radius: var(--list-radius, var(--radius-s));\n * --flat-list-crumb-padding: var(--space-xs);\n * --flat-list-crumb-font-size: var(--text-s);\n * --flat-list-toolbar-gap: var(--space-xs); // between the crumbs and slotted toolbar items\n * --flat-list-chevron-gap: 0.4em; // space after the branch chevron\n * --flat-list-marked-bg / --flat-list-marked-bar: the `marked-key` row\n * --flat-list-empty-text: var(--surface-muted-text);\n */\n@customElement(`ixfx-flat-list`)\nexport class FlatListElement extends LitElement {\n @property({ attribute: false })\n root: TreeNode | undefined;\n\n @property({ attribute: false })\n model: TreeDataModel | undefined;\n\n /** Keys from the root (excluded) to the level being shown. */\n @property({ attribute: false })\n path: readonly string[] = [];\n\n /** Lazily loads a branch's children when `node.children` is `undefined`. */\n @property({ attribute: false })\n loadChildren: LoadChildrenCallback | undefined;\n\n @property({ attribute: false })\n filterPredicate: TreeFilterPredicate | undefined;\n\n /** Orders nodes within the level (within each half when `branchOrder` is `first`). */\n @property({ attribute: false })\n sort: ((a: TreeNode, b: TreeNode) => number) | undefined;\n\n @property({ type: String, attribute: `branch-order`, reflect: true })\n branchOrder: FlatListBranchOrder = `first`;\n\n @property({ type: String, attribute: `selection-mode` })\n selectionMode: ListSelectionMode = `single`;\n\n @property({ type: String, attribute: `interaction-mode` })\n interactionMode: ListInteractionMode = `standard`;\n\n @property({ type: String, attribute: `item-wrap` })\n itemWrap: `stop` | `wrap` = `stop`;\n\n @property({ type: String, attribute: `search-modes`, reflect: true })\n searchModes: string | undefined;\n\n @property({ type: Boolean, attribute: `items-draggable`, reflect: true })\n itemsDraggable = false;\n\n /** Rows (and empty space) accept native drops. See `flat-list-drop`. */\n @property({ type: Boolean, attribute: `items-droppable`, reflect: true })\n itemsDroppable = false;\n\n /**\n * Refuse a drop before it is highlighted or reported. `node` is the row under\n * the drag, or the current level's node over empty space.\n */\n @property({ attribute: false })\n canDrop: ((node: TreeNode, dataTransfer: DataTransfer) => boolean) | undefined;\n\n /**\n * Opt in to in-place rename. Called with the typed text and the node when\n * the user commits; return `false` to reject it. Without it nothing can be\n * renamed and rows are plain text. Rows must also have `item.editable`.\n */\n @property({ attribute: false })\n validateEdit: ((value: string, node: TreeNode) => boolean) | undefined;\n\n /** Key of a node to keep visibly marked across level changes (unlike selection). */\n @property({ type: String, attribute: `marked-key`, reflect: true })\n markedKey: string | undefined;\n\n /** Only render the visible rows. Needs `itemHeight`. See `ixfx-vertical-list`. */\n @property({ type: Boolean, reflect: true })\n virtualize = false;\n\n /** Fixed row height in px, required for `virtualize`. */\n @property({ type: Number, attribute: `item-height` })\n itemHeight = 0;\n\n @property({ type: Boolean, attribute: `with-up`, reflect: true })\n withUp = true;\n\n @property({ type: Boolean, attribute: `hide-root`, reflect: true })\n hideRoot = false;\n\n /** Shown when the current level has no children. */\n @property({ type: String, attribute: `empty-text` })\n emptyText = `Empty`;\n\n /** Mirrors the inner list's `:focus-visible`, so the ring can go round the whole component. */\n @property({ type: Boolean, reflect: true, attribute: `data-focus-visible` })\n private _focusVisible = false;\n\n /** Whether anything is slotted into the toolbar; an empty toolbar takes no space. */\n @state() private _hasToolbar = false;\n\n @state() private _rows: readonly FlatRow[] = [];\n @state() private _loading = false;\n\n #modelUnsubscribe: (() => void) | undefined;\n #loadController: AbortController | undefined;\n #loadingNode: TreeNode | undefined;\n #lastPath: readonly string[] = [];\n /** Branch key to put the cursor on after the next rows arrive (set when going up). */\n #pendingFocusKey: string | undefined;\n #selected: ReadonlySet<TreeNode> = new Set();\n #direction: FlatListNavigateDetail[`direction`] = `jump`;\n /** Leaf key to select once the list shows its level (set when a leaf crumb is chosen). */\n #pendingSelectKey: string | undefined;\n\n /** The inner list, for registry / search commands and other advanced use. */\n get list(): VerticalListElement | undefined {\n return this.renderRoot.querySelector(`ixfx-vertical-list`) ?? undefined;\n }\n\n /** Command registry carrying the inner list's `list.search.*` commands. */\n get registry(): VerticalListElement[`registry`] {\n return this.list?.registry;\n }\n\n /** Run a command on the inner list, e.g. `dispatch('list.search.filter')`. */\n dispatch(commandId: string, args?: Record<string, unknown>): void {\n this.list?.dispatch(commandId, args);\n }\n\n /**\n * Rename a row in place. Needs `validateEdit`, and only rows whose\n * `item.editable` is true can be edited. Ends with `flat-list-edit-commit` or `flat-list-edit-cancel`; the\n * label is not rewritten — update the tree in response. Returns false if\n * the row is unknown, not editable, or not on screen.\n */\n beginEdit(key: string): boolean {\n const node = this.#nodeForKey(key);\n if (!this.validateEdit || !node?.item.editable)\n return false;\n return this.list?.beginEdit(key) ?? false;\n }\n\n /** The node whose children are listed. */\n get currentNode(): TreeNode | undefined {\n return resolvePath(this.#root, this.path).at(-1);\n }\n\n get selectedNodes(): ReadonlySet<TreeNode> {\n return this.#selected;\n }\n\n get #root(): TreeNode | undefined {\n return this.model?.root ?? this.root;\n }\n\n // --- Navigation API ---\n\n /** Show the children of the node at this key path. Returns false if the path does not resolve. */\n navigateTo(keys: readonly string[]): boolean {\n const nodes = resolvePath(this.#root, keys);\n if (nodes.length !== keys.length + 1)\n return false;\n this.#setPath(keys, `jump`);\n return true;\n }\n\n /** Enter the child branch with this key. */\n navigateInto(key: string): boolean {\n const node = this.currentNode?.children?.find(n => n.item.key === key);\n if (!node || !isBranch(node))\n return false;\n this.#setPath([...this.path, key], `into`);\n return true;\n }\n\n /** Move to the parent level. Returns false at the root. */\n navigateUp(): boolean {\n if (this.path.length === 0)\n return false;\n this.#pendingFocusKey = this.path.at(-1);\n this.#setPath(this.path.slice(0, -1), `up`);\n return true;\n }\n\n #setPath(path: readonly string[], direction: FlatListNavigateDetail[`direction`]): void {\n if (sameKeys(path, this.path))\n return;\n this.#lastPath = this.path;\n this.#direction = direction;\n // A search over the old level makes no sense on the new one.\n this.list?.search.close();\n this.list?.clearSelection();\n this.path = path;\n }\n\n // --- Lifecycle ---\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n this.#loadController?.abort();\n this.#loadingNode = undefined;\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n if (changed.has(`model`)) {\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = this.model?._subscribe((event) => {\n if (event.type === `invalidate` && event.key === this.currentNode?.item.key) {\n const node = this.currentNode;\n if (node)\n node.children = undefined;\n }\n this.requestUpdate();\n // Model data changed in place; recompute rows even though no property did.\n this.#refreshRows(true);\n });\n }\n\n // Keep `path` valid if the tree changed underneath it.\n const valid = resolvePath(this.#root, this.path).length - 1;\n if (this.#root && valid < this.path.length)\n this.path = this.path.slice(0, valid);\n\n const rowInputs = [`root`, `model`, `path`, `branchOrder`, `sort`, `filterPredicate`, `loadChildren`] as const;\n if (rowInputs.some(p => changed.has(p)))\n this.#refreshRows(changed.has(`root`) || changed.has(`model`) || changed.has(`loadChildren`));\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(`path`) && !sameKeys(this.path, this.#lastPath) && this.#root) {\n const node = this.currentNode;\n if (node) {\n const previousPath = this.#lastPath;\n this.#lastPath = this.path;\n this.dispatchEvent(new CustomEvent<FlatListNavigateDetail>(`flat-list-navigate`, {\n detail: { path: this.path, previousPath, node, direction: this.#direction },\n bubbles: true,\n composed: true,\n }));\n this.#direction = `jump`;\n }\n }\n if (changed.has(`_rows`))\n void this.#settleList();\n if (changed.has(`_rows`) || changed.has(`markedKey`))\n void this.#applyMarked();\n }\n\n /** Recompute the level's rows, loading children first when they are not yet known. */\n #refreshRows(reload: boolean): void {\n const node = this.currentNode;\n if (!node) {\n this._rows = [];\n return;\n }\n if (node.children === undefined && (this.model || this.loadChildren) && (reload || this.#loadingNode !== node)) {\n void this.#load(node);\n return;\n }\n this.#applyRows(node);\n }\n\n #applyRows(node: TreeNode): void {\n const filter = this.filterPredicate;\n const depth = this.path.length;\n const children = (node.children ?? []).filter(c => !filter || filter(c, depth));\n const rows = orderRows(children, this.branchOrder, this.sort);\n if (!sameNodes(rows, this._rows))\n this._rows = rows;\n }\n\n async #load(node: TreeNode): Promise<void> {\n this.#loadController?.abort();\n const controller = new AbortController();\n this.#loadController = controller;\n this.#loadingNode = node;\n this._loading = true;\n this._rows = [];\n try {\n const depth = this.path.length;\n const children = this.model\n ? await this.model.getChildren(node, depth, controller.signal)\n : [...await collectDataResult(this.loadChildren!({ node, depth }, controller.signal), controller.signal)];\n if (controller.signal.aborted)\n return;\n node.children = [...children];\n } catch {\n if (controller.signal.aborted)\n return;\n node.children = [];\n }\n this.#loadingNode = undefined;\n this._loading = false;\n if (node === this.currentNode)\n this.#applyRows(node);\n }\n\n // --- Interaction ---\n\n #nodeForKey(key: string | undefined): TreeNode | undefined {\n return key === undefined ? undefined : this._rows.find(r => r.key === key)?.node;\n }\n\n /** A single click on a branch's chevron enters it, without selecting the row. */\n #onChevronClick(e: Event, node: TreeNode): void {\n e.stopPropagation();\n this.navigateInto(node.item.key);\n }\n\n #nodeForElement(el: Element | undefined): TreeNode | undefined {\n return el ? this.#nodeForKey(el.getAttribute(`data-key`) ?? undefined) : this.currentNode;\n }\n\n #canDropOn = (el: Element | undefined, dataTransfer: DataTransfer): boolean => {\n const node = this.#nodeForElement(el);\n return !!node && (this.canDrop?.(node, dataTransfer) ?? true);\n };\n\n /** Accept every drag that got past `canDrop`; the consumer only hears about the drop. */\n #onListDragOver = (e: CustomEvent<ListDropDetail>): void => {\n if (this.itemsDroppable)\n e.preventDefault();\n };\n\n #onListDrop = (e: CustomEvent<ListDropDetail>): void => {\n const node = this.#nodeForKey(e.detail.key) ?? this.currentNode;\n if (!node)\n return;\n this.dispatchEvent(new CustomEvent<FlatListDropDetail>(`flat-list-drop`, {\n detail: { node, dataTransfer: e.detail.dataTransfer },\n bubbles: true,\n composed: true,\n }));\n };\n\n #onListContextMenu = (e: CustomEvent<ListContextMenuDetail>): void => {\n const node = this.#nodeForKey(e.detail.key);\n if (!node)\n return;\n const nodes = [...e.detail.selectedKeys].map(k => this.#nodeForKey(k)).filter((n): n is TreeNode => n !== undefined);\n const proceed = this.dispatchEvent(new CustomEvent<FlatListContextMenuDetail>(`flat-list-context-menu`, {\n detail: { node, nodes, x: e.detail.x, y: e.detail.y },\n bubbles: true,\n composed: true,\n cancelable: true,\n }));\n if (!proceed)\n e.preventDefault();\n };\n\n #validateEditKey = (value: string, key: string | undefined): boolean => {\n const node = this.#nodeForKey(key);\n return !!node && (this.validateEdit?.(value, node) ?? false);\n };\n\n #onListEditCommit = (e: CustomEvent<ListEditCommitDetail>): void => {\n const node = this.#nodeForKey(e.detail.key);\n if (node) {\n this.dispatchEvent(new CustomEvent<FlatListEditCommitDetail>(`flat-list-edit-commit`, {\n detail: { node, value: e.detail.value },\n bubbles: true,\n composed: true,\n }));\n }\n };\n\n #onListEditCancel = (e: CustomEvent<ListEditCancelDetail>): void => {\n const node = this.#nodeForKey(e.detail.key);\n if (node) {\n this.dispatchEvent(new CustomEvent<FlatListEditCancelDetail>(`flat-list-edit-cancel`, {\n detail: { node },\n bubbles: true,\n composed: true,\n }));\n }\n };\n\n #onListSelect = (e: CustomEvent<ListSelectDetail>): void => {\n const previous = this.#selected;\n const nodes = [...e.detail.selectedKeys]\n .map(k => this.#nodeForKey(k))\n .filter((n): n is TreeNode => n !== undefined);\n this.#selected = new Set(nodes);\n this.dispatchEvent(new CustomEvent<FlatListSelectDetail>(`flat-list-select`, {\n detail: { selected: this.#selected, selectedKeys: e.detail.selectedKeys, previous },\n bubbles: true,\n composed: true,\n }));\n };\n\n #onListActivate = (e: CustomEvent<{ item: Element }>): void => {\n const key = e.detail.item.getAttribute(`data-key`) ?? undefined;\n const node = this.#nodeForKey(key);\n if (!node)\n return;\n if (isBranch(node)) {\n this.navigateInto(node.item.key);\n return;\n }\n this.dispatchEvent(new CustomEvent<FlatListActivateDetail>(`flat-list-activate`, {\n detail: { node },\n bubbles: true,\n composed: true,\n }));\n };\n\n #onToolbarSlotChange = (e: Event): void => {\n this._hasToolbar = (e.target as HTMLSlotElement).assignedNodes({ flatten: true }).some(n => n.nodeType === Node.ELEMENT_NODE || !!n.textContent?.trim());\n };\n\n #syncFocusVisible = (): void => {\n this._focusVisible = this.list?.matches(`:focus-visible`) ?? false;\n };\n\n #onKeyDown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey)\n return;\n // Leave the search overlay's text field alone.\n const origin = e.composedPath()[0];\n if (origin instanceof HTMLInputElement || origin instanceof HTMLTextAreaElement)\n return;\n\n if (e.key === `ArrowRight` || e.key === `ArrowLeft` || e.key === `Backspace`) {\n // The level is about to change under a resting pointer; hover must not steal the cursor.\n TickledController.ignoreHoverUntilPointerMoves();\n }\n\n if (e.key === `ArrowRight`) {\n const node = this.#nodeForKey(this.list?.tickledKey);\n if (node && isBranch(node)) {\n e.preventDefault();\n this.navigateInto(node.item.key);\n }\n } else if (e.key === `ArrowLeft` || e.key === `Backspace`) {\n if (this.navigateUp())\n e.preventDefault();\n }\n };\n\n /** A crumb was chosen (or the Up button used): go to that node, or to its parent and select it if it is a leaf. */\n #onCrumbSelect = (e: CustomEvent<{ selected: ReadonlySet<TreeNode> }>): void => {\n e.stopPropagation();\n const target = [...e.detail.selected].at(-1);\n const root = this.#root;\n if (!target || !root)\n return;\n const keys = findKeyPath(root, target);\n if (!keys)\n return;\n if (isBranch(target)) {\n const direction = keys.length < this.path.length && keys.every((k, i) => k === this.path[i]) ? `up` : `jump`;\n this.#setPath(keys, direction);\n } else {\n const levelPath = keys.slice(0, -1);\n const sameLevel = sameKeys(levelPath, this.path);\n this.#setPath(levelPath, `jump`);\n this.#pendingSelectKey = target.item.key;\n // Rows will not change when the leaf is already on this level.\n if (sameLevel)\n void this.#settleList();\n }\n };\n\n /** Flag the marked row. Rows are rebuilt with the level, so this runs after each rebuild. */\n async #applyMarked(): Promise<void> {\n const list = this.list;\n if (!list)\n return;\n await list.updateComplete;\n for (const row of list.querySelectorAll(`li[data-key]`))\n row.toggleAttribute(`data-marked`, row.getAttribute(`data-key`) === this.markedKey);\n }\n\n /** After the inner list has rebuilt, place the cursor / selection / focus. */\n async #settleList(): Promise<void> {\n const list = this.list;\n if (!list)\n return;\n const hadFocus = this.matches(`:focus-within`);\n await list.updateComplete;\n const select = this.#pendingSelectKey;\n const focusKey = this.#pendingFocusKey ?? select ?? this._rows[0]?.key;\n this.#pendingSelectKey = undefined;\n this.#pendingFocusKey = undefined;\n if (select)\n list.selectKeys([select]);\n if (focusKey !== undefined)\n list.focusKey(focusKey);\n if (hadFocus)\n list.focus();\n }\n\n // --- Rendering ---\n\n /** Two stable formatters, so toggling `validateEdit` rebuilds the rows with or without edit hooks. */\n #renderPlainRow = (row: unknown) => this.#renderRow(row, false);\n #renderEditableRow = (row: unknown) => this.#renderRow(row, true);\n\n #renderRow(row: unknown, editingEnabled: boolean) {\n const { node } = row as FlatRow;\n const textColor = appearanceColor(node.item.textColor);\n const editable = editingEnabled && node.item.editable === true;\n return html`<span class=\"label\" data-edit-label=${editable ? `` : nothing} data-edit-value=${editable ? node.item.label : nothing} style=${textColor ? `color:${textColor}` : nothing}>${node.item.label}</span>`;\n }\n\n #renderIcon = (row: unknown) => {\n const { node } = row as FlatRow;\n return node.item.icon ? html`<ixfx-icon name=${node.item.icon}></ixfx-icon>` : undefined;\n };\n\n #renderBadge = (row: unknown) => {\n const { node, branch } = row as FlatRow;\n const badge = appearanceAbsent(node.item.badge) ? nothing : node.item.badge;\n const textColor = appearanceColor(node.item.textColor);\n return html`${badge}${branch\n ? html`<span\n class=\"chevron\"\n aria-hidden=\"true\"\n style=${textColor ? `color:${textColor}` : nothing}\n @pointerdown=${(e: Event) => e.stopPropagation()}\n @click=${(e: Event) => this.#onChevronClick(e, node)}\n >›</span>`\n : nothing}`;\n };\n\n protected override render() {\n const root = this.#root;\n return html`\n <div class=\"crumbs\" part=\"crumbs\">\n <ixfx-crumb-navigation\n .root=${root}\n .selectedNode=${this.currentNode}\n .loadChildren=${this.loadChildren}\n selection-filter=\"all\"\n pad-ending\n leading-caret\n ?with-up=${this.withUp}\n ?hide-root=${this.hideRoot}\n @select=${this.#onCrumbSelect}\n ></ixfx-crumb-navigation>\n <div class=\"toolbar\" part=\"toolbar\" ?hidden=${!this._hasToolbar}>\n <slot @slotchange=${this.#onToolbarSlotChange}></slot>\n </div>\n </div>\n <div class=\"body\">\n <ixfx-vertical-list\n .items=${this._rows}\n .formatter=${this.validateEdit ? this.#renderEditableRow : this.#renderPlainRow}\n .icon=${this.#renderIcon}\n .iconColor=${(row: unknown) => appearanceColor((row as FlatRow).node.item.iconColor)}\n .badge=${this.#renderBadge}\n key-property=\"key\"\n .selectionMode=${this.selectionMode}\n .interactionMode=${this.interactionMode}\n .itemWrap=${this.itemWrap}\n .searchModes=${this.searchModes}\n ?items-draggable=${this.itemsDraggable}\n ?items-droppable=${this.itemsDroppable}\n .canDrop=${this.#canDropOn}\n .editValidator=${this.#validateEditKey}\n .virtualize=${this.virtualize}\n .itemHeight=${this.itemHeight}\n @list-drag-over=${this.#onListDragOver}\n @list-drop=${this.#onListDrop}\n @list-context-menu=${this.#onListContextMenu}\n @list-edit-commit=${this.#onListEditCommit}\n @list-edit-cancel=${this.#onListEditCancel}\n @list-select=${this.#onListSelect}\n @list-activate=${this.#onListActivate}\n @keydown=${this.#onKeyDown}\n @focusin=${this.#syncFocusVisible}\n @focusout=${this.#syncFocusVisible}\n ></ixfx-vertical-list>\n ${this._rows.length === 0\n ? html`<div class=\"empty\" part=\"empty\">${this._loading ? `Loading…` : this.emptyText}</div>`\n : nothing}\n </div>\n `;\n }\n\n static override styles = [themeFallbacks, css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n overflow: hidden;\n background: var(--flat-list-bg, var(--list-bg, var(--surface-3)));\n color: var(--flat-list-text, var(--list-text, var(--surface-3-text)));\n border: 1px solid var(--flat-list-border, var(--list-border, var(--border)));\n border-radius: var(--flat-list-radius, var(--list-radius, var(--radius-s)));\n }\n\n .crumbs {\n display: flex;\n align-items: center;\n gap: var(--flat-list-toolbar-gap, var(--space-xs));\n flex: none;\n font-size: var(--flat-list-crumb-font-size, var(--text-s));\n padding: var(--flat-list-crumb-padding, var(--space-xs));\n border-bottom: 1px solid var(--flat-list-border, var(--list-border, var(--border)));\n }\n\n .crumbs ixfx-crumb-navigation {\n flex: 1 1 0;\n min-width: 0;\n }\n\n .toolbar {\n display: flex;\n flex: none;\n align-items: center;\n gap: var(--flat-list-toolbar-gap, var(--space-xs));\n }\n\n .toolbar[hidden] {\n display: none;\n }\n\n .body {\n position: relative;\n flex: 1 1 auto;\n min-height: 0;\n }\n\n :host([data-focus-visible]) {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n }\n\n ixfx-vertical-list {\n /* The ring is drawn round the whole component instead. */\n outline: none;\n /* Fill .body absolutely: a percentage height does not reliably resolve\n inside a flex item, and an unbounded list never scrolls the cursor into view. */\n position: absolute;\n inset: 0;\n --list-bg: transparent;\n --list-border: none;\n --list-radius: 0;\n }\n\n .empty {\n position: absolute;\n inset: 0;\n display: grid;\n place-items: center;\n pointer-events: none;\n color: var(--flat-list-empty-text, var(--surface-muted-text));\n }\n\n li[data-marked] {\n background: var(--flat-list-marked-bg, color-mix(in srgb, var(--accent) 18%, transparent));\n box-shadow: inset 3px 0 0 var(--flat-list-marked-bar, var(--accent));\n }\n\n .label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* Highlight rule for incremental search: the rows live in this shadow root,\n so the page-level ::highlight() rule cannot reach them. */\n ::highlight(vertical-list-search) {\n background: var(--accent);\n color: var(--accent-text, #fff);\n }\n\n .chevron {\n margin-inline-start: auto;\n padding-inline-start: 0.5em;\n padding-inline-end: var(--flat-list-chevron-gap, 0.4em);\n /* Inherit the row's text colour, so it follows selected / tickled states. */\n color: inherit;\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-flat-list': FlatListElement;\n }\n}\n\nexport interface FlatListElement {\n addEventListener<K extends keyof FlatListElementEventMap>(\n type: K,\n listener: (this: FlatListElement, event: FlatListElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions\n ): void;\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions\n ): void;\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -24,7 +24,7 @@ import { a as ListContextMenuDetail, c as ListDragLeaveEvent, d as ListDropEvent
24
24
  import { a as EditableMode, i as EditableLabelChangeEvent, n as EditableLabel, o as EntryMode, r as EditableLabelChangeDetail, t as DisplayTextLogic } from "./editable-label-rzXkjf1H.js";
25
25
  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-C1xzr1z7.js";
26
26
  import { ListGroupHeaderElement } from "./list-group-header.js";
27
- 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-DEDG6epz.js";
27
+ 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-Ohxqsy0g.js";
28
28
  import { FormElement } from "./form.js";
29
29
  import { A as DragSelectRect, C as TreeKeyboardNavControllerConfig, D as ListSelectionGesture, E as ListSelectionControllerConfig, M as ListDragSelectControllerConfig, O as ListSelectionModes, S as TreeKeyboardNavController, T as ListSelectionController, _ as GridListTickleDetail, a as GridListCaptionBackdrop, b as GridListViewportChangeEvent, c as GridListDataAdapter, d as GridListItemClickDetail, f as GridListItemClickEvent, g as GridListSelectEvent, h as GridListSelectDetail, i as GridListCaptionAlign, j as ListDragSelectController, k as isMultiMode, l as GridListElementEventMap, m as GridListOrientation, n as GridListActivateDetail, o as GridListCaptionPosition, p as GridListItemEventDetail, r as GridListActivateEvent, s as GridListCaptionStyle, t as GridListElement, u as GridListFullElementEventMap, v as GridListTickleEvent, w as TreeKeyboardNavItemId, x as TreeKeyboardNavCallbacks, y as GridListViewportChangeDetail } from "./grid-list-pefLORIr.js";
30
30
  import { n as ListNativeDragControllerConfig, t as ListNativeDragController } from "./list-native-drag-controller-ChIi3eK5.js";
@@ -103,8 +103,20 @@ Navigate / select / filter search works over the current level, as in [`ixfx-ver
103
103
 
104
104
  ## CSS variables
105
105
 
106
- `--flat-list-bg`, `--flat-list-text`, `--flat-list-border`, `--flat-list-radius`, `--flat-list-crumb-padding`, `--flat-list-crumb-font-size` (default `--text-s`), `--flat-list-chevron-gap`, `--flat-list-marked-bg`, `--flat-list-marked-bar`, `--flat-list-empty-text`. Each falls back to the matching `--list-*` variable. Other `--list-*` variables (e.g. `--list-item-height`) reach the inner list.
106
+ `--flat-list-bg`, `--flat-list-text`, `--flat-list-border`, `--flat-list-radius`, `--flat-list-crumb-padding`, `--flat-list-crumb-font-size` (default `--text-s`), `--flat-list-toolbar-gap`, `--flat-list-chevron-gap`, `--flat-list-marked-bg`, `--flat-list-marked-bar`, `--flat-list-empty-text`. Each falls back to the matching `--list-*` variable. Other `--list-*` variables (e.g. `--list-item-height`) reach the inner list.
107
+
108
+ ## Toolbar slot
109
+
110
+ Anything you put inside the element goes in a toolbar to the right of the crumb bar, which shrinks to make room. With nothing slotted, the crumbs use the full width.
111
+
112
+ ```html
113
+ <ixfx-flat-list>
114
+ <ixfx-button>New Set</ixfx-button>
115
+ </ixfx-flat-list>
116
+ ```
117
+
118
+ Space between items is `--flat-list-toolbar-gap`.
107
119
 
108
120
  ## CSS parts
109
121
 
110
- `crumbs` (the bar above the list), `empty`.
122
+ `crumbs` (the bar above the list), `toolbar` (the slot's wrapper), `empty`.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ixfx/components",
3
- "version": "0.13.1",
4
- "generated": "2026-10-01T20:18:51.052Z",
3
+ "version": "0.13.2",
4
+ "generated": "2026-10-01T21:51:41.922Z",
5
5
  "components": [
6
6
  {
7
7
  "name": "ac-text",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ixfx/components",
3
3
  "type": "module",
4
- "version": "0.13.1",
4
+ "version": "0.13.2",
5
5
  "packageManager": "pnpm@10.0.0",
6
6
  "description": "Web components for ixfx — Lit-based UI toolkit",
7
7
  "author": "Clint Heyer",
@@ -1 +0,0 @@
1
- {"version":3,"file":"flat-list-DEDG6epz.d.ts","names":[],"sources":["../src/flat-list/types.ts","../src/flat-list/flat-list.ts"],"mappings":";;;;;;;;;KAGY;KAEA;;WAED;;WAEA;;WAEA,MAAM;;WAEN;;KAGC;WACD,UAAU,YAAY;WACtB,cAAc;WACd,UAAU,YAAY;;KAGrB;WACD,MAAM;;KAGL;;WAED,MAAM;WACN,cAAc;;KAGb;;WAED,MAAM;;WAEN,gBAAgB;WAChB;WACA;;KAGC;WACD,MAAM;WACN;;KAGC;WACD,MAAM;;KAGL,wBAAwB,YAAY;KACpC,sBAAsB,YAAY;KAClC,wBAAwB,YAAY;KAEpC,oBAAoB,YAAY;KAChC,2BAA2B,YAAY;KACvC,0BAA0B,YAAY;KACtC,0BAA0B,YAAY;UAEjC;EACf,sBAAsB;EACtB,oBAAoB;EACpB,sBAAsB;EACtB,kBAAkB;EAClB,0BAA0B;EAC1B,yBAAyB;EACzB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCiFd,wBAAwB;;EAEnC,MAAM;EAGN,OAAO;;EAIP;;EAIA,cAAc;EAGd,iBAAiB;;EAIjB,QAAQ,GAAG,UAAU,GAAG;EAGxB,aAAa;EAGb,eAAe;EAGf,iBAAiB;EAGjB;EAGA;EAGA;;EAIA;;;;;EAOA,WAAW,MAAM,UAAU,cAAc;;;;;;EAQzC,gBAAgB,eAAe,MAAM;;EAIrC;;EAIA;;EAIA;EAGA;EAGA;;EAIA;;UAIQ;UAES;UACA;;MAcb,QAAQ;;MAKR,YAAY;;EAKhB,SAAS,mBAAmB,OAAO;;;;;;;EAUnC,UAAU;;MAQN,eAAe;MAIf,iBAAiB,YAAY;;EAWjC,WAAW;;EASX,aAAa;;EASb;EAqBS;YAQU,WAAW,SAAS;YAyBpB,QAAQ,SAAS;YAqSjB,wBAAM;SAoDT,sBAAM;;QAkFhB;YACI;IACR,kBAAkB;;;UAIL;EACf,iBAAiB,gBAAgB,yBAC/B,MAAM,GACN,WAAW,MAAM,iBAAiB,OAAO,wBAAwB,aACjE,oBAAoB;EAEtB,iBACE,cACA,UAAU,oCACV,oBAAoB"}