Skip to content

Commit

Permalink
fix(pte): removes empty text block when inserting a new block in that…
Browse files Browse the repository at this point in the history
… position (#5271)

* fix(pte): removes empty text block when inserting a new block in that position

* fix(pte): use isEqualToEmptyEditor helper function
  • Loading branch information
pedrobonamin authored Dec 13, 2023
1 parent 7452848 commit b6ef7dc
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,32 @@ const initialValue = [
style: 'normal',
},
]

const initialSelection = {
focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 7},
anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 7},
}

const emptyTextBlock = [
{
_key: 'emptyBlock',
_type: 'myTestBlockType',
children: [
{
_key: 'emptySpan',
_type: 'span',
marks: [],
text: '',
},
],
markDefs: [],
style: 'normal',
},
]
const emptyBlockSelection = {
focus: {path: [{_key: 'emptyBlock'}, 'children', {_key: 'emptySpan'}], offset: 0},
anchor: {path: [{_key: 'emptyBlock'}, 'children', {_key: 'emptySpan'}], offset: 0},
}

describe('plugin:withEditableAPI: .insertChild()', () => {
it('inserts child nodes correctly', async () => {
const editorRef: React.RefObject<PortableTextEditor> = React.createRef()
Expand Down Expand Up @@ -137,3 +157,188 @@ describe('plugin:withEditableAPI: .insertChild()', () => {
})
})
})

describe('plugin:withEditableAPI: .insertBlock()', () => {
it('should not add empty blank blocks: empty block', async () => {
const editorRef: React.RefObject<PortableTextEditor> = React.createRef()
const onChange = jest.fn()
render(
<PortableTextEditorTester
onChange={onChange}
ref={editorRef}
schemaType={schemaType}
value={emptyTextBlock}
/>,
)
const editor = editorRef.current
const someObject = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')

await waitFor(() => {
if (editorRef.current && someObject) {
PortableTextEditor.focus(editorRef.current)
PortableTextEditor.select(editorRef.current, emptyBlockSelection)
PortableTextEditor.insertBlock(editorRef.current, someObject, {color: 'red'})

expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
{_key: '2', _type: 'someObject', color: 'red'},
])
} else {
throw new Error('No editor or someObject')
}
})
})

