@ixfx/components 0.10.4 → 0.10.6

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.
package/bundle/index.js CHANGED
@@ -19723,6 +19723,7 @@ let TabListElement = class TabListElement extends i {
19723
19723
  this.flip = false;
19724
19724
  this.scrollable = false;
19725
19725
  this.hideLabels = false;
19726
+ this.labelNogrow = false;
19726
19727
  this.shrink = false;
19727
19728
  this.dragMode = `off`;
19728
19729
  this.#items = [];
@@ -19730,9 +19731,10 @@ let TabListElement = class TabListElement extends i {
19730
19731
  this.#suppressNextClick = false;
19731
19732
  this.#onSlotChange = () => {
19732
19733
  this.updateComplete.then(() => {
19733
- this.#items = (this.shadowRoot?.querySelector(`slot:not([name])`))?.assignedElements({ flatten: true }) ?? [];
19734
+ this.#refreshItems();
19734
19735
  this.#syncIndicatorColors();
19735
19736
  this.#syncHideLabels();
19737
+ this.#syncLabelNogrow();
19736
19738
  });
19737
19739
  };
19738
19740
  this.#onToolbarSlotChange = () => {
@@ -19891,13 +19893,21 @@ let TabListElement = class TabListElement extends i {
19891
19893
  </div>`;
19892
19894
  }
19893
19895
  #onSlotChange;
19896
+ /**
19897
+ * Re-read the assigned tab items. Some environments do not fire slotchange
19898
+ * for a slot's initial assignment, so firstUpdated also calls this before
19899
+ * syncing item attributes.
19900
+ */
19901
+ #refreshItems() {
19902
+ this.#items = (this.shadowRoot?.querySelector(`slot:not([name])`))?.assignedElements({ flatten: true }) ?? [];
19903
+ }
19894
19904
  #onToolbarSlotChange;
19895
19905
  firstUpdated() {
19896
19906
  this.updateComplete.then(() => {
19897
- if (this.#items.length > 0) {
19898
- this.#syncIndicatorColors();
19899
- this.#syncHideLabels();
19900
- }
19907
+ this.#refreshItems();
19908
+ this.#syncIndicatorColors();
19909
+ this.#syncHideLabels();
19910
+ this.#syncLabelNogrow();
19901
19911
  this.#onToolbarSlotChange();
19902
19912
  });
19903
19913
  }
@@ -19906,11 +19916,16 @@ let TabListElement = class TabListElement extends i {
19906
19916
  this.classList.toggle(`scrollable`, this.scrollable);
19907
19917
  if (changedProperties.has(`dragMode`)) this.toggleAttribute(`drag-mode`, this.dragMode !== `off`);
19908
19918
  if (changedProperties.has(`hideLabels`)) this.#syncHideLabels();
19919
+ if (changedProperties.has(`labelNogrow`)) this.#syncLabelNogrow();
19909
19920
  }
19910
19921
  #syncHideLabels() {
19911
19922
  for (const item of this.#items) if (this.hideLabels) item.setAttribute(`hide-labels`, ``);
19912
19923
  else item.removeAttribute(`hide-labels`);
19913
19924
  }
19925
+ #syncLabelNogrow() {
19926
+ for (const item of this.#items) if (this.labelNogrow) item.setAttribute(`label-nogrow`, ``);
19927
+ else item.removeAttribute(`label-nogrow`);
19928
+ }
19914
19929
  #syncIndicatorColors() {
19915
19930
  for (const item of this.#items) {
19916
19931
  item.style.setProperty(`--indicator-color-bottom`, `transparent`);
@@ -20329,6 +20344,10 @@ __decorate([property({
20329
20344
  type: Boolean,
20330
20345
  attribute: `hide-labels`
20331
20346
  })], TabListElement.prototype, "hideLabels", void 0);
20347
+ __decorate([property({
20348
+ type: Boolean,
20349
+ attribute: `label-nogrow`
20350
+ })], TabListElement.prototype, "labelNogrow", void 0);
20332
20351
  __decorate([property({
20333
20352
  type: Boolean,
20334
20353
  reflect: true
@@ -20345,16 +20364,21 @@ let TabListItemElement = class TabListItemElement extends i {
20345
20364
  super(..._args);
20346
20365
  this.closeable = false;
20347
20366
  this.hideLabels = false;
20367
+ this.labelNogrow = false;
20348
20368
  this.iconName = void 0;
20349
20369
  this.description = void 0;
20350
20370
  this.commandActive = void 0;
20351
20371
  this.registry = void 0;
20352
20372
  this._compact = false;
20353
20373
  this._hasToolbarContent = false;
20374
+ this._hasStatusContent = false;
20354
20375
  this._labelObserver = null;
20355
20376
  this._onToolbarSlotChange = () => {
20356
20377
  this._updateToolbarContent();
20357
20378
  };
20379
+ this._onStatusSlotChange = () => {
20380
+ this._updateStatusContent();
20381
+ };
20358
20382
  this._onLabelSlotChange = () => {
20359
20383
  this._syncLabelSizer();
20360
20384
  };
@@ -20365,13 +20389,18 @@ let TabListItemElement = class TabListItemElement extends i {
20365
20389
  this._compact = entry.contentRect.width < 64;
20366
20390
  });
20367
20391
  this._resizeObserver.observe(this);
20368
- (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.addEventListener(`slotchange`, this._onToolbarSlotChange);
20369
- (this.shadowRoot?.querySelector(`slot:not([name])`))?.addEventListener(`slotchange`, this._onLabelSlotChange);
20370
- this._labelObserver = new MutationObserver(() => this._syncLabelSizer());
20392
+ this._wireSlotListeners();
20393
+ this._labelObserver = new MutationObserver(() => {
20394
+ this._syncLabelSizer();
20395
+ this._updateToolbarContent();
20396
+ this._updateStatusContent();
20397
+ });
20371
20398
  this._labelObserver.observe(this, {
20372
20399
  childList: true,
20373
20400
  characterData: true,
20374
- subtree: true
20401
+ subtree: true,
20402
+ attributes: true,
20403
+ attributeFilter: [`slot`]
20375
20404
  });
20376
20405
  }
20377
20406
  disconnectedCallback() {
@@ -20382,8 +20411,7 @@ let TabListItemElement = class TabListItemElement extends i {
20382
20411
  this._commandCleanup = void 0;
20383
20412
  this._labelObserver?.disconnect();
20384
20413
  this._labelObserver = null;
20385
- (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.removeEventListener(`slotchange`, this._onToolbarSlotChange);
20386
- (this.shadowRoot?.querySelector(`slot:not([name])`))?.removeEventListener(`slotchange`, this._onLabelSlotChange);
20414
+ this._unwireSlotListeners();
20387
20415
  }
20388
20416
  updated(changed) {
20389
20417
  super.updated(changed);
@@ -20407,6 +20435,22 @@ let TabListItemElement = class TabListItemElement extends i {
20407
20435
  });
20408
20436
  }
20409
20437
  /**
20438
+ * Attach slotchange listeners. The shadow root is empty during the first
20439
+ * connectedCallback (the template only exists once rendered), so this is
20440
+ * called again from firstUpdated. addEventListener dedupes identical
20441
+ * listener registrations, so double-wiring is harmless.
20442
+ */
20443
+ _wireSlotListeners() {
20444
+ (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.addEventListener(`slotchange`, this._onToolbarSlotChange);
20445
+ (this.shadowRoot?.querySelector(`slot[name="status"]`))?.addEventListener(`slotchange`, this._onStatusSlotChange);
20446
+ (this.shadowRoot?.querySelector(`slot:not([name])`))?.addEventListener(`slotchange`, this._onLabelSlotChange);
20447
+ }
20448
+ _unwireSlotListeners() {
20449
+ (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.removeEventListener(`slotchange`, this._onToolbarSlotChange);
20450
+ (this.shadowRoot?.querySelector(`slot[name="status"]`))?.removeEventListener(`slotchange`, this._onStatusSlotChange);
20451
+ (this.shadowRoot?.querySelector(`slot:not([name])`))?.removeEventListener(`slotchange`, this._onLabelSlotChange);
20452
+ }
20453
+ /**
20410
20454
  * Mirror the default-slot text into `.label[data-label]` for the `::after`
20411
20455
  * width sizer. Slotted toolbar content is excluded.
20412
20456
  */
@@ -20419,11 +20463,20 @@ let TabListItemElement = class TabListItemElement extends i {
20419
20463
  else label.removeAttribute(`data-label`);
20420
20464
  }
20421
20465
  _updateToolbarContent() {
20422
- const slot = this.shadowRoot?.querySelector(`slot[name="toolbar"]`);
20423
- this._hasToolbarContent = (slot?.assignedElements().length ?? 0) > 0;
20466
+ this._hasToolbarContent = Array.from(this.children).some((child) => child.getAttribute(`slot`) === `toolbar`);
20467
+ }
20468
+ /**
20469
+ * Named slots only render once content has been detected, so reading
20470
+ * assignedElements() cannot bootstrap detection. Direct light-DOM children
20471
+ * are exactly what a slot assigns, so scan those instead.
20472
+ */
20473
+ _updateStatusContent() {
20474
+ this._hasStatusContent = Array.from(this.children).some((child) => child.getAttribute(`slot`) === `status`);
20424
20475
  }
20425
20476
  firstUpdated() {
20477
+ this._wireSlotListeners();
20426
20478
  this._updateToolbarContent();
20479
+ this._updateStatusContent();
20427
20480
  this._syncLabelSizer();
20428
20481
  }
20429
20482
  render() {
@@ -20433,6 +20486,7 @@ let TabListItemElement = class TabListItemElement extends i {
20433
20486
  <div>
20434
20487
  ${this.iconName ? b`<ixfx-icon name="${this.iconName}"></ixfx-icon>` : A}
20435
20488
  ${showLabel ? b`<span class="label"><slot></slot></span>` : A}
20489
+ ${this._hasStatusContent ? b`<div class="status"><slot name="status"></slot></div>` : A}
20436
20490
  ${hasActions ? b`
20437
20491
  <div class="actions">
20438
20492
  <div class="toolbar"><slot name="toolbar"></slot></div>
@@ -20585,6 +20639,28 @@ let TabListItemElement = class TabListItemElement extends i {
20585
20639
  display: contents;
20586
20640
  }
20587
20641
 
20642
+ /* Persistent status slot (e.g. an ixfx-led). Unlike .toolbar it is
20643
+ always visible, selection or not, and keeps its own size however
20644
+ much the label truncates. --size inherits through slotted content,
20645
+ so bare and button-wrapped LEDs both render smaller; consumers can
20646
+ override per element. */
20647
+ .status {
20648
+ display: flex;
20649
+ align-items: center;
20650
+ flex-shrink: 0;
20651
+ --size: 0.75ex;
20652
+ }
20653
+
20654
+ slot[name="status"] {
20655
+ display: contents;
20656
+ }
20657
+
20658
+ /* With label-nogrow, the label keeps its intrinsic width so status
20659
+ content lands next to the label text instead of the far edge. */
20660
+ :host([label-nogrow]) .label {
20661
+ flex: 0 0 auto;
20662
+ }
20663
+
20588
20664
  /* Slotted buttons inherit these through the shadow boundary; keeps a
20589
20665
  toolbar button from inflating the strip height. */
20590
20666
  .toolbar ::slotted(ixfx-button) {
@@ -20628,6 +20704,10 @@ __decorate([property({
20628
20704
  type: Boolean,
20629
20705
  attribute: `hide-labels`
20630
20706
  })], TabListItemElement.prototype, "hideLabels", void 0);
20707
+ __decorate([property({
20708
+ type: Boolean,
20709
+ attribute: `label-nogrow`
20710
+ })], TabListItemElement.prototype, "labelNogrow", void 0);
20631
20711
  __decorate([property({
20632
20712
  type: String,
20633
20713
  attribute: `icon-name`
@@ -20640,6 +20720,7 @@ __decorate([property({
20640
20720
  __decorate([property({ attribute: false })], TabListItemElement.prototype, "registry", void 0);
20641
20721
  __decorate([state()], TabListItemElement.prototype, "_compact", void 0);
20642
20722
  __decorate([state()], TabListItemElement.prototype, "_hasToolbarContent", void 0);
20723
+ __decorate([state()], TabListItemElement.prototype, "_hasStatusContent", void 0);
20643
20724
  TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabListItemElement);
20644
20725
  //#endregion
20645
20726
  //#region src/dock/dock-panel.ts
@@ -32390,7 +32471,7 @@ function clamp$2(value, min, max) {
32390
32471
  /**
32391
32472
  * Scale a value from one range to another
32392
32473
  */
32393
- function scale$1(value, fromMin, fromMax, toMin, toMax) {
32474
+ function scale$2(value, fromMin, fromMax, toMin, toMax) {
32394
32475
  return toMin + (value - fromMin) / (fromMax - fromMin) * (toMax - toMin);
32395
32476
  }
32396
32477
  //#endregion
@@ -32449,7 +32530,7 @@ let RadialInputElement = class RadialInputElement extends WheelNudgeMixin(i) {
32449
32530
  event.preventDefault();
32450
32531
  const effectiveSensitivity = this.clientHeight * 2 * (event.shiftKey ? 10 : 1);
32451
32532
  const deltaValue = (this.#dragStartY - event.clientY) / effectiveSensitivity * (this.max - this.min);
32452
- const relativeValue = scale$1(this.#valueAtDragStart + deltaValue, this.min, this.max, 0, 1);
32533
+ const relativeValue = scale$2(this.#valueAtDragStart + deltaValue, this.min, this.max, 0, 1);
32453
32534
  this.#setValueFromRelative(clamp$2(relativeValue, 0, 1), true);
32454
32535
  };
32455
32536
  this.#onPointerUp = () => {
@@ -32533,7 +32614,7 @@ let RadialInputElement = class RadialInputElement extends WheelNudgeMixin(i) {
32533
32614
  return this.#lanes.get(key);
32534
32615
  }
32535
32616
  #getRelativeValue() {
32536
- return scale$1(this.value, this.min, this.max, 0, 1);
32617
+ return scale$2(this.value, this.min, this.max, 0, 1);
32537
32618
  }
32538
32619
  #getEffectiveMarkerStyle() {
32539
32620
  if (this.valueMode === `unipolar` && this.markerStyle === `needle`) return `none`;
@@ -32547,7 +32628,7 @@ let RadialInputElement = class RadialInputElement extends WheelNudgeMixin(i) {
32547
32628
  return value;
32548
32629
  }
32549
32630
  #setValueFromRelative(relativeValue, isUserInteraction = false) {
32550
- const newValue = scale$1(relativeValue, 0, 1, this.min, this.max);
32631
+ const newValue = scale$2(relativeValue, 0, 1, this.min, this.max);
32551
32632
  const clampedValue = this.#quantise(clamp$2(newValue, this.min, this.max));
32552
32633
  if (clampedValue === this.value) return;
32553
32634
  const previousValue = this.value;
@@ -33308,7 +33389,7 @@ function clamp$1(value, min, max) {
33308
33389
  /**
33309
33390
  * Linear-reinterpolate `value` from [fromMin, fromMax] to [toMin, toMax].
33310
33391
  */
33311
- function scale(value, fromMin, fromMax, toMin, toMax) {
33392
+ function scale$1(value, fromMin, fromMax, toMin, toMax) {
33312
33393
  if (fromMax === fromMin) return toMin;
33313
33394
  return toMin + (value - fromMin) / (fromMax - fromMin) * (toMax - toMin);
33314
33395
  }
@@ -33316,7 +33397,7 @@ function scale(value, fromMin, fromMax, toMin, toMax) {
33316
33397
  * Convert an absolute value to a relative (0..1) position.
33317
33398
  */
33318
33399
  function valueToRelative(value, min, max) {
33319
- return scale(value, min, max, 0, 1);
33400
+ return scale$1(value, min, max, 0, 1);
33320
33401
  }
33321
33402
  //#endregion
33322
33403
  //#region src/slider-input/slider-input.ts
@@ -33875,7 +33956,7 @@ let SliderInputElement = class SliderInputElement extends WheelNudgeMixin(i) {
33875
33956
  return value;
33876
33957
  }
33877
33958
  #setSingleValueFromRelative(relativeValue, isUserInteraction = false) {
33878
- const newValue = scale(relativeValue, 0, 1, this.min, this.max);
33959
+ const newValue = scale$1(relativeValue, 0, 1, this.min, this.max);
33879
33960
  const clampedValue = this.#quantise(clamp$1(newValue, this.min, this.max));
33880
33961
  if (clampedValue === this.valueA) return;
33881
33962
  const previousValue = this.valueA;
@@ -33891,7 +33972,7 @@ let SliderInputElement = class SliderInputElement extends WheelNudgeMixin(i) {
33891
33972
  this.#emitInputAndChange({ previousValue }, isUserInteraction);
33892
33973
  }
33893
33974
  #setDualOrTripleValueFromRelative(relativeValue, handle, isUserInteraction = false) {
33894
- const clamped = clamp$1(scale(relativeValue, 0, 1, this.min, this.max), this.min, this.max);
33975
+ const clamped = clamp$1(scale$1(relativeValue, 0, 1, this.min, this.max), this.min, this.max);
33895
33976
  const result = this.#resolvePoleChange(handle, clamped, this.#lastInteractedHandle);
33896
33977
  if (!result) return;
33897
33978
  const previous = { ...this.#poles() };
@@ -34431,7 +34512,7 @@ let SliderInputElement = class SliderInputElement extends WheelNudgeMixin(i) {
34431
34512
  if (handle === `c`) {
34432
34513
  const lo = this.#low();
34433
34514
  const hi = this.#high();
34434
- const clamped = clamp$1(scale(clamp$1(targetRelative, 0, 1), 0, 1, this.min, this.max), lo, hi);
34515
+ const clamped = clamp$1(scale$1(clamp$1(targetRelative, 0, 1), 0, 1, this.min, this.max), lo, hi);
34435
34516
  const q = this.#quantise(clamped);
34436
34517
  if (q === this.#poleC) return;
34437
34518
  const previous = this.#poles();
@@ -43196,6 +43277,289 @@ __decorate([property({
43196
43277
  __decorate([property({ type: String })], SelectHorizElement.prototype, "selectedValue", null);
43197
43278
  SelectHorizElement = __decorate([safeCustomElement(`ixfx-select-horiz`)], SelectHorizElement);
43198
43279
  //#endregion
43280
+ //#region src/util/clamp.ts
43281
+ function clampValue(v, min, max) {
43282
+ return Math.min(Math.max(v, min), max);
43283
+ }
43284
+ //#endregion
43285
+ //#region src/util/geometry.ts
43286
+ function scale(v, fromMin, fromMax, toMin, toMax) {
43287
+ if (fromMax === fromMin) return toMin;
43288
+ return toMin + (v - fromMin) / (fromMax - fromMin) * (toMax - toMin);
43289
+ }
43290
+ //#endregion
43291
+ //#region src/shapefill-value/shapefill-value.ts
43292
+ let ShapefillValueElement = class ShapefillValueElement extends WheelNudgeMixin(i) {
43293
+ constructor(..._args) {
43294
+ super(..._args);
43295
+ this.display = `circle`;
43296
+ this.fillMode = `centre`;
43297
+ this.value = 0;
43298
+ this.min = 0;
43299
+ this.max = 100;
43300
+ this.step = void 0;
43301
+ this.disabled = false;
43302
+ this.#dragging = false;
43303
+ this.#dragStartY = 0;
43304
+ this.#valueAtDragStart = 0;
43305
+ this.#onPointerDown = (event) => {
43306
+ if (this.disabled) return;
43307
+ event.preventDefault();
43308
+ const svgEl = this.renderRoot.querySelector(`svg`);
43309
+ svgEl?.focus();
43310
+ this.#dragging = true;
43311
+ this.#dragStartY = event.clientY;
43312
+ this.#valueAtDragStart = this.value;
43313
+ this.toggleAttribute(`dragging`, true);
43314
+ if (svgEl) svgEl.setPointerCapture(event.pointerId);
43315
+ window.addEventListener(`pointermove`, this.#onPointerMove);
43316
+ window.addEventListener(`pointerup`, this.#onPointerUp);
43317
+ window.addEventListener(`pointercancel`, this.#onPointerUp);
43318
+ };
43319
+ this.#onPointerMove = (event) => {
43320
+ if (!this.#dragging) return;
43321
+ event.preventDefault();
43322
+ const effectiveSensitivity = this.clientHeight * 2 * (event.shiftKey ? 10 : 1);
43323
+ const deltaValue = (this.#dragStartY - event.clientY) / effectiveSensitivity * (this.max - this.min);
43324
+ const relativeValue = scale(this.#valueAtDragStart + deltaValue, this.min, this.max, 0, 1);
43325
+ this.#setValueFromRelative(clampValue(relativeValue, 0, 1), true);
43326
+ };
43327
+ this.#onPointerUp = () => {
43328
+ this.#dragging = false;
43329
+ this.toggleAttribute(`dragging`, false);
43330
+ const svgEl = this.renderRoot.querySelector(`svg`);
43331
+ if (svgEl && `hasPointerCapture` in svgEl && typeof svgEl.hasPointerCapture === `function`) {
43332
+ if (svgEl.hasPointerCapture(1)) svgEl.releasePointerCapture(1);
43333
+ }
43334
+ window.removeEventListener(`pointermove`, this.#onPointerMove);
43335
+ window.removeEventListener(`pointerup`, this.#onPointerUp);
43336
+ window.removeEventListener(`pointercancel`, this.#onPointerUp);
43337
+ };
43338
+ this.#onKeyDown = (event) => {
43339
+ if (this.disabled) return;
43340
+ const range = this.max - this.min;
43341
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, event.shiftKey);
43342
+ let handled = false;
43343
+ switch (event.key) {
43344
+ case `ArrowUp`:
43345
+ case `ArrowRight`:
43346
+ this.#stepByRelativeDelta(effectiveStep / range, true);
43347
+ handled = true;
43348
+ break;
43349
+ case `ArrowDown`:
43350
+ case `ArrowLeft`:
43351
+ this.#stepByRelativeDelta(-effectiveStep / range, true);
43352
+ handled = true;
43353
+ break;
43354
+ case `Home`:
43355
+ this.#setValueFromRelative(0, true);
43356
+ handled = true;
43357
+ break;
43358
+ case `End`:
43359
+ this.#setValueFromRelative(1, true);
43360
+ handled = true;
43361
+ }
43362
+ if (handled) event.preventDefault();
43363
+ };
43364
+ }
43365
+ #dragging;
43366
+ #dragStartY;
43367
+ #valueAtDragStart;
43368
+ #changeDebounceTimer;
43369
+ #getRelativeValue() {
43370
+ return scale(this.value, this.min, this.max, 0, 1);
43371
+ }
43372
+ #quantise(value) {
43373
+ if (this.stops && this.stops > 1) {
43374
+ const step = (this.max - this.min) / this.stops;
43375
+ return Math.round((value - this.min) / step) * step + this.min;
43376
+ }
43377
+ return value;
43378
+ }
43379
+ #setValueFromRelative(relativeValue, isUserInteraction = false) {
43380
+ const newValue = scale(relativeValue, 0, 1, this.min, this.max);
43381
+ const clampedValue = this.#quantise(clampValue(newValue, this.min, this.max));
43382
+ if (clampedValue === this.value) return;
43383
+ const previousValue = this.value;
43384
+ this.value = clampedValue;
43385
+ if (this.hasAttribute(`data-tooltip-live`)) {
43386
+ const percentage = Math.round(this.#getRelativeValue() * 100);
43387
+ this.setAttribute(`data-tooltip`, `${percentage}%`);
43388
+ }
43389
+ if (isUserInteraction) {
43390
+ this.dispatchEvent(new CustomEvent(`input`, {
43391
+ detail: {
43392
+ value: this.value,
43393
+ valueRelative: this.#getRelativeValue()
43394
+ },
43395
+ bubbles: true,
43396
+ composed: true
43397
+ }));
43398
+ this.#scheduleChangeEvent(previousValue);
43399
+ } else this.#fireChangeEvent(previousValue);
43400
+ }
43401
+ #scheduleChangeEvent(previousValue) {
43402
+ if (this.#changeDebounceTimer !== void 0) clearTimeout(this.#changeDebounceTimer);
43403
+ this.#changeDebounceTimer = window.setTimeout(() => {
43404
+ this.#fireChangeEvent(previousValue);
43405
+ this.#changeDebounceTimer = void 0;
43406
+ }, 150);
43407
+ }
43408
+ #fireChangeEvent(previousValue) {
43409
+ this.dispatchEvent(new CustomEvent(`change`, {
43410
+ detail: {
43411
+ value: this.value,
43412
+ valueRelative: this.#getRelativeValue(),
43413
+ previousValue
43414
+ },
43415
+ bubbles: true,
43416
+ composed: true
43417
+ }));
43418
+ }
43419
+ #onPointerDown;
43420
+ #onPointerMove;
43421
+ #onPointerUp;
43422
+ #onKeyDown;
43423
+ /**
43424
+ * Apply a relative-delta nudge to the current value, clamped to [min, max] and
43425
+ * quantised. Shared between keyboard arrow keys and the wheel handler.
43426
+ */
43427
+ #stepByRelativeDelta(relativeDelta, isUserInteraction) {
43428
+ this.#setValueFromRelative(clampValue(this.#getRelativeValue() + relativeDelta, 0, 1), isUserInteraction);
43429
+ }
43430
+ _applyWheelDelta(direction, event) {
43431
+ const range = this.max - this.min;
43432
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, event.shiftKey);
43433
+ this.#stepByRelativeDelta(direction * effectiveStep / range, true);
43434
+ }
43435
+ #renderCircle() {
43436
+ const relativeValue = this.#getRelativeValue();
43437
+ const outerRadius = 45;
43438
+ const innerRadius = outerRadius * relativeValue;
43439
+ const outerCx = 50;
43440
+ const outerCy = 50;
43441
+ let cx = outerCx;
43442
+ if (this.fillMode === `left`) cx = 5 + outerRadius * relativeValue;
43443
+ else if (this.fillMode === `right`) cx = 95 - outerRadius * relativeValue;
43444
+ return w`
43445
+ <circle class="fill" cx="${cx}" cy="${outerCy}" r="${innerRadius}" />
43446
+ <circle class="outline" cx="${outerCx}" cy="${outerCy}" r="${outerRadius}" fill="none" />
43447
+ `;
43448
+ }
43449
+ #renderRectangle() {
43450
+ const relativeValue = this.#getRelativeValue();
43451
+ const outerSize = 90;
43452
+ const outerOffset = 5;
43453
+ if (this.fillMode === `left` || this.fillMode === `right`) {
43454
+ const innerWidth = outerSize * relativeValue;
43455
+ const x = this.fillMode === `left` ? outerOffset : 95 - innerWidth;
43456
+ return w`
43457
+ <rect class="fill" x="${x}" y="${outerOffset}" width="${innerWidth}" height="${outerSize}" />
43458
+ <rect class="outline" x="${outerOffset}" y="${outerOffset}" width="${outerSize}" height="${outerSize}" fill="none" />
43459
+ `;
43460
+ }
43461
+ const innerSize = outerSize * relativeValue;
43462
+ const innerOffset = (100 - innerSize) / 2;
43463
+ return w`
43464
+ <rect class="fill" x="${innerOffset}" y="${innerOffset}" width="${innerSize}" height="${innerSize}" />
43465
+ <rect class="outline" x="${outerOffset}" y="${outerOffset}" width="${outerSize}" height="${outerSize}" fill="none" />
43466
+ `;
43467
+ }
43468
+ render() {
43469
+ const preserveAspectRatio = this.display === `rectangle` ? `none` : `xMidYMid meet`;
43470
+ return b`
43471
+ <svg
43472
+ viewBox="0 0 100 100"
43473
+ preserveAspectRatio="${preserveAspectRatio}"
43474
+ tabindex="${this.disabled ? -1 : 0}"
43475
+ @pointerdown="${this.#onPointerDown}"
43476
+ @keydown="${this.#onKeyDown}"
43477
+ style="cursor: ${this.#dragging ? `ns-resize` : `grab`}"
43478
+ >
43479
+ ${this.display === `rectangle` ? this.#renderRectangle() : this.#renderCircle()}
43480
+ </svg>
43481
+ `;
43482
+ }
43483
+ updated(changed) {
43484
+ super.updated(changed);
43485
+ this.style.setProperty(`--shapefill-value-relative`, this.#getRelativeValue().toString());
43486
+ }
43487
+ disconnectedCallback() {
43488
+ super.disconnectedCallback();
43489
+ if (this.#changeDebounceTimer !== void 0) clearTimeout(this.#changeDebounceTimer);
43490
+ this.#onPointerUp();
43491
+ }
43492
+ static {
43493
+ this.styles = [
43494
+ themeFallbacks,
43495
+ prominenceStyles,
43496
+ i$3`
43497
+ :host {
43498
+ display: inline-block;
43499
+ width: 2em;
43500
+ height: 2em;
43501
+ touch-action: none;
43502
+ user-select: none;
43503
+
43504
+ /* Dynamic value - set by JS */
43505
+ --shapefill-value-relative: 0;
43506
+
43507
+ /* Public styling variables — consumer customisable */
43508
+ --shapefill-value-outline-color: var(--surface-4);
43509
+ --shapefill-value-outline-width: 2;
43510
+ --shapefill-value-fill-color: var(--accent);
43511
+ }
43512
+
43513
+ :host([disabled]) {
43514
+ cursor: not-allowed;
43515
+ }
43516
+
43517
+ svg {
43518
+ width: 100%;
43519
+ height: 100%;
43520
+ outline: none;
43521
+ display: block;
43522
+ }
43523
+
43524
+ svg:active {
43525
+ cursor: grabbing;
43526
+ }
43527
+
43528
+ svg:focus-visible {
43529
+ outline: var(--shapefill-value-focus-outline, 2px solid var(--accent));
43530
+ outline-offset: var(--shapefill-value-focus-outline-offset, 2px);
43531
+ }
43532
+
43533
+ .outline {
43534
+ stroke: var(--shapefill-value-outline-color, var(--surface-4));
43535
+ stroke-width: var(--shapefill-value-outline-width, 2);
43536
+ vector-effect: non-scaling-stroke;
43537
+ }
43538
+
43539
+ .fill {
43540
+ fill: var(--shapefill-value-fill-color, var(--accent));
43541
+ transition: var(--shapefill-value-fill-transition, none);
43542
+ }
43543
+ `
43544
+ ];
43545
+ }
43546
+ };
43547
+ __decorate([property({ type: String })], ShapefillValueElement.prototype, "display", void 0);
43548
+ __decorate([property({
43549
+ type: String,
43550
+ attribute: `fill-mode`
43551
+ })], ShapefillValueElement.prototype, "fillMode", void 0);
43552
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "value", void 0);
43553
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "min", void 0);
43554
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "max", void 0);
43555
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "step", void 0);
43556
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "stops", void 0);
43557
+ __decorate([property({
43558
+ type: Boolean,
43559
+ reflect: true
43560
+ })], ShapefillValueElement.prototype, "disabled", void 0);
43561
+ ShapefillValueElement = __decorate([safeCustomElement(`ixfx-shapefill-value`)], ShapefillValueElement);
43562
+ //#endregion
43199
43563
  //#region src/sliding-number/sliding-number.ts
43200
43564
  const REEL_DIGITS = Array.from({ length: 30 }, (_, index) => index % 10);
43201
43565
  const SECTION_RANK = {
@@ -46813,6 +47177,7 @@ let ToolbarElement = class ToolbarElement extends i {
46813
47177
  this.invisibleGroups = false;
46814
47178
  this.allowReorder = false;
46815
47179
  this._overflowCount = 0;
47180
+ this._popoverOpen = false;
46816
47181
  this._ro = null;
46817
47182
  this._anchor = `--toolbar-${_ToolbarElement._cnt++}`;
46818
47183
  this._sizes = /* @__PURE__ */ new WeakMap();
@@ -46938,11 +47303,11 @@ let ToolbarElement = class ToolbarElement extends i {
46938
47303
  .overflow-btn[hidden] { display: none; }
46939
47304
  .overflow-popover {
46940
47305
  position: fixed;
46941
- top: anchor(bottom);
46942
- left: anchor(right);
47306
+ inset: auto;
47307
+ margin: 0;
46943
47308
  position-anchor: var(--anchor-name);
46944
47309
  position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
46945
- margin: 8px;
47310
+ position-visibility: anchors-visible;
46946
47311
  max-height: min(60vh, 400px);
46947
47312
  max-width: min(90vw, 320px);
46948
47313
  overflow: auto;
@@ -46952,6 +47317,18 @@ let ToolbarElement = class ToolbarElement extends i {
46952
47317
  flex-direction: column;
46953
47318
  gap: var(--space-s);
46954
47319
  }
47320
+ :host([orientation="horizontal"]) .overflow-popover {
47321
+ position-area: bottom span-left;
47322
+ margin-top: var(--toolbar-overflow-gap, 8px);
47323
+ }
47324
+ :host([orientation="vertical-left"]) .overflow-popover {
47325
+ position-area: right span-bottom;
47326
+ margin-left: var(--toolbar-overflow-gap, 8px);
47327
+ }
47328
+ :host([orientation="vertical-right"]) .overflow-popover {
47329
+ position-area: left span-bottom;
47330
+ margin-right: var(--toolbar-overflow-gap, 8px);
47331
+ }
46955
47332
  .overflow-popover:popover-open { display: flex; }
46956
47333
  .overflow-popover ::slotted(*) { writing-mode: horizontal-tb; text-orientation: mixed; }
46957
47334
 
@@ -46990,6 +47367,9 @@ let ToolbarElement = class ToolbarElement extends i {
46990
47367
  });
46991
47368
  this._ro = new ResizeObserver(() => this._scheduleMeasure());
46992
47369
  this._ro.observe(this._inner);
47370
+ this._popover.addEventListener(`toggle`, () => {
47371
+ this._popoverOpen = this._popover.matches(`:popover-open`);
47372
+ });
46993
47373
  this._scheduleMeasure();
46994
47374
  this._updateGroups();
46995
47375
  }
@@ -47330,7 +47710,7 @@ let ToolbarElement = class ToolbarElement extends i {
47330
47710
  return b`
47331
47711
  <div class="inner" role="toolbar" aria-orientation=${this.orientation}>
47332
47712
  <slot @pointerdown=${this._onPointerDown} @keydown=${this._onKeyDown}></slot>
47333
- <ixfx-button class="overflow-btn" ?hidden=${!hasOverflow} @click=${this._toggleOverflow} aria-label="More" aria-haspopup="true" aria-expanded=${this._popover?.matches(`:popover-open`) ?? false}>⋯</ixfx-button>
47713
+ <ixfx-button class="overflow-btn" ?hidden=${!hasOverflow} @click=${this._toggleOverflow} aria-label="More" aria-haspopup="true" aria-expanded=${this._popoverOpen}>⋯</ixfx-button>
47334
47714
  </div>
47335
47715
  <div class="overflow-popover popup-surface" popover="auto" @click=${(e) => e.stopPropagation()}>
47336
47716
  <slot name="overflow"></slot>
@@ -47373,6 +47753,7 @@ __decorate([property({
47373
47753
  reflect: true
47374
47754
  })], ToolbarElement.prototype, "allowReorder", void 0);
47375
47755
  __decorate([state()], ToolbarElement.prototype, "_overflowCount", void 0);
47756
+ __decorate([state()], ToolbarElement.prototype, "_popoverOpen", void 0);
47376
47757
  __decorate([query(`.inner`)], ToolbarElement.prototype, "_inner", void 0);
47377
47758
  __decorate([query(`.overflow-popover`)], ToolbarElement.prototype, "_popover", void 0);
47378
47759
  __decorate([query(`slot`)], ToolbarElement.prototype, "_slot", void 0);
@@ -50156,6 +50537,6 @@ function init() {
50156
50537
  console.log(`Init`);
50157
50538
  }
50158
50539
  //#endregion
50159
- export { AcTextElement, AcTokenElement, BottomDrawerElement, 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, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, MulticolListElement, 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, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, extractStack, findIcicleNode, findIciclePath, findNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, walk, wrapRoot };
50540
+ export { AcTextElement, AcTokenElement, BottomDrawerElement, 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, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, MulticolListElement, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, ShapefillValueElement, 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, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, extractStack, findIcicleNode, findIciclePath, findNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, walk, wrapRoot };
50160
50541
 
50161
50542
  //# sourceMappingURL=index.js.map