File size: 2,731 Bytes
2409829
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { writable } from "svelte/store";

import { type Editor } from "@graphite/editor";
import { defaultWidgetLayout, DisplayDialog, DisplayDialogDismiss, UpdateDialogButtons, UpdateDialogColumn1, UpdateDialogColumn2, patchWidgetLayout } from "@graphite/messages";
import { type IconName } from "@graphite/utility-functions/icons";

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function createDialogState(editor: Editor) {
	const { subscribe, update } = writable({
		visible: false,
		title: "",
		icon: "" as IconName,
		buttons: defaultWidgetLayout(),
		column1: defaultWidgetLayout(),
		column2: defaultWidgetLayout(),
		// Special case for the crash dialog because we cannot handle button widget callbacks from Rust once the editor has panicked
		panicDetails: "",
	});

	function dismissDialog() {
		update((state) => {
			// Disallow dismissing the crash dialog since it can confuse users why the app stopped responding if they dismiss it without realizing what it means
			if (state.panicDetails === "") state.visible = false;

			return state;
		});
	}

	// Creates a crash dialog from JS once the editor has panicked.
	// Normal dialogs are created in the Rust backend, but for the crash dialog, the editor has panicked so it cannot respond to widget callbacks.
	function createCrashDialog(panicDetails: string) {
		update((state) => {
			state.visible = true;

			state.icon = "Failure";
			state.title = "Crash";
			state.panicDetails = panicDetails;

			state.column1 = defaultWidgetLayout();
			state.column2 = defaultWidgetLayout();
			state.buttons = defaultWidgetLayout();

			return state;
		});
	}

	// Subscribe to process backend events
	editor.subscriptions.subscribeJsMessage(DisplayDialog, (displayDialog) => {
		update((state) => {
			state.visible = true;

			state.title = displayDialog.title;
			state.icon = displayDialog.icon;

			return state;
		});
	});
	editor.subscriptions.subscribeJsMessage(UpdateDialogButtons, (updateDialogButtons) => {
		update((state) => {
			patchWidgetLayout(state.buttons, updateDialogButtons);

			return state;
		});
	});
	editor.subscriptions.subscribeJsMessage(UpdateDialogColumn1, (updateDialogColumn1) => {
		update((state) => {
			patchWidgetLayout(state.column1, updateDialogColumn1);

			return state;
		});
	});
	editor.subscriptions.subscribeJsMessage(UpdateDialogColumn2, (updateDialogColumn2) => {
		update((state) => {
			patchWidgetLayout(state.column2, updateDialogColumn2);

			return state;
		});
	});
	editor.subscriptions.subscribeJsMessage(DisplayDialogDismiss, dismissDialog);

	return {
		subscribe,
		dismissDialog,
		createCrashDialog,
	};
}
export type DialogState = ReturnType<typeof createDialogState>;