1
1
/** @jsxRuntime classic */
2
2
/** @jsx jsx */
3
- import { sides , type Sides } from 'utopia-api/core'
4
3
import type { ElementPath } from 'utopia-shared/src/types'
5
- import {
6
- isStaticGridRepeat ,
7
- parseCSSLength ,
8
- printGridAutoOrTemplateBase ,
9
- } from '../../inspector/common/css-utils'
4
+ import { printGridAutoOrTemplateBase } from '../../inspector/common/css-utils'
10
5
import { MetadataUtils } from '../../../core/model/element-metadata-utils'
11
6
import { mapDropNulls } from '../../../core/shared/array-utils'
12
7
import * as EP from '../../../core/shared/element-path'
13
- import type { BorderWidths } from '../../../core/shared/element-template'
14
8
import { type GridAutoOrTemplateBase } from '../../../core/shared/element-template'
15
- import type { CanvasRectangle } from '../../../core/shared/math-utils'
16
9
import { assertNever } from '../../../core/shared/utils'
17
10
import { Substores , useEditorState } from '../../editor/store/store-hook'
18
11
import type {
@@ -23,7 +16,6 @@ import { controlForStrategyMemoized } from '../canvas-strategies/canvas-strategy
23
16
import type { GridResizeEdge } from '../canvas-strategies/interaction-state'
24
17
import type { EdgePosition } from '../canvas-types'
25
18
import {
26
- CanvasContainerID ,
27
19
EdgePositionBottom ,
28
20
EdgePositionLeft ,
29
21
EdgePositionRight ,
@@ -35,14 +27,8 @@ import {
35
27
GridRowColumnResizingControlsComponent ,
36
28
} from './grid-controls'
37
29
import { isEdgePositionOnSide } from '../canvas-utils'
38
- import { getFromElement } from '../direct-dom-lookups'
39
- import { applicativeSidesPxTransform , getGridContainerProperties } from '../dom-walker'
40
- import { applicative4Either , defaultEither , isRight , mapEither } from '../../../core/shared/either'
41
- import { domRectToScaledCanvasRectangle , getRoundingFn } from '../../../core/shared/dom-utils'
42
- import Utils from '../../../utils/utils'
43
30
import { useMonitorChangesToElements } from '../../../components/editor/store/store-monitor'
44
31
import { useKeepReferenceEqualityIfPossible } from '../../../utils/react-performance'
45
- import type { CSSProperties } from 'react'
46
32
import {
47
33
gridContainerIdentifier ,
48
34
gridItemIdentifier ,
@@ -51,29 +37,13 @@ import {
51
37
} from '../../editor/store/editor-state'
52
38
import { findOriginalGrid } from '../canvas-strategies/strategies/grid-helpers'
53
39
import * as React from 'react'
54
- import { addChangeCallback , removeChangeCallback } from '../observers'
40
+ import type { GridData } from './grid-measurements'
41
+ import { getGridMeasurementHelperData , useObserversToWatch } from './grid-measurements'
55
42
56
43
export const GridMeasurementHelperMap = { current : new WeakMap < HTMLElement , string > ( ) }
57
44
58
45
export const GridCellTestId = ( elementPath : ElementPath ) => `grid-cell-${ EP . toString ( elementPath ) } `
59
46
60
- function getCellsCount ( template : GridAutoOrTemplateBase | null ) : number {
61
- if ( template == null ) {
62
- return 0
63
- }
64
-
65
- switch ( template . type ) {
66
- case 'DIMENSIONS' :
67
- return template . dimensions . reduce ( ( acc , cur ) => {
68
- return acc + ( isStaticGridRepeat ( cur ) ? cur . times : 1 )
69
- } , 0 )
70
- case 'FALLBACK' :
71
- return 0
72
- default :
73
- assertNever ( template )
74
- }
75
- }
76
-
77
47
export function getNullableAutoOrTemplateBaseString (
78
48
template : GridAutoOrTemplateBase | null ,
79
49
) : string | undefined {
@@ -84,208 +54,6 @@ export function getNullableAutoOrTemplateBaseString(
84
54
}
85
55
}
86
56
87
- export type GridMeasurementHelperData = {
88
- frame : CanvasRectangle
89
- rows : number
90
- columns : number
91
- cells : number
92
- computedStyling : CSSProperties
93
- gridTemplateColumns : GridAutoOrTemplateBase | null
94
- gridTemplateRows : GridAutoOrTemplateBase | null
95
- gridTemplateColumnsFromProps : GridAutoOrTemplateBase | null
96
- gridTemplateRowsFromProps : GridAutoOrTemplateBase | null
97
- border : BorderWidths
98
- gap : number | null
99
- rowGap : number | null
100
- columnGap : number | null
101
- padding : Sides
102
- element : HTMLElement
103
- }
104
-
105
- export type ElementOrParent = 'parent' | 'element'
106
-
107
- export function getGridMeasurementHelperData (
108
- elementPath : ElementPath ,
109
- scale : number ,
110
- source : ElementOrParent ,
111
- ) : GridMeasurementHelperData | undefined {
112
- return getFromElement ( elementPath , gridMeasurementHelperDataFromElement ( scale ) , source )
113
- }
114
-
115
- function getStylingSubset ( styling : CSSStyleDeclaration ) : CSSProperties {
116
- // Fields chosen to not overlap with any others, so as to not make React complain.
117
- return {
118
- gridAutoFlow : styling . gridAutoFlow ,
119
- gridAutoColumns : styling . gridAutoColumns ,
120
- gridAutoRows : styling . gridAutoRows ,
121
- gridTemplateColumns : styling . gridTemplateColumns ,
122
- gridTemplateRows : styling . gridTemplateRows ,
123
- gridColumn : styling . gridColumn ,
124
- gridRow : styling . gridRow ,
125
- gap : styling . gap ,
126
- rowGap : styling . rowGap ,
127
- columnGap : styling . columnGap ,
128
- justifyContent : styling . justifyContent ,
129
- alignContent : styling . alignContent ,
130
- padding : styling . padding ,
131
- paddingTop : styling . paddingTop ,
132
- paddingLeft : styling . paddingLeft ,
133
- paddingBottom : styling . paddingBottom ,
134
- paddingRight : styling . paddingRight ,
135
- borderTop : styling . borderTopWidth ,
136
- borderLeft : styling . borderLeftWidth ,
137
- borderBottom : styling . borderBottomWidth ,
138
- borderRight : styling . borderRightWidth ,
139
- }
140
- }
141
-
142
- export function gridMeasurementHelperDataFromElement (
143
- scale : number ,
144
- ) : ( element : HTMLElement ) => GridMeasurementHelperData | undefined {
145
- return ( element ) => {
146
- const canvasRootContainer = document . getElementById ( CanvasContainerID )
147
- if ( canvasRootContainer == null ) {
148
- return undefined
149
- }
150
-
151
- const computedStyle = getComputedStyle ( element )
152
- const boundingRectangle = element . getBoundingClientRect ( )
153
-
154
- const computedStyling : CSSProperties = getStylingSubset ( computedStyle )
155
-
156
- const containerGridProperties = getGridContainerProperties ( computedStyle )
157
- const containerGridPropertiesFromProps = getGridContainerProperties ( element . style )
158
-
159
- const columns = getCellsCount ( containerGridProperties . gridTemplateColumns )
160
- const rows = getCellsCount ( containerGridProperties . gridTemplateRows )
161
- const borderTopWidth = parseCSSLength ( computedStyle . borderTopWidth )
162
- const borderRightWidth = parseCSSLength ( computedStyle . borderRightWidth )
163
- const borderBottomWidth = parseCSSLength ( computedStyle . borderBottomWidth )
164
- const borderLeftWidth = parseCSSLength ( computedStyle . borderLeftWidth )
165
- const border : BorderWidths = {
166
- top : isRight ( borderTopWidth ) ? borderTopWidth . value . value : 0 ,
167
- right : isRight ( borderRightWidth ) ? borderRightWidth . value . value : 0 ,
168
- bottom : isRight ( borderBottomWidth ) ? borderBottomWidth . value . value : 0 ,
169
- left : isRight ( borderLeftWidth ) ? borderLeftWidth . value . value : 0 ,
170
- }
171
- const padding = defaultEither (
172
- sides ( undefined , undefined , undefined , undefined ) ,
173
- applicative4Either (
174
- applicativeSidesPxTransform ,
175
- parseCSSLength ( computedStyle . paddingTop ) ,
176
- parseCSSLength ( computedStyle . paddingRight ) ,
177
- parseCSSLength ( computedStyle . paddingBottom ) ,
178
- parseCSSLength ( computedStyle . paddingLeft ) ,
179
- ) ,
180
- )
181
- const gap = defaultEither (
182
- null ,
183
- mapEither ( ( n ) => n . value , parseCSSLength ( computedStyle . gap ) ) ,
184
- )
185
-
186
- const rowGap = defaultEither (
187
- null ,
188
- mapEither ( ( n ) => n . value , parseCSSLength ( computedStyle . rowGap ) ) ,
189
- )
190
-
191
- const columnGap = defaultEither (
192
- null ,
193
- mapEither ( ( n ) => n . value , parseCSSLength ( computedStyle . columnGap ) ) ,
194
- )
195
-
196
- const elementRect = domRectToScaledCanvasRectangle (
197
- boundingRectangle ,
198
- 1 / scale ,
199
- getRoundingFn ( 'nearest-half' ) ,
200
- )
201
- const parentRect = domRectToScaledCanvasRectangle (
202
- canvasRootContainer . getBoundingClientRect ( ) ,
203
- 1 / scale ,
204
- getRoundingFn ( 'nearest-half' ) ,
205
- )
206
- const frame = Utils . offsetRect ( elementRect , Utils . negate ( parentRect ) )
207
-
208
- return {
209
- frame : frame ,
210
- gridTemplateColumns : containerGridProperties . gridTemplateColumns ,
211
- gridTemplateRows : containerGridProperties . gridTemplateRows ,
212
- gridTemplateColumnsFromProps : containerGridPropertiesFromProps . gridTemplateColumns ,
213
- gridTemplateRowsFromProps : containerGridPropertiesFromProps . gridTemplateRows ,
214
- border : border ,
215
- padding : padding ,
216
- gap : gap ,
217
- rowGap : rowGap ,
218
- columnGap : columnGap ,
219
- rows : rows ,
220
- columns : columns ,
221
- cells : columns * rows ,
222
- computedStyling : computedStyling ,
223
- element : element ,
224
- }
225
- }
226
- }
227
-
228
- function useObserversToWatch ( elementPathOrPaths : Array < ElementPath > | ElementPath ) : number {
229
- // Used to trigger extra renders.
230
- const [ counter , setCounter ] = React . useState ( 0 )
231
- const bumpCounter = React . useCallback ( ( ) => {
232
- setCounter ( ( value ) => value + 1 )
233
- } , [ ] )
234
-
235
- // Need to use the mount count for the callback trigger.
236
- const mountCount = useEditorState (
237
- Substores . canvas ,
238
- ( store ) => store . editor . canvas . mountCount ,
239
- 'useObserversToWatch mountCount' ,
240
- )
241
-
242
- React . useEffect ( ( ) => {
243
- // Add the change callback(s) for the element path or paths.
244
- if ( Array . isArray ( elementPathOrPaths ) ) {
245
- for ( const elementPath of elementPathOrPaths ) {
246
- addChangeCallback ( mountCount , elementPath , bumpCounter )
247
- }
248
- } else {
249
- addChangeCallback ( mountCount , elementPathOrPaths , bumpCounter )
250
- }
251
-
252
- return function cleanup ( ) {
253
- if ( Array . isArray ( elementPathOrPaths ) ) {
254
- for ( const elementPath of elementPathOrPaths ) {
255
- removeChangeCallback ( elementPath , bumpCounter )
256
- }
257
- } else {
258
- removeChangeCallback ( elementPathOrPaths , bumpCounter )
259
- }
260
- }
261
- } , [ mountCount , elementPathOrPaths , bumpCounter ] )
262
-
263
- return counter
264
- }
265
-
266
- export function useGridMeasurementHelperData (
267
- elementPath : ElementPath ,
268
- source : ElementOrParent ,
269
- ) : GridMeasurementHelperData | undefined {
270
- const scale = useEditorState (
271
- Substores . canvas ,
272
- ( store ) => store . editor . canvas . scale ,
273
- 'useGridMeasurementHelperData scale' ,
274
- )
275
-
276
- useMonitorChangesToElements ( [ elementPath ] )
277
-
278
- useObserversToWatch ( elementPath )
279
-
280
- return useKeepReferenceEqualityIfPossible (
281
- getGridMeasurementHelperData ( elementPath , scale , source ) ,
282
- )
283
- }
284
-
285
- export type GridData = GridMeasurementHelperData & {
286
- identifier : GridIdentifier
287
- }
288
-
289
57
export function useGridData ( gridIdentifiers : GridIdentifier [ ] ) : GridData [ ] {
290
58
const scale = useEditorState (
291
59
Substores . canvas ,
0 commit comments