react-simple-virtualize 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ozan Batuhan Ceylan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # react-simple-virtualize
2
+
3
+ ![NPM Version](https://img.shields.io/npm/v/react-simple-virtualize)
4
+ ![License](https://img.shields.io/npm/l/react-simple-virtualize)
5
+ ![Size](https://img.shields.io/bundlephobia/minzip/react-simple-virtualize)
6
+
7
+ **react-simple-virtualize** is a lightweight (less than 1kb), dependency-free React hook for rendering large lists efficiently.
8
+
9
+ It solves the "too many DOM elements" problem by rendering only the items visible in the viewport. Perfect for scenarios where you need raw performance without the complexity or weight of larger libraries.
10
+
11
+ ## 🚀 Features
12
+
13
+ * **Tiny:** < 1kb gzipped.
14
+ * **Zero Dependencies:** It does one thing and does it well.
15
+ * **Agnostic:** Works with `<div>`, `<ul>`, `<table>` or any other DOM element.
16
+ * **TypeScript:** Written in JS but includes full Type definitions.
17
+
18
+ ## 📦 Installation
19
+
20
+ ```bash
21
+ npm install react-simple-virtualize
22
+ # or
23
+ yarn add react-simple-virtualize
24
+ ```
25
+
26
+ ## 💻 Usage
27
+
28
+ Here is a basic example of a list with 10,000 items:
29
+
30
+ ```jsx
31
+ import React from 'react';
32
+ import { useVirtualize } from 'react-simple-virtualize';
33
+
34
+ const MyLargeList = () => {
35
+ // 1. Setup your data
36
+ const items = Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
37
+
38
+ // 2. Define dimensions
39
+ const containerHeight = 500;
40
+ const itemHeight = 50;
41
+
42
+ // 3. Initialize the hook
43
+ const { virtualItems, totalHeight, onScroll } = useVirtualize({
44
+ itemCount: items.length,
45
+ itemHeight,
46
+ containerHeight,
47
+ overscan: 5, // Optional: Number of items to render outside viewport
48
+ });
49
+
50
+ return (
51
+ // Outer Container: Needs fixed height & overflow-y: auto
52
+ <div
53
+ onScroll={onScroll}
54
+ style={{
55
+ height: containerHeight,
56
+ overflowY: 'auto',
57
+ position: 'relative',
58
+ border: '1px solid #ccc'
59
+ }}
60
+ >
61
+ {/* Inner Container: Sets the scrollable height */}
62
+ <div style={{ height: totalHeight, position: 'relative' }}>
63
+
64
+ {/* Render only visible items */}
65
+ {virtualItems.map(({ index, offsetTop }) => (
66
+ <div
67
+ key={index}
68
+ style={{
69
+ position: 'absolute',
70
+ top: 0,
71
+ left: 0,
72
+ width: '100%',
73
+ height: itemHeight,
74
+ transform: `translateY(${offsetTop}px)`, // Crucial for positioning
75
+ display: 'flex',
76
+ alignItems: 'center',
77
+ paddingLeft: 10,
78
+ background: index % 2 === 0 ? '#fff' : '#f5f5f5'
79
+ }}
80
+ >
81
+ {items[index]}
82
+ </div>
83
+ ))}
84
+ </div>
85
+ </div>
86
+ );
87
+ };
88
+
89
+ export default MyLargeList;
90
+ ```
91
+
92
+ ## ⚙️ API Reference
93
+
94
+ ### `useVirtualize(options)`
95
+
96
+ | Option | Type | Required | Description |
97
+ | :--- | :--- | :--- | :--- |
98
+ | `itemCount` | `number` | Yes | Total number of items in the list. |
99
+ | `itemHeight` | `number` | Yes | Height of a single item in pixels. |
100
+ | `containerHeight` | `number` | Yes | Height of the visible scroll area (viewport). |
101
+ | `overscan` | `number` | No | Number of extra items to render above/below the visible area (Default: 3). |
102
+
103
+ ### Returns
104
+
105
+ | Value | Type | Description |
106
+ | :--- | :--- | :--- |
107
+ | `virtualItems` | `array` | Array of items to be rendered. Each item contains `{ index, offsetTop }`. |
108
+ | `totalHeight` | `number` | Total height of the list (used for the inner container). |
109
+ | `onScroll` | `function` | Event handler to be attached to the outer container's `onScroll`. |
110
+
111
+ ## 🗺️ Roadmap & Support
112
+
113
+ Currently, this package is optimized for **Fixed Height** lists.
114
+ I am actively working on the following features for the next major release:
115
+
116
+ - [ ] **Dynamic Height Support:** For items with variable content (chat bubbles, feeds).
117
+ - [ ] **Grid Virtualization:** Virtualizing both rows and columns.
118
+ - [ ] **Horizontal Scrolling:** Support for X-axis virtualization.
119
+
120
+ ### ☕ Support the Development
121
+
122
+ If this package saved you time or if you want to speed up the development of **Dynamic Height** support, consider buying me a coffee. It helps keep the project alive and maintained!
123
+
124
+ <a href="https://www.buymeacoffee.com/obceylan" target="_blank">
125
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" >
126
+ </a>
127
+
128
+ ## 📄 License
129
+
130
+ MIT © Ozan Batuhan Ceylan
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var t=require("react");exports.useVirtualize=function(e){var r=e.itemCount,o=e.itemHeight,a=e.containerHeight,i=e.overscan,n=void 0===i?3:i,u=t.useState(0),l=u[0],h=u[1],s=t.useMemo(function(){for(var t=Math.floor(l/o),e=Math.min(r-1,Math.floor((l+a)/o)),i=Math.max(0,t-n),u=Math.min(r-1,e+n),h=[],s=i;s<=u;s++)h.push({index:s,offsetTop:s*o});return{virtualItems:h,totalHeight:r*o}},[l,r,o,a,n]);return{virtualItems:s.virtualItems,totalHeight:s.totalHeight,onScroll:function(t){h(t.currentTarget.scrollTop)}}};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["import { useState, useMemo } from 'react';\n\nexport const useVirtualize = ({\n itemCount,\n itemHeight,\n containerHeight,\n overscan = 3\n}) => {\n // Store the current scroll position\n const [scrollTop, setScrollTop] = useState(0);\n\n // Update scroll position on scroll event\n const onScroll = (e) => {\n setScrollTop(e.currentTarget.scrollTop);\n };\n\n // Memoize calculations to prevent unnecessary re-renders\n const { virtualItems, totalHeight } = useMemo(() => {\n // 1. Calculate the visible range based on scroll position\n const rangeStart = Math.floor(scrollTop / itemHeight);\n const rangeEnd = Math.min(\n itemCount - 1,\n Math.floor((scrollTop + containerHeight) / itemHeight)\n );\n\n // 2. Add overscan (buffer) to the range for smoother scrolling\n const startIndex = Math.max(0, rangeStart - overscan);\n const endIndex = Math.min(itemCount - 1, rangeEnd + overscan);\n\n // 3. Generate the array of items to be rendered\n const virtualItems = [];\n for (let i = startIndex; i <= endIndex; i++) {\n virtualItems.push({\n index: i,\n offsetTop: i * itemHeight, // Calculate absolute position for each item\n });\n }\n\n // 4. Calculate total phantom height to maintain scrollbar size\n const totalHeight = itemCount * itemHeight;\n\n return { virtualItems, totalHeight };\n }, [scrollTop, itemCount, itemHeight, containerHeight, overscan]);\n\n return {\n virtualItems,\n totalHeight,\n onScroll,\n };\n};"],"names":["_ref","itemCount","itemHeight","containerHeight","_ref$overscan","overscan","_useState","useState","scrollTop","setScrollTop","_useMemo","useMemo","rangeStart","Math","floor","rangeEnd","min","startIndex","max","endIndex","virtualItems","i","push","index","offsetTop","totalHeight","onScroll","e","currentTarget"],"mappings":"6CAE6B,SAAHA,GAKpB,IAJJC,EAASD,EAATC,UACAC,EAAUF,EAAVE,WACAC,EAAeH,EAAfG,gBAAeC,EAAAJ,EACfK,SAAAA,OAAQ,IAAAD,EAAG,EAACA,EAGZE,EAAkCC,EAAQA,SAAC,GAApCC,EAASF,EAAEG,GAAAA,EAAYH,EAG9B,GAKAI,EAAsCC,EAAAA,QAAQ,WAc5C,IAZA,IAAMC,EAAaC,KAAKC,MAAMN,EAAYN,GACpCa,EAAWF,KAAKG,IACpBf,EAAY,EACZY,KAAKC,OAAON,EAAYL,GAAmBD,IAIvCe,EAAaJ,KAAKK,IAAI,EAAGN,EAAaP,GACtCc,EAAWN,KAAKG,IAAIf,EAAY,EAAGc,EAAWV,GAG9Ce,EAAe,GACZC,EAAIJ,EAAYI,GAAKF,EAAUE,IACtCD,EAAaE,KAAK,CAChBC,MAAOF,EACPG,UAAWH,EAAInB,IAOnB,MAAO,CAAEkB,aAAAA,EAAcK,YAFHxB,EAAYC,EAGlC,EAAG,CAACM,EAAWP,EAAWC,EAAYC,EAAiBE,IAEvD,MAAO,CACLe,aA5BkBV,EAAZU,aA6BNK,YA7B+Bf,EAAXe,YA8BpBC,SAnCe,SAACC,GAChBlB,EAAakB,EAAEC,cAAcpB,UAC/B,EAmCF"}
@@ -0,0 +1,2 @@
1
+ import{useState as t,useMemo as o}from"react";const e=({itemCount:e,itemHeight:r,containerHeight:a,overscan:i=3})=>{const[n,l]=t(0),{virtualItems:h,totalHeight:m}=o(()=>{const t=Math.floor(n/r),o=Math.min(e-1,Math.floor((n+a)/r)),l=Math.max(0,t-i),h=Math.min(e-1,o+i),m=[];for(let t=l;t<=h;t++)m.push({index:t,offsetTop:t*r});return{virtualItems:m,totalHeight:e*r}},[n,e,r,a,i]);return{virtualItems:h,totalHeight:m,onScroll:t=>{l(t.currentTarget.scrollTop)}}};export{e as useVirtualize};
2
+ //# sourceMappingURL=index.modern.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.modern.mjs","sources":["../src/index.js"],"sourcesContent":["import { useState, useMemo } from 'react';\n\nexport const useVirtualize = ({\n itemCount,\n itemHeight,\n containerHeight,\n overscan = 3\n}) => {\n // Store the current scroll position\n const [scrollTop, setScrollTop] = useState(0);\n\n // Update scroll position on scroll event\n const onScroll = (e) => {\n setScrollTop(e.currentTarget.scrollTop);\n };\n\n // Memoize calculations to prevent unnecessary re-renders\n const { virtualItems, totalHeight } = useMemo(() => {\n // 1. Calculate the visible range based on scroll position\n const rangeStart = Math.floor(scrollTop / itemHeight);\n const rangeEnd = Math.min(\n itemCount - 1,\n Math.floor((scrollTop + containerHeight) / itemHeight)\n );\n\n // 2. Add overscan (buffer) to the range for smoother scrolling\n const startIndex = Math.max(0, rangeStart - overscan);\n const endIndex = Math.min(itemCount - 1, rangeEnd + overscan);\n\n // 3. Generate the array of items to be rendered\n const virtualItems = [];\n for (let i = startIndex; i <= endIndex; i++) {\n virtualItems.push({\n index: i,\n offsetTop: i * itemHeight, // Calculate absolute position for each item\n });\n }\n\n // 4. Calculate total phantom height to maintain scrollbar size\n const totalHeight = itemCount * itemHeight;\n\n return { virtualItems, totalHeight };\n }, [scrollTop, itemCount, itemHeight, containerHeight, overscan]);\n\n return {\n virtualItems,\n totalHeight,\n onScroll,\n };\n};"],"names":["useVirtualize","itemCount","itemHeight","containerHeight","overscan","scrollTop","setScrollTop","useState","virtualItems","totalHeight","useMemo","rangeStart","Math","floor","rangeEnd","min","startIndex","max","endIndex","i","push","index","offsetTop","onScroll","e","currentTarget"],"mappings":"8CAEa,MAAAA,EAAgBA,EAC3BC,YACAC,aACAC,kBACAC,SAAAA,EAAW,MAGX,MAAOC,EAAWC,GAAgBC,EAAS,IAQrCC,aAAEA,EAAYC,YAAEA,GAAgBC,EAAQ,KAE5C,MAAMC,EAAaC,KAAKC,MAAMR,EAAYH,GACpCY,EAAWF,KAAKG,IACpBd,EAAY,EACZW,KAAKC,OAAOR,EAAYF,GAAmBD,IAIvCc,EAAaJ,KAAKK,IAAI,EAAGN,EAAaP,GACtCc,EAAWN,KAAKG,IAAId,EAAY,EAAGa,EAAWV,GAG9CI,EAAe,GACrB,IAAK,IAAIW,EAAIH,EAAYG,GAAKD,EAAUC,IACtCX,EAAaY,KAAK,CAChBC,MAAOF,EACPG,UAAWH,EAAIjB,IAOnB,MAAO,CAAEM,eAAcC,YAFHR,EAAYC,IAG/B,CAACG,EAAWJ,EAAWC,EAAYC,EAAiBC,IAEvD,MAAO,CACLI,eACAC,cACAc,SAnCgBC,IAChBlB,EAAakB,EAAEC,cAAcpB"}
@@ -0,0 +1,2 @@
1
+ import{useState as t,useMemo as o}from"react";var r=function(r){var e=r.itemCount,a=r.itemHeight,i=r.containerHeight,n=r.overscan,l=void 0===n?3:n,h=t(0),u=h[0],m=h[1],c=o(function(){for(var t=Math.floor(u/a),o=Math.min(e-1,Math.floor((u+i)/a)),r=Math.max(0,t-l),n=Math.min(e-1,o+l),h=[],m=r;m<=n;m++)h.push({index:m,offsetTop:m*a});return{virtualItems:h,totalHeight:e*a}},[u,e,a,i,l]);return{virtualItems:c.virtualItems,totalHeight:c.totalHeight,onScroll:function(t){m(t.currentTarget.scrollTop)}}};export{r as useVirtualize};
2
+ //# sourceMappingURL=index.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.module.js","sources":["../src/index.js"],"sourcesContent":["import { useState, useMemo } from 'react';\n\nexport const useVirtualize = ({\n itemCount,\n itemHeight,\n containerHeight,\n overscan = 3\n}) => {\n // Store the current scroll position\n const [scrollTop, setScrollTop] = useState(0);\n\n // Update scroll position on scroll event\n const onScroll = (e) => {\n setScrollTop(e.currentTarget.scrollTop);\n };\n\n // Memoize calculations to prevent unnecessary re-renders\n const { virtualItems, totalHeight } = useMemo(() => {\n // 1. Calculate the visible range based on scroll position\n const rangeStart = Math.floor(scrollTop / itemHeight);\n const rangeEnd = Math.min(\n itemCount - 1,\n Math.floor((scrollTop + containerHeight) / itemHeight)\n );\n\n // 2. Add overscan (buffer) to the range for smoother scrolling\n const startIndex = Math.max(0, rangeStart - overscan);\n const endIndex = Math.min(itemCount - 1, rangeEnd + overscan);\n\n // 3. Generate the array of items to be rendered\n const virtualItems = [];\n for (let i = startIndex; i <= endIndex; i++) {\n virtualItems.push({\n index: i,\n offsetTop: i * itemHeight, // Calculate absolute position for each item\n });\n }\n\n // 4. Calculate total phantom height to maintain scrollbar size\n const totalHeight = itemCount * itemHeight;\n\n return { virtualItems, totalHeight };\n }, [scrollTop, itemCount, itemHeight, containerHeight, overscan]);\n\n return {\n virtualItems,\n totalHeight,\n onScroll,\n };\n};"],"names":["useVirtualize","_ref","itemCount","itemHeight","containerHeight","_ref$overscan","overscan","_useState","useState","scrollTop","setScrollTop","_useMemo","useMemo","rangeStart","Math","floor","rangeEnd","min","startIndex","max","endIndex","virtualItems","i","push","index","offsetTop","totalHeight","onScroll","e","currentTarget"],"mappings":"8CAEa,IAAAA,EAAgB,SAAHC,GAKpB,IAJJC,EAASD,EAATC,UACAC,EAAUF,EAAVE,WACAC,EAAeH,EAAfG,gBAAeC,EAAAJ,EACfK,SAAAA,OAAQ,IAAAD,EAAG,EAACA,EAGZE,EAAkCC,EAAS,GAApCC,EAASF,EAAEG,GAAAA,EAAYH,EAG9B,GAKAI,EAAsCC,EAAQ,WAc5C,IAZA,IAAMC,EAAaC,KAAKC,MAAMN,EAAYN,GACpCa,EAAWF,KAAKG,IACpBf,EAAY,EACZY,KAAKC,OAAON,EAAYL,GAAmBD,IAIvCe,EAAaJ,KAAKK,IAAI,EAAGN,EAAaP,GACtCc,EAAWN,KAAKG,IAAIf,EAAY,EAAGc,EAAWV,GAG9Ce,EAAe,GACZC,EAAIJ,EAAYI,GAAKF,EAAUE,IACtCD,EAAaE,KAAK,CAChBC,MAAOF,EACPG,UAAWH,EAAInB,IAOnB,MAAO,CAAEkB,aAAAA,EAAcK,YAFHxB,EAAYC,EAGlC,EAAG,CAACM,EAAWP,EAAWC,EAAYC,EAAiBE,IAEvD,MAAO,CACLe,aA5BkBV,EAAZU,aA6BNK,YA7B+Bf,EAAXe,YA8BpBC,SAnCe,SAACC,GAChBlB,EAAakB,EAAEC,cAAcpB,UAC/B,EAmCF"}
@@ -0,0 +1,2 @@
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((t||self).reactSimpleVirtualize={},t.react)}(this,function(t,e){t.useVirtualize=function(t){var o=t.itemCount,i=t.itemHeight,n=t.containerHeight,r=t.overscan,a=void 0===r?3:r,u=e.useState(0),f=u[0],l=u[1],s=e.useMemo(function(){for(var t=Math.floor(f/i),e=Math.min(o-1,Math.floor((f+n)/i)),r=Math.max(0,t-a),u=Math.min(o-1,e+a),l=[],s=r;s<=u;s++)l.push({index:s,offsetTop:s*i});return{virtualItems:l,totalHeight:o*i}},[f,o,i,n,a]);return{virtualItems:s.virtualItems,totalHeight:s.totalHeight,onScroll:function(t){l(t.currentTarget.scrollTop)}}}});
2
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../src/index.js"],"sourcesContent":["import { useState, useMemo } from 'react';\n\nexport const useVirtualize = ({\n itemCount,\n itemHeight,\n containerHeight,\n overscan = 3\n}) => {\n // Store the current scroll position\n const [scrollTop, setScrollTop] = useState(0);\n\n // Update scroll position on scroll event\n const onScroll = (e) => {\n setScrollTop(e.currentTarget.scrollTop);\n };\n\n // Memoize calculations to prevent unnecessary re-renders\n const { virtualItems, totalHeight } = useMemo(() => {\n // 1. Calculate the visible range based on scroll position\n const rangeStart = Math.floor(scrollTop / itemHeight);\n const rangeEnd = Math.min(\n itemCount - 1,\n Math.floor((scrollTop + containerHeight) / itemHeight)\n );\n\n // 2. Add overscan (buffer) to the range for smoother scrolling\n const startIndex = Math.max(0, rangeStart - overscan);\n const endIndex = Math.min(itemCount - 1, rangeEnd + overscan);\n\n // 3. Generate the array of items to be rendered\n const virtualItems = [];\n for (let i = startIndex; i <= endIndex; i++) {\n virtualItems.push({\n index: i,\n offsetTop: i * itemHeight, // Calculate absolute position for each item\n });\n }\n\n // 4. Calculate total phantom height to maintain scrollbar size\n const totalHeight = itemCount * itemHeight;\n\n return { virtualItems, totalHeight };\n }, [scrollTop, itemCount, itemHeight, containerHeight, overscan]);\n\n return {\n virtualItems,\n totalHeight,\n onScroll,\n };\n};"],"names":["_ref","itemCount","itemHeight","containerHeight","_ref$overscan","overscan","_useState","useState","scrollTop","setScrollTop","_useMemo","useMemo","rangeStart","Math","floor","rangeEnd","min","startIndex","max","endIndex","virtualItems","i","push","index","offsetTop","totalHeight","onScroll","e","currentTarget"],"mappings":"kSAE6B,SAAHA,GAKpB,IAJJC,EAASD,EAATC,UACAC,EAAUF,EAAVE,WACAC,EAAeH,EAAfG,gBAAeC,EAAAJ,EACfK,SAAAA,OAAQ,IAAAD,EAAG,EAACA,EAGZE,EAAkCC,EAAQA,SAAC,GAApCC,EAASF,EAAEG,GAAAA,EAAYH,EAG9B,GAKAI,EAAsCC,EAAAA,QAAQ,WAc5C,IAZA,IAAMC,EAAaC,KAAKC,MAAMN,EAAYN,GACpCa,EAAWF,KAAKG,IACpBf,EAAY,EACZY,KAAKC,OAAON,EAAYL,GAAmBD,IAIvCe,EAAaJ,KAAKK,IAAI,EAAGN,EAAaP,GACtCc,EAAWN,KAAKG,IAAIf,EAAY,EAAGc,EAAWV,GAG9Ce,EAAe,GACZC,EAAIJ,EAAYI,GAAKF,EAAUE,IACtCD,EAAaE,KAAK,CAChBC,MAAOF,EACPG,UAAWH,EAAInB,IAOnB,MAAO,CAAEkB,aAAAA,EAAcK,YAFHxB,EAAYC,EAGlC,EAAG,CAACM,EAAWP,EAAWC,EAAYC,EAAiBE,IAEvD,MAAO,CACLe,aA5BkBV,EAAZU,aA6BNK,YA7B+Bf,EAAXe,YA8BpBC,SAnCe,SAACC,GAChBlB,EAAakB,EAAEC,cAAcpB,UAC/B,EAmCF"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "react-simple-virtualize",
3
+ "version": "0.0.1",
4
+ "description": "A lightweight, dependency-free virtualization hook for React.",
5
+ "source": "src/index.js",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.module.js",
8
+ "unpkg": "dist/index.umd.js",
9
+ "types": "src/index.d.ts",
10
+ "scripts": {
11
+ "build": "microbundle",
12
+ "dev": "microbundle watch",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "react",
17
+ "virtual-list",
18
+ "virtualization",
19
+ "scroll",
20
+ "performance",
21
+ "hook"
22
+ ],
23
+ "author": "Ozan Batuhan Ceylan",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/ozanbatuhanceylan/react-simple-virtualize"
28
+ },
29
+ "funding": {
30
+ "type": "buymeacoffee",
31
+ "url": "https://www.buymeacoffee.com/obceylan"
32
+ },
33
+ "peerDependencies": {
34
+ "react": ">=16.8.0"
35
+ },
36
+ "devDependencies": {
37
+ "microbundle": "^0.15.1"
38
+ }
39
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export function useVirtualize({ itemCount, itemHeight, containerHeight, overscan }: {
2
+ itemCount: any;
3
+ itemHeight: any;
4
+ containerHeight: any;
5
+ overscan?: number;
6
+ }): {
7
+ virtualItems: any;
8
+ totalHeight: any;
9
+ onScroll: (e: any) => void;
10
+ };
package/src/index.js ADDED
@@ -0,0 +1,50 @@
1
+ import { useState, useMemo } from 'react';
2
+
3
+ export const useVirtualize = ({
4
+ itemCount,
5
+ itemHeight,
6
+ containerHeight,
7
+ overscan = 3
8
+ }) => {
9
+ // Store the current scroll position
10
+ const [scrollTop, setScrollTop] = useState(0);
11
+
12
+ // Update scroll position on scroll event
13
+ const onScroll = (e) => {
14
+ setScrollTop(e.currentTarget.scrollTop);
15
+ };
16
+
17
+ // Memoize calculations to prevent unnecessary re-renders
18
+ const { virtualItems, totalHeight } = useMemo(() => {
19
+ // 1. Calculate the visible range based on scroll position
20
+ const rangeStart = Math.floor(scrollTop / itemHeight);
21
+ const rangeEnd = Math.min(
22
+ itemCount - 1,
23
+ Math.floor((scrollTop + containerHeight) / itemHeight)
24
+ );
25
+
26
+ // 2. Add overscan (buffer) to the range for smoother scrolling
27
+ const startIndex = Math.max(0, rangeStart - overscan);
28
+ const endIndex = Math.min(itemCount - 1, rangeEnd + overscan);
29
+
30
+ // 3. Generate the array of items to be rendered
31
+ const virtualItems = [];
32
+ for (let i = startIndex; i <= endIndex; i++) {
33
+ virtualItems.push({
34
+ index: i,
35
+ offsetTop: i * itemHeight, // Calculate absolute position for each item
36
+ });
37
+ }
38
+
39
+ // 4. Calculate total phantom height to maintain scrollbar size
40
+ const totalHeight = itemCount * itemHeight;
41
+
42
+ return { virtualItems, totalHeight };
43
+ }, [scrollTop, itemCount, itemHeight, containerHeight, overscan]);
44
+
45
+ return {
46
+ virtualItems,
47
+ totalHeight,
48
+ onScroll,
49
+ };
50
+ };