@ixfx/components 0.7.5 → 0.8.1

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 (73) hide show
  1. package/bundle/index.d.ts +256 -17
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +1462 -166
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-token.js +1 -1
  6. package/dist/{data-grid-CtJ35v8L.d.ts → data-grid-D-z7bx5-.d.ts} +2 -2
  7. package/dist/{data-grid-CtJ35v8L.d.ts.map → data-grid-D-z7bx5-.d.ts.map} +1 -1
  8. package/dist/data-grid.d.ts +1 -1
  9. package/dist/data-grid.js +1 -1
  10. package/dist/{detail-list-BS5dRDda.d.ts → detail-list-_ZJHYEBr.d.ts} +3 -3
  11. package/dist/{detail-list-BS5dRDda.d.ts.map → detail-list-_ZJHYEBr.d.ts.map} +1 -1
  12. package/dist/detail-list.d.ts +2 -2
  13. package/dist/detail-list.js +1 -1
  14. package/dist/grid-list-nRUQOcEL.js +1537 -0
  15. package/dist/grid-list-nRUQOcEL.js.map +1 -0
  16. package/dist/{grid-list-D-GbghSH.d.ts → grid-list-u33vmKzb.d.ts} +116 -15
  17. package/dist/grid-list-u33vmKzb.d.ts.map +1 -0
  18. package/dist/grid-list.d.ts +1 -1
  19. package/dist/grid-list.js +1 -993
  20. package/dist/{incr-search-DpbSJtgj.js → incr-search-C05WjbZh.js} +40 -3
  21. package/dist/incr-search-C05WjbZh.js.map +1 -0
  22. package/dist/incr-search.d.ts +2 -2
  23. package/dist/incr-search.js +2 -2
  24. package/dist/{index-CBS4z1v-.d.ts → index-h6gxtfHH.d.ts} +34 -2
  25. package/dist/index-h6gxtfHH.d.ts.map +1 -0
  26. package/dist/index.d.ts +60 -11
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +343 -16
  29. package/dist/index.js.map +1 -1
  30. package/dist/led.d.ts +33 -1
  31. package/dist/led.d.ts.map +1 -1
  32. package/dist/led.js +157 -13
  33. package/dist/led.js.map +1 -1
  34. package/dist/miller.d.ts +1 -1
  35. package/dist/miller.js +1 -1
  36. package/dist/narrowed-text.js +1 -1
  37. package/dist/panel.d.ts +3 -1
  38. package/dist/panel.d.ts.map +1 -1
  39. package/dist/panel.js +31 -1
  40. package/dist/panel.js.map +1 -1
  41. package/dist/plots.d.ts +2 -2
  42. package/dist/plots.js +1 -1
  43. package/dist/{titlebar-Bj5pfdw_.d.ts → titlebar-YQ-jVQoS.d.ts} +2 -2
  44. package/dist/{titlebar-Bj5pfdw_.d.ts.map → titlebar-YQ-jVQoS.d.ts.map} +1 -1
  45. package/dist/titlebar.d.ts +1 -1
  46. package/dist/titlebar.js +83 -1
  47. package/dist/titlebar.js.map +1 -1
  48. package/dist/{tree-DAii2A1g.js → tree-Chptss7I.js} +2 -2
  49. package/dist/{tree-DAii2A1g.js.map → tree-Chptss7I.js.map} +1 -1
  50. package/dist/tree.d.ts +1 -1
  51. package/dist/tree.js +1 -1
  52. package/dist/{vertical-list-DwtCPy1b.d.ts → vertical-list-CFuFDygi.d.ts} +2 -2
  53. package/dist/{vertical-list-DwtCPy1b.d.ts.map → vertical-list-CFuFDygi.d.ts.map} +1 -1
  54. package/dist/vertical-list.d.ts +1 -1
  55. package/dist/vertical-list.js +1 -1
  56. package/dist/{xy-axis-5KhVTNoX.d.ts → xy-axis-BfP9hKLj.d.ts} +25 -2
  57. package/dist/{xy-axis-5KhVTNoX.d.ts.map → xy-axis-BfP9hKLj.d.ts.map} +1 -1
  58. package/dist/{xy-axis-VrX8dmvS.js → xy-axis-DzM1brBZ.js} +141 -8
  59. package/dist/xy-axis-DzM1brBZ.js.map +1 -0
  60. package/docs-user/dock.md +1 -0
  61. package/docs-user/grid-list.md +99 -14
  62. package/docs-user/index.json +3 -3
  63. package/docs-user/led.md +37 -7
  64. package/docs-user/llms.txt +1 -1
  65. package/docs-user/panel.md +68 -13
  66. package/docs-user/titlebar.md +3 -4
  67. package/llms.txt +1 -1
  68. package/package.json +1 -1
  69. package/dist/grid-list-D-GbghSH.d.ts.map +0 -1
  70. package/dist/grid-list.js.map +0 -1
  71. package/dist/incr-search-DpbSJtgj.js.map +0 -1
  72. package/dist/index-CBS4z1v-.d.ts.map +0 -1
  73. package/dist/xy-axis-VrX8dmvS.js.map +0 -1
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ 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 { a as LIST_SEARCH_COMMAND_IDS, c as createElementListSearchAdapter, d as IncrSearchTreeController, f as createIncrSearch, i as ListSearchController, l as KeyedElementIndex, m as createFuzzySearch, n as listSearchStyles, o as registerListSearchCommands, p as createAcCompletionProvider, r as LIST_SEARCH_MODES, s as createElementIncrSearch, t as createTreeListSearchAdapter, u as keyForElement } from "./incr-search-DpbSJtgj.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";
12
12
  import { AcTokenElement } from "./ac-token.js";
