From 055942a5523c0904b5af97c14f044186bd7706c8 Mon Sep 17 00:00:00 2001 From: Federico Ruggi <1081051+ruggi@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:54:37 +0100 Subject: [PATCH] adjust resize for spanning elements --- ...e-element-ruler-strategy.spec.browser2.tsx | 180 ++++++++++++++++++ .../grid-resize-element-ruler-strategy.ts | 40 +++- 2 files changed, 216 insertions(+), 4 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.spec.browser2.tsx index f3b6ef44b04d..153e382509cd 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.spec.browser2.tsx @@ -5,6 +5,7 @@ import { } from '../../../../utils/utils.test-utils' import { RulerMarkerColumnEndTestId, + RulerMarkerColumnStartTestId, RulerMarkerRowEndTestId, RulerMarkerRowStartTestId, } from '../../controls/grid-controls' @@ -155,6 +156,127 @@ describe('grid resize element ruler strategy', () => { expect(element.style.gridColumn).toBe('span 2') expect(element.style.gridRow).toBe('auto') }) + + describe('spans', () => { + it('can resize a flow spanning element (start, from the right)', async () => { + const renderResult = await renderTestEditorWithCode( + ProjectCodeWithSpans, + 'await-first-dom-report', + ) + + await selectComponentsForTest(renderResult, [EP.fromString('sb/grid/flow1')]) + + const control = await renderResult.renderedDOM.findByTestId(RulerMarkerColumnEndTestId) + const controlRect = control.getBoundingClientRect() + const startPoint = { x: controlRect.x + 5, y: controlRect.y + 5 } + const endPoint = { x: controlRect.x + 200, y: controlRect.y + 5 } + await mouseDownAtPoint(control, startPoint) + await mouseMoveToPoint(control, endPoint) + await mouseUpAtPoint(control, endPoint) + + const element = await renderResult.renderedDOM.findByTestId('flow1') + expect(element.style.gridColumn).toBe('span 3') + expect(element.style.gridRow).toBe('auto') + }) + + it('can resize a flow spanning element (start, from the left)', async () => { + const renderResult = await renderTestEditorWithCode( + ProjectCodeWithSpans, + 'await-first-dom-report', + ) + + await selectComponentsForTest(renderResult, [EP.fromString('sb/grid/flow1')]) + + const control = await renderResult.renderedDOM.findByTestId(RulerMarkerColumnStartTestId) + const controlRect = control.getBoundingClientRect() + const startPoint = { x: controlRect.x + 5, y: controlRect.y + 5 } + const endPoint = { x: controlRect.x + 200, y: controlRect.y + 5 } + await mouseDownAtPoint(control, startPoint) + await mouseMoveToPoint(control, endPoint) + await mouseUpAtPoint(control, endPoint) + + const element = await renderResult.renderedDOM.findByTestId('flow1') + expect(element.style.gridColumn).toBe('') + expect(element.style.gridColumnStart).toBe('') + expect(element.style.gridColumnEnd).toBe('3') + expect(element.style.gridRow).toBe('auto') + }) + + it('can resize a flow spanning element (end)', async () => { + const renderResult = await renderTestEditorWithCode( + ProjectCodeWithSpans, + 'await-first-dom-report', + ) + + await selectComponentsForTest(renderResult, [EP.fromString('sb/grid/flow2')]) + + // expand to the right + { + const control = await renderResult.renderedDOM.findByTestId(RulerMarkerColumnEndTestId) + const controlRect = control.getBoundingClientRect() + const startPoint = { x: controlRect.x + 5, y: controlRect.y + 5 } + const endPoint = { x: controlRect.x + 200, y: controlRect.y + 5 } + await mouseDownAtPoint(control, startPoint) + await mouseMoveToPoint(control, endPoint) + await mouseUpAtPoint(control, endPoint) + + const element = await renderResult.renderedDOM.findByTestId('flow2') + expect(element.style.gridColumn).toBe('2 / span 3') + expect(element.style.gridRow).toBe('auto') + } + + // shrink from the left + { + const control = await renderResult.renderedDOM.findByTestId(RulerMarkerColumnStartTestId) + const controlRect = control.getBoundingClientRect() + const startPoint = { x: controlRect.x + 5, y: controlRect.y + 5 } + const endPoint = { x: controlRect.x + 200, y: controlRect.y + 5 } + await mouseDownAtPoint(control, startPoint) + await mouseMoveToPoint(control, endPoint) + await mouseUpAtPoint(control, endPoint) + + const element = await renderResult.renderedDOM.findByTestId('flow2') + expect(element.style.gridColumn).toBe('3 / span 2') + expect(element.style.gridRow).toBe('auto') + } + + // expand back from the left + { + const control = await renderResult.renderedDOM.findByTestId(RulerMarkerColumnStartTestId) + const controlRect = control.getBoundingClientRect() + const startPoint = { x: controlRect.x + 5, y: controlRect.y + 5 } + const endPoint = { x: controlRect.x - 400, y: controlRect.y + 5 } + await mouseDownAtPoint(control, startPoint) + await mouseMoveToPoint(control, endPoint) + await mouseUpAtPoint(control, endPoint) + + const element = await renderResult.renderedDOM.findByTestId('flow2') + expect(element.style.gridColumn).toBe('1 / span 4') + expect(element.style.gridRow).toBe('auto') + } + }) + + it('can resize a pinned spanning element', async () => { + const renderResult = await renderTestEditorWithCode( + ProjectCodeWithSpans, + 'await-first-dom-report', + ) + + await selectComponentsForTest(renderResult, [EP.fromString('sb/grid/pinned')]) + + const control = await renderResult.renderedDOM.findByTestId(RulerMarkerColumnEndTestId) + const controlRect = control.getBoundingClientRect() + const startPoint = { x: controlRect.x + 5, y: controlRect.y + 5 } + const endPoint = { x: controlRect.x + 200, y: controlRect.y + 5 } + await mouseDownAtPoint(control, startPoint) + await mouseMoveToPoint(control, endPoint) + await mouseUpAtPoint(control, endPoint) + + const element = await renderResult.renderedDOM.findByTestId('pinned') + expect(element.style.gridColumn).toBe('2 / span 3') + expect(element.style.gridRow).toBe('3') + }) + }) }) const ProjectCode = ` @@ -232,3 +354,61 @@ export var storyboard = ( ) ` + +const ProjectCodeWithSpans = ` +import * as React from 'react' +import { Storyboard } from 'utopia-api' + +export var storyboard = ( + +
+
+
+
+
+ +) +` diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.ts index d23a45a82bcc..30c1fb75487a 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-ruler-strategy.ts @@ -5,7 +5,11 @@ import type { GridElementProperties, GridPositionOrSpan, } from '../../../../core/shared/element-template' -import { gridPositionValue, isGridPositionValue } from '../../../../core/shared/element-template' +import { + gridPositionValue, + isGridPositionValue, + isGridSpan, +} from '../../../../core/shared/element-template' import type { CanvasPoint, CanvasRectangle, CanvasVector } from '../../../../core/shared/math-utils' import { canvasRectangle, isInfinityRectangle } from '../../../../core/shared/math-utils' import { assertNever } from '../../../../core/shared/utils' @@ -160,8 +164,18 @@ export const gridResizeElementRulerStrategy: CanvasStrategyFactory = ( closestVertical, ) - const columnCount = getCellsCount(resizedProps.gridColumnStart, resizedProps.gridColumnEnd) - const rowCount = getCellsCount(resizedProps.gridRowStart, resizedProps.gridRowEnd) + const columnCount = getCellsCount( + resizedProps.gridColumnStart, + resizedProps.gridColumnEnd, + bounds.column, + bounds.width, + ) + const rowCount = getCellsCount( + resizedProps.gridRowStart, + resizedProps.gridRowEnd, + bounds.row, + bounds.height, + ) const normalizedGridProps: GridElementProperties = { gridColumnStart: normalizeGridElementPositionAfterResize( @@ -295,12 +309,30 @@ function getResizedElementProperties( function getCellsCount( start: GridPositionOrSpan | null, end: GridPositionOrSpan | null, + originalStart: number, + originalSize: number, ): number | null { + // start is a number if (isGridPositionValue(start) && start.numericalPosition != null) { + // end is also a number, return the difference if (isGridPositionValue(end) && end.numericalPosition != null) { return end.numericalPosition - start.numericalPosition } - return start.numericalPosition + + // end is a discrete span, recalculate the size as a shrink or an expansion of the original size + if (isGridSpan(end) && end.type === 'SPAN_NUMERIC') { + return originalSize + (originalStart - start.numericalPosition) + } } + + // start is a discrete span + if (isGridSpan(start) && start.type === 'SPAN_NUMERIC') { + // end is a number, return the max between the span size and the start position + if (isGridPositionValue(end) && end.numericalPosition != null) { + return Math.max(end.numericalPosition, start.value) - 1 + } + } + + // nothing specific found, will be handled with a separate fallback return null }