@aceshooting/lyra-ui 17.0.0 → 18.0.0

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +254 -0
  2. package/README.md +2 -2
  3. package/custom-elements.json +1 -1
  4. package/dist/cli/migration-contract.json +1 -1
  5. package/dist/components/conversation/streaming-text/streaming-text-core.class.d.ts +22 -0
  6. package/dist/components/conversation/streaming-text/streaming-text-core.class.js +1 -0
  7. package/dist/components/conversation/streaming-text/streaming-text.class.d.ts +22 -0
  8. package/dist/components/conversation/streaming-text/streaming-text.class.js +1 -0
  9. package/dist/components/conversation/thread-list/thread-list.class.js +1 -1
  10. package/dist/components/data/table/table.styles.js +1 -1
  11. package/dist/components/forms/combobox/combobox.class.d.ts +12 -2
  12. package/dist/components/forms/combobox/combobox.class.js +2 -2
  13. package/dist/components/forms/combobox/combobox.styles.js +1 -1
  14. package/dist/components/forms/select/select.class.d.ts +31 -5
  15. package/dist/components/forms/select/select.class.js +2 -2
  16. package/dist/components/layout/filter-bar/filter-bar.class.d.ts +68 -6
  17. package/dist/components/layout/filter-bar/filter-bar.class.js +2 -2
  18. package/dist/components/layout/reorder-list/reorder-list.class.js +1 -1
  19. package/dist/components/layout/virtual-list/virtual-list.class.d.ts +107 -2
  20. package/dist/components/layout/virtual-list/virtual-list.class.js +12 -7
  21. package/dist/components/media/map/map.class.d.ts +138 -12
  22. package/dist/components/media/map/map.class.js +25 -20
  23. package/dist/components/media/map/map.styles.js +1 -1
  24. package/dist/custom-elements-jsx.d.ts +1 -1
  25. package/dist/events.d.ts +7 -1
  26. package/dist/internal/package-metadata.d.ts +1 -1
  27. package/dist/internal/package-metadata.js +1 -1
  28. package/dist/lyra.d.ts +1 -1
  29. package/dist/lyra.js +1 -1
  30. package/dist/svelte.d.ts +1 -1
  31. package/dist/testing/lyra-tag-event-map.js +1 -1
  32. package/dist/translations/ar/retrieval.js +1 -1
  33. package/dist/translations/ar/shared.js +1 -1
  34. package/dist/translations/de/retrieval.js +1 -1
  35. package/dist/translations/de/shared.js +1 -1
  36. package/dist/translations/es/retrieval.js +1 -1
  37. package/dist/translations/es/shared.js +1 -1
  38. package/dist/translations/fa/retrieval.js +1 -1
  39. package/dist/translations/fa/shared.js +1 -1
  40. package/dist/translations/fr/retrieval.js +1 -1
  41. package/dist/translations/fr/shared.js +1 -1
  42. package/dist/translations/he/retrieval.js +1 -1
  43. package/dist/translations/he/shared.js +1 -1
  44. package/dist/translations/it/retrieval.js +1 -1
  45. package/dist/translations/it/shared.js +1 -1
  46. package/dist/translations/ja/retrieval.js +1 -1
  47. package/dist/translations/ja/shared.js +1 -1
  48. package/dist/translations/pt-BR/retrieval.js +1 -1
  49. package/dist/translations/pt-BR/shared.js +1 -1
  50. package/dist/translations/ro/agent-tools.d.ts +1 -0
  51. package/dist/translations/ro/agent-tools.js +1 -0
  52. package/dist/translations/ro/charts.d.ts +1 -0
  53. package/dist/translations/ro/charts.js +1 -0
  54. package/dist/translations/ro/conversation.d.ts +1 -0
  55. package/dist/translations/ro/conversation.js +1 -0
  56. package/dist/translations/ro/data.d.ts +1 -0
  57. package/dist/translations/ro/data.js +1 -0
  58. package/dist/translations/ro/forms.d.ts +1 -0
  59. package/dist/translations/ro/forms.js +1 -0
  60. package/dist/translations/ro/layout.d.ts +1 -0
  61. package/dist/translations/ro/layout.js +1 -0
  62. package/dist/translations/ro/media.d.ts +1 -0
  63. package/dist/translations/ro/media.js +1 -0
  64. package/dist/translations/ro/overlays.d.ts +1 -0
  65. package/dist/translations/ro/overlays.js +1 -0
  66. package/dist/translations/ro/retrieval.d.ts +1 -0
  67. package/dist/translations/ro/retrieval.js +1 -0
  68. package/dist/translations/ro/shared.d.ts +1 -0
  69. package/dist/translations/ro/shared.js +1 -0
  70. package/dist/translations/ro/utility.d.ts +1 -0
  71. package/dist/translations/ro/utility.js +1 -0
  72. package/dist/translations/ro/viewers.d.ts +1 -0
  73. package/dist/translations/ro/viewers.js +5 -0
  74. package/dist/translations/ro.d.ts +1 -0
  75. package/dist/translations/ro.js +1 -0
  76. package/dist/translations/ru/retrieval.js +1 -1
  77. package/dist/translations/ru/shared.js +1 -1
  78. package/dist/translations/zh-CN/retrieval.js +1 -1
  79. package/dist/translations/zh-CN/shared.js +1 -1
  80. package/dist/vue.d.ts +1 -1
  81. package/llms/components/lr-button.md +5 -4
  82. package/llms/components/lr-card.md +2 -1
  83. package/llms/components/lr-combobox.md +7 -0
  84. package/llms/components/lr-filter-bar.md +86 -3
  85. package/llms/components/lr-icon-button.md +2 -1
  86. package/llms/components/lr-map.md +63 -6
  87. package/llms/components/lr-option.md +7 -0
  88. package/llms/components/lr-select.md +19 -2
  89. package/llms/components/lr-streaming-text-core.md +7 -3
  90. package/llms/components/lr-streaming-text.md +7 -2
  91. package/llms/components/lr-virtual-list.md +53 -0
  92. package/llms/shared.md +6 -3
  93. package/llms-full.txt +273 -22
  94. package/package.json +28 -2
  95. package/registrations.json +1 -1
  96. package/vscode-css-data.json +1 -1
  97. package/vscode-html-data.json +1 -1
  98. package/web-types.json +1 -1
@@ -9,6 +9,28 @@ export interface LyraVirtualListGroup{key:string|number;label?:string;startIndex
9
9
  /** The ARIA role pairing each rendered row participates in -- see `itemRole`'s own doc for what
10
10
  * each value maps to. */
11
11
  export type LyraVirtualListItemRole='listitem'|'row';
12
+ /**
13
+ * Where `renderItem`'s output is instantiated.
14
+ *
15
+ * - `'shadow'` (the default) stamps it inside this component's shadow root, where only inherited
16
+ * custom properties and an explicitly exported part reach it.
17
+ * - `'light'` stamps it into the HOST'S OWN light DOM, assigned back into the windowed row wrapper
18
+ * through an internal named slot, so an ordinary document stylesheet styles a virtualized row.
19
+ * Windowing, measurement, spacer sizing, `scrollToIndex()`, the external-scroller mode and the
20
+ * ARIA contract all stay with this component either way.
21
+ */
22
+ export type LyraVirtualListRowProjection='shadow'|'light';
23
+ /**
24
+ * Reserved attribute marking a light-DOM row wrapper this component created in
25
+ * `row-projection="light"` mode, so consumer CSS, DOM diffing and snapshot tests can recognise a
26
+ * library-owned light-DOM node. `::part()` cannot address one -- a projected row is in the
27
+ * document's tree, not a shadow tree -- so this replaces `closest('[part="row"]')` for a delegated
28
+ * listener in that mode. Built through `tag()`, exactly like `ANNOUNCEMENT_SINK_ATTRIBUTE`.
29
+ */
30
+ export declare const VIRTUAL_LIST_ROW_ATTRIBUTE:string;
31
+ /** Reserved attribute marking the projected sticky-band wrapper. Same rationale as
32
+ * {@linkcode VIRTUAL_LIST_ROW_ATTRIBUTE}. */
33
+ export declare const VIRTUAL_LIST_STICKY_ATTRIBUTE:string;
12
34
  /** A fixed positive pixel height, or live per-row measurement. */
13
35
  export type LyraVirtualListRowHeight=number|'auto';type VirtualListKey=string|number;
14
36
  /** A random-access collection that does not have to materialize one JavaScript value per row. */
@@ -280,6 +302,12 @@ rowHeight:LyraVirtualListRowHeight;
280
302
  * `aria-rowindex` instead -- for a consumer composing a virtualized `role="table"` (see
281
303
  * `<lr-dataset-viewer>`). */
282
304
  itemRole:LyraVirtualListItemRole;
305
+ /** Where `renderItem`'s output is instantiated: `'shadow'` (the default) inside this component's
306
+ * shadow root, or `'light'` as a child of the host itself so ordinary document CSS reaches it.
307
+ * See the class doc's "Light-DOM row projection" section for the full contract. Unsupported
308
+ * attribute values and untyped property writes normalize back to `'shadow'`; the property is
309
+ * deliberately not reflected, matching `itemRole`. */
310
+ private _rowProjection;get rowProjection():LyraVirtualListRowProjection;set rowProjection(next:LyraVirtualListRowProjection);
283
311
  /** Added to a row's 1-based index to compute `aria-rowindex` in `item-role="row"` mode (e.g. `1`
284
312
  * when a consumer renders its own header row occupying `aria-rowindex="1"` outside this
285
313
  * component). No effect in `'listitem'` mode. */
@@ -367,6 +395,18 @@ get scrollContainer():HTMLElement|undefined;
367
395
  * update.
368
396
  */
369
397
  get renderedRows():HTMLElement[];
398
+ /**
399
+ * The projected light-DOM row wrappers (`[data-lr-virtual-list-row]`) that currently exist as
400
+ * direct children of this host, in item order — the `row-projection="light"` counterpart of
401
+ * {@linkcode renderedRows}, and always empty in the default `'shadow'` mode.
402
+ *
403
+ * Each one pairs 1:1 with the `[part="row"]` wrapper it is slotted into and mirrors that
404
+ * wrapper's `data-row-index`/`data-row-key`. Only direct children are considered, so a nested
405
+ * `<lr-virtual-list>` inside a projected row never contributes its own rows here. Treat the
406
+ * returned elements as read-only: their lifetime belongs to the windowing math, and any of them
407
+ * can be recycled or removed on the next update.
408
+ */
409
+ get projectedRows():HTMLElement[];
370
410
  /** The configured external scroller once it is usable, or `undefined` whenever this component
371
411
  * scrolls its own `[part="base"]` viewport. See `scrollElement` for why a non-`Element`,
372
412
  * non-`Window` assignment resolves to "no external scroller" instead of throwing. */
@@ -433,7 +473,29 @@ private offsetsDirty;
433
473
  * just `rowHeight`/`keyFunction`/a measurement) -- consumed by the next
434
474
  * `recomputeOffsets()` call to prune `measuredHeights` entries for keys
435
475
  * no longer present in `items`. */
436
- private itemsChangedPendingPrune;private renderStart;private renderEnd;private visibleStart;private visibleEnd;private lastEmittedStart;private lastEmittedEnd;
476
+ private itemsChangedPendingPrune;private renderStart;private renderEnd;
477
+ /** The window the most recent shadow `render()` emitted, with each row's identity already
478
+ * resolved. `row-projection="light"` renders the SAME array, keyed by the SAME identity, so the
479
+ * two sides can never disagree about which rows exist or what they are called. */
480
+ private renderedWindow;
481
+ /** Trailing comment bounding the light-DOM render part; also where lit-html caches that part. */
482
+ private projectionAnchor?;private projectionPart?;
483
+ /**
484
+ * True until the first render is safely past. A server render can never produce projected rows --
485
+ * `@lit-labs/ssr` calls `connectedCallback()`, `willUpdate()` and `render()`, never
486
+ * `update()`/`updated()`, and there is no DOM to render into -- so activating projection
487
+ * unconditionally would serialize this component's bounded deterministic first window EMPTY and
488
+ * make the browser's first render disagree with the markup it is hydrating.
489
+ *
490
+ * Released through `seedFirstRenderState()`, the same helper `renderUnmeasuredWindow` uses: a
491
+ * browser-only mount clears it synchronously inside `connectedCallback()` (so the very first
492
+ * render is already projected, with no flash and no extra update), while a hydrating mount keeps
493
+ * the server's shadow-rendered window for exactly its first render and swaps into the light DOM
494
+ * one task later.
495
+ */
496
+ private projectionDeferred;
497
+ /** Stable reference so `seedFirstRenderState()`'s pending set dedupes the re-arm below. */
498
+ private readonly releaseRowProjection;private visibleStart;private visibleEnd;private lastEmittedStart;private lastEmittedEnd;
437
499
  /** Re-armed whenever the window moves away from the end of `items` -- see the `lr-load-more` event doc. */
438
500
  private loadMoreArmed;
439
501
  /** Identity- and source-bound correction transaction for estimate-based programmatic scrolling. */
@@ -553,7 +615,50 @@ private get stickyInset();private scrollActiveIntoView;
553
615
  * and key function, and is canceled by replacement data, a new target, manual scroll intent, or
554
616
  * disconnect, so a late observation can never drag a newer view back to a stale row.
555
617
  */
556
- scrollToIndex(index:number,options?:{align?:'start'|'end'|'auto';behavior?:'auto'|'smooth';}):void;private hasUnmeasuredGroupThrough;private beginPendingScrollCorrection;private performScrollTo;private maybeCorrectPendingScroll;private emitRangeChangeIfNeeded;private maybeFireLoadMore;private renderRow;
618
+ scrollToIndex(index:number,options?:{align?:'start'|'end'|'auto';behavior?:'auto'|'smooth';}):void;private hasUnmeasuredGroupThrough;private beginPendingScrollCorrection;private performScrollTo;private maybeCorrectPendingScroll;private emitRangeChangeIfNeeded;private maybeFireLoadMore;
619
+ /** True whenever `renderItem`'s output belongs in the host's light DOM for THIS render. */
620
+ private get projectionActive();
621
+ /** The internal slot name pairing one shadow row wrapper with its projected light-DOM row.
622
+ * Keyed by the component's own row identity -- already the `repeat()` key on both sides -- so a
623
+ * scroll or a reorder moves rows without rewriting a single `slot`/`name` attribute. Slot
624
+ * matching is exact whole-value string comparison, so an identity containing a space or a colon
625
+ * still pairs correctly, and the name is never empty so it can never collide with a default
626
+ * slot (of which this component renders none). */
627
+ private rowSlotName;
628
+ /**
629
+ * Mounts, updates or tears down the light-DOM render root that holds `renderItem`'s output in
630
+ * `row-projection="light"` mode.
631
+ *
632
+ * The container is the HOST ITSELF — a slottable must be a direct child of the host — bounded by
633
+ * a trailing comment anchor, so the part only ever owns `[startMarker … anchor)`. Anything a
634
+ * consumer appends to this element later lands after the anchor and is never cleared by a
635
+ * re-render, which is also what keeps a server-rendered light child alive across hydration.
636
+ * `host: this` matches `ReactiveElement`'s own render options, so a `renderItem` template whose
637
+ * event binding is a method reference gets the same `this` it gets in shadow mode.
638
+ */
639
+ private syncRowProjection;private ensureProjectionAnchor;
640
+ /**
641
+ * Removes the projection completely, using public API only: `render(nothing, …)` so lit-html
642
+ * detaches its own child parts and their directives, then the part's start marker, then the
643
+ * anchor. Discarding the anchor discards lit's cached root part with it (the cache lives on the
644
+ * `renderBefore` node), so no private-field poking is ever required and a later re-projection
645
+ * starts from a genuinely fresh part.
646
+ *
647
+ * After this the host's light DOM holds exactly what the consumer put there: no rows, no lit
648
+ * markers, no anchor. The accepted cost is that per-row DOM state inside a projected row does not
649
+ * survive a disconnect/reconnect; scroll position, measurements and the window are unaffected,
650
+ * because they live in component state rather than in the rows.
651
+ */
652
+ private teardownRowProjection;
653
+ /**
654
+ * One light-DOM wrapper per windowed row, over the same array and keyed by the same identity the
655
+ * shadow window used. The wrapper carries no `part` (a `part` attribute outside a shadow tree is
656
+ * inert), no `role` and no inline positioning — the `[part="row"]` wrapper it is slotted into
657
+ * keeps sole ownership of absolute positioning, the per-frame transform and every ARIA
658
+ * attribute, so consumer CSS cannot break windowing. `data-row-index`/`data-row-key` are mirrored
659
+ * so document CSS and delegated listeners can still address a specific row.
660
+ */
661
+ private renderProjectedRows;private renderRow;
557
662
  /** Normalizes group definitions only when their inputs change. */
