= useEditorState(
Substores.metadata,
@@ -1129,9 +1152,11 @@ export const GridControlsComponent = ({ targets }: GridControlsProps) => {
// 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.
const grids = useGridData(
- uniqBy([...gridsWithVisibleControls, ...ancestorGrids], gridIdentifierSimilar).sort((a, b) => {
- const aDepth = a.type === 'GRID_CONTAINER' ? EP.fullDepth(a.path) : EP.fullDepth(a.path) - 1
- const bDepth = a.type === 'GRID_CONTAINER' ? EP.fullDepth(b.path) : EP.fullDepth(b.path) - 1
+ uniqBy([...gridsWithVisibleControls, ...ancestorGrids], gridIdentifiersSimilar).sort((a, b) => {
+ const aDepth =
+ a.type === 'GRID_CONTAINER' ? EP.fullDepth(a.container) : EP.fullDepth(a.item) - 1
+ const bDepth =
+ b.type === 'GRID_CONTAINER' ? EP.fullDepth(b.container) : EP.fullDepth(b.item) - 1
return aDepth - bDepth
}),
)
@@ -1144,18 +1169,17 @@ export const GridControlsComponent = ({ targets }: GridControlsProps) => {
{grids.map((grid) => {
- const gridPath =
- grid.identifier.type === 'GRID_CONTAINER'
- ? grid.identifier.path
- : EP.parentPath(grid.identifier.path)
+ const gridContainerOrComponentPath = getGridIdentifierContainerOrComponentPath(
+ grid.identifier,
+ )
const shouldHaveVisibleControls = gridsWithVisibleControls.some((g) => {
- const visibleControlPath = g.type === 'GRID_CONTAINER' ? g.path : EP.parentPath(g.path)
- return EP.pathsEqual(gridPath, visibleControlPath)
+ const visibleControlPath = getGridIdentifierContainerOrComponentPath(g)
+ return EP.pathsEqual(gridContainerOrComponentPath, visibleControlPath)
})
return (
@@ -1601,7 +1625,7 @@ interface GridResizeControlProps {
}
export const GridResizeControlsComponent = ({ target }: GridResizeControlProps) => {
- const gridTarget = target.type === 'GRID_CONTAINER' ? target.path : EP.parentPath(target.path)
+ const gridTarget = getGridIdentifierContainerOrComponentPath(target)
const colorTheme = useColorTheme()
const element = useEditorState(
@@ -1904,7 +1928,7 @@ export interface GridElementContainingBlockProps {
}
const GridElementContainingBlock = React.memo((props) => {
- const gridData = useGridMeasurementHelperData(props.gridPath)
+ const gridData = useGridMeasurementHelperData(props.gridPath, 'element')
const scale = useEditorState(
Substores.canvas,
(store) => store.editor.canvas.scale,
@@ -2075,6 +2099,14 @@ function gridPlaceholderWidthOrHeight(scale: number): string {
function useAllGrids(metadata: ElementInstanceMetadataMap) {
return React.useMemo(() => {
- return MetadataUtils.getAllGrids(metadata)
+ const gridPaths = MetadataUtils.getAllGrids(metadata)
+ const gridItemPaths = MetadataUtils.getAllGridItems(metadata)
+ const gridItemPathsWithoutGridPaths = gridItemPaths.filter(
+ (path) => !gridPaths.some((gridPath) => EP.isParentOf(gridPath, path)),
+ )
+ return {
+ grids: gridPaths,
+ gridItems: gridItemPathsWithoutGridPaths,
+ }
}, [metadata])
}
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 079cfb32238f..a0d08fe9d7f0 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
@@ -9,6 +9,7 @@ import { NO_OP } from '../../../../core/shared/utils'
import * as EP from '../../../../core/shared/element-path'
import { GridPaddingOutlineForDimension } from './grid-gap-control-component'
import { gridContainerIdentifier } from '../../../editor/store/editor-state'
+import { getGridIdentifierContainerOrComponentPath } from '../../canvas-strategies/strategies/grid-helpers'
export interface SubduedGridGapControlProps {
hoveredOrFocused: 'hovered' | 'focused'
@@ -33,8 +34,11 @@ export const SubduedGridGapControl = React.memo((pro
return (
{gridRowColumnInfo.map((gridData) => {
+ const gridContainerOrComponent = getGridIdentifierContainerOrComponentPath(
+ gridData.identifier,
+ )
return (
-
+
= (element: HTMLElement) => T
-export function getFromElement(path: ElementPath, fromElement: FromElement): T | undefined {
+export function getFromElement(
+ path: ElementPath,
+ fromElement: FromElement,
+ elementOrParent: ElementOrParent,
+): T | undefined {
const pathString = EP.toString(path)
const elements = document.querySelectorAll(
`#${CanvasContainerID} [${UTOPIA_PATH_KEY}^="${pathString}"]`,
@@ -19,8 +25,18 @@ export function getFromElement(path: ElementPath, fromElement: FromElement
!EP.isRootElementOfInstance(pathFromElement)) ||
EP.isRootElementOf(pathFromElement, path)
) {
- if (element instanceof HTMLElement) {
- return fromElement(element)
+ const realElement = (() => {
+ switch (elementOrParent) {
+ case 'element':
+ return element
+ case 'parent':
+ return element.parentElement
+ default:
+ assertNever(elementOrParent)
+ }
+ })()
+ if (realElement instanceof HTMLElement) {
+ return fromElement(realElement)
}
}
}
diff --git a/editor/src/components/canvas/dom-walker.ts b/editor/src/components/canvas/dom-walker.ts
index b96f1a660948..ab3f2962f950 100644
--- a/editor/src/components/canvas/dom-walker.ts
+++ b/editor/src/components/canvas/dom-walker.ts
@@ -62,11 +62,7 @@ import {
import type { UtopiaStoreAPI } from '../editor/store/store-hook'
import { UTOPIA_SCENE_ID_KEY, UTOPIA_UID_KEY } from '../../core/model/utopia-constants'
import { emptySet } from '../../core/shared/set-utils'
-import {
- getDeepestPathOnDomElement,
- getPathsOnDomElement,
- getPathStringsOnDomElement,
-} from '../../core/shared/uid-utils'
+import { getDeepestPathOnDomElement, getPathStringsOnDomElement } from '../../core/shared/uid-utils'
import { forceNotNull } from '../../core/shared/optional-utils'
import { fastForEach } from '../../core/shared/utils'
import type { EditorState, EditorStorePatched } from '../editor/store/editor-state'
@@ -83,7 +79,7 @@ import { runDOMWalker } from '../editor/actions/action-creators'
import { CanvasContainerOuterId } from './canvas-component-entry'
import { ElementsToRerenderGLOBAL } from './ui-jsx-canvas'
import type { GridCellGlobalFrames } from './canvas-strategies/strategies/grid-helpers'
-import { GridMeasurementHelperKey } from './controls/grid-controls-for-strategies'
+import { GridMeasurementHelperMap } from './controls/grid-controls-for-strategies'
export const ResizeObserver =
window.ResizeObserver ?? ResizeObserverSyntheticDefault.default ?? ResizeObserverSyntheticDefault
@@ -1079,18 +1075,12 @@ function measureGlobalFramesOfGridCells(
containerRectLazy: CanvasPoint | (() => CanvasPoint),
elementCanvasRectangleCache: ElementCanvasRectangleCache,
): GridCellGlobalFrames | null {
- const paths = getPathsOnDomElement(element)
-
let gridCellGlobalFrames: GridCellGlobalFrames | null = null
- const gridControlElement = (() => {
- for (let p of paths) {
- const maybeGridControlElement = document.getElementById(GridMeasurementHelperKey(p))
- if (maybeGridControlElement != null) {
- return maybeGridControlElement
- }
- }
- return null
- })()
+
+ const gridMeasurementHelperId = GridMeasurementHelperMap.current.get(element)
+
+ const gridControlElement =
+ gridMeasurementHelperId != null ? document.getElementById(gridMeasurementHelperId) : null
if (gridControlElement != null) {
gridCellGlobalFrames = []
diff --git a/editor/src/components/editor/store/editor-state.ts b/editor/src/components/editor/store/editor-state.ts
index 53e39973849b..91b563ddc7e8 100644
--- a/editor/src/components/editor/store/editor-state.ts
+++ b/editor/src/components/editor/store/editor-state.ts
@@ -826,36 +826,28 @@ export type GridIdentifier = GridContainerIdentifier | GridItemIdentifier
export interface GridContainerIdentifier {
type: 'GRID_CONTAINER'
- path: ElementPath
+ container: ElementPath
}
export function gridContainerIdentifier(path: ElementPath): GridContainerIdentifier {
return {
type: 'GRID_CONTAINER',
- path: path,
+ container: path,
}
}
export interface GridItemIdentifier {
type: 'GRID_ITEM'
- path: ElementPath
+ item: ElementPath
}
export function gridItemIdentifier(path: ElementPath): GridItemIdentifier {
return {
type: 'GRID_ITEM',
- path: path,
+ item: path,
}
}
-export function gridIdentifierSimilar(a: GridIdentifier, b: GridIdentifier): boolean {
- return (
- (a.type === b.type && EP.pathsEqual(a.path, b.path)) ||
- (a.type === 'GRID_ITEM' && b.type === 'GRID_CONTAINER' && EP.isParentOf(b.path, a.path)) ||
- (a.type === 'GRID_CONTAINER' && b.type === 'GRID_ITEM' && EP.isParentOf(a.path, b.path))
- )
-}
-
export interface GridControlData {
grid: GridIdentifier
targetCell: GridCellCoordinates | null // the cell under the mouse
diff --git a/editor/src/components/editor/store/store-deep-equality-instances.ts b/editor/src/components/editor/store/store-deep-equality-instances.ts
index 36f987d95400..0879447458ca 100644
--- a/editor/src/components/editor/store/store-deep-equality-instances.ts
+++ b/editor/src/components/editor/store/store-deep-equality-instances.ts
@@ -2856,14 +2856,14 @@ export const GridCellCoordinatesKeepDeepEquality: KeepDeepEqualityCall =
combine1EqualityCall(
- (identifier) => identifier.path,
+ (identifier) => identifier.container,
ElementPathKeepDeepEquality,
gridContainerIdentifier,
)
export const GridItemIdentifierKeepDeepEquality: KeepDeepEqualityCall =
combine1EqualityCall(
- (identifier) => identifier.path,
+ (identifier) => identifier.item,
ElementPathKeepDeepEquality,
gridItemIdentifier,
)
diff --git a/editor/src/core/model/element-metadata-utils.ts b/editor/src/core/model/element-metadata-utils.ts
index 062ec6344a04..7c3661bbcc77 100644
--- a/editor/src/core/model/element-metadata-utils.ts
+++ b/editor/src/core/model/element-metadata-utils.ts
@@ -416,6 +416,11 @@ export const MetadataUtils = {
.filter((m) => MetadataUtils.isGridLayoutedContainer(m))
.map((m) => m.elementPath)
},
+ getAllGridItems(metadata: ElementInstanceMetadataMap): Array {
+ return Object.values(metadata)
+ .filter((m) => MetadataUtils.isGridItem(metadata, m.elementPath))
+ .map((m) => m.elementPath)
+ },
isComponentInstanceFromMetadata(
metadata: ElementInstanceMetadataMap,
path: ElementPath,