@opengeni/react 7.4.0 → 7.5.0-canary.36927100590001
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -27
- package/dist/artifacts-document.js +3 -2
- package/dist/artifacts-presentation.js +3 -2
- package/dist/artifacts-spreadsheet.js +2 -2
- package/dist/artifacts.d.ts +1 -0
- package/dist/artifacts.js +516 -1413
- package/dist/artifacts.js.map +1 -1
- package/dist/{browser-viewer-2E6R2Y4W.js → browser-viewer-Z7S7QEJL.js} +6 -5
- package/dist/chat-interactive-block-UGBTNB3L.js +11 -0
- package/dist/{chunk-Y3QTZN2F.js → chunk-2VFNCX4E.js} +6 -6
- package/dist/{chunk-UDD6DLLT.js → chunk-3IJJEYW4.js} +15 -3
- package/dist/chunk-3IJJEYW4.js.map +1 -0
- package/dist/chunk-4RVYOY4O.js +379 -0
- package/dist/chunk-4RVYOY4O.js.map +1 -0
- package/dist/chunk-5CVXZA3Y.js +292 -0
- package/dist/chunk-5CVXZA3Y.js.map +1 -0
- package/dist/{chunk-5YK2ZDIG.js → chunk-5J4FOW6Q.js} +2 -10
- package/dist/chunk-5J4FOW6Q.js.map +1 -0
- package/dist/{chunk-KVERXCFY.js → chunk-5KYZIQFY.js} +40 -3
- package/dist/chunk-5KYZIQFY.js.map +1 -0
- package/dist/{chunk-KNDIXZN6.js → chunk-7UAMYXJY.js} +25 -18
- package/dist/{chunk-KNDIXZN6.js.map → chunk-7UAMYXJY.js.map} +1 -1
- package/dist/{chunk-SEEVCT36.js → chunk-A4UJB2MM.js} +2 -2
- package/dist/{chunk-X4HIN6TV.js → chunk-AFLPWUQ7.js} +71 -162
- package/dist/chunk-AFLPWUQ7.js.map +1 -0
- package/dist/chunk-B3V6TG77.js +41 -0
- package/dist/chunk-B3V6TG77.js.map +1 -0
- package/dist/{chunk-XEJEOAOV.js → chunk-B7WMS3CS.js} +51 -40
- package/dist/chunk-B7WMS3CS.js.map +1 -0
- package/dist/{chunk-S5JQ4R22.js → chunk-BDKR6BAR.js} +54 -24
- package/dist/chunk-BDKR6BAR.js.map +1 -0
- package/dist/{chunk-4MDLEHXL.js → chunk-DYWBUX5Q.js} +24 -12
- package/dist/chunk-DYWBUX5Q.js.map +1 -0
- package/dist/{chunk-YZ3YYMOM.js → chunk-E3G7SAYZ.js} +252 -624
- package/dist/chunk-E3G7SAYZ.js.map +1 -0
- package/dist/chunk-JT4JW7BC.js +54 -0
- package/dist/chunk-JT4JW7BC.js.map +1 -0
- package/dist/{chunk-5AZSK6MV.js → chunk-LWNLETQT.js} +5 -5
- package/dist/{chunk-USXVQACU.js → chunk-M7LBYP63.js} +5 -4
- package/dist/{chunk-USXVQACU.js.map → chunk-M7LBYP63.js.map} +1 -1
- package/dist/{chunk-L4OSXQ6H.js → chunk-NBOHNRLJ.js} +1289 -1060
- package/dist/chunk-NBOHNRLJ.js.map +1 -0
- package/dist/chunk-RHREZ7BO.js +11 -0
- package/dist/chunk-RHREZ7BO.js.map +1 -0
- package/dist/chunk-SCOTPE2I.js +589 -0
- package/dist/chunk-SCOTPE2I.js.map +1 -0
- package/dist/chunk-WEHMPOXK.js +39 -0
- package/dist/chunk-WEHMPOXK.js.map +1 -0
- package/dist/chunk-WRHIZYZF.js +988 -0
- package/dist/chunk-WRHIZYZF.js.map +1 -0
- package/dist/{chunk-3E2AITTZ.js → chunk-WUISZ3WU.js} +32 -28
- package/dist/{chunk-3E2AITTZ.js.map → chunk-WUISZ3WU.js.map} +1 -1
- package/dist/chunk-XCHWDJ22.js +107 -0
- package/dist/chunk-XCHWDJ22.js.map +1 -0
- package/dist/{chunk-DUEBTL3N.js → chunk-Y2PRMYLC.js} +4 -3
- package/dist/{chunk-DUEBTL3N.js.map → chunk-Y2PRMYLC.js.map} +1 -1
- package/dist/chunk-YBXQDQFX.js +1772 -0
- package/dist/chunk-YBXQDQFX.js.map +1 -0
- package/dist/chunk-YV4L3ILF.js +9 -0
- package/dist/chunk-YV4L3ILF.js.map +1 -0
- package/dist/{chunk-V2ABIVYJ.js → chunk-ZXSEDZP7.js} +70 -6
- package/dist/chunk-ZXSEDZP7.js.map +1 -0
- package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
- package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
- package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
- package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
- package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
- package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
- package/dist/components/artifacts/index.d.ts +7 -0
- package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
- package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
- package/dist/components/artifacts/site-view.d.ts +23 -0
- package/dist/components/browser-select-control.d.ts +3 -1
- package/dist/components/code-editor.d.ts +1 -4
- package/dist/components/desktop-viewer.d.ts +1 -1
- package/dist/components/message-timeline.d.ts +20 -3
- package/dist/components/open-geni-links.d.ts +16 -0
- package/dist/components/session-conversation.d.ts +20 -1
- package/dist/components/timeline-pill-geometry.d.ts +8 -0
- package/dist/components/timeline-pill-placement.d.ts +24 -0
- package/dist/components/usage-limit-notice.d.ts +49 -0
- package/dist/components/usage-member-list.d.ts +91 -0
- package/dist/components/usage-meter.d.ts +73 -0
- package/dist/composer.js +5 -5
- package/dist/{computer-viewer-WMJE6OA3.js → computer-viewer-KJWLH3GI.js} +7 -5
- package/dist/connect.js +7 -6
- package/dist/connect.js.map +1 -1
- package/dist/conversation-timeline.d.ts +1 -1
- package/dist/desktop.d.ts +7 -0
- package/dist/desktop.js +26 -0
- package/dist/desktop.js.map +1 -0
- package/dist/editor.d.ts +7 -0
- package/dist/editor.js +21 -0
- package/dist/editor.js.map +1 -0
- package/dist/hooks/latest-question.d.ts +1 -1
- package/dist/hooks/use-composer.d.ts +4 -0
- package/dist/hooks/use-desktop-stream.d.ts +1 -1
- package/dist/hooks/use-usage.d.ts +40 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +460 -1386
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +8 -6
- package/dist/interaction.js.map +1 -1
- package/dist/{latest-question-QB4EUCW5.js → latest-question-IS445HOW.js} +3 -3
- package/dist/lib/format.d.ts +6 -1
- package/dist/lib/workbench-peers.d.ts +36 -0
- package/dist/machines.js +2 -2
- package/dist/{markdown-table-layout-PFUEZ2U4.js → markdown-table-layout-QXSLK4BY.js} +37 -5
- package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
- package/dist/{queue-surface-implementation-IM2HD3SK.js → queue-surface-implementation-2CAQAIHM.js} +2 -2
- package/dist/realtime.js +3 -3
- package/dist/{sandbox-files-PXPIZAFG.js → sandbox-files-AEJTWGT4.js} +8 -5
- package/dist/sandbox-files-AEJTWGT4.js.map +1 -0
- package/dist/session-ui.d.ts +9 -2
- package/dist/session-ui.js +39 -20
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +4 -4
- package/dist/sites.js +4 -289
- package/dist/sites.js.map +1 -1
- package/dist/terminal.d.ts +8 -0
- package/dist/terminal.js +31 -0
- package/dist/terminal.js.map +1 -0
- package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
- package/dist/timeline/genie-loading.d.ts +3 -1
- package/dist/timeline/types.d.ts +8 -1
- package/dist/{timeline-annotation-selection-ODLVF4OI.js → timeline-annotation-selection-DMLMM2TX.js} +6 -1
- package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
- package/dist/timeline-pill-geometry-Z23V243M.js +110 -0
- package/dist/timeline-pill-geometry-Z23V243M.js.map +1 -0
- package/dist/usage/allowance-copy.d.ts +25 -0
- package/dist/usage/summary.d.ts +35 -0
- package/dist/usage.d.ts +13 -0
- package/dist/usage.js +1073 -0
- package/dist/usage.js.map +1 -0
- package/package.json +19 -3
- package/src/artifacts.ts +37 -0
- package/src/components/artifacts/artifact-chrome.tsx +413 -0
- package/src/components/artifacts/artifact-sandbox.tsx +185 -0
- package/src/components/artifacts/chat-interactive-block.tsx +260 -0
- package/src/components/artifacts/deferred-chat-media.tsx +67 -0
- package/src/components/artifacts/editable-artifact-ui.tsx +3 -1
- package/src/components/artifacts/editable-artifact-view.tsx +187 -0
- package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
- package/src/components/artifacts/editable-document.tsx +34 -36
- package/src/components/artifacts/editable-presentation.tsx +21 -16
- package/src/components/artifacts/index.ts +41 -0
- package/src/components/artifacts/latest-task-runner.ts +49 -0
- package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
- package/src/components/artifacts/site-view.tsx +116 -0
- package/src/components/browser-select-control.tsx +4 -1
- package/src/components/browser-viewer.tsx +81 -22
- package/src/components/code-editor.tsx +13 -16
- package/src/components/computer-viewer.tsx +51 -23
- package/src/components/desktop-viewer.tsx +1 -1
- package/src/components/markdown-table-layout.ts +49 -5
- package/src/components/markdown.tsx +5 -2
- package/src/components/message-timeline.tsx +557 -516
- package/src/components/open-geni-links.tsx +24 -0
- package/src/components/sandbox-terminal.tsx +48 -11
- package/src/components/session-chrome.tsx +22 -3
- package/src/components/session-conversation.tsx +195 -102
- package/src/components/timeline-annotation-selection.tsx +7 -0
- package/src/components/timeline-pill-geometry.ts +169 -0
- package/src/components/timeline-pill-placement.ts +99 -0
- package/src/components/usage-limit-notice.tsx +179 -0
- package/src/components/usage-member-list.tsx +792 -0
- package/src/components/usage-meter.tsx +382 -0
- package/src/conversation-timeline.ts +10 -2
- package/src/desktop.ts +24 -0
- package/src/editor.ts +13 -0
- package/src/hooks/use-available-models.ts +1 -1
- package/src/hooks/use-composer.ts +57 -2
- package/src/hooks/use-desktop-stream.ts +19 -28
- package/src/hooks/use-usage.ts +100 -0
- package/src/index.ts +22 -0
- package/src/lib/format.ts +32 -6
- package/src/lib/workbench-peers.ts +62 -0
- package/src/session-ui.ts +22 -0
- package/src/terminal.ts +26 -0
- package/src/timeline/activity-rail.tsx +5 -3
- package/src/timeline/allowance-exhausted-row.tsx +86 -0
- package/src/timeline/genie-loading.tsx +16 -6
- package/src/timeline/projection.ts +78 -4
- package/src/timeline/types.ts +8 -0
- package/src/usage/allowance-copy.ts +64 -0
- package/src/usage/summary.ts +93 -0
- package/src/usage.ts +50 -0
- package/styles/compiled.css +325 -0
- package/dist/chunk-4MDLEHXL.js.map +0 -1
- package/dist/chunk-5YK2ZDIG.js.map +0 -1
- package/dist/chunk-KVERXCFY.js.map +0 -1
- package/dist/chunk-L4OSXQ6H.js.map +0 -1
- package/dist/chunk-S5JQ4R22.js.map +0 -1
- package/dist/chunk-UDD6DLLT.js.map +0 -1
- package/dist/chunk-UGMKPUEM.js +0 -299
- package/dist/chunk-UGMKPUEM.js.map +0 -1
- package/dist/chunk-V2ABIVYJ.js.map +0 -1
- package/dist/chunk-X4HIN6TV.js.map +0 -1
- package/dist/chunk-XEJEOAOV.js.map +0 -1
- package/dist/chunk-YZ3YYMOM.js.map +0 -1
- package/dist/markdown-table-layout-PFUEZ2U4.js.map +0 -1
- package/dist/timeline-annotation-selection-ODLVF4OI.js.map +0 -1
- /package/dist/{browser-viewer-2E6R2Y4W.js.map → browser-viewer-Z7S7QEJL.js.map} +0 -0
- /package/dist/{computer-viewer-WMJE6OA3.js.map → chat-interactive-block-UGBTNB3L.js.map} +0 -0
- /package/dist/{chunk-Y3QTZN2F.js.map → chunk-2VFNCX4E.js.map} +0 -0
- /package/dist/{chunk-SEEVCT36.js.map → chunk-A4UJB2MM.js.map} +0 -0
- /package/dist/{chunk-5AZSK6MV.js.map → chunk-LWNLETQT.js.map} +0 -0
- /package/dist/{sandbox-files-PXPIZAFG.js.map → computer-viewer-KJWLH3GI.js.map} +0 -0
- /package/dist/{latest-question-QB4EUCW5.js.map → latest-question-IS445HOW.js.map} +0 -0
- /package/dist/{queue-surface-implementation-IM2HD3SK.js.map → queue-surface-implementation-2CAQAIHM.js.map} +0 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import {
|
|
2
|
+
codeEditorPeers
|
|
3
|
+
} from "./chunk-JT4JW7BC.js";
|
|
4
|
+
import {
|
|
5
|
+
cn
|
|
6
|
+
} from "./chunk-22KP6LR5.js";
|
|
7
|
+
|
|
8
|
+
// src/components/code-editor.tsx
|
|
9
|
+
import { Loader2Icon, SaveIcon } from "lucide-react";
|
|
10
|
+
import {
|
|
11
|
+
useCallback,
|
|
12
|
+
useEffect,
|
|
13
|
+
useMemo,
|
|
14
|
+
useRef,
|
|
15
|
+
useState,
|
|
16
|
+
useSyncExternalStore
|
|
17
|
+
} from "react";
|
|
18
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
function languageForPath(path) {
|
|
20
|
+
const name = path.split("/").pop() ?? path;
|
|
21
|
+
const ext = name.includes(".") ? (name.split(".").pop() ?? "").toLowerCase() : "";
|
|
22
|
+
switch (ext) {
|
|
23
|
+
case "js":
|
|
24
|
+
case "jsx":
|
|
25
|
+
case "ts":
|
|
26
|
+
case "tsx":
|
|
27
|
+
case "mjs":
|
|
28
|
+
case "cjs":
|
|
29
|
+
return "javascript";
|
|
30
|
+
case "json":
|
|
31
|
+
case "jsonc":
|
|
32
|
+
return "json";
|
|
33
|
+
case "py":
|
|
34
|
+
case "pyi":
|
|
35
|
+
return "python";
|
|
36
|
+
case "md":
|
|
37
|
+
case "markdown":
|
|
38
|
+
case "mdx":
|
|
39
|
+
return "markdown";
|
|
40
|
+
case "css":
|
|
41
|
+
case "scss":
|
|
42
|
+
case "less":
|
|
43
|
+
return "css";
|
|
44
|
+
case "html":
|
|
45
|
+
case "htm":
|
|
46
|
+
case "xml":
|
|
47
|
+
case "svg":
|
|
48
|
+
case "vue":
|
|
49
|
+
return "html";
|
|
50
|
+
default:
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function reconcileEditorBuffer(current, incoming) {
|
|
55
|
+
if (current.path === incoming.path && current.value !== current.baseline) {
|
|
56
|
+
return current;
|
|
57
|
+
}
|
|
58
|
+
if (current.path === incoming.path && current.value === incoming.contents && current.baseline === incoming.contents) {
|
|
59
|
+
return current;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
path: incoming.path,
|
|
63
|
+
value: incoming.contents,
|
|
64
|
+
baseline: incoming.contents
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function CodeEditor({
|
|
68
|
+
path,
|
|
69
|
+
initialContents,
|
|
70
|
+
onSave,
|
|
71
|
+
onOverwrite,
|
|
72
|
+
onReload,
|
|
73
|
+
onEditIntent,
|
|
74
|
+
readOnly = false,
|
|
75
|
+
themeType = "dark",
|
|
76
|
+
loading,
|
|
77
|
+
fallback,
|
|
78
|
+
className
|
|
79
|
+
}) {
|
|
80
|
+
const [failed, setFailed] = useState(false);
|
|
81
|
+
const [bundle, setBundle] = useState(null);
|
|
82
|
+
const peerRevision = useSyncExternalStore(
|
|
83
|
+
codeEditorPeers.subscribe,
|
|
84
|
+
codeEditorPeers.revision,
|
|
85
|
+
codeEditorPeers.revision
|
|
86
|
+
);
|
|
87
|
+
const [buffer, setBuffer] = useState(() => ({
|
|
88
|
+
path,
|
|
89
|
+
value: initialContents,
|
|
90
|
+
baseline: initialContents
|
|
91
|
+
}));
|
|
92
|
+
const { value, baseline } = buffer;
|
|
93
|
+
const [saving, setSaving] = useState(false);
|
|
94
|
+
const [saveError, setSaveError] = useState(null);
|
|
95
|
+
const [savedTick, setSavedTick] = useState(false);
|
|
96
|
+
const saveInFlightRef = useRef(false);
|
|
97
|
+
const dirty = value !== baseline;
|
|
98
|
+
const saveConflict = saveError !== null && saveError.code === "file_write_conflict";
|
|
99
|
+
const editIntentFiredRef = useRef(false);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
setBuffer((current) => reconcileEditorBuffer(current, { path, contents: initialContents }));
|
|
102
|
+
}, [path, initialContents]);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
editIntentFiredRef.current = false;
|
|
105
|
+
setSaveError(null);
|
|
106
|
+
setSavedTick(false);
|
|
107
|
+
}, [path]);
|
|
108
|
+
const noteEdit = useCallback(
|
|
109
|
+
(next) => {
|
|
110
|
+
setBuffer((current) => ({ ...current, value: next }));
|
|
111
|
+
setSavedTick(false);
|
|
112
|
+
if (!editIntentFiredRef.current && next !== baseline) {
|
|
113
|
+
editIntentFiredRef.current = true;
|
|
114
|
+
onEditIntent?.();
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
[baseline, onEditIntent]
|
|
118
|
+
);
|
|
119
|
+
const langKey = useMemo(() => languageForPath(path), [path]);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
let cancelled = false;
|
|
122
|
+
void (async () => {
|
|
123
|
+
try {
|
|
124
|
+
const peers = await codeEditorPeers.load();
|
|
125
|
+
const cmMod = peers.module;
|
|
126
|
+
let languageExtension = null;
|
|
127
|
+
if (langKey) {
|
|
128
|
+
try {
|
|
129
|
+
languageExtension = await peers.languages?.[langKey]?.() ?? null;
|
|
130
|
+
} catch {
|
|
131
|
+
languageExtension = null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (cancelled) return;
|
|
135
|
+
const saveKeymapExtension = (run) => cmMod.Prec.highest(
|
|
136
|
+
cmMod.keymap.of([
|
|
137
|
+
{
|
|
138
|
+
key: "Mod-s",
|
|
139
|
+
preventDefault: true,
|
|
140
|
+
run: () => {
|
|
141
|
+
run();
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
])
|
|
146
|
+
);
|
|
147
|
+
setBundle({
|
|
148
|
+
Editor: cmMod.default,
|
|
149
|
+
saveKeymapExtension,
|
|
150
|
+
languageExtension
|
|
151
|
+
});
|
|
152
|
+
setFailed(false);
|
|
153
|
+
} catch {
|
|
154
|
+
if (!cancelled) setFailed(true);
|
|
155
|
+
}
|
|
156
|
+
})();
|
|
157
|
+
return () => {
|
|
158
|
+
cancelled = true;
|
|
159
|
+
};
|
|
160
|
+
}, [langKey, peerRevision]);
|
|
161
|
+
const saveRef = useRef(() => {
|
|
162
|
+
});
|
|
163
|
+
const save = useCallback(async () => {
|
|
164
|
+
if (readOnly || saveInFlightRef.current) return;
|
|
165
|
+
const snapshot = value;
|
|
166
|
+
if (snapshot === baseline) return;
|
|
167
|
+
saveInFlightRef.current = true;
|
|
168
|
+
setSaving(true);
|
|
169
|
+
setSaveError(null);
|
|
170
|
+
setSavedTick(false);
|
|
171
|
+
try {
|
|
172
|
+
await onSave(snapshot, baseline);
|
|
173
|
+
setBuffer(
|
|
174
|
+
(current) => current.path === path ? { ...current, baseline: snapshot } : current
|
|
175
|
+
);
|
|
176
|
+
setSavedTick(true);
|
|
177
|
+
} catch (cause) {
|
|
178
|
+
setSaveError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
179
|
+
} finally {
|
|
180
|
+
saveInFlightRef.current = false;
|
|
181
|
+
setSaving(false);
|
|
182
|
+
}
|
|
183
|
+
}, [readOnly, value, baseline, onSave, path]);
|
|
184
|
+
const overwrite = useCallback(async () => {
|
|
185
|
+
if (readOnly || !onOverwrite || saveInFlightRef.current) return;
|
|
186
|
+
const snapshot = value;
|
|
187
|
+
if (snapshot === baseline) return;
|
|
188
|
+
saveInFlightRef.current = true;
|
|
189
|
+
setSaving(true);
|
|
190
|
+
setSaveError(null);
|
|
191
|
+
setSavedTick(false);
|
|
192
|
+
try {
|
|
193
|
+
await onOverwrite(snapshot);
|
|
194
|
+
setBuffer(
|
|
195
|
+
(current) => current.path === path ? { ...current, baseline: snapshot } : current
|
|
196
|
+
);
|
|
197
|
+
setSavedTick(true);
|
|
198
|
+
} catch (cause) {
|
|
199
|
+
setSaveError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
200
|
+
} finally {
|
|
201
|
+
saveInFlightRef.current = false;
|
|
202
|
+
setSaving(false);
|
|
203
|
+
}
|
|
204
|
+
}, [readOnly, onOverwrite, value, baseline, path]);
|
|
205
|
+
saveRef.current = () => {
|
|
206
|
+
void save();
|
|
207
|
+
};
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
if (!savedTick) return;
|
|
210
|
+
const t = setTimeout(() => setSavedTick(false), 1800);
|
|
211
|
+
return () => clearTimeout(t);
|
|
212
|
+
}, [savedTick]);
|
|
213
|
+
const fileName = path.split("/").filter(Boolean).pop() ?? path;
|
|
214
|
+
const cmExtensions = useMemo(() => {
|
|
215
|
+
if (!bundle) return [];
|
|
216
|
+
const exts = [bundle.saveKeymapExtension(() => saveRef.current())];
|
|
217
|
+
if (bundle.languageExtension) exts.push(bundle.languageExtension);
|
|
218
|
+
return exts;
|
|
219
|
+
}, [bundle]);
|
|
220
|
+
const Editor = bundle?.Editor;
|
|
221
|
+
const reload = useCallback(() => {
|
|
222
|
+
setBuffer({ path, value: initialContents, baseline: initialContents });
|
|
223
|
+
editIntentFiredRef.current = false;
|
|
224
|
+
setSaveError(null);
|
|
225
|
+
setSavedTick(false);
|
|
226
|
+
onReload?.();
|
|
227
|
+
}, [initialContents, onReload, path]);
|
|
228
|
+
return /* @__PURE__ */ jsxs(
|
|
229
|
+
"div",
|
|
230
|
+
{
|
|
231
|
+
className: cn("flex h-full min-h-0 flex-col", className),
|
|
232
|
+
"data-opengeni-code-editor": true,
|
|
233
|
+
"data-opengeni-editor-dirty": dirty ? "true" : "false",
|
|
234
|
+
style: editorVars,
|
|
235
|
+
children: [
|
|
236
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-9 shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
|
|
237
|
+
/* @__PURE__ */ jsx(
|
|
238
|
+
"span",
|
|
239
|
+
{
|
|
240
|
+
className: cn(
|
|
241
|
+
"size-1.5 shrink-0 rounded-full transition-colors",
|
|
242
|
+
readOnly ? "bg-transparent" : dirty ? "bg-og-status-running" : "bg-og-status-idle"
|
|
243
|
+
),
|
|
244
|
+
title: readOnly ? "read-only" : dirty ? "unsaved changes" : "saved"
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
/* @__PURE__ */ jsxs("span", { className: "truncate font-og-mono text-og-xs text-og-fg-muted", children: [
|
|
248
|
+
fileName,
|
|
249
|
+
dirty && !readOnly ? " \u2022" : ""
|
|
250
|
+
] }),
|
|
251
|
+
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
|
|
252
|
+
saveError && !saveConflict && /* @__PURE__ */ jsx(
|
|
253
|
+
"span",
|
|
254
|
+
{
|
|
255
|
+
className: "max-w-[220px] truncate text-og-xs text-og-status-failed",
|
|
256
|
+
title: saveError.message,
|
|
257
|
+
children: saveError.message
|
|
258
|
+
}
|
|
259
|
+
),
|
|
260
|
+
!saveError && savedTick && !dirty && /* @__PURE__ */ jsx("span", { className: "text-og-xs text-og-status-idle", children: "Saved" }),
|
|
261
|
+
readOnly ? /* @__PURE__ */ jsx("span", { className: "text-og-xs uppercase tracking-wide text-og-fg-subtle", children: "Read-only" }) : !saveConflict ? /* @__PURE__ */ jsxs(
|
|
262
|
+
"button",
|
|
263
|
+
{
|
|
264
|
+
type: "button",
|
|
265
|
+
onClick: () => void save(),
|
|
266
|
+
disabled: saving || !dirty,
|
|
267
|
+
className: cn(
|
|
268
|
+
"flex items-center gap-1 rounded-og-sm border border-og-border px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-11",
|
|
269
|
+
saving || !dirty ? "cursor-default text-og-fg-subtle opacity-60" : "text-og-fg hover:bg-og-accent-soft"
|
|
270
|
+
),
|
|
271
|
+
title: "Save (\u2318/Ctrl+S)",
|
|
272
|
+
children: [
|
|
273
|
+
saving ? /* @__PURE__ */ jsx(Loader2Icon, { className: "size-3 animate-spin" }) : /* @__PURE__ */ jsx(SaveIcon, { className: "size-3" }),
|
|
274
|
+
"Save"
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
) : null
|
|
278
|
+
] })
|
|
279
|
+
] }),
|
|
280
|
+
saveConflict ? /* @__PURE__ */ jsxs(
|
|
281
|
+
"div",
|
|
282
|
+
{
|
|
283
|
+
className: "flex shrink-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-og-status-failed/25 bg-og-status-failed/8 px-2 py-2",
|
|
284
|
+
role: "alert",
|
|
285
|
+
children: [
|
|
286
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-[12rem] flex-1 text-og-xs text-og-fg-muted", children: [
|
|
287
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-og-status-failed", children: "File changed on machine." }),
|
|
288
|
+
" ",
|
|
289
|
+
"Reloading discards your edits; overwriting replaces the live version."
|
|
290
|
+
] }),
|
|
291
|
+
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
|
|
292
|
+
onReload ? /* @__PURE__ */ jsx(
|
|
293
|
+
"button",
|
|
294
|
+
{
|
|
295
|
+
type: "button",
|
|
296
|
+
onClick: () => {
|
|
297
|
+
reload();
|
|
298
|
+
},
|
|
299
|
+
className: "min-h-8 rounded-og-sm border border-og-border bg-og-surface-1 px-2 text-og-xs font-medium text-og-fg hover:bg-og-surface-2 pointer-coarse:min-h-11",
|
|
300
|
+
children: "Reload live"
|
|
301
|
+
}
|
|
302
|
+
) : null,
|
|
303
|
+
onOverwrite ? /* @__PURE__ */ jsx(
|
|
304
|
+
"button",
|
|
305
|
+
{
|
|
306
|
+
type: "button",
|
|
307
|
+
onClick: () => void overwrite(),
|
|
308
|
+
disabled: saving,
|
|
309
|
+
className: "min-h-8 rounded-og-sm border border-og-status-failed/40 px-2 text-og-xs font-medium text-og-status-failed hover:bg-og-status-failed/10 disabled:opacity-50 pointer-coarse:min-h-11",
|
|
310
|
+
children: "Overwrite"
|
|
311
|
+
}
|
|
312
|
+
) : null
|
|
313
|
+
] })
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
) : null,
|
|
317
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: failed ? fallback ?? /* @__PURE__ */ jsx(
|
|
318
|
+
PlainTextarea,
|
|
319
|
+
{
|
|
320
|
+
value,
|
|
321
|
+
readOnly,
|
|
322
|
+
onChange: noteEdit,
|
|
323
|
+
onSave: () => void save()
|
|
324
|
+
}
|
|
325
|
+
) : Editor ? /* @__PURE__ */ jsx(
|
|
326
|
+
Editor,
|
|
327
|
+
{
|
|
328
|
+
value,
|
|
329
|
+
theme: themeType === "light" ? "light" : "dark",
|
|
330
|
+
editable: !readOnly,
|
|
331
|
+
readOnly,
|
|
332
|
+
basicSetup: true,
|
|
333
|
+
extensions: cmExtensions,
|
|
334
|
+
height: "100%",
|
|
335
|
+
className: "og-cm-editor min-h-full text-og-sm",
|
|
336
|
+
onChange: readOnly ? void 0 : noteEdit
|
|
337
|
+
}
|
|
338
|
+
) : loading ?? /* @__PURE__ */ jsx(EditorSkeleton, {}) })
|
|
339
|
+
]
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
var editorVars = {
|
|
344
|
+
"--og-cm-bg": "var(--og-color-bg)",
|
|
345
|
+
fontFamily: "var(--og-font-mono)"
|
|
346
|
+
};
|
|
347
|
+
function PlainTextarea({
|
|
348
|
+
value,
|
|
349
|
+
readOnly,
|
|
350
|
+
onChange,
|
|
351
|
+
onSave
|
|
352
|
+
}) {
|
|
353
|
+
return /* @__PURE__ */ jsx(
|
|
354
|
+
"textarea",
|
|
355
|
+
{
|
|
356
|
+
value,
|
|
357
|
+
readOnly,
|
|
358
|
+
spellCheck: false,
|
|
359
|
+
onChange: (e) => onChange(e.target.value),
|
|
360
|
+
onKeyDown: (event) => {
|
|
361
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "s") {
|
|
362
|
+
event.preventDefault();
|
|
363
|
+
onSave();
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
"aria-label": "Plain text file editor",
|
|
367
|
+
className: "h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-hidden"
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
function EditorSkeleton() {
|
|
372
|
+
return /* @__PURE__ */ jsx("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading editor\u2026" });
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export {
|
|
376
|
+
languageForPath,
|
|
377
|
+
CodeEditor
|
|
378
|
+
};
|
|
379
|
+
//# sourceMappingURL=chunk-4RVYOY4O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/code-editor.tsx"],"sourcesContent":["import { Loader2Icon, SaveIcon } from \"lucide-react\";\nimport {\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { codeEditorPeers, type CodeEditorLanguage } from \"../lib/workbench-peers\";\n\n// --- Lazy CodeMirror surface ----------------------------------------------\n//\n// CodeMirror 6 (via @uiw/react-codemirror) plus the per-language grammars are a\n// heavy bundle (lezer parsers, the view layer). We keep them OFF the critical\n// path and out of any SSR bundle by lazy-importing only when a file is actually\n// EDITED. The read-only viewer stays Pierre's Shiki `File`; this is the\n// editable complement, mounted on demand.\n\n/** The subset of `@uiw/react-codemirror`'s props we drive. */\ntype ReactCodeMirrorComponent = ComponentType<{\n value?: string;\n height?: string;\n theme?: \"light\" | \"dark\" | \"none\" | unknown;\n editable?: boolean;\n readOnly?: boolean;\n basicSetup?: boolean | Record<string, boolean>;\n extensions?: unknown[];\n onChange?: ((value: string) => void) | undefined;\n className?: string;\n style?: CSSProperties;\n}>;\n\n// Resolved lazily on first edit: the editor component + the keymap/Prec helpers\n// (both re-exported from @uiw/react-codemirror, which re-exports @codemirror/view\n// and @codemirror/state) + the chosen language extension.\ntype EditorBundle = {\n Editor: ReactCodeMirrorComponent;\n saveKeymapExtension: (onSave: () => void) => unknown;\n languageExtension: unknown | null;\n};\n\n/** Map a filename to a grammar key (or null for plain text — still fully editable). */\nexport function languageForPath(path: string): string | null {\n const name = path.split(\"/\").pop() ?? path;\n const ext = name.includes(\".\") ? (name.split(\".\").pop() ?? \"\").toLowerCase() : \"\";\n switch (ext) {\n case \"js\":\n case \"jsx\":\n case \"ts\":\n case \"tsx\":\n case \"mjs\":\n case \"cjs\":\n return \"javascript\";\n case \"json\":\n case \"jsonc\":\n return \"json\";\n case \"py\":\n case \"pyi\":\n return \"python\";\n case \"md\":\n case \"markdown\":\n case \"mdx\":\n return \"markdown\";\n case \"css\":\n case \"scss\":\n case \"less\":\n return \"css\";\n case \"html\":\n case \"htm\":\n case \"xml\":\n case \"svg\":\n case \"vue\":\n return \"html\";\n default:\n return null;\n }\n}\n\nexport type CodeEditorProps = {\n /** Workspace-relative path — drives language inference (and the save target upstream). */\n path: string;\n /** The decoded text contents to seed the editor with. */\n initialContents: string;\n /**\n * Persist the current buffer against the exact contents it was edited from.\n * The second argument is the immutable compare-and-swap baseline; hosts must\n * not replace it with a newer remote snapshot or concurrent writes can be\n * silently overwritten.\n */\n onSave: (contents: string, expectedContents: string) => Promise<unknown>;\n /** Explicitly overwrite after a visible expected-content conflict. */\n onOverwrite?: ((contents: string) => Promise<unknown>) | undefined;\n /** Re-read the selected file after a visible save conflict. */\n onReload?: (() => void) | undefined;\n /** Fired once when the buffer FIRST diverges from its baseline (the first real\n * keystroke) — the wake-on-edit intent. The host warms the box on this so the\n * eventual save lands fast; merely opening the file for reading never fires it. */\n onEditIntent?: (() => void) | undefined;\n /** Read-only mode (e.g. a truncated/too-large file shown for reference only). */\n readOnly?: boolean | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n /** Rendered while the (lazy) CodeMirror bundle loads. */\n loading?: ReactNode | undefined;\n /** Rendered if `@uiw/react-codemirror` is not installed / fails to import. */\n fallback?: ReactNode | undefined;\n className?: string | undefined;\n};\n\nexport type EditorBufferState = {\n path: string;\n value: string;\n baseline: string;\n};\n\n/**\n * Reconcile a remote file snapshot without destroying unsaved local work.\n *\n * A different path is a new document and always resets. For the same path, a\n * clean editor follows the remote snapshot while a dirty editor retains both\n * its local value and the original CAS baseline. The eventual save will then\n * either succeed against that baseline or surface a typed conflict.\n */\nexport function reconcileEditorBuffer(\n current: EditorBufferState,\n incoming: { path: string; contents: string },\n): EditorBufferState {\n if (current.path === incoming.path && current.value !== current.baseline) {\n return current;\n }\n if (\n current.path === incoming.path &&\n current.value === incoming.contents &&\n current.baseline === incoming.contents\n ) {\n return current;\n }\n return {\n path: incoming.path,\n value: incoming.contents,\n baseline: incoming.contents,\n };\n}\n\n/**\n * The EDITABLE single-file pane: CodeMirror 6 with a per-language grammar chosen\n * from the filename, og-* themed, with dirty tracking and a save path wired to\n * `Cmd/Ctrl+S` *and* an explicit Save button. The viewer (Pierre `File`) stays\n * the read-only complement — this is only mounted when the user opts to edit.\n *\n * Save semantics: the buffer is \"dirty\" the moment it diverges from the last\n * saved baseline; a successful `onSave` clears dirty and re-baselines. A failed\n * save keeps the buffer dirty (nothing is lost) and surfaces the error inline.\n * `readOnly` suppresses every mutation path so a truncated/binary file can never\n * be saved back (which would corrupt it by writing the truncated prefix).\n */\nexport function CodeEditor({\n path,\n initialContents,\n onSave,\n onOverwrite,\n onReload,\n onEditIntent,\n readOnly = false,\n themeType = \"dark\",\n loading,\n fallback,\n className,\n}: CodeEditorProps) {\n const [failed, setFailed] = useState(false);\n const [bundle, setBundle] = useState<EditorBundle | null>(null);\n const peerRevision = useSyncExternalStore(\n codeEditorPeers.subscribe,\n codeEditorPeers.revision,\n codeEditorPeers.revision,\n );\n\n // The live buffer and its compare-and-swap baseline are one state value so a\n // remote refresh cannot update one without the other.\n const [buffer, setBuffer] = useState<EditorBufferState>(() => ({\n path,\n value: initialContents,\n baseline: initialContents,\n }));\n const { value, baseline } = buffer;\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<Error | null>(null);\n const [savedTick, setSavedTick] = useState(false);\n const saveInFlightRef = useRef(false);\n\n const dirty = value !== baseline;\n const saveConflict =\n saveError !== null && (saveError as Error & { code?: unknown }).code === \"file_write_conflict\";\n\n // Follow path changes and clean same-file refreshes. Dirty same-file buffers\n // intentionally ignore remote snapshots: the original baseline must survive\n // until guarded save, explicit reload, or navigation.\n const editIntentFiredRef = useRef(false);\n useEffect(() => {\n setBuffer((current) => reconcileEditorBuffer(current, { path, contents: initialContents }));\n }, [path, initialContents]);\n\n // A new document is a new edit-intent/error lifecycle. The normal\n // SandboxFiles host also keys the component by path; this keeps standalone\n // consumers correct without relying on that implementation detail.\n useEffect(() => {\n editIntentFiredRef.current = false;\n setSaveError(null);\n setSavedTick(false);\n }, [path]);\n\n // Record a buffer change: the FIRST divergence from the baseline is the edit\n // intent that warms the box (idempotent — latched per opened file).\n const noteEdit = useCallback(\n (next: string) => {\n setBuffer((current) => ({ ...current, value: next }));\n setSavedTick(false);\n if (!editIntentFiredRef.current && next !== baseline) {\n editIntentFiredRef.current = true;\n onEditIntent?.();\n }\n },\n [baseline, onEditIntent],\n );\n\n // Resolve the lazy bundle (editor + keymap/Prec helpers + language grammar)\n // once, re-resolving the grammar when the file's language class changes.\n const langKey = useMemo(() => languageForPath(path) as CodeEditorLanguage | null, [path]);\n useEffect(() => {\n let cancelled = false;\n void (async () => {\n try {\n const peers = await codeEditorPeers.load();\n const cmMod = peers.module as {\n default: ReactCodeMirrorComponent;\n keymap: { of: (binds: unknown[]) => unknown };\n Prec: { highest: (ext: unknown) => unknown };\n };\n // Language peers are optional. A missing grammar must degrade to a plain\n // CodeMirror document, not throw the entire editor down to textarea.\n let languageExtension: unknown | null = null;\n if (langKey) {\n try {\n languageExtension = (await peers.languages?.[langKey]?.()) ?? null;\n } catch {\n languageExtension = null;\n }\n }\n if (cancelled) return;\n // A high-precedence Cmd/Ctrl-S keymap that calls back into the latest\n // save handler (kept fresh via a ref) and swallows the browser's\n // \"save page\" default.\n const saveKeymapExtension = (run: () => void) =>\n cmMod.Prec.highest(\n cmMod.keymap.of([\n {\n key: \"Mod-s\",\n preventDefault: true,\n run: () => {\n run();\n return true;\n },\n },\n ]),\n );\n setBundle({\n Editor: cmMod.default,\n saveKeymapExtension,\n languageExtension,\n });\n setFailed(false);\n } catch {\n if (!cancelled) setFailed(true);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [langKey, peerRevision]);\n\n // Keep the freshest save closure reachable from the (stable) keymap binding.\n const saveRef = useRef<() => void>(() => {});\n\n const save = useCallback(async () => {\n if (readOnly || saveInFlightRef.current) return;\n // Snapshot the buffer at call time so an in-flight edit can't race the write.\n const snapshot = value;\n if (snapshot === baseline) return; // nothing to persist\n saveInFlightRef.current = true;\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onSave(snapshot, baseline);\n setBuffer((current) =>\n current.path === path ? { ...current, baseline: snapshot } : current,\n );\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n saveInFlightRef.current = false;\n setSaving(false);\n }\n }, [readOnly, value, baseline, onSave, path]);\n\n const overwrite = useCallback(async () => {\n if (readOnly || !onOverwrite || saveInFlightRef.current) return;\n const snapshot = value;\n if (snapshot === baseline) return;\n saveInFlightRef.current = true;\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onOverwrite(snapshot);\n setBuffer((current) =>\n current.path === path ? { ...current, baseline: snapshot } : current,\n );\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n saveInFlightRef.current = false;\n setSaving(false);\n }\n }, [readOnly, onOverwrite, value, baseline, path]);\n\n saveRef.current = () => {\n void save();\n };\n\n // A brief \"Saved\" affordance after a successful write, cleared on the next edit.\n useEffect(() => {\n if (!savedTick) return;\n const t = setTimeout(() => setSavedTick(false), 1800);\n return () => clearTimeout(t);\n }, [savedTick]);\n\n const fileName = path.split(\"/\").filter(Boolean).pop() ?? path;\n\n const cmExtensions = useMemo(() => {\n if (!bundle) return [] as unknown[];\n const exts: unknown[] = [bundle.saveKeymapExtension(() => saveRef.current())];\n if (bundle.languageExtension) exts.push(bundle.languageExtension);\n return exts;\n }, [bundle]);\n\n const Editor = bundle?.Editor;\n\n const reload = useCallback(() => {\n setBuffer({ path, value: initialContents, baseline: initialContents });\n editIntentFiredRef.current = false;\n setSaveError(null);\n setSavedTick(false);\n onReload?.();\n }, [initialContents, onReload, path]);\n\n return (\n <div\n className={cn(\"flex h-full min-h-0 flex-col\", className)}\n data-opengeni-code-editor\n data-opengeni-editor-dirty={dirty ? \"true\" : \"false\"}\n style={editorVars}\n >\n {/* Save bar: dirty indicator + status + the explicit Save button. */}\n <div className=\"flex min-h-9 shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1\">\n <span\n className={cn(\n \"size-1.5 shrink-0 rounded-full transition-colors\",\n readOnly ? \"bg-transparent\" : dirty ? \"bg-og-status-running\" : \"bg-og-status-idle\",\n )}\n title={readOnly ? \"read-only\" : dirty ? \"unsaved changes\" : \"saved\"}\n />\n <span className=\"truncate font-og-mono text-og-xs text-og-fg-muted\">\n {fileName}\n {dirty && !readOnly ? \" •\" : \"\"}\n </span>\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {saveError && !saveConflict && (\n <span\n className=\"max-w-[220px] truncate text-og-xs text-og-status-failed\"\n title={saveError.message}\n >\n {saveError.message}\n </span>\n )}\n {!saveError && savedTick && !dirty && (\n <span className=\"text-og-xs text-og-status-idle\">Saved</span>\n )}\n {readOnly ? (\n <span className=\"text-og-xs uppercase tracking-wide text-og-fg-subtle\">Read-only</span>\n ) : !saveConflict ? (\n <button\n type=\"button\"\n onClick={() => void save()}\n disabled={saving || !dirty}\n className={cn(\n \"flex items-center gap-1 rounded-og-sm border border-og-border px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-11\",\n saving || !dirty\n ? \"cursor-default text-og-fg-subtle opacity-60\"\n : \"text-og-fg hover:bg-og-accent-soft\",\n )}\n title=\"Save (⌘/Ctrl+S)\"\n >\n {saving ? (\n <Loader2Icon className=\"size-3 animate-spin\" />\n ) : (\n <SaveIcon className=\"size-3\" />\n )}\n Save\n </button>\n ) : null}\n </div>\n </div>\n\n {saveConflict ? (\n <div\n className=\"flex shrink-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-og-status-failed/25 bg-og-status-failed/8 px-2 py-2\"\n role=\"alert\"\n >\n <div className=\"min-w-[12rem] flex-1 text-og-xs text-og-fg-muted\">\n <span className=\"font-medium text-og-status-failed\">File changed on machine.</span>{\" \"}\n Reloading discards your edits; overwriting replaces the live version.\n </div>\n <div className=\"ml-auto flex shrink-0 items-center gap-1.5\">\n {onReload ? (\n <button\n type=\"button\"\n onClick={() => {\n reload();\n }}\n className=\"min-h-8 rounded-og-sm border border-og-border bg-og-surface-1 px-2 text-og-xs font-medium text-og-fg hover:bg-og-surface-2 pointer-coarse:min-h-11\"\n >\n Reload live\n </button>\n ) : null}\n {onOverwrite ? (\n <button\n type=\"button\"\n onClick={() => void overwrite()}\n disabled={saving}\n className=\"min-h-8 rounded-og-sm border border-og-status-failed/40 px-2 text-og-xs font-medium text-og-status-failed hover:bg-og-status-failed/10 disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n Overwrite\n </button>\n ) : null}\n </div>\n </div>\n ) : null}\n\n {/* The editor surface. */}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {failed ? (\n (fallback ?? (\n <PlainTextarea\n value={value}\n readOnly={readOnly}\n onChange={noteEdit}\n onSave={() => void save()}\n />\n ))\n ) : Editor ? (\n <Editor\n value={value}\n theme={themeType === \"light\" ? \"light\" : \"dark\"}\n editable={!readOnly}\n readOnly={readOnly}\n basicSetup={true}\n extensions={cmExtensions}\n height=\"100%\"\n className=\"og-cm-editor min-h-full text-og-sm\"\n onChange={readOnly ? undefined : noteEdit}\n />\n ) : (\n (loading ?? <EditorSkeleton />)\n )}\n </div>\n </div>\n );\n}\n\n/** og-* themed CSS-var overrides handed to CodeMirror's container. */\nconst editorVars = {\n \"--og-cm-bg\": \"var(--og-color-bg)\",\n fontFamily: \"var(--og-font-mono)\",\n} as CSSProperties;\n\nfunction PlainTextarea({\n value,\n readOnly,\n onChange,\n onSave,\n}: {\n value: string;\n readOnly: boolean;\n onChange: (value: string) => void;\n onSave: () => void;\n}) {\n return (\n <textarea\n value={value}\n readOnly={readOnly}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"s\") {\n event.preventDefault();\n onSave();\n }\n }}\n aria-label=\"Plain text file editor\"\n className=\"h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-hidden\"\n />\n );\n}\n\nfunction EditorSkeleton() {\n return <div className=\"p-3 text-og-sm text-og-fg-subtle\">Loading editor…</div>;\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,aAAa,gBAAgB;AACtC;AAAA,EAIE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAwWC,cAOA,YAPA;AApUD,SAAS,gBAAgB,MAA6B;AAC3D,QAAM,OAAO,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AACtC,QAAM,MAAM,KAAK,SAAS,GAAG,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI,YAAY,IAAI;AAC/E,UAAQ,KAAK;AAAA,IACX,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AA8CO,SAAS,sBACd,SACA,UACmB;AACnB,MAAI,QAAQ,SAAS,SAAS,QAAQ,QAAQ,UAAU,QAAQ,UAAU;AACxE,WAAO;AAAA,EACT;AACA,MACE,QAAQ,SAAS,SAAS,QAC1B,QAAQ,UAAU,SAAS,YAC3B,QAAQ,aAAa,SAAS,UAC9B;AACA,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,UAAU,SAAS;AAAA,EACrB;AACF;AAcO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA8B,IAAI;AAC9D,QAAM,eAAe;AAAA,IACnB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB;AAIA,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA4B,OAAO;AAAA,IAC7D;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,EACZ,EAAE;AACF,QAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAuB,IAAI;AAC7D,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,kBAAkB,OAAO,KAAK;AAEpC,QAAM,QAAQ,UAAU;AACxB,QAAM,eACJ,cAAc,QAAS,UAAyC,SAAS;AAK3E,QAAM,qBAAqB,OAAO,KAAK;AACvC,YAAU,MAAM;AACd,cAAU,CAAC,YAAY,sBAAsB,SAAS,EAAE,MAAM,UAAU,gBAAgB,CAAC,CAAC;AAAA,EAC5F,GAAG,CAAC,MAAM,eAAe,CAAC;AAK1B,YAAU,MAAM;AACd,uBAAmB,UAAU;AAC7B,iBAAa,IAAI;AACjB,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAC,IAAI,CAAC;AAIT,QAAM,WAAW;AAAA,IACf,CAAC,SAAiB;AAChB,gBAAU,CAAC,aAAa,EAAE,GAAG,SAAS,OAAO,KAAK,EAAE;AACpD,mBAAa,KAAK;AAClB,UAAI,CAAC,mBAAmB,WAAW,SAAS,UAAU;AACpD,2BAAmB,UAAU;AAC7B,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,IACA,CAAC,UAAU,YAAY;AAAA,EACzB;AAIA,QAAM,UAAU,QAAQ,MAAM,gBAAgB,IAAI,GAAgC,CAAC,IAAI,CAAC;AACxF,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,QAAQ,MAAM,gBAAgB,KAAK;AACzC,cAAM,QAAQ,MAAM;AAOpB,YAAI,oBAAoC;AACxC,YAAI,SAAS;AACX,cAAI;AACF,gCAAqB,MAAM,MAAM,YAAY,OAAO,IAAI,KAAM;AAAA,UAChE,QAAQ;AACN,gCAAoB;AAAA,UACtB;AAAA,QACF;AACA,YAAI,UAAW;AAIf,cAAM,sBAAsB,CAAC,QAC3B,MAAM,KAAK;AAAA,UACT,MAAM,OAAO,GAAG;AAAA,YACd;AAAA,cACE,KAAK;AAAA,cACL,gBAAgB;AAAA,cAChB,KAAK,MAAM;AACT,oBAAI;AACJ,uBAAO;AAAA,cACT;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AACF,kBAAU;AAAA,UACR,QAAQ,MAAM;AAAA,UACd;AAAA,UACA;AAAA,QACF,CAAC;AACD,kBAAU,KAAK;AAAA,MACjB,QAAQ;AACN,YAAI,CAAC,UAAW,WAAU,IAAI;AAAA,MAChC;AAAA,IACF,GAAG;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,SAAS,YAAY,CAAC;AAG1B,QAAM,UAAU,OAAmB,MAAM;AAAA,EAAC,CAAC;AAE3C,QAAM,OAAO,YAAY,YAAY;AACnC,QAAI,YAAY,gBAAgB,QAAS;AAEzC,UAAM,WAAW;AACjB,QAAI,aAAa,SAAU;AAC3B,oBAAgB,UAAU;AAC1B,cAAU,IAAI;AACd,iBAAa,IAAI;AACjB,iBAAa,KAAK;AAClB,QAAI;AACF,YAAM,OAAO,UAAU,QAAQ;AAC/B;AAAA,QAAU,CAAC,YACT,QAAQ,SAAS,OAAO,EAAE,GAAG,SAAS,UAAU,SAAS,IAAI;AAAA,MAC/D;AACA,mBAAa,IAAI;AAAA,IACnB,SAAS,OAAO;AACd,mBAAa,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACxE,UAAE;AACA,sBAAgB,UAAU;AAC1B,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,UAAU,OAAO,UAAU,QAAQ,IAAI,CAAC;AAE5C,QAAM,YAAY,YAAY,YAAY;AACxC,QAAI,YAAY,CAAC,eAAe,gBAAgB,QAAS;AACzD,UAAM,WAAW;AACjB,QAAI,aAAa,SAAU;AAC3B,oBAAgB,UAAU;AAC1B,cAAU,IAAI;AACd,iBAAa,IAAI;AACjB,iBAAa,KAAK;AAClB,QAAI;AACF,YAAM,YAAY,QAAQ;AAC1B;AAAA,QAAU,CAAC,YACT,QAAQ,SAAS,OAAO,EAAE,GAAG,SAAS,UAAU,SAAS,IAAI;AAAA,MAC/D;AACA,mBAAa,IAAI;AAAA,IACnB,SAAS,OAAO;AACd,mBAAa,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACxE,UAAE;AACA,sBAAgB,UAAU;AAC1B,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,UAAU,aAAa,OAAO,UAAU,IAAI,CAAC;AAEjD,UAAQ,UAAU,MAAM;AACtB,SAAK,KAAK;AAAA,EACZ;AAGA,YAAU,MAAM;AACd,QAAI,CAAC,UAAW;AAChB,UAAM,IAAI,WAAW,MAAM,aAAa,KAAK,GAAG,IAAI;AACpD,WAAO,MAAM,aAAa,CAAC;AAAA,EAC7B,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAE1D,QAAM,eAAe,QAAQ,MAAM;AACjC,QAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,UAAM,OAAkB,CAAC,OAAO,oBAAoB,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAC5E,QAAI,OAAO,kBAAmB,MAAK,KAAK,OAAO,iBAAiB;AAChE,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,SAAS,QAAQ;AAEvB,QAAM,SAAS,YAAY,MAAM;AAC/B,cAAU,EAAE,MAAM,OAAO,iBAAiB,UAAU,gBAAgB,CAAC;AACrE,uBAAmB,UAAU;AAC7B,iBAAa,IAAI;AACjB,iBAAa,KAAK;AAClB,eAAW;AAAA,EACb,GAAG,CAAC,iBAAiB,UAAU,IAAI,CAAC;AAEpC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,gCAAgC,SAAS;AAAA,MACvD,6BAAyB;AAAA,MACzB,8BAA4B,QAAQ,SAAS;AAAA,MAC7C,OAAO;AAAA,MAGP;AAAA,6BAAC,SAAI,WAAU,gGACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,WAAW,mBAAmB,QAAQ,yBAAyB;AAAA,cACjE;AAAA,cACA,OAAO,WAAW,cAAc,QAAQ,oBAAoB;AAAA;AAAA,UAC9D;AAAA,UACA,qBAAC,UAAK,WAAU,qDACb;AAAA;AAAA,YACA,SAAS,CAAC,WAAW,YAAO;AAAA,aAC/B;AAAA,UACA,qBAAC,SAAI,WAAU,4CACZ;AAAA,yBAAa,CAAC,gBACb;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,UAAU;AAAA,gBAEhB,oBAAU;AAAA;AAAA,YACb;AAAA,YAED,CAAC,aAAa,aAAa,CAAC,SAC3B,oBAAC,UAAK,WAAU,kCAAiC,mBAAK;AAAA,YAEvD,WACC,oBAAC,UAAK,WAAU,wDAAuD,uBAAS,IAC9E,CAAC,eACH;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,KAAK,KAAK;AAAA,gBACzB,UAAU,UAAU,CAAC;AAAA,gBACrB,WAAW;AAAA,kBACT;AAAA,kBACA,UAAU,CAAC,QACP,gDACA;AAAA,gBACN;AAAA,gBACA,OAAM;AAAA,gBAEL;AAAA,2BACC,oBAAC,eAAY,WAAU,uBAAsB,IAE7C,oBAAC,YAAS,WAAU,UAAS;AAAA,kBAC7B;AAAA;AAAA;AAAA,YAEJ,IACE;AAAA,aACN;AAAA,WACF;AAAA,QAEC,eACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YAEL;AAAA,mCAAC,SAAI,WAAU,oDACb;AAAA,oCAAC,UAAK,WAAU,qCAAoC,sCAAwB;AAAA,gBAAQ;AAAA,gBAAI;AAAA,iBAE1F;AAAA,cACA,qBAAC,SAAI,WAAU,8CACZ;AAAA,2BACC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM;AACb,6BAAO;AAAA,oBACT;AAAA,oBACA,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED,IACE;AAAA,gBACH,cACC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM,KAAK,UAAU;AAAA,oBAC9B,UAAU;AAAA,oBACV,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED,IACE;AAAA,iBACN;AAAA;AAAA;AAAA,QACF,IACE;AAAA,QAGJ,oBAAC,SAAI,WAAU,gCACZ,mBACE,YACC;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,UAAU;AAAA,YACV,QAAQ,MAAM,KAAK,KAAK;AAAA;AAAA,QAC1B,IAEA,SACF;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,OAAO,cAAc,UAAU,UAAU;AAAA,YACzC,UAAU,CAAC;AAAA,YACX;AAAA,YACA,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,QAAO;AAAA,YACP,WAAU;AAAA,YACV,UAAU,WAAW,SAAY;AAAA;AAAA,QACnC,IAEC,WAAW,oBAAC,kBAAe,GAEhC;AAAA;AAAA;AAAA,EACF;AAEJ;AAGA,IAAM,aAAa;AAAA,EACjB,cAAc;AAAA,EACd,YAAY;AACd;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,MACxC,WAAW,CAAC,UAAU;AACpB,aAAK,MAAM,WAAW,MAAM,YAAY,MAAM,IAAI,YAAY,MAAM,KAAK;AACvE,gBAAM,eAAe;AACrB,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,cAAW;AAAA,MACX,WAAU;AAAA;AAAA,EACZ;AAEJ;AAEA,SAAS,iBAAiB;AACxB,SAAO,oBAAC,SAAI,WAAU,oCAAmC,kCAAe;AAC1E;","names":[]}
|