diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx new file mode 100644 index 000000000000..9712f1d1fb76 --- /dev/null +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.spec.browser2.tsx @@ -0,0 +1,261 @@ +import { matchInlineSnapshotBrowser } from '../../../../../test/karma-snapshots' +import { runDOMWalker } from '../../../editor/actions/action-creators' +import { makeTestProjectCodeWithSnippet, renderTestEditorWithCode } from '../../ui-jsx.test-utils' +import { getGlobalFramesOfGridCellsFromMetadata } from './grid-helpers' + +describe('Grids', () => { + it('can calculate global frames of grid cells', async () => { + const editor = await renderTestEditorWithCode( + makeTestProjectCodeWithSnippet(`
+
+
+
+
+
+
+
+
`), + 'await-first-dom-report', + ) + + await editor.dispatch([runDOMWalker()], true) + + // non-grids don't have cell measurements: + expect( + getGlobalFramesOfGridCellsFromMetadata( + editor.getEditorState().editor.jsxMetadata[ + 'utopia-storyboard-uid/scene-aaa/app-entity:grid/child' + ], + ), + ).toBeNull() + + // grids have cell measurements: + matchInlineSnapshotBrowser( + getGlobalFramesOfGridCellsFromMetadata( + editor.getEditorState().editor.jsxMetadata[ + 'utopia-storyboard-uid/scene-aaa/app-entity:grid' + ], + ), + `Array [ + Array [ + Object { + \"height\": 50, + \"width\": 150, + \"x\": 10, + \"y\": 10, + }, + Object { + \"height\": 50, + \"width\": 80, + \"x\": 170, + \"y\": 10, + }, + Object { + \"height\": 50, + \"width\": 119.5, + \"x\": 260, + \"y\": 10, + }, + Object { + \"height\": 50, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 10, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 70, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 70, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 70, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 70, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 163.25, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 163.25, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 163.25, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 163.25, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 256.5, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 256.5, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 256.5, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 256.5, + }, + ], + Array [ + Object { + \"height\": 83.25, + \"width\": 150, + \"x\": 10, + \"y\": 349.75, + }, + Object { + \"height\": 83.25, + \"width\": 80, + \"x\": 170, + \"y\": 349.75, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 260, + \"y\": 349.75, + }, + Object { + \"height\": 83.25, + \"width\": 119.5, + \"x\": 389.5, + \"y\": 349.75, + }, + ], +]`, + ) + }) +}) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts index 437329d52b4b..caff66fee4bd 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-helpers.ts @@ -4,6 +4,7 @@ import * as EP from '../../../../core/shared/element-path' import type { ElementInstanceMetadataMap, GridPositionValue, + GridTemplate, } from '../../../../core/shared/element-template' import { gridPositionValue, @@ -12,9 +13,14 @@ import { type GridElementProperties, type GridPosition, } from '../../../../core/shared/element-template' -import type { CanvasVector, WindowRectangle } from '../../../../core/shared/math-utils' +import type { + CanvasRectangle, + CanvasVector, + WindowRectangle, +} from '../../../../core/shared/math-utils' import { canvasPoint, + canvasRectangle, isInfinityRectangle, offsetPoint, scaleVector, @@ -40,6 +46,7 @@ import { getGridCellUnderMouseRecursive, gridCellCoordinates, } from './grid-cell-bounds' +import type { Sides } from 'utopia-api/core' export function runGridRearrangeMove( targetElement: ElementPath, @@ -604,3 +611,62 @@ function getGridPositionIndex(props: { }): number { return (props.row - 1) * props.gridTemplateColumns + props.column - 1 } + +export function getGlobalFramesOfGridCellsFromMetadata( + metadata: ElementInstanceMetadata, +): Array> | null { + return getGlobalFramesOfGridCells(metadata.specialSizeMeasurements) +} + +export function getGlobalFramesOfGridCells({ + containerGridProperties, + rowGap, + columnGap, + padding, +}: { + containerGridProperties: GridContainerProperties + rowGap: number | null + columnGap: number | null + padding: Sides +}): Array> | null { + const columnWidths = gridTemplateToNumbers(containerGridProperties.gridTemplateColumns) + + const rowHeights = gridTemplateToNumbers(containerGridProperties.gridTemplateRows) + + if (columnWidths == null || rowHeights == null) { + return null + } + + const cellRects: Array> = [] + let yOffset = padding.top ?? 0 + rowHeights.forEach((height) => { + let xOffset = padding.left ?? 0 + const rowRects: CanvasRectangle[] = [] + columnWidths.forEach((width) => { + const rect = canvasRectangle({ x: xOffset, y: yOffset, width: width, height: height }) + rowRects.push(rect) + xOffset += width + (columnGap ?? 0) + }) + cellRects.push(rowRects) + yOffset += height + (rowGap ?? 0) + }) + + return cellRects +} + +function gridTemplateToNumbers(gridTemplate: GridTemplate | null): Array | null { + if (gridTemplate?.type !== 'DIMENSIONS') { + return null + } + + const result: Array = [] + + for (const dimension of gridTemplate.dimensions) { + if (dimension.type !== 'NUMBER') { + return null + } + result.push(dimension.value.value) + } + + return result +}