-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathScriptEditorView.tsx
More file actions
110 lines (98 loc) · 2.89 KB
/
Copy pathScriptEditorView.tsx
File metadata and controls
110 lines (98 loc) · 2.89 KB
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { useEffect, useRef, useState } from "react";
import { assertExhausted } from "@userscript-proxy/core/assertions";
import type { ErrorInfo } from "@userscript-proxy/core/errors";
import type { NoRejectPromise } from "@userscript-proxy/core/promises";
import "./ScriptEditorView.css";
type ScriptEditorState =
| { tag: "Editing"; content: string; error: string | null }
| { tag: "Saving"; content: string };
type Props = {
filename: string;
initialContent: string;
onSave_NoReject: (content: string) => NoRejectPromise<null, ErrorInfo>;
onClose: () => void;
};
export function ScriptEditorView({
filename,
initialContent,
onSave_NoReject,
onClose,
}: Props) {
const [state, setState] = useState<ScriptEditorState>({
tag: "Editing",
content: initialContent,
error: null,
});
const textareaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
const textarea = textareaRef.current;
if (textarea !== null) {
textarea.focus();
textarea.setSelectionRange(textarea.value.length, textarea.value.length);
}
}, []);
const isSaving = state.tag === "Saving";
const content = state.content;
const error = state.tag === "Editing" ? state.error : null;
return (
<div className="modal-panel">
<div className="script-editor-header">
<p className="script-editor-filename">{filename}</p>
{error !== null && <p className="script-editor-error">{error}</p>}
<div className="script-editor-actions">
<button
disabled={isSaving}
onClick={() => {
save(content);
}}
>
Save
</button>
<button
className="button-secondary"
disabled={isSaving}
onClick={() => {
if (
content === initialContent ||
window.confirm("Are you sure?")
) {
onClose();
}
}}
>
Cancel
</button>
</div>
</div>
<textarea
ref={textareaRef}
className="script-editor-textarea"
disabled={isSaving}
value={content}
onChange={(e) => {
setState({ tag: "Editing", content: e.target.value, error: null });
}}
/>
</div>
);
function save(contentToSave: string) {
setState({ tag: "Saving", content: contentToSave });
void onSave_NoReject(contentToSave).then((result) => {
switch (result.tag) {
case "Ok":
// Parent handles navigation; nothing to do here.
break;
case "Err":
console.error(result.error.logError);
setState({
tag: "Editing",
content: contentToSave,
error: result.error.uiError,
});
break;
default:
assertExhausted(result, "script-editor save result");
}
});
}
}