Skip to content

Commit

Permalink
Merge branch 'fix/dont-render-when-code-ahead' of github.com:concrete…
Browse files Browse the repository at this point in the history
…-utopia/utopia into fix/dont-render-when-code-ahead
  • Loading branch information
Rheeseyb committed Jul 12, 2024
2 parents 1c41ac1 + b55430b commit aa79ac5
Show file tree
Hide file tree
Showing 27 changed files with 1,709 additions and 484 deletions.
1 change: 1 addition & 0 deletions editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
"@liveblocks/react-comments": "1.10.0",
"@liveblocks/yjs": "1.10.0",
"@popperjs/core": "2.4.4",
"@radix-ui/react-dropdown-menu": "2.1.1",
"@remix-run/react": "2.0.1",
"@remix-run/server-runtime": "2.3.1",
"@root/encoding": "1.0.1",
Expand Down
441 changes: 376 additions & 65 deletions editor/pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import { MetadataUtils } from '../../../core/model/element-metadata-utils'
import { gridRearrangeMoveStrategy } from './strategies/grid-rearrange-move-strategy'
import { resizeGridStrategy } from './strategies/resize-grid-strategy'
import { rearrangeGridSwapStrategy } from './strategies/rearrange-grid-swap-strategy'
import { gridResizeElementStrategy } from './strategies/grid-resize-element-strategy'
import { gridRearrangeMoveDuplicateStrategy } from './strategies/grid-rearrange-move-duplicate-strategy'

export type CanvasStrategyFactory = (
Expand Down Expand Up @@ -115,6 +116,7 @@ const resizeStrategies: MetaCanvasStrategy = (
flexResizeStrategy,
basicResizeStrategy,
resizeGridStrategy,
gridResizeElementStrategy,
],
)
}
Expand Down Expand Up @@ -229,7 +231,6 @@ function getInteractionTargetFromEditorState(editor: EditorState): InteractionTa
case 'textEdit':
case 'comment':
case 'follow':
case 'panels':
return targetPaths(editor.selectedViews)
default:
assertNever(editor.mode)
Expand Down Expand Up @@ -521,7 +522,7 @@ export function isResizableStrategy(canvasStrategy: CanvasStrategy): boolean {
case 'FLEX_RESIZE_BASIC':
case 'FLEX_RESIZE':
case 'BASIC_RESIZE':
// TODO add grid cell resize
case 'GRID-CELL-RESIZE-STRATEGY':
return true
default:
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,23 @@ export function gridCellHandle(params: { id: string }): GridCellHandle {
}
}

export const GridResizeEdges = ['row-start', 'row-end', 'column-start', 'column-end'] as const
export type GridResizeEdge = (typeof GridResizeEdges)[number]

export interface GridResizeHandle {
type: 'GRID_RESIZE_HANDLE'
id: string
edge: GridResizeEdge
}

export function gridResizeHandle(id: string, edge: GridResizeEdge): GridResizeHandle {
return {
type: 'GRID_RESIZE_HANDLE',
id: id,
edge: edge,
}
}

export type CanvasControlType =
| BoundingArea
| ResizeHandle
Expand All @@ -638,6 +655,7 @@ export type CanvasControlType =
| BorderRadiusResizeHandle
| GridCellHandle
| GridAxisHandle
| GridResizeHandle

