mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 14:43:06 +08:00
fix: resolve keystroke input being swallowed after link in Firefox (#1922)
* fix: resolve keystroke input being swallowed after link in Firefox In Firefox, when the cursor is at the right boundary of a link mark, contenteditable inserts new text inside the <a> element. ProseMirror then rejects the DOM mutation because the link mark has inclusive: false, causing keystrokes to be silently swallowed. Unlike Chrome, Firefox also does not fire ProseMirror's handleTextInput callback in this state. This adds a ProseMirror plugin that intercepts printable character keydowns at link mark boundaries and programmatically inserts the text without the link mark, bypassing Firefox's native contenteditable behavior entirely. Fixes #1773 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve keystroke input being swallowed before a link in Firefox Extend the linkBoundaryInput plugin to also handle the left boundary of links, where the cursor is just before a link (e.g. at the start of a line). Firefox inserts text inside the <a> element in this case too, causing ProseMirror to reject the mutation. Fixes #1748
This commit is contained in:
@@ -2,6 +2,7 @@ import { Dispatch, FC, SetStateAction, useCallback } from "react";
|
||||
import { IconLink } from "@tabler/icons-react";
|
||||
import { ActionIcon, Popover, Tooltip } from "@mantine/core";
|
||||
import { useEditor } from "@tiptap/react";
|
||||
import { TextSelection } from "@tiptap/pm/state";
|
||||
import { LinkEditorPanel } from "@/features/editor/components/link/link-editor-panel.tsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@@ -20,7 +21,15 @@ export const LinkSelector: FC<LinkSelectorProps> = ({
|
||||
const onLink = useCallback(
|
||||
(url: string) => {
|
||||
setIsOpen(false);
|
||||
editor.chain().focus().setLink({ href: url }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.setLink({ href: url })
|
||||
.command(({ tr }) => {
|
||||
tr.setSelection(TextSelection.create(tr.doc, tr.selection.to));
|
||||
return true;
|
||||
})
|
||||
.run();
|
||||
},
|
||||
[editor, setIsOpen],
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { TextSelection } from "@tiptap/pm/state";
|
||||
import { EditorMenuProps } from "@/features/editor/components/table/types/types.ts";
|
||||
import { LinkEditorPanel } from "@/features/editor/components/link/link-editor-panel.tsx";
|
||||
import { LinkPreviewPanel } from "@/features/editor/components/link/link-preview.tsx";
|
||||
@@ -37,6 +38,10 @@ export function LinkMenu({ editor, appendTo }: EditorMenuProps) {
|
||||
.focus()
|
||||
.extendMarkRange("link")
|
||||
.setLink({ href: url })
|
||||
.command(({ tr }) => {
|
||||
tr.setSelection(TextSelection.create(tr.doc, tr.selection.to));
|
||||
return true;
|
||||
})
|
||||
.run();
|
||||
setShowEdit(false);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user