it('should not add empty blank blocks: non-empty block', async () => {
const editorRef: React.RefObject<PortableTextEditor> = React.createRef()
const onChange = jest.fn()
render(
<PortableTextEditorTester
onChange={onChange}
ref={editorRef}
schemaType={schemaType}
value={initialValue}
/>,
)
const editor = editorRef.current
const someObject = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')

await waitFor(() => {
if (editorRef.current && someObject) {
PortableTextEditor.focus(editorRef.current)
PortableTextEditor.select(editorRef.current, initialSelection)
PortableTextEditor.insertBlock(editorRef.current, someObject, {color: 'red'})
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
...initialValue,
{_key: '2', _type: 'someObject', color: 'red'},
])
} else {
throw new Error('No editor or someObject')
}
})
})
it('should be inserted before if focus is on start of block', async () => {
const editorRef: React.RefObject<PortableTextEditor> = React.createRef()
const onChange = jest.fn()
render(
<PortableTextEditorTester
onChange={onChange}
ref={editorRef}
schemaType={schemaType}
value={initialValue}
/>,
)
const editor = editorRef.current
const someObject = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')

await waitFor(() => {
if (editorRef.current && someObject) {
PortableTextEditor.focus(editorRef.current)
PortableTextEditor.select(editorRef.current, {
focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
})
PortableTextEditor.insertBlock(editorRef.current, someObject, {color: 'red'})
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
{_key: '2', _type: 'someObject', color: 'red'},
...initialValue,
])
} else {
throw new Error('No editor or someObject')
}
})
})
it('should not add empty blank blocks: non text block', async () => {
const editorRef: React.RefObject<PortableTextEditor> = React.createRef()
const onChange = jest.fn()
const value = [...initialValue, {_key: 'b', _type: 'someObject', color: 'red'}]
render(
<PortableTextEditorTester
onChange={onChange}
ref={editorRef}
schemaType={schemaType}
value={value}
/>,
)
const editor = editorRef.current
const someObject = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')

await waitFor(() => {
if (editorRef.current && someObject) {
PortableTextEditor.focus(editorRef.current)
// Focus the `someObject` block
PortableTextEditor.select(editorRef.current, {
focus: {path: [{_key: 'b'}], offset: 0},
anchor: {path: [{_key: 'b'}], offset: 0},
})
PortableTextEditor.insertBlock(editorRef.current, someObject, {color: 'yellow'})
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
...value,
{_key: '2', _type: 'someObject', color: 'yellow'},
])
} else {
throw new Error('No editor or someObject')
}
})
})
it('should not add empty blank blocks: in between blocks', async () => {
const editorRef: React.RefObject<PortableTextEditor> = React.createRef()
const onChange = jest.fn()
const value = [...initialValue, {_key: 'b', _type: 'someObject', color: 'red'}]
render(
<PortableTextEditorTester
onChange={onChange}
ref={editorRef}
schemaType={schemaType}
value={value}
/>,
)
const editor = editorRef.current
const someObject = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')

await waitFor(() => {
if (editorRef.current && someObject) {
PortableTextEditor.focus(editorRef.current)
// Focus the `text` block
PortableTextEditor.select(editorRef.current, initialSelection)
PortableTextEditor.insertBlock(editorRef.current, someObject, {color: 'yellow'})
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
value[0],
{_key: '2', _type: 'someObject', color: 'yellow'},
value[1],
])
} else {
throw new Error('No editor or someObject')
}
})
})
it('should not add empty blank blocks: in new empty text block', async () => {
const editorRef: React.RefObject<PortableTextEditor> = React.createRef()
const onChange = jest.fn()
const value = [...initialValue, ...emptyTextBlock]
render(
<PortableTextEditorTester
onChange={onChange}
ref={editorRef}
schemaType={schemaType}
value={value}
/>,
)
const editor = editorRef.current
const someObject = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')

await waitFor(() => {
if (editorRef.current && someObject) {
PortableTextEditor.focus(editorRef.current)
// Focus the empty `text` block
PortableTextEditor.select(editorRef.current, emptyBlockSelection)
PortableTextEditor.insertBlock(editorRef.current, someObject, {color: 'yellow'})
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
value[0],
{_key: '2', _type: 'someObject', color: 'yellow'},
])
} else {
throw new Error('No editor or someObject')
}
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
PortableTextMemberSchemaTypes,
PortableTextSlateEditor,
} from '../../types/editor'
import {toSlateValue, fromSlateValue} from '../../utils/values'
import {toSlateValue, fromSlateValue, isEqualToEmptyEditor} from '../../utils/values'
import {toSlateRange, toPortableTextRange} from '../../utils/ranges'
import {PortableTextEditor} from '../PortableTextEditor'

Expand Down Expand Up @@ -181,6 +181,20 @@ export function createWithEditableAPI(
],
portableTextEditor,
)[0] as unknown as Node
const [focusBlock] = Array.from(
Editor.nodes(editor, {
at: editor.selection.focus.path.slice(0, 1),
match: (n) => n._type === types.block.name,
}),
)[0] || [undefined]

const isEmptyTextBlock = focusBlock && isEqualToEmptyEditor([focusBlock], types)

if (isEmptyTextBlock) {
// If the text block is empty, remove it before inserting the new block.
Transforms.removeNodes(editor, {at: editor.selection})
}

Editor.insertNode(editor, block)
editor.onChange()
return (
Expand Down

2 comments on commit b6ef7dc

@vercel
Copy link

@vercel vercel bot commented on b6ef7dc Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

test-studio – ./

test-studio.sanity.build
test-studio-git-next.sanity.build

@vercel
Copy link

@vercel vercel bot commented on b6ef7dc Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

performance-studio – ./

performance-studio.sanity.build
performance-studio-git-next.sanity.build

Please sign in to comment.