@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/dist/index.js CHANGED
@@ -38,6 +38,8 @@ import { DetailListElement } from "./detail-list.js";
38
38
  import { a as distribute, c as toSnapshot, i as buildModel, l as walk, n as SplitPanelElement, o as normalise, r as applySnapshot, s as resolveTracks, t as SplitLayoutElement } from "./split-layout-BJEU1W0d.js";
39
39
  import { TabListElement } from "./tabs.js";
40
40
  import { EditableLabel } from "./editable-label.js";
41
+ import { t as resolveAxisStep } from "./keyboard-B5xD7Fz-.js";
42
+ import { t as WheelNudgeMixin } from "./wheel-nudge-D5rmht3v.js";
41
43
  import { n as EditableNumber, t as LabelledSliderInput } from "./labelled-slider-input-CF2RtzgG.js";
42
44
  import { t as FormElement } from "./form-CsXJX15p.js";
43
45
  import { t as GridListElement } from "./grid-list-CaMcdpFJ.js";
@@ -63,7 +65,7 @@ import { SwipeElement } from "./swipe.js";
63
65
  import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-BP1Ux2EV.js";
64
66
  import { TransitoryLabelElement } from "./transitory-label.js";
65
67
  import { XyPad } from "./xy-pad.js";
66
- import { LitElement, css, html, nothing } from "lit";
68
+ import { LitElement, css, html, nothing, svg } from "lit";
67
69
  import { customElement, eventOptions, property, query, queryAssignedElements, state } from "lit/decorators.js";
68
70
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
69
71
  import { createCommandRegistry } from "@clinth/ui-commands";
@@ -3173,16 +3175,21 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3173
3175
  super(..._args);
3174
3176
  this.closeable = false;
3175
3177
  this.hideLabels = false;
3178
+ this.labelNogrow = false;
3176
3179
  this.iconName = void 0;
3177
3180
  this.description = void 0;
3178
3181
  this.commandActive = void 0;
3179
3182
  this.registry = void 0;
3180
3183
  this._compact = false;
3181
3184
  this._hasToolbarContent = false;
3185
+ this._hasStatusContent = false;
3182
3186
  this._labelObserver = null;
3183
3187
  this._onToolbarSlotChange = () => {
3184
3188
  this._updateToolbarContent();
3185
3189
  };
3190
+ this._onStatusSlotChange = () => {
3191
+ this._updateStatusContent();
3192
+ };
3186
3193
  this._onLabelSlotChange = () => {
3187
3194
  this._syncLabelSizer();
3188
3195
  };
@@ -3193,13 +3200,18 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3193
3200
  this._compact = entry.contentRect.width < 64;
3194
3201
  });
3195
3202
  this._resizeObserver.observe(this);
3196
- (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.addEventListener(`slotchange`, this._onToolbarSlotChange);
3197
- (this.shadowRoot?.querySelector(`slot:not([name])`))?.addEventListener(`slotchange`, this._onLabelSlotChange);
3198
- this._labelObserver = new MutationObserver(() => this._syncLabelSizer());
3203
+ this._wireSlotListeners();
3204
+ this._labelObserver = new MutationObserver(() => {
3205
+ this._syncLabelSizer();
3206
+ this._updateToolbarContent();
3207
+ this._updateStatusContent();
3208
+ });
3199
3209
  this._labelObserver.observe(this, {
3200
3210
  childList: true,
3201
3211
  characterData: true,
3202
- subtree: true
3212
+ subtree: true,
3213
+ attributes: true,
3214
+ attributeFilter: [`slot`]
3203
3215
  });
3204
3216
  }
3205
3217
  disconnectedCallback() {
@@ -3210,8 +3222,7 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3210
3222
  this._commandCleanup = void 0;
3211
3223
  this._labelObserver?.disconnect();
3212
3224
  this._labelObserver = null;
3213
- (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.removeEventListener(`slotchange`, this._onToolbarSlotChange);
3214
- (this.shadowRoot?.querySelector(`slot:not([name])`))?.removeEventListener(`slotchange`, this._onLabelSlotChange);
3225
+ this._unwireSlotListeners();
3215
3226
  }
3216
3227
  updated(changed) {
3217
3228
  super.updated(changed);
@@ -3235,6 +3246,22 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3235
3246
  });
