@coldsmirk/inkstone-react 0.8.3 → 0.9.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.
- package/README.md +2 -2
- package/dist/index.d.ts +8 -5
- package/dist/index.js +102 -51
- package/package.json +7 -15
- package/dist/index.cjs +0 -537
- package/dist/index.d.cts +0 -390
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ import { CodeMirrorEditor } from "@coldsmirk/inkstone-react";
|
|
|
50
50
|
/>;
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
A controlled CM6 editor: create-once view, external value changes reconcile without resetting cursor/undo, catppuccin latte/macchiato flipped by `dark`, and restyled chrome (completion tooltip with a currentColor SVG icon set, themed scrollbars, real search-panel metrics).
|
|
53
|
+
A controlled CM6 editor: create-once view, external value changes reconcile without resetting cursor/undo, catppuccin latte/macchiato flipped by `dark`, and restyled chrome (completion tooltip with a currentColor SVG icon set, hover / lint tooltips on the same frame with severity bars in flavor colors, themed scrollbars, real search-panel metrics).
|
|
54
54
|
|
|
55
55
|
- **`language`** lazily imports the matching grammar as its own chunk — the official Lezer parsers plus the `@codemirror/legacy-modes` catalog (`shell`, `dockerfile`, `ini` / `env`, `toml`, `nginx`, …). Includes the MiniJinja family — `minijinja` standalone or `minijinja-<host>` mixed variants (`minijinja-yaml`, `-json`, `-html`, `-sql`, `-shell`, `-dockerfile`, …).
|
|
56
56
|
- **`context`** — pass `{ schema }` (JSON Schema) or `{ sample }` (representative value) and MiniJinja completion suggests the render context's variables with member access. Memoize/hoist it — a fresh identity each render re-normalizes.
|
|
@@ -58,7 +58,7 @@ A controlled CM6 editor: create-once view, external value changes reconcile with
|
|
|
58
58
|
- **Metrics & layout** — `fontSize` 14 and `lineHeight` 1.6 by default; `height` / `width` size the editor; `lineWrapping`, `showLineNumbers`, `folding` are opt-in.
|
|
59
59
|
- **Extensions** — `extensions` is create-once; `dynamicExtensions` reconfigures live. The catppuccin theme sits at low precedence, so a caller theme in `dynamicExtensions` overrides it.
|
|
60
60
|
|
|
61
|
-
`useShikiHighlighter` and the `codeMirrorLanguages` / `normalizeContext` / `searchPhrasesZhCn` helpers are re-exported for hosts that build custom surfaces next to the components.
|
|
61
|
+
`useShikiHighlighter` and the `codeMirrorLanguages` / `monacoLanguages` / `normalizeContext` / `searchPhrasesZhCn` helpers are re-exported for hosts that build custom surfaces next to the components.
|
|
62
62
|
|
|
63
63
|
## License
|
|
64
64
|
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { EditorView } from "@codemirror/view";
|
|
|
3
3
|
import { CodeMirrorLanguage, CodeMirrorLanguage as CodeMirrorLanguage$1, EditorContext, EditorContext as EditorContext$1, codeMirrorLanguages, normalizeContext, searchPhrasesZhCn } from "@coldsmirk/inkstone-codemirror";
|
|
4
4
|
import { ReactNode, RefObject } from "react";
|
|
5
5
|
import { HighlighterCore } from "@coldsmirk/inkstone-core";
|
|
6
|
-
import { MonacoHostOptions, MonacoLanguage, MonacoLanguage as MonacoLanguage$1, MonacoUiLocale } from "@coldsmirk/inkstone-monaco";
|
|
6
|
+
import { MonacoHostOptions, MonacoLanguage, MonacoLanguage as MonacoLanguage$1, MonacoUiLocale, monacoLanguages } from "@coldsmirk/inkstone-monaco";
|
|
7
7
|
import { BeforeMount, OnMount } from "@monaco-editor/react";
|
|
8
8
|
import { editor } from "monaco-editor";
|
|
9
9
|
|
|
@@ -268,8 +268,9 @@ interface MonacoEditorProps {
|
|
|
268
268
|
disableContextMenu?: boolean;
|
|
269
269
|
/**
|
|
270
270
|
* Swallow the find/replace widget's keyboard entries — Ctrl/Cmd+F (find), Ctrl+H and
|
|
271
|
-
* Cmd+Alt+F (replace). Scoped to this editor via
|
|
272
|
-
* service is page-global, so an unscoped rule would rewire every editor on the page
|
|
271
|
+
* Cmd+Alt+F (replace). Scoped to this editor via its own context key: the standalone keybinding
|
|
272
|
+
* service is page-global, so an unscoped rule would rewire every editor on the page, and
|
|
273
|
+
* {@link disableCommandPalette} is gated separately so enabling one never implies the other.
|
|
273
274
|
* Fixed at creation.
|
|
274
275
|
*
|
|
275
276
|
* @default false
|
|
@@ -286,7 +287,9 @@ interface MonacoEditorProps {
|
|
|
286
287
|
disableCommandPalette?: boolean;
|
|
287
288
|
/**
|
|
288
289
|
* Model path — give each logically distinct document its own so view state (cursor,
|
|
289
|
-
* folds) survives remounts
|
|
290
|
+
* folds) survives remounts, and so a document switch never routes the outgoing model's
|
|
291
|
+
* text into the new document's `onChange` (changes from a model this prop no longer
|
|
292
|
+
* names are dropped).
|
|
290
293
|
*/
|
|
291
294
|
path?: string;
|
|
292
295
|
height?: string | number;
|
|
@@ -387,4 +390,4 @@ declare function useShikiHighlighter(): {
|
|
|
387
390
|
highlighterRef: RefObject<HighlighterCore | null>;
|
|
388
391
|
};
|
|
389
392
|
//#endregion
|
|
390
|
-
export { CodeMirrorEditor, type CodeMirrorEditorProps, type CodeMirrorLanguage, DEFAULT_MONACO_OPTIONS, type EditorContext, MonacoEditor, type MonacoEditorProps, type MonacoLanguage, type ShikiState, codeMirrorLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
|
|
393
|
+
export { CodeMirrorEditor, type CodeMirrorEditorProps, type CodeMirrorLanguage, DEFAULT_MONACO_OPTIONS, type EditorContext, MonacoEditor, type MonacoEditorProps, type MonacoLanguage, type ShikiState, codeMirrorLanguages, monacoLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,21 @@ import { indentUnit } from "@codemirror/language";
|
|
|
4
4
|
import { EditorState, Prec } from "@codemirror/state";
|
|
5
5
|
import { EditorView } from "@codemirror/view";
|
|
6
6
|
import { ControlledEditorHost, codeMirrorLanguages, documentExtensions, loadLanguage, normalizeContext, normalizeContext as normalizeContext$1, searchPhrasesZhCn, searchPhrasesZhCn as searchPhrasesZhCn$1, setMinijinjaContext } from "@coldsmirk/inkstone-codemirror";
|
|
7
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { useCallback, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
8
|
import { jsx } from "react/jsx-runtime";
|
|
9
9
|
import { getHighlighter, shikiThemeId } from "@coldsmirk/inkstone-core";
|
|
10
|
-
import { ensureMonacoHost } from "@coldsmirk/inkstone-monaco";
|
|
10
|
+
import { disabledKeybindings, ensureMonacoHost, installDisabledKeybindings, monacoLanguages } from "@coldsmirk/inkstone-monaco";
|
|
11
11
|
import { Editor, loader } from "@monaco-editor/react";
|
|
12
12
|
import { shikiToMonaco } from "@shikijs/monaco";
|
|
13
|
+
//#region src/use-latest.ts
|
|
14
|
+
function useLatest(value) {
|
|
15
|
+
const ref = useRef(value);
|
|
16
|
+
useInsertionEffect(() => {
|
|
17
|
+
ref.current = value;
|
|
18
|
+
});
|
|
19
|
+
return ref;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
13
22
|
//#region src/codemirror-editor.tsx
|
|
14
23
|
function toCssSize(value) {
|
|
15
24
|
if (value === void 0) return;
|
|
@@ -55,6 +64,7 @@ function chromeTheme(dark) {
|
|
|
55
64
|
};
|
|
56
65
|
return EditorView.theme({
|
|
57
66
|
"&": { colorScheme: dark ? "dark" : "light" },
|
|
67
|
+
".cm-tooltip": frame,
|
|
58
68
|
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
59
69
|
...frame,
|
|
60
70
|
"& > ul": {
|
|
@@ -122,6 +132,29 @@ function chromeTheme(dark) {
|
|
|
122
132
|
padding: "8px 10px",
|
|
123
133
|
maxWidth: "26em"
|
|
124
134
|
},
|
|
135
|
+
".cm-tooltip-lint": { padding: "4px" },
|
|
136
|
+
".cm-diagnostic": {
|
|
137
|
+
margin: "0",
|
|
138
|
+
padding: "3px 8px",
|
|
139
|
+
borderLeftWidth: "3px",
|
|
140
|
+
borderRadius: "5px",
|
|
141
|
+
lineHeight: "1.45"
|
|
142
|
+
},
|
|
143
|
+
".cm-diagnostic-error": { borderLeftColor: colors.red.hex },
|
|
144
|
+
".cm-diagnostic-warning": { borderLeftColor: colors.yellow.hex },
|
|
145
|
+
".cm-diagnostic-info": { borderLeftColor: colors.overlay1.hex },
|
|
146
|
+
".cm-diagnostic-hint": { borderLeftColor: colors.blue.hex },
|
|
147
|
+
".cm-diagnosticAction": {
|
|
148
|
+
padding: "2px 6px",
|
|
149
|
+
backgroundColor: colors.surface1.hex,
|
|
150
|
+
color: colors.text.hex,
|
|
151
|
+
borderRadius: "4px"
|
|
152
|
+
},
|
|
153
|
+
".cm-diagnosticSource": {
|
|
154
|
+
fontSize: "85%",
|
|
155
|
+
color: colors.overlay1.hex,
|
|
156
|
+
opacity: "1"
|
|
157
|
+
},
|
|
125
158
|
"&.cm-focused": { outline: "none" },
|
|
126
159
|
".cm-activeLine": { backgroundColor: alphaOf(colors.overlay0, .12) },
|
|
127
160
|
".cm-activeLineGutter": { backgroundColor: alphaOf(colors.overlay0, .12) },
|
|
@@ -248,14 +281,11 @@ function defaultThemeExtensions(dark, height, width, fontSize, lineHeight) {
|
|
|
248
281
|
function CodeMirrorEditor({ value, onChange, language, context, placeholder, lineWrapping = false, showLineNumbers = false, folding = false, spellcheck = false, search = false, extensions, dynamicExtensions, dark = false, locale = "en", height, width, fontSize = 14, lineHeight = 1.6, tabSize, className, onMount, onFocus, onBlur }) {
|
|
249
282
|
const containerRef = useRef(null);
|
|
250
283
|
const hostRef = useRef(null);
|
|
251
|
-
const
|
|
252
|
-
onChangeRef
|
|
253
|
-
const onMountRef =
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
onFocusRef.current = onFocus;
|
|
257
|
-
const onBlurRef = useRef(onBlur);
|
|
258
|
-
onBlurRef.current = onBlur;
|
|
284
|
+
const valueTransitionRef = useRef(false);
|
|
285
|
+
const onChangeRef = useLatest(onChange);
|
|
286
|
+
const onMountRef = useLatest(onMount);
|
|
287
|
+
const onFocusRef = useLatest(onFocus);
|
|
288
|
+
const onBlurRef = useLatest(onBlur);
|
|
259
289
|
const lastContextRef = useRef(null);
|
|
260
290
|
const [languageExtension, setLanguageExtension] = useState([]);
|
|
261
291
|
useEffect(() => {
|
|
@@ -268,6 +298,7 @@ function CodeMirrorEditor({ value, onChange, language, context, placeholder, lin
|
|
|
268
298
|
if (!cancelled) setLanguageExtension([extension]);
|
|
269
299
|
}).catch((error) => {
|
|
270
300
|
console.error("inkstone: failed to load CodeMirror language", language, error);
|
|
301
|
+
if (!cancelled) setLanguageExtension([]);
|
|
271
302
|
});
|
|
272
303
|
return () => {
|
|
273
304
|
cancelled = true;
|
|
@@ -297,7 +328,9 @@ function CodeMirrorEditor({ value, onChange, language, context, placeholder, lin
|
|
|
297
328
|
const host = new ControlledEditorHost({
|
|
298
329
|
parent: container,
|
|
299
330
|
doc: value,
|
|
300
|
-
onChange: (next) =>
|
|
331
|
+
onChange: (next) => {
|
|
332
|
+
if (!valueTransitionRef.current) onChangeRef.current?.(next);
|
|
333
|
+
},
|
|
301
334
|
extensions: [
|
|
302
335
|
...documentExtensions({
|
|
303
336
|
placeholder,
|
|
@@ -322,8 +355,16 @@ function CodeMirrorEditor({ value, onChange, language, context, placeholder, lin
|
|
|
322
355
|
hostRef.current = null;
|
|
323
356
|
};
|
|
324
357
|
}, []);
|
|
325
|
-
|
|
326
|
-
hostRef.current
|
|
358
|
+
useInsertionEffect(() => {
|
|
359
|
+
const host = hostRef.current;
|
|
360
|
+
valueTransitionRef.current = host !== null && host.view.state.doc.toString() !== value;
|
|
361
|
+
}, [value]);
|
|
362
|
+
useLayoutEffect(() => {
|
|
363
|
+
try {
|
|
364
|
+
hostRef.current?.setValue(value);
|
|
365
|
+
} finally {
|
|
366
|
+
valueTransitionRef.current = false;
|
|
367
|
+
}
|
|
327
368
|
}, [value]);
|
|
328
369
|
useEffect(() => {
|
|
329
370
|
hostRef.current?.reconfigure(dynamic);
|
|
@@ -419,15 +460,6 @@ function configureLoader(monaco) {
|
|
|
419
460
|
loaderConfigured = true;
|
|
420
461
|
loader.config({ monaco });
|
|
421
462
|
}
|
|
422
|
-
const DISABLED_KEYBINDINGS_CONTEXT_KEY = "inkstoneKeybindingsDisabled";
|
|
423
|
-
function disabledKeybindings(monaco, disableFind, disableCommandPalette) {
|
|
424
|
-
const { KeyCode, KeyMod } = monaco;
|
|
425
|
-
return [...disableFind ? [
|
|
426
|
-
KeyMod.CtrlCmd | KeyCode.KeyF,
|
|
427
|
-
KeyMod.CtrlCmd | KeyCode.KeyH,
|
|
428
|
-
KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyF
|
|
429
|
-
] : [], ...disableCommandPalette ? [KeyCode.F1] : []];
|
|
430
|
-
}
|
|
431
463
|
let shikiRegistered = false;
|
|
432
464
|
function registerShikiHighlighting(monaco, highlighter) {
|
|
433
465
|
if (shikiRegistered) return;
|
|
@@ -442,14 +474,50 @@ function MonacoEditor({ value, onChange, language = "javascript", dark = false,
|
|
|
442
474
|
const { state: shikiState, highlighterRef } = useShikiHighlighter();
|
|
443
475
|
const hostOptionsRef = useRef(hostOptions);
|
|
444
476
|
const localeRef = useRef(locale);
|
|
445
|
-
const beforeMountRef =
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
const
|
|
452
|
-
|
|
477
|
+
const beforeMountRef = useLatest(beforeMount);
|
|
478
|
+
const onMountRef = useLatest(onMount);
|
|
479
|
+
const onFocusRef = useLatest(onFocus);
|
|
480
|
+
const onBlurRef = useLatest(onBlur);
|
|
481
|
+
const onChangeRef = useLatest(onChange);
|
|
482
|
+
const appliedPathRef = useRef(path);
|
|
483
|
+
const pathChangingRef = useRef(false);
|
|
484
|
+
useInsertionEffect(() => {
|
|
485
|
+
pathChangingRef.current = path !== appliedPathRef.current;
|
|
486
|
+
}, [path]);
|
|
487
|
+
useEffect(() => {
|
|
488
|
+
appliedPathRef.current = path;
|
|
489
|
+
pathChangingRef.current = false;
|
|
490
|
+
}, [path]);
|
|
491
|
+
const handleChange = useCallback((next) => {
|
|
492
|
+
if (pathChangingRef.current) return;
|
|
493
|
+
onChangeRef.current?.(next ?? "");
|
|
494
|
+
}, [onChangeRef]);
|
|
495
|
+
const mergedOptions = useMemo(() => {
|
|
496
|
+
return {
|
|
497
|
+
...DEFAULT_MONACO_OPTIONS,
|
|
498
|
+
...documentOptions({
|
|
499
|
+
placeholder,
|
|
500
|
+
lineWrapping,
|
|
501
|
+
showLineNumbers,
|
|
502
|
+
folding,
|
|
503
|
+
disableContextMenu,
|
|
504
|
+
fontSize,
|
|
505
|
+
lineHeight,
|
|
506
|
+
tabSize
|
|
507
|
+
}),
|
|
508
|
+
...options
|
|
509
|
+
};
|
|
510
|
+
}, [
|
|
511
|
+
placeholder,
|
|
512
|
+
lineWrapping,
|
|
513
|
+
showLineNumbers,
|
|
514
|
+
folding,
|
|
515
|
+
disableContextMenu,
|
|
516
|
+
fontSize,
|
|
517
|
+
lineHeight,
|
|
518
|
+
tabSize,
|
|
519
|
+
options
|
|
520
|
+
]);
|
|
453
521
|
useEffect(() => {
|
|
454
522
|
let cancelled = false;
|
|
455
523
|
ensureMonacoHost({
|
|
@@ -474,11 +542,7 @@ function MonacoEditor({ value, onChange, language = "javascript", dark = false,
|
|
|
474
542
|
beforeMountRef.current?.(monaco);
|
|
475
543
|
};
|
|
476
544
|
const handleMount = (editorInstance, monaco) => {
|
|
477
|
-
|
|
478
|
-
if (swallowed.length > 0) {
|
|
479
|
-
editorInstance.createContextKey(DISABLED_KEYBINDINGS_CONTEXT_KEY, true);
|
|
480
|
-
for (const keybinding of swallowed) editorInstance.addCommand(keybinding, () => void 0, DISABLED_KEYBINDINGS_CONTEXT_KEY);
|
|
481
|
-
}
|
|
545
|
+
installDisabledKeybindings(monaco, editorInstance, disabledKeybindings(monaco, disableFind, disableCommandPalette));
|
|
482
546
|
editorInstance.onDidFocusEditorText(() => onFocusRef.current?.());
|
|
483
547
|
editorInstance.onDidBlurEditorText(() => onBlurRef.current?.());
|
|
484
548
|
onMountRef.current?.(editorInstance, monaco);
|
|
@@ -489,27 +553,14 @@ function MonacoEditor({ value, onChange, language = "javascript", dark = false,
|
|
|
489
553
|
height,
|
|
490
554
|
language,
|
|
491
555
|
loading,
|
|
556
|
+
options: mergedOptions,
|
|
492
557
|
path,
|
|
493
558
|
theme: shikiState === "ready" ? shikiThemeId(dark) : dark ? "vs-dark" : "vs",
|
|
494
559
|
value,
|
|
495
560
|
width,
|
|
496
|
-
|
|
497
|
-
...DEFAULT_MONACO_OPTIONS,
|
|
498
|
-
...documentOptions({
|
|
499
|
-
placeholder,
|
|
500
|
-
lineWrapping,
|
|
501
|
-
showLineNumbers,
|
|
502
|
-
folding,
|
|
503
|
-
disableContextMenu,
|
|
504
|
-
fontSize,
|
|
505
|
-
lineHeight,
|
|
506
|
-
tabSize
|
|
507
|
-
}),
|
|
508
|
-
...options
|
|
509
|
-
},
|
|
510
|
-
onChange: (next) => onChange?.(next ?? ""),
|
|
561
|
+
onChange: handleChange,
|
|
511
562
|
onMount: handleMount
|
|
512
563
|
});
|
|
513
564
|
}
|
|
514
565
|
//#endregion
|
|
515
|
-
export { CodeMirrorEditor, DEFAULT_MONACO_OPTIONS, MonacoEditor, codeMirrorLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
|
|
566
|
+
export { CodeMirrorEditor, DEFAULT_MONACO_OPTIONS, MonacoEditor, codeMirrorLanguages, monacoLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldsmirk/inkstone-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Drop-in React code editors: a preconfigured Monaco <MonacoEditor> (offline workers, Shiki catppuccin themes, dark switching, opt-in zh-CN UI) and a controlled CodeMirror 6 <CodeMirrorEditor> (catppuccin themes, dark switching, sizing).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -25,19 +25,11 @@
|
|
|
25
25
|
"type": "module",
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
"default": "./dist/index.js"
|
|
31
|
-
},
|
|
32
|
-
"require": {
|
|
33
|
-
"types": "./dist/index.d.cts",
|
|
34
|
-
"default": "./dist/index.cjs"
|
|
35
|
-
}
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
36
30
|
},
|
|
37
31
|
"./package.json": "./package.json"
|
|
38
32
|
},
|
|
39
|
-
"main": "./dist/index.cjs",
|
|
40
|
-
"module": "./dist/index.js",
|
|
41
33
|
"types": "./dist/index.d.ts",
|
|
42
34
|
"files": [
|
|
43
35
|
"dist"
|
|
@@ -47,9 +39,9 @@
|
|
|
47
39
|
"@catppuccin/palette": "^1.8.0",
|
|
48
40
|
"@monaco-editor/react": "^4.7.0",
|
|
49
41
|
"@shikijs/monaco": "^4.3.1",
|
|
50
|
-
"@coldsmirk/inkstone-codemirror": "^0.
|
|
51
|
-
"@coldsmirk/inkstone-core": "^0.
|
|
52
|
-
"@coldsmirk/inkstone-monaco": "^0.
|
|
42
|
+
"@coldsmirk/inkstone-codemirror": "^0.9.0",
|
|
43
|
+
"@coldsmirk/inkstone-core": "^0.9.0",
|
|
44
|
+
"@coldsmirk/inkstone-monaco": "^0.9.0"
|
|
53
45
|
},
|
|
54
46
|
"devDependencies": {
|
|
55
47
|
"@codemirror/autocomplete": "^6.20.3",
|
|
@@ -73,7 +65,7 @@
|
|
|
73
65
|
"react": ">=19"
|
|
74
66
|
},
|
|
75
67
|
"engines": {
|
|
76
|
-
"node": ">=
|
|
68
|
+
"node": ">=24"
|
|
77
69
|
},
|
|
78
70
|
"publishConfig": {
|
|
79
71
|
"access": "public"
|
package/dist/index.cjs
DELETED
|
@@ -1,537 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let _catppuccin_codemirror = require("@catppuccin/codemirror");
|
|
3
|
-
let _catppuccin_palette = require("@catppuccin/palette");
|
|
4
|
-
let _codemirror_language = require("@codemirror/language");
|
|
5
|
-
let _codemirror_state = require("@codemirror/state");
|
|
6
|
-
let _codemirror_view = require("@codemirror/view");
|
|
7
|
-
let _coldsmirk_inkstone_codemirror = require("@coldsmirk/inkstone-codemirror");
|
|
8
|
-
let react = require("react");
|
|
9
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
-
let _coldsmirk_inkstone_core = require("@coldsmirk/inkstone-core");
|
|
11
|
-
let _coldsmirk_inkstone_monaco = require("@coldsmirk/inkstone-monaco");
|
|
12
|
-
let _monaco_editor_react = require("@monaco-editor/react");
|
|
13
|
-
let _shikijs_monaco = require("@shikijs/monaco");
|
|
14
|
-
//#region src/codemirror-editor.tsx
|
|
15
|
-
function toCssSize(value) {
|
|
16
|
-
if (value === void 0) return;
|
|
17
|
-
return typeof value === "number" ? `${value}px` : value;
|
|
18
|
-
}
|
|
19
|
-
function alphaOf(color, alphaValue) {
|
|
20
|
-
return `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${alphaValue})`;
|
|
21
|
-
}
|
|
22
|
-
function completionIconMask(body) {
|
|
23
|
-
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">${body}</svg>`;
|
|
24
|
-
return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
|
|
25
|
-
}
|
|
26
|
-
const COMPLETION_ICON_FALLBACK = completionIconMask("<circle cx=\"8\" cy=\"8\" r=\"2.5\"/>");
|
|
27
|
-
const COMPLETION_ICONS = {
|
|
28
|
-
keyword: completionIconMask("<path d=\"M5.5 5 2.5 8l3 3\"/><path d=\"m10.5 5 3 3-3 3\"/>"),
|
|
29
|
-
function: completionIconMask("<path d=\"M10.8 3.4c-2-.4-2.9.7-3.2 2.5L6.4 12c-.3 1.7-1.2 2.2-2.6 1.8\"/><path d=\"M4.6 7.5h5\"/>"),
|
|
30
|
-
method: completionIconMask("<path d=\"M10.8 3.4c-2-.4-2.9.7-3.2 2.5L6.4 12c-.3 1.7-1.2 2.2-2.6 1.8\"/><path d=\"M4.6 7.5h5\"/>"),
|
|
31
|
-
variable: completionIconMask("<path d=\"M4 5c2.2 0 5.3 6 8 6\"/><path d=\"M12 5c-2.7 0-5.8 6-8 6\"/>"),
|
|
32
|
-
constant: completionIconMask("<path d=\"M3.5 5.2h9\"/><path d=\"M6.2 5.2v6.3\"/><path d=\"M10.2 5.2v4.4c0 1.3.6 1.9 1.7 1.9\"/>"),
|
|
33
|
-
property: completionIconMask("<circle cx=\"4.9\" cy=\"11.1\" r=\"1.8\"/><circle cx=\"11.1\" cy=\"4.9\" r=\"1.8\"/><path d=\"M6.4 9.6l3.2-3.2\"/>"),
|
|
34
|
-
class: completionIconMask("<rect x=\"3.5\" y=\"3.5\" width=\"9\" height=\"9\" rx=\"2.2\"/>"),
|
|
35
|
-
interface: completionIconMask("<circle cx=\"8\" cy=\"8\" r=\"4.5\"/>"),
|
|
36
|
-
type: completionIconMask("<path d=\"M4 4.5h8\"/><path d=\"M8 4.5V12\"/>"),
|
|
37
|
-
enum: completionIconMask("<path d=\"M6.5 4.5h6\"/><path d=\"M6.5 8h6\"/><path d=\"M6.5 11.5h6\"/><path d=\"M3.4 4.5h.01\"/><path d=\"M3.4 8h.01\"/><path d=\"M3.4 11.5h.01\"/>"),
|
|
38
|
-
namespace: completionIconMask("<path d=\"M6.2 3.5c-1.3 0-1.9.6-1.9 1.9v1.2c0 .9-.4 1.4-1.3 1.4.9 0 1.3.5 1.3 1.4v1.2c0 1.3.6 1.9 1.9 1.9\"/><path d=\"M9.8 3.5c1.3 0 1.9.6 1.9 1.9v1.2c0 .9.4 1.4 1.3 1.4-.9 0-1.3.5-1.3 1.4v1.2c0 1.3-.6 1.9-1.9 1.9\"/>"),
|
|
39
|
-
text: completionIconMask("<path d=\"M3.5 5h9\"/><path d=\"M3.5 8h9\"/><path d=\"M3.5 11h5.5\"/>")
|
|
40
|
-
};
|
|
41
|
-
function completionIconRules() {
|
|
42
|
-
const rules = {};
|
|
43
|
-
for (const [kind, mask] of Object.entries(COMPLETION_ICONS)) rules[`.cm-completionIcon-${kind}:after`] = {
|
|
44
|
-
maskImage: mask,
|
|
45
|
-
WebkitMaskImage: mask
|
|
46
|
-
};
|
|
47
|
-
return rules;
|
|
48
|
-
}
|
|
49
|
-
function chromeTheme(dark) {
|
|
50
|
-
const { colors } = dark ? _catppuccin_palette.flavors.macchiato : _catppuccin_palette.flavors.latte;
|
|
51
|
-
const hairline = `1px solid ${alphaOf(colors.overlay0, .35)}`;
|
|
52
|
-
const frame = {
|
|
53
|
-
border: hairline,
|
|
54
|
-
borderRadius: "8px",
|
|
55
|
-
boxShadow: dark ? "0 8px 24px rgba(0, 0, 0, 0.5)" : "0 8px 24px rgba(0, 0, 0, 0.12)"
|
|
56
|
-
};
|
|
57
|
-
return _codemirror_view.EditorView.theme({
|
|
58
|
-
"&": { colorScheme: dark ? "dark" : "light" },
|
|
59
|
-
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
60
|
-
...frame,
|
|
61
|
-
"& > ul": {
|
|
62
|
-
borderRadius: "7px",
|
|
63
|
-
padding: "4px",
|
|
64
|
-
maxHeight: "16em"
|
|
65
|
-
},
|
|
66
|
-
"& > ul > li": {
|
|
67
|
-
display: "flex",
|
|
68
|
-
alignItems: "center",
|
|
69
|
-
padding: "3px 8px",
|
|
70
|
-
borderRadius: "5px",
|
|
71
|
-
lineHeight: "1.45"
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
".cm-completionLabel": {
|
|
75
|
-
minWidth: "0",
|
|
76
|
-
overflow: "hidden",
|
|
77
|
-
textOverflow: "ellipsis"
|
|
78
|
-
},
|
|
79
|
-
".cm-completionMatchedText": {
|
|
80
|
-
textDecoration: "none",
|
|
81
|
-
fontWeight: "600",
|
|
82
|
-
color: colors.blue.hex
|
|
83
|
-
},
|
|
84
|
-
".cm-completionDetail": {
|
|
85
|
-
marginLeft: "auto",
|
|
86
|
-
paddingLeft: "12px",
|
|
87
|
-
fontStyle: "normal",
|
|
88
|
-
fontSize: "85%",
|
|
89
|
-
color: colors.overlay1.hex
|
|
90
|
-
},
|
|
91
|
-
".cm-completionIcon": {
|
|
92
|
-
width: "14px",
|
|
93
|
-
paddingRight: "8px",
|
|
94
|
-
opacity: "1",
|
|
95
|
-
color: colors.overlay1.hex
|
|
96
|
-
},
|
|
97
|
-
".cm-completionIcon:after": {
|
|
98
|
-
content: "''",
|
|
99
|
-
display: "block",
|
|
100
|
-
width: "12px",
|
|
101
|
-
height: "12px",
|
|
102
|
-
backgroundColor: "currentColor",
|
|
103
|
-
maskImage: COMPLETION_ICON_FALLBACK,
|
|
104
|
-
WebkitMaskImage: COMPLETION_ICON_FALLBACK,
|
|
105
|
-
maskRepeat: "no-repeat",
|
|
106
|
-
WebkitMaskRepeat: "no-repeat",
|
|
107
|
-
maskPosition: "center",
|
|
108
|
-
WebkitMaskPosition: "center",
|
|
109
|
-
maskSize: "contain",
|
|
110
|
-
WebkitMaskSize: "contain"
|
|
111
|
-
},
|
|
112
|
-
...completionIconRules(),
|
|
113
|
-
".cm-completionIcon-keyword": { color: colors.mauve.hex },
|
|
114
|
-
".cm-completionIcon-function, .cm-completionIcon-method": { color: colors.blue.hex },
|
|
115
|
-
".cm-completionIcon-variable": { color: colors.peach.hex },
|
|
116
|
-
".cm-completionIcon-constant": { color: colors.sky.hex },
|
|
117
|
-
".cm-completionIcon-property": { color: colors.teal.hex },
|
|
118
|
-
".cm-completionIcon-namespace": { color: colors.sapphire.hex },
|
|
119
|
-
".cm-completionIcon-text": { color: colors.overlay1.hex },
|
|
120
|
-
".cm-completionIcon-class, .cm-completionIcon-type, .cm-completionIcon-interface, .cm-completionIcon-enum": { color: colors.yellow.hex },
|
|
121
|
-
".cm-tooltip.cm-completionInfo": {
|
|
122
|
-
...frame,
|
|
123
|
-
padding: "8px 10px",
|
|
124
|
-
maxWidth: "26em"
|
|
125
|
-
},
|
|
126
|
-
"&.cm-focused": { outline: "none" },
|
|
127
|
-
".cm-activeLine": { backgroundColor: alphaOf(colors.overlay0, .12) },
|
|
128
|
-
".cm-activeLineGutter": { backgroundColor: alphaOf(colors.overlay0, .12) },
|
|
129
|
-
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": { backgroundColor: alphaOf(colors.blue, dark ? .35 : .25) },
|
|
130
|
-
".cm-selectionBackground": { backgroundColor: alphaOf(colors.blue, dark ? .2 : .14) },
|
|
131
|
-
".cm-content ::selection": { backgroundColor: alphaOf(colors.blue, dark ? .35 : .25) },
|
|
132
|
-
".cm-scroller, .cm-tooltip-autocomplete > ul, .cm-tooltip.cm-completionInfo": {
|
|
133
|
-
scrollbarWidth: "thin",
|
|
134
|
-
scrollbarColor: `${alphaOf(colors.overlay0, .55)} transparent`
|
|
135
|
-
},
|
|
136
|
-
".cm-panels.cm-panels-top": { borderBottom: hairline },
|
|
137
|
-
".cm-panels.cm-panels-bottom": { borderTop: hairline },
|
|
138
|
-
".cm-panel.cm-search, .cm-panel.cm-gotoLine": {
|
|
139
|
-
position: "relative",
|
|
140
|
-
display: "flex",
|
|
141
|
-
flexWrap: "wrap",
|
|
142
|
-
alignItems: "center",
|
|
143
|
-
columnGap: "8px",
|
|
144
|
-
rowGap: "8px",
|
|
145
|
-
margin: "0",
|
|
146
|
-
padding: "10px 44px 10px 14px"
|
|
147
|
-
},
|
|
148
|
-
".cm-panel.cm-search br": {
|
|
149
|
-
flexBasis: "100%",
|
|
150
|
-
height: "0",
|
|
151
|
-
margin: "0",
|
|
152
|
-
border: "none"
|
|
153
|
-
},
|
|
154
|
-
".cm-panel.cm-search label, .cm-panel.cm-gotoLine label": {
|
|
155
|
-
display: "inline-flex",
|
|
156
|
-
alignItems: "center",
|
|
157
|
-
gap: "6px",
|
|
158
|
-
margin: "0",
|
|
159
|
-
fontSize: "12.5px",
|
|
160
|
-
color: colors.subtext0.hex,
|
|
161
|
-
cursor: "pointer",
|
|
162
|
-
userSelect: "none"
|
|
163
|
-
},
|
|
164
|
-
".cm-panel.cm-search input[type=checkbox]": {
|
|
165
|
-
margin: "0",
|
|
166
|
-
width: "14px",
|
|
167
|
-
height: "14px",
|
|
168
|
-
accentColor: colors.blue.hex
|
|
169
|
-
},
|
|
170
|
-
".cm-panel.cm-search button[name=close]": {
|
|
171
|
-
position: "absolute",
|
|
172
|
-
top: "10px",
|
|
173
|
-
right: "10px",
|
|
174
|
-
boxSizing: "border-box",
|
|
175
|
-
width: "28px",
|
|
176
|
-
height: "28px",
|
|
177
|
-
padding: "0",
|
|
178
|
-
display: "inline-flex",
|
|
179
|
-
alignItems: "center",
|
|
180
|
-
justifyContent: "center",
|
|
181
|
-
fontSize: "16px",
|
|
182
|
-
lineHeight: "1",
|
|
183
|
-
color: colors.overlay1.hex,
|
|
184
|
-
background: "transparent",
|
|
185
|
-
border: "none",
|
|
186
|
-
borderRadius: "6px",
|
|
187
|
-
cursor: "pointer"
|
|
188
|
-
},
|
|
189
|
-
".cm-panel.cm-search button[name=close]:hover": {
|
|
190
|
-
backgroundColor: colors.surface0.hex,
|
|
191
|
-
color: colors.text.hex
|
|
192
|
-
},
|
|
193
|
-
".cm-panel .cm-textfield": {
|
|
194
|
-
boxSizing: "border-box",
|
|
195
|
-
height: "28px",
|
|
196
|
-
width: "240px",
|
|
197
|
-
maxWidth: "100%",
|
|
198
|
-
margin: "0",
|
|
199
|
-
padding: "0 10px",
|
|
200
|
-
fontSize: "12.5px",
|
|
201
|
-
color: colors.text.hex,
|
|
202
|
-
backgroundColor: colors.base.hex,
|
|
203
|
-
border: hairline,
|
|
204
|
-
borderRadius: "6px"
|
|
205
|
-
},
|
|
206
|
-
".cm-panel .cm-textfield:focus": {
|
|
207
|
-
outline: "none",
|
|
208
|
-
borderColor: alphaOf(colors.blue, .6),
|
|
209
|
-
boxShadow: `0 0 0 2px ${alphaOf(colors.blue, .2)}`
|
|
210
|
-
},
|
|
211
|
-
".cm-panel .cm-button": {
|
|
212
|
-
boxSizing: "border-box",
|
|
213
|
-
height: "28px",
|
|
214
|
-
margin: "0",
|
|
215
|
-
padding: "0 12px",
|
|
216
|
-
fontSize: "12.5px",
|
|
217
|
-
color: colors.text.hex,
|
|
218
|
-
backgroundImage: "none",
|
|
219
|
-
backgroundColor: colors.surface0.hex,
|
|
220
|
-
border: hairline,
|
|
221
|
-
borderRadius: "6px",
|
|
222
|
-
cursor: "pointer"
|
|
223
|
-
},
|
|
224
|
-
".cm-panel .cm-button:hover": { backgroundColor: colors.surface1.hex },
|
|
225
|
-
".cm-panel .cm-button:active": {
|
|
226
|
-
backgroundImage: "none",
|
|
227
|
-
backgroundColor: colors.surface1.hex
|
|
228
|
-
}
|
|
229
|
-
}, { dark });
|
|
230
|
-
}
|
|
231
|
-
function defaultThemeExtensions(dark, height, width, fontSize, lineHeight) {
|
|
232
|
-
const extensions = [_codemirror_state.Prec.low(chromeTheme(dark)), _codemirror_state.Prec.low(dark ? _catppuccin_codemirror.catppuccinMacchiato : _catppuccin_codemirror.catppuccinLatte)];
|
|
233
|
-
const cssHeight = toCssSize(height);
|
|
234
|
-
const cssWidth = toCssSize(width);
|
|
235
|
-
if (cssHeight !== void 0 || cssWidth !== void 0 || fontSize !== void 0 || lineHeight !== void 0) {
|
|
236
|
-
const root = {};
|
|
237
|
-
if (cssHeight !== void 0) root.height = cssHeight;
|
|
238
|
-
if (cssWidth !== void 0) root.width = cssWidth;
|
|
239
|
-
if (fontSize !== void 0) root.fontSize = `${fontSize}px`;
|
|
240
|
-
const spec = { "&": root };
|
|
241
|
-
const scroller = {};
|
|
242
|
-
if (cssHeight !== void 0) scroller.overflow = "auto";
|
|
243
|
-
if (lineHeight !== void 0) scroller.lineHeight = lineHeight < 8 ? String(lineHeight) : `${lineHeight}px`;
|
|
244
|
-
if (Object.keys(scroller).length > 0) spec[".cm-scroller"] = scroller;
|
|
245
|
-
extensions.push(_codemirror_view.EditorView.theme(spec));
|
|
246
|
-
}
|
|
247
|
-
return extensions;
|
|
248
|
-
}
|
|
249
|
-
function CodeMirrorEditor({ value, onChange, language, context, placeholder, lineWrapping = false, showLineNumbers = false, folding = false, spellcheck = false, search = false, extensions, dynamicExtensions, dark = false, locale = "en", height, width, fontSize = 14, lineHeight = 1.6, tabSize, className, onMount, onFocus, onBlur }) {
|
|
250
|
-
const containerRef = (0, react.useRef)(null);
|
|
251
|
-
const hostRef = (0, react.useRef)(null);
|
|
252
|
-
const onChangeRef = (0, react.useRef)(onChange);
|
|
253
|
-
onChangeRef.current = onChange;
|
|
254
|
-
const onMountRef = (0, react.useRef)(onMount);
|
|
255
|
-
onMountRef.current = onMount;
|
|
256
|
-
const onFocusRef = (0, react.useRef)(onFocus);
|
|
257
|
-
onFocusRef.current = onFocus;
|
|
258
|
-
const onBlurRef = (0, react.useRef)(onBlur);
|
|
259
|
-
onBlurRef.current = onBlur;
|
|
260
|
-
const lastContextRef = (0, react.useRef)(null);
|
|
261
|
-
const [languageExtension, setLanguageExtension] = (0, react.useState)([]);
|
|
262
|
-
(0, react.useEffect)(() => {
|
|
263
|
-
if (!language) {
|
|
264
|
-
setLanguageExtension([]);
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
let cancelled = false;
|
|
268
|
-
(0, _coldsmirk_inkstone_codemirror.loadLanguage)(language).then((extension) => {
|
|
269
|
-
if (!cancelled) setLanguageExtension([extension]);
|
|
270
|
-
}).catch((error) => {
|
|
271
|
-
console.error("inkstone: failed to load CodeMirror language", language, error);
|
|
272
|
-
});
|
|
273
|
-
return () => {
|
|
274
|
-
cancelled = true;
|
|
275
|
-
};
|
|
276
|
-
}, [language]);
|
|
277
|
-
const dynamic = (0, react.useMemo)(() => [
|
|
278
|
-
...defaultThemeExtensions(dark, height, width, fontSize, lineHeight),
|
|
279
|
-
...tabSize === void 0 ? [] : [_codemirror_state.EditorState.tabSize.of(tabSize), _codemirror_language.indentUnit.of(" ".repeat(tabSize))],
|
|
280
|
-
...locale === "zh-cn" ? [_coldsmirk_inkstone_codemirror.searchPhrasesZhCn] : [],
|
|
281
|
-
...languageExtension,
|
|
282
|
-
...dynamicExtensions ?? []
|
|
283
|
-
], [
|
|
284
|
-
dark,
|
|
285
|
-
height,
|
|
286
|
-
width,
|
|
287
|
-
fontSize,
|
|
288
|
-
lineHeight,
|
|
289
|
-
tabSize,
|
|
290
|
-
locale,
|
|
291
|
-
languageExtension,
|
|
292
|
-
dynamicExtensions
|
|
293
|
-
]);
|
|
294
|
-
const contextSchema = (0, react.useMemo)(() => context ? (0, _coldsmirk_inkstone_codemirror.normalizeContext)(context) : null, [context]);
|
|
295
|
-
(0, react.useEffect)(() => {
|
|
296
|
-
const container = containerRef.current;
|
|
297
|
-
if (!container) return;
|
|
298
|
-
const host = new _coldsmirk_inkstone_codemirror.ControlledEditorHost({
|
|
299
|
-
parent: container,
|
|
300
|
-
doc: value,
|
|
301
|
-
onChange: (next) => onChangeRef.current?.(next),
|
|
302
|
-
extensions: [
|
|
303
|
-
...(0, _coldsmirk_inkstone_codemirror.documentExtensions)({
|
|
304
|
-
placeholder,
|
|
305
|
-
lineWrapping,
|
|
306
|
-
showLineNumbers,
|
|
307
|
-
folding,
|
|
308
|
-
spellcheck,
|
|
309
|
-
search
|
|
310
|
-
}),
|
|
311
|
-
_codemirror_view.EditorView.updateListener.of((update) => {
|
|
312
|
-
if (update.focusChanged) if (update.view.hasFocus) onFocusRef.current?.();
|
|
313
|
-
else onBlurRef.current?.();
|
|
314
|
-
}),
|
|
315
|
-
...extensions ?? []
|
|
316
|
-
],
|
|
317
|
-
dynamicExtensions: dynamic
|
|
318
|
-
});
|
|
319
|
-
hostRef.current = host;
|
|
320
|
-
onMountRef.current?.(host.view);
|
|
321
|
-
return () => {
|
|
322
|
-
host.destroy();
|
|
323
|
-
hostRef.current = null;
|
|
324
|
-
};
|
|
325
|
-
}, []);
|
|
326
|
-
(0, react.useEffect)(() => {
|
|
327
|
-
hostRef.current?.setValue(value);
|
|
328
|
-
}, [value]);
|
|
329
|
-
(0, react.useEffect)(() => {
|
|
330
|
-
hostRef.current?.reconfigure(dynamic);
|
|
331
|
-
}, [dynamic]);
|
|
332
|
-
(0, react.useEffect)(() => {
|
|
333
|
-
const host = hostRef.current;
|
|
334
|
-
if (!host) return;
|
|
335
|
-
const key = contextSchema ? JSON.stringify(contextSchema) : "";
|
|
336
|
-
const last = lastContextRef.current;
|
|
337
|
-
if (last && last.key === key && last.language === languageExtension) return;
|
|
338
|
-
lastContextRef.current = {
|
|
339
|
-
key,
|
|
340
|
-
language: languageExtension
|
|
341
|
-
};
|
|
342
|
-
if (key === "" && (!last || last.key === "")) return;
|
|
343
|
-
host.view.dispatch({ effects: _coldsmirk_inkstone_codemirror.setMinijinjaContext.of(contextSchema) });
|
|
344
|
-
}, [contextSchema, languageExtension]);
|
|
345
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
346
|
-
ref: containerRef,
|
|
347
|
-
className
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
//#endregion
|
|
351
|
-
//#region src/use-shiki-highlighter.ts
|
|
352
|
-
function useShikiHighlighter() {
|
|
353
|
-
const [state, setState] = (0, react.useState)("loading");
|
|
354
|
-
const highlighterRef = (0, react.useRef)(null);
|
|
355
|
-
(0, react.useEffect)(() => {
|
|
356
|
-
let cancelled = false;
|
|
357
|
-
(0, _coldsmirk_inkstone_core.getHighlighter)().then((highlighter) => {
|
|
358
|
-
if (cancelled) return;
|
|
359
|
-
highlighterRef.current = highlighter;
|
|
360
|
-
setState("ready");
|
|
361
|
-
}).catch((error) => {
|
|
362
|
-
console.error("inkstone: shiki highlighter failed to load", error);
|
|
363
|
-
if (!cancelled) setState("failed");
|
|
364
|
-
});
|
|
365
|
-
return () => {
|
|
366
|
-
cancelled = true;
|
|
367
|
-
};
|
|
368
|
-
}, []);
|
|
369
|
-
return {
|
|
370
|
-
state,
|
|
371
|
-
highlighterRef
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
//#endregion
|
|
375
|
-
//#region src/monaco-editor.tsx
|
|
376
|
-
const DEFAULT_MONACO_OPTIONS = {
|
|
377
|
-
find: { addExtraSpaceOnTop: false },
|
|
378
|
-
minimap: { enabled: false },
|
|
379
|
-
fontSize: 14,
|
|
380
|
-
lineHeight: 1.6,
|
|
381
|
-
fontFamily: "var(--inkstone-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)",
|
|
382
|
-
scrollBeyondLastLine: false,
|
|
383
|
-
automaticLayout: true,
|
|
384
|
-
renderLineHighlight: "line",
|
|
385
|
-
smoothScrolling: true,
|
|
386
|
-
padding: {
|
|
387
|
-
top: 12,
|
|
388
|
-
bottom: 12
|
|
389
|
-
},
|
|
390
|
-
fixedOverflowWidgets: true,
|
|
391
|
-
quickSuggestions: {
|
|
392
|
-
other: true,
|
|
393
|
-
comments: false,
|
|
394
|
-
strings: true
|
|
395
|
-
},
|
|
396
|
-
wordBasedSuggestions: "off",
|
|
397
|
-
tabCompletion: "on",
|
|
398
|
-
scrollbar: {
|
|
399
|
-
alwaysConsumeMouseWheel: false,
|
|
400
|
-
verticalScrollbarSize: 8,
|
|
401
|
-
horizontalScrollbarSize: 8
|
|
402
|
-
}
|
|
403
|
-
};
|
|
404
|
-
function documentOptions({ placeholder, lineWrapping, showLineNumbers, folding, disableContextMenu, fontSize, lineHeight, tabSize }) {
|
|
405
|
-
const resolved = {
|
|
406
|
-
placeholder,
|
|
407
|
-
wordWrap: lineWrapping ? "on" : "off",
|
|
408
|
-
lineNumbers: showLineNumbers ? "on" : "off",
|
|
409
|
-
folding,
|
|
410
|
-
contextmenu: !disableContextMenu
|
|
411
|
-
};
|
|
412
|
-
if (fontSize !== void 0) resolved.fontSize = fontSize;
|
|
413
|
-
if (lineHeight !== void 0) resolved.lineHeight = lineHeight;
|
|
414
|
-
if (tabSize !== void 0) resolved.tabSize = tabSize;
|
|
415
|
-
return resolved;
|
|
416
|
-
}
|
|
417
|
-
let loaderConfigured = false;
|
|
418
|
-
function configureLoader(monaco) {
|
|
419
|
-
if (loaderConfigured) return;
|
|
420
|
-
loaderConfigured = true;
|
|
421
|
-
_monaco_editor_react.loader.config({ monaco });
|
|
422
|
-
}
|
|
423
|
-
const DISABLED_KEYBINDINGS_CONTEXT_KEY = "inkstoneKeybindingsDisabled";
|
|
424
|
-
function disabledKeybindings(monaco, disableFind, disableCommandPalette) {
|
|
425
|
-
const { KeyCode, KeyMod } = monaco;
|
|
426
|
-
return [...disableFind ? [
|
|
427
|
-
KeyMod.CtrlCmd | KeyCode.KeyF,
|
|
428
|
-
KeyMod.CtrlCmd | KeyCode.KeyH,
|
|
429
|
-
KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyF
|
|
430
|
-
] : [], ...disableCommandPalette ? [KeyCode.F1] : []];
|
|
431
|
-
}
|
|
432
|
-
let shikiRegistered = false;
|
|
433
|
-
function registerShikiHighlighting(monaco, highlighter) {
|
|
434
|
-
if (shikiRegistered) return;
|
|
435
|
-
shikiRegistered = true;
|
|
436
|
-
const canonical = new Set(highlighter.getLoadedLanguages().map((id) => highlighter.getLanguage(id).name));
|
|
437
|
-
const registered = new Set(monaco.languages.getLanguages().map((registeredLanguage) => registeredLanguage.id));
|
|
438
|
-
for (const lang of canonical) if (!registered.has(lang)) monaco.languages.register({ id: lang });
|
|
439
|
-
(0, _shikijs_monaco.shikiToMonaco)(highlighter, monaco);
|
|
440
|
-
}
|
|
441
|
-
function MonacoEditor({ value, onChange, language = "javascript", dark = false, locale, placeholder, lineWrapping = false, showLineNumbers = false, folding = false, disableContextMenu = false, disableFind = false, disableCommandPalette = false, fontSize, lineHeight, tabSize = 2, path, height = "100%", width, className, options, hostOptions, loading = "Loading editor…", failure = "Editor failed to load", beforeMount, onMount, onFocus, onBlur }) {
|
|
442
|
-
const [hostState, setHostState] = (0, react.useState)("loading");
|
|
443
|
-
const { state: shikiState, highlighterRef } = useShikiHighlighter();
|
|
444
|
-
const hostOptionsRef = (0, react.useRef)(hostOptions);
|
|
445
|
-
const localeRef = (0, react.useRef)(locale);
|
|
446
|
-
const beforeMountRef = (0, react.useRef)(beforeMount);
|
|
447
|
-
beforeMountRef.current = beforeMount;
|
|
448
|
-
const onMountRef = (0, react.useRef)(onMount);
|
|
449
|
-
onMountRef.current = onMount;
|
|
450
|
-
const onFocusRef = (0, react.useRef)(onFocus);
|
|
451
|
-
onFocusRef.current = onFocus;
|
|
452
|
-
const onBlurRef = (0, react.useRef)(onBlur);
|
|
453
|
-
onBlurRef.current = onBlur;
|
|
454
|
-
(0, react.useEffect)(() => {
|
|
455
|
-
let cancelled = false;
|
|
456
|
-
(0, _coldsmirk_inkstone_monaco.ensureMonacoHost)({
|
|
457
|
-
...hostOptionsRef.current,
|
|
458
|
-
locale: localeRef.current ?? hostOptionsRef.current?.locale
|
|
459
|
-
}).then((monaco) => {
|
|
460
|
-
configureLoader(monaco);
|
|
461
|
-
if (!cancelled) setHostState("ready");
|
|
462
|
-
}).catch((error) => {
|
|
463
|
-
console.error("inkstone: monaco host failed to load", error);
|
|
464
|
-
if (!cancelled) setHostState("failed");
|
|
465
|
-
});
|
|
466
|
-
return () => {
|
|
467
|
-
cancelled = true;
|
|
468
|
-
};
|
|
469
|
-
}, []);
|
|
470
|
-
if (hostState === "failed") return failure;
|
|
471
|
-
if (hostState === "loading" || shikiState === "loading") return loading;
|
|
472
|
-
const handleBeforeMount = (monaco) => {
|
|
473
|
-
const highlighter = highlighterRef.current;
|
|
474
|
-
if (highlighter) registerShikiHighlighting(monaco, highlighter);
|
|
475
|
-
beforeMountRef.current?.(monaco);
|
|
476
|
-
};
|
|
477
|
-
const handleMount = (editorInstance, monaco) => {
|
|
478
|
-
const swallowed = disabledKeybindings(monaco, disableFind, disableCommandPalette);
|
|
479
|
-
if (swallowed.length > 0) {
|
|
480
|
-
editorInstance.createContextKey(DISABLED_KEYBINDINGS_CONTEXT_KEY, true);
|
|
481
|
-
for (const keybinding of swallowed) editorInstance.addCommand(keybinding, () => void 0, DISABLED_KEYBINDINGS_CONTEXT_KEY);
|
|
482
|
-
}
|
|
483
|
-
editorInstance.onDidFocusEditorText(() => onFocusRef.current?.());
|
|
484
|
-
editorInstance.onDidBlurEditorText(() => onBlurRef.current?.());
|
|
485
|
-
onMountRef.current?.(editorInstance, monaco);
|
|
486
|
-
};
|
|
487
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_monaco_editor_react.Editor, {
|
|
488
|
-
beforeMount: handleBeforeMount,
|
|
489
|
-
className,
|
|
490
|
-
height,
|
|
491
|
-
language,
|
|
492
|
-
loading,
|
|
493
|
-
path,
|
|
494
|
-
theme: shikiState === "ready" ? (0, _coldsmirk_inkstone_core.shikiThemeId)(dark) : dark ? "vs-dark" : "vs",
|
|
495
|
-
value,
|
|
496
|
-
width,
|
|
497
|
-
options: {
|
|
498
|
-
...DEFAULT_MONACO_OPTIONS,
|
|
499
|
-
...documentOptions({
|
|
500
|
-
placeholder,
|
|
501
|
-
lineWrapping,
|
|
502
|
-
showLineNumbers,
|
|
503
|
-
folding,
|
|
504
|
-
disableContextMenu,
|
|
505
|
-
fontSize,
|
|
506
|
-
lineHeight,
|
|
507
|
-
tabSize
|
|
508
|
-
}),
|
|
509
|
-
...options
|
|
510
|
-
},
|
|
511
|
-
onChange: (next) => onChange?.(next ?? ""),
|
|
512
|
-
onMount: handleMount
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
//#endregion
|
|
516
|
-
exports.CodeMirrorEditor = CodeMirrorEditor;
|
|
517
|
-
exports.DEFAULT_MONACO_OPTIONS = DEFAULT_MONACO_OPTIONS;
|
|
518
|
-
exports.MonacoEditor = MonacoEditor;
|
|
519
|
-
Object.defineProperty(exports, "codeMirrorLanguages", {
|
|
520
|
-
enumerable: true,
|
|
521
|
-
get: function() {
|
|
522
|
-
return _coldsmirk_inkstone_codemirror.codeMirrorLanguages;
|
|
523
|
-
}
|
|
524
|
-
});
|
|
525
|
-
Object.defineProperty(exports, "normalizeContext", {
|
|
526
|
-
enumerable: true,
|
|
527
|
-
get: function() {
|
|
528
|
-
return _coldsmirk_inkstone_codemirror.normalizeContext;
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
Object.defineProperty(exports, "searchPhrasesZhCn", {
|
|
532
|
-
enumerable: true,
|
|
533
|
-
get: function() {
|
|
534
|
-
return _coldsmirk_inkstone_codemirror.searchPhrasesZhCn;
|
|
535
|
-
}
|
|
536
|
-
});
|
|
537
|
-
exports.useShikiHighlighter = useShikiHighlighter;
|
package/dist/index.d.cts
DELETED
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
import { Extension } from "@codemirror/state";
|
|
2
|
-
import { CodeMirrorLanguage, CodeMirrorLanguage as CodeMirrorLanguage$1, EditorContext, EditorContext as EditorContext$1, codeMirrorLanguages, normalizeContext, searchPhrasesZhCn } from "@coldsmirk/inkstone-codemirror";
|
|
3
|
-
import { ReactNode, RefObject } from "react";
|
|
4
|
-
import { EditorView } from "@codemirror/view";
|
|
5
|
-
import { MonacoHostOptions, MonacoLanguage, MonacoLanguage as MonacoLanguage$1, MonacoUiLocale } from "@coldsmirk/inkstone-monaco";
|
|
6
|
-
import { BeforeMount, OnMount } from "@monaco-editor/react";
|
|
7
|
-
import { editor } from "monaco-editor";
|
|
8
|
-
import { HighlighterCore } from "@coldsmirk/inkstone-core";
|
|
9
|
-
|
|
10
|
-
//#region src/codemirror-editor.d.ts
|
|
11
|
-
interface CodeMirrorEditorProps {
|
|
12
|
-
/**
|
|
13
|
-
* The controlled document text — external changes reconcile into the live editor
|
|
14
|
-
* without resetting the caret.
|
|
15
|
-
*/
|
|
16
|
-
value: string;
|
|
17
|
-
onChange?: (value: string) => void;
|
|
18
|
-
/**
|
|
19
|
-
* Language id — lazily loads the matching CodeMirror grammar as its own chunk (only the
|
|
20
|
-
* selected language is fetched, never the whole catalog). For a language outside this set,
|
|
21
|
-
* or for parser options / mixed languages, pass your own support through `extensions`.
|
|
22
|
-
*/
|
|
23
|
-
language?: CodeMirrorLanguage$1;
|
|
24
|
-
/**
|
|
25
|
-
* Render-context schema for variable / member autocomplete — currently consumed by the
|
|
26
|
-
* `minijinja` languages, where it makes `{{ }}` / `{% if %}` / `{% for x in %}` suggest the
|
|
27
|
-
* template's context variables and walk member access (`user.address.city`). Pass a JSON Schema
|
|
28
|
-
* (`{ schema }`, e.g. what Rust `schemars` derives) or a sample value (`{ sample }`); it updates
|
|
29
|
-
* reactively without recreating the editor. Memoize/hoist it — a new identity each render
|
|
30
|
-
* re-normalizes and re-dispatches. No effect on languages that don't read it.
|
|
31
|
-
*/
|
|
32
|
-
context?: EditorContext$1;
|
|
33
|
-
placeholder?: string;
|
|
34
|
-
/**
|
|
35
|
-
* Soft-wrap long lines.
|
|
36
|
-
*
|
|
37
|
-
* @default false
|
|
38
|
-
*/
|
|
39
|
-
lineWrapping?: boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Show the line-number gutter. Fixed at creation, like `lineWrapping` / `placeholder`.
|
|
42
|
-
*
|
|
43
|
-
* @default false
|
|
44
|
-
*/
|
|
45
|
-
showLineNumbers?: boolean;
|
|
46
|
-
/**
|
|
47
|
-
* Enable code folding (fold gutter + keymap). Fixed at creation; fold points come from the
|
|
48
|
-
* language, so set `language` too.
|
|
49
|
-
*
|
|
50
|
-
* @default false
|
|
51
|
-
*/
|
|
52
|
-
folding?: boolean;
|
|
53
|
-
/**
|
|
54
|
-
* Turn native browser spell-check on. Off by default (CodeMirror's own default, right for
|
|
55
|
-
* code); enable for prose-grade documents like prompt templates. Fixed at creation.
|
|
56
|
-
*
|
|
57
|
-
* @default false
|
|
58
|
-
*/
|
|
59
|
-
spellcheck?: boolean;
|
|
60
|
-
/**
|
|
61
|
-
* Enable in-editor search: Ctrl/Cmd-F opens a catppuccin-styled search/replace panel; F3 /
|
|
62
|
-
* Ctrl/Cmd-G cycle matches, Ctrl/Cmd-D selects the next occurrence, Alt-G jumps to a line.
|
|
63
|
-
* The panel speaks CodeMirror's stock English — set `locale="zh-cn"` (or pass
|
|
64
|
-
* `searchPhrasesZhCn` through `extensions`) for Simplified Chinese. Off by default —
|
|
65
|
-
* embedded fields rarely want a search UI. Fixed at creation.
|
|
66
|
-
*
|
|
67
|
-
* @default false
|
|
68
|
-
*/
|
|
69
|
-
search?: boolean;
|
|
70
|
-
/**
|
|
71
|
-
* Editor font size in px, applied as a theme extension.
|
|
72
|
-
*
|
|
73
|
-
* @default 14
|
|
74
|
-
*/
|
|
75
|
-
fontSize?: number;
|
|
76
|
-
/**
|
|
77
|
-
* Line height, applied as a theme extension on the scroller so content and gutters stay
|
|
78
|
-
* in step. Same convention as `<MonacoEditor>` (Monaco's own): values below 8 multiply the
|
|
79
|
-
* font size (e.g. `1.6` — CSS's unitless line-height), larger values are absolute pixels
|
|
80
|
-
* (e.g. `22`).
|
|
81
|
-
*
|
|
82
|
-
* @default 1.6
|
|
83
|
-
*/
|
|
84
|
-
lineHeight?: number;
|
|
85
|
-
/**
|
|
86
|
-
* Tab width in spaces — sets both the displayed tab width (`EditorState.tabSize`) and the
|
|
87
|
-
* indent string inserted on Tab (`indentUnit`), so display and indentation stay in sync.
|
|
88
|
-
*/
|
|
89
|
-
tabSize?: number;
|
|
90
|
-
/**
|
|
91
|
-
* Static extensions (language support, keymaps …), fixed for the editor's lifetime.
|
|
92
|
-
* Hoist the array — a new identity per render is ignored by design (create-once).
|
|
93
|
-
*/
|
|
94
|
-
extensions?: Extension[];
|
|
95
|
-
/**
|
|
96
|
-
* Extensions swapped in place when the identity changes (theme, language config) —
|
|
97
|
-
* memoize with `useMemo` keyed on what actually changes. Layered after (and so able to
|
|
98
|
-
* override) inkstone's default catppuccin theme.
|
|
99
|
-
*/
|
|
100
|
-
dynamicExtensions?: Extension[];
|
|
101
|
-
/**
|
|
102
|
-
* Use the dark catppuccin flavor (macchiato) instead of the light one (latte). The
|
|
103
|
-
* component never reads the OS `prefers-color-scheme`; wire this to your app's
|
|
104
|
-
* color-scheme state — same policy as `<MonacoEditor>`.
|
|
105
|
-
*
|
|
106
|
-
* @default false
|
|
107
|
-
*/
|
|
108
|
-
dark?: boolean;
|
|
109
|
-
/**
|
|
110
|
-
* Locale for the phrase tables inkstone ships for CodeMirror's stock UI strings —
|
|
111
|
-
* currently the search / goto-line panel. Unlike Monaco's page-global locale, this is
|
|
112
|
-
* genuinely per-editor (`EditorState.phrases`) and swaps in place. Equivalent to passing
|
|
113
|
-
* `searchPhrasesZhCn` through `extensions`, which stays the framework-agnostic surface.
|
|
114
|
-
*
|
|
115
|
-
* @default "en"
|
|
116
|
-
*/
|
|
117
|
-
locale?: "en" | "zh-cn";
|
|
118
|
-
/**
|
|
119
|
-
* Editor height — a number is treated as px. Sizes the editor box and hands overflow to
|
|
120
|
-
* the scroller; omit to grow with content.
|
|
121
|
-
*/
|
|
122
|
-
height?: string | number;
|
|
123
|
-
/**
|
|
124
|
-
* Editor width — a number is treated as px. Omit to fill the container.
|
|
125
|
-
*/
|
|
126
|
-
width?: string | number;
|
|
127
|
-
className?: string;
|
|
128
|
-
/**
|
|
129
|
-
* Runs once after the editor is created, with the CodeMirror `EditorView` — the imperative
|
|
130
|
-
* handle for focus, dispatch, scrolling, selection, etc. This is CodeMirror's analog of
|
|
131
|
-
* Monaco's `onMount`. Monaco's `loading` / `beforeMount` have no counterpart here: the
|
|
132
|
-
* editor mounts synchronously (no host or editor chunk to await — only the optional
|
|
133
|
-
* `language` grammar streams in behind an already-usable editor), and pre-creation setup is
|
|
134
|
-
* the `extensions` prop rather than a global instance to configure.
|
|
135
|
-
*/
|
|
136
|
-
onMount?: (view: EditorView) => void;
|
|
137
|
-
/**
|
|
138
|
-
* Called when the editor gains focus.
|
|
139
|
-
*/
|
|
140
|
-
onFocus?: () => void;
|
|
141
|
-
/**
|
|
142
|
-
* Called when the editor loses focus.
|
|
143
|
-
*/
|
|
144
|
-
onBlur?: () => void;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* A controlled CodeMirror 6 document editor: the standard document extension bundle
|
|
148
|
-
* (line numbers, history, brackets, completion UI — see `documentExtensions`) plus the
|
|
149
|
-
* create-once / reconcile-in-place plumbing of `ControlledEditorHost`, exposed as a plain
|
|
150
|
-
* React component.
|
|
151
|
-
*
|
|
152
|
-
* Ships the catppuccin theme by default (latte / macchiato, flipped by `dark`) and takes
|
|
153
|
-
* `height` / `width` for sizing — parity with `<MonacoEditor>`. Bring your own language
|
|
154
|
-
* support via `extensions`; a theme passed through `dynamicExtensions` overrides the default.
|
|
155
|
-
*/
|
|
156
|
-
declare function CodeMirrorEditor({
|
|
157
|
-
value,
|
|
158
|
-
onChange,
|
|
159
|
-
language,
|
|
160
|
-
context,
|
|
161
|
-
placeholder,
|
|
162
|
-
lineWrapping,
|
|
163
|
-
showLineNumbers,
|
|
164
|
-
folding,
|
|
165
|
-
spellcheck,
|
|
166
|
-
search,
|
|
167
|
-
extensions,
|
|
168
|
-
dynamicExtensions,
|
|
169
|
-
dark,
|
|
170
|
-
locale,
|
|
171
|
-
height,
|
|
172
|
-
width,
|
|
173
|
-
fontSize,
|
|
174
|
-
lineHeight,
|
|
175
|
-
tabSize,
|
|
176
|
-
className,
|
|
177
|
-
onMount,
|
|
178
|
-
onFocus,
|
|
179
|
-
onBlur
|
|
180
|
-
}: CodeMirrorEditorProps): ReactNode;
|
|
181
|
-
//#endregion
|
|
182
|
-
//#region src/monaco-editor.d.ts
|
|
183
|
-
/**
|
|
184
|
-
* Baseline construction options shared by every inkstone Monaco editor: no minimap, compact
|
|
185
|
-
* code type, in-place layout tracking, widgets floated above clipping containers, completion
|
|
186
|
-
* tuned for API-assisted editing, thin scrollbars, and an embedded-friendly find widget.
|
|
187
|
-
* Spread these to extend rather than replace: `options={{ ...DEFAULT_MONACO_OPTIONS, wordWrap: "on" }}`.
|
|
188
|
-
*/
|
|
189
|
-
declare const DEFAULT_MONACO_OPTIONS: editor.IStandaloneEditorConstructionOptions;
|
|
190
|
-
interface MonacoEditorProps {
|
|
191
|
-
/**
|
|
192
|
-
* The controlled document text.
|
|
193
|
-
*/
|
|
194
|
-
value: string;
|
|
195
|
-
onChange?: (value: string) => void;
|
|
196
|
-
/**
|
|
197
|
-
* Monaco language id. Built-in ids autocomplete; any custom-registered id is also accepted.
|
|
198
|
-
*
|
|
199
|
-
* @default "javascript"
|
|
200
|
-
*/
|
|
201
|
-
language?: MonacoLanguage$1;
|
|
202
|
-
/**
|
|
203
|
-
* Render with the dark theme. The component never reads the OS `prefers-color-scheme`;
|
|
204
|
-
* wire this to your app's color-scheme state.
|
|
205
|
-
*
|
|
206
|
-
* @default false
|
|
207
|
-
*/
|
|
208
|
-
dark?: boolean;
|
|
209
|
-
/**
|
|
210
|
-
* UI locale for Monaco's built-in chrome (context menu, find widget, command palette …).
|
|
211
|
-
* Unlike everything else on this component, the locale is **page-global and locked by the
|
|
212
|
-
* first editor to mount** — Monaco resolves its UI strings once, at module evaluation — so
|
|
213
|
-
* later editors with a different value are ignored. Overrides `hostOptions.locale` (the
|
|
214
|
-
* same knob on the framework-agnostic host layer).
|
|
215
|
-
*
|
|
216
|
-
* @default "en"
|
|
217
|
-
*/
|
|
218
|
-
locale?: MonacoUiLocale;
|
|
219
|
-
/**
|
|
220
|
-
* Placeholder shown while the document is empty. Maps to Monaco's native `placeholder`
|
|
221
|
-
* editor option (0.47+); an explicit `options.placeholder` still wins.
|
|
222
|
-
*/
|
|
223
|
-
placeholder?: string;
|
|
224
|
-
/**
|
|
225
|
-
* Soft-wrap long lines (Monaco `wordWrap`).
|
|
226
|
-
*
|
|
227
|
-
* @default false
|
|
228
|
-
*/
|
|
229
|
-
lineWrapping?: boolean;
|
|
230
|
-
/**
|
|
231
|
-
* Show the line-number gutter (Monaco `lineNumbers`). For relative/interval modes pass an
|
|
232
|
-
* explicit `options.lineNumbers`.
|
|
233
|
-
*
|
|
234
|
-
* @default false
|
|
235
|
-
*/
|
|
236
|
-
showLineNumbers?: boolean;
|
|
237
|
-
/**
|
|
238
|
-
* Editor font size in px (Monaco `fontSize`). Omit to keep the inkstone default (14).
|
|
239
|
-
*/
|
|
240
|
-
fontSize?: number;
|
|
241
|
-
/**
|
|
242
|
-
* Line height (Monaco `lineHeight`, and its convention): values below 8 multiply the font
|
|
243
|
-
* size (e.g. `1.6`), larger values are absolute pixels (e.g. `22`). `<CodeMirrorEditor>`
|
|
244
|
-
* mirrors the same semantics. Omit to keep the inkstone default (1.6).
|
|
245
|
-
*/
|
|
246
|
-
lineHeight?: number;
|
|
247
|
-
/**
|
|
248
|
-
* Tab width in spaces (Monaco `tabSize`).
|
|
249
|
-
*
|
|
250
|
-
* @default 2
|
|
251
|
-
*/
|
|
252
|
-
tabSize?: number;
|
|
253
|
-
/**
|
|
254
|
-
* Enable code folding (fold gutter + fold ranges). Unifies the toggle with
|
|
255
|
-
* `<CodeMirrorEditor>`; note Monaco folds by default, so this turns its folding off unless
|
|
256
|
-
* set.
|
|
257
|
-
*
|
|
258
|
-
* @default false
|
|
259
|
-
*/
|
|
260
|
-
folding?: boolean;
|
|
261
|
-
/**
|
|
262
|
-
* Disable Monaco's right-click context menu (`contextmenu: false`). Right-clicks then fall
|
|
263
|
-
* through to the browser, so its native menu applies — intercept `contextmenu` on a
|
|
264
|
-
* wrapping element to suppress that as well.
|
|
265
|
-
*
|
|
266
|
-
* @default false
|
|
267
|
-
*/
|
|
268
|
-
disableContextMenu?: boolean;
|
|
269
|
-
/**
|
|
270
|
-
* Swallow the find/replace widget's keyboard entries — Ctrl/Cmd+F (find), Ctrl+H and
|
|
271
|
-
* Cmd+Alt+F (replace). Scoped to this editor via a context key: the standalone keybinding
|
|
272
|
-
* service is page-global, so an unscoped rule would rewire every editor on the page.
|
|
273
|
-
* Fixed at creation.
|
|
274
|
-
*
|
|
275
|
-
* @default false
|
|
276
|
-
*/
|
|
277
|
-
disableFind?: boolean;
|
|
278
|
-
/**
|
|
279
|
-
* Swallow the command palette's keyboard entry, F1 — Monaco never binds Ctrl+Shift+P
|
|
280
|
-
* (that is a VS Code binding). While the context menu is enabled, its "Command Palette"
|
|
281
|
-
* item still opens the palette; pair with {@link disableContextMenu} to remove every
|
|
282
|
-
* entry point. Fixed at creation.
|
|
283
|
-
*
|
|
284
|
-
* @default false
|
|
285
|
-
*/
|
|
286
|
-
disableCommandPalette?: boolean;
|
|
287
|
-
/**
|
|
288
|
-
* Model path — give each logically distinct document its own so view state (cursor,
|
|
289
|
-
* folds) survives remounts.
|
|
290
|
-
*/
|
|
291
|
-
path?: string;
|
|
292
|
-
height?: string | number;
|
|
293
|
-
width?: string | number;
|
|
294
|
-
className?: string;
|
|
295
|
-
/**
|
|
296
|
-
* Extra construction options, merged over {@link DEFAULT_MONACO_OPTIONS}.
|
|
297
|
-
*/
|
|
298
|
-
options?: editor.IStandaloneEditorConstructionOptions;
|
|
299
|
-
/**
|
|
300
|
-
* Host bring-up options (UI locale, language workers). The Monaco host is a process-wide
|
|
301
|
-
* singleton, so the first mounted editor wins and later values are ignored.
|
|
302
|
-
*/
|
|
303
|
-
hostOptions?: MonacoHostOptions;
|
|
304
|
-
/**
|
|
305
|
-
* Shown while the host, highlighter, and editor chunk load.
|
|
306
|
-
*
|
|
307
|
-
* @default "Loading editor…"
|
|
308
|
-
*/
|
|
309
|
-
loading?: ReactNode;
|
|
310
|
-
/**
|
|
311
|
-
* Shown when the Monaco host fails to load (e.g. a stale chunk 404 after a redeploy).
|
|
312
|
-
* The failure is not cached by the host singleton, so a fresh mount retries.
|
|
313
|
-
*
|
|
314
|
-
* @default "Editor failed to load"
|
|
315
|
-
*/
|
|
316
|
-
failure?: ReactNode;
|
|
317
|
-
/**
|
|
318
|
-
* Runs after inkstone's own pre-mount setup (Shiki theme registration).
|
|
319
|
-
*/
|
|
320
|
-
beforeMount?: BeforeMount;
|
|
321
|
-
onMount?: OnMount;
|
|
322
|
-
/**
|
|
323
|
-
* Called when the editor's text area gains focus (Monaco `onDidFocusEditorText`).
|
|
324
|
-
*/
|
|
325
|
-
onFocus?: () => void;
|
|
326
|
-
/**
|
|
327
|
-
* Called when the editor's text area loses focus (Monaco `onDidBlurEditorText`).
|
|
328
|
-
*/
|
|
329
|
-
onBlur?: () => void;
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* A preconfigured, offline Monaco editor: bundled workers (no CDN), Shiki catppuccin
|
|
333
|
-
* highlighting with light/dark switching, and sensible document defaults — drop it in with
|
|
334
|
-
* `value` / `onChange` and everything else is wired. The UI speaks Monaco's stock English;
|
|
335
|
-
* pass `hostOptions={{ locale: "zh-cn" }}` for the official Simplified-Chinese chrome.
|
|
336
|
-
*
|
|
337
|
-
* Mounting is gated on the Monaco host and the Shiki highlighter so the first paint already
|
|
338
|
-
* has the right theme; if the highlighter fails to load, the editor falls back to Monaco's
|
|
339
|
-
* built-in themes and stays usable.
|
|
340
|
-
*
|
|
341
|
-
* Do not `import "monaco-editor"` statically elsewhere in the app — that would evaluate
|
|
342
|
-
* Monaco before its UI locale is set (see `ensureMonacoHost`). Type-only imports are fine.
|
|
343
|
-
*/
|
|
344
|
-
declare function MonacoEditor({
|
|
345
|
-
value,
|
|
346
|
-
onChange,
|
|
347
|
-
language,
|
|
348
|
-
dark,
|
|
349
|
-
locale,
|
|
350
|
-
placeholder,
|
|
351
|
-
lineWrapping,
|
|
352
|
-
showLineNumbers,
|
|
353
|
-
folding,
|
|
354
|
-
disableContextMenu,
|
|
355
|
-
disableFind,
|
|
356
|
-
disableCommandPalette,
|
|
357
|
-
fontSize,
|
|
358
|
-
lineHeight,
|
|
359
|
-
tabSize,
|
|
360
|
-
path,
|
|
361
|
-
height,
|
|
362
|
-
width,
|
|
363
|
-
className,
|
|
364
|
-
options,
|
|
365
|
-
hostOptions,
|
|
366
|
-
loading,
|
|
367
|
-
failure,
|
|
368
|
-
beforeMount,
|
|
369
|
-
onMount,
|
|
370
|
-
onFocus,
|
|
371
|
-
onBlur
|
|
372
|
-
}: MonacoEditorProps): ReactNode;
|
|
373
|
-
//#endregion
|
|
374
|
-
//#region src/use-shiki-highlighter.d.ts
|
|
375
|
-
type ShikiState = "loading" | "ready" | "failed";
|
|
376
|
-
/**
|
|
377
|
-
* Load the shared Shiki highlighter and expose its lifecycle to gate editor mounting:
|
|
378
|
-
* waiting for `ready` before creating the editor avoids a default-theme flash (and the
|
|
379
|
-
* "theme not found" console error) on first paint; on `failed` the caller falls back to
|
|
380
|
-
* the engine's built-in theme so the editor stays usable.
|
|
381
|
-
*
|
|
382
|
-
* `highlighterRef` is for pre-mount hooks (Monaco `beforeMount`) that must read the
|
|
383
|
-
* instance synchronously before the editor is created.
|
|
384
|
-
*/
|
|
385
|
-
declare function useShikiHighlighter(): {
|
|
386
|
-
state: ShikiState;
|
|
387
|
-
highlighterRef: RefObject<HighlighterCore | null>;
|
|
388
|
-
};
|
|
389
|
-
//#endregion
|
|
390
|
-
export { CodeMirrorEditor, type CodeMirrorEditorProps, type CodeMirrorLanguage, DEFAULT_MONACO_OPTIONS, type EditorContext, MonacoEditor, type MonacoEditorProps, type MonacoLanguage, type ShikiState, codeMirrorLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
|