@ixfx/components 0.10.2 → 0.10.4
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.d.ts +89 -28
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +298 -9
- package/bundle/index.js.map +1 -1
- package/dist/{button-DsFbV4XD.js → button-B7mgqtxR.js} +36 -2
- package/dist/button-B7mgqtxR.js.map +1 -0
- package/dist/button-BYuf72aR.d.ts +63 -0
- package/dist/button-BYuf72aR.d.ts.map +1 -0
- package/dist/button.d.ts +2 -21
- package/dist/button.js +1 -1
- package/dist/{data-grid-pv6eaJCZ.d.ts → data-grid-DE1_gZNk.d.ts} +7 -2
- package/dist/data-grid-DE1_gZNk.d.ts.map +1 -0
- package/dist/data-grid.d.ts +2 -2
- package/dist/data-grid.js +56 -0
- package/dist/data-grid.js.map +1 -1
- package/dist/{detail-list-BA3RVVCB.d.ts → detail-list-CaStSzYN.d.ts} +5 -3
- package/dist/detail-list-CaStSzYN.d.ts.map +1 -0
- package/dist/detail-list.d.ts +4 -3
- package/dist/detail-list.js +61 -1
- package/dist/detail-list.js.map +1 -1
- package/dist/{grid-list-DWXJoRnK.d.ts → grid-list-BJDxBL0x.d.ts} +15 -2
- package/dist/{grid-list-DWXJoRnK.d.ts.map → grid-list-BJDxBL0x.d.ts.map} +1 -1
- package/dist/{grid-list-CIc4jo-x.js → grid-list-CaMcdpFJ.js} +100 -7
- package/dist/grid-list-CaMcdpFJ.js.map +1 -0
- package/dist/grid-list.d.ts +2 -2
- package/dist/grid-list.js +1 -1
- package/dist/{grouped-item-lister-fdZHVxFM.d.ts → grouped-item-lister-DETte0Dh.d.ts} +2 -2
- package/dist/{grouped-item-lister-fdZHVxFM.d.ts.map → grouped-item-lister-DETte0Dh.d.ts.map} +1 -1
- package/dist/grouped-item-lister.d.ts +1 -1
- package/dist/index.d.ts +9 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{list-selection-types-B5ioL-dG.d.ts → list-selection-types-PjKdhF-a.d.ts} +1 -9
- package/dist/list-selection-types-PjKdhF-a.d.ts.map +1 -0
- package/dist/list-viewport-types-BRZsLcvp.d.ts +23 -0
- package/dist/list-viewport-types-BRZsLcvp.d.ts.map +1 -0
- package/dist/{vertical-list-BWLqy3PJ.d.ts → vertical-list-DfcNsa4p.d.ts} +10 -2
- package/dist/vertical-list-DfcNsa4p.d.ts.map +1 -0
- package/dist/vertical-list.d.ts +4 -3
- package/dist/vertical-list.js +47 -1
- package/dist/vertical-list.js.map +1 -1
- package/docs-user/data-grid.md +9 -0
- package/docs-user/detail-list.md +8 -0
- package/docs-user/grid-list.md +16 -1
- package/docs-user/index.json +2 -2
- package/docs-user/vertical-list.md +7 -0
- package/package.json +1 -1
- package/dist/button-DsFbV4XD.js.map +0 -1
- package/dist/button.d.ts.map +0 -1
- package/dist/data-grid-pv6eaJCZ.d.ts.map +0 -1
- package/dist/detail-list-BA3RVVCB.d.ts.map +0 -1
- package/dist/grid-list-CIc4jo-x.js.map +0 -1
- package/dist/list-selection-types-B5ioL-dG.d.ts.map +0 -1
- package/dist/vertical-list-BWLqy3PJ.d.ts.map +0 -1
package/bundle/index.js
CHANGED
|
@@ -5715,6 +5715,20 @@ const buttonStyles = i$3`
|
|
|
5715
5715
|
:host([subtle]) button:focus-visible:not(:disabled) {
|
|
5716
5716
|
background: color-mix(in oklch, var(--surface-4, #ccc) 70%, transparent);
|
|
5717
5717
|
}
|
|
5718
|
+
|
|
5719
|
+
:host([toggleable]) button:not(:disabled) {
|
|
5720
|
+
opacity: 0.7;
|
|
5721
|
+
}
|
|
5722
|
+
|
|
5723
|
+
:host([toggleable]) button:hover:not(:disabled) {
|
|
5724
|
+
opacity: 0.85;
|
|
5725
|
+
}
|
|
5726
|
+
|
|
5727
|
+
:host([toggleable][value]) button:not(:disabled) {
|
|
5728
|
+
opacity: 1;
|
|
5729
|
+
outline: var(--ixfx-button-toggle-outline-width, 2px) solid var(--ixfx-button-toggle-outline-color, oklch(from var(--accent, #666) l c calc(h + 130)));
|
|
5730
|
+
outline-offset: var(--ixfx-button-toggle-outline-offset, 2px);
|
|
5731
|
+
}
|
|
5718
5732
|
`;
|
|
5719
5733
|
//#endregion
|
|
5720
5734
|
//#region src/button/button.ts
|
|
@@ -5726,7 +5740,19 @@ let ButtonElement = class ButtonElement extends i {
|
|
|
5726
5740
|
this.hideLabel = false;
|
|
5727
5741
|
this.hasIcon = false;
|
|
5728
5742
|
this.subtle = false;
|
|
5743
|
+
this.toggleable = false;
|
|
5744
|
+
this.value = false;
|
|
5745
|
+
this.#handleClick = () => {
|
|
5746
|
+
if (!this.toggleable || this.disabled) return;
|
|
5747
|
+
this.value = !this.value;
|
|
5748
|
+
this.dispatchEvent(new CustomEvent(`toggle`, {
|
|
5749
|
+
detail: { value: this.value },
|
|
5750
|
+
bubbles: true,
|
|
5751
|
+
composed: true
|
|
5752
|
+
}));
|
|
5753
|
+
};
|
|
5729
5754
|
}
|
|
5755
|
+
#handleClick;
|
|
5730
5756
|
_renderIcon() {
|
|
5731
5757
|
if (this.hideIcon || !this.icon) return A;
|
|
5732
5758
|
if (this.icon.startsWith(`<svg`)) return b`<span class="button-icon">${unsafeHTML(this.icon)}</span>`;
|
|
@@ -5736,7 +5762,7 @@ let ButtonElement = class ButtonElement extends i {
|
|
|
5736
5762
|
render() {
|
|
5737
5763
|
this.hasIcon = !this.hideIcon && !!this.icon;
|
|
5738
5764
|
const label = this.hideLabel ? A : b`<span class="button-label"><slot></slot></span>`;
|
|
5739
|
-
return b`<button ?disabled=${this.disabled}>${this._renderIcon()}${label}</button>`;
|
|
5765
|
+
return b`<button ?disabled=${this.disabled} @click=${this.#handleClick}>${this._renderIcon()}${label}</button>`;
|
|
5740
5766
|
}
|
|
5741
5767
|
static {
|
|
5742
5768
|
this.styles = [prominenceStyles, buttonStyles];
|
|
@@ -5763,6 +5789,14 @@ __decorate([property({
|
|
|
5763
5789
|
type: Boolean,
|
|
5764
5790
|
reflect: true
|
|
5765
5791
|
})], ButtonElement.prototype, "subtle", void 0);
|
|
5792
|
+
__decorate([property({
|
|
5793
|
+
type: Boolean,
|
|
5794
|
+
reflect: true
|
|
5795
|
+
})], ButtonElement.prototype, "toggleable", void 0);
|
|
5796
|
+
__decorate([property({
|
|
5797
|
+
type: Boolean,
|
|
5798
|
+
reflect: true
|
|
5799
|
+
})], ButtonElement.prototype, "value", void 0);
|
|
5766
5800
|
ButtonElement = __decorate([safeCustomElement(`ixfx-button`)], ButtonElement);
|
|
5767
5801
|
//#endregion
|
|
5768
5802
|
//#region src/button/radio-group.ts
|
|
@@ -14627,6 +14661,12 @@ __decorate([query(`.text`)], PanTextElement.prototype, "_textEl", void 0);
|
|
|
14627
14661
|
PanTextElement = __decorate([safeCustomElement(`ixfx-pan-text`)], PanTextElement);
|
|
14628
14662
|
//#endregion
|
|
14629
14663
|
//#region src/data-grid/data-grid.ts
|
|
14664
|
+
/** Shallow key-array equality, treating `undefined` (never dispatched) as different. */
|
|
14665
|
+
function sameKeys$3(a, b) {
|
|
14666
|
+
if (a === void 0 || a.length !== b.length) return false;
|
|
14667
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
14668
|
+
return true;
|
|
14669
|
+
}
|
|
14630
14670
|
let DataGridElement = class DataGridElement extends i {
|
|
14631
14671
|
constructor(..._args) {
|
|
14632
14672
|
super(..._args);
|
|
@@ -14719,6 +14759,7 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
14719
14759
|
this._colOffsets = [];
|
|
14720
14760
|
this._colWidthSum = 0;
|
|
14721
14761
|
this._raf = 0;
|
|
14762
|
+
this.#viewportChangeRaf = 0;
|
|
14722
14763
|
this.#appendInProgress = false;
|
|
14723
14764
|
this.#resortRaf = 0;
|
|
14724
14765
|
this._drag = null;
|
|
@@ -14740,6 +14781,9 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
14740
14781
|
this._scrollLeft = el.scrollLeft;
|
|
14741
14782
|
if (this._headerScrollEl) this._headerScrollEl.scrollLeft = el.scrollLeft;
|
|
14742
14783
|
this.requestUpdate();
|
|
14784
|
+
cancelAnimationFrame(this.#viewportChangeRaf);
|
|
14785
|
+
this.#viewportChangeRaf = 0;
|
|
14786
|
+
this.#emitViewportChangeIfChanged();
|
|
14743
14787
|
});
|
|
14744
14788
|
};
|
|
14745
14789
|
this._onKeyDown = (e) => {
|
|
@@ -15173,6 +15217,10 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
15173
15217
|
#enteringRowKeys;
|
|
15174
15218
|
#rowReflowTimer;
|
|
15175
15219
|
#dataGridRenderedOnce;
|
|
15220
|
+
#viewportChangeRaf;
|
|
15221
|
+
/** Key sets as of the last `datagrid-viewport-change` dispatch, for dedupe. */
|
|
15222
|
+
#lastViewportRenderedKeys;
|
|
15223
|
+
#lastViewportVisibleKeys;
|
|
15176
15224
|
#appendInProgress;
|
|
15177
15225
|
#resortRaf;
|
|
15178
15226
|
connectedCallback() {
|
|
@@ -15188,6 +15236,8 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
15188
15236
|
this.removeEventListener(`keydown`, this._onKeyDown);
|
|
15189
15237
|
this.removeEventListener(`focusout`, this._onFocusOut);
|
|
15190
15238
|
cancelAnimationFrame(this._raf);
|
|
15239
|
+
cancelAnimationFrame(this.#viewportChangeRaf);
|
|
15240
|
+
this.#viewportChangeRaf = 0;
|
|
15191
15241
|
this.#unregisterSearchCommands?.();
|
|
15192
15242
|
this.#unregisterSearchCommands = void 0;
|
|
15193
15243
|
this.#searchRegistry = void 0;
|
|
@@ -15228,6 +15278,7 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
15228
15278
|
if (w === this._viewportW && h === this._viewportH) return;
|
|
15229
15279
|
this._viewportW = w;
|
|
15230
15280
|
this._viewportH = h;
|
|
15281
|
+
this.#scheduleViewportChangeEmit();
|
|
15231
15282
|
}
|
|
15232
15283
|
/**
|
|
15233
15284
|
* Force a fresh re-measure of the viewport and re-render. Normally
|
|
@@ -15242,6 +15293,7 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
15242
15293
|
}
|
|
15243
15294
|
updated(changed) {
|
|
15244
15295
|
super.updated(changed);
|
|
15296
|
+
if (changed.has(`rows`) || changed.has(`sortState`) || changed.has(`columns`) || changed.has(`groupBy`) || changed.has(`groupLabel`) || changed.has(`filterPredicate`) || changed.has(`rowHeight`)) this.#scheduleViewportChangeEmit();
|
|
15245
15297
|
if (changed.has(`_editing`) || changed.has(`_editingRow`)) requestAnimationFrame(() => {
|
|
15246
15298
|
let sel = null;
|
|
15247
15299
|
if (this._editing) sel = `.row[data-key="${this._editing.rowKey}"] .cell[data-col="${this._editing.colKey}"] input, .row[data-key="${this._editing.rowKey}"] .cell[data-col="${this._editing.colKey}"] select`;
|
|
@@ -16021,6 +16073,44 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
16021
16073
|
const { startRow, endRow } = this.getVisibleRange();
|
|
16022
16074
|
return this._flat.slice(startRow, endRow).filter((f) => f.type === `row`).map((f) => f.key);
|
|
16023
16075
|
}
|
|
16076
|
+
/**
|
|
16077
|
+
* Row keys strictly intersecting the viewport (no overscan), mirroring
|
|
16078
|
+
* `ixfx-grid-list.visibleKeys()` for the `datagrid-viewport-change` detail.
|
|
16079
|
+
*/
|
|
16080
|
+
#visibleKeys() {
|
|
16081
|
+
const rh = this.rowHeight;
|
|
16082
|
+
const startRow = Math.max(0, Math.floor(this._scrollTop / rh));
|
|
16083
|
+
const endRow = Math.min(this._flat.length, Math.ceil((this._scrollTop + this._viewportH) / rh));
|
|
16084
|
+
return this._flat.slice(startRow, endRow).filter((f) => f.type === `row`).map((f) => f.key);
|
|
16085
|
+
}
|
|
16086
|
+
/** Coalesce viewport-change dispatches to at most one per animation frame. */
|
|
16087
|
+
#scheduleViewportChangeEmit() {
|
|
16088
|
+
if (this.#viewportChangeRaf !== 0) return;
|
|
16089
|
+
this.#viewportChangeRaf = requestAnimationFrame(() => {
|
|
16090
|
+
this.#viewportChangeRaf = 0;
|
|
16091
|
+
this.#emitViewportChangeIfChanged();
|
|
16092
|
+
});
|
|
16093
|
+
}
|
|
16094
|
+
/**
|
|
16095
|
+
* Dispatch `datagrid-viewport-change` with the current key sets — unless
|
|
16096
|
+
* neither set changed since the last dispatch, so coalesced frames and
|
|
16097
|
+
* no-op scrolls stay silent.
|
|
16098
|
+
*/
|
|
16099
|
+
#emitViewportChangeIfChanged() {
|
|
16100
|
+
const renderedKeys = this.renderedKeys();
|
|
16101
|
+
const visibleKeys = this.#visibleKeys();
|
|
16102
|
+
if (sameKeys$3(this.#lastViewportRenderedKeys, renderedKeys) && sameKeys$3(this.#lastViewportVisibleKeys, visibleKeys)) return;
|
|
16103
|
+
this.#lastViewportRenderedKeys = renderedKeys;
|
|
16104
|
+
this.#lastViewportVisibleKeys = visibleKeys;
|
|
16105
|
+
this.dispatchEvent(new CustomEvent(`datagrid-viewport-change`, {
|
|
16106
|
+
detail: {
|
|
16107
|
+
renderedKeys,
|
|
16108
|
+
visibleKeys
|
|
16109
|
+
},
|
|
16110
|
+
bubbles: true,
|
|
16111
|
+
composed: true
|
|
16112
|
+
}));
|
|
16113
|
+
}
|
|
16024
16114
|
_findFirstVisibleCol(scrollLeft) {
|
|
16025
16115
|
let lo = 0;
|
|
16026
16116
|
let hi = this._colOffsets.length - 1;
|
|
@@ -16619,6 +16709,12 @@ DataTableElement = __decorate([safeCustomElement(`ixfx-data-table`)], DataTableE
|
|
|
16619
16709
|
const ITEM_SELECTOR$3 = `:scope > li`;
|
|
16620
16710
|
const SEARCH_HIGHLIGHT_KEY = `detail-list-search`;
|
|
16621
16711
|
const LABEL_SPAN_CSS = `overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0`;
|
|
16712
|
+
/** Shallow key-array equality, treating `undefined` (never dispatched) as different. */
|
|
16713
|
+
function sameKeys$2(a, b) {
|
|
16714
|
+
if (a === void 0 || a.length !== b.length) return false;
|
|
16715
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
16716
|
+
return true;
|
|
16717
|
+
}
|
|
16622
16718
|
let DetailListElement = class DetailListElement extends i {
|
|
16623
16719
|
constructor(..._args) {
|
|
16624
16720
|
super(..._args);
|
|
@@ -16637,6 +16733,7 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
16637
16733
|
this.#positions = /* @__PURE__ */ new Map();
|
|
16638
16734
|
this.#geometryScheduled = false;
|
|
16639
16735
|
this.#sortRaf = 0;
|
|
16736
|
+
this.#viewportScrollRaf = 0;
|
|
16640
16737
|
this.#animatedItems = /* @__PURE__ */ new WeakSet();
|
|
16641
16738
|
this.#builtFromProvider = [];
|
|
16642
16739
|
this.#providerBuilt = 0;
|
|
@@ -16730,6 +16827,13 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
16730
16827
|
getLabel: (el) => el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
|
|
16731
16828
|
highlightKey: SEARCH_HIGHLIGHT_KEY
|
|
16732
16829
|
}) });
|
|
16830
|
+
this.#onListScroll = () => {
|
|
16831
|
+
if (this.#viewportScrollRaf !== 0) return;
|
|
16832
|
+
this.#viewportScrollRaf = requestAnimationFrame(() => {
|
|
16833
|
+
this.#viewportScrollRaf = 0;
|
|
16834
|
+
this.#emitViewportChangeIfChanged();
|
|
16835
|
+
});
|
|
16836
|
+
};
|
|
16733
16837
|
this._onPointerOver = (e) => {
|
|
16734
16838
|
const item = this._findListItem(e.composedPath());
|
|
16735
16839
|
if (item) this.tickled.handlePointerEnter(item);
|
|
@@ -16821,6 +16925,10 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
16821
16925
|
#positions;
|
|
16822
16926
|
#geometryScheduled;
|
|
16823
16927
|
#sortRaf;
|
|
16928
|
+
#viewportScrollRaf;
|
|
16929
|
+
/** Key sets as of the last viewport-change dispatch, for dedupe. */
|
|
16930
|
+
#lastViewportRenderedKeys;
|
|
16931
|
+
#lastViewportVisibleKeys;
|
|
16824
16932
|
#resizeObserver;
|
|
16825
16933
|
#mutationObserver;
|
|
16826
16934
|
/** Items that have already played (or been skipped for) their enter animation. */
|
|
@@ -16960,6 +17068,8 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
16960
17068
|
this.removeEventListener(`dblclick`, this._onDblClick);
|
|
16961
17069
|
this.removeEventListener(`wheel`, this._onWheel);
|
|
16962
17070
|
cancelAnimationFrame(this.#sortRaf);
|
|
17071
|
+
cancelAnimationFrame(this.#viewportScrollRaf);
|
|
17072
|
+
this.#viewportScrollRaf = 0;
|
|
16963
17073
|
this.#resizeObserver?.disconnect();
|
|
16964
17074
|
this.#resizeObserver = void 0;
|
|
16965
17075
|
this.#mutationObserver?.disconnect();
|
|
@@ -17312,6 +17422,7 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
17312
17422
|
col: colIdx,
|
|
17313
17423
|
row: rowIdx
|
|
17314
17424
|
})));
|
|
17425
|
+
this.#scheduleViewportChangeEmit();
|
|
17315
17426
|
}
|
|
17316
17427
|
#positionOf(el) {
|
|
17317
17428
|
let pos = this.#positions.get(el);
|
|
@@ -17603,6 +17714,45 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
17603
17714
|
cancelable: true
|
|
17604
17715
|
}));
|
|
17605
17716
|
}
|
|
17717
|
+
/** Scroll on the `part="list"` element — rAF-coalesced viewport-change check. */
|
|
17718
|
+
#onListScroll;
|
|
17719
|
+
/** Coalesce non-scroll viewport checks to at most one per animation frame. */
|
|
17720
|
+
#scheduleViewportChangeEmit() {
|
|
17721
|
+
if (this.#viewportScrollRaf !== 0) return;
|
|
17722
|
+
this.#viewportScrollRaf = requestAnimationFrame(() => {
|
|
17723
|
+
this.#viewportScrollRaf = 0;
|
|
17724
|
+
this.#emitViewportChangeIfChanged();
|
|
17725
|
+
});
|
|
17726
|
+
}
|
|
17727
|
+
/**
|
|
17728
|
+
* Keys of everything currently rendered. The list has no virtual window —
|
|
17729
|
+
* every non-hidden item is in the DOM — so this is all keyed items, mirroring
|
|
17730
|
+
* `ixfx-vertical-list.renderedKeys()` in its non-virtualized mode.
|
|
17731
|
+
*/
|
|
17732
|
+
#renderedKeys() {
|
|
17733
|
+
const out = [];
|
|
17734
|
+
for (const el of this._getVisibleItems()) {
|
|
17735
|
+
const key = keyForElement(el);
|
|
17736
|
+
if (key !== void 0) out.push(key);
|
|
17737
|
+
}
|
|
17738
|
+
return out;
|
|
17739
|
+
}
|
|
17740
|
+
/**
|
|
17741
|
+
* Dispatch `detail-list-viewport-change` with the current key sets — unless
|
|
17742
|
+
* neither set changed since the last dispatch, so coalesced frames and
|
|
17743
|
+
* no-op scrolls stay silent.
|
|
17744
|
+
*/
|
|
17745
|
+
#emitViewportChangeIfChanged() {
|
|
17746
|
+
const renderedKeys = this.#renderedKeys();
|
|
17747
|
+
const visibleKeys = this.visibleKeys();
|
|
17748
|
+
if (sameKeys$2(this.#lastViewportRenderedKeys, renderedKeys) && sameKeys$2(this.#lastViewportVisibleKeys, visibleKeys)) return;
|
|
17749
|
+
this.#lastViewportRenderedKeys = renderedKeys;
|
|
17750
|
+
this.#lastViewportVisibleKeys = visibleKeys;
|
|
17751
|
+
this._dispatch(`detail-list-viewport-change`, {
|
|
17752
|
+
renderedKeys,
|
|
17753
|
+
visibleKeys
|
|
17754
|
+
});
|
|
17755
|
+
}
|
|
17606
17756
|
_activateItem(item) {
|
|
17607
17757
|
if (this.interactionMode !== `manual`) this.selection.replace(item);
|
|
17608
17758
|
this._dispatch(`list-activate`, { item });
|
|
@@ -17761,7 +17911,7 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
17761
17911
|
const progress = this.#data.progress;
|
|
17762
17912
|
return b`
|
|
17763
17913
|
<div class="container">
|
|
17764
|
-
<ul part="list" class="scroll-fade-x">
|
|
17914
|
+
<ul part="list" class="scroll-fade-x" @scroll=${this.#onListScroll}>
|
|
17765
17915
|
<slot></slot>
|
|
17766
17916
|
</ul>
|
|
17767
17917
|
${this.#marqueeRect ? b`<div class="marquee" part="marquee" style=${this.#marqueeStyle(this.#marqueeRect)}></div>` : ``}
|
|
@@ -23629,12 +23779,19 @@ function columnOf(index, cols) {
|
|
|
23629
23779
|
function rowOf(index, cols) {
|
|
23630
23780
|
return cols <= 1 ? index : Math.floor(index / cols);
|
|
23631
23781
|
}
|
|
23782
|
+
/** Shallow key-array equality, treating `undefined` (never dispatched) as different. */
|
|
23783
|
+
function sameKeys$1(a, b) {
|
|
23784
|
+
if (a === void 0 || a.length !== b.length) return false;
|
|
23785
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
23786
|
+
return true;
|
|
23787
|
+
}
|
|
23632
23788
|
let GridListElement = class GridListElement extends i {
|
|
23633
23789
|
constructor(..._args) {
|
|
23634
23790
|
super(..._args);
|
|
23635
23791
|
this.selectionMode = `single`;
|
|
23636
23792
|
this.interactionMode = `standard`;
|
|
23637
23793
|
this.disableHoverTickle = false;
|
|
23794
|
+
this.disableScrollHoverTickle = false;
|
|
23638
23795
|
this.itemSize = 160;
|
|
23639
23796
|
this.gap = 8;
|
|
23640
23797
|
this.orientation = `grid`;
|
|
@@ -23691,6 +23848,9 @@ let GridListElement = class GridListElement extends i {
|
|
|
23691
23848
|
itemWrap: this.#itemWrap,
|
|
23692
23849
|
hoverDisabled: () => this.disableHoverTickle || this.#dragSelect.isDragging || this.#nativeDrag.isDragging
|
|
23693
23850
|
});
|
|
23851
|
+
this.#scrollHoverSuppress = false;
|
|
23852
|
+
this.#lastPointerX = NaN;
|
|
23853
|
+
this.#lastPointerY = NaN;
|
|
23694
23854
|
this.#marqueePreview = /* @__PURE__ */ new Set();
|
|
23695
23855
|
this.#nativeDragging = false;
|
|
23696
23856
|
this.#dragOriginKey = void 0;
|
|
@@ -23773,6 +23933,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
23773
23933
|
this.#selectedSnapshot = /* @__PURE__ */ new Set();
|
|
23774
23934
|
this.#onScroll = (e) => {
|
|
23775
23935
|
const el = e.target;
|
|
23936
|
+
this.#markScrollHoverSuppress();
|
|
23776
23937
|
this.#cancelScrollRaf();
|
|
23777
23938
|
this.#scrollRaf = requestAnimationFrame(() => {
|
|
23778
23939
|
this.#scrollRaf = 0;
|
|
@@ -23789,9 +23950,23 @@ let GridListElement = class GridListElement extends i {
|
|
|
23789
23950
|
const vp = this.#viewportRef.value ?? e.currentTarget;
|
|
23790
23951
|
if (!vp) return;
|
|
23791
23952
|
if (vp.scrollWidth <= vp.clientWidth + 1) return;
|
|
23953
|
+
this.#markScrollHoverSuppress();
|
|
23792
23954
|
vp.scrollLeft += e.deltaX + e.deltaY;
|
|
23793
23955
|
e.preventDefault();
|
|
23794
23956
|
};
|
|
23957
|
+
this.#onHostPointerMove = (e) => {
|
|
23958
|
+
const moved = !Number.isNaN(this.#lastPointerX) && (e.clientX !== this.#lastPointerX || e.clientY !== this.#lastPointerY);
|
|
23959
|
+
this.#lastPointerX = e.clientX;
|
|
23960
|
+
this.#lastPointerY = e.clientY;
|
|
23961
|
+
if (!moved || !this.#scrollHoverSuppress) return;
|
|
23962
|
+
this.#endScrollHoverSuppress();
|
|
23963
|
+
if (this.disableHoverTickle) return;
|
|
23964
|
+
const key = this.shadowRoot?.elementFromPoint?.(e.clientX, e.clientY)?.closest(`.cell`)?.getAttribute(`data-key`);
|
|
23965
|
+
if (key) this.tickled.handlePointerEnter(key);
|
|
23966
|
+
};
|
|
23967
|
+
this.#onHostPointerLeave = () => {
|
|
23968
|
+
this.#endScrollHoverSuppress();
|
|
23969
|
+
};
|
|
23795
23970
|
this._onKeyDown = (e) => {
|
|
23796
23971
|
if ((e.ctrlKey || e.metaKey) && e.key === `f`) return;
|
|
23797
23972
|
if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
|
|
@@ -24037,7 +24212,10 @@ let GridListElement = class GridListElement extends i {
|
|
|
24037
24212
|
transition: background var(--transition), border-color var(--transition);
|
|
24038
24213
|
}
|
|
24039
24214
|
:host(:not([caption-style="separate"])) .cell.tickled,
|
|
24040
|
-
|
|
24215
|
+
/* [data-scroll-hover-suppress] is set while a scroll gesture moves
|
|
24216
|
+
cells beneath a stationary pointer (see disable-scroll-hover-tickle):
|
|
24217
|
+
the :hover highlight is gated so the visual cursor holds still too. */
|
|
24218
|
+
:host(:not([caption-style="separate"]):not([disable-hover-tickle]):not([data-scroll-hover-suppress])) .cell:hover {
|
|
24041
24219
|
background: var(--item-bg-tickled);
|
|
24042
24220
|
border: var(--item-border-tickled);
|
|
24043
24221
|
}
|
|
@@ -24113,7 +24291,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
24113
24291
|
border: 1px solid transparent;
|
|
24114
24292
|
}
|
|
24115
24293
|
:host([caption-style="separate"]) .cell.tickled .thumb,
|
|
24116
|
-
:host([caption-style="separate"]:not([disable-hover-tickle])) .cell:hover .thumb {
|
|
24294
|
+
:host([caption-style="separate"]:not([disable-hover-tickle]):not([data-scroll-hover-suppress])) .cell:hover .thumb {
|
|
24117
24295
|
background: var(--grid-list-thumb-bg-tickled, var(--item-bg-tickled));
|
|
24118
24296
|
border: var(--item-border-tickled);
|
|
24119
24297
|
}
|
|
@@ -24234,6 +24412,16 @@ let GridListElement = class GridListElement extends i {
|
|
|
24234
24412
|
*/
|
|
24235
24413
|
#sourceElement;
|
|
24236
24414
|
#source;
|
|
24415
|
+
/**
|
|
24416
|
+
* True while cell `pointerenter` tickling is suppressed by an active or
|
|
24417
|
+
* just-finished scroll gesture (`disable-scroll-hover-tickle`). While set,
|
|
24418
|
+
* the host carries `[data-scroll-hover-suppress]`, which gates the CSS
|
|
24419
|
+
* `:hover` highlight so the visual cursor does not churn either.
|
|
24420
|
+
*/
|
|
24421
|
+
#scrollHoverSuppress;
|
|
24422
|
+
/** Last pointer position seen over the host; real movement ends suppression. */
|
|
24423
|
+
#lastPointerX;
|
|
24424
|
+
#lastPointerY;
|
|
24237
24425
|
/** Live drag-select preview: covered keys + the surface-relative rect. */
|
|
24238
24426
|
#marqueePreview;
|
|
24239
24427
|
#marqueeRect;
|
|
@@ -24403,6 +24591,8 @@ let GridListElement = class GridListElement extends i {
|
|
|
24403
24591
|
[`caption-backdrop`, this.captionBackdrop]
|
|
24404
24592
|
]) if (!this.hasAttribute(attr)) this.setAttribute(attr, value);
|
|
24405
24593
|
this.addEventListener(`keydown`, this._onKeyDown);
|
|
24594
|
+
this.addEventListener(`pointermove`, this.#onHostPointerMove, { passive: true });
|
|
24595
|
+
this.addEventListener(`pointerleave`, this.#onHostPointerLeave);
|
|
24406
24596
|
this.#mutationObserver ??= new MutationObserver((records) => this.#onChildrenChanged(records));
|
|
24407
24597
|
this.#mutationObserver.observe(this, {
|
|
24408
24598
|
childList: true,
|
|
@@ -24416,6 +24606,9 @@ let GridListElement = class GridListElement extends i {
|
|
|
24416
24606
|
super.disconnectedCallback();
|
|
24417
24607
|
this.#stopActiveCaptionPan();
|
|
24418
24608
|
this.removeEventListener(`keydown`, this._onKeyDown);
|
|
24609
|
+
this.removeEventListener(`pointermove`, this.#onHostPointerMove);
|
|
24610
|
+
this.removeEventListener(`pointerleave`, this.#onHostPointerLeave);
|
|
24611
|
+
this.#endScrollHoverSuppress();
|
|
24419
24612
|
this.#resizeObserver?.disconnect();
|
|
24420
24613
|
this.#resizeObserver = void 0;
|
|
24421
24614
|
this.#mutationObserver?.disconnect();
|
|
@@ -24486,10 +24679,23 @@ let GridListElement = class GridListElement extends i {
|
|
|
24486
24679
|
this.requestUpdate();
|
|
24487
24680
|
}, REFLOW_WINDOW_MS);
|
|
24488
24681
|
}
|
|
24682
|
+
/** Key sets as of the last `grid-list-viewport-change` dispatch, for dedupe. */
|
|
24683
|
+
#lastViewportRenderedKeys;
|
|
24684
|
+
#lastViewportVisibleKeys;
|
|
24685
|
+
/**
|
|
24686
|
+
* Dispatch `grid-list-viewport-change` with the current key sets — unless
|
|
24687
|
+
* neither set changed since the last dispatch, so coalesced frames and
|
|
24688
|
+
* no-op scrolls stay silent.
|
|
24689
|
+
*/
|
|
24489
24690
|
#emitViewportChange() {
|
|
24691
|
+
const renderedKeys = this.renderedKeys();
|
|
24692
|
+
const visibleKeys = this.visibleKeys();
|
|
24693
|
+
if (sameKeys$1(this.#lastViewportRenderedKeys, renderedKeys) && sameKeys$1(this.#lastViewportVisibleKeys, visibleKeys)) return;
|
|
24694
|
+
this.#lastViewportRenderedKeys = renderedKeys;
|
|
24695
|
+
this.#lastViewportVisibleKeys = visibleKeys;
|
|
24490
24696
|
this._dispatch(`grid-list-viewport-change`, {
|
|
24491
|
-
renderedKeys
|
|
24492
|
-
visibleKeys
|
|
24697
|
+
renderedKeys,
|
|
24698
|
+
visibleKeys
|
|
24493
24699
|
});
|
|
24494
24700
|
}
|
|
24495
24701
|
firstUpdated() {
|
|
@@ -24599,6 +24805,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
24599
24805
|
this.selection.clearAnchor();
|
|
24600
24806
|
this.#syncAriaMultiselectable();
|
|
24601
24807
|
}
|
|
24808
|
+
if (changed.has(`disableScrollHoverTickle`) && !this.disableScrollHoverTickle) this.#endScrollHoverSuppress();
|
|
24602
24809
|
if (changed.has(`itemsDraggable`)) this.#nativeDrag.refreshDraggable();
|
|
24603
24810
|
if (changed.has(`orientation`)) {
|
|
24604
24811
|
const vp = this.#viewportRef.value;
|
|
@@ -25018,7 +25225,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
25018
25225
|
?data-marquee=${marquee}
|
|
25019
25226
|
@click=${(e) => this.#onCellClick(e, key)}
|
|
25020
25227
|
@dblclick=${() => this.#onCellActivate(key)}
|
|
25021
|
-
@pointerenter=${() => this
|
|
25228
|
+
@pointerenter=${() => this.#handleCellPointerEnter(key)}
|
|
25022
25229
|
>
|
|
25023
25230
|
<div class="content" part="content">${this.#source.renderCellContent(index)}</div>
|
|
25024
25231
|
${showCaption ? this.#renderCaption(caption, captionCss, tickled) : ``}
|
|
@@ -25102,7 +25309,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
25102
25309
|
?data-marquee=${marquee}
|
|
25103
25310
|
@click=${(e) => this.#onCellClick(e, key)}
|
|
25104
25311
|
@dblclick=${() => this.#onCellActivate(key)}
|
|
25105
|
-
@pointerenter=${() => this
|
|
25312
|
+
@pointerenter=${() => this.#handleCellPointerEnter(key)}
|
|
25106
25313
|
>
|
|
25107
25314
|
<div class="thumb" part="thumb" style=${thumbStyle}>
|
|
25108
25315
|
${this.#source.renderCellContent(index)}
|
|
@@ -25123,6 +25330,37 @@ let GridListElement = class GridListElement extends i {
|
|
|
25123
25330
|
* left to the browser when there is no vertical component.
|
|
25124
25331
|
*/
|
|
25125
25332
|
#onWheel;
|
|
25333
|
+
/**
|
|
25334
|
+
* Cell `pointerenter` funnel. While a scroll gesture moves cells beneath a
|
|
25335
|
+
* stationary pointer (`disable-scroll-hover-tickle`), the freshly
|
|
25336
|
+
* virtualised cell's enter event is ignored so the cursor holds still.
|
|
25337
|
+
*/
|
|
25338
|
+
#handleCellPointerEnter(key) {
|
|
25339
|
+
if (this.#scrollHoverSuppress) return;
|
|
25340
|
+
this.tickled.handlePointerEnter(key);
|
|
25341
|
+
}
|
|
25342
|
+
/** Open the scroll-hover suppression window (no-op unless opted in and not already open). */
|
|
25343
|
+
#markScrollHoverSuppress() {
|
|
25344
|
+
if (!this.disableScrollHoverTickle || this.#scrollHoverSuppress) return;
|
|
25345
|
+
this.#scrollHoverSuppress = true;
|
|
25346
|
+
this.toggleAttribute(`data-scroll-hover-suppress`, true);
|
|
25347
|
+
}
|
|
25348
|
+
#endScrollHoverSuppress() {
|
|
25349
|
+
if (!this.#scrollHoverSuppress) return;
|
|
25350
|
+
this.#scrollHoverSuppress = false;
|
|
25351
|
+
this.toggleAttribute(`data-scroll-hover-suppress`, false);
|
|
25352
|
+
}
|
|
25353
|
+
/**
|
|
25354
|
+
* A real pointer movement ends scroll-hover suppression. The first
|
|
25355
|
+
* `pointerenter` on a real move is swallowed by design (it can be
|
|
25356
|
+
* indistinguishable from a virtualisation enter), so the cell already under
|
|
25357
|
+
* the pointer is re-tickled here — otherwise the cursor would lag one cell
|
|
25358
|
+
* boundary behind the pointer. The very first tracked `pointermove` only
|
|
25359
|
+
* establishes the baseline; it cannot know the pointer moved.
|
|
25360
|
+
*/
|
|
25361
|
+
#onHostPointerMove;
|
|
25362
|
+
/** The pointer leaving the list ends suppression, so re-entry hovers normally. */
|
|
25363
|
+
#onHostPointerLeave;
|
|
25126
25364
|
#cancelScrollRaf() {
|
|
25127
25365
|
if (this.#scrollRaf !== 0) {
|
|
25128
25366
|
cancelAnimationFrame(this.#scrollRaf);
|
|
@@ -25206,6 +25444,11 @@ __decorate([property({
|
|
|
25206
25444
|
attribute: `disable-hover-tickle`,
|
|
25207
25445
|
reflect: true
|
|
25208
25446
|
})], GridListElement.prototype, "disableHoverTickle", void 0);
|
|
25447
|
+
__decorate([property({
|
|
25448
|
+
type: Boolean,
|
|
25449
|
+
attribute: `disable-scroll-hover-tickle`,
|
|
25450
|
+
reflect: true
|
|
25451
|
+
})], GridListElement.prototype, "disableScrollHoverTickle", void 0);
|
|
25209
25452
|
__decorate([property({
|
|
25210
25453
|
type: Number,
|
|
25211
25454
|
attribute: `item-size`
|
|
@@ -28183,6 +28426,12 @@ const ITEM_SELECTOR = `li:not([data-virtual-spacer]), [data-list-item]:not([data
|
|
|
28183
28426
|
* vertical rows are shorter relative to the viewport, so 3.
|
|
28184
28427
|
*/
|
|
28185
28428
|
const VIRTUAL_OVERSCAN = 3;
|
|
28429
|
+
/** Shallow key-array equality, treating `undefined` (never dispatched) as different. */
|
|
28430
|
+
function sameKeys(a, b) {
|
|
28431
|
+
if (a === void 0 || a.length !== b.length) return false;
|
|
28432
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
28433
|
+
return true;
|
|
28434
|
+
}
|
|
28186
28435
|
let VerticalListElement = class VerticalListElement extends i {
|
|
28187
28436
|
constructor(..._args) {
|
|
28188
28437
|
super(..._args);
|
|
@@ -28297,11 +28546,11 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
28297
28546
|
highlightKey: `vertical-list-search`
|
|
28298
28547
|
}) });
|
|
28299
28548
|
this.#onScroll = () => {
|
|
28300
|
-
if (!this.#virtualActive()) return;
|
|
28301
28549
|
if (this.#scrollRaf !== 0) return;
|
|
28302
28550
|
this.#scrollRaf = requestAnimationFrame(() => {
|
|
28303
28551
|
this.#scrollRaf = 0;
|
|
28304
28552
|
this.#syncVirtualWindow();
|
|
28553
|
+
this.#emitViewportChangeIfChanged();
|
|
28305
28554
|
});
|
|
28306
28555
|
};
|
|
28307
28556
|
this._onPointerOver = (e) => {
|
|
@@ -28394,6 +28643,9 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
28394
28643
|
#suspendAdapterRebuild;
|
|
28395
28644
|
#scrollRaf;
|
|
28396
28645
|
#resizeObserver;
|
|
28646
|
+
/** Key sets as of the last viewport-change dispatch, for dedupe. */
|
|
28647
|
+
#lastViewportRenderedKeys;
|
|
28648
|
+
#lastViewportVisibleKeys;
|
|
28397
28649
|
#topSpacer;
|
|
28398
28650
|
#bottomSpacer;
|
|
28399
28651
|
/** Last measured viewport height — kept so a 0 read can't collapse the window. */
|
|
@@ -28521,6 +28773,14 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
28521
28773
|
}
|
|
28522
28774
|
}
|
|
28523
28775
|
/**
|
|
28776
|
+
* The shadow scroll list only exists after the first render; start
|
|
28777
|
+
* watching it so resizes move the window (virtualized) and the visible
|
|
28778
|
+
* set (plain) too.
|
|
28779
|
+
*/
|
|
28780
|
+
firstUpdated() {
|
|
28781
|
+
this.#ensureResizeObserved();
|
|
28782
|
+
}
|
|
28783
|
+
/**
|
|
28524
28784
|
* Animate in items appended to the light DOM (however they got there —
|
|
28525
28785
|
* {@link addItem}, direct `appendChild`, a framework binding). A bulk populate
|
|
28526
28786
|
* (roughly everything at once) is left alone, as are the wrapper `<li>`s the
|
|
@@ -28530,6 +28790,7 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
28530
28790
|
if (!this.isConnected) return;
|
|
28531
28791
|
if (this.#virtualActive()) {
|
|
28532
28792
|
this.#syncVirtualWindow(this.#reconcileRecords(records));
|
|
28793
|
+
this.#scheduleViewportChangeEmit();
|
|
28533
28794
|
return;
|
|
28534
28795
|
}
|
|
28535
28796
|
const fresh = [];
|
|
@@ -28540,6 +28801,7 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
28540
28801
|
this.#animatedItems.add(node);
|
|
28541
28802
|
fresh.push(node);
|
|
28542
28803
|
}
|
|
28804
|
+
this.#scheduleViewportChangeEmit();
|
|
28543
28805
|
if (fresh.length === 0) return;
|
|
28544
28806
|
if (this.#isBulkPopulate(fresh.length)) return;
|
|
28545
28807
|
for (const el of fresh) animateListItemIn(el);
|
|
@@ -29093,6 +29355,7 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
29093
29355
|
if (!ul) return;
|
|
29094
29356
|
this.#resizeObserver ??= new ResizeObserver(() => {
|
|
29095
29357
|
this.#syncVirtualWindow();
|
|
29358
|
+
this.#scheduleViewportChangeEmit();
|
|
29096
29359
|
});
|
|
29097
29360
|
this.#resizeObserver.observe(ul);
|
|
29098
29361
|
}
|
|
@@ -29172,6 +29435,32 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
29172
29435
|
this._syncItemStates();
|
|
29173
29436
|
this._syncNativeDraggable();
|
|
29174
29437
|
this.#nativeDrag.refreshDraggable();
|
|
29438
|
+
this.#scheduleViewportChangeEmit();
|
|
29439
|
+
}
|
|
29440
|
+
/** Coalesce content/layout viewport checks to at most one animation frame. */
|
|
29441
|
+
#scheduleViewportChangeEmit() {
|
|
29442
|
+
if (this.#scrollRaf !== 0) return;
|
|
29443
|
+
this.#scrollRaf = requestAnimationFrame(() => {
|
|
29444
|
+
this.#scrollRaf = 0;
|
|
29445
|
+
this.#syncVirtualWindow();
|
|
29446
|
+
this.#emitViewportChangeIfChanged();
|
|
29447
|
+
});
|
|
29448
|
+
}
|
|
29449
|
+
/**
|
|
29450
|
+
* Dispatch `vertical-list-viewport-change` with the current key sets — unless
|
|
29451
|
+
* neither set changed since the last dispatch, so coalesced frames and
|
|
29452
|
+
* no-op scrolls stay silent.
|
|
29453
|
+
*/
|
|
29454
|
+
#emitViewportChangeIfChanged() {
|
|
29455
|
+
const renderedKeys = this.renderedKeys();
|
|
29456
|
+
const visibleKeys = this.visibleKeys();
|
|
29457
|
+
if (sameKeys(this.#lastViewportRenderedKeys, renderedKeys) && sameKeys(this.#lastViewportVisibleKeys, visibleKeys)) return;
|
|
29458
|
+
this.#lastViewportRenderedKeys = renderedKeys;
|
|
29459
|
+
this.#lastViewportVisibleKeys = visibleKeys;
|
|
29460
|
+
this._dispatch(`vertical-list-viewport-change`, {
|
|
29461
|
+
renderedKeys,
|
|
29462
|
+
visibleKeys
|
|
29463
|
+
});
|
|
29175
29464
|
}
|
|
29176
29465
|
_getVisibleItems() {
|
|
29177
29466
|
return Array.from(this.querySelectorAll(ITEM_SELECTOR)).filter((el) => {
|