From 426daec51f83f319a87ccf1a9e48a71718a1fd07 Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Thu, 28 Sep 2023 18:41:44 +0200
Subject: [PATCH 1/9] delete existing empty spans
---
.../text-editor/text-editor.spec.browser2.tsx | 17 ++---------------
.../src/components/text-editor/text-editor.tsx | 2 +-
2 files changed, 3 insertions(+), 16 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.spec.browser2.tsx b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
index b1378b65fd2c..83b1f7f38aae 100644
--- a/editor/src/components/text-editor/text-editor.spec.browser2.tsx
+++ b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
@@ -357,7 +357,7 @@ describe('Use the text editor', () => {
})
describe('blur', () => {
describe('when the element is empty', () => {
- it('keeps existing elements', async () => {
+ it('deletes existing elements', async () => {
const editor = await renderTestEditorWithCode(projectWithText, 'await-first-dom-report')
await enterTextEditMode(editor)
@@ -375,20 +375,7 @@ describe('Use the text editor', () => {
export var storyboard = (
-
-
-
+
)`),
)
})
diff --git a/editor/src/components/text-editor/text-editor.tsx b/editor/src/components/text-editor/text-editor.tsx
index 1c15a6935aaa..751130785c18 100644
--- a/editor/src/components/text-editor/text-editor.tsx
+++ b/editor/src/components/text-editor/text-editor.tsx
@@ -342,7 +342,7 @@ const TextEditor = React.memo((props: TextEditorProps) => {
return () => {
const content = currentElement.textContent
if (content != null) {
- if (elementState === 'new' && content.replace(/\n/g, '') === '') {
+ if (content.replace(/\n/g, '') === '') {
requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
} else {
if (elementState != null && savedContentRef.current !== content) {
From 2c67e18b0c8abe4719cb9e28bd93a8789be3a013 Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 09:49:17 +0200
Subject: [PATCH 2/9] only remove spans
---
editor/src/components/text-editor/text-editor.tsx | 15 +++++++++++++--
editor/src/core/model/element-metadata-utils.ts | 3 +++
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.tsx b/editor/src/components/text-editor/text-editor.tsx
index 751130785c18..03e7924a2d7b 100644
--- a/editor/src/components/text-editor/text-editor.tsx
+++ b/editor/src/components/text-editor/text-editor.tsx
@@ -342,7 +342,7 @@ const TextEditor = React.memo((props: TextEditorProps) => {
return () => {
const content = currentElement.textContent
if (content != null) {
- if (content.replace(/\n/g, '') === '') {
+ if (elementState === 'new' && content.replace(/\n/g, '') === '') {
requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
} else {
if (elementState != null && savedContentRef.current !== content) {
@@ -437,7 +437,18 @@ const TextEditor = React.memo((props: TextEditorProps) => {
} else {
dispatch([updateEditorMode(EditorModes.selectMode(null, false, 'none'))])
}
- }, [dispatch, elementPath, elementState, textProp])
+
+ // remove dangling empty spans
+ if (
+ content != null &&
+ content.replace(/^\n/, '').length === 0 &&
+ MetadataUtils.isMaybeSpan(
+ MetadataUtils.findElementByElementPath(metadataRef.current, elementPath),
+ )
+ ) {
+ requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
+ }
+ }, [dispatch, elementPath, elementState, textProp, metadataRef])
const editorProps: React.DetailedHTMLProps<
React.HTMLAttributes,
diff --git a/editor/src/core/model/element-metadata-utils.ts b/editor/src/core/model/element-metadata-utils.ts
index c20816f137ce..78bbc25b403e 100644
--- a/editor/src/core/model/element-metadata-utils.ts
+++ b/editor/src/core/model/element-metadata-utils.ts
@@ -903,6 +903,9 @@ export const MetadataUtils = {
isSpan(instance: ElementInstanceMetadata): boolean {
return this.isElementOfType(instance, 'span')
},
+ isMaybeSpan(instance: ElementInstanceMetadata | null): boolean {
+ return instance != null && this.isElementOfType(instance, 'span')
+ },
targetIsScene(metadata: ElementInstanceMetadataMap, path: ElementPath): boolean {
const elementMetadata = MetadataUtils.findElementByElementPath(metadata, path)
return elementMetadata != null && isSceneFromMetadata(elementMetadata)
From ebb4b12a58bb4aa3f86905f008723b7324253998 Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 09:52:39 +0200
Subject: [PATCH 3/9] helper
---
editor/src/components/text-editor/text-editor.tsx | 15 ++++++++++++---
editor/src/core/model/element-metadata-utils.ts | 3 ---
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.tsx b/editor/src/components/text-editor/text-editor.tsx
index 03e7924a2d7b..338d553069e3 100644
--- a/editor/src/components/text-editor/text-editor.tsx
+++ b/editor/src/components/text-editor/text-editor.tsx
@@ -442,9 +442,7 @@ const TextEditor = React.memo((props: TextEditorProps) => {
if (
content != null &&
content.replace(/^\n/, '').length === 0 &&
- MetadataUtils.isMaybeSpan(
- MetadataUtils.findElementByElementPath(metadataRef.current, elementPath),
- )
+ canDeleteWhenEmpty(metadataRef.current, elementPath)
) {
requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
}
@@ -604,3 +602,14 @@ function getSaveAction(
): EditorAction {
return updateText(elementPath, escapeHTML(content, textProp), textProp)
}
+
+function canDeleteWhenEmpty(jsxMetadata: ElementInstanceMetadataMap, path: ElementPath): boolean {
+ const element = MetadataUtils.findElementByElementPath(jsxMetadata, path)
+ if (element == null) {
+ return false
+ }
+ if (!MetadataUtils.isSpan(element)) {
+ return false
+ }
+ return true
+}
diff --git a/editor/src/core/model/element-metadata-utils.ts b/editor/src/core/model/element-metadata-utils.ts
index 78bbc25b403e..c20816f137ce 100644
--- a/editor/src/core/model/element-metadata-utils.ts
+++ b/editor/src/core/model/element-metadata-utils.ts
@@ -903,9 +903,6 @@ export const MetadataUtils = {
isSpan(instance: ElementInstanceMetadata): boolean {
return this.isElementOfType(instance, 'span')
},
- isMaybeSpan(instance: ElementInstanceMetadata | null): boolean {
- return instance != null && this.isElementOfType(instance, 'span')
- },
targetIsScene(metadata: ElementInstanceMetadataMap, path: ElementPath): boolean {
const elementMetadata = MetadataUtils.findElementByElementPath(metadata, path)
return elementMetadata != null && isSceneFromMetadata(elementMetadata)
From 29b573f9226ca7ffbfef54177ee0f670bfbd553c Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 10:08:40 +0200
Subject: [PATCH 4/9] delete if not styled and has no event handlers
---
.../components/text-editor/text-editor.tsx | 49 +++++++++++++++++--
1 file changed, 45 insertions(+), 4 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.tsx b/editor/src/components/text-editor/text-editor.tsx
index 338d553069e3..27ed7e893bbb 100644
--- a/editor/src/components/text-editor/text-editor.tsx
+++ b/editor/src/components/text-editor/text-editor.tsx
@@ -31,7 +31,7 @@ import { EditorModes } from '../editor/editor-modes'
import { useDispatch } from '../editor/store/dispatch-context'
import { MainEditorStoreProvider } from '../editor/store/store-context-providers'
import { Substores, useEditorState, useRefEditorState } from '../editor/store/store-hook'
-import { printCSSNumber } from '../inspector/common/css-utils'
+import { DOMEventHandlerNames, printCSSNumber } from '../inspector/common/css-utils'
import {
toggleTextBold,
toggleTextItalic,
@@ -43,6 +43,8 @@ import { mapArrayToDictionary } from '../../core/shared/array-utils'
import { TextRelatedProperties } from '../../core/properties/css-properties'
import { assertNever } from '../../core/shared/utils'
import { notice } from '../common/notice'
+import type { AllElementProps } from '../editor/store/editor-state'
+import { toString } from '../../core/shared/element-path'
export const TextEditorSpanId = 'text-editor'
@@ -305,6 +307,7 @@ const TextEditor = React.memo((props: TextEditorProps) => {
)
const metadataRef = useRefEditorState((store) => store.editor.jsxMetadata)
+ const allElementPropsRef = useRefEditorState((store) => store.editor.allElementProps)
const savedContentRef = React.useRef(null)
@@ -442,11 +445,11 @@ const TextEditor = React.memo((props: TextEditorProps) => {
if (
content != null &&
content.replace(/^\n/, '').length === 0 &&
- canDeleteWhenEmpty(metadataRef.current, elementPath)
+ canDeleteWhenEmpty(metadataRef.current, elementPath, allElementPropsRef.current)
) {
requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
}
- }, [dispatch, elementPath, elementState, textProp, metadataRef])
+ }, [dispatch, elementPath, elementState, textProp, metadataRef, allElementPropsRef])
const editorProps: React.DetailedHTMLProps<
React.HTMLAttributes,
@@ -603,7 +606,26 @@ function getSaveAction(
return updateText(elementPath, escapeHTML(content, textProp), textProp)
}
-function canDeleteWhenEmpty(jsxMetadata: ElementInstanceMetadataMap, path: ElementPath): boolean {
+const allowedStyleKeysForDeletion: string[] = [
+ 'position',
+ 'top',
+ 'left',
+ 'bottom',
+ 'right',
+ 'width',
+ 'height',
+ 'wordBreak',
+ 'fontSize',
+ 'fontWeight',
+ 'fontFamily',
+ 'font',
+]
+
+function canDeleteWhenEmpty(
+ jsxMetadata: ElementInstanceMetadataMap,
+ path: ElementPath,
+ allElementProps: AllElementProps,
+): boolean {
const element = MetadataUtils.findElementByElementPath(jsxMetadata, path)
if (element == null) {
return false
@@ -611,5 +633,24 @@ function canDeleteWhenEmpty(jsxMetadata: ElementInstanceMetadataMap, path: Eleme
if (!MetadataUtils.isSpan(element)) {
return false
}
+
+ const elementProps = allElementProps[toString(path)]
+ if (elementProps == null) {
+ return false
+ }
+
+ // it must not have defined styling
+ if (
+ elementProps.style != null &&
+ Object.keys(elementProps.style).some((key) => !allowedStyleKeysForDeletion.includes(key))
+ ) {
+ return false
+ }
+
+ // it must not have defined event handlers
+ if (Object.keys(elementProps).some((prop) => DOMEventHandlerNames.includes(prop as any))) {
+ return false
+ }
+
return true
}
From 2e637dd080c15aa1a27351ca07799152d24825b6 Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 10:32:27 +0200
Subject: [PATCH 5/9] style/handlers constraints
---
.../text-editor/text-editor.spec.browser2.tsx | 265 +++++++++++++++++-
.../components/text-editor/text-editor.tsx | 26 +-
2 files changed, 270 insertions(+), 21 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.spec.browser2.tsx b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
index 83b1f7f38aae..cdf888261ca5 100644
--- a/editor/src/components/text-editor/text-editor.spec.browser2.tsx
+++ b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
@@ -357,7 +357,7 @@ describe('Use the text editor', () => {
})
describe('blur', () => {
describe('when the element is empty', () => {
- it('deletes existing elements', async () => {
+ it('keeps existing elements', async () => {
const editor = await renderTestEditorWithCode(projectWithText, 'await-first-dom-report')
await enterTextEditMode(editor)
@@ -375,7 +375,20 @@ describe('Use the text editor', () => {
export var storyboard = (
-
+
+
+
)`),
)
})
@@ -407,6 +420,177 @@ describe('Use the text editor', () => {
)`),
)
})
+ it('deletes existing span elements', async () => {
+ const editor = await renderTestEditorWithCode(
+ formatTestProjectCode(`
+ import * as React from 'react'
+ import { Storyboard } from 'utopia-api'
+
+ export var storyboard = (
+
+
+ Hello
+
+
+ )
+ `),
+ 'await-first-dom-report',
+ )
+
+ await enterTextEditMode(editor, 'span')
+
+ deleteTypedText()
+
+ await closeTextEditor()
+ await editor.getDispatchFollowUpActionsFinished()
+
+ expect(editor.getEditorState().editor.mode.type).toEqual('select')
+ expect(getPrintedUiJsCode(editor.getEditorState())).toEqual(
+ formatTestProjectCode(`
+ import * as React from 'react'
+ import { Storyboard } from 'utopia-api'
+
+ export var storyboard = (
+
+ )
+ `),
+ )
+ })
+ it('does not delete span elements with styling', async () => {
+ const editor = await renderTestEditorWithCode(
+ formatTestProjectCode(`
+ import * as React from 'react'
+ import { Storyboard } from 'utopia-api'
+
+ export var storyboard = (
+
+
+ Hello
+
+
+ )
+ `),
+ 'await-first-dom-report',
+ )
+
+ await enterTextEditMode(editor, 'span')
+
+ deleteTypedText()
+
+ await closeTextEditor()
+ await editor.getDispatchFollowUpActionsFinished()
+
+ expect(editor.getEditorState().editor.mode.type).toEqual('select')
+ expect(getPrintedUiJsCode(editor.getEditorState())).toEqual(
+ formatTestProjectCode(`
+ import * as React from 'react'
+ import { Storyboard } from 'utopia-api'
+
+ export var storyboard = (
+
+
+
+ )
+ `),
+ )
+ })
+ it('does not delete span elements with event handlers', async () => {
+ const editor = await renderTestEditorWithCode(
+ formatTestProjectCode(`
+ import * as React from 'react'
+ import { Storyboard } from 'utopia-api'
+
+ export var storyboard = (
+
+ console.log('click')}
+ >
+ Hello
+
+
+ )
+ `),
+ 'await-first-dom-report',
+ )
+
+ await enterTextEditMode(editor, 'span')
+
+ deleteTypedText()
+
+ await closeTextEditor()
+ await editor.getDispatchFollowUpActionsFinished()
+
+ expect(editor.getEditorState().editor.mode.type).toEqual('select')
+ expect(getPrintedUiJsCode(editor.getEditorState())).toEqual(
+ formatTestProjectCode(`
+ import * as React from 'react'
+ import { Storyboard } from 'utopia-api'
+
+ export var storyboard = (
+
+ console.log('click')}
+ />
+
+ )
+ `),
+ )
+ })
})
describe('collapses runs of text', () => {
it('only when the elements involved are eligible', async () => {
@@ -1784,20 +1968,23 @@ async function testModifierExpectingWayTooManySavesTheFirstTime(
return { before, after }
}
-async function enterTextEditMode(editor: EditorRenderResult): Promise {
+async function enterTextEditMode(
+ editor: EditorRenderResult,
+ testId: string = 'div',
+): Promise {
const canvasControlsLayer = editor.renderedDOM.getByTestId(CanvasControlsContainerID)
- const div = editor.renderedDOM.getByTestId('div')
- const divBounds = div.getBoundingClientRect()
- const divCorner = {
- x: divBounds.x + 50,
- y: divBounds.y + 40,
+ const element = editor.renderedDOM.getByTestId(testId)
+ const bounds = element.getBoundingClientRect()
+ const corner = {
+ x: bounds.x + 1,
+ y: bounds.y + 1,
}
FOR_TESTS_setNextGeneratedUid('text-span')
await pressKey('t')
await editor.getDispatchFollowUpActionsFinished()
- await mouseClickAtPoint(canvasControlsLayer, divCorner)
+ await mouseClickAtPoint(canvasControlsLayer, corner)
await editor.getDispatchFollowUpActionsFinished()
}
@@ -1910,6 +2097,66 @@ function projectWithoutTextWithExtraStyle(extraStyleProps: { [prop: string]: str
`)
}
+const projectWithTextSpan = formatTestProjectCode(`
+import * as React from 'react'
+import { Storyboard } from 'utopia-api'
+
+
+export var storyboard = (
+
+
+ Hello
+
+
+)
+`)
+
+function projectWithoutTextSpanWithExtraStyle(extraStyleProps: { [prop: string]: string }) {
+ const styleProps = {
+ backgroundColor: '#0091FFAA',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ width: 288,
+ height: 362,
+ ...extraStyleProps,
+ }
+
+ return formatTestProjectCode(`
+ import * as React from 'react'
+ import { Storyboard } from 'utopia-api'
+
+
+ export var storyboard = (
+
+
+ Hello
+
+
+ )
+ `)
+}
+
const emptyProject = formatTestProjectCode(`import * as React from 'react'
import { Storyboard } from 'utopia-api'
diff --git a/editor/src/components/text-editor/text-editor.tsx b/editor/src/components/text-editor/text-editor.tsx
index 27ed7e893bbb..7cfb9f75bd06 100644
--- a/editor/src/components/text-editor/text-editor.tsx
+++ b/editor/src/components/text-editor/text-editor.tsx
@@ -342,6 +342,12 @@ const TextEditor = React.memo((props: TextEditorProps) => {
currentElement.style.minWidth = '0.5px'
}
+ const canDeleteWhenEmpty = canDeleteElementWhenEmpty(
+ metadataRef.current,
+ elementPath,
+ allElementPropsRef.current,
+ )
+
return () => {
const content = currentElement.textContent
if (content != null) {
@@ -352,10 +358,15 @@ const TextEditor = React.memo((props: TextEditorProps) => {
savedContentRef.current = content
requestAnimationFrame(() => dispatch([getSaveAction(elementPath, content, textProp)]))
}
+
+ // remove dangling empty spans
+ if (content != null && content.replace(/^\n/, '').length === 0 && canDeleteWhenEmpty) {
+ requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
+ }
}
}
}
- }, [dispatch, elementPath, elementState, metadataRef, textProp])
+ }, [dispatch, elementPath, elementState, textProp, metadataRef, allElementPropsRef])
React.useLayoutEffect(() => {
if (myElement.current == null) {
@@ -440,16 +451,7 @@ const TextEditor = React.memo((props: TextEditorProps) => {
} else {
dispatch([updateEditorMode(EditorModes.selectMode(null, false, 'none'))])
}
-
- // remove dangling empty spans
- if (
- content != null &&
- content.replace(/^\n/, '').length === 0 &&
- canDeleteWhenEmpty(metadataRef.current, elementPath, allElementPropsRef.current)
- ) {
- requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
- }
- }, [dispatch, elementPath, elementState, textProp, metadataRef, allElementPropsRef])
+ }, [dispatch, elementPath, elementState, textProp])
const editorProps: React.DetailedHTMLProps<
React.HTMLAttributes,
@@ -621,7 +623,7 @@ const allowedStyleKeysForDeletion: string[] = [
'font',
]
-function canDeleteWhenEmpty(
+function canDeleteElementWhenEmpty(
jsxMetadata: ElementInstanceMetadataMap,
path: ElementPath,
allElementProps: AllElementProps,
From c467d454708e339315e18840919f26e738cd26f1 Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 11:12:44 +0200
Subject: [PATCH 6/9] update helper
---
.../text-editor/text-editor.spec.browser2.tsx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.spec.browser2.tsx b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
index cdf888261ca5..1131b23d876a 100644
--- a/editor/src/components/text-editor/text-editor.spec.browser2.tsx
+++ b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
@@ -448,7 +448,7 @@ describe('Use the text editor', () => {
'await-first-dom-report',
)
- await enterTextEditMode(editor, 'span')
+ await enterTextEditMode(editor, 'start', 'span')
deleteTypedText()
@@ -496,7 +496,7 @@ describe('Use the text editor', () => {
'await-first-dom-report',
)
- await enterTextEditMode(editor, 'span')
+ await enterTextEditMode(editor, 'start', 'span')
deleteTypedText()
@@ -558,7 +558,7 @@ describe('Use the text editor', () => {
'await-first-dom-report',
)
- await enterTextEditMode(editor, 'span')
+ await enterTextEditMode(editor, 'start', 'span')
deleteTypedText()
@@ -1970,14 +1970,15 @@ async function testModifierExpectingWayTooManySavesTheFirstTime(
async function enterTextEditMode(
editor: EditorRenderResult,
+ where: 'start' | 'end' = 'end',
testId: string = 'div',
): Promise {
const canvasControlsLayer = editor.renderedDOM.getByTestId(CanvasControlsContainerID)
const element = editor.renderedDOM.getByTestId(testId)
const bounds = element.getBoundingClientRect()
const corner = {
- x: bounds.x + 1,
- y: bounds.y + 1,
+ x: bounds.x + (where === 'start' ? 1 : 50),
+ y: bounds.y + (where === 'start' ? 1 : 40),
}
FOR_TESTS_setNextGeneratedUid('text-span')
@@ -1987,7 +1988,6 @@ async function enterTextEditMode(
await mouseClickAtPoint(canvasControlsLayer, corner)
await editor.getDispatchFollowUpActionsFinished()
}
-
function typeText(text: string) {
document.execCommand('insertText', false, text)
}
From 5d69256eeace177c96c15a619338693cd88c1ad5 Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 12:30:54 +0200
Subject: [PATCH 7/9] when content changes
---
editor/src/components/text-editor/text-editor.tsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.tsx b/editor/src/components/text-editor/text-editor.tsx
index 7cfb9f75bd06..2cf12ce9406a 100644
--- a/editor/src/components/text-editor/text-editor.tsx
+++ b/editor/src/components/text-editor/text-editor.tsx
@@ -357,11 +357,11 @@ const TextEditor = React.memo((props: TextEditorProps) => {
if (elementState != null && savedContentRef.current !== content) {
savedContentRef.current = content
requestAnimationFrame(() => dispatch([getSaveAction(elementPath, content, textProp)]))
- }
- // remove dangling empty spans
- if (content != null && content.replace(/^\n/, '').length === 0 && canDeleteWhenEmpty) {
- requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
+ // remove dangling empty spans
+ if (content != null && content.replace(/^\n/, '').length === 0 && canDeleteWhenEmpty) {
+ requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
+ }
}
}
}
From 4730c30b337aa6ba7f6102ece840cf8f6d6ca79d Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 16:13:28 +0200
Subject: [PATCH 8/9] drop style constraint
---
.../components/text-editor/text-editor.tsx | 38 +++++--------------
1 file changed, 10 insertions(+), 28 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.tsx b/editor/src/components/text-editor/text-editor.tsx
index 2cf12ce9406a..91139ea6e20c 100644
--- a/editor/src/components/text-editor/text-editor.tsx
+++ b/editor/src/components/text-editor/text-editor.tsx
@@ -333,6 +333,7 @@ const TextEditor = React.memo((props: TextEditorProps) => {
currentElement.focus()
savedContentRef.current = currentElement.textContent
+ const initialText = currentElement.textContent
const elementCanvasFrame = MetadataUtils.getFrameOrZeroRectInCanvasCoords(
elementPath,
@@ -357,11 +358,15 @@ const TextEditor = React.memo((props: TextEditorProps) => {
if (elementState != null && savedContentRef.current !== content) {
savedContentRef.current = content
requestAnimationFrame(() => dispatch([getSaveAction(elementPath, content, textProp)]))
-
- // remove dangling empty spans
- if (content != null && content.replace(/^\n/, '').length === 0 && canDeleteWhenEmpty) {
- requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
- }
+ }
+ // remove dangling empty spans
+ if (
+ content != null &&
+ initialText !== content &&
+ content.replace(/^\n/, '').length === 0 &&
+ canDeleteWhenEmpty
+ ) {
+ requestAnimationFrame(() => dispatch([deleteView(elementPath)]))
}
}
}
@@ -608,21 +613,6 @@ function getSaveAction(
return updateText(elementPath, escapeHTML(content, textProp), textProp)
}
-const allowedStyleKeysForDeletion: string[] = [
- 'position',
- 'top',
- 'left',
- 'bottom',
- 'right',
- 'width',
- 'height',
- 'wordBreak',
- 'fontSize',
- 'fontWeight',
- 'fontFamily',
- 'font',
-]
-
function canDeleteElementWhenEmpty(
jsxMetadata: ElementInstanceMetadataMap,
path: ElementPath,
@@ -641,14 +631,6 @@ function canDeleteElementWhenEmpty(
return false
}
- // it must not have defined styling
- if (
- elementProps.style != null &&
- Object.keys(elementProps.style).some((key) => !allowedStyleKeysForDeletion.includes(key))
- ) {
- return false
- }
-
// it must not have defined event handlers
if (Object.keys(elementProps).some((prop) => DOMEventHandlerNames.includes(prop as any))) {
return false
From d6cba5c35546364f13f0b17e393a7aa99fb2349d Mon Sep 17 00:00:00 2001
From: Federico Ruggi <1081051+ruggi@users.noreply.github.com>
Date: Fri, 29 Sep 2023 16:47:19 +0200
Subject: [PATCH 9/9] drop outdated test
---
.../text-editor/text-editor.spec.browser2.tsx | 62 -------------------
1 file changed, 62 deletions(-)
diff --git a/editor/src/components/text-editor/text-editor.spec.browser2.tsx b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
index 1131b23d876a..99da66b44416 100644
--- a/editor/src/components/text-editor/text-editor.spec.browser2.tsx
+++ b/editor/src/components/text-editor/text-editor.spec.browser2.tsx
@@ -467,68 +467,6 @@ describe('Use the text editor', () => {
`),
)
})
- it('does not delete span elements with styling', async () => {
- const editor = await renderTestEditorWithCode(
- formatTestProjectCode(`
- import * as React from 'react'
- import { Storyboard } from 'utopia-api'
-
- export var storyboard = (
-
-
- Hello
-
-
- )
- `),
- 'await-first-dom-report',
- )
-
- await enterTextEditMode(editor, 'start', 'span')
-
- deleteTypedText()
-
- await closeTextEditor()
- await editor.getDispatchFollowUpActionsFinished()
-
- expect(editor.getEditorState().editor.mode.type).toEqual('select')
- expect(getPrintedUiJsCode(editor.getEditorState())).toEqual(
- formatTestProjectCode(`
- import * as React from 'react'
- import { Storyboard } from 'utopia-api'
-
- export var storyboard = (
-
-
-
- )
- `),
- )
- })
it('does not delete span elements with event handlers', async () => {
const editor = await renderTestEditorWithCode(
formatTestProjectCode(`