Skip to content

Commit 72d682b

Browse files
authored
Grid component support preparation (#6636)
**Problem:** This PR is a preparation step to support strategies for grid items in the following scenario: - the grid is in a component - the grid renders the component's children - the grid is not the root element of the component The main issue is that we still identify the grid control using the element path of the grid, even though that grid doesn't have a path in this case. We need to be able to show and manage a grid control using the element path of one of its items. **Fix:** Instead of storing the element path of the `GridControlData`, I introduced a new type `GridIdentifier` which can identify a grid either by its container element path, or an item's element path. I updated the strategies and commands to use this grid identifier, and also made sure the strategies for grid items identify using the item, and do not refer to the parent path as the grid. (For reparent we can not really do that, because the item is not in the grid yet. Solving that is not in scope now). What is missing: I still use mostly the old control implementations, it only works now because the `useGridData` hook converts GridItemIdentifier-s to a GridContainerIdentifier-s (using parentPath). So this PR is just a preparation, it does not solve the component problem yet. Next step is to make sure the control can render on the parent element when it receives a GridItemIdentifier. **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Play mode
1 parent f196d14 commit 72d682b

20 files changed

+231
-201
lines changed

editor/src/components/canvas/canvas-strategies/canvas-strategies.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
EditorState,
88
EditorStatePatch,
99
EditorStorePatched,
10+
GridIdentifier,
1011
} from '../../editor/store/editor-state'
1112
import { Substores, useEditorState, useSelectorWithCallback } from '../../editor/store/store-hook'
1213
import type {
@@ -676,7 +677,7 @@ export function combineApplicableControls(
676677
}
677678

678679
// Sift the instances of `GridControls`, storing their targets by when they should be shown.
679-
let gridControlsTargets: Map<WhenToShowControl, Array<ElementPath>> = new Map()
680+
let gridControlsTargets: Map<WhenToShowControl, Array<GridIdentifier>> = new Map()
680681
for (const control of gridControlsInstances) {
681682
if (isGridControlsProps(control.props)) {
682683
const possibleTargets = gridControlsTargets.get(control.show)

editor/src/components/canvas/canvas-strategies/strategies/basic-resize-strategy.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from '../../../../core/shared/math-utils'
1414
import * as PP from '../../../../core/shared/property-path'
1515
import { styleStringInArray } from '../../../../utils/common-constants'
16-
import { trueUpGroupElementChanged } from '../../../editor/store/editor-state'
16+
import { gridItemIdentifier, trueUpGroupElementChanged } from '../../../editor/store/editor-state'
1717
import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks'
1818
import { isFillOrStretchModeApplied } from '../../../inspector/inspector-common'
1919
import type { EdgePosition } from '../../canvas-types'
@@ -122,7 +122,7 @@ export function basicResizeStrategy(
122122
key: 'parent-bounds-control',
123123
show: 'visible-only-while-active',
124124
}),
125-
...(isGridCell ? [controlsForGridPlaceholders(EP.parentPath(selectedElement))] : []),
125+
...(isGridCell ? [controlsForGridPlaceholders(gridItemIdentifier(selectedElement))] : []),
126126
],
127127
fitness:
128128
interactionSession != null &&

editor/src/components/canvas/canvas-strategies/strategies/grid-change-element-location-duplicate-strategy.ts

+4-23
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
22
import { generateUidWithExistingComponents } from '../../../../core/model/element-template-utils'
33
import * as EP from '../../../../core/shared/element-path'
4-
import { isInfinityRectangle } from '../../../../core/shared/math-utils'
54
import { CSSCursor } from '../../../../uuiui-deps'
65
import { duplicateElement } from '../../commands/duplicate-element-command'
76
import { setCursorCommand } from '../../commands/set-cursor-command'
@@ -19,11 +18,11 @@ import {
1918
} from '../canvas-strategy-types'
2019
import type { InteractionSession } from '../interaction-state'
2120
import {
22-
findOriginalGrid,
2321
getParentGridTemplatesFromChildMeasurements,
2422
gridMoveStrategiesExtraCommands,
2523
} from './grid-helpers'
2624
import { runGridChangeElementLocation } from './grid-change-element-location-strategy'
25+
import { gridItemIdentifier } from '../../../editor/store/editor-state'
2726

2827
export const gridChangeElementLocationDuplicateStrategy: CanvasStrategyFactory = (
2928
canvasState: InteractionCanvasState,
@@ -72,22 +71,6 @@ export const gridChangeElementLocationDuplicateStrategy: CanvasStrategyFactory =
7271
return null
7372
}
7473

75-
const parentGridPath = findOriginalGrid(
76-
canvasState.startingMetadata,
77-
EP.parentPath(selectedElement),
78-
) // TODO don't use EP.parentPath
79-
if (parentGridPath == null) {
80-
return null
81-
}
82-
83-
const gridFrame = MetadataUtils.findElementByElementPath(
84-
canvasState.startingMetadata,
85-
parentGridPath,
86-
)?.globalFrame
87-
if (gridFrame == null || isInfinityRectangle(gridFrame)) {
88-
return null
89-
}
90-
9174
return {
9275
id: 'grid-change-element-location-duplicate-strategy',
9376
name: 'Change Location (Duplicate)',
@@ -96,7 +79,7 @@ export const gridChangeElementLocationDuplicateStrategy: CanvasStrategyFactory =
9679
category: 'tools',
9780
type: 'pointer',
9881
},
99-
controlsToRender: [controlsForGridPlaceholders(parentGridPath)],
82+
controlsToRender: [controlsForGridPlaceholders(gridItemIdentifier(selectedElement))],
10083
fitness: onlyFitWhenDraggingThisControl(interactionSession, 'GRID_CELL_HANDLE', 3),
10184
apply: () => {
10285
if (
@@ -117,8 +100,7 @@ export const gridChangeElementLocationDuplicateStrategy: CanvasStrategyFactory =
117100
duplicatedElementNewUids[oldUid] = newUid
118101
}
119102

120-
const targetElement = EP.appendToPath(parentGridPath, newUid)
121-
103+
const targetElement = EP.appendToPath(EP.parentPath(selectedElement), newUid)
122104
const { parentGridCellGlobalFrames, parentContainerGridProperties } =
123105
selectedElementMetadata.specialSizeMeasurements
124106
if (parentGridCellGlobalFrames == null) {
@@ -129,14 +111,13 @@ export const gridChangeElementLocationDuplicateStrategy: CanvasStrategyFactory =
129111
canvasState.startingMetadata,
130112
interactionSession.interactionData,
131113
selectedElementMetadata,
132-
parentGridPath,
133114
parentGridCellGlobalFrames,
134115
parentContainerGridProperties,
135116
null,
136117
)
137118

138119
const { midInteractionCommands, onCompleteCommands } = gridMoveStrategiesExtraCommands(
139-
parentGridPath,
120+
EP.parentPath(selectedElement), // TODO: don't use EP.parentPath
140121
initialTemplates,
141122
)
142123

editor/src/components/canvas/canvas-strategies/strategies/grid-change-element-location-keyboard-strategy.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import {
1010
strategyApplicationResult,
1111
} from '../canvas-strategy-types'
1212
import type { InteractionSession } from '../interaction-state'
13-
import { findOriginalGrid, setGridPropsCommands } from './grid-helpers'
13+
import { setGridPropsCommands } from './grid-helpers'
1414
import { getGridChildCellCoordBoundsFromCanvas } from './grid-cell-bounds'
1515
import { accumulatePresses } from './shared-keyboard-strategy-helpers'
16+
import { gridItemIdentifier } from '../../../editor/store/editor-state'
1617

1718
export function gridChangeElementLocationResizeKeyboardStrategy(
1819
canvasState: InteractionCanvasState,
@@ -41,11 +42,6 @@ export function gridChangeElementLocationResizeKeyboardStrategy(
4142
return null
4243
}
4344

44-
const parentGridPath = findOriginalGrid(canvasState.startingMetadata, EP.parentPath(target)) // TODO don't use EP.parentPath
45-
if (parentGridPath == null) {
46-
return null
47-
}
48-
4945
const gridTemplate = cell.specialSizeMeasurements.parentContainerGridProperties
5046
const gridCellGlobalFrames = cell.specialSizeMeasurements.parentGridCellGlobalFrames
5147

@@ -72,7 +68,7 @@ export function gridChangeElementLocationResizeKeyboardStrategy(
7268
category: 'modalities',
7369
type: 'reorder-large',
7470
},
75-
controlsToRender: [controlsForGridPlaceholders(parentGridPath)],
71+
controlsToRender: [controlsForGridPlaceholders(gridItemIdentifier(target))],
7672
fitness: fitness(interactionSession),
7773
apply: () => {
7874
if (interactionSession == null || interactionSession.interactionData.type !== 'KEYBOARD') {
@@ -131,7 +127,7 @@ export function gridChangeElementLocationResizeKeyboardStrategy(
131127
gridRowStart,
132128
gridRowEnd,
133129
}),
134-
[parentGridPath],
130+
[EP.parentPath(target)],
135131
)
136132
},
137133
}

editor/src/components/canvas/canvas-strategies/strategies/grid-change-element-location-strategy.ts

+11-26
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
import type { DragInteractionData, InteractionSession } from '../interaction-state'
2727
import type { GridCellGlobalFrames, SortableGridElementProperties } from './grid-helpers'
2828
import {
29-
findOriginalGrid,
3029
getOriginalElementGridConfiguration,
3130
getParentGridTemplatesFromChildMeasurements,
3231
gridMoveStrategiesExtraCommands,
@@ -41,6 +40,7 @@ import {
4140
fromTypeGuard,
4241
} from '../../../../core/shared/optics/optic-creators'
4342
import { getJSXAttributesAtPath } from '../../../..//core/shared/jsx-attribute-utils'
43+
import { gridItemIdentifier } from '../../../editor/store/editor-state'
4444

4545
export const gridChangeElementLocationStrategy: CanvasStrategyFactory = (
4646
canvasState: InteractionCanvasState,
@@ -88,22 +88,6 @@ export const gridChangeElementLocationStrategy: CanvasStrategyFactory = (
8888
return null
8989
}
9090

91-
const parentGridPath = findOriginalGrid(
92-
canvasState.startingMetadata,
93-
EP.parentPath(selectedElement),
94-
) // TODO don't use EP.parentPath
95-
if (parentGridPath == null) {
96-
return null
97-
}
98-
99-
const gridFrame = MetadataUtils.findElementByElementPath(
100-
canvasState.startingMetadata,
101-
parentGridPath,
102-
)?.globalFrame
103-
if (gridFrame == null || isInfinityRectangle(gridFrame)) {
104-
return null
105-
}
106-
10791
if (MetadataUtils.isPositionAbsolute(selectedElementMetadata)) {
10892
return null
10993
}
@@ -116,7 +100,9 @@ export const gridChangeElementLocationStrategy: CanvasStrategyFactory = (
116100
category: 'tools',
117101
type: 'pointer',
118102
},
119-
controlsToRender: [controlsForGridPlaceholders(parentGridPath, 'visible-only-while-active')],
103+
controlsToRender: [
104+
controlsForGridPlaceholders(gridItemIdentifier(selectedElement), 'visible-only-while-active'),
105+
],
120106
fitness: onlyFitWhenDraggingThisControl(interactionSession, 'GRID_CELL_HANDLE', 2),
121107
apply: () => {
122108
if (
@@ -132,14 +118,13 @@ export const gridChangeElementLocationStrategy: CanvasStrategyFactory = (
132118
canvasState,
133119
interactionSession.interactionData,
134120
selectedElement,
135-
parentGridPath,
136121
)
137122
if (commands.length === 0) {
138123
return emptyStrategyApplicationResult
139124
}
140125

141126
const { midInteractionCommands, onCompleteCommands } = gridMoveStrategiesExtraCommands(
142-
parentGridPath,
127+
EP.parentPath(selectedElement), // TODO: don't use EP.parentPath
143128
initialTemplates,
144129
)
145130

@@ -155,7 +140,6 @@ function getCommandsAndPatchForGridChangeElementLocation(
155140
canvasState: InteractionCanvasState,
156141
interactionData: DragInteractionData,
157142
selectedElement: ElementPath,
158-
gridPath: ElementPath,
159143
): {
160144
commands: CanvasCommand[]
161145
elementsToRerender: ElementPath[]
@@ -182,23 +166,21 @@ function getCommandsAndPatchForGridChangeElementLocation(
182166
canvasState.startingMetadata,
183167
interactionData,
184168
selectedElementMetadata,
185-
gridPath,
186169
parentGridCellGlobalFrames,
187170
parentContainerGridProperties,
188171
null,
189172
)
190173

191174
return {
192175
commands: commands,
193-
elementsToRerender: [gridPath, selectedElement],
176+
elementsToRerender: [EP.parentPath(selectedElement), selectedElement],
194177
}
195178
}
196179

197180
export function runGridChangeElementLocation(
198181
jsxMetadata: ElementInstanceMetadataMap,
199182
interactionData: DragInteractionData,
200183
selectedElementMetadata: ElementInstanceMetadata,
201-
gridPath: ElementPath,
202184
gridCellGlobalFrames: GridCellGlobalFrames,
203185
gridTemplate: GridContainerProperties,
204186
newPathAfterReparent: ElementPath | null,
@@ -298,7 +280,10 @@ export function runGridChangeElementLocation(
298280
})
299281

300282
// The siblings of the grid element being moved
301-
const siblings = MetadataUtils.getChildrenUnordered(jsxMetadata, gridPath)
283+
const siblings = MetadataUtils.getSiblingsUnordered(
284+
jsxMetadata,
285+
newPathAfterReparent ?? selectedElementMetadata.elementPath,
286+
)
302287
.filter((s) => !EP.pathsEqual(s.elementPath, selectedElementMetadata.elementPath))
303288
.map(
304289
(s, index): SortableGridElementProperties => ({
@@ -333,7 +318,7 @@ export function runGridChangeElementLocation(
333318

334319
const updateGridControlsCommand = showGridControls(
335320
'mid-interaction',
336-
gridPath,
321+
gridItemIdentifier(selectedElementMetadata.elementPath),
337322
targetCellCoords,
338323
targetRootCell,
339324
)

editor/src/components/canvas/canvas-strategies/strategies/grid-draw-to-insert-strategy.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { newReparentSubjects } from './reparent-helpers/reparent-strategy-helper
4848
import { getReparentTargetUnified } from './reparent-helpers/reparent-strategy-parent-lookup'
4949
import { getGridCellUnderMouseFromMetadata } from './grid-cell-bounds'
5050
import { nukeAllAbsolutePositioningPropsCommands } from '../../../inspector/inspector-common'
51+
import { gridContainerIdentifier } from '../../../editor/store/editor-state'
5152

5253
export const gridDrawToInsertText: CanvasStrategyFactory = (
5354
canvasState: InteractionCanvasState,
@@ -149,7 +150,7 @@ const gridDrawToInsertStrategyInner =
149150
category: 'tools',
150151
type: 'pointer',
151152
},
152-
controlsToRender: [controlsForGridPlaceholders(targetParent)],
153+
controlsToRender: [controlsForGridPlaceholders(gridContainerIdentifier(targetParent))],
153154
fitness: 5,
154155
apply: (strategyLifecycle) => {
155156
const canvasPointToUse =
@@ -165,7 +166,7 @@ const gridDrawToInsertStrategyInner =
165166
}),
166167
showGridControls(
167168
'mid-interaction',
168-
targetParent,
169+
gridContainerIdentifier(targetParent),
169170
newTargetCell?.gridCellCoordinates ?? null,
170171
null,
171172
),

0 commit comments

Comments
 (0)