mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-03 23:58:11 +08:00
Implement the Text Tool and text layer MVP (#492)
* Add text tool * Double click with the select tool to edit text * Fix (I think?) transitioning to select tool * Commit and abort text editing * Transition to a contenteditable div and autosize * Fix right click blocking * Cleanup hints * Ctrl + enter leaves text edit mode * Render indervidual bounding boxes for text * Re-format space indents * Reflect font size in the textarea * Fix change tool behaviour * Remove starting text * Populate the cache (caused doc load bug) * Remove console log * Chrome display the flashing text entry cursor * Update overlay on input * Cleanup input.ts * Fix bounding boxes * Apply review feedback * Remove manual test * Remove svg from gitignore Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
committed by
Keavon Chambers
co-authored by
Keavon Chambers
parent
1d2768c26d
commit
121a68ad3c
@@ -3,7 +3,7 @@ import { DocumentsState } from "@/state/documents";
|
||||
import { FullscreenState } from "@/state/fullscreen";
|
||||
import { EditorState } from "@/state/wasm-loader";
|
||||
|
||||
type EventName = keyof HTMLElementEventMap | keyof WindowEventHandlersEventMap;
|
||||
type EventName = keyof HTMLElementEventMap | keyof WindowEventHandlersEventMap | "modifyinputfield";
|
||||
interface EventListenerTarget {
|
||||
addEventListener: typeof window.addEventListener;
|
||||
removeEventListener: typeof window.removeEventListener;
|
||||
@@ -22,25 +22,29 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
||||
{ target: window, eventName: "pointermove", action: (e: PointerEvent): void => onPointerMove(e) },
|
||||
{ target: window, eventName: "pointerdown", action: (e: PointerEvent): void => onPointerDown(e) },
|
||||
{ target: window, eventName: "pointerup", action: (e: PointerEvent): void => onPointerUp(e) },
|
||||
{ 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) },
|
||||
];
|
||||
|
||||
let viewportPointerInteractionOngoing = false;
|
||||
let textInput = undefined as undefined | HTMLDivElement;
|
||||
|
||||
// Keyboard events
|
||||
|
||||
const shouldRedirectKeyboardEventToBackend = (e: KeyboardEvent): boolean => {
|
||||
// Don't redirect user input from text entry into HTML elements
|
||||
const { target } = e;
|
||||
if (target instanceof HTMLElement && (target.nodeName === "INPUT" || target.nodeName === "TEXTAREA" || target.isContentEditable)) return false;
|
||||
|
||||
// Don't redirect when a modal is covering the workspace
|
||||
if (dialog.dialogIsVisible()) return false;
|
||||
|
||||
const key = getLatinKey(e);
|
||||
if (!key) return false;
|
||||
|
||||
// Don't redirect user input from text entry into HTML elements
|
||||
const { target } = e;
|
||||
if (key !== "escape" && !(key === "enter" && e.ctrlKey) && target instanceof HTMLElement && (target.nodeName === "INPUT" || target.nodeName === "TEXTAREA" || target.isContentEditable))
|
||||
return false;
|
||||
|
||||
// Don't redirect a fullscreen request
|
||||
if (key === "f11" && e.type === "keydown" && !e.repeat) {
|
||||
e.preventDefault();
|
||||
@@ -107,6 +111,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
||||
const { target } = e;
|
||||
const inCanvas = target instanceof Element && target.closest("[data-canvas]");
|
||||
const inDialog = target instanceof Element && target.closest("[data-dialog-modal] [data-floating-menu-content]");
|
||||
const inTextInput = target === textInput;
|
||||
|
||||
if (dialog.dialogIsVisible() && !inDialog) {
|
||||
dialog.dismissDialog();
|
||||
@@ -114,7 +119,9 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
if (inCanvas) viewportPointerInteractionOngoing = true;
|
||||
if (textInput && !inTextInput) {
|
||||
editor.instance.on_change_text(textInput.textContent || "");
|
||||
} else if (inCanvas && !inTextInput) viewportPointerInteractionOngoing = true;
|
||||
|
||||
if (viewportPointerInteractionOngoing) {
|
||||
const modifiers = makeModifiersBitfield(e);
|
||||
@@ -125,8 +132,19 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
||||
const onPointerUp = (e: PointerEvent): void => {
|
||||
if (!e.buttons) viewportPointerInteractionOngoing = false;
|
||||
|
||||
const modifiers = makeModifiersBitfield(e);
|
||||
editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers);
|
||||
if (!textInput) {
|
||||
const modifiers = makeModifiersBitfield(e);
|
||||
editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers);
|
||||
}
|
||||
};
|
||||
|
||||
const onDoubleClick = (e: PointerEvent): void => {
|
||||
if (!e.buttons) viewportPointerInteractionOngoing = false;
|
||||
|
||||
if (!textInput) {
|
||||
const modifiers = makeModifiersBitfield(e);
|
||||
editor.instance.on_double_click(e.clientX, e.clientY, e.buttons, modifiers);
|
||||
}
|
||||
};
|
||||
|
||||
// Mouse events
|
||||
@@ -154,6 +172,10 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
||||
}
|
||||
};
|
||||
|
||||
const onmodifyinputfiled = (e: CustomEvent): void => {
|
||||
textInput = e.detail;
|
||||
};
|
||||
|
||||
// Window events
|
||||
|
||||
const onWindowResize = (container: HTMLElement): void => {
|
||||
|
||||
Reference in New Issue
Block a user