@hxdhxd/harmony-flow-ui 0.2.0 → 0.4.0

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.
Files changed (56) hide show
  1. package/README.md +43 -5
  2. package/dist/index.cjs +2022 -1297
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +786 -155
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.cts +115 -12
  7. package/dist/index.d.ts +115 -12
  8. package/dist/index.js +2003 -1285
  9. package/dist/index.js.map +1 -1
  10. package/dist/monaco-assets/LICENSE.monaco.txt +21 -0
  11. package/dist/monaco-assets/ThirdPartyNotices.txt +448 -0
  12. package/dist/monaco-assets/chunks/chunk-2KWDR4W3.js +1 -0
  13. package/dist/monaco-assets/chunks/chunk-2KWDR4W3.js.gz +0 -0
  14. package/dist/monaco-assets/chunks/chunk-6CWAYXCI.js +870 -0
  15. package/dist/monaco-assets/chunks/chunk-6CWAYXCI.js.gz +0 -0
  16. package/dist/monaco-assets/chunks/chunk-AD5KIREA.js +61 -0
  17. package/dist/monaco-assets/chunks/chunk-AD5KIREA.js.gz +0 -0
  18. package/dist/monaco-assets/chunks/chunk-NYAGVHXV.js +1 -0
  19. package/dist/monaco-assets/chunks/chunk-NYAGVHXV.js.gz +0 -0
  20. package/dist/monaco-assets/chunks/javascript-Q5O4BLC5.css +1 -0
  21. package/dist/monaco-assets/chunks/javascript-Q5O4BLC5.css.gz +0 -0
  22. package/dist/monaco-assets/chunks/javascript-R6AQIXSX.js +1 -0
  23. package/dist/monaco-assets/chunks/javascript-R6AQIXSX.js.gz +0 -0
  24. package/dist/monaco-assets/chunks/jsonMode-I4YAYKCC.css +1 -0
  25. package/dist/monaco-assets/chunks/jsonMode-I4YAYKCC.css.gz +0 -0
  26. package/dist/monaco-assets/chunks/jsonMode-PVXHFVY4.js +10 -0
  27. package/dist/monaco-assets/chunks/jsonMode-PVXHFVY4.js.gz +0 -0
  28. package/dist/monaco-assets/chunks/tsMode-4CIG5YX5.js +11 -0
  29. package/dist/monaco-assets/chunks/tsMode-4CIG5YX5.js.gz +0 -0
  30. package/dist/monaco-assets/chunks/tsMode-LEY4YWTP.css +1 -0
  31. package/dist/monaco-assets/chunks/tsMode-LEY4YWTP.css.gz +0 -0
  32. package/dist/monaco-assets/chunks/typescript-DYIPN6WN.js +1 -0
  33. package/dist/monaco-assets/chunks/typescript-DYIPN6WN.js.gz +0 -0
  34. package/dist/monaco-assets/chunks/typescript-Z6MD7EEQ.css +1 -0
  35. package/dist/monaco-assets/chunks/typescript-Z6MD7EEQ.css.gz +0 -0
  36. package/dist/monaco-assets/editor.worker.js +30 -0
  37. package/dist/monaco-assets/editor.worker.js.gz +0 -0
  38. package/dist/monaco-assets/fonts/codicon-KP4OV2OO.ttf +0 -0
  39. package/dist/monaco-assets/json.worker.js +62 -0
  40. package/dist/monaco-assets/json.worker.js.gz +0 -0
  41. package/dist/monaco-assets/manifest.json +5 -0
  42. package/dist/monaco-assets/runtime.css +1 -0
  43. package/dist/monaco-assets/runtime.css.gz +0 -0
  44. package/dist/monaco-assets/runtime.js +1 -0
  45. package/dist/monaco-assets/runtime.js.gz +0 -0
  46. package/dist/monaco-assets/typescript.worker.js +67740 -0
  47. package/dist/monaco-assets/typescript.worker.js.gz +0 -0
  48. package/dist/monaco.cjs +521 -0
  49. package/dist/monaco.cjs.map +1 -0
  50. package/dist/monaco.css +35 -0
  51. package/dist/monaco.css.map +1 -0
  52. package/dist/monaco.d.cts +22 -0
  53. package/dist/monaco.d.ts +22 -0
  54. package/dist/monaco.js +494 -0
  55. package/dist/monaco.js.map +1 -0
  56. package/package.json +11 -3
