@pyreon/virtual 0.11.5 → 0.11.7

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
@@ -11,8 +11,8 @@ bun add @pyreon/virtual @tanstack/virtual-core
11
11
  ## Quick Start
12
12
 
13
13
  ```tsx
14
- import { signal } from "@pyreon/reactivity"
15
- import { useVirtualizer } from "@pyreon/virtual"
14
+ import { signal } from '@pyreon/reactivity'
15
+ import { useVirtualizer } from '@pyreon/virtual'
16
16
 
17
17
  function VirtualList() {
18
18
  const parentRef = signal<HTMLElement | null>(null)
@@ -48,20 +48,20 @@ function VirtualList() {
48
48
 
49
49
  Create a reactive virtualizer for element-based scrolling. Options are passed as a function so reactive signals can be read inside, and the virtualizer updates automatically when they change.
50
50
 
51
- | Parameter | Type | Description |
52
- | --- | --- | --- |
51
+ | Parameter | Type | Description |
52
+ | --------- | ----------------------------- | ------------------------------------- |
53
53
  | `options` | `() => UseVirtualizerOptions` | Function returning virtualizer config |
54
54
 
55
55
  Options extend `VirtualizerOptions` from `@tanstack/virtual-core` with `observeElementRect`, `observeElementOffset`, and `scrollToFn` pre-filled (overridable).
56
56
 
57
57
  **Returns:** `UseVirtualizerResult` with:
58
58
 
59
- | Property | Type | Description |
60
- | --- | --- | --- |
61
- | `instance` | `Virtualizer` | The underlying TanStack Virtualizer instance |
62
- | `virtualItems` | `Signal<VirtualItem[]>` | Currently visible virtual items |
63
- | `totalSize` | `Signal<number>` | Total scrollable size in pixels |
64
- | `isScrolling` | `Signal<boolean>` | Whether the user is currently scrolling |
59
+ | Property | Type | Description |
60
+ | -------------- | ----------------------- | -------------------------------------------- |
61
+ | `instance` | `Virtualizer` | The underlying TanStack Virtualizer instance |
62
+ | `virtualItems` | `Signal<VirtualItem[]>` | Currently visible virtual items |
63
+ | `totalSize` | `Signal<number>` | Total scrollable size in pixels |
64
+ | `isScrolling` | `Signal<boolean>` | Whether the user is currently scrolling |
65
65
 
66
66
  ```ts
67
67
  const parentRef = signal<HTMLDivElement | null>(null)
@@ -82,8 +82,8 @@ instance.scrollToIndex(500)
82
82
 
83
83
  Create a reactive virtualizer for window-based scrolling. The scroll element is automatically set to `window`. SSR-safe — checks for `window` and `document` availability.
84
84
 
85
- | Parameter | Type | Description |
86
- | --- | --- | --- |
85
+ | Parameter | Type | Description |
86
+ | --------- | ----------------------------------- | -------------------------------------------------------- |
87
87
  | `options` | `() => UseWindowVirtualizerOptions` | Function returning config (no `getScrollElement` needed) |
88
88
 
89
89
  **Returns:** `UseWindowVirtualizerResult` — same shape as `UseVirtualizerResult` but typed with `Window` as the scroll element.