13
13
  import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-BJwDsMH4.js";
14
14
  import "./icons.js";
@@ -22,7 +22,7 @@ import { Checkbox } from "./checkbox.js";
22
22
  import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-Ddsk-7E_.js";
23
23
  import { LabelledRangeInput } from "./labelled-range-input.js";
24
24
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
25
- import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-DAii2A1g.js";
25
+ import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-Chptss7I.js";
26
26
  import { t as scrollFadeStyles } from "./scroll-fade-CAs1EabA.js";
27
27
  import { NarrowedTextElement } from "./narrowed-text.js";
28
28
  import { CrumbNavigationElement } from "./crumbs.js";
@@ -37,7 +37,7 @@ import { TitlebarElement } from "./titlebar.js";
37
37
  import { EditableLabel } from "./editable-label.js";
38
38
  import { n as EditableNumber, t as LabelledSliderInput } from "./labelled-slider-input-BInB5GKL.js";
39
39
  import { t as FormElement } from "./form-CsXJX15p.js";
40
- import { GridListElement } from "./grid-list.js";
40
+ import { t as GridListElement } from "./grid-list-nRUQOcEL.js";
41
41
  import { PanelElement } from "./panel.js";
42
42
  import { GroupedItemListerElement } from "./grouped-item-lister.js";
43
43
  import { VerticalListElement } from "./vertical-list.js";
@@ -48,7 +48,7 @@ import { t as SliderInputElement } from "./slider-input-Bl1hFE89.js";
48
48
  import { LedElement } from "./led.js";
49
49
  import { MillerBaseElement, MillerListElement, MillerTreeController } from "./miller.js";
50
50
  import { NotificationPillElement } from "./notifier.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-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";
52
52
  import { PolarPad } from "./polar-pad.js";
53
53
  import { t as tooltipValueStyles } from "./tooltip-CJt3WLmN.js";
54
54
  import { RangeInput } from "./range-input.js";
@@ -2943,7 +2943,7 @@ TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabLi
2943
2943
  //#endregion
2944
2944
  //#region src/dock/dock-panel.ts
2945
2945
  /** Pointer movement threshold before a titlebar press becomes a dock drag. */
