diff --git a/components/email/__tests__/recipient-mention.test.tsx b/components/email/__tests__/recipient-mention.test.tsx index 851e3a42b..98cacbc02 100644 --- a/components/email/__tests__/recipient-mention.test.tsx +++ b/components/email/__tests__/recipient-mention.test.tsx @@ -189,6 +189,21 @@ describe('RecipientMention insertion', () => { editor.destroy(); }); + it('never lets a click on a chip follow its mailto link', () => { + // Firefox follows a link in a non-editable island of the editor. + const { editor } = setup('
'); + document.body.appendChild(editor.view.dom); + const chip = editor.view.dom.querySelector('a.mention')!; + const click = new MouseEvent('click', { bubbles: true, cancelable: true }); + chip.dispatchEvent(click); + expect(click.defaultPrevented).toBe(true); + const middle = new MouseEvent('auxclick', { bubbles: true, cancelable: true, button: 1 }); + chip.dispatchEvent(middle); + expect(middle.defaultPrevented).toBe(true); + editor.view.dom.remove(); + editor.destroy(); + }); + it('turns a sent mention back into a chip, and leaves other mailto links alone', () => { const { editor } = setup( '', diff --git a/components/email/mention-chip.tsx b/components/email/mention-chip.tsx index ee89437ba..a3ef586cc 100644 --- a/components/email/mention-chip.tsx +++ b/components/email/mention-chip.tsx @@ -77,6 +77,20 @@ export const MentionChip = Node.create({ }, }, props: { + // The chip is a mailto: link that isn't editable, and Firefox + // follows such links even inside the editor - asking which app + // should write the mail. A click only selects it (and opens the + // card); ProseMirror's selection doesn't rely on the default. + handleDOMEvents: { + click: (_view, event) => { + if ((event.target as Element | null)?.closest?.("a.mention")) event.preventDefault(); + return false; + }, + auxclick: (_view, event) => { + if ((event.target as Element | null)?.closest?.("a.mention")) event.preventDefault(); + return false; + }, + }, decorations(state) { const recipients = mentionRecipientsKey.getState(state); if (!recipients) return null;