Skip to content

Commit

Permalink
feature(grid) Grid Child Pin Outlines (#6617)
Browse files Browse the repository at this point in the history
- Fixed `parseGridRange` to more closely reflect the behaviour in
browsers.
- Renamed `elementStyle` to `computedStyle` in `getSpecialMeasurements`
for clarity.
- `PinLines` excludes grid cells from those elements which will get
regular pin outlines.
- `PinOutlineProps` now has `endX` and `endY` properties, along with
supporting `string` values for most of the properties.
- `PinOutline` now defers a lot of the calculations down into the CSS.
- Added `GridElementContainingBlocks` into the controls hierarchy.
- Implemented `collectGridPinOutlines` which handles the more
complicated case that grids present.
- Implemented `GridElementContainingBlock` to render `PinOutline`
instances for the grid children.
  • Loading branch information
seanparsons authored Nov 8, 2024
1 parent 16a0ff6 commit c7c479b
Show file tree
Hide file tree
Showing 12 changed files with 1,078 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
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 * as PP from '../../../../core/shared/property-path'
import type {
ElementInstanceMetadata,
ElementInstanceMetadataMap,
GridContainerProperties,
GridElementProperties,
} from '../../../../core/shared/element-template'
import {
getJSXAttribute,
gridPositionValue,
isJSXElement,
} from '../../../../core/shared/element-template'
import { gridPositionValue } from '../../../../core/shared/element-template'
import { isInfinityRectangle } from '../../../../core/shared/math-utils'
import { absolute } from '../../../../utils/utils'
import type { CanvasCommand } from '../../commands/commands'
Expand All @@ -32,6 +38,13 @@ import {
sortElementsByGridPosition,
} from './grid-helpers'
import { getTargetGridCellData } from '../../../inspector/grid-helpers'
import { forEachOf } from '../../../../core/shared/optics/optic-utilities'
import {
eitherRight,
fromField,
fromTypeGuard,
} from '../../../../core/shared/optics/optic-creators'
import { getJSXAttributesAtPath } from '../../../..//core/shared/jsx-attribute-utils'

export const gridChangeElementLocationStrategy: CanvasStrategyFactory = (
canvasState: InteractionCanvasState,
Expand Down Expand Up @@ -215,11 +228,53 @@ export function runGridChangeElementLocation(
}
const { targetCellCoords, targetRootCell } = targetGridCellData

const gridCellMoveCommands = setGridPropsCommands(pathForCommands, gridTemplate, {
const gridProps: Partial<GridElementProperties> = {
gridColumnStart: gridPositionValue(targetRootCell.column),
gridColumnEnd: gridPositionValue(targetRootCell.column + originalCellBounds.height),
gridRowStart: gridPositionValue(targetRootCell.row),
gridRowEnd: gridPositionValue(targetRootCell.row + originalCellBounds.width),
}

// TODO: Remove this logic once there is a fix for the handling of the track end fields.
let keepGridColumnEnd: boolean = true
let keepGridRowEnd: boolean = true
forEachOf(
fromField<ElementInstanceMetadata, 'element'>('element')
.compose(eitherRight())
.compose(fromTypeGuard(isJSXElement))
.compose(fromField('props')),
selectedElementMetadata,
(elementProperties) => {
const gridColumnEnd = getJSXAttributesAtPath(
elementProperties,
PP.create('style', 'gridColumnEnd'),
)
if (gridColumnEnd.attribute.type === 'ATTRIBUTE_NOT_FOUND') {
keepGridColumnEnd = false
}
const gridRowEnd = getJSXAttributesAtPath(elementProperties, PP.create('style', 'gridRowEnd'))
if (gridRowEnd.attribute.type === 'ATTRIBUTE_NOT_FOUND') {
keepGridRowEnd = false
}
},
)

const gridCellMoveCommands = setGridPropsCommands(
pathForCommands,
gridTemplate,
gridProps,
).filter((command) => {
if (command.type === 'SET_PROPERTY') {
if (PP.pathsEqual(command.property, PP.create('style', 'gridColumnEnd'))) {
return keepGridColumnEnd
} else if (PP.pathsEqual(command.property, PP.create('style', 'gridRowEnd'))) {
return keepGridRowEnd
} else {
return true
}
} else {
return true
}
})

// The siblings of the grid element being moved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,10 +504,13 @@ export var storyboard = (
await mouseUpAtPoint(dragTarget, endPoint)

{
const { top, left, gridColumn, gridRow } = child.style
expect({ top, left, gridColumn, gridRow }).toEqual({
gridColumn: '1',
gridRow: '1',
const { top, left, gridColumnStart, gridColumnEnd, gridRowStart, gridRowEnd } =
child.style
expect({ top, left, gridColumnStart, gridColumnEnd, gridRowStart, gridRowEnd }).toEqual({
gridColumnStart: '1',
gridColumnEnd: '',
gridRowStart: '1',
gridRowEnd: '',
left: '59px',
top: '59.5px',
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ export const GridMeasurementHelpersKey = (gridPath: ElementPath) =>
`grid-measurement-helpers-${EP.toString(gridPath)}`
export const GridMeasurementHelperKey = (gridPath: ElementPath) =>
`grid-measurement-helper-${EP.toString(gridPath)}`
export const GridElementContainingBlockKey = (gridPath: ElementPath) =>
`grid-measurement-containing-block-${EP.toString(gridPath)}`

export interface GridControlProps {
grid: GridData
Expand Down
Loading

0 comments on commit c7c479b

Please sign in to comment.