558
663
  private recomputeGroups;private renderGroups;
559
664
  /** The group the viewport is currently inside -- the last one whose first row's offset is at or
@@ -1,4 +1,9 @@
1
- var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing}from"lit";import{property,state}from"lit/decorators.js";import{repeat}from"lit/directives/repeat.js";import{styleMap}from"lit/directives/style-map.js";import{LyraElement}from"../../../internal/lyra-element.js";import{prefersReducedMotion}from"../../../internal/motion.js";import{finiteAdd,finiteCount,finiteInteger,finiteNumber}from"../../../internal/numbers.js";import{getNumberFormat}from"../../../internal/intl-cache.js";import{getOwnDataDescriptor,MISSING_OWN_DATA_DESCRIPTOR,UNSAFE_OWN_DATA_DESCRIPTOR}from"../../../internal/data-descriptors.js";import{styles}from"./virtual-list.styles.js";const DEFAULT_ROW_ESTIMATE_PX=48,DEFAULT_GROUP_ESTIMATE_PX=32,DEFAULT_OVERSCAN_ROWS=6,MAX_OVERSCAN_ROWS=100,MAX_VIRTUAL_LIST_GROUPS=1e4,EMPTY_VIRTUAL_LIST_GROUPS=Object.freeze([]);function normalizeOverscan(value){if(value===null)return DEFAULT_OVERSCAN_ROWS;const numeric=typeof value=="number"?value:Number(value);return Number.isFinite(numeric)?Math.min(MAX_OVERSCAN_ROWS,Math.max(0,Math.floor(numeric))):DEFAULT_OVERSCAN_ROWS}const overscanConverter={fromAttribute(value){return normalizeOverscan(value)}};function virtualListGroupsChanged(value,oldValue){if(value===oldValue)return!1;const next=value,previous=oldValue;if(next==null||previous==null)return next!==previous;if(next.length!==previous.length)return!0;for(let index=0;index<next.length;index+=1){const a=next[index],b=previous[index];if(a.key!==b.key||a.label!==b.label||a.startIndex!==b.startIndex)return!0}return!1}function normalizeRowHeight(value){if(value==="auto")return"auto";const numeric=typeof value=="number"?value:Number(value);return Number.isFinite(numeric)&&numeric>0?numeric:"auto"}const rowHeightConverter={fromAttribute(value){return value===null?"auto":normalizeRowHeight(value)}};function isIndexedSource(source){return!Array.isArray(source)}const ELEMENT_NODE_TYPE=1;function isWindowScroller(target){return target.window===target}function domKeyToken(key){if(typeof key=="number"){if(Number.isNaN(key))return"number:NaN";if(Object.is(key,-0))return"number:-0"}return`${typeof key}:${String(key)}`}class LyraVirtualList extends LyraElement{constructor(){super(...arguments),this.items=[],this.renderItem=()=>nothing,this.rowHeight="auto",this.itemRole="listitem",this.rowIndexOffset=0,this.overscan=DEFAULT_OVERSCAN_ROWS,this.activeItemId="",this.loading=!1,this.hasMore=!1,this.containerScrollTop=0,this.viewportHeight=0,this.renderUnmeasuredWindow=!0,this.offsets=[0],this.rowIdentities=[],this.fixedRowHeight=null,this.measuredHeights=new Map,this.measuredIndices=new Map,this.indexedMeasurementIndices=[],this.indexedMeasurementDeltaPrefix=[0],this.indexedMeasurementIndexDirty=!0,this.offsetsDirty=!0,this.itemsChangedPendingPrune=!1,this.renderStart=0,this.renderEnd=-1,this.visibleStart=0,this.visibleEnd=-1,this.lastEmittedStart=-1,this.lastEmittedEnd=-1,this.loadMoreArmed=!0,this.measurementGeneration=0,this.isFirstUpdate=!0,this.stickyHeight=0,this.observedRows=new Map,this.observedRowKeys=new WeakMap,this.observedRowIndices=new WeakMap,this.observedGroups=new Map,this.observedGroupIndices=new WeakMap,this.externalMetricsPending=!1,this.ownerRealmGeneration=0,this.inResizeDelivery=!1,this.deferredRowObservations=new Map,this.deferredGroupObservations=new Map,this.activeIndexForLength=-1,this.activeIndexForId="",this.activeIndexCache=-1,this.pendingScrollTop=null,this.normalizedGroups=EMPTY_VIRTUAL_LIST_GROUPS,this.normalizedGroupByIndex=new Map,this.measuredGroupHeights=new Map,this.groupHeightPrefix=[0],this.onExternalViewportResize=()=>{this.syncExternalScrollMetrics()},this.onUserScrollIntent=event=>{event instanceof KeyboardEvent&&!new Set(["ArrowUp","ArrowDown","PageUp","PageDown","Home","End"," "]).has(event.key)||(this.pendingScrollCorrection=void 0)},this.onScroll=e=>{if(this.externalScroller?(this.pendingScrollTop=null,this.externalMetricsPending=!0):this.pendingScrollTop=e.currentTarget.scrollTop,this.scrollRafId!==void 0)return;const ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView;if(!ownerWindow||!this.isConnected)return;const generation=this.ownerRealmGeneration,handle=ownerWindow.requestAnimationFrame(()=>{if(!(this.scrollRafId!==handle||this.scrollRafOwner!==ownerWindow||this.scrollRafDocument!==ownerDocument||!this.isCurrentOwnerWork(ownerDocument,generation))){if(this.scrollRafId=void 0,this.scrollRafOwner=void 0,this.scrollRafDocument=void 0,this.externalMetricsPending){this.externalMetricsPending=!1;const metrics=this.readScrollMetrics();metrics&&(this.pendingScrollTop=metrics.scrollTop,this.viewportHeight!==metrics.viewportHeight&&(this.viewportHeight=metrics.viewportHeight))}if(this.pendingScrollTop!==null){const scrollTop=this.pendingScrollTop;this.pendingScrollTop=null;const moved=this.containerScrollTop!==scrollTop;this.containerScrollTop=scrollTop,moved&&this.emit("lr-virtual-scroll",{scrollTop,viewportHeight:this.viewportHeight})}}});this.scrollRafId=handle,this.scrollRafOwner=ownerWindow,this.scrollRafDocument=ownerDocument},this.onRowsResized=entries=>{if(this.beginResizeDelivery(),this.fixedRowHeight!=null)return;const base=this.scrollContainer,oldScrollTop=this.readScrollMetrics()?.rawScrollTop??this.containerScrollTop;let scrollAdjustment=0,changed=!1;for(const entry of entries){const row=entry.target,key=this.observedRowKeys.get(row),index=this.observedRowIndices.get(row);if(key===void 0||index===void 0)continue;const height=entry.borderBoxSize?.[0]?.blockSize??entry.target.getBoundingClientRect().height,prev=this.measuredHeights.get(key);if(prev===void 0||Math.abs(prev-height)>.5){const oldBottom=this.rowBottomAt(index);this.measuredHeights.set(key,height),this.measuredIndices.set(key,index);const oldHeight=prev??DEFAULT_ROW_ESTIMATE_PX;oldBottom<=oldScrollTop&&(scrollAdjustment+=height-oldHeight),changed=!0}}if(changed){if(this.indexedMeasurementIndexDirty=!0,base&&scrollAdjustment!==0){const nextScrollTop=oldScrollTop+scrollAdjustment;this.applyScrollPosition(nextScrollTop),this.containerScrollTop=Math.max(0,nextScrollTop),this.pendingScrollTop=null}this.offsetsDirty=!0,this.measurementGeneration+=1,this.requestUpdate()}},this.onGroupsResized=entries=>{this.beginResizeDelivery();const base=this.scrollContainer,oldScrollTop=this.readScrollMetrics()?.rawScrollTop??this.containerScrollTop;let scrollAdjustment=0,changed=!1;for(const entry of entries){const marker=entry.target,index=this.observedGroupIndices.get(marker);if(index===void 0||!this.normalizedGroupByIndex.has(index))continue;const height=entry.borderBoxSize?.[0]?.blockSize??entry.target.getBoundingClientRect().height;if(!Number.isFinite(height)||height<0)continue;const previous=this.measuredGroupHeights.get(index)??DEFAULT_GROUP_ESTIMATE_PX;if(Math.abs(previous-height)<=.5)continue;const oldRowTop=this.offsetAt(index);this.measuredGroupHeights.set(index,height),oldRowTop<=oldScrollTop&&(scrollAdjustment+=height-previous),changed=!0}if(changed){if(base&&scrollAdjustment!==0){const nextScrollTop=oldScrollTop+scrollAdjustment;this.applyScrollPosition(nextScrollTop),this.containerScrollTop=Math.max(0,nextScrollTop),this.pendingScrollTop=null}this.offsetsDirty=!0,this.measurementGeneration+=1,this.requestUpdate()}},this.onStickyResized=entries=>{this.beginResizeDelivery();const entry=entries[0];if(!entry)return;const height=entry.borderBoxSize?.[0]?.blockSize??entry.contentRect.height;Math.abs(this.stickyHeight-height)>.5&&(this.stickyHeight=height)}}static{this.ownedCollectionProperties=Object.freeze(["items","source","groups"])}static{this.identityCollectionProperties=Object.freeze(["items","source"])}static{this.identityCollectionObjectProperties=Object.freeze(["source"])}static{this.styles=[LyraElement.styles,styles]}get scrollContainer(){return this.renderRoot?.querySelector('[part="base"]')??void 0}get renderedRows(){const root=this.renderRoot;return root?[...root.querySelectorAll('[part="row"]')]:[]}get externalScroller(){const target=this.scrollElement;if(target!=null)return isWindowScroller(target)||target.nodeType===ELEMENT_NODE_TYPE?target:void 0}get spacerElement(){return this.renderRoot?.querySelector('[part="spacer"]')??void 0}readScrollMetrics(){const base=this.scrollContainer;if(!base)return null;const external=this.externalScroller;if(!external)return{scrollTop:base.scrollTop,rawScrollTop:base.scrollTop,viewportHeight:base.clientHeight};const spacerTop=(this.spacerElement??base).getBoundingClientRect().top;if(isWindowScroller(external)){const documentHeight=finiteNumber(external.document?.documentElement?.clientHeight??0,0),rawScrollTop2=finiteNumber(-spacerTop,0);return{scrollTop:Math.max(0,rawScrollTop2),rawScrollTop:rawScrollTop2,viewportHeight:documentHeight>0?documentHeight:finiteNumber(external.innerHeight,0)}}const scrollerTop=external.getBoundingClientRect().top,rawScrollTop=finiteNumber(scrollerTop-spacerTop,0);return{scrollTop:Math.max(0,rawScrollTop),rawScrollTop,viewportHeight:finiteNumber(external.clientHeight,0)}}applyScrollPosition(top,behavior){const external=this.externalScroller;if(!external){const base=this.scrollContainer;if(!base)return;const next2=Math.max(0,finiteNumber(top,0));behavior===void 0?base.scrollTop=next2:base.scrollTo({top:next2,behavior});return}const metrics=this.readScrollMetrics();if(!metrics)return;const delta=finiteNumber(top,metrics.rawScrollTop)-metrics.rawScrollTop;if(isWindowScroller(external)){const options={top:Math.max(0,finiteNumber(external.scrollY+delta,0))};behavior!==void 0&&(options.behavior=behavior),external.scrollTo(options);return}const next=Math.max(0,finiteNumber(external.scrollTop+delta,0));behavior===void 0?external.scrollTop=next:external.scrollTo({top:next,behavior})}syncExternalScrollMetrics(){const metrics=this.readScrollMetrics();metrics&&(this.viewportHeight!==metrics.viewportHeight&&(this.viewportHeight=metrics.viewportHeight),this.containerScrollTop!==metrics.scrollTop&&(this.containerScrollTop=metrics.scrollTop))}get safeRowIndexOffset(){return finiteCount(this.rowIndexOffset)}computedAriaRowIndex(index){return finiteInteger(finiteAdd(index+1,this.safeRowIndexOffset),1,1,Number.MAX_SAFE_INTEGER)}get activeIndex(){if(this.activeItemId==="")return-1;const source=this.effectiveSource,count=this.itemCount;if(this.activeIndexFor===source&&this.activeIndexForLength===count&&Object.is(this.activeIndexForId,this.activeItemId)&&this.activeIndexForKeyFn===this.keyFunction)return this.activeIndexCache;if(this.activeIndexFor=source,this.activeIndexForLength=count,this.activeIndexForId=this.activeItemId,this.activeIndexForKeyFn=this.keyFunction,this.activeIndexCache=-1,isIndexedSource(source)){if(!this.keyFunction&&source.indexOfKey){const candidate=source.indexOfKey(this.activeItemId);Number.isInteger(candidate)&&candidate>=0&&candidate<count&&(this.activeIndexCache=candidate)}return this.activeIndexCache}for(let index=0;index<count;index++){const item=this.itemAt(index);if(Object.is(this.keyOf(item,index),this.activeItemId)){this.activeIndexCache=index;break}}return this.activeIndexCache}connectedCallback(){super.connectedCallback(),this.ownerDocument.defaultView&&this.seedFirstRenderState(()=>{this.renderUnmeasuredWindow=!1,this.requestUpdate()}),this.resetOwnerRealmWork();const ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView,generation=this.ownerRealmGeneration,ResizeObserverCtor=ownerWindow?.ResizeObserver;if(ResizeObserverCtor){const rowObserver=new ResizeObserverCtor(entries=>{this.rowResizeObserver!==rowObserver||!this.isCurrentOwnerWork(ownerDocument,generation)||this.onRowsResized(entries)}),groupObserver=new ResizeObserverCtor(entries=>{this.groupResizeObserver!==groupObserver||!this.isCurrentOwnerWork(ownerDocument,generation)||this.onGroupsResized(entries)}),stickyObserver=new ResizeObserverCtor(entries=>{this.stickyResizeObserver!==stickyObserver||!this.isCurrentOwnerWork(ownerDocument,generation)||this.onStickyResized(entries)});this.rowResizeObserver=rowObserver,this.groupResizeObserver=groupObserver,this.stickyResizeObserver=stickyObserver}this.hasUpdated&&(this.attachContainerListeners(),this.syncRowObservers(),this.syncGroupObservers(),this.syncStickyOverlay())}disconnectedCallback(){this.resetOwnerRealmWork(),super.disconnectedCallback()}adoptedCallback(){super.adoptedCallback(),this.resetOwnerRealmWork()}isCurrentOwnerWork(ownerDocument,generation){return this.ownerRealmGeneration===generation&&this.isConnected&&this.ownerDocument===ownerDocument}resetOwnerRealmWork(){this.ownerRealmGeneration+=1,this.rowResizeObserver?.disconnect(),this.rowResizeObserver=void 0,this.groupResizeObserver?.disconnect(),this.groupResizeObserver=void 0,this.observedRows.clear(),this.observedGroups.clear(),this.deferredRowObservations.clear(),this.deferredGroupObservations.clear(),this.inResizeDelivery=!1,this.rowObserveRafId!==void 0&&this.rowObserveRafOwner?.cancelAnimationFrame(this.rowObserveRafId),this.rowObserveRafId=void 0,this.rowObserveRafOwner=void 0,this.rowObserveRafDocument=void 0,this.containerResizeObserver?.disconnect(),this.containerResizeObserver=void 0,this.stickyResizeObserver?.disconnect(),this.stickyResizeObserver=void 0,this.observedSticky=void 0,this.scrollRafId!==void 0&&this.scrollRafOwner?.cancelAnimationFrame(this.scrollRafId),this.scrollRafId=void 0,this.scrollRafOwner=void 0,this.scrollRafDocument=void 0,this.pendingScrollTop=null,this.externalMetricsPending=!1,this.pendingScrollCorrection=void 0,this.detachContainerListeners(),this.scrollListenerTarget=void 0}firstUpdated(changed){super.firstUpdated(changed),this.attachContainerListeners()}willUpdate(changed){super.willUpdate(changed),this.isFirstUpdate=!this.hasUpdated,(changed.has("items")||changed.has("source")||changed.has("keyFunction")||changed.has("rowHeight")||changed.has("groups")||changed.has("activeItemId")||changed.has("scrollElement"))&&(this.pendingScrollCorrection=void 0),(changed.has("items")||changed.has("source")||changed.has("rowHeight")||changed.has("keyFunction")||changed.has("groups"))&&(this.offsetsDirty=!0),(changed.has("items")||changed.has("source"))&&(this.itemsChangedPendingPrune=!0),(changed.has("keyFunction")||isIndexedSource(this.effectiveSource)&&(changed.has("items")||changed.has("source")))&&(this.measuredHeights.clear(),this.measuredIndices.clear(),this.indexedMeasurementIndexDirty=!0),changed.has("groups")&&this.measuredGroupHeights.clear(),(changed.has("items")||changed.has("source")||changed.has("groups"))&&this.recomputeGroups(),changed.has("rowHeight")&&(this.fixedRowHeight=this.parseRowHeight(this.rowHeight),this.fixedRowHeight!=null&&(this.measuredHeights.clear(),this.measuredIndices.clear(),this.indexedMeasurementIndexDirty=!0)),this.offsetsDirty&&(this.recomputeOffsets(),this.offsetsDirty=!1),this.computeRange()}updated(changed){super.updated(changed),this.syncRowObservers(),this.syncGroupObservers(),this.syncStickyOverlay(),changed.has("scrollElement")&&!this.isFirstUpdate&&this.attachContainerListeners(),changed.has("activeItemId")&&!this.isFirstUpdate&&this.scrollActiveIntoView(),this.emitRangeChangeIfNeeded(),this.maybeFireLoadMore(),this.maybeCorrectPendingScroll()}parseRowHeight(value){const normalized=normalizeRowHeight(value);return normalized==="auto"?null:normalized}get effectiveSource(){return this.source??this.items}get itemCount(){const source=this.effectiveSource;return isIndexedSource(source)?finiteCount(source.count):source.length}itemAt(index){const source=this.effectiveSource;return isIndexedSource(source)?source.itemAt(index):source[index]}keyOf(item,index){const source=this.effectiveSource,key=this.keyFunction?this.keyFunction(item,index):isIndexedSource(source)?source.keyAt?.(index)??index:index;return typeof key=="string"||typeof key=="number"?key:index}rowIdentity(key,occurrence){const token=domKeyToken(key);return`${token.length}:${token}:${occurrence}`}identityAt(index,item=this.itemAt(index)){return isIndexedSource(this.effectiveSource)?this.rowIdentity(this.keyOf(item,index),index):this.rowIdentities[index]??this.rowIdentity(this.keyOf(item,index),index)}groupHeightAt(index){const group=this.normalizedGroupByIndex.get(index);return!group||group.label===""?0:this.measuredGroupHeights.get(index)??DEFAULT_GROUP_ESTIMATE_PX}rowHeightAt(index){return this.fixedRowHeight!=null?this.fixedRowHeight:this.measuredHeights.get(this.identityAt(index))??DEFAULT_ROW_ESTIMATE_PX}groupContributionThrough(index){let low=0,high=this.normalizedGroups.length;for(;low<high;){const middle=low+high>>1;this.normalizedGroups[middle].startIndex<=index?low=middle+1:high=middle}return this.groupHeightPrefix[low]??0}recomputeGroupHeightPrefix(){const prefix=new Array(this.normalizedGroups.length+1);prefix[0]=0;for(let index=0;index<this.normalizedGroups.length;index++){const group=this.normalizedGroups[index],height=group.label===""?0:this.measuredGroupHeights.get(group.startIndex)??DEFAULT_GROUP_ESTIMATE_PX;prefix[index+1]=finiteAdd(prefix[index],height)}this.groupHeightPrefix=prefix}indexedOffsetForIndex(index){const baseHeight=this.fixedRowHeight??DEFAULT_ROW_ESTIMATE_PX;let offset=index>Number.MAX_VALUE/baseHeight?Number.MAX_VALUE:index*baseHeight;if(this.fixedRowHeight==null){this.rebuildIndexedMeasurementIndex();let low=0,high=this.indexedMeasurementIndices.length;for(;low<high;){const middle=low+high>>1;this.indexedMeasurementIndices[middle]<index?low=middle+1:high=middle}offset=finiteAdd(offset,this.indexedMeasurementDeltaPrefix[low]??0)}return Math.max(0,finiteAdd(offset,this.groupContributionThrough(index)))}rebuildIndexedMeasurementIndex(){if(!this.indexedMeasurementIndexDirty)return;const retained=[];for(const[identity,index]of this.measuredIndices){const height=this.measuredHeights.get(identity);height!==void 0&&retained.push({index,delta:height-DEFAULT_ROW_ESTIMATE_PX})}retained.sort((a,b)=>a.index-b.index);const indices=new Array(retained.length),prefix=new Array(retained.length+1);prefix[0]=0;for(let position=0;position<retained.length;position++){const measurement=retained[position];indices[position]=measurement.index,prefix[position+1]=finiteAdd(prefix[position],measurement.delta)}this.indexedMeasurementIndices=indices,this.indexedMeasurementDeltaPrefix=prefix,this.indexedMeasurementIndexDirty=!1}pruneIndexedMeasurements(){if(!isIndexedSource(this.effectiveSource)||this.fixedRowHeight!=null||this.renderEnd<this.renderStart)return!1;const renderedCount=this.renderEnd-this.renderStart+1,retentionRows=Math.max(renderedCount,normalizeOverscan(this.overscan)*4),firstRetained=Math.max(0,this.renderStart-retentionRows),lastRetained=Math.min(this.itemCount-1,this.renderEnd+retentionRows);let removedDeltaBeforeWindow=0,pruned=!1;for(const[identity,measuredIndex]of this.measuredIndices)if(measuredIndex<firstRetained||measuredIndex>lastRetained){const height=this.measuredHeights.get(identity);height!==void 0&&measuredIndex<firstRetained&&(removedDeltaBeforeWindow=finiteAdd(removedDeltaBeforeWindow,height-DEFAULT_ROW_ESTIMATE_PX)),this.measuredIndices.delete(identity),this.measuredHeights.delete(identity),pruned=!0}if(pruned&&(this.indexedMeasurementIndexDirty=!0,removedDeltaBeforeWindow!==0)){const nextScrollTop=(this.readScrollMetrics()?.rawScrollTop??this.containerScrollTop)-removedDeltaBeforeWindow;this.applyScrollPosition(nextScrollTop),this.containerScrollTop=Math.max(0,nextScrollTop),this.pendingScrollTop=null}return pruned}offsetAt(index){return isIndexedSource(this.effectiveSource)?this.indexedOffsetForIndex(index):this.offsets[index]??0}recomputeOffsets(){const n=this.itemCount;if(this.recomputeGroupHeightPrefix(),isIndexedSource(this.effectiveSource)){this.offsets=[0],this.rowIdentities=[],this.itemsChangedPendingPrune=!1;return}const offsets=new Array(n+1);let cursor=0;const liveKeys=this.itemsChangedPendingPrune&&this.fixedRowHeight==null?new Set:null,occurrences=new Map,identities=new Array(n);for(let i=0;i<n;i++){cursor=finiteAdd(cursor,this.groupHeightAt(i)),offsets[i]=cursor;const key=this.keyOf(this.itemAt(i),i),token=domKeyToken(key),occurrence=occurrences.get(token)??0;occurrences.set(token,occurrence+1);const identity=this.rowIdentity(key,occurrence);identities[i]=identity;let h;this.fixedRowHeight!=null?h=this.fixedRowHeight:(liveKeys?.add(identity),h=this.measuredHeights.get(identity)??DEFAULT_ROW_ESTIMATE_PX),cursor=finiteAdd(cursor,h)}if(offsets[n]=cursor,this.offsets=offsets,this.rowIdentities=identities,this.itemsChangedPendingPrune=!1,liveKeys){for(const key of this.measuredHeights.keys())liveKeys.has(key)||(this.measuredHeights.delete(key),this.measuredIndices.delete(key),this.indexedMeasurementIndexDirty=!0);for(const key of this.measuredIndices.keys())liveKeys.has(key)||(this.measuredIndices.delete(key),this.indexedMeasurementIndexDirty=!0)}}groupTopAt(index){return Math.max(0,this.offsetAt(index)-this.groupHeightAt(index))}rowBottomAt(index){return finiteAdd(this.offsetAt(index),this.rowHeightAt(index))}entryTopAt(index){return this.groupTopAt(index)}findIndexAtOrAfter(offset){let lo=0,hi=this.itemCount-1;for(;lo<hi;){const mid=lo+Math.floor((hi-lo)/2);this.rowBottomAt(mid)<=offset?lo=mid+1:hi=mid}return lo}findIndexAtOrBefore(offset){let lo=0,hi=this.itemCount-1;for(;lo<hi;){const mid=lo+Math.ceil((hi-lo)/2);this.entryTopAt(mid)<offset?lo=mid:hi=mid-1}return lo}offsetForIndex(index){const clamped=Math.min(this.itemCount,Math.max(0,Math.trunc(index)||0));return this.offsetAt(clamped)}indexAtOffset(px){const n=this.itemCount;return n===0?-1:Number.isFinite(px)?Math.min(n-1,Math.max(0,this.findIndexAtOrAfter(px))):px>0?n-1:0}computeRange(){const n=this.itemCount;if(n===0){this.visibleStart=0,this.visibleEnd=-1,this.renderStart=0,this.renderEnd=-1;return}if(this.viewportHeight<=0){if(!this.renderUnmeasuredWindow){this.visibleStart=0,this.visibleEnd=-1,this.renderStart=0,this.renderEnd=-1;return}this.visibleStart=0,this.visibleEnd=0,this.renderStart=0,this.renderEnd=Math.min(n-1,normalizeOverscan(this.overscan));return}const viewTop=this.containerScrollTop,viewBottom=viewTop+this.viewportHeight;this.visibleStart=this.findIndexAtOrAfter(viewTop),this.visibleEnd=this.findIndexAtOrBefore(viewBottom);const overscan=normalizeOverscan(this.overscan);this.renderStart=Math.max(0,this.visibleStart-overscan),this.renderEnd=Math.min(n-1,this.visibleEnd+overscan),this.pruneIndexedMeasurements()&&this.computeRange()}attachContainerListeners(){const base=this.scrollContainer,ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView;if(!base||!this.isConnected||!ownerWindow)return;this.containerResizeObserver?.disconnect(),this.containerResizeObserver=void 0,this.detachContainerListeners();const external=this.externalScroller,scrollTarget=external??base,generation=this.ownerRealmGeneration,ResizeObserverCtor=ownerWindow.ResizeObserver;if(ResizeObserverCtor){const observer=new ResizeObserverCtor(entries=>{if(this.containerResizeObserver!==observer||this.scrollListenerTarget!==scrollTarget||!this.isCurrentOwnerWork(ownerDocument,generation))return;if(this.beginResizeDelivery(),external){this.syncExternalScrollMetrics();return}const entry=entries[0];entry&&(this.viewportHeight=entry.borderBoxSize?.[0]?.blockSize??entry.contentRect.height)});this.containerResizeObserver=observer,observer.observe(base),external&&!isWindowScroller(external)&&observer.observe(external)}scrollTarget.addEventListener("scroll",this.onScroll,{passive:!0}),scrollTarget.addEventListener("wheel",this.onUserScrollIntent,{passive:!0}),scrollTarget.addEventListener("pointerdown",this.onUserScrollIntent,{passive:!0}),scrollTarget.addEventListener("touchstart",this.onUserScrollIntent,{passive:!0}),scrollTarget.addEventListener("keydown",this.onUserScrollIntent),this.scrollListenerTarget=scrollTarget,external&&isWindowScroller(external)&&(external.addEventListener("resize",this.onExternalViewportResize,{passive:!0}),this.viewportResizeTarget=external),ownerWindow.queueMicrotask(()=>{if(this.scrollListenerTarget!==scrollTarget||this.scrollContainer!==base||!this.isCurrentOwnerWork(ownerDocument,generation))return;const metrics=this.readScrollMetrics();metrics&&(this.viewportHeight!==metrics.viewportHeight&&(this.viewportHeight=metrics.viewportHeight),this.containerScrollTop!==metrics.scrollTop&&(this.containerScrollTop=metrics.scrollTop))})}detachContainerListeners(){const viewportTarget=this.viewportResizeTarget;viewportTarget&&(viewportTarget.removeEventListener("resize",this.onExternalViewportResize),this.viewportResizeTarget=void 0);const target=this.scrollListenerTarget;target&&(target.removeEventListener("scroll",this.onScroll),target.removeEventListener("wheel",this.onUserScrollIntent),target.removeEventListener("pointerdown",this.onUserScrollIntent),target.removeEventListener("touchstart",this.onUserScrollIntent),target.removeEventListener("keydown",this.onUserScrollIntent))}beginResizeDelivery(){if(this.inResizeDelivery=!0,this.rowObserveRafId!==void 0)return;const ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView;if(!ownerWindow||!this.isConnected){this.inResizeDelivery=!1;return}const generation=this.ownerRealmGeneration,handle=ownerWindow.requestAnimationFrame(()=>{if(this.rowObserveRafId!==handle||this.rowObserveRafOwner!==ownerWindow||this.rowObserveRafDocument!==ownerDocument||!this.isCurrentOwnerWork(ownerDocument,generation))return;this.rowObserveRafId=void 0,this.rowObserveRafOwner=void 0,this.rowObserveRafDocument=void 0,this.inResizeDelivery=!1;const ro=this.rowResizeObserver;for(const[identity,el]of this.deferredRowObservations)ro&&this.observedRows.get(identity)===el&&ro.observe(el);this.deferredRowObservations.clear();const groupObserver=this.groupResizeObserver;for(const[index,el]of this.deferredGroupObservations)groupObserver&&this.observedGroups.get(index)===el&&groupObserver.observe(el);this.deferredGroupObservations.clear()});this.rowObserveRafId=handle,this.rowObserveRafOwner=ownerWindow,this.rowObserveRafDocument=ownerDocument}syncRowObservers(){const ro=this.rowResizeObserver;if(!ro)return;if(this.fixedRowHeight!=null){for(const el of this.observedRows.values())ro.unobserve(el);this.observedRows.clear(),this.deferredRowObservations.clear();return}const current=new Map;this.renderRoot.querySelectorAll('[part="row"]').forEach(el=>{const index=Number(el.getAttribute("data-row-index"));if(!Number.isInteger(index)||index<0||index>=this.itemCount)return;const identity=this.identityAt(index);current.set(identity,el),this.observedRowKeys.set(el,identity),this.observedRowIndices.set(el,index)});for(const[identity,el]of this.observedRows)current.get(identity)!==el&&(ro.unobserve(el),this.observedRows.delete(identity),this.deferredRowObservations.delete(identity));for(const[identity,el]of current)this.observedRows.has(identity)||(this.observedRows.set(identity,el),this.inResizeDelivery?this.deferredRowObservations.set(identity,el):ro.observe(el))}syncGroupObservers(){const observer=this.groupResizeObserver;if(!observer)return;const current=new Map;this.renderRoot.querySelectorAll('[part="group"][data-group-index]').forEach(marker=>{const index=Number(marker.dataset.groupIndex);!Number.isInteger(index)||!this.normalizedGroupByIndex.has(index)||(current.set(index,marker),this.observedGroupIndices.set(marker,index))});for(const[index,marker]of this.observedGroups)current.get(index)!==marker&&(observer.unobserve(marker),this.observedGroups.delete(index),this.deferredGroupObservations.delete(index));for(const[index,marker]of current)this.observedGroups.has(index)||(this.observedGroups.set(index,marker),this.inResizeDelivery?this.deferredGroupObservations.set(index,marker):observer.observe(marker))}get stickyInset(){return this.renderStickyGroup?this.stickyHeight:0}scrollActiveIntoView(){const index=this.activeIndex;if(index<0)return;const behavior=prefersReducedMotion(this.ownerDocument.defaultView)?"auto":"smooth";this.performScrollTo(index,"auto",behavior)&&this.beginPendingScrollCorrection(index,"auto",behavior,this.activeItemId)}scrollToIndex(index,options){const n=this.itemCount;if(n===0)return;const clamped=finiteInteger(index,0,0,n-1),align=options?.align??"auto",behavior=prefersReducedMotion(this.ownerDocument.defaultView)?"auto":options?.behavior??"smooth";this.performScrollTo(clamped,align,behavior)?this.beginPendingScrollCorrection(clamped,align,behavior):this.pendingScrollCorrection=void 0}hasUnmeasuredGroupThrough(index){return this.normalizedGroups.some(group=>group.startIndex<=index&&group.label!==""&&!this.measuredGroupHeights.has(group.startIndex))}beginPendingScrollCorrection(index,align,behavior,activeItemId){if(this.fixedRowHeight!=null&&!this.hasUnmeasuredGroupThrough(index)){this.pendingScrollCorrection=void 0;return}this.pendingScrollCorrection={identity:this.identityAt(index),index,align,behavior,source:this.effectiveSource,keyFunction:this.keyFunction,activeItemId:activeItemId===""?void 0:activeItemId,lastMeasurementGeneration:this.measurementGeneration}}performScrollTo(index,align,behavior){const metrics=this.readScrollMetrics();if(!metrics)return!1;const inset=this.stickyInset,top=this.offsetAt(index),bottom=this.rowBottomAt(index),viewTop=metrics.rawScrollTop,viewBottom=viewTop+metrics.viewportHeight;let target=null;return align==="start"?target=top-inset:align==="end"?target=bottom-metrics.viewportHeight:top-inset<viewTop?target=top-inset:bottom>viewBottom&&(target=bottom-metrics.viewportHeight),target===null?!1:(this.applyScrollPosition(target,behavior),!0)}maybeCorrectPendingScroll(){const pending=this.pendingScrollCorrection;if(!pending||pending.lastMeasurementGeneration>=this.measurementGeneration)return;if(pending.source!==this.effectiveSource||pending.keyFunction!==this.keyFunction||pending.activeItemId!==void 0&&!Object.is(pending.activeItemId,this.activeItemId)){this.pendingScrollCorrection=void 0;return}const index=pending.activeItemId!==void 0?this.activeIndex:isIndexedSource(this.effectiveSource)?pending.index:this.rowIdentities.indexOf(pending.identity);if(index<0||index>=this.itemCount||this.identityAt(index)!==pending.identity){this.pendingScrollCorrection=void 0;return}this.performScrollTo(index,pending.align,pending.behavior),pending.index=index,pending.lastMeasurementGeneration=this.measurementGeneration,(this.fixedRowHeight!=null||this.measuredHeights.has(pending.identity))&&!this.hasUnmeasuredGroupThrough(index)&&(this.pendingScrollCorrection=void 0)}emitRangeChangeIfNeeded(){if(this.visibleEnd<this.visibleStart){this.lastEmittedStart=-1,this.lastEmittedEnd=-1;return}this.visibleStart===this.lastEmittedStart&&this.visibleEnd===this.lastEmittedEnd||(this.lastEmittedStart=this.visibleStart,this.lastEmittedEnd=this.visibleEnd,this.emit("lr-visible-range-change",{start:this.visibleStart,end:this.visibleEnd}))}maybeFireLoadMore(){const n=this.itemCount;if(!(n>0&&this.visibleEnd>=n-1)){this.loadMoreArmed=!0;return}!this.hasMore||this.loading||!this.loadMoreArmed||(this.loadMoreArmed=!1,this.emit("lr-load-more"))}renderRow(item,index,total,activeIndex){const key=this.keyOf(item,index),top=this.offsetAt(index),isActive=index===activeIndex,isRowMode=this.itemRole==="row";return html`
1
+ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)(d=decorators[i])&&(r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r);return c>3&&r&&Object.defineProperty(target,key,r),r};import{html,nothing,render}from"lit";import{html as staticHtml,unsafeStatic}from"lit/static-html.js";import{property,state}from"lit/decorators.js";import{repeat}from"lit/directives/repeat.js";import{styleMap}from"lit/directives/style-map.js";import{LyraElement}from"../../../internal/lyra-element.js";import{literalSetConverter}from"../../../internal/converters.js";import{tag}from"../../../internal/prefix.js";import{prefersReducedMotion}from"../../../internal/motion.js";import{finiteAdd,finiteCount,finiteInteger,finiteNumber}from"../../../internal/numbers.js";import{getNumberFormat}from"../../../internal/intl-cache.js";import{getOwnDataDescriptor,MISSING_OWN_DATA_DESCRIPTOR,UNSAFE_OWN_DATA_DESCRIPTOR}from"../../../internal/data-descriptors.js";import{styles}from"./virtual-list.styles.js";const DEFAULT_ROW_ESTIMATE_PX=48,DEFAULT_GROUP_ESTIMATE_PX=32,DEFAULT_OVERSCAN_ROWS=6,MAX_OVERSCAN_ROWS=100,MAX_VIRTUAL_LIST_GROUPS=1e4,EMPTY_VIRTUAL_LIST_GROUPS=Object.freeze([]);function normalizeOverscan(value){if(value===null)return DEFAULT_OVERSCAN_ROWS;const numeric=typeof value=="number"?value:Number(value);return Number.isFinite(numeric)?Math.min(MAX_OVERSCAN_ROWS,Math.max(0,Math.floor(numeric))):DEFAULT_OVERSCAN_ROWS}const overscanConverter={fromAttribute(value){return normalizeOverscan(value)}};function virtualListGroupsChanged(value,oldValue){if(value===oldValue)return!1;const next=value,previous=oldValue;if(next==null||previous==null)return next!==previous;if(next.length!==previous.length)return!0;for(let index=0;index<next.length;index+=1){const a=next[index],b=previous[index];if(a.key!==b.key||a.label!==b.label||a.startIndex!==b.startIndex)return!0}return!1}const ROW_PROJECTION=literalSetConverter(["shadow","light"],"shadow"),VIRTUAL_LIST_ROW_ATTRIBUTE=`data-${tag("virtual-list-row")}`,VIRTUAL_LIST_STICKY_ATTRIBUTE=`data-${tag("virtual-list-sticky")}`,ROW_ATTRIBUTE_STATIC=unsafeStatic(VIRTUAL_LIST_ROW_ATTRIBUTE),PROJECTION_ANCHOR_MARKER=`${tag("virtual-list")}-projection`;function normalizeRowHeight(value){if(value==="auto")return"auto";const numeric=typeof value=="number"?value:Number(value);return Number.isFinite(numeric)&&numeric>0?numeric:"auto"}const rowHeightConverter={fromAttribute(value){return value===null?"auto":normalizeRowHeight(value)}};function isIndexedSource(source){return!Array.isArray(source)}const ELEMENT_NODE_TYPE=1;function isWindowScroller(target){return target.window===target}function domKeyToken(key){if(typeof key=="number"){if(Number.isNaN(key))return"number:NaN";if(Object.is(key,-0))return"number:-0"}return`${typeof key}:${String(key)}`}class LyraVirtualList extends LyraElement{constructor(){super(...arguments),this.items=[],this.renderItem=()=>nothing,this.rowHeight="auto",this.itemRole="listitem",this._rowProjection="shadow",this.rowIndexOffset=0,this.overscan=DEFAULT_OVERSCAN_ROWS,this.activeItemId="",this.loading=!1,this.hasMore=!1,this.containerScrollTop=0,this.viewportHeight=0,this.renderUnmeasuredWindow=!0,this.offsets=[0],this.rowIdentities=[],this.fixedRowHeight=null,this.measuredHeights=new Map,this.measuredIndices=new Map,this.indexedMeasurementIndices=[],this.indexedMeasurementDeltaPrefix=[0],this.indexedMeasurementIndexDirty=!0,this.offsetsDirty=!0,this.itemsChangedPendingPrune=!1,this.renderStart=0,this.renderEnd=-1,this.renderedWindow=[],this.projectionDeferred=!0,this.releaseRowProjection=()=>{this.projectionDeferred=!1,this.requestUpdate()},this.visibleStart=0,this.visibleEnd=-1,this.lastEmittedStart=-1,this.lastEmittedEnd=-1,this.loadMoreArmed=!0,this.measurementGeneration=0,this.isFirstUpdate=!0,this.stickyHeight=0,this.observedRows=new Map,this.observedRowKeys=new WeakMap,this.observedRowIndices=new WeakMap,this.observedGroups=new Map,this.observedGroupIndices=new WeakMap,this.externalMetricsPending=!1,this.ownerRealmGeneration=0,this.inResizeDelivery=!1,this.deferredRowObservations=new Map,this.deferredGroupObservations=new Map,this.activeIndexForLength=-1,this.activeIndexForId="",this.activeIndexCache=-1,this.pendingScrollTop=null,this.normalizedGroups=EMPTY_VIRTUAL_LIST_GROUPS,this.normalizedGroupByIndex=new Map,this.measuredGroupHeights=new Map,this.groupHeightPrefix=[0],this.onExternalViewportResize=()=>{this.syncExternalScrollMetrics()},this.onUserScrollIntent=event=>{event instanceof KeyboardEvent&&!new Set(["ArrowUp","ArrowDown","PageUp","PageDown","Home","End"," "]).has(event.key)||(this.pendingScrollCorrection=void 0)},this.onScroll=e=>{if(this.externalScroller?(this.pendingScrollTop=null,this.externalMetricsPending=!0):this.pendingScrollTop=e.currentTarget.scrollTop,this.scrollRafId!==void 0)return;const ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView;if(!ownerWindow||!this.isConnected)return;const generation=this.ownerRealmGeneration,handle=ownerWindow.requestAnimationFrame(()=>{if(!(this.scrollRafId!==handle||this.scrollRafOwner!==ownerWindow||this.scrollRafDocument!==ownerDocument||!this.isCurrentOwnerWork(ownerDocument,generation))){if(this.scrollRafId=void 0,this.scrollRafOwner=void 0,this.scrollRafDocument=void 0,this.externalMetricsPending){this.externalMetricsPending=!1;const metrics=this.readScrollMetrics();metrics&&(this.pendingScrollTop=metrics.scrollTop,this.viewportHeight!==metrics.viewportHeight&&(this.viewportHeight=metrics.viewportHeight))}if(this.pendingScrollTop!==null){const scrollTop=this.pendingScrollTop;this.pendingScrollTop=null;const moved=this.containerScrollTop!==scrollTop;this.containerScrollTop=scrollTop,moved&&this.emit("lr-virtual-scroll",{scrollTop,viewportHeight:this.viewportHeight})}}});this.scrollRafId=handle,this.scrollRafOwner=ownerWindow,this.scrollRafDocument=ownerDocument},this.onRowsResized=entries=>{if(this.beginResizeDelivery(),this.fixedRowHeight!=null)return;const base=this.scrollContainer,oldScrollTop=this.readScrollMetrics()?.rawScrollTop??this.containerScrollTop;let scrollAdjustment=0,changed=!1;for(const entry of entries){const row=entry.target,key=this.observedRowKeys.get(row),index=this.observedRowIndices.get(row);if(key===void 0||index===void 0)continue;const height=entry.borderBoxSize?.[0]?.blockSize??entry.target.getBoundingClientRect().height,prev=this.measuredHeights.get(key);if(prev===void 0||Math.abs(prev-height)>.5){const oldBottom=this.rowBottomAt(index);this.measuredHeights.set(key,height),this.measuredIndices.set(key,index);const oldHeight=prev??DEFAULT_ROW_ESTIMATE_PX;oldBottom<=oldScrollTop&&(scrollAdjustment+=height-oldHeight),changed=!0}}if(changed){if(this.indexedMeasurementIndexDirty=!0,base&&scrollAdjustment!==0){const nextScrollTop=oldScrollTop+scrollAdjustment;this.applyScrollPosition(nextScrollTop),this.containerScrollTop=Math.max(0,nextScrollTop),this.pendingScrollTop=null}this.offsetsDirty=!0,this.measurementGeneration+=1,this.requestUpdate()}},this.onGroupsResized=entries=>{this.beginResizeDelivery();const base=this.scrollContainer,oldScrollTop=this.readScrollMetrics()?.rawScrollTop??this.containerScrollTop;let scrollAdjustment=0,changed=!1;for(const entry of entries){const marker=entry.target,index=this.observedGroupIndices.get(marker);if(index===void 0||!this.normalizedGroupByIndex.has(index))continue;const height=entry.borderBoxSize?.[0]?.blockSize??entry.target.getBoundingClientRect().height;if(!Number.isFinite(height)||height<0)continue;const previous=this.measuredGroupHeights.get(index)??DEFAULT_GROUP_ESTIMATE_PX;if(Math.abs(previous-height)<=.5)continue;const oldRowTop=this.offsetAt(index);this.measuredGroupHeights.set(index,height),oldRowTop<=oldScrollTop&&(scrollAdjustment+=height-previous),changed=!0}if(changed){if(base&&scrollAdjustment!==0){const nextScrollTop=oldScrollTop+scrollAdjustment;this.applyScrollPosition(nextScrollTop),this.containerScrollTop=Math.max(0,nextScrollTop),this.pendingScrollTop=null}this.offsetsDirty=!0,this.measurementGeneration+=1,this.requestUpdate()}},this.onStickyResized=entries=>{this.beginResizeDelivery();const entry=entries[0];if(!entry)return;const height=entry.borderBoxSize?.[0]?.blockSize??entry.contentRect.height;Math.abs(this.stickyHeight-height)>.5&&(this.stickyHeight=height)}}static{this.ownedCollectionProperties=Object.freeze(["items","source","groups"])}static{this.identityCollectionProperties=Object.freeze(["items","source"])}static{this.identityCollectionObjectProperties=Object.freeze(["source"])}static{this.styles=[LyraElement.styles,styles]}get rowProjection(){return this._rowProjection}set rowProjection(next){const normalized=ROW_PROJECTION.normalize(next),previous=this._rowProjection;previous!==normalized&&(this._rowProjection=normalized,this.requestUpdate("rowProjection",previous))}get scrollContainer(){return this.renderRoot?.querySelector('[part="base"]')??void 0}get renderedRows(){const root=this.renderRoot;return root?[...root.querySelectorAll('[part="row"]')]:[]}get projectedRows(){const rows=[];for(const child of this.children)child.hasAttribute(VIRTUAL_LIST_ROW_ATTRIBUTE)&&rows.push(child);return rows}get externalScroller(){const target=this.scrollElement;if(target!=null)return isWindowScroller(target)||target.nodeType===ELEMENT_NODE_TYPE?target:void 0}get spacerElement(){return this.renderRoot?.querySelector('[part="spacer"]')??void 0}readScrollMetrics(){const base=this.scrollContainer;if(!base)return null;const external=this.externalScroller;if(!external)return{scrollTop:base.scrollTop,rawScrollTop:base.scrollTop,viewportHeight:base.clientHeight};const spacerTop=(this.spacerElement??base).getBoundingClientRect().top;if(isWindowScroller(external)){const documentHeight=finiteNumber(external.document?.documentElement?.clientHeight??0,0),rawScrollTop2=finiteNumber(-spacerTop,0);return{scrollTop:Math.max(0,rawScrollTop2),rawScrollTop:rawScrollTop2,viewportHeight:documentHeight>0?documentHeight:finiteNumber(external.innerHeight,0)}}const scrollerTop=external.getBoundingClientRect().top,rawScrollTop=finiteNumber(scrollerTop-spacerTop,0);return{scrollTop:Math.max(0,rawScrollTop),rawScrollTop,viewportHeight:finiteNumber(external.clientHeight,0)}}applyScrollPosition(top,behavior){const external=this.externalScroller;if(!external){const base=this.scrollContainer;if(!base)return;const next2=Math.max(0,finiteNumber(top,0));behavior===void 0?base.scrollTop=next2:base.scrollTo({top:next2,behavior});return}const metrics=this.readScrollMetrics();if(!metrics)return;const delta=finiteNumber(top,metrics.rawScrollTop)-metrics.rawScrollTop;if(isWindowScroller(external)){const options={top:Math.max(0,finiteNumber(external.scrollY+delta,0))};behavior!==void 0&&(options.behavior=behavior),external.scrollTo(options);return}const next=Math.max(0,finiteNumber(external.scrollTop+delta,0));behavior===void 0?external.scrollTop=next:external.scrollTo({top:next,behavior})}syncExternalScrollMetrics(){const metrics=this.readScrollMetrics();metrics&&(this.viewportHeight!==metrics.viewportHeight&&(this.viewportHeight=metrics.viewportHeight),this.containerScrollTop!==metrics.scrollTop&&(this.containerScrollTop=metrics.scrollTop))}get safeRowIndexOffset(){return finiteCount(this.rowIndexOffset)}computedAriaRowIndex(index){return finiteInteger(finiteAdd(index+1,this.safeRowIndexOffset),1,1,Number.MAX_SAFE_INTEGER)}get activeIndex(){if(this.activeItemId==="")return-1;const source=this.effectiveSource,count=this.itemCount;if(this.activeIndexFor===source&&this.activeIndexForLength===count&&Object.is(this.activeIndexForId,this.activeItemId)&&this.activeIndexForKeyFn===this.keyFunction)return this.activeIndexCache;if(this.activeIndexFor=source,this.activeIndexForLength=count,this.activeIndexForId=this.activeItemId,this.activeIndexForKeyFn=this.keyFunction,this.activeIndexCache=-1,isIndexedSource(source)){if(!this.keyFunction&&source.indexOfKey){const candidate=source.indexOfKey(this.activeItemId);Number.isInteger(candidate)&&candidate>=0&&candidate<count&&(this.activeIndexCache=candidate)}return this.activeIndexCache}for(let index=0;index<count;index++){const item=this.itemAt(index);if(Object.is(this.keyOf(item,index),this.activeItemId)){this.activeIndexCache=index;break}}return this.activeIndexCache}connectedCallback(){super.connectedCallback(),this.ownerDocument.defaultView&&(this.seedFirstRenderState(()=>{this.renderUnmeasuredWindow=!1,this.requestUpdate()}),this.seedFirstRenderState(this.releaseRowProjection),this.hasUpdated&&(this.projectionDeferred=!1)),this.resetOwnerRealmWork();const ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView,generation=this.ownerRealmGeneration,ResizeObserverCtor=ownerWindow?.ResizeObserver;if(ResizeObserverCtor){const rowObserver=new ResizeObserverCtor(entries=>{this.rowResizeObserver!==rowObserver||!this.isCurrentOwnerWork(ownerDocument,generation)||this.onRowsResized(entries)}),groupObserver=new ResizeObserverCtor(entries=>{this.groupResizeObserver!==groupObserver||!this.isCurrentOwnerWork(ownerDocument,generation)||this.onGroupsResized(entries)}),stickyObserver=new ResizeObserverCtor(entries=>{this.stickyResizeObserver!==stickyObserver||!this.isCurrentOwnerWork(ownerDocument,generation)||this.onStickyResized(entries)});this.rowResizeObserver=rowObserver,this.groupResizeObserver=groupObserver,this.stickyResizeObserver=stickyObserver}this.hasUpdated&&(this.syncRowProjection(),this.attachContainerListeners(),this.syncRowObservers(),this.syncGroupObservers(),this.syncStickyOverlay())}disconnectedCallback(){this.teardownRowProjection(),this.resetOwnerRealmWork(),super.disconnectedCallback()}adoptedCallback(){super.adoptedCallback(),this.teardownRowProjection(),this.resetOwnerRealmWork()}isCurrentOwnerWork(ownerDocument,generation){return this.ownerRealmGeneration===generation&&this.isConnected&&this.ownerDocument===ownerDocument}resetOwnerRealmWork(){this.ownerRealmGeneration+=1,this.rowResizeObserver?.disconnect(),this.rowResizeObserver=void 0,this.groupResizeObserver?.disconnect(),this.groupResizeObserver=void 0,this.observedRows.clear(),this.observedGroups.clear(),this.deferredRowObservations.clear(),this.deferredGroupObservations.clear(),this.inResizeDelivery=!1,this.rowObserveRafId!==void 0&&this.rowObserveRafOwner?.cancelAnimationFrame(this.rowObserveRafId),this.rowObserveRafId=void 0,this.rowObserveRafOwner=void 0,this.rowObserveRafDocument=void 0,this.containerResizeObserver?.disconnect(),this.containerResizeObserver=void 0,this.stickyResizeObserver?.disconnect(),this.stickyResizeObserver=void 0,this.observedSticky=void 0,this.scrollRafId!==void 0&&this.scrollRafOwner?.cancelAnimationFrame(this.scrollRafId),this.scrollRafId=void 0,this.scrollRafOwner=void 0,this.scrollRafDocument=void 0,this.pendingScrollTop=null,this.externalMetricsPending=!1,this.pendingScrollCorrection=void 0,this.detachContainerListeners(),this.scrollListenerTarget=void 0}firstUpdated(changed){super.firstUpdated(changed),this.attachContainerListeners()}willUpdate(changed){super.willUpdate(changed),this.projectionDeferred&&!this.hasUpdated&&this.ownerDocument?.defaultView&&this.seedFirstRenderState(this.releaseRowProjection),this.isFirstUpdate=!this.hasUpdated,(changed.has("items")||changed.has("source")||changed.has("keyFunction")||changed.has("rowHeight")||changed.has("groups")||changed.has("activeItemId")||changed.has("scrollElement"))&&(this.pendingScrollCorrection=void 0),(changed.has("items")||changed.has("source")||changed.has("rowHeight")||changed.has("keyFunction")||changed.has("groups"))&&(this.offsetsDirty=!0),(changed.has("items")||changed.has("source"))&&(this.itemsChangedPendingPrune=!0),(changed.has("keyFunction")||isIndexedSource(this.effectiveSource)&&(changed.has("items")||changed.has("source")))&&(this.measuredHeights.clear(),this.measuredIndices.clear(),this.indexedMeasurementIndexDirty=!0),changed.has("groups")&&this.measuredGroupHeights.clear(),(changed.has("items")||changed.has("source")||changed.has("groups"))&&this.recomputeGroups(),changed.has("rowHeight")&&(this.fixedRowHeight=this.parseRowHeight(this.rowHeight),this.fixedRowHeight!=null&&(this.measuredHeights.clear(),this.measuredIndices.clear(),this.indexedMeasurementIndexDirty=!0)),this.offsetsDirty&&(this.recomputeOffsets(),this.offsetsDirty=!1),this.computeRange()}updated(changed){super.updated(changed),this.syncRowProjection(),this.syncRowObservers(),this.syncGroupObservers(),this.syncStickyOverlay(),changed.has("scrollElement")&&!this.isFirstUpdate&&this.attachContainerListeners(),changed.has("activeItemId")&&!this.isFirstUpdate&&this.scrollActiveIntoView(),this.emitRangeChangeIfNeeded(),this.maybeFireLoadMore(),this.maybeCorrectPendingScroll()}parseRowHeight(value){const normalized=normalizeRowHeight(value);return normalized==="auto"?null:normalized}get effectiveSource(){return this.source??this.items}get itemCount(){const source=this.effectiveSource;return isIndexedSource(source)?finiteCount(source.count):source.length}itemAt(index){const source=this.effectiveSource;return isIndexedSource(source)?source.itemAt(index):source[index]}keyOf(item,index){const source=this.effectiveSource,key=this.keyFunction?this.keyFunction(item,index):isIndexedSource(source)?source.keyAt?.(index)??index:index;return typeof key=="string"||typeof key=="number"?key:index}rowIdentity(key,occurrence){const token=domKeyToken(key);return`${token.length}:${token}:${occurrence}`}identityAt(index,item=this.itemAt(index)){return isIndexedSource(this.effectiveSource)?this.rowIdentity(this.keyOf(item,index),index):this.rowIdentities[index]??this.rowIdentity(this.keyOf(item,index),index)}groupHeightAt(index){const group=this.normalizedGroupByIndex.get(index);return!group||group.label===""?0:this.measuredGroupHeights.get(index)??DEFAULT_GROUP_ESTIMATE_PX}rowHeightAt(index){return this.fixedRowHeight!=null?this.fixedRowHeight:this.measuredHeights.get(this.identityAt(index))??DEFAULT_ROW_ESTIMATE_PX}groupContributionThrough(index){let low=0,high=this.normalizedGroups.length;for(;low<high;){const middle=low+high>>1;this.normalizedGroups[middle].startIndex<=index?low=middle+1:high=middle}return this.groupHeightPrefix[low]??0}recomputeGroupHeightPrefix(){const prefix=new Array(this.normalizedGroups.length+1);prefix[0]=0;for(let index=0;index<this.normalizedGroups.length;index++){const group=this.normalizedGroups[index],height=group.label===""?0:this.measuredGroupHeights.get(group.startIndex)??DEFAULT_GROUP_ESTIMATE_PX;prefix[index+1]=finiteAdd(prefix[index],height)}this.groupHeightPrefix=prefix}indexedOffsetForIndex(index){const baseHeight=this.fixedRowHeight??DEFAULT_ROW_ESTIMATE_PX;let offset=index>Number.MAX_VALUE/baseHeight?Number.MAX_VALUE:index*baseHeight;if(this.fixedRowHeight==null){this.rebuildIndexedMeasurementIndex();let low=0,high=this.indexedMeasurementIndices.length;for(;low<high;){const middle=low+high>>1;this.indexedMeasurementIndices[middle]<index?low=middle+1:high=middle}offset=finiteAdd(offset,this.indexedMeasurementDeltaPrefix[low]??0)}return Math.max(0,finiteAdd(offset,this.groupContributionThrough(index)))}rebuildIndexedMeasurementIndex(){if(!this.indexedMeasurementIndexDirty)return;const retained=[];for(const[identity,index]of this.measuredIndices){const height=this.measuredHeights.get(identity);height!==void 0&&retained.push({index,delta:height-DEFAULT_ROW_ESTIMATE_PX})}retained.sort((a,b)=>a.index-b.index);const indices=new Array(retained.length),prefix=new Array(retained.length+1);prefix[0]=0;for(let position=0;position<retained.length;position++){const measurement=retained[position];indices[position]=measurement.index,prefix[position+1]=finiteAdd(prefix[position],measurement.delta)}this.indexedMeasurementIndices=indices,this.indexedMeasurementDeltaPrefix=prefix,this.indexedMeasurementIndexDirty=!1}pruneIndexedMeasurements(){if(!isIndexedSource(this.effectiveSource)||this.fixedRowHeight!=null||this.renderEnd<this.renderStart)return!1;const renderedCount=this.renderEnd-this.renderStart+1,retentionRows=Math.max(renderedCount,normalizeOverscan(this.overscan)*4),firstRetained=Math.max(0,this.renderStart-retentionRows),lastRetained=Math.min(this.itemCount-1,this.renderEnd+retentionRows);let removedDeltaBeforeWindow=0,pruned=!1;for(const[identity,measuredIndex]of this.measuredIndices)if(measuredIndex<firstRetained||measuredIndex>lastRetained){const height=this.measuredHeights.get(identity);height!==void 0&&measuredIndex<firstRetained&&(removedDeltaBeforeWindow=finiteAdd(removedDeltaBeforeWindow,height-DEFAULT_ROW_ESTIMATE_PX)),this.measuredIndices.delete(identity),this.measuredHeights.delete(identity),pruned=!0}if(pruned&&(this.indexedMeasurementIndexDirty=!0,removedDeltaBeforeWindow!==0)){const nextScrollTop=(this.readScrollMetrics()?.rawScrollTop??this.containerScrollTop)-removedDeltaBeforeWindow;this.applyScrollPosition(nextScrollTop),this.containerScrollTop=Math.max(0,nextScrollTop),this.pendingScrollTop=null}return pruned}offsetAt(index){return isIndexedSource(this.effectiveSource)?this.indexedOffsetForIndex(index):this.offsets[index]??0}recomputeOffsets(){const n=this.itemCount;if(this.recomputeGroupHeightPrefix(),isIndexedSource(this.effectiveSource)){this.offsets=[0],this.rowIdentities=[],this.itemsChangedPendingPrune=!1;return}const offsets=new Array(n+1);let cursor=0;const liveKeys=this.itemsChangedPendingPrune&&this.fixedRowHeight==null?new Set:null,occurrences=new Map,identities=new Array(n);for(let i=0;i<n;i++){cursor=finiteAdd(cursor,this.groupHeightAt(i)),offsets[i]=cursor;const key=this.keyOf(this.itemAt(i),i),token=domKeyToken(key),occurrence=occurrences.get(token)??0;occurrences.set(token,occurrence+1);const identity=this.rowIdentity(key,occurrence);identities[i]=identity;let h;this.fixedRowHeight!=null?h=this.fixedRowHeight:(liveKeys?.add(identity),h=this.measuredHeights.get(identity)??DEFAULT_ROW_ESTIMATE_PX),cursor=finiteAdd(cursor,h)}if(offsets[n]=cursor,this.offsets=offsets,this.rowIdentities=identities,this.itemsChangedPendingPrune=!1,liveKeys){for(const key of this.measuredHeights.keys())liveKeys.has(key)||(this.measuredHeights.delete(key),this.measuredIndices.delete(key),this.indexedMeasurementIndexDirty=!0);for(const key of this.measuredIndices.keys())liveKeys.has(key)||(this.measuredIndices.delete(key),this.indexedMeasurementIndexDirty=!0)}}groupTopAt(index){return Math.max(0,this.offsetAt(index)-this.groupHeightAt(index))}rowBottomAt(index){return finiteAdd(this.offsetAt(index),this.rowHeightAt(index))}entryTopAt(index){return this.groupTopAt(index)}findIndexAtOrAfter(offset){let lo=0,hi=this.itemCount-1;for(;lo<hi;){const mid=lo+Math.floor((hi-lo)/2);this.rowBottomAt(mid)<=offset?lo=mid+1:hi=mid}return lo}findIndexAtOrBefore(offset){let lo=0,hi=this.itemCount-1;for(;lo<hi;){const mid=lo+Math.ceil((hi-lo)/2);this.entryTopAt(mid)<offset?lo=mid:hi=mid-1}return lo}offsetForIndex(index){const clamped=Math.min(this.itemCount,Math.max(0,Math.trunc(index)||0));return this.offsetAt(clamped)}indexAtOffset(px){const n=this.itemCount;return n===0?-1:Number.isFinite(px)?Math.min(n-1,Math.max(0,this.findIndexAtOrAfter(px))):px>0?n-1:0}computeRange(){const n=this.itemCount;if(n===0){this.visibleStart=0,this.visibleEnd=-1,this.renderStart=0,this.renderEnd=-1;return}if(this.viewportHeight<=0){if(!this.renderUnmeasuredWindow){this.visibleStart=0,this.visibleEnd=-1,this.renderStart=0,this.renderEnd=-1;return}this.visibleStart=0,this.visibleEnd=0,this.renderStart=0,this.renderEnd=Math.min(n-1,normalizeOverscan(this.overscan));return}const viewTop=this.containerScrollTop,viewBottom=viewTop+this.viewportHeight;this.visibleStart=this.findIndexAtOrAfter(viewTop),this.visibleEnd=this.findIndexAtOrBefore(viewBottom);const overscan=normalizeOverscan(this.overscan);this.renderStart=Math.max(0,this.visibleStart-overscan),this.renderEnd=Math.min(n-1,this.visibleEnd+overscan),this.pruneIndexedMeasurements()&&this.computeRange()}attachContainerListeners(){const base=this.scrollContainer,ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView;if(!base||!this.isConnected||!ownerWindow)return;this.containerResizeObserver?.disconnect(),this.containerResizeObserver=void 0,this.detachContainerListeners();const external=this.externalScroller,scrollTarget=external??base,generation=this.ownerRealmGeneration,ResizeObserverCtor=ownerWindow.ResizeObserver;if(ResizeObserverCtor){const observer=new ResizeObserverCtor(entries=>{if(this.containerResizeObserver!==observer||this.scrollListenerTarget!==scrollTarget||!this.isCurrentOwnerWork(ownerDocument,generation))return;if(this.beginResizeDelivery(),external){this.syncExternalScrollMetrics();return}const entry=entries[0];entry&&(this.viewportHeight=entry.borderBoxSize?.[0]?.blockSize??entry.contentRect.height)});this.containerResizeObserver=observer,observer.observe(base),external&&!isWindowScroller(external)&&observer.observe(external)}scrollTarget.addEventListener("scroll",this.onScroll,{passive:!0}),scrollTarget.addEventListener("wheel",this.onUserScrollIntent,{passive:!0}),scrollTarget.addEventListener("pointerdown",this.onUserScrollIntent,{passive:!0}),scrollTarget.addEventListener("touchstart",this.onUserScrollIntent,{passive:!0}),scrollTarget.addEventListener("keydown",this.onUserScrollIntent),this.scrollListenerTarget=scrollTarget,external&&isWindowScroller(external)&&(external.addEventListener("resize",this.onExternalViewportResize,{passive:!0}),this.viewportResizeTarget=external),ownerWindow.queueMicrotask(()=>{if(this.scrollListenerTarget!==scrollTarget||this.scrollContainer!==base||!this.isCurrentOwnerWork(ownerDocument,generation))return;const metrics=this.readScrollMetrics();metrics&&(this.viewportHeight!==metrics.viewportHeight&&(this.viewportHeight=metrics.viewportHeight),this.containerScrollTop!==metrics.scrollTop&&(this.containerScrollTop=metrics.scrollTop))})}detachContainerListeners(){const viewportTarget=this.viewportResizeTarget;viewportTarget&&(viewportTarget.removeEventListener("resize",this.onExternalViewportResize),this.viewportResizeTarget=void 0);const target=this.scrollListenerTarget;target&&(target.removeEventListener("scroll",this.onScroll),target.removeEventListener("wheel",this.onUserScrollIntent),target.removeEventListener("pointerdown",this.onUserScrollIntent),target.removeEventListener("touchstart",this.onUserScrollIntent),target.removeEventListener("keydown",this.onUserScrollIntent))}beginResizeDelivery(){if(this.inResizeDelivery=!0,this.rowObserveRafId!==void 0)return;const ownerDocument=this.ownerDocument,ownerWindow=ownerDocument.defaultView;if(!ownerWindow||!this.isConnected){this.inResizeDelivery=!1;return}const generation=this.ownerRealmGeneration,handle=ownerWindow.requestAnimationFrame(()=>{if(this.rowObserveRafId!==handle||this.rowObserveRafOwner!==ownerWindow||this.rowObserveRafDocument!==ownerDocument||!this.isCurrentOwnerWork(ownerDocument,generation))return;this.rowObserveRafId=void 0,this.rowObserveRafOwner=void 0,this.rowObserveRafDocument=void 0,this.inResizeDelivery=!1;const ro=this.rowResizeObserver;for(const[identity,el]of this.deferredRowObservations)ro&&this.observedRows.get(identity)===el&&ro.observe(el);this.deferredRowObservations.clear();const groupObserver=this.groupResizeObserver;for(const[index,el]of this.deferredGroupObservations)groupObserver&&this.observedGroups.get(index)===el&&groupObserver.observe(el);this.deferredGroupObservations.clear()});this.rowObserveRafId=handle,this.rowObserveRafOwner=ownerWindow,this.rowObserveRafDocument=ownerDocument}syncRowObservers(){const ro=this.rowResizeObserver;if(!ro)return;if(this.fixedRowHeight!=null){for(const el of this.observedRows.values())ro.unobserve(el);this.observedRows.clear(),this.deferredRowObservations.clear();return}const current=new Map;this.renderRoot.querySelectorAll('[part="row"]').forEach(el=>{const index=Number(el.getAttribute("data-row-index"));if(!Number.isInteger(index)||index<0||index>=this.itemCount)return;const identity=this.identityAt(index);current.set(identity,el),this.observedRowKeys.set(el,identity),this.observedRowIndices.set(el,index)});for(const[identity,el]of this.observedRows)current.get(identity)!==el&&(ro.unobserve(el),this.observedRows.delete(identity),this.deferredRowObservations.delete(identity));for(const[identity,el]of current)this.observedRows.has(identity)||(this.observedRows.set(identity,el),this.inResizeDelivery?this.deferredRowObservations.set(identity,el):ro.observe(el))}syncGroupObservers(){const observer=this.groupResizeObserver;if(!observer)return;const current=new Map;this.renderRoot.querySelectorAll('[part="group"][data-group-index]').forEach(marker=>{const index=Number(marker.dataset.groupIndex);!Number.isInteger(index)||!this.normalizedGroupByIndex.has(index)||(current.set(index,marker),this.observedGroupIndices.set(marker,index))});for(const[index,marker]of this.observedGroups)current.get(index)!==marker&&(observer.unobserve(marker),this.observedGroups.delete(index),this.deferredGroupObservations.delete(index));for(const[index,marker]of current)this.observedGroups.has(index)||(this.observedGroups.set(index,marker),this.inResizeDelivery?this.deferredGroupObservations.set(index,marker):observer.observe(marker))}get stickyInset(){return this.renderStickyGroup?this.stickyHeight:0}scrollActiveIntoView(){const index=this.activeIndex;if(index<0)return;const behavior=prefersReducedMotion(this.ownerDocument.defaultView)?"auto":"smooth";this.performScrollTo(index,"auto",behavior)&&this.beginPendingScrollCorrection(index,"auto",behavior,this.activeItemId)}scrollToIndex(index,options){const n=this.itemCount;if(n===0)return;const clamped=finiteInteger(index,0,0,n-1),align=options?.align??"auto",behavior=prefersReducedMotion(this.ownerDocument.defaultView)?"auto":options?.behavior??"smooth";this.performScrollTo(clamped,align,behavior)?this.beginPendingScrollCorrection(clamped,align,behavior):this.pendingScrollCorrection=void 0}hasUnmeasuredGroupThrough(index){return this.normalizedGroups.some(group=>group.startIndex<=index&&group.label!==""&&!this.measuredGroupHeights.has(group.startIndex))}beginPendingScrollCorrection(index,align,behavior,activeItemId){if(this.fixedRowHeight!=null&&!this.hasUnmeasuredGroupThrough(index)){this.pendingScrollCorrection=void 0;return}this.pendingScrollCorrection={identity:this.identityAt(index),index,align,behavior,source:this.effectiveSource,keyFunction:this.keyFunction,activeItemId:activeItemId===""?void 0:activeItemId,lastMeasurementGeneration:this.measurementGeneration}}performScrollTo(index,align,behavior){const metrics=this.readScrollMetrics();if(!metrics)return!1;const inset=this.stickyInset,top=this.offsetAt(index),bottom=this.rowBottomAt(index),viewTop=metrics.rawScrollTop,viewBottom=viewTop+metrics.viewportHeight;let target=null;return align==="start"?target=top-inset:align==="end"?target=bottom-metrics.viewportHeight:top-inset<viewTop?target=top-inset:bottom>viewBottom&&(target=bottom-metrics.viewportHeight),target===null?!1:(this.applyScrollPosition(target,behavior),!0)}maybeCorrectPendingScroll(){const pending=this.pendingScrollCorrection;if(!pending||pending.lastMeasurementGeneration>=this.measurementGeneration)return;if(pending.source!==this.effectiveSource||pending.keyFunction!==this.keyFunction||pending.activeItemId!==void 0&&!Object.is(pending.activeItemId,this.activeItemId)){this.pendingScrollCorrection=void 0;return}const index=pending.activeItemId!==void 0?this.activeIndex:isIndexedSource(this.effectiveSource)?pending.index:this.rowIdentities.indexOf(pending.identity);if(index<0||index>=this.itemCount||this.identityAt(index)!==pending.identity){this.pendingScrollCorrection=void 0;return}this.performScrollTo(index,pending.align,pending.behavior),pending.index=index,pending.lastMeasurementGeneration=this.measurementGeneration,(this.fixedRowHeight!=null||this.measuredHeights.has(pending.identity))&&!this.hasUnmeasuredGroupThrough(index)&&(this.pendingScrollCorrection=void 0)}emitRangeChangeIfNeeded(){if(this.visibleEnd<this.visibleStart){this.lastEmittedStart=-1,this.lastEmittedEnd=-1;return}this.visibleStart===this.lastEmittedStart&&this.visibleEnd===this.lastEmittedEnd||(this.lastEmittedStart=this.visibleStart,this.lastEmittedEnd=this.visibleEnd,this.emit("lr-visible-range-change",{start:this.visibleStart,end:this.visibleEnd}))}maybeFireLoadMore(){const n=this.itemCount;if(!(n>0&&this.visibleEnd>=n-1)){this.loadMoreArmed=!0;return}!this.hasMore||this.loading||!this.loadMoreArmed||(this.loadMoreArmed=!1,this.emit("lr-load-more"))}get projectionActive(){return!this.projectionDeferred&&this.rowProjection==="light"}rowSlotName(identity){return`${tag("virtual-list")}-row-${identity}`}syncRowProjection(){if(!this.projectionActive||!this.isConnected){this.projectionAnchor!==void 0&&this.teardownRowProjection();return}const anchor=this.ensureProjectionAnchor();this.projectionPart=render(this.renderProjectedRows(),this,{renderBefore:anchor,host:this})}ensureProjectionAnchor(){const existing=this.projectionAnchor;if(existing!==void 0&&existing.parentNode===this&&existing.ownerDocument===this.ownerDocument)return existing;existing!==void 0&&this.teardownRowProjection();const anchor=this.ownerDocument.createComment(PROJECTION_ANCHOR_MARKER);return this.append(anchor),this.projectionAnchor=anchor,this.projectionPart=void 0,anchor}teardownRowProjection(){const anchor=this.projectionAnchor,part=this.projectionPart;if(this.projectionAnchor=void 0,this.projectionPart=void 0,anchor!==void 0){if(part!==void 0){const container=anchor.parentNode;container!==null&&render(nothing,container,{renderBefore:anchor,host:this});const start=part.startNode;start?.parentNode?.removeChild(start)}anchor.parentNode?.removeChild(anchor)}}renderProjectedRows(){return repeat(this.renderedWindow,w=>w.identity,w=>staticHtml`<div
2
+ ${ROW_ATTRIBUTE_STATIC}
3
+ slot=${this.rowSlotName(w.identity)}
4
+ data-row-index=${w.index}
5
+ data-row-key=${domKeyToken(this.keyOf(w.item,w.index))}
6
+ >${this.renderItem(w.item,w.index)}</div>`)}renderRow(item,index,total,activeIndex,identity){const key=this.keyOf(item,index),top=this.offsetAt(index),isActive=index===activeIndex,isRowMode=this.itemRole==="row";return html`
2
7
  <div
3
8
  part="row"
4
9
  role=${isRowMode?"row":"listitem"}
@@ -10,7 +15,7 @@ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3
10
15
  aria-current=${isActive?"true":"false"}
11
16
  style=${styleMap({transform:`translateY(${top}px)`})}
12
17
  >
13
- ${this.renderItem(item,index)}
18
+ ${this.projectionActive?html`<slot name=${this.rowSlotName(identity)}></slot>`:this.renderItem(item,index)}
14
19
  </div>
15
20
  `}recomputeGroups(){const normalized=[],seen=new Set;try{const groups=this.groups;if(!Array.isArray(groups))throw new TypeError("groups must be an array");const length=getOwnDataDescriptor(groups,"length");if(length===MISSING_OWN_DATA_DESCRIPTOR||length===UNSAFE_OWN_DATA_DESCRIPTOR||typeof length.value!="number"||!Number.isSafeInteger(length.value)||length.value<0)throw new TypeError("groups must have a bounded length");for(let position=0;position<Math.min(length.value,MAX_VIRTUAL_LIST_GROUPS);position+=1){const entry=getOwnDataDescriptor(groups,String(position));if(entry===MISSING_OWN_DATA_DESCRIPTOR||entry===UNSAFE_OWN_DATA_DESCRIPTOR||entry.value===null||typeof entry.value!="object"||Array.isArray(entry.value))continue;const key=getOwnDataDescriptor(entry.value,"key"),label=getOwnDataDescriptor(entry.value,"label"),startIndex=getOwnDataDescriptor(entry.value,"startIndex");if(key===MISSING_OWN_DATA_DESCRIPTOR||key===UNSAFE_OWN_DATA_DESCRIPTOR||startIndex===MISSING_OWN_DATA_DESCRIPTOR||startIndex===UNSAFE_OWN_DATA_DESCRIPTOR||label===UNSAFE_OWN_DATA_DESCRIPTOR||typeof key.value!="string"&&typeof key.value!="number"||typeof startIndex.value!="number"||!Number.isInteger(startIndex.value)||startIndex.value<0||startIndex.value>=this.itemCount||seen.has(startIndex.value))continue;const labelValue=label===MISSING_OWN_DATA_DESCRIPTOR||typeof label.value!="string"?void 0:label.value;seen.add(startIndex.value),normalized.push(Object.freeze({key:key.value,startIndex:startIndex.value,...labelValue===void 0?{}:{label:labelValue}}))}}catch{}this.normalizedGroups=Object.freeze(normalized.sort((a,b)=>a.startIndex-b.startIndex)),this.normalizedGroupByIndex.clear();for(const group of this.normalizedGroups)this.normalizedGroupByIndex.set(group.startIndex,group)}renderGroups(){return this.normalizedGroups.filter(group=>group.startIndex>=this.renderStart&&group.startIndex<=this.renderEnd).filter(group=>group.label!=="").map(group=>html`
16
21
  <div
@@ -20,7 +25,7 @@ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3
20
25
  >
21
26
  ${group.label??(typeof group.key=="number"?getNumberFormat(this.effectiveLocale).format(group.key):group.key)}
22
27
  </div>
23
- `)}currentStickyGroup(){const groups=this.normalizedGroups;if(groups.length===0)return null;const scrollTop=this.containerScrollTop;let low=0,high=groups.length-1,current=-1;for(;low<=high;){const middle=low+high>>1;this.groupTopAt(groups[middle].startIndex)<=scrollTop?(current=middle,low=middle+1):high=middle-1}if(current<0)return{group:groups[0],shift:0,active:!1};const next=groups[current+1];let shift=0;if(next&&this.stickyHeight>0){const distance=this.groupTopAt(next.startIndex)-scrollTop;distance<this.stickyHeight&&(shift=Math.min(0,distance-this.stickyHeight))}return{group:groups[current],shift,active:!0}}renderStickyLayer(){const render=this.renderStickyGroup;if(!render)return nothing;const state2=this.currentStickyGroup();return state2?html`
28
+ `)}currentStickyGroup(){const groups=this.normalizedGroups;if(groups.length===0)return null;const scrollTop=this.containerScrollTop;let low=0,high=groups.length-1,current=-1;for(;low<=high;){const middle=low+high>>1;this.groupTopAt(groups[middle].startIndex)<=scrollTop?(current=middle,low=middle+1):high=middle-1}if(current<0)return{group:groups[0],shift:0,active:!1};const next=groups[current+1];let shift=0;if(next&&this.stickyHeight>0){const distance=this.groupTopAt(next.startIndex)-scrollTop;distance<this.stickyHeight&&(shift=Math.min(0,distance-this.stickyHeight))}return{group:groups[current],shift,active:!0}}renderStickyLayer(){const render2=this.renderStickyGroup;if(!render2)return nothing;const state2=this.currentStickyGroup();return state2?html`
24
29
  <div
25
30
  part="sticky-group"
26
31
  aria-hidden="true"
@@ -28,9 +33,9 @@ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3
28
33
  ?data-inactive=${!state2.active}
29
34
  style=${state2.shift!==0?`transform:translateY(${state2.shift}px)`:nothing}
30
35
  >
31
- ${render(state2.group)}
36
+ ${render2(state2.group)}
32
37
  </div>
33
- `:nothing}syncStickyOverlay(){const overlay=this.renderRoot.querySelector('[part="sticky-group"]');overlay!==this.observedSticky&&(this.observedSticky&&this.stickyResizeObserver?.unobserve(this.observedSticky),this.observedSticky=overlay??void 0,overlay&&this.stickyResizeObserver?.observe(overlay))}render(){const n=this.itemCount,totalHeight=this.offsetAt(n),windowed=[];for(let i=this.renderStart;i<=this.renderEnd;i++)windowed.push({item:this.itemAt(i),index:i});const isRowMode=this.itemRole==="row",stickyInset=this.stickyInset,activeIndex=this.activeIndex,isExternallyScrolled=this.externalScroller!==void 0;return html`
38
+ `:nothing}syncStickyOverlay(){const overlay=this.renderRoot.querySelector('[part="sticky-group"]');overlay!==this.observedSticky&&(this.observedSticky&&this.stickyResizeObserver?.unobserve(this.observedSticky),this.observedSticky=overlay??void 0,overlay&&this.stickyResizeObserver?.observe(overlay))}render(){const n=this.itemCount,totalHeight=this.offsetAt(n),windowed=[];for(let i=this.renderStart;i<=this.renderEnd;i++){const item=this.itemAt(i);windowed.push({item,index:i,identity:this.identityAt(i,item)})}this.renderedWindow=windowed;const isRowMode=this.itemRole==="row",stickyInset=this.stickyInset,activeIndex=this.activeIndex,isExternallyScrolled=this.externalScroller!==void 0;return html`
34
39
  <div
35
40
  part="base"
36
41
  role=${isRowMode?"rowgroup":"list"}
@@ -46,8 +51,8 @@ var __decorate=function(decorators,target,key,desc){var c=arguments.length,r=c<3
46
51
  style=${styleMap({height:`${totalHeight}px`})}
47
52
  >
48
53
  ${this.renderGroups()}
49
- ${repeat(windowed,w=>this.identityAt(w.index,w.item),w=>this.renderRow(w.item,w.index,n,activeIndex))}
54
+ ${repeat(windowed,w=>w.identity,w=>this.renderRow(w.item,w.index,n,activeIndex,w.identity))}
50
55
  ${this.renderStickyLayer()}
51
56
  </div>
52
57
  </div>
53
- `}}__decorate([property({attribute:!1})],LyraVirtualList.prototype,"items",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"source",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"renderItem",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"keyFunction",void 0),__decorate([property({attribute:!1,hasChanged:virtualListGroupsChanged})],LyraVirtualList.prototype,"groups",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"renderStickyGroup",void 0),__decorate([property({attribute:"row-height",converter:rowHeightConverter})],LyraVirtualList.prototype,"rowHeight",void 0),__decorate([property({attribute:"item-role"})],LyraVirtualList.prototype,"itemRole",void 0),__decorate([property({type:Number,attribute:"row-index-offset"})],LyraVirtualList.prototype,"rowIndexOffset",void 0),__decorate([property({converter:overscanConverter})],LyraVirtualList.prototype,"overscan",void 0),__decorate([property({attribute:"active-item-id"})],LyraVirtualList.prototype,"activeItemId",void 0),__decorate([property({type:Boolean,reflect:!0})],LyraVirtualList.prototype,"loading",void 0),__decorate([property({type:Boolean,attribute:"has-more",reflect:!0})],LyraVirtualList.prototype,"hasMore",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"scrollElement",void 0),__decorate([state()],LyraVirtualList.prototype,"containerScrollTop",void 0),__decorate([state()],LyraVirtualList.prototype,"viewportHeight",void 0),__decorate([state()],LyraVirtualList.prototype,"stickyHeight",void 0);export{LyraVirtualList,MAX_OVERSCAN_ROWS};
58
+ `}}__decorate([property({attribute:!1})],LyraVirtualList.prototype,"items",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"source",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"renderItem",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"keyFunction",void 0),__decorate([property({attribute:!1,hasChanged:virtualListGroupsChanged})],LyraVirtualList.prototype,"groups",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"renderStickyGroup",void 0),__decorate([property({attribute:"row-height",converter:rowHeightConverter})],LyraVirtualList.prototype,"rowHeight",void 0),__decorate([property({attribute:"item-role"})],LyraVirtualList.prototype,"itemRole",void 0),__decorate([property({attribute:"row-projection",converter:ROW_PROJECTION})],LyraVirtualList.prototype,"rowProjection",null),__decorate([property({type:Number,attribute:"row-index-offset"})],LyraVirtualList.prototype,"rowIndexOffset",void 0),__decorate([property({converter:overscanConverter})],LyraVirtualList.prototype,"overscan",void 0),__decorate([property({attribute:"active-item-id"})],LyraVirtualList.prototype,"activeItemId",void 0),__decorate([property({type:Boolean,reflect:!0})],LyraVirtualList.prototype,"loading",void 0),__decorate([property({type:Boolean,attribute:"has-more",reflect:!0})],LyraVirtualList.prototype,"hasMore",void 0),__decorate([property({attribute:!1})],LyraVirtualList.prototype,"scrollElement",void 0),__decorate([state()],LyraVirtualList.prototype,"containerScrollTop",void 0),__decorate([state()],LyraVirtualList.prototype,"viewportHeight",void 0),__decorate([state()],LyraVirtualList.prototype,"stickyHeight",void 0);export{LyraVirtualList,MAX_OVERSCAN_ROWS,VIRTUAL_LIST_ROW_ATTRIBUTE,VIRTUAL_LIST_STICKY_ATTRIBUTE};
@@ -4,15 +4,27 @@ export type LyraMapLegendPattern='solid'|'diagonal'|'dots'|'crosshatch';
4
4
  /** One immutable, bounded map-legend row. Pattern is required so color is never the sole cue. */
