1+ <!DOCTYPE html>
2+ < html >
3+
4+ < head >
5+ < meta charset ="UTF-8 " />
6+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 " />
7+ < title > Gridstack.js React integration example</ title >
8+ < link rel ="stylesheet " href ="demo.css " />
9+ < script src ="../dist/gridstack-all.js "> </ script >
10+
11+ <!-- Scripts to use react inside html -->
12+ < script src ="https://unpkg.com/react@16/umd/react.production.min.js "> </ script >
13+ < script src ="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js "> </ script >
14+ < script src ="https://unpkg.com/babel-standalone@6.15.0/babel.min.js "> </ script >
15+ </ head >
16+
17+ < body >
18+
19+ < div >
20+ < h2 > Controlled stack</ h2 >
21+ < div id ="controlled-stack "> </ div >
22+ </ div >
23+
24+ </ body >
25+
26+ < script type ="text/babel ">
27+ const { useState, useEffect, useLayoutEffect, createRef, useRef } = React
28+
29+ const Item = ( { id } ) => < div > I am item: { id } </ div >
30+
31+ //
32+ // Controlled example
33+ //
34+ const ControlledStack = ( { items, addItem, removeItem, id } ) => {
35+ const refs = useRef ( { } )
36+ const gridRef = useRef ( )
37+ refs . current = { }
38+
39+ if ( Object . keys ( refs . current ) . length !== items . length ) {
40+ items . forEach ( ( { id } ) => {
41+ refs . current [ id ] = refs . current [ id ] || createRef ( )
42+ } )
43+ }
44+
45+
46+ useLayoutEffect ( ( ) => {
47+
48+ gridRef . current =
49+ // gridRef.current ||
50+ GridStack . init (
51+ {
52+ float : true ,
53+ acceptWidgets : true ,
54+ } ,
55+ `.controlled-${ id } `
56+ )
57+
58+ const grid = gridRef . current
59+
60+ grid . on ( 'removed' , ( e , el ) => {
61+ const elId = Array . isArray ( el ) ? el [ el . length - 1 ] . id : el . id ;
62+ removeItem ( elId . split ( ':' ) [ 1 ] )
63+ } )
64+
65+ grid . on ( 'dropped' , ( e , p , n ) => {
66+ console . log ( 'dropped' , p , n )
67+
68+ // Remove "placeholder" item
69+ // Gridstack creates a DOM element for dropped items, those need to be removed
70+ // as they are rendered by React
71+ grid . getGridItems ( ) . forEach ( ( item ) => {
72+ const ids = item . getAttribute ( 'gs-id' ) . split ( ':' )
73+ if ( ids [ 0 ] !== id ) {
74+ grid . removeWidget ( item , true , false ) ;
75+ }
76+ } ) ;
77+ addItem ( { id : n . id . split ( ':' ) [ 1 ] , x : n . x , y : n . y , w : n . w , h : n . h } )
78+ } )
79+
80+ grid . batchUpdate ( )
81+
82+
83+ items . forEach ( ( a ) => {
84+ // remove existing widgets
85+ if ( refs . current [ a . id ] && refs . current [ a . id ] . current ) {
86+ grid . removeWidget ( refs . current [ a . id ] . current , false , false )
87+ }
88+
89+ grid . makeWidget ( refs . current [ a . id ] . current )
90+ } )
91+ grid . batchUpdate ( false )
92+
93+
94+
95+ } , [ items ] )
96+
97+ useEffect ( ( ) => {
98+ return ( ) => {
99+ // console.log('cleanup', id)
100+ // gridRef.current.destroy(false, false)
101+ // gridRef.current = null
102+ }
103+ } )
104+
105+
106+
107+
108+ return (
109+ < div style = { { width : '100%' } } >
110+ < div className = { `grid-stack controlled-${ id } ` } >
111+ { items . map ( ( item , i ) => {
112+ // console.log('render', id, item.id)
113+ return (
114+ < div ref = { refs . current [ item . id ] } key = { `${ id } -${ item . id } ` } className = { 'grid-stack-item' } gs-id = { `${ id } :${ item . id } ` } gs-w = { item . w } gs-h = { item . h } gs-x = { item . x } gs-y = { item . y } >
115+ < div className = "grid-stack-item-content" >
116+ < Item { ...item } />
117+ </ div >
118+ </ div >
119+ )
120+ } ) }
121+ </ div >
122+ < code >
123+ < pre > { JSON . stringify ( items , null , 2 ) } </ pre >
124+ </ code >
125+ </ div >
126+ )
127+ }
128+
129+ const ControlledExample = ( ) => {
130+ const [ items1 , setItems1 ] = useState ( [ { id : 'item-1-1' , x : 0 , y : 0 , w : 2 , h : 2 } , { id : 'item-1-2' , x : 2 , y : 0 , w : 2 , h : 2 } ] )
131+ const [ items2 , setItems2 ] = useState ( [ { id : 'item-2-1' , x : 0 , y : 0 , w : 1 , h : 1 } , { id : 'item-2-2' , x : 0 , y : 1 , w : 1 , h : 1 } , { id : 'item-2-3' , x : 1 , y : 0 , w : 1 , h : 1 } ] )
132+
133+ return (
134+ < div style = { {
135+ display : 'flex'
136+ } } >
137+ < div style = { { display : 'flex' , width : '50%' } } >
138+ < ControlledStack
139+ id = 'gs1'
140+ items = { items1 }
141+ addItem = { ( item ) => {
142+ setItems1 ( [ ...items1 , item ] )
143+ } }
144+ removeItem = { ( id ) => {
145+ setItems1 ( items1 . filter ( i => i . id !== id ) )
146+ } }
147+ />
148+ </ div >
149+ < div style = { { display : 'flex' , width : '50%' } } >
150+ < ControlledStack
151+ id = 'gs2'
152+ items = { items2 }
153+ addItem = { ( item ) => {
154+ setItems2 ( [ ...items2 , item ] )
155+ } }
156+ removeItem = { ( id ) => {
157+ setItems2 ( items2 . filter ( i => i . id !== id ) )
158+ } }
159+ />
160+
161+ </ div >
162+
163+ </ div >
164+ )
165+ }
166+
167+
168+
169+ ReactDOM . render ( < ControlledExample /> , document . getElementById ( 'controlled-stack' ) )
170+
171+ </ script >
172+
173+ </ html >
0 commit comments