@alauda/react-code-editor 0.1.0-next.20260812.1786527360

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 ADDED
@@ -0,0 +1,62 @@
1
+ # `@alauda/react-code-editor`
2
+
3
+ 面向 React 应用的 Monaco 代码编辑器。根入口提供受控 `CodeEditor` 和 `DiffCodeEditor`;
4
+ `@alauda/react-code-editor/yaml` 提供按需加载的 YAML Schema、diagnostics 和 Kubernetes mode。
5
+
6
+ 首版支持 JSON、Markdown、纯文本和 YAML。调用方负责提供受控值、稳定的 `modelPath`、Schema、文案
7
+ 以及数据获取和提交逻辑;本包不依赖 Console SDK,不获取 Kubernetes 资源,也不执行 mutation。
8
+
9
+ 本包是 Code Editor 的唯一公共 package,不属于 `@alauda/console-ui`,也不通过 `console-ui` 二次封装。
10
+ Console 业务 plugin 直接消费本包;`console-ui` 可以提供编辑器外围的页面、表单和反馈组件,但不拥有
11
+ Monaco、worker、language service 或 Code Editor 公共 API。
12
+
13
+ 独立拆包依据、OCP Code Editor 对比和最终选型见
14
+ [Code Editor 独立拆包与 OCP 调研结论](docs/research/code-editor-package-and-ocp-evaluation.md)。
15
+
16
+ 在 ACP Console Host 和业务 plugin 中安装、配置 Module Federation、处理 Rsbuild worker 路径及进行
17
+ 生产验收时,请参阅 [ACP Console 接入指南](docs/guides/console-integration.md)。
18
+
19
+ ## 使用方式
20
+
21
+ ```tsx
22
+ import { CodeEditor, DiffCodeEditor } from '@alauda/react-code-editor';
23
+ import { ResourceYamlEditor } from '@alauda/react-code-editor/yaml';
24
+ ```
25
+
26
+ - 根入口:受控编辑器、Diff 编辑器、语义 handle、diagnostics、toolbar actions 和 labels。
27
+ - `./yaml`:调用方提供 JSON-compatible Schema、稳定 `modelPath` 和可选 Kubernetes mode;本包管理
28
+ YAML language service、Schema owner 和 worker 生命周期。
29
+ - 不要从 `src/**` 或 `dist/**` 深层导入。
30
+
31
+ ## Module Federation
32
+
33
+ 普通 React 应用可以直接使用本包。用于 Module Federation Host/remote 时,双方应把 React、MUI、
34
+ Emotion、`@monaco-editor/react`、`monaco-editor` 和 `monaco-yaml` 配置为 singleton。不同 remote 中的
35
+ package module 即使被重复执行,也会通过全局 registry 合并 Monaco loader、model 和 Schema lifecycle。
36
+
37
+ ## 本地验证
38
+
39
+ 启动可交互 playground:
40
+
41
+ ```sh
42
+ yarn install
43
+ yarn dev
44
+ ```
45
+
46
+ 打开 `http://localhost:9001`,可以切换 YAML、JSON、Markdown、纯文本和 Diff 场景,并验证只读模式与
47
+ light/dark theme。`yarn build:demo` 用于验证 playground 的生产构建和 worker 产物;demo 不进入 npm
48
+ 发布包。
49
+
50
+ 完整检查:
51
+
52
+ ```sh
53
+ yarn typecheck
54
+ yarn lint
55
+ yarn test
56
+ yarn build:demo
57
+ yarn build
58
+ yarn check
59
+ yarn pack:dry-run
60
+ ```
61
+
62
+ 构建后的可发布目录为 `dist/package`。实际发布前应由 CI 注入正式版本并完成审批。
@@ -0,0 +1,431 @@
1
+ import Editor, { 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 Tooltip from "@mui/material/Tooltip";
7
+ import Typography from "@mui/material/Typography";
8
+ import { useTheme } from "@mui/material/styles";
9
+ import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useRef, useState } from "react";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ //#region src/monacoEnvironment.ts
12
+ function configureMonacoEnvironment() {
13
+ if (typeof window === "undefined") return;
14
+ if (typeof Reflect.get(window, "MonacoEnvironment")?.getWorker === "function") return;
15
+ window.MonacoEnvironment = { getWorker: (_moduleId, label) => {
16
+ if (label === "yaml") return new Worker(new URL("./yaml/yaml.worker.js", import.meta.url));
17
+ if (label === "json") return new Worker(new URL("monaco-editor/esm/vs/language/json/json.worker.js", import.meta.url));
18
+ return new Worker(new URL("monaco-editor/esm/vs/editor/editor.worker.js", import.meta.url));
19
+ } };
20
+ }
21
+ //#endregion
22
+ //#region src/runtime/runtimeState.ts
23
+ const runtimeKey = Symbol.for("alauda.react-code-editor.runtime");
24
+ function getSharedRuntimeState() {
25
+ const target = globalThis;
26
+ target[runtimeKey] ??= {};
27
+ return target[runtimeKey];
28
+ }
29
+ //#endregion
30
+ //#region src/runtime/loadMonaco.ts
31
+ function loadMonacoRuntime() {
32
+ const runtime = getSharedRuntimeState();
33
+ if (runtime.monacoPromise) return runtime.monacoPromise;
34
+ const promise = (async () => {
35
+ configureMonacoEnvironment();
36
+ const monaco = await import("monaco-editor/esm/vs/editor/editor.main.js");
37
+ loader.config({ monaco });
38
+ runtime.monaco = monaco;
39
+ return monaco;
40
+ })();
41
+ runtime.monacoPromise = promise;
42
+ promise.catch(() => {
43
+ if (runtime.monacoPromise === promise) runtime.monacoPromise = void 0;
44
+ });
45
+ return promise;
46
+ }
47
+ //#endregion
48
+ //#region src/runtime/modelOwnership.ts
49
+ function ownershipRegistry() {
50
+ const runtime = getSharedRuntimeState();
51
+ runtime.models ??= /* @__PURE__ */ new Map();
52
+ return runtime.models;
53
+ }
54
+ function acquireModelOwnership(monaco, ownerId, modelPath, language) {
55
+ const registry = ownershipRegistry();
56
+ const existing = registry.get(modelPath);
57
+ if (existing && existing.language !== language) throw new Error(`Conflicting editor languages for ${modelPath}: ${existing.language} and ${language}`);
58
+ const ownership = existing ?? (() => {
59
+ const uri = monaco.Uri.parse(modelPath);
60
+ return {
61
+ language,
62
+ owners: /* @__PURE__ */ new Set(),
63
+ uri,
64
+ ownedByPackage: !monaco.editor.getModel(uri)
65
+ };
66
+ })();
67
+ ownership.owners.add(ownerId);
68
+ registry.set(modelPath, ownership);
69
+ let active = true;
70
+ return () => {
71
+ if (!active) return;
72
+ active = false;
73
+ ownership.owners.delete(ownerId);
74
+ if (ownership.owners.size > 0) return;
75
+ registry.delete(modelPath);
76
+ if (ownership.ownedByPackage) monaco.editor.getModel(ownership.uri)?.dispose();
77
+ };
78
+ }
79
+ //#endregion
80
+ //#region src/CodeEditor.tsx
81
+ const defaultLabels = {
82
+ copy: "Copy",
83
+ copied: "Copied",
84
+ copyFailed: "Copy failed",
85
+ find: "Search",
86
+ format: "Format",
87
+ fullscreen: "Enter fullscreen",
88
+ exitFullscreen: "Exit fullscreen",
89
+ undo: "Undo",
90
+ redo: "Redo",
91
+ loading: "Loading editor",
92
+ valid: "Validation passed",
93
+ errors: (count) => `${count} validation error${count === 1 ? "" : "s"}`,
94
+ lineColumn: (line, column) => `Ln ${line}, Col ${column}`
95
+ };
96
+ const defaultActions = [
97
+ "find",
98
+ "copy",
99
+ "format",
100
+ "undo",
101
+ "redo",
102
+ "fullscreen"
103
+ ];
104
+ const paths = {
105
+ copy: "M16 1H4a2 2 0 0 0-2 2v14h2V3h12zm3 4H8a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2m0 16H8V7h11z",
106
+ find: "M9.5 3a6.5 6.5 0 1 0 3.98 11.64L19.85 21 21 19.85l-6.36-6.37A6.5 6.5 0 0 0 9.5 3m0 2a4.5 4.5 0 1 1 0 9 4.5 4.5 0 0 1 0-9",
107
+ format: "M3 5h18v2H3zm0 6h12v2H3zm0 6h18v2H3z",
108
+ fullscreen: "M4 4h6v2H6v4H4zm10 0h6v6h-2V6h-4zM4 14h2v4h4v2H4zm14 0h2v6h-6v-2h4z",
109
+ redo: "M15 6V3l5 5-5 5v-3c-4 0-7 1-9 5 1-6 4-9 9-9",
110
+ undo: "M9 6V3L4 8l5 5v-3c4 0 7 1 9 5-1-6-4-9-9-9"
111
+ };
112
+ const ToolIcon = ({ path }) => /* @__PURE__ */ jsx(Box, {
113
+ component: "svg",
114
+ "aria-hidden": "true",
115
+ viewBox: "0 0 24 24",
116
+ sx: {
117
+ width: 20,
118
+ height: 20,
119
+ fill: "currentColor"
120
+ },
121
+ children: /* @__PURE__ */ jsx("path", { d: path })
122
+ });
123
+ function markerSeverity(marker, monaco) {
124
+ if (marker.severity === monaco.MarkerSeverity.Error) return "error";
125
+ if (marker.severity === monaco.MarkerSeverity.Warning) return "warning";
126
+ if (marker.severity === monaco.MarkerSeverity.Info) return "info";
127
+ return "hint";
128
+ }
129
+ function mapDiagnostics(markers, monaco) {
130
+ return markers.map((marker) => ({
131
+ severity: markerSeverity(marker, monaco),
132
+ message: marker.message,
133
+ line: marker.startLineNumber,
134
+ column: marker.startColumn,
135
+ endLine: marker.endLineNumber,
136
+ endColumn: marker.endColumn,
137
+ ...marker.code === void 0 ? {} : { code: String(marker.code) }
138
+ }));
139
+ }
140
+ const CodeEditor = forwardRef(function CodeEditor({ value, onChange, onBlur, language, modelPath, ariaLabel, readOnly = false, disabled = false, height = 400, actions = defaultActions, labels: labelOverrides, error, onDiagnostics, toolbarStart, toolbarEnd }, ref) {
141
+ const theme = useTheme();
142
+ const ownerId = useId();
143
+ const editorRef = useRef(null);
144
+ const disposablesRef = useRef([]);
145
+ const diagnosticsRef = useRef([]);
146
+ const externalValueSyncRef = useRef(false);
147
+ const pendingLocalValuesRef = useRef([]);
148
+ const modelPathRef = useRef(modelPath);
149
+ const valueRef = useRef(value);
150
+ const [monaco, setMonaco] = useState(null);
151
+ const [runtimeError, setRuntimeError] = useState();
152
+ const [position, setPosition] = useState({
153
+ lineNumber: 1,
154
+ column: 1
155
+ });
156
+ const [diagnosticCount, setDiagnosticCount] = useState(0);
157
+ const [copyState, setCopyState] = useState("idle");
158
+ const [fullscreen, setFullscreen] = useState(false);
159
+ const labels = {
160
+ ...defaultLabels,
161
+ ...labelOverrides
162
+ };
163
+ valueRef.current = value;
164
+ const synchronizeExternalValue = useCallback((editor, nextValue) => {
165
+ const model = editor.getModel();
166
+ if (!model) return;
167
+ const pending = pendingLocalValuesRef.current;
168
+ const acknowledgedIndex = pending.lastIndexOf(nextValue);
169
+ if (acknowledgedIndex >= 0) {
170
+ pending.splice(0, acknowledgedIndex + 1);
171
+ return;
172
+ }
173
+ if (model.getValue() === nextValue) return;
174
+ pending.length = 0;
175
+ const selections = editor.getSelections();
176
+ const scrollPosition = {
177
+ scrollLeft: editor.getScrollLeft(),
178
+ scrollTop: editor.getScrollTop()
179
+ };
180
+ externalValueSyncRef.current = true;
181
+ try {
182
+ editor.pushUndoStop();
183
+ if (!editor.executeEdits("alauda.react-code-editor.external-value", [{
184
+ range: model.getFullModelRange(),
185
+ text: nextValue,
186
+ forceMoveMarkers: true
187
+ }], selections ?? void 0)) model.setValue(nextValue);
188
+ editor.pushUndoStop();
189
+ if (selections) editor.setSelections(selections);
190
+ editor.setScrollPosition(scrollPosition);
191
+ } finally {
192
+ externalValueSyncRef.current = false;
193
+ }
194
+ }, []);
195
+ useEffect(() => {
196
+ let active = true;
197
+ let release;
198
+ setMonaco(null);
199
+ setRuntimeError(void 0);
200
+ loadMonacoRuntime().then((instance) => {
201
+ if (!active) return;
202
+ release = acquireModelOwnership(instance, ownerId, modelPath, language);
203
+ if (active) setMonaco(instance);
204
+ else release();
205
+ }).catch((errorValue) => {
206
+ if (active) setRuntimeError(errorValue instanceof Error ? errorValue.message : String(errorValue));
207
+ });
208
+ return () => {
209
+ active = false;
210
+ release?.();
211
+ };
212
+ }, [
213
+ language,
214
+ modelPath,
215
+ ownerId
216
+ ]);
217
+ useEffect(() => () => {
218
+ disposablesRef.current.forEach((disposable) => disposable.dispose());
219
+ disposablesRef.current = [];
220
+ editorRef.current = null;
221
+ }, []);
222
+ useEffect(() => {
223
+ if (modelPathRef.current !== modelPath) {
224
+ modelPathRef.current = modelPath;
225
+ pendingLocalValuesRef.current = [];
226
+ }
227
+ const editor = editorRef.current;
228
+ if (editor) synchronizeExternalValue(editor, value);
229
+ }, [
230
+ modelPath,
231
+ synchronizeExternalValue,
232
+ value
233
+ ]);
234
+ const find = async () => {
235
+ editorRef.current?.focus();
236
+ await editorRef.current?.getAction("actions.find")?.run();
237
+ };
238
+ const format = async () => {
239
+ editorRef.current?.focus();
240
+ await editorRef.current?.getAction("editor.action.formatDocument")?.run();
241
+ };
242
+ useImperativeHandle(ref, () => ({
243
+ focus: () => editorRef.current?.focus(),
244
+ find,
245
+ format,
246
+ undo: () => editorRef.current?.trigger("code-editor", "undo", null),
247
+ redo: () => editorRef.current?.trigger("code-editor", "redo", null),
248
+ validate: async () => diagnosticsRef.current
249
+ }));
250
+ const onMount = (editor) => {
251
+ editorRef.current = editor;
252
+ synchronizeExternalValue(editor, valueRef.current);
253
+ disposablesRef.current.forEach((disposable) => disposable.dispose());
254
+ disposablesRef.current = [editor.onDidChangeCursorPosition((event) => setPosition(event.position)), editor.onDidBlurEditorText(() => onBlur?.())];
255
+ const currentPosition = editor.getPosition();
256
+ if (currentPosition) setPosition(currentPosition);
257
+ };
258
+ const copy = async () => {
259
+ try {
260
+ await navigator.clipboard.writeText(editorRef.current?.getModel()?.getValue() ?? valueRef.current);
261
+ setCopyState("copied");
262
+ } catch {
263
+ setCopyState("failed");
264
+ }
265
+ };
266
+ const runAction = (action) => {
267
+ if (action === "find") find();
268
+ if (action === "copy") copy();
269
+ if (action === "format") format();
270
+ if (action === "undo") editorRef.current?.trigger("code-editor", "undo", null);
271
+ if (action === "redo") editorRef.current?.trigger("code-editor", "redo", null);
272
+ if (action === "fullscreen") setFullscreen((current) => !current);
273
+ };
274
+ const actionLabel = (action) => {
275
+ if (action === "copy" && copyState === "copied") return labels.copied;
276
+ if (action === "copy" && copyState === "failed") return labels.copyFailed;
277
+ if (action === "fullscreen" && fullscreen) return labels.exitFullscreen;
278
+ return labels[action];
279
+ };
280
+ if (runtimeError) return /* @__PURE__ */ jsx(Alert, {
281
+ severity: "error",
282
+ role: "alert",
283
+ children: runtimeError
284
+ });
285
+ if (!monaco) return /* @__PURE__ */ jsx(Box, {
286
+ role: "status",
287
+ "aria-label": labels.loading,
288
+ sx: {
289
+ display: "grid",
290
+ height,
291
+ minHeight: 160,
292
+ placeItems: "center"
293
+ },
294
+ children: /* @__PURE__ */ jsx(CircularProgress, { "aria-hidden": "true" })
295
+ });
296
+ return /* @__PURE__ */ jsxs(Box, {
297
+ role: "region",
298
+ "aria-label": `${ariaLabel} editor`,
299
+ sx: {
300
+ position: fullscreen ? "fixed" : "relative",
301
+ inset: fullscreen ? 0 : void 0,
302
+ zIndex: fullscreen ? theme.zIndex.modal : void 0,
303
+ display: "flex",
304
+ flexDirection: "column",
305
+ height: fullscreen ? "100dvh" : height,
306
+ minHeight: 160,
307
+ overflow: "hidden",
308
+ bgcolor: "background.paper",
309
+ border: 1,
310
+ borderColor: error ? "error.main" : "divider",
311
+ borderRadius: fullscreen ? 0 : 1
312
+ },
313
+ children: [
314
+ /* @__PURE__ */ jsxs(Box, {
315
+ sx: {
316
+ display: "flex",
317
+ alignItems: "center",
318
+ gap: 1,
319
+ minHeight: 40,
320
+ px: 1,
321
+ borderBottom: 1,
322
+ borderColor: "divider"
323
+ },
324
+ children: [
325
+ toolbarStart,
326
+ /* @__PURE__ */ jsx(Box, { sx: { flex: 1 } }),
327
+ actions.map((action) => /* @__PURE__ */ jsx(Tooltip, {
328
+ title: actionLabel(action),
329
+ children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(IconButton, {
330
+ "aria-label": actionLabel(action),
331
+ "aria-pressed": action === "fullscreen" ? fullscreen : void 0,
332
+ disabled: disabled || readOnly && [
333
+ "format",
334
+ "undo",
335
+ "redo"
336
+ ].includes(action),
337
+ size: "small",
338
+ onClick: () => runAction(action),
339
+ children: /* @__PURE__ */ jsx(ToolIcon, { path: paths[action] })
340
+ }) })
341
+ }, action)),
342
+ toolbarEnd
343
+ ]
344
+ }),
345
+ /* @__PURE__ */ jsx(Box, {
346
+ sx: {
347
+ flex: "1 1 auto",
348
+ minHeight: 0,
349
+ overflow: "hidden"
350
+ },
351
+ children: /* @__PURE__ */ jsx(Editor, {
352
+ height: "100%",
353
+ language,
354
+ path: modelPath,
355
+ theme: theme.palette.mode === "dark" ? "vs-dark" : "vs",
356
+ defaultValue: value,
357
+ keepCurrentModel: true,
358
+ onMount,
359
+ onChange: (nextValue) => {
360
+ if (externalValueSyncRef.current) return;
361
+ const normalized = nextValue ?? "";
362
+ const pending = pendingLocalValuesRef.current;
363
+ if (pending.at(-1) !== normalized) {
364
+ pending.push(normalized);
365
+ if (pending.length > 64) pending.splice(0, pending.length - 64);
366
+ }
367
+ onChange(normalized);
368
+ },
369
+ onValidate: (markers) => {
370
+ const diagnostics = mapDiagnostics(markers, monaco);
371
+ diagnosticsRef.current = diagnostics;
372
+ setDiagnosticCount(diagnostics.filter((item) => item.severity === "error").length);
373
+ onDiagnostics?.(diagnostics);
374
+ },
375
+ options: {
376
+ ariaLabel,
377
+ automaticLayout: true,
378
+ bracketPairColorization: { enabled: true },
379
+ folding: true,
380
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
381
+ fontSize: 13,
382
+ formatOnPaste: true,
383
+ insertSpaces: true,
384
+ lineHeight: 22,
385
+ minimap: { enabled: false },
386
+ padding: {
387
+ top: 12,
388
+ bottom: 12
389
+ },
390
+ readOnly: readOnly || disabled,
391
+ renderValidationDecorations: "on",
392
+ scrollBeyondLastLine: false,
393
+ tabSize: 2
394
+ }
395
+ })
396
+ }),
397
+ /* @__PURE__ */ jsxs(Box, {
398
+ "aria-live": "polite",
399
+ sx: {
400
+ display: "flex",
401
+ justifyContent: "space-between",
402
+ gap: 2,
403
+ minHeight: 28,
404
+ px: 1.5,
405
+ py: .5,
406
+ borderTop: 1,
407
+ borderColor: "divider"
408
+ },
409
+ children: [
410
+ /* @__PURE__ */ jsx(Typography, {
411
+ variant: "caption",
412
+ children: language.toUpperCase()
413
+ }),
414
+ /* @__PURE__ */ jsx(Typography, {
415
+ variant: "caption",
416
+ color: error || diagnosticCount ? "error" : "text.secondary",
417
+ children: error ?? (diagnosticCount ? labels.errors(diagnosticCount) : labels.valid)
418
+ }),
419
+ /* @__PURE__ */ jsx(Typography, {
420
+ variant: "caption",
421
+ children: labels.lineColumn(position.lineNumber, position.column)
422
+ })
423
+ ]
424
+ })
425
+ ]
426
+ });
427
+ });
428
+ //#endregion
429
+ export { getSharedRuntimeState as i, acquireModelOwnership as n, loadMonacoRuntime as r, CodeEditor as t };
430
+
431
+ //# sourceMappingURL=CodeEditor-CEfhCmSA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeEditor-CEfhCmSA.js","names":[],"sources":["../../../src/monacoEnvironment.ts","../../../src/runtime/runtimeState.ts","../../../src/runtime/loadMonaco.ts","../../../src/runtime/modelOwnership.ts","../../../src/CodeEditor.tsx"],"sourcesContent":["declare global {\n interface Window {\n MonacoEnvironment: {\n getWorker: (_moduleId: string, label: string) => Worker;\n };\n }\n}\n\nexport function configureMonacoEnvironment(): void {\n if (typeof window === 'undefined') return;\n const existing = Reflect.get(window, 'MonacoEnvironment') as\n | { readonly getWorker?: unknown }\n | undefined;\n if (typeof existing?.getWorker === 'function') return;\n\n window.MonacoEnvironment = {\n getWorker: (_moduleId, label) => {\n if (label === 'yaml') {\n return new Worker(new URL('./yaml/yaml.worker.js', import.meta.url));\n }\n if (label === 'json') {\n return new Worker(new URL(\n 'monaco-editor/esm/vs/language/json/json.worker.js',\n import.meta.url,\n ));\n }\n return new Worker(new URL(\n 'monaco-editor/esm/vs/editor/editor.worker.js',\n import.meta.url,\n ));\n },\n };\n}\n","import type * as Monaco from 'monaco-editor/esm/vs/editor/editor.main.js';\n\nexport interface SharedCodeEditorRuntimeState {\n monaco?: typeof Monaco;\n monacoPromise?: Promise<typeof Monaco>;\n models?: Map<string, unknown>;\n yaml?: unknown;\n}\n\nconst runtimeKey = Symbol.for('alauda.react-code-editor.runtime');\n\nexport function getSharedRuntimeState(): SharedCodeEditorRuntimeState {\n const target = globalThis as typeof globalThis & {\n [runtimeKey]?: SharedCodeEditorRuntimeState;\n };\n target[runtimeKey] ??= {};\n return target[runtimeKey];\n}\n","import { loader } from '@monaco-editor/react';\nimport type * as Monaco from 'monaco-editor/esm/vs/editor/editor.main.js';\n\nimport { configureMonacoEnvironment } from '../monacoEnvironment';\nimport { getSharedRuntimeState } from './runtimeState';\n\nexport function loadMonacoRuntime(): Promise<typeof Monaco> {\n const runtime = getSharedRuntimeState();\n if (runtime.monacoPromise) return runtime.monacoPromise;\n const promise = (async () => {\n configureMonacoEnvironment();\n const monaco = await import(\n 'monaco-editor/esm/vs/editor/editor.main.js'\n );\n loader.config({ monaco });\n runtime.monaco = monaco;\n return monaco;\n })();\n runtime.monacoPromise = promise;\n void promise.catch(() => {\n if (runtime.monacoPromise === promise) runtime.monacoPromise = undefined;\n });\n return promise;\n}\n","import type * as Monaco from 'monaco-editor/esm/vs/editor/editor.main.js';\n\nimport { getSharedRuntimeState } from './runtimeState';\n\ninterface ModelOwnership {\n readonly language: string;\n readonly owners: Set<string>;\n readonly uri: Monaco.Uri;\n readonly ownedByPackage: boolean;\n}\n\nfunction ownershipRegistry(): Map<string, ModelOwnership> {\n const runtime = getSharedRuntimeState();\n runtime.models ??= new Map();\n return runtime.models as Map<string, ModelOwnership>;\n}\n\nexport function acquireModelOwnership(\n monaco: typeof Monaco,\n ownerId: string,\n modelPath: string,\n language: string,\n): () => void {\n const registry = ownershipRegistry();\n const existing = registry.get(modelPath);\n if (existing && existing.language !== language) {\n throw new Error(\n `Conflicting editor languages for ${modelPath}: `\n + `${existing.language} and ${language}`,\n );\n }\n\n const ownership = existing ?? (() => {\n const uri = monaco.Uri.parse(modelPath);\n return {\n language,\n owners: new Set<string>(),\n uri,\n ownedByPackage: !monaco.editor.getModel(uri),\n } satisfies ModelOwnership;\n })();\n ownership.owners.add(ownerId);\n registry.set(modelPath, ownership);\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n ownership.owners.delete(ownerId);\n if (ownership.owners.size > 0) return;\n registry.delete(modelPath);\n if (ownership.ownedByPackage) {\n monaco.editor.getModel(ownership.uri)?.dispose();\n }\n };\n}\n","import Editor, { type OnMount } from '@monaco-editor/react';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport { useTheme } from '@mui/material/styles';\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useRef,\n useState,\n type FC,\n type ReactNode,\n} from 'react';\nimport type * as Monaco from 'monaco-editor/esm/vs/editor/editor.main.js';\n\nimport { loadMonacoRuntime } from './runtime/loadMonaco';\nimport { acquireModelOwnership } from './runtime/modelOwnership';\n\nexport type CodeEditorLanguage =\n | 'json'\n | 'markdown'\n | 'plaintext'\n | 'yaml';\n\nexport type CodeEditorAction =\n | 'copy'\n | 'find'\n | 'format'\n | 'fullscreen'\n | 'redo'\n | 'undo';\n\nexport type CodeEditorDiagnosticSeverity =\n | 'error'\n | 'warning'\n | 'info'\n | 'hint';\n\nexport interface CodeEditorDiagnostic {\n readonly severity: CodeEditorDiagnosticSeverity;\n readonly message: string;\n readonly line: number;\n readonly column: number;\n readonly endLine: number;\n readonly endColumn: number;\n readonly code?: string;\n}\n\nexport interface CodeEditorLabels {\n readonly copy: string;\n readonly copied: string;\n readonly copyFailed: string;\n readonly find: string;\n readonly format: string;\n readonly fullscreen: string;\n readonly exitFullscreen: string;\n readonly undo: string;\n readonly redo: string;\n readonly loading: string;\n readonly valid: string;\n readonly errors: (count: number) => string;\n readonly lineColumn: (line: number, column: number) => string;\n}\n\nexport interface CodeEditorHandle {\n focus(): void;\n find(): Promise<void>;\n format(): Promise<void>;\n undo(): void;\n redo(): void;\n validate(): Promise<readonly CodeEditorDiagnostic[]>;\n}\n\nexport interface CodeEditorProps {\n readonly value: string;\n readonly onChange: (value: string) => void;\n readonly onBlur?: () => void;\n readonly language: CodeEditorLanguage;\n readonly modelPath: string;\n readonly ariaLabel: string;\n readonly readOnly?: boolean;\n readonly disabled?: boolean;\n readonly height?: number | string;\n readonly actions?: readonly CodeEditorAction[];\n readonly labels?: Partial<CodeEditorLabels>;\n readonly error?: string | null;\n readonly onDiagnostics?: (\n diagnostics: readonly CodeEditorDiagnostic[],\n ) => void;\n readonly toolbarStart?: ReactNode;\n readonly toolbarEnd?: ReactNode;\n}\n\nconst defaultLabels: CodeEditorLabels = {\n copy: 'Copy',\n copied: 'Copied',\n copyFailed: 'Copy failed',\n find: 'Search',\n format: 'Format',\n fullscreen: 'Enter fullscreen',\n exitFullscreen: 'Exit fullscreen',\n undo: 'Undo',\n redo: 'Redo',\n loading: 'Loading editor',\n valid: 'Validation passed',\n errors: count => `${count} validation error${count === 1 ? '' : 's'}`,\n lineColumn: (line, column) => `Ln ${line}, Col ${column}`,\n};\n\nconst defaultActions: readonly CodeEditorAction[] = [\n 'find',\n 'copy',\n 'format',\n 'undo',\n 'redo',\n 'fullscreen',\n];\n\nconst paths = {\n copy: 'M16 1H4a2 2 0 0 0-2 2v14h2V3h12zm3 4H8a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2m0 16H8V7h11z',\n find: 'M9.5 3a6.5 6.5 0 1 0 3.98 11.64L19.85 21 21 19.85l-6.36-6.37A6.5 6.5 0 0 0 9.5 3m0 2a4.5 4.5 0 1 1 0 9 4.5 4.5 0 0 1 0-9',\n format: 'M3 5h18v2H3zm0 6h12v2H3zm0 6h18v2H3z',\n fullscreen: 'M4 4h6v2H6v4H4zm10 0h6v6h-2V6h-4zM4 14h2v4h4v2H4zm14 0h2v6h-6v-2h4z',\n redo: 'M15 6V3l5 5-5 5v-3c-4 0-7 1-9 5 1-6 4-9 9-9',\n undo: 'M9 6V3L4 8l5 5v-3c4 0 7 1 9 5-1-6-4-9-9-9',\n} satisfies Record<CodeEditorAction, string>;\n\nconst ToolIcon: FC<{ readonly path: string }> = ({ path }) => (\n <Box\n component=\"svg\"\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n sx={{ width: 20, height: 20, fill: 'currentColor' }}\n >\n <path d={path} />\n </Box>\n);\n\nfunction markerSeverity(\n marker: Monaco.editor.IMarker,\n monaco: typeof Monaco,\n): CodeEditorDiagnosticSeverity {\n if (marker.severity === monaco.MarkerSeverity.Error) return 'error';\n if (marker.severity === monaco.MarkerSeverity.Warning) return 'warning';\n if (marker.severity === monaco.MarkerSeverity.Info) return 'info';\n return 'hint';\n}\n\nfunction mapDiagnostics(\n markers: readonly Monaco.editor.IMarker[],\n monaco: typeof Monaco,\n): readonly CodeEditorDiagnostic[] {\n return markers.map(marker => ({\n severity: markerSeverity(marker, monaco),\n message: marker.message,\n line: marker.startLineNumber,\n column: marker.startColumn,\n endLine: marker.endLineNumber,\n endColumn: marker.endColumn,\n ...(marker.code === undefined ? {} : { code: String(marker.code) }),\n }));\n}\n\nexport const CodeEditor = forwardRef<CodeEditorHandle, CodeEditorProps>(\n function CodeEditor({\n value,\n onChange,\n onBlur,\n language,\n modelPath,\n ariaLabel,\n readOnly = false,\n disabled = false,\n height = 400,\n actions = defaultActions,\n labels: labelOverrides,\n error,\n onDiagnostics,\n toolbarStart,\n toolbarEnd,\n }, ref) {\n const theme = useTheme();\n const ownerId = useId();\n const editorRef = useRef<Monaco.editor.IStandaloneCodeEditor | null>(null);\n const disposablesRef = useRef<Monaco.IDisposable[]>([]);\n const diagnosticsRef = useRef<readonly CodeEditorDiagnostic[]>([]);\n const externalValueSyncRef = useRef(false);\n const pendingLocalValuesRef = useRef<string[]>([]);\n const modelPathRef = useRef(modelPath);\n const valueRef = useRef(value);\n const [monaco, setMonaco] = useState<typeof Monaco | null>(null);\n const [runtimeError, setRuntimeError] = useState<string>();\n const [position, setPosition] = useState({ lineNumber: 1, column: 1 });\n const [diagnosticCount, setDiagnosticCount] = useState(0);\n const [copyState, setCopyState] = useState<'idle' | 'copied' | 'failed'>('idle');\n const [fullscreen, setFullscreen] = useState(false);\n const labels = { ...defaultLabels, ...labelOverrides };\n valueRef.current = value;\n\n const synchronizeExternalValue = useCallback((\n editor: Monaco.editor.IStandaloneCodeEditor,\n nextValue: string,\n ): void => {\n const model = editor.getModel();\n if (!model) return;\n\n const pending = pendingLocalValuesRef.current;\n const acknowledgedIndex = pending.lastIndexOf(nextValue);\n if (acknowledgedIndex >= 0) {\n pending.splice(0, acknowledgedIndex + 1);\n return;\n }\n if (model.getValue() === nextValue) return;\n\n pending.length = 0;\n const selections = editor.getSelections();\n const scrollPosition = {\n scrollLeft: editor.getScrollLeft(),\n scrollTop: editor.getScrollTop(),\n };\n externalValueSyncRef.current = true;\n try {\n editor.pushUndoStop();\n const applied = editor.executeEdits(\n 'alauda.react-code-editor.external-value',\n [{\n range: model.getFullModelRange(),\n text: nextValue,\n forceMoveMarkers: true,\n }],\n selections ?? undefined,\n );\n if (!applied) model.setValue(nextValue);\n editor.pushUndoStop();\n if (selections) editor.setSelections(selections);\n editor.setScrollPosition(scrollPosition);\n } finally {\n externalValueSyncRef.current = false;\n }\n }, []);\n\n useEffect(() => {\n let active = true;\n let release: (() => void) | undefined;\n setMonaco(null);\n setRuntimeError(undefined);\n void loadMonacoRuntime()\n .then(instance => {\n if (!active) return;\n release = acquireModelOwnership(\n instance,\n ownerId,\n modelPath,\n language,\n );\n if (active) setMonaco(instance);\n else release();\n })\n .catch(errorValue => {\n if (active) {\n setRuntimeError(\n errorValue instanceof Error\n ? errorValue.message\n : String(errorValue),\n );\n }\n });\n return () => {\n active = false;\n release?.();\n };\n }, [language, modelPath, ownerId]);\n\n useEffect(() => () => {\n disposablesRef.current.forEach(disposable => disposable.dispose());\n disposablesRef.current = [];\n editorRef.current = null;\n }, []);\n\n useEffect(() => {\n if (modelPathRef.current !== modelPath) {\n modelPathRef.current = modelPath;\n pendingLocalValuesRef.current = [];\n }\n const editor = editorRef.current;\n if (editor) synchronizeExternalValue(editor, value);\n }, [modelPath, synchronizeExternalValue, value]);\n\n const find = async (): Promise<void> => {\n editorRef.current?.focus();\n await editorRef.current?.getAction('actions.find')?.run();\n };\n const format = async (): Promise<void> => {\n editorRef.current?.focus();\n await editorRef.current?.getAction('editor.action.formatDocument')?.run();\n };\n\n useImperativeHandle(ref, () => ({\n focus: () => editorRef.current?.focus(),\n find,\n format,\n undo: () => editorRef.current?.trigger('code-editor', 'undo', null),\n redo: () => editorRef.current?.trigger('code-editor', 'redo', null),\n validate: async () => diagnosticsRef.current,\n }));\n\n const onMount: OnMount = editor => {\n editorRef.current = editor;\n synchronizeExternalValue(editor, valueRef.current);\n disposablesRef.current.forEach(disposable => disposable.dispose());\n disposablesRef.current = [\n editor.onDidChangeCursorPosition(event => setPosition(event.position)),\n editor.onDidBlurEditorText(() => onBlur?.()),\n ];\n const currentPosition = editor.getPosition();\n if (currentPosition) setPosition(currentPosition);\n };\n\n const copy = async (): Promise<void> => {\n try {\n await navigator.clipboard.writeText(\n editorRef.current?.getModel()?.getValue() ?? valueRef.current,\n );\n setCopyState('copied');\n } catch {\n setCopyState('failed');\n }\n };\n\n const runAction = (action: CodeEditorAction): void => {\n if (action === 'find') void find();\n if (action === 'copy') void copy();\n if (action === 'format') void format();\n if (action === 'undo') {\n editorRef.current?.trigger('code-editor', 'undo', null);\n }\n if (action === 'redo') {\n editorRef.current?.trigger('code-editor', 'redo', null);\n }\n if (action === 'fullscreen') setFullscreen(current => !current);\n };\n\n const actionLabel = (action: CodeEditorAction): string => {\n if (action === 'copy' && copyState === 'copied') return labels.copied;\n if (action === 'copy' && copyState === 'failed') return labels.copyFailed;\n if (action === 'fullscreen' && fullscreen) return labels.exitFullscreen;\n return labels[action];\n };\n\n if (runtimeError) {\n return <Alert severity=\"error\" role=\"alert\">{runtimeError}</Alert>;\n }\n\n if (!monaco) {\n return (\n <Box\n role=\"status\"\n aria-label={labels.loading}\n sx={{ display: 'grid', height, minHeight: 160, placeItems: 'center' }}\n >\n <CircularProgress aria-hidden=\"true\" />\n </Box>\n );\n }\n\n return (\n <Box\n role=\"region\"\n aria-label={`${ariaLabel} editor`}\n sx={{\n position: fullscreen ? 'fixed' : 'relative',\n inset: fullscreen ? 0 : undefined,\n zIndex: fullscreen ? theme.zIndex.modal : undefined,\n display: 'flex',\n flexDirection: 'column',\n height: fullscreen ? '100dvh' : height,\n minHeight: 160,\n overflow: 'hidden',\n bgcolor: 'background.paper',\n border: 1,\n borderColor: error ? 'error.main' : 'divider',\n borderRadius: fullscreen ? 0 : 1,\n }}\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n minHeight: 40,\n px: 1,\n borderBottom: 1,\n borderColor: 'divider',\n }}\n >\n {toolbarStart}\n <Box sx={{ flex: 1 }} />\n {actions.map(action => (\n <Tooltip key={action} title={actionLabel(action)}>\n <span>\n <IconButton\n aria-label={actionLabel(action)}\n aria-pressed={action === 'fullscreen' ? fullscreen : undefined}\n disabled={disabled || (\n readOnly && ['format', 'undo', 'redo'].includes(action)\n )}\n size=\"small\"\n onClick={() => runAction(action)}\n >\n <ToolIcon path={paths[action]} />\n </IconButton>\n </span>\n </Tooltip>\n ))}\n {toolbarEnd}\n </Box>\n <Box sx={{ flex: '1 1 auto', minHeight: 0, overflow: 'hidden' }}>\n <Editor\n height=\"100%\"\n language={language}\n path={modelPath}\n theme={theme.palette.mode === 'dark' ? 'vs-dark' : 'vs'}\n defaultValue={value}\n keepCurrentModel\n onMount={onMount}\n onChange={nextValue => {\n if (externalValueSyncRef.current) return;\n const normalized = nextValue ?? '';\n const pending = pendingLocalValuesRef.current;\n if (pending.at(-1) !== normalized) {\n pending.push(normalized);\n if (pending.length > 64) {\n pending.splice(0, pending.length - 64);\n }\n }\n onChange(normalized);\n }}\n onValidate={markers => {\n const diagnostics = mapDiagnostics(markers, monaco);\n diagnosticsRef.current = diagnostics;\n setDiagnosticCount(diagnostics.filter(item => (\n item.severity === 'error'\n )).length);\n onDiagnostics?.(diagnostics);\n }}\n options={{\n ariaLabel,\n automaticLayout: true,\n bracketPairColorization: { enabled: true },\n folding: true,\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',\n fontSize: 13,\n formatOnPaste: true,\n insertSpaces: true,\n lineHeight: 22,\n minimap: { enabled: false },\n padding: { top: 12, bottom: 12 },\n readOnly: readOnly || disabled,\n renderValidationDecorations: 'on',\n scrollBeyondLastLine: false,\n tabSize: 2,\n }}\n />\n </Box>\n <Box\n aria-live=\"polite\"\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n gap: 2,\n minHeight: 28,\n px: 1.5,\n py: 0.5,\n borderTop: 1,\n borderColor: 'divider',\n }}\n >\n <Typography variant=\"caption\">{language.toUpperCase()}</Typography>\n <Typography\n variant=\"caption\"\n color={error || diagnosticCount ? 'error' : 'text.secondary'}\n >\n {error ?? (\n diagnosticCount ? labels.errors(diagnosticCount) : labels.valid\n )}\n </Typography>\n <Typography variant=\"caption\">\n {labels.lineColumn(position.lineNumber, position.column)}\n </Typography>\n </Box>\n </Box>\n );\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import "monaco-yaml/yaml.worker";
package/index.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ import { ForwardRefExoticComponent } from 'react';
2
+ import { JSX } from 'react';
3
+ import { ReactNode } from 'react';
4
+ import { RefAttributes } from 'react';
5
+
6
+ export declare const CodeEditor: ForwardRefExoticComponent<CodeEditorProps & RefAttributes<CodeEditorHandle>>;
7
+
8
+ export declare type CodeEditorAction = 'copy' | 'find' | 'format' | 'fullscreen' | 'redo' | 'undo';
9
+
10
+ export declare interface CodeEditorDiagnostic {
11
+ readonly severity: CodeEditorDiagnosticSeverity;
12
+ readonly message: string;
13
+ readonly line: number;
14
+ readonly column: number;
15
+ readonly endLine: number;
16
+ readonly endColumn: number;
17
+ readonly code?: string;
18
+ }
19
+
20
+ export declare type CodeEditorDiagnosticSeverity = 'error' | 'warning' | 'info' | 'hint';
21
+
22
+ export declare interface CodeEditorHandle {
23
+ focus(): void;
24
+ find(): Promise<void>;
25
+ format(): Promise<void>;
26
+ undo(): void;
27
+ redo(): void;
28
+ validate(): Promise<readonly CodeEditorDiagnostic[]>;
29
+ }
30
+
31
+ export declare interface CodeEditorLabels {
32
+ readonly copy: string;
33
+ readonly copied: string;
34
+ readonly copyFailed: string;
35
+ readonly find: string;
36
+ readonly format: string;
37
+ readonly fullscreen: string;
38
+ readonly exitFullscreen: string;
39
+ readonly undo: string;
40
+ readonly redo: string;
41
+ readonly loading: string;
42
+ readonly valid: string;
43
+ readonly errors: (count: number) => string;
44
+ readonly lineColumn: (line: number, column: number) => string;
45
+ }
46
+
47
+ export declare type CodeEditorLanguage = 'json' | 'markdown' | 'plaintext' | 'yaml';
48
+
49
+ export declare interface CodeEditorProps {
50
+ readonly value: string;
51
+ readonly onChange: (value: string) => void;
52
+ readonly onBlur?: () => void;
53
+ readonly language: CodeEditorLanguage;
54
+ readonly modelPath: string;
55
+ readonly ariaLabel: string;
56
+ readonly readOnly?: boolean;
57
+ readonly disabled?: boolean;
58
+ readonly height?: number | string;
59
+ readonly actions?: readonly CodeEditorAction[];
60
+ readonly labels?: Partial<CodeEditorLabels>;
61
+ readonly error?: string | null;
62
+ readonly onDiagnostics?: (diagnostics: readonly CodeEditorDiagnostic[]) => void;
63
+ readonly toolbarStart?: ReactNode;
64
+ readonly toolbarEnd?: ReactNode;
65
+ }
66
+
67
+ export declare function DiffCodeEditor({ originalValue, value, onChange, language, originalModelPath, modelPath, ariaLabel, readOnly, height, }: DiffCodeEditorProps): JSX.Element;
68
+
69
+ export declare interface DiffCodeEditorProps {
70
+ readonly originalValue: string;
71
+ readonly value: string;
72
+ readonly onChange?: (value: string) => void;
73
+ readonly language: CodeEditorLanguage;
74
+ readonly originalModelPath: string;
75
+ readonly modelPath: string;
76
+ readonly ariaLabel: string;
77
+ readonly readOnly?: boolean;
78
+ readonly height?: number | string;
79
+ }
80
+
81
+ export { }
package/index.js ADDED
@@ -0,0 +1,103 @@
1
+ import { n as acquireModelOwnership, r as loadMonacoRuntime, t as CodeEditor } from "./chunks/CodeEditor-CEfhCmSA.js";
2
+ import { DiffEditor } from "@monaco-editor/react";
3
+ import Alert from "@mui/material/Alert";
4
+ import Box from "@mui/material/Box";
5
+ import CircularProgress from "@mui/material/CircularProgress";
6
+ import { useTheme } from "@mui/material/styles";
7
+ import { useEffect, useId, useRef, useState } from "react";
8
+ import { jsx } from "react/jsx-runtime";
9
+ //#region src/DiffCodeEditor.tsx
10
+ function DiffCodeEditor({ originalValue, value, onChange, language, originalModelPath, modelPath, ariaLabel, readOnly = false, height = 400 }) {
11
+ const theme = useTheme();
12
+ const ownerId = useId();
13
+ const contentListenerRef = useRef(null);
14
+ const valueRef = useRef(value);
15
+ const [ready, setReady] = useState(false);
16
+ const [runtimeError, setRuntimeError] = useState();
17
+ valueRef.current = value;
18
+ useEffect(() => {
19
+ let active = true;
20
+ const releases = [];
21
+ setReady(false);
22
+ setRuntimeError(void 0);
23
+ loadMonacoRuntime().then((monaco) => {
24
+ if (!active) return;
25
+ if (originalModelPath === modelPath) throw new Error("Diff editor model paths must be different");
26
+ releases.push(acquireModelOwnership(monaco, `${ownerId}:original`, originalModelPath, language));
27
+ releases.push(acquireModelOwnership(monaco, `${ownerId}:modified`, modelPath, language));
28
+ if (active) setReady(true);
29
+ else releases.splice(0).reverse().forEach((release) => release());
30
+ }).catch((errorValue) => {
31
+ releases.splice(0).reverse().forEach((release) => release());
32
+ if (active) setRuntimeError(errorValue instanceof Error ? errorValue.message : String(errorValue));
33
+ });
34
+ return () => {
35
+ active = false;
36
+ contentListenerRef.current?.dispose();
37
+ contentListenerRef.current = null;
38
+ releases.splice(0).reverse().forEach((release) => release());
39
+ };
40
+ }, [
41
+ language,
42
+ modelPath,
43
+ originalModelPath,
44
+ ownerId
45
+ ]);
46
+ if (runtimeError) return /* @__PURE__ */ jsx(Alert, {
47
+ severity: "error",
48
+ role: "alert",
49
+ children: runtimeError
50
+ });
51
+ if (!ready) return /* @__PURE__ */ jsx(Box, {
52
+ role: "status",
53
+ "aria-label": `Loading ${ariaLabel}`,
54
+ sx: {
55
+ display: "grid",
56
+ height,
57
+ minHeight: 160,
58
+ placeItems: "center"
59
+ },
60
+ children: /* @__PURE__ */ jsx(CircularProgress, { "aria-hidden": "true" })
61
+ });
62
+ return /* @__PURE__ */ jsx(Box, {
63
+ role: "region",
64
+ "aria-label": ariaLabel,
65
+ sx: {
66
+ height,
67
+ minHeight: 160,
68
+ overflow: "hidden"
69
+ },
70
+ children: /* @__PURE__ */ jsx(DiffEditor, {
71
+ height: "100%",
72
+ language,
73
+ original: originalValue,
74
+ modified: value,
75
+ originalModelPath,
76
+ modifiedModelPath: modelPath,
77
+ theme: theme.palette.mode === "dark" ? "vs-dark" : "vs",
78
+ keepCurrentOriginalModel: true,
79
+ keepCurrentModifiedModel: true,
80
+ onMount: (editor) => {
81
+ contentListenerRef.current?.dispose();
82
+ const modifiedEditor = editor.getModifiedEditor();
83
+ contentListenerRef.current = modifiedEditor.onDidChangeModelContent(() => {
84
+ const nextValue = modifiedEditor.getValue();
85
+ if (nextValue !== valueRef.current) onChange?.(nextValue);
86
+ });
87
+ },
88
+ options: {
89
+ ariaLabel,
90
+ automaticLayout: true,
91
+ minimap: { enabled: false },
92
+ originalEditable: false,
93
+ readOnly,
94
+ renderSideBySide: true,
95
+ scrollBeyondLastLine: false
96
+ }
97
+ })
98
+ });
99
+ }
100
+ //#endregion
101
+ export { CodeEditor, DiffCodeEditor };
102
+
103
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/DiffCodeEditor.tsx"],"sourcesContent":["import { DiffEditor } from '@monaco-editor/react';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport { useTheme } from '@mui/material/styles';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport type * as Monaco from 'monaco-editor/esm/vs/editor/editor.main.js';\n\nimport type { CodeEditorLanguage } from './CodeEditor';\nimport { loadMonacoRuntime } from './runtime/loadMonaco';\nimport { acquireModelOwnership } from './runtime/modelOwnership';\n\nexport interface DiffCodeEditorProps {\n readonly originalValue: string;\n readonly value: string;\n readonly onChange?: (value: string) => void;\n readonly language: CodeEditorLanguage;\n readonly originalModelPath: string;\n readonly modelPath: string;\n readonly ariaLabel: string;\n readonly readOnly?: boolean;\n readonly height?: number | string;\n}\n\nexport function DiffCodeEditor({\n originalValue,\n value,\n onChange,\n language,\n originalModelPath,\n modelPath,\n ariaLabel,\n readOnly = false,\n height = 400,\n}: DiffCodeEditorProps) {\n const theme = useTheme();\n const ownerId = useId();\n const contentListenerRef = useRef<Monaco.IDisposable | null>(null);\n const valueRef = useRef(value);\n const [ready, setReady] = useState(false);\n const [runtimeError, setRuntimeError] = useState<string>();\n valueRef.current = value;\n\n useEffect(() => {\n let active = true;\n const releases: Array<() => void> = [];\n setReady(false);\n setRuntimeError(undefined);\n void loadMonacoRuntime()\n .then(monaco => {\n if (!active) return;\n if (originalModelPath === modelPath) {\n throw new Error('Diff editor model paths must be different');\n }\n releases.push(acquireModelOwnership(\n monaco,\n `${ownerId}:original`,\n originalModelPath,\n language,\n ));\n releases.push(acquireModelOwnership(\n monaco,\n `${ownerId}:modified`,\n modelPath,\n language,\n ));\n if (active) setReady(true);\n else releases.splice(0).reverse().forEach(release => release());\n })\n .catch(errorValue => {\n releases.splice(0).reverse().forEach(release => release());\n if (active) {\n setRuntimeError(\n errorValue instanceof Error\n ? errorValue.message\n : String(errorValue),\n );\n }\n });\n return () => {\n active = false;\n contentListenerRef.current?.dispose();\n contentListenerRef.current = null;\n releases.splice(0).reverse().forEach(release => release());\n };\n }, [language, modelPath, originalModelPath, ownerId]);\n\n if (runtimeError) {\n return <Alert severity=\"error\" role=\"alert\">{runtimeError}</Alert>;\n }\n\n if (!ready) {\n return (\n <Box\n role=\"status\"\n aria-label={`Loading ${ariaLabel}`}\n sx={{ display: 'grid', height, minHeight: 160, placeItems: 'center' }}\n >\n <CircularProgress aria-hidden=\"true\" />\n </Box>\n );\n }\n\n return (\n <Box\n role=\"region\"\n aria-label={ariaLabel}\n sx={{ height, minHeight: 160, overflow: 'hidden' }}\n >\n <DiffEditor\n height=\"100%\"\n language={language}\n original={originalValue}\n modified={value}\n originalModelPath={originalModelPath}\n modifiedModelPath={modelPath}\n theme={theme.palette.mode === 'dark' ? 'vs-dark' : 'vs'}\n keepCurrentOriginalModel\n keepCurrentModifiedModel\n onMount={editor => {\n contentListenerRef.current?.dispose();\n const modifiedEditor = editor.getModifiedEditor();\n contentListenerRef.current = modifiedEditor\n .onDidChangeModelContent(() => {\n const nextValue = modifiedEditor.getValue();\n if (nextValue !== valueRef.current) onChange?.(nextValue);\n });\n }}\n options={{\n ariaLabel,\n automaticLayout: true,\n minimap: { enabled: false },\n originalEditable: false,\n readOnly,\n renderSideBySide: true,\n scrollBeyondLastLine: false,\n }}\n />\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAgB,eAAe,EAC7B,eACA,OACA,UACA,UACA,mBACA,WACA,WACA,WAAW,OACX,SAAS,OACa;CACtB,MAAM,QAAQ,SAAS;CACvB,MAAM,UAAU,MAAM;CACtB,MAAM,qBAAqB,OAAkC,IAAI;CACjE,MAAM,WAAW,OAAO,KAAK;CAC7B,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CACxC,MAAM,CAAC,cAAc,mBAAmB,SAAiB;CACzD,SAAS,UAAU;CAEnB,gBAAgB;EACd,IAAI,SAAS;EACb,MAAM,WAA8B,CAAC;EACrC,SAAS,KAAK;EACd,gBAAgB,KAAA,CAAS;EACzB,kBAAuB,CAAC,CACrB,MAAK,WAAU;GACd,IAAI,CAAC,QAAQ;GACb,IAAI,sBAAsB,WACxB,MAAM,IAAI,MAAM,2CAA2C;GAE7D,SAAS,KAAK,sBACZ,QACA,GAAG,QAAQ,YACX,mBACA,QACF,CAAC;GACD,SAAS,KAAK,sBACZ,QACA,GAAG,QAAQ,YACX,WACA,QACF,CAAC;GACD,IAAI,QAAQ,SAAS,IAAI;QACpB,SAAS,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAQ,YAAW,QAAQ,CAAC;EAChE,CAAC,CAAC,CACD,OAAM,eAAc;GACnB,SAAS,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAQ,YAAW,QAAQ,CAAC;GACzD,IAAI,QACF,gBACE,sBAAsB,QAClB,WAAW,UACX,OAAO,UAAU,CACvB;EAEJ,CAAC;EACH,aAAa;GACX,SAAS;GACT,mBAAmB,SAAS,QAAQ;GACpC,mBAAmB,UAAU;GAC7B,SAAS,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAQ,YAAW,QAAQ,CAAC;EAC3D;CACF,GAAG;EAAC;EAAU;EAAW;EAAmB;CAAO,CAAC;CAEpD,IAAI,cACF,OAAO,oBAAC,OAAD;EAAO,UAAS;EAAQ,MAAK;YAAS;CAAoB,CAAA;CAGnE,IAAI,CAAC,OACH,OACE,oBAAC,KAAD;EACE,MAAK;EACL,cAAY,WAAW;EACvB,IAAI;GAAE,SAAS;GAAQ;GAAQ,WAAW;GAAK,YAAY;EAAS;YAEpE,oBAAC,kBAAD,EAAkB,eAAY,OAAQ,CAAA;CACnC,CAAA;CAIT,OACE,oBAAC,KAAD;EACE,MAAK;EACL,cAAY;EACZ,IAAI;GAAE;GAAQ,WAAW;GAAK,UAAU;EAAS;YAEjD,oBAAC,YAAD;GACE,QAAO;GACG;GACV,UAAU;GACV,UAAU;GACS;GACnB,mBAAmB;GACnB,OAAO,MAAM,QAAQ,SAAS,SAAS,YAAY;GACnD,0BAAA;GACA,0BAAA;GACA,UAAS,WAAU;IACjB,mBAAmB,SAAS,QAAQ;IACpC,MAAM,iBAAiB,OAAO,kBAAkB;IAChD,mBAAmB,UAAU,eAC1B,8BAA8B;KAC7B,MAAM,YAAY,eAAe,SAAS;KAC1C,IAAI,cAAc,SAAS,SAAS,WAAW,SAAS;IAC1D,CAAC;GACL;GACA,SAAS;IACP;IACA,iBAAiB;IACjB,SAAS,EAAE,SAAS,MAAM;IAC1B,kBAAkB;IAClB;IACA,kBAAkB;IAClB,sBAAsB;GACxB;EACD,CAAA;CACE,CAAA;AAET"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@alauda/react-code-editor",
3
+ "version": "0.1.0-next.20260812.1786527360",
4
+ "description": "React Monaco code editor with schema-aware YAML support.",
5
+ "type": "module",
6
+ "main": "./index.js",
7
+ "module": "./index.js",
8
+ "types": "./index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./index.d.ts",
12
+ "import": "./index.js",
13
+ "default": "./index.js"
14
+ },
15
+ "./yaml": {
16
+ "types": "./yaml/index.d.ts",
17
+ "import": "./yaml/index.js",
18
+ "default": "./yaml/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "index.js",
23
+ "index.js.map",
24
+ "index.d.ts",
25
+ "yaml/index.js",
26
+ "yaml/index.js.map",
27
+ "yaml/index.d.ts",
28
+ "chunks",
29
+ "README.md"
30
+ ],
31
+ "dependencies": {
32
+ "@monaco-editor/react": "^4.7.0",
33
+ "monaco-editor": "^0.54.0",
34
+ "monaco-yaml": "^5.5.1"
35
+ },
36
+ "peerDependencies": {
37
+ "@emotion/react": "^11.0.0",
38
+ "@emotion/styled": "^11.0.0",
39
+ "@mui/material": "^9.2.0",
40
+ "react": "^18.0.0 || ^19.0.0",
41
+ "react-dom": "^18.0.0 || ^19.0.0"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
46
+ }
@@ -0,0 +1,87 @@
1
+ import { ForwardRefExoticComponent } from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { RefAttributes } from 'react';
4
+
5
+ declare type CodeEditorAction = 'copy' | 'find' | 'format' | 'fullscreen' | 'redo' | 'undo';
6
+
7
+ declare interface CodeEditorDiagnostic {
8
+ readonly severity: CodeEditorDiagnosticSeverity;
9
+ readonly message: string;
10
+ readonly line: number;
11
+ readonly column: number;
12
+ readonly endLine: number;
13
+ readonly endColumn: number;
14
+ readonly code?: string;
15
+ }
16
+
17
+ declare type CodeEditorDiagnosticSeverity = 'error' | 'warning' | 'info' | 'hint';
18
+
19
+ declare interface CodeEditorHandle {
20
+ focus(): void;
21
+ find(): Promise<void>;
22
+ format(): Promise<void>;
23
+ undo(): void;
24
+ redo(): void;
25
+ validate(): Promise<readonly CodeEditorDiagnostic[]>;
26
+ }
27
+
28
+ export declare type CodeEditorJsonSchema = {
29
+ readonly [key: string]: JsonValue;
30
+ };
31
+
32
+ declare interface CodeEditorLabels {
33
+ readonly copy: string;
34
+ readonly copied: string;
35
+ readonly copyFailed: string;
36
+ readonly find: string;
37
+ readonly format: string;
38
+ readonly fullscreen: string;
39
+ readonly exitFullscreen: string;
40
+ readonly undo: string;
41
+ readonly redo: string;
42
+ readonly loading: string;
43
+ readonly valid: string;
44
+ readonly errors: (count: number) => string;
45
+ readonly lineColumn: (line: number, column: number) => string;
46
+ }
47
+
48
+ declare type CodeEditorLanguage = 'json' | 'markdown' | 'plaintext' | 'yaml';
49
+
50
+ declare interface CodeEditorProps {
51
+ readonly value: string;
52
+ readonly onChange: (value: string) => void;
53
+ readonly onBlur?: () => void;
54
+ readonly language: CodeEditorLanguage;
55
+ readonly modelPath: string;
56
+ readonly ariaLabel: string;
57
+ readonly readOnly?: boolean;
58
+ readonly disabled?: boolean;
59
+ readonly height?: number | string;
60
+ readonly actions?: readonly CodeEditorAction[];
61
+ readonly labels?: Partial<CodeEditorLabels>;
62
+ readonly error?: string | null;
63
+ readonly onDiagnostics?: (diagnostics: readonly CodeEditorDiagnostic[]) => void;
64
+ readonly toolbarStart?: ReactNode;
65
+ readonly toolbarEnd?: ReactNode;
66
+ }
67
+
68
+ export declare type JsonPrimitive = boolean | number | string | null;
69
+
70
+ export declare type JsonValue = JsonPrimitive | readonly JsonValue[] | {
71
+ readonly [key: string]: JsonValue;
72
+ };
73
+
74
+ export declare const ResourceYamlEditor: ForwardRefExoticComponent<ResourceYamlEditorProps & RefAttributes<CodeEditorHandle>>;
75
+
76
+ export declare interface ResourceYamlEditorProps extends Omit<CodeEditorProps, 'language'> {
77
+ readonly schemas?: readonly YamlSchemaRegistration[];
78
+ readonly isKubernetes?: boolean;
79
+ }
80
+
81
+ export declare interface YamlSchemaRegistration {
82
+ readonly id: string;
83
+ readonly modelPath: string;
84
+ readonly schema: CodeEditorJsonSchema;
85
+ }
86
+
87
+ export { }
package/yaml/index.js ADDED
@@ -0,0 +1,158 @@
1
+ import { i as getSharedRuntimeState, r as loadMonacoRuntime, t as CodeEditor } from "../chunks/CodeEditor-CEfhCmSA.js";
2
+ import Alert from "@mui/material/Alert";
3
+ import Box from "@mui/material/Box";
4
+ import CircularProgress from "@mui/material/CircularProgress";
5
+ import { forwardRef, useEffect, useId, useRef, useState } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region src/yaml/yamlRuntime.ts
8
+ function getYamlRuntime() {
9
+ const runtime = getSharedRuntimeState();
10
+ runtime.yaml ??= { owners: /* @__PURE__ */ new Map() };
11
+ return runtime.yaml;
12
+ }
13
+ function yamlOptions(owners) {
14
+ const registrations = [...owners];
15
+ const schemas = /* @__PURE__ */ new Map();
16
+ for (const registration of registrations) for (const schema of registration.schemas) {
17
+ const key = `${schema.id}\u0000${schema.modelPath}`;
18
+ schemas.set(key, {
19
+ uri: `alauda://schemas/${encodeURIComponent(schema.id)}`,
20
+ fileMatch: [schema.modelPath],
21
+ schema: schema.schema
22
+ });
23
+ }
24
+ return {
25
+ completion: true,
26
+ enableSchemaRequest: false,
27
+ format: {
28
+ enable: true,
29
+ printWidth: 120
30
+ },
31
+ hover: true,
32
+ isKubernetes: registrations.some((item) => item.isKubernetes),
33
+ validate: true,
34
+ yamlVersion: "1.2",
35
+ schemas: [...schemas.values()]
36
+ };
37
+ }
38
+ async function updateYamlRuntime() {
39
+ const runtime = getYamlRuntime();
40
+ runtime.updatePromise = (runtime.updatePromise ?? Promise.resolve()).catch(() => void 0).then(async () => {
41
+ await runtime.controller?.update(yamlOptions(runtime.owners.values()));
42
+ });
43
+ await runtime.updatePromise;
44
+ }
45
+ function ensureYamlRuntime(monaco) {
46
+ const runtime = getYamlRuntime();
47
+ if (runtime.promise) return runtime.promise;
48
+ const promise = import("monaco-yaml").then(({ configureMonacoYaml }) => {
49
+ runtime.controller = configureMonacoYaml(monaco, yamlOptions(runtime.owners.values()));
50
+ });
51
+ runtime.promise = promise;
52
+ promise.catch(() => {
53
+ if (runtime.promise === promise) runtime.promise = void 0;
54
+ });
55
+ return promise;
56
+ }
57
+ function schemaSignature(schemas) {
58
+ return JSON.stringify(schemas.map((schema) => ({
59
+ id: schema.id,
60
+ modelPath: schema.modelPath,
61
+ schema: schema.schema
62
+ })));
63
+ }
64
+ async function registerYamlOwner(ownerId, registration) {
65
+ const runtime = getYamlRuntime();
66
+ if ([...runtime.owners.entries()].find(([otherOwner, item]) => otherOwner !== ownerId && item.modelPath === registration.modelPath && schemaSignature(item.schemas) !== schemaSignature(registration.schemas))) throw new Error(`Conflicting YAML schema ownership for ${registration.modelPath}`);
67
+ runtime.owners.set(ownerId, registration);
68
+ try {
69
+ await updateYamlRuntime();
70
+ } catch (error) {
71
+ runtime.owners.delete(ownerId);
72
+ updateYamlRuntime();
73
+ throw error;
74
+ }
75
+ let active = true;
76
+ return () => {
77
+ if (!active) return;
78
+ active = false;
79
+ runtime.owners.delete(ownerId);
80
+ updateYamlRuntime();
81
+ };
82
+ }
83
+ //#endregion
84
+ //#region src/yaml/ResourceYamlEditor.tsx
85
+ const emptySchemas = [];
86
+ const ResourceYamlEditor = forwardRef(function ResourceYamlEditor({ schemas = emptySchemas, isKubernetes = false, modelPath, height = 400, ...props }, ref) {
87
+ const ownerId = useId();
88
+ const schemaKey = JSON.stringify(schemas);
89
+ const schemasRef = useRef({
90
+ key: schemaKey,
91
+ value: schemas
92
+ });
93
+ if (schemasRef.current.key !== schemaKey) schemasRef.current = {
94
+ key: schemaKey,
95
+ value: schemas
96
+ };
97
+ const stableSchemas = schemasRef.current.value;
98
+ const [ready, setReady] = useState(false);
99
+ const [runtimeError, setRuntimeError] = useState();
100
+ useEffect(() => {
101
+ let active = true;
102
+ let release;
103
+ loadMonacoRuntime().then(async (monaco) => {
104
+ await ensureYamlRuntime(monaco);
105
+ if (!active) return;
106
+ release = await registerYamlOwner(ownerId, {
107
+ modelPath,
108
+ schemas: stableSchemas,
109
+ isKubernetes
110
+ });
111
+ if (active) {
112
+ setRuntimeError(void 0);
113
+ setReady(true);
114
+ } else release();
115
+ }).catch((error) => {
116
+ if (active) {
117
+ setReady(false);
118
+ setRuntimeError(error instanceof Error ? error.message : String(error));
119
+ }
120
+ });
121
+ return () => {
122
+ active = false;
123
+ release?.();
124
+ };
125
+ }, [
126
+ isKubernetes,
127
+ modelPath,
128
+ ownerId,
129
+ stableSchemas
130
+ ]);
131
+ if (runtimeError) return /* @__PURE__ */ jsx(Alert, {
132
+ severity: "error",
133
+ role: "alert",
134
+ children: runtimeError
135
+ });
136
+ if (!ready) return /* @__PURE__ */ jsx(Box, {
137
+ role: "status",
138
+ "aria-label": "Loading YAML editor",
139
+ sx: {
140
+ display: "grid",
141
+ height,
142
+ minHeight: 160,
143
+ placeItems: "center"
144
+ },
145
+ children: /* @__PURE__ */ jsx(CircularProgress, { "aria-hidden": "true" })
146
+ });
147
+ return /* @__PURE__ */ jsx(CodeEditor, {
148
+ ...props,
149
+ ref,
150
+ height,
151
+ language: "yaml",
152
+ modelPath
153
+ });
154
+ });
155
+ //#endregion
156
+ export { ResourceYamlEditor };
157
+
158
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/yaml/yamlRuntime.ts","../../../src/yaml/ResourceYamlEditor.tsx"],"sourcesContent":["import type * as Monaco from 'monaco-editor/esm/vs/editor/editor.main.js';\nimport type {\n MonacoYaml,\n MonacoYamlOptions,\n} from 'monaco-yaml';\n\nimport { getSharedRuntimeState } from '../runtime/runtimeState';\nimport type { YamlSchemaRegistration } from './types';\n\ninterface YamlOwnerRegistration {\n readonly modelPath: string;\n readonly schemas: readonly YamlSchemaRegistration[];\n readonly isKubernetes: boolean;\n}\n\ninterface SharedYamlRuntime {\n controller?: MonacoYaml;\n promise?: Promise<void>;\n updatePromise?: Promise<void>;\n readonly owners: Map<string, YamlOwnerRegistration>;\n}\n\nfunction getYamlRuntime(): SharedYamlRuntime {\n const runtime = getSharedRuntimeState();\n runtime.yaml ??= { owners: new Map() } satisfies SharedYamlRuntime;\n return runtime.yaml as SharedYamlRuntime;\n}\n\nfunction yamlOptions(\n owners: Iterable<YamlOwnerRegistration>,\n): MonacoYamlOptions {\n const registrations = [...owners];\n const schemas = new Map<string, {\n uri: string;\n fileMatch: string[];\n schema: import('monaco-yaml').JSONSchema;\n }>();\n for (const registration of registrations) {\n for (const schema of registration.schemas) {\n const key = `${schema.id}\\u0000${schema.modelPath}`;\n schemas.set(key, {\n uri: `alauda://schemas/${encodeURIComponent(schema.id)}`,\n fileMatch: [schema.modelPath],\n schema: schema.schema as import('monaco-yaml').JSONSchema,\n });\n }\n }\n return {\n completion: true,\n enableSchemaRequest: false,\n format: { enable: true, printWidth: 120 },\n hover: true,\n isKubernetes: registrations.some(item => item.isKubernetes),\n validate: true,\n yamlVersion: '1.2',\n schemas: [...schemas.values()],\n };\n}\n\nasync function updateYamlRuntime(): Promise<void> {\n const runtime = getYamlRuntime();\n runtime.updatePromise = (runtime.updatePromise ?? Promise.resolve())\n .catch(() => undefined)\n .then(async () => {\n await runtime.controller?.update(yamlOptions(runtime.owners.values()));\n });\n await runtime.updatePromise;\n}\n\nexport function ensureYamlRuntime(monaco: typeof Monaco): Promise<void> {\n const runtime = getYamlRuntime();\n if (runtime.promise) return runtime.promise;\n const promise = import('monaco-yaml').then(({ configureMonacoYaml }) => {\n runtime.controller = configureMonacoYaml(\n monaco,\n yamlOptions(runtime.owners.values()),\n );\n });\n runtime.promise = promise;\n void promise.catch(() => {\n if (runtime.promise === promise) runtime.promise = undefined;\n });\n return promise;\n}\n\nfunction schemaSignature(\n schemas: readonly YamlSchemaRegistration[],\n): string {\n return JSON.stringify(schemas.map(schema => ({\n id: schema.id,\n modelPath: schema.modelPath,\n schema: schema.schema,\n })));\n}\n\nexport async function registerYamlOwner(\n ownerId: string,\n registration: YamlOwnerRegistration,\n): Promise<() => void> {\n const runtime = getYamlRuntime();\n const conflict = [...runtime.owners.entries()].find(([otherOwner, item]) => (\n otherOwner !== ownerId\n && item.modelPath === registration.modelPath\n && schemaSignature(item.schemas) !== schemaSignature(registration.schemas)\n ));\n if (conflict) {\n throw new Error(\n `Conflicting YAML schema ownership for ${registration.modelPath}`,\n );\n }\n\n runtime.owners.set(ownerId, registration);\n try {\n await updateYamlRuntime();\n } catch (error) {\n runtime.owners.delete(ownerId);\n void updateYamlRuntime();\n throw error;\n }\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n runtime.owners.delete(ownerId);\n void updateYamlRuntime();\n };\n}\n","import Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport {\n CodeEditor,\n type CodeEditorHandle,\n type CodeEditorProps,\n} from '../CodeEditor';\nimport { loadMonacoRuntime } from '../runtime/loadMonaco';\nimport type { YamlSchemaRegistration } from './types';\nimport {\n ensureYamlRuntime,\n registerYamlOwner,\n} from './yamlRuntime';\n\nexport interface ResourceYamlEditorProps extends Omit<\n CodeEditorProps,\n 'language'\n> {\n readonly schemas?: readonly YamlSchemaRegistration[];\n readonly isKubernetes?: boolean;\n}\n\nconst emptySchemas: readonly YamlSchemaRegistration[] = [];\n\nexport const ResourceYamlEditor = forwardRef<\nCodeEditorHandle,\nResourceYamlEditorProps\n>(function ResourceYamlEditor({\n schemas = emptySchemas,\n isKubernetes = false,\n modelPath,\n height = 400,\n ...props\n}, ref) {\n const ownerId = useId();\n const schemaKey = JSON.stringify(schemas);\n const schemasRef = useRef({ key: schemaKey, value: schemas });\n if (schemasRef.current.key !== schemaKey) {\n schemasRef.current = { key: schemaKey, value: schemas };\n }\n const stableSchemas = schemasRef.current.value;\n const [ready, setReady] = useState(false);\n const [runtimeError, setRuntimeError] = useState<string>();\n\n useEffect(() => {\n let active = true;\n let release: (() => void) | undefined;\n void loadMonacoRuntime()\n .then(async monaco => {\n await ensureYamlRuntime(monaco);\n if (!active) return;\n release = await registerYamlOwner(ownerId, {\n modelPath,\n schemas: stableSchemas,\n isKubernetes,\n });\n if (active) {\n setRuntimeError(undefined);\n setReady(true);\n } else {\n release();\n }\n })\n .catch(error => {\n if (active) {\n setReady(false);\n setRuntimeError(\n error instanceof Error ? error.message : String(error),\n );\n }\n });\n return () => {\n active = false;\n release?.();\n };\n }, [isKubernetes, modelPath, ownerId, stableSchemas]);\n\n if (runtimeError) {\n return <Alert severity=\"error\" role=\"alert\">{runtimeError}</Alert>;\n }\n\n if (!ready) {\n return (\n <Box\n role=\"status\"\n aria-label=\"Loading YAML editor\"\n sx={{ display: 'grid', height, minHeight: 160, placeItems: 'center' }}\n >\n <CircularProgress aria-hidden=\"true\" />\n </Box>\n );\n }\n\n return (\n <CodeEditor\n {...props}\n ref={ref}\n height={height}\n language=\"yaml\"\n modelPath={modelPath}\n />\n );\n});\n"],"mappings":"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"}