@ixfx/components 0.11.2 → 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/bundle/index.d.ts +62 -4
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +224 -23
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-text.d.ts +1 -1
  6. package/dist/{ac-token--_vCHXWw.d.ts → ac-token-TCLAZeVg.d.ts} +2 -2
  7. package/dist/{ac-token--_vCHXWw.d.ts.map → ac-token-TCLAZeVg.d.ts.map} +1 -1
  8. package/dist/ac-token.d.ts +1 -1
  9. package/dist/{button-BYuf72aR.d.ts → button-CTL45aBl.d.ts} +2 -2
  10. package/dist/{button-BYuf72aR.d.ts.map → button-CTL45aBl.d.ts.map} +1 -1
  11. package/dist/button.d.ts +1 -1
  12. package/dist/colour-picker.d.ts +1 -1
  13. package/dist/crumbs.d.ts +1 -1
  14. package/dist/crumbs.js +1 -1
  15. package/dist/{data-grid-3yIylIH-.d.ts → data-grid-CfiaBqTA.d.ts} +4 -4
  16. package/dist/{data-grid-3yIylIH-.d.ts.map → data-grid-CfiaBqTA.d.ts.map} +1 -1
  17. package/dist/data-grid.d.ts +1 -1
  18. package/dist/data-grid.js +1 -1
  19. package/dist/{detail-list-ccWFyhEc.d.ts → detail-list-DxQZkK-C.d.ts} +4 -4
  20. package/dist/{detail-list-ccWFyhEc.d.ts.map → detail-list-DxQZkK-C.d.ts.map} +1 -1
  21. package/dist/detail-list.d.ts +2 -2
  22. package/dist/{grid-list-BnOVgtLI.d.ts → grid-list-ChgYpUUq.d.ts} +2 -2
  23. package/dist/{grid-list-BnOVgtLI.d.ts.map → grid-list-ChgYpUUq.d.ts.map} +1 -1
  24. package/dist/grid-list.d.ts +1 -1
  25. package/dist/{grouped-item-lister-DETte0Dh.d.ts → grouped-item-lister-Bhyo-dkH.d.ts} +2 -2
  26. package/dist/{grouped-item-lister-DETte0Dh.d.ts.map → grouped-item-lister-Bhyo-dkH.d.ts.map} +1 -1
  27. package/dist/grouped-item-lister.d.ts +1 -1
  28. package/dist/{icon-CDGprSdE.d.ts → icon-DR_3rSyZ.d.ts} +2 -2
  29. package/dist/icon-DR_3rSyZ.d.ts.map +1 -0
  30. package/dist/icons.d.ts +2 -2
  31. package/dist/incr-search.d.ts +1 -1
  32. package/dist/{index-tq6f8007.d.ts → index-BOUaDIW-.d.ts} +2 -2
  33. package/dist/{index-tq6f8007.d.ts.map → index-BOUaDIW-.d.ts.map} +1 -1
  34. package/dist/{index-CoqtMSd9.d.ts → index-BUB5SICW.d.ts} +2 -2
  35. package/dist/{index-CoqtMSd9.d.ts.map → index-BUB5SICW.d.ts.map} +1 -1
  36. package/dist/{index-RImMNo0r.d.ts → index-CDllxjVG.d.ts} +3 -3
  37. package/dist/{index-RImMNo0r.d.ts.map → index-CDllxjVG.d.ts.map} +1 -1
  38. package/dist/{index-5-cwYpmx.d.ts → index-CHbuPyLL.d.ts} +2 -2
  39. package/dist/{index-5-cwYpmx.d.ts.map → index-CHbuPyLL.d.ts.map} +1 -1
  40. package/dist/{index-UvnoZUAo.d.ts → index-CJ5fshD3.d.ts} +2 -2
  41. package/dist/{index-UvnoZUAo.d.ts.map → index-CJ5fshD3.d.ts.map} +1 -1
  42. package/dist/{index-CYndvTWH.d.ts → index-garxxqgV.d.ts} +2 -2
  43. package/dist/{index-CYndvTWH.d.ts.map → index-garxxqgV.d.ts.map} +1 -1
  44. package/dist/index.d.ts +78 -22
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +180 -12
  47. package/dist/index.js.map +1 -1
  48. package/dist/{labelled-input-base-hoKGwyKT.js → labelled-input-base-BFa4xlYV.js} +11 -8
  49. package/dist/labelled-input-base-BFa4xlYV.js.map +1 -0
  50. package/dist/{labelled-input-base-DiTme1JO.d.ts → labelled-input-base-Dp_9KP0G.d.ts} +2 -2
  51. package/dist/{labelled-input-base-DiTme1JO.d.ts.map → labelled-input-base-Dp_9KP0G.d.ts.map} +1 -1
  52. package/dist/labelled-radial-input.d.ts +2 -2
  53. package/dist/labelled-radial-input.d.ts.map +1 -1
  54. package/dist/labelled-radial-input.js +1 -1
  55. package/dist/labelled-range-input.d.ts +1 -1
  56. package/dist/labelled-range-input.js +1 -1
  57. package/dist/{labelled-slider-input-CF2RtzgG.js → labelled-slider-input-FdCRi6st.js} +2 -2
  58. package/dist/{labelled-slider-input-CF2RtzgG.js.map → labelled-slider-input-FdCRi6st.js.map} +1 -1
  59. package/dist/labelled-slider-input.d.ts +1 -1
  60. package/dist/labelled-slider-input.js +1 -1
  61. package/dist/{menu-B2Qv3Oiz.js → menu-BHT6HRND.js} +2 -2
  62. package/dist/{menu-B2Qv3Oiz.js.map → menu-BHT6HRND.js.map} +1 -1
  63. package/dist/{menu-item-CZi9vy5O.d.ts → menu-item-DlxAb0Xr.d.ts} +4 -2
  64. package/dist/menu-item-DlxAb0Xr.d.ts.map +1 -0
  65. package/dist/{menu-item-Woc8jJc1.js → menu-item-JcpHCyF0.js} +30 -6
  66. package/dist/menu-item-JcpHCyF0.js.map +1 -0
  67. package/dist/menu.d.ts +2 -2
  68. package/dist/menu.js +2 -2
  69. package/dist/miller.d.ts +1 -1
  70. package/dist/panel.d.ts +1 -1
  71. package/dist/range-input.js +8 -2
  72. package/dist/range-input.js.map +1 -1
  73. package/dist/{split-layout-JK3xWVX2.d.ts → split-layout-C5SYbDrq.d.ts} +2 -2
  74. package/dist/{split-layout-JK3xWVX2.d.ts.map → split-layout-C5SYbDrq.d.ts.map} +1 -1
  75. package/dist/split-layout.d.ts +1 -1
  76. package/dist/{tab-list-pqfKaVAE.d.ts → tab-list-v8mKX7Fu.d.ts} +2 -2
  77. package/dist/{tab-list-pqfKaVAE.d.ts.map → tab-list-v8mKX7Fu.d.ts.map} +1 -1
  78. package/dist/tabs.d.ts +1 -1
  79. package/dist/{titlebar-Tqu-VvMU.d.ts → titlebar-B5zSTZnF.d.ts} +2 -2
  80. package/dist/{titlebar-Tqu-VvMU.d.ts.map → titlebar-B5zSTZnF.d.ts.map} +1 -1
  81. package/dist/titlebar.d.ts +1 -1
  82. package/dist/tree.d.ts +1 -1
  83. package/dist/{vertical-list-9dJ1R1hU.d.ts → vertical-list-R25WqAVO.d.ts} +2 -2
  84. package/dist/{vertical-list-9dJ1R1hU.d.ts.map → vertical-list-R25WqAVO.d.ts.map} +1 -1
  85. package/dist/vertical-list.d.ts +1 -1
  86. package/docs-user/index.json +2 -2
  87. package/docs-user/multicol-list.md +1 -0
  88. package/package.json +1 -1
  89. package/dist/icon-CDGprSdE.d.ts.map +0 -1
  90. package/dist/labelled-input-base-hoKGwyKT.js.map +0 -1
  91. package/dist/menu-item-CZi9vy5O.d.ts.map +0 -1
  92. package/dist/menu-item-Woc8jJc1.js.map +0 -1
