Contenteditable wysiwyg (#274)

* Contenteditable wysiwyg

* Added comment about pasting multiline text
This commit is contained in:
Timur Khazamov 2020-01-09 02:04:53 +05:00 committed by GitHub
parent 556843d9a2
commit e38f65dea7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 18 deletions

View File

@ -17,27 +17,34 @@ export function textWysiwyg({
font, font,
onSubmit onSubmit
}: TextWysiwygParams) { }: TextWysiwygParams) {
const input = document.createElement("input"); // Using contenteditable here as it has dynamic width.
input.value = initText; // But this solution has an issue — it allows to paste
Object.assign(input.style, { // multiline text, which is not currently supported
const editable = document.createElement("div");
editable.contentEditable = "plaintext-only";
editable.tabIndex = 0;
editable.innerText = initText;
editable.dataset.type = "wysiwyg";
Object.assign(editable.style, {
color: strokeColor, color: strokeColor,
position: "absolute", position: "absolute",
top: y + "px", top: y + "px",
left: x + "px", left: x + "px",
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
boxShadow: "none",
textAlign: "center", textAlign: "center",
width: (window.innerWidth - x) * 2 + "px", display: "inline-block",
font: font, font: font,
border: "none", padding: "4px",
background: "transparent" outline: "transparent",
whiteSpace: "nowrap"
}); });
input.onkeydown = ev => { editable.onkeydown = ev => {
if (ev.key === KEYS.ESCAPE) { if (ev.key === KEYS.ESCAPE) {
ev.preventDefault(); ev.preventDefault();
if (initText) { if (initText) {
input.value = initText; editable.innerText = initText;
handleSubmit(); handleSubmit();
return; return;
} }
@ -49,28 +56,34 @@ export function textWysiwyg({
handleSubmit(); handleSubmit();
} }
}; };
input.onblur = handleSubmit; editable.onblur = handleSubmit;
function stopEvent(ev: Event) { function stopEvent(ev: Event) {
ev.stopPropagation(); ev.stopPropagation();
} }
function handleSubmit() { function handleSubmit() {
if (input.value) { if (editable.innerText) {
onSubmit(input.value); onSubmit(editable.innerText);
} }
cleanup(); cleanup();
} }
function cleanup() { function cleanup() {
input.onblur = null; editable.onblur = null;
input.onkeydown = null; editable.onkeydown = null;
window.removeEventListener("wheel", stopEvent, true); window.removeEventListener("wheel", stopEvent, true);
document.body.removeChild(input); document.body.removeChild(editable);
} }
window.addEventListener("wheel", stopEvent, true); window.addEventListener("wheel", stopEvent, true);
document.body.appendChild(input); document.body.appendChild(editable);
input.focus(); editable.focus();
input.select(); const selection = window.getSelection();
if (selection) {
const range = document.createRange();
range.selectNodeContents(editable);
selection.removeAllRanges();
selection.addRange(range);
}
} }

View File

@ -18,6 +18,7 @@ export function isInputLike(
target: Element | EventTarget | null target: Element | EventTarget | null
): target is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement { ): target is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement {
return ( return (
(target instanceof HTMLElement && target.dataset.type === "wysiwyg") ||
target instanceof HTMLInputElement || target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement || target instanceof HTMLTextAreaElement ||
target instanceof HTMLSelectElement target instanceof HTMLSelectElement