@vielzeug/virtualit 2.1.0 → 3.0.3
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 +59 -42
- package/dist/dom/dom.cjs +1 -1
- package/dist/dom/dom.cjs.map +1 -1
- package/dist/dom/dom.d.ts +10 -7
- package/dist/dom/dom.d.ts.map +1 -1
- package/dist/dom/dom.js +68 -33
- package/dist/dom/dom.js.map +1 -1
- package/dist/dom.cjs +1 -1
- package/dist/dom.js +3 -3
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/virtualit.cjs +1 -1
- package/dist/virtualit.cjs.map +1 -1
- package/dist/virtualit.d.ts +45 -112
- package/dist/virtualit.d.ts.map +1 -1
- package/dist/virtualit.js +222 -125
- package/dist/virtualit.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@vielzeug/virtualit) [](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
**Virtualit** renders only the items visible in the viewport plus a configurable overscan buffer. It uses a `ResizeObserver` for
|
|
7
|
+
**Virtualit** renders only the items visible in the viewport plus a configurable overscan buffer. It uses a `ResizeObserver` for container size changes and a passive `scroll` listener to keep the visible window in sync — no framework required.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -30,7 +30,7 @@ const virt = createVirtualizer(scrollEl, {
|
|
|
30
30
|
|
|
31
31
|
for (const item of virtualItems) {
|
|
32
32
|
const row = document.createElement('div');
|
|
33
|
-
row.style.cssText = `position:absolute;top:${item.
|
|
33
|
+
row.style.cssText = `position:absolute;top:${item.start}px;left:0;right:0;height:${item.size}px;`;
|
|
34
34
|
row.textContent = items[item.index].label;
|
|
35
35
|
list.appendChild(row);
|
|
36
36
|
}
|
|
@@ -44,11 +44,14 @@ virt.destroy();
|
|
|
44
44
|
## Features
|
|
45
45
|
|
|
46
46
|
- ✅ **Framework-agnostic** — callback-based `onChange`; works with React, Vue, Svelte, Lit, or vanilla DOM
|
|
47
|
-
- ✅ **Fixed and variable
|
|
48
|
-
- ✅ **Batched measurements** —
|
|
47
|
+
- ✅ **Fixed and variable sizes** — pass a number or a per-index estimator; call `measure()` for exact size capture
|
|
48
|
+
- ✅ **Batched measurements** — measurement calls within a single tick are coalesced into one rebuild via `queueMicrotask`
|
|
49
|
+
- ✅ **Stable-key reflow** — `refresh()` rebuilds offsets after reorder/filter changes without discarding measured sizes
|
|
49
50
|
- ✅ **Skipped re-renders** — `onChange` is not fired when a scroll event doesn't cross an item boundary
|
|
50
|
-
- ✅ **Programmatic scrolling** — `scrollToIndex()` with `start`, `end`, `center`, and `auto` alignment; `scrollToOffset()` for pixel-level control; both support `behavior: 'smooth'
|
|
51
|
-
- ✅ **
|
|
51
|
+
- ✅ **Programmatic scrolling** — `scrollToIndex()` with `start`, `end`, `center`, and `auto` alignment; `scrollToOffset()` for pixel-level control; both support `behavior: 'smooth'`; variable-height lists use current estimates until rows are measured
|
|
52
|
+
- ✅ **Atomic updates** — `update()` can change count, estimator, overscan, callbacks, and scroll behavior config together
|
|
53
|
+
- ✅ **Horizontal and window targets** — supports horizontal virtualization and `window` as scroll target
|
|
54
|
+
- ✅ **Asymmetric overscan and gaps** — control start/end overscan independently and set inter-item spacing
|
|
52
55
|
- ✅ **Typed Float64Array offsets** — dense contiguous buffer for cache-friendly binary search
|
|
53
56
|
- ✅ **Disposable** — implements `[Symbol.dispose]` for `using` declarations
|
|
54
57
|
- ✅ **Zero dependencies**
|
|
@@ -67,14 +70,15 @@ const list = document.getElementById('list')!;
|
|
|
67
70
|
const virt = createVirtualizer(scrollEl, {
|
|
68
71
|
count: 10_000,
|
|
69
72
|
estimateSize: 36,
|
|
70
|
-
overscan: 3,
|
|
73
|
+
overscan: { start: 3, end: 3 },
|
|
71
74
|
onChange: (virtualItems, totalSize) => {
|
|
72
75
|
spacer.style.height = `${totalSize}px`;
|
|
73
76
|
list.innerHTML = '';
|
|
74
77
|
|
|
75
78
|
for (const item of virtualItems) {
|
|
76
79
|
const el = document.createElement('div');
|
|
77
|
-
el.
|
|
80
|
+
el.dataset.index = String(item.index);
|
|
81
|
+
el.style.cssText = `position:absolute;top:${item.start}px;`;
|
|
78
82
|
el.textContent = `Row ${item.index}`;
|
|
79
83
|
list.appendChild(el);
|
|
80
84
|
}
|
|
@@ -94,7 +98,7 @@ const virt = createVirtualizer(scrollEl, {
|
|
|
94
98
|
// After rendering, report the actual measured heights
|
|
95
99
|
for (const item of virtualItems) {
|
|
96
100
|
const el = list.querySelector(`[data-index="${item.index}"]`) as HTMLElement | null;
|
|
97
|
-
if (el) virt.
|
|
101
|
+
if (el) virt.measure(item.index, el.offsetHeight);
|
|
98
102
|
}
|
|
99
103
|
},
|
|
100
104
|
});
|
|
@@ -113,14 +117,21 @@ virt.scrollToIndex(50, { align: 'start', behavior: 'smooth' });
|
|
|
113
117
|
virt.scrollToOffset(1440, { behavior: 'smooth' });
|
|
114
118
|
```
|
|
115
119
|
|
|
120
|
+
For variable-height lists, `scrollToIndex()` uses the current estimate/measured cache. If row sizes changed materially, call `invalidate()` and then scroll again.
|
|
121
|
+
|
|
122
|
+
If the same logical rows were reordered or filtered while keeping stable keys, call `refresh()` to rebuild offsets without dropping measured sizes.
|
|
123
|
+
|
|
116
124
|
### Updating the List
|
|
117
125
|
|
|
118
126
|
```ts
|
|
119
|
-
// Append more items
|
|
120
|
-
virt.count
|
|
127
|
+
// Append more items
|
|
128
|
+
virt.update({ count: newItems.length });
|
|
121
129
|
|
|
122
130
|
// Switch row density (e.g. compact ↔ comfortable view)
|
|
123
|
-
virt.estimateSize
|
|
131
|
+
virt.update({ estimateSize: isDense ? 32 : 48 });
|
|
132
|
+
|
|
133
|
+
// Rebuild after reordering stable-key rows
|
|
134
|
+
virt.refresh();
|
|
124
135
|
|
|
125
136
|
// Recompute after a font swap or layout shift
|
|
126
137
|
virt.invalidate();
|
|
@@ -140,47 +151,55 @@ virt.invalidate();
|
|
|
140
151
|
### Package Exports
|
|
141
152
|
|
|
142
153
|
```ts
|
|
143
|
-
export {
|
|
144
|
-
export type {
|
|
154
|
+
export { createVirtualizer } from '@vielzeug/virtualit';
|
|
155
|
+
export type {
|
|
156
|
+
Overscan,
|
|
157
|
+
ScrollToIndexOptions,
|
|
158
|
+
VirtualItem,
|
|
159
|
+
Virtualizer,
|
|
160
|
+
VirtualizerOptions,
|
|
161
|
+
VirtualizerUpdateOptions,
|
|
162
|
+
} from '@vielzeug/virtualit';
|
|
145
163
|
```
|
|
146
164
|
|
|
147
165
|
### `createVirtualizer(el, options)`
|
|
148
166
|
|
|
149
167
|
Creates and immediately attaches a `Virtualizer` to `el`.
|
|
150
168
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
| `options.onChange` | `(items: VirtualItem[], totalSize: number) => void` | Called whenever the visible range changes |
|
|
169
|
+
- `el`: `HTMLElement | Window` — the scroll target to observe.
|
|
170
|
+
- `options.count`: `number` — total number of items.
|
|
171
|
+
- `options.estimateSize`: `number | (i: number) => number` — row size estimate (default: `36`).
|
|
172
|
+
- `options.gap`: `number` — gap in px inserted between items.
|
|
173
|
+
- `options.overscan`: `{ start?: number; end?: number }` — items rendered beyond viewport edge (default: `{ start: 3, end: 3 }`).
|
|
174
|
+
- `options.onChange`: `(items: VirtualItem[], totalSize: number) => void` — called whenever the visible range changes.
|
|
158
175
|
|
|
159
176
|
Returns a `Virtualizer` instance.
|
|
160
177
|
|
|
161
178
|
### `Virtualizer`
|
|
162
179
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
180
|
+
- `count`: `readonly number` — current item count.
|
|
181
|
+
- `estimateSize`: `readonly number | (i) => number` — active estimator.
|
|
182
|
+
- `update(next)`: `(next: VirtualizerUpdateOptions) => void` — atomically update options.
|
|
183
|
+
- `destroy()`: `() => void` — remove all listeners; idempotent.
|
|
184
|
+
- `[Symbol.dispose]()` — delegates to `destroy()`.
|
|
185
|
+
- `items`: `readonly VirtualItem[]` — currently rendered items.
|
|
186
|
+
- `totalSize`: `readonly number` — total scrollable size in px.
|
|
187
|
+
- `scrollOffset`: `readonly number` — current scroll offset.
|
|
188
|
+
- `isScrolling`: `readonly boolean` — true while in active scrolling window.
|
|
189
|
+
- `measure(i, h)`: `(index: number, size: number) => void` — record exact item size; batched per microtask.
|
|
190
|
+
- `refresh()`: `() => void` — rebuild offsets and re-render while keeping measured sizes.
|
|
191
|
+
- `scrollToIndex(i, opts?)`: `(index, ScrollToIndexOptions) => void` — scroll to an item.
|
|
192
|
+
- `scrollToOffset(px, opts?)`: `(offset, { behavior? }) => void` — scroll to a pixel offset.
|
|
193
|
+
- `invalidate()`: `() => void` — clear measured sizes and re-render.
|
|
176
194
|
|
|
177
195
|
### `VirtualItem`
|
|
178
196
|
|
|
179
197
|
```ts
|
|
180
198
|
interface VirtualItem {
|
|
181
|
-
index: number;
|
|
182
|
-
|
|
183
|
-
|
|
199
|
+
index: number;
|
|
200
|
+
start: number;
|
|
201
|
+
end: number;
|
|
202
|
+
size: number;
|
|
184
203
|
}
|
|
185
204
|
```
|
|
186
205
|
|
|
@@ -188,11 +207,9 @@ interface VirtualItem {
|
|
|
188
207
|
|
|
189
208
|
Full docs at **[vielzeug.dev/virtualit](https://vielzeug.dev/virtualit)**
|
|
190
209
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
| [API Reference](https://vielzeug.dev/virtualit/api) | Complete type signatures |
|
|
195
|
-
| [Examples](https://vielzeug.dev/virtualit/examples) | Real-world virtual list patterns |
|
|
210
|
+
- [Usage Guide](https://vielzeug.dev/virtualit/usage) — fixed/variable heights, overscan, scrolling.
|
|
211
|
+
- [API Reference](https://vielzeug.dev/virtualit/api) — complete type signatures.
|
|
212
|
+
- [Examples](https://vielzeug.dev/virtualit/examples) — real-world virtual list patterns.
|
|
196
213
|
|
|
197
214
|
## License
|
|
198
215
|
|
package/dist/dom/dom.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../virtualit.cjs`);function
|
|
1
|
+
const e=require(`../virtualit.cjs`);var t=36,n=3;function r(r){let i=[],a=!0,o=null,s=null,c=null,l=0,u=e=>{let t=i[e];return t&&r.getItemKey?r.getItemKey(e,t):`${l}:${e}`},d=e=>{if(typeof r.estimateSize==`number`)return r.estimateSize;let n=i[e];return n?r.estimateSize(e,n):t},f=(e=o)=>{e&&(r.clear?r.clear(e):e.textContent=``,e.style.height=``,e.style.width=``,e.style.position=``,e.style.contain=``)},p=e=>{o&&(r.horizontal?(o.style.width=`${e}px`,o.style.height=``):(o.style.height=`${e}px`,o.style.width=``))},m=(e,t)=>{o&&(p(t),r.render({items:i,listEl:o,totalSize:t,virtualItems:e}))},h=t=>{let l=r.getScrollElement(),p=r.getListElement(),h=o;if(!a||!l||!p||i.length===0){c?.destroy(),c=null,o=p,s=l,f();return}let g=s!==l||o!==p;if(o=p,s=l,!c||g){let t=!!c&&g;c?.destroy(),t&&f(h),c=e.createVirtualizer(s,{count:i.length,estimateSize:d,gap:r.gap,getItemKey:u,horizontal:r.horizontal,onChange:(e,t)=>m(e,t),overscan:r.overscan??{end:n,start:n}}),o.style.position=`relative`,o.style.contain=`layout`;return}if(c.update({count:i.length,estimateSize:d,gap:r.gap,getItemKey:u,overscan:r.overscan}),t===`invalidate`){c.invalidate();return}t===`refresh`&&c.refresh()};return{destroy(){c?.destroy(),c=null,f()},invalidate(){c?.invalidate()},measure(e,t){c?.measure(e,t)},scrollToIndex(e,t){c?.scrollToIndex(e,t)},setActive(e){a=e,h(null)},setItems(e){if(i=e,r.getItemKey){h(`refresh`);return}l+=1,h(`invalidate`)}}}exports.createDomVirtualList=r;
|
|
2
2
|
//# sourceMappingURL=dom.cjs.map
|
package/dist/dom/dom.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.cjs","names":[],"sources":["../../src/dom/dom.ts"],"sourcesContent":["import { type ScrollToIndexOptions
|
|
1
|
+
{"version":3,"file":"dom.cjs","names":[],"sources":["../../src/dom/dom.ts"],"sourcesContent":["import {\n type Overscan,\n type ScrollToIndexOptions,\n type VirtualItem,\n type VirtualKey,\n type Virtualizer,\n createVirtualizer,\n} from '../virtualit';\n\nexport * from '../virtualit';\n\nconst DEFAULT_ESTIMATE_SIZE = 36;\nconst DEFAULT_OVERSCAN = 3;\n\nexport type DomVirtualListRenderArgs<T> = {\n items: T[];\n listEl: HTMLElement;\n totalSize: number;\n virtualItems: VirtualItem[];\n};\n\nexport type DomVirtualListOptions<T> = {\n clear?: (listEl: HTMLElement) => void;\n estimateSize: number | ((index: number, item: T) => number);\n gap?: number;\n getItemKey?: (index: number, item: T) => VirtualKey;\n getListElement: () => HTMLElement | null;\n getScrollElement: () => HTMLElement | Window | null;\n horizontal?: boolean;\n overscan?: Overscan;\n render: (args: DomVirtualListRenderArgs<T>) => void;\n};\n\nexport type DomVirtualListController<T> = {\n destroy: () => void;\n invalidate: () => void;\n measure: (index: number, size: number) => void;\n scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;\n setActive: (active: boolean) => void;\n setItems: (items: T[]) => void;\n};\n\ntype MeasurementSyncMode = 'invalidate' | 'refresh' | null;\n\nexport function createDomVirtualList<T>(options: DomVirtualListOptions<T>): DomVirtualListController<T> {\n let currentItems: T[] = [];\n let isActive = true;\n let listElRef: HTMLElement | null = null;\n let scrollElRef: HTMLElement | Window | null = null;\n let virtualizer: Virtualizer | null = null;\n let itemKeyRevision = 0;\n\n const resolveItemKey = (index: number): VirtualKey => {\n const item = currentItems[index];\n\n if (item && options.getItemKey) return options.getItemKey(index, item);\n\n return `${itemKeyRevision}:${index}`;\n };\n\n const resolveEstimate = (index: number): number => {\n if (typeof options.estimateSize === 'number') return options.estimateSize;\n\n const item = currentItems[index];\n\n if (!item) return DEFAULT_ESTIMATE_SIZE;\n\n return options.estimateSize(index, item);\n };\n\n const clearAndReset = (listEl: HTMLElement | null = listElRef) => {\n if (!listEl) return;\n\n if (options.clear) options.clear(listEl);\n else listEl.textContent = '';\n\n listEl.style.height = '';\n listEl.style.width = '';\n listEl.style.position = '';\n listEl.style.contain = '';\n };\n\n const applyListSize = (totalSize: number) => {\n if (!listElRef) return;\n\n if (options.horizontal) {\n listElRef.style.width = `${totalSize}px`;\n listElRef.style.height = '';\n } else {\n listElRef.style.height = `${totalSize}px`;\n listElRef.style.width = '';\n }\n };\n\n const renderFromChange = (virtualItems: VirtualItem[], totalSize: number) => {\n if (!listElRef) return;\n\n applyListSize(totalSize);\n options.render({\n items: currentItems,\n listEl: listElRef,\n totalSize,\n virtualItems,\n });\n };\n\n const syncVirtualizer = (measurementSync: MeasurementSyncMode) => {\n const nextScroll = options.getScrollElement();\n const nextList = options.getListElement();\n const previousList = listElRef;\n\n if (!isActive || !nextScroll || !nextList || currentItems.length === 0) {\n virtualizer?.destroy();\n virtualizer = null;\n listElRef = nextList;\n scrollElRef = nextScroll;\n clearAndReset();\n\n return;\n }\n\n const targetChanged = scrollElRef !== nextScroll || listElRef !== nextList;\n\n listElRef = nextList;\n scrollElRef = nextScroll;\n\n if (!virtualizer || targetChanged) {\n const shouldClearForTargetSwap = !!virtualizer && targetChanged;\n\n virtualizer?.destroy();\n\n if (shouldClearForTargetSwap) clearAndReset(previousList);\n\n virtualizer = createVirtualizer(scrollElRef, {\n count: currentItems.length,\n estimateSize: resolveEstimate,\n gap: options.gap,\n getItemKey: resolveItemKey,\n horizontal: options.horizontal,\n onChange: (virtualItems, totalSize) => renderFromChange(virtualItems, totalSize),\n overscan: options.overscan ?? { end: DEFAULT_OVERSCAN, start: DEFAULT_OVERSCAN },\n });\n\n listElRef.style.position = 'relative';\n listElRef.style.contain = 'layout';\n\n return;\n }\n\n virtualizer.update({\n count: currentItems.length,\n estimateSize: resolveEstimate,\n gap: options.gap,\n getItemKey: resolveItemKey,\n overscan: options.overscan,\n });\n\n if (measurementSync === 'invalidate') {\n virtualizer.invalidate();\n\n return;\n }\n\n if (measurementSync === 'refresh') virtualizer.refresh();\n };\n\n return {\n destroy() {\n virtualizer?.destroy();\n virtualizer = null;\n clearAndReset();\n },\n invalidate() {\n virtualizer?.invalidate();\n },\n measure(index, size) {\n virtualizer?.measure(index, size);\n },\n scrollToIndex(index, scrollOptions) {\n virtualizer?.scrollToIndex(index, scrollOptions);\n },\n setActive(active) {\n isActive = active;\n syncVirtualizer(null);\n },\n setItems(items) {\n currentItems = items;\n\n if (options.getItemKey) {\n syncVirtualizer('refresh');\n\n return;\n }\n\n itemKeyRevision += 1;\n syncVirtualizer('invalidate');\n },\n };\n}\n"],"mappings":"oCAWA,IAAM,EAAwB,GACxB,EAAmB,EAgCzB,SAAgB,EAAwB,EAAgE,CACtG,IAAI,EAAoB,CAAC,EACrB,EAAW,GACX,EAAgC,KAChC,EAA2C,KAC3C,EAAkC,KAClC,EAAkB,EAEhB,EAAkB,GAA8B,CACpD,IAAM,EAAO,EAAa,GAI1B,OAFI,GAAQ,EAAQ,WAAmB,EAAQ,WAAW,EAAO,CAAI,EAE9D,GAAG,EAAgB,GAAG,GAC/B,EAEM,EAAmB,GAA0B,CACjD,GAAI,OAAO,EAAQ,cAAiB,SAAU,OAAO,EAAQ,aAE7D,IAAM,EAAO,EAAa,GAI1B,OAFK,EAEE,EAAQ,aAAa,EAAO,CAAI,EAFrB,CAGpB,EAEM,GAAiB,EAA6B,IAAc,CAC3D,IAED,EAAQ,MAAO,EAAQ,MAAM,CAAM,EAClC,EAAO,YAAc,GAE1B,EAAO,MAAM,OAAS,GACtB,EAAO,MAAM,MAAQ,GACrB,EAAO,MAAM,SAAW,GACxB,EAAO,MAAM,QAAU,GACzB,EAEM,EAAiB,GAAsB,CACtC,IAED,EAAQ,YACV,EAAU,MAAM,MAAQ,GAAG,EAAU,IACrC,EAAU,MAAM,OAAS,KAEzB,EAAU,MAAM,OAAS,GAAG,EAAU,IACtC,EAAU,MAAM,MAAQ,IAE5B,EAEM,GAAoB,EAA6B,IAAsB,CACtE,IAEL,EAAc,CAAS,EACvB,EAAQ,OAAO,CACb,MAAO,EACP,OAAQ,EACR,YACA,cACF,CAAC,EACH,EAEM,EAAmB,GAAyC,CAChE,IAAM,EAAa,EAAQ,iBAAiB,EACtC,EAAW,EAAQ,eAAe,EAClC,EAAe,EAErB,GAAI,CAAC,GAAY,CAAC,GAAc,CAAC,GAAY,EAAa,SAAW,EAAG,CACtE,GAAa,QAAQ,EACrB,EAAc,KACd,EAAY,EACZ,EAAc,EACd,EAAc,EAEd,MACF,CAEA,IAAM,EAAgB,IAAgB,GAAc,IAAc,EAKlE,GAHA,EAAY,EACZ,EAAc,EAEV,CAAC,GAAe,EAAe,CACjC,IAAM,EAA2B,CAAC,CAAC,GAAe,EAElD,GAAa,QAAQ,EAEjB,GAA0B,EAAc,CAAY,EAExD,EAAc,EAAA,kBAAkB,EAAa,CAC3C,MAAO,EAAa,OACpB,aAAc,EACd,IAAK,EAAQ,IACb,WAAY,EACZ,WAAY,EAAQ,WACpB,UAAW,EAAc,IAAc,EAAiB,EAAc,CAAS,EAC/E,SAAU,EAAQ,UAAY,CAAE,IAAK,EAAkB,MAAO,CAAiB,CACjF,CAAC,EAED,EAAU,MAAM,SAAW,WAC3B,EAAU,MAAM,QAAU,SAE1B,MACF,CAUA,GARA,EAAY,OAAO,CACjB,MAAO,EAAa,OACpB,aAAc,EACd,IAAK,EAAQ,IACb,WAAY,EACZ,SAAU,EAAQ,QACpB,CAAC,EAEG,IAAoB,aAAc,CACpC,EAAY,WAAW,EAEvB,MACF,CAEI,IAAoB,WAAW,EAAY,QAAQ,CACzD,EAEA,MAAO,CACL,SAAU,CACR,GAAa,QAAQ,EACrB,EAAc,KACd,EAAc,CAChB,EACA,YAAa,CACX,GAAa,WAAW,CAC1B,EACA,QAAQ,EAAO,EAAM,CACnB,GAAa,QAAQ,EAAO,CAAI,CAClC,EACA,cAAc,EAAO,EAAe,CAClC,GAAa,cAAc,EAAO,CAAa,CACjD,EACA,UAAU,EAAQ,CAChB,EAAW,EACX,EAAgB,IAAI,CACtB,EACA,SAAS,EAAO,CAGd,GAFA,EAAe,EAEX,EAAQ,WAAY,CACtB,EAAgB,SAAS,EAEzB,MACF,CAEA,GAAmB,EACnB,EAAgB,YAAY,CAC9B,CACF,CACF"}
|
package/dist/dom/dom.d.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
import { type ScrollToIndexOptions, type VirtualItem } from '../virtualit';
|
|
1
|
+
import { type Overscan, type ScrollToIndexOptions, type VirtualItem, type VirtualKey } from '../virtualit';
|
|
2
2
|
export * from '../virtualit';
|
|
3
3
|
export type DomVirtualListRenderArgs<T> = {
|
|
4
4
|
items: T[];
|
|
5
5
|
listEl: HTMLElement;
|
|
6
|
+
totalSize: number;
|
|
6
7
|
virtualItems: VirtualItem[];
|
|
7
8
|
};
|
|
8
9
|
export type DomVirtualListOptions<T> = {
|
|
9
10
|
clear?: (listEl: HTMLElement) => void;
|
|
10
11
|
estimateSize: number | ((index: number, item: T) => number);
|
|
12
|
+
gap?: number;
|
|
13
|
+
getItemKey?: (index: number, item: T) => VirtualKey;
|
|
11
14
|
getListElement: () => HTMLElement | null;
|
|
12
|
-
getScrollElement: () => HTMLElement | null;
|
|
13
|
-
|
|
15
|
+
getScrollElement: () => HTMLElement | Window | null;
|
|
16
|
+
horizontal?: boolean;
|
|
17
|
+
overscan?: Overscan;
|
|
14
18
|
render: (args: DomVirtualListRenderArgs<T>) => void;
|
|
15
19
|
};
|
|
16
|
-
export type DomVirtualListSetItemsOptions = {
|
|
17
|
-
remeasure?: boolean;
|
|
18
|
-
};
|
|
19
20
|
export type DomVirtualListController<T> = {
|
|
20
21
|
destroy: () => void;
|
|
22
|
+
invalidate: () => void;
|
|
23
|
+
measure: (index: number, size: number) => void;
|
|
21
24
|
scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;
|
|
22
25
|
setActive: (active: boolean) => void;
|
|
23
|
-
setItems: (items: T[]
|
|
26
|
+
setItems: (items: T[]) => void;
|
|
24
27
|
};
|
|
25
28
|
export declare function createDomVirtualList<T>(options: DomVirtualListOptions<T>): DomVirtualListController<T>;
|
|
26
29
|
//# sourceMappingURL=dom.d.ts.map
|
package/dist/dom/dom.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/dom/dom.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/dom/dom.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,KAAK,WAAW,EAChB,KAAK,UAAU,EAGhB,MAAM,cAAc,CAAC;AAEtB,cAAc,cAAc,CAAC;AAK7B,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAAI;IACxC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,CAAC,IAAI;IACrC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,YAAY,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC;IAC5D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,UAAU,CAAC;IACpD,cAAc,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACzC,gBAAgB,EAAE,MAAM,WAAW,GAAG,MAAM,GAAG,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAAI;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACvE,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;CAChC,CAAC;AAIF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,wBAAwB,CAAC,CAAC,CAAC,CA0JtG"}
|
package/dist/dom/dom.js
CHANGED
|
@@ -1,51 +1,86 @@
|
|
|
1
1
|
import { createVirtualizer as e } from "../virtualit.js";
|
|
2
2
|
//#region src/dom/dom.ts
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let
|
|
7
|
-
return r ?
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
var t = 36, n = 3;
|
|
4
|
+
function r(r) {
|
|
5
|
+
let i = [], a = !0, o = null, s = null, c = null, l = 0, u = (e) => {
|
|
6
|
+
let t = i[e];
|
|
7
|
+
return t && r.getItemKey ? r.getItemKey(e, t) : `${l}:${e}`;
|
|
8
|
+
}, d = (e) => {
|
|
9
|
+
if (typeof r.estimateSize == "number") return r.estimateSize;
|
|
10
|
+
let n = i[e];
|
|
11
|
+
return n ? r.estimateSize(e, n) : t;
|
|
12
|
+
}, f = (e = o) => {
|
|
13
|
+
e && (r.clear ? r.clear(e) : e.textContent = "", e.style.height = "", e.style.width = "", e.style.position = "", e.style.contain = "");
|
|
14
|
+
}, p = (e) => {
|
|
15
|
+
o && (r.horizontal ? (o.style.width = `${e}px`, o.style.height = "") : (o.style.height = `${e}px`, o.style.width = ""));
|
|
16
|
+
}, m = (e, t) => {
|
|
17
|
+
o && (p(t), r.render({
|
|
18
|
+
items: i,
|
|
19
|
+
listEl: o,
|
|
20
|
+
totalSize: t,
|
|
21
|
+
virtualItems: e
|
|
22
|
+
}));
|
|
23
|
+
}, h = (t) => {
|
|
24
|
+
let l = r.getScrollElement(), p = r.getListElement(), h = o;
|
|
25
|
+
if (!a || !l || !p || i.length === 0) {
|
|
26
|
+
c?.destroy(), c = null, o = p, s = l, f();
|
|
16
27
|
return;
|
|
17
28
|
}
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
let g = s !== l || o !== p;
|
|
30
|
+
if (o = p, s = l, !c || g) {
|
|
31
|
+
let t = !!c && g;
|
|
32
|
+
c?.destroy(), t && f(h), c = e(s, {
|
|
33
|
+
count: i.length,
|
|
34
|
+
estimateSize: d,
|
|
35
|
+
gap: r.gap,
|
|
36
|
+
getItemKey: u,
|
|
37
|
+
horizontal: r.horizontal,
|
|
38
|
+
onChange: (e, t) => m(e, t),
|
|
39
|
+
overscan: r.overscan ?? {
|
|
40
|
+
end: n,
|
|
41
|
+
start: n
|
|
42
|
+
}
|
|
43
|
+
}), o.style.position = "relative", o.style.contain = "layout";
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (c.update({
|
|
47
|
+
count: i.length,
|
|
48
|
+
estimateSize: d,
|
|
49
|
+
gap: r.gap,
|
|
50
|
+
getItemKey: u,
|
|
51
|
+
overscan: r.overscan
|
|
52
|
+
}), t === "invalidate") {
|
|
53
|
+
c.invalidate();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
t === "refresh" && c.refresh();
|
|
31
57
|
};
|
|
32
58
|
return {
|
|
33
59
|
destroy() {
|
|
34
|
-
|
|
60
|
+
c?.destroy(), c = null, f();
|
|
61
|
+
},
|
|
62
|
+
invalidate() {
|
|
63
|
+
c?.invalidate();
|
|
64
|
+
},
|
|
65
|
+
measure(e, t) {
|
|
66
|
+
c?.measure(e, t);
|
|
35
67
|
},
|
|
36
68
|
scrollToIndex(e, t) {
|
|
37
|
-
|
|
69
|
+
c?.scrollToIndex(e, t);
|
|
38
70
|
},
|
|
39
71
|
setActive(e) {
|
|
40
|
-
|
|
72
|
+
a = e, h(null);
|
|
41
73
|
},
|
|
42
|
-
setItems(e
|
|
43
|
-
|
|
44
|
-
|
|
74
|
+
setItems(e) {
|
|
75
|
+
if (i = e, r.getItemKey) {
|
|
76
|
+
h("refresh");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
l += 1, h("invalidate");
|
|
45
80
|
}
|
|
46
81
|
};
|
|
47
82
|
}
|
|
48
83
|
//#endregion
|
|
49
|
-
export {
|
|
84
|
+
export { r as createDomVirtualList };
|
|
50
85
|
|
|
51
86
|
//# sourceMappingURL=dom.js.map
|
package/dist/dom/dom.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.js","names":[],"sources":["../../src/dom/dom.ts"],"sourcesContent":["import { type ScrollToIndexOptions
|
|
1
|
+
{"version":3,"file":"dom.js","names":[],"sources":["../../src/dom/dom.ts"],"sourcesContent":["import {\n type Overscan,\n type ScrollToIndexOptions,\n type VirtualItem,\n type VirtualKey,\n type Virtualizer,\n createVirtualizer,\n} from '../virtualit';\n\nexport * from '../virtualit';\n\nconst DEFAULT_ESTIMATE_SIZE = 36;\nconst DEFAULT_OVERSCAN = 3;\n\nexport type DomVirtualListRenderArgs<T> = {\n items: T[];\n listEl: HTMLElement;\n totalSize: number;\n virtualItems: VirtualItem[];\n};\n\nexport type DomVirtualListOptions<T> = {\n clear?: (listEl: HTMLElement) => void;\n estimateSize: number | ((index: number, item: T) => number);\n gap?: number;\n getItemKey?: (index: number, item: T) => VirtualKey;\n getListElement: () => HTMLElement | null;\n getScrollElement: () => HTMLElement | Window | null;\n horizontal?: boolean;\n overscan?: Overscan;\n render: (args: DomVirtualListRenderArgs<T>) => void;\n};\n\nexport type DomVirtualListController<T> = {\n destroy: () => void;\n invalidate: () => void;\n measure: (index: number, size: number) => void;\n scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;\n setActive: (active: boolean) => void;\n setItems: (items: T[]) => void;\n};\n\ntype MeasurementSyncMode = 'invalidate' | 'refresh' | null;\n\nexport function createDomVirtualList<T>(options: DomVirtualListOptions<T>): DomVirtualListController<T> {\n let currentItems: T[] = [];\n let isActive = true;\n let listElRef: HTMLElement | null = null;\n let scrollElRef: HTMLElement | Window | null = null;\n let virtualizer: Virtualizer | null = null;\n let itemKeyRevision = 0;\n\n const resolveItemKey = (index: number): VirtualKey => {\n const item = currentItems[index];\n\n if (item && options.getItemKey) return options.getItemKey(index, item);\n\n return `${itemKeyRevision}:${index}`;\n };\n\n const resolveEstimate = (index: number): number => {\n if (typeof options.estimateSize === 'number') return options.estimateSize;\n\n const item = currentItems[index];\n\n if (!item) return DEFAULT_ESTIMATE_SIZE;\n\n return options.estimateSize(index, item);\n };\n\n const clearAndReset = (listEl: HTMLElement | null = listElRef) => {\n if (!listEl) return;\n\n if (options.clear) options.clear(listEl);\n else listEl.textContent = '';\n\n listEl.style.height = '';\n listEl.style.width = '';\n listEl.style.position = '';\n listEl.style.contain = '';\n };\n\n const applyListSize = (totalSize: number) => {\n if (!listElRef) return;\n\n if (options.horizontal) {\n listElRef.style.width = `${totalSize}px`;\n listElRef.style.height = '';\n } else {\n listElRef.style.height = `${totalSize}px`;\n listElRef.style.width = '';\n }\n };\n\n const renderFromChange = (virtualItems: VirtualItem[], totalSize: number) => {\n if (!listElRef) return;\n\n applyListSize(totalSize);\n options.render({\n items: currentItems,\n listEl: listElRef,\n totalSize,\n virtualItems,\n });\n };\n\n const syncVirtualizer = (measurementSync: MeasurementSyncMode) => {\n const nextScroll = options.getScrollElement();\n const nextList = options.getListElement();\n const previousList = listElRef;\n\n if (!isActive || !nextScroll || !nextList || currentItems.length === 0) {\n virtualizer?.destroy();\n virtualizer = null;\n listElRef = nextList;\n scrollElRef = nextScroll;\n clearAndReset();\n\n return;\n }\n\n const targetChanged = scrollElRef !== nextScroll || listElRef !== nextList;\n\n listElRef = nextList;\n scrollElRef = nextScroll;\n\n if (!virtualizer || targetChanged) {\n const shouldClearForTargetSwap = !!virtualizer && targetChanged;\n\n virtualizer?.destroy();\n\n if (shouldClearForTargetSwap) clearAndReset(previousList);\n\n virtualizer = createVirtualizer(scrollElRef, {\n count: currentItems.length,\n estimateSize: resolveEstimate,\n gap: options.gap,\n getItemKey: resolveItemKey,\n horizontal: options.horizontal,\n onChange: (virtualItems, totalSize) => renderFromChange(virtualItems, totalSize),\n overscan: options.overscan ?? { end: DEFAULT_OVERSCAN, start: DEFAULT_OVERSCAN },\n });\n\n listElRef.style.position = 'relative';\n listElRef.style.contain = 'layout';\n\n return;\n }\n\n virtualizer.update({\n count: currentItems.length,\n estimateSize: resolveEstimate,\n gap: options.gap,\n getItemKey: resolveItemKey,\n overscan: options.overscan,\n });\n\n if (measurementSync === 'invalidate') {\n virtualizer.invalidate();\n\n return;\n }\n\n if (measurementSync === 'refresh') virtualizer.refresh();\n };\n\n return {\n destroy() {\n virtualizer?.destroy();\n virtualizer = null;\n clearAndReset();\n },\n invalidate() {\n virtualizer?.invalidate();\n },\n measure(index, size) {\n virtualizer?.measure(index, size);\n },\n scrollToIndex(index, scrollOptions) {\n virtualizer?.scrollToIndex(index, scrollOptions);\n },\n setActive(active) {\n isActive = active;\n syncVirtualizer(null);\n },\n setItems(items) {\n currentItems = items;\n\n if (options.getItemKey) {\n syncVirtualizer('refresh');\n\n return;\n }\n\n itemKeyRevision += 1;\n syncVirtualizer('invalidate');\n },\n };\n}\n"],"mappings":";;AAWA,IAAM,IAAwB,IACxB,IAAmB;AAgCzB,SAAgB,EAAwB,GAAgE;CACtG,IAAI,IAAoB,CAAC,GACrB,IAAW,IACX,IAAgC,MAChC,IAA2C,MAC3C,IAAkC,MAClC,IAAkB,GAEhB,KAAkB,MAA8B;EACpD,IAAM,IAAO,EAAa;EAI1B,OAFI,KAAQ,EAAQ,aAAmB,EAAQ,WAAW,GAAO,CAAI,IAE9D,GAAG,EAAgB,GAAG;CAC/B,GAEM,KAAmB,MAA0B;EACjD,IAAI,OAAO,EAAQ,gBAAiB,UAAU,OAAO,EAAQ;EAE7D,IAAM,IAAO,EAAa;EAI1B,OAFK,IAEE,EAAQ,aAAa,GAAO,CAAI,IAFrB;CAGpB,GAEM,KAAiB,IAA6B,MAAc;EAC3D,MAED,EAAQ,QAAO,EAAQ,MAAM,CAAM,IAClC,EAAO,cAAc,IAE1B,EAAO,MAAM,SAAS,IACtB,EAAO,MAAM,QAAQ,IACrB,EAAO,MAAM,WAAW,IACxB,EAAO,MAAM,UAAU;CACzB,GAEM,KAAiB,MAAsB;EACtC,MAED,EAAQ,cACV,EAAU,MAAM,QAAQ,GAAG,EAAU,KACrC,EAAU,MAAM,SAAS,OAEzB,EAAU,MAAM,SAAS,GAAG,EAAU,KACtC,EAAU,MAAM,QAAQ;CAE5B,GAEM,KAAoB,GAA6B,MAAsB;EACtE,MAEL,EAAc,CAAS,GACvB,EAAQ,OAAO;GACb,OAAO;GACP,QAAQ;GACR;GACA;EACF,CAAC;CACH,GAEM,KAAmB,MAAyC;EAChE,IAAM,IAAa,EAAQ,iBAAiB,GACtC,IAAW,EAAQ,eAAe,GAClC,IAAe;EAErB,IAAI,CAAC,KAAY,CAAC,KAAc,CAAC,KAAY,EAAa,WAAW,GAAG;GAKtE,AAJA,GAAa,QAAQ,GACrB,IAAc,MACd,IAAY,GACZ,IAAc,GACd,EAAc;GAEd;EACF;EAEA,IAAM,IAAgB,MAAgB,KAAc,MAAc;EAKlE,IAHA,IAAY,GACZ,IAAc,GAEV,CAAC,KAAe,GAAe;GACjC,IAAM,IAA2B,CAAC,CAAC,KAAe;GAiBlD,AAfA,GAAa,QAAQ,GAEjB,KAA0B,EAAc,CAAY,GAExD,IAAc,EAAkB,GAAa;IAC3C,OAAO,EAAa;IACpB,cAAc;IACd,KAAK,EAAQ;IACb,YAAY;IACZ,YAAY,EAAQ;IACpB,WAAW,GAAc,MAAc,EAAiB,GAAc,CAAS;IAC/E,UAAU,EAAQ,YAAY;KAAE,KAAK;KAAkB,OAAO;IAAiB;GACjF,CAAC,GAED,EAAU,MAAM,WAAW,YAC3B,EAAU,MAAM,UAAU;GAE1B;EACF;EAUA,IARA,EAAY,OAAO;GACjB,OAAO,EAAa;GACpB,cAAc;GACd,KAAK,EAAQ;GACb,YAAY;GACZ,UAAU,EAAQ;EACpB,CAAC,GAEG,MAAoB,cAAc;GACpC,EAAY,WAAW;GAEvB;EACF;EAEA,AAAI,MAAoB,aAAW,EAAY,QAAQ;CACzD;CAEA,OAAO;EACL,UAAU;GAGR,AAFA,GAAa,QAAQ,GACrB,IAAc,MACd,EAAc;EAChB;EACA,aAAa;GACX,GAAa,WAAW;EAC1B;EACA,QAAQ,GAAO,GAAM;GACnB,GAAa,QAAQ,GAAO,CAAI;EAClC;EACA,cAAc,GAAO,GAAe;GAClC,GAAa,cAAc,GAAO,CAAa;EACjD;EACA,UAAU,GAAQ;GAEhB,AADA,IAAW,GACX,EAAgB,IAAI;EACtB;EACA,SAAS,GAAO;GAGd,IAFA,IAAe,GAEX,EAAQ,YAAY;IACtB,EAAgB,SAAS;IAEzB;GACF;GAGA,AADA,KAAmB,GACnB,EAAgB,YAAY;EAC9B;CACF;AACF"}
|
package/dist/dom.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./virtualit.cjs`),t=require(`./dom/dom.cjs`);exports.
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./virtualit.cjs`),t=require(`./dom/dom.cjs`);exports.createDomVirtualList=t.createDomVirtualList,exports.createVirtualizer=e.createVirtualizer;
|
package/dist/dom.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createDomVirtualList as
|
|
3
|
-
export {
|
|
1
|
+
import { createVirtualizer as e } from "./virtualit.js";
|
|
2
|
+
import { createDomVirtualList as t } from "./dom/dom.js";
|
|
3
|
+
export { t as createDomVirtualList, e as createVirtualizer };
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./virtualit.cjs`);exports.
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./virtualit.cjs`);exports.createVirtualizer=e.createVirtualizer;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { e as
|
|
1
|
+
import { createVirtualizer as e } from "./virtualit.js";
|
|
2
|
+
export { e as createVirtualizer };
|
package/dist/virtualit.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=36,t=3;function
|
|
1
|
+
var e=36,t=3,n=120;function r(e,t=0){return Number.isFinite(e)?Math.max(0,Math.floor(e)):t}function i(e,t){return!Number.isFinite(e)||e<=0?t:e}function a(t){return typeof t==`number`?i(t,e):typeof t==`function`?t:e}function o(t){return typeof t==`number`?()=>t:n=>i(t(n),e)}function s(e){return{end:r(e?.end??t),start:r(e?.start??t)}}function c(e){return`innerHeight`in e&&`innerWidth`in e&&!(`clientHeight`in e)}function l(e,t){return c(e)?{attach(t,n){return e.addEventListener(`scroll`,t,{passive:!0}),e.addEventListener(`resize`,n,{passive:!0}),()=>{e.removeEventListener(`scroll`,t),e.removeEventListener(`resize`,n)}},readOffset:t?()=>e.scrollX:()=>e.scrollY,readViewportSize:t?()=>e.innerWidth:()=>e.innerHeight,writeOffset:(n,r)=>{e.scrollTo(t?{behavior:r,left:n}:{behavior:r,top:n})}}:{attach(t,n){let r=new ResizeObserver(n);return e.addEventListener(`scroll`,t,{passive:!0}),r.observe(e),()=>{e.removeEventListener(`scroll`,t),r.disconnect()}},readOffset:t?()=>e.scrollLeft:()=>e.scrollTop,readViewportSize:t?()=>e.clientWidth:()=>e.clientHeight,writeOffset:(n,r)=>{e.scrollTo(t?{behavior:r,left:n}:{behavior:r,top:n})}}}function u(e,t){let c=l(e,!!t.horizontal),u=r(t.count),d=a(t.estimateSize),f=o(d),p=r(t.gap??0),m=t.getItemKey??(e=>e),h=s(t.overscan),g=r(t.scrollEndDelay??n,n),_=t.onChange,v=t.onScrollEnd,y=t.onScrollingChange,b=[],x=0,S=0,C=!1,w=new Map,T=new Float64Array(u+1),E=c.readViewportSize(),D=-1,O=-1,k=-1,A=!1,j=!1,M=null;function N(e){return m(e)}function P(e){return w.get(N(e))??f(e)}function F(e){return T[e]??0}function I(e){return F(e)+P(e)}function L(e){let t=Number.isFinite(e)?e:0,n=Math.max(0,x-E);return Math.min(n,Math.max(0,t))}function R(){M&&=(clearTimeout(M),null)}function z(e){C!==e&&(C=e,y?.(e))}function B(){R(),M=setTimeout(()=>{M=null,z(!1),v?.(S)},g)}function V(){S=L(c.readOffset()),z(!0),B(),Y()}function H(){E=c.readViewportSize(),Y()}function U(e){let t=0,n=u-1;for(;t<n;){let r=t+n>>1;I(r)<=e?t=r+1:n=r}return t}function W(e,t){let n=t,r=u-1;for(;n<r;){let t=n+r+1>>1;F(t)<e?n=t:r=t-1}return n}function G(e){let t=F(e),n=P(e);return{end:t+n,index:e,size:n,start:t}}function K(e){b=e,_?.(e,x)}function q(){let e=c.readOffset(),t=L(e);t!==S&&(S=t,e!==t&&c.writeOffset(t,`auto`))}function J(){D=-1,O=-1;let e=new Float64Array(u+1);for(let t=0;t<u;t++)e[t+1]=e[t]+P(t)+(t<u-1?p:0);T=e,x=e[u]??0}function Y(){if(j)return;if(q(),u===0||E<=0){(D!==-1||k!==x)&&(D=-1,O=-1,k=x,K([]));return}let e=S,t=e+E,n=U(e),r=W(t,n),i=Math.max(0,n-h.start),a=Math.min(u-1,r+h.end);if(i===D&&a===O&&k===x)return;D=i,O=a,k=x;let o=[];for(let e=i;e<=a;e++)o.push(G(e));K(o)}function X(e){let t=!1,i=!1;if(`count`in e&&e.count!==void 0){let n=r(e.count);n!==u&&(u=n,t=!0,i=!0)}if(`estimateSize`in e&&e.estimateSize!==void 0){let n=a(e.estimateSize);n!==d&&(d=n,f=o(d),w.clear(),t=!0,i=!0)}if(`gap`in e&&e.gap!==void 0){let n=r(e.gap);n!==p&&(p=n,t=!0,i=!0)}if(`getItemKey`in e&&e.getItemKey&&e.getItemKey!==m&&(m=e.getItemKey,w.clear(),t=!0,i=!0),`overscan`in e){let t=s(e.overscan);(t.start!==h.start||t.end!==h.end)&&(h=t,i=!0)}if(`scrollEndDelay`in e&&e.scrollEndDelay!==void 0){let t=r(e.scrollEndDelay,n);t!==g&&(g=t)}`onChange`in e&&(_=e.onChange),`onScrollEnd`in e&&(v=e.onScrollEnd),`onScrollingChange`in e&&(y=e.onScrollingChange),t&&J(),(i||t)&&Y()}function Z(e){j||X(e)}function Q(e,t){if(j||!Number.isFinite(e))return;let n=Math.floor(e);if(n<0||n>=u)return;let r=i(t,-1);if(r<=0)return;let a=N(n);w.get(a)!==r&&(w.set(a,r),!A&&(A=!0,queueMicrotask(()=>{A=!1,J(),Y()})))}function ee(){j||(w.clear(),J(),Y())}function te(){j||(J(),Y())}function ne(e,t={}){if(j||u<=0)return;let n=Math.max(0,Math.min(Number.isFinite(e)?Math.floor(e):0,u-1)),r=t.align??`auto`,i=t.behavior??`auto`,a=F(n),o=P(n),s=a+o,l;if(r===`start`)l=a;else if(r===`end`)l=s-E;else if(r===`center`)l=a-(E-o)/2;else{let e=S,t=e+E;if(a>=e&&s<=t)return;l=a<e?a:s-E}c.writeOffset(L(l),i)}function re(e,t={}){j||c.writeOffset(L(e),t.behavior??`auto`)}function $(){j||(j=!0,R(),ie())}J(),t.initialOffset!==void 0&&c.writeOffset(L(t.initialOffset),`auto`),S=L(c.readOffset());let ie=c.attach(V,H);return Y(),{get count(){return u},destroy:$,invalidate:ee,get isScrolling(){return C},get items(){return b},measure:Q,refresh:te,get scrollOffset(){return S},scrollToIndex:ne,scrollToOffset:re,[Symbol.dispose](){$()},get totalSize(){return x},update:Z}}exports.createVirtualizer=u;
|
|
2
2
|
//# sourceMappingURL=virtualit.cjs.map
|