@pdanpdan/virtual-scroll 0.2.1 → 0.3.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.
package/README.md CHANGED
@@ -57,6 +57,45 @@ import VirtualScroll from '@pdanpdan/virtual-scroll/VirtualScroll.vue';
57
57
  - Enables deep integration with your project's CSS-in-JS or specialized styling solutions.
58
58
  - Easier debugging of the component source in some IDEs.
59
59
 
60
+ ### 3. CDN Usage
61
+
62
+ You can use the library directly from a CDN like unpkg or jsdelivr.
63
+
64
+ ```html
65
+ <!-- Import Vue 3 first -->
66
+ <script src="https://unpkg.com/vue@3"></script>
67
+
68
+ <!-- Import VirtualScroll CSS -->
69
+ <link rel="stylesheet" href="https://unpkg.com/@pdanpdan/virtual-scroll/dist/virtual-scroll.css">
70
+
71
+ <!-- Import VirtualScroll JavaScript -->
72
+ <script src="https://unpkg.com/@pdanpdan/virtual-scroll"></script>
73
+
74
+ <div id="app">
75
+ <div style="height: 400px; overflow: auto;">
76
+ <virtual-scroll :items="items" :item-size="50">
77
+ <template #item="{ item, index }">
78
+ <div style="height: 50px;">{{ index }}: {{ item.label }}</div>
79
+ </template>
80
+ </virtual-scroll>
81
+ </div>
82
+ </div>
83
+
84
+ <script>
85
+ const { createApp, ref } = Vue;
86
+ const { VirtualScroll } = window.VirtualScroll;
87
+
88
+ createApp({
89
+ setup() {
90
+ const items = ref(Array.from({ length: 1000 }, (_, i) => ({ label: `Item ${i}` })));
91
+ return { items };
92
+ }
93
+ })
94
+ .component('VirtualScroll', VirtualScroll)
95
+ .mount('#app');
96
+ </script>
97
+ ```
98
+
60
99
  ## Basic Usage
61
100
 
