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