-
Notifications
You must be signed in to change notification settings - Fork 418
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(pte): preserve block key when pressing enter at start of block (#…
…6521) * fix(pte): preserve block key when pressing enter at start of block * fix(pte): add withHotkeys test (wip) * fix(pte): remove withHotkeys for new withInsertBreak plugin * chore(pte): share createEmptyTextBlock function * fix(pte): update e2e tests * fix(pte): update writing together snapshot test
- Loading branch information
1 parent
790bc8f
commit 7df5396
Showing
10 changed files
with
264 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
145 changes: 145 additions & 0 deletions
145
packages/@sanity/portable-text-editor/src/editor/plugins/__tests__/withInsertBreak.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import {describe, expect, it, jest} from '@jest/globals' | ||
import {render, waitFor} from '@testing-library/react' | ||
import {createRef, type RefObject} from 'react' | ||
|
||
import {PortableTextEditorTester, schemaType} from '../../__tests__/PortableTextEditorTester' | ||
import {PortableTextEditor} from '../../PortableTextEditor' | ||
|
||
const initialValue = [ | ||
{ | ||
_key: 'a', | ||
_type: 'myTestBlockType', | ||
children: [ | ||
{ | ||
_key: 'a1', | ||
_type: 'span', | ||
marks: [], | ||
text: 'Block A', | ||
}, | ||
], | ||
markDefs: [], | ||
style: 'normal', | ||
}, | ||
{ | ||
_key: 'b', | ||
_type: 'myTestBlockType', | ||
children: [ | ||
{ | ||
_key: 'b1', | ||
_type: 'span', | ||
marks: [], | ||
text: 'Block B', | ||
}, | ||
], | ||
markDefs: [], | ||
style: 'normal', | ||
}, | ||
] | ||
|
||
describe('plugin:withInsertBreak: "enter"', () => { | ||
it('keeps text block key if enter is pressed at the start of the block, creating a new one in "before" position', async () => { | ||
const initialSelection = { | ||
focus: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 0}, | ||
anchor: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 0}, | ||
} | ||
|
||
const editorRef: RefObject<PortableTextEditor> = createRef() | ||
const onChange = jest.fn() | ||
render( | ||
<PortableTextEditorTester | ||
onChange={onChange} | ||
ref={editorRef} | ||
schemaType={schemaType} | ||
value={initialValue} | ||
/>, | ||
) | ||
const editor = editorRef.current | ||
const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject') | ||
await waitFor(async () => { | ||
if (editor && inlineType) { | ||
PortableTextEditor.focus(editor) | ||
PortableTextEditor.select(editor, initialSelection) | ||
PortableTextEditor.insertBreak(editor) | ||
|
||
const value = PortableTextEditor.getValue(editor) | ||
expect(value).toEqual([ | ||
initialValue[0], | ||
{ | ||
_type: 'myTestBlockType', | ||
_key: '3', | ||
style: 'normal', | ||
markDefs: [], | ||
children: [ | ||
{ | ||
_type: 'span', | ||
_key: '2', | ||
text: '', | ||
marks: [], | ||
}, | ||
], | ||
}, | ||
initialValue[1], | ||
]) | ||
} | ||
}) | ||
}) | ||
it('splits the text block key if enter is pressed at the middle of the block', async () => { | ||
const initialSelection = { | ||
focus: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 2}, | ||
anchor: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 2}, | ||
} | ||
|
||
const editorRef: RefObject<PortableTextEditor> = createRef() | ||
const onChange = jest.fn() | ||
render( | ||
<PortableTextEditorTester | ||
onChange={onChange} | ||
ref={editorRef} | ||
schemaType={schemaType} | ||
value={initialValue} | ||
/>, | ||
) | ||
const editor = editorRef.current | ||
const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject') | ||
await waitFor(async () => { | ||
if (editor && inlineType) { | ||
PortableTextEditor.focus(editor) | ||
PortableTextEditor.select(editor, initialSelection) | ||
PortableTextEditor.insertBreak(editor) | ||
|
||
const value = PortableTextEditor.getValue(editor) | ||
expect(value).toEqual([ | ||
initialValue[0], | ||
{ | ||
_key: 'b', | ||
_type: 'myTestBlockType', | ||
children: [ | ||
{ | ||
_key: 'b1', | ||
_type: 'span', | ||
marks: [], | ||
text: 'Bl', | ||
}, | ||
], | ||
markDefs: [], | ||
style: 'normal', | ||
}, | ||
{ | ||
_key: '2', | ||
_type: 'myTestBlockType', | ||
markDefs: [], | ||
style: 'normal', | ||
children: [ | ||
{ | ||
_key: '1', | ||
_type: 'span', | ||
marks: [], | ||
text: 'ock B', | ||
}, | ||
], | ||
}, | ||
]) | ||
} | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
packages/@sanity/portable-text-editor/src/editor/plugins/createWithInsertBreak.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import {Editor, Node, Path, Range, Transforms} from 'slate' | ||
|
||
import {type PortableTextSlateEditor} from '../../types/editor' | ||
import {type SlateTextBlock, type VoidElement} from '../../types/slate' | ||
|
||
/** | ||
* Changes default behavior of insertBreak to insert a new block instead of splitting current when the cursor is at the | ||
* start of the block. | ||
*/ | ||
export function createWithInsertBreak(): ( | ||
editor: PortableTextSlateEditor, | ||
) => PortableTextSlateEditor { | ||
return function withInsertBreak(editor: PortableTextSlateEditor): PortableTextSlateEditor { | ||
const {insertBreak} = editor | ||
|
||
editor.insertBreak = () => { | ||
if (editor.selection) { | ||
const focusBlockPath = editor.selection.focus.path.slice(0, 1) | ||
const focusBlock = Node.descendant(editor, focusBlockPath) as SlateTextBlock | VoidElement | ||
|
||
if (editor.isTextBlock(focusBlock)) { | ||
// Enter from another style than the first (default one) | ||
const [, end] = Range.edges(editor.selection) | ||
// If it's at the start of block, we want to preserve the current block key and insert a new one in the current position instead of splitting the node. | ||
const isEndAtStartOfNode = Editor.isStart(editor, end, end.path) | ||
if (isEndAtStartOfNode) { | ||
Editor.insertNode(editor, editor.pteCreateEmptyBlock()) | ||
const [nextBlockPath] = Path.next(focusBlockPath) | ||
Transforms.select(editor, { | ||
anchor: {path: [nextBlockPath, 0], offset: 0}, | ||
focus: {path: [nextBlockPath, 0], offset: 0}, | ||
}) | ||
|
||
editor.onChange() | ||
return | ||
} | ||
} | ||
} | ||
insertBreak() | ||
} | ||
return editor | ||
} | ||
} |
Oops, something went wrong.