export function isDragToPan(
interaction: InteractionSession | null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,35 @@ import type {
ElementInstanceMetadata,
ElementInstanceMetadataMap,
GridElementProperties,
GridPosition,
} from '../../../../core/shared/element-template'
import type { CanvasVector } from '../../../../core/shared/math-utils'
import {
offsetPoint,
rectContainsPoint,
scaleRect,
windowRectangle,
type WindowPoint,
} from '../../../../core/shared/math-utils'
import { create } from '../../../../core/shared/property-path'
import * as PP from '../../../../core/shared/property-path'
import type { CanvasCommand } from '../../commands/commands'
import { setProperty } from '../../commands/set-property-command'
import { canvasPointToWindowPoint } from '../../dom-lookup'
import type { DragInteractionData } from '../interaction-state'
import { stripNulls } from '../../../../core/shared/array-utils'
import { optionalMap } from '../../../../core/shared/optional-utils'
import type { GridCustomStrategyState } from '../canvas-strategy-types'
import type { GridCellCoordinates } from '../../controls/grid-controls'
import { gridCellCoordinates } from '../../controls/grid-controls'
import * as EP from '../../../../core/shared/element-path'
import { deleteProperties } from '../../commands/delete-properties-command'

export function getGridCellUnderMouse(mousePoint: WindowPoint) {
return getGridCellAtPoint(mousePoint, false)
export function getGridCellUnderMouse(mousePoint: WindowPoint, canvasScale: number) {
return getGridCellAtPoint(mousePoint, canvasScale, false)
}

function getGridCellUnderMouseRecursive(mousePoint: WindowPoint) {
return getGridCellAtPoint(mousePoint, true)
function getGridCellUnderMouseRecursive(mousePoint: WindowPoint, canvasScale: number) {
return getGridCellAtPoint(mousePoint, canvasScale, true)
}

const gridCellTargetIdPrefix = 'grid-cell-target-'
Expand All @@ -46,14 +51,19 @@ function isGridCellTargetId(id: string): boolean {

function getGridCellAtPoint(
windowPoint: WindowPoint,
canvasScale: number,
duplicating: boolean,
): { id: string; coordinates: GridCellCoordinates } | null {
function maybeRecursivelyFindCellAtPoint(elements: Element[]): Element | null {
// If this used during duplication, the canvas controls will be in the way and we need to traverse the children too.
for (const element of elements) {
if (isGridCellTargetId(element.id)) {
const rect = element.getBoundingClientRect()
if (rectContainsPoint(windowRectangle(rect), windowPoint)) {
const domRect = element.getBoundingClientRect()
const windowRect =
canvasScale > 1
? scaleRect(windowRectangle(domRect), canvasScale)
: windowRectangle(domRect)
if (rectContainsPoint(windowRect, windowPoint)) {
return element
}
}
Expand Down Expand Up @@ -119,7 +129,12 @@ export function runGridRearrangeMove(
canvasOffset,
)

const newTargetCell = getTargetCell(customState.targetCell, duplicating, mouseWindowPoint)
const newTargetCell = getTargetCell(
customState.targetCell,
canvasScale,
duplicating,
mouseWindowPoint,
)
if (newTargetCell == null) {
return {
commands: [],
Expand Down Expand Up @@ -162,10 +177,10 @@ export function runGridRearrangeMove(

return {
commands: [
setProperty('always', targetElement, create('style', 'gridColumnStart'), column.start),
setProperty('always', targetElement, create('style', 'gridColumnEnd'), column.end),
setProperty('always', targetElement, create('style', 'gridRowStart'), row.start),
setProperty('always', targetElement, create('style', 'gridRowEnd'), row.end),
setProperty('always', targetElement, PP.create('style', 'gridColumnStart'), column.start),
setProperty('always', targetElement, PP.create('style', 'gridColumnEnd'), column.end),
setProperty('always', targetElement, PP.create('style', 'gridRowStart'), row.start),
setProperty('always', targetElement, PP.create('style', 'gridRowEnd'), row.end),
],
targetCell: newTargetCell,
originalRootCell: rootCell,
Expand All @@ -174,15 +189,55 @@ export function runGridRearrangeMove(
}
}

export function gridPositionToValue(p: GridPosition | null | undefined): string | number | null {
if (p == null) {
return null
}
if (p === 'auto') {
return 'auto'
}

return p.numericalPosition
}

export function setGridPropsCommands(
elementPath: ElementPath,
gridProps: Partial<GridElementProperties>,
): CanvasCommand[] {
return stripNulls([
deleteProperties('always', elementPath, [
PP.create('style', 'gridColumn'),
PP.create('style', 'gridRow'),
]),
optionalMap(
(s) => setProperty('always', elementPath, PP.create('style', 'gridColumnStart'), s),
gridPositionToValue(gridProps?.gridColumnStart),
),
optionalMap(
(s) => setProperty('always', elementPath, PP.create('style', 'gridColumnEnd'), s),
gridPositionToValue(gridProps?.gridColumnEnd),
),
optionalMap(
(s) => setProperty('always', elementPath, PP.create('style', 'gridRowStart'), s),
gridPositionToValue(gridProps?.gridRowStart),
),
optionalMap(
(s) => setProperty('always', elementPath, PP.create('style', 'gridRowEnd'), s),
gridPositionToValue(gridProps?.gridRowEnd),
),
])
}

function getTargetCell(
previousTargetCell: GridCellCoordinates | null,
canvasScale: number,
duplicating: boolean,
mouseWindowPoint: WindowPoint,
): GridCellCoordinates | null {
let cell = previousTargetCell ?? null
const cellUnderMouse = duplicating
? getGridCellUnderMouseRecursive(mouseWindowPoint)
: getGridCellUnderMouse(mouseWindowPoint)
? getGridCellUnderMouseRecursive(mouseWindowPoint, canvasScale)
: getGridCellUnderMouse(mouseWindowPoint, canvasScale)
if (cellUnderMouse != null) {
cell = cellUnderMouse.coordinates
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,40 @@
import * as EP from '../../../../core/shared/element-path'
import { getRectCenter, localRectangle } from '../../../../core/shared/math-utils'
import { selectComponentsForTest } from '../../../../utils/utils.test-utils'
import CanvasActions from '../../canvas-actions'
import { GridCellTestId } from '../../controls/grid-controls'
import { mouseDragFromPointToPoint } from '../../event-helpers.test-utils'
import { renderTestEditorWithCode } from '../../ui-jsx.test-utils'
import { gridCellTargetId } from './grid-helpers'

describe('grid rearrange move strategy', () => {
it('can rearrange elements on a grid', async () => {
const editor = await renderTestEditorWithCode(ProjectCode, 'await-first-dom-report')

const elementPathToDrag = EP.fromString('sb/scene/grid/aaa')

await selectComponentsForTest(editor, [elementPathToDrag])

const sourceGridCell = editor.renderedDOM.getByTestId(GridCellTestId(elementPathToDrag))
const targetGridCell = editor.renderedDOM.getByTestId(
gridCellTargetId(EP.fromString('sb/scene/grid'), 2, 3),
)

await mouseDragFromPointToPoint(
sourceGridCell,
{
x: sourceGridCell.getBoundingClientRect().x + 10,
y: sourceGridCell.getBoundingClientRect().y + 10,
},
getRectCenter(
localRectangle({
x: targetGridCell.getBoundingClientRect().x,
y: targetGridCell.getBoundingClientRect().y,
width: targetGridCell.getBoundingClientRect().width,
height: targetGridCell.getBoundingClientRect().height,
}),
),
)
const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } = await runMoveTest({
scale: 1,
})
expect({ gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd }).toEqual({
gridColumnEnd: '7',
gridColumnStart: '3',
gridRowEnd: '4',
gridRowStart: '2',
})
})
it('can rearrange elements on a grid (zoom out)', async () => {
const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } = await runMoveTest({
scale: 0.5,
})
expect({ gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd }).toEqual({
gridColumnEnd: '7',
gridColumnStart: '3',
gridRowEnd: '4',
gridRowStart: '2',
})
})

const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } =
editor.renderedDOM.getByTestId('aaa').style
it('can rearrange elements on a grid (zoom in)', async () => {
const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } = await runMoveTest({
scale: 2,
})
expect({ gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd }).toEqual({
gridColumnEnd: '7',
gridColumnStart: '3',
Expand All @@ -46,6 +44,42 @@ describe('grid rearrange move strategy', () => {
})
})

async function runMoveTest(props: { scale: number }) {
const editor = await renderTestEditorWithCode(ProjectCode, 'await-first-dom-report')

const elementPathToDrag = EP.fromString('sb/scene/grid/aaa')

await selectComponentsForTest(editor, [elementPathToDrag])

await editor.dispatch([CanvasActions.zoom(props.scale)], true)

const sourceGridCell = editor.renderedDOM.getByTestId(GridCellTestId(elementPathToDrag))
const targetGridCell = editor.renderedDOM.getByTestId(
gridCellTargetId(EP.fromString('sb/scene/grid'), 2, 3),
)

const sourceRect = sourceGridCell.getBoundingClientRect()
const targetRect = targetGridCell.getBoundingClientRect()

await mouseDragFromPointToPoint(
sourceGridCell,
{
x: sourceRect.x * (props.scale > 1 ? props.scale : 1) + 10,
y: sourceRect.y * (props.scale > 1 ? props.scale : 1) + 10,
},
getRectCenter(
localRectangle({
x: targetRect.x * (props.scale > 1 ? props.scale : 1),
y: targetRect.y * (props.scale > 1 ? props.scale : 1),
width: targetRect.width,
height: targetRect.height,
}),
),
)

return editor.renderedDOM.getByTestId('aaa').style
}

const ProjectCode = `import * as React from 'react'
import { Scene, Storyboard, Placeholder } from 'utopia-api'
Expand Down
Loading

0 comments on commit aa79ac5

Please sign in to comment.