Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
2.5 kB · 58 lines
TypeScript
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859// src/editor/extensions/firefox-android-backspace.ts/** * Workaround for a CM6 gap on Firefox Android. * * CM6 has special handling for Chrome Android's IME-routed backspace * (the PendingKeys / delayAndroidKey mechanism in @codemirror/view), * but no equivalent for Firefox Android. When Firefox Android routes * Backspace through the IME pipeline (keydown: Process, keyCode 229), * CM6 falls back to watching for DOM mutations. But backspace at the * start of a line (<div class="cm-line"><br></div>) produces no DOM * mutation, so CM6 sees nothing and drops the event. * * The fix mimics exactly what CM6 does for Chrome Android: * - On beforeinput(deleteContentBackward), call delayAndroidKey('Backspace', 8) * - Do NOT preventDefault — let Firefox apply its native backspace * - The delayedAndroidKey lock suppresses onSelectionChange and flush * until the next RAF * - The RAF calls flush() to read whatever DOM mutations Firefox made * - If flush() found no mutations (empty-line case) AND force is true, * CM6 dispatches a synthetic keydown that triggers deleteCharBackward * from defaultKeymap * * This is the same proven code path Chrome Android uses, just triggered * for Firefox Android too. See @codemirror/view input.ts PendingKeys * and domobserver.ts delayAndroidKey. * * Uses internal CM6 API (view.observer.delayAndroidKey). Guarded with * runtime checks so a future CM6 refactor degrades gracefully. * Tested against @codemirror/view 6.41.1. */import { type Extension } from '@codemirror/state'import { EditorView } from '@codemirror/view'
/** Detect Firefox Android using the same UA signals CM6 uses internally. */const isFirefoxAndroid = typeof navigator !== 'undefined' && /Firefox/.test(navigator.userAgent) && /Android/.test(navigator.userAgent)
export function firefoxAndroidBackspace(): Extension { if (!isFirefoxAndroid) return []
return EditorView.domEventHandlers({ beforeinput(event, view) { if (event.inputType !== 'deleteContentBackward') return false
const observer = (view as any).observer if (typeof observer?.delayAndroidKey !== 'function') return false
observer.delayAndroidKey('Backspace', 8)
// Return false: do NOT consume the event. Let Firefox apply its // native backspace to the DOM, and let CM6's own beforeinput handler // run too (it won't do anything for Firefox since its PendingKeys // check is gated on browser.chrome && browser.android). return false }, })}