@ixfx/components 0.14.3 → 0.14.5

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.
@@ -3,7 +3,7 @@ import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrA
3
3
  import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
5
  import { t as handleStyles } from "./handle-DAXs7kbJ.js";
6
- import "./interaction-ZTh4htzr.js";
6
+ import "./interaction-E-uMGHkJ.js";
7
7
  import "./checkbox.js";
8
8
  import { LitElement, css, html, nothing } from "lit";
9
9
  import { property, state } from "lit/decorators.js";
@@ -1,3 +1,3 @@
1
1
  import "./checkbox.js";
2
- import { t as CheckedSelect } from "./checked-select-lDgAQQ7v.js";
2
+ import { t as CheckedSelect } from "./checked-select-CBUidG7n.js";
3
3
  export { CheckedSelect };
package/dist/crumbs.js CHANGED
@@ -2,8 +2,8 @@ import { t as TickledController } from "./tickled-controller-D-HZymaZ.js";
2
2
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
- import "./interaction-ZTh4htzr.js";
6
- import "./menu-item-BDEekBVy.js";
5
+ import "./interaction-E-uMGHkJ.js";
6
+ import "./menu-item-BUv8An2k.js";
7
7
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
8
8
  import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
9
9
  import "./narrowed-text.js";
@@ -5,13 +5,12 @@ import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js"
5
5
  import "./icon-1gpwtPx8.js";
6
6
  import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES } from "./incr-search-JIhwB49y.js";
7
7
  import { t as handleStyles } from "./handle-DAXs7kbJ.js";
8
- import { t as ListNativeDragController } from "./list-native-drag-controller-B9xO0XWn.js";
9
- import { i as listItemFadeKeyframes } from "./list-item-animation-BUoEKi5s.js";
10
- import "./interaction-ZTh4htzr.js";
8
+ import { a as listItemFadeKeyframes, t as ListNativeDragController } from "./list-native-drag-controller-CcXoS0YX.js";
9
+ import "./interaction-E-uMGHkJ.js";
11
10
  import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
12
11
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-BjcMyauw.js";
13
12
  import { t as createDragGhost } from "./drag-ghost-DtSDvjri.js";
14
- import "./menu-CwcXXeLM.js";
13
+ import "./menu-CU9KAm8s.js";
15
14
  import "./pan-text-CqtvjPyK.js";
16
15
  import { LitElement, css, html, nothing } from "lit";
17
16
  import { property, query, state } from "lit/decorators.js";
package/dist/data-grid.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as DataGridElement } from "./data-grid-FHr7wZ_k.js";
1
+ import { t as DataGridElement } from "./data-grid-Dx3l3dxw.js";
2
2
  export { DataGridElement };
@@ -5,9 +5,8 @@ import "./icon-1gpwtPx8.js";
5
5
  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