@@ -119,7 +119,7 @@ function WindowList() {
119
119
  Use `measureElement` for variable-height items that are measured after render.
120
120
 
121
121
  ```tsx
122
- import { measureElement } from "@pyreon/virtual"
122
+ import { measureElement } from '@pyreon/virtual'
123
123
 
124
124
  const { virtualItems, totalSize, instance } = useVirtualizer(() => ({
125
125
  count: items.length,
@@ -130,11 +130,7 @@ const { virtualItems, totalSize, instance } = useVirtualizer(() => ({
130
130
 
131
131
  // In render, set the ref on each item:
132
132
  virtualItems().map((row) => (
133
- <div
134
- key={row.key}
135
- ref={(el) => instance.measureElement(el)}
136
- data-index={row.index}
137
- >
133
+ <div key={row.key} ref={(el) => instance.measureElement(el)} data-index={row.index}>
138
134
  {items[row.index]}
139
135
  </div>
140
136
  ))
@@ -166,7 +162,7 @@ const { virtualItems } = useVirtualizer(() => ({
166
162
  }))
167
163
 
168
164
  // Updating filteredItems triggers recalculation
169
- filteredItems.set(allItems.filter(i => i.includes(search())))
165
+ filteredItems.set(allItems.filter((i) => i.includes(search())))
170
166
  ```
171
167
 
172
168
  ## Re-exports from `@tanstack/virtual-core`
package/lib/index.js.map CHANGED
@@ -1 +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 type { Signal } from \"@pyreon/reactivity\"\nimport { batch, effect, signal } from \"@pyreon/reactivity\"\nimport {\n elementScroll,\n observeElementOffset,\n observeElementRect,\n type VirtualItem,\n Virtualizer,\n type VirtualizerOptions,\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<TScrollElement extends Element, TItemElement extends Element>(\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>(resolvedOptions)\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 type { Signal } from \"@pyreon/reactivity\"\nimport { batch, effect, signal } from \"@pyreon/reactivity\"\nimport {\n observeWindowOffset,\n observeWindowRect,\n type VirtualItem,\n Virtualizer,\n type VirtualizerOptions,\n windowScroll,\n} from \"@tanstack/virtual-core\"\n\nexport type UseWindowVirtualizerOptions<TItemElement extends Element> = () => Omit<\n VirtualizerOptions<Window, TItemElement>,\n \"observeElementRect\" | \"observeElementOffset\" | \"scrollToFn\" | \"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: () => (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,eACd,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,cAA0C,gBAAgB;CAG/E,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;;;;;;;;;;;;;;AC9E3D,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,wBAAyB,OAAO,WAAW,cAAc,SAAU;EACnE,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"}
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 type { Signal } from '@pyreon/reactivity'\nimport { batch, effect, signal } from '@pyreon/reactivity'\nimport {\n elementScroll,\n observeElementOffset,\n observeElementRect,\n type VirtualItem,\n Virtualizer,\n type VirtualizerOptions,\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<TScrollElement extends Element, TItemElement extends Element>(\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>(resolvedOptions)\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 type { Signal } from '@pyreon/reactivity'\nimport { batch, effect, signal } from '@pyreon/reactivity'\nimport {\n observeWindowOffset,\n observeWindowRect,\n type VirtualItem,\n Virtualizer,\n type VirtualizerOptions,\n windowScroll,\n} from '@tanstack/virtual-core'\n\nexport type UseWindowVirtualizerOptions<TItemElement extends Element> = () => Omit<\n VirtualizerOptions<Window, TItemElement>,\n 'observeElementRect' | 'observeElementOffset' | 'scrollToFn' | '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: () => (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,eACd,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,cAA0C,gBAAgB;CAG/E,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;;;;;;;;;;;;;;AC9E3D,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,wBAAyB,OAAO,WAAW,cAAc,SAAU;EACnE,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"}
@@ -2,7 +2,7 @@ import { Range, Rect, ScrollToOptions, VirtualItem, VirtualItem as VirtualItem$1
2
2
  import { Signal } from "@pyreon/reactivity";
3
3
 
4
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">>;
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
6
  interface UseVirtualizerResult<TScrollElement extends Element, TItemElement extends Element> {
7
7
  /** The virtualizer instance — read to access all methods. */
8
8
  instance: Virtualizer$1<TScrollElement, TItemElement>;
@@ -32,7 +32,7 @@ interface UseVirtualizerResult<TScrollElement extends Element, TItemElement exte
32
32
  declare function useVirtualizer<TScrollElement extends Element, TItemElement extends Element>(options: UseVirtualizerOptions<TScrollElement, TItemElement>): UseVirtualizerResult<TScrollElement, TItemElement>;
33
33
  //#endregion
34
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">>;
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
36
  interface UseWindowVirtualizerResult<TItemElement extends Element> {
37
37
  instance: Virtualizer$1<Window, TItemElement>;
38
38
  virtualItems: Signal<VirtualItem$1[]>;
package/package.json CHANGED
@@ -1,20 +1,17 @@
1
1
  {
2
2
  "name": "@pyreon/virtual",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
4
  "description": "Pyreon adapter for TanStack Virtual",
5
+ "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/virtual#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/pyreon/pyreon/issues"
8
+ },
5
9
  "license": "MIT",
6
10
  "repository": {
7
11
  "type": "git",
8
12
  "url": "https://github.com/pyreon/pyreon.git",
9
13
  "directory": "packages/fundamentals/virtual"
10
14
  },
11
- "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/virtual#readme",
12
- "bugs": {
13
- "url": "https://github.com/pyreon/pyreon/issues"
14
- },
15
- "publishConfig": {
16
- "access": "public"
17
- },
18
15
  "files": [
19
16
  "lib",
20
17
  "src",
@@ -33,24 +30,27 @@
33
30
  "types": "./lib/types/index.d.ts"
34
31
  }
35
32
  },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
36
  "scripts": {
37
37
  "build": "vl_rolldown_build",
38
38
  "dev": "vl_rolldown_build-watch",
39
39
  "test": "vitest run",
40
40
  "typecheck": "tsc --noEmit",
41
- "lint": "biome check ."
41
+ "lint": "oxlint ."
42
42
  },
43
43
  "dependencies": {
44
44
  "@tanstack/virtual-core": "^3.0.0"
45
45
  },
46
- "peerDependencies": {
47
- "@pyreon/core": "^0.11.5",
48
- "@pyreon/reactivity": "^0.11.5"
49
- },
50
46
  "devDependencies": {
51
47
  "@happy-dom/global-registrator": "^20.8.3",
52
- "@pyreon/core": "^0.11.5",
53
- "@pyreon/reactivity": "^0.11.5",
54
- "@pyreon/runtime-dom": "^0.11.5"
48
+ "@pyreon/core": "^0.11.7",
49
+ "@pyreon/reactivity": "^0.11.7",
50
+ "@pyreon/runtime-dom": "^0.11.7"
51
+ },
52
+ "peerDependencies": {
53
+ "@pyreon/core": "^0.11.7",
54
+ "@pyreon/reactivity": "^0.11.7"
55
55
  }
56
56
  }
package/src/index.ts CHANGED
@@ -7,7 +7,7 @@ export type {
7
7
  ScrollToOptions,
8
8
  VirtualItem,
9
9
  VirtualizerOptions,
10
- } from "@tanstack/virtual-core"
10
+ } from '@tanstack/virtual-core'
11
11
  export {
12
12
  defaultKeyExtractor,
13
13
  defaultRangeExtractor,
@@ -19,17 +19,14 @@ export {
19
19
  observeWindowRect,
20
20
  Virtualizer,
21
21
  windowScroll,
22
- } from "@tanstack/virtual-core"
22
+ } from '@tanstack/virtual-core'
23
23
 
24
24
  // ─── Pyreon adapter ─────────────────────────────────────────────────────────────
25
25
 
26
- export type {
27
- UseVirtualizerOptions,
28
- UseVirtualizerResult,
29
- } from "./use-virtualizer"
30
- export { useVirtualizer } from "./use-virtualizer"
26
+ export type { UseVirtualizerOptions, UseVirtualizerResult } from './use-virtualizer'
27
+ export { useVirtualizer } from './use-virtualizer'
31
28
  export type {
32
29
  UseWindowVirtualizerOptions,
33
30
  UseWindowVirtualizerResult,
34
- } from "./use-window-virtualizer"
35
- export { useWindowVirtualizer } from "./use-window-virtualizer"
31
+ } from './use-window-virtualizer'
32
+ export { useWindowVirtualizer } from './use-window-virtualizer'
@@ -1,12 +1,12 @@
1
- import { signal } from "@pyreon/reactivity"
2
- import { mount } from "@pyreon/runtime-dom"
3
- import { useVirtualizer, useWindowVirtualizer } from "../index"
1
+ import { signal } from '@pyreon/reactivity'
2
+ import { mount } from '@pyreon/runtime-dom'
3
+ import { useVirtualizer, useWindowVirtualizer } from '../index'
4
4
 
5
5
  // ─── Helpers ──────────────────────────────────────────────────────────────────
6
6
 
7
7
  function mountWith<T>(fn: () => T): { result: T; unmount: () => void } {
8
8
  let result: T | undefined
9
- const el = document.createElement("div")
9
+ const el = document.createElement('div')
10
10
  document.body.appendChild(el)
11
11
  const Wrapper = () => {
12
12
  result = fn()
@@ -23,19 +23,19 @@ function mountWith<T>(fn: () => T): { result: T; unmount: () => void } {
23
23
  }
24
24
 
25
25
  function createScrollContainer(height = 200): HTMLDivElement {
26
- const container = document.createElement("div")
27
- Object.defineProperty(container, "offsetHeight", { value: height })
28
- Object.defineProperty(container, "offsetWidth", { value: 300 })
29
- Object.defineProperty(container, "scrollHeight", { value: 10000 })
30
- Object.defineProperty(container, "clientHeight", { value: height })
26
+ const container = document.createElement('div')
27
+ Object.defineProperty(container, 'offsetHeight', { value: height })
28
+ Object.defineProperty(container, 'offsetWidth', { value: 300 })
29
+ Object.defineProperty(container, 'scrollHeight', { value: 10000 })
30
+ Object.defineProperty(container, 'clientHeight', { value: height })
31
31
  document.body.appendChild(container)
32
32
  return container
33
33
  }
34
34
 
35
35
  // ─── useVirtualizer — virtualItems signal ──────────────────────────────────
36
36
 
37
- describe("useVirtualizer — virtualItems signal", () => {
38
- it("returns a signal that holds an array of VirtualItem", () => {
37
+ describe('useVirtualizer — virtualItems signal', () => {
38
+ it('returns a signal that holds an array of VirtualItem', () => {
39
39
  const container = createScrollContainer()
40
40
  const { result: virt, unmount } = mountWith(() =>
41
41
  useVirtualizer(() => ({
@@ -52,7 +52,7 @@ describe("useVirtualizer — virtualItems signal", () => {
52
52
  container.remove()
53
53
  })
54
54
 
55
- it("virtual items have index, start, end, size, key properties", () => {
55
+ it('virtual items have index, start, end, size, key properties', () => {
56
56
  const container = createScrollContainer()
57
57
  const { result: virt, unmount } = mountWith(() =>
58
58
  useVirtualizer(() => ({
@@ -65,16 +65,16 @@ describe("useVirtualizer — virtualItems signal", () => {
65
65
  const items = virt.virtualItems()
66
66
  expect(items.length).toBeGreaterThan(0)
67
67
  const first = items[0]!
68
- expect(typeof first.index).toBe("number")
69
- expect(typeof first.start).toBe("number")
70
- expect(typeof first.end).toBe("number")
71
- expect(typeof first.size).toBe("number")
68
+ expect(typeof first.index).toBe('number')
69
+ expect(typeof first.start).toBe('number')
70
+ expect(typeof first.end).toBe('number')
71
+ expect(typeof first.size).toBe('number')
72
72
  expect(first.key).toBeDefined()
73
73
  unmount()
74
74
  container.remove()
75
75
  })
76
76
 
77
- it("first item starts at index 0", () => {
77
+ it('first item starts at index 0', () => {
78
78
  const container = createScrollContainer()
79
79
  const { result: virt, unmount } = mountWith(() =>
80
80
  useVirtualizer(() => ({
@@ -92,8 +92,8 @@ describe("useVirtualizer — virtualItems signal", () => {
92
92
 
93
93
  // ─── useVirtualizer — totalSize signal ─────────────────────────────────────
94
94
 
95
- describe("useVirtualizer — totalSize signal", () => {
96
- it("returns count * estimateSize for uniform items", () => {
95
+ describe('useVirtualizer — totalSize signal', () => {
96
+ it('returns count * estimateSize for uniform items', () => {
97
97
  const container = createScrollContainer()
98
98
  const { result: virt, unmount } = mountWith(() =>
99
99
  useVirtualizer(() => ({
@@ -108,7 +108,7 @@ describe("useVirtualizer — totalSize signal", () => {
108
108
  container.remove()
109
109
  })
110
110
 
111
- it("includes padding in totalSize", () => {
111
+ it('includes padding in totalSize', () => {
112
112
  const container = createScrollContainer()
113
113
  const { result: virt, unmount } = mountWith(() =>
114
114
  useVirtualizer(() => ({
@@ -125,7 +125,7 @@ describe("useVirtualizer — totalSize signal", () => {
125
125
  container.remove()
126
126
  })
127
127
 
128
- it("includes gaps in totalSize", () => {
128
+ it('includes gaps in totalSize', () => {
129
129
  const container = createScrollContainer()
130
130
  const { result: virt, unmount } = mountWith(() =>
131
131
  useVirtualizer(() => ({
@@ -141,7 +141,7 @@ describe("useVirtualizer — totalSize signal", () => {
141
141
  container.remove()
142
142
  })
143
143
 
144
- it("returns 0 when count is 0", () => {
144
+ it('returns 0 when count is 0', () => {
145
145
  const container = createScrollContainer()
146
146
  const { result: virt, unmount } = mountWith(() =>
147
147
  useVirtualizer(() => ({
@@ -159,8 +159,8 @@ describe("useVirtualizer — totalSize signal", () => {
159
159
 
160
160
  // ─── useVirtualizer — count changes update virtualItems ────────────────────
161
161
 
162
- describe("useVirtualizer — count changes update virtualItems", () => {
163
- it("increasing count increases totalSize", () => {
162
+ describe('useVirtualizer — count changes update virtualItems', () => {
163
+ it('increasing count increases totalSize', () => {
164
164
  const container = createScrollContainer()
165
165
  const count = signal(100)
166
166
  const { result: virt, unmount } = mountWith(() =>
@@ -182,7 +182,7 @@ describe("useVirtualizer — count changes update virtualItems", () => {
182
182
  container.remove()
183
183
  })
184
184
 
185
- it("setting count to 0 empties virtualItems", () => {
185
+ it('setting count to 0 empties virtualItems', () => {
186
186
  const container = createScrollContainer()
187
187
  const count = signal(100)
188
188
  const { result: virt, unmount } = mountWith(() =>
@@ -202,7 +202,7 @@ describe("useVirtualizer — count changes update virtualItems", () => {
202
202
  container.remove()
203
203
  })
204
204
 
205
- it("growing count from 0 creates virtualItems", () => {
205
+ it('growing count from 0 creates virtualItems', () => {
206
206
  const container = createScrollContainer()
207
207
  const count = signal(0)
208
208
  const { result: virt, unmount } = mountWith(() =>
@@ -225,8 +225,8 @@ describe("useVirtualizer — count changes update virtualItems", () => {
225
225
 
226
226
  // ─── useVirtualizer — estimateSize callback ────────────────────────────────
227
227
 
228
- describe("useVirtualizer — estimateSize callback", () => {
229
- it("uses the provided estimateSize for totalSize calculation", () => {
228
+ describe('useVirtualizer — estimateSize callback', () => {
229
+ it('uses the provided estimateSize for totalSize calculation', () => {
230
230
  const container = createScrollContainer()
231
231
  const { result: virt, unmount } = mountWith(() =>
232
232
  useVirtualizer(() => ({
@@ -241,7 +241,7 @@ describe("useVirtualizer — estimateSize callback", () => {
241
241
  container.remove()
242
242
  })
243
243
 
244
- it("reactive estimateSize updates totalSize after measure()", () => {
244
+ it('reactive estimateSize updates totalSize after measure()', () => {
245
245
  const container = createScrollContainer()
246
246
  const itemSize = signal(50)
247
247
  const { result: virt, unmount } = mountWith(() =>
@@ -261,7 +261,7 @@ describe("useVirtualizer — estimateSize callback", () => {
261
261
  container.remove()
262
262
  })
263
263
 
264
- it("small estimateSize produces more visible items", () => {
264
+ it('small estimateSize produces more visible items', () => {
265
265
  const container = createScrollContainer(200)
266
266
  const { result: small, unmount: u1 } = mountWith(() =>
267
267
  useVirtualizer(() => ({
@@ -291,8 +291,8 @@ describe("useVirtualizer — estimateSize callback", () => {
291
291
 
292
292
  // ─── useVirtualizer — additional options ───────────────────────────────────
293
293
 
294
- describe("useVirtualizer — additional options", () => {
295
- it("overscan controls extra items rendered", () => {
294
+ describe('useVirtualizer — additional options', () => {
295
+ it('overscan controls extra items rendered', () => {
296
296
  const container = createScrollContainer(200)
297
297
  const { result: noOverscan, unmount: u1 } = mountWith(() =>
298
298
  useVirtualizer(() => ({
@@ -320,7 +320,7 @@ describe("useVirtualizer — additional options", () => {
320
320
  container.remove()
321
321
  })
322
322
 
323
- it("horizontal mode works", () => {
323
+ it('horizontal mode works', () => {
324
324
  const container = createScrollContainer()
325
325
  const { result: virt, unmount } = mountWith(() =>
326
326
  useVirtualizer(() => ({
@@ -337,7 +337,7 @@ describe("useVirtualizer — additional options", () => {
337
337
  container.remove()
338
338
  })
339
339
 
340
- it("enabled: false produces empty output", () => {
340
+ it('enabled: false produces empty output', () => {
341
341
  const container = createScrollContainer()
342
342
  const { result: virt, unmount } = mountWith(() =>
343
343
  useVirtualizer(() => ({
@@ -354,7 +354,7 @@ describe("useVirtualizer — additional options", () => {
354
354
  container.remove()
355
355
  })
356
356
 
357
- it("isScrolling starts as false", () => {
357
+ it('isScrolling starts as false', () => {
358
358
  const container = createScrollContainer()
359
359
  const { result: virt, unmount } = mountWith(() =>
360
360
  useVirtualizer(() => ({
@@ -369,7 +369,7 @@ describe("useVirtualizer — additional options", () => {
369
369
  container.remove()
370
370
  })
371
371
 
372
- it("exposes instance with scrollToIndex and scrollToOffset", () => {
372
+ it('exposes instance with scrollToIndex and scrollToOffset', () => {
373
373
  const container = createScrollContainer()
374
374
  const { result: virt, unmount } = mountWith(() =>
375
375
  useVirtualizer(() => ({
@@ -379,9 +379,9 @@ describe("useVirtualizer — additional options", () => {
379
379
  })),
380
380
  )
381
381
 
382
- expect(typeof virt.instance.scrollToIndex).toBe("function")
383
- expect(typeof virt.instance.scrollToOffset).toBe("function")
384
- expect(typeof virt.instance.measureElement).toBe("function")
382
+ expect(typeof virt.instance.scrollToIndex).toBe('function')
383
+ expect(typeof virt.instance.scrollToOffset).toBe('function')
384
+ expect(typeof virt.instance.measureElement).toBe('function')
385
385
  unmount()
386
386
  container.remove()
387
387
  })
@@ -389,26 +389,26 @@ describe("useVirtualizer — additional options", () => {
389
389
 
390
390
  // ─── useWindowVirtualizer ──────────────────────────────────────────────────
391
391
 
392
- describe("useWindowVirtualizer — comprehensive", () => {
392
+ describe('useWindowVirtualizer — comprehensive', () => {
393
393
  beforeEach(() => {
394
- Object.defineProperty(window, "innerHeight", {
394
+ Object.defineProperty(window, 'innerHeight', {
395
395
  value: 768,
396
396
  writable: true,
397
397
  configurable: true,
398
398
  })
399
- Object.defineProperty(window, "innerWidth", {
399
+ Object.defineProperty(window, 'innerWidth', {
400
400
  value: 1024,
401
401
  writable: true,
402
402
  configurable: true,
403
403
  })
404
- Object.defineProperty(window, "scrollY", {
404
+ Object.defineProperty(window, 'scrollY', {
405
405
  value: 0,
406
406
  writable: true,
407
407
  configurable: true,
408
408
  })
409
409
  })
410
410
 
411
- it("returns virtualItems, totalSize, isScrolling signals", () => {
411
+ it('returns virtualItems, totalSize, isScrolling signals', () => {
412
412
  const { result: virt, unmount } = mountWith(() =>
413
413
  useWindowVirtualizer(() => ({
414
414
  count: 1000,
@@ -416,16 +416,16 @@ describe("useWindowVirtualizer — comprehensive", () => {
416
416
  })),
417
417
  )
418
418
 
419
- expect(typeof virt.virtualItems).toBe("function")
420
- expect(typeof virt.totalSize).toBe("function")
421
- expect(typeof virt.isScrolling).toBe("function")
419
+ expect(typeof virt.virtualItems).toBe('function')
420
+ expect(typeof virt.totalSize).toBe('function')
421
+ expect(typeof virt.isScrolling).toBe('function')
422
422
  expect(Array.isArray(virt.virtualItems())).toBe(true)
423
- expect(typeof virt.totalSize()).toBe("number")
424
- expect(typeof virt.isScrolling()).toBe("boolean")
423
+ expect(typeof virt.totalSize()).toBe('number')
424
+ expect(typeof virt.isScrolling()).toBe('boolean')
425
425
  unmount()
426
426
  })
427
427
 
428
- it("totalSize equals count * estimateSize", () => {
428
+ it('totalSize equals count * estimateSize', () => {
429
429
  const { result: virt, unmount } = mountWith(() =>
430
430
  useWindowVirtualizer(() => ({
431
431
  count: 100,
@@ -437,7 +437,7 @@ describe("useWindowVirtualizer — comprehensive", () => {
437
437
  unmount()
438
438
  })
439
439
 
440
- it("reactive count updates totalSize", () => {
440
+ it('reactive count updates totalSize', () => {
441
441
  const count = signal(100)
442
442
  const { result: virt, unmount } = mountWith(() =>
443
443
  useWindowVirtualizer(() => ({
@@ -456,7 +456,7 @@ describe("useWindowVirtualizer — comprehensive", () => {
456
456
  unmount()
457
457
  })
458
458
 
459
- it("reactive estimateSize updates totalSize after measure()", () => {
459
+ it('reactive estimateSize updates totalSize after measure()', () => {
460
460
  const size = signal(50)
461
461
  const { result: virt, unmount } = mountWith(() =>
462
462
  useWindowVirtualizer(() => ({
@@ -473,7 +473,7 @@ describe("useWindowVirtualizer — comprehensive", () => {
473
473
  unmount()
474
474
  })
475
475
 
476
- it("SSR-safe — handles missing document/window", () => {
476
+ it('SSR-safe — handles missing document/window', () => {
477
477
  const origDoc = globalThis.document
478
478
  const origWin = globalThis.window
479
479
  try {
@@ -494,7 +494,7 @@ describe("useWindowVirtualizer — comprehensive", () => {
494
494
  }
495
495
  })
496
496
 
497
- it("gap affects totalSize", () => {
497
+ it('gap affects totalSize', () => {
498
498
  const { result: virt, unmount } = mountWith(() =>
499
499
  useWindowVirtualizer(() => ({
500
500
  count: 10,
@@ -507,7 +507,7 @@ describe("useWindowVirtualizer — comprehensive", () => {
507
507
  unmount()
508
508
  })
509
509
 
510
- it("enabled: false produces empty output", () => {
510
+ it('enabled: false produces empty output', () => {
511
511
  const { result: virt, unmount } = mountWith(() =>
512
512
  useWindowVirtualizer(() => ({
513
513
  count: 100,
@@ -521,7 +521,7 @@ describe("useWindowVirtualizer — comprehensive", () => {
521
521
  unmount()
522
522
  })
523
523
 
524
- it("onChange callback is forwarded", () => {
524
+ it('onChange callback is forwarded', () => {
525
525
  const spy = vi.fn()
526
526
  const { result: virt, unmount } = mountWith(() =>
527
527
  useWindowVirtualizer(() => ({
@@ -540,7 +540,7 @@ describe("useWindowVirtualizer — comprehensive", () => {
540
540
  unmount()
541
541
  })
542
542
 
543
- it("overscan controls extra rendered items", () => {
543
+ it('overscan controls extra rendered items', () => {
544
544
  const { result: small, unmount: u1 } = mountWith(() =>
545
545
  useWindowVirtualizer(() => ({
546
546
  count: 1000,
@@ -1,12 +1,12 @@
1
- import { signal } from "@pyreon/reactivity"
2
- import { mount } from "@pyreon/runtime-dom"
3
- import { useVirtualizer, useWindowVirtualizer } from "../index"
1
+ import { signal } from '@pyreon/reactivity'
2
+ import { mount } from '@pyreon/runtime-dom'
3
+ import { useVirtualizer, useWindowVirtualizer } from '../index'
4
4
 
5
5
  // ─── Helpers ──────────────────────────────────────────────────────────────────
6
6
 
7
7
  function mountWith<T>(fn: () => T): { result: T; unmount: () => void } {
8
8
  let result: T | undefined
9
- const el = document.createElement("div")
9
+ const el = document.createElement('div')
10
10
  document.body.appendChild(el)
11
11
  const Wrapper = () => {
12
12
  result = fn()
@@ -24,20 +24,20 @@ function mountWith<T>(fn: () => T): { result: T; unmount: () => void } {
24
24
 
25
25
  /** Create a mock scroll container with a known size. */
26
26
  function createScrollContainer(height = 200): HTMLDivElement {
27
- const container = document.createElement("div")
27
+ const container = document.createElement('div')
28
28
  // happy-dom doesn't have real layout, but we can set properties
29
- Object.defineProperty(container, "offsetHeight", { value: height })
30
- Object.defineProperty(container, "offsetWidth", { value: 300 })
31
- Object.defineProperty(container, "scrollHeight", { value: 10000 })
32
- Object.defineProperty(container, "clientHeight", { value: height })
29
+ Object.defineProperty(container, 'offsetHeight', { value: height })
30
+ Object.defineProperty(container, 'offsetWidth', { value: 300 })
31
+ Object.defineProperty(container, 'scrollHeight', { value: 10000 })
32
+ Object.defineProperty(container, 'clientHeight', { value: height })
33
33
  document.body.appendChild(container)
34
34
  return container
35
35
  }
36
36
 
37
37
  // ─── useVirtualizer ──────────────────────────────────────────────────────────
38
38
 
39
- describe("useVirtualizer", () => {
40
- it("creates a virtualizer with virtual items", () => {
39
+ describe('useVirtualizer', () => {
40
+ it('creates a virtualizer with virtual items', () => {
41
41
  const container = createScrollContainer()
42
42
  const { result: virt, unmount } = mountWith(() =>
43
43
  useVirtualizer(() => ({
@@ -54,7 +54,7 @@ describe("useVirtualizer", () => {
54
54
  container.remove()
55
55
  })
56
56
 
57
- it("returns correct total size", () => {
57
+ it('returns correct total size', () => {
58
58
  const container = createScrollContainer()
59
59
  const { result: virt, unmount } = mountWith(() =>
60
60
  useVirtualizer(() => ({
@@ -70,7 +70,7 @@ describe("useVirtualizer", () => {
70
70
  container.remove()
71
71
  })
72
72
 
73
- it("reactive count — updates when count signal changes", () => {
73
+ it('reactive count — updates when count signal changes', () => {
74
74
  const container = createScrollContainer()
75
75
  const count = signal(100)
76
76
  const { result: virt, unmount } = mountWith(() =>
@@ -89,7 +89,7 @@ describe("useVirtualizer", () => {
89
89
  container.remove()
90
90
  })
91
91
 
92
- it("reactive estimateSize — updates total size", () => {
92
+ it('reactive estimateSize — updates total size', () => {
93
93
  const container = createScrollContainer()
94
94
  const itemSize = signal(50)
95
95
  const { result: virt, unmount } = mountWith(() =>
@@ -110,7 +110,7 @@ describe("useVirtualizer", () => {
110
110
  container.remove()
111
111
  })
112
112
 
113
- it("exposes the virtualizer instance", () => {
113
+ it('exposes the virtualizer instance', () => {
114
114
  const container = createScrollContainer()
115
115
  const { result: virt, unmount } = mountWith(() =>
116
116
  useVirtualizer(() => ({
@@ -121,14 +121,14 @@ describe("useVirtualizer", () => {
121
121
  )
122
122
 
123
123
  expect(virt.instance).toBeDefined()
124
- expect(typeof virt.instance.scrollToIndex).toBe("function")
125
- expect(typeof virt.instance.scrollToOffset).toBe("function")
126
- expect(typeof virt.instance.measureElement).toBe("function")
124
+ expect(typeof virt.instance.scrollToIndex).toBe('function')
125
+ expect(typeof virt.instance.scrollToOffset).toBe('function')
126
+ expect(typeof virt.instance.measureElement).toBe('function')
127
127
  unmount()
128
128
  container.remove()
129
129
  })
130
130
 
131
- it("virtual items have correct structure", () => {
131
+ it('virtual items have correct structure', () => {
132
132
  const container = createScrollContainer()
133
133
  const { result: virt, unmount } = mountWith(() =>
134
134
  useVirtualizer(() => ({
@@ -141,17 +141,17 @@ describe("useVirtualizer", () => {
141
141
  const items = virt.virtualItems()
142
142
  if (items.length > 0) {
143
143
  const item = items[0]!
144
- expect(typeof item.index).toBe("number")
145
- expect(typeof item.start).toBe("number")
146
- expect(typeof item.end).toBe("number")
147
- expect(typeof item.size).toBe("number")
144
+ expect(typeof item.index).toBe('number')
145
+ expect(typeof item.start).toBe('number')
146
+ expect(typeof item.end).toBe('number')
147
+ expect(typeof item.size).toBe('number')
148
148
  expect(typeof item.key).toBeDefined()
149
149
  }
150
150
  unmount()
151
151
  container.remove()
152
152
  })
153
153
 
154
- it("overscan controls extra items rendered", () => {
154
+ it('overscan controls extra items rendered', () => {
155
155
  const container = createScrollContainer(200)
156
156
  const { result: small, unmount: unmount1 } = mountWith(() =>
157
157
  useVirtualizer(() => ({
@@ -178,7 +178,7 @@ describe("useVirtualizer", () => {
178
178
  container.remove()
179
179
  })
180
180
 
181
- it("gap option affects total size", () => {
181
+ it('gap option affects total size', () => {
182
182
  const container = createScrollContainer()
183
183
  const { result: noGap, unmount: unmount1 } = mountWith(() =>
184
184
  useVirtualizer(() => ({
@@ -206,7 +206,7 @@ describe("useVirtualizer", () => {
206
206
  container.remove()
207
207
  })
208
208
 
209
- it("horizontal mode works", () => {
209
+ it('horizontal mode works', () => {
210
210
  const container = createScrollContainer()
211
211
  const { result: virt, unmount } = mountWith(() =>
212
212
  useVirtualizer(() => ({
@@ -223,7 +223,7 @@ describe("useVirtualizer", () => {
223
223
  container.remove()
224
224
  })
225
225
 
226
- it("padding affects total size", () => {
226
+ it('padding affects total size', () => {
227
227
  const container = createScrollContainer()
228
228
  const { result: virt, unmount } = mountWith(() =>
229
229
  useVirtualizer(() => ({
@@ -241,7 +241,7 @@ describe("useVirtualizer", () => {
241
241
  container.remove()
242
242
  })
243
243
 
244
- it("isScrolling starts as false", () => {
244
+ it('isScrolling starts as false', () => {
245
245
  const container = createScrollContainer()
246
246
  const { result: virt, unmount } = mountWith(() =>
247
247
  useVirtualizer(() => ({
@@ -256,7 +256,7 @@ describe("useVirtualizer", () => {
256
256
  container.remove()
257
257
  })
258
258
 
259
- it("enabled: false produces empty virtual items", () => {
259
+ it('enabled: false produces empty virtual items', () => {
260
260
  const container = createScrollContainer()
261
261
  const { result: virt, unmount } = mountWith(() =>
262
262
  useVirtualizer(() => ({
@@ -273,7 +273,7 @@ describe("useVirtualizer", () => {
273
273
  container.remove()
274
274
  })
275
275
 
276
- it("onChange callback updates signals when triggered", () => {
276
+ it('onChange callback updates signals when triggered', () => {
277
277
  const container = createScrollContainer()
278
278
  const onChangeSpy = vi.fn()
279
279
  const { result: virt, unmount } = mountWith(() =>
@@ -293,15 +293,15 @@ describe("useVirtualizer", () => {
293
293
  }
294
294
 
295
295
  expect(virt.virtualItems()).toBeDefined()
296
- expect(typeof virt.totalSize()).toBe("number")
297
- expect(typeof virt.isScrolling()).toBe("boolean")
296
+ expect(typeof virt.totalSize()).toBe('number')
297
+ expect(typeof virt.isScrolling()).toBe('boolean')
298
298
  // The user's onChange should have been forwarded
299
299
  expect(onChangeSpy).toHaveBeenCalled()
300
300
  unmount()
301
301
  container.remove()
302
302
  })
303
303
 
304
- it("onChange callback works without user-provided onChange", () => {
304
+ it('onChange callback works without user-provided onChange', () => {
305
305
  const container = createScrollContainer()
306
306
  const { result: virt, unmount } = mountWith(() =>
307
307
  useVirtualizer(() => ({
@@ -326,27 +326,27 @@ describe("useVirtualizer", () => {
326
326
 
327
327
  // ─── useWindowVirtualizer ─────────────────────────────────────────────────────
328
328
 
329
- describe("useWindowVirtualizer", () => {
329
+ describe('useWindowVirtualizer', () => {
330
330
  beforeEach(() => {
331
331
  // Ensure window has layout-like properties for happy-dom
332
- Object.defineProperty(window, "innerHeight", {
332
+ Object.defineProperty(window, 'innerHeight', {
333
333
  value: 768,
334
334
  writable: true,
335
335
  configurable: true,
336
336
  })
337
- Object.defineProperty(window, "innerWidth", {
337
+ Object.defineProperty(window, 'innerWidth', {
338
338
  value: 1024,
339
339
  writable: true,
340
340
  configurable: true,
341
341
  })
342
- Object.defineProperty(window, "scrollY", {
342
+ Object.defineProperty(window, 'scrollY', {
343
343
  value: 0,
344
344
  writable: true,
345
345
  configurable: true,
346
346
  })
347
347
  })
348
348
 
349
- it("creates an instance and returns virtualItems, totalSize, isScrolling signals", () => {
349
+ it('creates an instance and returns virtualItems, totalSize, isScrolling signals', () => {
350
350
  const { result: virt, unmount } = mountWith(() =>
351
351
  useWindowVirtualizer(() => ({
352
352
  count: 1000,
@@ -357,12 +357,12 @@ describe("useWindowVirtualizer", () => {
357
357
  expect(virt.instance).toBeDefined()
358
358
  expect(virt.virtualItems()).toBeDefined()
359
359
  expect(Array.isArray(virt.virtualItems())).toBe(true)
360
- expect(typeof virt.totalSize()).toBe("number")
360
+ expect(typeof virt.totalSize()).toBe('number')
361
361
  expect(virt.isScrolling()).toBe(false)
362
362
  unmount()
363
363
  })
364
364
 
365
- it("returns correct total size", () => {
365
+ it('returns correct total size', () => {
366
366
  const { result: virt, unmount } = mountWith(() =>
367
367
  useWindowVirtualizer(() => ({
368
368
  count: 100,
@@ -374,7 +374,7 @@ describe("useWindowVirtualizer", () => {
374
374
  unmount()
375
375
  })
376
376
 
377
- it("reactive count — updates when count signal changes", () => {
377
+ it('reactive count — updates when count signal changes', () => {
378
378
  const count = signal(100)
379
379
  const { result: virt, unmount } = mountWith(() =>
380
380
  useWindowVirtualizer(() => ({
@@ -390,7 +390,7 @@ describe("useWindowVirtualizer", () => {
390
390
  unmount()
391
391
  })
392
392
 
393
- it("reactive estimateSize — updates total size after measure()", () => {
393
+ it('reactive estimateSize — updates total size after measure()', () => {
394
394
  const itemSize = signal(50)
395
395
  const { result: virt, unmount } = mountWith(() =>
396
396
  useWindowVirtualizer(() => ({
@@ -407,7 +407,7 @@ describe("useWindowVirtualizer", () => {
407
407
  unmount()
408
408
  })
409
409
 
410
- it("exposes instance methods (scrollToIndex, scrollToOffset, measureElement)", () => {
410
+ it('exposes instance methods (scrollToIndex, scrollToOffset, measureElement)', () => {
411
411
  const { result: virt, unmount } = mountWith(() =>
412
412
  useWindowVirtualizer(() => ({
413
413
  count: 50,
@@ -415,13 +415,13 @@ describe("useWindowVirtualizer", () => {
415
415
  })),
416
416
  )
417
417
 
418
- expect(typeof virt.instance.scrollToIndex).toBe("function")
419
- expect(typeof virt.instance.scrollToOffset).toBe("function")
420
- expect(typeof virt.instance.measureElement).toBe("function")
418
+ expect(typeof virt.instance.scrollToIndex).toBe('function')
419
+ expect(typeof virt.instance.scrollToOffset).toBe('function')
420
+ expect(typeof virt.instance.measureElement).toBe('function')
421
421
  unmount()
422
422
  })
423
423
 
424
- it("virtual items have correct structure", () => {
424
+ it('virtual items have correct structure', () => {
425
425
  const { result: virt, unmount } = mountWith(() =>
426
426
  useWindowVirtualizer(() => ({
427
427
  count: 1000,
@@ -432,16 +432,16 @@ describe("useWindowVirtualizer", () => {
432
432
  const items = virt.virtualItems()
433
433
  if (items.length > 0) {
434
434
  const item = items[0]!
435
- expect(typeof item.index).toBe("number")
436
- expect(typeof item.start).toBe("number")
437
- expect(typeof item.end).toBe("number")
438
- expect(typeof item.size).toBe("number")
435
+ expect(typeof item.index).toBe('number')
436
+ expect(typeof item.start).toBe('number')
437
+ expect(typeof item.end).toBe('number')
438
+ expect(typeof item.size).toBe('number')
439
439
  expect(typeof item.key).toBeDefined()
440
440
  }
441
441
  unmount()
442
442
  })
443
443
 
444
- it("gap option affects total size", () => {
444
+ it('gap option affects total size', () => {
445
445
  const { result: noGap, unmount: unmount1 } = mountWith(() =>
446
446
  useWindowVirtualizer(() => ({
447
447
  count: 10,
@@ -465,7 +465,7 @@ describe("useWindowVirtualizer", () => {
465
465
  unmount2()
466
466
  })
467
467
 
468
- it("padding affects total size", () => {
468
+ it('padding affects total size', () => {
469
469
  const { result: virt, unmount } = mountWith(() =>
470
470
  useWindowVirtualizer(() => ({
471
471
  count: 10,
@@ -480,7 +480,7 @@ describe("useWindowVirtualizer", () => {
480
480
  unmount()
481
481
  })
482
482
 
483
- it("horizontal mode works", () => {
483
+ it('horizontal mode works', () => {
484
484
  const { result: virt, unmount } = mountWith(() =>
485
485
  useWindowVirtualizer(() => ({
486
486
  count: 100,
@@ -494,7 +494,7 @@ describe("useWindowVirtualizer", () => {
494
494
  unmount()
495
495
  })
496
496
 
497
- it("enabled: false produces empty virtual items", () => {
497
+ it('enabled: false produces empty virtual items', () => {
498
498
  const { result: virt, unmount } = mountWith(() =>
499
499
  useWindowVirtualizer(() => ({
500
500
  count: 100,
@@ -508,7 +508,7 @@ describe("useWindowVirtualizer", () => {
508
508
  unmount()
509
509
  })
510
510
 
511
- it("calls user-provided onChange callback", () => {
511
+ it('calls user-provided onChange callback', () => {
512
512
  const onChangeSpy = vi.fn()
513
513
  const count = signal(10)
514
514
  const { result: virt, unmount } = mountWith(() =>
@@ -527,7 +527,7 @@ describe("useWindowVirtualizer", () => {
527
527
  unmount()
528
528
  })
529
529
 
530
- it("overscan controls extra items rendered", () => {
530
+ it('overscan controls extra items rendered', () => {
531
531
  const { result: small, unmount: unmount1 } = mountWith(() =>
532
532
  useWindowVirtualizer(() => ({
533
533
  count: 1000,
@@ -549,7 +549,7 @@ describe("useWindowVirtualizer", () => {
549
549
  unmount2()
550
550
  })
551
551
 
552
- it("onChange callback updates signals when triggered directly", () => {
552
+ it('onChange callback updates signals when triggered directly', () => {
553
553
  const onChangeSpy = vi.fn()
554
554
  const { result: virt, unmount } = mountWith(() =>
555
555
  useWindowVirtualizer(() => ({
@@ -566,13 +566,13 @@ describe("useWindowVirtualizer", () => {
566
566
  }
567
567
 
568
568
  expect(virt.virtualItems()).toBeDefined()
569
- expect(typeof virt.totalSize()).toBe("number")
570
- expect(typeof virt.isScrolling()).toBe("boolean")
569
+ expect(typeof virt.totalSize()).toBe('number')
570
+ expect(typeof virt.isScrolling()).toBe('boolean')
571
571
  expect(onChangeSpy).toHaveBeenCalled()
572
572
  unmount()
573
573
  })
574
574
 
575
- it("onChange works without user-provided onChange", () => {
575
+ it('onChange works without user-provided onChange', () => {
576
576
  const { result: virt, unmount } = mountWith(() =>
577
577
  useWindowVirtualizer(() => ({
578
578
  count: 100,
@@ -589,7 +589,7 @@ describe("useWindowVirtualizer", () => {
589
589
  unmount()
590
590
  })
591
591
 
592
- it("handles missing document/window gracefully", () => {
592
+ it('handles missing document/window gracefully', () => {
593
593
  const origDoc = globalThis.document
594
594
  const origWin = globalThis.window
595
595
  try {
@@ -1,6 +1,6 @@
1
- import { onMount, onUnmount } from "@pyreon/core"
2
- import type { Signal } from "@pyreon/reactivity"
3
- import { batch, effect, signal } from "@pyreon/reactivity"
1
+ import { onMount, onUnmount } from '@pyreon/core'
2
+ import type { Signal } from '@pyreon/reactivity'
3
+ import { batch, effect, signal } from '@pyreon/reactivity'
4
4
  import {
5
5
  elementScroll,
6
6
  observeElementOffset,
@@ -8,19 +8,19 @@ import {
8
8
  type VirtualItem,
9
9
  Virtualizer,
10
10
  type VirtualizerOptions,
11
- } from "@tanstack/virtual-core"
11
+ } from '@tanstack/virtual-core'
12
12
 
13
13
  export type UseVirtualizerOptions<
14
14
  TScrollElement extends Element,
15
15
  TItemElement extends Element,
16
16
  > = () => Omit<
17
17
  VirtualizerOptions<TScrollElement, TItemElement>,
18
- "observeElementRect" | "observeElementOffset" | "scrollToFn"
18
+ 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
19
19
  > &
20
20
  Partial<
21
21
  Pick<
22
22
  VirtualizerOptions<TScrollElement, TItemElement>,
23
- "observeElementRect" | "observeElementOffset" | "scrollToFn"
23
+ 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
24
24
  >
25
25
  >
26
26
 
@@ -1,6 +1,6 @@
1
- import { onMount, onUnmount } from "@pyreon/core"
2
- import type { Signal } from "@pyreon/reactivity"
3
- import { batch, effect, signal } from "@pyreon/reactivity"
1
+ import { onMount, onUnmount } from '@pyreon/core'
2
+ import type { Signal } from '@pyreon/reactivity'
3
+ import { batch, effect, signal } from '@pyreon/reactivity'
4
4
  import {
5
5
  observeWindowOffset,
6
6
  observeWindowRect,
@@ -8,16 +8,16 @@ import {
8
8
  Virtualizer,
9
9
  type VirtualizerOptions,
10
10
  windowScroll,
11
- } from "@tanstack/virtual-core"
11
+ } from '@tanstack/virtual-core'
12
12
 
13
13
  export type UseWindowVirtualizerOptions<TItemElement extends Element> = () => Omit<
14
14
  VirtualizerOptions<Window, TItemElement>,
15
- "observeElementRect" | "observeElementOffset" | "scrollToFn" | "getScrollElement"
15
+ 'observeElementRect' | 'observeElementOffset' | 'scrollToFn' | 'getScrollElement'
16
16
  > &
17
17
  Partial<
18
18
  Pick<
19
19
  VirtualizerOptions<Window, TItemElement>,
20
- "observeElementRect" | "observeElementOffset" | "scrollToFn"
20
+ 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
21
21
  >
22
22
  >
23
23
 
@@ -48,8 +48,8 @@ export function useWindowVirtualizer<TItemElement extends Element>(
48
48
  observeElementRect: observeWindowRect,
49
49
  observeElementOffset: observeWindowOffset,
50
50
  scrollToFn: windowScroll,
51
- initialOffset: typeof document !== "undefined" ? window.scrollY : 0,
52
- getScrollElement: () => (typeof window !== "undefined" ? window : (null as unknown as Window)),
51
+ initialOffset: typeof document !== 'undefined' ? window.scrollY : 0,
52
+ getScrollElement: () => (typeof window !== 'undefined' ? window : (null as unknown as Window)),
53
53
  ...options(),
54
54
  }
55
55