diff --git a/frontend/src/components/panels/Document.vue b/frontend/src/components/panels/Document.vue index 21cba17e..e8223868 100644 --- a/frontend/src/components/panels/Document.vue +++ b/frontend/src/components/panels/Document.vue @@ -192,9 +192,9 @@ } } foreignObject { + width: 10000px; + height: 10000px; overflow: visible; - width: 1px; - height: 1px; div { color: black; @@ -245,6 +245,8 @@ import { DisplayEditableTextbox, } from "@/dispatcher/js-messages"; +import { textInputCleanup } from "@/lifetime/input"; + import LayoutCol from "@/components/layout/LayoutCol.vue"; import LayoutRow from "@/components/layout/LayoutRow.vue"; import IconButton from "@/components/widgets/buttons/IconButton.vue"; @@ -379,19 +381,22 @@ export default defineComponent({ this.canvasCursor = updateMouseCursor.cursor; }); this.editor.dispatcher.subscribeJsMessage(TriggerTextCommit, () => { - if (this.textInput) this.editor.instance.on_change_text(this.textInput.textContent || ""); + if (this.textInput) this.editor.instance.on_change_text(textInputCleanup(this.textInput.innerText)); }); this.editor.dispatcher.subscribeJsMessage(DisplayEditableTextbox, (displayEditableTextbox) => { this.textInput = document.createElement("DIV") as HTMLDivElement; - this.textInput.id = "editable-textbox"; - this.textInput.textContent = displayEditableTextbox.text; + + if (displayEditableTextbox.text === "") this.textInput.textContent = ""; + else this.textInput.textContent = `${displayEditableTextbox.text}\n`; + this.textInput.contentEditable = "true"; this.textInput.style.width = displayEditableTextbox.line_width ? `${displayEditableTextbox.line_width}px` : "max-content"; this.textInput.style.height = "auto"; this.textInput.style.fontSize = `${displayEditableTextbox.font_size}px`; + this.textInput.oninput = (): void => { - if (this.textInput) this.editor.instance.update_bounds(this.textInput.textContent || ""); + if (this.textInput) this.editor.instance.update_bounds(textInputCleanup(this.textInput.innerText)); }; }); diff --git a/frontend/src/lifetime/input.ts b/frontend/src/lifetime/input.ts index 2d46dd39..d878ff19 100644 --- a/frontend/src/lifetime/input.ts +++ b/frontend/src/lifetime/input.ts @@ -25,7 +25,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement, { target: window, eventName: "dblclick", action: (e: PointerEvent): void => onDoubleClick(e) }, { target: window, eventName: "mousedown", action: (e: MouseEvent): void => onMouseDown(e) }, { target: window, eventName: "wheel", action: (e: WheelEvent): void => onMouseScroll(e), options: { passive: false } }, - { target: window, eventName: "modifyinputfield", action: (e: CustomEvent): void => onmodifyinputfiled(e) }, + { target: window, eventName: "modifyinputfield", action: (e: CustomEvent): void => onModifyInputField(e) }, ]; let viewportPointerInteractionOngoing = false; @@ -120,7 +120,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement, } if (textInput && !inTextInput) { - editor.instance.on_change_text(textInput.textContent || ""); + editor.instance.on_change_text(textInputCleanup(textInput.innerText)); } else if (inCanvas && !inTextInput) viewportPointerInteractionOngoing = true; if (viewportPointerInteractionOngoing) { @@ -172,7 +172,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement, } }; - const onmodifyinputfiled = (e: CustomEvent): void => { + const onModifyInputField = (e: CustomEvent): void => { textInput = e.detail; }; @@ -232,6 +232,12 @@ export function makeModifiersBitfield(e: WheelEvent | PointerEvent | KeyboardEve return Number(e.ctrlKey) | (Number(e.shiftKey) << 1) | (Number(e.altKey) << 2); } +// Necessary because innerText puts an extra newline character at the end when the text is more than one line. +export function textInputCleanup(text: string): string { + if (text[text.length - 1] === "\n") return text.slice(0, -1); + return text; +} + // This function is a naive, temporary solution to allow non-Latin keyboards to fall back on the physical QWERTY layout function getLatinKey(e: KeyboardEvent): string | null { const key = e.key.toLowerCase(); diff --git a/graphene/src/layers/text/to_kurbo.rs b/graphene/src/layers/text/to_kurbo.rs index 584e88b9..30b16126 100644 --- a/graphene/src/layers/text/to_kurbo.rs +++ b/graphene/src/layers/text/to_kurbo.rs @@ -74,7 +74,7 @@ pub fn to_kurbo(str: &str, buzz_face: rustybuzz::Face, font_size: f64, line_widt path: BezPath::new(), pos: Point::ZERO, offset: Vec2::ZERO, - ascender: buzz_face.ascender() as f64, + ascender: (buzz_face.ascender() as f64 / buzz_face.height() as f64) * font_size / scale, scale, };