5
5
  export interface LyraMapLegendEntry{readonly color:string;readonly label:string;readonly pattern:LyraMapLegendPattern;
6
6
  /**
7
+ * Category key this row stands for -- the same string a `point.colors` / `point.icons` entry
8
+ * matches against `point.field` / `point.iconField`. Trimmed, bounded to 256 characters and
9
+ * retained in the canonical readback, unlike the `value` on the `icon` record below, which is
10
+ * still dropped. A row that carries one becomes a keyboard-operable visibility toggle under
11
+ * `legendInteractive`; a row without one stays inert. An absent, non-string, empty or
12
+ * whitespace-only key leaves no `value` key at all, so a legend that never used categories
13
+ * reads back exactly as it did before this field existed.
14
+ */
15
+ readonly value?:string;
16
+ /**
7
17
  * Optional glyph painted inside `[part="legend-swatch"]`, in the entry's own color, instead of
8
18
  * the solid color block that would otherwise cover it. Deliberately the record `point.icons`
9
19
  * already carries, so a key can reproduce the symbol its point layer draws rather than
10
20
  * describing it in color alone — hand the legend the very icon object the layer renders.
11
21
  *
12
- * The point layer's `value` category key means nothing to a legend row: it is accepted so a
13
- * pass-through needs no reshaping, and left out of the canonical readback. Validation is the
14
- * point icon's own (path data only, at most 8192 characters, positive `viewBox` dimensions);
15
- * an unusable record is dropped and the row keeps rendering its color swatch.
22
+ * The **icon record's own** `value` is accepted so a pass-through needs no reshaping, and is
23
+ * left out of the canonical readback: a row's category key is the row-level `value` above, and
24
+ * is never derived from the glyph's. Deriving it would silently make a row interactive that the
25
+ * author never marked. Validation is the point icon's own (path data only, at most 8192
26
+ * characters, positive `viewBox` dimensions); an unusable record is dropped and the row keeps
27
+ * rendering its color swatch.
16
28
  *
17
29
  * That per-record 8192-character cap is deliberately the whole bound on path data, with no
18
30
  * aggregate budget of the kind `label` carries across the legend. Two reasons. The admission
@@ -325,7 +337,19 @@ export interface LyraMapInstance{getCanvas():HTMLCanvasElement;getCenter():{lng:
325
337
  */
326
338
  setMaxBounds?(bounds?:unknown):unknown;}
