Skip to content

Commit

Permalink
Resize grid cell if the element is set to fill, resize the element ot…
Browse files Browse the repository at this point in the history
…herwise (#6347)

**Problem:**

Currently when a grid element is selected, it's only possible to resize
it's _cell_.

**Fix:**

This PR expands the functionality in two ways:

1. if the selected element is set to fill on both width and height, show
the _cell_ resize controls
2. otherwise, show the regular _element_ resize controls



https://github.com/user-attachments/assets/9e1ad8ac-0dae-43c2-b0f0-c282152e884b



Fixes #6348
  • Loading branch information
ruggi authored Sep 10, 2024
1 parent 74db368 commit 1293ce4
Show file tree
Hide file tree
Showing 13 changed files with 94 additions and 110 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { styleStringInArray } from '../../../../utils/common-constants'
import { getLayoutProperty } from '../../../../core/layout/getLayoutProperty'
import type { PropsOrJSXAttributes } from '../../../../core/model/element-metadata-utils'
import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
import { foldEither, isLeft, right } from '../../../../core/shared/either'
import * as EP from '../../../../core/shared/element-path'
import type { ElementInstanceMetadata } from '../../../../core/shared/element-template'
import { isJSXElement } from '../../../../core/shared/element-template'
import type { CanvasPoint, CanvasRectangle } from '../../../../core/shared/math-utils'
Expand All @@ -11,7 +11,10 @@ import {
isInfinityRectangle,
offsetPoint,
} from '../../../../core/shared/math-utils'
import { styleStringInArray } from '../../../../utils/common-constants'
import { trueUpGroupElementChanged } from '../../../editor/store/editor-state'
import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks'
import { isFixedHugFillModeApplied } from '../../../inspector/inspector-common'
import type { EdgePosition } from '../../canvas-types'
import { oppositeEdgePosition } from '../../canvas-types'
import {
Expand All @@ -24,9 +27,12 @@ import {
adjustCssLengthProperties,
lengthPropertyToAdjust,
} from '../../commands/adjust-css-length-command'
import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command'
import { queueTrueUpElement } from '../../commands/queue-true-up-command'
import { setCursorCommand } from '../../commands/set-cursor-command'
import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command'
import { updateHighlightedViews } from '../../commands/update-highlighted-views-command'
import { controlsForGridPlaceholders } from '../../controls/grid-controls'
import { ImmediateParentBounds } from '../../controls/parent-bounds'
import { ImmediateParentOutlines } from '../../controls/parent-outlines'
import { AbsoluteResizeControl } from '../../controls/select-mode/absolute-resize-control'
Expand All @@ -44,16 +50,13 @@ import {
} from '../canvas-strategy-types'
import type { InteractionSession } from '../interaction-state'
import { honoursPropsSize } from './absolute-utils'
import { treatElementAsGroupLike } from './group-helpers'
import {
getLockedAspectRatio,
isAnySelectedElementAspectRatioLocked,
pickCursorFromEdgePosition,
resizeBoundingBox,
} from './resize-helpers'
import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command'
import { queueTrueUpElement } from '../../commands/queue-true-up-command'
import { treatElementAsGroupLike } from './group-helpers'
import { trueUpGroupElementChanged } from '../../../editor/store/editor-state'

export const BASIC_RESIZE_STRATEGY_ID = 'BASIC_RESIZE'

Expand All @@ -76,7 +79,11 @@ export function basicResizeStrategy(
const elementDimensionsProps = metadata != null ? getElementDimensions(metadata) : null
const elementParentBounds = metadata?.specialSizeMeasurements.immediateParentBounds ?? null

if (MetadataUtils.isGridCell(canvasState.startingMetadata, selectedElement)) {
const isGridCell = MetadataUtils.isGridCell(canvasState.startingMetadata, selectedElement)
if (
isGridCell &&
isFixedHugFillModeApplied(canvasState.startingMetadata, selectedElement, 'fill')
) {
return null
}

Expand Down Expand Up @@ -113,6 +120,7 @@ export function basicResizeStrategy(
key: 'parent-bounds-control',
show: 'visible-only-while-active',
}),
...(isGridCell ? [controlsForGridPlaceholders(EP.parentPath(selectedElement))] : []),
],
fitness:
interactionSession != null &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import type { InsertElementInsertionSubject } from '../../commands/insert-elemen
import { insertElementInsertionSubject } from '../../commands/insert-element-insertion-subject'
import { updateHighlightedViews } from '../../commands/update-highlighted-views-command'
import { wildcardPatch } from '../../commands/wildcard-patch-command'
import { GridControls } from '../../controls/grid-controls'
import { controlsForGridPlaceholders } from '../../controls/grid-controls'
import { canvasPointToWindowPoint } from '../../dom-lookup'
import {
getWrapperWithGeneratedUid,
Expand Down Expand Up @@ -153,15 +153,7 @@ const gridDrawToInsertStrategyInner =
category: 'tools',
type: 'pointer',
},
controlsToRender: [
{
control: GridControls,
props: { targets: [targetParent] },
key: `draw-into-grid-strategy-controls`,
show: 'always-visible',
priority: 'bottom',
},
],
controlsToRender: [controlsForGridPlaceholders(targetParent)],
fitness: 5,
apply: (strategyLifecycle) => {
const newTargetCell = getGridCellUnderCursor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
import * as EP from '../../../../core/shared/element-path'
import type { GridPositionValue } from '../../../../core/shared/element-template'
import { gridPositionValue } from '../../../../core/shared/element-template'
import { GridControls, GridControlsKey } from '../../controls/grid-controls'
import { controlsForGridPlaceholders } from '../../controls/grid-controls'
import type {
CanvasStrategy,
CustomStrategyState,
Expand Down Expand Up @@ -78,15 +78,7 @@ export function gridRearrangeResizeKeyboardStrategy(
category: 'modalities',
type: 'reorder-large',
},
controlsToRender: [
{
control: GridControls,
props: { targets: [parentGridPath] },
key: GridControlsKey(parentGridPath),
show: 'always-visible',
priority: 'bottom',
},
],
controlsToRender: [controlsForGridPlaceholders(parentGridPath)],
fitness: fitness(interactionSession),
apply: () => {
if (interactionSession == null || interactionSession.interactionData.type !== 'KEYBOARD') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setCursorCommand } from '../../commands/set-cursor-command'
import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command'
import { updateHighlightedViews } from '../../commands/update-highlighted-views-command'
import { updateSelectedViews } from '../../commands/update-selected-views-command'
import { GridControls, GridControlsKey } from '../../controls/grid-controls'
import { controlsForGridPlaceholders } from '../../controls/grid-controls'
import type { CanvasStrategyFactory } from '../canvas-strategies'
import { onlyFitWhenDraggingThisControl } from '../canvas-strategies'
import type { CustomStrategyState, InteractionCanvasState } from '../canvas-strategy-types'
Expand Down Expand Up @@ -49,15 +49,7 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = (
category: 'tools',
type: 'pointer',
},
controlsToRender: [
{
control: GridControls,
props: { targets: [EP.parentPath(selectedElement)] },
key: GridControlsKey(EP.parentPath(selectedElement)),
show: 'always-visible',
priority: 'bottom',
},
],
controlsToRender: [controlsForGridPlaceholders(EP.parentPath(selectedElement))],
fitness: onlyFitWhenDraggingThisControl(interactionSession, 'GRID_CELL_HANDLE', 3),
apply: () => {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
offsetPoint,
windowPoint,
} from '../../../../core/shared/math-utils'
import { selectComponentsForTest, wait } from '../../../../utils/utils.test-utils'
import { selectComponentsForTest } from '../../../../utils/utils.test-utils'
import CanvasActions from '../../canvas-actions'
import { GridCellTestId } from '../../controls/grid-controls'
import { mouseDragFromPointToPoint } from '../../event-helpers.test-utils'
Expand Down Expand Up @@ -117,6 +117,8 @@ export var storyboard = (
gridTemplateRows: '1fr',
gridColumn: 1,
gridRow: 2,
width: '100%',
height: '100%',
}}
>
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ElementPath } from 'utopia-shared/src/types'
import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
import * as EP from '../../../../core/shared/element-path'
import { GridControls, GridControlsKey } from '../../controls/grid-controls'
import { controlsForGridPlaceholders } from '../../controls/grid-controls'
import type {
ElementInstanceMetadataMap,
GridAutoOrTemplateBase,
Expand Down Expand Up @@ -409,14 +409,6 @@ function getStrategyToApply(
return {
type: 'GRID_REARRANGE',
name: 'Rearrange Grid (Move)',
controlsToRender: [
{
control: GridControls,
props: { targets: [parentGridPath] },
key: GridControlsKey(parentGridPath),
show: 'always-visible',
priority: 'bottom',
},
],
controlsToRender: [controlsForGridPlaceholders(parentGridPath)],
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import type { NodeModules, ProjectContentTreeRoot } from 'utopia-shared/src/types'
import type { BuiltInDependencies } from '../../../../core/es-modules/package-manager/built-in-dependencies-list'
import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
import { mapDropNulls } from '../../../../core/shared/array-utils'
import * as EP from '../../../../core/shared/element-path'
import * as PP from '../../../../core/shared/property-path'
import type { ElementPathTrees } from '../../../../core/shared/element-path-tree'
import {
gridPositionValue,
type ElementInstanceMetadataMap,
} from '../../../../core/shared/element-template'
import type { CanvasRectangle, CanvasVector } from '../../../../core/shared/math-utils'
import { canvasVector, isInfinityRectangle, offsetPoint } 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'
import type { InsertionPath } from '../../../editor/store/insertion-path'
import { CSSCursor } from '../../canvas-types'
import { setCursorCommand } from '../../commands/set-cursor-command'
import { propertyToSet, updateBulkProperties } from '../../commands/set-property-command'
import { showGridControls } from '../../commands/show-grid-controls-command'
import { updateSelectedViews } from '../../commands/update-selected-views-command'
import { controlsForGridPlaceholders } from '../../controls/grid-controls'
import { ParentBounds } from '../../controls/parent-bounds'
import { ParentOutlines } from '../../controls/parent-outlines'
import { ZeroSizedElementControls } from '../../controls/zero-sized-element-controls'
import { canvasPointToWindowPoint } from '../../dom-lookup'
import type { CanvasStrategyFactory } from '../canvas-strategies'
import type {
CanvasStrategy,
Expand All @@ -27,27 +41,13 @@ import {
import type { DragInteractionData, InteractionSession, UpdatedPathMap } from '../interaction-state'
import { honoursPropsPosition, shouldKeepMovingDraggedGroupChildren } from './absolute-utils'
import { replaceFragmentLikePathsWithTheirChildrenRecursive } from './fragment-like-helpers'
import type { TargetGridCellData } from './grid-helpers'
import { getTargetCell, setGridPropsCommands } 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 type { CanvasRectangle, CanvasVector } from '../../../../core/shared/math-utils'
import { canvasVector, isInfinityRectangle, offsetPoint } from '../../../../core/shared/math-utils'
import { showGridControls } from '../../commands/show-grid-controls-command'
import { GridControls } from '../../controls/grid-controls'
import {
gridPositionValue,
type ElementInstanceMetadataMap,
} from '../../../../core/shared/element-template'
import type { ElementPathTrees } from '../../../../core/shared/element-path-tree'
import type { AllElementProps } from '../../../editor/store/editor-state'
import type { BuiltInDependencies } from '../../../../core/es-modules/package-manager/built-in-dependencies-list'
import type { NodeModules, ProjectContentTreeRoot } from 'utopia-shared/src/types'
import type { InsertionPath } from '../../../editor/store/insertion-path'
import { removeAbsolutePositioningProps } from './reparent-helpers/reparent-property-changes'
import { canvasPointToWindowPoint } from '../../dom-lookup'
import type { TargetGridCellData } from './grid-helpers'
import { getTargetCell, setGridPropsCommands } from './grid-helpers'
import type { GridCellCoordinates } from './grid-cell-bounds'

export function gridReparentStrategy(
Expand Down Expand Up @@ -137,13 +137,7 @@ export function controlsForGridReparent(reparentTarget: ReparentTarget): Control
key: 'zero-size-control',
show: 'visible-only-while-active',
}),
{
control: GridControls,
props: { targets: [reparentTarget.newParent.intendedParentPath] },
key: `draw-into-grid-strategy-controls`,
show: 'always-visible',
priority: 'bottom',
},
controlsForGridPlaceholders(reparentTarget.newParent.intendedParentPath),
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ async function runCellResizeTest(
}

describe('grid resize element strategy', () => {
it('cannot resize non-filling cells', async () => {
const editor = await renderTestEditorWithCode(ProjectCode, 'await-first-dom-report')

await selectComponentsForTest(editor, [EP.fromString('sb/scene/grid/grid-child-not-filling')])

const resizeControl = editor.renderedDOM.queryByTestId(GridResizeEdgeTestId('column-end'))
expect(resizeControl).toBeNull()
})

describe('column-end', () => {
it('can enlarge element', async () => {
const editor = await renderTestEditorWithCode(ProjectCode, 'await-first-dom-report')
Expand Down Expand Up @@ -230,6 +239,8 @@ describe('grid resize element strategy', () => {
expect(styleProp).toEqual([
['minHeight', 0],
['backgroundColor', '#db48f6'],
['width', '100%'],
['height', '100%'],
['gridColumnStart', 7],
['gridColumnEnd', 11],
['gridRow', 2],
Expand Down Expand Up @@ -271,6 +282,8 @@ export var storyboard = (
gridTemplateRows: '1fr',
gridColumn: 1,
gridRow: 2,
width: '100%',
height: '100%',
}}
>
<div
Expand Down Expand Up @@ -392,8 +405,11 @@ export var storyboard = (
gridColumnStart: 1,
gridRowStart: 3,
backgroundColor: '#0074ff',
width: 25,
height: 30,
}}
data-uid='ccc'
data-uid='grid-child-not-filling'
data-testid='grid-child-not-filling'
/>
<div
style={{
Expand All @@ -403,6 +419,8 @@ export var storyboard = (
gridColumnStart: 7,
gridRowStart: 2,
backgroundColor: '#db48f6',
width: '100%',
height: '100%',
}}
data-uid='ddd'
data-testid='grid-child'
Expand Down Expand Up @@ -451,6 +469,8 @@ export var storyboard = (
minHeight: 0,
gridArea: '2 / 7 / 3 / 10',
backgroundColor: '#db48f6',
width: '100%',
height: '100%',
}}
data-uid='ddd'
data-testid='grid-child'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type { GridElementProperties, GridPosition } from '../../../../core/share
import { offsetPoint } from '../../../../core/shared/math-utils'
import { assertNever } from '../../../../core/shared/utils'
import { isCSSKeyword } from '../../../inspector/common/css-utils'
import { GridControls, GridControlsKey, GridResizeControls } from '../../controls/grid-controls'
import { isFixedHugFillModeApplied } from '../../../inspector/inspector-common'
import { controlsForGridPlaceholders, GridResizeControls } from '../../controls/grid-controls'
import { canvasPointToWindowPoint } from '../../dom-lookup'
import type { CanvasStrategyFactory } from '../canvas-strategies'
import { onlyFitWhenDraggingThisControl } from '../canvas-strategies'
Expand Down Expand Up @@ -38,6 +39,15 @@ export const gridResizeElementStrategy: CanvasStrategyFactory = (
return null
}

const isFillContainer = isFixedHugFillModeApplied(
canvasState.startingMetadata,
selectedElement,
'fill',
)
if (!isFillContainer) {
return null
}

const parentGridPath = EP.parentPath(selectedElement)

return {
Expand All @@ -55,13 +65,7 @@ export const gridResizeElementStrategy: CanvasStrategyFactory = (
key: `grid-resize-controls-${EP.toString(selectedElement)}`,
show: 'always-visible',
},
{
control: GridControls,
props: { targets: [parentGridPath] },
key: GridControlsKey(parentGridPath),
show: 'always-visible',
priority: 'bottom',
},
controlsForGridPlaceholders(parentGridPath),
],
fitness: onlyFitWhenDraggingThisControl(interactionSession, 'GRID_RESIZE_HANDLE', 1),
apply: () => {
Expand Down
Loading

0 comments on commit 1293ce4

Please sign in to comment.