@pyreon/virtual 0.24.4 → 0.24.6
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/package.json +6 -8
- package/src/index.ts +0 -32
- package/src/manifest.ts +0 -129
- package/src/tests/manifest-snapshot.test.ts +0 -87
- package/src/tests/virtual-comprehensive.test.tsx +0 -564
- package/src/tests/virtual.test.tsx +0 -612
- package/src/use-virtualizer.ts +0 -119
- package/src/use-window-virtualizer.ts +0 -101
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/virtual",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.6",
|
|
4
4
|
"description": "Pyreon adapter for TanStack Virtual",
|
|
5
5
|
"homepage": "https://github.com/pyreon/pyreon/tree/main/packages/virtual#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"lib",
|
|
17
17
|
"!lib/**/*.map",
|
|
18
|
-
"src",
|
|
19
18
|
"README.md",
|
|
20
19
|
"LICENSE"
|
|
21
20
|
],
|
|
@@ -26,7 +25,6 @@
|
|
|
26
25
|
"types": "./lib/types/index.d.ts",
|
|
27
26
|
"exports": {
|
|
28
27
|
".": {
|
|
29
|
-
"bun": "./src/index.ts",
|
|
30
28
|
"import": "./lib/index.js",
|
|
31
29
|
"types": "./lib/types/index.d.ts"
|
|
32
30
|
}
|
|
@@ -42,15 +40,15 @@
|
|
|
42
40
|
"lint": "oxlint ."
|
|
43
41
|
},
|
|
44
42
|
"dependencies": {
|
|
45
|
-
"@pyreon/core": "^0.24.
|
|
46
|
-
"@pyreon/reactivity": "^0.24.
|
|
43
|
+
"@pyreon/core": "^0.24.6",
|
|
44
|
+
"@pyreon/reactivity": "^0.24.6",
|
|
47
45
|
"@tanstack/virtual-core": "^3.0.0"
|
|
48
46
|
},
|
|
49
47
|
"devDependencies": {
|
|
50
48
|
"@happy-dom/global-registrator": "^20.8.9",
|
|
51
|
-
"@pyreon/core": "^0.24.
|
|
49
|
+
"@pyreon/core": "^0.24.6",
|
|
52
50
|
"@pyreon/manifest": "0.13.1",
|
|
53
|
-
"@pyreon/reactivity": "^0.24.
|
|
54
|
-
"@pyreon/runtime-dom": "^0.24.
|
|
51
|
+
"@pyreon/reactivity": "^0.24.6",
|
|
52
|
+
"@pyreon/runtime-dom": "^0.24.6"
|
|
55
53
|
}
|
|
56
54
|
}
|
package/src/index.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// ─── TanStack Virtual core re-exports ────────────────────────────────────────
|
|
2
|
-
// Users can import utilities and types from @pyreon/virtual directly.
|
|
3
|
-
|
|
4
|
-
export type {
|
|
5
|
-
Range,
|
|
6
|
-
Rect,
|
|
7
|
-
ScrollToOptions,
|
|
8
|
-
VirtualItem,
|
|
9
|
-
VirtualizerOptions,
|
|
10
|
-
} from '@tanstack/virtual-core'
|
|
11
|
-
export {
|
|
12
|
-
defaultKeyExtractor,
|
|
13
|
-
defaultRangeExtractor,
|
|
14
|
-
elementScroll,
|
|
15
|
-
measureElement,
|
|
16
|
-
observeElementOffset,
|
|
17
|
-
observeElementRect,
|
|
18
|
-
observeWindowOffset,
|
|
19
|
-
observeWindowRect,
|
|
20
|
-
Virtualizer,
|
|
21
|
-
windowScroll,
|
|
22
|
-
} from '@tanstack/virtual-core'
|
|
23
|
-
|
|
24
|
-
// ─── Pyreon adapter ─────────────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
export type { UseVirtualizerOptions, UseVirtualizerResult } from './use-virtualizer'
|
|
27
|
-
export { useVirtualizer } from './use-virtualizer'
|
|
28
|
-
export type {
|
|
29
|
-
UseWindowVirtualizerOptions,
|
|
30
|
-
UseWindowVirtualizerResult,
|
|
31
|
-
} from './use-window-virtualizer'
|
|
32
|
-
export { useWindowVirtualizer } from './use-window-virtualizer'
|
package/src/manifest.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { defineManifest } from '@pyreon/manifest'
|
|
2
|
-
|
|
3
|
-
export default defineManifest({
|
|
4
|
-
name: '@pyreon/virtual',
|
|
5
|
-
title: 'TanStack Virtual Adapter',
|
|
6
|
-
tagline: 'Pyreon adapter for TanStack Virtual — element-scoped and window-scoped virtualization',
|
|
7
|
-
description:
|
|
8
|
-
'Reactive TanStack Virtual adapter for Pyreon. Signal-driven virtualizer that returns reactive `virtualItems`, `totalSize`, and `isScrolling` signals. Supports element-scoped (`useVirtualizer`) and window-scoped (`useWindowVirtualizer`) variants. SSR-safe — window virtualizer checks for browser environment before attaching scroll listeners.',
|
|
9
|
-
category: 'universal',
|
|
10
|
-
longExample: `import { useVirtualizer, useWindowVirtualizer } from '@pyreon/virtual'
|
|
11
|
-
import { signal } from '@pyreon/reactivity'
|
|
12
|
-
|
|
13
|
-
// Element-scoped virtualizer — attach to a scrollable container
|
|
14
|
-
const items = signal(Array.from({ length: 10000 }, (_, i) => ({ id: i, label: \`Item \${i}\` })))
|
|
15
|
-
|
|
16
|
-
const MyList = () => {
|
|
17
|
-
let scrollRef!: HTMLDivElement
|
|
18
|
-
|
|
19
|
-
const virtualizer = useVirtualizer({
|
|
20
|
-
count: () => items().length,
|
|
21
|
-
getScrollElement: () => scrollRef,
|
|
22
|
-
estimateSize: () => 35, // px per row
|
|
23
|
-
overscan: 5, // render 5 extra items above/below viewport
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<div ref={(el) => (scrollRef = el)} style="height: 400px; overflow: auto">
|
|
28
|
-
<div style={() => \`height: \${virtualizer.totalSize()}px; position: relative\`}>
|
|
29
|
-
<For each={() => virtualizer.virtualItems()} by={(item) => item.index}>
|
|
30
|
-
{(item) => (
|
|
31
|
-
<div
|
|
32
|
-
style={() => \`position: absolute; top: \${item.start}px; height: \${item.size}px; width: 100%\`}
|
|
33
|
-
>
|
|
34
|
-
{() => items()[item.index].label}
|
|
35
|
-
</div>
|
|
36
|
-
)}
|
|
37
|
-
</For>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Window-scoped virtualizer — scrolls with the page
|
|
44
|
-
const WindowList = () => {
|
|
45
|
-
const virtualizer = useWindowVirtualizer({
|
|
46
|
-
count: () => items().length,
|
|
47
|
-
estimateSize: () => 50,
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<div style={() => \`height: \${virtualizer.totalSize()}px; position: relative\`}>
|
|
52
|
-
<For each={() => virtualizer.virtualItems()} by={(item) => item.index}>
|
|
53
|
-
{(item) => (
|
|
54
|
-
<div style={() => \`position: absolute; top: \${item.start}px; height: \${item.size}px\`}>
|
|
55
|
-
{() => items()[item.index].label}
|
|
56
|
-
</div>
|
|
57
|
-
)}
|
|
58
|
-
</For>
|
|
59
|
-
</div>
|
|
60
|
-
)
|
|
61
|
-
}`,
|
|
62
|
-
features: [
|
|
63
|
-
'useVirtualizer — element-scoped with reactive virtualItems, totalSize, isScrolling',
|
|
64
|
-
'useWindowVirtualizer — window-scoped variant with SSR-safe browser checks',
|
|
65
|
-
'Signal-driven count and estimateSize for reactive list lengths',
|
|
66
|
-
'scrollToIndex / scrollToOffset for programmatic scrolling',
|
|
67
|
-
'TanStack Virtual core utilities re-exported for convenience',
|
|
68
|
-
],
|
|
69
|
-
api: [
|
|
70
|
-
{
|
|
71
|
-
name: 'useVirtualizer',
|
|
72
|
-
kind: 'hook',
|
|
73
|
-
signature: '(options: UseVirtualizerOptions) => UseVirtualizerResult',
|
|
74
|
-
summary:
|
|
75
|
-
'Create an element-scoped virtualizer. Attach to a scrollable container via `getScrollElement`. Returns reactive `virtualItems()`, `totalSize()`, and `isScrolling()` signals plus `scrollToIndex()` and `scrollToOffset()` for programmatic control. Options that accept functions (`count`, `estimateSize`) track signal reads reactively.',
|
|
76
|
-
example: `const virtualizer = useVirtualizer({
|
|
77
|
-
count: () => items().length,
|
|
78
|
-
getScrollElement: () => scrollRef,
|
|
79
|
-
estimateSize: () => 35,
|
|
80
|
-
overscan: 5,
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
// virtualItems() is reactive — re-evaluates as user scrolls
|
|
84
|
-
<For each={() => virtualizer.virtualItems()} by={(item) => item.index}>
|
|
85
|
-
{(item) => <div style={() => \`top: \${item.start}px\`}>{item.index}</div>}
|
|
86
|
-
</For>`,
|
|
87
|
-
mistakes: [
|
|
88
|
-
'Forgetting to set a fixed height on the scroll container — without overflow:auto + a height, the virtualizer has no viewport to measure',
|
|
89
|
-
'Passing count as a plain number instead of a function when the list length is dynamic — the virtualizer won\'t update when items change',
|
|
90
|
-
'Reading virtualItems() outside a reactive scope — captures the initial window only, never updates on scroll',
|
|
91
|
-
'Using .map() instead of <For> on virtualItems — loses keyed reconciliation',
|
|
92
|
-
],
|
|
93
|
-
seeAlso: ['useWindowVirtualizer'],
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
name: 'useWindowVirtualizer',
|
|
97
|
-
kind: 'hook',
|
|
98
|
-
signature: '(options: UseWindowVirtualizerOptions) => UseWindowVirtualizerResult',
|
|
99
|
-
summary:
|
|
100
|
-
'Create a window-scoped virtualizer that uses the browser window as the scroll container. SSR-safe — checks for browser environment before attaching scroll listeners. Same return shape as `useVirtualizer` (virtualItems, totalSize, isScrolling, scrollToIndex). Use for long page-level lists where the entire page scrolls.',
|
|
101
|
-
example: `const virtualizer = useWindowVirtualizer({
|
|
102
|
-
count: () => items().length,
|
|
103
|
-
estimateSize: () => 50,
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
<div style={() => \`height: \${virtualizer.totalSize()}px; position: relative\`}>
|
|
107
|
-
<For each={() => virtualizer.virtualItems()} by={(item) => item.index}>
|
|
108
|
-
{(item) => <div style={() => \`position: absolute; top: \${item.start}px\`}>Row {item.index}</div>}
|
|
109
|
-
</For>
|
|
110
|
-
</div>`,
|
|
111
|
-
mistakes: [
|
|
112
|
-
'Using useWindowVirtualizer inside a scrollable container that is not the window — use useVirtualizer with getScrollElement instead',
|
|
113
|
-
'Forgetting to position items absolutely inside a relative container with the total height — items overlap or collapse',
|
|
114
|
-
],
|
|
115
|
-
seeAlso: ['useVirtualizer'],
|
|
116
|
-
},
|
|
117
|
-
],
|
|
118
|
-
gotchas: [
|
|
119
|
-
'Both hooks return reactive signals (`virtualItems()`, `totalSize()`, `isScrolling()`). Always read them inside reactive scopes (JSX thunks, effect, computed) so they update on scroll.',
|
|
120
|
-
{
|
|
121
|
-
label: 'Absolute positioning',
|
|
122
|
-
note: 'Virtual items must be positioned absolutely inside a container whose height equals `totalSize()`. Each item\'s `start` property gives its pixel offset from the top.',
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
label: 'Re-exports',
|
|
126
|
-
note: 'TanStack Virtual core types and utilities (VirtualItem, Virtualizer, measureElement, etc.) are re-exported from `@pyreon/virtual` for single-import convenience.',
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
})
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
renderApiReferenceEntries,
|
|
3
|
-
renderLlmsFullSection,
|
|
4
|
-
renderLlmsTxtLine,
|
|
5
|
-
} from '@pyreon/manifest'
|
|
6
|
-
import manifest from '../manifest'
|
|
7
|
-
|
|
8
|
-
describe('gen-docs — virtual snapshot', () => {
|
|
9
|
-
it('renders to llms.txt bullet', () => {
|
|
10
|
-
expect(renderLlmsTxtLine(manifest)).toMatchInlineSnapshot(`"- @pyreon/virtual — Pyreon adapter for TanStack Virtual — element-scoped and window-scoped virtualization. Both hooks return reactive signals (\`virtualItems()\`, \`totalSize()\`, \`isScrolling()\`). Always read them inside reactive scopes (JSX thunks, effect, computed) so they update on scroll."`)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('renders to llms-full.txt section', () => {
|
|
14
|
-
expect(renderLlmsFullSection(manifest)).toMatchInlineSnapshot(`
|
|
15
|
-
"## @pyreon/virtual — TanStack Virtual Adapter
|
|
16
|
-
|
|
17
|
-
Reactive TanStack Virtual adapter for Pyreon. Signal-driven virtualizer that returns reactive \`virtualItems\`, \`totalSize\`, and \`isScrolling\` signals. Supports element-scoped (\`useVirtualizer\`) and window-scoped (\`useWindowVirtualizer\`) variants. SSR-safe — window virtualizer checks for browser environment before attaching scroll listeners.
|
|
18
|
-
|
|
19
|
-
\`\`\`typescript
|
|
20
|
-
import { useVirtualizer, useWindowVirtualizer } from '@pyreon/virtual'
|
|
21
|
-
import { signal } from '@pyreon/reactivity'
|
|
22
|
-
|
|
23
|
-
// Element-scoped virtualizer — attach to a scrollable container
|
|
24
|
-
const items = signal(Array.from({ length: 10000 }, (_, i) => ({ id: i, label: \`Item \${i}\` })))
|
|
25
|
-
|
|
26
|
-
const MyList = () => {
|
|
27
|
-
let scrollRef!: HTMLDivElement
|
|
28
|
-
|
|
29
|
-
const virtualizer = useVirtualizer({
|
|
30
|
-
count: () => items().length,
|
|
31
|
-
getScrollElement: () => scrollRef,
|
|
32
|
-
estimateSize: () => 35, // px per row
|
|
33
|
-
overscan: 5, // render 5 extra items above/below viewport
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<div ref={(el) => (scrollRef = el)} style="height: 400px; overflow: auto">
|
|
38
|
-
<div style={() => \`height: \${virtualizer.totalSize()}px; position: relative\`}>
|
|
39
|
-
<For each={() => virtualizer.virtualItems()} by={(item) => item.index}>
|
|
40
|
-
{(item) => (
|
|
41
|
-
<div
|
|
42
|
-
style={() => \`position: absolute; top: \${item.start}px; height: \${item.size}px; width: 100%\`}
|
|
43
|
-
>
|
|
44
|
-
{() => items()[item.index].label}
|
|
45
|
-
</div>
|
|
46
|
-
)}
|
|
47
|
-
</For>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Window-scoped virtualizer — scrolls with the page
|
|
54
|
-
const WindowList = () => {
|
|
55
|
-
const virtualizer = useWindowVirtualizer({
|
|
56
|
-
count: () => items().length,
|
|
57
|
-
estimateSize: () => 50,
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<div style={() => \`height: \${virtualizer.totalSize()}px; position: relative\`}>
|
|
62
|
-
<For each={() => virtualizer.virtualItems()} by={(item) => item.index}>
|
|
63
|
-
{(item) => (
|
|
64
|
-
<div style={() => \`position: absolute; top: \${item.start}px; height: \${item.size}px\`}>
|
|
65
|
-
{() => items()[item.index].label}
|
|
66
|
-
</div>
|
|
67
|
-
)}
|
|
68
|
-
</For>
|
|
69
|
-
</div>
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
\`\`\`
|
|
73
|
-
|
|
74
|
-
> **Note**: Both hooks return reactive signals (\`virtualItems()\`, \`totalSize()\`, \`isScrolling()\`). Always read them inside reactive scopes (JSX thunks, effect, computed) so they update on scroll.
|
|
75
|
-
>
|
|
76
|
-
> **Absolute positioning**: Virtual items must be positioned absolutely inside a container whose height equals \`totalSize()\`. Each item's \`start\` property gives its pixel offset from the top.
|
|
77
|
-
>
|
|
78
|
-
> **Re-exports**: TanStack Virtual core types and utilities (VirtualItem, Virtualizer, measureElement, etc.) are re-exported from \`@pyreon/virtual\` for single-import convenience.
|
|
79
|
-
"
|
|
80
|
-
`)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('renders to MCP api-reference entries', () => {
|
|
84
|
-
const record = renderApiReferenceEntries(manifest)
|
|
85
|
-
expect(Object.keys(record).length).toBe(2)
|
|
86
|
-
})
|
|
87
|
-
})
|