@ixfx/components 0.7.4 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/bundle/index.d.ts +787 -190
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +2770 -592
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-token.js +1 -1
  6. package/dist/crumbs.d.ts +5 -1
  7. package/dist/crumbs.d.ts.map +1 -1
  8. package/dist/crumbs.js +10 -0
  9. package/dist/crumbs.js.map +1 -1
  10. package/dist/{data-grid-BddUjAti.d.ts → data-grid-D-z7bx5-.d.ts} +26 -1
  11. package/dist/data-grid-D-z7bx5-.d.ts.map +1 -0
  12. package/dist/data-grid.d.ts +1 -1
  13. package/dist/data-grid.js +88 -7
  14. package/dist/data-grid.js.map +1 -1
  15. package/dist/{detail-list-Br0WAnry.d.ts → detail-list-_ZJHYEBr.d.ts} +20 -12
  16. package/dist/detail-list-_ZJHYEBr.d.ts.map +1 -0
  17. package/dist/detail-list.d.ts +2 -2
  18. package/dist/detail-list.js +51 -135
  19. package/dist/detail-list.js.map +1 -1
  20. package/dist/grid-list-nRUQOcEL.js +1537 -0
  21. package/dist/grid-list-nRUQOcEL.js.map +1 -0
  22. package/dist/{grid-list-B_orPsot.d.ts → grid-list-u33vmKzb.d.ts} +128 -10
  23. package/dist/grid-list-u33vmKzb.d.ts.map +1 -0
  24. package/dist/grid-list.d.ts +1 -1
  25. package/dist/grid-list.js +1 -932
  26. package/dist/incr-search-C05WjbZh.js +999 -0
  27. package/dist/incr-search-C05WjbZh.js.map +1 -0
  28. package/dist/incr-search.d.ts +2 -2
  29. package/dist/incr-search.js +2 -3
  30. package/dist/index-h6gxtfHH.d.ts +397 -0
  31. package/dist/index-h6gxtfHH.d.ts.map +1 -0
  32. package/dist/index.d.ts +62 -13
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +343 -17
  35. package/dist/index.js.map +1 -1
  36. package/dist/led.d.ts +33 -1
  37. package/dist/led.d.ts.map +1 -1
  38. package/dist/led.js +157 -13
  39. package/dist/led.js.map +1 -1
  40. package/dist/{list-selection-controller-CUo-Hhcm.js → list-selection-controller-DTFI40li.js} +2 -76
  41. package/dist/list-selection-controller-DTFI40li.js.map +1 -0
  42. package/dist/miller.d.ts +81 -3
  43. package/dist/miller.d.ts.map +1 -1
  44. package/dist/miller.js +327 -68
  45. package/dist/miller.js.map +1 -1
  46. package/dist/narrowed-text.js +1 -2
  47. package/dist/narrowed-text.js.map +1 -1
  48. package/dist/panel.d.ts +3 -1
  49. package/dist/panel.d.ts.map +1 -1
  50. package/dist/panel.js +31 -1
  51. package/dist/panel.js.map +1 -1
  52. package/dist/plots.d.ts +2 -2
  53. package/dist/plots.js +1 -1
  54. package/dist/{titlebar-Bj5pfdw_.d.ts → titlebar-YQ-jVQoS.d.ts} +2 -2
  55. package/dist/{titlebar-Bj5pfdw_.d.ts.map → titlebar-YQ-jVQoS.d.ts.map} +1 -1
  56. package/dist/titlebar.d.ts +1 -1
  57. package/dist/titlebar.js +83 -1
  58. package/dist/titlebar.js.map +1 -1
  59. package/dist/{tree-B74zdI60.js → tree-Chptss7I.js} +77 -15
  60. package/dist/tree-Chptss7I.js.map +1 -0
  61. package/dist/{tree-component-BvV4muxx.d.ts → tree-component-F6qZ0Gdv.d.ts} +9 -1
  62. package/dist/{tree-component-BvV4muxx.d.ts.map → tree-component-F6qZ0Gdv.d.ts.map} +1 -1
  63. package/dist/tree.d.ts +22 -1
  64. package/dist/tree.d.ts.map +1 -1
  65. package/dist/tree.js +1 -1
  66. package/dist/{vertical-list-CQSEVeOT.d.ts → vertical-list-CFuFDygi.d.ts} +17 -14
  67. package/dist/vertical-list-CFuFDygi.d.ts.map +1 -0
  68. package/dist/vertical-list.d.ts +1 -1
  69. package/dist/vertical-list.js +59 -127
  70. package/dist/vertical-list.js.map +1 -1
  71. package/dist/{xy-axis-5KhVTNoX.d.ts → xy-axis-BfP9hKLj.d.ts} +25 -2
  72. package/dist/{xy-axis-5KhVTNoX.d.ts.map → xy-axis-BfP9hKLj.d.ts.map} +1 -1
  73. package/dist/{xy-axis-VrX8dmvS.js → xy-axis-DzM1brBZ.js} +141 -8
  74. package/dist/xy-axis-DzM1brBZ.js.map +1 -0
  75. package/docs-user/data-grid.md +19 -0
  76. package/docs-user/detail-list.md +1 -1
  77. package/docs-user/grid-list.md +120 -11
  78. package/docs-user/incr-search.md +12 -2
  79. package/docs-user/index.json +3 -3
  80. package/docs-user/led.md +37 -7
  81. package/docs-user/llms.txt +1 -1
  82. package/docs-user/panel.md +68 -13
  83. package/docs-user/titlebar.md +3 -4
  84. package/docs-user/tree.md +22 -1
  85. package/docs-user/vertical-list.md +7 -1
  86. package/llms.txt +1 -1
  87. package/package.json +1 -1
  88. package/dist/data-grid-BddUjAti.d.ts.map +0 -1
  89. package/dist/detail-list-Br0WAnry.d.ts.map +0 -1
  90. package/dist/element-search-Y8SRfPGM.js +0 -185
  91. package/dist/element-search-Y8SRfPGM.js.map +0 -1
  92. package/dist/grid-list-B_orPsot.d.ts.map +0 -1
  93. package/dist/grid-list.js.map +0 -1
  94. package/dist/incr-search-vCzuao-2.js +0 -137
  95. package/dist/incr-search-vCzuao-2.js.map +0 -1
  96. package/dist/index-Cu5i8zZY.d.ts +0 -160
  97. package/dist/index-Cu5i8zZY.d.ts.map +0 -1
  98. package/dist/list-selection-controller-CUo-Hhcm.js.map +0 -1
  99. package/dist/tree-B74zdI60.js.map +0 -1
  100. package/dist/vertical-list-CQSEVeOT.d.ts.map +0 -1
  101. package/dist/xy-axis-VrX8dmvS.js.map +0 -1
