diff --git a/.playwright/tests/checkboxList.spec.ts b/.playwright/tests/checkboxList.spec.ts index 0348da532..8472a7d42 100644 --- a/.playwright/tests/checkboxList.spec.ts +++ b/.playwright/tests/checkboxList.spec.ts @@ -59,4 +59,33 @@ test.describe('checkbox list (web)', () => { const html = await getSerializedHtml(page); expect(html.match(/
  • { + await setEditorHtml( + page, + '' + ); + + const editor = editorLocator(page); + const checkbox = editor.locator('input[type="checkbox"]').first(); + await checkbox.click(); + + const selection = await editor.evaluate(() => { + const s = window.getSelection(); + if (!s || s.rangeCount === 0) { + return null; + } + const range = s.getRangeAt(0); + return { + startOffset: range.startOffset, + endOffset: range.endOffset, + collapsed: range.collapsed, + }; + }); + expect(selection).toEqual({ + startOffset: 3, + endOffset: 3, + collapsed: true, + }); + }); }); diff --git a/src/web/EnrichedTextInput.tsx b/src/web/EnrichedTextInput.tsx index 1002b647c..7d118ff3f 100644 --- a/src/web/EnrichedTextInput.tsx +++ b/src/web/EnrichedTextInput.tsx @@ -18,12 +18,7 @@ import { nativePosToTiptapPos, nativeLeafText, } from './nativeMappers/positionMapping'; -import { - useEditor, - EditorContent, - type ChainedCommands, - Editor, -} from '@tiptap/react'; +import { useEditor, EditorContent, Editor } from '@tiptap/react'; import Document from '@tiptap/extension-document'; import Paragraph from '@tiptap/extension-paragraph'; import Text from '@tiptap/extension-text'; @@ -92,13 +87,8 @@ import { import { assertBrowserEnvironment } from './utils/assertBrowserEnvironment'; import { runSafelyInEditor } from './utils/runSafelyInEditor'; import { useLinkPress } from './htmlExtensions/useLinkPress'; - -function runFocused( - editor: Editor, - apply: (chain: ChainedCommands) => ChainedCommands -) { - runSafelyInEditor(editor, (e) => apply(e.chain().focus()).run()); -} +import { handleCheckboxPress } from './htmlExtensions/handleCheckboxPress'; +import { runFocused } from './utils/runFocused'; export const EnrichedTextInput = ({ ref, @@ -292,7 +282,12 @@ export const EnrichedTextInput = ({ editorProps: { handleKeyDown: (view, event) => handleKeyDown(view.state.doc, event), handleDOMEvents: { - click: (_view, event) => handleLinkPress(event), + click: (view, event) => { + if (handleCheckboxPress(event, editor, view)) { + return true; + } + return handleLinkPress(event); + }, mousedown: (_view, event) => handleLinkMouseDown(event), }, handlePaste: (_view, event) => diff --git a/src/web/htmlExtensions/handleCheckboxPress.ts b/src/web/htmlExtensions/handleCheckboxPress.ts new file mode 100644 index 000000000..5e8f1f14f --- /dev/null +++ b/src/web/htmlExtensions/handleCheckboxPress.ts @@ -0,0 +1,19 @@ +import { Editor } from '@tiptap/core'; +import type { EditorView } from '@tiptap/pm/view'; +import { runFocused } from '../utils/runFocused'; + +export function handleCheckboxPress( + event: MouseEvent, + editor: Editor, + view: EditorView +): boolean { + const target = event.target; + if (target instanceof HTMLInputElement && target.type === 'checkbox') { + const position = view.posAtDOM(target, 0); + const node = view.state.doc.nodeAt(position); + if (!node) return false; + runFocused(editor, (c) => c.setTextSelection(position + node.nodeSize - 1)); + return true; + } + return false; +} diff --git a/src/web/utils/runFocused.ts b/src/web/utils/runFocused.ts new file mode 100644 index 000000000..a1f97f9da --- /dev/null +++ b/src/web/utils/runFocused.ts @@ -0,0 +1,8 @@ +import { Editor, type ChainedCommands } from '@tiptap/core'; +import { runSafelyInEditor } from './runSafelyInEditor'; +export function runFocused( + editor: Editor, + apply: (chain: ChainedCommands) => ChainedCommands +) { + runSafelyInEditor(editor, (e) => apply(e.chain().focus()).run()); +}