package/bundle/index.js CHANGED
@@ -7245,6 +7245,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7245
7245
  this._isOpen = false;
7246
7246
  this._hasMenu = false;
7247
7247
  this._hasTriggerSlot = false;
7248
+ this._hasContextTarget = false;
7248
7249
  this._anchorName = `--mt-${_MenuTrigger._count++}`;
7249
7250
  this._clickListener = this._handleClickOutside.bind(this);
7250
7251
  this._handlePopoverToggle = (e) => {
@@ -7297,11 +7298,14 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7297
7298
  this._propagateContext();
7298
7299
  }
7299
7300
  }
7301
+ const contextSlot = this.shadowRoot?.querySelector(`slot[name="context-target"]`);
7302
+ if (contextSlot) this._hasContextTarget = contextSlot.assignedElements({ flatten: true }).length > 0;
7300
7303
  this._updatePosition();
7301
7304
  });
7302
7305
  }
7303
7306
  updated(changedProperties) {
7304
7307
  if (changedProperties.has(`registry`) || changedProperties.has(`keyboardManager`)) this._propagateContext();
7308
+ if (changedProperties.has(`mode`)) this._updatePosition();
7305
7309
  }
7306
7310
  _updatePosition() {
7307
7311
  const pos = {
@@ -7348,6 +7352,10 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7348
7352
  const slot = e.target;
7349
7353
  this._hasTriggerSlot = slot.assignedElements({ flatten: true }).length > 0;
7350
7354
  }
7355
+ _handleContextTargetSlotChange(e) {
7356
+ const slot = e.target;
7357
+ this._hasContextTarget = slot.assignedElements({ flatten: true }).length > 0;
7358
+ }
7351
7359
  get isOpen() {
7352
7360
  return this._isOpen;
7353
7361
  }
@@ -7386,6 +7394,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7386
7394
  document.removeEventListener(`click`, this._clickListener);
7387
7395
  }
