mardora 1.2.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/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/chunk-3OCUX4OO.js +7690 -0
- package/dist/chunk-3OCUX4OO.js.map +1 -0
- package/dist/chunk-3ZOCCFDL.cjs +74 -0
- package/dist/chunk-3ZOCCFDL.cjs.map +1 -0
- package/dist/chunk-7JOEPNEV.cjs +7740 -0
- package/dist/chunk-7JOEPNEV.cjs.map +1 -0
- package/dist/chunk-BIKZQZ6W.js +33 -0
- package/dist/chunk-BIKZQZ6W.js.map +1 -0
- package/dist/chunk-EQJESPP2.js +234 -0
- package/dist/chunk-EQJESPP2.js.map +1 -0
- package/dist/chunk-G4SE26YY.js +70 -0
- package/dist/chunk-G4SE26YY.js.map +1 -0
- package/dist/chunk-KNDWF2DP.cjs +35 -0
- package/dist/chunk-KNDWF2DP.cjs.map +1 -0
- package/dist/chunk-MLBEBFHB.cjs +2971 -0
- package/dist/chunk-MLBEBFHB.cjs.map +1 -0
- package/dist/chunk-P7JFCYU3.js +905 -0
- package/dist/chunk-P7JFCYU3.js.map +1 -0
- package/dist/chunk-SWFUKJDO.cjs +243 -0
- package/dist/chunk-SWFUKJDO.cjs.map +1 -0
- package/dist/chunk-WFVCG4LD.cjs +926 -0
- package/dist/chunk-WFVCG4LD.cjs.map +1 -0
- package/dist/chunk-XL6WFGJT.js +2901 -0
- package/dist/chunk-XL6WFGJT.js.map +1 -0
- package/dist/editor/index.cjs +277 -0
- package/dist/editor/index.cjs.map +1 -0
- package/dist/editor/index.d.cts +186 -0
- package/dist/editor/index.d.ts +186 -0
- package/dist/editor/index.js +4 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/index.cjs +405 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/index.cjs +12 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.d.cts +16 -0
- package/dist/lib/index.d.ts +16 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/mardora-DCwjomil.d.cts +640 -0
- package/dist/mardora-DCwjomil.d.ts +640 -0
- package/dist/plugins/index.cjs +104 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.cts +740 -0
- package/dist/plugins/index.d.ts +740 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/preview/index.cjs +38 -0
- package/dist/preview/index.cjs.map +1 -0
- package/dist/preview/index.d.cts +101 -0
- package/dist/preview/index.d.ts +101 -0
- package/dist/preview/index.js +5 -0
- package/dist/preview/index.js.map +1 -0
- package/dist/types-NBsaxl4d.d.cts +71 -0
- package/dist/types-Pw2SWWAR.d.ts +71 -0
- package/package.json +92 -0
- package/src/editor/attachments/extension.ts +181 -0
- package/src/editor/attachments/format.ts +63 -0
- package/src/editor/attachments/index.ts +3 -0
- package/src/editor/attachments/types.ts +37 -0
- package/src/editor/heading-fold/config.ts +25 -0
- package/src/editor/heading-fold/extension.ts +268 -0
- package/src/editor/heading-fold/extract.ts +88 -0
- package/src/editor/heading-fold/index.ts +5 -0
- package/src/editor/heading-fold/theme.ts +85 -0
- package/src/editor/heading-fold/types.ts +24 -0
- package/src/editor/i18n.ts +13 -0
- package/src/editor/icons/index.ts +367 -0
- package/src/editor/index.ts +16 -0
- package/src/editor/mardora.ts +257 -0
- package/src/editor/media-lightbox-theme.ts +146 -0
- package/src/editor/media-lightbox.ts +125 -0
- package/src/editor/plugin.ts +294 -0
- package/src/editor/selection-toolbar/activation.ts +123 -0
- package/src/editor/selection-toolbar/commands.ts +279 -0
- package/src/editor/selection-toolbar/extension.ts +564 -0
- package/src/editor/selection-toolbar/i18n.ts +164 -0
- package/src/editor/selection-toolbar/index.ts +7 -0
- package/src/editor/selection-toolbar/menu.ts +252 -0
- package/src/editor/selection-toolbar/position.ts +43 -0
- package/src/editor/selection-toolbar/theme.ts +195 -0
- package/src/editor/selection-toolbar/types.ts +155 -0
- package/src/editor/slash/default-commands.ts +190 -0
- package/src/editor/slash/extension.ts +319 -0
- package/src/editor/slash/index.ts +7 -0
- package/src/editor/slash/insertions.ts +26 -0
- package/src/editor/slash/menu.ts +123 -0
- package/src/editor/slash/position.ts +61 -0
- package/src/editor/slash/query.ts +33 -0
- package/src/editor/slash/theme.ts +113 -0
- package/src/editor/slash/types.ts +40 -0
- package/src/editor/table-of-contents/extension.ts +202 -0
- package/src/editor/table-of-contents/extract.ts +53 -0
- package/src/editor/table-of-contents/index.ts +7 -0
- package/src/editor/table-of-contents/panel.ts +83 -0
- package/src/editor/table-of-contents/slug.ts +50 -0
- package/src/editor/table-of-contents/storage.ts +35 -0
- package/src/editor/table-of-contents/theme.ts +153 -0
- package/src/editor/table-of-contents/types.ts +44 -0
- package/src/editor/theme.ts +72 -0
- package/src/editor/utils.ts +176 -0
- package/src/editor/view-plugin.ts +189 -0
- package/src/index.ts +5 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/input-handler.ts +47 -0
- package/src/plugins/code-plugin.theme.ts +545 -0
- package/src/plugins/code-plugin.ts +1892 -0
- package/src/plugins/emoji-plugin.ts +140 -0
- package/src/plugins/heading-plugin.ts +194 -0
- package/src/plugins/hr-plugin.ts +102 -0
- package/src/plugins/html-plugin.ts +353 -0
- package/src/plugins/image-plugin.ts +806 -0
- package/src/plugins/index.ts +71 -0
- package/src/plugins/inline-plugin.ts +311 -0
- package/src/plugins/link-plugin.ts +509 -0
- package/src/plugins/list-plugin.ts +492 -0
- package/src/plugins/math-plugin.ts +526 -0
- package/src/plugins/mermaid-plugin.ts +513 -0
- package/src/plugins/paragraph-plugin.ts +38 -0
- package/src/plugins/quote-plugin.ts +733 -0
- package/src/plugins/table-controls-theme.ts +126 -0
- package/src/plugins/table-controls.ts +423 -0
- package/src/plugins/table-model.ts +661 -0
- package/src/plugins/table-plugin.ts +2111 -0
- package/src/preview/context.ts +45 -0
- package/src/preview/css-generator.ts +64 -0
- package/src/preview/default-renderers.ts +29 -0
- package/src/preview/index.ts +29 -0
- package/src/preview/preview.ts +41 -0
- package/src/preview/renderer.ts +184 -0
- package/src/preview/syntax-theme.ts +112 -0
- package/src/preview/toc.ts +23 -0
- package/src/preview/types.ts +89 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view";
|
|
2
|
+
import { Extension, Facet, Range, RangeSetBuilder } from "@codemirror/state";
|
|
3
|
+
import { syntaxTree } from "@codemirror/language";
|
|
4
|
+
import { cursorInRange, selectionOverlapsRange, ThemeEnum } from "./utils";
|
|
5
|
+
import { mardoraBaseTheme } from "./theme";
|
|
6
|
+
import { DecorationContext, MardoraPlugin } from "./plugin";
|
|
7
|
+
import { MardoraNode } from "./mardora";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Facet to register plugins with the view plugin
|
|
11
|
+
*/
|
|
12
|
+
export const MardoraPluginsFacet = Facet.define<MardoraPlugin[], MardoraPlugin[]>({
|
|
13
|
+
combine: (values) => values.flat(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Facet to register the onNodesChange callback
|
|
18
|
+
*/
|
|
19
|
+
export const mardoraOnNodesChangeFacet = Facet.define<
|
|
20
|
+
((nodes: MardoraNode[]) => void) | undefined,
|
|
21
|
+
((nodes: MardoraNode[]) => void) | undefined
|
|
22
|
+
>({
|
|
23
|
+
combine: (values) => values.find((v) => v !== undefined),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Facet to register the theme
|
|
28
|
+
*/
|
|
29
|
+
export const mardoraThemeFacet = Facet.define<ThemeEnum, ThemeEnum>({
|
|
30
|
+
combine: (values) => values.find((v) => v !== undefined) || ThemeEnum.AUTO,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build decorations for the visible viewport
|
|
35
|
+
* @param view - The EditorView instance
|
|
36
|
+
* @param plugins - Optional array of plugins to invoke for decorations
|
|
37
|
+
*/
|
|
38
|
+
function buildDecorations(view: EditorView, plugins: MardoraPlugin[] = []): DecorationSet {
|
|
39
|
+
const builder = new RangeSetBuilder<Decoration>();
|
|
40
|
+
const decorations: Range<Decoration>[] = [];
|
|
41
|
+
|
|
42
|
+
// Allow plugins to contribute decorations
|
|
43
|
+
if (plugins.length > 0) {
|
|
44
|
+
const ctx: DecorationContext = {
|
|
45
|
+
view,
|
|
46
|
+
decorations,
|
|
47
|
+
selectionOverlapsRange: (from, to) => selectionOverlapsRange(view, from, to),
|
|
48
|
+
cursorInRange: (from, to) => cursorInRange(view, from, to),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Sort plugins by priority and invoke each one's decoration builder
|
|
52
|
+
const sortedPlugins = [...plugins].sort((a, b) => a.decorationPriority - b.decorationPriority);
|
|
53
|
+
|
|
54
|
+
for (const plugin of sortedPlugins) {
|
|
55
|
+
try {
|
|
56
|
+
plugin.buildDecorations(ctx);
|
|
57
|
+
} catch {
|
|
58
|
+
// Silently ignore errors from partial tree states (e.g., Lezer TreeBuffer
|
|
59
|
+
// "Invalid child in posBefore"). These resolve on the next update cycle.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Sort decorations by position (required for RangeSetBuilder)
|
|
65
|
+
decorations.sort((a, b) => a.from - b.from || a.value.startSide - b.value.startSide);
|
|
66
|
+
|
|
67
|
+
// Build the decoration set
|
|
68
|
+
for (const decoration of decorations) {
|
|
69
|
+
builder.add(decoration.from, decoration.to, decoration.value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return builder.finish();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* mardora View Plugin
|
|
77
|
+
* Handles rich markdown rendering with decorations
|
|
78
|
+
*/
|
|
79
|
+
class mardoraViewPluginClass {
|
|
80
|
+
decorations: DecorationSet;
|
|
81
|
+
private plugins: MardoraPlugin[];
|
|
82
|
+
private onNodesChange: ((nodes: MardoraNode[]) => void) | undefined;
|
|
83
|
+
|
|
84
|
+
constructor(view: EditorView) {
|
|
85
|
+
this.plugins = view.state.facet(MardoraPluginsFacet);
|
|
86
|
+
this.onNodesChange = view.state.facet(mardoraOnNodesChangeFacet);
|
|
87
|
+
this.decorations = buildDecorations(view, this.plugins);
|
|
88
|
+
|
|
89
|
+
// Notify plugins that view is ready
|
|
90
|
+
for (const plugin of this.plugins) {
|
|
91
|
+
plugin.onViewReady(view);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Call onNodesChange callback with initial nodes
|
|
95
|
+
if (this.onNodesChange && typeof this.onNodesChange === "function") {
|
|
96
|
+
this.onNodesChange(this.buildNodes(view));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
update(update: ViewUpdate) {
|
|
101
|
+
// Update plugins list if facet changed
|
|
102
|
+
this.plugins = update.view.state.facet(MardoraPluginsFacet);
|
|
103
|
+
this.onNodesChange = update.view.state.facet(mardoraOnNodesChangeFacet);
|
|
104
|
+
|
|
105
|
+
// Notify plugins of the update
|
|
106
|
+
for (const plugin of this.plugins) {
|
|
107
|
+
plugin.onViewUpdate(update);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Rebuild decorations when:
|
|
111
|
+
// - Document changes
|
|
112
|
+
// - Selection changes (to show/hide syntax markers)
|
|
113
|
+
// - Viewport changes
|
|
114
|
+
if (update.docChanged || update.selectionSet || update.viewportChanged) {
|
|
115
|
+
this.decorations = buildDecorations(update.view, this.plugins);
|
|
116
|
+
|
|
117
|
+
// Call onNodesChange callback
|
|
118
|
+
if (this.onNodesChange) {
|
|
119
|
+
this.onNodesChange(this.buildNodes(update.view));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private buildNodes(view: EditorView): MardoraNode[] {
|
|
125
|
+
const tree = syntaxTree(view.state);
|
|
126
|
+
const roots: MardoraNode[] = [];
|
|
127
|
+
const stack: MardoraNode[] = [];
|
|
128
|
+
|
|
129
|
+
tree.iterate({
|
|
130
|
+
enter: (nodeRef) => {
|
|
131
|
+
const node: MardoraNode = {
|
|
132
|
+
from: nodeRef.from,
|
|
133
|
+
to: nodeRef.to,
|
|
134
|
+
name: nodeRef.name,
|
|
135
|
+
children: [],
|
|
136
|
+
isSelected: selectionOverlapsRange(view, nodeRef.from, nodeRef.to),
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
if (stack.length > 0) {
|
|
140
|
+
stack[stack.length - 1]!.children.push(node);
|
|
141
|
+
} else {
|
|
142
|
+
roots.push(node);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
stack.push(node);
|
|
146
|
+
},
|
|
147
|
+
leave: () => {
|
|
148
|
+
stack.pop();
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return roots;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The main mardora ViewPlugin extension
|
|
158
|
+
*/
|
|
159
|
+
export const mardoraViewPlugin = ViewPlugin.fromClass(mardoraViewPluginClass, {
|
|
160
|
+
decorations: (v) => v.decorations,
|
|
161
|
+
provide: () => [],
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Extension to add the cm-mardora-enabled class to the editor
|
|
166
|
+
*/
|
|
167
|
+
const mardoraEditorClass = EditorView.editorAttributes.of({ class: "cm-mardora" });
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Create mardora view extension bundle with plugin support
|
|
171
|
+
* @param plugins - Optional array of MardoraPlugin instances
|
|
172
|
+
* @param onNodesChange - Optional callback to receive nodes on every update
|
|
173
|
+
* @returns Extension array including view plugin, theme, and plugin facet
|
|
174
|
+
*/
|
|
175
|
+
export function createMardoraViewExtension(
|
|
176
|
+
theme: ThemeEnum = ThemeEnum.AUTO,
|
|
177
|
+
baseStyles: boolean = true,
|
|
178
|
+
plugins: MardoraPlugin[] = [],
|
|
179
|
+
onNodesChange?: (nodes: MardoraNode[]) => void
|
|
180
|
+
): Extension[] {
|
|
181
|
+
return [
|
|
182
|
+
mardoraEditorClass,
|
|
183
|
+
MardoraPluginsFacet.of(plugins),
|
|
184
|
+
mardoraOnNodesChangeFacet.of(onNodesChange),
|
|
185
|
+
mardoraThemeFacet.of(theme),
|
|
186
|
+
mardoraViewPlugin,
|
|
187
|
+
...(baseStyles ? [mardoraBaseTheme] : []),
|
|
188
|
+
];
|
|
189
|
+
}
|
package/src/index.ts
ADDED
package/src/lib/index.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { EditorSelection, Extension } from "@codemirror/state";
|
|
2
|
+
import { EditorView } from "@codemirror/view";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mapping of typed input characters to surrounding markers.
|
|
6
|
+
*
|
|
7
|
+
* Example:
|
|
8
|
+
* { "*": "*", "=": "==" }
|
|
9
|
+
*/
|
|
10
|
+
export type WrapSelectionMarkerMap = Record<string, string>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates an input handler that wraps non-empty selections with markdown markers
|
|
14
|
+
* when a mapped character is typed.
|
|
15
|
+
*/
|
|
16
|
+
export function createWrapSelectionInputHandler(markersByInput: WrapSelectionMarkerMap): Extension {
|
|
17
|
+
return EditorView.inputHandler.of((view, _from, _to, text) => {
|
|
18
|
+
const marker = markersByInput[text];
|
|
19
|
+
if (!marker) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ranges = view.state.selection.ranges;
|
|
24
|
+
if (ranges.length === 0 || ranges.some((range) => range.empty)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const changes = ranges
|
|
29
|
+
.map((range) => ({
|
|
30
|
+
from: range.from,
|
|
31
|
+
to: range.to,
|
|
32
|
+
insert: `${marker}${view.state.sliceDoc(range.from, range.to)}${marker}`,
|
|
33
|
+
}))
|
|
34
|
+
.reverse();
|
|
35
|
+
|
|
36
|
+
const nextRanges = ranges.map((range) =>
|
|
37
|
+
EditorSelection.range(range.from + marker.length, range.to + marker.length)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
view.dispatch({
|
|
41
|
+
changes,
|
|
42
|
+
selection: EditorSelection.create(nextRanges, view.state.selection.mainIndex),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return true;
|
|
46
|
+
});
|
|
47
|
+
}
|