diff --git a/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx index 9655e83687b5..cb0a48afbbd2 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/absolute-resize-bounding-box-strategy.tsx @@ -14,7 +14,7 @@ import { import type { ElementPath } from '../../../../core/shared/project-file-types' import type { AllElementProps } from '../../../editor/store/editor-state' import { - getElementFromProjectContents, + getJSXElementFromProjectContents, trueUpElementChanged, } from '../../../editor/store/editor-state' import { getSafeGroupChildConstraintsArray } from '../../../inspector/fill-hug-fixed-control' @@ -166,7 +166,7 @@ export function absoluteResizeBoundingBoxStrategy( ) const commandsForSelectedElements = retargetedTargets.flatMap((selectedElement) => { - const element = getElementFromProjectContents( + const element = getJSXElementFromProjectContents( selectedElement, canvasState.projectContents, ) diff --git a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx index 5c69be37c265..84b16fa71713 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx +++ b/editor/src/components/canvas/canvas-strategies/strategies/convert-to-absolute-and-move-strategy.tsx @@ -38,7 +38,7 @@ import { } from '../../../../core/shared/math-utils' import type { ElementPath } from '../../../../core/shared/project-file-types' import { fastForEach } from '../../../../core/shared/utils' -import { getElementFromProjectContents } from '../../../editor/store/editor-state' +import { getJSXElementFromProjectContents } from '../../../editor/store/editor-state' import type { FullFrame } from '../../../frame' import { getFullFrame } from '../../../frame' import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks' @@ -438,7 +438,7 @@ function filterPinsToSet( path: ElementPath, canvasState: InteractionCanvasState, ): Array { - const element = getElementFromProjectContents(path, canvasState.projectContents) + const element = getJSXElementFromProjectContents(path, canvasState.projectContents) if (element == null) { return ['top', 'left', 'width', 'height'] } else { diff --git a/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts b/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts index 264415144dfc..627411b996e7 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/reparent-helpers/reparent-property-changes.ts @@ -23,7 +23,7 @@ import type { ElementPath, PropertyPath } from '../../../../../core/shared/proje import * as PP from '../../../../../core/shared/property-path' import type { ProjectContentTreeRoot } from '../../../../assets' import type { AllElementProps } from '../../../../editor/store/editor-state' -import { getElementFromProjectContents } from '../../../../editor/store/editor-state' +import { getJSXElementFromProjectContents } from '../../../../editor/store/editor-state' import type { CSSPosition, Direction } from '../../../../inspector/common/css-utils' import { cssNumber } from '../../../../inspector/common/css-utils' import { stylePropPathMappingFn } from '../../../../inspector/common/property-path-hooks' @@ -78,7 +78,7 @@ export function getAbsoluteReparentPropertyChanges( newParentStartingMetadata: ElementInstanceMetadataMap, projectContents: ProjectContentTreeRoot, ): Array { - const element: JSXElement | null = getElementFromProjectContents(target, projectContents) + const element: JSXElement | null = getJSXElementFromProjectContents(target, projectContents) const originalParentInstance = MetadataUtils.findElementByElementPath( targetStartingMetadata, diff --git a/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts b/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts index b77bf561d457..79a6e56e5bad 100644 --- a/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts +++ b/editor/src/components/canvas/canvas-strategies/strategies/shared-move-strategies-helpers.ts @@ -26,7 +26,7 @@ import { } from '../../../../core/shared/math-utils' import type { ElementPath } from '../../../../core/shared/project-file-types' -import { getElementFromProjectContents } from '../../../editor/store/editor-state' +import { getJSXElementFromProjectContents } from '../../../editor/store/editor-state' import { stylePropPathMappingFn } from '../../../inspector/common/property-path-hooks' import { determineConstrainedDragAxis } from '../../canvas-controls-frame' import type { CanvasFrameAndTarget } from '../../canvas-types' @@ -177,7 +177,10 @@ export function getMoveCommandsForSelectedElement( commands: Array intendedBounds: Array } { - const element: JSXElement | null = getElementFromProjectContents(selectedElement, projectContents) + const element: JSXElement | null = getJSXElementFromProjectContents( + selectedElement, + projectContents, + ) const elementMetadata = MetadataUtils.findElementByElementPath( startingMetadata, // TODO should this be using the current metadata? diff --git a/editor/src/components/canvas/canvas-utils.ts b/editor/src/components/canvas/canvas-utils.ts index d644ab75b9a5..13bc58f6c8df 100644 --- a/editor/src/components/canvas/canvas-utils.ts +++ b/editor/src/components/canvas/canvas-utils.ts @@ -15,7 +15,6 @@ import { import { findElementAtPath, findJSXElementAtPath, - findJSXElementLikeAtPath, getSimpleAttributeAtPath, MetadataUtils, } from '../../core/model/element-metadata-utils' @@ -104,6 +103,8 @@ import { withUnderlyingTargetFromEditorState, modifyUnderlyingElementForOpenFile, isSyntheticNavigatorEntry, + getElementFromProjectContents, + getJSXElementFromProjectContents, } from '../editor/store/editor-state' import * as Frame from '../frame' import { getImageSizeFromMetadata, MultipliersForImages, scaleImageDimensions } from '../images' @@ -1851,9 +1852,9 @@ export function reorderComponent( ): Array { let workingComponents = [...components] - const jsxElement = findElementAtPath(target, workingComponents) + const jsxElement = getElementFromProjectContents(target, projectContents) const parentPath = EP.parentPath(target) - const parentElement = findJSXElementLikeAtPath(parentPath, workingComponents) + const parentElement = getJSXElementFromProjectContents(parentPath, projectContents) if (jsxElement != null && parentElement != null) { const indexOfRemovedElement = parentElement.children.indexOf(jsxElement) diff --git a/editor/src/components/editor/actions/actions.tsx b/editor/src/components/editor/actions/actions.tsx index ab9fd2bad958..32ca0df69cbe 100644 --- a/editor/src/components/editor/actions/actions.tsx +++ b/editor/src/components/editor/actions/actions.tsx @@ -154,12 +154,12 @@ import { } from '../../assets' import type { CanvasFrameAndTarget, PinOrFlexFrameChange } from '../../canvas/canvas-types' import { pinSizeChange } from '../../canvas/canvas-types' +import type { SkipFrameChange } from '../../canvas/canvas-utils' import { canvasPanelOffsets, duplicate, getFrameChange, moveTemplate, - SkipFrameChange, updateFramesOfScenesAndComponents, } from '../../canvas/canvas-utils' import type { ResizeLeftPane, SetFocus } from '../../common/actions' @@ -1017,17 +1017,10 @@ function setZIndexOnSelected( } const indexPosition = indexPositionForAdjustment(selectedView, working, index) - return editorMoveTemplate( - selectedView, - selectedView, - SkipFrameChange, - indexPosition, - EP.parentPath(selectedView), - null, - editor, - null, - null, - ).editor + + const reorderElementCommand = reorderElement('always', selectedView, indexPosition) + + return foldAndApplyCommandsSimple(working, [reorderElementCommand]) }, editor) } @@ -1569,17 +1562,9 @@ export const UPDATE_FNS = { return setCanvasFramesInnerNew(editor, action.framesAndTargets, null) }, SET_Z_INDEX: (action: SetZIndex, editor: EditorModel): EditorModel => { - return editorMoveTemplate( - action.target, - action.target, - SkipFrameChange, - action.indexPosition, - EP.parentPath(action.target), - null, - editor, - null, - null, - ).editor + return foldAndApplyCommandsSimple(editor, [ + reorderElement('always', action.target, action.indexPosition), + ]) }, DELETE_SELECTED: (editorForAction: EditorModel, dispatch: EditorDispatch): EditorModel => { // This function returns whether the given path will have the following deletion behavior: diff --git a/editor/src/components/editor/store/editor-state.ts b/editor/src/components/editor/store/editor-state.ts index 52c94d3273dd..51106f7c66c7 100644 --- a/editor/src/components/editor/store/editor-state.ts +++ b/editor/src/components/editor/store/editor-state.ts @@ -3462,7 +3462,7 @@ export function forUnderlyingTargetFromEditorState( withUnderlyingTargetFromEditorState(target, editor, {}, withTarget) } -export function getElementFromProjectContents( +export function getJSXElementFromProjectContents( target: ElementPath | null, projectContents: ProjectContentTreeRoot, ): JSXElement | null { @@ -3475,6 +3475,13 @@ export function getElementFromProjectContents( }) } +export function getElementFromProjectContents( + target: ElementPath | null, + projectContents: ProjectContentTreeRoot, +): JSXElementChild | null { + return withUnderlyingTarget(target, projectContents, null, (_, element) => element) +} + export function getCurrentTheme(userConfiguration: ThemeSubstate['userState']): Theme { const currentTheme = userConfiguration.themeConfig ?? DefaultTheme if (currentTheme === 'system') { diff --git a/editor/src/components/inspector/common/property-path-hooks.ts b/editor/src/components/inspector/common/property-path-hooks.ts index 808dfa482ee4..e75ea6bb0f72 100644 --- a/editor/src/components/inspector/common/property-path-hooks.ts +++ b/editor/src/components/inspector/common/property-path-hooks.ts @@ -41,32 +41,14 @@ import { isLayoutPropDetectedInCSS, maybePrintCSSValue, parseAnyParseableValue, - ParsedCSSPropertiesKeysNoLayout, printCSSValue, - cssNumber, isTrivialDefaultValue, - CSSNumber, } from '../../../components/inspector/common/css-utils' import type { StyleLayoutProp } from '../../../core/layout/layout-helpers-new' -import { findElementAtPath, MetadataUtils } from '../../../core/model/element-metadata-utils' -import { - getFilePathForImportedComponent, - getUtopiaJSXComponentsFromSuccess, - isHTMLComponent, - isUtopiaAPIComponent, -} from '../../../core/model/project-file-utils' -import { addUniquely, mapDropNulls, stripNulls } from '../../../core/shared/array-utils' +import { isHTMLComponent, isUtopiaAPIComponent } from '../../../core/model/project-file-utils' +import { stripNulls } from '../../../core/shared/array-utils' import type { Either } from '../../../core/shared/either' -import { - defaultEither, - eitherToMaybe, - flatMapEither, - foldEither, - isRight, - left, - mapEither, - unwrapEither, -} from '../../../core/shared/either' +import { eitherToMaybe, flatMapEither, isRight, left } from '../../../core/shared/either' import type { JSXAttributes, ComputedStyle, @@ -75,11 +57,8 @@ import type { } from '../../../core/shared/element-template' import { getJSXElementNameLastPart, - getJSXElementNameNoPathName, isJSXElement, - UtopiaJSXComponent, getJSXAttribute, - JSExpression, isRegularJSXAttribute, clearExpressionUniqueIDs, } from '../../../core/shared/element-template' @@ -92,31 +71,24 @@ import { getModifiableJSXAttributeAtPath, jsxSimpleAttributeToValue, } from '../../../core/shared/jsx-attributes' -import { forEachOptional, optionalMap } from '../../../core/shared/optional-utils' +import { optionalMap } from '../../../core/shared/optional-utils' import type { PropertyPath, ElementPath, PropertyPathPart, } from '../../../core/shared/project-file-types' -import { fastForEach } from '../../../core/shared/utils' -import { KeepDeepEqualityCall } from '../../../utils/deep-equality' import { - keepDeepReferenceEqualityIfPossible, useKeepReferenceEqualityIfPossible, useKeepShallowReferenceEquality, } from '../../../utils/react-performance' import { default as Utils } from '../../../utils/utils' -import { descriptionParseError, ParseResult } from '../../../utils/value-parser-utils' import type { ReadonlyRef } from './inspector-utils' import type { MapLike } from 'typescript' import { omitWithPredicate } from '../../../core/shared/object-utils' import { UtopiaKeys } from '../../../core/model/utopia-constants' -import fastDeepEquals from 'fast-deep-equal' -import { getPropertyControlNames } from '../../../core/property-controls/property-control-values' import type { EditorAction } from '../../editor/action-types' import { useDispatch } from '../../editor/store/dispatch-context' -import { Optic } from '../../../core/shared/optics/optics' import { eitherRight, fromTypeGuard } from '../../../core/shared/optics/optic-creators' import { modify } from '../../../core/shared/optics/optic-utilities' diff --git a/editor/src/components/inspector/inspector.tsx b/editor/src/components/inspector/inspector.tsx index fd3db9364472..b1a0a5cfc548 100644 --- a/editor/src/components/inspector/inspector.tsx +++ b/editor/src/components/inspector/inspector.tsx @@ -26,9 +26,9 @@ import { import type { ElementsToRerender } from '../editor/store/editor-state' import { - getElementFromProjectContents, getJSXComponentsAndImportsForPathFromState, isOpenFileUiJs, + getElementFromProjectContents, } from '../editor/store/editor-state' import { Substores, useEditorState, useRefEditorState } from '../editor/store/store-hook' import { diff --git a/editor/src/core/model/element-metadata-utils.ts b/editor/src/core/model/element-metadata-utils.ts index 9e3a3d6e1e61..3b252ad1d5d9 100644 --- a/editor/src/core/model/element-metadata-utils.ts +++ b/editor/src/core/model/element-metadata-utils.ts @@ -1634,30 +1634,6 @@ export const MetadataUtils = { return null } }, - getJSXElementBaseName(path: ElementPath, components: Array): string | null { - const jsxElement = findElementAtPath(path, components) - if (jsxElement != null) { - if (isJSXElement(jsxElement)) { - return jsxElement.name.baseVariable - } else { - return null - } - } else { - return null - } - }, - getJSXElementTagName(path: ElementPath, components: Array): string | null { - const jsxElement = findElementAtPath(path, components) - if (jsxElement != null) { - if (isJSXElement(jsxElement)) { - return getJSXElementNameAsString(jsxElement.name) - } else { - return null - } - } else { - return null - } - }, getDuplicationParentTargets(targets: ElementPath[]): ElementPath | null { return EP.getCommonParent(targets) }, @@ -2659,20 +2635,6 @@ export function findJSXElementAtPath( }, elem) } -export function findJSXElementLikeAtPath( - target: ElementPath | null, - components: Array, -): JSXElementLike | null { - const elem = findElementAtPath(target, components) - return Utils.optionalMap((e) => { - if (isJSXElementLike(e)) { - return e - } else { - return null - } - }, elem) -} - export function getScenePropsOrElementAttributes( target: ElementPath, metadata: ElementInstanceMetadataMap, diff --git a/editor/src/core/tailwind/tailwind-options.tsx b/editor/src/core/tailwind/tailwind-options.tsx index 0b5fcf53b5c4..addcd7c513d7 100644 --- a/editor/src/core/tailwind/tailwind-options.tsx +++ b/editor/src/core/tailwind/tailwind-options.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { filterDuplicates, flatMapArray, last, stripNulls } from '../shared/array-utils' +import { filterDuplicates, flatMapArray, stripNulls } from '../shared/array-utils' import { mapToArray, mapValues } from '../shared/object-utils' import { NO_OP } from '../shared/utils' import { @@ -9,24 +9,18 @@ import { } from '../third-party/tailwind-defaults' import Highlighter from 'react-highlight-words' import type { ElementPath } from '../shared/project-file-types' -import { isParseSuccess, isTextFile } from '../shared/project-file-types' import { Substores, useEditorState, useRefEditorState, } from '../../components/editor/store/store-hook' -import { getOpenUIJSFileKey } from '../../components/editor/store/editor-state' -import { normalisePathToUnderlyingTarget } from '../../components/custom-code/code-file' -import type { ProjectContentTreeRoot } from '../../components/assets' -import { getProjectFileByFilePath } from '../../components/assets' +import { getElementFromProjectContents } from '../../components/editor/store/editor-state' import type { JSXElementChild } from '../shared/element-template' import { modifiableAttributeIsAttributeNotFound, isJSXElement, modifiableAttributeIsAttributeValue, } from '../shared/element-template' -import { findElementAtPath, MetadataUtils } from '../model/element-metadata-utils' -import { getUtopiaJSXComponentsFromSuccess } from '../model/project-file-utils' import { eitherToMaybe, flatMapEither, foldEither } from '../shared/either' import { getModifiableJSXAttributeAtPath, @@ -228,29 +222,6 @@ export function useFilteredOptions( }, [filter, maxResults, onEmptyResults]) } -function getJSXElementForTarget( - target: ElementPath, - openUIJSFileKey: string, - projectContents: ProjectContentTreeRoot, -): JSXElementChild | null { - const underlyingTarget = normalisePathToUnderlyingTarget(projectContents, target) - const underlyingPath = - underlyingTarget.type === 'NORMALISE_PATH_SUCCESS' ? underlyingTarget.filePath : openUIJSFileKey - const projectFile = getProjectFileByFilePath(projectContents, underlyingPath) - if ( - projectFile != null && - isTextFile(projectFile) && - isParseSuccess(projectFile.fileContents.parsed) - ) { - return findElementAtPath( - target, - getUtopiaJSXComponentsFromSuccess(projectFile.fileContents.parsed), - ) - } else { - return null - } -} - function getClassNameAttribute(element: JSXElementChild | null): { value: string | null isSettable: boolean @@ -285,16 +256,10 @@ export function useGetSelectedClasses(): { const metadataRef = useRefEditorState((store) => store.editor.jsxMetadata) const elements = useEditorState( Substores.fullStore, - (store) => { - const openUIJSFileKey = getOpenUIJSFileKey(store.editor) - if (openUIJSFileKey == null) { - return [] - } else { - return store.editor.selectedViews.map((elementPath) => - getJSXElementForTarget(elementPath, openUIJSFileKey, store.editor.projectContents), - ) - } - }, + (store) => + store.editor.selectedViews.map((elementPath) => + getElementFromProjectContents(elementPath, store.editor.projectContents), + ), 'ClassNameSelect elements', ) @@ -314,17 +279,13 @@ export function useGetSelectedClasses(): { return fromAttributes } else { const elementPath = elementPaths[index] - const elementMetadata = MetadataUtils.findElementByElementPath( - metadataRef.current, - elementPath, - ) return { value: allElementPropsRef.current[EP.toString(elementPath)]?.className, isSettable: fromAttributes.isSettable, } } }), - [elements, elementPaths, metadataRef, allElementPropsRef], + [elements, elementPaths, allElementPropsRef], ) const isSettable = diff --git a/editor/src/utils/clipboard.ts b/editor/src/utils/clipboard.ts index 6f06dba88639..b1ae057d0f68 100644 --- a/editor/src/utils/clipboard.ts +++ b/editor/src/utils/clipboard.ts @@ -7,10 +7,14 @@ import type { EditorState, PastePostActionMenuData, } from '../components/editor/store/editor-state' -import { getOpenUIJSFileKey, withUnderlyingTarget } from '../components/editor/store/editor-state' +import { + getElementFromProjectContents, + getOpenUIJSFileKey, + withUnderlyingTarget, +} from '../components/editor/store/editor-state' import { getFrameAndMultiplier } from '../components/images' import * as EP from '../core/shared/element-path' -import { findElementAtPath, MetadataUtils } from '../core/model/element-metadata-utils' +import { MetadataUtils } from '../core/model/element-metadata-utils' import type { ElementInstanceMetadataMap } from '../core/shared/element-template' import { isJSXConditionalExpression, @@ -332,29 +336,29 @@ export function createClipboardDataFromSelection( const underlyingTarget = normalisePathToUnderlyingTarget(editor.projectContents, target) const targetPathSuccess = normalisePathSuccessOrThrowError(underlyingTarget) const projectFile = getProjectFileByFilePath(editor.projectContents, targetPathSuccess.filePath) + if ( - projectFile != null && - isTextFile(projectFile) && - isParseSuccess(projectFile.fileContents.parsed) + projectFile == null || + !isTextFile(projectFile) || + !isParseSuccess(projectFile.fileContents.parsed) ) { - const components = getUtopiaJSXComponentsFromSuccess(projectFile.fileContents.parsed) - const elementToPaste = findElementAtPath(target, components) - if (elementToPaste == null || targetPathSuccess.normalisedPath == null) { - return null - } else { - const requiredImports = getRequiredImportsForElement( - target, - editor.projectContents, - editor.nodeModules.files, - targetPathSuccess.filePath, - builtInDependencies, - ) + return null + } - return EditorActions.elementPaste(elementToPaste, requiredImports, target) - } - } else { + const elementToPaste = getElementFromProjectContents(target, editor.projectContents) + if (elementToPaste == null || targetPathSuccess.normalisedPath == null) { return null } + + const requiredImports = getRequiredImportsForElement( + target, + editor.projectContents, + editor.nodeModules.files, + targetPathSuccess.filePath, + builtInDependencies, + ) + + return EditorActions.elementPaste(elementToPaste, requiredImports, target) }, filteredSelectedViews) const copyDataWithPropsPreserved: ElementPasteWithMetadata = {