62
101
  ```vue
@@ -91,54 +130,87 @@ const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, label: `Item ${
91
130
  </style>
92
131
  ```
93
132
 
94
- ## Props
133
+ ## Sizing Guide
134
+
135
+ The component offers flexible ways to define item and column sizes. Understanding how these options interact is key to achieving smooth scrolling and correct layout.
136
+
137
+ ### Sizing Options
138
+
139
+ | Option Type | `itemSize` / `columnWidth` | Performance | Description |
140
+ |-------------|----------------------------|-------------|-------------|
141
+ | **Fixed** | `number` (e.g., `50`) | **Best** | Every item has the exact same size. Calculations are *O(1)*. |
142
+ | **Array** | `number[]` (cols only) | **Great** | Each column has a fixed size from the array (cycles if shorter). |
143
+ | **Function** | `(item, index) => number` | **Good** | Size is known but varies per item. No `ResizeObserver` overhead unless it differs from measured size. |
144
+ | **Dynamic** | `0`, `null`, or `undefined` | **Fair** | Sizes are measured automatically via `ResizeObserver` after rendering. |
145
+
146
+ ### How Sizing Works
147
+
148
+ 1. **Initial Estimate**:
149
+ - If a **fixed size** or **function** is provided, it's used as the initial size.
150
+ - If **dynamic** is used, the component uses `defaultItemSize` (default: `40`) or `defaultColumnWidth` (default: `100`) as the initial estimate.
151
+ 2. **Measurement**:
152
+ - When an item is rendered, its actual size is measured using `ResizeObserver`.
153
+ - If the measured size differs from the estimate (by more than 0.5px), the internal Fenwick Tree is updated.
154
+ 3. **Refinement**:
155
+ - All subsequent item positions are automatically adjusted based on the new measurement.
156
+ - The total scrollable area (`totalWidth`/`totalHeight`) is updated to reflect the real content size.
157
+
158
+ ### Fallback Logic
159
+
160
+ - **Unset Props**: If `itemSize` or `columnWidth` are not provided, they default to `40` and `100` respectively (fixed).
161
+ - **Dynamic Fallback**: When using dynamic sizing, `defaultItemSize` and `defaultColumnWidth` act as the source of truth for items that haven't been rendered yet.
162
+ - **Function/Array Fallback**: If a function or array returns an invalid value, it falls back to the respective `default...` prop.
163
+
164
+ ### Recommendations for Smooth Scrolling
165
+
166
+ 1. **Accurate Estimates**: When using dynamic sizing, set `defaultItemSize` as close as possible to the *average* height of your items. This minimizes scrollbar "jumping".
167
+ 2. **Avoid 0 sizes**: Ensure your items have a minimum height/width (e.g., via CSS `min-height`). Items with 0 size might not be detected correctly by the virtualizer.
168
+ 3. **Box Sizing**: Use `box-sizing: border-box` on your items to ensure padding and borders are included in the measured size.
169
+ 4. **Manual Refresh**: If you change external state that affects a sizing function's output without changing the function reference itself, call `virtualScrollRef.refresh()` to force a full re-calculation.
170
+
171
+ ## Component Reference
172
+
173
+ The `VirtualScroll` component provides a declarative interface for virtualizing lists and grids. It automatically manages the rendering lifecycle of items, measures dynamic sizes, and handles complex scroll behaviors like stickiness and restoration.
95
174
 
96
- ### Core Configuration
175
+ ### Props
176
+
177
+ #### Core Configuration
97
178
  | Prop | Type | Default | Description |
98
179
  |------|------|---------|-------------|
99
180
  | `items` | `T[]` | Required | Array of items to be virtualized. |
100
- | `itemSize` | `number \| ((item: T, index: number) => number) \| null` | `50` | Fixed size of each item or a function that returns the size. Pass `0`, `null` or `undefined` for dynamic size detection. |
101
- | `direction` | `'vertical' \| 'horizontal' \| 'both'` | `'vertical'` | Direction of the scroll. |
102
- | `gap` | `number` | `0` | Gap between items in pixels (vertical). |
181
+ | `itemSize` | `number \| ((item: T, index: number) => number) \| null` | `40` | Fixed size or function. Pass `0`/`null` for dynamic. |
182
+ | `direction` | `'vertical' \| 'horizontal' \| 'both'` | `'vertical'` | Scroll direction. |
183
+ | `gap` | `number` | `0` | Spacing between items. |
103
184
 
104
185
  ### Grid Configuration (direction="both")
105
186
  | Prop | Type | Default | Description |
106
187
  |------|------|---------|-------------|
107
- | `columnCount` | `number` | `0` | Number of columns for bidirectional (grid) scroll. |
108
- | `columnWidth` | `number \| number[] \| ((index: number) => number) \| null` | `150` | Fixed width of columns or an array/function for column widths. Pass `0`, `null` or `undefined` for dynamic width. |
109
- | `columnGap` | `number` | `0` | Gap between columns in pixels. |
188
+ | `columnCount` | `number` | `0` | Number of columns. |
189
+ | `columnWidth` | `num \| num[] \| fn \| null` | `100` | Width for columns. |
190
+ | `columnGap` | `number` | `0` | Spacing between columns. |
110
191
 
111
- ### Feature-Specific Props
112
- | Prop | Type | Default | Description |
113
- |------|------|---------|-------------|
114
- | `stickyIndices` | `number[]` | `[]` | Indices of items that should stick to the top/start. Supports iOS-style pushing effect. |
115
- | `stickyHeader` | `boolean` | `false` | Whether the header slot content is sticky. If true, header size is measured and added to `scrollPaddingStart`. |
116
- | `stickyFooter` | `boolean` | `false` | Whether the footer slot content is sticky. If true, footer size is measured and added to `scrollPaddingEnd`. |
117
- | `loading` | `boolean` | `false` | Whether items are currently being loaded. Prevents multiple `load` events and displays the `#loading` slot. |
118
- | `loadDistance` | `number` | `200` | Distance from the end of the scrollable area to trigger `load` event. |
119
- | `restoreScrollOnPrepend` | `boolean` | `false` | Whether to automatically restore scroll position when items are prepended to the list. |
120
-
121
- ### Advanced Configuration
192
+ ### Features & Behavior
122
193
  | Prop | Type | Default | Description |
123
194
  |------|------|---------|-------------|
124
- | `container` | `HTMLElement \| Window \| null` | `host element` | The scrollable container element or window. |
125
- | `scrollPaddingStart` | `number \| { x?: number; y?: number; }` | `0` | Padding at the start of the scroll container. |
126
- | `scrollPaddingEnd` | `number \| { x?: number; y?: number; }` | `0` | Padding at the end of the scroll container. |
127
- | `containerTag` | `string` | `'div'` | The HTML tag to use for the root container. |
128
- | `wrapperTag` | `string` | `'div'` | The HTML tag to use for the items wrapper. |
129
- | `itemTag` | `string` | `'div'` | The HTML tag to use for each item. |
130
- | `bufferBefore` | `number` | `5` | Number of items to render before the visible viewport. |
131
- | `bufferAfter` | `number` | `5` | Number of items to render after the visible viewport. |
132
- | `ssrRange` | `{ start: number; end: number; colStart?: number; colEnd?: number; }` | `undefined` | Range of items to render for SSR. |
133
- | `initialScrollIndex` | `number` | `undefined` | Initial scroll index to jump to on mount. |
134
- | `initialScrollAlign` | `ScrollAlignment \| ScrollAlignmentOptions` | `'start'` | Alignment for the initial scroll index. |
135
-
136
- ### Development
195
+ | `stickyIndices` | `number[]` | `[]` | Indices of items that should remain sticky. |
196
+ | `stickyHeader` / `stickyFooter` | `boolean` | `false` | If true, measures and adds slot size to padding. |
197
+ | `ssrRange` | `object` | `undefined` | Items to pre-render on server. |
198
+ | `loading` | `boolean` | `false` | Shows loading state and prevents duplicate events. |
199
+ | `loadDistance` | `number` | `200` | Distance from end to trigger `load` event. |
200
+ | `restoreScrollOnPrepend` | `boolean` | `false` | Maintain position when items added to top. |
201
+ | `initialScrollIndex` | `number` | `undefined` | Index to jump to on mount. |
202
+ | `initialScrollAlign` | `string \| object` | `'start'` | Alignment for initial jump. |
203
+
204
+ ### Advanced & Performance
137
205
  | Prop | Type | Default | Description |
138
206
  |------|------|---------|-------------|
139
- | `defaultItemSize` | `number` | `50` | Default size for items before they are measured. |
140
- | `defaultColumnWidth` | `number` | `150` | Default width for columns before they are measured. |
141
- | `debug` | `boolean` | `false` | Enables debug visualization showing item indices and offsets. |
207
+ | `container` | `HTMLElement \| Window` | `host element` | The scrollable container element. |
208
+ | `scrollPaddingStart` / `End` | `num \| {x, y}` | `0` | Padding for scroll calculations. |
209
+ | `containerTag` / `wrapperTag` / `itemTag` | `string` | `'div'` | HTML tags for component parts. |
210
+ | `bufferBefore` / `bufferAfter` | `number` | `5` | Items to render outside the viewport. |
211
+ | `defaultItemSize` | `number` | `40` | Initial estimate for items. |
212
+ | `defaultColumnWidth` | `number` | `100` | Initial estimate for columns. |
213
+ | `debug` | `boolean` | `false` | Enables debug visualization. |
142
214
 
143
215
  ## Slots
144
216
 
@@ -165,72 +237,71 @@ const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, label: `Item ${
165
237
  ## Keyboard Navigation
166
238
 
167
239
  When the container is focused, it supports the following keys:
168
- - `Home` / `End`: Scroll to top/bottom or start/end of the list.
169
- - `ArrowUp` / `ArrowDown`: Scroll up/down by 40px.
170
- - `ArrowLeft` / `ArrowRight`: Scroll left/right by 40px.
240
+ - `Home`: Scroll to the beginning of the list (index 0).
241
+ - `End`: Scroll to the last item in the list.
242
+ - `ArrowUp` / `ArrowDown`: Scroll up/down by 40px (or `DEFAULT_ITEM_SIZE`).
243
+ - `ArrowLeft` / `ArrowRight`: Scroll left/right by 40px (or `DEFAULT_ITEM_SIZE`).
171
244
  - `PageUp` / `PageDown`: Scroll up/down (or left/right) by one viewport size.
172
245
 
173
246
  ## Methods (Exposed)
174
247
 
175
248
  - `scrollToIndex(rowIndex: number | null, colIndex: number | null, options?: ScrollAlignment | ScrollAlignmentOptions | ScrollToIndexOptions)`
176
- - `rowIndex`: Row index to scroll to.
177
- - `colIndex`: Column index to scroll to (for horizontal or grid).
249
+ - `rowIndex`: Row index to scroll to. Pass `null` to only scroll horizontally.
250
+ - `colIndex`: Column index to scroll to. Pass `null` to only scroll vertically.
178
251
  - `options`:
179
- - `align`: `'start' | 'center' | 'end' | 'auto'` or `{ x, y }` alignments.
252
+ - `align`: `'start' | 'center' | 'end' | 'auto'` or `{ x: ScrollAlignment, y: ScrollAlignment }`.
180
253
  - `behavior`: `'auto' | 'smooth'`.
181
254
  - `scrollToOffset(x: number | null, y: number | null, options?: { behavior?: 'auto' | 'smooth' })`
182
- - `x`: Pixel offset on X axis.
183
- - `y`: Pixel offset on Y axis.
255
+ - `x`: Pixel offset on X axis. Pass `null` to keep current position.
256
+ - `y`: Pixel offset on Y axis. Pass `null` to keep current position.
257
+ - `options`:
258
+ - `behavior`: `'auto' | 'smooth'`.
184
259
  - `refresh()`: Resets all dynamic measurements and re-initializes sizes from current items and props.
260
+ - `stopProgrammaticScroll()`: Immediately stops any active smooth scroll.
185
261
 
186
262
  ## Types
187
263
 
188
264
  ### ScrollDetails&lt;T&gt;
189
- ```typescript
190
- /* eslint-disable unused-imports/no-unused-vars */
191
- interface ScrollDetails<T = unknown> {
192
- items: Array<{
193
- item: T;
194
- index: number;
195
- offset: { x: number; y: number; };
196
- size: { width: number; height: number; };
197
- originalX: number;
198
- originalY: number;
199
- isSticky?: boolean;
200
- isStickyActive?: boolean;
201
- stickyOffset: { x: number; y: number; };
202
- }>;
203
- currentIndex: number;
204
- currentColIndex: number;
205
- scrollOffset: { x: number; y: number; };
206
- viewportSize: { width: number; height: number; };
207
- totalSize: { width: number; height: number; };
208
- isScrolling: boolean;
209
- isProgrammaticScroll: boolean;
210
- range: { start: number; end: number; };
211
- columnRange: { start: number; end: number; padStart: number; padEnd: number; };
212
- }
213
- ```
265
+
266
+ The full state of the virtualizer, emitted in the `scroll` event and available via the `scrollDetails` ref.
267
+
268
+ | Property | Type | Description |
269
+ |----------|------|-------------|
270
+ | `items` | `RenderedItem<T>[]` | List of items currently rendered with their offsets and sizes. |
271
+ | `currentIndex` | `number` | Index of the first item partially or fully visible in the viewport. |
272
+ | `currentColIndex` | `number` | Index of the first column partially or fully visible. |
273
+ | `scrollOffset` | `{ x: number, y: number }` | Current scroll position relative to content start. |
274
+ | `viewportSize` | `{ width: number, height: number }` | Dimensions of the visible area. |
275
+ | `totalSize` | `{ width: number, height: number }` | Total calculated size of all items and gaps. |
276
+ | `isScrolling` | `boolean` | Whether the container is currently being scrolled. |
277
+ | `isProgrammaticScroll` | `boolean` | Whether the current scroll was initiated by a method call. |
278
+ | `range` | `{ start: number, end: number }` | Current rendered item indices. |
279
+ | `columnRange` | `{ start: number, end: number, padStart: number, padEnd: number }` | Visible column range and paddings. |
214
280
 
215
281
  ### RenderedItem&lt;T&gt;
216
- ```typescript
217
- /* eslint-disable unused-imports/no-unused-vars */
218
- interface RenderedItem<T = unknown> {
219
- item: T;
220
- index: number;
221
- offset: { x: number; y: number; };
222
- size: { width: number; height: number; };
223
- originalX: number;
224
- originalY: number;
225
- isSticky?: boolean;
226
- isStickyActive?: boolean;
227
- stickyOffset: { x: number; y: number; };
228
- }
229
- ```
282
+
283
+ | Property | Type | Description |
284
+ |----------|------|-------------|
285
+ | `item` | `T` | The data item. |
286
+ | `index` | `number` | The item's index in the original array. |
287
+ | `offset` | `{ x: number, y: number }` | Calculated position for rendering. |
288
+ | `size` | `{ width: number, height: number }` | Measured or estimated size. |
289
+ | `originalX` / `originalY` | `number` | Raw offsets before sticky adjustments. |
290
+ | `isSticky` | `boolean` | Whether the item is configured to be sticky. |
291
+ | `isStickyActive` | `boolean` | Whether the item is currently stuck. |
292
+ | `stickyOffset` | `{ x: number, y: number }` | Offset applied for the pushing effect. |
293
+
294
+ ### ScrollAlignment
295
+
296
+ - `'start'`: Aligns the item to the top/left of the viewport.
297
+ - `'center'`: Aligns the item to the center of the viewport.
298
+ - `'end'`: Aligns the item to the bottom/right of the viewport.
299
+ - `'auto'`: Smart alignment - if the item is already visible, do nothing; if it's above/left, align to `start`; if it's below/right, align to `end`.
230
300
 
231
301
  ## CSS Classes
232
302
 
233
303
  - `.virtual-scroll-container`: Root container.
304
+ - `.virtual-scroll--vertical`, `.virtual-scroll--horizontal`, `.virtual-scroll--both`: Direction modifier.
234
305
  - `.virtual-scroll-wrapper`: Items wrapper.
235
306
  - `.virtual-scroll-item`: Individual item.
236
307
  - `.virtual-scroll-header` / `.virtual-scroll-footer`: Header/Footer slots.
@@ -239,6 +310,7 @@ interface RenderedItem<T = unknown> {
239
310
  - `.virtual-scroll--hydrated`: Applied when client-side mount is complete.
240
311
  - `.virtual-scroll--window`: Applied when using window/body scroll.
241
312
  - `.virtual-scroll--table`: Applied when `containerTag="table"` is used.
313
+ - `.virtual-scroll--debug`: Applied when debug mode is enabled.
242
314
 
243
315
  ## SSR Support
244
316
 
@@ -264,28 +336,50 @@ When `ssrRange` is provided:
264
336
 
265
337
  For advanced use cases, you can use the underlying logic via the `useVirtualScroll` composable.
266
338
 
339
+ ### Example
340
+
267
341
  ```typescript
342
+ /* eslint-disable unused-imports/no-unused-vars */
268
343
  import { useVirtualScroll } from '@pdanpdan/virtual-scroll';
269
344
  import { computed, ref } from 'vue';
270
345
 
271
346
  const items = ref([ { id: 1 }, { id: 2 } ]);
347
+ const containerRef = ref<HTMLElement | null>(null);
348
+
272
349
  const props = computed(() => ({
273
350
  items: items.value,
274
351
  itemSize: 50,
352
+ container: containerRef.value,
275
353
  direction: 'vertical' as const,
276
354
  }));
277
355
 
278
- const { renderedItems, scrollDetails } = useVirtualScroll(props);
279
- console.log(renderedItems.value, scrollDetails.value);
356
+ const { renderedItems, scrollDetails, totalHeight } = useVirtualScroll(props);
280
357
  ```
281
358
 
359
+ ### Return Values
360
+
361
+ | Member | Type | Description |
362
+ |--------|------|-------------|
363
+ | `renderedItems` | `Ref<RenderedItem<T>[]>` | List of items to be rendered. |
364
+ | `scrollDetails` | `Ref<ScrollDetails<T>>` | Full state of the virtualizer. |
365
+ | `totalWidth` / `totalHeight` | `Ref<number>` | Calculated total dimensions. |
366
+ | `columnRange` | `Ref<object>` | Visible column range. |
367
+ | `isHydrated` | `Ref<boolean>` | Whether hydration is complete. |
368
+ | `scrollToIndex` | `Function` | Programmatic scroll to index. |
369
+ | `scrollToOffset` | `Function` | Programmatic scroll to offset. |
370
+ | `refresh` | `Function` | Resets and recalculates all sizes. |
371
+ | `updateItemSize` | `Function` | Manually update an item's size. |
372
+
282
373
  ## Utilities
283
374
 
284
- The library exports several utility functions for scroll-related checks:
375
+ The library exports several utility functions and classes:
285
376
 
286
- - `isElement(container: HTMLElement | Window | null | undefined): container is HTMLElement`: Checks if the container is an `HTMLElement` (and not `Window`).
287
- - `isScrollableElement(target: EventTarget | null): target is HTMLElement`: Checks if the target is an `HTMLElement` with scroll properties.
288
- - `isScrollToIndexOptions(options: unknown): options is ScrollToIndexOptions`: Checks if the options object is a full `ScrollToIndexOptions` object.
377
+ - `isElement(val: any): val is HTMLElement`: Checks if value is an `HTMLElement` (excludes `window`).
378
+ - `isScrollableElement(val: any): val is HTMLElement | Window`: Checks if value has scroll properties.
379
+ - `isScrollToIndexOptions(val: any): val is ScrollToIndexOptions`: Type guard for scroll options.
380
+ - `getPaddingX / getPaddingY`: Internal helpers for extraction of padding from props.
381
+ - `FenwickTree`: The underlying data structure for efficient size and offset management.
382
+ - `DEFAULT_ITEM_SIZE / DEFAULT_COLUMN_WIDTH / DEFAULT_BUFFER`: The default values used by the library.
289
383
 
290
384
  ## License
291
385
 
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`);var t=class{tree;values;constructor(e){this.tree=new Float64Array(e+1),this.values=new Float64Array(e)}update(e,t){if(!(e<0||e>=this.values.length))for(this.values[e]=this.values[e]+t,e++;e<this.tree.length;)this.tree[e]=this.tree[e]+t,e+=e&-e}query(e){let t=0;for(;e>0;)t+=this.tree[e]||0,e-=e&-e;return t}set(e,t){e<0||e>=this.values.length||(this.values[e]=t)}get length(){return this.values.length}get(e){return this.values[e]||0}getValues(){return this.values}findLowerBound(e){let t=0,n=this.tree.length,r=1<<Math.floor(Math.log2(n-1));for(;r>0;){let i=t+r;if(i<n){let n=this.tree[i]||0;n<=e&&(t=i,e-=n)}r>>=1}return t}rebuild(){this.tree.fill(0);for(let e=0;e<this.values.length;e++)this.tree[e+1]=this.values[e]||0;for(let e=1;e<this.tree.length;e++){let t=e+(e&-e);t<this.tree.length&&(this.tree[t]=this.tree[t]+this.tree[e])}}resize(e){if(e===this.values.length)return;let t=new Float64Array(e);t.set(this.values.subarray(0,Math.min(e,this.values.length))),this.values=t,this.tree=new Float64Array(e+1),this.rebuild()}shift(e){if(e===0)return;let t=this.values.length,n=new Float64Array(t);e>0?n.set(this.values.subarray(0,Math.min(t-e,this.values.length)),e):n.set(this.values.subarray(-e)),this.values=n,this.rebuild()}};function n(e){return!!e&&`getBoundingClientRect`in e}function r(e){return!!e&&`scrollLeft`in e}function i(e){return typeof e==`object`&&!!e&&(`align`in e||`behavior`in e||`isCorrection`in e)}function a(e,t){return typeof e==`object`&&e?e.x||0:t===`horizontal`&&e||0}function o(e,t){return typeof e==`object`&&e?e.y||0:(t===`vertical`||t===`both`)&&e||0}const s=40,c=100,l=5;function u(s){let c=(0,e.ref)(0),l=(0,e.ref)(0),u=(0,e.ref)(!1),d=(0,e.ref)(!1),f=(0,e.ref)(!1),p=(0,e.ref)(!1),m=(0,e.ref)(0),h=(0,e.ref)(0),g=(0,e.reactive)({x:0,y:0}),_,v=(0,e.ref)(!1),y=new t(s.value.items.length),b=new t(s.value.items.length),x=new t(s.value.columnCount||0),S=(0,e.ref)(0),C=new Uint8Array,w=new Uint8Array,T=new Uint8Array,E=(0,e.ref)(null),D=(0,e.ref)(!1),O=[],k=(0,e.computed)(()=>s.value.itemSize===void 0||s.value.itemSize===null||s.value.itemSize===0),A=(0,e.computed)(()=>s.value.columnWidth===void 0||s.value.columnWidth===null||s.value.columnWidth===0),j=(0,e.computed)(()=>typeof s.value.itemSize==`number`&&s.value.itemSize>0?s.value.itemSize:null),M=(0,e.computed)(()=>s.value.defaultItemSize||j.value||40),N=(0,e.computed)(()=>[...s.value.stickyIndices||[]].sort((e,t)=>e-t)),P=(0,e.computed)(()=>{if(S.value,!d.value&&s.value.ssrRange&&!p.value){let{start:e=0,end:t=0,colStart:n=0,colEnd:r=0}=s.value.ssrRange,i=s.value.columnCount||0;if(s.value.direction===`both`){if(i<=0)return 0;let e=r||i,t=x.query(e)-x.query(n);return Math.max(0,t-(e>n&&s.value.columnGap||0))}if(s.value.direction===`horizontal`){if(j.value!==null){let n=t-e;return Math.max(0,n*(j.value+(s.value.columnGap||0))-(n>0&&s.value.columnGap||0))}let n=y.query(t)-y.query(e);return Math.max(0,n-(t>e&&s.value.columnGap||0))}}if(s.value.direction===`both`){let e=s.value.columnCount||0;if(e<=0)return 0;let t=x.query(e);return Math.max(0,t-(s.value.columnGap||0))}if(s.value.direction===`vertical`)return 0;if(j.value!==null){let e=s.value.items.length;return Math.max(0,e*(j.value+(s.value.columnGap||0))-(e>0&&s.value.columnGap||0))}let e=y.query(s.value.items.length);return Math.max(0,e-(s.value.items.length>0&&s.value.columnGap||0))}),F=(0,e.computed)(()=>{if(S.value,!d.value&&s.value.ssrRange&&!p.value){let{start:e,end:t}=s.value.ssrRange;if(s.value.direction===`vertical`||s.value.direction===`both`){if(j.value!==null){let n=t-e;return Math.max(0,n*(j.value+(s.value.gap||0))-(n>0&&s.value.gap||0))}let n=b.query(t)-b.query(e);return Math.max(0,n-(t>e&&s.value.gap||0))}}if(s.value.direction===`horizontal`)return 0;if(j.value!==null){let e=s.value.items.length;return Math.max(0,e*(j.value+(s.value.gap||0))-(e>0&&s.value.gap||0))}let e=b.query(s.value.items.length);return Math.max(0,e-(s.value.items.length>0&&s.value.gap||0))}),I=(0,e.computed)(()=>{let e=s.value.direction===`horizontal`||s.value.direction===`both`?a(s.value.scrollPaddingStart,s.value.direction):0;return Math.max(0,c.value+e-g.x)}),L=(0,e.computed)(()=>{let e=s.value.direction===`vertical`||s.value.direction===`both`?o(s.value.scrollPaddingStart,s.value.direction):0;return Math.max(0,l.value+e-g.y)}),R=e=>{S.value;let t=s.value.columnWidth;if(typeof t==`number`&&t>0)return t;if(Array.isArray(t)&&t.length>0){let n=t[e%t.length];return n!=null&&n>0?n:s.value.defaultColumnWidth||100}return typeof t==`function`?t(e):x.get(e)||s.value.defaultColumnWidth||100},z=(e,t,d)=>{let f=typeof d==`object`&&d&&`isCorrection`in d?d.isCorrection:!1;f||(E.value={rowIndex:e,colIndex:t,options:d});let p=s.value.container||window,_=j.value,S=s.value.gap||0,C=s.value.columnGap||0,w,T;i(d)?(w=d.align,T=d.behavior):w=d;let D=(typeof w==`object`?w.x:w)||`auto`,O=(typeof w==`object`?w.y:w)||`auto`,k=a(s.value.scrollPaddingStart,s.value.direction),A=a(s.value.scrollPaddingEnd,s.value.direction),M=o(s.value.scrollPaddingStart,s.value.direction),N=o(s.value.scrollPaddingEnd,s.value.direction),R=s.value.direction===`vertical`||s.value.direction===`both`,z=s.value.direction===`horizontal`||s.value.direction===`both`,B=m.value-(z?k+A:0),V=h.value-(R?M+N:0),H=I.value,U=L.value,W=0,G=0;if(e!=null&&(e>=s.value.items.length?(U=F.value,G=0):(U=_===null?b.query(e):e*(_+S),G=_===null?b.get(e)-S:_),O===`start`||(O===`center`?U-=(V-G)/2:O===`end`?U-=V-G:U>=L.value&&U+G<=L.value+V||U<L.value||(U-=V-G))),t!=null){let e=s.value.columnCount||0;t>=e&&e>0?(H=P.value,W=0):s.value.direction===`horizontal`?(H=_===null?y.query(t):t*(_+C),W=_===null?y.get(t)-C:_):(H=x.query(t),W=x.get(t)-C),D===`start`||(D===`center`?H-=(B-W)/2:D===`end`?H-=B-W:H>=I.value&&H+W<=I.value+B||H<I.value||(H-=B-W))}H=Math.max(0,Math.min(H,Math.max(0,P.value-B))),U=Math.max(0,Math.min(U,Math.max(0,F.value-V)));let K=H+g.x-(z?k:0),q=U+g.y-(R?M:0),J=t==null||Math.abs(I.value-H)<1,Y=e==null||Math.abs(L.value-U)<1;if(!J||!Y){let r=0,i=0,a=0,o=0,s=0,c=0;if(typeof window<`u`){if(p===window?(r=window.scrollX,i=window.scrollY,a=document.documentElement.scrollWidth,o=document.documentElement.scrollHeight,s=window.innerWidth,c=window.innerHeight):n(p)&&(r=p.scrollLeft,i=p.scrollTop,a=p.scrollWidth,o=p.scrollHeight,s=p.clientWidth,c=p.clientHeight),!J&&t!=null){let e=r<=1&&K<=1,t=r>=a-s-1&&K>=a-s-1;(e||t)&&(J=!0)}if(!Y&&e!=null){let e=i<=1&&q<=1,t=i>=o-c-1&&q>=o-c-1;(e||t)&&(Y=!0)}}}let X=f?`auto`:T||`smooth`;if(v.value=!0,typeof window<`u`&&p===window)window.scrollTo({left:t==null?void 0:Math.max(0,K),top:e==null?void 0:Math.max(0,q),behavior:X});else if(r(p)){let n={behavior:X};t!=null&&(n.left=Math.max(0,K)),e!=null&&(n.top=Math.max(0,q)),typeof p.scrollTo==`function`?p.scrollTo(n):(n.left!==void 0&&(p.scrollLeft=n.left),n.top!==void 0&&(p.scrollTop=n.top))}(X===`auto`||X===void 0)&&(t!=null&&(c.value=Math.max(0,K)),e!=null&&(l.value=Math.max(0,q))),J&&Y&&!u.value&&(E.value=null)},B=(e,t,n)=>{let i=s.value.container||window;v.value=!0;let u=s.value.direction===`vertical`||s.value.direction===`both`,d=s.value.direction===`horizontal`||s.value.direction===`both`,f=a(s.value.scrollPaddingStart,s.value.direction),p=o(s.value.scrollPaddingStart,s.value.direction),_=a(s.value.scrollPaddingEnd,s.value.direction),y=o(s.value.scrollPaddingEnd,s.value.direction),b=m.value-(d?f+_:0),x=h.value-(u?p+y:0),S=e==null?null:d?Math.max(0,Math.min(e,Math.max(0,P.value-b))):Math.max(0,e),C=t==null?null:u?Math.max(0,Math.min(t,Math.max(0,F.value-x))):Math.max(0,t),w=typeof window<`u`&&i===window?window.scrollX:i.scrollLeft,T=typeof window<`u`&&i===window?window.scrollY:i.scrollTop,E=S===null?w:S+g.x-(d?f:0),D=C===null?T:C+g.y-(u?p:0);if(typeof window<`u`&&i===window)window.scrollTo({left:e==null?void 0:E,top:t==null?void 0:D,behavior:n?.behavior||`auto`});else if(r(i)){let r={behavior:n?.behavior||`auto`};e!=null&&(r.left=E),t!=null&&(r.top=D),typeof i.scrollTo==`function`?i.scrollTo(r):(r.left!==void 0&&(i.scrollLeft=r.left),r.top!==void 0&&(i.scrollTop=r.top))}(n?.behavior===`auto`||n?.behavior===void 0)&&(e!=null&&(c.value=E),t!=null&&(l.value=D))},V=()=>{let t=s.value.items,n=t.length,r=s.value.columnCount||0;if(y.resize(n),b.resize(n),x.resize(r),w.length!==n){let e=new Uint8Array(n);e.set(w.subarray(0,Math.min(n,w.length))),w=e}if(T.length!==n){let e=new Uint8Array(n);e.set(T.subarray(0,Math.min(n,T.length))),T=e}if(C.length!==r){let e=new Uint8Array(r);e.set(C.subarray(0,Math.min(r,C.length))),C=e}let i=0;if(s.value.restoreScrollOnPrepend&&O.length>0&&n>O.length){let e=O[0];if(e!==void 0){for(let r=1;r<=n-O.length;r++)if(t[r]===e){i=r;break}}}if(i>0){y.shift(i),b.shift(i),E.value&&E.value.rowIndex!==null&&E.value.rowIndex!==void 0&&(E.value.rowIndex+=i);let r=new Uint8Array(n),a=new Uint8Array(n);r.set(w.subarray(0,Math.min(n-i,w.length)),i),a.set(T.subarray(0,Math.min(n-i,T.length)),i),w=r,T=a;let o=s.value.gap||0,c=s.value.columnGap||0,l=0,u=0;for(let e=0;e<i;e++){let n=typeof s.value.itemSize==`function`?s.value.itemSize(t[e],e):M.value;s.value.direction===`horizontal`?l+=n+c:u+=n+o}(l>0||u>0)&&(0,e.nextTick)(()=>{B(l>0?I.value+l:null,u>0?L.value+u:null,{behavior:`auto`})})}if(r>0){let e=s.value.columnGap||0,t=!1;for(let n=0;n<r;n++){let r=R(n),i=x.get(n),a=C[n]===1;if(!A.value||!a||i===0){let a=r+e;Math.abs(i-a)>.5?(x.set(n,a),C[n]=A.value?0:1,t=!0):A.value||(C[n]=1)}}t&&x.rebuild()}let a=s.value.gap||0,o=s.value.columnGap||0,c=!1;for(let e=0;e<n;e++){let t=s.value.items[e],n=y.get(e),r=b.get(e),i=typeof s.value.itemSize==`function`?s.value.itemSize(t,e):M.value,l=s.value.direction===`vertical`,u=s.value.direction===`horizontal`,d=s.value.direction===`both`,f=u?i+o:0,p=l||d?i+a:0,m=w[e]===1,h=T[e]===1;u?(!k.value||!m||n===0)&&(Math.abs(n-f)>.5?(y.set(e,f),w[e]=k.value?0:1,c=!0):k.value||(w[e]=1)):n!==0&&(y.set(e,0),w[e]=0,c=!0),l||d?(!k.value||!h||r===0)&&(Math.abs(r-p)>.5?(b.set(e,p),T[e]=k.value?0:1,c=!0):k.value||(T[e]=1)):r!==0&&(b.set(e,0),T[e]=0,c=!0)}c&&(y.rebuild(),b.rebuild()),O=[...t],D.value=!0,S.value++},H=()=>{if(s.value.hostElement&&typeof window<`u`){let e=s.value.hostElement.getBoundingClientRect(),t=s.value.container||window,r=0,i=0;if(t===window)r=e.left+window.scrollX,i=e.top+window.scrollY;else if(t===s.value.hostElement)r=0,i=0;else if(n(t)){let n=t.getBoundingClientRect();r=e.left-n.left+t.scrollLeft,i=e.top-n.top+t.scrollTop}(Math.abs(g.x-r)>.1||Math.abs(g.y-i)>.1)&&(g.x=r,g.y=i)}};(0,e.watch)([()=>s.value.items,()=>s.value.direction,()=>s.value.columnCount,()=>s.value.columnWidth,()=>s.value.itemSize,()=>s.value.gap,()=>s.value.columnGap,()=>s.value.defaultItemSize,()=>s.value.defaultColumnWidth],V,{immediate:!0}),(0,e.watch)(()=>[s.value.container,s.value.hostElement],()=>{H()});let U=(0,e.computed)(()=>{if(S.value,(!d.value||f.value)&&s.value.ssrRange)return{start:s.value.ssrRange.start,end:s.value.ssrRange.end};let e=s.value.direction||`vertical`,t=s.value.ssrRange&&!u.value?0:s.value.bufferBefore??5,n=s.value.bufferAfter??5,r=s.value.gap||0,i=s.value.columnGap||0,c=j.value,l=a(s.value.scrollPaddingStart,e),p=a(s.value.scrollPaddingEnd,e),g=o(s.value.scrollPaddingStart,e),_=o(s.value.scrollPaddingEnd,e),v=e===`vertical`||e===`both`,x=e===`horizontal`||e===`both`,C=m.value-(x?l+p:0),w=h.value-(v?g+_:0),T=0,E=s.value.items.length;if(v)if(c!==null)T=Math.floor(L.value/(c+r)),E=Math.ceil((L.value+w)/(c+r));else{T=b.findLowerBound(L.value);let e=b.query(T),t=T;for(;t<s.value.items.length&&e<L.value+w;)e=b.query(++t);E=t}else if(c!==null)T=Math.floor(I.value/(c+i)),E=Math.ceil((I.value+C)/(c+i));else{T=y.findLowerBound(I.value);let e=y.query(T),t=T;for(;t<s.value.items.length&&e<I.value+C;)e=y.query(++t);E=t}return{start:Math.max(0,T-t),end:Math.min(s.value.items.length,E+n)}}),W=(0,e.computed)(()=>{S.value;let e=j.value,t=s.value.gap||0,n=s.value.columnGap||0;return s.value.direction===`horizontal`?e===null?y.findLowerBound(I.value):Math.floor(I.value/(e+n)):e===null?b.findLowerBound(L.value):Math.floor(L.value/(e+t))}),G=(0,e.computed)(()=>{S.value;let{start:e,end:t}=U.value,n=[],r=j.value,i=s.value.gap||0,a=s.value.columnGap||0,o=N.value,c=new Set;for(let n=e;n<t;n++)c.add(n);if(d.value||!s.value.ssrRange){let n=W.value,r,i=0,a=o.length-1;for(;i<=a;){let e=i+a>>>1;o[e]<n?(r=o[e],i=e+1):a=e-1}r!==void 0&&c.add(r);for(let n of o)n>=e&&n<t&&c.add(n)}let l=Array.from(c).sort((e,t)=>e-t),u=s.value.ssrRange?.start||0,f=s.value.ssrRange?.colStart||0,p=0,g=0;!d.value&&s.value.ssrRange&&(g=s.value.direction===`vertical`||s.value.direction===`both`?r===null?b.query(u):u*(r+i):0,s.value.direction===`horizontal`?p=r===null?y.query(f):f*(r+a):s.value.direction===`both`&&(p=x.query(f)));for(let e of l){let t=s.value.items[e];if(t===void 0)continue;let c=0,l=0,u=0,d=0;s.value.direction===`horizontal`?(c=r===null?y.query(e):e*(r+a),u=r===null?y.get(e)-a:r,d=h.value):(l=(s.value.direction===`vertical`||s.value.direction===`both`)&&r!==null?e*(r+i):b.query(e),d=r===null?b.get(e)-i:r,u=s.value.direction===`both`?P.value:m.value);let f=o.includes(e),_=c,v=l,x=!1,S={x:0,y:0};if(f){if(s.value.direction===`vertical`||s.value.direction===`both`){if(L.value>v){x=!0;let t,n=0,a=o.length-1;for(;n<=a;){let r=n+a>>>1;o[r]>e?(t=o[r],a=r-1):n=r+1}if(t!==void 0){let e=(r===null?b.query(t):t*(r+i))-L.value;e<d&&(S.y=-(d-e))}}}else if(s.value.direction===`horizontal`&&I.value>_){x=!0;let t,n=0,i=o.length-1;for(;n<=i;){let r=n+i>>>1;o[r]>e?(t=o[r],i=r-1):n=r+1}if(t!==void 0){let e=(r===null?y.query(t):t*(r+a))-I.value;e<u&&(S.x=-(u-e))}}}n.push({item:t,index:e,offset:{x:_-p,y:v-g},size:{width:u,height:d},originalX:_,originalY:v,isSticky:f,isStickyActive:x,stickyOffset:S})}return n}),K=(0,e.computed)(()=>{S.value;let e=s.value.columnCount||0;if(!e)return{start:0,end:0,padStart:0,padEnd:0};if((!d.value||f.value)&&s.value.ssrRange){let{colStart:t=0,colEnd:n=0}=s.value.ssrRange;return{start:Math.max(0,t),end:Math.min(e,n||e),padStart:0,padEnd:0}}let t=x.findLowerBound(I.value),n=x.query(t),r=t;for(;r<e&&n<I.value+m.value;)n=x.query(++r);let i=s.value.ssrRange&&!u.value?0:2,a=Math.max(0,t-i),o=Math.min(e,r+i);return{start:a,end:o,padStart:x.query(a),padEnd:x.query(e)-x.query(o)}}),q=(0,e.computed)(()=>{S.value;let e=j.value,t=s.value.columnGap||0,n=0;return(s.value.direction===`horizontal`||s.value.direction===`both`)&&(n=e===null?y.findLowerBound(I.value):Math.floor(I.value/(e+t))),{items:G.value,currentIndex:W.value,currentColIndex:n,scrollOffset:{x:I.value,y:L.value},viewportSize:{width:m.value,height:h.value},totalSize:{width:P.value,height:F.value},isScrolling:u.value,isProgrammaticScroll:v.value,range:U.value,columnRange:K.value}}),J=()=>{v.value=!1,E.value=null},Y=e=>{let t=e.target;typeof window>`u`||(t===window||t===document?(c.value=window.scrollX,l.value=window.scrollY):r(t)&&(c.value=t.scrollLeft,l.value=t.scrollTop),u.value||=(v.value||(E.value=null),!0),clearTimeout(_),_=setTimeout(()=>{u.value=!1,v.value=!1},250))},X=e=>{let t=!1,n=s.value.gap||0,r=s.value.columnGap||0;for(let{index:i,inlineSize:a,blockSize:o,element:c}of e){if((k.value||typeof s.value.itemSize==`function`)&&i>=0){if(s.value.direction===`horizontal`){let e=y.get(i),n=a+r;(!w[i]||Math.abs(n-e)>.5)&&(y.update(i,n-e),w[i]=1,t=!0)}if(s.value.direction===`vertical`||s.value.direction===`both`){let e=b.get(i),r=o+n;s.value.direction,(!T[i]||Math.abs(r-e)>.5)&&(b.update(i,r-e),T[i]=1,t=!0)}}let e=A.value||typeof s.value.columnWidth==`function`;if(s.value.direction===`both`&&c&&s.value.columnCount&&e){let e=c.dataset.colIndex===void 0?Array.from(c.querySelectorAll(`[data-col-index]`)):[c];for(let n of e){let e=Number.parseInt(n.dataset.colIndex,10);if(e>=0&&e<(s.value.columnCount||0)){let i=n.offsetWidth,a=x.get(e),o=i+r;Math.abs(a-o)>.5&&(x.update(e,o-a),C[e]=1,t=!0)}}}}t&&S.value++},ee=(e,t,n,r)=>{X([{index:e,inlineSize:t,blockSize:n,element:r}])},Z=()=>{if(E.value&&!f.value){let{rowIndex:e,colIndex:t,options:n}=E.value;z(e,t,i(n)?{...n,isCorrection:!0}:{align:n,isCorrection:!0})}};(0,e.watch)(S,Z),(0,e.watch)(u,e=>{e||Z()});let Q=null,te=e=>{if(!e||typeof window>`u`)return;let t=e===window?document:e;if(t.addEventListener(`scroll`,Y,{passive:!0}),e===window){m.value=window.innerWidth,h.value=window.innerHeight,c.value=window.scrollX,l.value=window.scrollY;let e=()=>{m.value=window.innerWidth,h.value=window.innerHeight,H()};return window.addEventListener(`resize`,e),()=>{t.removeEventListener(`scroll`,Y),window.removeEventListener(`resize`,e)}}else return m.value=e.clientWidth,h.value=e.clientHeight,c.value=e.scrollLeft,l.value=e.scrollTop,Q=new ResizeObserver(t=>{for(let n of t)n.target===e&&(m.value=e.clientWidth,h.value=e.clientHeight,H())}),Q.observe(e),()=>{t.removeEventListener(`scroll`,Y),Q?.disconnect()}},$;return(0,e.getCurrentInstance)()&&((0,e.onMounted)(()=>{p.value=!0,(0,e.watch)(()=>s.value.container,e=>{$?.(),$=te(e||null)},{immediate:!0}),H(),s.value.ssrRange||s.value.initialScrollIndex!==void 0?(0,e.nextTick)(()=>{H();let t=s.value.initialScrollIndex===void 0?s.value.ssrRange?.start:s.value.initialScrollIndex,n=s.value.initialScrollAlign||`start`;t!=null&&z(t,s.value.ssrRange?.colStart,{align:n,behavior:`auto`}),d.value=!0,f.value=!0,(0,e.nextTick)(()=>{f.value=!1})}):d.value=!0}),(0,e.onUnmounted)(()=>{$?.()})),{renderedItems:G,totalWidth:P,totalHeight:F,scrollDetails:q,scrollToIndex:z,scrollToOffset:B,stopProgrammaticScroll:J,updateItemSize:ee,updateItemSizes:X,updateHostOffset:H,columnRange:K,getColumnWidth:R,refresh:()=>{y.resize(0),b.resize(0),x.resize(0),C.fill(0),w.fill(0),T.fill(0),V()},isHydrated:d}}var d={key:0,class:`virtual-scroll-debug-info`},f=(0,e.defineComponent)({__name:`VirtualScroll`,props:{items:{},itemSize:{},direction:{default:`vertical`},bufferBefore:{default:5},bufferAfter:{default:5},container:{},ssrRange:{},columnCount:{default:0},columnWidth:{},containerTag:{default:`div`},wrapperTag:{default:`div`},itemTag:{default:`div`},scrollPaddingStart:{default:0},scrollPaddingEnd:{default:0},stickyHeader:{type:Boolean,default:!1},stickyFooter:{type:Boolean,default:!1},gap:{default:0},columnGap:{default:0},stickyIndices:{default:()=>[]},loadDistance:{default:200},loading:{type:Boolean,default:!1},restoreScrollOnPrepend:{type:Boolean,default:!1},initialScrollIndex:{},initialScrollAlign:{},defaultItemSize:{},defaultColumnWidth:{},debug:{type:Boolean,default:!1}},emits:[`scroll`,`load`,`visibleRangeChange`],setup(t,{expose:n,emit:r}){let i=t,s=r,c=(0,e.useSlots)(),l=(0,e.ref)(null),f=(0,e.ref)(null),p=(0,e.ref)(null),m=(0,e.ref)(null),h=new Map,g=(0,e.ref)(0),_=(0,e.ref)(0),v=(0,e.computed)(()=>{let e=i.container===void 0?l.value:i.container;return e===l.value||typeof window<`u`&&(e===window||e===null)}),{isHydrated:y,columnRange:b,renderedItems:x,scrollDetails:S,totalHeight:C,totalWidth:w,getColumnWidth:T,scrollToIndex:E,scrollToOffset:D,updateHostOffset:O,updateItemSizes:k,refresh:A,stopProgrammaticScroll:j}=u((0,e.computed)(()=>{let e=i.scrollPaddingStart,t=i.scrollPaddingEnd,n=typeof e==`object`?e.x||0:i.direction===`horizontal`&&e||0,r=typeof e==`object`?e.y||0:i.direction===`horizontal`?0:e||0,a=typeof t==`object`?t.x||0:i.direction===`horizontal`&&t||0,o=typeof t==`object`?t.y||0:i.direction===`horizontal`?0:t||0;return{items:i.items,itemSize:i.itemSize,direction:i.direction,bufferBefore:i.bufferBefore,bufferAfter:i.bufferAfter,container:i.container===void 0?l.value:i.container,hostElement:f.value,ssrRange:i.ssrRange,columnCount:i.columnCount,columnWidth:i.columnWidth,scrollPaddingStart:{x:n,y:r+(i.stickyHeader&&v.value?g.value:0)},scrollPaddingEnd:{x:a,y:o+(i.stickyFooter&&v.value?_.value:0)},gap:i.gap,columnGap:i.columnGap,stickyIndices:i.stickyIndices,loadDistance:i.loadDistance,loading:i.loading,restoreScrollOnPrepend:i.restoreScrollOnPrepend,initialScrollIndex:i.initialScrollIndex,initialScrollAlign:i.initialScrollAlign,defaultItemSize:i.defaultItemSize,defaultColumnWidth:i.defaultColumnWidth,debug:i.debug}}));function M(){A(),(0,e.nextTick)(()=>{let e=[];for(let[t,n]of h.entries())n&&e.push({index:t,inlineSize:n.offsetWidth,blockSize:n.offsetHeight,element:n});e.length>0&&k(e)})}(0,e.watch)(S,(e,t)=>{y.value&&(s(`scroll`,e),(!t||e.range.start!==t.range.start||e.range.end!==t.range.end||e.columnRange.start!==t.columnRange.start||e.columnRange.end!==t.columnRange.end)&&s(`visibleRangeChange`,{start:e.range.start,end:e.range.end,colStart:e.columnRange.start,colEnd:e.columnRange.end}),!i.loading&&(i.direction!==`horizontal`&&e.totalSize.height-(e.scrollOffset.y+e.viewportSize.height)<=i.loadDistance&&s(`load`,`vertical`),i.direction!==`vertical`&&e.totalSize.width-(e.scrollOffset.x+e.viewportSize.width)<=i.loadDistance&&s(`load`,`horizontal`)))}),(0,e.watch)(y,e=>{e&&s(`visibleRangeChange`,{start:S.value.range.start,end:S.value.range.end,colStart:S.value.columnRange.start,colEnd:S.value.columnRange.end})},{once:!0});let N=typeof window>`u`?null:new ResizeObserver(O),P=typeof window>`u`?null:new ResizeObserver(e=>{let t=[];for(let n of e){let e=n.target,r=Number(e.dataset.index);if(e.dataset.colIndex!==void 0)t.push({index:-1,inlineSize:0,blockSize:0,element:e});else if(!Number.isNaN(r)){let i=n.contentRect.width,a=n.contentRect.height;n.borderBoxSize&&n.borderBoxSize.length>0?(i=n.borderBoxSize[0].inlineSize,a=n.borderBoxSize[0].blockSize):(i=e.offsetWidth,a=e.offsetHeight),t.push({index:r,inlineSize:i,blockSize:a,element:e})}}t.length>0&&k(t)}),F=typeof window>`u`?null:new ResizeObserver(()=>{g.value=p.value?.offsetHeight||0,_.value=m.value?.offsetHeight||0,O()});(0,e.watch)(p,(e,t)=>{t&&F?.unobserve(t),e&&F?.observe(e)},{immediate:!0}),(0,e.watch)(m,(e,t)=>{t&&F?.unobserve(t),e&&F?.observe(e)},{immediate:!0});let I=(0,e.computed)(()=>x.value[0]?.index);(0,e.watch)(I,(e,t)=>{if(i.direction===`both`){if(t!==void 0){let e=h.get(t);e&&e.querySelectorAll(`[data-col-index]`).forEach(e=>P?.unobserve(e))}if(e!==void 0){let t=h.get(e);t&&t.querySelectorAll(`[data-col-index]`).forEach(e=>P?.observe(e))}}},{flush:`post`}),(0,e.onMounted)(()=>{l.value&&N?.observe(l.value);for(let e of h.values())P?.observe(e);if(I.value!==void 0){let e=h.get(I.value);e&&e.querySelectorAll(`[data-col-index]`).forEach(e=>P?.observe(e))}}),(0,e.watch)([l,f],([e],[t])=>{t&&N?.unobserve(t),e&&N?.observe(e)});function L(e,t){if(e)h.set(t,e),P?.observe(e);else{let e=h.get(t);e&&(P?.unobserve(e),h.delete(t))}}function R(e){j();let{viewportSize:t,scrollOffset:n}=S.value,r=i.direction!==`vertical`,a=i.direction!==`horizontal`;if(e.key===`Home`){e.preventDefault(),E(0,0,`start`);return}if(e.key===`End`){e.preventDefault();let t=i.items.length-1,n=(i.columnCount||0)>0?i.columnCount-1:0;r?a?E(t,n,`end`):E(0,t,`end`):E(t,0,`end`);return}if(e.key===`ArrowUp`){e.preventDefault(),D(null,n.y-40);return}if(e.key===`ArrowDown`){e.preventDefault(),D(null,n.y+40);return}if(e.key===`ArrowLeft`){e.preventDefault(),D(n.x-40,null);return}if(e.key===`ArrowRight`){e.preventDefault(),D(n.x+40,null);return}if(e.key===`PageUp`){e.preventDefault(),D(!a&&r?n.x-t.width:null,a?n.y-t.height:null);return}e.key===`PageDown`&&(e.preventDefault(),D(!a&&r?n.x+t.width:null,a?n.y+t.height:null))}(0,e.onUnmounted)(()=>{N?.disconnect(),P?.disconnect(),F?.disconnect()});let z=(0,e.computed)(()=>{let e=i.container;return e===null||typeof window<`u`&&e===window?!0:e&&typeof e==`object`&&`tagName`in e?e.tagName===`BODY`:!1}),B=(0,e.computed)(()=>z.value?{...i.direction===`vertical`?{}:{whiteSpace:`nowrap`}}:i.containerTag===`table`?{minInlineSize:i.direction===`vertical`?`100%`:`auto`}:{...i.direction===`vertical`?{}:{whiteSpace:`nowrap`}}),V=(0,e.computed)(()=>({inlineSize:i.direction===`vertical`?`100%`:`${w.value}px`,blockSize:i.direction===`horizontal`?`100%`:`${C.value}px`})),H=(0,e.computed)(()=>{let e=i.direction===`horizontal`;return{display:e?`inline-block`:`block`,...e?{blockSize:`100%`,verticalAlign:`top`}:{inlineSize:`100%`}}}),U=(0,e.computed)(()=>({inlineSize:i.direction===`vertical`?`1px`:`${w.value}px`,blockSize:i.direction===`horizontal`?`1px`:`${C.value}px`}));function W(e){let t=i.direction===`vertical`,n=i.direction===`horizontal`,r=i.direction===`both`,s=i.itemSize===void 0||i.itemSize===null||i.itemSize===0,c={blockSize:n?`100%`:s?`auto`:`${e.size.height}px`};return t&&i.containerTag===`table`?c.minInlineSize=`100%`:c.inlineSize=t?`100%`:s?`auto`:`${e.size.width}px`,s&&(t||(c.minInlineSize=`1px`),n||(c.minBlockSize=`1px`)),y.value&&(e.isStickyActive?((t||r)&&(c.insetBlockStart=`${o(i.scrollPaddingStart,i.direction)}px`),(n||r)&&(c.insetInlineStart=`${a(i.scrollPaddingStart,i.direction)}px`),c.transform=`translate(${e.stickyOffset.x}px, ${e.stickyOffset.y}px)`):c.transform=`translate(${e.offset.x}px, ${e.offset.y}px)`),c}let G=(0,e.computed)(()=>i.debug),K=(0,e.computed)(()=>i.containerTag===`table`),q=(0,e.computed)(()=>K.value?`thead`:`div`),J=(0,e.computed)(()=>K.value?`tfoot`:`div`);return n({scrollDetails:S,columnRange:b,getColumnWidth:T,scrollToIndex:E,scrollToOffset:D,refresh:M,stopProgrammaticScroll:j}),(n,r)=>((0,e.openBlock)(),(0,e.createBlock)((0,e.resolveDynamicComponent)(t.containerTag),{ref_key:`hostRef`,ref:l,class:(0,e.normalizeClass)([`virtual-scroll-container`,[`virtual-scroll--${t.direction}`,{"virtual-scroll--hydrated":(0,e.unref)(y),"virtual-scroll--window":z.value,"virtual-scroll--table":K.value}]]),style:(0,e.normalizeStyle)(B.value),tabindex:`0`,onKeydown:R,onWheelPassive:(0,e.unref)(j),onPointerdownPassive:(0,e.unref)(j),onTouchstartPassive:(0,e.unref)(j)},{default:(0,e.withCtx)(()=>[c.header?((0,e.openBlock)(),(0,e.createBlock)((0,e.resolveDynamicComponent)(q.value),{key:0,ref_key:`headerRef`,ref:p,class:(0,e.normalizeClass)([`virtual-scroll-header`,{"virtual-scroll--sticky":t.stickyHeader}])},{default:(0,e.withCtx)(()=>[(0,e.renderSlot)(n.$slots,`header`,{},void 0,!0)]),_:3},8,[`class`])):(0,e.createCommentVNode)(``,!0),((0,e.openBlock)(),(0,e.createBlock)((0,e.resolveDynamicComponent)(t.wrapperTag),{ref_key:`wrapperRef`,ref:f,class:`virtual-scroll-wrapper`,style:(0,e.normalizeStyle)(V.value)},{default:(0,e.withCtx)(()=>[K.value?((0,e.openBlock)(),(0,e.createBlock)((0,e.resolveDynamicComponent)(t.itemTag),{key:0,class:`virtual-scroll-spacer`,style:(0,e.normalizeStyle)(U.value)},{default:(0,e.withCtx)(()=>[...r[0]||=[(0,e.createElementVNode)(`td`,{style:{padding:`0`,border:`none`,"block-size":`inherit`}},null,-1)]]),_:1},8,[`style`])):(0,e.createCommentVNode)(``,!0),((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)((0,e.unref)(x),r=>((0,e.openBlock)(),(0,e.createBlock)((0,e.resolveDynamicComponent)(t.itemTag),{key:r.index,ref_for:!0,ref:e=>L(e,r.index),"data-index":r.index,class:(0,e.normalizeClass)([`virtual-scroll-item`,{"virtual-scroll--sticky":r.isStickyActive,"virtual-scroll--debug":G.value}]),style:(0,e.normalizeStyle)(W(r))},{default:(0,e.withCtx)(()=>[(0,e.renderSlot)(n.$slots,`item`,{item:r.item,index:r.index,columnRange:(0,e.unref)(b),getColumnWidth:(0,e.unref)(T),isSticky:r.isSticky,isStickyActive:r.isStickyActive},void 0,!0),G.value?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,d,` #`+(0,e.toDisplayString)(r.index)+` (`+(0,e.toDisplayString)(Math.round(r.offset.x))+`, `+(0,e.toDisplayString)(Math.round(r.offset.y))+`) `,1)):(0,e.createCommentVNode)(``,!0)]),_:2},1032,[`data-index`,`class`,`style`]))),128))]),_:3},8,[`style`])),t.loading&&c.loading?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{key:1,class:`virtual-scroll-loading`,style:(0,e.normalizeStyle)(H.value)},[(0,e.renderSlot)(n.$slots,`loading`,{},void 0,!0)],4)):(0,e.createCommentVNode)(``,!0),c.footer?((0,e.openBlock)(),(0,e.createBlock)((0,e.resolveDynamicComponent)(J.value),{key:2,ref_key:`footerRef`,ref:m,class:(0,e.normalizeClass)([`virtual-scroll-footer`,{"virtual-scroll--sticky":t.stickyFooter}])},{default:(0,e.withCtx)(()=>[(0,e.renderSlot)(n.$slots,`footer`,{},void 0,!0)]),_:3},8,[`class`])):(0,e.createCommentVNode)(``,!0)]),_:3},40,[`class`,`style`,`onWheelPassive`,`onPointerdownPassive`,`onTouchstartPassive`]))}}),p=(e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n},m=p(f,[[`__scopeId`,`data-v-d61a0f1d`]]);exports.DEFAULT_BUFFER=5,exports.DEFAULT_COLUMN_WIDTH=100,exports.DEFAULT_ITEM_SIZE=40,exports.FenwickTree=t,exports.VirtualScroll=m,exports.getPaddingX=a,exports.getPaddingY=o,exports.isElement=n,exports.isScrollToIndexOptions=i,exports.isScrollableElement=r,exports.useVirtualScroll=u;
2
+ //# sourceMappingURL=index.cjs.map