@alauda/react-code-editor 0.1.0-next.20260903.1788425608 → 0.1.0-next.20261021.1792553055

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.
@@ -0,0 +1,892 @@
1
+ import Editor, { DiffEditor, loader } from "@monaco-editor/react";
2
+ import Alert from "@mui/material/Alert";
3
+ import Box from "@mui/material/Box";
4
+ import CircularProgress from "@mui/material/CircularProgress";
5
+ import IconButton from "@mui/material/IconButton";
6
+ import Menu from "@mui/material/Menu";
7
+ import MenuItem from "@mui/material/MenuItem";
8
+ import Tooltip from "@mui/material/Tooltip";
9
+ import FormatAlignLeftRoundedIcon from "@mui/icons-material/FormatAlignLeftRounded";
10
+ import RedoRoundedIcon from "@mui/icons-material/RedoRounded";
11
+ import UndoRoundedIcon from "@mui/icons-material/UndoRounded";
12
+ import { SvgIcon } from "@mui/material";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ import { useTheme } from "@mui/material/styles";
15
+ import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useRef, useState, useSyncExternalStore } from "react";
16
+ //#region src/icons/CodeEditorIcon.tsx
17
+ /**
18
+ * Minimal AUI icon subset used by the Angular-compatible Code Editor toolbar.
19
+ *
20
+ * AUI paths are extracted from @alauda/ui@10.0.1 (MIT), source commit
21
+ * 7453f1274bb2f4e7f9ca34481ba788b1ec84d8c7. The rollback path is extracted
22
+ * from Angular Console's prod-icons.js at pinned source commit
23
+ * 46ec7ae9f48d95db84d7d1207c2d8199ff18a7cb.
24
+ * This module intentionally has no Angular runtime dependency.
25
+ */
26
+ const codeEditorIconPaths = {
27
+ file_import: {
28
+ source: "aui:file_import",
29
+ paths: ["M723.2 64h1.92a76.8 76.8 0 0 1 74.88 74.88V307.2h-76.8V140.8H384V384H140.8v499.2h582.4v-64h76.8v65.92A76.8 76.8 0 0 1 725.12 960H138.88a76.8 76.8 0 0 1-73.472-62.08L65.088 896H64V307.2L307.2 64h416zM640 384l54.336 54.336L607.808 524.8H960v76.8H607.808l86.528 86.528L640 742.4 460.8 563.2 640 384zM313.6 172.608L172.608 313.6H313.6V172.608z"]
30
+ },
31
+ file_export: {
32
+ source: "aui:file_export",
33
+ paths: ["M723.2 64h1.92a76.8 76.8 0 0 1 74.88 74.88V307.2h-76.8V140.8H384V384H140.8v499.2h582.4v-64h76.8v65.92A76.8 76.8 0 0 1 725.12 960H138.88a76.8 76.8 0 0 1-73.472-62.08L65.088 896H64V307.2L307.2 64h416z m57.6 320L960 563.2l-179.2 179.2-54.336-54.272L812.992 601.6H460.8V524.8h352.192L726.4 438.4 780.8 384zM313.6 172.608L172.608 313.6H313.6V172.608z"]
34
+ },
35
+ xmark_circle: {
36
+ source: "aui:xmark_circle",
37
+ paths: ["M512 0a512 512 0 1 1 0 1024A512 512 0 0 1 512 0z m0 71.424a440.576 440.576 0 1 0 0 881.152A440.576 440.576 0 0 0 512 71.424z m134.72 238.528l67.328 67.328L579.328 512l134.72 134.72-67.328 67.328L512 579.328l-134.72 134.72-67.328-67.328L444.672 512 309.952 377.28l67.328-67.328L512 444.672l134.72-134.72z"]
38
+ },
39
+ magnifier: {
40
+ source: "aui:magnifier",
41
+ paths: ["M499.2 70.4a428.8 428.8 0 0 1 335.296 696.128L1011.2 943.36 943.36 1011.2l-176.832-176.704A428.8 428.8 0 1 1 499.2 70.4z m0 96a332.8 332.8 0 1 0 0 665.6 332.8 332.8 0 0 0 0-665.6z"]
42
+ },
43
+ copy: {
44
+ source: "aui:copy",
45
+ paths: ["M524.8 192L768 435.2v512a76.8 76.8 0 0 1-74.88 76.8H140.8A76.8 76.8 0 0 1 64 947.2V266.88A76.8 76.8 0 0 1 138.88 192H524.8zM448 435.2V268.8H140.8v678.4h550.4V512H524.8A76.8 76.8 0 0 1 448 435.2zM716.8 0L960 243.2v513.92A76.8 76.8 0 0 1 885.12 832h-40.32v-76.8h38.4V275.008L684.992 76.8H332.8v38.4H256v-40.32A76.8 76.8 0 0 1 330.88 0h385.92z m-192 300.608V435.2h134.592L524.8 300.608z"]
46
+ },
47
+ computer: {
48
+ source: "aui:computer",
49
+ paths: ["M883.2 102.4A76.8 76.8 0 0 1 960 179.2v486.4a76.8 76.8 0 0 1-76.8 76.8H550.4v102.4H473.6v-102.4H140.8A76.8 76.8 0 0 1 64 665.6V179.2a76.8 76.8 0 0 1 76.8-76.8h742.4z m0 76.8H140.8v486.4h742.4V179.2zM256 844.8h512v76.8H256v-76.8z"]
50
+ },
51
+ sun: {
52
+ source: "aui:sun",
53
+ paths: ["M556.8 870.4V1024H467.2v-153.6h89.6z m-329.92-136.64l63.36 63.36-108.608 108.608-63.36-63.36 108.608-108.608z m570.24 0l108.608 108.608-63.36 63.36-108.608-108.608 63.36-63.36zM512 230.4a281.6 281.6 0 1 1 0 563.2 281.6 281.6 0 0 1 0-563.2z m0 96a185.6 185.6 0 1 0 0 371.2 185.6 185.6 0 0 0 0-371.2z m512 140.8v89.6h-153.6V467.2H1024z m-870.4 0v89.6H0V467.2h153.6z m688.768-348.928l63.36 63.36-108.608 108.608-63.36-63.36 108.608-108.608z m-660.736 0l108.608 108.608-63.36 63.36-108.608-108.608 63.36-63.36zM556.8 0v153.6H467.2V0h89.6z"]
54
+ },
55
+ moon: {
56
+ source: "aui:moon",
57
+ paths: ["M470.4 64a60.16 60.16 0 0 1 25.216 5.76c8.448 3.904 14.72 9.344 18.944 16.384 4.928 9.152 6.528 17.92 4.736 26.432a74.24 74.24 0 0 1-8.96 23.168 268.096 268.096 0 0 0-46.336 98.176 272.64 272.64 0 0 0 31.616 200.512c18.24 30.272 42.496 56.64 72.64 79.168a262.528 262.528 0 0 0 160.064 54.848c28.096 0 55.808-4.544 83.2-13.696a248.768 248.768 0 0 0 75.84-41.152 38.592 38.592 0 0 1 25.28-10.048 41.152 41.152 0 0 1 22.784 4.928l1.408 0.896c7.04 4.224 12.608 10.368 16.832 18.432 4.224 8.128 6.336 15.36 6.336 21.632a508.224 508.224 0 0 1-17.92 88.704c-8.384 28.8-19.456 56.064-33.152 81.792a496.128 496.128 0 0 1-47.936 73.344 448.256 448.256 0 0 1-63.168 63.296 451.2 451.2 0 0 1-281.92 103.36L510.336 960H470.4a427.136 427.136 0 0 1-170.56-51.712 458.048 458.048 0 0 1-132.672-109.76 454.592 454.592 0 0 1-82.176-152 438.784 438.784 0 0 1-19.392-171.648l0.448-5.632a427.008 427.008 0 0 1 40-151.936 442.24 442.24 0 0 1 87.424-125.632A441.152 441.152 0 0 1 318.72 104.128 424.576 424.576 0 0 1 470.4 64zM389.504 171.648l-1.92 0.64a330.176 330.176 0 0 0-30.72 12.8 351.616 351.616 0 0 0-100.096 69.888A353.536 353.536 0 0 0 186.88 355.84a336.256 336.256 0 0 0-31.168 115.392l-0.512 6.144c-4.48 49.984 0.512 96.896 15.04 141.824a365.12 365.12 0 0 0 65.984 122.368 368.512 368.512 0 0 0 107.008 88.384 336.384 336.384 0 0 0 130.304 40.32l1.216 0.128h35.584c40 0 78.912-6.464 117.184-19.456l4.992-1.728a353.28 353.28 0 0 0 108.288-61.76c17.856-14.72 33.6-30.208 47.232-46.528l2.944-3.584 3.328-4.288c12.16-16 23.104-32.64 32.704-50.048l2.88-5.248c6.592-12.416 12.48-25.408 17.6-39.04l0.704-1.92-3.648 1.28-4.608 1.664a350.528 350.528 0 0 1-321.984-51.84l-7.296-5.568a366.08 366.08 0 0 1-89.216-97.472l-2.56-4.16-0.448-0.768a362.24 362.24 0 0 1-42.88-260.544l1.024-5.12 0.32-1.28c3.072-12.928 6.912-25.664 11.456-38.144l1.216-3.2z"]
58
+ },
59
+ expand: {
60
+ source: "aui:expand",
61
+ paths: ["M960 640v243.2a76.8 76.8 0 0 1-74.88 76.8H640v-76.8h243.2V640H960zM387.264 576l54.336 54.336-250.624 250.624h195.264v76.8h-320v-320h76.8v182.464L387.264 576zM960 64v320h-76.8V201.472L638.976 445.76l-54.336-54.336L835.264 140.8H640V64h320zM384 64v76.8H140.8V384H64V140.8A76.8 76.8 0 0 1 138.88 64H384z"]
62
+ },
63
+ compress: {
64
+ source: "aui:compress",
65
+ paths: ["M960 640v243.2a76.8 76.8 0 0 1-74.88 76.8H640v-76.8h243.2V640H960zM460.8 563.2v320H384v-179.84l-243.2 243.2-63.36-63.36 243.2-243.2H140.8V563.2h320z m422.4-485.76l63.36 63.36-243.2 243.2h179.84v76.8h-320v-320H640v179.84l243.2-243.2zM384 64v76.8H140.8V384H64V140.8A76.8 76.8 0 0 1 138.88 64H384z"]
66
+ },
67
+ rollback: {
68
+ source: "prod:rollback",
69
+ paths: ["M505.728 25.6C777.728 25.6 998.4 243.2 998.4 512c0 268.8-220.672 486.4-492.672 486.4-192.256 0-364.416-109.76-445.312-278.08l-2.432-5.12 69.568-32.448C194.88 827.072 341.504 921.6 505.728 921.6c229.76 0 415.872-183.488 415.872-409.6 0-226.112-186.048-409.6-415.872-409.6a417.6 417.6 0 0 0-354.816 195.712L268.8 416H0V147.2l95.36 95.36A494.656 494.656 0 0 1 505.728 25.6zM588.8 268.8v332.8h-192V524.8H512v-256h76.8z"]
70
+ }
71
+ };
72
+ function CodeEditorIcon({ name, ...props }) {
73
+ const icon = codeEditorIconPaths[name];
74
+ return /* @__PURE__ */ jsx(SvgIcon, {
75
+ ...props,
76
+ sx: {
77
+ width: 14,
78
+ height: 14,
79
+ ...props.sx
80
+ },
81
+ viewBox: "0 0 1024 1024",
82
+ "data-aui-icon": icon.source,
83
+ children: icon.paths.map((path) => /* @__PURE__ */ jsx("path", { d: path }, path))
84
+ });
85
+ }
86
+ //#endregion
87
+ //#region src/monacoEnvironment.ts
88
+ function configureMonacoEnvironment() {
89
+ if (typeof window === "undefined") return;
90
+ if (typeof Reflect.get(window, "MonacoEnvironment")?.getWorker === "function") return;
91
+ window.MonacoEnvironment = { getWorker: (_moduleId, label) => {
92
+ if (label === "yaml") return new Worker(new URL("./yaml/yaml.worker.js", import.meta.url), { type: "module" });
93
+ if (label === "json") return new Worker(new URL("monaco-editor/esm/vs/language/json/json.worker.js", import.meta.url), { type: "module" });
94
+ return new Worker(new URL("monaco-editor/esm/vs/editor/editor.worker.js", import.meta.url), { type: "module" });
95
+ } };
96
+ }
97
+ //#endregion
98
+ //#region src/runtime/runtimeState.ts
99
+ const runtimeKey = Symbol.for("alauda.react-code-editor.runtime");
100
+ function getSharedRuntimeState() {
101
+ const target = globalThis;
102
+ target[runtimeKey] ??= {};
103
+ return target[runtimeKey];
104
+ }
105
+ //#endregion
106
+ //#region src/runtime/loadMonaco.ts
107
+ function loadMonacoRuntime() {
108
+ const runtime = getSharedRuntimeState();
109
+ if (runtime.monacoPromise) return runtime.monacoPromise;
110
+ const promise = (async () => {
111
+ configureMonacoEnvironment();
112
+ const monaco = await import("monaco-editor/esm/vs/editor/editor.main.js");
113
+ loader.config({ monaco });
114
+ runtime.monaco = monaco;
115
+ return monaco;
116
+ })();
117
+ runtime.monacoPromise = promise;
118
+ promise.catch(() => {
119
+ if (runtime.monacoPromise === promise) runtime.monacoPromise = void 0;
120
+ });
121
+ return promise;
122
+ }
123
+ //#endregion
124
+ //#region src/runtime/modelOwnership.ts
125
+ function ownershipRegistry() {
126
+ const runtime = getSharedRuntimeState();
127
+ runtime.models ??= /* @__PURE__ */ new Map();
128
+ return runtime.models;
129
+ }
130
+ function acquireModelOwnership(monaco, ownerId, modelPath, language) {
131
+ const registry = ownershipRegistry();
132
+ const existing = registry.get(modelPath);
133
+ if (existing && existing.language !== language) throw new Error(`Conflicting editor languages for ${modelPath}: ${existing.language} and ${language}`);
134
+ const ownership = existing ?? (() => {
135
+ const uri = monaco.Uri.parse(modelPath);
136
+ return {
137
+ language,
138
+ owners: /* @__PURE__ */ new Set(),
139
+ uri,
140
+ ownedByPackage: !monaco.editor.getModel(uri)
141
+ };
142
+ })();
143
+ ownership.owners.add(ownerId);
144
+ registry.set(modelPath, ownership);
145
+ let active = true;
146
+ return () => {
147
+ if (!active) return;
148
+ active = false;
149
+ ownership.owners.delete(ownerId);
150
+ if (ownership.owners.size > 0) return;
151
+ registry.delete(modelPath);
152
+ if (ownership.ownedByPackage) monaco.editor.getModel(ownership.uri)?.dispose();
153
+ };
154
+ }
155
+ //#endregion
156
+ //#region src/themeAppearance.ts
157
+ const systemDarkQuery = "(prefers-color-scheme: dark)";
158
+ function hostThemeSelection() {
159
+ if (typeof document === "undefined") return void 0;
160
+ const value = document.documentElement.dataset.auiThemeMode;
161
+ return value === "light" || value === "dark" || value === "system" ? value : void 0;
162
+ }
163
+ function prefersDark() {
164
+ return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(systemDarkQuery).matches;
165
+ }
166
+ function resolveCodeEditorThemeMode(selection, fallback, systemPrefersDark) {
167
+ if (selection === "dark") return "dark";
168
+ if (selection === "light") return "light";
169
+ if (selection === "system") return systemPrefersDark ? "dark" : "light";
170
+ return fallback;
171
+ }
172
+ function readEffectiveThemeMode(fallback) {
173
+ return resolveCodeEditorThemeMode(hostThemeSelection(), fallback, prefersDark());
174
+ }
175
+ function subscribeToThemeAppearance(listener) {
176
+ if (typeof document === "undefined") return () => void 0;
177
+ const root = document.documentElement;
178
+ const observer = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver((records) => {
179
+ if (records.some((record) => record.attributeName === "data-aui-theme-mode")) listener();
180
+ });
181
+ observer?.observe(root, {
182
+ attributes: true,
183
+ attributeFilter: ["data-aui-theme-mode"]
184
+ });
185
+ const mediaQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(systemDarkQuery) : void 0;
186
+ const mediaListener = () => listener();
187
+ mediaQuery?.addEventListener("change", mediaListener);
188
+ return () => {
189
+ observer?.disconnect();
190
+ mediaQuery?.removeEventListener("change", mediaListener);
191
+ };
192
+ }
193
+ /**
194
+ * Reads the Host's CSS-backed appearance while retaining MUI compatibility for
195
+ * standalone consumers that do not publish data-aui-theme-mode.
196
+ */
197
+ function useCodeEditorThemeMode() {
198
+ const fallback = useTheme().palette.mode;
199
+ return useSyncExternalStore(subscribeToThemeAppearance, () => readEffectiveThemeMode(fallback), () => fallback);
200
+ }
201
+ //#endregion
202
+ //#region src/CodeEditor.tsx
203
+ const codeEditorActionPresets = {
204
+ create: [
205
+ "import",
206
+ "export",
207
+ "clear",
208
+ "find",
209
+ "copy",
210
+ "theme",
211
+ "fullscreen"
212
+ ],
213
+ view: [
214
+ "export",
215
+ "find",
216
+ "copy",
217
+ "theme",
218
+ "fullscreen"
219
+ ],
220
+ update: [
221
+ "import",
222
+ "export",
223
+ "recover",
224
+ "clear",
225
+ "find",
226
+ "copy",
227
+ "theme",
228
+ "fullscreen"
229
+ ],
230
+ logs: [
231
+ "export",
232
+ "find",
233
+ "copy",
234
+ "theme",
235
+ "fullscreen"
236
+ ]
237
+ };
238
+ const defaultLabels = {
239
+ copy: "Copy",
240
+ copied: "Copied",
241
+ copyFailed: "Copy failed",
242
+ clear: "Clear",
243
+ export: "Export",
244
+ find: "Find",
245
+ format: "Format",
246
+ fullscreen: "Full Screen",
247
+ exitFullscreen: "Exit",
248
+ import: "Import",
249
+ importFailed: "Unable to read file",
250
+ recover: "Recover",
251
+ theme: "Theme",
252
+ themeSystem: "Auto",
253
+ themeLight: "Light",
254
+ themeDark: "Dark",
255
+ undo: "Undo",
256
+ redo: "Redo",
257
+ loading: "Loading editor",
258
+ valid: "Validation passed",
259
+ errors: (count) => `${count} validation error${count === 1 ? "" : "s"}`,
260
+ lineColumn: (line, column) => `Ln ${line}, Col ${column}`
261
+ };
262
+ const defaultActions = [
263
+ "find",
264
+ "copy",
265
+ "format",
266
+ "undo",
267
+ "redo",
268
+ "fullscreen"
269
+ ];
270
+ const exportFormats = {
271
+ json: {
272
+ mime: "application/json",
273
+ extension: "json"
274
+ },
275
+ markdown: {
276
+ mime: "text/markdown",
277
+ extension: "md"
278
+ },
279
+ plaintext: {
280
+ mime: "text/plain",
281
+ extension: "txt"
282
+ },
283
+ yaml: {
284
+ mime: "text/yaml",
285
+ extension: "yaml"
286
+ }
287
+ };
288
+ function markerSeverity(marker, monaco) {
289
+ if (marker.severity === monaco.MarkerSeverity.Error) return "error";
290
+ if (marker.severity === monaco.MarkerSeverity.Warning) return "warning";
291
+ if (marker.severity === monaco.MarkerSeverity.Info) return "info";
292
+ return "hint";
293
+ }
294
+ function mapDiagnostics(markers, monaco) {
295
+ return markers.map((marker) => ({
296
+ severity: markerSeverity(marker, monaco),
297
+ message: marker.message,
298
+ line: marker.startLineNumber,
299
+ column: marker.startColumn,
300
+ endLine: marker.endLineNumber,
301
+ endColumn: marker.endColumn,
302
+ ...marker.code === void 0 ? {} : { code: String(marker.code) }
303
+ }));
304
+ }
305
+ const CodeEditor = forwardRef(function CodeEditor({ value, onChange, onBlur, language, modelPath, ariaLabel, readOnly = false, disabled = false, height = 400, minimap = false, actions = defaultActions, labels: labelOverrides, error, onDiagnostics, originalValue, diffMode = false, importAccept, exportFileName, onImportText, onExport, onRecover, onClear, themeMode: controlledThemeMode, onThemeModeChange, onFullscreenChange, sidebar, toolbarStart, toolbarActions, toolbarEnd }, ref) {
306
+ const theme = useTheme();
307
+ const appearanceMode = useCodeEditorThemeMode();
308
+ const ownerId = useId();
309
+ const editorRef = useRef(null);
310
+ const disposablesRef = useRef([]);
311
+ const diagnosticsRef = useRef([]);
312
+ const externalValueSyncRef = useRef(false);
313
+ const pendingLocalValuesRef = useRef([]);
314
+ const modelPathRef = useRef(modelPath);
315
+ const valueRef = useRef(value);
316
+ const [monaco, setMonaco] = useState(null);
317
+ const [runtimeError, setRuntimeError] = useState();
318
+ const [copyState, setCopyState] = useState("idle");
319
+ const [fullscreen, setFullscreen] = useState(false);
320
+ const importRevision = useRef(0);
321
+ const importTarget = useRef({
322
+ readOnly,
323
+ disabled,
324
+ modelPath,
325
+ onImportText,
326
+ onChange
327
+ });
328
+ importTarget.current = {
329
+ readOnly,
330
+ disabled,
331
+ modelPath,
332
+ onImportText,
333
+ onChange
334
+ };
335
+ const [importError, setImportError] = useState(false);
336
+ useEffect(() => {
337
+ importRevision.current += 1;
338
+ return () => {
339
+ importRevision.current += 1;
340
+ };
341
+ }, [
342
+ modelPath,
343
+ readOnly,
344
+ disabled,
345
+ value
346
+ ]);
347
+ const [themeMenuAnchor, setThemeMenuAnchor] = useState(null);
348
+ const [localThemeMode, setLocalThemeMode] = useState("system");
349
+ const importInputRef = useRef(null);
350
+ const themeButtonRef = useRef(null);
351
+ const selectedThemeMode = controlledThemeMode ?? localThemeMode;
352
+ const resolvedTheme = selectedThemeMode === "system" ? appearanceMode : selectedThemeMode;
353
+ const editorColors = resolvedTheme === "dark" ? {
354
+ surface: "#181B27",
355
+ content: "#242733",
356
+ text: "#EEEFF3",
357
+ secondary: "#C8C9CD",
358
+ border: "#5C5F6B",
359
+ hover: "rgba(238,239,243,0.08)"
360
+ } : {
361
+ surface: "#F7F9FC",
362
+ content: "#FFFFFF",
363
+ text: "#323437",
364
+ secondary: "#646669",
365
+ border: "#D4D6D9",
366
+ hover: "rgba(50,52,55,0.04)"
367
+ };
368
+ const labels = {
369
+ ...defaultLabels,
370
+ ...labelOverrides
371
+ };
372
+ valueRef.current = value;
373
+ const synchronizeExternalValue = useCallback((editor, nextValue) => {
374
+ const model = editor.getModel();
375
+ if (!model) return;
376
+ const pending = pendingLocalValuesRef.current;
377
+ const acknowledgedIndex = pending.lastIndexOf(nextValue);
378
+ if (acknowledgedIndex >= 0) {
379
+ pending.splice(0, acknowledgedIndex + 1);
380
+ return;
381
+ }
382
+ if (model.getValue() === nextValue) return;
383
+ pending.length = 0;
384
+ const selections = editor.getSelections();
385
+ const scrollPosition = {
386
+ scrollLeft: editor.getScrollLeft(),
387
+ scrollTop: editor.getScrollTop()
388
+ };
389
+ externalValueSyncRef.current = true;
390
+ try {
391
+ editor.pushUndoStop();
392
+ if (!editor.executeEdits("alauda.react-code-editor.external-value", [{
393
+ range: model.getFullModelRange(),
394
+ text: nextValue,
395
+ forceMoveMarkers: true
396
+ }], selections ?? void 0)) model.setValue(nextValue);
397
+ editor.pushUndoStop();
398
+ if (selections) editor.setSelections(selections);
399
+ editor.setScrollPosition(scrollPosition);
400
+ } finally {
401
+ externalValueSyncRef.current = false;
402
+ }
403
+ }, []);
404
+ useEffect(() => {
405
+ let active = true;
406
+ let release;
407
+ setMonaco(null);
408
+ setRuntimeError(void 0);
409
+ loadMonacoRuntime().then((instance) => {
410
+ if (!active) return;
411
+ instance.editor.defineTheme("alauda-dark", {
412
+ base: "vs-dark",
413
+ inherit: true,
414
+ rules: [],
415
+ colors: {
416
+ "editor.background": "#242733",
417
+ "minimap.background": "#242733"
418
+ }
419
+ });
420
+ release = acquireModelOwnership(instance, ownerId, modelPath, language);
421
+ if (active) setMonaco(instance);
422
+ else release();
423
+ }).catch((errorValue) => {
424
+ if (active) setRuntimeError(errorValue instanceof Error ? errorValue.message : String(errorValue));
425
+ });
426
+ return () => {
427
+ active = false;
428
+ release?.();
429
+ };
430
+ }, [
431
+ language,
432
+ modelPath,
433
+ ownerId
434
+ ]);
435
+ useEffect(() => () => {
436
+ disposablesRef.current.forEach((disposable) => disposable.dispose());
437
+ disposablesRef.current = [];
438
+ editorRef.current = null;
439
+ }, []);
440
+ useEffect(() => {
441
+ if (!monaco || !diffMode) return;
442
+ return acquireModelOwnership(monaco, `${ownerId}:original`, `${modelPath}.original`, language);
443
+ }, [
444
+ diffMode,
445
+ language,
446
+ modelPath,
447
+ monaco,
448
+ ownerId
449
+ ]);
450
+ useEffect(() => {
451
+ if (modelPathRef.current !== modelPath) {
452
+ modelPathRef.current = modelPath;
453
+ pendingLocalValuesRef.current = [];
454
+ }
455
+ const editor = editorRef.current;
456
+ if (editor) synchronizeExternalValue(editor, value);
457
+ }, [
458
+ modelPath,
459
+ synchronizeExternalValue,
460
+ value
461
+ ]);
462
+ const find = async () => {
463
+ editorRef.current?.focus();
464
+ await editorRef.current?.getAction("actions.find")?.run();
465
+ };
466
+ const format = async () => {
467
+ editorRef.current?.focus();
468
+ await editorRef.current?.getAction("editor.action.formatDocument")?.run();
469
+ };
470
+ useImperativeHandle(ref, () => ({
471
+ focus: () => editorRef.current?.focus(),
472
+ find,
473
+ format,
474
+ undo: () => editorRef.current?.trigger("code-editor", "undo", null),
475
+ redo: () => editorRef.current?.trigger("code-editor", "redo", null),
476
+ validate: async () => diagnosticsRef.current
477
+ }));
478
+ const onMount = (editor, instance) => {
479
+ editorRef.current = editor;
480
+ synchronizeExternalValue(editor, valueRef.current);
481
+ disposablesRef.current.forEach((disposable) => disposable.dispose());
482
+ disposablesRef.current = [editor.onDidBlurEditorText(() => onBlur?.())];
483
+ if (instance.editor?.onDidChangeMarkers) {
484
+ const publish = () => {
485
+ const model = editor.getModel();
486
+ if (!model) return;
487
+ const diagnostics = mapDiagnostics(instance.editor.getModelMarkers({ resource: model.uri }), instance);
488
+ diagnosticsRef.current = diagnostics;
489
+ onDiagnostics?.(diagnostics);
490
+ };
491
+ disposablesRef.current.push(instance.editor.onDidChangeMarkers((uris) => {
492
+ const uri = editor.getModel()?.uri.toString();
493
+ if (uris.some((changed) => changed.toString() === uri)) publish();
494
+ }));
495
+ publish();
496
+ }
497
+ };
498
+ const copy = async () => {
499
+ try {
500
+ await navigator.clipboard.writeText(editorRef.current?.getModel()?.getValue() ?? valueRef.current);
501
+ setCopyState("copied");
502
+ } catch {
503
+ setCopyState("failed");
504
+ }
505
+ };
506
+ const exportValue = () => {
507
+ if (onExport) {
508
+ onExport(valueRef.current);
509
+ return;
510
+ }
511
+ const format = exportFormats[language];
512
+ const basename = modelPath.split(/[?#]/)[0]?.split("/").at(-1) || "document";
513
+ const filename = exportFileName ?? (/\.[^./]+$/.test(basename) ? basename : `${basename}.${format.extension}`);
514
+ const blob = new Blob([valueRef.current], { type: `${format.mime};charset=utf-8` });
515
+ const url = URL.createObjectURL(blob);
516
+ const link = document.createElement("a");
517
+ link.href = url;
518
+ link.download = filename;
519
+ link.click();
520
+ URL.revokeObjectURL(url);
521
+ };
522
+ const importFile = (event) => {
523
+ const file = event.target.files?.[0];
524
+ event.target.value = "";
525
+ if (!file || readOnly || disabled) return;
526
+ const revision = ++importRevision.current;
527
+ const owner = modelPath;
528
+ setImportError(false);
529
+ file.text().then((text) => {
530
+ const target = importTarget.current;
531
+ if (revision !== importRevision.current || target.modelPath !== owner || target.readOnly || target.disabled) return;
532
+ if (target.onImportText) target.onImportText(text, file);
533
+ else target.onChange(text);
534
+ }).catch(() => {
535
+ if (revision === importRevision.current) setImportError(true);
536
+ });
537
+ };
538
+ const runAction = (action) => {
539
+ if (action === "find") find();
540
+ if (action === "copy") copy();
541
+ if (action === "clear") if (onClear) onClear();
542
+ else onChange("");
543
+ if (action === "export") exportValue();
544
+ if (action === "format") format();
545
+ if (action === "undo") editorRef.current?.trigger("code-editor", "undo", null);
546
+ if (action === "redo") editorRef.current?.trigger("code-editor", "redo", null);
547
+ if (action === "fullscreen") {
548
+ const next = !fullscreen;
549
+ setFullscreen(next);
550
+ onFullscreenChange?.(next);
551
+ }
552
+ if (action === "import") importInputRef.current?.click();
553
+ if (action === "recover") {
554
+ const nextValue = originalValue ?? "";
555
+ if (onRecover) onRecover(nextValue);
556
+ else onChange(nextValue);
557
+ }
558
+ if (action === "theme") setThemeMenuAnchor(themeButtonRef.current);
559
+ };
560
+ const actionLabel = (action) => {
561
+ if (action === "copy" && copyState === "copied") return labels.copied;
562
+ if (action === "copy" && copyState === "failed") return labels.copyFailed;
563
+ if (action === "fullscreen" && fullscreen) return labels.exitFullscreen;
564
+ return labels[action] ?? action;
565
+ };
566
+ const chooseTheme = (mode) => {
567
+ setLocalThemeMode(mode);
568
+ onThemeModeChange?.(mode);
569
+ setThemeMenuAnchor(null);
570
+ };
571
+ const actionIcon = (action) => {
572
+ const size = {
573
+ width: 14,
574
+ height: 14
575
+ };
576
+ if (action === "clear") return /* @__PURE__ */ jsx(CodeEditorIcon, {
577
+ name: "xmark_circle",
578
+ sx: size
579
+ });
580
+ if (action === "copy") return /* @__PURE__ */ jsx(CodeEditorIcon, {
581
+ name: "copy",
582
+ sx: size
583
+ });
584
+ if (action === "export") return /* @__PURE__ */ jsx(CodeEditorIcon, {
585
+ name: "file_export",
586
+ sx: size
587
+ });
588
+ if (action === "find") return /* @__PURE__ */ jsx(CodeEditorIcon, {
589
+ name: "magnifier",
590
+ sx: size
591
+ });
592
+ if (action === "format") return /* @__PURE__ */ jsx(FormatAlignLeftRoundedIcon, { sx: size });
593
+ if (action === "fullscreen") return /* @__PURE__ */ jsx(CodeEditorIcon, {
594
+ name: fullscreen ? "compress" : "expand",
595
+ sx: size
596
+ });
597
+ if (action === "import") return /* @__PURE__ */ jsx(CodeEditorIcon, {
598
+ name: "file_import",
599
+ sx: size
600
+ });
601
+ if (action === "recover") return /* @__PURE__ */ jsx(CodeEditorIcon, {
602
+ name: "rollback",
603
+ sx: size
604
+ });
605
+ if (action === "redo") return /* @__PURE__ */ jsx(RedoRoundedIcon, { sx: size });
606
+ if (action === "theme") {
607
+ if (selectedThemeMode === "dark") return /* @__PURE__ */ jsx(CodeEditorIcon, {
608
+ name: "moon",
609
+ sx: size
610
+ });
611
+ if (selectedThemeMode === "light") return /* @__PURE__ */ jsx(CodeEditorIcon, {
612
+ name: "sun",
613
+ sx: size
614
+ });
615
+ return /* @__PURE__ */ jsx(CodeEditorIcon, {
616
+ name: "computer",
617
+ sx: size
618
+ });
619
+ }
620
+ return /* @__PURE__ */ jsx(UndoRoundedIcon, { sx: size });
621
+ };
622
+ if (runtimeError) return /* @__PURE__ */ jsx(Alert, {
623
+ severity: "error",
624
+ role: "alert",
625
+ children: runtimeError
626
+ });
627
+ if (!monaco) return /* @__PURE__ */ jsx(Box, {
628
+ role: "status",
629
+ "aria-label": labels.loading,
630
+ sx: {
631
+ display: "grid",
632
+ height,
633
+ minHeight: 160,
634
+ placeItems: "center"
635
+ },
636
+ children: /* @__PURE__ */ jsx(CircularProgress, { "aria-hidden": "true" })
637
+ });
638
+ return /* @__PURE__ */ jsxs(Box, {
639
+ role: "region",
640
+ "aria-label": `${ariaLabel} editor`,
641
+ sx: {
642
+ position: fullscreen ? "fixed" : "relative",
643
+ inset: fullscreen ? 0 : void 0,
644
+ zIndex: fullscreen ? theme.zIndex.modal : void 0,
645
+ display: "flex",
646
+ flexDirection: sidebar ? "row" : "column",
647
+ height: fullscreen ? "100dvh" : height,
648
+ minHeight: 160,
649
+ overflow: "hidden",
650
+ bgcolor: "transparent"
651
+ },
652
+ children: [/* @__PURE__ */ jsxs(Box, {
653
+ "data-code-editor-appearance": resolvedTheme,
654
+ sx: {
655
+ display: "flex",
656
+ flex: sidebar ? "2 1 0%" : "1 1 auto",
657
+ flexDirection: "column",
658
+ minWidth: 0,
659
+ minHeight: 0,
660
+ bgcolor: editorColors.surface,
661
+ color: editorColors.text,
662
+ padding: "0 12px 12px",
663
+ border: 0,
664
+ borderRadius: fullscreen ? 0 : 1,
665
+ overflow: "hidden"
666
+ },
667
+ children: [
668
+ /* @__PURE__ */ jsxs(Box, {
669
+ sx: {
670
+ display: "flex",
671
+ alignItems: "center",
672
+ gap: 1,
673
+ flexWrap: "wrap",
674
+ minHeight: 22,
675
+ flexShrink: 0,
676
+ px: 2,
677
+ py: 3,
678
+ "& .MuiIconButton-root, & .MuiCheckbox-root": { color: editorColors.secondary },
679
+ "& .MuiCheckbox-root": { padding: "5px" },
680
+ "& .MuiIconButton-root:hover": { bgcolor: editorColors.hover },
681
+ "& .MuiFormControlLabel-root": { color: editorColors.text }
682
+ },
683
+ children: [
684
+ toolbarStart,
685
+ /* @__PURE__ */ jsx(Box, { sx: { flex: 1 } }),
686
+ actions.filter((action) => {
687
+ if (readOnly && [
688
+ "import",
689
+ "recover",
690
+ "clear",
691
+ "format",
692
+ "undo",
693
+ "redo"
694
+ ].includes(action)) return false;
695
+ if (action === "recover" && originalValue === void 0) return false;
696
+ if ([
697
+ "export",
698
+ "find",
699
+ "copy",
700
+ "clear"
701
+ ].includes(action)) return Boolean(value);
702
+ return true;
703
+ }).map((action) => /* @__PURE__ */ jsx(Tooltip, {
704
+ title: actionLabel(action),
705
+ children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(IconButton, {
706
+ ref: action === "theme" ? themeButtonRef : void 0,
707
+ "aria-label": actionLabel(action),
708
+ "aria-pressed": action === "fullscreen" ? fullscreen : void 0,
709
+ disabled: disabled || readOnly && [
710
+ "format",
711
+ "undo",
712
+ "redo",
713
+ "clear",
714
+ "recover",
715
+ "import"
716
+ ].includes(action),
717
+ size: "small",
718
+ sx: {
719
+ width: 28,
720
+ height: 28
721
+ },
722
+ onClick: () => runAction(action),
723
+ children: actionIcon(action)
724
+ }) })
725
+ }, action)),
726
+ toolbarEnd,
727
+ toolbarActions
728
+ ]
729
+ }),
730
+ importError ? /* @__PURE__ */ jsx(Alert, {
731
+ severity: "error",
732
+ role: "alert",
733
+ children: labels.importFailed
734
+ }) : null,
735
+ /* @__PURE__ */ jsx("input", {
736
+ ref: importInputRef,
737
+ hidden: true,
738
+ type: "file",
739
+ accept: importAccept,
740
+ onChange: importFile
741
+ }),
742
+ /* @__PURE__ */ jsxs(Menu, {
743
+ anchorEl: themeMenuAnchor,
744
+ open: Boolean(themeMenuAnchor),
745
+ onClose: () => setThemeMenuAnchor(null),
746
+ slotProps: { paper: { sx: {
747
+ bgcolor: editorColors.surface,
748
+ color: editorColors.text
749
+ } } },
750
+ children: [
751
+ /* @__PURE__ */ jsxs(MenuItem, {
752
+ selected: selectedThemeMode === "system",
753
+ onClick: () => chooseTheme("system"),
754
+ children: [/* @__PURE__ */ jsx(CodeEditorIcon, {
755
+ name: "computer",
756
+ sx: {
757
+ width: 14,
758
+ height: 14,
759
+ mr: 1
760
+ }
761
+ }), labels.themeSystem]
762
+ }),
763
+ /* @__PURE__ */ jsxs(MenuItem, {
764
+ selected: selectedThemeMode === "light",
765
+ onClick: () => chooseTheme("light"),
766
+ children: [/* @__PURE__ */ jsx(CodeEditorIcon, {
767
+ name: "sun",
768
+ sx: {
769
+ width: 14,
770
+ height: 14,
771
+ mr: 1
772
+ }
773
+ }), labels.themeLight]
774
+ }),
775
+ /* @__PURE__ */ jsxs(MenuItem, {
776
+ selected: selectedThemeMode === "dark",
777
+ onClick: () => chooseTheme("dark"),
778
+ children: [/* @__PURE__ */ jsx(CodeEditorIcon, {
779
+ name: "moon",
780
+ sx: {
781
+ width: 14,
782
+ height: 14,
783
+ mr: 1
784
+ }
785
+ }), labels.themeDark]
786
+ })
787
+ ]
788
+ }),
789
+ error ? /* @__PURE__ */ jsx(Alert, {
790
+ severity: "error",
791
+ role: "alert",
792
+ children: error
793
+ }) : null,
794
+ /* @__PURE__ */ jsx(Box, {
795
+ sx: {
796
+ display: "flex",
797
+ flex: "1 1 auto",
798
+ minHeight: 0,
799
+ overflow: "hidden",
800
+ px: 0,
801
+ pb: 0
802
+ },
803
+ children: /* @__PURE__ */ jsx(Box, {
804
+ sx: {
805
+ flex: "1 1 auto",
806
+ minWidth: 0,
807
+ minHeight: 0,
808
+ overflow: "hidden",
809
+ border: 1,
810
+ borderColor: error ? "error.main" : editorColors.border,
811
+ borderRadius: 1
812
+ },
813
+ children: diffMode ? /* @__PURE__ */ jsx(DiffEditor, {
814
+ height: "100%",
815
+ language,
816
+ original: originalValue ?? "",
817
+ modified: value,
818
+ originalModelPath: `${modelPath}.original`,
819
+ modifiedModelPath: modelPath,
820
+ theme: resolvedTheme === "dark" ? "alauda-dark" : "vs",
821
+ keepCurrentOriginalModel: true,
822
+ keepCurrentModifiedModel: true,
823
+ onMount: (diffEditor, instance) => {
824
+ const modified = diffEditor.getModifiedEditor();
825
+ onMount(modified, instance);
826
+ disposablesRef.current.push(modified.onDidChangeModelContent(() => {
827
+ if (!externalValueSyncRef.current) onChange(modified.getValue());
828
+ }));
829
+ },
830
+ options: {
831
+ ariaLabel,
832
+ automaticLayout: true,
833
+ originalEditable: false,
834
+ readOnly: readOnly || disabled,
835
+ renderSideBySide: true,
836
+ scrollBeyondLastLine: false,
837
+ minimap: { enabled: minimap }
838
+ }
839
+ }) : /* @__PURE__ */ jsx(Editor, {
840
+ height: "100%",
841
+ language,
842
+ path: modelPath,
843
+ theme: resolvedTheme === "dark" ? "alauda-dark" : "vs",
844
+ defaultValue: value,
845
+ keepCurrentModel: true,
846
+ onMount,
847
+ onChange: (nextValue) => {
848
+ if (externalValueSyncRef.current) return;
849
+ const normalized = nextValue ?? "";
850
+ const pending = pendingLocalValuesRef.current;
851
+ if (pending.at(-1) !== normalized) {
852
+ pending.push(normalized);
853
+ if (pending.length > 64) pending.splice(0, pending.length - 64);
854
+ }
855
+ onChange(normalized);
856
+ },
857
+ onValidate: (markers) => {
858
+ const diagnostics = mapDiagnostics(markers, monaco);
859
+ diagnosticsRef.current = diagnostics;
860
+ onDiagnostics?.(diagnostics);
861
+ },
862
+ options: {
863
+ ariaLabel,
864
+ automaticLayout: true,
865
+ bracketPairColorization: { enabled: true },
866
+ folding: true,
867
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
868
+ fontSize: 13,
869
+ formatOnPaste: true,
870
+ insertSpaces: true,
871
+ lineHeight: 22,
872
+ minimap: { enabled: minimap },
873
+ padding: {
874
+ top: 12,
875
+ bottom: 12
876
+ },
877
+ readOnly: readOnly || disabled,
878
+ renderValidationDecorations: "on",
879
+ scrollBeyondLastLine: false,
880
+ tabSize: 2
881
+ }
882
+ })
883
+ })
884
+ })
885
+ ]
886
+ }), sidebar]
887
+ });
888
+ });
889
+ //#endregion
890
+ export { loadMonacoRuntime as a, acquireModelOwnership as i, codeEditorActionPresets as n, getSharedRuntimeState as o, useCodeEditorThemeMode as r, CodeEditor as t };
891
+
892
+ //# sourceMappingURL=CodeEditor-DhYaoBaC.js.map