7388
7396
  _handleTriggerClick(e) {
7397
+ if (this.mode === `context`) return;
7389
7398
  e.stopPropagation();
7390
7399
  if (this._isOpen) {
7391
7400
  this._closeMenu();
@@ -7432,9 +7441,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7432
7441
  this._popup.style.left = `${e.clientX}px`;
7433
7442
  this._popup.style.position = `fixed`;
7434
7443
  this._popup.style.positionAnchor = `none`;
7435
- if (this._popup?.popover) try {
7436
- this._popup.showPopover();
7437
- } catch {}
7444
+ this._openMenu();
7438
7445
  }
7439
7446
  static {
7440
7447
  this.styles = [
@@ -7456,6 +7463,18 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7456
7463
  align-items: stretch;
7457
7464
  }
7458
7465
 
7466
+ /* In context mode the target is the consumer's own content surface (a
7467
+ list, canvas, whole panel) rather than a button wrapper. Dissolve the
7468
+ wrapper's box by default so slotted content participates directly in
7469
+ the layout established around the host and can be clipped/scroll within
7470
+ the space actually available. Set --menu-trigger-area-display: flex
7471
+ (plus --menu-trigger-area-flex) to keep a real box instead, e.g. for
7472
+ a mixed visible-trigger + context-target use. */
7473
+ :host([mode="context"]) .trigger-area {
7474
+ display: var(--menu-trigger-area-display, contents);
7475
+ flex: var(--menu-trigger-area-flex, initial);
7476
+ }
7477
+
7459
7478
  .trigger-btn {
7460
7479
  display: inline-flex;
7461
7480
  align-items: center;
@@ -7518,7 +7537,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7518
7537
  ];
7519
7538
  }
7520
7539
  render() {
7521
- const showButton = this.mode !== `dropdown` && this._hasMenu && !this._hasTriggerSlot;
7540
+ const showButton = this.mode !== `dropdown` && this._hasMenu && !this._hasTriggerSlot && !(this.mode === `context` && this._hasContextTarget);
7522
7541
  return html`
7523
7542
  <div
7524
7543
  class="trigger-area"
@@ -7526,6 +7545,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7526
7545
  @contextmenu=${this._handleContextMenu}
7527
7546
  >
7528
7547
  ${showButton ? html`<button class="trigger-btn" part="base" tabindex=${this.tabStop ? `0` : `-1`}>${this.iconName ? html`<ixfx-icon name=${this.iconName}></ixfx-icon>` : this.label || html`<ixfx-icon name="ellipsis-vertical"></ixfx-icon>`}</button>` : null}
7548
+ ${this.mode === `context` ? html`<slot name="context-target" @slotchange=${this._handleContextTargetSlotChange}></slot>` : null}
7529
7549
  <slot name="trigger" @slotchange=${this._handleTriggerSlotChange}></slot>
7530
7550
  </div>
7531
7551
  <div
@@ -7538,7 +7558,10 @@ let MenuTrigger = class MenuTrigger extends LitElement {
7538
7558
  `;
7539
7559
  }
7540
7560
  };
7541
- __decorate([property({ type: String })], MenuTrigger.prototype, "mode", void 0);
7561
+ __decorate([property({
7562
+ type: String,
7563
+ reflect: true
7564
+ })], MenuTrigger.prototype, "mode", void 0);
7542
7565
  __decorate([property({ type: String })], MenuTrigger.prototype, "label", void 0);
