react-virtual-renderer 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -0
- package/dist/App.d.ts +3 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/App.js +7 -0
- package/dist/App.js.map +1 -0
- package/dist/accessibility/a11y.d.ts +111 -0
- package/dist/accessibility/a11y.d.ts.map +1 -0
- package/dist/accessibility/a11y.js +254 -0
- package/dist/accessibility/a11y.js.map +1 -0
- package/dist/components/VirtualGrid.d.ts +8 -0
- package/dist/components/VirtualGrid.d.ts.map +1 -0
- package/dist/components/VirtualGrid.js +187 -0
- package/dist/components/VirtualGrid.js.map +1 -0
- package/dist/components/VirtualList.d.ts +8 -0
- package/dist/components/VirtualList.d.ts.map +1 -0
- package/dist/components/VirtualList.js +102 -0
- package/dist/components/VirtualList.js.map +1 -0
- package/dist/core/MeasurementSystem.d.ts +52 -0
- package/dist/core/MeasurementSystem.d.ts.map +1 -0
- package/dist/core/MeasurementSystem.js +138 -0
- package/dist/core/MeasurementSystem.js.map +1 -0
- package/dist/core/VirtualizationEngine.d.ts +65 -0
- package/dist/core/VirtualizationEngine.d.ts.map +1 -0
- package/dist/core/VirtualizationEngine.js +203 -0
- package/dist/core/VirtualizationEngine.js.map +1 -0
- package/dist/examples/AdvancedExamples.d.ts +24 -0
- package/dist/examples/AdvancedExamples.d.ts.map +1 -0
- package/dist/examples/AdvancedExamples.js +216 -0
- package/dist/examples/AdvancedExamples.js.map +1 -0
- package/dist/examples/Example.d.ts +26 -0
- package/dist/examples/Example.d.ts.map +1 -0
- package/dist/examples/Example.js +186 -0
- package/dist/examples/Example.js.map +1 -0
- package/dist/hooks/useInfiniteScroll.d.ts +17 -0
- package/dist/hooks/useInfiniteScroll.d.ts.map +1 -0
- package/dist/hooks/useInfiniteScroll.js +41 -0
- package/dist/hooks/useInfiniteScroll.js.map +1 -0
- package/dist/hooks/useLazyLoad.d.ts +16 -0
- package/dist/hooks/useLazyLoad.d.ts.map +1 -0
- package/dist/hooks/useLazyLoad.js +34 -0
- package/dist/hooks/useLazyLoad.js.map +1 -0
- package/dist/hooks/useScrollRestoration.d.ts +10 -0
- package/dist/hooks/useScrollRestoration.d.ts.map +1 -0
- package/dist/hooks/useScrollRestoration.js +63 -0
- package/dist/hooks/useScrollRestoration.js.map +1 -0
- package/dist/hooks/useVirtualList.d.ts +33 -0
- package/dist/hooks/useVirtualList.d.ts.map +1 -0
- package/dist/hooks/useVirtualList.js +226 -0
- package/dist/hooks/useVirtualList.js.map +1 -0
- package/dist/hooks/useVirtualizedSearch.d.ts +40 -0
- package/dist/hooks/useVirtualizedSearch.d.ts.map +1 -0
- package/dist/hooks/useVirtualizedSearch.js +168 -0
- package/dist/hooks/useVirtualizedSearch.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +11 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -0
- package/dist/performance/metrics.d.ts +110 -0
- package/dist/performance/metrics.d.ts.map +1 -0
- package/dist/performance/metrics.js +310 -0
- package/dist/performance/metrics.js.map +1 -0
- package/dist/plugin.d.ts +182 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +409 -0
- package/dist/plugin.js.map +1 -0
- package/dist/types.d.ts +84 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/helpers.d.ts +66 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +166 -0
- package/dist/utils/helpers.js.map +1 -0
- package/package.json +111 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// examples/Examples.tsx
|
|
3
|
+
import { useRef, useState } from 'react';
|
|
4
|
+
import { VirtualList, VirtualGrid, useVirtualList } from '../index';
|
|
5
|
+
import { CollapsibleRowsExample, CommentThreadExample, EcommerceCatalogExample, SearchableListExample, StockTickerExample } from './AdvancedExamples';
|
|
6
|
+
/**
|
|
7
|
+
* EXAMPLE 1: Chat Interface with Reverse Scrolling
|
|
8
|
+
*/
|
|
9
|
+
export function ChatExample() {
|
|
10
|
+
const [messages] = useState(Array.from({ length: 1000 }, (_, i) => ({
|
|
11
|
+
id: i,
|
|
12
|
+
author: i % 2 === 0 ? 'Alice' : 'Bob',
|
|
13
|
+
text: `Message ${i}: ${Math.random().toString(36).substring(7)}`,
|
|
14
|
+
timestamp: new Date(Date.now() - i * 60000),
|
|
15
|
+
})));
|
|
16
|
+
const containerRef = useRef(null);
|
|
17
|
+
return (_jsxs("div", { style: { padding: 20 }, children: [_jsx("h2", { children: "Chat Interface (Reverse Scrolling)" }), _jsx(VirtualList, { ref: containerRef, items: messages, height: 400, width: 800, scrollDirection: "reverse", estimatedItemSize: 60, renderItem: ({ item, isScrolling }) => (_jsxs("div", { style: {
|
|
18
|
+
padding: 12,
|
|
19
|
+
borderBottom: '1px solid #eee',
|
|
20
|
+
opacity: isScrolling ? 0.7 : 1,
|
|
21
|
+
}, children: [_jsxs("strong", { children: [item.author, ":"] }), " ", item.text, _jsx("br", {}), _jsx("small", { children: item.timestamp.toLocaleTimeString() })] })) })] }));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* EXAMPLE 2: Data Table with Variable Row Heights
|
|
25
|
+
*/
|
|
26
|
+
export function DataTableExample() {
|
|
27
|
+
const [rows] = useState(Array.from({ length: 500 }, (_, i) => ({
|
|
28
|
+
id: i,
|
|
29
|
+
name: `User ${i}`,
|
|
30
|
+
email: `user${i}@example.com`,
|
|
31
|
+
status: ['Active', 'Inactive', 'Pending'][i % 3],
|
|
32
|
+
description: `A longer description that varies in length. ${i % 5 === 0
|
|
33
|
+
? 'This one is longer with more text content to show variable row heights.'
|
|
34
|
+
: ''}`,
|
|
35
|
+
})));
|
|
36
|
+
const getRowHeight = (index) => {
|
|
37
|
+
// Some rows are taller due to longer content
|
|
38
|
+
return rows[index]?.description.length > 50 ? 100 : 60;
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs("div", { style: { padding: 20 }, children: [_jsx("h2", { children: "Data Table (Dynamic Heights)" }), _jsx("div", { style: {
|
|
41
|
+
width: 800,
|
|
42
|
+
border: '1px solid #ddd',
|
|
43
|
+
borderBottom: 'none',
|
|
44
|
+
backgroundColor: '#f5f5f5',
|
|
45
|
+
fontWeight: 600,
|
|
46
|
+
}, children: _jsxs("div", { style: {
|
|
47
|
+
display: 'flex',
|
|
48
|
+
alignItems: 'center',
|
|
49
|
+
}, children: [_jsx("div", { style: {
|
|
50
|
+
width: 180,
|
|
51
|
+
padding: 8,
|
|
52
|
+
boxSizing: 'border-box',
|
|
53
|
+
}, children: "Name" }), _jsx("div", { style: {
|
|
54
|
+
width: 240,
|
|
55
|
+
padding: 8,
|
|
56
|
+
boxSizing: 'border-box',
|
|
57
|
+
}, children: "Email" }), _jsx("div", { style: {
|
|
58
|
+
width: 160,
|
|
59
|
+
padding: 8,
|
|
60
|
+
boxSizing: 'border-box',
|
|
61
|
+
}, children: "Status" }), _jsx("div", { style: {
|
|
62
|
+
flex: 1,
|
|
63
|
+
padding: 8,
|
|
64
|
+
boxSizing: 'border-box',
|
|
65
|
+
}, children: "Description" })] }) }), _jsx(VirtualList, { items: rows, height: 400, width: 800, getItemSize: getRowHeight, estimatedItemSize: 60, scrollDirection: 'forward', renderItem: ({ item, index, style }) => (_jsxs("div", { style: {
|
|
66
|
+
...style,
|
|
67
|
+
display: 'flex',
|
|
68
|
+
alignItems: 'center',
|
|
69
|
+
borderBottom: '1px solid #ddd',
|
|
70
|
+
height: getRowHeight(index),
|
|
71
|
+
boxSizing: 'border-box',
|
|
72
|
+
background: '#fff',
|
|
73
|
+
}, children: [_jsx("div", { style: {
|
|
74
|
+
width: 180,
|
|
75
|
+
padding: 8,
|
|
76
|
+
boxSizing: 'border-box',
|
|
77
|
+
}, children: item.name }), _jsx("div", { style: {
|
|
78
|
+
width: 240,
|
|
79
|
+
padding: 8,
|
|
80
|
+
boxSizing: 'border-box',
|
|
81
|
+
}, children: item.email }), _jsx("div", { style: {
|
|
82
|
+
width: 160,
|
|
83
|
+
padding: 8,
|
|
84
|
+
boxSizing: 'border-box',
|
|
85
|
+
}, children: _jsx("span", { style: {
|
|
86
|
+
padding: '4px 8px',
|
|
87
|
+
borderRadius: 4,
|
|
88
|
+
backgroundColor: item.status === 'Active'
|
|
89
|
+
? '#d4edda'
|
|
90
|
+
: item.status === 'Inactive'
|
|
91
|
+
? '#f8d7da'
|
|
92
|
+
: '#fff3cd',
|
|
93
|
+
}, children: item.status }) }), _jsx("div", { style: {
|
|
94
|
+
flex: 1,
|
|
95
|
+
padding: 8,
|
|
96
|
+
fontSize: 12,
|
|
97
|
+
boxSizing: 'border-box',
|
|
98
|
+
}, children: item.description })] })) })] }));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* EXAMPLE 3: Image Grid with Masonry Layout
|
|
102
|
+
*/
|
|
103
|
+
export function MasonryGridExample() {
|
|
104
|
+
const [images] = useState(Array.from({ length: 200 }, (_, i) => ({
|
|
105
|
+
id: i,
|
|
106
|
+
url: `https://picsum.photos/300/${200 + (i % 4) * 50}?random=${i}`,
|
|
107
|
+
title: `Image ${i}`,
|
|
108
|
+
height: 200 + (i % 4) * 50,
|
|
109
|
+
})));
|
|
110
|
+
return (_jsxs("div", { style: { padding: 20 }, children: [_jsx("h2", { children: "Masonry Grid (Pinterest-style)" }), _jsx(VirtualGrid, { items: images, height: 600, width: 800, columnCount: 3, rowHeight: (index) => images[index]?.height || 200, layout: "masonry", gap: 16, renderItem: ({ item, isScrolling }) => (_jsxs("div", { style: {
|
|
111
|
+
backgroundColor: '#f0f0f0',
|
|
112
|
+
borderRadius: 8,
|
|
113
|
+
overflow: 'hidden',
|
|
114
|
+
opacity: isScrolling ? 0.7 : 1,
|
|
115
|
+
}, children: [_jsx("img", { src: item.url, alt: item.title, style: { width: '100%', height: '100%', objectFit: 'cover' } }), _jsx("div", { style: { padding: 8, fontSize: 12 }, children: item.title })] })) })] }));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* EXAMPLE 4: Traditional Grid Layout
|
|
119
|
+
*/
|
|
120
|
+
export function GridLayoutExample() {
|
|
121
|
+
const [items] = useState(Array.from({ length: 300 }, (_, i) => ({
|
|
122
|
+
id: i,
|
|
123
|
+
title: `Product ${i}`,
|
|
124
|
+
price: Math.floor(Math.random() * 1000),
|
|
125
|
+
image: `https://picsum.photos/200/200?random=${i}`,
|
|
126
|
+
})));
|
|
127
|
+
return (_jsxs("div", { style: { padding: 20 }, children: [_jsx("h2", { children: "Product Grid (Traditional Layout)" }), _jsx(VirtualGrid, { items: items, height: 600, width: 1000, columnCount: 5, rowHeight: 280, gap: 16, renderItem: ({ item }) => (_jsxs("div", { style: {
|
|
128
|
+
border: '1px solid #ddd',
|
|
129
|
+
borderRadius: 8,
|
|
130
|
+
padding: 12,
|
|
131
|
+
textAlign: 'center',
|
|
132
|
+
}, children: [_jsx("img", { src: item.image, alt: item.title, style: { width: '100%', height: 180, objectFit: 'cover' } }), _jsx("h4", { children: item.title }), _jsxs("p", { style: { color: '#e74c3c', fontSize: 18, fontWeight: 'bold' }, children: ["$", item.price] })] })) })] }));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* EXAMPLE 5: Using Hook Directly for Custom Layouts
|
|
136
|
+
*/
|
|
137
|
+
export function HookExample() {
|
|
138
|
+
const [items] = useState(Array.from({ length: 100 }, (_, i) => ({
|
|
139
|
+
id: i,
|
|
140
|
+
value: Math.random() * 100,
|
|
141
|
+
})));
|
|
142
|
+
const { virtualItems, scrollToItem, containerRef, getItemStyle } = useVirtualList({
|
|
143
|
+
items,
|
|
144
|
+
containerHeight: 400,
|
|
145
|
+
estimatedItemSize: 40,
|
|
146
|
+
});
|
|
147
|
+
return (_jsxs("div", { style: { padding: 20 }, children: [_jsx("h2", { children: "Using Hook Directly" }), _jsxs("div", { style: { marginBottom: 10 }, children: [_jsx("button", { onClick: () => scrollToItem(0), children: "Go to Start" }), _jsx("button", { onClick: () => scrollToItem(50, 'center'), children: "Jump to 50" }), _jsx("button", { onClick: () => scrollToItem(items.length - 1, 'end'), children: "Go to End" })] }), _jsx("div", { ref: containerRef, style: {
|
|
148
|
+
height: 400,
|
|
149
|
+
border: '1px solid #ccc',
|
|
150
|
+
overflow: 'auto',
|
|
151
|
+
position: 'relative',
|
|
152
|
+
}, children: virtualItems.map((vItem) => (_jsxs("div", { style: {
|
|
153
|
+
...getItemStyle(vItem.index, vItem.size),
|
|
154
|
+
padding: 8,
|
|
155
|
+
borderBottom: '1px solid #eee',
|
|
156
|
+
background: vItem.index % 2 === 0 ? '#f9f9f9' : 'white',
|
|
157
|
+
}, children: ["Item ", vItem.index, ": Value = ", items[vItem.index].value.toFixed(2)] }, vItem.index))) })] }));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Main Demo Component
|
|
161
|
+
*/
|
|
162
|
+
export function VirtualizeDemo() {
|
|
163
|
+
const [activeExample, setActiveExample] = useState('chat');
|
|
164
|
+
return (_jsxs("div", { style: { fontFamily: 'Arial, sans-serif', padding: 20 }, children: [_jsx("h1", { children: "Virtualize Library - Complete Examples" }), _jsx("div", { style: { marginBottom: 20, borderBottom: '2px solid #ddd' }, children: [
|
|
165
|
+
{ key: 'ecommerce', label: 'E-Commerce' },
|
|
166
|
+
{ key: 'search', label: 'Search' },
|
|
167
|
+
{ key: 'ticker', label: 'Stock Ticker' },
|
|
168
|
+
{ key: 'collapsible', label: 'Collapsible' },
|
|
169
|
+
{ key: 'comments', label: 'Comments' },
|
|
170
|
+
{ key: 'chat', label: 'Chat' },
|
|
171
|
+
{ key: 'table', label: 'Data Table' },
|
|
172
|
+
{ key: 'masonry', label: 'Masonry' },
|
|
173
|
+
{ key: 'grid', label: 'Grid' },
|
|
174
|
+
{ key: 'hook', label: 'Hooks' },
|
|
175
|
+
].map(({ key, label }) => (_jsx("button", { onClick: () => setActiveExample(key), style: {
|
|
176
|
+
padding: 10,
|
|
177
|
+
margin: 5,
|
|
178
|
+
backgroundColor: activeExample === key ? '#007bff' : '#f0f0f0',
|
|
179
|
+
color: activeExample === key ? 'white' : 'black',
|
|
180
|
+
border: 'none',
|
|
181
|
+
borderRadius: 4,
|
|
182
|
+
cursor: 'pointer',
|
|
183
|
+
}, children: label }, key))) }), activeExample === 'chat' && _jsx(ChatExample, {}), activeExample === 'table' && _jsx(DataTableExample, {}), activeExample === 'masonry' && _jsx(MasonryGridExample, {}), activeExample === 'grid' && _jsx(GridLayoutExample, {}), activeExample === 'hook' && _jsx(HookExample, {}), activeExample === 'ecommerce' && _jsx(EcommerceCatalogExample, {}), activeExample === 'search' && _jsx(SearchableListExample, {}), activeExample === 'ticker' && _jsx(StockTickerExample, {}), activeExample === 'collapsible' && _jsx(CollapsibleRowsExample, {}), activeExample === 'comments' && _jsx(CommentThreadExample, {})] }));
|
|
184
|
+
}
|
|
185
|
+
export default VirtualizeDemo;
|
|
186
|
+
//# sourceMappingURL=Example.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Example.js","sourceRoot":"","sources":["../../src/examples/Example.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
interface UseInfiniteScrollParams {
|
|
3
|
+
onLoadMore: () => Promise<void>;
|
|
4
|
+
threshold?: number;
|
|
5
|
+
isLoading?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Hook for infinite scroll pagination
|
|
9
|
+
* Automatically loads more items when user scrolls near the bottom
|
|
10
|
+
*/
|
|
11
|
+
export declare function useInfiniteScroll({ onLoadMore, threshold, isLoading, }: UseInfiniteScrollParams): {
|
|
12
|
+
containerRef: import("react").RefObject<HTMLDivElement>;
|
|
13
|
+
isAtBottom: boolean;
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=useInfiniteScroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInfiniteScroll.d.ts","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":";AAEA,UAAU,uBAAuB;IAC7B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAC9B,UAAU,EACV,SAAe,EACf,SAAiB,GACpB,EAAE,uBAAuB;;;;EAwCzB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useCallback, useRef, useEffect, useState } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for infinite scroll pagination
|
|
4
|
+
* Automatically loads more items when user scrolls near the bottom
|
|
5
|
+
*/
|
|
6
|
+
export function useInfiniteScroll({ onLoadMore, threshold = 500, isLoading = false, }) {
|
|
7
|
+
const containerRef = useRef(null);
|
|
8
|
+
const [isAtBottom, setIsAtBottom] = useState(false);
|
|
9
|
+
const hasCalledRef = useRef(false);
|
|
10
|
+
const checkIfAtBottom = useCallback(() => {
|
|
11
|
+
if (!containerRef.current || isLoading)
|
|
12
|
+
return;
|
|
13
|
+
const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
|
|
14
|
+
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
|
15
|
+
const atBottom = distanceFromBottom < threshold;
|
|
16
|
+
setIsAtBottom(atBottom);
|
|
17
|
+
// Trigger load when at bottom
|
|
18
|
+
if (atBottom && !hasCalledRef.current && !isLoading) {
|
|
19
|
+
hasCalledRef.current = true;
|
|
20
|
+
onLoadMore().finally(() => {
|
|
21
|
+
hasCalledRef.current = false;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}, [onLoadMore, threshold, isLoading]);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const container = containerRef.current;
|
|
27
|
+
if (!container)
|
|
28
|
+
return;
|
|
29
|
+
const handleScroll = () => {
|
|
30
|
+
checkIfAtBottom();
|
|
31
|
+
};
|
|
32
|
+
container.addEventListener('scroll', handleScroll);
|
|
33
|
+
return () => container.removeEventListener('scroll', handleScroll);
|
|
34
|
+
}, [checkIfAtBottom]);
|
|
35
|
+
return {
|
|
36
|
+
containerRef,
|
|
37
|
+
isAtBottom,
|
|
38
|
+
isLoading,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=useInfiniteScroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInfiniteScroll.js","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAQjE;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAC9B,UAAU,EACV,SAAS,GAAG,GAAG,EACf,SAAS,GAAG,KAAK,GACK;IACtB,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEnC,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,SAAS;YAAE,OAAO;QAE/C,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC;QACvE,MAAM,kBAAkB,GAAG,YAAY,GAAG,SAAS,GAAG,YAAY,CAAC;QAEnE,MAAM,QAAQ,GAAG,kBAAkB,GAAG,SAAS,CAAC;QAChD,aAAa,CAAC,QAAQ,CAAC,CAAC;QAExB,8BAA8B;QAC9B,IAAI,QAAQ,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,CAAC,SAAS,EAAE;YACjD,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC;YAC5B,UAAU,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACtB,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;YACjC,CAAC,CAAC,CAAC;SACN;IACL,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAEvC,SAAS,CAAC,GAAG,EAAE;QACX,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QACvC,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,eAAe,EAAE,CAAC;QACtB,CAAC,CAAC;QAEF,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QACnD,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACvE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,OAAO;QACH,YAAY;QACZ,UAAU;QACV,SAAS;KACZ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
interface UseLazyLoadParams {
|
|
3
|
+
threshold?: number;
|
|
4
|
+
onVisible?: () => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Hook for lazy loading items as they become visible
|
|
8
|
+
* Integrates with IntersectionObserver for efficiency
|
|
9
|
+
*/
|
|
10
|
+
export declare function useLazyLoad({ threshold, onVisible }: UseLazyLoadParams): {
|
|
11
|
+
ref: import("react").RefObject<HTMLDivElement>;
|
|
12
|
+
isVisible: boolean;
|
|
13
|
+
setupObserver: () => (() => void) | undefined;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=useLazyLoad.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLazyLoad.d.ts","sourceRoot":"","sources":["../../src/hooks/useLazyLoad.ts"],"names":[],"mappings":";AAEA,UAAU,iBAAiB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAe,EAAE,SAAS,EAAE,EAAE,iBAAiB;;;;EAmC5E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useState, useCallback, useRef } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for lazy loading items as they become visible
|
|
4
|
+
* Integrates with IntersectionObserver for efficiency
|
|
5
|
+
*/
|
|
6
|
+
export function useLazyLoad({ threshold = 0.1, onVisible }) {
|
|
7
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
8
|
+
const elementRef = useRef(null);
|
|
9
|
+
const setupObserver = useCallback(() => {
|
|
10
|
+
if (!elementRef.current || !('IntersectionObserver' in window)) {
|
|
11
|
+
// Fallback: consider visible if IntersectionObserver not supported
|
|
12
|
+
setIsVisible(true);
|
|
13
|
+
onVisible?.();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
17
|
+
if (entry.isIntersecting) {
|
|
18
|
+
setIsVisible(true);
|
|
19
|
+
onVisible?.();
|
|
20
|
+
observer.unobserve(entry.target);
|
|
21
|
+
}
|
|
22
|
+
}, { threshold });
|
|
23
|
+
observer.observe(elementRef.current);
|
|
24
|
+
return () => observer.disconnect();
|
|
25
|
+
}, [threshold, onVisible]);
|
|
26
|
+
// Setup observer when component mounts
|
|
27
|
+
// (This would be in useEffect in actual usage)
|
|
28
|
+
return {
|
|
29
|
+
ref: elementRef,
|
|
30
|
+
isVisible,
|
|
31
|
+
setupObserver,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=useLazyLoad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLazyLoad.js","sourceRoot":"","sources":["../../src/hooks/useLazyLoad.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAOtD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG,EAAE,SAAS,EAAqB;IACzE,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAEhD,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,IAAI,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,sBAAsB,IAAI,MAAM,CAAC,EAAE;YAC5D,mEAAmE;YACnE,YAAY,CAAC,IAAI,CAAC,CAAC;YACnB,SAAS,EAAE,EAAE,CAAC;YACd,OAAO;SACV;QAED,MAAM,QAAQ,GAAG,IAAI,oBAAoB,CACrC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE;YACR,IAAI,KAAK,CAAC,cAAc,EAAE;gBACtB,YAAY,CAAC,IAAI,CAAC,CAAC;gBACnB,SAAS,EAAE,EAAE,CAAC;gBACd,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;aACpC;QACL,CAAC,EACD,EAAE,SAAS,EAAE,CAChB,CAAC;QAEF,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAErC,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IACvC,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAE3B,uCAAuC;IACvC,+CAA+C;IAC/C,OAAO;QACH,GAAG,EAAE,UAAU;QACf,SAAS;QACT,aAAa;KAChB,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
/**
|
|
3
|
+
* Hook for restoring scroll position on navigation
|
|
4
|
+
* Useful when navigating away and coming back to a list
|
|
5
|
+
*/
|
|
6
|
+
export declare function useScrollRestoration(key: string, containerRef: React.RefObject<HTMLDivElement>): {
|
|
7
|
+
savePosition: () => void;
|
|
8
|
+
restorePosition: () => void;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=useScrollRestoration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollRestoration.d.ts","sourceRoot":"","sources":["../../src/hooks/useScrollRestoration.ts"],"names":[],"mappings":";AAUA;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC;;;EA6D9F"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useEffect, useRef, useCallback } from 'react';
|
|
2
|
+
const SCROLL_POSITION_STORAGE_KEY = 'virtualize-scroll-positions';
|
|
3
|
+
/**
|
|
4
|
+
* Hook for restoring scroll position on navigation
|
|
5
|
+
* Useful when navigating away and coming back to a list
|
|
6
|
+
*/
|
|
7
|
+
export function useScrollRestoration(key, containerRef) {
|
|
8
|
+
const positionMapRef = useRef(new Map());
|
|
9
|
+
// Save scroll position to localStorage
|
|
10
|
+
const savePosition = useCallback(() => {
|
|
11
|
+
if (!containerRef.current)
|
|
12
|
+
return;
|
|
13
|
+
const position = {
|
|
14
|
+
key,
|
|
15
|
+
offset: containerRef.current.scrollTop,
|
|
16
|
+
timestamp: Date.now(),
|
|
17
|
+
};
|
|
18
|
+
positionMapRef.current.set(key, position);
|
|
19
|
+
// Persist to localStorage
|
|
20
|
+
try {
|
|
21
|
+
const positions = Array.from(positionMapRef.current.values());
|
|
22
|
+
localStorage.setItem(SCROLL_POSITION_STORAGE_KEY, JSON.stringify(positions));
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
console.warn('Failed to save scroll position:', e);
|
|
26
|
+
}
|
|
27
|
+
}, [key, containerRef]);
|
|
28
|
+
// Restore scroll position from localStorage
|
|
29
|
+
const restorePosition = useCallback(() => {
|
|
30
|
+
if (!containerRef.current)
|
|
31
|
+
return;
|
|
32
|
+
try {
|
|
33
|
+
const stored = localStorage.getItem(SCROLL_POSITION_STORAGE_KEY);
|
|
34
|
+
if (!stored)
|
|
35
|
+
return;
|
|
36
|
+
const positions = JSON.parse(stored);
|
|
37
|
+
const savedPosition = positions.find((p) => p.key === key);
|
|
38
|
+
if (savedPosition) {
|
|
39
|
+
// Restore with a small delay to ensure DOM is ready
|
|
40
|
+
requestAnimationFrame(() => {
|
|
41
|
+
if (containerRef.current) {
|
|
42
|
+
containerRef.current.scrollTop = savedPosition.offset;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.warn('Failed to restore scroll position:', e);
|
|
49
|
+
}
|
|
50
|
+
}, [key, containerRef]);
|
|
51
|
+
// Save on unmount, restore on mount
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
restorePosition();
|
|
54
|
+
return () => {
|
|
55
|
+
savePosition();
|
|
56
|
+
};
|
|
57
|
+
}, [restorePosition, savePosition]);
|
|
58
|
+
return {
|
|
59
|
+
savePosition,
|
|
60
|
+
restorePosition,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=useScrollRestoration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollRestoration.js","sourceRoot":"","sources":["../../src/hooks/useScrollRestoration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAQvD,MAAM,2BAA2B,GAAG,6BAA6B,CAAC;AAElE;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW,EAAE,YAA6C;IAC3F,MAAM,cAAc,GAAG,MAAM,CAA8B,IAAI,GAAG,EAAE,CAAC,CAAC;IAEtE,uCAAuC;IACvC,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,IAAI,CAAC,YAAY,CAAC,OAAO;YAAE,OAAO;QAElC,MAAM,QAAQ,GAAmB;YAC7B,GAAG;YACH,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS;YACtC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACxB,CAAC;QAEF,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAE1C,0BAA0B;QAC1B,IAAI;YACA,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9D,YAAY,CAAC,OAAO,CAAC,2BAA2B,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;SAChF;QAAC,OAAO,CAAC,EAAE;YACR,OAAO,CAAC,IAAI,CAAC,iCAAiC,EAAE,CAAC,CAAC,CAAC;SACtD;IACL,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;IAExB,4CAA4C;IAC5C,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,YAAY,CAAC,OAAO;YAAE,OAAO;QAElC,IAAI;YACA,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM;gBAAE,OAAO;YAEpB,MAAM,SAAS,GAAqB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACvD,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;YAE3D,IAAI,aAAa,EAAE;gBACf,oDAAoD;gBACpD,qBAAqB,CAAC,GAAG,EAAE;oBACvB,IAAI,YAAY,CAAC,OAAO,EAAE;wBACtB,YAAY,CAAC,OAAO,CAAC,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC;qBACzD;gBACL,CAAC,CAAC,CAAC;aACN;SACJ;QAAC,OAAO,CAAC,EAAE;YACR,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE,CAAC,CAAC,CAAC;SACzD;IACL,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;IAExB,oCAAoC;IACpC,SAAS,CAAC,GAAG,EAAE;QACX,eAAe,EAAE,CAAC;QAElB,OAAO,GAAG,EAAE;YACR,YAAY,EAAE,CAAC;QACnB,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC;IAEpC,OAAO;QACH,YAAY;QACZ,eAAe;KAClB,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CSSProperties, MutableRefObject } from 'react';
|
|
2
|
+
import { VirtualItem, ScrollDirection } from '../types';
|
|
3
|
+
interface UseVirtualListParams<T> {
|
|
4
|
+
items: T[];
|
|
5
|
+
getItemKey?: (index: number, item: T) => string | number;
|
|
6
|
+
containerHeight: number;
|
|
7
|
+
containerWidth?: number;
|
|
8
|
+
itemSize?: number | ((index: number) => number);
|
|
9
|
+
overscan?: number;
|
|
10
|
+
scrollDirection?: ScrollDirection;
|
|
11
|
+
estimatedItemSize?: number;
|
|
12
|
+
onScroll?: (offset: number, direction: ScrollDirection) => void;
|
|
13
|
+
onScrollEnd?: () => void;
|
|
14
|
+
stickyIndices?: number[];
|
|
15
|
+
}
|
|
16
|
+
interface UseVirtualListReturn {
|
|
17
|
+
virtualItems: VirtualItem[];
|
|
18
|
+
isScrolling: boolean;
|
|
19
|
+
scrollOffset: number;
|
|
20
|
+
totalSize: number;
|
|
21
|
+
scrollToItem: (index: number, alignment?: 'start' | 'center' | 'end') => void;
|
|
22
|
+
scrollToOffset: (offset: number) => void;
|
|
23
|
+
setScrollOffset: (offset: number) => void;
|
|
24
|
+
containerRef: MutableRefObject<HTMLDivElement | null>;
|
|
25
|
+
innerRef: MutableRefObject<HTMLDivElement | null>;
|
|
26
|
+
getItemStyle: (index: number, size: number) => CSSProperties;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Virtualized list hook
|
|
30
|
+
*/
|
|
31
|
+
export declare function useVirtualList<T = any>(params: UseVirtualListParams<T>): UseVirtualListReturn;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=useVirtualList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useVirtualList.d.ts","sourceRoot":"","sources":["../../src/hooks/useVirtualList.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,aAAa,EACb,gBAAgB,EACnB,MAAM,OAAO,CAAC;AAKf,OAAO,EACH,WAAW,EACX,eAAe,EAClB,MAAM,UAAU,CAAC;AAElB,UAAU,oBAAoB,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,EAAE,CAAC;IAEX,UAAU,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,KACN,MAAM,GAAG,MAAM,CAAC;IAErB,eAAe,EAAE,MAAM,CAAC;IAExB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,QAAQ,CAAC,EACP,MAAM,GACN,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IAE9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,QAAQ,CAAC,EAAE,CACP,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,eAAe,KACzB,IAAI,CAAC;IAEV,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAEzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,UAAU,oBAAoB;IAC1B,YAAY,EAAE,WAAW,EAAE,CAAC;IAE5B,WAAW,EAAE,OAAO,CAAC;IAErB,YAAY,EAAE,MAAM,CAAC;IAErB,SAAS,EAAE,MAAM,CAAC;IAElB,YAAY,EAAE,CACV,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EACJ,OAAO,GACP,QAAQ,GACR,KAAK,KACV,IAAI,CAAC;IAEV,cAAc,EAAE,CACZ,MAAM,EAAE,MAAM,KACb,IAAI,CAAC;IAEV,eAAe,EAAE,CACb,MAAM,EAAE,MAAM,KACb,IAAI,CAAC;IAEV,YAAY,EAAE,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAEtD,QAAQ,EAAE,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAElD,YAAY,EAAE,CACV,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,KACX,aAAa,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,GAAG,GAAG,EAClC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAChC,oBAAoB,CAuZtB"}
|