Rename EditorHandle -> EditorWrapper and organize editor_api.rs (#3925)

* Rename EditorHandle -> EditorWrapper and organize editor_api.rs

* pub -> pub(crate)
This commit is contained in:
Keavon Chambers
2026-03-21 03:27:57 -07:00
committed by GitHub
parent 9bcac1af2d
commit 087b4cd71f
34 changed files with 352 additions and 358 deletions

View File

@@ -5,11 +5,11 @@
import type { MessageName, SubscriptionsRouter } from "/src/subscriptions-router";
import { loadDemoArtwork } from "/src/utility-functions/network";
import { operatingSystem } from "/src/utility-functions/platform";
import init, { EditorHandle, receiveNativeMessage } from "/wasm/pkg/graphite_wasm";
import init, { EditorWrapper, receiveNativeMessage } from "/wasm/pkg/graphite_wasm";
import type { FrontendMessage } from "/wasm/pkg/graphite_wasm";
let subscriptions: SubscriptionsRouter | undefined = undefined;
let editor: EditorHandle | undefined = undefined;
let editor: EditorWrapper | undefined = undefined;
onMount(async () => {
// Initialize the Wasm module
@@ -23,7 +23,7 @@
// Create the editor and subscriptions router
const randomSeed = BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER));
subscriptions = createSubscriptionsRouter();
editor = EditorHandle.create(operatingSystem(), randomSeed, (messageType: MessageName, messageData: FrontendMessage) => {
editor = EditorWrapper.create(operatingSystem(), randomSeed, (messageType: MessageName, messageData: FrontendMessage) => {
subscriptions?.handleFrontendMessage(messageType, messageData);
});

View File

@@ -8,7 +8,7 @@ Svelte components that build the Graphite editor GUI from layouts, panels, widge
TypeScript files, constructed by the editor frontend, which manage the input/output of browser APIs and link this functionality with the editor backend. These files subscribe to frontend messages to execute JS APIs, and in response to these APIs or user interactions, they may call functions in the backend (defined in `/frontend/wasm/editor_api.rs`).
Each manager module stores its dependencies (like `subscriptionsRouter` and `editorHandle`) in module-level variables and exports a `create*()` and `destroy*()` function pair. `Editor.svelte` calls each `create*()` constructor in its `onMount` and calls each `destroy*()` in its `onDestroy`. Managers replace themselves during HMR updates if they are modified live during development.
Each manager module stores its dependencies (like `subscriptionsRouter` and `editorWrapper`) in module-level variables and exports a `create*()` and `destroy*()` function pair. `Editor.svelte` calls each `create*()` constructor in its `onMount` and calls each `destroy*()` in its `onDestroy`. Managers replace themselves during HMR updates if they are modified live during development.
## Stores: `stores/`
@@ -26,11 +26,11 @@ TypeScript files which define and `export` individual helper functions for use e
## Subscriptions router: `subscriptions-router.ts`
Associates messages from the backend with subscribers in the frontend, and routes messages to subscriber callbacks. This module provides a `subscribeFrontendMessage(messageType, callback)` function which JS code throughout the frontend can call to be registered as the exclusive handler for a chosen message type. The router's other function, `handleFrontendMessage(messageType, messageData)`, is called via the callback passed to `EditorHandle.create()` in `App.svelte` when the backend sends a `FrontendMessage`. When this occurs, the subscriptions router delivers the message to the subscriber by executing its registered `callback` function.
Associates messages from the backend with subscribers in the frontend, and routes messages to subscriber callbacks. This module provides a `subscribeFrontendMessage(messageType, callback)` function which JS code throughout the frontend can call to be registered as the exclusive handler for a chosen message type. The router's other function, `handleFrontendMessage(messageType, messageData)`, is called via the callback passed to `EditorWrapper.create()` in `App.svelte` when the backend sends a `FrontendMessage`. When this occurs, the subscriptions router delivers the message to the subscriber by executing its registered `callback` function.
## Svelte app entry point: `App.svelte`
The entry point for the Svelte application. Initializes the Wasm module, creates the `EditorHandle` backend instance and the subscriptions router, and renders `Editor.svelte` once both are ready. The `EditorHandle` is the wasm-bindgen interface to the Rust editor backend (defined in `/frontend/wasm/editor_api.rs`), providing access to callable backend functions. Both the editor and subscriptions router are passed as props to `Editor.svelte` and set as Svelte contexts for use throughout the component tree.
The entry point for the Svelte application. Initializes the Wasm module, creates the `EditorWrapper` backend instance and the subscriptions router, and renders `Editor.svelte` once both are ready. The `EditorWrapper` is the wasm-bindgen interface to the Rust editor backend (defined in `/frontend/wasm/editor_api.rs`), providing access to callable backend functions. Both the editor and subscriptions router are passed as props to `Editor.svelte` and set as Svelte contexts for use throughout the component tree.
## Editor base instance: `Editor.svelte`

View File

@@ -16,11 +16,11 @@
import { createPortfolioStore, destroyPortfolioStore } from "/src/stores/portfolio";
import { createTooltipStore, destroyTooltipStore } from "/src/stores/tooltip";
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
// Graphite Wasm editor and subscriptions router
export let subscriptions: SubscriptionsRouter;
export let editor: EditorHandle;
export let editor: EditorWrapper;
setContext("subscriptions", subscriptions);
setContext("editor", editor);

View File

@@ -5,10 +5,10 @@
import ShortcutLabel from "/src/components/widgets/labels/ShortcutLabel.svelte";
import TextLabel from "/src/components/widgets/labels/TextLabel.svelte";
import type { TooltipStore } from "/src/stores/tooltip";
import type { EditorHandle, LabeledShortcut } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, LabeledShortcut } from "/wasm/pkg/graphite_wasm";
const tooltip = getContext<TooltipStore>("tooltip");
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
let self: FloatingMenu | undefined;

View File

@@ -17,7 +17,7 @@
import { textInputCleanup } from "/src/utility-functions/keyboard-entry";
import { rasterizeSVGCanvas } from "/src/utility-functions/rasterization";
import { setupViewportResizeObserver } from "/src/utility-functions/viewports";
import type { Color, EditorHandle, MenuDirection, MouseCursorIcon } from "/wasm/pkg/graphite_wasm";
import type { Color, EditorWrapper, MenuDirection, MouseCursorIcon } from "/wasm/pkg/graphite_wasm";
let rulerHorizontal: RulerInput | undefined;
let rulerVertical: RulerInput | undefined;
@@ -25,7 +25,7 @@
let gradientStopPicker: ColorPicker | undefined;
const subscriptions = getContext<SubscriptionsRouter>("subscriptions");
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
const appWindow = getContext<AppWindowStore>("appWindow");
const document = getContext<DocumentStore>("document");

View File

@@ -13,7 +13,7 @@
import { pasteFile } from "/src/utility-functions/files";
import { operatingSystem } from "/src/utility-functions/platform";
import { patchLayout } from "/src/utility-functions/widgets";
import type { EditorHandle, LayerPanelEntry, LayerStructureEntry, Layout } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, LayerPanelEntry, LayerStructureEntry, Layout } from "/wasm/pkg/graphite_wasm";
type LayerListingInfo = {
folderIndex: number;
@@ -40,7 +40,7 @@
};
const subscriptions = getContext<SubscriptionsRouter>("subscriptions");
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
const nodeGraph = getContext<NodeGraphStore>("nodeGraph");
const tooltip = getContext<TooltipStore>("tooltip");

View File

@@ -9,10 +9,10 @@
import { pasteFile } from "/src/utility-functions/files";
import { patchLayout } from "/src/utility-functions/widgets";
import { isPlatformNative } from "/wasm/pkg/graphite_wasm";
import type { EditorHandle, Layout } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, Layout } from "/wasm/pkg/graphite_wasm";
const subscriptions = getContext<SubscriptionsRouter>("subscriptions");
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
let welcomePanelButtonsLayout: Layout = [];

