Break out helper functions from the frontend's managers and stores (#3920)

* Move destructor call to each manager/store constructor for safety

* Break out utility functions
This commit is contained in:
Keavon Chambers
2026-03-20 14:22:46 -07:00
committed by GitHub
parent 0c7b5cd534
commit 64fd12a1a0
19 changed files with 846 additions and 826 deletions
+2
View File
@@ -29,6 +29,8 @@ if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createAppWindowStore(editor: Editor) {
destroyAppWindowStore();
editorRef = editor;
editor.subscriptions.subscribeFrontendMessage("UpdatePlatform", (data) => {
+5
View File
@@ -37,6 +37,8 @@ if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createDialogStore(editor: Editor) {
destroyDialogStore();
editorRef = editor;
editor.subscriptions.subscribeFrontendMessage("DisplayDialog", (data) => {
@@ -49,6 +51,7 @@ export function createDialogStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("DialogButtons", async (data) => {
await tick();
@@ -58,6 +61,7 @@ export function createDialogStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("DialogColumn1", async (data) => {
await tick();
@@ -67,6 +71,7 @@ export function createDialogStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("DialogColumn2", async (data) => {
await tick();
+7 -2
View File
@@ -35,15 +35,17 @@ if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createDocumentStore(editor: Editor) {
destroyDocumentStore();
editorRef = editor;
// Update layouts
editor.subscriptions.subscribeFrontendMessage("UpdateGraphFadeArtwork", (data) => {
update((state) => {
state.fadeArtwork = data.percentage;
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("ToolOptions", async (data) => {
await tick();
@@ -52,6 +54,7 @@ export function createDocumentStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("DocumentBar", async (data) => {
await tick();
@@ -60,6 +63,7 @@ export function createDocumentStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("ToolShelf", async (data) => {
await tick();
@@ -68,6 +72,7 @@ export function createDocumentStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("WorkingColors", async (data) => {
await tick();
@@ -76,6 +81,7 @@ export function createDocumentStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeLayoutUpdate("NodeGraphControlBar", async (data) => {
await tick();
@@ -85,7 +91,6 @@ export function createDocumentStore(editor: Editor) {
});
});
// Show or hide the graph view overlay
editor.subscriptions.subscribeFrontendMessage("UpdateGraphViewOverlay", (data) => {
update((state) => {
state.graphViewOverlayOpen = data.open;
+2
View File
@@ -22,6 +22,8 @@ if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createFullscreenStore(editor: Editor) {
destroyFullscreenStore();
editorRef = editor;
editor.subscriptions.subscribeFrontendMessage("WindowFullscreen", () => {
+2 -1
View File
@@ -61,9 +61,10 @@ if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createNodeGraphStore(editor: Editor) {
destroyNodeGraphStore();
editorRef = editor;
// Set up message subscriptions on creation
editor.subscriptions.subscribeFrontendMessage("SendUIMetadata", (data) => {
update((state) => {
state.nodeDescriptions = new Map(data.nodeDescriptions);
+2
View File
@@ -33,6 +33,8 @@ if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createPortfolioStore(editor: Editor) {
destroyPortfolioStore();
editorRef = editor;
editor.subscriptions.subscribeFrontendMessage("UpdateOpenDocumentsList", (data) => {
+19 -16
View File
@@ -9,8 +9,6 @@ export type TooltipStore = ReturnType<typeof createTooltipStore>;
const SHOW_TOOLTIP_DELAY_MS = 500;
let tooltipTimeout: ReturnType<typeof setTimeout> | undefined = undefined;
type TooltipStoreState = {
visible: boolean;
element: Element | undefined;
@@ -28,7 +26,18 @@ const initialState: TooltipStoreState = {
fullscreenShortcut: undefined,
};
type Listener = { eventName: keyof DocumentEventMap; action(event: Event): void };
const tooltipEventListeners: Listener[] = [
{ eventName: "mouseover", action: onMouseOver },
{ eventName: "mousemove", action: onMouseMove },
{ eventName: "mouseleave", action: onMouseLeave },
{ eventName: "mousedown", action: closeTooltip },
{ eventName: "keydown", action: closeTooltip },
{ eventName: "wheel", action: closeTooltip },
];
let editorRef: Editor | undefined = undefined;
let tooltipTimeout: ReturnType<typeof setTimeout> | undefined = undefined;
// Store state persisted across HMR to maintain reactive subscriptions in the component tree
const store: Writable<TooltipStoreState> = import.meta.hot?.data?.store || writable<TooltipStoreState>(initialState);
@@ -36,14 +45,9 @@ if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
export function createTooltipStore(editor: Editor) {
editorRef = editor;
destroyTooltipStore();
document.addEventListener("mouseover", onMouseOver);
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseleave", onMouseLeave);
document.addEventListener("mousedown", closeTooltip);
document.addEventListener("keydown", closeTooltip);
document.addEventListener("wheel", closeTooltip);
editorRef = editor;
editor.subscriptions.subscribeFrontendMessage("SendShortcutShiftClick", async (data) => {
update((state) => {
@@ -51,12 +55,14 @@ export function createTooltipStore(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeFrontendMessage("SendShortcutAltClick", async (data) => {
update((state) => {
state.altClickShortcut = data.shortcut;
return state;
});
});
editor.subscriptions.subscribeFrontendMessage("SendShortcutFullscreen", async (data) => {
update((state) => {
state.fullscreenShortcut = operatingSystem() === "Mac" ? data.shortcutMac : data.shortcut;
@@ -64,6 +70,8 @@ export function createTooltipStore(editor: Editor) {
});
});
tooltipEventListeners.forEach(({ eventName, action }) => document.addEventListener(eventName, action));
return { subscribe };
}
@@ -73,16 +81,11 @@ export function destroyTooltipStore() {
if (tooltipTimeout) clearTimeout(tooltipTimeout);
document.removeEventListener("mouseover", onMouseOver);
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseleave", onMouseLeave);
document.removeEventListener("mousedown", closeTooltip);
document.removeEventListener("keydown", closeTooltip);
document.removeEventListener("wheel", closeTooltip);
editor.subscriptions.unsubscribeFrontendMessage("SendShortcutShiftClick");
editor.subscriptions.unsubscribeFrontendMessage("SendShortcutAltClick");
editor.subscriptions.unsubscribeFrontendMessage("SendShortcutFullscreen");
tooltipEventListeners.forEach(({ eventName, action }) => document.removeEventListener(eventName, action));
}
// Listen for mouse movements onto tooltip-bearing HTML elements to track the future target of a tooltip