@coldsmirk/inkstone-react 0.11.0 → 0.13.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 +1 -1
- package/dist/codemirror-Bvwl0fxH.js +261 -0
- package/dist/codemirror.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/{monaco-DXifh803.d.ts → monaco-BoTcTdm-.d.ts} +2 -9
- package/dist/{monaco-CP5BIXrw.js → monaco-IkYCUn1k.js} +125 -213
- package/dist/monaco.d.ts +1 -1
- package/dist/monaco.js +1 -1
- package/dist/{use-latest-BhihMdOp.js → use-latest-BxJHbqOv.js} +1 -4
- package/package.json +27 -7
- package/dist/codemirror-B27C5np1.js +0 -604
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ pnpm add @coldsmirk/inkstone-react monaco-editor react \
|
|
|
11
11
|
@codemirror/state @codemirror/view @codemirror/language @codemirror/autocomplete @codemirror/commands @codemirror/search
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
`monaco-editor`, `react`, and the `@codemirror/*` packages are **peer dependencies** — your app owns the single copy of each (`@codemirror/state` breaks at runtime if two copies load). Node.js >= 24 for build / SSR hosts.
|
|
14
|
+
`monaco-editor`, `react`, and the `@codemirror/*` packages are **peer dependencies** — your app owns the single copy of each (`@codemirror/state` breaks at runtime if two copies load). The engine peers are **optional**: a `/codemirror`-only consumer installs just the `@codemirror/*` set, a `/monaco`-only consumer just `monaco-editor`; only `react` is always required (`@monaco-editor/react` still declares `monaco-editor` a required peer, so a CodeMirror-only install may print one unmet-peer warning — harmless, nothing Monaco is loaded). Node.js >= 24 for build / SSR hosts.
|
|
15
15
|
|
|
16
16
|
Import from the engine-specific entry points below so a CodeMirror-only build never traverses or emits Monaco (and vice versa). The aggregate `@coldsmirk/inkstone-react` entry remains available for existing consumers; `@coldsmirk/inkstone-react/shiki` exposes the standalone highlighter hook.
|
|
17
17
|
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { n as useControlledReconcileSignal, t as useLatest } from "./use-latest-BxJHbqOv.js";
|
|
2
|
+
import { EditorState } from "@codemirror/state";
|
|
3
|
+
import { EditorView, lineNumbers } from "@codemirror/view";
|
|
4
|
+
import { ControlledEditorHost, ControlledMergeHost, codeMirrorLanguages, defaultThemeExtensions, diffChromeColor, documentExtensions, editorRoot, installDiffChrome, installDiffControlKeyboardSupport, loadLanguage, mergeTheme, minijinjaContextField, normalizeContext, normalizeContext as normalizeContext$1, searchPhrasesZhCn, searchPhrasesZhCn as searchPhrasesZhCn$1, setMinijinjaContext, setSqlSchema, sqlSchemaField, toCssSize } from "@coldsmirk/inkstone-codemirror";
|
|
5
|
+
import { useEffect, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { indentUnit } from "@codemirror/language";
|
|
8
|
+
//#region src/codemirror-diff-editor.tsx
|
|
9
|
+
function CodeMirrorDiffEditor({ original, modified, onChange, language, readOnly = false, revertControls = false, collapseUnchanged = false, lineWrapping = false, showLineNumbers = true, extensions, dynamicExtensions, dark = false, height, width, fontSize = 14, lineHeight = 1.6, className, originalAriaLabel = "Original content", modifiedAriaLabel = "Modified content", onMount }) {
|
|
10
|
+
const containerRef = useRef(null);
|
|
11
|
+
const hostRef = useRef(null);
|
|
12
|
+
const modifiedTransitionRef = useRef(false);
|
|
13
|
+
const [reconcileRevision, requestControlledReconcile] = useControlledReconcileSignal();
|
|
14
|
+
const onChangeRef = useLatest(onChange);
|
|
15
|
+
const onMountRef = useLatest(onMount);
|
|
16
|
+
const [loadedLanguage, setLoadedLanguage] = useState(null);
|
|
17
|
+
const languageExtension = useMemo(() => loadedLanguage && loadedLanguage.id === language ? [loadedLanguage.extension] : [], [language, loadedLanguage]);
|
|
18
|
+
const activeRevertControls = revertControls && !readOnly;
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!language) return;
|
|
21
|
+
let cancelled = false;
|
|
22
|
+
loadLanguage(language).then((extension) => {
|
|
23
|
+
if (!cancelled) setLoadedLanguage({
|
|
24
|
+
id: language,
|
|
25
|
+
extension
|
|
26
|
+
});
|
|
27
|
+
}).catch((error) => {
|
|
28
|
+
console.error("inkstone: failed to load CodeMirror language", language, error);
|
|
29
|
+
if (!cancelled) setLoadedLanguage(null);
|
|
30
|
+
});
|
|
31
|
+
return () => {
|
|
32
|
+
cancelled = true;
|
|
33
|
+
};
|
|
34
|
+
}, [language]);
|
|
35
|
+
const dynamic = useMemo(() => [
|
|
36
|
+
...defaultThemeExtensions(dark, void 0, void 0, fontSize, lineHeight),
|
|
37
|
+
mergeTheme(dark),
|
|
38
|
+
...showLineNumbers ? [lineNumbers()] : [],
|
|
39
|
+
...lineWrapping ? [EditorView.lineWrapping] : [],
|
|
40
|
+
...readOnly ? [EditorState.readOnly.of(true), EditorView.editable.of(false)] : [],
|
|
41
|
+
...languageExtension,
|
|
42
|
+
...dynamicExtensions ?? []
|
|
43
|
+
], [
|
|
44
|
+
dark,
|
|
45
|
+
fontSize,
|
|
46
|
+
lineHeight,
|
|
47
|
+
showLineNumbers,
|
|
48
|
+
lineWrapping,
|
|
49
|
+
readOnly,
|
|
50
|
+
languageExtension,
|
|
51
|
+
dynamicExtensions
|
|
52
|
+
]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const container = containerRef.current;
|
|
55
|
+
if (!container) return;
|
|
56
|
+
const root = editorRoot(container);
|
|
57
|
+
installDiffChrome(root);
|
|
58
|
+
const host = new ControlledMergeHost({
|
|
59
|
+
parent: container,
|
|
60
|
+
root,
|
|
61
|
+
original,
|
|
62
|
+
modified,
|
|
63
|
+
onModifiedChange: (next) => {
|
|
64
|
+
if (modifiedTransitionRef.current) return;
|
|
65
|
+
onChangeRef.current?.(next);
|
|
66
|
+
requestControlledReconcile();
|
|
67
|
+
},
|
|
68
|
+
extensions: [
|
|
69
|
+
minijinjaContextField,
|
|
70
|
+
sqlSchemaField,
|
|
71
|
+
...documentExtensions(),
|
|
72
|
+
...extensions ?? []
|
|
73
|
+
],
|
|
74
|
+
originalExtensions: [
|
|
75
|
+
EditorState.readOnly.of(true),
|
|
76
|
+
EditorView.editable.of(false),
|
|
77
|
+
EditorView.contentAttributes.of({ "aria-label": originalAriaLabel })
|
|
78
|
+
],
|
|
79
|
+
modifiedExtensions: [EditorView.contentAttributes.of({ "aria-label": modifiedAriaLabel })],
|
|
80
|
+
dynamicExtensions: dynamic,
|
|
81
|
+
revertControls: activeRevertControls ? "a-to-b" : void 0,
|
|
82
|
+
collapseUnchanged: collapseUnchanged ? {} : void 0
|
|
83
|
+
});
|
|
84
|
+
hostRef.current = host;
|
|
85
|
+
const removeDiffControlKeyboardSupport = installDiffControlKeyboardSupport(container);
|
|
86
|
+
onMountRef.current?.(host.view);
|
|
87
|
+
return () => {
|
|
88
|
+
removeDiffControlKeyboardSupport();
|
|
89
|
+
host.destroy();
|
|
90
|
+
hostRef.current = null;
|
|
91
|
+
};
|
|
92
|
+
}, []);
|
|
93
|
+
useInsertionEffect(() => {
|
|
94
|
+
const host = hostRef.current;
|
|
95
|
+
modifiedTransitionRef.current = host !== null && host.view.b.state.doc.toString() !== modified;
|
|
96
|
+
}, [modified, reconcileRevision]);
|
|
97
|
+
useLayoutEffect(() => {
|
|
98
|
+
hostRef.current?.setOriginal(original);
|
|
99
|
+
}, [original]);
|
|
100
|
+
useLayoutEffect(() => {
|
|
101
|
+
try {
|
|
102
|
+
hostRef.current?.setModified(modified);
|
|
103
|
+
} finally {
|
|
104
|
+
modifiedTransitionRef.current = false;
|
|
105
|
+
}
|
|
106
|
+
}, [modified, reconcileRevision]);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
hostRef.current?.reconfigure(dynamic);
|
|
109
|
+
}, [dynamic]);
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
hostRef.current?.view.reconfigure({
|
|
112
|
+
revertControls: activeRevertControls ? "a-to-b" : void 0,
|
|
113
|
+
collapseUnchanged: collapseUnchanged ? {} : void 0
|
|
114
|
+
});
|
|
115
|
+
}, [activeRevertControls, collapseUnchanged]);
|
|
116
|
+
return /* @__PURE__ */ jsx("div", {
|
|
117
|
+
ref: containerRef,
|
|
118
|
+
className,
|
|
119
|
+
"data-inkstone-diff": "",
|
|
120
|
+
style: {
|
|
121
|
+
height: toCssSize(height),
|
|
122
|
+
width: toCssSize(width),
|
|
123
|
+
color: diffChromeColor(dark)
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/codemirror-editor.tsx
|
|
129
|
+
function CodeMirrorEditor({ value, onChange, language, context, sqlSchema, 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, ariaLabel = "Editor content" }) {
|
|
130
|
+
const containerRef = useRef(null);
|
|
131
|
+
const hostRef = useRef(null);
|
|
132
|
+
const valueTransitionRef = useRef(false);
|
|
133
|
+
const [reconcileRevision, requestControlledReconcile] = useControlledReconcileSignal();
|
|
134
|
+
const onChangeRef = useLatest(onChange);
|
|
135
|
+
const onMountRef = useLatest(onMount);
|
|
136
|
+
const onFocusRef = useLatest(onFocus);
|
|
137
|
+
const onBlurRef = useLatest(onBlur);
|
|
138
|
+
const lastContextKeyRef = useRef(null);
|
|
139
|
+
const lastSqlSchemaKeyRef = useRef(null);
|
|
140
|
+
const [loadedLanguage, setLoadedLanguage] = useState(null);
|
|
141
|
+
const languageExtension = useMemo(() => loadedLanguage && loadedLanguage.id === language ? [loadedLanguage.extension] : [], [language, loadedLanguage]);
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (!language) return;
|
|
144
|
+
let cancelled = false;
|
|
145
|
+
loadLanguage(language).then((extension) => {
|
|
146
|
+
if (!cancelled) setLoadedLanguage({
|
|
147
|
+
id: language,
|
|
148
|
+
extension
|
|
149
|
+
});
|
|
150
|
+
}).catch((error) => {
|
|
151
|
+
console.error("inkstone: failed to load CodeMirror language", language, error);
|
|
152
|
+
if (!cancelled) setLoadedLanguage(null);
|
|
153
|
+
});
|
|
154
|
+
return () => {
|
|
155
|
+
cancelled = true;
|
|
156
|
+
};
|
|
157
|
+
}, [language]);
|
|
158
|
+
const dynamic = useMemo(() => [
|
|
159
|
+
...defaultThemeExtensions(dark, height, width, fontSize, lineHeight),
|
|
160
|
+
...tabSize === void 0 ? [] : [EditorState.tabSize.of(tabSize), indentUnit.of(" ".repeat(tabSize))],
|
|
161
|
+
...locale === "zh-cn" ? [searchPhrasesZhCn] : [],
|
|
162
|
+
...languageExtension,
|
|
163
|
+
EditorView.contentAttributes.of({ "aria-label": ariaLabel }),
|
|
164
|
+
...dynamicExtensions ?? []
|
|
165
|
+
], [
|
|
166
|
+
dark,
|
|
167
|
+
height,
|
|
168
|
+
width,
|
|
169
|
+
fontSize,
|
|
170
|
+
lineHeight,
|
|
171
|
+
tabSize,
|
|
172
|
+
locale,
|
|
173
|
+
languageExtension,
|
|
174
|
+
ariaLabel,
|
|
175
|
+
dynamicExtensions
|
|
176
|
+
]);
|
|
177
|
+
const contextSchema = useMemo(() => context ? normalizeContext(context) : null, [context]);
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
const container = containerRef.current;
|
|
180
|
+
if (!container) return;
|
|
181
|
+
const host = new ControlledEditorHost({
|
|
182
|
+
parent: container,
|
|
183
|
+
doc: value,
|
|
184
|
+
onChange: (next) => {
|
|
185
|
+
if (valueTransitionRef.current) return;
|
|
186
|
+
onChangeRef.current?.(next);
|
|
187
|
+
requestControlledReconcile();
|
|
188
|
+
},
|
|
189
|
+
extensions: [
|
|
190
|
+
minijinjaContextField,
|
|
191
|
+
sqlSchemaField,
|
|
192
|
+
...documentExtensions({
|
|
193
|
+
placeholder,
|
|
194
|
+
lineWrapping,
|
|
195
|
+
showLineNumbers,
|
|
196
|
+
folding,
|
|
197
|
+
spellcheck,
|
|
198
|
+
search
|
|
199
|
+
}),
|
|
200
|
+
EditorView.updateListener.of((update) => {
|
|
201
|
+
if (update.focusChanged) if (update.view.hasFocus) onFocusRef.current?.();
|
|
202
|
+
else onBlurRef.current?.();
|
|
203
|
+
}),
|
|
204
|
+
...extensions ?? []
|
|
205
|
+
],
|
|
206
|
+
dynamicExtensions: dynamic
|
|
207
|
+
});
|
|
208
|
+
hostRef.current = host;
|
|
209
|
+
onMountRef.current?.(host.view);
|
|
210
|
+
return () => {
|
|
211
|
+
host.destroy();
|
|
212
|
+
hostRef.current = null;
|
|
213
|
+
};
|
|
214
|
+
}, []);
|
|
215
|
+
useInsertionEffect(() => {
|
|
216
|
+
const host = hostRef.current;
|
|
217
|
+
valueTransitionRef.current = host !== null && host.view.state.doc.toString() !== value;
|
|
218
|
+
}, [reconcileRevision, value]);
|
|
219
|
+
useLayoutEffect(() => {
|
|
220
|
+
try {
|
|
221
|
+
hostRef.current?.setValue(value);
|
|
222
|
+
} finally {
|
|
223
|
+
valueTransitionRef.current = false;
|
|
224
|
+
}
|
|
225
|
+
}, [reconcileRevision, value]);
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
hostRef.current?.reconfigure(dynamic);
|
|
228
|
+
}, [dynamic]);
|
|
229
|
+
useEffect(() => {
|
|
230
|
+
const host = hostRef.current;
|
|
231
|
+
if (!host) return;
|
|
232
|
+
const key = contextSchema ? JSON.stringify(contextSchema) : "";
|
|
233
|
+
const last = lastContextKeyRef.current;
|
|
234
|
+
if (last?.host === host && last.key === key) return;
|
|
235
|
+
lastContextKeyRef.current = {
|
|
236
|
+
host,
|
|
237
|
+
key
|
|
238
|
+
};
|
|
239
|
+
if (key === "" && last?.host !== host) return;
|
|
240
|
+
host.view.dispatch({ effects: setMinijinjaContext.of(contextSchema) });
|
|
241
|
+
}, [contextSchema]);
|
|
242
|
+
useEffect(() => {
|
|
243
|
+
const host = hostRef.current;
|
|
244
|
+
if (!host) return;
|
|
245
|
+
const key = sqlSchema ? JSON.stringify(sqlSchema) : "";
|
|
246
|
+
const last = lastSqlSchemaKeyRef.current;
|
|
247
|
+
if (last?.host === host && last.key === key) return;
|
|
248
|
+
lastSqlSchemaKeyRef.current = {
|
|
249
|
+
host,
|
|
250
|
+
key
|
|
251
|
+
};
|
|
252
|
+
if (key === "" && last?.host !== host) return;
|
|
253
|
+
host.view.dispatch({ effects: setSqlSchema.of(sqlSchema ?? null) });
|
|
254
|
+
}, [sqlSchema]);
|
|
255
|
+
return /* @__PURE__ */ jsx("div", {
|
|
256
|
+
ref: containerRef,
|
|
257
|
+
className
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
//#endregion
|
|
261
|
+
export { CodeMirrorDiffEditor as a, CodeMirrorEditor as i, normalizeContext$1 as n, searchPhrasesZhCn$1 as r, codeMirrorLanguages as t };
|
package/dist/codemirror.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as CodeMirrorDiffEditor, i as CodeMirrorEditor, n as normalizeContext, r as searchPhrasesZhCn, t as codeMirrorLanguages } from "./codemirror-
|
|
1
|
+
import { a as CodeMirrorDiffEditor, i as CodeMirrorEditor, n as normalizeContext, r as searchPhrasesZhCn, t as codeMirrorLanguages } from "./codemirror-Bvwl0fxH.js";
|
|
2
2
|
export { CodeMirrorDiffEditor, CodeMirrorEditor, codeMirrorLanguages, normalizeContext, searchPhrasesZhCn };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { a as codeMirrorLanguages, c as CodeMirrorEditor, d as CodeMirrorDiffEditorProps, i as SqlSchema, l as CodeMirrorEditorProps, n as EditorContext, o as normalizeContext, r as MergeView, s as searchPhrasesZhCn, t as CodeMirrorLanguage, u as CodeMirrorDiffEditor } from "./codemirror-B3GlIVaX.js";
|
|
2
|
-
import { a as MonacoEditorProps, i as MonacoEditor, n as
|
|
2
|
+
import { a as MonacoEditorProps, i as MonacoEditor, n as MonacoLanguage, o as MonacoDiffEditor, r as monacoLanguages, s as MonacoDiffEditorProps, t as DEFAULT_MONACO_OPTIONS } from "./monaco-BoTcTdm-.js";
|
|
3
3
|
import { n as useShikiHighlighter, t as ShikiState } from "./shiki-D-IjmhhO.js";
|
|
4
4
|
export { CodeMirrorDiffEditor, type CodeMirrorDiffEditorProps, CodeMirrorEditor, type CodeMirrorEditorProps, type CodeMirrorLanguage, DEFAULT_MONACO_OPTIONS, type EditorContext, type MergeView, MonacoDiffEditor, type MonacoDiffEditorProps, MonacoEditor, type MonacoEditorProps, type MonacoLanguage, type ShikiState, type SqlSchema, codeMirrorLanguages, monacoLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as CodeMirrorDiffEditor, i as CodeMirrorEditor, n as normalizeContext, r as searchPhrasesZhCn, t as codeMirrorLanguages } from "./codemirror-
|
|
2
|
-
import { i as
|
|
1
|
+
import { a as CodeMirrorDiffEditor, i as CodeMirrorEditor, n as normalizeContext, r as searchPhrasesZhCn, t as codeMirrorLanguages } from "./codemirror-Bvwl0fxH.js";
|
|
2
|
+
import { i as MonacoDiffEditor, n as monacoLanguages, r as MonacoEditor, t as DEFAULT_MONACO_OPTIONS } from "./monaco-IkYCUn1k.js";
|
|
3
3
|
import { t as useShikiHighlighter } from "./use-shiki-highlighter-CzSQcX2f.js";
|
|
4
4
|
import "./shiki.js";
|
|
5
5
|
export { CodeMirrorDiffEditor, CodeMirrorEditor, DEFAULT_MONACO_OPTIONS, MonacoDiffEditor, MonacoEditor, codeMirrorLanguages, monacoLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
+
import { DEFAULT_MONACO_OPTIONS as DEFAULT_MONACO_OPTIONS$1, MonacoHostOptions, MonacoLanguage, MonacoLanguage as MonacoLanguage$1, MonacoUiLocale, monacoLanguages } from "@coldsmirk/inkstone-monaco";
|
|
2
3
|
import { BeforeMount, DiffBeforeMount, DiffOnMount, OnMount } from "@monaco-editor/react";
|
|
3
|
-
import { MonacoHostOptions, MonacoLanguage, MonacoLanguage as MonacoLanguage$1, MonacoUiLocale, monacoLanguages } from "@coldsmirk/inkstone-monaco";
|
|
4
4
|
import { editor } from "monaco-editor";
|
|
5
5
|
|
|
6
6
|
//#region src/monaco-diff-editor.d.ts
|
|
@@ -163,13 +163,6 @@ declare function MonacoDiffEditor({
|
|
|
163
163
|
}: MonacoDiffEditorProps): ReactNode;
|
|
164
164
|
//#endregion
|
|
165
165
|
//#region src/monaco-editor.d.ts
|
|
166
|
-
/**
|
|
167
|
-
* Baseline construction options shared by every inkstone Monaco editor: no minimap, compact
|
|
168
|
-
* code type, in-place layout tracking, widgets floated above clipping containers, completion
|
|
169
|
-
* tuned for API-assisted editing, thin scrollbars, and an embedded-friendly find widget.
|
|
170
|
-
* Spread these to extend rather than replace: `options={{ ...DEFAULT_MONACO_OPTIONS, wordWrap: "on" }}`.
|
|
171
|
-
*/
|
|
172
|
-
declare const DEFAULT_MONACO_OPTIONS: editor.IStandaloneEditorConstructionOptions;
|
|
173
166
|
interface MonacoEditorProps {
|
|
174
167
|
/**
|
|
175
168
|
* The controlled document text.
|
|
@@ -357,4 +350,4 @@ declare function MonacoEditor({
|
|
|
357
350
|
onBlur
|
|
358
351
|
}: MonacoEditorProps): ReactNode;
|
|
359
352
|
//#endregion
|
|
360
|
-
export { MonacoEditorProps as a, MonacoEditor as i,
|
|
353
|
+
export { MonacoEditorProps as a, MonacoEditor as i, MonacoLanguage$1 as n, MonacoDiffEditor as o, monacoLanguages as r, MonacoDiffEditorProps as s, DEFAULT_MONACO_OPTIONS$1 as t };
|