Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions playwright/integration/examples/inlines.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { test, expect } from '@playwright/test'
import { clearEditor, getEditorHandle } from '../support/editor'

test.describe('Inlines example', () => {
test.beforeEach(async ({ page }) => {
Expand All @@ -11,6 +12,74 @@ test.describe('Inlines example', () => {
).toContain('hyperlink')
})

for (const scenario of [
{
name: 'end of link',
anchor: 4,
focus: 4,
links: ['link'],
paragraphs: ['before link', ' after'],
},
{
name: 'middle of link',
anchor: 2,
focus: 2,
links: ['li', 'nk'],
paragraphs: ['before li', 'nk after'],
},
{
name: 'selected link text',
anchor: 1,
focus: 3,
links: ['l', 'k'],
paragraphs: ['before l', 'k after'],
},
]) {
test(`Enter at ${scenario.name}`, async ({ page }, testInfo) => {
test.skip(
testInfo.project.name === 'mobile',
'Synthetic Enter does not simulate a soft keyboard'
)
const element = page.getByRole('textbox')
await clearEditor(element)
const editor = await getEditorHandle(element)
await editor.evaluate((editor, scenario) => {
editor.insertText('before ')
const link = {
type: 'link',
url: 'https://example.com',
children: [{ text: 'link' }],
}
editor.insertNodes(link)
editor.select({ path: [0, 2], offset: 0 })
editor.insertText(' after')
editor.select({
anchor: { path: [0, 1, 0], offset: scenario.anchor },
focus: { path: [0, 1, 0], offset: scenario.focus },
})
}, scenario)
await expect
.poll(() =>
element.evaluate(element => {
const selection = window.getSelection()!
return (
selection.anchorNode?.parentElement?.closest('a') !== null &&
selection.anchorOffset
)
})
)
.toBe(scenario.anchor)
await page.keyboard.press('Enter')
await expect(element.locator('a')).toHaveText(scenario.links)
expect(
await editor.evaluate(editor =>
editor.children.map((_, index) => editor.string([index]))
)
).toEqual(scenario.paragraphs)
await editor.dispose()
})
}

// FIXME: unstable, has issues with selection.anchorNode
test.skip('arrow keys skip over read-only inline', async ({ page }) => {
const badge = page.locator('text=Approved >> xpath=../../..')
Expand Down
25 changes: 23 additions & 2 deletions site/examples/js/inlines.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,35 @@ const InlinesExample = () => {
)
}
const withInlines = editor => {
const { insertData, insertText, isInline, isElementReadOnly, isSelectable } =
editor
const {
insertData,
insertText,
insertBreak,
isInline,
isElementReadOnly,
isSelectable,
} = editor
editor.isInline = element =>
['link', 'button', 'badge'].includes(element.type) || isInline(element)
editor.isElementReadOnly = element =>
element.type === 'badge' || isElementReadOnly(element)
editor.isSelectable = element =>
element.type !== 'badge' && isSelectable(element)
editor.insertBreak = () => {
const { selection } = editor
if (selection && Range.isCollapsed(selection)) {
const link = Editor.above(editor, {
match: n => Node.isElement(n) && n.type === 'link',
})
if (link && Editor.isEnd(editor, selection.anchor, link[1])) {
const after = Editor.after(editor, link[1])
if (after) {
Transforms.select(editor, after)
}
}
}
insertBreak()
}
editor.insertText = text => {
if (text && isUrl(text)) {
wrapLink(editor, text)
Expand Down
29 changes: 27 additions & 2 deletions site/examples/ts/inlines.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,14 @@ const InlinesExample = () => {
}

const withInlines = (editor: CustomEditor) => {
const { insertData, insertText, isInline, isElementReadOnly, isSelectable } =
editor
const {
insertData,
insertText,
insertBreak,
isInline,
isElementReadOnly,
isSelectable,
} = editor

editor.isInline = (element: CustomElement) =>
['link', 'button', 'badge'].includes(element.type) || isInline(element)
Expand All @@ -139,6 +145,25 @@ const withInlines = (editor: CustomEditor) => {
editor.isSelectable = (element: CustomElement) =>
element.type !== 'badge' && isSelectable(element)

editor.insertBreak = () => {
const { selection } = editor

if (selection && Range.isCollapsed(selection)) {
const link = Editor.above(editor, {
match: n => Node.isElement(n) && n.type === 'link',
})

if (link && Editor.isEnd(editor, selection.anchor, link[1])) {
const after = Editor.after(editor, link[1])
if (after) {
Transforms.select(editor, after)
}
}
}

insertBreak()
}

editor.insertText = text => {
if (text && isUrl(text)) {
wrapLink(editor, text)
Expand Down
Loading