@simple-mark/codemirror 0.1.0 → 0.3.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 +5 -0
- package/index.d.ts +33 -5
- package/index.js +150 -85
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ const view = createEditor(document.getElementById('editor')!, {
|
|
|
11
11
|
doc: '# Hello **world**\n\n| a | b |\n|---|---|\n| 1 | 2 |\n',
|
|
12
12
|
onChange: (text) => save(text), // in the document's own line endings
|
|
13
13
|
resolveImage: (src) => new URL(src, base).href,
|
|
14
|
+
openLink: (target) => open(target), // { kind: 'web' | 'file' | 'image', url }
|
|
14
15
|
});
|
|
15
16
|
```
|
|
16
17
|
|
|
@@ -19,6 +20,10 @@ const view = createEditor(document.getElementById('editor')!, {
|
|
|
19
20
|
them with an IME is safe.
|
|
20
21
|
- **Images** and `$$` math preview below their source; `$inline$` math in a tooltip. Math
|
|
21
22
|
(`@simple-mark/math`) loads only when a document has math.
|
|
23
|
+
- **Links**: Ctrl+Click (⌘+Click on macOS) follows a link — a plain click keeps placing the
|
|
24
|
+
cursor, since links are editable text. `#heading` links jump within the document; other
|
|
25
|
+
schemes than http(s)/mailto are refused; web pages and paths go to `openLink` (default: a
|
|
26
|
+
new browser tab). A click on an image preview opens the image.
|
|
22
27
|
- **Line endings** are kept (`\r\n`, `\r`), so an unedited file saves back byte for byte.
|
|
23
28
|
- Accurate scroll heights for documents with many images and formulas.
|
|
24
29
|
- `simpleMark(theme)` gives the extensions for your own `EditorState`.
|
package/index.d.ts
CHANGED
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import { EditorState, Extension, Facet, StateCommand } from "@codemirror/state";
|
|
2
2
|
import { DecorationSet, EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view";
|
|
3
3
|
import { LineLook, Theme } from "@simple-mark/model";
|
|
4
|
-
//#region packages/codemirror/src/
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
//#region packages/codemirror/src/links.d.ts
|
|
5
|
+
/** What to open: a web address, or a path as written (an image, another document, …). */
|
|
6
|
+
interface LinkTarget {
|
|
7
|
+
kind: 'web' | 'file' | 'image';
|
|
8
|
+
url: string;
|
|
9
|
+
}
|
|
10
|
+
/** Opens a link target; hosts replace this with their own (see `createEditor`'s `openLink`). */
|
|
11
|
+
type LinkOpener = (target: LinkTarget, view: EditorView) => void;
|
|
12
|
+
/** How links are opened. */
|
|
13
|
+
export declare const linkOpener: Facet<LinkOpener, LinkOpener>;
|
|
14
|
+
/**
|
|
15
|
+
* Follows a link target as written (`isImage`: from ``). Returns false when there
|
|
16
|
+
* is nothing to open: no target, an unsafe scheme, or an anchor no heading has.
|
|
17
|
+
*/
|
|
18
|
+
export declare function followLink(view: EditorView, target: string | null, isImage?: boolean): boolean;
|
|
19
|
+
/** Ctrl/Cmd+Click follows links; `#anchors` jump to headings. */
|
|
20
|
+
export declare function links(): Extension;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region packages/codemirror/src/image-resolver.d.ts
|
|
23
|
+
/**
|
|
24
|
+
* Turns a path as written in the document into a URL to load, or several to try in order
|
|
25
|
+
* (the first that loads is shown), or null if it can't be loaded.
|
|
26
|
+
*/
|
|
27
|
+
type ImageResolver = (src: string) => string | readonly string[] | null;
|
|
28
|
+
/** How image (and file) paths are resolved; by default they are used as written. */
|
|
8
29
|
export declare const imageResolver: Facet<ImageResolver, ImageResolver>;
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region packages/codemirror/src/previews.d.ts
|
|
9
32
|
/** Image and math previews; the source text always stays visible. */
|
|
10
33
|
export declare function previews(): Extension;
|
|
11
34
|
//#endregion
|
|
@@ -63,6 +86,11 @@ export interface EditorOptions {
|
|
|
63
86
|
lineSeparator?: string;
|
|
64
87
|
/** Turns an image path from the document into a URL to load (default: as written). */
|
|
65
88
|
resolveImage?: ImageResolver;
|
|
89
|
+
/**
|
|
90
|
+
* Opens a followed link (Ctrl/Cmd+Click) or a clicked image preview. Default: web addresses
|
|
91
|
+
* and paths (resolved like images) in a new browser tab.
|
|
92
|
+
*/
|
|
93
|
+
openLink?: LinkOpener;
|
|
66
94
|
/** Off when the host owns undo (VS Code). */
|
|
67
95
|
history?: boolean;
|
|
68
96
|
/** Called after every change with the full text, in the original line endings. */
|
|
@@ -72,4 +100,4 @@ export interface EditorOptions {
|
|
|
72
100
|
/** A Markdown editor in `parent`. The text is kept exactly as given, line endings included. */
|
|
73
101
|
export declare function createEditor(parent: HTMLElement, options?: EditorOptions): EditorView;
|
|
74
102
|
//#endregion
|
|
75
|
-
export type { ImageResolver };
|
|
103
|
+
export type { ImageResolver, LinkOpener, LinkTarget };
|
package/index.js
CHANGED
|
@@ -2,8 +2,115 @@ import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
|
|
|
2
2
|
import { commonmarkLanguage, markdown } from "@codemirror/lang-markdown";
|
|
3
3
|
import { EditorState, Facet, Prec, StateEffect, StateField } from "@codemirror/state";
|
|
4
4
|
import { Decoration, EditorView, ViewPlugin, WidgetType, hoverTooltip, keymap, showTooltip } from "@codemirror/view";
|
|
5
|
-
import { cellAt, charWidth, defaultTheme, markdownExtensions, markdownStyles, parseTable, renderTable, resolveLineLook, resolveLook, rowLine } from "@simple-mark/model";
|
|
5
|
+
import { cellAt, charWidth, defaultTheme, headingAnchors, linkAt, linkKind, markdownExtensions, markdownStyles, mathSource, parseTable, previewBlocks, renderTable, resolveLineLook, resolveLook, rowLine } from "@simple-mark/model";
|
|
6
6
|
import { ensureSyntaxTree, syntaxTree } from "@codemirror/language";
|
|
7
|
+
//#region packages/codemirror/src/image-resolver.ts
|
|
8
|
+
/** The URLs a resolver gives for `src`, in order. */
|
|
9
|
+
function resolvedUrls(resolve, src) {
|
|
10
|
+
const result = resolve(src);
|
|
11
|
+
return result === null ? [] : typeof result === "string" ? [result] : [...result];
|
|
12
|
+
}
|
|
13
|
+
/** How image (and file) paths are resolved; by default they are used as written. */
|
|
14
|
+
const imageResolver = Facet.define({ combine: (values) => values[0] ?? ((src) => src) });
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region packages/codemirror/src/links.ts
|
|
17
|
+
/** In a browser: web addresses and paths (resolved like images) open in a new tab. */
|
|
18
|
+
const openInBrowser = (target, view) => {
|
|
19
|
+
const url = target.kind === "web" ? target.url : resolvedUrls(view.state.facet(imageResolver), target.url)[0];
|
|
20
|
+
if (url) window.open(url, "_blank", "noopener,noreferrer");
|
|
21
|
+
};
|
|
22
|
+
/** How links are opened. */
|
|
23
|
+
const linkOpener = Facet.define({ combine: (values) => values[0] ?? openInBrowser });
|
|
24
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
|
|
25
|
+
/** The key held to follow a link: Cmd on macOS, Ctrl elsewhere. */
|
|
26
|
+
const followKeyName = isMac ? "⌘" : "Ctrl";
|
|
27
|
+
const followKey = (event) => isMac ? event.metaKey : event.ctrlKey;
|
|
28
|
+
/**
|
|
29
|
+
* Follows a link target as written (`isImage`: from ``). Returns false when there
|
|
30
|
+
* is nothing to open: no target, an unsafe scheme, or an anchor no heading has.
|
|
31
|
+
*/
|
|
32
|
+
function followLink(view, target, isImage = false) {
|
|
33
|
+
if (target === null) return false;
|
|
34
|
+
const { kind, url } = linkKind(target);
|
|
35
|
+
if (kind === "unsafe") return false;
|
|
36
|
+
if (kind === "anchor") {
|
|
37
|
+
const wanted = decodeURIComponent(url.slice(1)).toLowerCase();
|
|
38
|
+
const heading = headingAnchors(syntaxTree(view.state), view.state.doc.toString()).find((h) => h.anchor === wanted);
|
|
39
|
+
if (!heading) return false;
|
|
40
|
+
view.dispatch({
|
|
41
|
+
selection: { anchor: heading.from },
|
|
42
|
+
effects: EditorView.scrollIntoView(heading.from, {
|
|
43
|
+
y: "start",
|
|
44
|
+
yMargin: 24
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
view.focus();
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
view.state.facet(linkOpener)({
|
|
51
|
+
kind: kind === "file" && isImage ? "image" : kind,
|
|
52
|
+
url
|
|
53
|
+
}, view);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
/** Ctrl/Cmd+Click on a link follows it (instead of adding a cursor there). */
|
|
57
|
+
const clickToFollow = EditorView.domEventHandlers({ mousedown(event, view) {
|
|
58
|
+
if (event.button !== 0 || !followKey(event) || event.shiftKey || event.altKey) return false;
|
|
59
|
+
if (!(event.target instanceof Element) || !event.target.closest(".sm-link, .sm-url")) return false;
|
|
60
|
+
const pos = view.posAtCoords({
|
|
61
|
+
x: event.clientX,
|
|
62
|
+
y: event.clientY
|
|
63
|
+
});
|
|
64
|
+
if (pos === null) return false;
|
|
65
|
+
const link = linkAt(syntaxTree(view.state), view.state.doc.toString(), pos);
|
|
66
|
+
if (!link) return false;
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
followLink(view, link.target, link.kind === "image");
|
|
69
|
+
return true;
|
|
70
|
+
} });
|
|
71
|
+
/** While Ctrl/Cmd is held, links look clickable (pointer, underline). */
|
|
72
|
+
const followKeyHint = ViewPlugin.fromClass(class {
|
|
73
|
+
view;
|
|
74
|
+
constructor(view) {
|
|
75
|
+
this.view = view;
|
|
76
|
+
for (const type of [
|
|
77
|
+
"keydown",
|
|
78
|
+
"keyup",
|
|
79
|
+
"mousemove"
|
|
80
|
+
]) window.addEventListener(type, this.track, true);
|
|
81
|
+
window.addEventListener("blur", this.clear);
|
|
82
|
+
}
|
|
83
|
+
destroy() {
|
|
84
|
+
for (const type of [
|
|
85
|
+
"keydown",
|
|
86
|
+
"keyup",
|
|
87
|
+
"mousemove"
|
|
88
|
+
]) window.removeEventListener(type, this.track, true);
|
|
89
|
+
window.removeEventListener("blur", this.clear);
|
|
90
|
+
}
|
|
91
|
+
track = (event) => {
|
|
92
|
+
this.view.dom.classList.toggle("sm-follow-links", followKey(event));
|
|
93
|
+
};
|
|
94
|
+
clear = () => {
|
|
95
|
+
this.view.dom.classList.remove("sm-follow-links");
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
const followTheme = EditorView.theme({
|
|
99
|
+
"&.sm-follow-links .sm-link, &.sm-follow-links .sm-url": {
|
|
100
|
+
cursor: "pointer",
|
|
101
|
+
textDecoration: "underline"
|
|
102
|
+
},
|
|
103
|
+
".sm-image-preview img": { cursor: "pointer" }
|
|
104
|
+
});
|
|
105
|
+
/** Ctrl/Cmd+Click follows links; `#anchors` jump to headings. */
|
|
106
|
+
function links() {
|
|
107
|
+
return [
|
|
108
|
+
clickToFollow,
|
|
109
|
+
followKeyHint,
|
|
110
|
+
followTheme
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
7
114
|
//#region packages/codemirror/src/decorations.ts
|
|
8
115
|
/** The theme the editor draws with. */
|
|
9
116
|
const markdownTheme = Facet.define({ combine: (values) => values[0] ?? defaultTheme });
|
|
@@ -144,9 +251,13 @@ var MarkdownDecorations = class {
|
|
|
144
251
|
const key = `mark:${styles.join(" ")}`;
|
|
145
252
|
let deco = this.cache.get(key);
|
|
146
253
|
if (!deco) {
|
|
254
|
+
const linked = styles.includes("link") || styles.includes("url");
|
|
147
255
|
deco = Decoration.mark({
|
|
148
256
|
class: styles.map((s) => `sm-${s}`).join(" "),
|
|
149
|
-
attributes: {
|
|
257
|
+
attributes: {
|
|
258
|
+
style: lookCss(resolveLook([], styles, this.theme), this.theme),
|
|
259
|
+
...linked ? { title: `${followKeyName}+Click to open` } : {}
|
|
260
|
+
}
|
|
150
261
|
});
|
|
151
262
|
this.cache.set(key, deco);
|
|
152
263
|
}
|
|
@@ -497,8 +608,6 @@ function lineHeightHints() {
|
|
|
497
608
|
}
|
|
498
609
|
//#endregion
|
|
499
610
|
//#region packages/codemirror/src/previews.ts
|
|
500
|
-
/** How image paths are resolved; by default they are used as written. */
|
|
501
|
-
const imageResolver = Facet.define({ combine: (values) => values[0] ?? ((src) => src) });
|
|
502
611
|
/** Fills `dom` with rendered math now if known, otherwise when it is ready. */
|
|
503
612
|
function renderInto(dom, tex, display, onDone) {
|
|
504
613
|
const show = (result) => {
|
|
@@ -549,56 +658,26 @@ var MathBlockWidget = class extends WidgetType {
|
|
|
549
658
|
return dom;
|
|
550
659
|
}
|
|
551
660
|
};
|
|
552
|
-
/**
|
|
553
|
-
function
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
if (label && url) {
|
|
570
|
-
const key = normalizeLabel(state.sliceDoc(label.from, label.to));
|
|
571
|
-
if (!definitions.has(key)) definitions.set(key, destination(state, url));
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
return definitions;
|
|
575
|
-
}
|
|
576
|
-
function imageRef(state, node, definitions, resolve) {
|
|
577
|
-
const marks = node.getChildren("LinkMark");
|
|
578
|
-
const alt = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
579
|
-
const url = node.getChild("URL");
|
|
580
|
-
let raw = url ? destination(state, url) : void 0;
|
|
581
|
-
if (raw === void 0) {
|
|
582
|
-
const labelNode = node.getChild("LinkLabel");
|
|
583
|
-
const labelText = labelNode && labelNode.to - labelNode.from > 2 ? state.sliceDoc(labelNode.from, labelNode.to) : `[${alt}]`;
|
|
584
|
-
raw = definitions.get(normalizeLabel(labelText));
|
|
585
|
-
if (raw === void 0) return {
|
|
586
|
-
raw: labelText,
|
|
587
|
-
src: null,
|
|
588
|
-
alt,
|
|
589
|
-
problem: `No definition for ${labelText}`
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
const src = resolve(raw);
|
|
593
|
-
return src === null ? {
|
|
594
|
-
raw,
|
|
595
|
-
src,
|
|
596
|
-
alt,
|
|
597
|
-
problem: `Can't load ${raw}`
|
|
598
|
-
} : {
|
|
599
|
-
raw,
|
|
661
|
+
/** An image from the document with its path resolved by the host. */
|
|
662
|
+
function imageRef(image, resolve) {
|
|
663
|
+
if (image.src === null) return {
|
|
664
|
+
raw: image.raw,
|
|
665
|
+
src: null,
|
|
666
|
+
alt: image.alt,
|
|
667
|
+
problem: `No definition for ${image.raw}`
|
|
668
|
+
};
|
|
669
|
+
const [src, ...fallbacks] = resolvedUrls(resolve, image.src);
|
|
670
|
+
if (src === void 0) return {
|
|
671
|
+
raw: image.raw,
|
|
672
|
+
src: null,
|
|
673
|
+
alt: image.alt,
|
|
674
|
+
problem: `Can't load ${image.raw}`
|
|
675
|
+
};
|
|
676
|
+
return {
|
|
677
|
+
raw: image.raw,
|
|
600
678
|
src,
|
|
601
|
-
|
|
679
|
+
...fallbacks.length ? { fallbacks } : {},
|
|
680
|
+
alt: image.alt
|
|
602
681
|
};
|
|
603
682
|
}
|
|
604
683
|
var ImageWidget = class extends WidgetType {
|
|
@@ -658,9 +737,17 @@ var ImageWidget = class extends WidgetType {
|
|
|
658
737
|
img.decoding = "async";
|
|
659
738
|
img.src = image.src;
|
|
660
739
|
img.alt = image.alt;
|
|
661
|
-
img.title = image.raw
|
|
740
|
+
img.title = `${image.raw} (click to open)`;
|
|
741
|
+
img.addEventListener("click", () => followLink(view, image.raw, true));
|
|
662
742
|
img.onload = settled;
|
|
743
|
+
const fallbacks = [...image.fallbacks ?? []];
|
|
663
744
|
img.onerror = () => {
|
|
745
|
+
const next = fallbacks.shift();
|
|
746
|
+
if (next !== void 0) {
|
|
747
|
+
watchImage(img, next);
|
|
748
|
+
img.src = next;
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
664
751
|
img.replaceWith(problem(`Image not found: ${image.raw}`));
|
|
665
752
|
settled();
|
|
666
753
|
};
|
|
@@ -672,35 +759,11 @@ var ImageWidget = class extends WidgetType {
|
|
|
672
759
|
};
|
|
673
760
|
/** What to preview below which lines: the images of each line, and closed non-empty $$ blocks. */
|
|
674
761
|
function blockPreviewSources(state) {
|
|
675
|
-
const tree = syntaxTree(state);
|
|
676
762
|
const resolve = state.facet(imageResolver);
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
if (node.name === "Image") {
|
|
682
|
-
const at = state.doc.lineAt(node.to).to;
|
|
683
|
-
let images = imagesByLine.get(at);
|
|
684
|
-
if (!images) {
|
|
685
|
-
imagesByLine.set(at, images = []);
|
|
686
|
-
previews.push({
|
|
687
|
-
at,
|
|
688
|
-
images
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
images.push(imageRef(state, node.node, definitions, resolve));
|
|
692
|
-
return false;
|
|
693
|
-
}
|
|
694
|
-
if (node.name === "BlockMath") {
|
|
695
|
-
const tex = mathTex(state, node.node);
|
|
696
|
-
if (tex !== null && tex.trim()) previews.push({
|
|
697
|
-
at: state.doc.lineAt(node.to).to,
|
|
698
|
-
tex
|
|
699
|
-
});
|
|
700
|
-
return false;
|
|
701
|
-
}
|
|
702
|
-
} });
|
|
703
|
-
return previews;
|
|
763
|
+
return previewBlocks(syntaxTree(state), state.doc.toString()).map((block) => "tex" in block ? block : {
|
|
764
|
+
at: block.at,
|
|
765
|
+
images: block.images.map((image) => imageRef(image, resolve))
|
|
766
|
+
});
|
|
704
767
|
}
|
|
705
768
|
function blockPreviews(state) {
|
|
706
769
|
const ranges = blockPreviewSources(state).map((preview) => {
|
|
@@ -728,7 +791,7 @@ function inlineMathAt(state, pos) {
|
|
|
728
791
|
}
|
|
729
792
|
function mathTooltip(state, pos) {
|
|
730
793
|
const node = inlineMathAt(state, pos);
|
|
731
|
-
const tex = node &&
|
|
794
|
+
const tex = node && mathSource(node, (from, to) => state.sliceDoc(from, to));
|
|
732
795
|
if (!node || !tex) return null;
|
|
733
796
|
const display = node.getChild("MathMark").to - node.from === 2;
|
|
734
797
|
return {
|
|
@@ -1021,6 +1084,7 @@ function simpleMark(theme = defaultTheme) {
|
|
|
1021
1084
|
markdownTheme.of(theme),
|
|
1022
1085
|
markdownDecorations,
|
|
1023
1086
|
previews(),
|
|
1087
|
+
links(),
|
|
1024
1088
|
EditorView.theme({
|
|
1025
1089
|
"&": { color: theme.color },
|
|
1026
1090
|
".cm-scroller": {
|
|
@@ -1032,7 +1096,7 @@ function simpleMark(theme = defaultTheme) {
|
|
|
1032
1096
|
}
|
|
1033
1097
|
/** A Markdown editor in `parent`. The text is kept exactly as given, line endings included. */
|
|
1034
1098
|
function createEditor(parent, options = {}) {
|
|
1035
|
-
const { doc = "", readOnly = false, theme = defaultTheme, resolveImage, onChange, extensions = [] } = options;
|
|
1099
|
+
const { doc = "", readOnly = false, theme = defaultTheme, resolveImage, openLink, onChange, extensions = [] } = options;
|
|
1036
1100
|
const useHistory = options.history ?? true;
|
|
1037
1101
|
return new EditorView({
|
|
1038
1102
|
parent,
|
|
@@ -1045,6 +1109,7 @@ function createEditor(parent, options = {}) {
|
|
|
1045
1109
|
EditorView.lineWrapping,
|
|
1046
1110
|
simpleMark(theme),
|
|
1047
1111
|
resolveImage ? imageResolver.of(resolveImage) : [],
|
|
1112
|
+
openLink ? linkOpener.of(openLink) : [],
|
|
1048
1113
|
EditorState.readOnly.of(readOnly),
|
|
1049
1114
|
EditorView.editable.of(!readOnly),
|
|
1050
1115
|
onChange ? EditorView.updateListener.of((update) => update.docChanged && onChange(update.state.sliceDoc(), update)) : [],
|
|
@@ -1054,4 +1119,4 @@ function createEditor(parent, options = {}) {
|
|
|
1054
1119
|
});
|
|
1055
1120
|
}
|
|
1056
1121
|
//#endregion
|
|
1057
|
-
export { createEditor, imageResolver, insertRowBelow, keepLineSeparator, lookCss, markdownDecorations, markdownTheme, nextCell, previews, previousCell, simpleMark, tableEditing };
|
|
1122
|
+
export { createEditor, followLink, imageResolver, insertRowBelow, keepLineSeparator, linkOpener, links, lookCss, markdownDecorations, markdownTheme, nextCell, previews, previousCell, simpleMark, tableEditing };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simple-mark/codemirror",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CodeMirror 6 editor that styles Markdown without hiding its syntax.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@codemirror/state": "^6.7.6",
|
|
29
29
|
"@codemirror/view": "^6.43.15",
|
|
30
30
|
"@lezer/common": "^1.5.3",
|
|
31
|
-
"@simple-mark/math": "^0.
|
|
32
|
-
"@simple-mark/model": "^0.
|
|
31
|
+
"@simple-mark/math": "^0.3.0",
|
|
32
|
+
"@simple-mark/model": "^0.3.0"
|
|
33
33
|
}
|
|
34
34
|
}
|