View File

@@ -11,13 +11,13 @@
import type { DocumentStore } from "/src/stores/document";
import type { NodeGraphStore } from "/src/stores/node-graph";
import { closeContextMenu } from "/src/stores/node-graph";
import type { EditorHandle, FrontendGraphInput, FrontendGraphOutput, FrontendNode } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, FrontendGraphInput, FrontendGraphOutput, FrontendNode } from "/wasm/pkg/graphite_wasm";
const GRID_COLLAPSE_SPACING = 10;
const GRID_SIZE = 24;
const FADE_TRANSITION = { duration: 200, easing: cubicInOut };
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
const nodeGraph = getContext<NodeGraphStore>("nodeGraph");
const documentState = getContext<DocumentStore>("document");

View File

@@ -4,7 +4,7 @@
import IconButton from "/src/components/widgets/buttons/IconButton.svelte";
import TextLabel from "/src/components/widgets/labels/TextLabel.svelte";
import WidgetSpan from "/src/components/widgets/WidgetSpan.svelte";
import type { EditorHandle, LayoutTarget, WidgetSection as WidgetSectionData } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, LayoutTarget, WidgetSection as WidgetSectionData } from "/wasm/pkg/graphite_wasm";
export let widgetData: WidgetSectionData;
export let layoutTarget: LayoutTarget;
@@ -15,7 +15,7 @@
let expanded = true;
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
</script>
<!-- TODO: Implement collapsable sections with properties system -->

