diff --git a/src/trix/controllers/level_2_input_controller.js b/src/trix/controllers/level_2_input_controller.js index 65b302157..5cf79c840 100644 --- a/src/trix/controllers/level_2_input_controller.js +++ b/src/trix/controllers/level_2_input_controller.js @@ -1,4 +1,4 @@ -import { getAllAttributeNames, squishBreakableWhitespace } from "trix/core/helpers" +import { getAllAttributeNames, shouldRenderInmmediately, squishBreakableWhitespace } from "trix/core/helpers" import InputController from "trix/controllers/input_controller" import * as config from "trix/config" @@ -80,7 +80,12 @@ export default class Level2InputController extends InputController { if (handler) { this.withEvent(event, handler) - this.scheduleRender() + + if (shouldRenderInmmediately(event)) { + this.render() + } else { + this.scheduleRender() + } } }, diff --git a/src/trix/core/helpers/events.js b/src/trix/core/helpers/events.js index 4248830d3..3c36f1cc5 100644 --- a/src/trix/core/helpers/events.js +++ b/src/trix/core/helpers/events.js @@ -43,3 +43,16 @@ export const keyEventIsKeyboardCommand = (function() { return (event) => event.ctrlKey } })() + +export function shouldRenderInmmediately(inputEvent) { + if (/iPhone|iPad/i.test(navigator.userAgent)) { + // Handle duplicated newlines when using dictation on iOS 18+. Upon dictation completion, iOS sends + // the list of insertText / insertParagraph events in a quick sequence. For newlines, if we don't render + // the editor synchronously, the internal range fails to update and results in duplicated newlines. + // This workaround is necessary because iOS doesn't send composing events as expected while dictating: + // https://bugs.webkit.org/show_bug.cgi?id=261764 + return inputEvent.inputType === "insertParagraph" + } else { + return false + } +}