mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-25 21:48:11 +08:00
Refactor the TypeScript data flow for full type safety and auto-generation of Rust types (#3865)
* Migrate Specta to Tsify to auto-generate messages.ts, working except colors and widgets * Adopt the generated FillColor/Color/GradientStops * Fix widget typing * Separate WidgetGroup enum variants into wrapper structs * Small rename * Simplify widgets further * Clean up message type references * Switch type imports to the auto-generated file * Remove lowercase serde rename * Fix FillChoice deserialization * Fix small regression from #3837 * Improve type safety * Make WidgetSpan type-safe * More cleanup and type safety * More type safety * More type safety * Get the rest to type-check without errors; improve widget builder macro to have optional icons; improve Svelte 5 configs * Cargo fmt * Fix imports * Update outdated readme info * Fix lint command rename references * Fix typos * One more typos fix * Remove unnecessary dep: prefix from the edited Cargo.toml files * Remove excess parts from Cargo.toml * Fix compiling on desktop * Revert "Remove excess parts from Cargo.toml" This reverts commit 6b711117b3a5d5d8a3ee20f36a43bc74930b7c82. * Update dev docs with simpler, more accurate instructions
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import type { AppWindowPlatform } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { AppWindowPlatform } from "@graphite/messages";
|
||||
|
||||
export function createAppWindowState(editor: Editor) {
|
||||
const { subscribe, update } = writable({
|
||||
platform: "Web" as AppWindowPlatform,
|
||||
const { subscribe, update } = writable<{
|
||||
platform: AppWindowPlatform;
|
||||
maximized: boolean;
|
||||
fullscreen: boolean;
|
||||
viewportHolePunch: boolean;
|
||||
uiScale: number;
|
||||
}>({
|
||||
platform: "Web",
|
||||
maximized: false,
|
||||
fullscreen: false,
|
||||
viewportHolePunch: false,
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import type { Layout } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { IconName } from "@graphite/icons";
|
||||
import type { Layout } from "@graphite/messages";
|
||||
import { patchLayout } from "@graphite/utility-functions/widgets";
|
||||
|
||||
export function createDialogState(editor: Editor) {
|
||||
const { subscribe, update } = writable({
|
||||
const { subscribe, update } = writable<{
|
||||
visible: boolean;
|
||||
title: string;
|
||||
icon: IconName | undefined;
|
||||
buttons: Layout;
|
||||
column1: Layout;
|
||||
column2: Layout;
|
||||
panicDetails: string;
|
||||
}>({
|
||||
visible: false,
|
||||
title: "",
|
||||
icon: "" as IconName,
|
||||
buttons: [] as Layout,
|
||||
column1: [] as Layout,
|
||||
column2: [] as Layout,
|
||||
icon: undefined,
|
||||
buttons: [],
|
||||
column1: [],
|
||||
column2: [],
|
||||
// Special case for the crash dialog because we cannot handle button widget callbacks from Rust once the editor has panicked
|
||||
panicDetails: "",
|
||||
});
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
import { tick } from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import type { Layout } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { Layout } from "@graphite/messages";
|
||||
import { patchLayout } from "@graphite/utility-functions/widgets";
|
||||
|
||||
export function createDocumentState(editor: Editor) {
|
||||
const state = writable({
|
||||
// Layouts
|
||||
toolOptionsLayout: [] as Layout,
|
||||
documentBarLayout: [] as Layout,
|
||||
toolShelfLayout: [] as Layout,
|
||||
workingColorsLayout: [] as Layout,
|
||||
nodeGraphControlBarLayout: [] as Layout,
|
||||
// Graph view overlay
|
||||
const state = writable<{
|
||||
toolOptionsLayout: Layout;
|
||||
documentBarLayout: Layout;
|
||||
toolShelfLayout: Layout;
|
||||
workingColorsLayout: Layout;
|
||||
nodeGraphControlBarLayout: Layout;
|
||||
graphViewOverlayOpen: boolean;
|
||||
fadeArtwork: number;
|
||||
}>({
|
||||
toolOptionsLayout: [],
|
||||
documentBarLayout: [],
|
||||
toolShelfLayout: [],
|
||||
workingColorsLayout: [],
|
||||
nodeGraphControlBarLayout: [],
|
||||
graphViewOverlayOpen: false,
|
||||
fadeArtwork: 100,
|
||||
});
|
||||
|
||||
@@ -4,8 +4,7 @@ import type { Editor } from "@graphite/editor";
|
||||
|
||||
export function createFullscreenState(editor: Editor) {
|
||||
// Experimental Keyboard API: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/keyboard
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const keyboardLockApiSupported: Readonly<boolean> = "keyboard" in navigator && (navigator as any).keyboard && "lock" in (navigator as any).keyboard;
|
||||
const keyboardLockApiSupported: Readonly<boolean> = navigator.keyboard !== undefined && "lock" in navigator.keyboard;
|
||||
|
||||
const { subscribe, update } = writable({
|
||||
windowFullscreen: false,
|
||||
@@ -24,9 +23,8 @@ export function createFullscreenState(editor: Editor) {
|
||||
async function enterFullscreen() {
|
||||
await document.documentElement.requestFullscreen();
|
||||
|
||||
if (keyboardLockApiSupported) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
await (navigator as any).keyboard.lock(["ControlLeft", "ControlRight"]);
|
||||
if (keyboardLockApiSupported && navigator.keyboard) {
|
||||
await navigator.keyboard.lock(["ControlLeft", "ControlRight"]);
|
||||
|
||||
update((state) => {
|
||||
state.keyboardLocked = true;
|
||||
|
||||
@@ -1,33 +1,53 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import type { NodeGraphErrorDiagnostic, BoxSelection, FrontendClickTargets, ContextMenuInformation, FrontendNode, FrontendNodeType, WirePath } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { NodeGraphError, Box, FrontendClickTargets, ContextMenuInformation, FrontendNode, FrontendNodeType, WirePath, FrontendMessages } from "@graphite/messages";
|
||||
|
||||
type UpdateImportsExports = FrontendMessages["UpdateImportsExports"];
|
||||
import type { MessageBody } from "@graphite/subscription-router";
|
||||
|
||||
export function createNodeGraphState(editor: Editor) {
|
||||
const { subscribe, update } = writable({
|
||||
box: undefined as Box | undefined,
|
||||
clickTargets: undefined as FrontendClickTargets | undefined,
|
||||
contextMenuInformation: undefined as ContextMenuInformation | undefined,
|
||||
error: undefined as NodeGraphError | undefined,
|
||||
layerWidths: new Map<bigint, number>(),
|
||||
chainWidths: new Map<bigint, number>(),
|
||||
hasLeftInputWire: new Map<bigint, boolean>(),
|
||||
updateImportsExports: undefined as UpdateImportsExports | undefined,
|
||||
nodes: new Map<bigint, FrontendNode>(),
|
||||
visibleNodes: new Set<bigint>(),
|
||||
const { subscribe, update } = writable<{
|
||||
box: BoxSelection | undefined;
|
||||
clickTargets: FrontendClickTargets | undefined;
|
||||
contextMenuInformation: ContextMenuInformation | undefined;
|
||||
error: NodeGraphErrorDiagnostic | undefined;
|
||||
layerWidths: Map<bigint, number>;
|
||||
chainWidths: Map<bigint, number>;
|
||||
hasLeftInputWire: Map<bigint, boolean>;
|
||||
updateImportsExports: MessageBody<"UpdateImportsExports"> | undefined;
|
||||
nodes: Map<bigint, FrontendNode>;
|
||||
visibleNodes: Set<bigint>;
|
||||
/// The index is the exposed input index. The exports have a first key value of u32::MAX.
|
||||
wires: new Map<bigint, Map<number, WirePath>>(),
|
||||
wirePathInProgress: undefined as WirePath | undefined,
|
||||
nodeDescriptions: new Map<string, string>(),
|
||||
nodeTypes: [] as FrontendNodeType[],
|
||||
thumbnails: new Map<bigint, string>(),
|
||||
selected: [] as bigint[],
|
||||
wires: Map<bigint, Map<number, WirePath>>;
|
||||
wirePathInProgress: WirePath | undefined;
|
||||
nodeDescriptions: Map<string, string>;
|
||||
nodeTypes: FrontendNodeType[];
|
||||
thumbnails: Map<bigint, string>;
|
||||
selected: bigint[];
|
||||
transform: { scale: number; x: number; y: number };
|
||||
inSelectedNetwork: boolean;
|
||||
reorderImportIndex: number | undefined;
|
||||
reorderExportIndex: number | undefined;
|
||||
}>({
|
||||
box: undefined,
|
||||
clickTargets: undefined,
|
||||
contextMenuInformation: undefined,
|
||||
error: undefined,
|
||||
layerWidths: new Map(),
|
||||
chainWidths: new Map(),
|
||||
hasLeftInputWire: new Map(),
|
||||
updateImportsExports: undefined,
|
||||
nodes: new Map(),
|
||||
visibleNodes: new Set(),
|
||||
wires: new Map(),
|
||||
wirePathInProgress: undefined,
|
||||
nodeDescriptions: new Map(),
|
||||
nodeTypes: [],
|
||||
thumbnails: new Map(),
|
||||
selected: [],
|
||||
transform: { scale: 1, x: 0, y: 0 },
|
||||
inSelectedNetwork: true,
|
||||
reorderImportIndex: undefined as number | undefined,
|
||||
reorderExportIndex: undefined as number | undefined,
|
||||
reorderImportIndex: undefined,
|
||||
reorderExportIndex: undefined,
|
||||
});
|
||||
|
||||
function closeContextMenu() {
|
||||
@@ -148,7 +168,7 @@ export function createNodeGraphState(editor: Editor) {
|
||||
});
|
||||
editor.subscriptions.subscribeFrontendMessage("UpdateNodeGraphTransform", (data) => {
|
||||
update((state) => {
|
||||
state.transform = data.transform;
|
||||
state.transform = { scale: data.scale, x: data.translation[0], y: data.translation[1] };
|
||||
return state;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import type { OpenDocument } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { OpenDocument } from "@graphite/messages";
|
||||
import { downloadFile, downloadFileBlob, upload } from "@graphite/utility-functions/files";
|
||||
import { rasterizeSVG } from "@graphite/utility-functions/rasterization";
|
||||
|
||||
export function createPortfolioState(editor: Editor) {
|
||||
const { subscribe, update } = writable({
|
||||
const { subscribe, update } = writable<{
|
||||
unsaved: boolean;
|
||||
documents: OpenDocument[];
|
||||
activeDocumentIndex: number;
|
||||
dataPanelOpen: boolean;
|
||||
propertiesPanelOpen: boolean;
|
||||
layersPanelOpen: boolean;
|
||||
}>({
|
||||
unsaved: false,
|
||||
documents: [] as OpenDocument[],
|
||||
documents: [],
|
||||
activeDocumentIndex: 0,
|
||||
dataPanelOpen: false,
|
||||
propertiesPanelOpen: true,
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import type { ActionShortcut } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { ActionShortcut } from "@graphite/messages";
|
||||
import { operatingSystem } from "@graphite/utility-functions/platform";
|
||||
|
||||
const SHOW_TOOLTIP_DELAY_MS = 500;
|
||||
|
||||
export function createTooltipState(editor: Editor) {
|
||||
const { subscribe, update } = writable({
|
||||
const { subscribe, update } = writable<{
|
||||
visible: boolean;
|
||||
element: Element | undefined;
|
||||
position: { x: number; y: number };
|
||||
shiftClickShortcut: ActionShortcut | undefined;
|
||||
altClickShortcut: ActionShortcut | undefined;
|
||||
fullscreenShortcut: ActionShortcut | undefined;
|
||||
}>({
|
||||
visible: false,
|
||||
element: undefined as Element | undefined,
|
||||
element: undefined,
|
||||
position: { x: 0, y: 0 },
|
||||
shiftClickShortcut: undefined as ActionShortcut | undefined,
|
||||
altClickShortcut: undefined as ActionShortcut | undefined,
|
||||
fullscreenShortcut: undefined as ActionShortcut | undefined,
|
||||
shiftClickShortcut: undefined,
|
||||
altClickShortcut: undefined,
|
||||
fullscreenShortcut: undefined,
|
||||
});
|
||||
|
||||
let tooltipTimeout: ReturnType<typeof setTimeout> | undefined = undefined;
|
||||
|
||||
Reference in New Issue
Block a user