Skip to content

Commit 7917f6f

Browse files
committed
fix: make document context reactive
1 parent 0d360bf commit 7917f6f

File tree

5 files changed

+48
-128
lines changed

5 files changed

+48
-128
lines changed

frontend/src/components/Editor.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import { createPanicManager } from "@graphite/io-managers/panic";
1111
import { createPersistenceManager } from "@graphite/io-managers/persistence";
1212
import { createDialogState } from "@graphite/state-providers/dialog";
13-
import { createDocumentState } from "@graphite/state-providers/document";
13+
import { createDocumentState } from "@graphite/state-providers/document.svelte";
1414
import { createFontsState } from "@graphite/state-providers/fonts";
1515
import { createFullscreenState } from "@graphite/state-providers/fullscreen";
1616
import { createNodeGraphState } from "@graphite/state-providers/node-graph";

frontend/src/components/panels/Document.svelte

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
UpdateMouseCursor,
1717
isWidgetSpanRow,
1818
} from "@graphite/messages.svelte";
19-
import type { DocumentState } from "@graphite/state-providers/document";
19+
import type { DocumentState } from "@graphite/state-providers/document.svelte";
2020
import { textInputCleanup } from "@graphite/utility-functions/keyboard-entry";
2121
import { extractPixelData, rasterizeSVGCanvas } from "@graphite/utility-functions/rasterization";
2222
import { updateBoundsOfViewports } from "@graphite/utility-functions/viewports";
@@ -124,7 +124,7 @@
124124
totalToolRowsFor2Columns,
125125
totalToolRowsFor3Columns,
126126
};
127-
})($document.toolShelfLayout.layout[0]));
127+
})(document.toolShelfLayout.layout[0]));
128128
129129
function dropFile(e: DragEvent) {
130130
const { dataTransfer } = e;
@@ -462,14 +462,14 @@
462462
</script>
463463

464464
<LayoutCol class="document" ondragover={(e) => e.preventDefault()} ondrop={dropFile}>
465-
<LayoutRow class="control-bar" classes={{ "for-graph": $document.graphViewOverlayOpen }} scrollableX={true}>
466-
{#if !$document.graphViewOverlayOpen}
467-
<WidgetLayout layout={$document.documentModeLayout} />
468-
<WidgetLayout layout={$document.toolOptionsLayout} />
465+
<LayoutRow class="control-bar" classes={{ "for-graph": document.graphViewOverlayOpen }} scrollableX={true}>
466+
{#if !document.graphViewOverlayOpen}
467+
<WidgetLayout layout={document.documentModeLayout} />
468+
<WidgetLayout layout={document.toolOptionsLayout} />
469469
<LayoutRow class="spacer" />
470-
<WidgetLayout layout={$document.documentBarLayout} />
470+
<WidgetLayout layout={document.documentBarLayout} />
471471
{:else}
472-
<WidgetLayout layout={$document.nodeGraphControlBarLayout} />
472+
<WidgetLayout layout={document.nodeGraphControlBarLayout} />
473473
{/if}
474474
</LayoutRow>
475475
<LayoutRow
@@ -482,15 +482,15 @@
482482
}}
483483
>
484484
<LayoutCol class="tool-shelf">
485-
{#if !$document.graphViewOverlayOpen}
485+
{#if !document.graphViewOverlayOpen}
486486
<LayoutCol class="tools" scrollableY={true}>
487-
<WidgetLayout layout={$document.toolShelfLayout} />
487+
<WidgetLayout layout={document.toolShelfLayout} />
488488
</LayoutCol>
489489
{:else}
490490
<LayoutRow class="spacer" />
491491
{/if}
492492
<LayoutCol class="tool-shelf-bottom-widgets">
493-
<WidgetLayout class={"working-colors-input-area"} layout={$document.workingColorsLayout} />
493+
<WidgetLayout class={"working-colors-input-area"} layout={document.workingColorsLayout} />
494494
</LayoutCol>
495495
</LayoutCol>
496496
<LayoutCol class="viewport-container">
@@ -536,7 +536,7 @@
536536
>
537537
</canvas>
538538
</div>
539-
<div class="graph-view" class:open={$document.graphViewOverlayOpen} style:--fade-artwork={`${$document.fadeArtwork}%`} data-graph>
539+
<div class="graph-view" class:open={document.graphViewOverlayOpen} style:--fade-artwork={`${document.fadeArtwork}%`} data-graph>
540540
<Graph />
541541
</div>
542542
</LayoutCol>

frontend/src/io-managers/input.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { get } from "svelte/store";
33
import { type Editor } from "@graphite/editor";
44
import { TriggerPaste } from "@graphite/messages.svelte";
55
import { type DialogState } from "@graphite/state-providers/dialog";
6-
import { type DocumentState } from "@graphite/state-providers/document";
6+
import { type DocumentState } from "@graphite/state-providers/document.svelte";
7+
import { documentContextState } from "@graphite/state-providers/document.svelte";
78
import { type FullscreenState } from "@graphite/state-providers/fullscreen";
89
import { type PortfolioState } from "@graphite/state-providers/portfolio";
910
import { makeKeyboardModifiersBitfield, textInputCleanup, getLocalizedScanCode } from "@graphite/utility-functions/keyboard-entry";
@@ -155,7 +156,7 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli
155156
// TODO: This would allow it to properly decide to act on removing hover focus from something that was hovered in the canvas before moving over the GUI.
156157
// TODO: Further explanation: https://github.com/GraphiteEditor/Graphite/pull/623#discussion_r866436197
157158
const inFloatingMenu = e.target instanceof Element && e.target.closest("[data-floating-menu-content]");
158-
const inGraphOverlay = get(document).graphViewOverlayOpen;
159+
const inGraphOverlay = documentContextState.graphViewOverlayOpen;
159160
if (!viewportPointerInteractionOngoing && (inFloatingMenu || inGraphOverlay)) return;
160161

161162
const modifiers = makeKeyboardModifiersBitfield(e);

frontend/src/messages.svelte.ts

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,62 +1531,6 @@ export function patchWidgetLayout(layout: /* &mut */ WidgetLayout, updates: Widg
15311531
});
15321532
}
15331533

1534-
// export function patchWidgetLayout(layout: /* &mut */ WidgetLayout, updates: WidgetDiffUpdate) {
1535-
// // Use Reflect.set to ensure proxy reactivity
1536-
// Reflect.set(layout, "layoutTarget", updates.layoutTarget);
1537-
1538-
// updates.diff.forEach((update) => {
1539-
// // Find the object where the diff applies to
1540-
// let diffObject = update.widgetPath.reduce((targetLayout, index) => {
1541-
// // Use Reflect.get to ensure we're going through the proxy
1542-
// if (Reflect.has(targetLayout, "columnWidgets")) {
1543-
// return Reflect.get(Reflect.get(targetLayout, "columnWidgets"), index);
1544-
// }
1545-
// if (Reflect.has(targetLayout, "rowWidgets")) {
1546-
// return Reflect.get(Reflect.get(targetLayout, "rowWidgets"), index);
1547-
// }
1548-
// if (Reflect.has(targetLayout, "tableWidgets")) {
1549-
// return Reflect.get(Reflect.get(targetLayout, "tableWidgets"), index);
1550-
// }
1551-
// if (Reflect.has(targetLayout, "layout")) {
1552-
// return Reflect.get(Reflect.get(targetLayout, "layout"), index);
1553-
// }
1554-
// if (targetLayout instanceof Widget) {
1555-
// if (targetLayout.props.kind === "PopoverButton" && targetLayout.props instanceof PopoverButton && targetLayout.props.popoverLayout) {
1556-
// return Reflect.get(targetLayout.props.popoverLayout, index);
1557-
// }
1558-
// console.error("Tried to index widget");
1559-
// return targetLayout;
1560-
// }
1561-
// if (Reflect.has(targetLayout, "action")) {
1562-
// const children = Reflect.get(targetLayout, "children");
1563-
// return children ? Reflect.get(children, index) : undefined;
1564-
// }
1565-
// return Reflect.get(targetLayout, index);
1566-
// }, layout.layout as UIItem);
1567-
1568-
// // Clear array length using Reflect to trigger reactivity
1569-
// if (Reflect.has(diffObject, "length")) {
1570-
// Reflect.set(diffObject, "length", 0);
1571-
// }
1572-
1573-
// // Remove all keys using Reflect.deleteProperty to ensure proxy notifications
1574-
// Reflect.ownKeys(diffObject).forEach((key) => {
1575-
// if (key !== "length") {
1576-
// // Don't delete length property on arrays
1577-
// Reflect.deleteProperty(diffObject, key);
1578-
// }
1579-
// });
1580-
1581-
// // Assign new properties using Reflect.set
1582-
// if (update.newValue && typeof update.newValue === "object") {
1583-
// Object.entries(update.newValue).forEach(([key, value]) => {
1584-
// Reflect.set(diffObject, key, value);
1585-
// });
1586-
// }
1587-
// });
1588-
// }
1589-
15901534
export type LayoutGroup = WidgetSpanRow | WidgetSpanColumn | WidgetTable | WidgetSection;
15911535

15921536
export type WidgetSpanColumn = { columnWidgets: Widget[] };
Lines changed: 32 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { tick } from "svelte";
2-
import { writable } from "svelte/store";
32

43
import { type Editor } from "@graphite/editor";
54

@@ -17,92 +16,68 @@ import {
1716
UpdateGraphFadeArtwork,
1817
} from "@graphite/messages.svelte";
1918

19+
export const documentContextState = $state({
20+
// Layouts - these are already $state objects from defaultWidgetLayout()
21+
documentModeLayout: defaultWidgetLayout(),
22+
toolOptionsLayout: defaultWidgetLayout(),
23+
documentBarLayout: defaultWidgetLayout(),
24+
toolShelfLayout: defaultWidgetLayout(),
25+
workingColorsLayout: defaultWidgetLayout(),
26+
nodeGraphControlBarLayout: defaultWidgetLayout(),
27+
// Graph view overlay
28+
graphViewOverlayOpen: false,
29+
fadeArtwork: 100,
30+
});
31+
2032
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
2133
export function createDocumentState(editor: Editor) {
22-
const state = writable({
23-
// Layouts
24-
documentModeLayout: defaultWidgetLayout(),
25-
toolOptionsLayout: defaultWidgetLayout(),
26-
documentBarLayout: defaultWidgetLayout(),
27-
toolShelfLayout: defaultWidgetLayout(),
28-
workingColorsLayout: defaultWidgetLayout(),
29-
nodeGraphControlBarLayout: defaultWidgetLayout(),
30-
// Graph view overlay
31-
graphViewOverlayOpen: false,
32-
fadeArtwork: 100,
33-
});
34-
const { subscribe, update } = state;
35-
36-
// Update layouts
34+
// Set up subscriptions (these run once when the function is called)
3735
editor.subscriptions.subscribeJsMessage(UpdateGraphFadeArtwork, (updateGraphFadeArtwork) => {
38-
update((state) => {
39-
state.fadeArtwork = updateGraphFadeArtwork.percentage;
40-
return state;
41-
});
36+
documentContextState.fadeArtwork = updateGraphFadeArtwork.percentage;
4237
});
38+
4339
editor.subscriptions.subscribeJsMessage(UpdateDocumentModeLayout, async (updateDocumentModeLayout) => {
4440
await tick();
45-
46-
update((state) => {
47-
patchWidgetLayout(state.documentModeLayout, updateDocumentModeLayout);
48-
return state;
49-
});
41+
patchWidgetLayout(documentContextState.documentModeLayout, updateDocumentModeLayout);
5042
});
43+
5144
editor.subscriptions.subscribeJsMessage(UpdateToolOptionsLayout, async (updateToolOptionsLayout) => {
5245
await tick();
53-
54-
update((state) => {
55-
patchWidgetLayout(state.toolOptionsLayout, updateToolOptionsLayout);
56-
return state;
57-
});
46+
patchWidgetLayout(documentContextState.toolOptionsLayout, updateToolOptionsLayout);
5847
});
48+
5949
editor.subscriptions.subscribeJsMessage(UpdateDocumentBarLayout, async (updateDocumentBarLayout) => {
6050
await tick();
61-
62-
update((state) => {
63-
patchWidgetLayout(state.documentBarLayout, updateDocumentBarLayout);
64-
return state;
65-
});
51+
patchWidgetLayout(documentContextState.documentBarLayout, updateDocumentBarLayout);
6652
});
53+
6754
editor.subscriptions.subscribeJsMessage(UpdateToolShelfLayout, async (updateToolShelfLayout) => {
6855
await tick();
69-
70-
update((state) => {
71-
patchWidgetLayout(state.toolShelfLayout, updateToolShelfLayout);
72-
return state;
73-
});
56+
patchWidgetLayout(documentContextState.toolShelfLayout, updateToolShelfLayout);
7457
});
58+
7559
editor.subscriptions.subscribeJsMessage(UpdateWorkingColorsLayout, async (updateWorkingColorsLayout) => {
7660
await tick();
77-
78-
update((state) => {
79-
patchWidgetLayout(state.workingColorsLayout, updateWorkingColorsLayout);
80-
return state;
81-
});
61+
patchWidgetLayout(documentContextState.workingColorsLayout, updateWorkingColorsLayout);
8262
});
63+
8364
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphControlBarLayout, (updateNodeGraphControlBarLayout) => {
84-
update((state) => {
85-
patchWidgetLayout(state.nodeGraphControlBarLayout, updateNodeGraphControlBarLayout);
86-
return state;
87-
});
65+
patchWidgetLayout(documentContextState.nodeGraphControlBarLayout, updateNodeGraphControlBarLayout);
8866
});
8967

90-
// Show or hide the graph view overlay
9168
editor.subscriptions.subscribeJsMessage(UpdateGraphViewOverlay, (updateGraphViewOverlay) => {
92-
update((state) => {
93-
state.graphViewOverlayOpen = updateGraphViewOverlay.open;
94-
return state;
95-
});
69+
documentContextState.graphViewOverlayOpen = updateGraphViewOverlay.open;
9670
});
71+
9772
editor.subscriptions.subscribeJsMessage(TriggerDelayedZoomCanvasToFitAll, () => {
9873
// TODO: This is horribly hacky
9974
[0, 1, 10, 50, 100, 200, 300, 400, 500].forEach((delay) => {
10075
setTimeout(() => editor.handle.zoomCanvasToFitAll(), delay);
10176
});
10277
});
10378

104-
return {
105-
subscribe,
106-
};
79+
// Return the reactive state object directly
80+
return documentContextState;
10781
}
82+
10883
export type DocumentState = ReturnType<typeof createDocumentState>;

0 commit comments

Comments
 (0)