Fix editor blur on Safari (#3083)

This commit is contained in:
Jonatan Kłosko 2025-10-22 00:15:55 +02:00 committed by GitHub
parent 8514f12d21
commit d18094f943
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 69 additions and 22 deletions

View file

@ -45,7 +45,7 @@ import { settingsStore } from "../../lib/settings";
import Delta from "../../lib/delta";
import Markdown from "../../lib/markdown";
import { readOnlyHint } from "./live_editor/codemirror/read_only_hint";
import { isMacOS, wait } from "../../lib/utils";
import { isMacOS, wait, isSafari } from "../../lib/utils";
import Emitter from "../../lib/emitter";
import CollabClient from "./live_editor/collab_client";
import { languages } from "./live_editor/codemirror/languages";
@ -397,6 +397,33 @@ export default class LiveEditor {
selectionChangeListener,
],
});
// In Safari, when a contenteditable element (here the editor) is
// blurred in favour of non-input element, typing something still
// targets the contenteditable element. This is a known bug [1],
// with a corresponding CodeMirror thread [2]. A workaround is to
// create and focus a temporary input, to properly remove focus
// from the contenteditable element.
//
// This is particularly annoying in our case, because the user may
// blur the editor and then use a letter shortcut, such as "n" for
// a new cell, which ends up typing in the editor.
//
// [1]: https://bugs.webkit.org/show_bug.cgi?id=112854
// [2]: https://discuss.codemirror.net/t/how-to-force-unfocus-of-the-codemirror-element-in-safari/8095
if (isSafari()) {
this.view.contentDOM.addEventListener("blur", (event) => {
const input = document.createElement("input");
input.style.cssText =
"width: 1px; height: 1px; border: none; margin: 0; padding: 0;";
input.tabIndex = -1;
this.view.contentDOM.appendChild(input);
input.focus();
input.setSelectionRange(0, 0);
input.blur();
input.remove();
});
}
}
/** @private */

View file

@ -70,35 +70,55 @@
}
},
"../deps/phoenix": {
"version": "1.7.20",
"license": "MIT"
"version": "1.8.0",
"license": "MIT",
"devDependencies": {
"@babel/cli": "7.28.0",
"@babel/core": "7.28.0",
"@babel/preset-env": "7.28.0",
"@eslint/js": "^9.28.0",
"@stylistic/eslint-plugin": "^5.0.0",
"documentation": "^14.0.3",
"eslint": "9.32.0",
"eslint-plugin-jest": "29.0.1",
"jest": "^30.0.0",
"jest-environment-jsdom": "^30.0.0",
"jsdom": "^26.1.0",
"mock-socket": "^9.3.1"
}
},
"../deps/phoenix_html": {
"version": "4.2.1"
},
"../deps/phoenix_live_view": {
"version": "1.0.5",
"version": "1.1.11",
"license": "MIT",
"dependencies": {
"morphdom": "2.7.4"
"morphdom": "2.7.7"
},
"devDependencies": {
"@babel/cli": "7.26.4",
"@babel/core": "7.26.0",
"@babel/preset-env": "7.26.0",
"@eslint/js": "^9.18.0",
"@playwright/test": "^1.49.1",
"@stylistic/eslint-plugin-js": "^2.12.1",
"@babel/cli": "7.27.2",
"@babel/core": "7.27.4",
"@babel/preset-env": "7.27.2",
"@babel/preset-typescript": "^7.27.1",
"@eslint/js": "^9.29.0",
"@playwright/test": "^1.53.0",
"@types/jest": "^30.0.0",
"@types/phoenix": "^1.6.6",
"css.escape": "^1.5.1",
"eslint": "9.18.0",
"eslint-plugin-jest": "28.10.0",
"eslint-plugin-playwright": "^2.1.0",
"globals": "^15.14.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"eslint": "9.29.0",
"eslint-plugin-jest": "28.14.0",
"eslint-plugin-playwright": "^2.2.0",
"globals": "^16.2.0",
"jest": "^30.0.0",
"jest-environment-jsdom": "^30.0.0",
"jest-monocart-coverage": "^1.1.1",
"monocart-reporter": "^2.9.13",
"phoenix": "1.7.18"
"monocart-reporter": "^2.9.21",
"phoenix": "1.7.21",
"prettier": "3.5.3",
"ts-jest": "^29.4.0",
"typescript": "^5.8.3",
"typescript-eslint": "^8.34.0"
}
},
"node_modules/@alloc/quick-lru": {
@ -4342,9 +4362,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001703",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001703.tgz",
"integrity": "sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==",
"version": "1.0.30001751",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz",
"integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==",
"funding": [
{
"type": "opencollective",