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.
Files changed (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -0
  3. package/dist/chunk-3OCUX4OO.js +7690 -0
  4. package/dist/chunk-3OCUX4OO.js.map +1 -0
  5. package/dist/chunk-3ZOCCFDL.cjs +74 -0
  6. package/dist/chunk-3ZOCCFDL.cjs.map +1 -0
  7. package/dist/chunk-7JOEPNEV.cjs +7740 -0
  8. package/dist/chunk-7JOEPNEV.cjs.map +1 -0
  9. package/dist/chunk-BIKZQZ6W.js +33 -0
  10. package/dist/chunk-BIKZQZ6W.js.map +1 -0
  11. package/dist/chunk-EQJESPP2.js +234 -0
  12. package/dist/chunk-EQJESPP2.js.map +1 -0
  13. package/dist/chunk-G4SE26YY.js +70 -0
  14. package/dist/chunk-G4SE26YY.js.map +1 -0
  15. package/dist/chunk-KNDWF2DP.cjs +35 -0
  16. package/dist/chunk-KNDWF2DP.cjs.map +1 -0
  17. package/dist/chunk-MLBEBFHB.cjs +2971 -0
  18. package/dist/chunk-MLBEBFHB.cjs.map +1 -0
  19. package/dist/chunk-P7JFCYU3.js +905 -0
  20. package/dist/chunk-P7JFCYU3.js.map +1 -0
  21. package/dist/chunk-SWFUKJDO.cjs +243 -0
  22. package/dist/chunk-SWFUKJDO.cjs.map +1 -0
  23. package/dist/chunk-WFVCG4LD.cjs +926 -0
  24. package/dist/chunk-WFVCG4LD.cjs.map +1 -0
  25. package/dist/chunk-XL6WFGJT.js +2901 -0
  26. package/dist/chunk-XL6WFGJT.js.map +1 -0
  27. package/dist/editor/index.cjs +277 -0
  28. package/dist/editor/index.cjs.map +1 -0
  29. package/dist/editor/index.d.cts +186 -0
  30. package/dist/editor/index.d.ts +186 -0
  31. package/dist/editor/index.js +4 -0
  32. package/dist/editor/index.js.map +1 -0
  33. package/dist/index.cjs +405 -0
  34. package/dist/index.cjs.map +1 -0
  35. package/dist/index.d.cts +13 -0
  36. package/dist/index.d.ts +13 -0
  37. package/dist/index.js +8 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/lib/index.cjs +12 -0
  40. package/dist/lib/index.cjs.map +1 -0
  41. package/dist/lib/index.d.cts +16 -0
  42. package/dist/lib/index.d.ts +16 -0
  43. package/dist/lib/index.js +3 -0
  44. package/dist/lib/index.js.map +1 -0
  45. package/dist/mardora-DCwjomil.d.cts +640 -0
  46. package/dist/mardora-DCwjomil.d.ts +640 -0
  47. package/dist/plugins/index.cjs +104 -0
  48. package/dist/plugins/index.cjs.map +1 -0
  49. package/dist/plugins/index.d.cts +740 -0
  50. package/dist/plugins/index.d.ts +740 -0
  51. package/dist/plugins/index.js +7 -0
  52. package/dist/plugins/index.js.map +1 -0
  53. package/dist/preview/index.cjs +38 -0
  54. package/dist/preview/index.cjs.map +1 -0
  55. package/dist/preview/index.d.cts +101 -0
  56. package/dist/preview/index.d.ts +101 -0
  57. package/dist/preview/index.js +5 -0
  58. package/dist/preview/index.js.map +1 -0
  59. package/dist/types-NBsaxl4d.d.cts +71 -0
  60. package/dist/types-Pw2SWWAR.d.ts +71 -0
  61. package/package.json +92 -0
  62. package/src/editor/attachments/extension.ts +181 -0
  63. package/src/editor/attachments/format.ts +63 -0
  64. package/src/editor/attachments/index.ts +3 -0
  65. package/src/editor/attachments/types.ts +37 -0
  66. package/src/editor/heading-fold/config.ts +25 -0
  67. package/src/editor/heading-fold/extension.ts +268 -0
  68. package/src/editor/heading-fold/extract.ts +88 -0
  69. package/src/editor/heading-fold/index.ts +5 -0
  70. package/src/editor/heading-fold/theme.ts +85 -0
  71. package/src/editor/heading-fold/types.ts +24 -0
  72. package/src/editor/i18n.ts +13 -0
  73. package/src/editor/icons/index.ts +367 -0
  74. package/src/editor/index.ts +16 -0
  75. package/src/editor/mardora.ts +257 -0
  76. package/src/editor/media-lightbox-theme.ts +146 -0
  77. package/src/editor/media-lightbox.ts +125 -0
  78. package/src/editor/plugin.ts +294 -0
  79. package/src/editor/selection-toolbar/activation.ts +123 -0
  80. package/src/editor/selection-toolbar/commands.ts +279 -0
  81. package/src/editor/selection-toolbar/extension.ts +564 -0
  82. package/src/editor/selection-toolbar/i18n.ts +164 -0
  83. package/src/editor/selection-toolbar/index.ts +7 -0
  84. package/src/editor/selection-toolbar/menu.ts +252 -0
  85. package/src/editor/selection-toolbar/position.ts +43 -0
  86. package/src/editor/selection-toolbar/theme.ts +195 -0
  87. package/src/editor/selection-toolbar/types.ts +155 -0
  88. package/src/editor/slash/default-commands.ts +190 -0
  89. package/src/editor/slash/extension.ts +319 -0
  90. package/src/editor/slash/index.ts +7 -0
  91. package/src/editor/slash/insertions.ts +26 -0
  92. package/src/editor/slash/menu.ts +123 -0
  93. package/src/editor/slash/position.ts +61 -0
  94. package/src/editor/slash/query.ts +33 -0
  95. package/src/editor/slash/theme.ts +113 -0
  96. package/src/editor/slash/types.ts +40 -0
  97. package/src/editor/table-of-contents/extension.ts +202 -0
  98. package/src/editor/table-of-contents/extract.ts +53 -0
  99. package/src/editor/table-of-contents/index.ts +7 -0
  100. package/src/editor/table-of-contents/panel.ts +83 -0
  101. package/src/editor/table-of-contents/slug.ts +50 -0
  102. package/src/editor/table-of-contents/storage.ts +35 -0
  103. package/src/editor/table-of-contents/theme.ts +153 -0
  104. package/src/editor/table-of-contents/types.ts +44 -0
  105. package/src/editor/theme.ts +72 -0
  106. package/src/editor/utils.ts +176 -0
  107. package/src/editor/view-plugin.ts +189 -0
  108. package/src/index.ts +5 -0
  109. package/src/lib/index.ts +2 -0
  110. package/src/lib/input-handler.ts +47 -0
  111. package/src/plugins/code-plugin.theme.ts +545 -0
  112. package/src/plugins/code-plugin.ts +1892 -0
  113. package/src/plugins/emoji-plugin.ts +140 -0
  114. package/src/plugins/heading-plugin.ts +194 -0
  115. package/src/plugins/hr-plugin.ts +102 -0
  116. package/src/plugins/html-plugin.ts +353 -0
  117. package/src/plugins/image-plugin.ts +806 -0
  118. package/src/plugins/index.ts +71 -0
  119. package/src/plugins/inline-plugin.ts +311 -0
  120. package/src/plugins/link-plugin.ts +509 -0
  121. package/src/plugins/list-plugin.ts +492 -0
  122. package/src/plugins/math-plugin.ts +526 -0
  123. package/src/plugins/mermaid-plugin.ts +513 -0
  124. package/src/plugins/paragraph-plugin.ts +38 -0
  125. package/src/plugins/quote-plugin.ts +733 -0
  126. package/src/plugins/table-controls-theme.ts +126 -0
  127. package/src/plugins/table-controls.ts +423 -0
  128. package/src/plugins/table-model.ts +661 -0
  129. package/src/plugins/table-plugin.ts +2111 -0
  130. package/src/preview/context.ts +45 -0
  131. package/src/preview/css-generator.ts +64 -0
  132. package/src/preview/default-renderers.ts +29 -0
  133. package/src/preview/index.ts +29 -0
  134. package/src/preview/preview.ts +41 -0
  135. package/src/preview/renderer.ts +184 -0
  136. package/src/preview/syntax-theme.ts +112 -0
  137. package/src/preview/toc.ts +23 -0
  138. 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
@@ -0,0 +1,5 @@
1
+ // Re-export everything for backward compatibility
2
+ export * from "./editor";
3
+ export * from "./plugins";
4
+ export * from "./preview";
5
+ export * from "./lib";
@@ -0,0 +1,2 @@
1
+ export { createWrapSelectionInputHandler } from "./input-handler";
2
+ export type { WrapSelectionMarkerMap } from "./input-handler";
@@ -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
+ }