From 0c140fb00e73c745a68e32f1c68423589fc3d75d Mon Sep 17 00:00:00 2001 From: Sean Parsons <217400+seanparsons@users.noreply.github.com> Date: Wed, 4 Oct 2023 14:43:10 +0100 Subject: [PATCH] feature(groups) Convert group child percentage pins to pixel based pins. (#4314) - Added `whenReplacingPercentageValues` property to `SetCssLengthProperty`. - `runSetCssLengthProperty` now adds an appropriate toast when replacing a percentage based property and when it is instructed to warn in this particular case. - `setElementPins` now replaces the children's pin values with pixel based ones in all cases regardless of what was there before. - `runPushIntendedBoundsAndUpdateGroups` ensures that any toasts are carried forward in the editor state patch. - The patching part of `runShowToastCommand` has been extracted into a utility function `addToastPatch`. --- .../strategies/groups.spec.browser2.tsx | 14 +++- ...ard-absolute-move-resize.spec.browser2.tsx | 4 +- ...tended-bounds-and-update-groups-command.ts | 31 +++++--- .../canvas/commands/set-css-length-command.ts | 35 ++++++++- .../canvas/commands/show-toast-command.ts | 13 +++- .../editor/shortcuts.spec.browser2.tsx | 76 +++++++++++++++++++ 6 files changed, 153 insertions(+), 20 deletions(-) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/groups.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/groups.spec.browser2.tsx index eb60781446c7..27200ab719ea 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/groups.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/groups.spec.browser2.tsx @@ -32,6 +32,7 @@ import { resizeElement } from './absolute-resize.test-utils' import { changeInspectorNumberControl } from '../../../inspector/common/inspector.test-utils' import { ParentOutlinesTestIdSuffix } from '../../controls/parent-outlines' import { ParentBoundsTestIdSuffix } from '../../controls/parent-bounds' +import { safeIndex } from '../../../../core/shared/array-utils' const GroupPath = `${BakedInStoryboardUID}/${TestSceneUID}/${TestAppUID}:root-div/group` @@ -2156,6 +2157,11 @@ describe('Groups behaviors', () => { await selectComponentsForTest(editor, [fromString(GroupPath)]) await resizeElement(editor, { x: 100, y: 50 }, EdgePositionBottomRight, emptyModifiers) + const toasts = editor.getEditorState().editor.toasts + expect(toasts).toHaveLength(1) + const firstToast = safeIndex(toasts, 0) + expect(firstToast?.id).toEqual('percentage-pin-replaced') + expect(groupDiv.style.width).toBe('300px') expect(groupDiv.style.height).toBe('300px') @@ -2178,8 +2184,8 @@ describe('Groups behaviors', () => { assertStylePropsSet(editor, `${GroupPath}/child-2`, { left: 150, top: 120, - width: '50%', - height: '60%', + width: 150, + height: 180, right: undefined, bottom: undefined, }) @@ -2212,8 +2218,8 @@ describe('Groups behaviors', () => { assertStylePropsSet(editor, `${GroupPath}/child-2`, { left: 175, top: 140, - width: '50%', - height: '60%', + width: 175, + height: 210, right: undefined, bottom: undefined, }) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-resize.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-resize.spec.browser2.tsx index f47972be72f9..383d8d60170e 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-resize.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/keyboard-absolute-move-resize.spec.browser2.tsx @@ -265,7 +265,7 @@ describe('Keyboard Absolute Resize E2E', () => { }) }) - it('keeps trueuing up groups as directions change', async () => { + it('keeps trueing up groups as directions change', async () => { const renderResult = await renderTestEditorWithCode( formatTestProjectCode( makeTestProjectCodeWithSnippet(` @@ -349,7 +349,7 @@ describe('Keyboard Absolute Resize E2E', () => { >
= ( let propsToUpdate: Array = [] + let percentageValueWasReplaced: boolean = false + const parsePercentResult = parseCSSPercent(simpleValueResult.value) if ( isRight(parsePercentResult) && @@ -146,6 +153,13 @@ export const runSetCssLengthProperty: CommandFunction = ( ? command.value.value : cssPixelLength(command.value.valuePx) + if ( + command.whenReplacingPercentageValues === 'warn-about-replacement' && + isRight(parsePercentResult) + ) { + percentageValueWasReplaced = true + } + const printedValue = printCSSNumberOrKeyword(newCssValue, 'px') propsToUpdate.push({ @@ -161,8 +175,25 @@ export const runSetCssLengthProperty: CommandFunction = ( propsToUpdate, ) + // Always include the property update patch, but potentially also include a warning + // that a percentage based property was replaced with a pixel based one. + let editorStatePatches: Array = [propertyUpdatePatch] + if (percentageValueWasReplaced) { + editorStatePatches.push( + addToastPatch( + editorStateWithPropsDeleted.toasts, + notice( + 'One or more percentage based style properties were replaced with a pixel based one.', + 'INFO', + false, + 'percentage-pin-replaced', + ), + ), + ) + } + return { - editorStatePatches: [propertyUpdatePatch], + editorStatePatches: editorStatePatches, commandDescription: `Set Css Length Prop: ${EP.toUid(command.target)}/${PP.toString( command.property, )} by ${ diff --git a/editor/src/components/canvas/commands/show-toast-command.ts b/editor/src/components/canvas/commands/show-toast-command.ts index 21e1e81c897e..004b79a6b8bb 100644 --- a/editor/src/components/canvas/commands/show-toast-command.ts +++ b/editor/src/components/canvas/commands/show-toast-command.ts @@ -1,6 +1,6 @@ import type { Notice, NoticeLevel } from '../../common/notice' import { notice } from '../../common/notice' -import type { EditorState } from '../../editor/store/editor-state' +import type { EditorState, EditorStatePatch } from '../../editor/store/editor-state' import type { InteractionLifecycle } from '../canvas-strategies/canvas-strategy-types' import type { CommandFunctionResult, WhenToRun } from './commands' @@ -22,6 +22,14 @@ export function showToastCommand( } } +export function addToastPatch( + currentToasts: ReadonlyArray, + noticeToAdd: Notice, +): EditorStatePatch { + const updatedToasts = [...currentToasts.filter((t) => t.id !== noticeToAdd.id), noticeToAdd] + return { toasts: { $set: updatedToasts } } +} + export function runShowToastCommand( editorState: EditorState, command: ShowToastCommand, @@ -34,9 +42,8 @@ export function runShowToastCommand( } } - const toasts = [...editorState.toasts.filter((t) => t.id !== command.notice.id), command.notice] return { commandDescription: 'Show a toast', - editorStatePatches: [{ toasts: { $set: toasts } }], + editorStatePatches: [addToastPatch(editorState.toasts, command.notice)], } } diff --git a/editor/src/components/editor/shortcuts.spec.browser2.tsx b/editor/src/components/editor/shortcuts.spec.browser2.tsx index 683ccc50dc1d..dc9190d9954f 100644 --- a/editor/src/components/editor/shortcuts.spec.browser2.tsx +++ b/editor/src/components/editor/shortcuts.spec.browser2.tsx @@ -1,3 +1,4 @@ +import { safeIndex } from '../../core/shared/array-utils' import { BakedInStoryboardUID, BakedInStoryboardVariableName } from '../../core/model/scene-utils' import * as EP from '../../core/shared/element-path' import type { CanvasRectangle } from '../../core/shared/math-utils' @@ -1263,6 +1264,81 @@ describe('group selection', () => { ) }) + it('wraps selected elements with percentage dimensions in a Group', async () => { + const renderResult = await renderTestEditorWithCode( + makeTestProjectCodeWithSnippet( + `
+
+
+
`, + ), + 'await-first-dom-report', + ) + + await selectComponentsForTest(renderResult, [ + EP.fromString(`${BakedInStoryboardUID}/${TestSceneUID}/${TestAppUID}:container/aaa`), + EP.fromString(`${BakedInStoryboardUID}/${TestSceneUID}/${TestAppUID}:container/bbb`), + ]) + + await expectSingleUndo2Saves(renderResult, async () => + pressKey('g', { modifiers: cmdModifier }), + ) + + const toasts = renderResult.getEditorState().editor.toasts + expect(toasts).toHaveLength(1) + const firstToast = safeIndex(toasts, 0) + expect(firstToast?.id).toEqual('percentage-pin-replaced') + + expect(getPrintedUiJsCodeWithoutUIDs(renderResult.getEditorState())).toEqual( + makeTestProjectCodeWithSnippetWithoutUIDs( + `
+ +
+
+ +
`, + ), + ) + }) + it('if Group is not imported, it is added to the imports after the Group has been inserted', async () => { const editor = await renderTestEditorWithCode( `import { Scene, Storyboard } from 'utopia-api'