@pyreon/virtual 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +184 -0
- package/lib/analysis/index.js.html +5406 -0
- package/lib/index.js +143 -0
- package/lib/index.js.map +1 -0
- package/lib/types/index.d.ts +143 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index2.d.ts +54 -0
- package/lib/types/index2.d.ts.map +1 -0
- package/package.json +55 -0
- package/src/index.ts +37 -0
- package/src/tests/virtual.test.ts +619 -0
- package/src/use-virtualizer.ts +124 -0
- package/src/use-window-virtualizer.ts +106 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Virtualizer, Virtualizer as Virtualizer$1, defaultKeyExtractor, defaultRangeExtractor, elementScroll, elementScroll as elementScroll$1, measureElement, observeElementOffset, observeElementOffset as observeElementOffset$1, observeElementRect, observeElementRect as observeElementRect$1, observeWindowOffset, observeWindowOffset as observeWindowOffset$1, observeWindowRect, observeWindowRect as observeWindowRect$1, windowScroll, windowScroll as windowScroll$1 } from "@tanstack/virtual-core";
|
|
2
|
+
import { onMount, onUnmount } from "@pyreon/core";
|
|
3
|
+
import { batch, effect, signal } from "@pyreon/reactivity";
|
|
4
|
+
|
|
5
|
+
//#region src/use-virtualizer.ts
|
|
6
|
+
/**
|
|
7
|
+
* Create a reactive TanStack Virtual virtualizer for element-based scrolling.
|
|
8
|
+
*
|
|
9
|
+
* Options are passed as a function so reactive signals (e.g. count, estimateSize)
|
|
10
|
+
* can be read inside, and the virtualizer updates automatically when they change.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const parentRef = signal<HTMLDivElement | null>(null)
|
|
14
|
+
* const virtual = useVirtualizer(() => ({
|
|
15
|
+
* count: 10000,
|
|
16
|
+
* getScrollElement: () => parentRef(),
|
|
17
|
+
* estimateSize: () => 35,
|
|
18
|
+
* }))
|
|
19
|
+
* // virtual.virtualItems() — array of visible VirtualItem
|
|
20
|
+
* // virtual.totalSize() — total height/width for the inner container
|
|
21
|
+
*/
|
|
22
|
+
function useVirtualizer(options) {
|
|
23
|
+
const resolvedOptions = {
|
|
24
|
+
observeElementRect: observeElementRect$1,
|
|
25
|
+
observeElementOffset: observeElementOffset$1,
|
|
26
|
+
scrollToFn: elementScroll$1,
|
|
27
|
+
...options()
|
|
28
|
+
};
|
|
29
|
+
const virtualItems = signal([]);
|
|
30
|
+
const totalSize = signal(0);
|
|
31
|
+
const isScrolling = signal(false);
|
|
32
|
+
let latestUserOpts = options();
|
|
33
|
+
const instance = new Virtualizer$1(resolvedOptions);
|
|
34
|
+
const effectCleanup = effect(() => {
|
|
35
|
+
latestUserOpts = options();
|
|
36
|
+
instance.setOptions({
|
|
37
|
+
...instance.options,
|
|
38
|
+
...latestUserOpts,
|
|
39
|
+
onChange: (inst, sync) => {
|
|
40
|
+
batch(() => {
|
|
41
|
+
virtualItems.set(inst.getVirtualItems());
|
|
42
|
+
totalSize.set(inst.getTotalSize());
|
|
43
|
+
isScrolling.set(inst.isScrolling);
|
|
44
|
+
});
|
|
45
|
+
latestUserOpts.onChange?.(inst, sync);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
instance._willUpdate();
|
|
49
|
+
batch(() => {
|
|
50
|
+
virtualItems.set(instance.getVirtualItems());
|
|
51
|
+
totalSize.set(instance.getTotalSize());
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
let mountCleanup;
|
|
55
|
+
onMount(() => {
|
|
56
|
+
mountCleanup = instance._didMount();
|
|
57
|
+
instance._willUpdate();
|
|
58
|
+
batch(() => {
|
|
59
|
+
virtualItems.set(instance.getVirtualItems());
|
|
60
|
+
totalSize.set(instance.getTotalSize());
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
onUnmount(() => {
|
|
64
|
+
effectCleanup.dispose();
|
|
65
|
+
mountCleanup?.();
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
instance,
|
|
69
|
+
virtualItems,
|
|
70
|
+
totalSize,
|
|
71
|
+
isScrolling
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/use-window-virtualizer.ts
|
|
77
|
+
/**
|
|
78
|
+
* Create a reactive TanStack Virtual virtualizer for window-based scrolling.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const virtual = useWindowVirtualizer(() => ({
|
|
82
|
+
* count: 10000,
|
|
83
|
+
* estimateSize: () => 35,
|
|
84
|
+
* }))
|
|
85
|
+
*/
|
|
86
|
+
function useWindowVirtualizer(options) {
|
|
87
|
+
const virtualItems = signal([]);
|
|
88
|
+
const totalSize = signal(0);
|
|
89
|
+
const isScrolling = signal(false);
|
|
90
|
+
const resolvedOptions = {
|
|
91
|
+
observeElementRect: observeWindowRect$1,
|
|
92
|
+
observeElementOffset: observeWindowOffset$1,
|
|
93
|
+
scrollToFn: windowScroll$1,
|
|
94
|
+
initialOffset: typeof document !== "undefined" ? window.scrollY : 0,
|
|
95
|
+
getScrollElement: () => typeof window !== "undefined" ? window : null,
|
|
96
|
+
...options()
|
|
97
|
+
};
|
|
98
|
+
let latestUserOpts = options();
|
|
99
|
+
const instance = new Virtualizer$1(resolvedOptions);
|
|
100
|
+
const effectCleanup = effect(() => {
|
|
101
|
+
latestUserOpts = options();
|
|
102
|
+
instance.setOptions({
|
|
103
|
+
...instance.options,
|
|
104
|
+
...latestUserOpts,
|
|
105
|
+
onChange: (inst, sync) => {
|
|
106
|
+
batch(() => {
|
|
107
|
+
virtualItems.set(inst.getVirtualItems());
|
|
108
|
+
totalSize.set(inst.getTotalSize());
|
|
109
|
+
isScrolling.set(inst.isScrolling);
|
|
110
|
+
});
|
|
111
|
+
latestUserOpts.onChange?.(inst, sync);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
instance._willUpdate();
|
|
115
|
+
batch(() => {
|
|
116
|
+
virtualItems.set(instance.getVirtualItems());
|
|
117
|
+
totalSize.set(instance.getTotalSize());
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
let mountCleanup;
|
|
121
|
+
onMount(() => {
|
|
122
|
+
mountCleanup = instance._didMount();
|
|
123
|
+
instance._willUpdate();
|
|
124
|
+
batch(() => {
|
|
125
|
+
virtualItems.set(instance.getVirtualItems());
|
|
126
|
+
totalSize.set(instance.getTotalSize());
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
onUnmount(() => {
|
|
130
|
+
effectCleanup.dispose();
|
|
131
|
+
mountCleanup?.();
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
instance,
|
|
135
|
+
virtualItems,
|
|
136
|
+
totalSize,
|
|
137
|
+
isScrolling
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
export { Virtualizer, defaultKeyExtractor, defaultRangeExtractor, elementScroll, measureElement, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, useVirtualizer, useWindowVirtualizer, windowScroll };
|
|
143
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["elementScroll","Virtualizer","observeWindowRect","observeWindowOffset","windowScroll","Virtualizer"],"sources":["../src/use-virtualizer.ts","../src/use-window-virtualizer.ts"],"sourcesContent":["import { onMount, onUnmount } from '@pyreon/core'\nimport { signal, effect, batch } from '@pyreon/reactivity'\nimport type { Signal } from '@pyreon/reactivity'\nimport {\n Virtualizer,\n elementScroll,\n observeElementOffset,\n observeElementRect,\n type VirtualizerOptions,\n type VirtualItem,\n} from '@tanstack/virtual-core'\n\nexport type UseVirtualizerOptions<\n TScrollElement extends Element,\n TItemElement extends Element,\n> = () => Omit<\n VirtualizerOptions<TScrollElement, TItemElement>,\n 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'\n> &\n Partial<\n Pick<\n VirtualizerOptions<TScrollElement, TItemElement>,\n 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'\n >\n >\n\nexport interface UseVirtualizerResult<\n TScrollElement extends Element,\n TItemElement extends Element,\n> {\n /** The virtualizer instance — read to access all methods. */\n instance: Virtualizer<TScrollElement, TItemElement>\n /** Reactive signal of currently visible virtual items. */\n virtualItems: Signal<VirtualItem[]>\n /** Reactive signal of the total scrollable size in pixels. */\n totalSize: Signal<number>\n /** Reactive signal indicating whether the user is scrolling. */\n isScrolling: Signal<boolean>\n}\n\n/**\n * Create a reactive TanStack Virtual virtualizer for element-based scrolling.\n *\n * Options are passed as a function so reactive signals (e.g. count, estimateSize)\n * can be read inside, and the virtualizer updates automatically when they change.\n *\n * @example\n * const parentRef = signal<HTMLDivElement | null>(null)\n * const virtual = useVirtualizer(() => ({\n * count: 10000,\n * getScrollElement: () => parentRef(),\n * estimateSize: () => 35,\n * }))\n * // virtual.virtualItems() — array of visible VirtualItem\n * // virtual.totalSize() — total height/width for the inner container\n */\nexport function useVirtualizer<\n TScrollElement extends Element,\n TItemElement extends Element,\n>(\n options: UseVirtualizerOptions<TScrollElement, TItemElement>,\n): UseVirtualizerResult<TScrollElement, TItemElement> {\n const resolvedOptions: VirtualizerOptions<TScrollElement, TItemElement> = {\n observeElementRect,\n observeElementOffset,\n scrollToFn: elementScroll,\n ...options(),\n }\n\n const virtualItems = signal<VirtualItem[]>([])\n const totalSize = signal(0)\n const isScrolling = signal(false)\n\n // Store latest user options so onChange always reads the freshest reference\n let latestUserOpts = options()\n\n const instance = new Virtualizer<TScrollElement, TItemElement>(\n resolvedOptions,\n )\n\n // Track reactive options: when signals inside options() change, update the virtualizer.\n const effectCleanup = effect(() => {\n latestUserOpts = options()\n instance.setOptions({\n ...instance.options,\n ...latestUserOpts,\n onChange: (inst, sync) => {\n batch(() => {\n virtualItems.set(inst.getVirtualItems())\n totalSize.set(inst.getTotalSize())\n isScrolling.set(inst.isScrolling)\n })\n // Read latest opts to avoid stale closure\n latestUserOpts.onChange?.(inst, sync)\n },\n })\n\n // After updating options, recalculate and re-emit\n instance._willUpdate()\n batch(() => {\n virtualItems.set(instance.getVirtualItems())\n totalSize.set(instance.getTotalSize())\n })\n })\n\n // Lifecycle: mount observers, clean up on unmount.\n let mountCleanup: (() => void) | undefined\n onMount(() => {\n mountCleanup = instance._didMount()\n instance._willUpdate()\n batch(() => {\n virtualItems.set(instance.getVirtualItems())\n totalSize.set(instance.getTotalSize())\n })\n return undefined\n })\n\n onUnmount(() => {\n effectCleanup.dispose()\n mountCleanup?.()\n })\n\n return { instance, virtualItems, totalSize, isScrolling }\n}\n","import { onMount, onUnmount } from '@pyreon/core'\nimport { signal, effect, batch } from '@pyreon/reactivity'\nimport type { Signal } from '@pyreon/reactivity'\nimport {\n Virtualizer,\n windowScroll,\n observeWindowOffset,\n observeWindowRect,\n type VirtualizerOptions,\n type VirtualItem,\n} from '@tanstack/virtual-core'\n\nexport type UseWindowVirtualizerOptions<TItemElement extends Element> =\n () => Omit<\n VirtualizerOptions<Window, TItemElement>,\n | 'observeElementRect'\n | 'observeElementOffset'\n | 'scrollToFn'\n | 'getScrollElement'\n > &\n Partial<\n Pick<\n VirtualizerOptions<Window, TItemElement>,\n 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'\n >\n >\n\nexport interface UseWindowVirtualizerResult<TItemElement extends Element> {\n instance: Virtualizer<Window, TItemElement>\n virtualItems: Signal<VirtualItem[]>\n totalSize: Signal<number>\n isScrolling: Signal<boolean>\n}\n\n/**\n * Create a reactive TanStack Virtual virtualizer for window-based scrolling.\n *\n * @example\n * const virtual = useWindowVirtualizer(() => ({\n * count: 10000,\n * estimateSize: () => 35,\n * }))\n */\nexport function useWindowVirtualizer<TItemElement extends Element>(\n options: UseWindowVirtualizerOptions<TItemElement>,\n): UseWindowVirtualizerResult<TItemElement> {\n const virtualItems = signal<VirtualItem[]>([])\n const totalSize = signal(0)\n const isScrolling = signal(false)\n\n const resolvedOptions: VirtualizerOptions<Window, TItemElement> = {\n observeElementRect: observeWindowRect,\n observeElementOffset: observeWindowOffset,\n scrollToFn: windowScroll,\n initialOffset: typeof document !== 'undefined' ? window.scrollY : 0,\n getScrollElement: () =>\n typeof window !== 'undefined' ? window : (null as unknown as Window),\n ...options(),\n }\n\n // Store latest user options so onChange always reads the freshest reference\n let latestUserOpts = options()\n\n const instance = new Virtualizer<Window, TItemElement>(resolvedOptions)\n\n const effectCleanup = effect(() => {\n latestUserOpts = options()\n instance.setOptions({\n ...instance.options,\n ...latestUserOpts,\n onChange: (inst, sync) => {\n batch(() => {\n virtualItems.set(inst.getVirtualItems())\n totalSize.set(inst.getTotalSize())\n isScrolling.set(inst.isScrolling)\n })\n // Read latest opts to avoid stale closure\n latestUserOpts.onChange?.(inst, sync)\n },\n })\n\n instance._willUpdate()\n batch(() => {\n virtualItems.set(instance.getVirtualItems())\n totalSize.set(instance.getTotalSize())\n })\n })\n\n let mountCleanup: (() => void) | undefined\n onMount(() => {\n mountCleanup = instance._didMount()\n instance._willUpdate()\n batch(() => {\n virtualItems.set(instance.getVirtualItems())\n totalSize.set(instance.getTotalSize())\n })\n return undefined\n })\n\n onUnmount(() => {\n effectCleanup.dispose()\n mountCleanup?.()\n })\n\n return { instance, virtualItems, totalSize, isScrolling }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwDA,SAAgB,eAId,SACoD;CACpD,MAAM,kBAAoE;EACxE;EACA;EACA,YAAYA;EACZ,GAAG,SAAS;EACb;CAED,MAAM,eAAe,OAAsB,EAAE,CAAC;CAC9C,MAAM,YAAY,OAAO,EAAE;CAC3B,MAAM,cAAc,OAAO,MAAM;CAGjC,IAAI,iBAAiB,SAAS;CAE9B,MAAM,WAAW,IAAIC,cACnB,gBACD;CAGD,MAAM,gBAAgB,aAAa;AACjC,mBAAiB,SAAS;AAC1B,WAAS,WAAW;GAClB,GAAG,SAAS;GACZ,GAAG;GACH,WAAW,MAAM,SAAS;AACxB,gBAAY;AACV,kBAAa,IAAI,KAAK,iBAAiB,CAAC;AACxC,eAAU,IAAI,KAAK,cAAc,CAAC;AAClC,iBAAY,IAAI,KAAK,YAAY;MACjC;AAEF,mBAAe,WAAW,MAAM,KAAK;;GAExC,CAAC;AAGF,WAAS,aAAa;AACtB,cAAY;AACV,gBAAa,IAAI,SAAS,iBAAiB,CAAC;AAC5C,aAAU,IAAI,SAAS,cAAc,CAAC;IACtC;GACF;CAGF,IAAI;AACJ,eAAc;AACZ,iBAAe,SAAS,WAAW;AACnC,WAAS,aAAa;AACtB,cAAY;AACV,gBAAa,IAAI,SAAS,iBAAiB,CAAC;AAC5C,aAAU,IAAI,SAAS,cAAc,CAAC;IACtC;GAEF;AAEF,iBAAgB;AACd,gBAAc,SAAS;AACvB,kBAAgB;GAChB;AAEF,QAAO;EAAE;EAAU;EAAc;EAAW;EAAa;;;;;;;;;;;;;;AC/E3D,SAAgB,qBACd,SAC0C;CAC1C,MAAM,eAAe,OAAsB,EAAE,CAAC;CAC9C,MAAM,YAAY,OAAO,EAAE;CAC3B,MAAM,cAAc,OAAO,MAAM;CAEjC,MAAM,kBAA4D;EAChE,oBAAoBC;EACpB,sBAAsBC;EACtB,YAAYC;EACZ,eAAe,OAAO,aAAa,cAAc,OAAO,UAAU;EAClE,wBACE,OAAO,WAAW,cAAc,SAAU;EAC5C,GAAG,SAAS;EACb;CAGD,IAAI,iBAAiB,SAAS;CAE9B,MAAM,WAAW,IAAIC,cAAkC,gBAAgB;CAEvE,MAAM,gBAAgB,aAAa;AACjC,mBAAiB,SAAS;AAC1B,WAAS,WAAW;GAClB,GAAG,SAAS;GACZ,GAAG;GACH,WAAW,MAAM,SAAS;AACxB,gBAAY;AACV,kBAAa,IAAI,KAAK,iBAAiB,CAAC;AACxC,eAAU,IAAI,KAAK,cAAc,CAAC;AAClC,iBAAY,IAAI,KAAK,YAAY;MACjC;AAEF,mBAAe,WAAW,MAAM,KAAK;;GAExC,CAAC;AAEF,WAAS,aAAa;AACtB,cAAY;AACV,gBAAa,IAAI,SAAS,iBAAiB,CAAC;AAC5C,aAAU,IAAI,SAAS,cAAc,CAAC;IACtC;GACF;CAEF,IAAI;AACJ,eAAc;AACZ,iBAAe,SAAS,WAAW;AACnC,WAAS,aAAa;AACtB,cAAY;AACV,gBAAa,IAAI,SAAS,iBAAiB,CAAC;AAC5C,aAAU,IAAI,SAAS,cAAc,CAAC;IACtC;GAEF;AAEF,iBAAgB;AACd,gBAAc,SAAS;AACvB,kBAAgB;GAChB;AAEF,QAAO;EAAE;EAAU;EAAc;EAAW;EAAa"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Virtualizer, Virtualizer as Virtualizer$1, defaultKeyExtractor, defaultRangeExtractor, elementScroll, elementScroll as elementScroll$1, measureElement, observeElementOffset, observeElementOffset as observeElementOffset$1, observeElementRect, observeElementRect as observeElementRect$1, observeWindowOffset, observeWindowOffset as observeWindowOffset$1, observeWindowRect, observeWindowRect as observeWindowRect$1, windowScroll, windowScroll as windowScroll$1 } from "@tanstack/virtual-core";
|
|
2
|
+
import { onMount, onUnmount } from "@pyreon/core";
|
|
3
|
+
import { batch, effect, signal } from "@pyreon/reactivity";
|
|
4
|
+
|
|
5
|
+
//#region src/use-virtualizer.ts
|
|
6
|
+
/**
|
|
7
|
+
* Create a reactive TanStack Virtual virtualizer for element-based scrolling.
|
|
8
|
+
*
|
|
9
|
+
* Options are passed as a function so reactive signals (e.g. count, estimateSize)
|
|
10
|
+
* can be read inside, and the virtualizer updates automatically when they change.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const parentRef = signal<HTMLDivElement | null>(null)
|
|
14
|
+
* const virtual = useVirtualizer(() => ({
|
|
15
|
+
* count: 10000,
|
|
16
|
+
* getScrollElement: () => parentRef(),
|
|
17
|
+
* estimateSize: () => 35,
|
|
18
|
+
* }))
|
|
19
|
+
* // virtual.virtualItems() — array of visible VirtualItem
|
|
20
|
+
* // virtual.totalSize() — total height/width for the inner container
|
|
21
|
+
*/
|
|
22
|
+
function useVirtualizer(options) {
|
|
23
|
+
const resolvedOptions = {
|
|
24
|
+
observeElementRect: observeElementRect$1,
|
|
25
|
+
observeElementOffset: observeElementOffset$1,
|
|
26
|
+
scrollToFn: elementScroll$1,
|
|
27
|
+
...options()
|
|
28
|
+
};
|
|
29
|
+
const virtualItems = signal([]);
|
|
30
|
+
const totalSize = signal(0);
|
|
31
|
+
const isScrolling = signal(false);
|
|
32
|
+
let latestUserOpts = options();
|
|
33
|
+
const instance = new Virtualizer$1(resolvedOptions);
|
|
34
|
+
const effectCleanup = effect(() => {
|
|
35
|
+
latestUserOpts = options();
|
|
36
|
+
instance.setOptions({
|
|
37
|
+
...instance.options,
|
|
38
|
+
...latestUserOpts,
|
|
39
|
+
onChange: (inst, sync) => {
|
|
40
|
+
batch(() => {
|
|
41
|
+
virtualItems.set(inst.getVirtualItems());
|
|
42
|
+
totalSize.set(inst.getTotalSize());
|
|
43
|
+
isScrolling.set(inst.isScrolling);
|
|
44
|
+
});
|
|
45
|
+
latestUserOpts.onChange?.(inst, sync);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
instance._willUpdate();
|
|
49
|
+
batch(() => {
|
|
50
|
+
virtualItems.set(instance.getVirtualItems());
|
|
51
|
+
totalSize.set(instance.getTotalSize());
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
let mountCleanup;
|
|
55
|
+
onMount(() => {
|
|
56
|
+
mountCleanup = instance._didMount();
|
|
57
|
+
instance._willUpdate();
|
|
58
|
+
batch(() => {
|
|
59
|
+
virtualItems.set(instance.getVirtualItems());
|
|
60
|
+
totalSize.set(instance.getTotalSize());
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
onUnmount(() => {
|
|
64
|
+
effectCleanup.dispose();
|
|
65
|
+
mountCleanup?.();
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
instance,
|
|
69
|
+
virtualItems,
|
|
70
|
+
totalSize,
|
|
71
|
+
isScrolling
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/use-window-virtualizer.ts
|
|
77
|
+
/**
|
|
78
|
+
* Create a reactive TanStack Virtual virtualizer for window-based scrolling.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const virtual = useWindowVirtualizer(() => ({
|
|
82
|
+
* count: 10000,
|
|
83
|
+
* estimateSize: () => 35,
|
|
84
|
+
* }))
|
|
85
|
+
*/
|
|
86
|
+
function useWindowVirtualizer(options) {
|
|
87
|
+
const virtualItems = signal([]);
|
|
88
|
+
const totalSize = signal(0);
|
|
89
|
+
const isScrolling = signal(false);
|
|
90
|
+
const resolvedOptions = {
|
|
91
|
+
observeElementRect: observeWindowRect$1,
|
|
92
|
+
observeElementOffset: observeWindowOffset$1,
|
|
93
|
+
scrollToFn: windowScroll$1,
|
|
94
|
+
initialOffset: typeof document !== "undefined" ? window.scrollY : 0,
|
|
95
|
+
getScrollElement: () => typeof window !== "undefined" ? window : null,
|
|
96
|
+
...options()
|
|
97
|
+
};
|
|
98
|
+
let latestUserOpts = options();
|
|
99
|
+
const instance = new Virtualizer$1(resolvedOptions);
|
|
100
|
+
const effectCleanup = effect(() => {
|
|
101
|
+
latestUserOpts = options();
|
|
102
|
+
instance.setOptions({
|
|
103
|
+
...instance.options,
|
|
104
|
+
...latestUserOpts,
|
|
105
|
+
onChange: (inst, sync) => {
|
|
106
|
+
batch(() => {
|
|
107
|
+
virtualItems.set(inst.getVirtualItems());
|
|
108
|
+
totalSize.set(inst.getTotalSize());
|
|
109
|
+
isScrolling.set(inst.isScrolling);
|
|
110
|
+
});
|
|
111
|
+
latestUserOpts.onChange?.(inst, sync);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
instance._willUpdate();
|
|
115
|
+
batch(() => {
|
|
116
|
+
virtualItems.set(instance.getVirtualItems());
|
|
117
|
+
totalSize.set(instance.getTotalSize());
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
let mountCleanup;
|
|
121
|
+
onMount(() => {
|
|
122
|
+
mountCleanup = instance._didMount();
|
|
123
|
+
instance._willUpdate();
|
|
124
|
+
batch(() => {
|
|
125
|
+
virtualItems.set(instance.getVirtualItems());
|
|
126
|
+
totalSize.set(instance.getTotalSize());
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
onUnmount(() => {
|
|
130
|
+
effectCleanup.dispose();
|
|
131
|
+
mountCleanup?.();
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
instance,
|
|
135
|
+
virtualItems,
|
|
136
|
+
totalSize,
|
|
137
|
+
isScrolling
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
export { Virtualizer, defaultKeyExtractor, defaultRangeExtractor, elementScroll, measureElement, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, useVirtualizer, useWindowVirtualizer, windowScroll };
|
|
143
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":["elementScroll","Virtualizer","observeWindowRect","observeWindowOffset","windowScroll","Virtualizer"],"sources":["../../src/use-virtualizer.ts","../../src/use-window-virtualizer.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Range, Rect, ScrollToOptions, VirtualItem, VirtualItem as VirtualItem$1, Virtualizer, Virtualizer as Virtualizer$1, VirtualizerOptions, VirtualizerOptions as VirtualizerOptions$1, defaultKeyExtractor, defaultRangeExtractor, elementScroll, measureElement, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, windowScroll } from "@tanstack/virtual-core";
|
|
2
|
+
import { Signal } from "@pyreon/reactivity";
|
|
3
|
+
|
|
4
|
+
//#region src/use-virtualizer.d.ts
|
|
5
|
+
type UseVirtualizerOptions<TScrollElement extends Element, TItemElement extends Element> = () => Omit<VirtualizerOptions$1<TScrollElement, TItemElement>, 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'> & Partial<Pick<VirtualizerOptions$1<TScrollElement, TItemElement>, 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'>>;
|
|
6
|
+
interface UseVirtualizerResult<TScrollElement extends Element, TItemElement extends Element> {
|
|
7
|
+
/** The virtualizer instance — read to access all methods. */
|
|
8
|
+
instance: Virtualizer$1<TScrollElement, TItemElement>;
|
|
9
|
+
/** Reactive signal of currently visible virtual items. */
|
|
10
|
+
virtualItems: Signal<VirtualItem$1[]>;
|
|
11
|
+
/** Reactive signal of the total scrollable size in pixels. */
|
|
12
|
+
totalSize: Signal<number>;
|
|
13
|
+
/** Reactive signal indicating whether the user is scrolling. */
|
|
14
|
+
isScrolling: Signal<boolean>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a reactive TanStack Virtual virtualizer for element-based scrolling.
|
|
18
|
+
*
|
|
19
|
+
* Options are passed as a function so reactive signals (e.g. count, estimateSize)
|
|
20
|
+
* can be read inside, and the virtualizer updates automatically when they change.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const parentRef = signal<HTMLDivElement | null>(null)
|
|
24
|
+
* const virtual = useVirtualizer(() => ({
|
|
25
|
+
* count: 10000,
|
|
26
|
+
* getScrollElement: () => parentRef(),
|
|
27
|
+
* estimateSize: () => 35,
|
|
28
|
+
* }))
|
|
29
|
+
* // virtual.virtualItems() — array of visible VirtualItem
|
|
30
|
+
* // virtual.totalSize() — total height/width for the inner container
|
|
31
|
+
*/
|
|
32
|
+
declare function useVirtualizer<TScrollElement extends Element, TItemElement extends Element>(options: UseVirtualizerOptions<TScrollElement, TItemElement>): UseVirtualizerResult<TScrollElement, TItemElement>;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/use-window-virtualizer.d.ts
|
|
35
|
+
type UseWindowVirtualizerOptions<TItemElement extends Element> = () => Omit<VirtualizerOptions$1<Window, TItemElement>, 'observeElementRect' | 'observeElementOffset' | 'scrollToFn' | 'getScrollElement'> & Partial<Pick<VirtualizerOptions$1<Window, TItemElement>, 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'>>;
|
|
36
|
+
interface UseWindowVirtualizerResult<TItemElement extends Element> {
|
|
37
|
+
instance: Virtualizer$1<Window, TItemElement>;
|
|
38
|
+
virtualItems: Signal<VirtualItem$1[]>;
|
|
39
|
+
totalSize: Signal<number>;
|
|
40
|
+
isScrolling: Signal<boolean>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a reactive TanStack Virtual virtualizer for window-based scrolling.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const virtual = useWindowVirtualizer(() => ({
|
|
47
|
+
* count: 10000,
|
|
48
|
+
* estimateSize: () => 35,
|
|
49
|
+
* }))
|
|
50
|
+
*/
|
|
51
|
+
declare function useWindowVirtualizer<TItemElement extends Element>(options: UseWindowVirtualizerOptions<TItemElement>): UseWindowVirtualizerResult<TItemElement>;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { type Range, type Rect, type ScrollToOptions, type UseVirtualizerOptions, type UseVirtualizerResult, type UseWindowVirtualizerOptions, type UseWindowVirtualizerResult, type VirtualItem, Virtualizer, type VirtualizerOptions, defaultKeyExtractor, defaultRangeExtractor, elementScroll, measureElement, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, useVirtualizer, useWindowVirtualizer, windowScroll };
|
|
54
|
+
//# sourceMappingURL=index2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/use-virtualizer.ts","../../src/use-window-virtualizer.ts"],"mappings":";;;;KAYY,qBAAA,wBACa,OAAA,uBACF,OAAA,UACb,IAAA,CACR,oBAAA,CAAmB,cAAA,EAAgB,YAAA,mEAGnC,OAAA,CACE,IAAA,CACE,oBAAA,CAAmB,cAAA,EAAgB,YAAA;AAAA,UAKxB,oBAAA,wBACQ,OAAA,uBACF,OAAA;EAhBX;EAmBV,QAAA,EAAU,aAAA,CAAY,cAAA,EAAgB,YAAA;EAnBP;EAqB/B,YAAA,EAAc,MAAA,CAAO,aAAA;EAnBA;EAqBrB,SAAA,EAAW,MAAA;EAnBwB;EAqBnC,WAAA,EAAa,MAAA;AAAA;;;;;;;;;;;;;;;;;iBAmBC,cAAA,wBACS,OAAA,uBACF,OAAA,CAAA,CAErB,OAAA,EAAS,qBAAA,CAAsB,cAAA,EAAgB,YAAA,IAC9C,oBAAA,CAAqB,cAAA,EAAgB,YAAA;;;KCjD5B,2BAAA,sBAAiD,OAAA,UACrD,IAAA,CACJ,oBAAA,CAAmB,MAAA,EAAQ,YAAA,wFAM3B,OAAA,CACE,IAAA,CACE,oBAAA,CAAmB,MAAA,EAAQ,YAAA;AAAA,UAKlB,0BAAA,sBAAgD,OAAA;EAC/D,QAAA,EAAU,aAAA,CAAY,MAAA,EAAQ,YAAA;EAC9B,YAAA,EAAc,MAAA,CAAO,aAAA;EACrB,SAAA,EAAW,MAAA;EACX,WAAA,EAAa,MAAA;AAAA;;;;;;;;;;iBAYC,oBAAA,sBAA0C,OAAA,CAAA,CACxD,OAAA,EAAS,2BAAA,CAA4B,YAAA,IACpC,0BAAA,CAA2B,YAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pyreon/virtual",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Pyreon adapter for TanStack Virtual",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/pyreon/fundamentals.git",
|
|
9
|
+
"directory": "packages/virtual"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/pyreon/fundamentals/tree/main/packages/virtual#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/pyreon/fundamentals/issues"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"lib",
|
|
20
|
+
"src",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"main": "./lib/index.js",
|
|
27
|
+
"module": "./lib/index.js",
|
|
28
|
+
"types": "./lib/types/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"bun": "./src/index.ts",
|
|
32
|
+
"import": "./lib/index.js",
|
|
33
|
+
"types": "./lib/types/index.d.ts"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "vl_rolldown_build",
|
|
38
|
+
"dev": "vl_rolldown_build-watch",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"typecheck": "tsc --noEmit"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@tanstack/virtual-core": "^3.0.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@pyreon/core": "^0.2.1",
|
|
47
|
+
"@pyreon/reactivity": "^0.2.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@happy-dom/global-registrator": "^20.8.3",
|
|
51
|
+
"@pyreon/core": "^0.2.1",
|
|
52
|
+
"@pyreon/reactivity": "^0.2.1",
|
|
53
|
+
"@pyreon/runtime-dom": "^0.2.1"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// ─── TanStack Virtual core re-exports ────────────────────────────────────────
|
|
2
|
+
// Users can import utilities and types from @pyreon/virtual directly.
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
defaultKeyExtractor,
|
|
6
|
+
defaultRangeExtractor,
|
|
7
|
+
observeElementOffset,
|
|
8
|
+
observeElementRect,
|
|
9
|
+
observeWindowOffset,
|
|
10
|
+
observeWindowRect,
|
|
11
|
+
elementScroll,
|
|
12
|
+
windowScroll,
|
|
13
|
+
measureElement,
|
|
14
|
+
Virtualizer,
|
|
15
|
+
} from '@tanstack/virtual-core'
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
VirtualizerOptions,
|
|
19
|
+
VirtualItem,
|
|
20
|
+
Range,
|
|
21
|
+
Rect,
|
|
22
|
+
ScrollToOptions,
|
|
23
|
+
} from '@tanstack/virtual-core'
|
|
24
|
+
|
|
25
|
+
// ─── Pyreon adapter ─────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
export { useVirtualizer } from './use-virtualizer'
|
|
28
|
+
export type {
|
|
29
|
+
UseVirtualizerOptions,
|
|
30
|
+
UseVirtualizerResult,
|
|
31
|
+
} from './use-virtualizer'
|
|
32
|
+
|
|
33
|
+
export { useWindowVirtualizer } from './use-window-virtualizer'
|
|
34
|
+
export type {
|
|
35
|
+
UseWindowVirtualizerOptions,
|
|
36
|
+
UseWindowVirtualizerResult,
|
|
37
|
+
} from './use-window-virtualizer'
|