package/dist/index.js CHANGED
@@ -8,22 +8,21 @@ import { a as iconBus, c as setIconFont, i as hasIcon, l as svgToDataUri, n as g
8
8
  import { t as IxfxIconElement } from "./icon-DcEEGQa_.js";
9
9
  import { AcTextElement } from "./ac-text.js";
10
10
  import { t as DataController } from "./data-controller-DOlmqNKb.js";
11
- import { n as createIncrSearch, r as createFuzzySearch, t as createElementIncrSearch } from "./element-search-Y8SRfPGM.js";
12
- import { n as createAcCompletionProvider, t as IncrSearchTreeController } from "./incr-search-vCzuao-2.js";
11
+ import { a as LIST_SEARCH_COMMAND_IDS, c as createElementListSearchAdapter, d as createDataListSearchAdapter, f as IncrSearchTreeController, h as createFuzzySearch, i as ListSearchController, l as KeyedElementIndex, m as createAcCompletionProvider, n as listSearchStyles, o as registerListSearchCommands, p as createIncrSearch, r as LIST_SEARCH_MODES, s as createElementIncrSearch, t as createTreeListSearchAdapter, u as keyForElement } from "./incr-search-C05WjbZh.js";
13
12
  import { AcTokenElement } from "./ac-token.js";
14
13
  import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-BJwDsMH4.js";
15
14
  import "./icons.js";
16
15
  import { t as prominenceStyles } from "./prominence-DlFShic3.js";
17
16
  import { n as buttonStyles, t as ButtonElement } from "./button-DsFbV4XD.js";
18
- import { i as keyForElement, n as isMultiMode, r as KeyedElementIndex, t as ListSelectionController } from "./list-selection-controller-CUo-Hhcm.js";
19
17
  import { a as prefersReducedMotion, i as listItemFadeKeyframes, n as animateListItemIn, r as animateListItemOut, t as LIST_ITEM_MOTION_MS } from "./list-item-animation-DuiwgN3l.js";
18
+ import { n as isMultiMode, t as ListSelectionController } from "./list-selection-controller-DTFI40li.js";
20
19
  import "./interaction-Cr13azbM.js";
21
20
  import "./menu-item-Bx-Fs7jq.js";
22
21
  import { Checkbox } from "./checkbox.js";
23
22
  import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-Ddsk-7E_.js";
24
23
  import { LabelledRangeInput } from "./labelled-range-input.js";
25
24
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
26
- import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-B74zdI60.js";
25
+ import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-Chptss7I.js";
27
26
  import { t as scrollFadeStyles } from "./scroll-fade-CAs1EabA.js";
28
27
  import { NarrowedTextElement } from "./narrowed-text.js";
29
28
  import { CrumbNavigationElement } from "./crumbs.js";
@@ -38,7 +37,7 @@ import { TitlebarElement } from "./titlebar.js";
38
37
  import { EditableLabel } from "./editable-label.js";
39
38
  import { n as EditableNumber, t as LabelledSliderInput } from "./labelled-slider-input-BInB5GKL.js";
40
39
  import { t as FormElement } from "./form-CsXJX15p.js";
41
- import { GridListElement } from "./grid-list.js";
40
+ import { t as GridListElement } from "./grid-list-nRUQOcEL.js";
42
41
  import { PanelElement } from "./panel.js";
43
42
  import { GroupedItemListerElement } from "./grouped-item-lister.js";
44
43
  import { VerticalListElement } from "./vertical-list.js";
@@ -49,7 +48,7 @@ import { t as SliderInputElement } from "./slider-input-Bl1hFE89.js";
49
48
  import { LedElement } from "./led.js";
50
49
  import { MillerBaseElement, MillerListElement, MillerTreeController } from "./miller.js";
51
50
  import { NotificationPillElement } from "./notifier.js";
52
- import { a as TooltipElement, c as computeColour, i as PlotMultiAxis, l as parseColourScaleAttr, n as PlotSingleAxis, o as PlotDataSeries, r as PlotHistogram, s as applyAgeModification, t as PlotXyAxis, u as readBaseColour } from "./xy-axis-VrX8dmvS.js";
51
+ import { a as TooltipElement, c as computeColour, i as PlotMultiAxis, l as parseColourScaleAttr, n as PlotSingleAxis, o as PlotDataSeries, r as PlotHistogram, s as applyAgeModification, t as PlotXyAxis, u as readBaseColour } from "./xy-axis-DzM1brBZ.js";
53
52
  import { PolarPad } from "./polar-pad.js";
54
53
  import { t as tooltipValueStyles } from "./tooltip-CJt3WLmN.js";
55
54
  import { RangeInput } from "./range-input.js";
@@ -2944,7 +2943,7 @@ TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabLi
2944
2943
  //#endregion
2945
2944
  //#region src/dock/dock-panel.ts
2946
2945
  /** Pointer movement threshold before a titlebar press becomes a dock drag. */
2947
- const DRAG_THRESHOLD_PX$1 = 5;
2946
+ const DRAG_THRESHOLD_PX$2 = 5;
2948
2947
  let DockPanelElement = class DockPanelElement extends LitElement {
2949
2948
  constructor(..._args) {
2950
2949
  super(..._args);
@@ -2976,7 +2975,7 @@ let DockPanelElement = class DockPanelElement extends LitElement {
2976
2975
  this._onPointerMove = (event) => {
2977
2976
  if (this._dragPointerId === null || event.pointerId !== this._dragPointerId) return;
2978
2977
  if (!this._dragStarted) {
2979
- if (Math.hypot(event.clientX - this._dragStartX, event.clientY - this._dragStartY) < DRAG_THRESHOLD_PX$1) return;
2978
+ if (Math.hypot(event.clientX - this._dragStartX, event.clientY - this._dragStartY) < DRAG_THRESHOLD_PX$2) return;
2980
2979
  this._dragStarted = true;
2981
2980
  const pointerId = this._dragPointerId;
2982
2981
  this._teardownDragListeners();
@@ -3131,7 +3130,7 @@ DockPanelElement = __decorate([safeCustomElement(`ixfx-dock-panel`)], DockPanelE
3131
3130
  /** Fraction of the leaf rect (from each edge) that forms the split bands. */
3132
3131
  const BAND = .25;
3133
3132
  /** Pointer movement threshold before a press becomes a dock drag (matches tab-list). */
3134
- const DRAG_THRESHOLD_PX = 5;
3133
+ const DRAG_THRESHOLD_PX$1 = 5;
3135
3134
  /** Tolerance (px) when matching a child gutter endpoint to a parent gutter line. */
3136
3135
  const JUNCTION_TOL_PX = 6;
3137
3136
  /** Junction points closer than this merge into one handle (a 4-way cross yields one per side). */
@@ -3246,7 +3245,7 @@ let DockHostElement = class DockHostElement extends LitElement {
3246
3245
  this._onTabDragMove = (event) => {
3247
3246
  const pending = this._tabDragPending;
3248
3247
  if (pending === null || event.pointerId !== pending.pointerId) return;
3249
- if (Math.hypot(event.clientX - pending.startX, event.clientY - pending.startY) < DRAG_THRESHOLD_PX) return;
3248
+ if (Math.hypot(event.clientX - pending.startX, event.clientY - pending.startY) < DRAG_THRESHOLD_PX$1) return;
3250
3249
  this._tabDragPending = null;
3251
3250
  this._teardownTabDragListeners();
3252
3251
  this._suppressNextClick();
@@ -5292,6 +5291,66 @@ __decorate([query(`.text`)], PanTextElement.prototype, "_textEl", void 0);
5292
5291
  PanTextElement = __decorate([safeCustomElement(`ixfx-pan-text`)], PanTextElement);
5293
5292
  //#endregion
5294
5293
  //#region src/panel/panel-group.ts
5294
+ /** Pointer movement threshold (px) before a press becomes a drag. */
5295
+ const DRAG_THRESHOLD_PX = 5;
5296
+ /**
5297
+ * Pure helper: nearest gap index for a pointer position along one axis.
5298
+ * `edges` are the [start, end] of each sibling (excluding the drag source),
5299
+ * in DOM order. Returns 0..edges.length.
5300
+ */
5301
+ function panelGapIndex(edges, pos) {
5302
+ let bestGap = 0;
5303
+ let bestDist = Number.POSITIVE_INFINITY;
5304
+ for (let i = 0; i < edges.length; i++) {
5305
+ const [start, end] = edges[i];
5306
+ if (pos < (start + end) / 2) {
5307
+ const d = Math.abs(pos - start);
5308
+ if (d < bestDist) {
5309
+ bestDist = d;
5310
+ bestGap = i;
5311
+ }
5312
+ } else {
5313
+ const d = Math.abs(pos - end);
5314
+ if (d < bestDist) {
5315
+ bestDist = d;
5316
+ bestGap = i + 1;
5317
+ }
5318
+ }
5319
+ }
5320
+ return bestGap;
5321
+ }
5322
+ let panelGhostStylesInjected = false;
5323
+ /**
5324
+ * Global ghost styling so the drag preview matches `ixfx-titlebar` chrome
5325
+ * (font, colours, padding). Injected once; the ghost lives outside shadow DOM
5326
+ * (body/theme container) so component styles cannot reach it.
5327
+ */
5328
+ function injectPanelGhostStyles() {
5329
+ if (panelGhostStylesInjected) return;
5330
+ panelGhostStylesInjected = true;
5331
+ const style = document.createElement(`style`);
5332
+ style.textContent = `
5333
+ .ixfx-drag-ghost.ixfx-panel-group-ghost {
5334
+ padding: var(--space-s, 8px) var(--space-m, 16px);
5335
+ background: var(--surface-4);
5336
+ color: var(--surface-3-text);
5337
+ border: none;
5338
+ border-radius: var(--radius-s, 4px);
5339
+ font-family: var(--font-family);
5340
+ font-size: var(--text-m);
5341
+ font-weight: var(--font-weight-bold, 600);
5342
+ min-height: 2em;
5343
+ user-select: none;
5344
+ -webkit-user-select: none;
5345
+ }
5346
+ .ixfx-drag-ghost.ixfx-panel-group-ghost ixfx-icon {
5347
+ width: 1.25em;
5348
+ height: 1.25em;
5349
+ flex-shrink: 0;
5350
+ }
5351
+ `;
5352
+ document.head.appendChild(style);
5353
+ }
5295
5354
  let PanelGroupElement = class PanelGroupElement extends LitElement {
5296
5355
  constructor(..._args) {
5297
5356
  super(..._args);
@@ -5299,22 +5358,105 @@ let PanelGroupElement = class PanelGroupElement extends LitElement {
5299
5358
  this.variant = `titlebar`;
5300
5359
  this.toggleInteraction = `implicit`;
5301
5360
  this.collapsible = true;
5302
- this.allowMultiple = false;
5303
- this.gap = `var(--space-m)`;
5361
+ this.accordion = false;
5362
+ this.allowReorder = false;
5363
+ this._dragState = null;
5364
+ this._suppressNextClick = false;
5365
+ this._onClickCapture = (event) => {
5366
+ if (!this._suppressNextClick) return;
5367
+ this._suppressNextClick = false;
5368
+ event.preventDefault();
5369
+ event.stopPropagation();
5370
+ };
5371
+ this._onKeyDown = (event) => {
5372
+ const state = this._dragState;
5373
+ if (event.key !== `Escape` || !state?.active) return;
5374
+ event.preventDefault();
5375
+ const pointerId = state.pointerId;
5376
+ this._abortDrag();
5377
+ this._endDrag(pointerId);
5378
+ };
5379
+ this._onPointerDown = (event) => {
5380
+ if (!this.allowReorder || event.button !== 0) return;
5381
+ const target = this._findDragTarget(event);
5382
+ if (!target?.parentNode) return;
5383
+ const fromIndex = Array.prototype.indexOf.call(target.parentNode.children, target);
5384
+ if (fromIndex < 0) return;
5385
+ this._dragState = {
5386
+ pointerId: event.pointerId,
5387
+ source: target,
5388
+ fromIndex,
5389
+ startX: event.clientX,
5390
+ startY: event.clientY,
5391
+ active: false,
5392
+ ghost: null,
5393
+ gapIndex: void 0
5394
+ };
5395
+ window.addEventListener(`pointermove`, this._onPointerMove);
5396
+ window.addEventListener(`pointerup`, this._onPointerUp);
5397
+ window.addEventListener(`pointercancel`, this._onPointerCancel);
5398
+ };
5399
+ this._onPointerMove = (event) => {
5400
+ const state = this._dragState;
5401
+ if (!state || event.pointerId !== state.pointerId) return;
5402
+ const distance = Math.hypot(event.clientX - state.startX, event.clientY - state.startY);
5403
+ if (!state.active) {
5404
+ if (distance < DRAG_THRESHOLD_PX) return;
5405
+ this._beginDrag(event);
5406
+ }
5407
+ state.ghost?.move(event.clientX, event.clientY);
5408
+ const gap = this._computeGapIndex(event.clientX, event.clientY);
5409
+ if (gap !== state.gapIndex) {
5410
+ state.gapIndex = gap;
5411
+ this.requestUpdate();
5412
+ }
5413
+ };
5414
+ this._onPointerUp = (event) => {
5415
+ const state = this._dragState;
5416
+ if (!state || event.pointerId !== state.pointerId) return;
5417
+ if (state.active) {
5418
+ const gap = this._computeGapIndex(event.clientX, event.clientY);
5419
+ this._commitDrag(state.source, state.fromIndex, gap);
5420
+ }
5421
+ this._endDrag(event.pointerId);
5422
+ };
5423
+ this._onPointerCancel = (event) => {
5424
+ const state = this._dragState;
5425
+ if (!state || event.pointerId !== state.pointerId) return;
5426
+ this._abortDrag();
5427
+ this._endDrag(event.pointerId);
5428
+ };
5304
5429
  }
5305
5430
  _onPanelToggle(e) {
5306
5431
  const panel = e.target;
5307
5432
  if (panel.collapsed) return;
5308
- if (this.allowMultiple) return;
5433
+ if (!this.accordion) return;
5309
5434
  for (const p of this._panels) if (p !== panel) p.collapsed = true;
5310
5435
  }
5436
+ connectedCallback() {
5437
+ super.connectedCallback();
5438
+ this.addEventListener(`click`, this._onClickCapture, true);
5439
+ }
5440
+ disconnectedCallback() {
5441
+ this.removeEventListener(`click`, this._onClickCapture, true);
5442
+ if (this._dragState) {
5443
+ this._abortDrag();
5444
+ this._endDrag(this._dragState.pointerId);
5445
+ }
5446
+ super.disconnectedCallback();
5447
+ }
5311
5448
  firstUpdated() {
5449
+ if (this.gap !== void 0) this.style.setProperty(`--group-gap`, this.gap);
5312
5450
  this.updateComplete.then(() => {
5313
5451
  this._propagateAll();
5314
5452
  });
5315
5453
  }
5316
5454
  updated(changed) {
5317
5455
  super.updated(changed);
5456
+ if (changed.has(`gap`)) {
5457
+ if (this.gap !== void 0) this.style.setProperty(`--group-gap`, this.gap);
5458
+ else this.style.removeProperty(`--group-gap`);
5459
+ }
5318
5460
  if (changed.has(`variant`) || changed.has(`toggleInteraction`) || changed.has(`orientation`) || changed.has(`collapsible`)) this.updateComplete.then(() => {
5319
5461
  this._propagateAll();
5320
5462
  });
@@ -5329,19 +5471,167 @@ let PanelGroupElement = class PanelGroupElement extends LitElement {
5329
5471
  else panel.removeAttribute(`collapsible`);
5330
5472
  }
5331
5473
  }
5474
+ _onSlotChange() {
5475
+ this.updateComplete.then(() => {
5476
+ this._propagateAll();
5477
+ });
5478
+ }
5479
+ /**
5480
+ * Walk composedPath for the nearest ixfx-panel, requiring the press to have
5481
+ * gone through an ixfx-titlebar (titlebar-anywhere drag). Bails when the
5482
+ * path crosses interactive chrome (buttons/links/inputs/toolbar/caret/close)
5483
+ * so those controls always win over dragging.
5484
+ */
5485
+ _findDragTarget(event) {
5486
+ if (!this.allowReorder) return null;
5487
+ const path = event.composedPath();
5488
+ let panel = null;
5489
+ let viaTitlebar = false;
5490
+ for (const node of path) {
5491
+ if (!(node instanceof HTMLElement)) continue;
5492
+ const tag = node.tagName;
5493
+ if (tag === `BUTTON` || tag === `A` || tag === `INPUT` || tag === `SELECT` || tag === `TEXTAREA`) return null;
5494
+ if (node.classList.contains(`toolbar`) || node.classList.contains(`close-btn`) || node.classList.contains(`caret-btn`)) return null;
5495
+ if (node.hasAttribute?.(`slot`) && node.getAttribute(`slot`) === `toolbar`) return null;
5496
+ if (tag === `IXFX-TITLEBAR`) viaTitlebar = true;
5497
+ if (!panel && tag === `IXFX-PANEL`) panel = node;
5498
+ }
5499
+ if (!panel || !viaTitlebar) return null;
5500
+ return panel;
5501
+ }
5502
+ _beginDrag(event) {
5503
+ const state = this._dragState;
5504
+ if (!state || state.active) return;
5505
+ try {
5506
+ this.setPointerCapture(event.pointerId);
5507
+ } catch {}
5508
+ state.active = true;
5509
+ this.setAttribute(`dragging`, ``);
5510
+ state.source.setAttribute(`drag-source`, ``);
5511
+ state.ghost = this._createGhost(state.source);
5512
+ state.ghost?.move(event.clientX, event.clientY);
5513
+ }
5514
+ _abortDrag() {
5515
+ const state = this._dragState;
5516
+ if (!state) return;
5517
+ state.source.removeAttribute(`drag-source`);
5518
+ if (state.gapIndex !== void 0) {
5519
+ state.gapIndex = void 0;
5520
+ this.requestUpdate();
5521
+ }
5522
+ }
5523
+ _endDrag(pointerId) {
5524
+ const state = this._dragState;
5525
+ if (!state) return;
5526
+ state.ghost?.destroy();
5527
+ state.ghost = null;
5528
+ this.removeAttribute(`dragging`);
5529
+ this._dragState = null;
5530
+ window.removeEventListener(`pointermove`, this._onPointerMove);
5531
+ window.removeEventListener(`pointerup`, this._onPointerUp);
5532
+ window.removeEventListener(`pointercancel`, this._onPointerCancel);
5533
+ try {
5534
+ this.releasePointerCapture(pointerId);
5535
+ } catch {}
5536
+ this.requestUpdate();
5537
+ }
5538
+ _commitDrag(source, fromIndex, gapIndex) {
5539
+ source.removeAttribute(`drag-source`);
5540
+ const siblings = (this._panels ?? []).filter((el) => el !== source);
5541
+ const target = gapIndex === void 0 ? siblings.length : Math.max(0, Math.min(gapIndex, siblings.length));
5542
+ const parent = source.parentNode;
5543
+ if (!parent) return;
5544
+ const ref = siblings[target] ?? null;
5545
+ parent.insertBefore(source, ref);
5546
+ const toIndex = Array.prototype.indexOf.call(parent.children, source);
5547
+ if (toIndex === fromIndex) return;
5548
+ this._suppressNextClick = true;
5549
+ this.dispatchEvent(new CustomEvent(`reorder`, {
5550
+ bubbles: true,
5551
+ composed: true,
5552
+ detail: {
5553
+ fromIndex,
5554
+ toIndex,
5555
+ panel: source
5556
+ }
5557
+ }));
5558
+ }
5559
+ _createGhost(source) {
5560
+ const content = document.createElement(`span`);
5561
+ content.style.display = `inline-flex`;
5562
+ content.style.alignItems = `center`;
5563
+ content.style.padding = `0 var(--space-s, 8px)`;
5564
+ content.style.minWidth = `0`;
5565
+ if (source.iconName) {
5566
+ const icon = document.createElement(`ixfx-icon`);
5567
+ icon.name = source.iconName;
5568
+ content.appendChild(icon);
5569
+ }
5570
+ const label = document.createElement(`span`);
5571
+ label.textContent = (source.title || (source.textContent ?? ``).trim()).slice(0, 60);
5572
+ label.style.paddingLeft = `1ch`;
5573
+ label.style.overflow = `hidden`;
5574
+ label.style.textOverflow = `ellipsis`;
5575
+ label.style.whiteSpace = `nowrap`;
5576
+ content.appendChild(label);
5577
+ try {
5578
+ injectPanelGhostStyles();
5579
+ return createDragGhost({
5580
+ anchor: source,
5581
+ content,
5582
+ className: `ixfx-panel-group-ghost`
5583
+ });
5584
+ } catch {
5585
+ return null;
5586
+ }
5587
+ }
5588
+ /**
5589
+ * Nearest panel gap to the pointer, ignoring the drag source.
5590
+ * The perpendicular axis is ignored — the pointer always resolves to a gap.
5591
+ */
5592
+ _computeGapIndex(clientX, clientY) {
5593
+ const state = this._dragState;
5594
+ if (!state) return;
5595
+ const siblings = (this._panels ?? []).filter((el) => el !== state.source);
5596
+ if (siblings.length === 0) return 0;
5597
+ const useX = this.orientation === `horizontal`;
5598
+ const pos = useX ? clientX : clientY;
5599
+ return panelGapIndex(siblings.map((el) => {
5600
+ const rect = el.getBoundingClientRect();
5601
+ return [useX ? rect.left : rect.top, useX ? rect.right : rect.bottom];
5602
+ }), pos);
5603
+ }
5604
+ _computeCaretStyle() {
5605
+ const state = this._dragState;
5606
+ if (!state?.active || state.gapIndex === void 0) return;
5607
+ const siblings = (this._panels ?? []).filter((el) => el !== state.source);
5608
+ if (siblings.length === 0) return;
5609
+ const hostRect = this.getBoundingClientRect();
5610
+ if (!hostRect) return;
5611
+ const gap = Math.max(0, Math.min(state.gapIndex, siblings.length));
5612
+ const rect = gap < siblings.length ? siblings[gap].getBoundingClientRect() : siblings[siblings.length - 1].getBoundingClientRect();
5613
+ if (this.orientation === `horizontal`) return `transform: translate(${(gap < siblings.length ? rect.left : rect.right) - hostRect.left - 1}px, 0); width: 2px; height: ${hostRect.height}px;`;
5614
+ return `transform: translate(0, ${(gap < siblings.length ? rect.top : rect.bottom) - hostRect.top - 1}px); width: ${hostRect.width}px; height: 2px;`;
5615
+ }
5332
5616
  render() {
5617
+ const caretStyle = this._computeCaretStyle();
5333
5618
  return html`
5334
5619
  <slot
5335
5620
  @toggle=${this._onPanelToggle}
5621
+ @slotchange=${this._onSlotChange}
5622
+ @pointerdown=${this._onPointerDown}
5623
+ @keydown=${this._onKeyDown}
5336
5624
  ></slot>
5625
+ ${caretStyle ? html`<div class="drop-caret" style=${caretStyle}></div>` : nothing}
5337
5626
  `;
5338
5627
  }
5339
5628
  static {
5340
5629
  this.styles = css`
5341
5630
  :host {
5631
+ position: relative;
5342
5632
  display: flex;
5343
5633
  flex-direction: column;
5344
- gap: var(--group-gap, var(--space-m));
5634
+ gap: var(--group-gap, var(--space-l));
5345
5635
  }
5346
5636
 
5347
5637
  :host([orientation="horizontal"]) {
@@ -5362,6 +5652,36 @@ let PanelGroupElement = class PanelGroupElement extends LitElement {
5362
5652
  flex-basis: content;
5363
5653
  min-width: 0;
5364
5654
  }
5655
+
5656
+ :host([allow-reorder]) ::slotted(ixfx-panel) {
5657
+ cursor: grab;
5658
+ }
5659
+
5660
+ :host([allow-reorder]) ::slotted(ixfx-panel[drag-source]) {
5661
+ cursor: grabbing;
5662
+ opacity: 0.4;
5663
+ }
5664
+
5665
+ /* While dragging, suppress text selection inside the panels. */
5666
+ :host([dragging]),
5667
+ :host([dragging]) ::slotted(*) {
5668
+ user-select: none;
5669
+ -webkit-user-select: none;
5670
+ }
5671
+
5672
+ :host([dragging]) ::slotted(ixfx-panel) {
5673
+ cursor: grabbing;
5674
+ }
5675
+
5676
+ .drop-caret {
5677
+ position: absolute;
5678
+ top: 0;
5679
+ left: 0;
5680
+ background: var(--accent);
5681
+ border-radius: 1px;
5682
+ pointer-events: none;
5683
+ z-index: 1;
5684
+ }
5365
5685
  `;
5366
5686
  }
5367
5687
  };
@@ -5377,8 +5697,14 @@ __decorate([property({
5377
5697
  __decorate([property({ type: Boolean })], PanelGroupElement.prototype, "collapsible", void 0);
5378
5698
  __decorate([property({
5379
5699
  type: Boolean,
5380
- attribute: `allow-multiple`
5381
- })], PanelGroupElement.prototype, "allowMultiple", void 0);
5700
+ attribute: `accordion`,
5701
+ reflect: true
5702
+ })], PanelGroupElement.prototype, "accordion", void 0);
5703
+ __decorate([property({
5704
+ type: Boolean,
5705
+ attribute: `allow-reorder`,
5706
+ reflect: true
5707
+ })], PanelGroupElement.prototype, "allowReorder", void 0);
5382
5708
  __decorate([property()], PanelGroupElement.prototype, "gap", void 0);
5383
5709
  __decorate([queryAssignedElements({ slot: `` })], PanelGroupElement.prototype, "_panels", void 0);
5384
5710
  PanelGroupElement = __decorate([safeCustomElement(`ixfx-panel-group`)], PanelGroupElement);
@@ -7981,6 +8307,6 @@ function init() {
7981
8307
  console.log(`Init`);
7982
8308
  }
7983
8309
  //#endregion
7984
- export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeKeyboardNavController, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, attachTimelineInteractions, buildHighlightTargets, buildModel, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeLeafGeoms, createAcCompletionProvider, createElementIncrSearch, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createVerticalListAdapter, distribute, extractStack, findNode, findParentOf, findStackOf, findStackPathByName, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normalize, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, readBaseColour, registerFontIcon, registerIcon, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, walk, wrapRoot };
8310
+ export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeKeyboardNavController, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, attachTimelineInteractions, buildHighlightTargets, buildModel, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeLeafGeoms, createAcCompletionProvider, createDataListSearchAdapter, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, extractStack, findNode, findParentOf, findStackOf, findStackPathByName, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, walk, wrapRoot };
7985
8311
 
7986
8312
  //# sourceMappingURL=index.js.map