327
339
  /** A pan-constraining box, `[[west, south], [east, north]]`, in the order maplibre-gl takes. */
328
- export type LyraMapBounds=readonly[readonly[number,number],readonly[number,number]];export declare function buildGeoJsonPropertyDiff(previous:unknown,next:unknown):MapLibreGeoJsonDiff|null;export interface LyraMapEventMap{'lr-map-load':CustomEvent<null>;'lr-map-marker-activate':CustomEvent<LyraMapMarkerActivationDetail>;'lr-map-click':CustomEvent<{readonly lngLat:readonly[number,number];readonly feature:Feature|undefined;
340
+ export type LyraMapBounds=readonly[readonly[number,number],readonly[number,number]];export declare function buildGeoJsonPropertyDiff(previous:unknown,next:unknown):MapLibreGeoJsonDiff|null;
341
+ /**
342
+ * Complete proposed visibility snapshot for one map legend category, mirroring
343
+ * `LyraChartLegendVisibilityChangeDetail`'s shape so a host that already reconciles a chart legend
344
+ * reconciles this one the same way. Frozen, and detached from the component's own state.
345
+ */
346
+ export interface LyraMapLegendToggleDetail{
347
+ /** The activated row's `value` category key, exactly as it was admitted. */
348
+ readonly value:string;
349
+ /** Proposed visibility of `value` after this toggle. */
350
+ readonly visible:boolean;
351
+ /** Complete canonical proposed hidden-category set, in the order it would be committed. */
352
+ readonly hiddenCategories:readonly string[];}export interface LyraMapEventMap{'lr-map-load':CustomEvent<null>;'lr-map-marker-activate':CustomEvent<LyraMapMarkerActivationDetail>;'lr-map-legend-toggle':CustomEvent<LyraMapLegendToggleDetail>;'lr-map-click':CustomEvent<{readonly lngLat:readonly[number,number];readonly feature:Feature|undefined;
329
353
  /** Which layer `feature` was hit on, so a click is attributable when both a choropleth and
330
354
  * `dataLayers` are painted. `'cluster'` marks a hit on a clustered entry's aggregate circle,
331
355
  * whose `point_count`/`cluster_id` properties describe the group rather than one feature.
@@ -370,6 +394,17 @@ readonly sourceId:string|undefined;}>;}
370
394
  *
371
395
  * @customElement lr-map
372
396
  * @event lr-map-load - Fired once the underlying maplibregl.Map loads.
397
+ * @event lr-map-legend-toggle - **Cancelable.** Fired once when an interactive legend row is
398
+ * activated by pointer or by Enter/Space, carrying the immutable
399
+ * `detail: { value, visible, hiddenCategories }` -- the activated category key, its proposed
400
+ * visibility, and the complete proposed hidden set in the order it would be committed.
401
+ * `preventDefault()` is a real veto: `hiddenCategories` is not written, the row's `aria-pressed`
402
+ * does not change, the MapLibre paint is untouched, and nothing is announced, which is what lets
403
+ * a host own the set and write it itself. There is deliberately no second confirmation event:
404
+ * the committed state is `hiddenCategories`, which the host already observes, so a paired
405
+ * before/after vocabulary would be permanent public surface nobody asked for. A programmatic
406
+ * `hiddenCategories` assignment reconciles without emitting anything -- this event is a
407
+ * DOM-interaction proposal only.
373
408
  * @event lr-map-marker-activate - Fired once when an accepted declarative marker is activated by
374
409
  * pointer/click or by Enter/Space. The immutable detail carries its normalized `id`, validated
375
410
  * `lngLat`, accepted marker snapshot, and activation `source`.
@@ -384,12 +419,20 @@ readonly sourceId:string|undefined;}>;}
384
419
  * @csspart container - The MapLibre container. Its generated canvas is the actual focusable map
385
420
  * region and receives the host-first accessible name and effective locale.
386
421
  * @slot legend - Custom legend content, rendered inside the legend panel's own layout so it stays
387
- * positioned with the map instead of floating beside it.
422
+ * positioned with the map instead of floating beside it. Slotted content is never made
423
+ * interactive by `legendInteractive`, which only reaches rows projected from `legend`.
388
424
  * @csspart legend - The map legend.
389
425
  * @csspart legend-swatch - A legend color swatch, or the entry's glyph when it carries an `icon`
390
426
  * — in which case the swatch drops its color block and pattern overlay, keeps the `pattern`
391
427
  * border framing the glyph as its non-color cue, carries `data-icon="true"`, and paints the
392
- * glyph itself in the entry color.
428
+ * glyph itself in the entry color. It nests inside `legend-toggle` on an interactive row and
429
+ * stays `aria-hidden`/`inert` there, so it never contributes to the button's accessible name.
430
+ * @csspart legend-toggle - The `button` an interactive legend row renders around its swatch and
431
+ * label when `legendInteractive` is set and the row carries a `value`. Absent entirely when
432
+ * either is missing, so an unset map's legend markup is unchanged.
433
+ * @csspart legend-toggle-hidden - Second token carried alongside `legend-toggle` while that row's
434
+ * category is in `hiddenCategories`. State lives in the part name rather than a separate
435
+ * attribute, so `::part(legend-toggle-hidden)` is a reachable styling hook.
393
436
  * @csspart legend-gradient - The continuous ramp bar rendered from `legendGradient`.
394
437
  * @csspart legend-lo - The low endpoint caption of the `legendGradient` bar (mirrors `lr-heatmap`).
395
438
  * @csspart legend-hi - The high endpoint caption of the `legendGradient` bar (mirrors `lr-heatmap`).
@@ -414,6 +457,12 @@ readonly sourceId:string|undefined;}>;}
414
457
  * @cssprop [--lr-map-choropleth-fill-opacity=0.75] - Fill opacity for choropleth and polygon
415
458
  * `dataLayers` fills. Read from the resolved cascade whenever those layers are applied or painted
416
459
  * after a theme change.
460
+ * @cssprop [--lr-map-hidden-category-opacity=0.15] - Opacity a hidden category's points, point
461
+ * strokes and point icons are muted to in the rendered MapLibre paint. Read from the resolved
462
+ * cascade on every paint, because MapLibre draws to a WebGL canvas the CSS cascade never reaches.
463
+ * @cssprop [--lr-map-legend-hidden-swatch-opacity=0.5] - Opacity of a hidden interactive legend
464
+ * row's decorative swatch. Only the `aria-hidden` swatch dims; the label re-colors through the
465
+ * quiet text token instead, so it keeps AA contrast.
417
466
  * @cssprop [--lr-map-popup-close-button-hover-bg=var(--lr-color-brand-quiet)] - Hover background
418
467
  * of `popup-close-button`.
419
468
  * @cssprop [--lr-map-popup-close-button-hover-color=var(--lr-color-brand)] - Hover foreground of
@@ -422,6 +471,18 @@ readonly sourceId:string|undefined;}>;}
422
471
  * @cssprop [--lr-map-popup-close-button-active-color=var(--lr-color-brand)] - Pressed foreground
423
472
  * of `popup-close-button`.
424
473
  *
474
+ * The legend is read-only unless `legendInteractive` is set, which is opt-in for a reason: an
475
+ * unset map renders exactly the key it rendered before, with no button, no extra attribute and no
476
+ * extra MapLibre paint key. Only a row that carries its own `value` becomes a toggle -- the key is
477
+ * never derived from an `icon` record's `value`, which would silently make a row operable the
478
+ * author never marked. Each toggle is a native `button`, so it is one independent tab stop per row
479
+ * (a 100-row legend contributes 100, exactly as a 100-series `lr-chart` legend does) and it grows
480
+ * to the shared `--lr-icon-button-size` hit-area floor. Activation emits the cancelable
481
+ * `lr-map-legend-toggle`; there is deliberately no confirmation event, because the committed state
482
+ * is `hiddenCategories` and the host already observes it. A hidden category mutes its points,
483
+ * point strokes and point icons through `--lr-map-hidden-category-opacity`; a `kind: 'heatmap'`
484
+ * entry is deliberately out of scope, having no per-category field to mute.
485
+ *
425
486
  * No style or tile provider is selected implicitly. Set `mapStyle` explicitly before connection;
426
487
  * this prevents a bare component from making an undeclared third-party request.
427
488
  * @status stable
@@ -500,6 +561,30 @@ legendGradientHiLabel:string|null;
500
561
  /** Counts from the latest bounded legend normalization. `truncated` covers omitted rows or
501
562
  * shortened labels; the returned record is frozen and never aliases caller input. */
502
563
  get legendProjection():LyraMapLegendProjection;
564
+ /**
565
+ * Turns every legend row that carries a `value` into a keyboard-operable visibility toggle;
566
+ * rows without one stay inert. Default `false`, and an unset map renders exactly the read-only
567
+ * key it rendered before this property existed -- no button, no extra attribute, and no extra
568
+ * MapLibre paint key.
569
+ *
570
+ * Each toggle is an independently tabbable native `button`, so Enter and Space are the
571
+ * platform's own activation and no roving tabindex is involved. The consequence is stated
572
+ * rather than hidden: a 100-row interactive legend contributes 100 tab stops, exactly as a
573
+ * 100-series `lr-chart` legend does. Each row also grows to the `--lr-icon-button-size` hit-area
574
+ * floor; the legend panel's own `max-block-size`/`overflow: auto` contains the taller list.
575
+ */
576
+ legendInteractive:boolean;private _hiddenCategories;
577
+ /**
578
+ * Complete controlled set of muted category keys, mirroring `lr-chart`'s `hiddenDatasets`.
579
+ * Clone-owned and frozen; non-string, empty, whitespace-only and duplicate entries are dropped,
580
+ * and at most 100 keys are retained. Honoured on the first render and the first MapLibre paint,
581
+ * not only after a user toggle. An empty array deliberately means every category is visible.
582
+ *
583
+ * Controlled public state, so it deliberately survives a disconnect and reconnect: the
584
+ * "reset transient open-state in `disconnectedCallback()`" rule covers dropdown/preview/tooltip
585
+ * `@state`, not a documented property a host owns and re-reads.
586
+ */
587
+ get hiddenCategories():readonly string[];set hiddenCategories(value:readonly string[]);
503
588
  /** Optional GeoJSON choropleth layer and value-to-color configuration. */
504
589
  choropleth?:Readonly<LyraMapChoroplethLayer>;
505
590
  /** Point markers rendered over the map. Explicit IDs are unique-nonempty first-wins. An idless
@@ -530,7 +615,7 @@ label:string;
530
615
  private loading;
531
616
  /** Classified failure rendered as localized ordinary text and announced through the owner
532
617
  * document's assertive sink. */
533
- private failure?;private errorAnnouncementSink?;private loadLibrary;private visible;private intersectionObserver?;private containerEl?;private _map?;private _styleLoaded;private _appliedChoroplethSourceId?;private _appliedFillLayerId?;private _appliedDataLayerIds;
618
+ private failure?;private errorAnnouncementSink?;private legendAnnouncementSink?;private loadLibrary;private visible;private intersectionObserver?;private containerEl?;private _map?;private _styleLoaded;private _appliedChoroplethSourceId?;private _appliedFillLayerId?;private _appliedDataLayerIds;
534
619
  /**
535
620
  * The rendering shape (`'auto'`, a cluster signature, `'heatmap'`) each applied data layer was
536
621
  * built with, keyed identically to `_appliedDataLayerIds`.
@@ -543,7 +628,12 @@ private failure?;private errorAnnouncementSink?;private loadLibrary;private visi
543
628
  private _appliedDataLayerShapes;
544
629
  /** Last GeoJSON applied per resolved source id, so an update can be diffed against it rather
545
630
  * than replacing the whole source. Holds a reference, not a copy -- it is only ever compared. */
546
- private _appliedGeoJson;private _nextDataLayerId;private nextPointIconId;private appliedPointPaint;private appliedPointIcons;private _maplibreModule?;
631
+ private _appliedGeoJson;private _nextDataLayerId;private nextPointIconId;private appliedPointPaint;
632
+ /** Layer ids whose paint currently carries a muting opacity, so the first paint after the last
633
+ * category is un-hidden can restore it -- and a layer that was never muted keeps its paint
634
+ * object free of the key entirely. Keyed by layer id, not source id, because one source's
635
+ * circle and point-icon layers mute independently on different fields. */
636
+ private appliedPointMuting;private appliedPointIcons;private _maplibreModule?;
547
637
  /** True only after WebGL2 has been proved in the current owner-document realm. */
548
638
  private _webglReady;private _markerInstances;private _markerLabels;private _markerPopupIds;private readonly markerActivationDetails;private _configuredPopups;private _nextPopupId;private peerChromeObserver?;private observedPeerContainer?;private mapResizeObserver?;private observedMapContainer?;private _markerColors;private _connectGeneration;
549
639
  /** The underlying runtime `maplibregl.Map`, declared through Lyra's peer-neutral common-method
@@ -596,7 +686,9 @@ private get safeCenter();connectedCallback():void;disconnectedCallback():void;pr
596
686
  * below without risking a double construction.
597
687
  */
598
688
  private tryConstructMap;protected updated(changed:PropertyValues):void;protected willUpdate(changed:PropertyValues):void;
599
- /** Repaints token-derived MapLibre values without touching sources, layers, or map geometry. */
689
+ /** Repaints token-derived and visibility-derived MapLibre values without touching sources,
690
+ * layers, or map geometry -- which is exactly what a theme change and a `hiddenCategories`
691
+ * change each need. */
600
692
  private refreshThemePaint;private applyChoropleth;private choroplethColorExpression;
601
693
  /**
602
694
  * Keeps the choropleth out of every caller-controlled data-layer namespace. Repeatedly prefixing
@@ -630,7 +722,18 @@ private paintDataLayer;
630
722
  /** The pre-existing geometry split: polygons filled, lines/outlines stroked, points circled. */
631
723
  private applyGeometryLayers;
632
724
  /** Paint-only half of `applyGeometryLayers`. See `paintDataLayer` for why the halves are split. */
633
- private paintGeometryLayers;private lineColor;private paintPoints;private pointIconColor;private removePointIcons;private applyPointIcons;private paintPointIcons;
725
+ private paintGeometryLayers;private lineColor;
726
+ /**
727
+ * A `match` expression over `['get', field]` while any admitted category is hidden; a literal
728
+ * `1` on the first paint after the last category is un-hidden; and `undefined` whenever nothing
729
+ * is or was muted on `layerId` -- which is what leaves a `legendInteractive`-unset map
730
+ * byte-identical: the paint key is never written, so MapLibre keeps its own default and the
731
+ * layer's paint object gains no extra property.
732
+ *
733
+ * The flat `label, output` pair form is deliberately the shape `point.colors` already emits two
734
+ * lines above its own `match`, so this file speaks one expression idiom rather than two.
735
+ */
736
+ private mutedPointOpacity;private paintPoints;private pointIconColor;private removePointIcons;private applyPointIcons;private paintPointIcons;
634
737
  /**
635
738
  * `['step', ['get', 'point_count'], …]` over the authored cluster color breaks, or the layer's
636
739
  * own flat color when none were supplied.
@@ -686,4 +789,27 @@ private syncPeerChromeParts;private observePeerChrome;private syncPopupSemantics
686
789
  * holds fewer than two usable stops. Part names mirror `lr-heatmap`'s
687
790
  * `legend-lo`/`legend-hi` so a consumer styling both components learns one vocabulary.
688
791
  */
689
- private renderLegendGradient;render():TemplateResult;}declare global{interface HTMLElementTagNameMap{'lr-map':LyraMap;}}
792
+ /**
793
+ * The swatch-plus-label pair every legend row renders: directly inside the row when the row is
794
+ * inert, and inside the row's toggle button when `legendInteractive` has made it operable. One
795
+ * source of truth, so the two branches can never drift, and an unset map keeps rendering exactly
796
+ * the markup it rendered before the toggle existed.
797
+ */
798
+ private renderLegendRowContent;
799
+ /**
800
+ * Flips one category's visibility from a legend toggle activation.
801
+ *
802
+ * `hiddenCategories` is a key set, so every row carrying the activated key flips together --
803
+ * self-consistent by construction rather than by a per-row visibility flag that two rows
804
+ * describing one category could disagree about.
805
+ */
806
+ private toggleLegendCategory;
807
+ /**
808
+ * The state change belongs in a live region because the thing that changed -- the map, and the
809
+ * legend row's own styling -- is not the focused element, and `aria-pressed` alone only reports
810
+ * the button's new state once focus is already on it.
811
+ */
812
+ private announceLegendVisibility;
813
+ /** Acquired lazily on the first toggle, and re-acquired against a new owner document, so a map
814
+ * that never renders an interactive legend never mounts a live region at all. */
815
+ private syncLegendAnnouncementSink;private releaseLegendAnnouncementSink;private renderLegendGradient;render():TemplateResult;}declare global{interface HTMLElementTagNameMap{'lr-map':LyraMap;}}