View File

@@ -23,7 +23,7 @@
import ShortcutLabel from "/src/components/widgets/labels/ShortcutLabel.svelte";
import TextLabel from "/src/components/widgets/labels/TextLabel.svelte";
import { parseFillChoice } from "/src/utility-functions/colors";
import type { EditorHandle, LayoutTarget, Widget, WidgetInstance } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, LayoutTarget, Widget, WidgetInstance } from "/wasm/pkg/graphite_wasm";
// Extract the discriminant key names from the Widget tagged enum union (e.g. "TextButton" | "CheckboxInput" | ...)
type WidgetKind = Widget extends infer T ? (T extends Record<infer K, unknown> ? K & string : never) : never;
@@ -32,7 +32,7 @@
// A Widget tagged enum unwrapped into a correlated [kind, props] tuple
type UnwrappedWidget = { [K in WidgetKind]: [kind: K, props: WidgetProps<K>] }[WidgetKind];
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
export let widgets: WidgetInstance[];
export let direction: "row" | "column";

View File

@@ -5,7 +5,7 @@
import { PRESS_REPEAT_DELAY_MS, PRESS_REPEAT_INTERVAL_MS } from "/src/managers/input";
import { browserVersion } from "/src/utility-functions/platform";
import { evaluateMathExpression, isPlatformNative } from "/wasm/pkg/graphite_wasm";
import type { ActionShortcut, EditorHandle, NumberInputIncrementBehavior, NumberInputMode } from "/wasm/pkg/graphite_wasm";
import type { ActionShortcut, EditorWrapper, NumberInputIncrementBehavior, NumberInputMode } from "/wasm/pkg/graphite_wasm";
const BUTTONS_LEFT = 0b0000_0001;
const BUTTONS_RIGHT = 0b0000_0010;
@@ -14,7 +14,7 @@
const dispatch = createEventDispatcher<{ value: number | undefined; startHistoryTransaction: undefined }>();
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
// Content
/// When `value` is not provided (i.e. it's `undefined`), a dash is displayed.

View File

@@ -4,9 +4,9 @@
import LayoutCol from "/src/components/layout/LayoutCol.svelte";
import LayoutRow from "/src/components/layout/LayoutRow.svelte";
import { fillChoiceColor, colorToRgbaCSS } from "/src/utility-functions/colors";
import type { Color, EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { Color, EditorWrapper } from "/wasm/pkg/graphite_wasm";
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
// Content
export let primary: Color;

View File

@@ -9,7 +9,7 @@
import Welcome from "/src/components/panels/Welcome.svelte";
import IconButton from "/src/components/widgets/buttons/IconButton.svelte";
import TextLabel from "/src/components/widgets/labels/TextLabel.svelte";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
type PanelType = keyof typeof PANEL_COMPONENTS;
@@ -23,7 +23,7 @@
const BUTTON_LEFT = 0;
const BUTTON_MIDDLE = 1;
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
export let tabMinWidths = false;
export let tabCloseButtons = false;

View File

@@ -9,12 +9,12 @@
import type { TooltipStore } from "/src/stores/tooltip";
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import { patchLayout } from "/src/utility-functions/widgets";
import type { EditorHandle, Layout } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, Layout } from "/wasm/pkg/graphite_wasm";
import { isPlatformNative } from "/wasm/pkg/graphite_wasm";
const keyboardLockApiSupported = navigator.keyboard !== undefined && "lock" in navigator.keyboard;
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
const subscriptions = getContext<SubscriptionsRouter>("subscriptions");
const appWindow = getContext<AppWindowStore>("appWindow");
const fullscreen = getContext<FullscreenStore>("fullscreen");

View File

