mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 20:58:12 +08:00
Clean up text input (#506)
* Fix firefox text input * Fix descenders below bounding box * Fix chromium empty text * Descenders back below baseline * Fix trailing newline on chromium * Reinstate correct baseline height * Fix highlighted new line on empty text * Add comment for trailing new line removal * Extract cleanupTextInput to a separate file * Function import simplification Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
committed by
Keavon Chambers
co-authored by
Keavon Chambers
parent
dd36339605
commit
376f4da480
@@ -192,9 +192,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreignObject {
|
foreignObject {
|
||||||
|
width: 10000px;
|
||||||
|
height: 10000px;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
|
|
||||||
div {
|
div {
|
||||||
color: black;
|
color: black;
|
||||||
@@ -245,6 +245,8 @@ import {
|
|||||||
DisplayEditableTextbox,
|
DisplayEditableTextbox,
|
||||||
} from "@/dispatcher/js-messages";
|
} from "@/dispatcher/js-messages";
|
||||||
|
|
||||||
|
import { textInputCleanup } from "@/lifetime/input";
|
||||||
|
|
||||||
import LayoutCol from "@/components/layout/LayoutCol.vue";
|
import LayoutCol from "@/components/layout/LayoutCol.vue";
|
||||||
import LayoutRow from "@/components/layout/LayoutRow.vue";
|
import LayoutRow from "@/components/layout/LayoutRow.vue";
|
||||||
import IconButton from "@/components/widgets/buttons/IconButton.vue";
|
import IconButton from "@/components/widgets/buttons/IconButton.vue";
|
||||||
@@ -379,19 +381,22 @@ export default defineComponent({
|
|||||||
this.canvasCursor = updateMouseCursor.cursor;
|
this.canvasCursor = updateMouseCursor.cursor;
|
||||||
});
|
});
|
||||||
this.editor.dispatcher.subscribeJsMessage(TriggerTextCommit, () => {
|
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.editor.dispatcher.subscribeJsMessage(DisplayEditableTextbox, (displayEditableTextbox) => {
|
||||||
this.textInput = document.createElement("DIV") as HTMLDivElement;
|
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.contentEditable = "true";
|
||||||
this.textInput.style.width = displayEditableTextbox.line_width ? `${displayEditableTextbox.line_width}px` : "max-content";
|
this.textInput.style.width = displayEditableTextbox.line_width ? `${displayEditableTextbox.line_width}px` : "max-content";
|
||||||
this.textInput.style.height = "auto";
|
this.textInput.style.height = "auto";
|
||||||
this.textInput.style.fontSize = `${displayEditableTextbox.font_size}px`;
|
this.textInput.style.fontSize = `${displayEditableTextbox.font_size}px`;
|
||||||
|
|
||||||
this.textInput.oninput = (): void => {
|
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));
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
{ target: window, eventName: "dblclick", action: (e: PointerEvent): void => onDoubleClick(e) },
|
{ target: window, eventName: "dblclick", action: (e: PointerEvent): void => onDoubleClick(e) },
|
||||||
{ target: window, eventName: "mousedown", action: (e: MouseEvent): void => onMouseDown(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: "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;
|
let viewportPointerInteractionOngoing = false;
|
||||||
@@ -120,7 +120,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (textInput && !inTextInput) {
|
if (textInput && !inTextInput) {
|
||||||
editor.instance.on_change_text(textInput.textContent || "");
|
editor.instance.on_change_text(textInputCleanup(textInput.innerText));
|
||||||
} else if (inCanvas && !inTextInput) viewportPointerInteractionOngoing = true;
|
} else if (inCanvas && !inTextInput) viewportPointerInteractionOngoing = true;
|
||||||
|
|
||||||
if (viewportPointerInteractionOngoing) {
|
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;
|
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);
|
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
|
// 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 {
|
function getLatinKey(e: KeyboardEvent): string | null {
|
||||||
const key = e.key.toLowerCase();
|
const key = e.key.toLowerCase();
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ pub fn to_kurbo(str: &str, buzz_face: rustybuzz::Face, font_size: f64, line_widt
|
|||||||
path: BezPath::new(),
|
path: BezPath::new(),
|
||||||
pos: Point::ZERO,
|
pos: Point::ZERO,
|
||||||
offset: Vec2::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,
|
scale,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user