1+ import React from "react" ;
2+ import { DataEditorAll as DataEditor } from "../../data-editor-all.js" ;
3+ import {
4+ BeautifulWrapper ,
5+ Description ,
6+ PropName ,
7+ useMockDataGenerator ,
8+ } from "../../data-editor/stories/utils.js" ;
9+ import type { GridSelection , CompactSelectionRanges } from "../../internal/data-grid/data-grid-types.js" ;
10+ import { CompactSelection } from "../../internal/data-grid/data-grid-types.js" ;
11+ import { SimpleThemeWrapper } from "../../stories/story-utils.js" ;
12+
13+ export default {
14+ title : "Glide-Data-Grid/DataEditor Demos" ,
15+
16+ decorators : [
17+ ( Story : React . ComponentType ) => (
18+ < SimpleThemeWrapper >
19+ < Story />
20+ </ SimpleThemeWrapper >
21+ ) ,
22+ ] ,
23+ } ;
24+
25+ export const SelectionSerialization : React . VFC = ( ) => {
26+ const { cols, getCellContent } = useMockDataGenerator ( 30 , true , true ) ;
27+
28+ // Load selection from localStorage on mount
29+ const [ selection , setSelection ] = React . useState < GridSelection > ( ( ) => {
30+ try {
31+ const saved = localStorage . getItem ( "grid-selection-demo" ) ;
32+ if ( saved !== null ) {
33+ const parsed = JSON . parse ( saved ) as { columns ?: any [ ] ; rows ?: any [ ] ; current ?: any } ;
34+ return {
35+ columns : CompactSelection . create ( Array . isArray ( parsed . columns ) ? parsed . columns : [ ] ) ,
36+ rows : CompactSelection . create ( Array . isArray ( parsed . rows ) ? parsed . rows : [ ] ) ,
37+ current : parsed . current ,
38+ } ;
39+ }
40+ } catch ( error ) {
41+ console . error ( "Failed to restore selection" , error ) ;
42+ }
43+ return {
44+ columns : CompactSelection . empty ( ) ,
45+ rows : CompactSelection . empty ( ) ,
46+ } ;
47+ } ) ;
48+
49+ // Save selection to localStorage whenever it changes
50+ React . useEffect ( ( ) => {
51+ const toSave = {
52+ columns : selection . columns . items ,
53+ rows : selection . rows . items ,
54+ current : selection . current ,
55+ } ;
56+ localStorage . setItem ( "grid-selection-demo" , JSON . stringify ( toSave ) ) ;
57+ } , [ selection ] ) ;
58+
59+ const clearSelection = ( ) => {
60+ setSelection ( {
61+ columns : CompactSelection . empty ( ) ,
62+ rows : CompactSelection . empty ( ) ,
63+ current : undefined ,
64+ } ) ;
65+ } ;
66+
67+ const createExampleSelection = ( ) => {
68+ setSelection ( {
69+ columns : CompactSelection . create ( [ [ 2 , 5 ] , [ 8 , 10 ] ] ) ,
70+ rows : CompactSelection . create ( [ [ 1 , 4 ] , [ 10 , 15 ] , [ 20 , 23 ] ] ) ,
71+ current : {
72+ cell : [ 3 , 5 ] ,
73+ range : { x : 3 , y : 5 , width : 1 , height : 1 } ,
74+ rangeStack : [ ] ,
75+ } ,
76+ } ) ;
77+ } ;
78+
79+ return (
80+ < BeautifulWrapper
81+ title = "Selection Serialization"
82+ description = {
83+ < Description >
84+ This example demonstrates how to serialize and persist grid selections using the new{ " " }
85+ < PropName > CompactSelection.create()</ PropName > and < PropName > .items</ PropName > APIs.
86+ The selection is automatically saved to localStorage and restored when the page refreshes.
87+ < br />
88+ < br />
89+ < button onClick = { createExampleSelection } style = { { marginRight : 8 } } >
90+ Create Example Selection
91+ </ button >
92+ < button onClick = { clearSelection } > Clear Selection</ button >
93+ < br />
94+ < br />
95+ < strong > Current selection:</ strong > { selection . rows . length } rows, { selection . columns . length } columns
96+ < br />
97+ < strong > Persisted data:</ strong > < code > { JSON . stringify ( { columns : selection . columns . items , rows : selection . rows . items } ) } </ code >
98+ </ Description >
99+ } >
100+ < DataEditor
101+ { ...useMockDataGenerator ( 30 , false ) }
102+ columns = { cols }
103+ getCellContent = { getCellContent }
104+ rows = { 10_000 }
105+ gridSelection = { selection }
106+ onGridSelectionChange = { setSelection }
107+ rowMarkers = "both"
108+ columnSelect = "multi"
109+ />
110+ </ BeautifulWrapper >
111+ ) ;
112+ } ;
113+
114+ export const SelectionRoundTrip : React . VFC = ( ) => {
115+ const { cols, getCellContent } = useMockDataGenerator ( 30 , true , true ) ;
116+
117+ const [ originalSelection , setOriginalSelection ] = React . useState < GridSelection > ( {
118+ columns : CompactSelection . empty ( ) ,
119+ rows : CompactSelection . empty ( ) ,
120+ } ) ;
121+
122+ const [ restoredSelection , setRestoredSelection ] = React . useState < GridSelection > ( {
123+ columns : CompactSelection . empty ( ) ,
124+ rows : CompactSelection . empty ( ) ,
125+ } ) ;
126+
127+ const performRoundTrip = ( ) => {
128+ // Serialize the selection
129+ const serialized = {
130+ columns : originalSelection . columns . items ,
131+ rows : originalSelection . rows . items ,
132+ current : originalSelection . current ,
133+ } ;
134+
135+ // Simulate persistence (e.g., sending to server, storing in database)
136+ const jsonString = JSON . stringify ( serialized ) ;
137+ console . log ( "Serialized selection:" , jsonString ) ;
138+
139+ // Deserialize and restore
140+ const parsed = JSON . parse ( jsonString ) as { columns : CompactSelectionRanges ; rows : CompactSelectionRanges ; current ?: any } ;
141+ const restored = {
142+ columns : CompactSelection . create ( parsed . columns ) ,
143+ rows : CompactSelection . create ( parsed . rows ) ,
144+ current : parsed . current ,
145+ } ;
146+
147+ setRestoredSelection ( restored ) ;
148+ } ;
149+
150+ return (
151+ < BeautifulWrapper
152+ title = "Selection Round Trip"
153+ description = {
154+ < Description >
155+ This example demonstrates a complete round trip: create a selection, serialize it to JSON,
156+ then deserialize it back to a < PropName > CompactSelection</ PropName > using the new APIs.
157+ < br />
158+ < br />
159+ < button onClick = { performRoundTrip } > Perform Round Trip</ button >
160+ < br />
161+ < br />
162+ < strong > Original equals restored:</ strong > { originalSelection . columns . equals ( restoredSelection . columns ) && originalSelection . rows . equals ( restoredSelection . rows ) ? "✅ Yes" : "❌ No" }
163+ </ Description >
164+ } >
165+ < div style = { { display : "grid" , gridTemplateColumns : "1fr 1fr" , gap : 16 , height : 600 } } >
166+ < div >
167+ < h3 > Original Selection</ h3 >
168+ < DataEditor
169+ { ...useMockDataGenerator ( 30 , false ) }
170+ columns = { cols }
171+ getCellContent = { getCellContent }
172+ rows = { 1000 }
173+ gridSelection = { originalSelection }
174+ onGridSelectionChange = { setOriginalSelection }
175+ rowMarkers = "both"
176+ columnSelect = "multi"
177+ />
178+ </ div >
179+ < div >
180+ < h3 > Restored Selection</ h3 >
181+ < DataEditor
182+ { ...useMockDataGenerator ( 30 , false ) }
183+ columns = { cols }
184+ getCellContent = { getCellContent }
185+ rows = { 1000 }
186+ gridSelection = { restoredSelection }
187+ onGridSelectionChange = { setRestoredSelection }
188+ rowMarkers = "both"
189+ columnSelect = "multi"
190+ />
191+ </ div >
192+ </ div >
193+ </ BeautifulWrapper >
194+ ) ;
195+ } ;
0 commit comments