@@ -4,7 +4,7 @@
import LayoutRow from "/src/components/layout/LayoutRow.svelte";
import Panel from "/src/components/window/Panel.svelte";
import type { PortfolioStore } from "/src/stores/portfolio";
import type { EditorHandle, OpenDocument } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, OpenDocument } from "/wasm/pkg/graphite_wasm";
const MIN_PANEL_SIZE = 100;
const PANEL_SIZES = {
@@ -38,7 +38,7 @@
return { name, unsaved, tooltipLabel: name, tooltipDescription };
});
const editor = getContext<EditorHandle>("editor");
const editor = getContext<EditorWrapper>("editor");
const portfolio = getContext<PortfolioStore>("portfolio");
function resizePanel(e: PointerEvent) {

View File

@@ -1,15 +1,15 @@
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import { insertAtCaret, readAtCaret } from "/src/utility-functions/clipboard";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
let subscriptionsRouter: SubscriptionsRouter | undefined = undefined;
let editorHandle: EditorHandle | undefined = undefined;
let editorWrapper: EditorWrapper | undefined = undefined;
export function createClipboardManager(subscriptions: SubscriptionsRouter, editor: EditorHandle) {
export function createClipboardManager(subscriptions: SubscriptionsRouter, editor: EditorWrapper) {
destroyClipboardManager();
subscriptionsRouter = subscriptions;
editorHandle = editor;
editorWrapper = editor;
subscriptions.subscribeFrontendMessage("TriggerClipboardWrite", (data) => {
// If the Clipboard API is supported in the browser, copy text to the clipboard
@@ -36,5 +36,5 @@ export function destroyClipboardManager() {
// Self-accepting HMR: tear down the old instance and re-create with the new module's code
import.meta.hot?.accept((newModule) => {
if (subscriptionsRouter && editorHandle) newModule?.createClipboardManager(subscriptionsRouter, editorHandle);
if (subscriptionsRouter && editorWrapper) newModule?.createClipboardManager(subscriptionsRouter, editorWrapper);
});

View File

@@ -1,19 +1,19 @@
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
type ApiResponse = { family: string; variants: string[]; files: Record<string, string> }[];
const FONT_LIST_API = "https://api.graphite.art/font-list";
let subscriptionsRouter: SubscriptionsRouter | undefined = undefined;
let editorHandle: EditorHandle | undefined = undefined;
let editorWrapper: EditorWrapper | undefined = undefined;
let abortController: AbortController | undefined = undefined;
export function createFontsManager(subscriptions: SubscriptionsRouter, editor: EditorHandle) {
export function createFontsManager(subscriptions: SubscriptionsRouter, editor: EditorWrapper) {
destroyFontsManager();
subscriptionsRouter = subscriptions;
editorHandle = editor;
editorWrapper = editor;
abortController = new AbortController();
subscriptions.subscribeFrontendMessage("TriggerFontCatalogLoad", async () => {
@@ -71,5 +71,5 @@ export function destroyFontsManager() {
// Self-accepting HMR: tear down the old instance and re-create with the new module's code
import.meta.hot?.accept((newModule) => {
if (subscriptionsRouter && editorHandle) newModule?.createFontsManager(subscriptionsRouter, editorHandle);
if (subscriptionsRouter && editorWrapper) newModule?.createFontsManager(subscriptionsRouter, editorWrapper);
});

View File

@@ -20,7 +20,7 @@ import {
onPaste,
onPointerLockChange,
} from "/src/utility-functions/input";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
type EventName = keyof HTMLElementEventMap | keyof WindowEventHandlersEventMap | "modifyinputfield" | "pointerlockchange" | "pointerlockerror";
type EventListenerTarget = {
@@ -33,35 +33,35 @@ export const PRESS_REPEAT_DELAY_MS = 400;
export const PRESS_REPEAT_INTERVAL_MS = 72;
export const PRESS_REPEAT_INTERVAL_RAPID_MS = 10;
const listeners: Listener[] = [
{ target: window, eventName: "beforeunload", action: (e: BeforeUnloadEvent) => editorHandle && portfolioStore && onBeforeUnload(e, editorHandle, portfolioStore) },
{ target: window, eventName: "keyup", action: (e: KeyboardEvent) => editorHandle && dialogStore && onKeyUp(e, editorHandle, dialogStore) },
{ target: window, eventName: "keydown", action: (e: KeyboardEvent) => editorHandle && dialogStore && onKeyDown(e, editorHandle, dialogStore) },
{ target: window, eventName: "pointermove", action: (e: PointerEvent) => editorHandle && documentStore && onPointerMove(e, editorHandle, documentStore) },
{ target: window, eventName: "pointerdown", action: (e: PointerEvent) => editorHandle && dialogStore && onPointerDown(e, editorHandle, dialogStore) },
{ target: window, eventName: "pointerup", action: (e: PointerEvent) => editorHandle && onPointerUp(e, editorHandle) },
{ target: window, eventName: "beforeunload", action: (e: BeforeUnloadEvent) => editorWrapper && portfolioStore && onBeforeUnload(e, editorWrapper, portfolioStore) },
{ target: window, eventName: "keyup", action: (e: KeyboardEvent) => editorWrapper && dialogStore && onKeyUp(e, editorWrapper, dialogStore) },
{ target: window, eventName: "keydown", action: (e: KeyboardEvent) => editorWrapper && dialogStore && onKeyDown(e, editorWrapper, dialogStore) },
{ target: window, eventName: "pointermove", action: (e: PointerEvent) => editorWrapper && documentStore && onPointerMove(e, editorWrapper, documentStore) },
{ target: window, eventName: "pointerdown", action: (e: PointerEvent) => editorWrapper && dialogStore && onPointerDown(e, editorWrapper, dialogStore) },
{ target: window, eventName: "pointerup", action: (e: PointerEvent) => editorWrapper && onPointerUp(e, editorWrapper) },
{ target: window, eventName: "mousedown", action: (e: MouseEvent) => onMouseDown(e) },
{ target: window, eventName: "mouseup", action: (e: MouseEvent) => editorHandle && onPotentialDoubleClick(e, editorHandle) },
{ target: window, eventName: "wheel", action: (e: WheelEvent) => editorHandle && onWheelScroll(e, editorHandle), options: { passive: false } },
{ target: window, eventName: "mouseup", action: (e: MouseEvent) => editorWrapper && onPotentialDoubleClick(e, editorWrapper) },
{ target: window, eventName: "wheel", action: (e: WheelEvent) => editorWrapper && onWheelScroll(e, editorWrapper), options: { passive: false } },
{ target: window, eventName: "modifyinputfield", action: (e: CustomEvent) => onModifyInputField(e) },
{ target: window, eventName: "focusout", action: () => onFocusOut() },
{ target: window.document, eventName: "contextmenu", action: (e: MouseEvent) => onContextMenu(e) },
{ target: window.document, eventName: "fullscreenchange", action: () => fullscreenModeChanged() },
{ target: window.document.body, eventName: "paste", action: (e: ClipboardEvent) => editorHandle && onPaste(e, editorHandle) },
{ target: window.document.body, eventName: "paste", action: (e: ClipboardEvent) => editorWrapper && onPaste(e, editorWrapper) },
{ target: window.document, eventName: "pointerlockchange", action: onPointerLockChange },
{ target: window.document, eventName: "pointerlockerror", action: onPointerLockChange },
];
let subscriptionsRouter: SubscriptionsRouter | undefined = undefined;
let editorHandle: EditorHandle | undefined = undefined;
let editorWrapper: EditorWrapper | undefined = undefined;
let dialogStore: DialogStore | undefined = undefined;
let portfolioStore: PortfolioStore | undefined = undefined;
let documentStore: DocumentStore | undefined = undefined;
export function createInputManager(subscriptions: SubscriptionsRouter, editor: EditorHandle, dialog: DialogStore, portfolio: PortfolioStore, doc: DocumentStore) {
export function createInputManager(subscriptions: SubscriptionsRouter, editor: EditorWrapper, dialog: DialogStore, portfolio: PortfolioStore, doc: DocumentStore) {
destroyInputManager();
subscriptionsRouter = subscriptions;
editorHandle = editor;
editorWrapper = editor;
dialogStore = dialog;
portfolioStore = portfolio;
documentStore = doc;
@@ -98,6 +98,6 @@ export function destroyInputManager() {
// Self-accepting HMR: tear down the old instance and re-create with the new module's code
import.meta.hot?.accept((newModule) => {
if (subscriptionsRouter && editorHandle && dialogStore && portfolioStore && documentStore)
newModule?.createInputManager(subscriptionsRouter, editorHandle, dialogStore, portfolioStore, documentStore);
if (subscriptionsRouter && editorWrapper && dialogStore && portfolioStore && documentStore)
newModule?.createInputManager(subscriptionsRouter, editorWrapper, dialogStore, portfolioStore, documentStore);
});

View File

@@ -1,15 +1,15 @@
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import { localizeTimestamp } from "/src/utility-functions/time";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
let subscriptionsRouter: SubscriptionsRouter | undefined = undefined;
let editorHandle: EditorHandle | undefined = undefined;
let editorWrapper: EditorWrapper | undefined = undefined;
export function createLocalizationManager(subscriptions: SubscriptionsRouter, editor: EditorHandle) {
export function createLocalizationManager(subscriptions: SubscriptionsRouter, editor: EditorWrapper) {
destroyLocalizationManager();
subscriptionsRouter = subscriptions;
editorHandle = editor;
editorWrapper = editor;
subscriptions.subscribeFrontendMessage("TriggerAboutGraphiteLocalizedCommitDate", (data) => {
const localized = localizeTimestamp(data.commitDate);
@@ -26,5 +26,5 @@ export function destroyLocalizationManager() {
// Self-accepting HMR: tear down the old instance and re-create with the new module's code
import.meta.hot?.accept((newModule) => {
if (subscriptionsRouter && editorHandle) newModule?.createLocalizationManager(subscriptionsRouter, editorHandle);
if (subscriptionsRouter && editorWrapper) newModule?.createLocalizationManager(subscriptionsRouter, editorWrapper);
});

View File

@@ -1,17 +1,17 @@
import type { PortfolioStore } from "/src/stores/portfolio";
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import { saveEditorPreferences, loadEditorPreferences, storeDocument, removeDocument, loadFirstDocument, loadRestDocuments, saveActiveDocument } from "/src/utility-functions/persistence";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
let subscriptionsRouter: SubscriptionsRouter | undefined = undefined;
let editorHandle: EditorHandle | undefined = undefined;
let editorWrapper: EditorWrapper | undefined = undefined;
let portfolioStore: PortfolioStore | undefined = undefined;
export function createPersistenceManager(subscriptions: SubscriptionsRouter, editor: EditorHandle, portfolio: PortfolioStore) {
export function createPersistenceManager(subscriptions: SubscriptionsRouter, editor: EditorWrapper, portfolio: PortfolioStore) {
destroyPersistenceManager();
subscriptionsRouter = subscriptions;
editorHandle = editor;
editorWrapper = editor;
portfolioStore = portfolio;
subscriptions.subscribeFrontendMessage("TriggerSavePreferences", async (data) => {
@@ -63,5 +63,5 @@ export function destroyPersistenceManager() {
// Self-accepting HMR: tear down the old instance and re-create with the new module's code
import.meta.hot?.accept((newModule) => {
if (subscriptionsRouter && editorHandle && portfolioStore) newModule?.createPersistenceManager(subscriptionsRouter, editorHandle, portfolioStore);
if (subscriptionsRouter && editorWrapper && portfolioStore) newModule?.createPersistenceManager(subscriptionsRouter, editorWrapper, portfolioStore);
});

View File

@@ -4,7 +4,7 @@ import type { Writable } from "svelte/store";
import type { IconName } from "/src/icons";
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import { patchLayout } from "/src/utility-functions/widgets";
import type { EditorHandle, Layout } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, Layout } from "/wasm/pkg/graphite_wasm";
export type DialogStore = ReturnType<typeof createDialogStore>;
@@ -35,7 +35,7 @@ const store: Writable<DialogStoreState> = import.meta.hot?.data?.store || writab
if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createDialogStore(subscriptions: SubscriptionsRouter, editor: EditorHandle) {
export function createDialogStore(subscriptions: SubscriptionsRouter, editor: EditorWrapper) {
destroyDialogStore();
subscriptionsRouter = subscriptions;

View File

@@ -3,7 +3,7 @@ import type { Writable } from "svelte/store";
import type { SubscriptionsRouter } from "/src/subscriptions-router";
import { downloadFile, downloadFileBlob, upload } from "/src/utility-functions/files";
import { rasterizeSVG } from "/src/utility-functions/rasterization";
import type { EditorHandle, OpenDocument } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper, OpenDocument } from "/wasm/pkg/graphite_wasm";
export type PortfolioStore = ReturnType<typeof createPortfolioStore>;
@@ -31,7 +31,7 @@ const store: Writable<PortfolioStoreState> = import.meta.hot?.data?.store || wri
if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createPortfolioStore(subscriptions: SubscriptionsRouter, editor: EditorHandle) {
export function createPortfolioStore(subscriptions: SubscriptionsRouter, editor: EditorWrapper) {
destroyPortfolioStore();
subscriptionsRouter = subscriptions;

View File

@@ -1,6 +1,6 @@
import { extractPixelData } from "/src/utility-functions/rasterization";
import { stripIndents } from "/src/utility-functions/strip-indents";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
export function readAtCaret(cut: boolean): string | undefined {
const element = window.document.activeElement;
@@ -83,7 +83,7 @@ export function insertAtCaret(text: string) {
element.dispatchEvent(new Event("input", { bubbles: true }));
}
export async function triggerClipboardRead(editor: EditorHandle) {
export async function triggerClipboardRead(editor: EditorWrapper) {
// In the try block, attempt to read from the Clipboard API, which may not have permission and may not be supported in all browsers
// In the catch block, explain to the user why the paste failed and how to fix or work around the problem
try {

View File

@@ -1,5 +1,5 @@
import { extractPixelData } from "/src/utility-functions/rasterization";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
export function downloadFileURL(filename: string, url: string) {
const element = document.createElement("a");
@@ -66,7 +66,7 @@ export async function upload(accept: string, textOrData: "text" | "data" | "both
}
export type UploadResult<T> = { filename: string; type: string; content: T };
export async function pasteFile(item: DataTransferItem, editor: EditorHandle, mouse?: [number, number], insertParentId?: bigint, insertIndex?: number) {
export async function pasteFile(item: DataTransferItem, editor: EditorWrapper, mouse?: [number, number], insertParentId?: bigint, insertIndex?: number) {
const file = item.getAsFile();
if (!file) return;

View File

@@ -6,7 +6,7 @@ import type { PortfolioStore } from "/src/stores/portfolio";
import { pasteFile } from "/src/utility-functions/files";
import { makeKeyboardModifiersBitfield, textInputCleanup, getLocalizedScanCode } from "/src/utility-functions/keyboard-entry";
import { operatingSystem } from "/src/utility-functions/platform";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
import { isPlatformNative } from "/wasm/pkg/graphite_wasm";
const BUTTON_LEFT = 0;
@@ -78,7 +78,7 @@ export async function shouldRedirectKeyboardEventToBackend(e: KeyboardEvent, dia
return true;
}
export async function onKeyDown(e: KeyboardEvent, editor: EditorHandle, dialogStore: DialogStore) {
export async function onKeyDown(e: KeyboardEvent, editor: EditorWrapper, dialogStore: DialogStore) {
const key = await getLocalizedScanCode(e);
const NO_KEY_REPEAT_MODIFIER_KEYS = ["ControlLeft", "ControlRight", "ShiftLeft", "ShiftRight", "MetaLeft", "MetaRight", "AltLeft", "AltRight", "AltGraph", "CapsLock", "Fn", "FnLock"];
@@ -96,7 +96,7 @@ export async function onKeyDown(e: KeyboardEvent, editor: EditorHandle, dialogSt
}
}
export async function onKeyUp(e: KeyboardEvent, editor: EditorHandle, dialogStore: DialogStore) {
export async function onKeyUp(e: KeyboardEvent, editor: EditorWrapper, dialogStore: DialogStore) {
const key = await getLocalizedScanCode(e);
if (await shouldRedirectKeyboardEventToBackend(e, dialogStore)) {
@@ -109,7 +109,7 @@ export async function onKeyUp(e: KeyboardEvent, editor: EditorHandle, dialogStor
// Pointer events
// While any pointer button is already down, additional button down events are not reported, but they are sent as `pointermove` events and these are handled in the backend
export function onPointerMove(e: PointerEvent, editor: EditorHandle, documentStore: DocumentStore) {
export function onPointerMove(e: PointerEvent, editor: EditorWrapper, documentStore: DocumentStore) {
potentiallyRestoreCanvasFocus(e);
if (!e.buttons) viewportPointerInteractionOngoing = false;
@@ -127,7 +127,7 @@ export function onPointerMove(e: PointerEvent, editor: EditorHandle, documentSto
editor.onMouseMove(e.clientX, e.clientY, e.buttons, modifiers);
}
export function onPointerDown(e: PointerEvent, editor: EditorHandle, dialogStore: DialogStore) {
export function onPointerDown(e: PointerEvent, editor: EditorWrapper, dialogStore: DialogStore) {
potentiallyRestoreCanvasFocus(e);
const inFloatingMenu = e.target instanceof Element && e.target.closest("[data-floating-menu-content]");
@@ -157,7 +157,7 @@ export function onPointerDown(e: PointerEvent, editor: EditorHandle, dialogStore
}
}
export function onPointerUp(e: PointerEvent, editor: EditorHandle) {
export function onPointerUp(e: PointerEvent, editor: EditorWrapper) {
potentiallyRestoreCanvasFocus(e);
// Don't let the browser navigate back or forward when using the buttons on some mice
@@ -176,7 +176,7 @@ export function onPointerUp(e: PointerEvent, editor: EditorHandle) {
// Mouse events
export function onPotentialDoubleClick(e: MouseEvent, editor: EditorHandle) {
export function onPotentialDoubleClick(e: MouseEvent, editor: EditorWrapper) {
if (textToolInteractiveInputElement || inPointerLock) return;
// Allow only events within the viewport or node graph boundaries
@@ -215,7 +215,7 @@ export function onPointerLockChange() {
// Wheel events
export function onWheelScroll(e: WheelEvent, editor: EditorHandle) {
export function onWheelScroll(e: WheelEvent, editor: EditorWrapper) {
const isTargetingCanvas = e.target instanceof Element && e.target.closest("[data-viewport], [data-viewport-container], [data-node-graph]");
// Prevent zooming the entire page when using Ctrl + scroll wheel outside of the viewport
@@ -246,7 +246,7 @@ export function onModifyInputField(e: CustomEvent) {
// Window events
export async function onBeforeUnload(e: BeforeUnloadEvent, editor: EditorHandle, portfolioStore: PortfolioStore) {
export async function onBeforeUnload(e: BeforeUnloadEvent, editor: EditorWrapper, portfolioStore: PortfolioStore) {
const activeDocument = get(portfolioStore).documents[get(portfolioStore).activeDocumentIndex];
if (activeDocument && !activeDocument.details.isAutoSaved) editor.triggerAutoSave(activeDocument.id);
@@ -263,7 +263,7 @@ export async function onBeforeUnload(e: BeforeUnloadEvent, editor: EditorHandle,
}
}
export function onPaste(e: ClipboardEvent, editor: EditorHandle) {
export function onPaste(e: ClipboardEvent, editor: EditorWrapper) {
const dataTransfer = e.clipboardData;
if (!dataTransfer || targetIsTextField(e.target || undefined)) return;
e.preventDefault();

View File

@@ -1,4 +1,4 @@
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
export type RequestResult = { body: string; status: number };
@@ -35,7 +35,7 @@ export function requestWithUploadDownloadProgress(
}
// If the URL hash fragment contains a demo artwork path (e.g. #demo/isometric-light), fetch and open it
export async function loadDemoArtwork(editor: EditorHandle) {
export async function loadDemoArtwork(editor: EditorWrapper) {
const demoArtwork = window.location.hash.trim().match(/#demo\/(.*)/)?.[1];
if (!demoArtwork) return;

View File

@@ -2,7 +2,7 @@ import * as idb from "idb-keyval";
import { get } from "svelte/store";
import type { PortfolioStore } from "/src/stores/portfolio";
import type { MessageBody } from "/src/subscriptions-router";
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
export async function storeCurrentDocumentId(documentId: string) {
const indexedDbStorage = idb.createStore("graphite", "store");
@@ -64,7 +64,7 @@ export async function removeDocument(id: string, portfolio: PortfolioStore) {
}
}
export async function loadFirstDocument(editor: EditorHandle) {
export async function loadFirstDocument(editor: EditorWrapper) {
const indexedDbStorage = idb.createStore("graphite", "store");
const previouslySavedDocuments = await idb.get<Record<string, MessageBody<"TriggerPersistenceWriteDocument">>>("documents", indexedDbStorage);
@@ -98,7 +98,7 @@ export async function loadFirstDocument(editor: EditorHandle) {
}
}
export async function loadRestDocuments(editor: EditorHandle) {
export async function loadRestDocuments(editor: EditorWrapper) {
const indexedDbStorage = idb.createStore("graphite", "store");
const previouslySavedDocuments = await idb.get<Record<string, MessageBody<"TriggerPersistenceWriteDocument">>>("documents", indexedDbStorage);
@@ -176,7 +176,7 @@ export async function saveEditorPreferences(preferences: unknown) {
await idb.set("preferences", preferences, indexedDbStorage);
}
export async function loadEditorPreferences(editor: EditorHandle) {
export async function loadEditorPreferences(editor: EditorWrapper) {
const indexedDbStorage = idb.createStore("graphite", "store");
const preferences = await idb.get<Record<string, unknown>>("preferences", indexedDbStorage);

View File

@@ -1,6 +1,6 @@
import type { EditorHandle } from "/wasm/pkg/graphite_wasm";
import type { EditorWrapper } from "/wasm/pkg/graphite_wasm";
export function setupViewportResizeObserver(editor: EditorHandle): () => void {
export function setupViewportResizeObserver(editor: EditorWrapper): () => void {
const viewports = Array.from(window.document.querySelectorAll("[data-viewport-container]"));
if (viewports.length <= 0) return () => {};