@ixfx/components 0.10.4 → 0.10.5

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
@@ -46813,6 +46894,7 @@ let ToolbarElement = class ToolbarElement extends i {
46813
46894
  this.invisibleGroups = false;
46814
46895
  this.allowReorder = false;
46815
46896
  this._overflowCount = 0;
46897
+ this._popoverOpen = false;
46816
46898
  this._ro = null;
46817
46899
  this._anchor = `--toolbar-${_ToolbarElement._cnt++}`;
46818
46900
  this._sizes = /* @__PURE__ */ new WeakMap();
@@ -46938,11 +47020,11 @@ let ToolbarElement = class ToolbarElement extends i {
46938
47020
  .overflow-btn[hidden] { display: none; }
46939
47021
  .overflow-popover {
46940
47022
  position: fixed;
46941
- top: anchor(bottom);
46942
- left: anchor(right);
47023
+ inset: auto;
47024
+ margin: 0;
46943
47025
  position-anchor: var(--anchor-name);
46944
47026
  position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
46945
- margin: 8px;
47027
+ position-visibility: anchors-visible;
46946
47028
  max-height: min(60vh, 400px);
46947
47029
  max-width: min(90vw, 320px);
46948
47030
  overflow: auto;
@@ -46952,6 +47034,18 @@ let ToolbarElement = class ToolbarElement extends i {
46952
47034
  flex-direction: column;
46953
47035
  gap: var(--space-s);
46954
47036
  }
47037
+ :host([orientation="horizontal"]) .overflow-popover {
47038
+ position-area: bottom span-left;
47039
+ margin-top: var(--toolbar-overflow-gap, 8px);
47040
+ }
47041
+ :host([orientation="vertical-left"]) .overflow-popover {
47042
+ position-area: right span-bottom;
47043
+ margin-left: var(--toolbar-overflow-gap, 8px);
47044
+ }
47045
+ :host([orientation="vertical-right"]) .overflow-popover {
47046
+ position-area: left span-bottom;
47047
+ margin-right: var(--toolbar-overflow-gap, 8px);
47048
+ }
46955
47049
  .overflow-popover:popover-open { display: flex; }
46956
47050
  .overflow-popover ::slotted(*) { writing-mode: horizontal-tb; text-orientation: mixed; }
46957
47051
 
@@ -46990,6 +47084,9 @@ let ToolbarElement = class ToolbarElement extends i {
46990
47084
  });
46991
47085
  this._ro = new ResizeObserver(() => this._scheduleMeasure());
46992
47086
  this._ro.observe(this._inner);
47087
+ this._popover.addEventListener(`toggle`, () => {
47088
+ this._popoverOpen = this._popover.matches(`:popover-open`);
47089
+ });
46993
47090
  this._scheduleMeasure();
46994
47091
  this._updateGroups();
46995
47092
  }
@@ -47330,7 +47427,7 @@ let ToolbarElement = class ToolbarElement extends i {
47330
47427
  return b`
47331
47428
  <div class="inner" role="toolbar" aria-orientation=${this.orientation}>
47332
47429
  <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>
47430
+ <ixfx-button class="overflow-btn" ?hidden=${!hasOverflow} @click=${this._toggleOverflow} aria-label="More" aria-haspopup="true" aria-expanded=${this._popoverOpen}>⋯</ixfx-button>
47334
47431
  </div>
47335
47432
  <div class="overflow-popover popup-surface" popover="auto" @click=${(e) => e.stopPropagation()}>
47336
47433
  <slot name="overflow"></slot>
@@ -47373,6 +47470,7 @@ __decorate([property({
47373
47470
  reflect: true
47374
47471
  })], ToolbarElement.prototype, "allowReorder", void 0);
47375
47472
  __decorate([state()], ToolbarElement.prototype, "_overflowCount", void 0);
47473
+ __decorate([state()], ToolbarElement.prototype, "_popoverOpen", void 0);
47376
47474
  __decorate([query(`.inner`)], ToolbarElement.prototype, "_inner", void 0);
47377
47475
  __decorate([query(`.overflow-popover`)], ToolbarElement.prototype, "_popover", void 0);
47378
47476
  __decorate([query(`slot`)], ToolbarElement.prototype, "_slot", void 0);