7543
7566
  __decorate([property({
7544
7567
  type: String,
@@ -7554,6 +7577,7 @@ __decorate([property({
7554
7577
  __decorate([state()], MenuTrigger.prototype, "_isOpen", void 0);
7555
7578
  __decorate([state()], MenuTrigger.prototype, "_hasMenu", void 0);
7556
7579
  __decorate([state()], MenuTrigger.prototype, "_hasTriggerSlot", void 0);
7580
+ __decorate([state()], MenuTrigger.prototype, "_hasContextTarget", void 0);
7557
7581
  __decorate([query(`.trigger-btn`)], MenuTrigger.prototype, "_triggerBtn", void 0);
7558
7582
  __decorate([query(`.popup`)], MenuTrigger.prototype, "_popup", void 0);
7559
7583
  MenuTrigger = _MenuTrigger = __decorate([safeCustomElement(`ixfx-menu-trigger`)], MenuTrigger);
@@ -8460,37 +8484,40 @@ var LabelledInputBase = class extends LitElement {
8460
8484
  this._isDragging = false;
8461
8485
  this._debounceTimer = void 0;
8462
8486
  this._handleNumberChange = (e) => {
8463
- const newValue = Number.parseFloat(e.detail.value);
8487
+ const valueStr = e.detail?.value ?? String(this.value);
8488
+ const newValue = Number.parseFloat(valueStr);
8464
8489
  this.value = newValue;
8465
8490
  this._syncValue(newValue);
8466
8491
  this.dispatchEvent(new CustomEvent(`change`, {
8467
- detail: { value: e.detail.value },
8492
+ detail: { value: valueStr },
8468
8493
  bubbles: true,
8469
8494
  composed: true
8470
8495
  }));
8471
8496
  };
8472
8497
  this._handleInputChange = (e) => {
8473
- this.value = e.detail.value;
8498
+ const value = e.detail?.value ?? this.value;
8499
+ this.value = value;
8474
8500
  clearTimeout(this._debounceTimer);
8475
8501
  this._debounceTimer = window.setTimeout(() => {
8476
8502
  this._isDragging = false;
8477
8503
  }, 300);
8478
8504
  this.dispatchEvent(new CustomEvent(`change`, {
8479
- detail: { value: String(e.detail.value) },
8505
+ detail: { value: String(value) },
8480
8506
  bubbles: true,
8481
8507
  composed: true
8482
8508
  }));
8483
8509
  };
8484
8510
  this._handleSliderInput = (e) => {
8511
+ const value = e.detail?.value ?? this.value;
8485
8512
  console.log(`[LABELLED-INPUT] _handleSliderInput called`, {
8486
- value: e.detail.value,
8513
+ value,
8487
8514
  composedPath: e.composedPath()
8488
8515
  });
8489
- this.value = e.detail.value;
8516
+ this.value = value;
8490
8517
  this._isDragging = true;
8491
8518
  clearTimeout(this._debounceTimer);
8492
8519
  this.dispatchEvent(new CustomEvent(`input`, {
8493
- detail: { value: e.detail.value },
8520
+ detail: { value },
8494
8521
  bubbles: true,
8495
8522
  composed: true
8496
8523
  }));
@@ -11995,7 +12022,10 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
11995
12022
  this._editingCancelled = false;
11996
12023
  this._editStartIndex = null;
11997
12024
  this._openCumPath = null;
12025
+ this._dragCumPath = null;
12026
+ this._dropCumPath = null;
11998
12027
  this.#uid = Math.random().toString(36).slice(2, 8);
12028
+ this.#clickSuppressUntil = 0;
11999
12029
  this.#onPopoverToggle = (e) => {
12000
12030
  if (e.newState === `closed` && this._openIdx !== null) {
12001
12031
  this._openIdx = null;
@@ -12049,6 +12079,8 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12049
12079
  #pendingController;
12050
12080
  #pendingIndex;
12051
12081
  #uid;
12082
+ /** Clicks within this window after a drag are ignored (post-drag click-through guard). */
12083
+ #clickSuppressUntil;
12052
12084
  #anchorName(cumPath) {
12053
12085
  return `--cp-${this.#uid}-${cumPath.replaceAll(this.separator, `-`).replaceAll(` `, `-`).replace(INVALID_ANCHOR_CHARS_RE, `-`)}`;
12054
12086
  }
@@ -12110,6 +12142,23 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12110
12142
  if (isRoot) return rootSegments.slice(0, index + 1).join(this.separator);
12111
12143
  return [...rootSegments, ...segments.slice(0, index + 1)].join(this.separator);
12112
12144
  }
12145
+ #resolveFullPathSegments(index, isRoot) {
12146
+ const rootSegments = this.#getRootSegments();
12147
+ if (isRoot) return rootSegments.slice(0, index + 1);
12148
+ return [...rootSegments, ...this.#getSegments().slice(0, index + 1)];
12149
+ }
12150
+ #segmentDragPayloads(fullPathSegments) {
12151
+ try {
12152
+ const result = this.segmentDragLookup?.(fullPathSegments, fullPathSegments.length - 1);
12153
+ if (result === void 0 || result === null) return [];
12154
+ return Array.isArray(result) ? [...result] : [result];
12155
+ } catch {
12156
+ return [];
12157
+ }
12158
+ }
12159
+ #clicksSuppressed() {
12160
+ return Date.now() < this.#clickSuppressUntil || this._dragCumPath !== null;
12161
+ }
12113
12162
  #resolveSegmentIcon(fullPathSegments, index) {
12114
12163
  const direct = this.segmentIconLookup?.(fullPathSegments, index);
12115
12164
  if (typeof direct === `string` && direct.length > 0) return direct;
@@ -12176,7 +12225,87 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12176
12225
  }
12177
12226
  this.requestUpdate();
12178
12227
  }
12228
+ #onLabelDragStart(fullPathSegments, cumPath, event) {
12229
+ this.#closeDropdown();
12230
+ const index = fullPathSegments.length - 1;
12231
+ const dt = event.dataTransfer;
12232
+ const detail = {
12233
+ index,
12234
+ label: fullPathSegments[index] ?? ``,
12235
+ pathSegments: fullPathSegments,
12236
+ parentPath: fullPathSegments.slice(0, -1).join(this.separator),
12237
+ fullPath: fullPathSegments.join(this.separator),
12238
+ dataTransfer: dt
12239
+ };
12240
+ const evt = new CustomEvent(`crumb-drag-start`, {
12241
+ detail,
12242
+ bubbles: true,
12243
+ composed: true,
12244
+ cancelable: true
12245
+ });
12246
+ if (!this.dispatchEvent(evt)) {
12247
+ event.preventDefault();
12248
+ return;
12249
+ }
12250
+ this._dragCumPath = cumPath;
12251
+ this.toggleAttribute(`data-native-dragging`, true);
12252
+ if (!dt) return;
12253
+ try {
12254
+ if (dt.effectAllowed === `none` || dt.effectAllowed === `uninitialized`) dt.effectAllowed = `copyMove`;
12255
+ } catch {}
12256
+ try {
12257
+ for (const payload of this.#segmentDragPayloads(fullPathSegments)) dt.setData(payload.type, payload.data);
12258
+ if (!dt.types.includes(`text/plain`)) dt.setData(`text/plain`, detail.fullPath);
12259
+ } catch {}
12260
+ }
12261
+ #onLabelDragEnd() {
12262
+ this._dragCumPath = null;
12263
+ this._dropCumPath = null;
12264
+ this.toggleAttribute(`data-native-dragging`, false);
12265
+ this.#clickSuppressUntil = Date.now() + 150;
12266
+ }
12267
+ #onSegDragOver(cumPath, event) {
12268
+ if (!this.parseExternalDrop) return;
12269
+ if (!event.dataTransfer) return;
12270
+ event.preventDefault();
12271
+ if (this._dropCumPath !== cumPath) this._dropCumPath = cumPath;
12272
+ }
12273
+ #onSegDragLeave(cumPath, _event) {
12274
+ if (!this.parseExternalDrop) return;
12275
+ if (this._dropCumPath === cumPath) this._dropCumPath = null;
12276
+ }
12277
+ #onSegDrop(fullPathSegments, event) {
12278
+ if (!this.parseExternalDrop) return;
12279
+ event.preventDefault();
12280
+ event.stopPropagation();
12281
+ this._dropCumPath = null;
12282
+ const dt = event.dataTransfer;
12283
+ if (!dt) return;
12284
+ let data;
12285
+ try {
12286
+ data = this.parseExternalDrop(dt);
12287
+ } catch (err) {
12288
+ console.error(`parseExternalDrop failed:`, err);
12289
+ return;
12290
+ }
12291
+ if (data === void 0) return;
12292
+ const index = fullPathSegments.length - 1;
12293
+ this.dispatchEvent(new CustomEvent(`crumb-drop`, {
12294
+ detail: {
12295
+ index,
12296
+ label: fullPathSegments[index] ?? ``,
12297
+ pathSegments: fullPathSegments,
12298
+ parentPath: fullPathSegments.slice(0, -1).join(this.separator),
12299
+ fullPath: fullPathSegments.join(this.separator),
12300
+ data,
12301
+ dataTransfer: dt
12302
+ },
12303
+ bubbles: true,
12304
+ composed: true
12305
+ }));
12306
+ }
12179
12307
  #onLabelClick(index, event) {
12308
+ if (this.#clicksSuppressed()) return;
12180
12309
  event.preventDefault();
12181
12310
  event.stopPropagation();
12182
12311
  this.#closeDropdown();
@@ -12258,16 +12387,31 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12258
12387
  #renderSegment(label, index, isLast) {
12259
12388
  const isOpen = this._openIdx === index;
12260
12389
  const cumPath = this.#getCumulativePath(index, false);
12261
- const fullPathSegments = [...this.#getRootSegments(), ...this.#getSegments().slice(0, index + 1)];
12390
+ const fullPathSegments = this.#resolveFullPathSegments(index, false);
12262
12391
  const icon = this.#resolveSegmentIcon(fullPathSegments, fullPathSegments.length - 1);
12392
+ const draggable = this.#segmentDragPayloads(fullPathSegments).length > 0;
12393
+ const dragging = this._dragCumPath === cumPath;
12394
+ const dropInto = this._dropCumPath === cumPath;
12263
12395
  return html`
12264
- <div class="seg" data-cumulative=${cumPath} @click=${(e) => this.#onSegmentClick(index, e)}>
12265
- <label title=${label} @click=${(e) => this.#onLabelClick(index, e)}>
12396
+ <div class="seg ${dragging ? `dragging` : ``} ${dropInto ? `drop-into` : ``}"
12397
+ part=${dropInto ? `segment drop-target` : `segment`}
12398
+ data-cumulative=${cumPath}
12399
+ @click=${(e) => this.#onSegmentClick(index, e)}
12400
+ @dragover=${(e) => this.#onSegDragOver(cumPath, e)}
12401
+ @dragleave=${(e) => this.#onSegDragLeave(cumPath, e)}
12402
+ @drop=${(e) => this.#onSegDrop(fullPathSegments, e)}>
12403
+ <label title=${label}
12404
+ part="label"
12405
+ ?draggable=${draggable}
12406
+ @click=${(e) => this.#onLabelClick(index, e)}
12407
+ @dragstart=${(e) => this.#onLabelDragStart(fullPathSegments, cumPath, e)}
12408
+ @dragend=${() => this.#onLabelDragEnd()}>
12266
12409
  ${icon ? html`<ixfx-icon class="crumb-icon segment-icon" name=${icon}></ixfx-icon>` : nothing}
12267
12410
  ${label}
12268
12411
  </label>
12269
12412
  ${(!isLast || this.siblingLookup) && this._leafSegmentIndex !== index ? html`
12270
12413
  <div class="caret ${isOpen ? `open` : ``} ${this._confirmedLeafIndices.has(cumPath) ? `disabled` : ``}"
12414
+ part="caret"
12271
12415
  style="anchor-name: ${this.#anchorName(cumPath)}"
12272
12416
  data-cumulative=${cumPath}
12273
12417
  @click=${(e) => this.#onCaretClick(index, e)}>
@@ -12278,17 +12422,31 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12278
12422
  `;
12279
12423
  }
12280
12424
  #renderRootSegment(label, index) {
12281
- const rootSegments = this.#getRootSegments();
12282
- const isLast = index === rootSegments.length - 1;
12425
+ const isLast = index === this.#getRootSegments().length - 1;
12283
12426
  const isOpen = this._openIdx === index;
12284
12427
  const cumPath = this.#getCumulativePath(index, true);
12285
- const fullPathSegments = rootSegments.slice(0, index + 1);
12428
+ const fullPathSegments = this.#resolveFullPathSegments(index, true);
12286
12429
  const icon = this.#resolveSegmentIcon(fullPathSegments, index);
12430
+ const draggable = this.#segmentDragPayloads(fullPathSegments).length > 0;
12431
+ const dragging = this._dragCumPath === cumPath;
12432
+ const dropInto = this._dropCumPath === cumPath;
12287
12433
  return html`
12288
- <div class="seg seg-root" data-cumulative=${cumPath} @click=${(e) => this.#onRootSegmentClick(index, e)}>
12289
- <label title=${label}>${icon ? html`<ixfx-icon class="crumb-icon segment-icon" name=${icon}></ixfx-icon>` : nothing}${label}</label>
12434
+ <div class="seg seg-root ${dragging ? `dragging` : ``} ${dropInto ? `drop-into` : ``}"
12435
+ part=${dropInto ? `segment drop-target` : `segment`}
12436
+ data-cumulative=${cumPath}
12437
+ @click=${(e) => this.#onRootSegmentClick(index, e)}
12438
+ @dragover=${(e) => this.#onSegDragOver(cumPath, e)}
12439
+ @dragleave=${(e) => this.#onSegDragLeave(cumPath, e)}
12440
+ @drop=${(e) => this.#onSegDrop(fullPathSegments, e)}>
12441
+ <label title=${label}
12442
+ part="label"
12443
+ ?draggable=${draggable}
12444
+ @click=${(e) => this.#onLabelClick(index, e)}
12445
+ @dragstart=${(e) => this.#onLabelDragStart(fullPathSegments, cumPath, e)}
12446
+ @dragend=${() => this.#onLabelDragEnd()}>${icon ? html`<ixfx-icon class="crumb-icon segment-icon" name=${icon}></ixfx-icon>` : nothing}${label}</label>
12290
12447
  ${isLast && this.siblingLookup ? html`
12291
12448
  <div class="caret ${isOpen ? `open` : ``} ${this._confirmedLeafIndices.has(cumPath) ? `disabled` : ``}"
12449
+ part="caret"
12292
12450
  style="anchor-name: ${this.#anchorName(cumPath)}"
12293
12451
  data-cumulative=${cumPath}
12294
12452
  @click=${(e) => this.#onCaretClick(index, e)}>
@@ -12299,12 +12457,14 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12299
12457
  `;
12300
12458
  }
12301
12459
  #onRootSegmentClick(index, event) {
12460
+ if (this.#clicksSuppressed()) return;
12302
12461
  event.preventDefault();
12303
12462
  event.stopPropagation();
12304
12463
  const newPath = this.#getRootSegments().slice(0, index + 1).join(this.separator);
12305
12464
  this.setPath(newPath);
12306
12465
  }
12307
12466
  #onSegmentClick(index, event) {
12467
+ if (this.#clicksSuppressed()) return;
12308
12468
  event.preventDefault();
12309
12469
  event.stopPropagation();
12310
12470
  this.#closeDropdown();
@@ -12312,6 +12472,7 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12312
12472
  this._editStartIndex = index;
12313
12473
  }
12314
12474
  #onTrailingClick() {
12475
+ if (this.#clicksSuppressed()) return;
12315
12476
  this.#closeDropdown();
12316
12477
  this._editing = true;
12317
12478
  this._editStartIndex = null;
@@ -12533,6 +12694,21 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
12533
12694
  cursor: not-allowed;
12534
12695
  }
12535
12696
 
12697
+ /* Drag and drop styles */
12698
+ label[draggable] {
12699
+ cursor: grab;
12700
+ }
12701
+
12702
+ .seg.dragging {
12703
+ opacity: 0.4;
12704
+ }
12705
+
12706
+ .seg.drop-into {
12707
+ outline: var(--crumb-drop-into-outline, 2px solid var(--accent));
12708
+ outline-offset: -2px;
12709
+ background: var(--crumb-drop-into-bg, color-mix(in srgb, var(--accent) 14%, transparent));
12710
+ }
12711
+
12536
12712
  .crumb-icon {
12537
12713
  width: 1em;
12538
12714
  height: 1em;
@@ -12615,6 +12791,8 @@ __decorate([property({
12615
12791
  })], CrumbPathElement.prototype, "pathRoot", void 0);
12616
12792
  __decorate([property({ type: Object })], CrumbPathElement.prototype, "siblingLookup", void 0);
12617
12793
  __decorate([property({ type: Object })], CrumbPathElement.prototype, "segmentIconLookup", void 0);
12794
+ __decorate([property({ type: Object })], CrumbPathElement.prototype, "segmentDragLookup", void 0);
12795
+ __decorate([property({ type: Object })], CrumbPathElement.prototype, "parseExternalDrop", void 0);
12618
12796
  __decorate([state()], CrumbPathElement.prototype, "_openIdx", void 0);
12619
12797
  __decorate([state()], CrumbPathElement.prototype, "_editing", void 0);
12620
12798
  __decorate([state()], CrumbPathElement.prototype, "_cachedSiblings", void 0);
@@ -12624,6 +12802,8 @@ __decorate([state()], CrumbPathElement.prototype, "_dropdownActiveIndex", void 0
12624
12802
  __decorate([state()], CrumbPathElement.prototype, "_editingCancelled", void 0);
12625
12803
  __decorate([state()], CrumbPathElement.prototype, "_editStartIndex", void 0);
12626
12804
  __decorate([state()], CrumbPathElement.prototype, "_openCumPath", void 0);
12805
+ __decorate([state()], CrumbPathElement.prototype, "_dragCumPath", void 0);
12806
+ __decorate([state()], CrumbPathElement.prototype, "_dropCumPath", void 0);
12627
12807
  CrumbPathElement = __decorate([safeCustomElement(`ixfx-crumb-path`)], CrumbPathElement);
12628
12808
  //#endregion
12629
12809
  //#region src/data-display/data-display.ts
@@ -38359,6 +38539,7 @@ let MulticolListElement = class MulticolListElement extends LitElement {
38359
38539
  --multicol-list-border: var(--border);
38360
38540
  --multicol-list-min-column-width: ${MIN_COLUMN_WIDTH}px;
38361
38541
  --multicol-list-max-column-width: ${MAX_COLUMN_WIDTH}px;
38542
+ --multicol-list-header-font-size: unset;
38362
38543
 
38363
38544
  display: block;
38364
38545
  overflow: hidden;
@@ -38424,7 +38605,7 @@ let MulticolListElement = class MulticolListElement extends LitElement {
38424
38605
  text-overflow: ellipsis;
38425
38606
  white-space: nowrap;
38426
38607
  padding: 0 var(--space-s);
38427
- font-size: var(--text-m);
38608
+ font-size: var(--multicol-list-header-font-size);
38428
38609
  font-weight: 600;
38429
38610
  background: transparent;
38430
38611
  border: none;
@@ -42706,8 +42887,14 @@ let RangeInput = class RangeInput extends WheelNudgeMixin(LitElement) {
42706
42887
  const clamped = Math.min(this.max, Math.max(this.min, candidate));
42707
42888
  if (clamped === this.value) return;
42708
42889
  input.value = String(clamped);
42709
- input.dispatchEvent(new Event(`input`, { bubbles: true }));
42710
- input.dispatchEvent(new Event(`change`, { bubbles: true }));
42890
+ input.dispatchEvent(new CustomEvent(`input`, {
42891
+ detail: { value: clamped },
42892
+ bubbles: true
42893
+ }));
42894
+ input.dispatchEvent(new CustomEvent(`change`, {
42895
+ detail: { value: clamped },
42896
+ bubbles: true
42897
+ }));
42711
42898
  }
42712
42899
  render() {
42713
42900
  const tooltipEl = this.tooltip ? html`
@@ -44150,6 +44337,7 @@ let ShapefillValueElement = class ShapefillValueElement extends WheelNudgeMixin(
44150
44337
  this.#dragging = false;
44151
44338
  this.#dragStartY = 0;
44152
44339
  this.#valueAtDragStart = 0;
44340
+ this.#lastPointerY = 0;
44153
44341
  this.#onPointerDown = (event) => {
44154
44342
  if (this.disabled) return;
44155
44343
  event.preventDefault();
@@ -44157,7 +44345,9 @@ let ShapefillValueElement = class ShapefillValueElement extends WheelNudgeMixin(
44157
44345
  svgEl?.focus();
44158
44346
  this.#dragging = true;
44159
44347
  this.#dragStartY = event.clientY;
44348
+ this.#lastPointerY = event.clientY;
44160
44349
  this.#valueAtDragStart = this.value;
44350
+ this.#lastSetValue = this.value;
44161
44351
  this.toggleAttribute(`dragging`, true);
44162
44352
  if (svgEl) svgEl.setPointerCapture(event.pointerId);
44163
44353
  window.addEventListener(`pointermove`, this.#onPointerMove);
@@ -44167,10 +44357,16 @@ let ShapefillValueElement = class ShapefillValueElement extends WheelNudgeMixin(
44167
44357
  this.#onPointerMove = (event) => {
44168
44358
  if (!this.#dragging) return;
44169
44359
  event.preventDefault();
44360
+ if (this.value !== this.#lastSetValue) {
44361
+ this.#valueAtDragStart = this.value;
44362
+ this.#dragStartY = this.#lastPointerY;
44363
+ this.#lastSetValue = this.value;
44364
+ }
44170
44365
  const effectiveSensitivity = this.clientHeight * 2 * (event.shiftKey ? 10 : 1);
44171
44366
  const deltaValue = (this.#dragStartY - event.clientY) / effectiveSensitivity * (this.max - this.min);
44172
44367
  const relativeValue = scale(this.#valueAtDragStart + deltaValue, this.min, this.max, 0, 1);
44173
44368
  this.#setValueFromRelative(clampValue(relativeValue, 0, 1), true);
44369
+ this.#lastPointerY = event.clientY;
44174
44370
  };
44175
44371
  this.#onPointerUp = () => {
44176
44372
  this.#dragging = false;
@@ -44213,6 +44409,10 @@ let ShapefillValueElement = class ShapefillValueElement extends WheelNudgeMixin(
44213
44409
  #dragging;
44214
44410
  #dragStartY;
44215
44411
  #valueAtDragStart;
44412
+ /** Client Y of the last processed pointer event, for external-write re-baselining. */
44413
+ #lastPointerY;
44414
+ /** Value at the drag's last write — detects external `value` writes mid-drag. */
44415
+ #lastSetValue;
44216
44416
  #changeDebounceTimer;
44217
44417
  #getRelativeValue() {
44218
44418
  return scale(this.value, this.min, this.max, 0, 1);
@@ -44230,6 +44430,7 @@ let ShapefillValueElement = class ShapefillValueElement extends WheelNudgeMixin(
44230
44430
  if (clampedValue === this.value) return;
44231
44431
  const previousValue = this.value;
44232
44432
  this.value = clampedValue;
44433
+ this.#lastSetValue = clampedValue;
44233
44434
  if (this.hasAttribute(`data-tooltip-live`)) {
44234
44435
  const percentage = Math.round(this.#getRelativeValue() * 100);
44235
44436
  this.setAttribute(`data-tooltip`, `${percentage}%`);