- import { t as ListNativeDragController } from "./list-native-drag-controller-B9xO0XWn.js";
8
+ import { i as animateListItemOut, r as animateListItemIn, t as ListNativeDragController } from "./list-native-drag-controller-CcXoS0YX.js";
9
9
  import { r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-BeE70lbB.js";
10
- import { n as animateListItemIn, r as animateListItemOut } from "./list-item-animation-BUoEKi5s.js";
11
10
  import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
12
11
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-BjcMyauw.js";
13
12
  import "./list-group-header.js";
@@ -1,3 +1,3 @@
1
- import { t as DetailListElement } from "./detail-list-BfYHNh6B.js";
1
+ import { t as DetailListElement } from "./detail-list-q8bs67BM.js";
2
2
  import "./list-group-header.js";
3
3
  export { DetailListElement };
@@ -4,10 +4,9 @@ import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
5
  import { c as createElementListSearchAdapter, d as createDataListSearchAdapter, i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, u as keyForElement } from "./incr-search-JIhwB49y.js";
6
6
  import { i as resolveGroupKey, r as partitionByGroup } from "./grouping-RYPnHkrS.js";
7
- import { t as ListNativeDragController } from "./list-native-drag-controller-B9xO0XWn.js";
7
+ import { a as listItemFadeKeyframes, t as ListNativeDragController } from "./list-native-drag-controller-CcXoS0YX.js";
8
8
  import { r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-BeE70lbB.js";
9
- import { i as listItemFadeKeyframes } from "./list-item-animation-BUoEKi5s.js";
10
- import "./interaction-ZTh4htzr.js";
9
+ import "./interaction-E-uMGHkJ.js";
11
10
  import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
12
11
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-BjcMyauw.js";
13
12
  import "./pan-text-CqtvjPyK.js";
package/dist/grid-list.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import "./list-group-header.js";
2
- import { t as GridListElement } from "./grid-list-CkU8gHCh.js";
2
+ import { t as GridListElement } from "./grid-list-y6dWJYu3.js";
3
3
  export { GridListElement };
package/dist/index.d.ts CHANGED
@@ -105,7 +105,8 @@ declare class KeyedElementIndex {
105
105
  /** Caption for a drag entry — explicit element labels win, then data values, then generic element text, then the key. */
106
106
  declare function captionForEntry(entry: ListDragEntry<unknown>): string;
107
107
  /**
108
- * Uniform built-in HTML+canvas drag preview for all four list components.
108
+ * Built-in drag preview shared by the list components. `tree-list` gets a
109
+ * compact row pill (icon + label + count badge); the others get the layouts below.
109
110
  *
110
111
  * - ≤5 selected → a row of small cards (thumbnail well + caption).
111
112
  * - >5 selected → a compact list (`N items` header, up to 5 rows, `+N more`).
@@ -2571,6 +2572,23 @@ interface PillRendererOptions {
2571
2572
  queueDisplay?: PillQueueDisplay;
2572
2573
  /** Extra margin (px) added to the default spacing on each side, letting pills avoid eg. a fixed header/footer/notch. */
2573
2574
  safeArea?: PillSafeArea;
2575
+ /**
2576
+ * Render the toasts in the browser's top layer (via the Popover API), so they
2577
+ * appear above modal `<dialog>` backdrops and other popovers regardless of any
2578
+ * `z-index`. Each time a new toast arrives the container is re-promoted, so a
2579
+ * dialog opened after earlier toasts doesn't keep covering later ones.
2580
+ * Browsers without the Popover API silently fall back to normal stacking.
2581
+ *
2582
+ * Caveat: a modal dialog makes the rest of the page inert, including toasts, so
2583
+ * they show above it but can't be clicked until it closes (timed dismissal is
2584
+ * unaffected). Default `true`. Set `false` to manage stacking yourself with `zIndex`.
2585
+ */
2586
+ topLayer?: boolean;
2587
+ /**
2588
+ * `z-index` for the toast layer when `topLayer` is `false`. Ignored otherwise.
2589
+ * Leave unset to take no part in z-ordering.
2590
+ */
2591
+ zIndex?: number;
2574
2592
  }
2575
2593
  declare function createPillRenderer(options?: PillRendererOptions): NotificationRenderer;
2576
2594
  //#endregion
package/dist/index.js CHANGED
@@ -17,26 +17,25 @@ import "./icons.js";
17
17
  import { t as prominenceStyles } from "./prominence-DlFShic3.js";
18
18
  import { n as buttonStyles, t as ButtonElement } from "./button-B7mgqtxR.js";
19
19
  import { a as toGroupKey, i as resolveGroupKey, n as defaultGroupLabel, o as toggleInSet, r as partitionByGroup, t as EMPTY_GROUP_LABEL } from "./grouping-RYPnHkrS.js";
20
- import { n as captionForEntry, r as createDefaultListDragPreview, t as ListNativeDragController } from "./list-native-drag-controller-B9xO0XWn.js";
20
+ import { a as listItemFadeKeyframes, c as captionForEntry, i as animateListItemOut, l as createDefaultListDragPreview, n as LIST_ITEM_MOTION_MS, o as prefersReducedMotion, r as animateListItemIn, s as startListItemOutAnimation, t as ListNativeDragController } from "./list-native-drag-controller-CcXoS0YX.js";
21
21
  import { n as isMultiMode, r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-BeE70lbB.js";
22
- import { a as prefersReducedMotion, i as listItemFadeKeyframes, n as animateListItemIn, o as startListItemOutAnimation, r as animateListItemOut, t as LIST_ITEM_MOTION_MS } from "./list-item-animation-BUoEKi5s.js";
23
- import "./interaction-ZTh4htzr.js";
24
- import "./menu-item-BDEekBVy.js";
22
+ import "./interaction-E-uMGHkJ.js";
23
+ import "./menu-item-BUv8An2k.js";
25
24
  import { Checkbox } from "./checkbox.js";
26
- import { t as CheckedSelect } from "./checked-select-lDgAQQ7v.js";
25
+ import { t as CheckedSelect } from "./checked-select-CBUidG7n.js";
27
26
  import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-BCMU7W7R.js";
28
27
  import { LabelledRangeInput } from "./labelled-range-input.js";
29
28
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
30
- import { a as TreeDataModel, c as pruneDraggedDescendants, i as TreeDropController, n as TreeListElement, o as applyTreeDrop, r as TreeBaseElement, s as dropTargetFor, t as TreeController } from "./tree-BFoN2Z_P.js";
29
+ import { a as TreeDataModel, c as pruneDraggedDescendants, i as TreeDropController, n as TreeListElement, o as applyTreeDrop, r as TreeBaseElement, s as dropTargetFor, t as TreeController } from "./tree-2_TRrLAV.js";
31
30
  import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
32
31
  import { NarrowedTextElement } from "./narrowed-text.js";
33
32
  import { CrumbNavigationElement } from "./crumbs.js";
34
33
  import { DataDisplayComponent } from "./data-display.js";
35
34
  import { t as createDragGhost } from "./drag-ghost-DtSDvjri.js";
36
- import { t as DataGridElement } from "./data-grid-FHr7wZ_k.js";
37
- import { a as menuFromTreeToElements, t as menu_exports } from "./menu-CwcXXeLM.js";
35
+ import { t as DataGridElement } from "./data-grid-Dx3l3dxw.js";
36
+ import { a as menuFromTreeToElements, t as menu_exports } from "./menu-CU9KAm8s.js";
38
37
  import { t as PanTextElement } from "./pan-text-CqtvjPyK.js";
39
- import { t as DetailListElement } from "./detail-list-BfYHNh6B.js";
38
+ import { t as DetailListElement } from "./detail-list-q8bs67BM.js";
40
39
  import { ListGroupHeaderElement } from "./list-group-header.js";
41
40
  import { a as distribute, c as preserveRestoreWeights, d as toSnapshot, f as walk, i as buildModel, l as resolveTracks, n as SplitPanelElement, o as findPanelNode, r as applySnapshot, s as normalise, t as SplitLayoutElement, u as setPanelRestoreWeight } from "./split-layout-Deoxy47d.js";
42
41
  import { TabListElement } from "./tabs.js";
@@ -47,7 +46,7 @@ import { n as EditableNumber, t as LabelledSliderInput } from "./labelled-slider
47
46
  import { VerticalListElement } from "./vertical-list.js";
48
47
  import { FlatListElement } from "./flat-list.js";
49
48
  import { t as FormElement } from "./form-CsXJX15p.js";
50
- import { t as GridListElement } from "./grid-list-CkU8gHCh.js";
49
+ import { t as GridListElement } from "./grid-list-y6dWJYu3.js";
51
50
  import { PanelElement } from "./panel.js";
52
51
  import { GroupedItemListerElement } from "./grouped-item-lister.js";
53
52
  import { t as IxfxHexEditorElement } from "./hex-editor-DiYpgIKs.js";
@@ -10572,11 +10571,15 @@ function restingTransform(edges, dx, dy) {
10572
10571
  if (edges.horizontal === `middle`) return `translateX(-50%) translate(${dx}px, ${dy}px)`;
10573
10572
  return `translate(${dx}px, ${dy}px)`;
10574
10573
  }
10574
+ function supportsPopover(el) {
10575
+ return typeof el.showPopover === `function` && typeof el.hidePopover === `function`;
10576
+ }
10575
10577
  function createPillRenderer(options = {}) {
10576
10578
  const position = options.position ?? `top-right`;
10577
10579
  const queueDisplay = options.queueDisplay ?? `list`;
10578
10580
  const safeArea = options.safeArea ?? {};
10579
10581
  const edges = edgesOf(position);
10582
+ const useTopLayer = options.topLayer ?? true;
10580
10583
  let container = null;
10581
10584
  let hooks = null;
10582
10585
  const pills = /* @__PURE__ */ new Map();
@@ -10588,9 +10591,20 @@ function createPillRenderer(options = {}) {
10588
10591
  container.className = `ixfx-notification-container`;
10589
10592
  container.setAttribute(`role`, `region`);
10590
10593
  container.setAttribute(`aria-label`, `Notifications`);
10594
+ container.style.cssText = `pointer-events: none;`;
10595
+ if (useTopLayer && supportsPopover(container)) {
10596
+ container.setAttribute(`popover`, `manual`);
10597
+ container.style.cssText += `position: fixed; inset: 0 auto auto 0; width: 0; height: 0; margin: 0; padding: 0; border: 0; overflow: visible; background: transparent; color: inherit;`;
10598
+ } else if (!useTopLayer && options.zIndex !== void 0) container.style.cssText += `position: fixed; inset: 0 auto auto 0; width: 0; height: 0; z-index: ${options.zIndex};`;
10591
10599
  document.body.appendChild(container);
10592
10600
  return container;
10593
10601
  }
10602
+ /** Put the container on top of the top-layer stack (above anything opened since it was last shown). */
10603
+ function promote(cont) {
10604
+ if (!cont.hasAttribute(`popover`)) return;
10605
+ if (cont.matches(`:popover-open`)) cont.hidePopover();
10606
+ cont.showPopover();
10607
+ }
10594
10608
  function updateAttributes(el, notification) {
10595
10609
  el.setAttribute(`notification-type`, notification.type);
10596
10610
  el.setAttribute(`message`, notification.message);
@@ -10675,6 +10689,7 @@ function createPillRenderer(options = {}) {
10675
10689
  }
10676
10690
  function setNotifications(notifications, _queueSize) {
10677
10691
  const cont = ensureContainer();
10692
+ let added = false;
10678
10693
  const idsToKeep = new Set(notifications.map((n) => n.id));
10679
10694
  for (const notification of notifications) {
10680
10695
  const existing = pills.get(notification.id);
@@ -10689,8 +10704,10 @@ function createPillRenderer(options = {}) {
10689
10704
  notification
10690
10705
  });
10691
10706
  cont.appendChild(el);
10707
+ added = true;
10692
10708
  measureRowHeight(el);
10693
10709
  }
10710
+ if (added) promote(cont);
10694
10711
  for (const [id] of pills) if (!idsToKeep.has(id)) dismiss(id);
10695
10712
  requestAnimationFrame(() => applyLayout(notifications));
10696
10713
  }
@@ -1,3 +1,3 @@
1
1
  import "./tickled-controller-D-HZymaZ.js";
2
2
  import "./tickled-styles-BrAHEj1q.js";
3
- import "./list-item-animation-BUoEKi5s.js";
3
+ import "./list-native-drag-controller-CcXoS0YX.js";
@@ -1,3 +1,84 @@
1
+ import { n as getIconEntry, r as getIconFont } from "./registry-BEtb8_wB.js";
2
+ import { css } from "lit";
3
+ //#region src/interaction/list-drag-preview-row.ts
4
+ const ROW_MIN = 24;
5
+ const ROW_MAX = 36;
6
+ const ROW_DEFAULT = 28;
7
+ const MAX_WIDTH = 280;
8
+ function treeItemOf(entry) {
9
+ const raw = entry.item;
10
+ if (raw === null || typeof raw !== `object` || raw instanceof Element) return void 0;
11
+ const inner = raw.item;
12
+ return inner !== null && typeof inner === `object` ? inner : void 0;
13
+ }
14
+ function rowHeightOf(ctx) {
15
+ const raw = ctx.metrics.rowHeight;
16
+ if (raw !== void 0 && Number.isFinite(raw)) return Math.max(ROW_MIN, Math.min(ROW_MAX, Math.round(raw)));
17
+ return ROW_DEFAULT;
18
+ }
19
+ /** Synchronous icon (the `<ixfx-icon>` element renders asynchronously, too late for a drag-image snapshot). */
20
+ function iconNode(name, color) {
21
+ const entry = getIconEntry(name);
22
+ if (!entry) return void 0;
23
+ const el = document.createElement(`span`);
24
+ el.setAttribute(`data-icon`, ``);
25
+ el.setAttribute(`aria-hidden`, `true`);
26
+ el.style.cssText = `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.1em;height:1.1em;${color ? `color:${color};` : ``}`;
27
+ if (entry.kind === `svg`) {
28
+ el.innerHTML = entry.svg;
29
+ const svg = el.querySelector(`svg`);
30
+ if (svg) {
31
+ svg.style.width = `100%`;
32
+ svg.style.height = `100%`;
33
+ }
34
+ } else {
35
+ const family = getIconFont();
36
+ if (family) el.style.fontFamily = family;
37
+ el.textContent = entry.char;
38
+ }
39
+ return el;
40
+ }
41
+ /**
42
+ * Drag preview for row-shaped lists (the tree): a single compact pill with the
43
+ * dragged row's icon and label, plus a count badge when several rows travel
44
+ * together. Sized from the row height so it reads as "the row you picked up".
45
+ */
46
+ function createRowDragPreview(ctx, fallbackCaption) {
47
+ const height = rowHeightOf(ctx);
48
+ const origin = ctx.origin ?? ctx.selected[0];
49
+ const tree = treeItemOf(origin);
50
+ const label = typeof tree?.label === `string` && tree.label.length > 0 ? tree.label : fallbackCaption(origin);
51
+ const iconName = typeof tree?.icon === `string` ? tree.icon : void 0;
52
+ const iconColor = typeof tree?.iconColor === `string` ? tree.iconColor : void 0;
53
+ const root = document.createElement(`div`);
54
+ root.setAttribute(`data-preview`, `row`);
55
+ root.setAttribute(`part`, `drag-preview`);
56
+ root.style.cssText = `position:fixed;top:-9999px;left:-9999px;display:inline-flex;align-items:center;gap:6px;box-sizing:border-box;height:${height}px;max-width:${MAX_WIDTH}px;padding:0 10px 0 8px;background:var(--surface-4, #333);color:var(--surface-4-text, #fff);border:1px solid var(--border-subtle, #555);border-radius:var(--radius-m, 8px);box-shadow:0 4px 16px rgba(0,0,0,0.3);font-family:system-ui,sans-serif;font-size:13px;white-space:nowrap;z-index:999999;pointer-events:none;`;
57
+ const icon = iconName ? iconNode(iconName, iconColor) : void 0;
58
+ if (icon) root.appendChild(icon);
59
+ const text = document.createElement(`span`);
60
+ text.setAttribute(`data-caption`, ``);
61
+ text.style.cssText = `min-width:0;overflow:hidden;text-overflow:ellipsis;`;
62
+ text.textContent = label;
63
+ root.appendChild(text);
64
+ const count = ctx.selected.length;
65
+ if (count > 1) {
66
+ const badge = document.createElement(`span`);
67
+ badge.setAttribute(`data-count`, ``);
68
+ badge.style.cssText = "flex-shrink:0;min-width:18px;height:18px;padding:0 5px;box-sizing:border-box;border-radius:9px;background:var(--accent, #4da3ff);color:var(--accent-text, #fff);font-size:11px;font-weight:600;line-height:18px;text-align:center;";
69
+ badge.textContent = String(count);
70
+ root.appendChild(badge);
71
+ }
72
+ return {
73
+ element: root,
74
+ hotspot: {
75
+ x: 14,
76
+ y: Math.round(height / 2)
77
+ },
78
+ dispose: () => {}
79
+ };
80
+ }
81
+ //#endregion
1
82
  //#region src/interaction/list-drag-preview-default.ts
2
83
  const CARD_DEFAULT = 72;
3
84
  const CARD_MIN = 48;
@@ -318,7 +399,8 @@ function paintList(context, scale, palette, captions, images, rh, cssW, cssH) {
318
399
  context.restore();
319
400
  }
320
401
  /**
321
- * Uniform built-in HTML+canvas drag preview for all four list components.
402
+ * Built-in drag preview shared by the list components. `tree-list` gets a
403
+ * compact row pill (icon + label + count badge); the others get the layouts below.
322
404
  *
323
405
  * - ≤5 selected → a row of small cards (thumbnail well + caption).
324
406
  * - >5 selected → a compact list (`N items` header, up to 5 rows, `+N more`).
@@ -336,6 +418,7 @@ function paintList(context, scale, palette, captions, images, rh, cssW, cssH) {
336
418
  */
337
419
  function createDefaultListDragPreview(context) {
338
420
  const ctx = context;
421
+ if (ctx.source === `tree-list`) return createRowDragPreview(ctx, captionForEntry);
339
422
  const entries = ctx.selected;
340
423
  const captions = entries.map((entry) => captionForEntry(entry));
341
424
  const images = entries.map((entry) => sourceImage(entry, ctx.resolveDragPreviewSource));
@@ -381,6 +464,133 @@ function createDefaultListDragPreview(context) {
381
464
  };
382
465
  }
383
466
  //#endregion
467
+ //#region src/interaction/list-item-animation.ts
468
+ /**
469
+ * Shared insertion / removal animation for the list & tree components.
470
+ *
471
+ * Two flavours, because the components split into two layout families:
472
+ *
473
+ * - **Flow layouts** (`ixfx-vertical-list`, `ixfx-detail-list`, `ixfx-tree-*`) —
474
+ * rows sit in normal flow, so a new row can collapse in from zero height and a
475
+ * leaving row can collapse back to zero, and the rows around it slide to make
476
+ * or close the gap for free. Use {@link animateListItemIn} /
477
+ * {@link animateListItemOut} (Web Animations API, exact measured sizes).
478
+ *
479
+ * - **Virtualised layouts** (`ixfx-grid-list`, `ixfx-data-grid`) — rows are
480
+ * absolutely positioned (`transform` / `top`), so collapsing a row's box moves
481
+ * nothing. Those components instead fade the entering / leaving row with the
482
+ * {@link listItemFadeKeyframes} keyframes and slide the survivors by
483
+ * transitioning their position for a short window after the change.
484
+ *
485
+ * Everything here is a no-op under `prefers-reduced-motion: reduce`.
486
+ */
487
+ /** Default duration (ms) for both flavours; overridable per call / per component. */
488
+ const LIST_ITEM_MOTION_MS = 200;
489
+ function prefersReducedMotion() {
490
+ return typeof window !== `undefined` && typeof window.matchMedia === `function` && window.matchMedia(`(prefers-reduced-motion: reduce)`).matches;
491
+ }
492
+ /**
493
+ * Opacity keyframes for the virtualised components. Each one adds its own
494
+ * one-line rule binding `.<row>.ixfx-item-entering` / `.ixfx-item-leaving` to
495
+ * these, plus a `prefers-reduced-motion` guard on its own selectors.
496
+ */
497
+ const listItemFadeKeyframes = css`
498
+ @keyframes ixfx-list-item-in {
499
+ from { opacity: 0; }
500
+ to { opacity: 1; }
501
+ }
502
+ @keyframes ixfx-list-item-out {
503
+ from { opacity: 1; }
504
+ to { opacity: 0; }
505
+ }
506
+ `;
507
+ function measure(el, axis) {
508
+ const rect = el.getBoundingClientRect();
509
+ return axis === `inline` ? rect.width : rect.height;
510
+ }
511
+ function resolveDuration(el, explicit) {
512
+ if (explicit !== void 0) return explicit;
513
+ const raw = getComputedStyle(el).getPropertyValue(`--ixfx-list-item-move-duration`).trim();
514
+ if (raw) {
515
+ const n = Number.parseFloat(raw);
516
+ if (!Number.isNaN(n)) return raw.endsWith(`ms`) ? n : raw.endsWith(`s`) ? n * 1e3 : n;
517
+ }
518
+ return 200;
519
+ }
520
+ function collapsedFrame(axis) {
521
+ const prop = axis === `inline` ? `width` : `height`;
522
+ const minProp = axis === `inline` ? `minWidth` : `minHeight`;
523
+ return {
524
+ [prop]: `0px`,
525
+ [minProp]: `0px`,
526
+ opacity: 0,
527
+ overflow: `hidden`
528
+ };
529
+ }
530
+ function fullFrame(size, axis) {
531
+ const prop = axis === `inline` ? `width` : `height`;
532
+ const minProp = axis === `inline` ? `minWidth` : `minHeight`;
533
+ return {
534
+ [prop]: `${size}px`,
535
+ [minProp]: `0px`,
536
+ opacity: 1,
537
+ overflow: `hidden`
538
+ };
539
+ }
540
+ /**
541
+ * Collapse + fade `el` in from nothing to its natural size. Call it just after
542
+ * the element has been inserted (it must already be laid out at full size so it
543
+ * can be measured). No-op under reduced motion.
544
+ */
545
+ function animateListItemIn(el, options = {}) {
546
+ if (prefersReducedMotion()) return void 0;
547
+ const { axis = `block`, easing = `ease` } = options;
548
+ const duration = resolveDuration(el, options.duration);
549
+ const size = measure(el, axis);
550
+ if (size <= 0) return void 0;
551
+ return el.animate([collapsedFrame(axis), fullFrame(size, axis)], {
552
+ duration,
553
+ easing
554
+ });
555
+ }
556
+ function outResult(finished, animation) {
557
+ return Object.assign(finished, { animation });
558
+ }
559
+ /**
560
+ * Start the collapse + fade-out animation for `el` and return the handle.
561
+ * Returns `undefined` when no animation was started (reduced motion or zero
562
+ * size). The caller owns the handle and must `cancel()` it if the removal is
563
+ * reversed — a retained `fill: forwards` frame otherwise keeps overriding the
564
+ * element's ordinary CSS indefinitely.
565
+ */
566
+ function startListItemOutAnimation(el, options = {}) {
567
+ if (prefersReducedMotion()) return void 0;
568
+ const { axis = `block`, easing = `ease` } = options;
569
+ const duration = resolveDuration(el, options.duration);
570
+ const size = measure(el, axis);
571
+ if (size <= 0) return void 0;
572
+ return el.animate([fullFrame(size, axis), collapsedFrame(axis)], {
573
+ duration,
574
+ easing,
575
+ fill: `forwards`
576
+ });
577
+ }
578
+ /**
579
+ * Collapse + fade `el` out. Resolves once the animation finishes (or straight
580
+ * away under reduced motion); the caller detaches the element after. The final
581
+ * collapsed state is held (`fill: forwards`) so there's no flash back to full
582
+ * size in the gap before removal.
583
+ *
584
+ * The returned promise carries an `.animation` handle. If the removal is
585
+ * reversed (the same key becomes visible again), cancel that handle so its
586
+ * filled final frame stops overriding the reused element's style.
587
+ */
588
+ function animateListItemOut(el, options = {}) {
589
+ const animation = startListItemOutAnimation(el, options);
590
+ if (!animation) return outResult(Promise.resolve(), void 0);
591
+ return outResult(animation.finished.then(() => void 0, () => void 0), animation);
592
+ }
593
+ //#endregion
384
594
  //#region src/interaction/list-native-drag-controller.ts
385
595
  /**
386
596
  * Shared native item/row drag-out for list components.
@@ -609,4 +819,4 @@ var ListNativeDragController = class {
609
819
  };
610
820
  };
611
821
  //#endregion
612
- export { captionForEntry as n, createDefaultListDragPreview as r, ListNativeDragController as t };
822
+ export { listItemFadeKeyframes as a, captionForEntry as c, animateListItemOut as i, createDefaultListDragPreview as l, LIST_ITEM_MOTION_MS as n, prefersReducedMotion as o, animateListItemIn as r, startListItemOutAnimation as s, ListNativeDragController as t };
@@ -3,8 +3,8 @@ import { t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
5
  import "./icon-1gpwtPx8.js";
6
- import "./interaction-ZTh4htzr.js";
7
- import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-BDEekBVy.js";
6
+ import "./interaction-E-uMGHkJ.js";
7
+ import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-BUv8An2k.js";
8
8
  import { LitElement, css, html, nothing } from "lit";
9
9
  import { property, query, state } from "lit/decorators.js";
10
10
  //#region src/menu/menu-bar.ts
@@ -4,7 +4,7 @@ import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
4
4
  import { t as popupSurfaceStyles } from "./popup-D80sj2QC.js";
5
5
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
6
6
  import "./icon-1gpwtPx8.js";
7
- import "./interaction-ZTh4htzr.js";
7
+ import "./interaction-E-uMGHkJ.js";
8
8
  import { LitElement, css, html } from "lit";
9
9
  import { property, query, state } from "lit/decorators.js";
10
10
  //#region src/menu/menu-container.ts
package/dist/menu.js CHANGED
@@ -1,3 +1,3 @@
1
- import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-BDEekBVy.js";
2
- import { a as menuFromTreeToElements, c as MenuSubTrigger, d as MenuBar, i as menuFromTree, l as MenuCommandController, n as MenuRadioGroup, o as MenuHeader, r as MenuRadioItem, s as MenuSeparator, u as MenuCheckItem } from "./menu-CwcXXeLM.js";
1
+ import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-BUv8An2k.js";
2
+ import { a as menuFromTreeToElements, c as MenuSubTrigger, d as MenuBar, i as menuFromTree, l as MenuCommandController, n as MenuRadioGroup, o as MenuHeader, r as MenuRadioItem, s as MenuSeparator, u as MenuCheckItem } from "./menu-CU9KAm8s.js";
3
3
  export { MenuBar, MenuCheckItem, MenuCommandController, MenuContainer, MenuHeader, MenuItem, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSubTrigger, MenuTrigger, menuFromTree, menuFromTreeToElements };
package/dist/miller.js CHANGED
@@ -3,7 +3,7 @@ import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrA
3
3
  import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
5
  import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-JIhwB49y.js";
6
- import "./interaction-ZTh4htzr.js";
6
+ import "./interaction-E-uMGHkJ.js";
7
7
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
8
8
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-BjcMyauw.js";
9
9
  import { LitElement, css, html, nothing } from "lit";
@@ -4,7 +4,7 @@ import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrA
4
4
  import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
5
5
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
6
6
  import { p as createIncrSearch } from "./incr-search-JIhwB49y.js";
7
- import "./interaction-ZTh4htzr.js";
7
+ import "./interaction-E-uMGHkJ.js";
8
8
  import { LitElement, css, html, nothing } from "lit";
9
9
  import { property, query, state } from "lit/decorators.js";
10
10
  import { createCommandRegistry } from "@clinth/ui-commands";
@@ -2,7 +2,7 @@ import { t as TickledController } from "./tickled-controller-D-HZymaZ.js";
2
2
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
- import "./interaction-ZTh4htzr.js";
5
+ import "./interaction-E-uMGHkJ.js";
6
6
  import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
7
7
  import { t as WheelNudgeMixin } from "./wheel-nudge-D5rmht3v.js";
8
8
  import { LitElement, css, html } from "lit";