3236
3247
  }
3237
3248
  /**
3249
+ * Attach slotchange listeners. The shadow root is empty during the first
3250
+ * connectedCallback (the template only exists once rendered), so this is
3251
+ * called again from firstUpdated. addEventListener dedupes identical
3252
+ * listener registrations, so double-wiring is harmless.
3253
+ */
3254
+ _wireSlotListeners() {
3255
+ (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.addEventListener(`slotchange`, this._onToolbarSlotChange);
3256
+ (this.shadowRoot?.querySelector(`slot[name="status"]`))?.addEventListener(`slotchange`, this._onStatusSlotChange);
3257
+ (this.shadowRoot?.querySelector(`slot:not([name])`))?.addEventListener(`slotchange`, this._onLabelSlotChange);
3258
+ }
3259
+ _unwireSlotListeners() {
3260
+ (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.removeEventListener(`slotchange`, this._onToolbarSlotChange);
3261
+ (this.shadowRoot?.querySelector(`slot[name="status"]`))?.removeEventListener(`slotchange`, this._onStatusSlotChange);
3262
+ (this.shadowRoot?.querySelector(`slot:not([name])`))?.removeEventListener(`slotchange`, this._onLabelSlotChange);
3263
+ }
3264
+ /**
3238
3265
  * Mirror the default-slot text into `.label[data-label]` for the `::after`
3239
3266
  * width sizer. Slotted toolbar content is excluded.
3240
3267
  */
@@ -3247,11 +3274,20 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3247
3274
  else label.removeAttribute(`data-label`);
3248
3275
  }
3249
3276
  _updateToolbarContent() {
3250
- const slot = this.shadowRoot?.querySelector(`slot[name="toolbar"]`);
3251
- this._hasToolbarContent = (slot?.assignedElements().length ?? 0) > 0;
3277
+ this._hasToolbarContent = Array.from(this.children).some((child) => child.getAttribute(`slot`) === `toolbar`);
3278
+ }
3279
+ /**
3280
+ * Named slots only render once content has been detected, so reading
3281
+ * assignedElements() cannot bootstrap detection. Direct light-DOM children
3282
+ * are exactly what a slot assigns, so scan those instead.
3283
+ */
3284
+ _updateStatusContent() {
3285
+ this._hasStatusContent = Array.from(this.children).some((child) => child.getAttribute(`slot`) === `status`);
3252
3286
  }
3253
3287
  firstUpdated() {
3288
+ this._wireSlotListeners();
3254
3289
  this._updateToolbarContent();
3290
+ this._updateStatusContent();
3255
3291
  this._syncLabelSizer();
3256
3292
  }
3257
3293
  render() {
@@ -3261,6 +3297,7 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3261
3297
  <div>
3262
3298
  ${this.iconName ? html`<ixfx-icon name="${this.iconName}"></ixfx-icon>` : nothing}
3263
3299
  ${showLabel ? html`<span class="label"><slot></slot></span>` : nothing}
3300
+ ${this._hasStatusContent ? html`<div class="status"><slot name="status"></slot></div>` : nothing}
3264
3301
  ${hasActions ? html`
3265
3302
  <div class="actions">
3266
3303
  <div class="toolbar"><slot name="toolbar"></slot></div>
@@ -3413,6 +3450,28 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3413
3450
  display: contents;
3414
3451
  }
3415
3452
 
3453
+ /* Persistent status slot (e.g. an ixfx-led). Unlike .toolbar it is
3454
+ always visible, selection or not, and keeps its own size however
3455
+ much the label truncates. --size inherits through slotted content,
3456
+ so bare and button-wrapped LEDs both render smaller; consumers can
3457
+ override per element. */
3458
+ .status {
3459
+ display: flex;
3460
+ align-items: center;
3461
+ flex-shrink: 0;
3462
+ --size: 0.75ex;
3463
+ }
3464
+
3465
+ slot[name="status"] {
3466
+ display: contents;
3467
+ }
3468
+
3469
+ /* With label-nogrow, the label keeps its intrinsic width so status
3470
+ content lands next to the label text instead of the far edge. */
3471
+ :host([label-nogrow]) .label {
3472
+ flex: 0 0 auto;
3473
+ }
3474
+
3416
3475
  /* Slotted buttons inherit these through the shadow boundary; keeps a
3417
3476
  toolbar button from inflating the strip height. */
3418
3477
  .toolbar ::slotted(ixfx-button) {
@@ -3456,6 +3515,10 @@ __decorate([property({
3456
3515
  type: Boolean,
3457
3516
  attribute: `hide-labels`
3458
3517
  })], TabListItemElement.prototype, "hideLabels", void 0);
3518
+ __decorate([property({
3519
+ type: Boolean,
3520
+ attribute: `label-nogrow`
3521
+ })], TabListItemElement.prototype, "labelNogrow", void 0);
3459
3522
  __decorate([property({
3460
3523
  type: String,
3461
3524
  attribute: `icon-name`
@@ -3468,6 +3531,7 @@ __decorate([property({
3468
3531
  __decorate([property({ attribute: false })], TabListItemElement.prototype, "registry", void 0);
3469
3532
  __decorate([state()], TabListItemElement.prototype, "_compact", void 0);
3470
3533
  __decorate([state()], TabListItemElement.prototype, "_hasToolbarContent", void 0);
3534
+ __decorate([state()], TabListItemElement.prototype, "_hasStatusContent", void 0);
3471
3535
  TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabListItemElement);
3472
3536
  //#endregion
3473
3537
  //#region src/dock/dock-panel.ts
@@ -8853,6 +8917,289 @@ __decorate([property({ type: String })], RatingElement.prototype, "variant", voi
8853
8917
  __decorate([state()], RatingElement.prototype, "_preview", void 0);
8854
8918
  RatingElement = __decorate([customElement(`ixfx-rating`)], RatingElement);
8855
8919
  //#endregion
8920
+ //#region src/util/clamp.ts
8921
+ function clampValue(v, min, max) {
8922
+ return Math.min(Math.max(v, min), max);
8923
+ }
8924
+ //#endregion
8925
+ //#region src/util/geometry.ts
8926
+ function scale(v, fromMin, fromMax, toMin, toMax) {
8927
+ if (fromMax === fromMin) return toMin;
8928
+ return toMin + (v - fromMin) / (fromMax - fromMin) * (toMax - toMin);
8929
+ }
8930
+ //#endregion
8931
+ //#region src/shapefill-value/shapefill-value.ts
8932
+ let ShapefillValueElement = class ShapefillValueElement extends WheelNudgeMixin(LitElement) {
8933
+ constructor(..._args) {
8934
+ super(..._args);
8935
+ this.display = `circle`;
8936
+ this.fillMode = `centre`;
8937
+ this.value = 0;
8938
+ this.min = 0;
8939
+ this.max = 100;
8940
+ this.step = void 0;
8941
+ this.disabled = false;
8942
+ this.#dragging = false;
8943
+ this.#dragStartY = 0;
8944
+ this.#valueAtDragStart = 0;
8945
+ this.#onPointerDown = (event) => {
8946
+ if (this.disabled) return;
8947
+ event.preventDefault();
8948
+ const svgEl = this.renderRoot.querySelector(`svg`);
8949
+ svgEl?.focus();
8950
+ this.#dragging = true;
8951
+ this.#dragStartY = event.clientY;
8952
+ this.#valueAtDragStart = this.value;
8953
+ this.toggleAttribute(`dragging`, true);
8954
+ if (svgEl) svgEl.setPointerCapture(event.pointerId);
8955
+ window.addEventListener(`pointermove`, this.#onPointerMove);
8956
+ window.addEventListener(`pointerup`, this.#onPointerUp);
8957
+ window.addEventListener(`pointercancel`, this.#onPointerUp);
8958
+ };
8959
+ this.#onPointerMove = (event) => {
8960
+ if (!this.#dragging) return;
8961
+ event.preventDefault();
8962
+ const effectiveSensitivity = this.clientHeight * 2 * (event.shiftKey ? 10 : 1);
8963
+ const deltaValue = (this.#dragStartY - event.clientY) / effectiveSensitivity * (this.max - this.min);
8964
+ const relativeValue = scale(this.#valueAtDragStart + deltaValue, this.min, this.max, 0, 1);
8965
+ this.#setValueFromRelative(clampValue(relativeValue, 0, 1), true);
8966
+ };
8967
+ this.#onPointerUp = () => {
8968
+ this.#dragging = false;
8969
+ this.toggleAttribute(`dragging`, false);
8970
+ const svgEl = this.renderRoot.querySelector(`svg`);
8971
+ if (svgEl && `hasPointerCapture` in svgEl && typeof svgEl.hasPointerCapture === `function`) {
8972
+ if (svgEl.hasPointerCapture(1)) svgEl.releasePointerCapture(1);
8973
+ }
8974
+ window.removeEventListener(`pointermove`, this.#onPointerMove);
8975
+ window.removeEventListener(`pointerup`, this.#onPointerUp);
8976
+ window.removeEventListener(`pointercancel`, this.#onPointerUp);
8977
+ };
8978
+ this.#onKeyDown = (event) => {
8979
+ if (this.disabled) return;
8980
+ const range = this.max - this.min;
8981
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, event.shiftKey);
8982
+ let handled = false;
8983
+ switch (event.key) {
8984
+ case `ArrowUp`:
8985
+ case `ArrowRight`:
8986
+ this.#stepByRelativeDelta(effectiveStep / range, true);
8987
+ handled = true;
8988
+ break;
8989
+ case `ArrowDown`:
8990
+ case `ArrowLeft`:
8991
+ this.#stepByRelativeDelta(-effectiveStep / range, true);
8992
+ handled = true;
8993
+ break;
8994
+ case `Home`:
8995
+ this.#setValueFromRelative(0, true);
8996
+ handled = true;
8997
+ break;
8998
+ case `End`:
8999
+ this.#setValueFromRelative(1, true);
9000
+ handled = true;
9001
+ }
9002
+ if (handled) event.preventDefault();
9003
+ };
9004
+ }
9005
+ #dragging;
9006
+ #dragStartY;
9007
+ #valueAtDragStart;
9008
+ #changeDebounceTimer;
9009
+ #getRelativeValue() {
9010
+ return scale(this.value, this.min, this.max, 0, 1);
9011
+ }
9012
+ #quantise(value) {
9013
+ if (this.stops && this.stops > 1) {
9014
+ const step = (this.max - this.min) / this.stops;
9015
+ return Math.round((value - this.min) / step) * step + this.min;
9016
+ }
9017
+ return value;
9018
+ }
9019
+ #setValueFromRelative(relativeValue, isUserInteraction = false) {
9020
+ const newValue = scale(relativeValue, 0, 1, this.min, this.max);
9021
+ const clampedValue = this.#quantise(clampValue(newValue, this.min, this.max));
9022
+ if (clampedValue === this.value) return;
9023
+ const previousValue = this.value;
9024
+ this.value = clampedValue;
9025
+ if (this.hasAttribute(`data-tooltip-live`)) {
9026
+ const percentage = Math.round(this.#getRelativeValue() * 100);
9027
+ this.setAttribute(`data-tooltip`, `${percentage}%`);
9028
+ }
9029
+ if (isUserInteraction) {
9030
+ this.dispatchEvent(new CustomEvent(`input`, {
9031
+ detail: {
9032
+ value: this.value,
9033
+ valueRelative: this.#getRelativeValue()
9034
+ },
9035
+ bubbles: true,
9036
+ composed: true
9037
+ }));
9038
+ this.#scheduleChangeEvent(previousValue);
9039
+ } else this.#fireChangeEvent(previousValue);
9040
+ }
9041
+ #scheduleChangeEvent(previousValue) {
9042
+ if (this.#changeDebounceTimer !== void 0) clearTimeout(this.#changeDebounceTimer);
9043
+ this.#changeDebounceTimer = window.setTimeout(() => {
9044
+ this.#fireChangeEvent(previousValue);
9045
+ this.#changeDebounceTimer = void 0;
9046
+ }, 150);
9047
+ }
9048
+ #fireChangeEvent(previousValue) {
9049
+ this.dispatchEvent(new CustomEvent(`change`, {
9050
+ detail: {
9051
+ value: this.value,
9052
+ valueRelative: this.#getRelativeValue(),
9053
+ previousValue
9054
+ },
9055
+ bubbles: true,
9056
+ composed: true
9057
+ }));
9058
+ }
9059
+ #onPointerDown;
9060
+ #onPointerMove;
9061
+ #onPointerUp;
9062
+ #onKeyDown;
9063
+ /**
9064
+ * Apply a relative-delta nudge to the current value, clamped to [min, max] and
9065
+ * quantised. Shared between keyboard arrow keys and the wheel handler.
9066
+ */
9067
+ #stepByRelativeDelta(relativeDelta, isUserInteraction) {
9068
+ this.#setValueFromRelative(clampValue(this.#getRelativeValue() + relativeDelta, 0, 1), isUserInteraction);
9069
+ }
9070
+ _applyWheelDelta(direction, event) {
9071
+ const range = this.max - this.min;
9072
+ const effectiveStep = resolveAxisStep(range, this.stops, this.step, event.shiftKey);
9073
+ this.#stepByRelativeDelta(direction * effectiveStep / range, true);
9074
+ }
9075
+ #renderCircle() {
9076
+ const relativeValue = this.#getRelativeValue();
9077
+ const outerRadius = 45;
9078
+ const innerRadius = outerRadius * relativeValue;
9079
+ const outerCx = 50;
9080
+ const outerCy = 50;
9081
+ let cx = outerCx;
9082
+ if (this.fillMode === `left`) cx = 5 + outerRadius * relativeValue;
9083
+ else if (this.fillMode === `right`) cx = 95 - outerRadius * relativeValue;
9084
+ return svg`
9085
+ <circle class="fill" cx="${cx}" cy="${outerCy}" r="${innerRadius}" />
9086
+ <circle class="outline" cx="${outerCx}" cy="${outerCy}" r="${outerRadius}" fill="none" />
9087
+ `;
9088
+ }
9089
+ #renderRectangle() {
9090
+ const relativeValue = this.#getRelativeValue();
9091
+ const outerSize = 90;
9092
+ const outerOffset = 5;
9093
+ if (this.fillMode === `left` || this.fillMode === `right`) {
9094
+ const innerWidth = outerSize * relativeValue;
9095
+ const x = this.fillMode === `left` ? outerOffset : 95 - innerWidth;
9096
+ return svg`
9097
+ <rect class="fill" x="${x}" y="${outerOffset}" width="${innerWidth}" height="${outerSize}" />
9098
+ <rect class="outline" x="${outerOffset}" y="${outerOffset}" width="${outerSize}" height="${outerSize}" fill="none" />
9099
+ `;
9100
+ }
9101
+ const innerSize = outerSize * relativeValue;
9102
+ const innerOffset = (100 - innerSize) / 2;
9103
+ return svg`
9104
+ <rect class="fill" x="${innerOffset}" y="${innerOffset}" width="${innerSize}" height="${innerSize}" />
9105
+ <rect class="outline" x="${outerOffset}" y="${outerOffset}" width="${outerSize}" height="${outerSize}" fill="none" />
9106
+ `;
9107
+ }
9108
+ render() {
9109
+ const preserveAspectRatio = this.display === `rectangle` ? `none` : `xMidYMid meet`;
9110
+ return html`
9111
+ <svg
9112
+ viewBox="0 0 100 100"
9113
+ preserveAspectRatio="${preserveAspectRatio}"
9114
+ tabindex="${this.disabled ? -1 : 0}"
9115
+ @pointerdown="${this.#onPointerDown}"
9116
+ @keydown="${this.#onKeyDown}"
9117
+ style="cursor: ${this.#dragging ? `ns-resize` : `grab`}"
9118
+ >
9119
+ ${this.display === `rectangle` ? this.#renderRectangle() : this.#renderCircle()}
9120
+ </svg>
9121
+ `;
9122
+ }
9123
+ updated(changed) {
9124
+ super.updated(changed);
9125
+ this.style.setProperty(`--shapefill-value-relative`, this.#getRelativeValue().toString());
9126
+ }
9127
+ disconnectedCallback() {
9128
+ super.disconnectedCallback();
9129
+ if (this.#changeDebounceTimer !== void 0) clearTimeout(this.#changeDebounceTimer);
9130
+ this.#onPointerUp();
9131
+ }
9132
+ static {
9133
+ this.styles = [
9134
+ themeFallbacks,
9135
+ prominenceStyles,
9136
+ css`
9137
+ :host {
9138
+ display: inline-block;
9139
+ width: 2em;
9140
+ height: 2em;
9141
+ touch-action: none;
9142
+ user-select: none;
9143
+
9144
+ /* Dynamic value - set by JS */
9145
+ --shapefill-value-relative: 0;
9146
+
9147
+ /* Public styling variables — consumer customisable */
9148
+ --shapefill-value-outline-color: var(--surface-4);
9149
+ --shapefill-value-outline-width: 2;
9150
+ --shapefill-value-fill-color: var(--accent);
9151
+ }
9152
+
9153
+ :host([disabled]) {
9154
+ cursor: not-allowed;
9155
+ }
9156
+
9157
+ svg {
9158
+ width: 100%;
9159
+ height: 100%;
9160
+ outline: none;
9161
+ display: block;
9162
+ }
9163
+
9164
+ svg:active {
9165
+ cursor: grabbing;
9166
+ }
9167
+
9168
+ svg:focus-visible {
9169
+ outline: var(--shapefill-value-focus-outline, 2px solid var(--accent));
9170
+ outline-offset: var(--shapefill-value-focus-outline-offset, 2px);
9171
+ }
9172
+
9173
+ .outline {
9174
+ stroke: var(--shapefill-value-outline-color, var(--surface-4));
9175
+ stroke-width: var(--shapefill-value-outline-width, 2);
9176
+ vector-effect: non-scaling-stroke;
9177
+ }
9178
+
9179
+ .fill {
9180
+ fill: var(--shapefill-value-fill-color, var(--accent));
9181
+ transition: var(--shapefill-value-fill-transition, none);
9182
+ }
9183
+ `
9184
+ ];
9185
+ }
9186
+ };
9187
+ __decorate([property({ type: String })], ShapefillValueElement.prototype, "display", void 0);
9188
+ __decorate([property({
9189
+ type: String,
9190
+ attribute: `fill-mode`
9191
+ })], ShapefillValueElement.prototype, "fillMode", void 0);
9192
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "value", void 0);
9193
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "min", void 0);
9194
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "max", void 0);
9195
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "step", void 0);
9196
+ __decorate([property({ type: Number })], ShapefillValueElement.prototype, "stops", void 0);
9197
+ __decorate([property({
9198
+ type: Boolean,
9199
+ reflect: true
9200
+ })], ShapefillValueElement.prototype, "disabled", void 0);
9201
+ ShapefillValueElement = __decorate([safeCustomElement(`ixfx-shapefill-value`)], ShapefillValueElement);
9202
+ //#endregion
8856
9203
  //#region src/sliding-number/sliding-number.ts
8857
9204
  const REEL_DIGITS = Array.from({ length: 30 }, (_, index) => index % 10);
8858
9205
  const SECTION_RANK = {
@@ -9953,6 +10300,7 @@ let ToolbarElement = class ToolbarElement extends LitElement {
9953
10300
  this.invisibleGroups = false;
9954
10301
  this.allowReorder = false;
9955
10302
  this._overflowCount = 0;
10303
+ this._popoverOpen = false;
9956
10304
  this._ro = null;
9957
10305
  this._anchor = `--toolbar-${_ToolbarElement._cnt++}`;
9958
10306
  this._sizes = /* @__PURE__ */ new WeakMap();
@@ -10078,11 +10426,11 @@ let ToolbarElement = class ToolbarElement extends LitElement {
10078
10426
  .overflow-btn[hidden] { display: none; }
10079
10427
  .overflow-popover {
10080
10428
  position: fixed;
10081
- top: anchor(bottom);
10082
- left: anchor(right);
10429
+ inset: auto;
10430
+ margin: 0;
10083
10431
  position-anchor: var(--anchor-name);
10084
10432
  position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
10085
- margin: 8px;
10433
+ position-visibility: anchors-visible;
10086
10434
  max-height: min(60vh, 400px);
10087
10435
  max-width: min(90vw, 320px);
10088
10436
  overflow: auto;
@@ -10092,6 +10440,18 @@ let ToolbarElement = class ToolbarElement extends LitElement {
10092
10440
  flex-direction: column;
10093
10441
  gap: var(--space-s);
10094
10442
  }
10443
+ :host([orientation="horizontal"]) .overflow-popover {
10444
+ position-area: bottom span-left;
10445
+ margin-top: var(--toolbar-overflow-gap, 8px);
10446
+ }
10447
+ :host([orientation="vertical-left"]) .overflow-popover {
10448
+ position-area: right span-bottom;
10449
+ margin-left: var(--toolbar-overflow-gap, 8px);
10450
+ }
10451
+ :host([orientation="vertical-right"]) .overflow-popover {
10452
+ position-area: left span-bottom;
10453
+ margin-right: var(--toolbar-overflow-gap, 8px);
10454
+ }
10095
10455
  .overflow-popover:popover-open { display: flex; }
10096
10456
  .overflow-popover ::slotted(*) { writing-mode: horizontal-tb; text-orientation: mixed; }
10097
10457
 
@@ -10130,6 +10490,9 @@ let ToolbarElement = class ToolbarElement extends LitElement {
10130
10490
  });
10131
10491
  this._ro = new ResizeObserver(() => this._scheduleMeasure());
10132
10492
  this._ro.observe(this._inner);
10493
+ this._popover.addEventListener(`toggle`, () => {
10494
+ this._popoverOpen = this._popover.matches(`:popover-open`);
10495
+ });
10133
10496
  this._scheduleMeasure();
10134
10497
  this._updateGroups();
10135
10498
  }
@@ -10470,7 +10833,7 @@ let ToolbarElement = class ToolbarElement extends LitElement {
10470
10833
  return html`
10471
10834
  <div class="inner" role="toolbar" aria-orientation=${this.orientation}>
10472
10835
  <slot @pointerdown=${this._onPointerDown} @keydown=${this._onKeyDown}></slot>
10473
- <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>
10836
+ <ixfx-button class="overflow-btn" ?hidden=${!hasOverflow} @click=${this._toggleOverflow} aria-label="More" aria-haspopup="true" aria-expanded=${this._popoverOpen}>⋯</ixfx-button>
10474
10837
  </div>
10475
10838
  <div class="overflow-popover popup-surface" popover="auto" @click=${(e) => e.stopPropagation()}>
10476
10839
  <slot name="overflow"></slot>
@@ -10513,6 +10876,7 @@ __decorate([property({
10513
10876
  reflect: true
10514
10877
  })], ToolbarElement.prototype, "allowReorder", void 0);
10515
10878
  __decorate([state()], ToolbarElement.prototype, "_overflowCount", void 0);
10879
+ __decorate([state()], ToolbarElement.prototype, "_popoverOpen", void 0);
10516
10880
  __decorate([query(`.inner`)], ToolbarElement.prototype, "_inner", void 0);
10517
10881
  __decorate([query(`.overflow-popover`)], ToolbarElement.prototype, "_popover", void 0);
10518
10882
  __decorate([query(`slot`)], ToolbarElement.prototype, "_slot", void 0);
@@ -12499,6 +12863,6 @@ function init() {
12499
12863
  console.log(`Init`);
12500
12864
  }
12501
12865
  //#endregion
12502
- 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 };
12866
+ 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 };
12503
12867
 
12504
12868
  //# sourceMappingURL=index.js.map