@@ -10,35 +10,68 @@ import {
10
10
useRef ,
11
11
useState ,
12
12
} from 'react' ;
13
- import type { Layout } from 'react-grid-layout' ;
13
+ // To me, the "layout" is the collection of grid items and their positions.
14
+ // To the react-grid-layout component, a "layout" is a single item's positions.
15
+ // To help with terminology, aliasing the type here, redefining it below.
16
+ import type { Layout as GridLayoutItem } from 'react-grid-layout' ;
14
17
import GridLayout from 'react-grid-layout' ;
18
+ import { useLogger } from '../../hooks/logger' ;
15
19
import { LocalStorage } from '../../lib/local-storage' ;
20
+ import type { GridItemProps } from './grid-item' ;
16
21
import { GridItem } from './grid-item' ;
17
22
23
+ // See comment above about terminology.
24
+ type Layout = Array < GridLayoutItem > ;
25
+
18
26
export interface GridProps {
27
+ /**
28
+ * The dimension for the grid.
29
+ */
19
30
dimensions : {
31
+ /**
32
+ * The max height of the grid in pixels.
33
+ */
20
34
height : number ;
35
+ /**
36
+ * The max width of the grid in pixels.
37
+ */
21
38
width : number ;
22
39
} ;
40
+ /**
41
+ * The items to display in the grid.
42
+ */
23
43
items : Array < {
24
- itemId : string ;
25
- title : string ;
26
- content : ReactNode ;
44
+ /**
45
+ * The unique identifier for the grid item.
46
+ */
47
+ itemId : GridItemProps [ 'itemId' ] ;
48
+ /**
49
+ * Text to display in the title bar of the grid item.
50
+ */
51
+ title : GridItemProps [ 'titleBarText' ] ;
52
+ /**
53
+ * Content to show inside the grid item.
54
+ */
55
+ content : GridItemProps [ 'children' ] ;
27
56
} > ;
28
57
}
29
58
30
59
export const Grid : React . FC < GridProps > = ( props : GridProps ) : ReactNode => {
31
60
const { dimensions, items } = props ;
32
61
62
+ const { logger } = useLogger ( 'grid' ) ;
63
+
64
+ const { height, width } = dimensions ;
65
+
33
66
const { euiTheme } = useEuiTheme ( ) ;
34
67
35
68
const [ gridLayoutStyles , setGridLayoutStyles ] = useState < SerializedStyles > ( ) ;
36
69
37
70
useEffect ( ( ) => {
38
71
setGridLayoutStyles ( css `
39
72
${ css ( {
40
- height : dimensions . height ,
41
- width : dimensions . width ,
73
+ height,
74
+ width,
42
75
} ) }
43
76
.react-grid-item .react-grid-placeholder {
44
77
${ css ( {
@@ -56,7 +89,7 @@ export const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
56
89
} ) }
57
90
}
58
91
` ) ;
59
- } , [ dimensions , euiTheme ] ) ;
92
+ } , [ height , width , euiTheme ] ) ;
60
93
61
94
/**
62
95
* When grid items are resized the increment is based on the the layout size.
@@ -92,24 +125,30 @@ export const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
92
125
// so that the layout always fits the window exactly.
93
126
// This allows the user to drag grid items anywhere within the window.
94
127
const [ gridMaxRows , setGridMaxRows ] = useState < number > ( 1 ) ;
95
- const [ gridMaxWidthPx , setGridMaxWidth ] = useState < number > ( dimensions . width ) ;
128
+ const [ gridMaxWidthPx , setGridMaxWidth ] = useState < number > ( width ) ;
96
129
97
130
useEffect ( ( ) => {
98
- const { height, width } = dimensions ;
99
- if ( height ) {
100
- const newMaxRows = Math . floor ( height / gridRowHeightWithMarginPx ) ;
101
- setGridMaxRows ( newMaxRows ) ;
131
+ // Note, when first rendering the UI, the received dimensions may be <= 0.
132
+ // Once things start to flesh out in the UI then true dimensions come in.
133
+ // So only adjust the grid rows/cols if we received true dimensions.
134
+ if ( height <= 0 || width <= 0 ) {
135
+ logger . debug ( 'received invalid dimensions, not resizing grid' , {
136
+ height,
137
+ width,
138
+ } ) ;
139
+ return ;
102
140
}
103
- if ( width ) {
141
+
142
+ const newMaxRows = Math . floor ( height / gridRowHeightWithMarginPx ) ;
143
+ setGridMaxRows ( newMaxRows ) ;
104
144
setGridMaxWidth ( width ) ;
105
- }
106
- } , [ dimensions , gridRowHeightWithMarginPx ] ) ;
145
+ } , [ logger , height , width , gridRowHeightWithMarginPx ] ) ;
107
146
108
147
/**
109
148
* Load the layout from storage or build a default layout.
110
149
*/
111
- const buildDefaultLayout = useCallback ( ( ) : Array < Layout > => {
112
- let layout = LocalStorage . get < Array < Layout > > ( 'layout' ) ;
150
+ const buildDefaultLayout = useCallback ( ( ) : Layout => {
151
+ let layout = LocalStorage . get < Layout > ( 'layout' ) ;
113
152
114
153
if ( layout ) {
115
154
// Discard any old layout items that are not in the grid's items list.
@@ -147,7 +186,7 @@ export const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
147
186
// and column spans for the x-index. It's weird.
148
187
let colOffset = 0 ;
149
188
150
- layout = items . map ( ( item , index ) : Layout => {
189
+ layout = items . map ( ( item , index ) : GridLayoutItem => {
151
190
// If time to move to next row then adjust the offsets.
152
191
if ( index > 0 && index % maxItemsPerRow === 0 ) {
153
192
// Only increase the offset by an item's row height (without margin)
@@ -157,7 +196,7 @@ export const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
157
196
colOffset = 0 ;
158
197
}
159
198
160
- const newItem = {
199
+ const newItem : GridLayoutItem = {
161
200
i : item . itemId , // unique identifier for the grid item
162
201
x : defaultCols * colOffset , // which column to start at, not pixels
163
202
y : rowOffset , // pixels (row # x row height px without margin)
@@ -175,10 +214,10 @@ export const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
175
214
return layout ;
176
215
} , [ items ] ) ;
177
216
178
- const [ layout , setLayout ] = useState < Array < Layout > > ( buildDefaultLayout ) ;
217
+ const [ layout , setLayout ] = useState < Layout > ( buildDefaultLayout ) ;
179
218
180
219
// Save the layout when it changes in the grid.
181
- const onLayoutChange = useCallback ( ( newLayout : Array < Layout > ) => {
220
+ const onLayoutChange = useCallback ( ( newLayout : Layout ) => {
182
221
setLayout ( newLayout ) ;
183
222
LocalStorage . set ( 'layout' , newLayout ) ;
184
223
} , [ ] ) ;
@@ -275,6 +314,8 @@ export const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
275
314
compactType = { null }
276
315
// Prevent items from overlapping or being pushed.
277
316
preventCollision = { true }
317
+ // Prevent items from being dragged over each other.
318
+ allowOverlap = { false }
278
319
// Prevent items from being dragged outside the grid.
279
320
isBounded = { true }
280
321
// Allow items to be dragged around the grid.
0 commit comments