From b0c79feff7523c06c3f2137f459e73eb9e50e8fb Mon Sep 17 00:00:00 2001
From: RheeseyB <1044774+Rheeseyb@users.noreply.github.com>
Date: Thu, 12 Oct 2023 15:48:30 +0100
Subject: [PATCH] Merge the core of the escape hatch commands (#4360)
* chore(editor) Merge the core of the escape hatch commands
* chore(tests) Fix tests
* fix(editor) Converting to absolute now rounds the frame
* chore(tests) Fix tests
* chore(tests) Fix tests broken by merge
* fix(editor) prune bottom and right pins when fixing size
---
...solute-and-move-strategy.spec.browser2.tsx | 38 +++++-
.../convert-to-absolute-and-move-strategy.tsx | 37 +++---
.../reparent-property-changes.ts | 6 +-
.../components/editor/global-shortcuts.tsx | 1 -
.../components/inspector/inspector-common.ts | 108 +++++++++++++-----
.../inspector-strategies.ts | 4 +-
...emove-flex-convert-to-absolute-strategy.ts | 19 +--
.../inspector/resize-to-fit-control.tsx | 1 -
8 files changed, 140 insertions(+), 74 deletions(-)
diff --git a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.browser2.tsx
index 2b495fcbc37a..44f04cebecde 100644
--- a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.browser2.tsx
+++ b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.spec.browser2.tsx
@@ -1135,7 +1135,7 @@ describe('Convert to absolute/escape hatch', () => {
right: 200,
bottom: 320,
top: 0,
- left: 0
+ left: 0,
}}
data-uid='bbb'
data-testid='bbb'
@@ -1178,7 +1178,14 @@ describe('Convert to absolute/escape hatch', () => {
data-uid='aaa'
>
@@ -1298,7 +1305,14 @@ describe('Convert to absolute/escape hatch', () => {
data-uid='aaa'
>
@@ -1451,7 +1465,14 @@ describe('Convert to absolute/escape hatch', () => {
makeTestProjectCodeWithSnippet(
`
@@ -1512,7 +1533,14 @@ describe('Convert to absolute/escape hatch', () => {
makeTestProjectCodeWithSnippet(
`
diff --git a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx
index 03d6d78122f7..2c7899fbeeea 100644
--- a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx
+++ b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx
@@ -79,7 +79,10 @@ import type { ElementPathTrees } from '../../../../core/shared/element-path-tree
import { cssPixelLength } from '../../../inspector/common/css-utils'
import type { ProjectContentTreeRoot } from '../../../assets'
import { showToastCommand } from '../../commands/show-toast-command'
-import { sizeToVisualDimensions } from '../../../inspector/inspector-common'
+import {
+ getConvertIndividualElementToAbsoluteCommands,
+ sizeToVisualDimensions,
+} from '../../../inspector/inspector-common'
export type SetHuggingParentToFixed =
| 'set-hugging-parent-to-fixed'
@@ -426,35 +429,29 @@ function collectSetLayoutPropCommands(
intendedBounds: Array
} {
const globalFrame = MetadataUtils.getFrameInCanvasCoords(path, metadata)
- if (globalFrame != null && isFiniteRectangle(globalFrame)) {
+ const element = MetadataUtils.findElementByElementPath(metadata, path)
+ if (element != null && globalFrame != null && isFiniteRectangle(globalFrame)) {
+ const updatedGlobalFrame = offsetRect(globalFrame, dragDelta ?? zeroCanvasRect)
+ const intendedBounds: Array = [
+ { frame: updatedGlobalFrame, target: path },
+ ]
+
const newLocalFrame = MetadataUtils.getFrameRelativeToTargetContainingBlock(
targetParent ?? EP.parentPath(path),
metadata,
- globalFrame,
+ updatedGlobalFrame,
)
- const intendedBounds: Array = (() => {
- if (globalFrame == null) {
- return []
- } else {
- const updatedGlobalFrame = offsetRect(globalFrame, dragDelta ?? zeroCanvasRect)
- return [{ frame: updatedGlobalFrame, target: path }]
- }
- })()
-
if (newLocalFrame != null) {
- let commands: Array = [
- ...sizeToVisualDimensions(metadata, canvasState.startingElementPathTree, path),
- convertToAbsolute('always', path),
- ]
- const updatePinsCommands = createUpdatePinsCommands(
+ const parentFlexDirection = element.specialSizeMeasurements.parentFlexDirection
+
+ let commands: Array = getConvertIndividualElementToAbsoluteCommands(
path,
metadata,
- canvasState,
- dragDelta,
+ canvasState.startingElementPathTree,
newLocalFrame,
+ parentFlexDirection,
)
- commands.push(...updatePinsCommands)
return { commands: commands, intendedBounds: intendedBounds }
}
diff --git a/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts b/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts
index 627411b996e7..7aa8ad89e515 100644
--- a/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts
+++ b/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts
@@ -55,7 +55,7 @@ import {
stripPinsConvertToVisualSize,
} from './reparent-property-strategies'
import { assertNever } from '../../../../../core/shared/utils'
-import { flexChildProps, pruneFlexPropsCommands } from '../../../../inspector/inspector-common'
+import { flexChildProps, prunePropsCommands } from '../../../../inspector/inspector-common'
import { setCssLengthProperty } from '../../../commands/set-css-length-command'
import type { ElementPathTrees } from '../../../../../core/shared/element-path-tree'
import {
@@ -221,7 +221,7 @@ export function positionElementToCoordinatesCommands(
pathLookup: OldPathToNewPathMapping,
): CanvasCommand[] {
const basicCommands = [
- ...pruneFlexPropsCommands(flexChildProps, elementToReparent.newPath),
+ ...prunePropsCommands(flexChildProps, elementToReparent.newPath),
setCssLengthProperty(
'always',
elementToReparent.newPath,
@@ -280,7 +280,7 @@ export function positionElementToCoordinatesCommands(
}
return [
- ...pruneFlexPropsCommands(flexChildProps, targetPath),
+ ...prunePropsCommands(flexChildProps, targetPath),
setProperty('always', targetPath, PP.create('style', 'position'), 'absolute'),
setCssLengthProperty(
'always',
diff --git a/editor/src/components/editor/global-shortcuts.tsx b/editor/src/components/editor/global-shortcuts.tsx
index 26d16a9025c6..808a67d1c3aa 100644
--- a/editor/src/components/editor/global-shortcuts.tsx
+++ b/editor/src/components/editor/global-shortcuts.tsx
@@ -134,7 +134,6 @@ import {
import {
detectAreElementsFlexContainers,
nukeAllAbsolutePositioningPropsCommands,
- addPositionAbsoluteTopLeft,
sizeToVisualDimensions,
toggleResizeToFitSetToFixed,
isIntrinsicallyInlineElement,
diff --git a/editor/src/components/inspector/inspector-common.ts b/editor/src/components/inspector/inspector-common.ts
index 239d5b35ad1a..57f5da18900b 100644
--- a/editor/src/components/inspector/inspector-common.ts
+++ b/editor/src/components/inspector/inspector-common.ts
@@ -45,7 +45,12 @@ import {
setPropHugStrategies,
} from './inspector-strategies/inspector-strategies'
import { commandsForFirstApplicableStrategy } from './inspector-strategies/inspector-strategy'
-import { isFiniteRectangle, isInfinityRectangle } from '../../core/shared/math-utils'
+import {
+ isFiniteRectangle,
+ isInfinityRectangle,
+ roundRectangleToNearestWhole,
+ type LocalRectangle,
+} from '../../core/shared/math-utils'
import { inlineHtmlElements } from '../../utils/html-elements'
import { intersection } from '../../core/shared/set-utils'
import { showToastCommand } from '../canvas/commands/show-toast-command'
@@ -64,6 +69,7 @@ import {
groupConversionCommands,
} from '../canvas/canvas-strategies/strategies/group-conversion-helpers'
import { fixedSizeDimensionHandlingText } from '../text-editor/text-handling'
+import { convertToAbsolute } from '../canvas/commands/convert-to-absolute-command'
export type StartCenterEnd = 'flex-start' | 'center' | 'flex-end'
@@ -384,7 +390,9 @@ export const flexChildProps = [
styleP('flexBasis'),
]
-export function pruneFlexPropsCommands(
+const flexChildAndBottomRightProps = [...flexChildProps, styleP('bottom'), styleP('right')]
+
+export function prunePropsCommands(
props: PropertyPath[],
elementPath: ElementPath,
): Array {
@@ -420,21 +428,30 @@ export function sizeToVisualDimensions(
pathTrees: ElementPathTrees,
elementPath: ElementPath,
): Array {
- const element = MetadataUtils.findElementByElementPath(metadata, elementPath)
- if (element == null) {
+ const globalFrame = MetadataUtils.getFrameInCanvasCoords(elementPath, metadata)
+ if (globalFrame == null || isInfinityRectangle(globalFrame)) {
return []
}
- const globalFrame = MetadataUtils.getFrameInCanvasCoords(elementPath, metadata)
- if (globalFrame == null || isInfinityRectangle(globalFrame)) {
+ return sizeToDimensionsFromFrame(metadata, pathTrees, elementPath, globalFrame)
+}
+
+function sizeToDimensionsFromFrame(
+ metadata: ElementInstanceMetadataMap,
+ pathTrees: ElementPathTrees,
+ elementPath: ElementPath,
+ frame: { width: number; height: number },
+): Array {
+ const element = MetadataUtils.findElementByElementPath(metadata, elementPath)
+ if (element == null) {
return []
}
- const width = fixedSizeDimensionHandlingText(metadata, pathTrees, elementPath, globalFrame.width)
- const height = globalFrame.height
+ const width = fixedSizeDimensionHandlingText(metadata, pathTrees, elementPath, frame.width)
+ const height = frame.height
return [
- ...pruneFlexPropsCommands(flexChildProps, elementPath),
+ ...prunePropsCommands(flexChildAndBottomRightProps, elementPath),
setCssLengthProperty(
'always',
elementPath,
@@ -465,7 +482,7 @@ export const sizeToVisualDimensionsAlongAxisInstance =
const value = globalFrame[dimension]
return [
- ...pruneFlexPropsCommands(flexChildProps, elementPath),
+ ...prunePropsCommands(flexChildProps, elementPath),
setCssLengthProperty(
'always',
elementPath,
@@ -831,36 +848,27 @@ export function resizeToFillCommands(
return commands
}
-export function addPositionAbsoluteTopLeft(
- metadata: ElementInstanceMetadataMap,
+function addPositionAbsoluteTopLeft(
elementPath: ElementPath,
+ localFrame: LocalRectangle,
+ parentFlexDirection: FlexDirection | null,
): Array {
- const element = MetadataUtils.findElementByElementPath(metadata, elementPath)
- if (element == null) {
- return []
- }
-
- const left = element.specialSizeMeasurements.offset.x
- const top = element.specialSizeMeasurements.offset.y
-
- const parentFlexDirection = element.specialSizeMeasurements.parentFlexDirection
-
return [
+ convertToAbsolute('always', elementPath),
setCssLengthProperty(
'always',
elementPath,
styleP('left'),
- setExplicitCssValue(cssPixelLength(left)),
+ setExplicitCssValue(cssPixelLength(localFrame.x)),
parentFlexDirection,
),
setCssLengthProperty(
'always',
elementPath,
styleP('top'),
- setExplicitCssValue(cssPixelLength(top)),
+ setExplicitCssValue(cssPixelLength(localFrame.y)),
parentFlexDirection,
),
- setProperty('always', elementPath, styleP('position'), 'absolute'),
]
}
@@ -1120,12 +1128,54 @@ export function toggleAbsolutePositioningCommands(
: []),
]
} else {
- return [
- ...sizeToVisualDimensions(jsxMetadata, elementPathTree, elementPath),
- ...addPositionAbsoluteTopLeft(jsxMetadata, elementPath),
- ]
+ return getConvertIndividualElementToAbsoluteCommandsFromMetadata(
+ elementPath,
+ jsxMetadata,
+ elementPathTree,
+ )
}
})
return commands
}
+
+export function getConvertIndividualElementToAbsoluteCommandsFromMetadata(
+ target: ElementPath,
+ jsxMetadata: ElementInstanceMetadataMap,
+ elementPathTree: ElementPathTrees,
+): Array {
+ const localFrame = MetadataUtils.getFrame(target, jsxMetadata)
+ if (localFrame == null || isInfinityRectangle(localFrame)) {
+ return []
+ }
+
+ const element = MetadataUtils.findElementByElementPath(jsxMetadata, target)
+ if (element == null) {
+ return []
+ }
+
+ const parentFlexDirection = element.specialSizeMeasurements.parentFlexDirection
+
+ return getConvertIndividualElementToAbsoluteCommands(
+ target,
+ jsxMetadata,
+ elementPathTree,
+ localFrame,
+ parentFlexDirection,
+ )
+}
+
+export function getConvertIndividualElementToAbsoluteCommands(
+ target: ElementPath,
+ jsxMetadata: ElementInstanceMetadataMap,
+ elementPathTree: ElementPathTrees,
+ frame: LocalRectangle,
+ parentFlexDirection: FlexDirection | null,
+): Array {
+ // First round the frame so that we don't end up with half pixel values
+ const roundedFrame = roundRectangleToNearestWhole(frame)
+ return [
+ ...sizeToDimensionsFromFrame(jsxMetadata, elementPathTree, target, roundedFrame),
+ ...addPositionAbsoluteTopLeft(target, roundedFrame, parentFlexDirection),
+ ]
+}
diff --git a/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts b/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts
index c0017c5255a4..962d941de634 100644
--- a/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts
+++ b/editor/src/components/inspector/inspector-strategies/inspector-strategies.ts
@@ -4,7 +4,7 @@ import type { Axis, FlexAlignment, FlexJustifyContent } from '../inspector-commo
import {
filterKeepFlexContainers,
flexChildProps,
- pruneFlexPropsCommands,
+ prunePropsCommands,
sizeToVisualDimensions,
} from '../inspector-common'
import { MetadataUtils } from '../../../core/model/element-metadata-utils'
@@ -115,7 +115,7 @@ export const updateFlexDirectionStrategies = (
return elements.flatMap((path) => [
setProperty('always', path, PP.create('style', 'flexDirection'), flexDirection),
...MetadataUtils.getChildrenPathsOrdered(metadata, pathTrees, path).flatMap((child) => [
- ...pruneFlexPropsCommands(flexChildProps, child),
+ ...prunePropsCommands(flexChildProps, child),
...sizeToVisualDimensions(metadata, pathTrees, child),
]),
])
diff --git a/editor/src/components/inspector/inspector-strategies/remove-flex-convert-to-absolute-strategy.ts b/editor/src/components/inspector/inspector-strategies/remove-flex-convert-to-absolute-strategy.ts
index b9051904b6b9..6113772236fd 100644
--- a/editor/src/components/inspector/inspector-strategies/remove-flex-convert-to-absolute-strategy.ts
+++ b/editor/src/components/inspector/inspector-strategies/remove-flex-convert-to-absolute-strategy.ts
@@ -3,20 +3,13 @@ import { MetadataUtils } from '../../../core/model/element-metadata-utils'
import type { ElementInstanceMetadataMap } from '../../../core/shared/element-template'
import type { ElementPath } from '../../../core/shared/project-file-types'
import type { CanvasCommand } from '../../canvas/commands/commands'
-import {
- setCssLengthProperty,
- setExplicitCssValue,
-} from '../../canvas/commands/set-css-length-command'
-import { setProperty } from '../../canvas/commands/set-property-command'
-import { cssPixelLength } from '../common/css-utils'
import {
filterKeepFlexContainers,
- flexChildProps,
flexContainerProps,
nullOrNonEmpty,
- addPositionAbsoluteTopLeft,
- pruneFlexPropsCommands,
+ prunePropsCommands,
sizeToVisualDimensions,
+ getConvertIndividualElementToAbsoluteCommandsFromMetadata,
} from '../inspector-common'
import type { InspectorStrategy } from './inspector-strategy'
@@ -27,10 +20,10 @@ function removeFlexConvertToAbsoluteOne(
): Array {
const children = MetadataUtils.getChildrenPathsOrdered(metadata, pathTrees, elementPath)
return [
- ...pruneFlexPropsCommands(flexContainerProps, elementPath), // flex-related stuff is pruned
- ...children.flatMap((c) => addPositionAbsoluteTopLeft(metadata, c)), // all children are converted to absolute,
- ...children.flatMap((c) => sizeToVisualDimensions(metadata, pathTrees, c)), // with width/height based on measured dimensions
- ...children.flatMap((c) => pruneFlexPropsCommands(flexChildProps, c)),
+ ...prunePropsCommands(flexContainerProps, elementPath), // flex-related stuff is pruned
+ ...children.flatMap((c) =>
+ getConvertIndividualElementToAbsoluteCommandsFromMetadata(c, metadata, pathTrees),
+ ), // all children are converted to absolute,
...sizeToVisualDimensions(metadata, pathTrees, elementPath), // container is sized to keep its visual dimensions
]
}
diff --git a/editor/src/components/inspector/resize-to-fit-control.tsx b/editor/src/components/inspector/resize-to-fit-control.tsx
index 63e9363fd082..68a82b78cb07 100644
--- a/editor/src/components/inspector/resize-to-fit-control.tsx
+++ b/editor/src/components/inspector/resize-to-fit-control.tsx
@@ -17,7 +17,6 @@ import {
getFixedFillHugOptionsForElement,
resizeToFillCommands,
resizeToFitCommands,
- sizeToVisualDimensions,
} from './inspector-common'
import * as EP from '../../core/shared/element-path'
import { assertNever } from '../../core/shared/utils'