@@ -0,0 +1,22 @@
1
+ import * as react from 'react';
2
+
3
+ interface CodeEditorProps {
4
+ value: string;
5
+ onChange: (value: string) => void;
6
+ language?: string;
7
+ label?: string;
8
+ readOnly?: boolean;
9
+ height?: number;
10
+ }
11
+
12
+ interface MonacoCodeEditorProps extends CodeEditorProps {
13
+ /** Stable file identity. Up to 20 recently opened models retain undo and view state. */
14
+ path?: string;
15
+ /** Same-origin directory containing the prebuilt monaco-assets files. Default: /monaco/. */
16
+ assetsUrl?: string;
17
+ /** Force the lightweight editor, e.g. for low-memory devices. Mobile uses it automatically. */
18
+ lightweight?: boolean;
19
+ }
20
+ declare function MonacoCodeEditor(props: MonacoCodeEditorProps): react.JSX.Element;
21
+
22
+ export { MonacoCodeEditor, type MonacoCodeEditorProps };
@@ -0,0 +1,22 @@
1
+ import * as react from 'react';
2
+
3
+ interface CodeEditorProps {
4
+ value: string;
5
+ onChange: (value: string) => void;
6
+ language?: string;
7
+ label?: string;
8
+ readOnly?: boolean;
9
+ height?: number;
10
+ }
11
+
12
+ interface MonacoCodeEditorProps extends CodeEditorProps {
13
+ /** Stable file identity. Up to 20 recently opened models retain undo and view state. */
14
+ path?: string;
15
+ /** Same-origin directory containing the prebuilt monaco-assets files. Default: /monaco/. */
16
+ assetsUrl?: string;
17
+ /** Force the lightweight editor, e.g. for low-memory devices. Mobile uses it automatically. */
18
+ lightweight?: boolean;
19
+ }
20
+ declare function MonacoCodeEditor(props: MonacoCodeEditorProps): react.JSX.Element;
21
+
22
+ export { MonacoCodeEditor, type MonacoCodeEditorProps };
package/dist/monaco.js ADDED
@@ -0,0 +1,494 @@
1
+ // src/monaco/MonacoCodeEditor.tsx
2
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
3
+
4
+ // src/components/CodeEditor.tsx
5
+ import { useId } from "react";
6
+
7
+ // src/foundations/Icon.tsx
8
+ import { jsx } from "react/jsx-runtime";
9
+ var paths = {
10
+ check: "M5 12.5 9.2 17 19 7",
11
+ close: "m7 7 10 10M17 7 7 17",
12
+ info: "M12 11v6M12 7.5h.01",
13
+ warning: "M12 4 3.5 19h17L12 4Zm0 5v4.5m0 2.5h.01",
14
+ error: "M8 8l8 8m0-8-8 8",
15
+ search: "m20 20-4.5-4.5m2.5-4A7 7 0 1 1 4 11a7 7 0 0 1 14 0Z",
16
+ "chevron-down": "m7 10 5 5 5-5",
17
+ "arrow-right": "M5 12h14m-5-5 5 5-5 5",
18
+ user: "M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm7 8a7 7 0 0 0-14 0",
19
+ inbox: "M4 5h16v13H4V5Zm0 9h4l2 2h4l2-2h4"
20
+ };
21
+ function Icon({ name, size = 20, label, className = "", ...props }) {
22
+ return /* @__PURE__ */ jsx("svg", { className: `hf-icon ${className}`, width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", role: label ? "img" : void 0, "aria-label": label, "aria-hidden": label ? void 0 : true, ...props, children: /* @__PURE__ */ jsx("path", { d: paths[name] }) });
23
+ }
24
+
25
+ // src/components/useCodeEditor.ts
26
+ import { useEffect, useRef, useState } from "react";
27
+ function useCodeEditor(value, onChange, readOnly) {
28
+ const input = useRef(null);
29
+ const gutter = useRef(null);
30
+ const search = useRef(null);
31
+ const pending = useRef(void 0);
32
+ const escapeTab = useRef(false);
33
+ const [selection, setSelection] = useState({ start: 0, end: 0 });
34
+ const [finding, setFinding] = useState(false);
35
+ const [query, setQuery] = useState("");
36
+ const [copyStatus, setCopyStatus] = useState("");
37
+ const line = value.slice(0, Math.min(selection.start, value.length)).split("\n");
38
+ const position = { line: line.length, column: (line.at(-1)?.length ?? 0) + 1 };
39
+ const matches = [];
40
+ if (query) {
41
+ let offset = value.indexOf(query);
42
+ while (offset !== -1) {
43
+ matches.push(offset);
44
+ offset = value.indexOf(query, offset + query.length);
45
+ }
46
+ }
47
+ useEffect(() => () => {
48
+ if (pending.current !== void 0) cancelAnimationFrame(pending.current);
49
+ }, []);
50
+ useEffect(() => {
51
+ setCopyStatus("");
52
+ }, [value]);
53
+ function syncSelection() {
54
+ if (input.current) setSelection({ start: input.current.selectionStart, end: input.current.selectionEnd });
55
+ }
56
+ function openFind() {
57
+ setFinding(true);
58
+ requestAnimationFrame(() => search.current?.focus());
59
+ }
60
+ function closeFind() {
61
+ setFinding(false);
62
+ input.current?.focus();
63
+ }
64
+ function find(direction = 1) {
65
+ if (!matches.length || !input.current) return;
66
+ const start = input.current.selectionStart;
67
+ const end = input.current.selectionEnd;
68
+ const next = direction > 0 ? matches.find((offset) => offset >= (end > start ? end : start)) ?? matches[0] : [...matches].reverse().find((offset) => offset < start) ?? matches.at(-1);
69
+ input.current.focus();
70
+ input.current.setSelectionRange(next, next + query.length);
71
+ const row = value.slice(0, next).split("\n").length - 1;
72
+ input.current.scrollTop = Math.max(0, row * 22 - input.current.clientHeight / 2);
73
+ if (gutter.current) gutter.current.scrollTop = input.current.scrollTop;
74
+ syncSelection();
75
+ }
76
+ async function copy() {
77
+ try {
78
+ await navigator.clipboard.writeText(value);
79
+ setCopyStatus("\u5DF2\u590D\u5236");
80
+ } catch {
81
+ setCopyStatus("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u9009\u4E2D\u6587\u672C\u540E\u590D\u5236");
82
+ }
83
+ }
84
+ function keyDown(event) {
85
+ if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "f") {
86
+ event.preventDefault();
87
+ openFind();
88
+ return;
89
+ }
90
+ if (event.key === "Escape") {
91
+ escapeTab.current = true;
92
+ if (finding) closeFind();
93
+ return;
94
+ }
95
+ if (event.key === "Tab") {
96
+ if (escapeTab.current || event.shiftKey || readOnly) {
97
+ escapeTab.current = false;
98
+ return;
99
+ }
100
+ if (event.nativeEvent.isComposing) return;
101
+ event.preventDefault();
102
+ const start = event.currentTarget.selectionStart;
103
+ const end = event.currentTarget.selectionEnd;
104
+ onChange(`${value.slice(0, start)} ${value.slice(end)}`);
105
+ pending.current = requestAnimationFrame(() => {
106
+ input.current?.setSelectionRange(start + 2, start + 2);
107
+ syncSelection();
108
+ });
109
+ } else escapeTab.current = false;
110
+ }
111
+ return {
112
+ input,
113
+ gutter,
114
+ search,
115
+ selection,
116
+ position,
117
+ finding,
118
+ query,
119
+ setQuery,
120
+ matches,
121
+ copyStatus,
122
+ syncSelection,
123
+ openFind,
124
+ closeFind,
125
+ find,
126
+ copy,
127
+ keyDown
128
+ };
129
+ }
130
+
131
+ // src/components/CodeEditor.tsx
132
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
133
+ function CodeEditor({ value, onChange, language = "text", label = "\u4EE3\u7801\u7F16\u8F91\u5668", readOnly, height = 260 }) {
134
+ const editor = useCodeEditor(value, onChange, readOnly);
135
+ const helpId = useId();
136
+ const lines = value.split("\n").length;
137
+ return /* @__PURE__ */ jsxs("div", { className: `hf-code-editor${readOnly ? " is-readonly" : ""}`, children: [
138
+ /* @__PURE__ */ jsxs("header", { className: "hf-code-editor__header", children: [
139
+ /* @__PURE__ */ jsxs("div", { className: "hf-code-editor__title", children: [
140
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "</>" }),
141
+ /* @__PURE__ */ jsx2("strong", { children: label })
142
+ ] }),
143
+ /* @__PURE__ */ jsxs("div", { className: "hf-code-editor__tools", children: [
144
+ /* @__PURE__ */ jsxs("button", { type: "button", "aria-label": "\u67E5\u627E\u4EE3\u7801", "aria-expanded": editor.finding, onClick: editor.openFind, children: [
145
+ /* @__PURE__ */ jsx2(Icon, { name: "search", size: 16 }),
146
+ /* @__PURE__ */ jsx2("span", { children: "\u67E5\u627E" })
147
+ ] }),
148
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: editor.copy, children: "\u590D\u5236" })
149
+ ] })
150
+ ] }),
151
+ editor.finding && /* @__PURE__ */ jsxs("div", { className: "hf-code-editor__find", role: "search", "aria-label": "\u4EE3\u7801\u67E5\u627E", children: [
152
+ /* @__PURE__ */ jsx2(
153
+ "input",
154
+ {
155
+ ref: editor.search,
156
+ "aria-label": "\u67E5\u627E\u5185\u5BB9",
157
+ placeholder: "\u67E5\u627E\u6587\u672C\uFF08\u533A\u5206\u5927\u5C0F\u5199\uFF09",
158
+ value: editor.query,
159
+ onChange: (event) => editor.setQuery(event.target.value),
160
+ onKeyDown: (event) => {
161
+ if (event.key === "Enter") {
162
+ event.preventDefault();
163
+ editor.find(event.shiftKey ? -1 : 1);
164
+ } else if (event.key === "Escape") editor.closeFind();
165
+ }
166
+ }
167
+ ),
168
+ /* @__PURE__ */ jsx2("span", { role: "status", children: editor.query ? `${editor.matches.length} \u4E2A\u5339\u914D` : "\u8F93\u5165\u5173\u952E\u8BCD" }),
169
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": "\u4E0A\u4E00\u4E2A\u5339\u914D", disabled: !editor.matches.length, onClick: () => editor.find(-1), children: "\u2191" }),
170
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": "\u4E0B\u4E00\u4E2A\u5339\u914D", disabled: !editor.matches.length, onClick: () => editor.find(1), children: "\u2193" }),
171
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": "\u5173\u95ED\u67E5\u627E", onClick: editor.closeFind, children: /* @__PURE__ */ jsx2(Icon, { name: "close", size: 14 }) })
172
+ ] }),
173
+ /* @__PURE__ */ jsxs("div", { className: "hf-code-editor__body", style: { height }, children: [
174
+ /* @__PURE__ */ jsx2("pre", { ref: editor.gutter, className: "hf-code-editor__gutter", "aria-hidden": "true", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsxs("span", { className: editor.position.line === index + 1 ? "is-active" : "", children: [
175
+ index + 1,
176
+ "\n"
177
+ ] }, index)) }),
178
+ /* @__PURE__ */ jsx2(
179
+ "textarea",
180
+ {
181
+ ref: editor.input,
182
+ spellCheck: false,
183
+ autoCapitalize: "off",
184
+ autoCorrect: "off",
185
+ wrap: "off",
186
+ readOnly,
187
+ "aria-label": label,
188
+ "aria-describedby": helpId,
189
+ value,
190
+ onChange: (event) => onChange(event.target.value),
191
+ onSelect: editor.syncSelection,
192
+ onKeyDown: editor.keyDown,
193
+ onScroll: (event) => {
194
+ if (editor.gutter.current) editor.gutter.current.scrollTop = event.currentTarget.scrollTop;
195
+ }
196
+ }
197
+ )
198
+ ] }),
199
+ /* @__PURE__ */ jsxs("footer", { className: "hf-code-editor__status", children: [
200
+ /* @__PURE__ */ jsx2("span", { children: readOnly ? "\u53EA\u8BFB" : "\u53EF\u7F16\u8F91" }),
201
+ /* @__PURE__ */ jsxs("span", { children: [
202
+ "\u884C ",
203
+ editor.position.line,
204
+ "\uFF0C\u5217 ",
205
+ editor.position.column
206
+ ] }),
207
+ /* @__PURE__ */ jsx2("span", { children: editor.selection.end > editor.selection.start ? `\u5DF2\u9009 ${editor.selection.end - editor.selection.start} \u5B57\u7B26` : `${lines} \u884C \xB7 ${value.length} \u5B57\u7B26` }),
208
+ /* @__PURE__ */ jsx2("span", { className: "hf-code-editor__language", children: language })
209
+ ] }),
210
+ /* @__PURE__ */ jsx2("span", { className: "hf-code-editor__sr", id: helpId, children: "Tab \u63D2\u5165\u4E24\u4E2A\u7A7A\u683C\uFF1B\u6309 Escape \u540E\u518D\u6309 Tab \u79BB\u5F00\u7F16\u8F91\u5668\uFF0CShift+Tab \u8FD4\u56DE\u4E0A\u4E00\u4E2A\u63A7\u4EF6\u3002" }),
211
+ editor.copyStatus && /* @__PURE__ */ jsx2("div", { className: "hf-code-editor__message", role: "status", children: editor.copyStatus })
212
+ ] });
213
+ }
214
+
215
+ // src/monaco/loadRuntime.ts
216
+ var requests = /* @__PURE__ */ new Map();
217
+ function withTimeout(promise, milliseconds = 2e4) {
218
+ return new Promise((resolve, reject) => {
219
+ const timer = setTimeout(() => reject(new Error("Monaco \u8D44\u6E90\u6216 Worker \u52A0\u8F7D\u8D85\u65F6")), milliseconds);
220
+ promise.then((value) => {
221
+ clearTimeout(timer);
222
+ resolve(value);
223
+ }, (error) => {
224
+ clearTimeout(timer);
225
+ reject(error);
226
+ });
227
+ });
228
+ }
229
+ function loadRuntime(assetsUrl, retry) {
230
+ const base = new URL(assetsUrl.endsWith("/") ? assetsUrl : `${assetsUrl}/`, document.baseURI);
231
+ if (base.origin !== location.origin) return Promise.reject(new Error("Monaco \u8D44\u6E90\u5FC5\u987B\u4E0E\u9875\u9762\u540C\u6E90"));
232
+ const key = base.href;
233
+ const existing = requests.get(key);
234
+ if (existing) return existing;
235
+ const link = document.createElement("link");
236
+ link.rel = "stylesheet";
237
+ link.href = new URL("runtime.css", base).href;
238
+ const css = new Promise((resolve, reject) => {
239
+ link.onload = () => resolve();
240
+ link.onerror = () => reject(new Error("Monaco \u6837\u5F0F\u52A0\u8F7D\u5931\u8D25"));
241
+ document.head.append(link);
242
+ });
243
+ const script = new URL("runtime.js", base);
244
+ if (retry) script.searchParams.set("retry", String(retry));
245
+ const request = withTimeout(Promise.all([import(script.href), css])).then(([runtime]) => runtime).catch((error) => {
246
+ link.remove();
247
+ requests.delete(key);
248
+ throw error;
249
+ });
250
+ requests.set(key, request);
251
+ return request;
252
+ }
253
+ function prefersLightEditor() {
254
+ return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent) || navigator.maxTouchPoints > 1 && /Macintosh/i.test(navigator.userAgent);
255
+ }
256
+
257
+ // src/monaco/theme.ts
258
+ function observeTheme(runtime, host) {
259
+ const themeRoot = host.closest(".hf-theme") ?? document.documentElement;
260
+ const apply = () => {
261
+ const style = getComputedStyle(host);
262
+ const color = (token, fallback) => {
263
+ const value = style.getPropertyValue(token).trim();
264
+ if (/^#[\da-f]{3,8}$/i.test(value)) return value;
265
+ if (!value || !CSS.supports("color", value)) return fallback;
266
+ const canvas = document.createElement("canvas").getContext("2d");
267
+ if (!canvas) return fallback;
268
+ canvas.fillStyle = value;
269
+ canvas.fillRect(0, 0, 1, 1);
270
+ return "#" + Array.from(canvas.getImageData(0, 0, 1, 1).data, (channel) => channel.toString(16).padStart(2, "0")).join("");
271
+ };
272
+ const highContrast = themeRoot.classList.contains("hf-theme--high-contrast");
273
+ const dark = themeRoot.classList.contains("hf-theme--dark");
274
+ runtime.monaco.editor.defineTheme("harmony-flow", {
275
+ base: highContrast ? "hc-light" : dark ? "vs-dark" : "vs",
276
+ inherit: true,
277
+ rules: [],
278
+ colors: {
279
+ "editor.background": color("--hf-color-surface", dark ? "#172235" : "#ffffff"),
280
+ "editor.foreground": color("--hf-color-text", dark ? "#f2f6fc" : "#142033"),
281
+ "editorLineNumber.foreground": color("--hf-color-text-muted", "#66758c"),
282
+ "editorLineNumber.activeForeground": color("--hf-color-primary", "#0a7cff"),
283
+ "editorCursor.foreground": color("--hf-color-primary", "#0a7cff"),
284
+ "editorWidget.background": color("--hf-color-surface", "#ffffff"),
285
+ "editorWidget.border": color("--hf-color-border", "#dce9f7"),
286
+ "editorSuggestWidget.background": color("--hf-color-surface", "#ffffff"),
287
+ "editorSuggestWidget.foreground": color("--hf-color-text", "#142033"),
288
+ "focusBorder": color("--hf-color-primary", "#0a7cff")
289
+ }
290
+ });
291
+ runtime.monaco.editor.setTheme("harmony-flow");
292
+ };
293
+ apply();
294
+ const observer = new MutationObserver(apply);
295
+ for (let node = themeRoot; node; node = node.parentElement) {
296
+ observer.observe(node, { attributes: true, attributeFilter: ["class", "style"] });
297
+ }
298
+ return () => observer.disconnect();
299
+ }
300
+
301
+ // src/monaco/session.ts
302
+ var instance = 0;
303
+ function createSession(runtime, host, options, onChange, onPosition) {
304
+ const { monaco } = runtime;
305
+ const id = ++instance;
306
+ const models = /* @__PURE__ */ new Map();
307
+ let path = "";
308
+ let syncing = false;
309
+ const stopTheme = observeTheme(runtime, host);
310
+ const editor = monaco.editor.create(host, {
311
+ model: null,
312
+ automaticLayout: true,
313
+ minimap: { enabled: false },
314
+ fontSize: 13,
315
+ lineHeight: 22,
316
+ fontFamily: 'Consolas, "SFMono-Regular", Menlo, Monaco, "Liberation Mono", monospace',
317
+ fontLigatures: false,
318
+ padding: { top: 12, bottom: 12 },
319
+ scrollBeyondLastLine: false,
320
+ tabSize: 2,
321
+ insertSpaces: true,
322
+ detectIndentation: false,
323
+ renderLineHighlight: "line",
324
+ overviewRulerBorder: false,
325
+ hideCursorInOverviewRuler: true,
326
+ fixedOverflowWidgets: false,
327
+ accessibilitySupport: "auto",
328
+ stickyScroll: { enabled: false },
329
+ tabFocusMode: true
330
+ });
331
+ const changed = editor.onDidChangeModelContent(() => {
332
+ if (!syncing) onChange(editor.getValue());
333
+ });
334
+ const positioned = editor.onDidChangeCursorPosition((event) => onPosition(event.position.lineNumber, event.position.column));
335
+ function update(next) {
336
+ const nextPath = next.path ?? "untitled";
337
+ const language = ["typescript", "javascript", "json"].includes(next.language ?? "") ? next.language : "plaintext";
338
+ if (path !== nextPath || !editor.getModel()) {
339
+ const previous = models.get(path);
340
+ if (previous) previous.view = editor.saveViewState();
341
+ let entry = models.get(nextPath);
342
+ if (!entry) {
343
+ const uri = monaco.Uri.parse(`file:///harmony-${id}/${nextPath.split("/").map(encodeURIComponent).join("/")}`);
344
+ entry = { model: monaco.editor.createModel(next.value, language, uri), view: null };
345
+ }
346
+ models.delete(nextPath);
347
+ models.set(nextPath, entry);
348
+ path = nextPath;
349
+ editor.setModel(entry.model);
350
+ if (entry.view) editor.restoreViewState(entry.view);
351
+ if (models.size > 20) {
352
+ const oldest = models.keys().next().value;
353
+ models.get(oldest).model.dispose();
354
+ models.delete(oldest);
355
+ }
356
+ }
357
+ const model = editor.getModel();
358
+ model.updateOptions({ tabSize: 2, insertSpaces: true });
359
+ if (model.getLanguageId() !== language) monaco.editor.setModelLanguage(model, language);
360
+ if (model.getValue() !== next.value) {
361
+ syncing = true;
362
+ try {
363
+ model.setValue(next.value);
364
+ } finally {
365
+ syncing = false;
366
+ }
367
+ }
368
+ editor.updateOptions({ readOnly: !!next.readOnly, ariaLabel: next.label ?? "\u4EE3\u7801\u7F16\u8F91\u5668" });
369
+ return model;
370
+ }
371
+ update(options);
372
+ return {
373
+ editor,
374
+ update,
375
+ dispose() {
376
+ changed.dispose();
377
+ positioned.dispose();
378
+ stopTheme();
379
+ editor.dispose();
380
+ models.forEach(({ model }) => model.dispose());
381
+ models.clear();
382
+ }
383
+ };
384
+ }
385
+
386
+ // src/monaco/MonacoCodeEditor.tsx
387
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
388
+ function MonacoCodeEditor(props) {
389
+ const { assetsUrl = "/monaco/", lightweight = false, height = 260, label = "\u4EE3\u7801\u7F16\u8F91\u5668" } = props;
390
+ const host = useRef2(null);
391
+ const current = useRef2(props);
392
+ current.current = props;
393
+ const session = useRef2(null);
394
+ const [status, setStatus] = useState2("loading");
395
+ const [retry, setRetry] = useState2(0);
396
+ const [position, setPosition] = useState2({ line: 1, column: 1 });
397
+ const [message, setMessage] = useState2("");
398
+ useEffect2(() => {
399
+ if (lightweight || prefersLightEditor()) {
400
+ setStatus("fallback");
401
+ return;
402
+ }
403
+ let disposed = false;
404
+ let stopErrors;
405
+ let owned;
406
+ const fail = (error) => {
407
+ if (disposed) return;
408
+ console.error("[Harmony Flow Monaco]", error);
409
+ stopErrors?.();
410
+ owned?.dispose();
411
+ owned = void 0;
412
+ session.current = null;
413
+ setStatus("error");
414
+ };
415
+ setStatus("loading");
416
+ loadRuntime(assetsUrl, retry).then(async (runtime) => {
417
+ if (disposed || !host.current) return;
418
+ if (retry) runtime.restartWorkers();
419
+ stopErrors = runtime.onWorkerError(() => fail(new Error("Monaco Worker \u52A0\u8F7D\u5931\u8D25")));
420
+ owned = createSession(
421
+ runtime,
422
+ host.current,
423
+ current.current,
424
+ (value) => current.current.onChange(value),
425
+ (line, column) => setPosition({ line, column })
426
+ );
427
+ session.current = owned;
428
+ await withTimeout(runtime.verifyWorker(owned.editor.getModel()));
429
+ if (!disposed && owned) {
430
+ owned.update(current.current);
431
+ setStatus("ready");
432
+ }
433
+ }).catch(fail);
434
+ return () => {
435
+ disposed = true;
436
+ stopErrors?.();
437
+ owned?.dispose();
438
+ session.current = null;
439
+ };
440
+ }, [assetsUrl, lightweight, retry]);
441
+ useEffect2(() => {
442
+ session.current?.update(props);
443
+ }, [props.value, props.path, props.language, props.readOnly, props.label]);
444
+ const copy = async () => {
445
+ try {
446
+ await navigator.clipboard.writeText(current.current.value);
447
+ setMessage("\u5DF2\u590D\u5236");
448
+ } catch {
449
+ setMessage("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u9009\u4E2D\u4EE3\u7801\u540E\u590D\u5236");
450
+ }
451
+ };
452
+ return /* @__PURE__ */ jsxs2("div", { className: "hf-monaco", "data-editor-state": status, children: [
453
+ status !== "ready" && /* @__PURE__ */ jsxs2(Fragment, { children: [
454
+ /* @__PURE__ */ jsxs2("div", { className: "hf-monaco__notice", role: "status", children: [
455
+ status === "loading" ? "\u6B63\u5728\u52A0\u8F7D\u589E\u5F3A\u7F16\u8F91\u5668\uFF0C\u53EF\u5148\u7EE7\u7EED\u7F16\u8F91" : status === "error" ? "\u589E\u5F3A\u7F16\u8F91\u5668\u52A0\u8F7D\u5931\u8D25\uFF0C\u5DF2\u4F7F\u7528\u8F7B\u91CF\u6A21\u5F0F" : "\u8F7B\u91CF\u7F16\u8F91\u6A21\u5F0F",
456
+ status === "error" && /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => setRetry((value) => value + 1), children: "\u91CD\u8BD5\u52A0\u8F7D" })
457
+ ] }),
458
+ /* @__PURE__ */ jsx3(CodeEditor, { ...props })
459
+ ] }),
460
+ /* @__PURE__ */ jsxs2("div", { className: "hf-code-editor hf-monaco__enhanced", hidden: status !== "ready", children: [
461
+ /* @__PURE__ */ jsxs2("header", { className: "hf-code-editor__header", children: [
462
+ /* @__PURE__ */ jsxs2("div", { className: "hf-code-editor__title", children: [
463
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "</>" }),
464
+ /* @__PURE__ */ jsx3("strong", { children: label })
465
+ ] }),
466
+ /* @__PURE__ */ jsxs2("div", { className: "hf-code-editor__tools", children: [
467
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => {
468
+ session.current?.editor.focus();
469
+ void session.current?.editor.getAction("actions.find")?.run();
470
+ }, children: "\u67E5\u627E" }),
471
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: copy, children: "\u590D\u5236" })
472
+ ] })
473
+ ] }),
474
+ /* @__PURE__ */ jsx3("div", { ref: host, className: "hf-monaco__canvas", style: { height } }),
475
+ /* @__PURE__ */ jsxs2("footer", { className: "hf-code-editor__status", children: [
476
+ /* @__PURE__ */ jsx3("span", { children: props.readOnly ? "\u53EA\u8BFB" : "\u53EF\u7F16\u8F91" }),
477
+ /* @__PURE__ */ jsxs2("span", { children: [
478
+ "\u884C ",
479
+ position.line,
480
+ "\uFF0C\u5217 ",
481
+ position.column
482
+ ] }),
483
+ /* @__PURE__ */ jsx3("span", { children: "UTF-8 \xB7 Monaco" }),
484
+ /* @__PURE__ */ jsx3("span", { className: "hf-code-editor__language", children: props.language ?? "text" })
485
+ ] }),
486
+ /* @__PURE__ */ jsx3("span", { className: "hf-code-editor__sr", children: "Tab \u79BB\u5F00\u7F16\u8F91\u5668\uFF1BCtrl+M \u5207\u6362 Tab \u7F29\u8FDB\u6A21\u5F0F\u3002" }),
487
+ message && /* @__PURE__ */ jsx3("div", { className: "hf-code-editor__message", role: "status", children: message })
488
+ ] })
489
+ ] });
490
+ }
491
+ export {
492
+ MonacoCodeEditor
493
+ };
494
+ //# sourceMappingURL=monaco.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/monaco/MonacoCodeEditor.tsx","../../src/components/CodeEditor.tsx","../../src/foundations/Icon.tsx","../../src/components/useCodeEditor.ts","../../src/monaco/loadRuntime.ts","../../src/monaco/theme.ts","../../src/monaco/session.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { CodeEditor, type CodeEditorProps } from '../components/CodeEditor';\nimport { loadRuntime, prefersLightEditor, withTimeout } from './loadRuntime';\nimport { createSession } from './session';\nimport './style.css';\n\nexport interface MonacoCodeEditorProps extends CodeEditorProps {\n /** Stable file identity. Up to 20 recently opened models retain undo and view state. */\n path?: string;\n /** Same-origin directory containing the prebuilt monaco-assets files. Default: /monaco/. */\n assetsUrl?: string;\n /** Force the lightweight editor, e.g. for low-memory devices. Mobile uses it automatically. */\n lightweight?: boolean;\n}\n\nexport function MonacoCodeEditor(props: MonacoCodeEditorProps) {\n const { assetsUrl = '/monaco/', lightweight = false, height = 260, label = '代码编辑器' } = props;\n const host = useRef<HTMLDivElement>(null);\n const current = useRef(props);\n current.current = props;\n const session = useRef<ReturnType<typeof createSession> | null>(null);\n const [status, setStatus] = useState<'loading' | 'ready' | 'fallback' | 'error'>('loading');\n const [retry, setRetry] = useState(0);\n const [position, setPosition] = useState({ line: 1, column: 1 });\n const [message, setMessage] = useState('');\n\n useEffect(() => {\n if (lightweight || prefersLightEditor()) { setStatus('fallback'); return; }\n let disposed = false;\n let stopErrors: (() => void) | undefined;\n let owned: ReturnType<typeof createSession> | undefined;\n const fail = (error: unknown) => {\n if (disposed) return;\n console.error('[Harmony Flow Monaco]', error);\n stopErrors?.(); owned?.dispose(); owned = undefined; session.current = null;\n setStatus('error');\n };\n setStatus('loading');\n loadRuntime(assetsUrl, retry).then(async runtime => {\n if (disposed || !host.current) return;\n if (retry) runtime.restartWorkers();\n stopErrors = runtime.onWorkerError(() => fail(new Error('Monaco Worker 加载失败')));\n owned = createSession(runtime, host.current, current.current,\n value => current.current.onChange(value), (line, column) => setPosition({ line, column }));\n session.current = owned;\n await withTimeout(runtime.verifyWorker(owned.editor.getModel()!));\n if (!disposed && owned) { owned.update(current.current); setStatus('ready'); }\n }).catch(fail);\n return () => { disposed = true; stopErrors?.(); owned?.dispose(); session.current = null; };\n }, [assetsUrl, lightweight, retry]);\n\n useEffect(() => { session.current?.update(props); }, [props.value, props.path, props.language, props.readOnly, props.label]);\n\n const copy = async () => {\n try { await navigator.clipboard.writeText(current.current.value); setMessage('已复制'); }\n catch { setMessage('复制失败,请选中代码后复制'); }\n };\n return <div className=\"hf-monaco\" data-editor-state={status}>\n {status !== 'ready' && <>\n <div className=\"hf-monaco__notice\" role=\"status\">\n {status === 'loading' ? '正在加载增强编辑器,可先继续编辑' : status === 'error' ? '增强编辑器加载失败,已使用轻量模式' : '轻量编辑模式'}\n {status === 'error' && <button type=\"button\" onClick={() => setRetry(value => value + 1)}>重试加载</button>}\n </div>\n <CodeEditor {...props} />\n </>}\n <div className=\"hf-code-editor hf-monaco__enhanced\" hidden={status !== 'ready'}>\n <header className=\"hf-code-editor__header\">\n <div className=\"hf-code-editor__title\"><span aria-hidden=\"true\">{'</>'}</span><strong>{label}</strong></div>\n <div className=\"hf-code-editor__tools\">\n <button type=\"button\" onClick={() => { session.current?.editor.focus(); void session.current?.editor.getAction('actions.find')?.run(); }}>查找</button>\n <button type=\"button\" onClick={copy}>复制</button>\n </div>\n </header>\n <div ref={host} className=\"hf-monaco__canvas\" style={{ height }} />\n <footer className=\"hf-code-editor__status\">\n <span>{props.readOnly ? '只读' : '可编辑'}</span><span>行 {position.line},列 {position.column}</span>\n <span>UTF-8 · Monaco</span><span className=\"hf-code-editor__language\">{props.language ?? 'text'}</span>\n </footer>\n <span className=\"hf-code-editor__sr\">Tab 离开编辑器;Ctrl+M 切换 Tab 缩进模式。</span>\n {message && <div className=\"hf-code-editor__message\" role=\"status\">{message}</div>}\n </div>\n </div>;\n}\n","import { useId } from 'react';\nimport { Icon } from '../foundations/Icon';\nimport { useCodeEditor } from './useCodeEditor';\n\nexport interface CodeEditorProps {\n value: string;\n onChange: (value: string) => void;\n language?: string;\n label?: string;\n readOnly?: boolean;\n height?: number;\n}\n\nexport function CodeEditor({ value, onChange, language = 'text', label = '代码编辑器', readOnly, height = 260 }: CodeEditorProps) {\n const editor = useCodeEditor(value, onChange, readOnly);\n const helpId = useId();\n const lines = value.split('\\n').length;\n return <div className={`hf-code-editor${readOnly ? ' is-readonly' : ''}`}>\n <header className=\"hf-code-editor__header\">\n <div className=\"hf-code-editor__title\"><span aria-hidden=\"true\">{'</>'}</span><strong>{label}</strong></div>\n <div className=\"hf-code-editor__tools\">\n <button type=\"button\" aria-label=\"查找代码\" aria-expanded={editor.finding} onClick={editor.openFind}><Icon name=\"search\" size={16} /><span>查找</span></button>\n <button type=\"button\" onClick={editor.copy}>复制</button>\n </div>\n </header>\n {editor.finding && <div className=\"hf-code-editor__find\" role=\"search\" aria-label=\"代码查找\">\n <input ref={editor.search} aria-label=\"查找内容\" placeholder=\"查找文本(区分大小写)\" value={editor.query}\n onChange={(event) => editor.setQuery(event.target.value)}\n onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); editor.find(event.shiftKey ? -1 : 1); } else if (event.key === 'Escape') editor.closeFind(); }} />\n <span role=\"status\">{editor.query ? `${editor.matches.length} 个匹配` : '输入关键词'}</span>\n <button type=\"button\" aria-label=\"上一个匹配\" disabled={!editor.matches.length} onClick={() => editor.find(-1)}>↑</button>\n <button type=\"button\" aria-label=\"下一个匹配\" disabled={!editor.matches.length} onClick={() => editor.find(1)}>↓</button>\n <button type=\"button\" aria-label=\"关闭查找\" onClick={editor.closeFind}><Icon name=\"close\" size={14} /></button>\n </div>}\n <div className=\"hf-code-editor__body\" style={{ height }}>\n <pre ref={editor.gutter} className=\"hf-code-editor__gutter\" aria-hidden=\"true\">\n {Array.from({ length: lines }, (_, index) => <span className={editor.position.line === index + 1 ? 'is-active' : ''} key={index}>{index + 1}{'\\n'}</span>)}\n </pre>\n <textarea ref={editor.input} spellCheck={false} autoCapitalize=\"off\" autoCorrect=\"off\" wrap=\"off\"\n readOnly={readOnly} aria-label={label} aria-describedby={helpId} value={value}\n onChange={(event) => onChange(event.target.value)} onSelect={editor.syncSelection} onKeyDown={editor.keyDown}\n onScroll={(event) => { if (editor.gutter.current) editor.gutter.current.scrollTop = event.currentTarget.scrollTop; }} />\n </div>\n <footer className=\"hf-code-editor__status\">\n <span>{readOnly ? '只读' : '可编辑'}</span><span>行 {editor.position.line},列 {editor.position.column}</span>\n <span>{editor.selection.end > editor.selection.start ? `已选 ${editor.selection.end - editor.selection.start} 字符` : `${lines} 行 · ${value.length} 字符`}</span>\n <span className=\"hf-code-editor__language\">{language}</span>\n </footer>\n <span className=\"hf-code-editor__sr\" id={helpId}>Tab 插入两个空格;按 Escape 后再按 Tab 离开编辑器,Shift+Tab 返回上一个控件。</span>\n {editor.copyStatus && <div className=\"hf-code-editor__message\" role=\"status\">{editor.copyStatus}</div>}\n </div>;\n}\n","import type { SVGAttributes } from 'react';\n\nexport type IconName = 'check' | 'close' | 'info' | 'warning' | 'error' | 'search' | 'chevron-down' | 'arrow-right' | 'user' | 'inbox';\nexport interface IconProps extends Omit<SVGAttributes<SVGSVGElement>, 'children'> { name: IconName; size?: number; label?: string; }\n\nconst paths: Record<IconName, string> = {\n check: 'M5 12.5 9.2 17 19 7', close: 'm7 7 10 10M17 7 7 17', info: 'M12 11v6M12 7.5h.01',\n warning: 'M12 4 3.5 19h17L12 4Zm0 5v4.5m0 2.5h.01', error: 'M8 8l8 8m0-8-8 8',\n search: 'm20 20-4.5-4.5m2.5-4A7 7 0 1 1 4 11a7 7 0 0 1 14 0Z', 'chevron-down': 'm7 10 5 5 5-5',\n 'arrow-right': 'M5 12h14m-5-5 5 5-5 5', user: 'M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm7 8a7 7 0 0 0-14 0',\n inbox: 'M4 5h16v13H4V5Zm0 9h4l2 2h4l2-2h4',\n};\n\nexport function Icon({ name, size = 20, label, className = '', ...props }: IconProps) {\n return <svg className={`hf-icon ${className}`} width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" role={label ? 'img' : undefined} aria-label={label} aria-hidden={label ? undefined : true} {...props}><path d={paths[name]} /></svg>;\n}\n","import { useEffect, useRef, useState, type KeyboardEvent } from 'react';\r\n\r\nexport function useCodeEditor(value: string, onChange: (value: string) => void, readOnly?: boolean) {\r\n const input = useRef<HTMLTextAreaElement>(null);\r\n const gutter = useRef<HTMLPreElement>(null);\r\n const search = useRef<HTMLInputElement>(null);\r\n const pending = useRef<number | undefined>(undefined);\r\n const escapeTab = useRef(false);\r\n const [selection, setSelection] = useState({ start: 0, end: 0 });\r\n const [finding, setFinding] = useState(false);\r\n const [query, setQuery] = useState('');\r\n const [copyStatus, setCopyStatus] = useState('');\r\n const line = value.slice(0, Math.min(selection.start, value.length)).split('\\n');\r\n const position = { line: line.length, column: (line.at(-1)?.length ?? 0) + 1 };\r\n const matches: number[] = [];\r\n if (query) {\r\n let offset = value.indexOf(query);\r\n while (offset !== -1) { matches.push(offset); offset = value.indexOf(query, offset + query.length); }\r\n }\r\n useEffect(() => () => { if (pending.current !== undefined) cancelAnimationFrame(pending.current); }, []);\r\n useEffect(() => { setCopyStatus(''); }, [value]);\r\n function syncSelection() {\r\n if (input.current) setSelection({ start: input.current.selectionStart, end: input.current.selectionEnd });\r\n }\r\n function openFind() { setFinding(true); requestAnimationFrame(() => search.current?.focus()); }\r\n function closeFind() { setFinding(false); input.current?.focus(); }\r\n function find(direction = 1) {\r\n if (!matches.length || !input.current) return;\r\n const start = input.current.selectionStart;\r\n const end = input.current.selectionEnd;\r\n const next = direction > 0\r\n ? matches.find((offset) => offset >= (end > start ? end : start)) ?? matches[0]!\r\n : [...matches].reverse().find((offset) => offset < start) ?? matches.at(-1)!;\r\n input.current.focus();\r\n input.current.setSelectionRange(next, next + query.length);\r\n const row = value.slice(0, next).split('\\n').length - 1;\r\n input.current.scrollTop = Math.max(0, row * 22 - input.current.clientHeight / 2);\r\n if (gutter.current) gutter.current.scrollTop = input.current.scrollTop;\r\n syncSelection();\r\n }\r\n async function copy() {\r\n try { await navigator.clipboard.writeText(value); setCopyStatus('已复制'); }\r\n catch { setCopyStatus('复制失败,请选中文本后复制'); }\r\n }\r\n function keyDown(event: KeyboardEvent<HTMLTextAreaElement>) {\r\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'f') { event.preventDefault(); openFind(); return; }\r\n if (event.key === 'Escape') { escapeTab.current = true; if (finding) closeFind(); return; }\r\n if (event.key === 'Tab') {\r\n if (escapeTab.current || event.shiftKey || readOnly) { escapeTab.current = false; return; }\r\n if (event.nativeEvent.isComposing) return;\r\n event.preventDefault();\r\n const start = event.currentTarget.selectionStart;\r\n const end = event.currentTarget.selectionEnd;\r\n onChange(`${value.slice(0, start)} ${value.slice(end)}`);\r\n pending.current = requestAnimationFrame(() => { input.current?.setSelectionRange(start + 2, start + 2); syncSelection(); });\r\n } else escapeTab.current = false;\r\n }\r\n return { input, gutter, search, selection, position, finding, query, setQuery, matches, copyStatus,\r\n syncSelection, openFind, closeFind, find, copy, keyDown };\r\n}\r\n","export type Runtime = typeof import('./runtime-entry');\r\nconst requests = new Map<string, Promise<Runtime>>();\r\n\r\nexport function withTimeout<T>(promise: Promise<T>, milliseconds = 20000): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timer = setTimeout(() => reject(new Error('Monaco 资源或 Worker 加载超时')), milliseconds);\r\n promise.then(value => { clearTimeout(timer); resolve(value); }, error => { clearTimeout(timer); reject(error); });\r\n });\r\n}\r\n\r\n/** Assets are explicitly self-hosted. Never silently switch to a public CDN. */\r\nexport function loadRuntime(assetsUrl: string, retry: number): Promise<Runtime> {\r\n const base = new URL(assetsUrl.endsWith('/') ? assetsUrl : `${assetsUrl}/`, document.baseURI);\r\n if (base.origin !== location.origin) return Promise.reject(new Error('Monaco 资源必须与页面同源'));\r\n const key = base.href;\r\n const existing = requests.get(key);\r\n if (existing) return existing;\r\n const link = document.createElement('link');\r\n link.rel = 'stylesheet';\r\n link.href = new URL('runtime.css', base).href;\r\n const css = new Promise<void>((resolve, reject) => {\r\n link.onload = () => resolve();\r\n link.onerror = () => reject(new Error('Monaco 样式加载失败'));\r\n document.head.append(link);\r\n });\r\n const script = new URL('runtime.js', base);\r\n if (retry) script.searchParams.set('retry', String(retry));\r\n const request = withTimeout(Promise.all([import(script.href) as Promise<Runtime>, css]))\r\n .then(([runtime]) => runtime)\r\n .catch(error => { link.remove(); requests.delete(key); throw error; });\r\n requests.set(key, request);\r\n return request;\r\n}\r\n\r\nexport function prefersLightEditor() {\r\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent)\r\n || (navigator.maxTouchPoints > 1 && /Macintosh/i.test(navigator.userAgent));\r\n}\r\n","import type { Runtime } from './loadRuntime';\r\n\r\n/** Monaco's theme service is shared: all enhanced editors follow the page theme. */\r\nexport function observeTheme(runtime: Runtime, host: HTMLElement) {\r\n const themeRoot = host.closest('.hf-theme') ?? document.documentElement;\r\n const apply = () => {\r\n const style = getComputedStyle(host);\r\n const color = (token: string, fallback: string) => {\r\n const value = style.getPropertyValue(token).trim();\r\n if (/^#[\\da-f]{3,8}$/i.test(value)) return value;\r\n if (!value || !CSS.supports('color', value)) return fallback;\r\n const canvas = document.createElement('canvas').getContext('2d');\n if (!canvas) return fallback;\n canvas.fillStyle = value;\n canvas.fillRect(0, 0, 1, 1);\n return '#' + Array.from(canvas.getImageData(0, 0, 1, 1).data, channel => channel.toString(16).padStart(2, '0')).join('');\n };\r\n const highContrast = themeRoot.classList.contains('hf-theme--high-contrast');\r\n const dark = themeRoot.classList.contains('hf-theme--dark');\r\n runtime.monaco.editor.defineTheme('harmony-flow', {\r\n base: highContrast ? 'hc-light' : dark ? 'vs-dark' : 'vs', inherit: true, rules: [],\r\n colors: {\r\n 'editor.background': color('--hf-color-surface', dark ? '#172235' : '#ffffff'),\r\n 'editor.foreground': color('--hf-color-text', dark ? '#f2f6fc' : '#142033'),\r\n 'editorLineNumber.foreground': color('--hf-color-text-muted', '#66758c'),\r\n 'editorLineNumber.activeForeground': color('--hf-color-primary', '#0a7cff'),\r\n 'editorCursor.foreground': color('--hf-color-primary', '#0a7cff'),\r\n 'editorWidget.background': color('--hf-color-surface', '#ffffff'),\r\n 'editorWidget.border': color('--hf-color-border', '#dce9f7'),\r\n 'editorSuggestWidget.background': color('--hf-color-surface', '#ffffff'),\r\n 'editorSuggestWidget.foreground': color('--hf-color-text', '#142033'),\r\n 'focusBorder': color('--hf-color-primary', '#0a7cff'),\r\n },\r\n });\r\n runtime.monaco.editor.setTheme('harmony-flow');\r\n };\r\n apply();\r\n const observer = new MutationObserver(apply);\r\n for (let node: Element | null = themeRoot; node; node = node.parentElement) {\r\n observer.observe(node, { attributes: true, attributeFilter: ['class', 'style'] });\r\n }\r\n return () => observer.disconnect();\r\n}\r\n","import type { CodeEditorProps } from '../components/CodeEditor';\nimport type { Runtime } from './loadRuntime';\nimport { observeTheme } from './theme';\n\ntype Editor = import('monaco-editor').editor.IStandaloneCodeEditor;\ntype Model = import('monaco-editor').editor.ITextModel;\ntype View = import('monaco-editor').editor.ICodeEditorViewState;\ntype Options = CodeEditorProps & { path?: string };\nlet instance = 0;\n\nexport function createSession(runtime: Runtime, host: HTMLElement, options: Options, onChange: (value: string) => void,\n onPosition: (line: number, column: number) => void) {\n const { monaco } = runtime;\n const id = ++instance;\n const models = new Map<string, { model: Model; view: View | null }>();\n let path = '';\n let syncing = false;\n const stopTheme = observeTheme(runtime, host);\n const editor: Editor = monaco.editor.create(host, {\n model: null, automaticLayout: true, minimap: { enabled: false }, fontSize: 13, lineHeight: 22,\n fontFamily: 'Consolas, \"SFMono-Regular\", Menlo, Monaco, \"Liberation Mono\", monospace',\n fontLigatures: false, padding: { top: 12, bottom: 12 }, scrollBeyondLastLine: false,\n tabSize: 2, insertSpaces: true, detectIndentation: false, renderLineHighlight: 'line',\n overviewRulerBorder: false, hideCursorInOverviewRuler: true, fixedOverflowWidgets: false,\n accessibilitySupport: 'auto', stickyScroll: { enabled: false }, tabFocusMode: true,\n });\n const changed = editor.onDidChangeModelContent(() => { if (!syncing) onChange(editor.getValue()); });\n const positioned = editor.onDidChangeCursorPosition(event => onPosition(event.position.lineNumber, event.position.column));\n\n function update(next: Options) {\n const nextPath = next.path ?? 'untitled';\n const language = ['typescript', 'javascript', 'json'].includes(next.language ?? '') ? next.language! : 'plaintext';\n if (path !== nextPath || !editor.getModel()) {\n const previous = models.get(path);\n if (previous) previous.view = editor.saveViewState();\n let entry = models.get(nextPath);\n if (!entry) {\n const uri = monaco.Uri.parse(`file:///harmony-${id}/${nextPath.split('/').map(encodeURIComponent).join('/')}`);\n entry = { model: monaco.editor.createModel(next.value, language, uri), view: null };\n }\n models.delete(nextPath);\n models.set(nextPath, entry);\n path = nextPath;\n editor.setModel(entry.model);\n if (entry.view) editor.restoreViewState(entry.view);\n if (models.size > 20) {\n const oldest = models.keys().next().value!;\n models.get(oldest)!.model.dispose();\n models.delete(oldest);\n }\n }\n const model = editor.getModel()!;\n model.updateOptions({ tabSize: 2, insertSpaces: true });\n if (model.getLanguageId() !== language) monaco.editor.setModelLanguage(model, language);\n if (model.getValue() !== next.value) {\n syncing = true;\n try { model.setValue(next.value); } finally { syncing = false; }\n }\n editor.updateOptions({ readOnly: !!next.readOnly, ariaLabel: next.label ?? '代码编辑器' });\n return model;\n }\n update(options);\n return {\n editor, update,\n dispose() {\n changed.dispose(); positioned.dispose(); stopTheme(); editor.dispose();\n models.forEach(({ model }) => model.dispose()); models.clear();\n },\n };\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","jsx","jsx","jsxs","useRef","useState","useEffect"]}