This was added when we were computing the width without adding "pre" behavior. Now it is no longer an issue
124 lines
2.8 KiB
TypeScript
124 lines
2.8 KiB
TypeScript
import { KEYS } from "../keys";
|
|
import { selectNode } from "../utils";
|
|
|
|
type TextWysiwygParams = {
|
|
initText: string;
|
|
x: number;
|
|
y: number;
|
|
strokeColor: string;
|
|
font: string;
|
|
opacity: number;
|
|
zoom: number;
|
|
onSubmit: (text: string) => void;
|
|
onCancel: () => void;
|
|
};
|
|
|
|
export function textWysiwyg({
|
|
initText,
|
|
x,
|
|
y,
|
|
strokeColor,
|
|
font,
|
|
opacity,
|
|
zoom,
|
|
onSubmit,
|
|
onCancel,
|
|
}: TextWysiwygParams) {
|
|
const editable = document.createElement("div");
|
|
try {
|
|
editable.contentEditable = "plaintext-only";
|
|
} catch {
|
|
editable.contentEditable = "true";
|
|
}
|
|
editable.tabIndex = 0;
|
|
editable.innerText = initText;
|
|
editable.dataset.type = "wysiwyg";
|
|
|
|
Object.assign(editable.style, {
|
|
color: strokeColor,
|
|
position: "fixed",
|
|
opacity: opacity / 100,
|
|
top: `${y}px`,
|
|
left: `${x}px`,
|
|
transform: `translate(-50%, -50%) scale(${zoom})`,
|
|
textAlign: "left",
|
|
display: "inline-block",
|
|
font: font,
|
|
padding: "4px",
|
|
// This needs to have "1px solid" otherwise the carret doesn't show up
|
|
// the first time on Safari and Chrome!
|
|
outline: "1px solid transparent",
|
|
whiteSpace: "nowrap",
|
|
minHeight: "1em",
|
|
backfaceVisibility: "hidden",
|
|
});
|
|
|
|
editable.onpaste = ev => {
|
|
try {
|
|
const selection = window.getSelection();
|
|
if (!selection?.rangeCount) {
|
|
return;
|
|
}
|
|
selection.deleteFromDocument();
|
|
|
|
const text = ev.clipboardData!.getData("text").replace(/\r\n?/g, "\n");
|
|
|
|
const span = document.createElement("span");
|
|
span.innerText = text;
|
|
const range = selection.getRangeAt(0);
|
|
range.insertNode(span);
|
|
|
|
// deselect
|
|
window.getSelection()!.removeAllRanges();
|
|
range.setStart(span, span.childNodes.length);
|
|
range.setEnd(span, span.childNodes.length);
|
|
selection.addRange(range);
|
|
|
|
ev.preventDefault();
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
};
|
|
|
|
editable.onkeydown = ev => {
|
|
if (ev.key === KEYS.ESCAPE) {
|
|
ev.preventDefault();
|
|
handleSubmit();
|
|
}
|
|
if (ev.key === KEYS.ENTER && !ev.shiftKey) {
|
|
ev.preventDefault();
|
|
if (ev.isComposing || ev.keyCode === 229) {
|
|
return;
|
|
}
|
|
handleSubmit();
|
|
}
|
|
};
|
|
editable.onblur = handleSubmit;
|
|
|
|
function stopEvent(ev: Event) {
|
|
ev.stopPropagation();
|
|
}
|
|
|
|
function handleSubmit() {
|
|
if (editable.innerText) {
|
|
onSubmit(editable.innerText);
|
|
} else {
|
|
onCancel();
|
|
}
|
|
cleanup();
|
|
}
|
|
|
|
function cleanup() {
|
|
editable.onblur = null;
|
|
editable.onkeydown = null;
|
|
editable.onpaste = null;
|
|
window.removeEventListener("wheel", stopEvent, true);
|
|
document.body.removeChild(editable);
|
|
}
|
|
|
|
window.addEventListener("wheel", stopEvent, true);
|
|
document.body.appendChild(editable);
|
|
editable.focus();
|
|
selectNode(editable);
|
|
}
|