diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-element-change-location-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-element-change-location-strategy.spec.browser2.tsx index 293e304d1a18..a0774e94e142 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-element-change-location-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-element-change-location-strategy.spec.browser2.tsx @@ -1,16 +1,10 @@ import * as EP from '../../../../core/shared/element-path' -import { - getRectCenter, - localRectangle, - offsetPoint, - windowPoint, -} from '../../../../core/shared/math-utils' +import { offsetPoint, windowPoint } from '../../../../core/shared/math-utils' import { selectComponentsForTest } from '../../../../utils/utils.test-utils' import CanvasActions from '../../canvas-actions' import { GridCellTestId } from '../../controls/grid-controls-for-strategies' import { mouseDownAtPoint, mouseMoveToPoint, mouseUpAtPoint } from '../../event-helpers.test-utils' import { renderTestEditorWithCode } from '../../ui-jsx.test-utils' -import { gridCellTargetId } from './grid-cell-bounds' import { runGridMoveTest } from './grid.test-utils' describe('grid element change location strategy', () => { @@ -22,7 +16,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -52,7 +46,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -79,7 +73,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, (ed) => { @@ -109,7 +103,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid/', testId: testId, }, ) @@ -131,7 +125,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, targetCell: { row: 2, column: 1 }, draggedCell: { row: 2, column: 2 }, @@ -153,7 +147,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, tab: true, }, @@ -178,7 +172,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, targetCell: { row: 3, column: 1 }, }, @@ -200,7 +194,7 @@ describe('grid element change location strategy', () => { editor, { scale: 0.5, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -220,7 +214,7 @@ describe('grid element change location strategy', () => { editor, { scale: 2, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -243,7 +237,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -267,7 +261,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -291,7 +285,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, targetCell: { row: 3, column: 2 }, }, @@ -316,7 +310,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -340,7 +334,7 @@ describe('grid element change location strategy', () => { editor, { scale: 1, - pathString: `sb/scene/grid/${testId}`, + gridPath: 'sb/scene/grid', testId: testId, }, ) @@ -366,8 +360,6 @@ export var storyboard = ( data-testid='grid' style={{ position: 'absolute', - left: -94, - top: 698, display: 'grid', gap: 10, width: 600, @@ -428,33 +420,11 @@ export var storyboard = ( ) const testId = 'grid-inside-grid' - const elementPathToDrag = EP.fromString(`sb/grid/${testId}`) - - await selectComponentsForTest(editor, [elementPathToDrag]) - - const sourceGridCell = editor.renderedDOM.getByTestId(GridCellTestId(elementPathToDrag)) - const targetGridCell = editor.renderedDOM.getByTestId( - gridCellTargetId(EP.fromString('sb/grid'), 2, 3), - ) - - const sourceRect = sourceGridCell.getBoundingClientRect() - const targetRect = targetGridCell.getBoundingClientRect() - - const dragFrom = { - x: sourceRect.x + 10, - y: sourceRect.y + 10, - } - const dragTo = getRectCenter( - localRectangle({ - x: targetRect.x, - y: targetRect.y, - width: targetRect.width, - height: targetRect.height, - }), - ) - await mouseDownAtPoint(sourceGridCell, dragFrom) - await mouseMoveToPoint(sourceGridCell, dragTo) - await mouseUpAtPoint(sourceGridCell, dragTo) + await runGridMoveTest(editor, { + scale: 1, + gridPath: 'sb/grid', + testId: testId, + }) const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } = editor.renderedDOM.getByTestId(testId).style diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-reorder-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-reorder-strategy.spec.browser2.tsx index 8361c3668036..30699b6b2d84 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-reorder-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-reorder-strategy.spec.browser2.tsx @@ -6,6 +6,7 @@ import { renderTestEditorWithCode } from '../../ui-jsx.test-utils' import type { GridCellCoordinates } from './grid-cell-bounds' import { runGridMoveTest } from './grid.test-utils' import * as EP from '../../../../core/shared/element-path' +import { selectComponentsForTest } from '../../../../utils/utils.test-utils' describe('grid reorder', () => { it('reorders an element without setting positioning (inside contiguous area)', async () => { @@ -111,6 +112,8 @@ describe('grid reorder', () => { expect(first.cells).toEqual(['pink', 'cyan', 'blue', 'orange']) + await selectComponentsForTest(editor, []) + const second = await runReorderTest( editor, 'sb/scene/grid', @@ -242,7 +245,7 @@ describe('grid reorder', () => { async function runReorderTest( editor: EditorRenderResult, - gridTestId: string, + gridPath: string, testId: string, targetCell: GridCellCoordinates, options?: { tab?: boolean }, @@ -251,22 +254,22 @@ async function runReorderTest( editor, { scale: 1, - pathString: `${gridTestId}/${testId}`, + gridPath: gridPath, testId: testId, targetCell: targetCell, tab: options?.tab, }, ) - const element = editor.getEditorState().editor.jsxMetadata[gridTestId] - if (isLeft(element.element) || !isJSXElement(element.element.value)) { + const grid = editor.getEditorState().editor.jsxMetadata[gridPath] + if (isLeft(grid.element) || !isJSXElement(grid.element.value)) { throw new Error('expected jsx element') } const cells = MetadataUtils.getChildrenOrdered( editor.getEditorState().editor.jsxMetadata, editor.getEditorState().editor.elementPathTree, - element.elementPath, + EP.fromString(gridPath), ) return { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx index d4f8319e350a..2ddbdf0315ce 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid-resize-element-strategy.spec.browser2.tsx @@ -15,7 +15,7 @@ import { offsetPoint, } from '../../../../core/shared/math-utils' import { selectComponentsForTest } from '../../../../utils/utils.test-utils' -import { mouseDragFromPointToPoint } from '../../event-helpers.test-utils' +import { mouseDownAtPoint, mouseDragFromPointToPoint } from '../../event-helpers.test-utils' import type { EditorRenderResult } from '../../ui-jsx.test-utils' import { renderTestEditorWithCode } from '../../ui-jsx.test-utils' import type { GridResizeEdge } from '../interaction-state' @@ -34,6 +34,9 @@ async function runCellResizeTest( const resizeControl = editor.renderedDOM.getByTestId( ResizePointTestId(gridEdgeToEdgePosition(edge)), ) + + const resizeControlBox = resizeControl.getBoundingClientRect() + await mouseDownAtPoint(resizeControl, { x: resizeControlBox.x + 5, y: resizeControlBox.y + 5 }) const targetGridCell = editor.renderedDOM.getByTestId(dragToCellTestId) await mouseDragFromPointToPoint( diff --git a/editor/src/components/canvas/canvas-strategies/strategies/grid.test-utils.ts b/editor/src/components/canvas/canvas-strategies/strategies/grid.test-utils.ts index 26eae7685310..2250a04742af 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/grid.test-utils.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/grid.test-utils.ts @@ -2,7 +2,6 @@ import { getRectCenter, localRectangle } from '../../../../core/shared/math-util import { selectComponentsForTest } from '../../../../utils/utils.test-utils' import CanvasActions from '../../canvas-actions' import { GridCellTestId } from '../../controls/grid-controls-for-strategies' -import { CanvasControlsContainerID } from '../../controls/new-canvas-controls' import { mouseDownAtPoint, mouseMoveToPoint, @@ -13,12 +12,14 @@ import type { EditorRenderResult } from '../../ui-jsx.test-utils' import type { GridCellCoordinates } from './grid-cell-bounds' import { gridCellTargetId } from './grid-cell-bounds' import * as EP from '../../../../core/shared/element-path' +import type { ElementPath } from 'utopia-shared/src/types' +import { CanvasControlsContainerID } from '../../controls/new-canvas-controls' export async function runGridMoveTest( editor: EditorRenderResult, props: { scale: number - pathString: string + gridPath: string testId: string targetCell?: GridCellCoordinates draggedCell?: GridCellCoordinates @@ -26,7 +27,7 @@ export async function runGridMoveTest( }, midDragCallback?: (editor: EditorRenderResult) => void, ) { - const elementPathToDrag = EP.fromString(props.pathString) + const elementPathToDrag = EP.appendToPath(EP.fromString(props.gridPath), props.testId) await selectComponentsForTest(editor, [elementPathToDrag]) @@ -34,41 +35,19 @@ export async function runGridMoveTest( await editor.dispatch([CanvasActions.zoom(props.scale)], true) } - const sourceGridCell = editor.renderedDOM.getByTestId( - props.draggedCell == null - ? GridCellTestId(elementPathToDrag) - : gridCellTargetId( - EP.fromString('sb/scene/grid'), - props.draggedCell.row, - props.draggedCell.column, - ), - ) - const targetGridCell = editor.renderedDOM.getByTestId( - gridCellTargetId( - EP.fromString('sb/scene/grid'), - props.targetCell?.row ?? 2, - props.targetCell?.column ?? 3, - ), - ) - - const sourceRect = sourceGridCell.getBoundingClientRect() - const targetRect = targetGridCell.getBoundingClientRect() - - const dragFrom = { - x: sourceRect.x + 10, - y: sourceRect.y + 10, - } - const endPoint = getRectCenter( - localRectangle({ - x: targetRect.x, - y: targetRect.y, - width: targetRect.width, - height: targetRect.height, - }), + // trigger the grid controls so we know where to find the cells + const { sourceGridCell, dragFrom, dragTo } = await getSafeGridMoveTestEndpoints( + editor, + elementPathToDrag, + props.gridPath, + { + draggedCell: props.draggedCell, + targetCell: props.targetCell, + }, ) await mouseDownAtPoint(sourceGridCell, dragFrom) - await mouseMoveToPoint(sourceGridCell, endPoint) + await mouseMoveToPoint(sourceGridCell, dragTo) if (props.tab) { await keyDown('Tab') } @@ -76,7 +55,51 @@ export async function runGridMoveTest( midDragCallback(editor) } - await mouseUpAtPoint(editor.renderedDOM.getByTestId(CanvasControlsContainerID), endPoint) + await mouseUpAtPoint(editor.renderedDOM.getByTestId(CanvasControlsContainerID), dragTo) return editor.renderedDOM.getByTestId(props.testId).style } + +export async function getSafeGridMoveTestEndpoints( + editor: EditorRenderResult, + elementPathToDrag: ElementPath, + gridPath: string, + props?: { + draggedCell?: GridCellCoordinates + targetCell?: GridCellCoordinates + }, +) { + const gridCellTestId = GridCellTestId(elementPathToDrag) + const gridCellBaseElement = editor.renderedDOM.getByTestId(gridCellTestId) + const gridCellBaseElementBox = gridCellBaseElement.getBoundingClientRect() + const testPoint = getRectCenter(localRectangle(gridCellBaseElementBox)) + + await mouseDownAtPoint(gridCellBaseElement, testPoint) + + const sourceGridCell = editor.renderedDOM.getByTestId( + props?.draggedCell == null + ? gridCellTestId + : gridCellTargetId( + EP.fromString(gridPath), + props?.draggedCell.row, + props?.draggedCell.column, + ), + ) + + const targetGridCell = editor.renderedDOM.getByTestId( + gridCellTargetId( + EP.fromString(gridPath), + props?.targetCell?.row ?? 2, + props?.targetCell?.column ?? 3, + ), + ) + const sourceRect = sourceGridCell.getBoundingClientRect() + const dragFrom = { x: sourceRect.x + 5, y: sourceRect.y + 5 } + + const targetRect = targetGridCell.getBoundingClientRect() + const dragTo = { x: targetRect.x + 5, y: targetRect.y + 5 } + + await mouseUpAtPoint(editor.renderedDOM.getByTestId(CanvasControlsContainerID), testPoint) + + return { sourceGridCell, dragFrom, dragTo } +} diff --git a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx index a8bc6730953f..5a83237fe0ec 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/resize-grid-strategy.spec.browser2.tsx @@ -140,7 +140,7 @@ describe('resize a grid', () => { makeTestProject({ columns: '2.4fr 1fr 1fr', rows: '99px 109px 90px', shorthand: null }), 'await-first-dom-report', ) - const target = EP.fromString(`sb/grid/row-1-column-2`) + const target = EP.fromString(`sb/grid`) await renderResult.dispatch(selectComponents([target], false), true) await renderResult.getDispatchFollowUpActionsFinished() const canvasControlsLayer = renderResult.renderedDOM.getByTestId(CanvasControlsContainerID) @@ -316,7 +316,7 @@ export var storyboard = ( makeTestProject({ columns: '2.4fr 1fr 1fr', rows: '99px 109px 90px', shorthand: null }), 'await-first-dom-report', ) - const target = EP.fromString(`sb/grid/row-1-column-2`) + const target = EP.fromString(`sb/grid`) await renderResult.dispatch(selectComponents([target], false), true) await renderResult.getDispatchFollowUpActionsFinished() const canvasControlsLayer = renderResult.renderedDOM.getByTestId(CanvasControlsContainerID) @@ -431,7 +431,7 @@ export var storyboard = ( makeTestProject({ columns: 'repeat(3, 1fr)', rows: '99px 109px 90px', shorthand: null }), 'await-first-dom-report', ) - const target = EP.fromString(`sb/grid/row-1-column-2`) + const target = EP.fromString(`sb/grid`) await renderResult.dispatch(selectComponents([target], false), true) await renderResult.getDispatchFollowUpActionsFinished() const canvasControlsLayer = renderResult.renderedDOM.getByTestId(CanvasControlsContainerID) @@ -551,7 +551,7 @@ export var storyboard = ( }), 'await-first-dom-report', ) - const target = EP.fromString(`sb/grid/row-1-column-2`) + const target = EP.fromString(`sb/grid`) await renderResult.dispatch(selectComponents([target], false), true) await renderResult.getDispatchFollowUpActionsFinished() const canvasControlsLayer = renderResult.renderedDOM.getByTestId(CanvasControlsContainerID) @@ -670,7 +670,7 @@ export var storyboard = ( }), 'await-first-dom-report', ) - const target = EP.fromString(`sb/grid/row-1-column-2`) + const target = EP.fromString(`sb/grid`) await renderResult.dispatch(selectComponents([target], false), true) await renderResult.getDispatchFollowUpActionsFinished() const canvasControlsLayer = renderResult.renderedDOM.getByTestId(CanvasControlsContainerID) @@ -788,7 +788,7 @@ export var storyboard = ( }), 'await-first-dom-report', ) - const target = EP.fromString(`sb/grid/row-1-column-2`) + const target = EP.fromString(`sb/grid`) await renderResult.dispatch(selectComponents([target], false), true) await renderResult.getDispatchFollowUpActionsFinished() const canvasControlsLayer = renderResult.renderedDOM.getByTestId(CanvasControlsContainerID) diff --git a/editor/src/components/canvas/controls/grid-controls.tsx b/editor/src/components/canvas/controls/grid-controls.tsx index 2940f9cf3b9e..ac23b73918e0 100644 --- a/editor/src/components/canvas/controls/grid-controls.tsx +++ b/editor/src/components/canvas/controls/grid-controls.tsx @@ -536,6 +536,8 @@ export const GridRowColumnResizingControlsComponent = ({ 'GridRowColumnResizingControls scale', ) + const isGridItemSelected = useIsGridItemSelected() + const gridsWithVisibleResizeControls = React.useMemo(() => { return grids.filter((grid) => { if ( @@ -571,6 +573,9 @@ export const GridRowColumnResizingControlsComponent = ({ return ( {gridsWithVisibleResizeControls.flatMap((grid) => { + if (isGridItemSelected) { + return null + } return ( { + if (isGridItemSelected) { + return null + } return ( { const gridsWithVisibleControls: Array = [...targets, ...hoveredGrids] + const isGridItemSelected = useIsGridItemSelected() + const isGridItemInteractionActive = useIsGridItemInteractionActive() + // Uniqify the grid paths, and then sort them by depth. // With the lowest depth grid at the end so that it renders on top and catches the events // before those above it in the hierarchy. @@ -1161,6 +1172,8 @@ export const GridControlsComponent = ({ targets }: GridControlsProps) => { }), ) + const isGridItemSelectedWithoutInteraction = isGridItemSelected && !isGridItemInteractionActive + if (grids.length === 0) { return null } @@ -1173,6 +1186,10 @@ export const GridControlsComponent = ({ targets }: GridControlsProps) => { grid.identifier, ) const shouldHaveVisibleControls = gridsWithVisibleControls.some((g) => { + if (isGridItemSelectedWithoutInteraction) { + return false + } + const visibleControlPath = getGridIdentifierContainerOrComponentPath(g) return EP.pathsEqual(gridContainerOrComponentPath, visibleControlPath) }) @@ -2110,3 +2127,31 @@ function useAllGrids(metadata: ElementInstanceMetadataMap) { } }, [metadata]) } + +function useIsGridItemInteractionActive() { + return useEditorState( + Substores.canvas, + (store) => { + if (store.editor.canvas.interactionSession == null) { + return false + } + return ( + // movement + store.editor.canvas.interactionSession.activeControl.type === 'GRID_CELL_HANDLE' || + // resize (cell) + store.editor.canvas.interactionSession.activeControl.type === 'GRID_RESIZE_HANDLE' || + // resize (abs) + store.editor.canvas.interactionSession.activeControl.type === 'RESIZE_HANDLE' + ) + }, + 'useIsGridItemInteractionActive isItemInteractionActive', + ) +} + +function useIsGridItemSelected() { + const selectedViewsRef = useRefEditorState((store) => store.editor.selectedViews) + const jsxMetadataRef = useRefEditorState((store) => store.editor.jsxMetadata) + return selectedViewsRef.current.some((selected) => + MetadataUtils.isGridItem(jsxMetadataRef.current, selected), + ) +}