11'use client' ;
22
33import * as React from 'react' ;
4- import { GridSheet , buildInitialCellsFromOrigin , makeBorder } from '@gridsheet/react-core' ;
4+ import { GridSheet , buildInitialCells } from '@gridsheet/react-core' ;
55import { useSpellbook } from '@gridsheet/react-core/spellbook' ;
66
7- export default function LargeDatasetDemo ( ) {
8- const [ isLoading , setIsLoading ] = React . useState ( true ) ;
9- const [ progress , setProgress ] = React . useState ( 0 ) ;
7+ const NUM_ROWS = 200000 ;
8+ const NUM_COLS = 10 ;
9+
10+ const generateHugeData = ( ) => {
11+ const data : any [ ] [ ] = [ ] ;
12+ for ( let i = 1 ; i <= NUM_ROWS ; i ++ ) {
13+ data . push ( [
14+ i ,
15+ `Row ${ i } ` ,
16+ Math . floor ( Math . random ( ) * 10000 ) ,
17+ Math . floor ( Math . random ( ) * 10000 ) ,
18+ Math . floor ( Math . random ( ) * 10000 ) ,
19+ Math . floor ( Math . random ( ) * 10000 ) ,
20+ Math . floor ( Math . random ( ) * 10000 ) ,
21+ [ 'Alpha' , 'Beta' , 'Gamma' , 'Delta' ] [ Math . floor ( Math . random ( ) * 4 ) ] ,
22+ [ 'Active' , 'Inactive' , 'Pending' ] [ Math . floor ( Math . random ( ) * 3 ) ] ,
23+ `Note ${ i } ` ,
24+ ] ) ;
25+ }
26+ return data ;
27+ } ;
1028
29+ export default function LargeDatasetDemo ( ) {
1130 const book = useSpellbook ( ) ;
31+ const containerRef = React . useRef < HTMLDivElement > ( null ) ;
32+ const [ ready , setReady ] = React . useState ( false ) ;
33+
34+ const sheetHeight = 400 ;
35+ const sheetWidth = typeof window !== 'undefined' ? Math . min ( 800 , window . innerWidth - 60 ) : 800 ;
36+
37+ const initialCells = React . useMemo (
38+ ( ) =>
39+ buildInitialCells ( {
40+ matrices : { A1 : generateHugeData ( ) } ,
41+ cells : {
42+ A0 : { label : 'ID' } ,
43+ B0 : { label : 'Name' } ,
44+ C0 : { label : 'Value1' } ,
45+ D0 : { label : 'Value2' } ,
46+ E0 : { label : 'Value3' } ,
47+ F0 : { label : 'Value4' } ,
48+ G0 : { label : 'Value5' } ,
49+ H0 : { label : 'Group' } ,
50+ I0 : { label : 'Status' } ,
51+ J0 : { label : 'Notes' } ,
52+ } ,
53+ ensured : { numRows : NUM_ROWS , numCols : NUM_COLS } ,
54+ } ) ,
55+ [ ] ,
56+ ) ;
1257
13- // Generate large dataset efficiently
14- const generateLargeDataset = React . useCallback ( ( ) => {
15- const rows = 10000 ;
16- const cols = 100 ;
17- const cells : { [ address : string ] : any } = { } ;
18-
19- // Helper function to convert column number to letter(s)
20- const getColumnLetter = ( colNum : number ) : string => {
21- let result = '' ;
22- while ( colNum > 0 ) {
23- colNum -- ;
24- result = String . fromCharCode ( 65 + ( colNum % 26 ) ) + result ;
25- colNum = Math . floor ( colNum / 26 ) ;
26- }
27- return result ;
28- } ;
29-
30- // Generate column labels
31- for ( let col = 1 ; col <= cols ; col ++ ) {
32- const colLetter = getColumnLetter ( col ) ;
33- cells [ colLetter ] = {
34- label : `Column ${ col } ` ,
35- } ;
58+ React . useEffect ( ( ) => {
59+ const el = containerRef . current ;
60+ if ( ! el ) {
61+ return ;
3662 }
37-
38- // Generate data rows efficiently
39- const batchSize = 1000 ;
40- const totalBatches = Math . ceil ( rows / batchSize ) ;
41-
42- const generateBatch = ( batchIndex : number ) => {
43- const startRow = batchIndex * batchSize + 1 ;
44- const endRow = Math . min ( startRow + batchSize - 1 , rows ) ;
45-
46- for ( let row = startRow ; row <= endRow ; row ++ ) {
47- for ( let col = 1 ; col <= cols ; col ++ ) {
48- const colLetter = getColumnLetter ( col ) ;
49- const address = `${ colLetter } ${ row } ` ;
50-
51- // Generate different types of data based on column
52- let value : string | number ;
53- let style : any = {
54- fontSize : '11px' ,
55- padding : '2px' ,
56- ...makeBorder ( { all : '1px solid #e5e7eb' } ) ,
57- } ;
58-
59- if ( col === 1 ) {
60- // ID column
61- value = row ;
62- style = {
63- ...style ,
64- fontWeight : 'bold' ,
65- textAlign : 'center' ,
66- } ;
67- } else if ( col === 2 ) {
68- // Name column
69- const names = [ 'Alice' , 'Bob' , 'Charlie' , 'Diana' , 'Eve' , 'Frank' , 'Grace' , 'Henry' , 'Ivy' , 'Jack' ] ;
70- value = `${ names [ ( row - 1 ) % names . length ] } ${ Math . floor ( ( row - 1 ) / names . length ) + 1 } ` ;
71- style = {
72- ...style ,
73- fontWeight : '500' ,
74- } ;
75- } else if ( col === 3 ) {
76- // Department column
77- const departments = [
78- 'Engineering' ,
79- 'Marketing' ,
80- 'Sales' ,
81- 'HR' ,
82- 'Finance' ,
83- 'Operations' ,
84- 'Product' ,
85- 'Support' ,
86- ] ;
87- value = departments [ ( row - 1 ) % departments . length ] ;
88- style = {
89- ...style ,
90- textAlign : 'center' ,
91- fontSize : '10px' ,
92- } ;
93- } else if ( col === 4 ) {
94- // Salary column
95- value = Math . floor ( Math . random ( ) * 50000 ) + 30000 ;
96- style = {
97- ...style ,
98- textAlign : 'right' ,
99- fontWeight : '500' ,
100- } ;
101- } else if ( col === 5 ) {
102- // Status column
103- const statuses = [ 'Active' , 'Inactive' , 'Pending' , 'Terminated' ] ;
104- value = statuses [ ( row - 1 ) % statuses . length ] ;
105- style = {
106- ...style ,
107- textAlign : 'center' ,
108- fontSize : '10px' ,
109- } ;
110- } else if ( col <= 10 ) {
111- // Additional data columns
112- value = Math . floor ( Math . random ( ) * 1000 ) ;
113- style = {
114- ...style ,
115- textAlign : 'right' ,
116- } ;
117- } else {
118- // Generic data for remaining columns
119- value = Math . floor ( Math . random ( ) * 100 ) ;
120- style = {
121- ...style ,
122- textAlign : 'center' ,
123- } ;
124- }
125-
126- cells [ address ] = {
127- value,
128- style,
129- } ;
130- }
131- }
132-
133- // Update progress
134- const newProgress = Math . round ( ( ( batchIndex + 1 ) / totalBatches ) * 100 ) ;
135- setProgress ( newProgress ) ;
136-
137- // Schedule next batch
138- if ( batchIndex + 1 < totalBatches ) {
139- setTimeout ( ( ) => generateBatch ( batchIndex + 1 ) , 0 ) ;
140- } else {
141- setIsLoading ( false ) ;
63+ const observer = new MutationObserver ( ( ) => {
64+ if ( el . querySelector ( '.gs-initialized' ) ) {
65+ setReady ( true ) ;
66+ observer . disconnect ( ) ;
14267 }
143- } ;
144-
145- // Start batch generation
146- generateBatch ( 0 ) ;
147- return cells ;
68+ } ) ;
69+ observer . observe ( el , { attributes : true , subtree : true , attributeFilter : [ 'class' ] } ) ;
70+ // Check immediately in case already initialized
71+ if ( el . querySelector ( '.gs-initialized' ) ) {
72+ setReady ( true ) ;
73+ }
74+ return ( ) => observer . disconnect ( ) ;
14875 } , [ ] ) ;
14976
150- const [ initialCells , setInitialCells ] = React . useState < { [ address : string ] : any } > ( {
151- defaultCol : { width : 80 } ,
152- defaultRow : { height : 20 } ,
153- } ) ;
154-
155- React . useEffect ( ( ) => {
156- const cells = generateLargeDataset ( ) ;
157- setInitialCells ( cells ) ;
158- } , [ generateLargeDataset ] ) ;
159-
160- if ( isLoading ) {
161- return (
162- < div
163- style = { {
164- display : 'flex' ,
165- flexDirection : 'column' ,
166- alignItems : 'center' ,
167- justifyContent : 'center' ,
168- height : '400px' ,
169- backgroundColor : '#f8fafc' ,
170- borderRadius : '8px' ,
171- border : '1px solid #e5e7eb' ,
172- } }
173- >
174- < div style = { { fontSize : '18px' , fontWeight : 'bold' , marginBottom : '20px' , color : '#374151' } } >
175- Generating Large Dataset...
176- </ div >
177- < div
178- style = { {
179- width : '300px' ,
180- height : '20px' ,
181- backgroundColor : '#e5e7eb' ,
182- borderRadius : '10px' ,
183- overflow : 'hidden' ,
184- } }
185- >
186- < div
187- style = { {
188- width : `${ progress } %` ,
189- height : '100%' ,
190- backgroundColor : '#3b82f6' ,
191- transition : 'width 0.3s ease' ,
192- borderRadius : '10px' ,
193- } }
194- />
195- </ div >
196- < div style = { { marginTop : '10px' , fontSize : '14px' , color : '#6b7280' } } > { progress } % Complete</ div >
197- < div style = { { marginTop : '20px' , fontSize : '12px' , color : '#9ca3af' , textAlign : 'center' } } >
198- Creating 10,000 rows × 100 columns
199- < br />
200- Total: 1,000,000 cells
201- </ div >
202- </ div >
203- ) ;
204- }
205-
20677 return (
20778 < div
20879 style = { {
@@ -214,17 +85,44 @@ export default function LargeDatasetDemo() {
21485 padding : '20px' ,
21586 } }
21687 >
217- < GridSheet
218- book = { book }
219- sheetName = "large-dataset"
220- initialCells = { initialCells }
221- options = { {
222- sheetHeight : 400 ,
223- sheetWidth : typeof window !== 'undefined' ? Math . min ( 800 , window . innerWidth - 60 ) : 800 ,
224- sheetResize : 'both' ,
225- } }
226- />
88+ < div ref = { containerRef } style = { { position : 'relative' , width : sheetWidth , height : sheetHeight } } >
89+ < GridSheet
90+ book = { book }
91+ sheetName = "large-dataset"
92+ initialCells = { initialCells }
93+ options = { {
94+ sheetHeight,
95+ sheetWidth,
96+ sheetResize : 'both' ,
97+ } }
98+ />
99+ { ! ready && (
100+ < div
101+ style = { {
102+ position : 'absolute' ,
103+ inset : 0 ,
104+ background : 'rgba(255, 255, 255, 0.8)' ,
105+ display : 'flex' ,
106+ alignItems : 'center' ,
107+ justifyContent : 'center' ,
108+ zIndex : 200 ,
109+ } }
110+ >
111+ < div
112+ style = { {
113+ width : 32 ,
114+ height : 32 ,
115+ border : '3px solid #e0e0e0' ,
116+ borderTopColor : '#0077ff' ,
117+ borderRadius : '50%' ,
118+ animation : 'case8-spin 0.8s linear infinite' ,
119+ } }
120+ />
121+ </ div >
122+ ) }
123+ </ div >
227124 < style > { `
125+ @keyframes case8-spin { to { transform: rotate(360deg); } }
228126 .gs-row-odd .gs-cell { background-color: #ffffff; }
229127 .gs-row-even .gs-cell { background-color: #f0f4f8; }
230128 ` } </ style >
0 commit comments