Fix headline blur on click and improve editor focus

This commit is contained in:
Jonatan Kłosko 2021-11-18 17:34:04 +01:00
parent 551444ec76
commit bfe2036d34
2 changed files with 48 additions and 45 deletions

View file

@ -231,18 +231,21 @@ function handleElementFocused(hook, focusableId, scroll) {
} }
function handleInsertModeChanged(hook, insertMode) { function handleInsertModeChanged(hook, insertMode) {
if (hook.state.isFocused) { const input = getInput(hook);
if (hook.state.isFocused && !hook.state.insertMode && insertMode) {
hook.state.insertMode = insertMode; hook.state.insertMode = insertMode;
if (hook.state.liveEditor) { if (hook.state.liveEditor) {
if (hook.state.insertMode) { // For some reason, when clicking the editor for a brief moment it is
hook.state.liveEditor.focus(); // already focused and the cursor is in the previous location, which
// The insert mode may be enabled as a result of clicking the editor, // makes the browser immediately scroll there. We blur the editor,
// in which case we want to wait until editor handles the click // then wait for the editor to update the cursor position, finally
// and sets new cursor position. // we focus the editor and scroll if the cursor is not in the view
// To achieve this, we simply put this task at the end of event loop, // (when entering insert mode with "i").
// ensuring all click handlers are executed first. hook.state.liveEditor.blur();
setTimeout(() => { setTimeout(() => {
hook.state.liveEditor.focus();
scrollIntoView(document.activeElement, { scrollIntoView(document.activeElement, {
scrollMode: "if-needed", scrollMode: "if-needed",
behavior: "smooth", behavior: "smooth",
@ -251,23 +254,24 @@ function handleInsertModeChanged(hook, insertMode) {
}, 0); }, 0);
broadcastSelection(hook); broadcastSelection(hook);
} else {
hook.state.liveEditor.blur();
} }
}
const input = getInput(hook);
if (input) { if (input) {
if (hook.state.insertMode) {
input.focus(); input.focus();
// selectionStart is only supported on text based input // selectionStart is only supported on text based input
if (input.selectionStart !== null) { if (input.selectionStart !== null) {
input.selectionStart = input.selectionEnd = input.value.length; input.selectionStart = input.selectionEnd = input.value.length;
} }
} else {
input.blur();
} }
} else if (hook.state.insertMode && !insertMode) {
hook.state.insertMode = insertMode;
if (hook.state.liveEditor) {
hook.state.liveEditor.blur();
}
if (input) {
input.blur();
} }
} }
} }

View file

@ -95,18 +95,18 @@ function handleElementFocused(hook, cellId, scroll) {
} }
function handleInsertModeChanged(hook, insertMode) { function handleInsertModeChanged(hook, insertMode) {
if (hook.state.isFocused) {
hook.state.insertMode = insertMode;
const heading = getHeading(hook); const heading = getHeading(hook);
if (hook.state.insertMode) { if (hook.state.isFocused && !hook.state.insertMode && insertMode) {
hook.state.insertMode = insertMode;
// While in insert mode, ignore the incoming changes // While in insert mode, ignore the incoming changes
hook.el.setAttribute("phx-update", "ignore"); hook.el.setAttribute("phx-update", "ignore");
heading.setAttribute("contenteditable", "true"); heading.setAttribute("contenteditable", "true");
heading.focus(); heading.focus();
moveSelectionToEnd(heading); moveSelectionToEnd(heading);
} else { } else if (hook.state.insertMode && !insertMode) {
hook.state.insertMode = insertMode;
heading.removeAttribute("contenteditable"); heading.removeAttribute("contenteditable");
hook.el.removeAttribute("phx-update"); hook.el.removeAttribute("phx-update");
hook.pushEvent(hook.props.onValueChange, { hook.pushEvent(hook.props.onValueChange, {
@ -115,7 +115,6 @@ function handleInsertModeChanged(hook, insertMode) {
}); });
} }
} }
}
function getHeading(hook) { function getHeading(hook) {
return hook.el.querySelector(`[data-element="heading"]`); return hook.el.querySelector(`[data-element="heading"]`);