2946
- const DRAG_THRESHOLD_PX$1 = 5;
2946
+ const DRAG_THRESHOLD_PX$2 = 5;
2947
2947
  let DockPanelElement = class DockPanelElement extends LitElement {
2948
2948
  constructor(..._args) {
2949
2949
  super(..._args);
@@ -2975,7 +2975,7 @@ let DockPanelElement = class DockPanelElement extends LitElement {
2975
2975
  this._onPointerMove = (event) => {
2976
2976
  if (this._dragPointerId === null || event.pointerId !== this._dragPointerId) return;
2977
2977
  if (!this._dragStarted) {
2978
- 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;
2979
2979
  this._dragStarted = true;
2980
2980
  const pointerId = this._dragPointerId;
2981
2981
  this._teardownDragListeners();
@@ -3130,7 +3130,7 @@ DockPanelElement = __decorate([safeCustomElement(`ixfx-dock-panel`)], DockPanelE
3130
3130
  /** Fraction of the leaf rect (from each edge) that forms the split bands. */
3131
3131
  const BAND = .25;
3132
3132
  /** Pointer movement threshold before a press becomes a dock drag (matches tab-list). */
3133
- const DRAG_THRESHOLD_PX = 5;
3133
+ const DRAG_THRESHOLD_PX$1 = 5;
3134
3134
  /** Tolerance (px) when matching a child gutter endpoint to a parent gutter line. */
3135
3135
  const JUNCTION_TOL_PX = 6;
3136
3136
  /** Junction points closer than this merge into one handle (a 4-way cross yields one per side). */
@@ -3245,7 +3245,7 @@ let DockHostElement = class DockHostElement extends LitElement {
3245
3245
  this._onTabDragMove = (event) => {
3246
3246
  const pending = this._tabDragPending;
3247
3247
  if (pending === null || event.pointerId !== pending.pointerId) return;
3248
- 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;
3249
3249
  this._tabDragPending = null;
3250
3250
  this._teardownTabDragListeners();
3251
3251
  this._suppressNextClick();
@@ -4347,7 +4347,7 @@ let DockHostElement = class DockHostElement extends LitElement {
4347
4347
  min-height: 0;
4348
4348
  min-width: 0;
4349
4349
  box-sizing: border-box;
4350
- padding: var(--space-s);
4350
+ padding: var(--dock-leaf-body-padding, var(--space-s));
4351
4351
  }
4352
4352
 
4353
4353
  .empty {
@@ -5291,6 +5291,66 @@ __decorate([query(`.text`)], PanTextElement.prototype, "_textEl", void 0);
5291
5291
  PanTextElement = __decorate([safeCustomElement(`ixfx-pan-text`)], PanTextElement);
5292
5292
  //#endregion
5293
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
+ }
5294
5354
  let PanelGroupElement = class PanelGroupElement extends LitElement {
5295
5355
  constructor(..._args) {
5296
5356
  super(..._args);
@@ -5298,22 +5358,105 @@ let PanelGroupElement = class PanelGroupElement extends LitElement {
5298
5358
  this.variant = `titlebar`;
5299
5359
  this.toggleInteraction = `implicit`;
5300
5360
  this.collapsible = true;
5301
- this.allowMultiple = false;
5302
- 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
+ };
5303
5429
  }
5304
5430
  _onPanelToggle(e) {
5305
5431
  const panel = e.target;
5306
5432
  if (panel.collapsed) return;
5307
- if (this.allowMultiple) return;
5433
+ if (!this.accordion) return;
5308
5434
  for (const p of this._panels) if (p !== panel) p.collapsed = true;
5309
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
+ }
5310
5448
  firstUpdated() {
5449
+ if (this.gap !== void 0) this.style.setProperty(`--group-gap`, this.gap);
5311
5450
  this.updateComplete.then(() => {
5312
5451
  this._propagateAll();
5313
5452
  });
5314
5453
  }
5315
5454
  updated(changed) {
5316
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
+ }
5317
5460
  if (changed.has(`variant`) || changed.has(`toggleInteraction`) || changed.has(`orientation`) || changed.has(`collapsible`)) this.updateComplete.then(() => {
5318
5461
  this._propagateAll();
5319
5462
  });
@@ -5328,19 +5471,167 @@ let PanelGroupElement = class PanelGroupElement extends LitElement {
5328
5471
  else panel.removeAttribute(`collapsible`);
5329
5472
  }
5330
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
+ }
5331
5616
  render() {
5617
+ const caretStyle = this._computeCaretStyle();
5332
5618
  return html`
5333
5619
  <slot
5334
5620
  @toggle=${this._onPanelToggle}
5621
+ @slotchange=${this._onSlotChange}
5622
+ @pointerdown=${this._onPointerDown}
5623
+ @keydown=${this._onKeyDown}
5335
5624
  ></slot>
5625
+ ${caretStyle ? html`<div class="drop-caret" style=${caretStyle}></div>` : nothing}
5336
5626
  `;
5337
5627
  }
5338
5628
  static {
5339
5629
  this.styles = css`
5340
5630
  :host {
5631
+ position: relative;
5341
5632
  display: flex;
5342
5633
  flex-direction: column;
5343
- gap: var(--group-gap, var(--space-m));
5634
+ gap: var(--group-gap, var(--space-l));
5344
5635
  }
5345
5636
 
5346
5637
  :host([orientation="horizontal"]) {
@@ -5361,6 +5652,36 @@ let PanelGroupElement = class PanelGroupElement extends LitElement {
5361
5652
  flex-basis: content;
5362
5653
  min-width: 0;
5363
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
+ }
5364
5685
  `;
5365
5686
  }
5366
5687
  };
@@ -5376,8 +5697,14 @@ __decorate([property({
5376
5697
  __decorate([property({ type: Boolean })], PanelGroupElement.prototype, "collapsible", void 0);
5377
5698
  __decorate([property({
5378
5699
  type: Boolean,
5379
- attribute: `allow-multiple`
5380
- })], 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);
5381
5708
  __decorate([property()], PanelGroupElement.prototype, "gap", void 0);
5382
5709
  __decorate([queryAssignedElements({ slot: `` })], PanelGroupElement.prototype, "_panels", void 0);
5383
5710
  PanelGroupElement = __decorate([safeCustomElement(`ixfx-panel-group`)], PanelGroupElement);
@@ -7980,6 +8307,6 @@ function init() {
7980
8307
  console.log(`Init`);
7981
8308
  }
7982
8309
  //#endregion
7983
- 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, 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, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, 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 };
7984
8311
 
7985
8312
  //# sourceMappingURL=index.js.map