@coldsmirk/inkstone-react 0.8.2

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/dist/index.js ADDED
@@ -0,0 +1,515 @@
1
+ import { catppuccinLatte, catppuccinMacchiato } from "@catppuccin/codemirror";
2
+ import { flavors } from "@catppuccin/palette";
3
+ import { indentUnit } from "@codemirror/language";
4
+ import { EditorState, Prec } from "@codemirror/state";
5
+ import { EditorView } from "@codemirror/view";
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";
8
+ import { jsx } from "react/jsx-runtime";
9
+ import { getHighlighter, shikiThemeId } from "@coldsmirk/inkstone-core";
10
+ import { ensureMonacoHost } from "@coldsmirk/inkstone-monaco";
11
+ import { Editor, loader } from "@monaco-editor/react";
12
+ import { shikiToMonaco } from "@shikijs/monaco";
13
+ //#region src/codemirror-editor.tsx
14
+ function toCssSize(value) {
15
+ if (value === void 0) return;
16
+ return typeof value === "number" ? `${value}px` : value;
17
+ }
18
+ function alphaOf(color, alphaValue) {
19
+ return `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${alphaValue})`;
20
+ }
21
+ function completionIconMask(body) {
22
+ 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>`;
23
+ return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
24
+ }
25
+ const COMPLETION_ICON_FALLBACK = completionIconMask("<circle cx=\"8\" cy=\"8\" r=\"2.5\"/>");
26
+ const COMPLETION_ICONS = {
27
+ keyword: completionIconMask("<path d=\"M5.5 5 2.5 8l3 3\"/><path d=\"m10.5 5 3 3-3 3\"/>"),
28
+ 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\"/>"),
29
+ 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\"/>"),
30
+ 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\"/>"),
31
+ 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\"/>"),
32
+ 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\"/>"),
33
+ class: completionIconMask("<rect x=\"3.5\" y=\"3.5\" width=\"9\" height=\"9\" rx=\"2.2\"/>"),
34
+ interface: completionIconMask("<circle cx=\"8\" cy=\"8\" r=\"4.5\"/>"),
35
+ type: completionIconMask("<path d=\"M4 4.5h8\"/><path d=\"M8 4.5V12\"/>"),
36
+ 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\"/>"),
37
+ 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\"/>"),
38
+ text: completionIconMask("<path d=\"M3.5 5h9\"/><path d=\"M3.5 8h9\"/><path d=\"M3.5 11h5.5\"/>")
39
+ };
40
+ function completionIconRules() {
41
+ const rules = {};
42
+ for (const [kind, mask] of Object.entries(COMPLETION_ICONS)) rules[`.cm-completionIcon-${kind}:after`] = {
43
+ maskImage: mask,
44
+ WebkitMaskImage: mask
45
+ };
46
+ return rules;
47
+ }
48
+ function chromeTheme(dark) {
49
+ const { colors } = dark ? flavors.macchiato : flavors.latte;
50
+ const hairline = `1px solid ${alphaOf(colors.overlay0, .35)}`;
51
+ const frame = {
52
+ border: hairline,
53
+ borderRadius: "8px",
54
+ boxShadow: dark ? "0 8px 24px rgba(0, 0, 0, 0.5)" : "0 8px 24px rgba(0, 0, 0, 0.12)"
55
+ };
56
+ return EditorView.theme({
57
+ "&": { colorScheme: dark ? "dark" : "light" },
58
+ ".cm-tooltip.cm-tooltip-autocomplete": {
59
+ ...frame,
60
+ "& > ul": {
61
+ borderRadius: "7px",
62
+ padding: "4px",
63
+ maxHeight: "16em"
64
+ },
65
+ "& > ul > li": {
66
+ display: "flex",
67
+ alignItems: "center",
68
+ padding: "3px 8px",
69
+ borderRadius: "5px",
70
+ lineHeight: "1.45"
71
+ }
72
+ },
73
+ ".cm-completionLabel": {
74
+ minWidth: "0",
75
+ overflow: "hidden",
76
+ textOverflow: "ellipsis"
77
+ },
78
+ ".cm-completionMatchedText": {
79
+ textDecoration: "none",
80
+ fontWeight: "600",
81
+ color: colors.blue.hex
82
+ },
83
+ ".cm-completionDetail": {
84
+ marginLeft: "auto",
85
+ paddingLeft: "12px",
86
+ fontStyle: "normal",
87
+ fontSize: "85%",
88
+ color: colors.overlay1.hex
89
+ },
90
+ ".cm-completionIcon": {
91
+ width: "14px",
92
+ paddingRight: "8px",
93
+ opacity: "1",
94
+ color: colors.overlay1.hex
95
+ },
96
+ ".cm-completionIcon:after": {
97
+ content: "''",
98
+ display: "block",
99
+ width: "12px",
100
+ height: "12px",
101
+ backgroundColor: "currentColor",
102
+ maskImage: COMPLETION_ICON_FALLBACK,
103
+ WebkitMaskImage: COMPLETION_ICON_FALLBACK,
104
+ maskRepeat: "no-repeat",
105
+ WebkitMaskRepeat: "no-repeat",
106
+ maskPosition: "center",
107
+ WebkitMaskPosition: "center",
108
+ maskSize: "contain",
109
+ WebkitMaskSize: "contain"
110
+ },
111
+ ...completionIconRules(),
112
+ ".cm-completionIcon-keyword": { color: colors.mauve.hex },
113
+ ".cm-completionIcon-function, .cm-completionIcon-method": { color: colors.blue.hex },
114
+ ".cm-completionIcon-variable": { color: colors.peach.hex },
115
+ ".cm-completionIcon-constant": { color: colors.sky.hex },
116
+ ".cm-completionIcon-property": { color: colors.teal.hex },
117
+ ".cm-completionIcon-namespace": { color: colors.sapphire.hex },
118
+ ".cm-completionIcon-text": { color: colors.overlay1.hex },
119
+ ".cm-completionIcon-class, .cm-completionIcon-type, .cm-completionIcon-interface, .cm-completionIcon-enum": { color: colors.yellow.hex },
120
+ ".cm-tooltip.cm-completionInfo": {
121
+ ...frame,
122
+ padding: "8px 10px",
123
+ maxWidth: "26em"
124
+ },
125
+ "&.cm-focused": { outline: "none" },
126
+ ".cm-activeLine": { backgroundColor: alphaOf(colors.overlay0, .12) },
127
+ ".cm-activeLineGutter": { backgroundColor: alphaOf(colors.overlay0, .12) },
128
+ "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": { backgroundColor: alphaOf(colors.blue, dark ? .35 : .25) },
129
+ ".cm-selectionBackground": { backgroundColor: alphaOf(colors.blue, dark ? .2 : .14) },
130
+ ".cm-content ::selection": { backgroundColor: alphaOf(colors.blue, dark ? .35 : .25) },
131
+ ".cm-scroller, .cm-tooltip-autocomplete > ul, .cm-tooltip.cm-completionInfo": {
132
+ scrollbarWidth: "thin",
133
+ scrollbarColor: `${alphaOf(colors.overlay0, .55)} transparent`
134
+ },
135
+ ".cm-panels.cm-panels-top": { borderBottom: hairline },
136
+ ".cm-panels.cm-panels-bottom": { borderTop: hairline },
137
+ ".cm-panel.cm-search, .cm-panel.cm-gotoLine": {
138
+ position: "relative",
139
+ display: "flex",
140
+ flexWrap: "wrap",
141
+ alignItems: "center",
142
+ columnGap: "8px",
143
+ rowGap: "8px",
144
+ margin: "0",
145
+ padding: "10px 44px 10px 14px"
146
+ },
147
+ ".cm-panel.cm-search br": {
148
+ flexBasis: "100%",
149
+ height: "0",
150
+ margin: "0",
151
+ border: "none"
152
+ },
153
+ ".cm-panel.cm-search label, .cm-panel.cm-gotoLine label": {
154
+ display: "inline-flex",
155
+ alignItems: "center",
156
+ gap: "6px",
157
+ margin: "0",
158
+ fontSize: "12.5px",
159
+ color: colors.subtext0.hex,
160
+ cursor: "pointer",
161
+ userSelect: "none"
162
+ },
163
+ ".cm-panel.cm-search input[type=checkbox]": {
164
+ margin: "0",
165
+ width: "14px",
166
+ height: "14px",
167
+ accentColor: colors.blue.hex
168
+ },
169
+ ".cm-panel.cm-search button[name=close]": {
170
+ position: "absolute",
171
+ top: "10px",
172
+ right: "10px",
173
+ boxSizing: "border-box",
174
+ width: "28px",
175
+ height: "28px",
176
+ padding: "0",
177
+ display: "inline-flex",
178
+ alignItems: "center",
179
+ justifyContent: "center",
180
+ fontSize: "16px",
181
+ lineHeight: "1",
182
+ color: colors.overlay1.hex,
183
+ background: "transparent",
184
+ border: "none",
185
+ borderRadius: "6px",
186
+ cursor: "pointer"
187
+ },
188
+ ".cm-panel.cm-search button[name=close]:hover": {
189
+ backgroundColor: colors.surface0.hex,
190
+ color: colors.text.hex
191
+ },
192
+ ".cm-panel .cm-textfield": {
193
+ boxSizing: "border-box",
194
+ height: "28px",
195
+ width: "240px",
196
+ maxWidth: "100%",
197
+ margin: "0",
198
+ padding: "0 10px",
199
+ fontSize: "12.5px",
200
+ color: colors.text.hex,
201
+ backgroundColor: colors.base.hex,
202
+ border: hairline,
203
+ borderRadius: "6px"
204
+ },
205
+ ".cm-panel .cm-textfield:focus": {
206
+ outline: "none",
207
+ borderColor: alphaOf(colors.blue, .6),
208
+ boxShadow: `0 0 0 2px ${alphaOf(colors.blue, .2)}`
209
+ },
210
+ ".cm-panel .cm-button": {
211
+ boxSizing: "border-box",
212
+ height: "28px",
213
+ margin: "0",
214
+ padding: "0 12px",
215
+ fontSize: "12.5px",
216
+ color: colors.text.hex,
217
+ backgroundImage: "none",
218
+ backgroundColor: colors.surface0.hex,
219
+ border: hairline,
220
+ borderRadius: "6px",
221
+ cursor: "pointer"
222
+ },
223
+ ".cm-panel .cm-button:hover": { backgroundColor: colors.surface1.hex },
224
+ ".cm-panel .cm-button:active": {
225
+ backgroundImage: "none",
226
+ backgroundColor: colors.surface1.hex
227
+ }
228
+ }, { dark });
229
+ }
230
+ function defaultThemeExtensions(dark, height, width, fontSize, lineHeight) {
231
+ const extensions = [Prec.low(chromeTheme(dark)), Prec.low(dark ? catppuccinMacchiato : catppuccinLatte)];
232
+ const cssHeight = toCssSize(height);
233
+ const cssWidth = toCssSize(width);
234
+ if (cssHeight !== void 0 || cssWidth !== void 0 || fontSize !== void 0 || lineHeight !== void 0) {
235
+ const root = {};
236
+ if (cssHeight !== void 0) root.height = cssHeight;
237
+ if (cssWidth !== void 0) root.width = cssWidth;
238
+ if (fontSize !== void 0) root.fontSize = `${fontSize}px`;
239
+ const spec = { "&": root };
240
+ const scroller = {};
241
+ if (cssHeight !== void 0) scroller.overflow = "auto";
242
+ if (lineHeight !== void 0) scroller.lineHeight = lineHeight < 8 ? String(lineHeight) : `${lineHeight}px`;
243
+ if (Object.keys(scroller).length > 0) spec[".cm-scroller"] = scroller;
244
+ extensions.push(EditorView.theme(spec));
245
+ }
246
+ return extensions;
247
+ }
248
+ 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
+ const containerRef = useRef(null);
250
+ const hostRef = useRef(null);
251
+ const onChangeRef = useRef(onChange);
252
+ onChangeRef.current = onChange;
253
+ const onMountRef = useRef(onMount);
254
+ onMountRef.current = onMount;
255
+ const onFocusRef = useRef(onFocus);
256
+ onFocusRef.current = onFocus;
257
+ const onBlurRef = useRef(onBlur);
258
+ onBlurRef.current = onBlur;
259
+ const lastContextRef = useRef(null);
260
+ const [languageExtension, setLanguageExtension] = useState([]);
261
+ useEffect(() => {
262
+ if (!language) {
263
+ setLanguageExtension([]);
264
+ return;
265
+ }
266
+ let cancelled = false;
267
+ loadLanguage(language).then((extension) => {
268
+ if (!cancelled) setLanguageExtension([extension]);
269
+ }).catch((error) => {
270
+ console.error("inkstone: failed to load CodeMirror language", language, error);
271
+ });
272
+ return () => {
273
+ cancelled = true;
274
+ };
275
+ }, [language]);
276
+ const dynamic = useMemo(() => [
277
+ ...defaultThemeExtensions(dark, height, width, fontSize, lineHeight),
278
+ ...tabSize === void 0 ? [] : [EditorState.tabSize.of(tabSize), indentUnit.of(" ".repeat(tabSize))],
279
+ ...locale === "zh-cn" ? [searchPhrasesZhCn$1] : [],
280
+ ...languageExtension,
281
+ ...dynamicExtensions ?? []
282
+ ], [
283
+ dark,
284
+ height,
285
+ width,
286
+ fontSize,
287
+ lineHeight,
288
+ tabSize,
289
+ locale,
290
+ languageExtension,
291
+ dynamicExtensions
292
+ ]);
293
+ const contextSchema = useMemo(() => context ? normalizeContext$1(context) : null, [context]);
294
+ useEffect(() => {
295
+ const container = containerRef.current;
296
+ if (!container) return;
297
+ const host = new ControlledEditorHost({
298
+ parent: container,
299
+ doc: value,
300
+ onChange: (next) => onChangeRef.current?.(next),
301
+ extensions: [
302
+ ...documentExtensions({
303
+ placeholder,
304
+ lineWrapping,
305
+ showLineNumbers,
306
+ folding,
307
+ spellcheck,
308
+ search
309
+ }),
310
+ EditorView.updateListener.of((update) => {
311
+ if (update.focusChanged) if (update.view.hasFocus) onFocusRef.current?.();
312
+ else onBlurRef.current?.();
313
+ }),
314
+ ...extensions ?? []
315
+ ],
316
+ dynamicExtensions: dynamic
317
+ });
318
+ hostRef.current = host;
319
+ onMountRef.current?.(host.view);
320
+ return () => {
321
+ host.destroy();
322
+ hostRef.current = null;
323
+ };
324
+ }, []);
325
+ useEffect(() => {
326
+ hostRef.current?.setValue(value);
327
+ }, [value]);
328
+ useEffect(() => {
329
+ hostRef.current?.reconfigure(dynamic);
330
+ }, [dynamic]);
331
+ useEffect(() => {
332
+ const host = hostRef.current;
333
+ if (!host) return;
334
+ const key = contextSchema ? JSON.stringify(contextSchema) : "";
335
+ const last = lastContextRef.current;
336
+ if (last && last.key === key && last.language === languageExtension) return;
337
+ lastContextRef.current = {
338
+ key,
339
+ language: languageExtension
340
+ };
341
+ if (key === "" && (!last || last.key === "")) return;
342
+ host.view.dispatch({ effects: setMinijinjaContext.of(contextSchema) });
343
+ }, [contextSchema, languageExtension]);
344
+ return /* @__PURE__ */ jsx("div", {
345
+ ref: containerRef,
346
+ className
347
+ });
348
+ }
349
+ //#endregion
350
+ //#region src/use-shiki-highlighter.ts
351
+ function useShikiHighlighter() {
352
+ const [state, setState] = useState("loading");
353
+ const highlighterRef = useRef(null);
354
+ useEffect(() => {
355
+ let cancelled = false;
356
+ getHighlighter().then((highlighter) => {
357
+ if (cancelled) return;
358
+ highlighterRef.current = highlighter;
359
+ setState("ready");
360
+ }).catch((error) => {
361
+ console.error("inkstone: shiki highlighter failed to load", error);
362
+ if (!cancelled) setState("failed");
363
+ });
364
+ return () => {
365
+ cancelled = true;
366
+ };
367
+ }, []);
368
+ return {
369
+ state,
370
+ highlighterRef
371
+ };
372
+ }
373
+ //#endregion
374
+ //#region src/monaco-editor.tsx
375
+ const DEFAULT_MONACO_OPTIONS = {
376
+ find: { addExtraSpaceOnTop: false },
377
+ minimap: { enabled: false },
378
+ fontSize: 14,
379
+ lineHeight: 1.6,
380
+ fontFamily: "var(--inkstone-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)",
381
+ scrollBeyondLastLine: false,
382
+ automaticLayout: true,
383
+ renderLineHighlight: "line",
384
+ smoothScrolling: true,
385
+ padding: {
386
+ top: 12,
387
+ bottom: 12
388
+ },
389
+ fixedOverflowWidgets: true,
390
+ quickSuggestions: {
391
+ other: true,
392
+ comments: false,
393
+ strings: true
394
+ },
395
+ wordBasedSuggestions: "off",
396
+ tabCompletion: "on",
397
+ scrollbar: {
398
+ alwaysConsumeMouseWheel: false,
399
+ verticalScrollbarSize: 8,
400
+ horizontalScrollbarSize: 8
401
+ }
402
+ };
403
+ function documentOptions({ placeholder, lineWrapping, showLineNumbers, folding, disableContextMenu, fontSize, lineHeight, tabSize }) {
404
+ const resolved = {
405
+ placeholder,
406
+ wordWrap: lineWrapping ? "on" : "off",
407
+ lineNumbers: showLineNumbers ? "on" : "off",
408
+ folding,
409
+ contextmenu: !disableContextMenu
410
+ };
411
+ if (fontSize !== void 0) resolved.fontSize = fontSize;
412
+ if (lineHeight !== void 0) resolved.lineHeight = lineHeight;
413
+ if (tabSize !== void 0) resolved.tabSize = tabSize;
414
+ return resolved;
415
+ }
416
+ let loaderConfigured = false;
417
+ function configureLoader(monaco) {
418
+ if (loaderConfigured) return;
419
+ loaderConfigured = true;
420
+ loader.config({ monaco });
421
+ }
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
+ let shikiRegistered = false;
432
+ function registerShikiHighlighting(monaco, highlighter) {
433
+ if (shikiRegistered) return;
434
+ shikiRegistered = true;
435
+ const canonical = new Set(highlighter.getLoadedLanguages().map((id) => highlighter.getLanguage(id).name));
436
+ const registered = new Set(monaco.languages.getLanguages().map((registeredLanguage) => registeredLanguage.id));
437
+ for (const lang of canonical) if (!registered.has(lang)) monaco.languages.register({ id: lang });
438
+ shikiToMonaco(highlighter, monaco);
439
+ }
440
+ 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 }) {
441
+ const [hostState, setHostState] = useState("loading");
442
+ const { state: shikiState, highlighterRef } = useShikiHighlighter();
443
+ const hostOptionsRef = useRef(hostOptions);
444
+ const localeRef = useRef(locale);
445
+ const beforeMountRef = useRef(beforeMount);
446
+ beforeMountRef.current = beforeMount;
447
+ const onMountRef = useRef(onMount);
448
+ onMountRef.current = onMount;
449
+ const onFocusRef = useRef(onFocus);
450
+ onFocusRef.current = onFocus;
451
+ const onBlurRef = useRef(onBlur);
452
+ onBlurRef.current = onBlur;
453
+ useEffect(() => {
454
+ let cancelled = false;
455
+ ensureMonacoHost({
456
+ ...hostOptionsRef.current,
457
+ locale: localeRef.current ?? hostOptionsRef.current?.locale
458
+ }).then((monaco) => {
459
+ configureLoader(monaco);
460
+ if (!cancelled) setHostState("ready");
461
+ }).catch((error) => {
462
+ console.error("inkstone: monaco host failed to load", error);
463
+ if (!cancelled) setHostState("failed");
464
+ });
465
+ return () => {
466
+ cancelled = true;
467
+ };
468
+ }, []);
469
+ if (hostState === "failed") return failure;
470
+ if (hostState === "loading" || shikiState === "loading") return loading;
471
+ const handleBeforeMount = (monaco) => {
472
+ const highlighter = highlighterRef.current;
473
+ if (highlighter) registerShikiHighlighting(monaco, highlighter);
474
+ beforeMountRef.current?.(monaco);
475
+ };
476
+ const handleMount = (editorInstance, monaco) => {
477
+ const swallowed = disabledKeybindings(monaco, disableFind, disableCommandPalette);
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
+ }
482
+ editorInstance.onDidFocusEditorText(() => onFocusRef.current?.());
483
+ editorInstance.onDidBlurEditorText(() => onBlurRef.current?.());
484
+ onMountRef.current?.(editorInstance, monaco);
485
+ };
486
+ return /* @__PURE__ */ jsx(Editor, {
487
+ beforeMount: handleBeforeMount,
488
+ className,
489
+ height,
490
+ language,
491
+ loading,
492
+ path,
493
+ theme: shikiState === "ready" ? shikiThemeId(dark) : dark ? "vs-dark" : "vs",
494
+ value,
495
+ width,
496
+ options: {
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 ?? ""),
511
+ onMount: handleMount
512
+ });
513
+ }
514
+ //#endregion
515
+ export { CodeMirrorEditor, DEFAULT_MONACO_OPTIONS, MonacoEditor, codeMirrorLanguages, normalizeContext, searchPhrasesZhCn, useShikiHighlighter };
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@coldsmirk/inkstone-react",
3
+ "version": "0.8.2",
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
+ "keywords": [
6
+ "react",
7
+ "monaco",
8
+ "codemirror",
9
+ "editor",
10
+ "shiki",
11
+ "code-editor"
12
+ ],
13
+ "homepage": "https://github.com/coldsmirk/inkstone/tree/main/packages/react#readme",
14
+ "bugs": "https://github.com/coldsmirk/inkstone/issues",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/coldsmirk/inkstone.git",
18
+ "directory": "packages/react"
19
+ },
20
+ "license": "UNLICENSED",
21
+ "author": {
22
+ "name": "Venus"
23
+ },
24
+ "sideEffects": false,
25
+ "type": "module",
26
+ "exports": {
27
+ ".": {
28
+ "import": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ },
32
+ "require": {
33
+ "types": "./dist/index.d.cts",
34
+ "default": "./dist/index.cjs"
35
+ }
36
+ },
37
+ "./package.json": "./package.json"
38
+ },
39
+ "main": "./dist/index.cjs",
40
+ "module": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "files": [
43
+ "dist"
44
+ ],
45
+ "dependencies": {
46
+ "@catppuccin/codemirror": "^1.0.1",
47
+ "@catppuccin/palette": "^1.8.0",
48
+ "@monaco-editor/react": "^4.7.0",
49
+ "@shikijs/monaco": "^4.3.1",
50
+ "@coldsmirk/inkstone-codemirror": "^0.8.2",
51
+ "@coldsmirk/inkstone-core": "^0.8.2",
52
+ "@coldsmirk/inkstone-monaco": "^0.8.2"
53
+ },
54
+ "devDependencies": {
55
+ "@codemirror/autocomplete": "^6.20.3",
56
+ "@codemirror/commands": "^6.10.4",
57
+ "@codemirror/language": "^6.12.3",
58
+ "@codemirror/search": "^6.6.0",
59
+ "@codemirror/state": "^6.6.0",
60
+ "@codemirror/view": "^6.43.0",
61
+ "monaco-editor": "^0.55.1",
62
+ "react": "^19.2.7",
63
+ "react-dom": "^19.2.7"
64
+ },
65
+ "peerDependencies": {
66
+ "@codemirror/autocomplete": "^6.20.3",
67
+ "@codemirror/commands": "^6.10.4",
68
+ "@codemirror/language": "^6.12.3",
69
+ "@codemirror/search": "^6.6.0",
70
+ "@codemirror/state": "^6.6.0",
71
+ "@codemirror/view": "^6.43.0",
72
+ "monaco-editor": "^0.55.1",
73
+ "react": ">=19"
74
+ },
75
+ "engines": {
76
+ "node": ">=22"
77
+ },
78
+ "publishConfig": {
79
+ "access": "public"
80
+ },
81
+ "scripts": {
82
+ "build": "tsdown",
83
+ "clean": "rimraf dist",
84
+ "typecheck": "tsc --noEmit"
85
+ }
86
+ }