mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 20:28:11 +08:00
Fix frontend HMR so the page doesn't break upon saving TS files and restructure frontend architecture (#3871)
* Clean up component setup/tear-down side effects * Clean up more component setup/tear-down side effects * Remove nonfunctional debouncer * Clean up even more component setup/tear-down side effects * Reuse backend state * Fix HMR for IO Managers and for State Providers * Rename IO Managers -> Managers and State Providers -> Stores * Restructure and partially flatten managers/stores * Code review fixes * Review fixes
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
import { isPlatformNative } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { FillChoice, MenuDirection, Color } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { TooltipState } from "@graphite/state-providers/tooltip";
|
||||
import type { TooltipStore } from "@graphite/stores/tooltip";
|
||||
import {
|
||||
contrastingOutlineFactor,
|
||||
fillChoiceColor,
|
||||
@@ -22,7 +22,6 @@
|
||||
gradientFirstColor,
|
||||
} from "@graphite/utility-functions/colors";
|
||||
import type { HSV, RGB } from "@graphite/utility-functions/colors";
|
||||
import { clamp } from "@graphite/utility-functions/math";
|
||||
|
||||
import FloatingMenu, { preventEscapeClosingParentFloatingMenu } from "@graphite/components/layout/FloatingMenu.svelte";
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
@@ -57,7 +56,7 @@
|
||||
];
|
||||
|
||||
const dispatch = createEventDispatcher<{ colorOrGradient: FillChoice; startHistoryTransaction: undefined; commitHistoryTransaction: undefined }>();
|
||||
const tooltip = getContext<TooltipState>("tooltip");
|
||||
const tooltip = getContext<TooltipStore>("tooltip");
|
||||
|
||||
export let colorOrGradient: FillChoice;
|
||||
export let allowNone = false;
|
||||
@@ -438,6 +437,10 @@
|
||||
setOldHSVA(hsv.h, hsv.s, hsv.v, color.alpha, false);
|
||||
}
|
||||
|
||||
function clamp(value: number, min = 0, max = 1): number {
|
||||
return Math.max(min, Math.min(value, max));
|
||||
}
|
||||
|
||||
export function div(): HTMLDivElement | undefined {
|
||||
return self?.div();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from "svelte";
|
||||
|
||||
import { githubUrl } from "@graphite/io-managers/panic";
|
||||
import { wipeDocuments } from "@graphite/io-managers/persistence";
|
||||
|
||||
import type { DialogState } from "@graphite/state-providers/dialog";
|
||||
import { wipeDocuments } from "@graphite/managers/persistence";
|
||||
import type { DialogStore } from "@graphite/stores/dialog";
|
||||
import { crashReportUrl } from "/src/utility-functions/crash-report";
|
||||
|
||||
import FloatingMenu from "@graphite/components/layout/FloatingMenu.svelte";
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
@@ -14,7 +13,7 @@
|
||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||
import WidgetLayout from "@graphite/components/widgets/WidgetLayout.svelte";
|
||||
|
||||
const dialog = getContext<DialogState>("dialog");
|
||||
const dialog = getContext<DialogStore>("dialog");
|
||||
|
||||
let self: FloatingMenu | undefined;
|
||||
|
||||
@@ -43,7 +42,7 @@
|
||||
<div class="widget-layout details">
|
||||
<div class="widget-span row"><TextLabel bold={true}>The editor crashed — sorry about that</TextLabel></div>
|
||||
<div class="widget-span row"><TextLabel>Please report this by filing an issue on GitHub:</TextLabel></div>
|
||||
<div class="widget-span row"><TextButton label="Report Bug" icon="Warning" flush={true} action={() => window.open(githubUrl($dialog.panicDetails), "_blank")} /></div>
|
||||
<div class="widget-span row"><TextButton label="Report Bug" icon="Warning" flush={true} action={() => window.open(crashReportUrl($dialog.panicDetails), "_blank")} /></div>
|
||||
<div class="widget-span row"><TextLabel multiline={true}>Reload the editor to continue. If this occurs<br />immediately on repeated reloads, clear storage:</TextLabel></div>
|
||||
<div class="widget-span row">
|
||||
<TextButton
|
||||
|
||||
@@ -12,10 +12,7 @@
|
||||
|
||||
import FloatingMenu from "@graphite/components/layout/FloatingMenu.svelte";
|
||||
|
||||
const temporaryCanvas = document.createElement("canvas");
|
||||
temporaryCanvas.width = ZOOM_WINDOW_DIMENSIONS;
|
||||
temporaryCanvas.height = ZOOM_WINDOW_DIMENSIONS;
|
||||
|
||||
let temporaryCanvas: HTMLCanvasElement | undefined;
|
||||
let zoomPreviewCanvas: HTMLCanvasElement | undefined;
|
||||
|
||||
export let imageData: ImageData | undefined = undefined;
|
||||
@@ -31,6 +28,11 @@
|
||||
if (!zoomPreviewCanvas) return;
|
||||
const context = zoomPreviewCanvas.getContext("2d");
|
||||
|
||||
if (!temporaryCanvas) {
|
||||
temporaryCanvas = document.createElement("canvas");
|
||||
temporaryCanvas.width = ZOOM_WINDOW_DIMENSIONS;
|
||||
temporaryCanvas.height = ZOOM_WINDOW_DIMENSIONS;
|
||||
}
|
||||
const temporaryContext = temporaryCanvas.getContext("2d");
|
||||
|
||||
if (!imageData || !context || !temporaryContext) return;
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
let reactiveEntries = entries;
|
||||
let highlighted: MenuListEntry | undefined = activeEntry;
|
||||
let virtualScrollingEntriesStart = 0;
|
||||
let keydownListenerAdded = false;
|
||||
let destroyed = false;
|
||||
|
||||
// `watchOpen` is called only when `open` is changed from outside this component
|
||||
$: watchOpen(open);
|
||||
@@ -67,11 +69,15 @@
|
||||
// TODO: The current approach is hacky and blocks the allowances for shortcuts like the key to open the browser's dev tools.
|
||||
onMount(async () => {
|
||||
await tick();
|
||||
if (open && !inNestedMenuList()) addEventListener("keydown", keydown);
|
||||
if (!destroyed && open && !inNestedMenuList() && !keydownListenerAdded) {
|
||||
addEventListener("keydown", keydown);
|
||||
keydownListenerAdded = true;
|
||||
}
|
||||
});
|
||||
onDestroy(async () => {
|
||||
await tick();
|
||||
if (!inNestedMenuList()) removeEventListener("keydown", keydown);
|
||||
onDestroy(() => {
|
||||
removeEventListener("keydown", keydown);
|
||||
// Set the destroyed status in the closure kept by the awaited `tick()` in `onMount` in case that delayed run occurs after the component is destroyed
|
||||
destroyed = true;
|
||||
});
|
||||
|
||||
function inNestedMenuList(): boolean {
|
||||
@@ -129,8 +135,13 @@
|
||||
}
|
||||
|
||||
function watchOpen(open: boolean) {
|
||||
if (open && !inNestedMenuList()) addEventListener("keydown", keydown);
|
||||
else if (!inNestedMenuList()) removeEventListener("keydown", keydown);
|
||||
if (open && !inNestedMenuList() && !keydownListenerAdded) {
|
||||
addEventListener("keydown", keydown);
|
||||
keydownListenerAdded = true;
|
||||
} else if (!open && !inNestedMenuList() && keydownListenerAdded) {
|
||||
removeEventListener("keydown", keydown);
|
||||
keydownListenerAdded = false;
|
||||
}
|
||||
|
||||
highlighted = activeEntry;
|
||||
dispatch("open", open);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { SvelteMap } from "svelte/reactivity";
|
||||
|
||||
import type { FrontendNodeType } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
||||
import type { NodeGraphStore } from "@graphite/stores/node-graph";
|
||||
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
import TextButton from "@graphite/components/widgets/buttons/TextButton.svelte";
|
||||
@@ -11,7 +11,7 @@
|
||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher<{ selectNodeType: string }>();
|
||||
const nodeGraph = getContext<NodeGraphState>("nodeGraph");
|
||||
const nodeGraph = getContext<NodeGraphStore>("nodeGraph");
|
||||
|
||||
// Content
|
||||
export let disabled = false;
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
import type { LabeledShortcut } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { TooltipState } from "@graphite/state-providers/tooltip";
|
||||
import type { TooltipStore } from "@graphite/stores/tooltip";
|
||||
|
||||
import FloatingMenu from "@graphite/components/layout/FloatingMenu.svelte";
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
import ShortcutLabel from "@graphite/components/widgets/labels/ShortcutLabel.svelte";
|
||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||
|
||||
const tooltip = getContext<TooltipState>("tooltip");
|
||||
const tooltip = getContext<TooltipStore>("tooltip");
|
||||
const editor = getContext<Editor>("editor");
|
||||
|
||||
let self: FloatingMenu | undefined;
|
||||
|
||||
Reference in New Issue
Block a user