igniteui-webcomponents 7.4.0 → 7.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/components/checkbox/checkbox-base.d.ts +2 -0
- package/components/checkbox/checkbox-base.js +4 -0
- package/components/checkbox/checkbox-base.js.map +1 -1
- package/components/checkbox/checkbox.js +3 -11
- package/components/checkbox/checkbox.js.map +1 -1
- package/components/checkbox/switch.js +1 -8
- package/components/checkbox/switch.js.map +1 -1
- package/components/color-picker/color-picker.js +3 -3
- package/components/color-picker/color-picker.js.map +1 -1
- package/components/combo/combo.d.ts +6 -4
- package/components/combo/combo.js +13 -24
- package/components/combo/combo.js.map +1 -1
- package/components/date-picker/date-picker.base.d.ts +3 -3
- package/components/date-picker/date-picker.base.js +2 -2
- package/components/date-picker/date-picker.base.js.map +1 -1
- package/components/date-picker/date-picker.d.ts +1 -1
- package/components/date-range-picker/date-range-picker.d.ts +1 -1
- package/components/date-time-input/date-time-input.base.d.ts +4 -4
- package/components/date-time-input/date-time-input.base.js +3 -5
- package/components/date-time-input/date-time-input.base.js.map +1 -1
- package/components/file-input/file-input.d.ts +5 -0
- package/components/file-input/file-input.js +4 -0
- package/components/file-input/file-input.js.map +1 -1
- package/components/input/input-base.d.ts +2 -2
- package/components/input/input-base.js +3 -5
- package/components/input/input-base.js.map +1 -1
- package/components/input/input.d.ts +1 -1
- package/components/radio/radio.d.ts +2 -0
- package/components/radio/radio.js +7 -11
- package/components/radio/radio.js.map +1 -1
- package/components/rating/rating.d.ts +3 -0
- package/components/rating/rating.js +17 -18
- package/components/rating/rating.js.map +1 -1
- package/components/select/select.js +1 -1
- package/components/select/select.js.map +1 -1
- package/components/slider/range-slider.d.ts +0 -1
- package/components/slider/range-slider.js +6 -11
- package/components/slider/range-slider.js.map +1 -1
- package/components/slider/slider-base.d.ts +4 -1
- package/components/slider/slider-base.js +20 -18
- package/components/slider/slider-base.js.map +1 -1
- package/components/slider/slider.d.ts +2 -0
- package/components/slider/slider.js +5 -1
- package/components/slider/slider.js.map +1 -1
- package/components/textarea/textarea.d.ts +1 -4
- package/components/textarea/textarea.js +3 -5
- package/components/textarea/textarea.js.map +1 -1
- package/components/validation-container/validation-container.js +2 -1
- package/components/validation-container/validation-container.js.map +1 -1
- package/components/virtualization/engine.d.ts +35 -4
- package/components/virtualization/engine.js +126 -61
- package/components/virtualization/engine.js.map +1 -1
- package/components/virtualization/recycle.d.ts +13 -0
- package/components/virtualization/recycle.js +152 -0
- package/components/virtualization/recycle.js.map +1 -0
- package/components/virtualization/virtualization.d.ts +32 -11
- package/components/virtualization/virtualization.js +14 -11
- package/components/virtualization/virtualization.js.map +1 -1
- package/custom-elements.json +2382 -79
- package/igniteui-webcomponents.html-data.json +1 -1
- package/index.d.ts +1 -1
- package/index.js.map +1 -1
- package/internals/controllers/aria-projection.d.ts +61 -23
- package/internals/controllers/aria-projection.js +77 -26
- package/internals/controllers/aria-projection.js.map +1 -1
- package/internals/mixins/forms/associated.js +34 -0
- package/internals/mixins/forms/associated.js.map +1 -1
- package/internals/mixins/forms/types.d.ts +5 -0
- package/internals/mixins/forms/types.js.map +1 -1
- package/internals/templates/toggle-shell.d.ts +15 -14
- package/internals/templates/toggle-shell.js +12 -8
- package/internals/templates/toggle-shell.js.map +1 -1
- package/internals/utils/dom.d.ts +2 -2
- package/internals/utils/dom.js +2 -2
- package/internals/utils/dom.js.map +1 -1
- package/package.json +1 -1
- package/skills/README.md +2 -4
- package/skills/igniteui-wc-choose-components/SKILL.md +2 -1
- package/skills/igniteui-wc-customize-component-theme/SKILL.md +2 -1
- package/skills/igniteui-wc-figma-to-app/SKILL.md +133 -712
- package/skills/igniteui-wc-figma-to-app/references/asset-extraction.md +42 -62
- package/skills/igniteui-wc-figma-to-app/references/design-provenance.md +199 -0
- package/skills/igniteui-wc-figma-to-app/references/design-token-bridge.md +189 -107
- package/skills/igniteui-wc-figma-to-app/references/figma-component-map.md +129 -84
- package/skills/igniteui-wc-figma-to-app/references/figma-exploration.md +222 -0
- package/skills/igniteui-wc-figma-to-app/references/mcp-setup.md +81 -127
- package/skills/igniteui-wc-figma-to-app/references/project-setup.md +105 -0
- package/skills/igniteui-wc-figma-to-app/references/theme-generation.md +180 -0
- package/skills/igniteui-wc-figma-to-app/references/validation-patterns.md +74 -80
- package/skills/igniteui-wc-generate-from-image-design/SKILL.md +2 -1
- package/skills/igniteui-wc-generate-from-image-design/references/gotchas.md +3 -3
- package/skills/igniteui-wc-grids/SKILL.md +133 -0
- package/skills/igniteui-wc-integrate-with-framework/SKILL.md +2 -1
- package/skills/igniteui-wc-migrate-grid-lite-to-premium/SKILL.md +2 -1
- package/skills/igniteui-wc-optimize-bundle-size/SKILL.md +2 -1
- package/web-types.json +1 -1
|
@@ -3,6 +3,7 @@ import type { Constructor } from '#internals/mixins/constructor.js';
|
|
|
3
3
|
import { VirtualScrollEngine } from './engine.js';
|
|
4
4
|
import { type VirtualScrollDataRequest, VirtualScrollItemContext, type VirtualScrollState } from './types.js';
|
|
5
5
|
export type VirtualScrollItemTemplate<T> = (context: VirtualScrollItemContext<T>) => TemplateResult | typeof nothing;
|
|
6
|
+
export type VirtualScrollKeyFunction<T> = (item: T, index: number) => unknown;
|
|
6
7
|
export interface IgcVirtualScrollComponentEventMap {
|
|
7
8
|
igcStateChange: CustomEvent<VirtualScrollState>;
|
|
8
9
|
igcDataRequest: CustomEvent<VirtualScrollDataRequest>;
|
|
@@ -32,10 +33,8 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
|
|
|
32
33
|
private readonly _itemResizeController;
|
|
33
34
|
private _currentRange;
|
|
34
35
|
/**
|
|
35
|
-
* The item index each wrapper element was last observed under.
|
|
36
|
-
*
|
|
37
|
-
* different item at the same size, which a ResizeObserver does not report.
|
|
38
|
-
* See `_scheduleItemMeasurement`.
|
|
36
|
+
* The item index each wrapper element was last observed under. See
|
|
37
|
+
* `_scheduleItemMeasurement`.
|
|
39
38
|
*/
|
|
40
39
|
private readonly _observedItemIndexes;
|
|
41
40
|
private _lastEmittedState;
|
|
@@ -82,6 +81,8 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
|
|
|
82
81
|
/**
|
|
83
82
|
* Estimated item size in pixels, used before an item is measured in the DOM.
|
|
84
83
|
* After the first render of an item, the engine replaces the estimate with the measured size.
|
|
84
|
+
* The average measured size also replaces the estimate of the items that are not measured
|
|
85
|
+
* yet, so the scrollbar follows the real content.
|
|
85
86
|
* @attr estimated-item-size
|
|
86
87
|
* @default 50
|
|
87
88
|
*/
|
|
@@ -98,8 +99,26 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
|
|
|
98
99
|
* infer an item's position from the markup. Templates that render a role
|
|
99
100
|
* with set semantics (`option`, `listitem`, `row`, ...) should map the
|
|
100
101
|
* context's `index` and `count` onto `aria-posinset` and `aria-setsize`.
|
|
102
|
+
*
|
|
103
|
+
* Item elements are recycled (see `keyFunction`), so DOM state that the
|
|
104
|
+
* template does not bind moves to another item, for example the state of a
|
|
105
|
+
* checkbox without a `checked` binding. Bind all item state. Lit compares a
|
|
106
|
+
* binding with the value that it set last, not with the element, so bind
|
|
107
|
+
* state that the user changes with Lit's `live` directive. Also write user
|
|
108
|
+
* changes back to the item, or they are lost when the item leaves the window.
|
|
109
|
+
* To get new DOM for each item, wrap the content in Lit's `keyed` directive
|
|
110
|
+
* with the item key: `` html`${keyed(ctx.value.id, content)}` ``.
|
|
101
111
|
*/
|
|
102
112
|
itemTemplate: VirtualScrollItemTemplate<T> | null;
|
|
113
|
+
/**
|
|
114
|
+
* A function that returns a unique key for an item. Receives the item and its index in `data`.
|
|
115
|
+
*
|
|
116
|
+
* An item keeps its rendered element while its key stays in the rendered window. The elements
|
|
117
|
+
* of keys that leave the window are reused for keys that enter it. Without it, the index is the
|
|
118
|
+
* key, so after a `data` change an index keeps its element and shows its new item. Set it when
|
|
119
|
+
* items move within `data`, for example on sort, insert or remove.
|
|
120
|
+
*/
|
|
121
|
+
keyFunction: VirtualScrollKeyFunction<T> | null;
|
|
103
122
|
private _adoptStyles;
|
|
104
123
|
constructor();
|
|
105
124
|
/** @internal */
|
|
@@ -116,6 +135,8 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
|
|
|
116
135
|
private get _normalizedItemSize();
|
|
117
136
|
/** `data`, guarded against a nullish value set by the consumer. */
|
|
118
137
|
private get _items();
|
|
138
|
+
/** The key that ties the item at `index` to its rendered element. */
|
|
139
|
+
private _keyOf;
|
|
119
140
|
/**
|
|
120
141
|
* The window to render for the current scroll position and viewport. Empty
|
|
121
142
|
* until an `itemTemplate` is set, because nothing renders without one.
|
|
@@ -125,9 +146,6 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
|
|
|
125
146
|
* The scroll offset that aligns `index` in the viewport, as `options` gives,
|
|
126
147
|
* from the current size data of the engine. The same input can give a
|
|
127
148
|
* different result as more items are measured.
|
|
128
|
-
*
|
|
129
|
-
* For `block: 'nearest'` on an item in view, returns the current offset, so
|
|
130
|
-
* no scroll occurs.
|
|
131
149
|
*/
|
|
132
150
|
private _getAlignedScrollOffset;
|
|
133
151
|
/** Applies a scroll offset to the correct axis, accounting for RTL. */
|
|
@@ -188,10 +206,9 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
|
|
|
188
206
|
* @remarks
|
|
189
207
|
* `observe` on an already observed element does nothing, so a new
|
|
190
208
|
* measurement needs `unobserve` and then `observe`. Do this for each element
|
|
191
|
-
* whose `data-vs-index` changed.
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* estimated size.
|
|
209
|
+
* whose `data-vs-index` changed. The wrapper elements are recycled, so after
|
|
210
|
+
* a scroll one element can hold a different item at the same size. The
|
|
211
|
+
* observer does not report that, and the new index keeps its estimated size.
|
|
195
212
|
*/
|
|
196
213
|
private _scheduleItemMeasurement;
|
|
197
214
|
/**
|
|
@@ -228,6 +245,10 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
|
|
|
228
245
|
/**
|
|
229
246
|
* Scrolls to the specified item index.
|
|
230
247
|
*
|
|
248
|
+
* `block` (`inline` in the horizontal orientation) positions the item as in
|
|
249
|
+
* `scrollIntoView`, and defaults to `start`. With `nearest`, the item
|
|
250
|
+
* scrolls the smallest distance that brings it into view.
|
|
251
|
+
*
|
|
231
252
|
* Items outside the rendered window have only an estimated size, so the
|
|
232
253
|
* first jump can miss the target. The items at the landing point are then
|
|
233
254
|
* measured, and the scroll position is corrected. This repeats until the
|
|
@@ -15,6 +15,7 @@ import { EventEmitterMixin } from '#internals/mixins/event-emitter.js';
|
|
|
15
15
|
import { isLTR } from '#internals/utils/dom.js';
|
|
16
16
|
import { asNumber, clamp } from '#internals/utils/math.js';
|
|
17
17
|
import { VirtualScrollEngine } from './engine.js';
|
|
18
|
+
import { recycle } from './recycle.js';
|
|
18
19
|
import { VirtualScrollItemContext, } from './types.js';
|
|
19
20
|
const REMOTE_SCROLLING_THRESHOLD = 5;
|
|
20
21
|
const MAX_LAYOUT_SETTLE_PASSES = 20;
|
|
@@ -131,6 +132,7 @@ export default class IgcVirtualScrollComponent extends EventEmitterMixin(LitElem
|
|
|
131
132
|
this.overScan = 2;
|
|
132
133
|
this.estimatedItemSize = DEFAULT_ESTIMATED_ITEM_SIZE;
|
|
133
134
|
this.itemTemplate = null;
|
|
135
|
+
this.keyFunction = null;
|
|
134
136
|
this._engine.onSizeChange = () => this.requestUpdate();
|
|
135
137
|
this._handleScroll = this._handleScroll.bind(this);
|
|
136
138
|
addHostListeners(this, {
|
|
@@ -206,12 +208,12 @@ export default class IgcVirtualScrollComponent extends EventEmitterMixin(LitElem
|
|
|
206
208
|
role="presentation"
|
|
207
209
|
style=${styleMap(contentStyle)}
|
|
208
210
|
>
|
|
209
|
-
${visibleItems.
|
|
211
|
+
${recycle(visibleItems, (item, i) => this._keyOf(item, range.startIndex + i), (item, i) => {
|
|
210
212
|
const itemIndex = range.startIndex + i;
|
|
211
213
|
const ctx = new VirtualScrollItemContext(item, itemIndex, count);
|
|
212
214
|
return html `<div role="presentation" data-vs-index=${itemIndex}>
|
|
213
|
-
|
|
214
|
-
|
|
215
|
+
${this.itemTemplate(ctx)}
|
|
216
|
+
</div>`;
|
|
215
217
|
})}
|
|
216
218
|
</div>
|
|
217
219
|
</div>
|
|
@@ -230,22 +232,19 @@ export default class IgcVirtualScrollComponent extends EventEmitterMixin(LitElem
|
|
|
230
232
|
get _items() {
|
|
231
233
|
return this.data ?? [];
|
|
232
234
|
}
|
|
235
|
+
_keyOf(item, index) {
|
|
236
|
+
return this.keyFunction ? this.keyFunction(item, index) : index;
|
|
237
|
+
}
|
|
233
238
|
_computeRange() {
|
|
234
239
|
return this.itemTemplate
|
|
235
240
|
? this._engine.getVisibleRange(this._scrollPosition, this._viewportSize, this._normalizedOverScan)
|
|
236
241
|
: EMPTY_RANGE;
|
|
237
242
|
}
|
|
238
243
|
_getAlignedScrollOffset(index, options) {
|
|
239
|
-
const
|
|
244
|
+
const position = this._isVertical
|
|
240
245
|
? (options?.block ?? 'start')
|
|
241
246
|
: (options?.inline ?? options?.block ?? 'start');
|
|
242
|
-
|
|
243
|
-
if (requested === 'nearest' &&
|
|
244
|
-
this._engine.isIndexInView(index, current, this._viewportSize)) {
|
|
245
|
-
return current;
|
|
246
|
-
}
|
|
247
|
-
const align = requested === 'center' || requested === 'end' ? requested : 'start';
|
|
248
|
-
return this._engine.getAlignedScrollOffset(index, this._viewportSize, align);
|
|
247
|
+
return this._engine.resolveScrollOffset(index, this._currentAxisScroll(), this._viewportSize, position);
|
|
249
248
|
}
|
|
250
249
|
_applyScroll(offset, behavior) {
|
|
251
250
|
if (this._isVertical) {
|
|
@@ -344,6 +343,7 @@ export default class IgcVirtualScrollComponent extends EventEmitterMixin(LitElem
|
|
|
344
343
|
this._engine.measureItem(index, measured);
|
|
345
344
|
}
|
|
346
345
|
}
|
|
346
|
+
this._engine.adaptEstimate(this._currentRange.startIndex);
|
|
347
347
|
}
|
|
348
348
|
_scheduleItemMeasurement() {
|
|
349
349
|
const content = this._contentRef.value;
|
|
@@ -480,4 +480,7 @@ __decorate([
|
|
|
480
480
|
__decorate([
|
|
481
481
|
property({ attribute: false })
|
|
482
482
|
], IgcVirtualScrollComponent.prototype, "itemTemplate", void 0);
|
|
483
|
+
__decorate([
|
|
484
|
+
property({ attribute: false })
|
|
485
|
+
], IgcVirtualScrollComponent.prototype, "keyFunction", void 0);
|
|
483
486
|
//# sourceMappingURL=virtualization.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtualization.js","sourceRoot":"","sources":["../../../src/components/virtualization/virtualization.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,OAAO,GAGR,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,8BAA8B,EAAE,MAAM,2CAA2C,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAGL,wBAAwB,GAGzB,MAAM,YAAY,CAAC;AAWpB,MAAM,0BAA0B,GAAG,CAAC,CAAC;AACrC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AACpC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AACvC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAEnC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAEvC,MAAM,cAAc,GAAG,GAAG,CAAC;AAM3B,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAOpC,MAAM,mBAAmB,GAAG,CAAC,QAAQ,IAAI,aAAa,IAAI,MAAM,CAAC;AAEjE,MAAM,WAAW,GAAiB,MAAM,CAAC,MAAM,CAAC;IAC9C,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC,CAAC;CACb,CAAC,CAAC;AAgBH,MAAM,CAAC,OAAO,OAAO,yBAEnB,SAAQ,iBAAiB,CAGzB,UAAU,CAAC;aACY,YAAO,GAAG,oBAAoB,AAAvB,CAAwB;IAG/C,MAAM,CAAC,QAAQ;QACpB,iBAAiB,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;aAEc,gBAAW,GAAyB,IAAI,AAA7B,CAA8B;IAEhD,MAAM,CAAC,cAAc;QAC3B,IAAI,CAAC,yBAAyB,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,IAAI,aAAa,EAAE,CAAC;YAClC,KAAK,CAAC,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuDjB,CAAC,CAAC;YACH,yBAAyB,CAAC,WAAW,GAAG,KAAK,CAAC;QAChD,CAAC;QACD,OAAO,yBAAyB,CAAC,WAAW,CAAC;IAC/C,CAAC;IA2GO,YAAY;QAElB,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAA2B,CAAC;QACzD,MAAM,KAAK,GAAG,yBAAyB,CAAC,cAAc,EAAE,CAAC;QACzD,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,kBAAkB,GAAG,CAAC,GAAG,IAAI,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED;QACE,KAAK,EAAE,CAAC;QArHS,YAAO,GAAG,IAAI,mBAAmB,EAAE,CAAC;QACtC,gBAAW,GAAG,SAAS,EAAkB,CAAC;QAC1C,0BAAqB,GAAG,8BAA8B,CACrE,IAAI,EACJ;YACE,QAAQ,EAAE,IAAI,CAAC,iBAAiB;YAChC,MAAM,EAAE,IAAI;YACZ,aAAa,EAAE,KAAK;SACrB,CACF,CAAC;QAEM,kBAAa,GAAiB,WAAW,CAAC;QAQjC,yBAAoB,GAAG,IAAI,OAAO,EAAmB,CAAC;QAC/D,sBAAiB,GAA8B,IAAI,CAAC;QACpD,2BAAsB,GAAG,KAAK,CAAC;QAC/B,2BAAsB,GAAyB,IAAI,CAAC;QACpD,qBAAgB,GAAG,CAAC,CAAC;QAUrB,0BAAqB,GAAG,CAAC,CAAC,CAAC;QAO3B,oBAAe,GAAG,CAAC,CAAC;QAGpB,kBAAa,GAAG,CAAC,CAAC;QAcnB,SAAI,GAAQ,EAAE,CAAC;QAQf,gBAAW,GAA8B,UAAU,CAAC;QASpD,aAAQ,GAAG,CAAC,CAAC;QASb,sBAAiB,GAAG,2BAA2B,CAAC;QAgBhD,iBAAY,GAAwC,IAAI,CAAC;QAmB9D,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACvD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEnD,gBAAgB,CAAC,IAAI,EAAE;YACrB,MAAM,EAAE,CAAC,QAAQ,CAAC;YAClB,QAAQ,EAAE,IAAI,CAAC,aAAa;YAC5B,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;SAC3B,CAAC,CAAC;QAGH,8BAA8B,CAAC,IAAI,EAAE;YACnC,QAAQ,EAAE,IAAI,CAAC,gBAAgB;SAChC,CAAC,CAAC;IACL,CAAC;IAKe,gBAAgB;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAGe,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACpD,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAEkB,UAAU,CAAC,OAA6B;QAQzD,IAAI,CAAC,YAAY,EAAE,CAAC;QAEpB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,MAAM,CACjB,IAAI,CAAC,MAAM,CAAC,MAAM,EAClB,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAC7C,CAAC;YACF,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACtC,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACnD,CAAC;QAED,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5C,CAAC;IAEkB,OAAO,CAAC,QAA8B;QACvD,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAChC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAEkB,MAAM;QACvB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,IAAI,CAAA,GAAG,OAAO,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC;QAEpC,MAAM,UAAU,GAAG,UAAU;YAC3B,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE;YACzC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QAK3C,IAAI,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,uBAAuB,CACxD,KAAK,CAAC,UAAU,CACjB,CAAC;QACF,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB,CACzD,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,QAAQ,CACf,CAAC;QACF,eAAe,GAAG,KAAK,CACrB,eAAe,EACf,CAAC,EACD,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,iBAAiB,CACzC,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,YAAY,GAAG;YACnB,SAAS,EAAE,UAAU;gBACnB,CAAC,CAAC,cAAc,eAAe,KAAK;gBACpC,CAAC,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,KAAK;SAClE,CAAC;QAEF,MAAM,YAAY,GAChB,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,UAAU;YAChC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;YACnD,CAAC,CAAC,EAAE,CAAC;QAET,OAAO,IAAI,CAAA;;;;gBAIC,QAAQ,CAAC,UAAU,CAAC;;;YAGxB,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;;;kBAGf,QAAQ,CAAC,YAAY,CAAC;;YAE5B,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YAC7B,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC;YACvC,MAAM,GAAG,GAAG,IAAI,wBAAwB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YACjE,OAAO,IAAI,CAAA,0CAA0C,SAAS;gBAC1D,IAAI,CAAC,YAAa,CAAC,GAAG,CAAC;mBACpB,CAAC;QACV,CAAC,CAAC;;;KAGP,CAAC;IACJ,CAAC;IAMD,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,WAAW,KAAK,UAAU,CAAC;IACzC,CAAC;IAGD,IAAY,mBAAmB;QAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IAGD,IAAY,mBAAmB;QAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC9C,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,2BAA2B,CAAC;IACvD,CAAC;IAGD,IAAY,MAAM;QAChB,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IACzB,CAAC;IAMO,aAAa;QACnB,OAAO,IAAI,CAAC,YAAY;YACtB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAC1B,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,mBAAmB,CACzB;YACH,CAAC,CAAC,WAAW,CAAC;IAClB,CAAC;IAUO,uBAAuB,CAC7B,KAAa,EACb,OAA+B;QAE/B,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW;YAChC,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,IAAI,OAAO,CAAC;YAC7B,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,KAAK,IAAI,OAAO,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAE1C,IACE,SAAS,KAAK,SAAS;YACvB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,EAC9D,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,KAAK,GACT,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;QAEtE,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,CACxC,KAAK,EACL,IAAI,CAAC,aAAa,EAClB,KAAK,CACN,CAAC;IACJ,CAAC;IAGO,YAAY,CAAC,MAAc,EAAE,QAAwB;QAC3D,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAGO,kBAAkB;QACxB,OAAO,IAAI,CAAC,WAAW;YACrB,CAAC,CAAC,IAAI,CAAC,SAAS;YAChB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;gBACX,CAAC,CAAC,IAAI,CAAC,UAAU;gBACjB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAWO,oBAAoB,CAC1B,MAAc,EACd,QAAwB;QAExB,IACE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,MAAM,CAAC,GAAG,wBAAwB,EACvE,CAAC;YACD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,qBAAqB,EAAE,CAAC,MAAM,EAAE,EAAE;YAC1D,MAAM,OAAO,GAAG,mBAAmB;gBACjC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;gBAChC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAIpC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACpC,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAMO,aAAa,CACnB,EAAU,EACV,IAA4C;QAE5C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QAEzC,OAAO,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC;SACrC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;IACvC,CAAC;IAEO,iBAAiB,CAAC,MAAmB;QAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE;gBAClD,IAAI,EAAE,IAAI;gBACV,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAOO,kBAAkB,CAAC,MAAmB;QAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE7C,IAAI,CAAC,gBAAgB,CACnB,QAAQ,EACR,GAAG,EAAE;gBACH,YAAY,CAAC,EAAE,CAAC,CAAC;gBACjB,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAC3C,CAAC,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAC1B,CAAC;YAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,QAAQ,CAAC,EAAU,EAAE,MAAmB;QAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACnC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,WAAW;YACnC,CAAC,CAAC,IAAI,CAAC,YAAY;YACnB,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;IACvB,CAAC;IAYO,aAAa;QACnB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEjD,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACtD,IACE,UAAU,KAAK,IAAI,CAAC,aAAa,CAAC,UAAU;YAC5C,QAAQ,KAAK,IAAI,CAAC,aAAa,CAAC,QAAQ,EACxC,CAAC;YACD,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAYO,kBAAkB,CAAC,QAAyB;QAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,iBAAiB,CAAC,OAA8B;QACtD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAG,KAAK,CAAC,MAAqB,CAAC;YACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,IAAI,KAAK,GAAG,CAAC;gBAAE,SAAS;YAExB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW;gBAC/B,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC;gBACnE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEtE,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAcO,wBAAwB;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QACvC,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,QAAQ,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC;QAEpD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;gBACnC,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,QAAQ,CAAE,OAAuB,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YACrE,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAEzC,IAAI,UAAU,IAAI,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,EAAE,CAAC;gBACnE,SAAS;YACX,CAAC;YAED,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAChD,CAAC;YACD,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC5C,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAOO,gBAAgB;QACtB,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;QACpD,IAAI,QAAQ,GAAG,UAAU;YAAE,OAAO;QAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC;QACxC,MAAM,MAAM,GAAuB;YACjC,UAAU;YACV,QAAQ;YACR,YAAY,EAAE,IAAI,CAAC,aAAa;YAChC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;SAClC,CAAC;QAEF,IACE,QAAQ;YACR,QAAQ,CAAC,UAAU,KAAK,MAAM,CAAC,UAAU;YACzC,QAAQ,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ;YACrC,QAAQ,CAAC,YAAY,KAAK,MAAM,CAAC,YAAY;YAC7C,QAAQ,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,EACvC,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,iBAAiB,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;QACvC,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;IAEO,iBAAiB;QACvB,IAAI,IAAI,CAAC,sBAAsB;YAAE,OAAO;QAExC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAEjC,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,GAAG,KAAK,GAAG,0BAA0B,EAAE,CAAC;YACvE,OAAO;QACT,CAAC;QAMD,IAAI,IAAI,CAAC,qBAAqB,KAAK,KAAK,EAAE,CAAC;YACzC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;QAEnC,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE;YAC/B,MAAM,EAAE;gBACN,UAAU,EAAE,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,EAAE,EAAE,CAAC;aAClD;SACF,CAAC,CAAC;IACL,CAAC;IAQO,UAAU;QAChB,OAAO,IAAI,CAAC,aAAa,CACvB,uBAAuB,EACvB,CAAC,MAAM,EAAE,EAAE,CACT,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACtB,MAAM,EAAE,GAAG,qBAAqB,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAClD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAAE;gBAC/D,IAAI,EAAE,IAAI;aACX,CAAC,CAAC;QACL,CAAC,CAAC,CACL,CAAC;IACJ,CAAC;IAQO,KAAK,CAAC,sBAAsB;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC;YAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,wBAAwB,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClD,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBAExB,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;oBAC1B,MAAM;gBACR,CAAC;gBAED,MAAM,IAAI,CAAC,cAAc,CAAC;YAC5B,CAAC;QACH,CAAC;gBAAS,CAAC;YAGT,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACrC,CAAC;IACH,CAAC;IAgBD,IAAW,cAAc;QACvB,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAC,sBAAsB,CAAC;IACrC,CAAC;IAcM,KAAK,CAAC,aAAa,CACxB,KAAa,EACb,OAA+B;QAE/B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,MAAM,CAAC;QAI7C,MAAM,SAAS,GAAG,EAAE,IAAI,CAAC,gBAAgB,CAAC;QAE1C,IAAI,MAAM,GAAG,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACjE,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,4BAA4B,EAAE,CAAC,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,CAAC,cAAc,CAAC;YAE1B,IAAI,SAAS,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxC,OAAO;YACT,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACtE,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;gBAC5D,MAAM;YACR,CAAC;YAED,MAAM,GAAG,SAAS,CAAC;YACnB,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAEhD,IAAI,SAAS,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxC,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;;AAvpBO;IADP,KAAK,EAAE;gEACkB;AAcnB;IADN,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;uDACT;AAQf;IADN,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8DAC+B;AASpD;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;2DAC/B;AASb;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB,EAAE,CAAC;oEACN;AAgBhD;IADN,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;+DACiC","sourcesContent":["import {\n html,\n isServer,\n LitElement,\n nothing,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { createRef, ref } from 'lit/directives/ref.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { addHostListeners } from '#internals/controllers/host-listeners.js';\nimport { createResizeObserverController } from '#internals/controllers/resize-observer.js';\nimport { registerComponent } from '#internals/definitions/register.js';\nimport type { Constructor } from '#internals/mixins/constructor.js';\nimport { EventEmitterMixin } from '#internals/mixins/event-emitter.js';\nimport { isLTR } from '#internals/utils/dom.js';\nimport { asNumber, clamp } from '#internals/utils/math.js';\nimport { VirtualScrollEngine } from './engine.js';\nimport {\n type ScrollAlignment,\n type VirtualScrollDataRequest,\n VirtualScrollItemContext,\n type VirtualScrollState,\n type VisibleRange,\n} from './types.js';\n\nexport type VirtualScrollItemTemplate<T> = (\n context: VirtualScrollItemContext<T>\n) => TemplateResult | typeof nothing;\n\nexport interface IgcVirtualScrollComponentEventMap {\n igcStateChange: CustomEvent<VirtualScrollState>;\n igcDataRequest: CustomEvent<VirtualScrollDataRequest>;\n}\n\nconst REMOTE_SCROLLING_THRESHOLD = 5;\nconst MAX_LAYOUT_SETTLE_PASSES = 20;\nconst MAX_SCROLL_CORRECTION_PASSES = 5;\nconst SCROLL_END_TIMEOUT_MS = 2000;\nconst SCROLL_OFFSET_EPSILON_PX = 1;\n/** Fallback for a non-positive `estimatedItemSize`. Equal to its default. */\nconst DEFAULT_ESTIMATED_ITEM_SIZE = 50;\n/** How long the scroll position must stay unchanged to count as settled. */\nconst SCROLL_IDLE_MS = 100;\n/**\n * Upper limit on one `requestAnimationFrame` wait. A hidden tab or a\n * disconnected element gets no frames, and `layoutComplete` must still\n * resolve there.\n */\nconst LAYOUT_FRAME_TIMEOUT_MS = 100;\n\n/**\n * `scrollend` reports exactly when a scroll has settled. Safari before 18.2\n * does not have it, and `_scrollAndWaitForEnd` falls back to a scroll-idle\n * timer there.\n */\nconst SUPPORTS_SCROLL_END = !isServer && 'onscrollend' in window;\n\nconst EMPTY_RANGE: VisibleRange = Object.freeze({\n startIndex: 0,\n endIndex: -1,\n});\n\n/**\n * A virtual scroll component for large lists. Only the items visible in the\n * viewport are rendered.\n *\n * @element igc-virtual-scroll\n *\n * @fires igcStateChange - Emitted when the rendered virtual window changes.\n * @fires igcDataRequest - Emitted when the rendered window comes within a few items of the end\n * of `data`. Also emitted on the first render, when the loaded items do not fill the viewport.\n *\n * @csspart virtualization-track - The full-size element that gives the host its scrollable extent.\n * @csspart virtualization-content - The wrapper that holds the rendered items, translated into\n * position within the track.\n */\nexport default class IgcVirtualScrollComponent<\n T = any,\n> extends EventEmitterMixin<\n IgcVirtualScrollComponentEventMap,\n Constructor<LitElement>\n>(LitElement) {\n public static readonly tagName = 'igc-virtual-scroll';\n\n /* blazorSuppress */\n public static register(): void {\n registerComponent(IgcVirtualScrollComponent);\n }\n\n private static _styleSheet: CSSStyleSheet | null = null;\n\n private static _getStyleSheet(): CSSStyleSheet {\n if (!IgcVirtualScrollComponent._styleSheet) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(`\n :where(igc-virtual-scroll) {\n display: block;\n position: relative;\n overflow: auto;\n height: 18.75rem;\n }\n\n :where(igc-virtual-scroll[orientation='vertical']) {\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) {\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n :where(igc-virtual-scroll) [part=\"virtualization-track\"] {\n position: relative;\n width: 100%;\n min-height: 100%;\n }\n\n :where(igc-virtual-scroll) [part=\"virtualization-content\"] {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n will-change: transform;\n contain: layout style paint;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) [part=\"virtualization-track\"] {\n height: 100%;\n width: auto;\n min-height: unset;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) [part=\"virtualization-content\"] {\n display: flex;\n flex-direction: row;\n height: 100%;\n width: auto;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) [part=\"virtualization-content\"] > [data-vs-index] {\n flex-shrink: 0;\n height: 100%;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']):dir(rtl) [part=\"virtualization-content\"] {\n left: auto;\n right: 0;\n }\n `);\n IgcVirtualScrollComponent._styleSheet = sheet;\n }\n return IgcVirtualScrollComponent._styleSheet;\n }\n\n //#region Internal state\n\n protected readonly _engine = new VirtualScrollEngine();\n private readonly _contentRef = createRef<HTMLDivElement>();\n private readonly _itemResizeController = createResizeObserverController(\n this,\n {\n callback: this._handleItemResize,\n target: null,\n requestUpdate: false,\n }\n );\n\n private _currentRange: VisibleRange = EMPTY_RANGE;\n\n /**\n * The item index each wrapper element was last observed under. Lit keeps the\n * wrapper elements between renders, so after a scroll one element can hold a\n * different item at the same size, which a ResizeObserver does not report.\n * See `_scheduleItemMeasurement`.\n */\n private readonly _observedItemIndexes = new WeakMap<Element, number>();\n private _lastEmittedState: VirtualScrollState | null = null;\n private _hasPendingDataRequest = false;\n private _layoutCompletePromise: Promise<void> | null = null;\n private _scrollRequestId = 0;\n\n /**\n * The `startIndex` of the last `igcDataRequest`, which is also the item count\n * at that emit. See `_checkDataRequest`.\n *\n * Kept across a disconnect, as `_hasPendingDataRequest` is. A move in the DOM\n * does not cancel what the consumer was already asked for, and clearing only\n * one of the two opens the request loop again on reconnect.\n */\n private _lastDataRequestIndex = -1;\n\n /**\n * The live scroll offset on the active axis. Not reactive: `render` reads it\n * only through `_currentRange`, so `_handleScroll` schedules an update only\n * if the window moves.\n */\n private _scrollPosition = 0;\n\n @state()\n private _viewportSize = 0;\n\n //#endregion\n\n //#region Public properties\n\n /**\n * The array of items to virtualize.\n *\n * Compared by reference: a mutation in place (`data.push(...)`) causes no\n * update. Assign a new array instead. The `igcDataRequest` flow also\n * expects a new array.\n */\n @property({ attribute: false })\n public data: T[] = [];\n\n /**\n * Scroll orientation of the virtual scroll.\n * @attr orientation\n * @default 'vertical'\n */\n @property({ reflect: true })\n public orientation: 'vertical' | 'horizontal' = 'vertical';\n\n /**\n * Number of extra items to render beyond the visible area of the viewport.\n * Higher values reduce blank flashes during fast scrolling but can lower performance.\n * @attr over-scan\n * @default 2\n */\n @property({ type: Number, attribute: 'over-scan' })\n public overScan = 2;\n\n /**\n * Estimated item size in pixels, used before an item is measured in the DOM.\n * After the first render of an item, the engine replaces the estimate with the measured size.\n * @attr estimated-item-size\n * @default 50\n */\n @property({ type: Number, attribute: 'estimated-item-size' })\n public estimatedItemSize = DEFAULT_ESTIMATED_ITEM_SIZE;\n\n /**\n * A function that renders each item in the virtual scroll list.\n * Receives a VirtualScrollItemContext<T> with the item data, its index, and the total count.\n * Without it, nothing is rendered.\n *\n * Items are measured by their border box, so margins accumulate as drift\n * down the list. Use padding on the item, or a gap on a wrapper, instead.\n *\n * Only the current window is in the DOM, so assistive technology cannot\n * infer an item's position from the markup. Templates that render a role\n * with set semantics (`option`, `listitem`, `row`, ...) should map the\n * context's `index` and `count` onto `aria-posinset` and `aria-setsize`.\n */\n @property({ attribute: false })\n public itemTemplate: VirtualScrollItemTemplate<T> | null = null;\n\n //#endregion\n\n private _adoptStyles(): void {\n /* c8 ignore next 3 */\n if (isServer) {\n return;\n }\n\n const root = this.getRootNode() as Document | ShadowRoot;\n const sheet = IgcVirtualScrollComponent._getStyleSheet();\n if (!root.adoptedStyleSheets.includes(sheet)) {\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];\n }\n }\n\n constructor() {\n super();\n this._engine.onSizeChange = () => this.requestUpdate();\n this._handleScroll = this._handleScroll.bind(this);\n\n addHostListeners(this, {\n events: ['scroll'],\n listener: this._handleScroll,\n options: { passive: true },\n });\n\n // Viewport resize observer\n createResizeObserverController(this, {\n callback: this._measureViewport,\n });\n }\n\n //#region Lit lifecycle\n\n /** @internal */\n public override createRenderRoot(): HTMLElement | DocumentFragment {\n return this;\n }\n\n /** @internal */\n public override connectedCallback(): void {\n super.connectedCallback();\n this._adoptStyles();\n this._engine.initMaxBrowserSize(this.ownerDocument);\n this._measureViewport();\n }\n\n protected override willUpdate(changed: PropertyValues<this>): void {\n // TODO: Either fix this in the theming controller or come up with some other solution.\n\n // Checked on each update, not only in `connectedCallback`, and does\n // nothing if the sheet is there. A host that renders this component in its\n // own shadow root, such as combo, can replace that root's\n // `adoptedStyleSheets` from its theming logic. That drops this sheet while\n // the element stays connected.\n this._adoptStyles();\n\n if (changed.has('data')) {\n this._engine.resize(\n this._items.length,\n this._normalizedItemSize,\n this._firstChangedIndex(changed.get('data'))\n );\n this._hasPendingDataRequest = false;\n }\n\n if (changed.has('estimatedItemSize')) {\n this._engine.updateEstimatedSize(this._normalizedItemSize);\n }\n\n if (changed.has('orientation')) {\n this._measureViewport();\n this._scrollPosition = this._currentAxisScroll();\n }\n\n this._currentRange = this._computeRange();\n }\n\n protected override updated(_changed: PropertyValues<this>): void {\n this._scheduleItemMeasurement();\n this._checkDataRequest();\n this._emitStateChange();\n }\n\n protected override render(): TemplateResult {\n if (!this.itemTemplate) {\n return html`${nothing}`;\n }\n\n const items = this._items;\n const range = this._currentRange;\n const count = items.length;\n const isVertical = this._isVertical;\n\n const trackStyle = isVertical\n ? { height: `${this._engine.domSize}px` }\n : { width: `${this._engine.domSize}px` };\n\n // The content wrapper is absolutely positioned at the origin of a track of\n // `domSize` px. A translation to the scroll offset of the first rendered\n // item puts that item at its virtual position.\n let contentPosition = this._engine.getScrollOffsetForIndex(\n range.startIndex\n );\n const physicalRangeSize = this._engine.getPhysicalRangeSize(\n range.startIndex,\n range.endIndex\n );\n contentPosition = clamp(\n contentPosition,\n 0,\n this._engine.domSize - physicalRangeSize\n );\n const isRTL = !isVertical && !isLTR(this);\n const contentStyle = {\n transform: isVertical\n ? `translateY(${contentPosition}px)`\n : `translateX(${isRTL ? -contentPosition : contentPosition}px)`,\n };\n\n const visibleItems =\n range.endIndex >= range.startIndex\n ? items.slice(range.startIndex, range.endIndex + 1)\n : [];\n\n return html`\n <div\n part=\"virtualization-track\"\n role=\"presentation\"\n style=${styleMap(trackStyle)}\n >\n <div\n ${ref(this._contentRef)}\n part=\"virtualization-content\"\n role=\"presentation\"\n style=${styleMap(contentStyle)}\n >\n ${visibleItems.map((item, i) => {\n const itemIndex = range.startIndex + i;\n const ctx = new VirtualScrollItemContext(item, itemIndex, count);\n return html`<div role=\"presentation\" data-vs-index=${itemIndex}>\n ${this.itemTemplate!(ctx)}\n </div>`;\n })}\n </div>\n </div>\n `;\n }\n\n //#endregion\n\n //#region Internal API\n\n private get _isVertical(): boolean {\n return this.orientation === 'vertical';\n }\n\n /** The configured `overScan`, normalized to a non-negative integer. */\n private get _normalizedOverScan(): number {\n return Math.max(0, Math.floor(asNumber(this.overScan, 2)));\n }\n\n /** The configured `estimatedItemSize`, normalized to a positive number. */\n private get _normalizedItemSize(): number {\n const size = asNumber(this.estimatedItemSize);\n return size > 0 ? size : DEFAULT_ESTIMATED_ITEM_SIZE;\n }\n\n /** `data`, guarded against a nullish value set by the consumer. */\n private get _items(): T[] {\n return this.data ?? [];\n }\n\n /**\n * The window to render for the current scroll position and viewport. Empty\n * until an `itemTemplate` is set, because nothing renders without one.\n */\n private _computeRange(): VisibleRange {\n return this.itemTemplate\n ? this._engine.getVisibleRange(\n this._scrollPosition,\n this._viewportSize,\n this._normalizedOverScan\n )\n : EMPTY_RANGE;\n }\n\n /**\n * The scroll offset that aligns `index` in the viewport, as `options` gives,\n * from the current size data of the engine. The same input can give a\n * different result as more items are measured.\n *\n * For `block: 'nearest'` on an item in view, returns the current offset, so\n * no scroll occurs.\n */\n private _getAlignedScrollOffset(\n index: number,\n options?: ScrollIntoViewOptions\n ): number {\n const requested = this._isVertical\n ? (options?.block ?? 'start')\n : (options?.inline ?? options?.block ?? 'start');\n const current = this._currentAxisScroll();\n\n if (\n requested === 'nearest' &&\n this._engine.isIndexInView(index, current, this._viewportSize)\n ) {\n return current;\n }\n\n const align: ScrollAlignment =\n requested === 'center' || requested === 'end' ? requested : 'start';\n\n return this._engine.getAlignedScrollOffset(\n index,\n this._viewportSize,\n align\n );\n }\n\n /** Applies a scroll offset to the correct axis, accounting for RTL. */\n private _applyScroll(offset: number, behavior: ScrollBehavior): void {\n if (this._isVertical) {\n this.scrollTo({ top: offset, behavior });\n } else {\n this.scrollTo({ left: isLTR(this) ? offset : -offset, behavior });\n }\n }\n\n /** The current real scroll position on the active axis, normalized for RTL. */\n private _currentAxisScroll(): number {\n return this._isVertical\n ? this.scrollTop\n : isLTR(this)\n ? this.scrollLeft\n : -this.scrollLeft;\n }\n\n /**\n * Applies a scroll offset to the active axis, and waits for the scroll to\n * settle.\n *\n * @remarks\n * `scrollend` does not fire if the offset does not move the scroll position,\n * so that case resolves immediately. The timeout covers an event that never\n * arrives, for example when the element disconnects during the scroll.\n */\n private _scrollAndWaitForEnd(\n offset: number,\n behavior: ScrollBehavior\n ): Promise<void> {\n if (\n Math.abs(this._currentAxisScroll() - offset) < SCROLL_OFFSET_EPSILON_PX\n ) {\n return Promise.resolve();\n }\n\n return this._withDeadline(SCROLL_END_TIMEOUT_MS, (signal) => {\n const settled = SUPPORTS_SCROLL_END\n ? this._waitForScrollEnd(signal)\n : this._waitForScrollIdle(signal);\n\n // Applied only after the listener is attached, so an instant scroll\n // cannot settle before something watches for it.\n this._applyScroll(offset, behavior);\n return settled;\n });\n }\n\n /**\n * Resolves with `task`, or with a deadline of `ms`, whichever is first. The\n * signal then stops the other, so no timer or listener stays alive.\n */\n private _withDeadline(\n ms: number,\n task: (signal: AbortSignal) => Promise<void>\n ): Promise<void> {\n const controller = new AbortController();\n\n return Promise.race([\n task(controller.signal),\n this._timeout(ms, controller.signal),\n ]).finally(() => controller.abort());\n }\n\n private _waitForScrollEnd(signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n this.addEventListener('scrollend', () => resolve(), {\n once: true,\n signal,\n });\n });\n }\n\n /**\n * Resolves if no `scroll` event arrives for `SCROLL_IDLE_MS`, which is the\n * closest replacement for `scrollend`. The first timer starts immediately, so\n * a scroll that does not move also settles.\n */\n private _waitForScrollIdle(signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n let id = setTimeout(resolve, SCROLL_IDLE_MS);\n\n this.addEventListener(\n 'scroll',\n () => {\n clearTimeout(id);\n id = setTimeout(resolve, SCROLL_IDLE_MS);\n },\n { passive: true, signal }\n );\n\n signal.addEventListener('abort', () => clearTimeout(id), { once: true });\n });\n }\n\n private _timeout(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const id = setTimeout(resolve, ms);\n signal.addEventListener('abort', () => clearTimeout(id), { once: true });\n });\n }\n\n private _measureViewport(): void {\n this._viewportSize = this._isVertical\n ? this.clientHeight\n : this.clientWidth;\n }\n\n /**\n * Records the new scroll offset. Schedules a render only if the rendered\n * window moves.\n *\n * @remarks\n * `render` reads `_currentRange`, not the scroll offset. Without the guard,\n * a scroll inside one item runs each item template again for the same\n * result. `willUpdate` recomputes `_currentRange` for the other triggers,\n * so this skips only the redundant passes.\n */\n private _handleScroll(): void {\n this._scrollPosition = this._currentAxisScroll();\n\n const { startIndex, endIndex } = this._computeRange();\n if (\n startIndex !== this._currentRange.startIndex ||\n endIndex !== this._currentRange.endIndex\n ) {\n this.requestUpdate();\n }\n }\n\n /**\n * The length of the prefix that a `data` change keeps: the first index at\n * which the old and the new items differ, or the length of the shorter array\n * if neither differs. Measurements below that index stay valid. An append\n * keeps all the previous items. A filter or a replacement keeps fewer.\n *\n * @remarks\n * The test is item identity. An item that changes in place keeps its\n * measured size.\n */\n private _firstChangedIndex(previous: T[] | undefined): number {\n if (!previous) {\n return 0;\n }\n\n const items = this._items;\n const shared = Math.min(previous.length, items.length);\n for (let i = 0; i < shared; i++) {\n if (previous[i] !== items[i]) {\n return i;\n }\n }\n return shared;\n }\n\n private _handleItemResize(entries: ResizeObserverEntry[]): void {\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n const index = asNumber(el.dataset.vsIndex, -1);\n if (index < 0) continue;\n\n const measured = this._isVertical\n ? (entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height)\n : (entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width);\n\n if (measured > 0) {\n this._engine.measureItem(index, measured);\n }\n }\n }\n\n /**\n * Syncs the item observer with the rendered window, and applies only the\n * difference.\n *\n * @remarks\n * `observe` on an already observed element does nothing, so a new\n * measurement needs `unobserve` and then `observe`. Do this for each element\n * whose `data-vs-index` changed. Lit keeps the wrapper elements between\n * renders, so after a scroll one element can hold a different item at the\n * same size. The observer does not report that, and the new index keeps its\n * estimated size.\n */\n private _scheduleItemMeasurement(): void {\n const content = this._contentRef.value;\n if (!content) return;\n\n const observed = this._itemResizeController.targets;\n\n for (const element of observed) {\n if (element.parentNode !== content) {\n this._itemResizeController.unobserve(element);\n }\n }\n\n for (const element of content.children) {\n const index = asNumber((element as HTMLElement).dataset.vsIndex, -1);\n const isObserved = observed.has(element);\n\n if (isObserved && this._observedItemIndexes.get(element) === index) {\n continue;\n }\n\n if (isObserved) {\n this._itemResizeController.unobserve(element);\n }\n this._itemResizeController.observe(element);\n this._observedItemIndexes.set(element, index);\n }\n }\n\n /**\n * Emits `igcStateChange`. Does nothing if the window is empty or equal to\n * the last reported one, because a measurement pass renders again with no\n * window change.\n */\n private _emitStateChange(): void {\n const { startIndex, endIndex } = this._currentRange;\n if (endIndex < startIndex) return;\n\n const previous = this._lastEmittedState;\n const detail: VirtualScrollState = {\n startIndex,\n endIndex,\n viewportSize: this._viewportSize,\n totalSize: this._engine.totalSize,\n };\n\n if (\n previous &&\n previous.startIndex === detail.startIndex &&\n previous.endIndex === detail.endIndex &&\n previous.viewportSize === detail.viewportSize &&\n previous.totalSize === detail.totalSize\n ) {\n return;\n }\n\n this._lastEmittedState = { ...detail };\n this.emitEvent('igcStateChange', { detail });\n }\n\n private _checkDataRequest(): void {\n if (this._hasPendingDataRequest) return;\n\n const range = this._currentRange;\n const total = this._items.length;\n\n if (total === 0 || range.endIndex < total - REMOTE_SCROLLING_THRESHOLD) {\n return;\n }\n\n // Each `data` change clears `_hasPendingDataRequest`, also one that\n // appends nothing. Without this second guard, a consumer whose source is\n // exhausted and that assigns `data` again for each request gets that same\n // request again.\n if (this._lastDataRequestIndex === total) {\n return;\n }\n\n this._hasPendingDataRequest = true;\n this._lastDataRequestIndex = total;\n\n this.emitEvent('igcDataRequest', {\n detail: {\n startIndex: total,\n count: Math.max(this._normalizedOverScan * 4, 20),\n },\n });\n }\n\n /**\n * Resolves on the next animation frame, or after `LAYOUT_FRAME_TIMEOUT_MS` if\n * no frame arrives. A hidden tab or a disconnected element gets no frames,\n * and `layoutComplete` must still settle. Such a state has no layout to wait\n * for, so an early resolve is safe.\n */\n private _nextFrame(): Promise<void> {\n return this._withDeadline(\n LAYOUT_FRAME_TIMEOUT_MS,\n (signal) =>\n new Promise((resolve) => {\n const id = requestAnimationFrame(() => resolve());\n signal.addEventListener('abort', () => cancelAnimationFrame(id), {\n once: true,\n });\n })\n );\n }\n\n /**\n * Waits for the current update, then lets the ResizeObserver measurements\n * run. If those schedule one more render, for example when a measured size\n * replaces an estimate, the wait repeats until nothing is pending, up to a\n * safety cap.\n */\n private async _resolveLayoutComplete(): Promise<void> {\n try {\n await this.updateComplete;\n\n for (let i = 0; i < MAX_LAYOUT_SETTLE_PASSES; i++) {\n await this._nextFrame();\n\n if (!this.isUpdatePending) {\n break;\n }\n\n await this.updateComplete;\n }\n } finally {\n // Cleared here, not after the loop, so a run that throws cannot leave\n // the getter with a permanently rejected promise.\n this._layoutCompletePromise = null;\n }\n }\n\n //#endregion\n\n //#region Public API\n\n /* blazorSuppress */\n /**\n * Resolves when the virtual scroll has settled: the current render pass is\n * complete, the item-size measurements it triggers are complete, and so\n * are the renders those measurements schedule.\n *\n * `updateComplete` covers one Lit render pass. This covers `data` changes,\n * scrolls, and viewport resizes, where the stable DOM state comes after\n * one or more follow-up renders.\n */\n public get layoutComplete(): Promise<void> {\n if (!this._layoutCompletePromise) {\n this._layoutCompletePromise = this._resolveLayoutComplete();\n }\n return this._layoutCompletePromise;\n }\n\n /**\n * Scrolls to the specified item index.\n *\n * Items outside the rendered window have only an estimated size, so the\n * first jump can miss the target. The items at the landing point are then\n * measured, and the scroll position is corrected. This repeats until the\n * offset is stable.\n *\n * The returned promise resolves when the scroll settles on the final,\n * corrected offset. Callers that need only the first, approximate scroll\n * can ignore it.\n */\n public async scrollToIndex(\n index: number,\n options?: ScrollIntoViewOptions\n ): Promise<void> {\n const maxIndex = Math.max(0, this._items.length - 1);\n const clampedIndex = clamp(index, 0, maxIndex);\n const behavior = options?.behavior ?? 'auto';\n\n // A newer call supersedes a correction loop that still runs for a\n // previous call, for example under rapid, repeated calls.\n const requestId = ++this._scrollRequestId;\n\n let offset = this._getAlignedScrollOffset(clampedIndex, options);\n await this._scrollAndWaitForEnd(offset, behavior);\n\n for (let i = 0; i < MAX_SCROLL_CORRECTION_PASSES; i++) {\n await this.layoutComplete;\n\n if (requestId !== this._scrollRequestId) {\n return;\n }\n\n const corrected = this._getAlignedScrollOffset(clampedIndex, options);\n if (Math.abs(corrected - offset) < SCROLL_OFFSET_EPSILON_PX) {\n break;\n }\n\n offset = corrected;\n await this._scrollAndWaitForEnd(offset, 'auto');\n\n if (requestId !== this._scrollRequestId) {\n return;\n }\n }\n }\n\n //#endregion\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'igc-virtual-scroll': IgcVirtualScrollComponent;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"virtualization.js","sourceRoot":"","sources":["../../../src/components/virtualization/virtualization.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,OAAO,GAGR,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,8BAA8B,EAAE,MAAM,2CAA2C,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAEL,wBAAwB,GAGzB,MAAM,YAAY,CAAC;AAapB,MAAM,0BAA0B,GAAG,CAAC,CAAC;AACrC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AACpC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AACvC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAEnC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAEvC,MAAM,cAAc,GAAG,GAAG,CAAC;AAM3B,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAOpC,MAAM,mBAAmB,GAAG,CAAC,QAAQ,IAAI,aAAa,IAAI,MAAM,CAAC;AAEjE,MAAM,WAAW,GAAiB,MAAM,CAAC,MAAM,CAAC;IAC9C,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC,CAAC;CACb,CAAC,CAAC;AAgBH,MAAM,CAAC,OAAO,OAAO,yBAEnB,SAAQ,iBAAiB,CAGzB,UAAU,CAAC;aACY,YAAO,GAAG,oBAAoB,AAAvB,CAAwB;IAG/C,MAAM,CAAC,QAAQ;QACpB,iBAAiB,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;aAEc,gBAAW,GAAyB,IAAI,AAA7B,CAA8B;IAEhD,MAAM,CAAC,cAAc;QAC3B,IAAI,CAAC,yBAAyB,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,IAAI,aAAa,EAAE,CAAC;YAClC,KAAK,CAAC,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuDjB,CAAC,CAAC;YACH,yBAAyB,CAAC,WAAW,GAAG,KAAK,CAAC;QAChD,CAAC;QACD,OAAO,yBAAyB,CAAC,WAAW,CAAC;IAC/C,CAAC;IAgIO,YAAY;QAElB,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAA2B,CAAC;QACzD,MAAM,KAAK,GAAG,yBAAyB,CAAC,cAAc,EAAE,CAAC;QACzD,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,kBAAkB,GAAG,CAAC,GAAG,IAAI,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED;QACE,KAAK,EAAE,CAAC;QA1IS,YAAO,GAAG,IAAI,mBAAmB,EAAE,CAAC;QACtC,gBAAW,GAAG,SAAS,EAAkB,CAAC;QAC1C,0BAAqB,GAAG,8BAA8B,CACrE,IAAI,EACJ;YACE,QAAQ,EAAE,IAAI,CAAC,iBAAiB;YAChC,MAAM,EAAE,IAAI;YACZ,aAAa,EAAE,KAAK;SACrB,CACF,CAAC;QAEM,kBAAa,GAAiB,WAAW,CAAC;QAMjC,yBAAoB,GAAG,IAAI,OAAO,EAAmB,CAAC;QAC/D,sBAAiB,GAA8B,IAAI,CAAC;QACpD,2BAAsB,GAAG,KAAK,CAAC;QAC/B,2BAAsB,GAAyB,IAAI,CAAC;QACpD,qBAAgB,GAAG,CAAC,CAAC;QAUrB,0BAAqB,GAAG,CAAC,CAAC,CAAC;QAO3B,oBAAe,GAAG,CAAC,CAAC;QAGpB,kBAAa,GAAG,CAAC,CAAC;QAcnB,SAAI,GAAQ,EAAE,CAAC;QAQf,gBAAW,GAA8B,UAAU,CAAC;QASpD,aAAQ,GAAG,CAAC,CAAC;QAWb,sBAAiB,GAAG,2BAA2B,CAAC;QAyBhD,iBAAY,GAAwC,IAAI,CAAC;QAYzD,gBAAW,GAAuC,IAAI,CAAC;QAmB5D,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACvD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEnD,gBAAgB,CAAC,IAAI,EAAE;YACrB,MAAM,EAAE,CAAC,QAAQ,CAAC;YAClB,QAAQ,EAAE,IAAI,CAAC,aAAa;YAC5B,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;SAC3B,CAAC,CAAC;QAGH,8BAA8B,CAAC,IAAI,EAAE;YACnC,QAAQ,EAAE,IAAI,CAAC,gBAAgB;SAChC,CAAC,CAAC;IACL,CAAC;IAKe,gBAAgB;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAGe,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACpD,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAEkB,UAAU,CAAC,OAA6B;QAQzD,IAAI,CAAC,YAAY,EAAE,CAAC;QAEpB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,MAAM,CACjB,IAAI,CAAC,MAAM,CAAC,MAAM,EAClB,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAC7C,CAAC;YACF,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACtC,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACnD,CAAC;QAED,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5C,CAAC;IAEkB,OAAO,CAAC,QAA8B;QACvD,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAChC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAEkB,MAAM;QACvB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,IAAI,CAAA,GAAG,OAAO,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC;QAEpC,MAAM,UAAU,GAAG,UAAU;YAC3B,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE;YACzC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QAK3C,IAAI,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,uBAAuB,CACxD,KAAK,CAAC,UAAU,CACjB,CAAC;QACF,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB,CACzD,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,QAAQ,CACf,CAAC;QACF,eAAe,GAAG,KAAK,CACrB,eAAe,EACf,CAAC,EACD,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,iBAAiB,CACzC,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,YAAY,GAAG;YACnB,SAAS,EAAE,UAAU;gBACnB,CAAC,CAAC,cAAc,eAAe,KAAK;gBACpC,CAAC,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,KAAK;SAClE,CAAC;QAEF,MAAM,YAAY,GAChB,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,UAAU;YAChC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;YACnD,CAAC,CAAC,EAAE,CAAC;QAET,OAAO,IAAI,CAAA;;;;gBAIC,QAAQ,CAAC,UAAU,CAAC;;;YAGxB,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;;;kBAGf,QAAQ,CAAC,YAAY,CAAC;;YAE5B,OAAO,CACP,YAAY,EACZ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,EACpD,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACV,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC;YACvC,MAAM,GAAG,GAAG,IAAI,wBAAwB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YACjE,OAAO,IAAI,CAAA,0CAA0C,SAAS;kBAC1D,IAAI,CAAC,YAAa,CAAC,GAAG,CAAC;qBACpB,CAAC;QACV,CAAC,CACF;;;KAGN,CAAC;IACJ,CAAC;IAMD,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,WAAW,KAAK,UAAU,CAAC;IACzC,CAAC;IAGD,IAAY,mBAAmB;QAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IAGD,IAAY,mBAAmB;QAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC9C,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,2BAA2B,CAAC;IACvD,CAAC;IAGD,IAAY,MAAM;QAChB,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IACzB,CAAC;IAGO,MAAM,CAAC,IAAO,EAAE,KAAa;QACnC,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,CAAC;IAMO,aAAa;QACnB,OAAO,IAAI,CAAC,YAAY;YACtB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAC1B,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,mBAAmB,CACzB;YACH,CAAC,CAAC,WAAW,CAAC;IAClB,CAAC;IAOO,uBAAuB,CAC7B,KAAa,EACb,OAA+B;QAE/B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW;YAC/B,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,IAAI,OAAO,CAAC;YAC7B,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,KAAK,IAAI,OAAO,CAAC,CAAC;QAEnD,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,CACrC,KAAK,EACL,IAAI,CAAC,kBAAkB,EAAE,EACzB,IAAI,CAAC,aAAa,EAClB,QAAQ,CACT,CAAC;IACJ,CAAC;IAGO,YAAY,CAAC,MAAc,EAAE,QAAwB;QAC3D,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAGO,kBAAkB;QACxB,OAAO,IAAI,CAAC,WAAW;YACrB,CAAC,CAAC,IAAI,CAAC,SAAS;YAChB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;gBACX,CAAC,CAAC,IAAI,CAAC,UAAU;gBACjB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAWO,oBAAoB,CAC1B,MAAc,EACd,QAAwB;QAExB,IACE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,MAAM,CAAC,GAAG,wBAAwB,EACvE,CAAC;YACD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,qBAAqB,EAAE,CAAC,MAAM,EAAE,EAAE;YAC1D,MAAM,OAAO,GAAG,mBAAmB;gBACjC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;gBAChC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAIpC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACpC,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAMO,aAAa,CACnB,EAAU,EACV,IAA4C;QAE5C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QAEzC,OAAO,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC;SACrC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;IACvC,CAAC;IAEO,iBAAiB,CAAC,MAAmB;QAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE;gBAClD,IAAI,EAAE,IAAI;gBACV,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAOO,kBAAkB,CAAC,MAAmB;QAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE7C,IAAI,CAAC,gBAAgB,CACnB,QAAQ,EACR,GAAG,EAAE;gBACH,YAAY,CAAC,EAAE,CAAC,CAAC;gBACjB,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAC3C,CAAC,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAC1B,CAAC;YAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,QAAQ,CAAC,EAAU,EAAE,MAAmB;QAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACnC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,WAAW;YACnC,CAAC,CAAC,IAAI,CAAC,YAAY;YACnB,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;IACvB,CAAC;IAYO,aAAa;QACnB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEjD,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACtD,IACE,UAAU,KAAK,IAAI,CAAC,aAAa,CAAC,UAAU;YAC5C,QAAQ,KAAK,IAAI,CAAC,aAAa,CAAC,QAAQ,EACxC,CAAC;YACD,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAYO,kBAAkB,CAAC,QAAyB;QAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,iBAAiB,CAAC,OAA8B;QACtD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAG,KAAK,CAAC,MAAqB,CAAC;YACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,IAAI,KAAK,GAAG,CAAC;gBAAE,SAAS;YAExB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW;gBAC/B,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC;gBACnE,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEtE,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC;IAaO,wBAAwB;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QACvC,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,QAAQ,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC;QAEpD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;gBACnC,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,QAAQ,CAAE,OAAuB,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YACrE,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAEzC,IAAI,UAAU,IAAI,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,EAAE,CAAC;gBACnE,SAAS;YACX,CAAC;YAED,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAChD,CAAC;YACD,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC5C,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAOO,gBAAgB;QACtB,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;QACpD,IAAI,QAAQ,GAAG,UAAU;YAAE,OAAO;QAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC;QACxC,MAAM,MAAM,GAAuB;YACjC,UAAU;YACV,QAAQ;YACR,YAAY,EAAE,IAAI,CAAC,aAAa;YAChC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;SAClC,CAAC;QAEF,IACE,QAAQ;YACR,QAAQ,CAAC,UAAU,KAAK,MAAM,CAAC,UAAU;YACzC,QAAQ,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ;YACrC,QAAQ,CAAC,YAAY,KAAK,MAAM,CAAC,YAAY;YAC7C,QAAQ,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,EACvC,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,iBAAiB,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;QACvC,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;IAEO,iBAAiB;QACvB,IAAI,IAAI,CAAC,sBAAsB;YAAE,OAAO;QAExC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAEjC,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,GAAG,KAAK,GAAG,0BAA0B,EAAE,CAAC;YACvE,OAAO;QACT,CAAC;QAMD,IAAI,IAAI,CAAC,qBAAqB,KAAK,KAAK,EAAE,CAAC;YACzC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;QAEnC,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE;YAC/B,MAAM,EAAE;gBACN,UAAU,EAAE,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,EAAE,EAAE,CAAC;aAClD;SACF,CAAC,CAAC;IACL,CAAC;IAQO,UAAU;QAChB,OAAO,IAAI,CAAC,aAAa,CACvB,uBAAuB,EACvB,CAAC,MAAM,EAAE,EAAE,CACT,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACtB,MAAM,EAAE,GAAG,qBAAqB,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAClD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAAE;gBAC/D,IAAI,EAAE,IAAI;aACX,CAAC,CAAC;QACL,CAAC,CAAC,CACL,CAAC;IACJ,CAAC;IAQO,KAAK,CAAC,sBAAsB;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC;YAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,wBAAwB,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClD,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBAExB,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;oBAC1B,MAAM;gBACR,CAAC;gBAED,MAAM,IAAI,CAAC,cAAc,CAAC;YAC5B,CAAC;QACH,CAAC;gBAAS,CAAC;YAGT,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACrC,CAAC;IACH,CAAC;IAgBD,IAAW,cAAc;QACvB,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAC,sBAAsB,CAAC;IACrC,CAAC;IAkBM,KAAK,CAAC,aAAa,CACxB,KAAa,EACb,OAA+B;QAE/B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,MAAM,CAAC;QAI7C,MAAM,SAAS,GAAG,EAAE,IAAI,CAAC,gBAAgB,CAAC;QAE1C,IAAI,MAAM,GAAG,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACjE,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,4BAA4B,EAAE,CAAC,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,CAAC,cAAc,CAAC;YAE1B,IAAI,SAAS,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxC,OAAO;YACT,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACtE,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,wBAAwB,EAAE,CAAC;gBAC5D,MAAM;YACR,CAAC;YAED,MAAM,GAAG,SAAS,CAAC;YACnB,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAEhD,IAAI,SAAS,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxC,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;;AA/qBO;IADP,KAAK,EAAE;gEACkB;AAcnB;IADN,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;uDACT;AAQf;IADN,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8DAC+B;AASpD;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;2DAC/B;AAWb;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB,EAAE,CAAC;oEACN;AAyBhD;IADN,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;+DACiC;AAYzD;IADN,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;8DAC+B","sourcesContent":["import {\n html,\n isServer,\n LitElement,\n nothing,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { createRef, ref } from 'lit/directives/ref.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { addHostListeners } from '#internals/controllers/host-listeners.js';\nimport { createResizeObserverController } from '#internals/controllers/resize-observer.js';\nimport { registerComponent } from '#internals/definitions/register.js';\nimport type { Constructor } from '#internals/mixins/constructor.js';\nimport { EventEmitterMixin } from '#internals/mixins/event-emitter.js';\nimport { isLTR } from '#internals/utils/dom.js';\nimport { asNumber, clamp } from '#internals/utils/math.js';\nimport { VirtualScrollEngine } from './engine.js';\nimport { recycle } from './recycle.js';\nimport {\n type VirtualScrollDataRequest,\n VirtualScrollItemContext,\n type VirtualScrollState,\n type VisibleRange,\n} from './types.js';\n\nexport type VirtualScrollItemTemplate<T> = (\n context: VirtualScrollItemContext<T>\n) => TemplateResult | typeof nothing;\n\nexport type VirtualScrollKeyFunction<T> = (item: T, index: number) => unknown;\n\nexport interface IgcVirtualScrollComponentEventMap {\n igcStateChange: CustomEvent<VirtualScrollState>;\n igcDataRequest: CustomEvent<VirtualScrollDataRequest>;\n}\n\nconst REMOTE_SCROLLING_THRESHOLD = 5;\nconst MAX_LAYOUT_SETTLE_PASSES = 20;\nconst MAX_SCROLL_CORRECTION_PASSES = 5;\nconst SCROLL_END_TIMEOUT_MS = 2000;\nconst SCROLL_OFFSET_EPSILON_PX = 1;\n/** Fallback for a non-positive `estimatedItemSize`. Equal to its default. */\nconst DEFAULT_ESTIMATED_ITEM_SIZE = 50;\n/** How long the scroll position must stay unchanged to count as settled. */\nconst SCROLL_IDLE_MS = 100;\n/**\n * Upper limit on one `requestAnimationFrame` wait. A hidden tab or a\n * disconnected element gets no frames, and `layoutComplete` must still\n * resolve there.\n */\nconst LAYOUT_FRAME_TIMEOUT_MS = 100;\n\n/**\n * `scrollend` reports exactly when a scroll has settled. Safari before 18.2\n * does not have it, and `_scrollAndWaitForEnd` falls back to a scroll-idle\n * timer there.\n */\nconst SUPPORTS_SCROLL_END = !isServer && 'onscrollend' in window;\n\nconst EMPTY_RANGE: VisibleRange = Object.freeze({\n startIndex: 0,\n endIndex: -1,\n});\n\n/**\n * A virtual scroll component for large lists. Only the items visible in the\n * viewport are rendered.\n *\n * @element igc-virtual-scroll\n *\n * @fires igcStateChange - Emitted when the rendered virtual window changes.\n * @fires igcDataRequest - Emitted when the rendered window comes within a few items of the end\n * of `data`. Also emitted on the first render, when the loaded items do not fill the viewport.\n *\n * @csspart virtualization-track - The full-size element that gives the host its scrollable extent.\n * @csspart virtualization-content - The wrapper that holds the rendered items, translated into\n * position within the track.\n */\nexport default class IgcVirtualScrollComponent<\n T = any,\n> extends EventEmitterMixin<\n IgcVirtualScrollComponentEventMap,\n Constructor<LitElement>\n>(LitElement) {\n public static readonly tagName = 'igc-virtual-scroll';\n\n /* blazorSuppress */\n public static register(): void {\n registerComponent(IgcVirtualScrollComponent);\n }\n\n private static _styleSheet: CSSStyleSheet | null = null;\n\n private static _getStyleSheet(): CSSStyleSheet {\n if (!IgcVirtualScrollComponent._styleSheet) {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(`\n :where(igc-virtual-scroll) {\n display: block;\n position: relative;\n overflow: auto;\n height: 18.75rem;\n }\n\n :where(igc-virtual-scroll[orientation='vertical']) {\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) {\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n :where(igc-virtual-scroll) [part=\"virtualization-track\"] {\n position: relative;\n width: 100%;\n min-height: 100%;\n }\n\n :where(igc-virtual-scroll) [part=\"virtualization-content\"] {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n will-change: transform;\n contain: layout style paint;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) [part=\"virtualization-track\"] {\n height: 100%;\n width: auto;\n min-height: unset;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) [part=\"virtualization-content\"] {\n display: flex;\n flex-direction: row;\n height: 100%;\n width: auto;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']) [part=\"virtualization-content\"] > [data-vs-index] {\n flex-shrink: 0;\n height: 100%;\n }\n\n :where(igc-virtual-scroll[orientation='horizontal']):dir(rtl) [part=\"virtualization-content\"] {\n left: auto;\n right: 0;\n }\n `);\n IgcVirtualScrollComponent._styleSheet = sheet;\n }\n return IgcVirtualScrollComponent._styleSheet;\n }\n\n //#region Internal state\n\n protected readonly _engine = new VirtualScrollEngine();\n private readonly _contentRef = createRef<HTMLDivElement>();\n private readonly _itemResizeController = createResizeObserverController(\n this,\n {\n callback: this._handleItemResize,\n target: null,\n requestUpdate: false,\n }\n );\n\n private _currentRange: VisibleRange = EMPTY_RANGE;\n\n /**\n * The item index each wrapper element was last observed under. See\n * `_scheduleItemMeasurement`.\n */\n private readonly _observedItemIndexes = new WeakMap<Element, number>();\n private _lastEmittedState: VirtualScrollState | null = null;\n private _hasPendingDataRequest = false;\n private _layoutCompletePromise: Promise<void> | null = null;\n private _scrollRequestId = 0;\n\n /**\n * The `startIndex` of the last `igcDataRequest`, which is also the item count\n * at that emit. See `_checkDataRequest`.\n *\n * Kept across a disconnect, as `_hasPendingDataRequest` is. A move in the DOM\n * does not cancel what the consumer was already asked for, and clearing only\n * one of the two opens the request loop again on reconnect.\n */\n private _lastDataRequestIndex = -1;\n\n /**\n * The live scroll offset on the active axis. Not reactive: `render` reads it\n * only through `_currentRange`, so `_handleScroll` schedules an update only\n * if the window moves.\n */\n private _scrollPosition = 0;\n\n @state()\n private _viewportSize = 0;\n\n //#endregion\n\n //#region Public properties\n\n /**\n * The array of items to virtualize.\n *\n * Compared by reference: a mutation in place (`data.push(...)`) causes no\n * update. Assign a new array instead. The `igcDataRequest` flow also\n * expects a new array.\n */\n @property({ attribute: false })\n public data: T[] = [];\n\n /**\n * Scroll orientation of the virtual scroll.\n * @attr orientation\n * @default 'vertical'\n */\n @property({ reflect: true })\n public orientation: 'vertical' | 'horizontal' = 'vertical';\n\n /**\n * Number of extra items to render beyond the visible area of the viewport.\n * Higher values reduce blank flashes during fast scrolling but can lower performance.\n * @attr over-scan\n * @default 2\n */\n @property({ type: Number, attribute: 'over-scan' })\n public overScan = 2;\n\n /**\n * Estimated item size in pixels, used before an item is measured in the DOM.\n * After the first render of an item, the engine replaces the estimate with the measured size.\n * The average measured size also replaces the estimate of the items that are not measured\n * yet, so the scrollbar follows the real content.\n * @attr estimated-item-size\n * @default 50\n */\n @property({ type: Number, attribute: 'estimated-item-size' })\n public estimatedItemSize = DEFAULT_ESTIMATED_ITEM_SIZE;\n\n /**\n * A function that renders each item in the virtual scroll list.\n * Receives a VirtualScrollItemContext<T> with the item data, its index, and the total count.\n * Without it, nothing is rendered.\n *\n * Items are measured by their border box, so margins accumulate as drift\n * down the list. Use padding on the item, or a gap on a wrapper, instead.\n *\n * Only the current window is in the DOM, so assistive technology cannot\n * infer an item's position from the markup. Templates that render a role\n * with set semantics (`option`, `listitem`, `row`, ...) should map the\n * context's `index` and `count` onto `aria-posinset` and `aria-setsize`.\n *\n * Item elements are recycled (see `keyFunction`), so DOM state that the\n * template does not bind moves to another item, for example the state of a\n * checkbox without a `checked` binding. Bind all item state. Lit compares a\n * binding with the value that it set last, not with the element, so bind\n * state that the user changes with Lit's `live` directive. Also write user\n * changes back to the item, or they are lost when the item leaves the window.\n * To get new DOM for each item, wrap the content in Lit's `keyed` directive\n * with the item key: `` html`${keyed(ctx.value.id, content)}` ``.\n */\n @property({ attribute: false })\n public itemTemplate: VirtualScrollItemTemplate<T> | null = null;\n\n /* blazorSuppress */\n /**\n * A function that returns a unique key for an item. Receives the item and its index in `data`.\n *\n * An item keeps its rendered element while its key stays in the rendered window. The elements\n * of keys that leave the window are reused for keys that enter it. Without it, the index is the\n * key, so after a `data` change an index keeps its element and shows its new item. Set it when\n * items move within `data`, for example on sort, insert or remove.\n */\n @property({ attribute: false })\n public keyFunction: VirtualScrollKeyFunction<T> | null = null;\n\n //#endregion\n\n private _adoptStyles(): void {\n /* c8 ignore next 3 */\n if (isServer) {\n return;\n }\n\n const root = this.getRootNode() as Document | ShadowRoot;\n const sheet = IgcVirtualScrollComponent._getStyleSheet();\n if (!root.adoptedStyleSheets.includes(sheet)) {\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];\n }\n }\n\n constructor() {\n super();\n this._engine.onSizeChange = () => this.requestUpdate();\n this._handleScroll = this._handleScroll.bind(this);\n\n addHostListeners(this, {\n events: ['scroll'],\n listener: this._handleScroll,\n options: { passive: true },\n });\n\n // Viewport resize observer\n createResizeObserverController(this, {\n callback: this._measureViewport,\n });\n }\n\n //#region Lit lifecycle\n\n /** @internal */\n public override createRenderRoot(): HTMLElement | DocumentFragment {\n return this;\n }\n\n /** @internal */\n public override connectedCallback(): void {\n super.connectedCallback();\n this._adoptStyles();\n this._engine.initMaxBrowserSize(this.ownerDocument);\n this._measureViewport();\n }\n\n protected override willUpdate(changed: PropertyValues<this>): void {\n // TODO: Either fix this in the theming controller or come up with some other solution.\n\n // Checked on each update, not only in `connectedCallback`, and does\n // nothing if the sheet is there. A host that renders this component in its\n // own shadow root, such as combo, can replace that root's\n // `adoptedStyleSheets` from its theming logic. That drops this sheet while\n // the element stays connected.\n this._adoptStyles();\n\n if (changed.has('data')) {\n this._engine.resize(\n this._items.length,\n this._normalizedItemSize,\n this._firstChangedIndex(changed.get('data'))\n );\n this._hasPendingDataRequest = false;\n }\n\n if (changed.has('estimatedItemSize')) {\n this._engine.updateEstimatedSize(this._normalizedItemSize);\n }\n\n if (changed.has('orientation')) {\n this._measureViewport();\n this._scrollPosition = this._currentAxisScroll();\n }\n\n this._currentRange = this._computeRange();\n }\n\n protected override updated(_changed: PropertyValues<this>): void {\n this._scheduleItemMeasurement();\n this._checkDataRequest();\n this._emitStateChange();\n }\n\n protected override render(): TemplateResult {\n if (!this.itemTemplate) {\n return html`${nothing}`;\n }\n\n const items = this._items;\n const range = this._currentRange;\n const count = items.length;\n const isVertical = this._isVertical;\n\n const trackStyle = isVertical\n ? { height: `${this._engine.domSize}px` }\n : { width: `${this._engine.domSize}px` };\n\n // The content wrapper is absolutely positioned at the origin of a track of\n // `domSize` px. A translation to the scroll offset of the first rendered\n // item puts that item at its virtual position.\n let contentPosition = this._engine.getScrollOffsetForIndex(\n range.startIndex\n );\n const physicalRangeSize = this._engine.getPhysicalRangeSize(\n range.startIndex,\n range.endIndex\n );\n contentPosition = clamp(\n contentPosition,\n 0,\n this._engine.domSize - physicalRangeSize\n );\n const isRTL = !isVertical && !isLTR(this);\n const contentStyle = {\n transform: isVertical\n ? `translateY(${contentPosition}px)`\n : `translateX(${isRTL ? -contentPosition : contentPosition}px)`,\n };\n\n const visibleItems =\n range.endIndex >= range.startIndex\n ? items.slice(range.startIndex, range.endIndex + 1)\n : [];\n\n return html`\n <div\n part=\"virtualization-track\"\n role=\"presentation\"\n style=${styleMap(trackStyle)}\n >\n <div\n ${ref(this._contentRef)}\n part=\"virtualization-content\"\n role=\"presentation\"\n style=${styleMap(contentStyle)}\n >\n ${recycle(\n visibleItems,\n (item, i) => this._keyOf(item, range.startIndex + i),\n (item, i) => {\n const itemIndex = range.startIndex + i;\n const ctx = new VirtualScrollItemContext(item, itemIndex, count);\n return html`<div role=\"presentation\" data-vs-index=${itemIndex}>\n ${this.itemTemplate!(ctx)}\n </div>`;\n }\n )}\n </div>\n </div>\n `;\n }\n\n //#endregion\n\n //#region Internal API\n\n private get _isVertical(): boolean {\n return this.orientation === 'vertical';\n }\n\n /** The configured `overScan`, normalized to a non-negative integer. */\n private get _normalizedOverScan(): number {\n return Math.max(0, Math.floor(asNumber(this.overScan, 2)));\n }\n\n /** The configured `estimatedItemSize`, normalized to a positive number. */\n private get _normalizedItemSize(): number {\n const size = asNumber(this.estimatedItemSize);\n return size > 0 ? size : DEFAULT_ESTIMATED_ITEM_SIZE;\n }\n\n /** `data`, guarded against a nullish value set by the consumer. */\n private get _items(): T[] {\n return this.data ?? [];\n }\n\n /** The key that ties the item at `index` to its rendered element. */\n private _keyOf(item: T, index: number): unknown {\n return this.keyFunction ? this.keyFunction(item, index) : index;\n }\n\n /**\n * The window to render for the current scroll position and viewport. Empty\n * until an `itemTemplate` is set, because nothing renders without one.\n */\n private _computeRange(): VisibleRange {\n return this.itemTemplate\n ? this._engine.getVisibleRange(\n this._scrollPosition,\n this._viewportSize,\n this._normalizedOverScan\n )\n : EMPTY_RANGE;\n }\n\n /**\n * The scroll offset that aligns `index` in the viewport, as `options` gives,\n * from the current size data of the engine. The same input can give a\n * different result as more items are measured.\n */\n private _getAlignedScrollOffset(\n index: number,\n options?: ScrollIntoViewOptions\n ): number {\n const position = this._isVertical\n ? (options?.block ?? 'start')\n : (options?.inline ?? options?.block ?? 'start');\n\n return this._engine.resolveScrollOffset(\n index,\n this._currentAxisScroll(),\n this._viewportSize,\n position\n );\n }\n\n /** Applies a scroll offset to the correct axis, accounting for RTL. */\n private _applyScroll(offset: number, behavior: ScrollBehavior): void {\n if (this._isVertical) {\n this.scrollTo({ top: offset, behavior });\n } else {\n this.scrollTo({ left: isLTR(this) ? offset : -offset, behavior });\n }\n }\n\n /** The current real scroll position on the active axis, normalized for RTL. */\n private _currentAxisScroll(): number {\n return this._isVertical\n ? this.scrollTop\n : isLTR(this)\n ? this.scrollLeft\n : -this.scrollLeft;\n }\n\n /**\n * Applies a scroll offset to the active axis, and waits for the scroll to\n * settle.\n *\n * @remarks\n * `scrollend` does not fire if the offset does not move the scroll position,\n * so that case resolves immediately. The timeout covers an event that never\n * arrives, for example when the element disconnects during the scroll.\n */\n private _scrollAndWaitForEnd(\n offset: number,\n behavior: ScrollBehavior\n ): Promise<void> {\n if (\n Math.abs(this._currentAxisScroll() - offset) < SCROLL_OFFSET_EPSILON_PX\n ) {\n return Promise.resolve();\n }\n\n return this._withDeadline(SCROLL_END_TIMEOUT_MS, (signal) => {\n const settled = SUPPORTS_SCROLL_END\n ? this._waitForScrollEnd(signal)\n : this._waitForScrollIdle(signal);\n\n // Applied only after the listener is attached, so an instant scroll\n // cannot settle before something watches for it.\n this._applyScroll(offset, behavior);\n return settled;\n });\n }\n\n /**\n * Resolves with `task`, or with a deadline of `ms`, whichever is first. The\n * signal then stops the other, so no timer or listener stays alive.\n */\n private _withDeadline(\n ms: number,\n task: (signal: AbortSignal) => Promise<void>\n ): Promise<void> {\n const controller = new AbortController();\n\n return Promise.race([\n task(controller.signal),\n this._timeout(ms, controller.signal),\n ]).finally(() => controller.abort());\n }\n\n private _waitForScrollEnd(signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n this.addEventListener('scrollend', () => resolve(), {\n once: true,\n signal,\n });\n });\n }\n\n /**\n * Resolves if no `scroll` event arrives for `SCROLL_IDLE_MS`, which is the\n * closest replacement for `scrollend`. The first timer starts immediately, so\n * a scroll that does not move also settles.\n */\n private _waitForScrollIdle(signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n let id = setTimeout(resolve, SCROLL_IDLE_MS);\n\n this.addEventListener(\n 'scroll',\n () => {\n clearTimeout(id);\n id = setTimeout(resolve, SCROLL_IDLE_MS);\n },\n { passive: true, signal }\n );\n\n signal.addEventListener('abort', () => clearTimeout(id), { once: true });\n });\n }\n\n private _timeout(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const id = setTimeout(resolve, ms);\n signal.addEventListener('abort', () => clearTimeout(id), { once: true });\n });\n }\n\n private _measureViewport(): void {\n this._viewportSize = this._isVertical\n ? this.clientHeight\n : this.clientWidth;\n }\n\n /**\n * Records the new scroll offset. Schedules a render only if the rendered\n * window moves.\n *\n * @remarks\n * `render` reads `_currentRange`, not the scroll offset. Without the guard,\n * a scroll inside one item runs each item template again for the same\n * result. `willUpdate` recomputes `_currentRange` for the other triggers,\n * so this skips only the redundant passes.\n */\n private _handleScroll(): void {\n this._scrollPosition = this._currentAxisScroll();\n\n const { startIndex, endIndex } = this._computeRange();\n if (\n startIndex !== this._currentRange.startIndex ||\n endIndex !== this._currentRange.endIndex\n ) {\n this.requestUpdate();\n }\n }\n\n /**\n * The length of the prefix that a `data` change keeps: the first index at\n * which the old and the new items differ, or the length of the shorter array\n * if neither differs. Measurements below that index stay valid. An append\n * keeps all the previous items. A filter or a replacement keeps fewer.\n *\n * @remarks\n * The test is item identity. An item that changes in place keeps its\n * measured size.\n */\n private _firstChangedIndex(previous: T[] | undefined): number {\n if (!previous) {\n return 0;\n }\n\n const items = this._items;\n const shared = Math.min(previous.length, items.length);\n for (let i = 0; i < shared; i++) {\n if (previous[i] !== items[i]) {\n return i;\n }\n }\n return shared;\n }\n\n private _handleItemResize(entries: ResizeObserverEntry[]): void {\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n const index = asNumber(el.dataset.vsIndex, -1);\n if (index < 0) continue;\n\n const measured = this._isVertical\n ? (entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height)\n : (entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width);\n\n if (measured > 0) {\n this._engine.measureItem(index, measured);\n }\n }\n\n this._engine.adaptEstimate(this._currentRange.startIndex);\n }\n\n /**\n * Syncs the item observer with the rendered window, and applies only the\n * difference.\n *\n * @remarks\n * `observe` on an already observed element does nothing, so a new\n * measurement needs `unobserve` and then `observe`. Do this for each element\n * whose `data-vs-index` changed. The wrapper elements are recycled, so after\n * a scroll one element can hold a different item at the same size. The\n * observer does not report that, and the new index keeps its estimated size.\n */\n private _scheduleItemMeasurement(): void {\n const content = this._contentRef.value;\n if (!content) return;\n\n const observed = this._itemResizeController.targets;\n\n for (const element of observed) {\n if (element.parentNode !== content) {\n this._itemResizeController.unobserve(element);\n }\n }\n\n for (const element of content.children) {\n const index = asNumber((element as HTMLElement).dataset.vsIndex, -1);\n const isObserved = observed.has(element);\n\n if (isObserved && this._observedItemIndexes.get(element) === index) {\n continue;\n }\n\n if (isObserved) {\n this._itemResizeController.unobserve(element);\n }\n this._itemResizeController.observe(element);\n this._observedItemIndexes.set(element, index);\n }\n }\n\n /**\n * Emits `igcStateChange`. Does nothing if the window is empty or equal to\n * the last reported one, because a measurement pass renders again with no\n * window change.\n */\n private _emitStateChange(): void {\n const { startIndex, endIndex } = this._currentRange;\n if (endIndex < startIndex) return;\n\n const previous = this._lastEmittedState;\n const detail: VirtualScrollState = {\n startIndex,\n endIndex,\n viewportSize: this._viewportSize,\n totalSize: this._engine.totalSize,\n };\n\n if (\n previous &&\n previous.startIndex === detail.startIndex &&\n previous.endIndex === detail.endIndex &&\n previous.viewportSize === detail.viewportSize &&\n previous.totalSize === detail.totalSize\n ) {\n return;\n }\n\n this._lastEmittedState = { ...detail };\n this.emitEvent('igcStateChange', { detail });\n }\n\n private _checkDataRequest(): void {\n if (this._hasPendingDataRequest) return;\n\n const range = this._currentRange;\n const total = this._items.length;\n\n if (total === 0 || range.endIndex < total - REMOTE_SCROLLING_THRESHOLD) {\n return;\n }\n\n // Each `data` change clears `_hasPendingDataRequest`, also one that\n // appends nothing. Without this second guard, a consumer whose source is\n // exhausted and that assigns `data` again for each request gets that same\n // request again.\n if (this._lastDataRequestIndex === total) {\n return;\n }\n\n this._hasPendingDataRequest = true;\n this._lastDataRequestIndex = total;\n\n this.emitEvent('igcDataRequest', {\n detail: {\n startIndex: total,\n count: Math.max(this._normalizedOverScan * 4, 20),\n },\n });\n }\n\n /**\n * Resolves on the next animation frame, or after `LAYOUT_FRAME_TIMEOUT_MS` if\n * no frame arrives. A hidden tab or a disconnected element gets no frames,\n * and `layoutComplete` must still settle. Such a state has no layout to wait\n * for, so an early resolve is safe.\n */\n private _nextFrame(): Promise<void> {\n return this._withDeadline(\n LAYOUT_FRAME_TIMEOUT_MS,\n (signal) =>\n new Promise((resolve) => {\n const id = requestAnimationFrame(() => resolve());\n signal.addEventListener('abort', () => cancelAnimationFrame(id), {\n once: true,\n });\n })\n );\n }\n\n /**\n * Waits for the current update, then lets the ResizeObserver measurements\n * run. If those schedule one more render, for example when a measured size\n * replaces an estimate, the wait repeats until nothing is pending, up to a\n * safety cap.\n */\n private async _resolveLayoutComplete(): Promise<void> {\n try {\n await this.updateComplete;\n\n for (let i = 0; i < MAX_LAYOUT_SETTLE_PASSES; i++) {\n await this._nextFrame();\n\n if (!this.isUpdatePending) {\n break;\n }\n\n await this.updateComplete;\n }\n } finally {\n // Cleared here, not after the loop, so a run that throws cannot leave\n // the getter with a permanently rejected promise.\n this._layoutCompletePromise = null;\n }\n }\n\n //#endregion\n\n //#region Public API\n\n /* blazorSuppress */\n /**\n * Resolves when the virtual scroll has settled: the current render pass is\n * complete, the item-size measurements it triggers are complete, and so\n * are the renders those measurements schedule.\n *\n * `updateComplete` covers one Lit render pass. This covers `data` changes,\n * scrolls, and viewport resizes, where the stable DOM state comes after\n * one or more follow-up renders.\n */\n public get layoutComplete(): Promise<void> {\n if (!this._layoutCompletePromise) {\n this._layoutCompletePromise = this._resolveLayoutComplete();\n }\n return this._layoutCompletePromise;\n }\n\n /**\n * Scrolls to the specified item index.\n *\n * `block` (`inline` in the horizontal orientation) positions the item as in\n * `scrollIntoView`, and defaults to `start`. With `nearest`, the item\n * scrolls the smallest distance that brings it into view.\n *\n * Items outside the rendered window have only an estimated size, so the\n * first jump can miss the target. The items at the landing point are then\n * measured, and the scroll position is corrected. This repeats until the\n * offset is stable.\n *\n * The returned promise resolves when the scroll settles on the final,\n * corrected offset. Callers that need only the first, approximate scroll\n * can ignore it.\n */\n public async scrollToIndex(\n index: number,\n options?: ScrollIntoViewOptions\n ): Promise<void> {\n const maxIndex = Math.max(0, this._items.length - 1);\n const clampedIndex = clamp(index, 0, maxIndex);\n const behavior = options?.behavior ?? 'auto';\n\n // A newer call supersedes a correction loop that still runs for a\n // previous call, for example under rapid, repeated calls.\n const requestId = ++this._scrollRequestId;\n\n let offset = this._getAlignedScrollOffset(clampedIndex, options);\n await this._scrollAndWaitForEnd(offset, behavior);\n\n for (let i = 0; i < MAX_SCROLL_CORRECTION_PASSES; i++) {\n await this.layoutComplete;\n\n if (requestId !== this._scrollRequestId) {\n return;\n }\n\n const corrected = this._getAlignedScrollOffset(clampedIndex, options);\n if (Math.abs(corrected - offset) < SCROLL_OFFSET_EPSILON_PX) {\n break;\n }\n\n offset = corrected;\n await this._scrollAndWaitForEnd(offset, 'auto');\n\n if (requestId !== this._scrollRequestId) {\n return;\n }\n }\n }\n\n //#endregion\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'igc-virtual-scroll': IgcVirtualScrollComponent;\n }\n}\n"]}
|