Skip to content

Commit

Permalink
Grid reparent uses rearrange helper (#6505)
Browse files Browse the repository at this point in the history
**Description:**
Grid reparent uses the grid rearrange helper to set the grid specific
properties.

When you reparent into a grid container, moving the element to the
target cell, setting the grid control properties to support animation,
etc. is really similar to grid rearrange. Despite that, the two
strategies did not share code.

I modified the grid reparent strategy to call runGridRearrangeMove. This
automatically added animation to grid reparent, and fixed some jumping
around.

**Commit Details:** (< vv pls delete this section if's not relevant)
- `runGridRearrangeMove` has a new parameter for the grid metadata
(before that it could assume that the grid is parent of the selected
element, but during reparent this is not true)
- some of the `runGridRearrangeMove` which handles multicell elements is
not needed for grid reparent, I needed to handle that (e.g. during grid
reparent we always put the element into a single target cell, so no need
to handle the original size in cells, the offset between the dragged
cell and root cell, etc)
- Removed `getGridPositioningCommands` which is replaced by
`runGridRearrangeMove`

**Manual Tests:**
I hereby swear that:

- [x] I opened a hydrogen project and it loaded
- [x] I could navigate to various routes in Play mode
  • Loading branch information
gbalint authored Oct 9, 2024
1 parent 29c7829 commit 8314461
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,13 @@ export function runGridRearrangeMove(
selectedElement: ElementPath,
jsxMetadata: ElementInstanceMetadataMap,
interactionData: DragInteractionData,
grid: ElementInstanceMetadata,
): CanvasCommand[] {
if (interactionData.drag == null) {
return []
}

const parentGridPath = EP.parentPath(selectedElement)
const grid = MetadataUtils.findElementByElementPath(jsxMetadata, parentGridPath)

if (grid == null) {
return []
}
const isReparent = !EP.isParentOf(grid.elementPath, selectedElement)

const { gridCellGlobalFrames, containerGridProperties: gridTemplate } =
grid.specialSizeMeasurements
Expand All @@ -76,39 +72,25 @@ export function runGridRearrangeMove(
return []
}

const draggingFromCellCoords = getClosestGridCellToPoint(
gridCellGlobalFrames,
interactionData.dragStart,
)?.gridCellCoordinates
if (draggingFromCellCoords == null) {
const originalElementGridConfiguration = isReparent
? {
originalElementMetadata: null,
originalCellBounds: { width: 1, height: 1 }, //when reparenting, we just put it in a single cell
mouseCellPosInOriginalElement: { row: 0, column: 0 },
}
: getOriginalElementGridConfiguration(
gridCellGlobalFrames,
interactionData,
jsxMetadata,
selectedElement,
grid,
)
if (originalElementGridConfiguration == null) {
return []
}

const originalElementMetadata = MetadataUtils.findElementByElementPath(
jsxMetadata,
selectedElement,
)
if (originalElementMetadata == null) {
return []
}

// measured cell coord bounds on the canvas, this is the default when the cell position is not explicitly set
const originalElementCellCoordsOnCanvas = getGridChildCellCoordBoundsFromCanvas(
originalElementMetadata,
grid,
)

// get the bounds from the props, or the canvas, or just default to the cell of the starting mouse position
const originalCellBounds = getGridChildCellCoordBoundsFromProps(
originalElementMetadata,
originalElementCellCoordsOnCanvas ?? draggingFromCellCoords,
)

// the cell position of the mouse relative to the original element (we have to keep this offset while dragging)
const mouseCellPosInOriginalElement = getCellCoordsDelta(
draggingFromCellCoords,
originalCellBounds,
)
const { originalElementMetadata, originalCellBounds, mouseCellPosInOriginalElement } =
originalElementGridConfiguration

// get the new adjusted row
const row = targetCellCoords.row - mouseCellPosInOriginalElement.row
Expand All @@ -135,7 +117,7 @@ export function runGridRearrangeMove(
})

// The siblings of the grid element being moved
const siblings = MetadataUtils.getChildrenUnordered(jsxMetadata, EP.parentPath(selectedElement))
const siblings = MetadataUtils.getChildrenUnordered(jsxMetadata, grid.elementPath)
.filter((s) => !EP.pathsEqual(s.elementPath, selectedElement))
.map(
(s, index): SortableGridElementProperties => ({
Expand Down Expand Up @@ -165,15 +147,18 @@ export function runGridRearrangeMove(
EP.pathsEqual(selectedElement, s.path),
)

const moveType = getGridMoveType({
originalElementMetadata: originalElementMetadata,
possiblyReorderIndex: possiblyReorderIndex,
cellsSortedByPosition: cellsSortedByPosition,
})
const moveType =
originalElementMetadata == null
? 'rearrange'
: getGridMoveType({
originalElementMetadata: originalElementMetadata,
possiblyReorderIndex: possiblyReorderIndex,
cellsSortedByPosition: cellsSortedByPosition,
})

const updateGridControlsCommand = showGridControls(
'mid-interaction',
parentGridPath,
grid.elementPath,
targetCellData?.gridCellCoordinates ?? null,
gridCellCoordinates(row, column),
)
Expand Down Expand Up @@ -768,3 +753,51 @@ export function getMetadataWithGridCellBounds(
customStrategyState: null,
}
}

function getOriginalElementGridConfiguration(
gridCellGlobalFrames: GridCellGlobalFrames,
interactionData: DragInteractionData,
jsxMetadata: ElementInstanceMetadataMap,
selectedElement: ElementPath,
grid: ElementInstanceMetadata,
) {
const draggingFromCellCoords = getClosestGridCellToPoint(
gridCellGlobalFrames,
interactionData.dragStart,
)?.gridCellCoordinates
if (draggingFromCellCoords == null) {
return null
}

const originalElementMetadata = MetadataUtils.findElementByElementPath(
jsxMetadata,
selectedElement,
)
if (originalElementMetadata == null) {
return null
}

// measured cell coord bounds on the canvas, this is the default when the cell position is not explicitly set
const originalElementCellCoordsOnCanvas = getGridChildCellCoordBoundsFromCanvas(
originalElementMetadata,
grid,
)

// get the bounds from the props, or the canvas, or just default to the cell of the starting mouse position
const originalCellBounds = getGridChildCellCoordBoundsFromProps(
originalElementMetadata,
originalElementCellCoordsOnCanvas ?? draggingFromCellCoords,
)

// the cell position of the mouse relative to the original element (we have to keep this offset while dragging)
const mouseCellPosInOriginalElement = getCellCoordsDelta(
draggingFromCellCoords,
originalCellBounds,
)

return {
originalElementMetadata,
originalCellBounds,
mouseCellPosInOriginalElement,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,20 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = (

const targetElement = EP.appendToPath(EP.parentPath(selectedElement), newUid)

const grid = MetadataUtils.findElementByElementPath(
canvasState.startingMetadata,
EP.parentPath(selectedElement),
)
if (grid == null) {
return emptyStrategyApplicationResult
}

const moveCommands = runGridRearrangeMove(
targetElement,
selectedElement,
canvasState.startingMetadata,
interactionSession.interactionData,
grid,
)
if (moveCommands.length === 0) {
return emptyStrategyApplicationResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,20 @@ import {
} from '../../commands/set-property-command'
import type { CanvasStrategyFactory } from '../canvas-strategies'
import { onlyFitWhenDraggingThisControl } from '../canvas-strategies'
import type {
ControlWithProps,
CustomStrategyState,
CustomStrategyStatePatch,
InteractionCanvasState,
InteractionLifecycle,
} from '../canvas-strategy-types'
import type { ControlWithProps, InteractionCanvasState } from '../canvas-strategy-types'
import {
getTargetPathsFromInteractionTarget,
emptyStrategyApplicationResult,
strategyApplicationResult,
} from '../canvas-strategy-types'
import type { DragInteractionData, InteractionSession } from '../interaction-state'
import { runGridRearrangeMove } from './grid-helpers'
import type { CanvasRectangle } from '../../../../core/shared/math-utils'
import { isInfinityRectangle, offsetPoint } from '../../../../core/shared/math-utils'
import { findReparentStrategies } from './reparent-helpers/reparent-strategy-helpers'
import { applyAbsoluteReparent, controlsForAbsoluteReparent } from './absolute-reparent-strategy'
import { isInfinityRectangle } from '../../../../core/shared/math-utils'
import type { CanvasCommand } from '../../commands/commands'
import { applyStaticReparent, controlsForStaticReparent } from './reparent-as-static-strategy'
import type { FindReparentStrategyResult } from './reparent-helpers/reparent-strategy-parent-lookup'
import { applyGridReparent, controlsForGridReparent } from './grid-reparent-strategy'
import { assertNever } from '../../../../core/shared/utils'

export const gridRearrangeMoveStrategy: CanvasStrategyFactory = (
canvasState: InteractionCanvasState,
interactionSession: InteractionSession | null,
customState: CustomStrategyState,
) => {
const selectedElements = getTargetPathsFromInteractionTarget(canvasState.interactionTarget)
if (
Expand Down Expand Up @@ -129,7 +115,7 @@ export const gridRearrangeMoveStrategy: CanvasStrategyFactory = (
),
]

const { commands, patch, elementsToRerender } = getCommandsAndPatchForGridRearrange(
const { commands, elementsToRerender } = getCommandsAndPatchForGridRearrange(
canvasState,
interactionSession.interactionData,
selectedElement,
Expand All @@ -142,7 +128,6 @@ export const gridRearrangeMoveStrategy: CanvasStrategyFactory = (
return strategyApplicationResult(
[...midInteractionCommands, ...onCompleteCommands, ...commands],
elementsToRerender,
patch,
)
},
}
Expand All @@ -154,23 +139,30 @@ function getCommandsAndPatchForGridRearrange(
selectedElement: ElementPath,
): {
commands: CanvasCommand[]
patch: CustomStrategyStatePatch
elementsToRerender: ElementPath[]
} {
if (interactionData.drag == null) {
return { commands: [], patch: {}, elementsToRerender: [] }
return { commands: [], elementsToRerender: [] }
}

const grid = MetadataUtils.findElementByElementPath(
canvasState.startingMetadata,
EP.parentPath(selectedElement),
)
if (grid == null) {
return { commands: [], elementsToRerender: [] }
}

const commands = runGridRearrangeMove(
selectedElement,
selectedElement,
canvasState.startingMetadata,
interactionData,
grid,
)

return {
commands: commands,
patch: {},
elementsToRerender: [EP.parentPath(selectedElement)],
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { mapDropNulls } from '../../../../core/shared/array-utils'
import * as EP from '../../../../core/shared/element-path'
import type { ElementPathTrees } from '../../../../core/shared/element-path-tree'
import {
gridPositionValue,
type ElementInstanceMetadata,
type ElementInstanceMetadataMap,
} from '../../../../core/shared/element-template'
import type { CanvasRectangle } from '../../../../core/shared/math-utils'
import { canvasVector, isInfinityRectangle, offsetPoint } from '../../../../core/shared/math-utils'
import { isInfinityRectangle } from '../../../../core/shared/math-utils'
import type { ElementPath } from '../../../../core/shared/project-file-types'
import * as PP from '../../../../core/shared/property-path'
import type { AllElementProps } from '../../../editor/store/editor-state'
Expand Down Expand Up @@ -39,13 +39,12 @@ import {
import type { DragInteractionData, InteractionSession, UpdatedPathMap } from '../interaction-state'
import { honoursPropsPosition, shouldKeepMovingDraggedGroupChildren } from './absolute-utils'
import { replaceFragmentLikePathsWithTheirChildrenRecursive } from './fragment-like-helpers'
import { getMetadataWithGridCellBounds, setGridPropsCommands } from './grid-helpers'
import { getMetadataWithGridCellBounds, runGridRearrangeMove } from './grid-helpers'
import { ifAllowedToReparent, isAllowedToReparent } from './reparent-helpers/reparent-helpers'
import { removeAbsolutePositioningProps } from './reparent-helpers/reparent-property-changes'
import type { ReparentTarget } from './reparent-helpers/reparent-strategy-helpers'
import { getReparentOutcome, pathToReparent } from './reparent-utils'
import { flattenSelection } from './shared-move-strategies-helpers'
import { getClosestGridCellToPointFromMetadata, type GridCellCoordinates } from './grid-cell-bounds'

export function gridReparentStrategy(
reparentTarget: ReparentTarget,
Expand Down Expand Up @@ -190,16 +189,6 @@ export function applyGridReparent(
return emptyStrategyApplicationResult
}

const mousePos = offsetPoint(
interactionData.dragStart,
interactionData.drag ?? canvasVector({ x: 0, y: 0 }),
)

const targetCellData = getClosestGridCellToPointFromMetadata(grid, mousePos)

if (targetCellData == null) {
return strategyApplicationResult([], [newParent.intendedParentPath])
}
const outcomes = mapDropNulls(
(selectedElement) =>
gridReparentCommands(
Expand All @@ -211,7 +200,8 @@ export function applyGridReparent(
nodeModules,
selectedElement,
newParent,
targetCellData.gridCellCoordinates,
interactionData,
grid,
),
selectedElements,
)
Expand Down Expand Up @@ -253,12 +243,6 @@ export function applyGridReparent(
gridContainerCommands,
updateSelectedViews('always', newPaths),
setCursorCommand(CSSCursor.Reparent),
showGridControls(
'mid-interaction',
reparentTarget.newParent.intendedParentPath,
targetCellData.gridCellCoordinates,
null,
),
],
elementsToRerender,
customStrategyStatePatch,
Expand All @@ -268,35 +252,6 @@ export function applyGridReparent(
}
}

function getGridPositioningCommands(
jsxMetadata: ElementInstanceMetadataMap,
hoveredCoordinates: GridCellCoordinates,
{
parentPath,
target,
}: {
parentPath: ElementPath
target: ElementPath
},
) {
const containerMetadata = MetadataUtils.findElementByElementPath(jsxMetadata, parentPath)
if (containerMetadata == null) {
return null
}
const { column, row } = hoveredCoordinates

const gridTemplate = containerMetadata.specialSizeMeasurements.containerGridProperties

const gridPropsCommands = setGridPropsCommands(target, gridTemplate, {
gridColumnStart: gridPositionValue(column),
gridColumnEnd: gridPositionValue(column),
gridRowEnd: gridPositionValue(row),
gridRowStart: gridPositionValue(row),
})

return gridPropsCommands
}

function gridReparentCommands(
jsxMetadata: ElementInstanceMetadataMap,
tree: ElementPathTrees,
Expand All @@ -306,7 +261,8 @@ function gridReparentCommands(
nodeModules: NodeModules,
target: ElementPath,
newParent: InsertionPath,
hoveredCoordinates: GridCellCoordinates,
interactionData: DragInteractionData,
grid: ElementInstanceMetadata,
) {
const reparentResult = getReparentOutcome(
jsxMetadata,
Expand All @@ -324,11 +280,7 @@ function gridReparentCommands(
if (reparentResult == null) {
return null
}

const gridPropsCommands = getGridPositioningCommands(jsxMetadata, hoveredCoordinates, {
parentPath: newParent.intendedParentPath,
target: target,
})
const gridPropsCommands = runGridRearrangeMove(target, target, jsxMetadata, interactionData, grid)

if (gridPropsCommands == null) {
return null
Expand Down

0 comments on commit 8314461

Please sign in to comment.