diff --git a/editor/src/components/canvas/controls/select-mode/grid-gap-control-component.tsx b/editor/src/components/canvas/controls/select-mode/grid-gap-control-component.tsx index 9a754866e4ee..98ccb11f2a80 100644 --- a/editor/src/components/canvas/controls/select-mode/grid-gap-control-component.tsx +++ b/editor/src/components/canvas/controls/select-mode/grid-gap-control-component.tsx @@ -8,6 +8,7 @@ import type { ElementPath } from '../../../../core/shared/project-file-types' import { assertNever } from '../../../../core/shared/utils' import { Modifier } from '../../../../utils/modifiers' import { when } from '../../../../utils/react-conditionals' +import type { UtopiColor } from '../../../../uuiui' import { useColorTheme, UtopiaStyles } from '../../../../uuiui' import { CSSCursor } from '../../../../uuiui-deps' import type { EditorDispatch } from '../../../editor/action-types' @@ -139,7 +140,7 @@ export const GridGapControlComponent = React.memo((props) = ) }) -const GridPaddingOutlineForDimension = (props: { +export const GridPaddingOutlineForDimension = (props: { grid: GridData dimension: 'rows' | 'columns' onMouseDown: (e: React.MouseEvent) => void @@ -148,6 +149,7 @@ const GridPaddingOutlineForDimension = (props: { zIndexPriority: boolean gridGap: CSSNumberWithRenderedValue elementHovered: boolean + draggedOutlineColor?: UtopiColor }) => { const { grid, @@ -158,6 +160,7 @@ const GridPaddingOutlineForDimension = (props: { onMouseOver, zIndexPriority, elementHovered, + draggedOutlineColor, } = props let style: CSSProperties = { @@ -199,6 +202,7 @@ const GridPaddingOutlineForDimension = (props: { beingDragged={beingDragged} onMouseOver={onMouseOver} elementHovered={elementHovered} + draggedOutlineColor={draggedOutlineColor} /> ) })} @@ -218,6 +222,7 @@ const GridRowHighlight = (props: { beingDragged: boolean onMouseOver: () => void elementHovered: boolean + draggedOutlineColor?: UtopiColor }) => { const { gapId, @@ -231,6 +236,7 @@ const GridRowHighlight = (props: { beingDragged, onMouseOver, elementHovered, + draggedOutlineColor, } = props const colorTheme = useColorTheme() @@ -242,7 +248,9 @@ const GridRowHighlight = (props: { const lineWidth = 1 / canvasScale - const outlineColor = beingDragged ? colorTheme.brandNeonOrange.value : 'transparent' + const outlineColor = beingDragged + ? (draggedOutlineColor ?? colorTheme.brandNeonOrange).value + : 'transparent' const [backgroundShown, setBackgroundShown] = React.useState(false) diff --git a/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx b/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx index ffb35aae3811..3b45f1dcb3d7 100644 --- a/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx +++ b/editor/src/components/canvas/controls/select-mode/subdued-grid-gap-controls.tsx @@ -1,15 +1,13 @@ import React from 'react' import { useColorTheme } from '../../../../uuiui' -import { Substores, useEditorState, useRefEditorState } from '../../../editor/store/store-hook' -import { useBoundingBox } from '../bounding-box-hooks' +import { Substores, useEditorState } from '../../../editor/store/store-hook' import { CanvasOffsetWrapper } from '../canvas-offset-wrapper' import type { Axis } from '../../gap-utils' -import { gridGapControlBoundsFromMetadata, maybeGridGapData } from '../../gap-utils' -import type { ElementPath } from 'utopia-shared/src/types' import { useGridData } from '../grid-controls-for-strategies' -import { fallbackEmptyValue } from './controls-common' -import type { CanvasRectangle } from '../../../../core/shared/math-utils' -import type { CSSNumber } from '../../../../components/inspector/common/css-utils' +import { unitlessCSSNumberWithRenderedValue } from './controls-common' +import { NO_OP } from '../../../../core/shared/utils' +import * as EP from '../../../../core/shared/element-path' +import { GridPaddingOutlineForDimension } from './grid-gap-control-component' export interface SubduedGridGapControlProps { hoveredOrFocused: 'hovered' | 'focused' @@ -18,124 +16,49 @@ export interface SubduedGridGapControlProps { export const SubduedGridGapControl = React.memo((props) => { const { hoveredOrFocused, axis } = props + const colorTheme = useColorTheme() const targets = useEditorState( Substores.selectedViews, (store) => store.editor.selectedViews, 'SubduedGridGapControl selectedViews', ) - const metadata = useRefEditorState((store) => store.editor.jsxMetadata) - const selectedElement = targets.at(0) - const gridRowColumnInfo = useGridData(targets) - const selectedGrid = gridRowColumnInfo.at(0) - - const filteredGaps = React.useMemo(() => { - if (selectedElement == null || selectedGrid == null) { - return [] - } - const gridGap = maybeGridGapData(metadata.current, selectedElement) - if (gridGap == null) { - return [] - } - - const gridGapRow = gridGap.row - const gridGapColumn = gridGap.column - const controlBounds = gridGapControlBoundsFromMetadata(selectedGrid, { - row: fallbackEmptyValue(gridGapRow), - column: fallbackEmptyValue(gridGapColumn), - }) - return controlBounds.gaps.filter((gap) => gap.axis === axis || axis === 'both') - }, [axis, metadata, selectedElement, selectedGrid]) - - if (filteredGaps.length === 0 || selectedElement == null) { + if (gridRowColumnInfo.length === 0) { return null } - return ( - <> - {filteredGaps.map((gap) => ( - - ))} - - ) -}) - -function GridGapControl({ - targets, - selectedElement, - hoveredOrFocused, - gap, -}: { - targets: Array - selectedElement: ElementPath - hoveredOrFocused: 'hovered' | 'focused' - gap: { - bounds: CanvasRectangle - gapId: string - gap: CSSNumber - axis: Axis - } -}) { - const metadata = useRefEditorState((store) => store.editor.jsxMetadata) - const scale = useEditorState( - Substores.canvas, - (store) => store.editor.canvas.scale, - 'GridGapControl scale', - ) - const gridRowColumnInfo = useGridData([selectedElement]) - - const sideRef = useBoundingBox([selectedElement], (ref, parentBoundingBox) => { - const gridGap = maybeGridGapData(metadata.current, selectedElement) - const selectedGrid = gridRowColumnInfo.at(0) - if (gridGap == null || selectedGrid == null) { - return - } - - const controlBounds = gridGapControlBoundsFromMetadata(selectedGrid, { - row: fallbackEmptyValue(gridGap.row), - column: fallbackEmptyValue(gridGap.column), - }) - - const bound = controlBounds.gaps.find((updatedGap) => updatedGap.gapId === gap.gapId) - if (bound == null) { - return - } - - ref.current.style.display = 'block' - ref.current.style.left = `${bound.bounds.x + parentBoundingBox.x}px` - ref.current.style.top = `${bound.bounds.y + parentBoundingBox.y}px` - ref.current.style.height = numberToPxValue(bound.bounds.height) - ref.current.style.width = numberToPxValue(bound.bounds.width) - }) - - const color = useColorTheme().brandNeonPink.value - - const solidOrDashed = hoveredOrFocused === 'focused' ? 'solid' : 'dashed' - return ( -
+ {gridRowColumnInfo.map((gridData) => { + return ( + + + + + ) + })} ) -} - -export function getSubduedGridGaplTestID(hoveredOrFocused: 'hovered' | 'focused'): string { - return `SubduedGridGapControl-${hoveredOrFocused}` -} - -const numberToPxValue = (n: number) => n + 'px' +}) diff --git a/editor/src/components/canvas/gap-utils.ts b/editor/src/components/canvas/gap-utils.ts index e2e980f3e4d0..17387f867068 100644 --- a/editor/src/components/canvas/gap-utils.ts +++ b/editor/src/components/canvas/gap-utils.ts @@ -176,116 +176,6 @@ export function gapControlBoundsFromMetadata( ) } -export function gridGapControlBoundsFromMetadata( - gridRowColumnInfo: GridData, - gapValues: { row: CSSNumber; column: CSSNumber }, -): { - gaps: Array<{ - bounds: CanvasRectangle - gapId: string - gap: CSSNumber - axis: Axis - }> - rows: number - columns: number - cellBounds: CanvasRectangle - gapValues: { row: CSSNumber; column: CSSNumber } - gridTemplateRows: string - gridTemplateColumns: string -} { - const emptyResult = { - rows: 0, - columns: 0, - gaps: [], - cellBounds: canvasRectangle({ x: 0, y: 0, width: 0, height: 0 }), - gapValues: gapValues, - gridTemplateRows: '1fr', - gridTemplateColumns: '1fr', - } - const grid = gridRowColumnInfo.metadata - - if (grid == null) { - return emptyResult - } - - const parentGridBounds = grid.globalFrame - - if (parentGridBounds == null || isInfinityRectangle(parentGridBounds)) { - return emptyResult - } - - const gridRows = gridRowColumnInfo.rows - const gridColumns = gridRowColumnInfo.columns - const gridTemplateRows = getNullableAutoOrTemplateBaseString(gridRowColumnInfo.gridTemplateRows) - const gridTemplateColumns = getNullableAutoOrTemplateBaseString( - gridRowColumnInfo.gridTemplateColumns, - ) - - const gridCellBounds = grid.specialSizeMeasurements.gridCellGlobalFrames - - if (gridCellBounds == null || gridCellBounds.length == 0) { - return emptyResult - } - const allCellsBound = canvasRectangle({ - x: gridCellBounds[0][0].x - parentGridBounds.x, - y: gridCellBounds[0][0].y - parentGridBounds.y, - width: - gridCellBounds[0][gridCellBounds[0].length - 1].x + - gridCellBounds[0][gridCellBounds[0].length - 1].width - - gridCellBounds[0][0].x, - height: - gridCellBounds[gridCellBounds.length - 1][0].y + - gridCellBounds[gridCellBounds.length - 1][0].height - - gridCellBounds[0][0].y, - }) - - // row gaps array - const rowGaps = createArrayWithLength(gridCellBounds.length - 1, (i) => { - // cell i represents the gap between child [i * gridColumns] and child [(i+1) * gridColumns] - const firstChildBounds = gridCellBounds[i][0] - const secondChildBounds = gridCellBounds[i + 1][0] - return { - gapId: `${EP.toString(grid.elementPath)}-row-gap-${i}`, - bounds: canvasRectangle({ - x: allCellsBound.x, - y: firstChildBounds.y + firstChildBounds.height - parentGridBounds.y, - width: allCellsBound.width, - height: secondChildBounds.y - firstChildBounds.y - firstChildBounds.height, - }), - gap: gapValues.row, - axis: 'row' as Axis, - } - }) - - // column gaps array - const columnGaps = createArrayWithLength(gridCellBounds[0].length - 1, (i) => { - // cell i represents the gap between child [i] and child [i + 1] - const firstChildBounds = gridCellBounds[0][i] - const secondChildBounds = gridCellBounds[0][i + 1] - return { - gapId: `${EP.toString(grid.elementPath)}-column-gap-${i}`, - bounds: canvasRectangle({ - x: firstChildBounds.x + firstChildBounds.width - parentGridBounds.x, - y: allCellsBound.y, - width: secondChildBounds.x - firstChildBounds.x - firstChildBounds.width, - height: allCellsBound.height, - }), - gap: gapValues.column, - axis: 'column' as Axis, - } - }) - - return { - gaps: rowGaps.concat(columnGaps), - rows: gridRows, - columns: gridColumns, - gridTemplateRows: gridTemplateRows ?? '', - gridTemplateColumns: gridTemplateColumns ?? '', - cellBounds: allCellsBound, - gapValues: gapValues, - } -} - export interface GridGapData { row: CSSNumberWithRenderedValue column: CSSNumberWithRenderedValue