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,526 @@
1
+ import { Decoration, EditorView, WidgetType } from "@codemirror/view";
2
+ import { Extension } from "@codemirror/state";
3
+ import { syntaxTree } from "@codemirror/language";
4
+ import { DecorationContext, DecorationPlugin } from "../editor/plugin";
5
+ import { createTheme } from "../editor";
6
+ import { SyntaxNode } from "@lezer/common";
7
+ import { tags } from "@lezer/highlight";
8
+ import type { MarkdownConfig, InlineParser, BlockParser, Line, BlockContext } from "@lezer/markdown";
9
+ import katex from "katex";
10
+ import { createWrapSelectionInputHandler } from "../lib";
11
+ // @ts-expect-error - raw import for CSS as string
12
+ import katexCss from "katex/dist/katex.min.css?raw";
13
+
14
+ /**
15
+ * Inject KaTeX CSS into the document head (only once)
16
+ */
17
+ function injectKatexStyles(): void {
18
+ if (typeof document === "undefined") return;
19
+ if (document.getElementById("mardora-katex-styles")) return;
20
+
21
+ const style = document.createElement("style");
22
+ style.id = "mardora-katex-styles";
23
+ style.textContent = katexCss;
24
+ document.head.appendChild(style);
25
+ }
26
+
27
+ // Inject styles when module loads
28
+ injectKatexStyles();
29
+
30
+ // Character codes
31
+ const DOLLAR = 36; // '$'
32
+
33
+ /**
34
+ * Mark decorations for math syntax elements
35
+ */
36
+ const mathMarkDecorations = {
37
+ "math-block": Decoration.line({ class: "cm-mardora-math-block" }),
38
+ "math-inline": Decoration.mark({ class: "cm-mardora-math-inline" }),
39
+ "math-marker": Decoration.mark({ class: "cm-mardora-math-marker" }),
40
+ "math-hidden": Decoration.mark({ class: "cm-mardora-math-hidden" }),
41
+ };
42
+
43
+ /**
44
+ * Render LaTeX to HTML using KaTeX
45
+ */
46
+ function renderMath(latex: string, displayMode: boolean): { html: string; error: string | null } {
47
+ try {
48
+ const html = katex.renderToString(latex, {
49
+ displayMode,
50
+ throwOnError: false,
51
+ errorColor: "#d73a49",
52
+ trust: false,
53
+ strict: false,
54
+ });
55
+ return { html, error: null };
56
+ } catch (e) {
57
+ const errorMsg = e instanceof Error ? e.message : "Unknown error";
58
+ return { html: "", error: errorMsg };
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Widget to render inline math
64
+ */
65
+ class InlineMathWidget extends WidgetType {
66
+ constructor(
67
+ readonly latex: string,
68
+ readonly from: number,
69
+ readonly to: number
70
+ ) {
71
+ super();
72
+ }
73
+
74
+ override eq(other: InlineMathWidget): boolean {
75
+ return other.latex === this.latex && other.from === this.from && other.to === this.to;
76
+ }
77
+
78
+ toDOM(view: EditorView) {
79
+ const span = document.createElement("span");
80
+ span.className = "cm-mardora-math-rendered cm-mardora-math-rendered-inline";
81
+ span.style.cursor = "pointer";
82
+
83
+ const { html, error } = renderMath(this.latex, false);
84
+
85
+ if (error) {
86
+ span.className += " cm-mardora-math-error";
87
+ span.textContent = `[Math Error: ${error}]`;
88
+ } else {
89
+ span.innerHTML = html;
90
+ }
91
+
92
+ // Click handler to select the raw math text
93
+ span.addEventListener("click", (e) => {
94
+ e.preventDefault();
95
+ e.stopPropagation();
96
+ view.dispatch({
97
+ selection: { anchor: this.from, head: this.to },
98
+ scrollIntoView: true,
99
+ });
100
+ view.focus();
101
+ });
102
+
103
+ return span;
104
+ }
105
+
106
+ override ignoreEvent(event: Event) {
107
+ return event.type !== "click";
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Widget to render block math (display mode)
113
+ */
114
+ class MathBlockWidget extends WidgetType {
115
+ constructor(
116
+ readonly latex: string,
117
+ readonly from: number,
118
+ readonly to: number
119
+ ) {
120
+ super();
121
+ }
122
+
123
+ override eq(other: MathBlockWidget): boolean {
124
+ return other.latex === this.latex && other.from === this.from && other.to === this.to;
125
+ }
126
+
127
+ toDOM(view: EditorView) {
128
+ const div = document.createElement("div");
129
+ div.className = "cm-mardora-math-rendered cm-mardora-math-rendered-block";
130
+ div.style.cursor = "pointer";
131
+
132
+ const { html, error } = renderMath(this.latex, true);
133
+
134
+ if (error) {
135
+ div.className += " cm-mardora-math-error";
136
+ div.textContent = `[Math Error: ${error}]`;
137
+ } else {
138
+ div.innerHTML = html;
139
+ }
140
+
141
+ // Click handler to select the raw math text
142
+ div.addEventListener("click", (e) => {
143
+ e.preventDefault();
144
+ e.stopPropagation();
145
+ view.dispatch({
146
+ selection: { anchor: this.from, head: this.to },
147
+ scrollIntoView: true,
148
+ });
149
+ view.focus();
150
+ });
151
+
152
+ return div;
153
+ }
154
+
155
+ override ignoreEvent(event: Event) {
156
+ return event.type !== "click";
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Inline parser for inline math: $...$
162
+ * Does not match $$ (block math markers)
163
+ */
164
+ const inlineMathParser: InlineParser = {
165
+ name: "InlineMath",
166
+ parse(cx, next, pos) {
167
+ // Check if we are at a $ character
168
+ if (next !== DOLLAR) return -1;
169
+
170
+ // Don't match $$ (that's block math)
171
+ if (cx.char(pos + 1) === DOLLAR) return -1;
172
+
173
+ // Find the closing $
174
+ let end = pos + 1;
175
+ while (end < cx.end) {
176
+ const char = cx.char(end);
177
+ if (char === DOLLAR) {
178
+ // Found closing $, but make sure it's not $$
179
+ if (cx.char(end + 1) !== DOLLAR) {
180
+ // Extract the math content (excluding the $ markers)
181
+ const content = cx.slice(pos + 1, end);
182
+
183
+ // Skip empty math
184
+ if (content.trim().length === 0) return -1;
185
+
186
+ // Create the element with markers
187
+ const openMark = cx.elt("InlineMathMark", pos, pos + 1);
188
+ const closeMark = cx.elt("InlineMathMark", end, end + 1);
189
+ const inlineMath = cx.elt("InlineMath", pos, end + 1, [openMark, closeMark]);
190
+
191
+ return cx.addElement(inlineMath);
192
+ }
193
+ // Skip $$ for block math
194
+ return -1;
195
+ }
196
+ // Skip escaped characters
197
+ if (char === 92 /* backslash */) {
198
+ end += 2;
199
+ continue;
200
+ }
201
+ end++;
202
+ }
203
+
204
+ return -1;
205
+ },
206
+ };
207
+
208
+ /**
209
+ * Block parser for math blocks: $$...$$
210
+ */
211
+ const mathBlockParser: BlockParser = {
212
+ name: "MathBlock",
213
+ parse(cx: BlockContext, line: Line) {
214
+ // Check if line starts with $$
215
+ const text = line.text;
216
+ const trimmed = text.slice(line.pos).trimStart();
217
+
218
+ if (!trimmed.startsWith("$$")) return false;
219
+
220
+ // Find the end of the math block
221
+ const startLine = cx.lineStart;
222
+ let endPos = -1;
223
+ let lastLineEnd = startLine + line.text.length;
224
+
225
+ // Move past the opening line
226
+ while (cx.nextLine()) {
227
+ const currentText = line.text;
228
+ lastLineEnd = cx.lineStart + currentText.length;
229
+
230
+ // Check if this line contains closing $$
231
+ if (currentText.trimEnd().endsWith("$$")) {
232
+ endPos = lastLineEnd;
233
+ // Move past the closing line so subsequent markdown gets parsed
234
+ cx.nextLine();
235
+ break;
236
+ }
237
+ }
238
+
239
+ if (endPos === -1) {
240
+ // No closing found, treat as regular paragraph
241
+ return false;
242
+ }
243
+
244
+ // Create the math block element
245
+ const openMark = cx.elt("MathBlockMark", startLine, startLine + text.indexOf("$$") + 2);
246
+ const closeMark = cx.elt("MathBlockMark", endPos - 2, endPos);
247
+ cx.addElement(cx.elt("MathBlock", startLine, endPos, [openMark, closeMark]));
248
+
249
+ return true;
250
+ },
251
+ };
252
+
253
+ /**
254
+ * MathPlugin - Renders LaTeX math expressions using KaTeX
255
+ *
256
+ * Supports:
257
+ * - Inline math: $E = mc^2$
258
+ * - Block math (display mode):
259
+ * $$
260
+ * \int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
261
+ * $$
262
+ *
263
+ * Behavior:
264
+ * - Inline math: Show rendered output when cursor outside, raw LaTeX when inside
265
+ * - Block math: Always show rendered output below, hide raw when cursor outside (like ImagePlugin)
266
+ */
267
+ export class MathPlugin extends DecorationPlugin {
268
+ readonly name = "math";
269
+ readonly version = "1.0.0";
270
+ override decorationPriority = 25;
271
+ override readonly requiredNodes = ["InlineMath", "MathBlock", "InlineMathMark", "MathBlockMark"] as const;
272
+
273
+ constructor() {
274
+ super();
275
+ }
276
+
277
+ /**
278
+ * Plugin theme
279
+ */
280
+ override get theme() {
281
+ return theme;
282
+ }
283
+
284
+ /**
285
+ * Intercepts dollar typing to wrap selected text as inline math.
286
+ *
287
+ * If user types '$' while text is selected, wraps each selected range
288
+ * with single dollars (selected -> $selected$).
289
+ */
290
+ override getExtensions(): Extension[] {
291
+ return [createWrapSelectionInputHandler({ $: "$" })];
292
+ }
293
+
294
+ /**
295
+ * Return markdown parser extensions for math syntax
296
+ */
297
+ override getMarkdownConfig(): MarkdownConfig {
298
+ return {
299
+ defineNodes: [
300
+ { name: "InlineMath", style: tags.emphasis },
301
+ { name: "InlineMathMark", style: tags.processingInstruction },
302
+ { name: "MathBlock", block: true },
303
+ { name: "MathBlockMark", style: tags.processingInstruction },
304
+ ],
305
+ parseInline: [inlineMathParser],
306
+ parseBlock: [mathBlockParser],
307
+ };
308
+ }
309
+
310
+ /**
311
+ * Build decorations for math expressions
312
+ */
313
+ buildDecorations(ctx: DecorationContext): void {
314
+ const { view, decorations } = ctx;
315
+ const tree = syntaxTree(view.state);
316
+
317
+ tree.iterate({
318
+ enter: (node) => {
319
+ const { from, to, name } = node;
320
+
321
+ // Handle inline math
322
+ if (name === "InlineMath") {
323
+ const content = view.state.sliceDoc(from, to);
324
+ // Extract LaTeX content (remove $ markers)
325
+ const latex = content.slice(1, -1);
326
+
327
+ const cursorInRange = ctx.selectionOverlapsRange(from, to);
328
+
329
+ if (cursorInRange) {
330
+ // Show raw math with styled markers
331
+ decorations.push(mathMarkDecorations["math-inline"].range(from, to));
332
+
333
+ // Style the $ markers
334
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
335
+ if (child.name === "InlineMathMark") {
336
+ decorations.push(mathMarkDecorations["math-marker"].range(child.from, child.to));
337
+ }
338
+ }
339
+ } else {
340
+ // Replace with rendered math widget
341
+ decorations.push(
342
+ Decoration.replace({
343
+ widget: new InlineMathWidget(latex, from, to),
344
+ }).range(from, to)
345
+ );
346
+ }
347
+ }
348
+
349
+ // Handle math blocks
350
+ if (name === "MathBlock") {
351
+ const content = view.state.sliceDoc(from, to);
352
+
353
+ // Extract LaTeX content (remove $$ markers and trim)
354
+ const lines = content.split("\n");
355
+ const latex = lines
356
+ .slice(1, -1) // Remove first and last lines (the $$ markers)
357
+ .join("\n")
358
+ .trim();
359
+
360
+ // If the block is simple (everything on one line), handle differently
361
+ const singleLine = !content.includes("\n");
362
+ const latexContent = singleLine ? content.slice(2, -2).trim() : latex;
363
+
364
+ const nodeLineStart = view.state.doc.lineAt(from);
365
+ const nodeLineEnd = view.state.doc.lineAt(to);
366
+ const cursorInRange = ctx.selectionOverlapsRange(nodeLineStart.from, nodeLineEnd.to);
367
+
368
+ // Add line decoration for math block
369
+ decorations.push(mathMarkDecorations["math-block"].range(from));
370
+
371
+ // Always add the math block widget below the node (like image plugin)
372
+ decorations.push(
373
+ Decoration.widget({
374
+ widget: new MathBlockWidget(latexContent, from, to),
375
+ side: 1,
376
+ block: false,
377
+ }).range(to)
378
+ );
379
+
380
+ for (let i = nodeLineStart.number; i <= nodeLineEnd.number; i++) {
381
+ const line = view.state.doc.line(i);
382
+ decorations.push(mathMarkDecorations["math-block"].range(line.from));
383
+ }
384
+
385
+ // Cursor in range: show raw LaTeX with styling
386
+ if (cursorInRange) {
387
+ // Style the $$ markers
388
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
389
+ if (child.name === "MathBlockMark") {
390
+ decorations.push(mathMarkDecorations["math-marker"].range(child.from, child.to));
391
+ }
392
+ }
393
+ } else {
394
+ // Cursor out of range: hide the raw math text
395
+ decorations.push(mathMarkDecorations["math-hidden"].range(from, to));
396
+ }
397
+ }
398
+ },
399
+ });
400
+ }
401
+
402
+ /**
403
+ * Render math to HTML for preview mode
404
+ */
405
+ override renderToHTML(
406
+ node: SyntaxNode,
407
+ _children: string,
408
+ ctx: { sliceDoc(from: number, to: number): string; sanitize(html: string): string }
409
+ ): string | null {
410
+ if (node.name === "InlineMath") {
411
+ const content = ctx.sliceDoc(node.from, node.to);
412
+ const latex = content.slice(1, -1);
413
+ const { html, error } = renderMath(latex, false);
414
+
415
+ if (error) {
416
+ return `<span class="cm-mardora-math-error">[Math Error: ${ctx.sanitize(error)}]</span>`;
417
+ }
418
+ return `<span class="cm-mardora-math-rendered cm-mardora-math-rendered-inline">${html}</span>`;
419
+ }
420
+
421
+ if (node.name === "MathBlock") {
422
+ const content = ctx.sliceDoc(node.from, node.to);
423
+ const lines = content.split("\n");
424
+ const latex = lines.length > 1 ? lines.slice(1, -1).join("\n").trim() : content.slice(2, -2).trim();
425
+ const { html, error } = renderMath(latex, true);
426
+
427
+ if (error) {
428
+ return `<div class="cm-mardora-math-error">[Math Error: ${ctx.sanitize(error)}]</div>`;
429
+ }
430
+ return `<div class="cm-mardora-math-rendered cm-mardora-math-rendered-block">${html}</div>`;
431
+ }
432
+
433
+ // Hide math markers in preview
434
+ if (node.name === "InlineMathMark" || node.name === "MathBlockMark") {
435
+ return "";
436
+ }
437
+
438
+ return null;
439
+ }
440
+ }
441
+
442
+ /**
443
+ * Theme for math styling
444
+ */
445
+ const theme = createTheme({
446
+ default: {
447
+ ".cm-mardora-math-block": {
448
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
449
+ },
450
+
451
+ ".cm-mardora-math-block br": {
452
+ display: "none",
453
+ },
454
+
455
+ // Math markers ($ $$)
456
+ ".cm-mardora-math-marker": {
457
+ color: "#6a737d",
458
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
459
+ },
460
+
461
+ // Inline math styling when editing
462
+ ".cm-mardora-math-inline": {
463
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
464
+ fontSize: "0.9em",
465
+ },
466
+
467
+ // Hidden math syntax (when cursor is not in range)
468
+ ".cm-mardora-math-hidden": {
469
+ display: "none",
470
+ },
471
+
472
+ // Hidden line (for multi-line blocks)
473
+ ".cm-mardora-hidden-line": {
474
+ display: "none",
475
+ },
476
+
477
+ // Rendered math container (both inline and block)
478
+ ".cm-mardora-math-rendered": {
479
+ fontFamily: "KaTeX_Main, 'Times New Roman', serif",
480
+ },
481
+
482
+ // Inline rendered math
483
+ ".cm-mardora-math-rendered-inline": {
484
+ display: "inline",
485
+ verticalAlign: "baseline",
486
+ },
487
+
488
+ // Block rendered math (display mode)
489
+ ".cm-mardora-math-rendered-block": {
490
+ display: "flex",
491
+ justifyContent: "center",
492
+ alignItems: "center",
493
+ padding: "1em 0",
494
+ backgroundColor: "rgba(0, 0, 0, 0.02)",
495
+ borderRadius: "4px",
496
+ overflow: "auto",
497
+ },
498
+
499
+ // Math error styling
500
+ ".cm-mardora-math-error": {
501
+ display: "inline-block",
502
+ padding: "0.25em 0.5em",
503
+ backgroundColor: "rgba(255, 0, 0, 0.1)",
504
+ color: "#d73a49",
505
+ borderRadius: "4px",
506
+ fontSize: "0.875em",
507
+ fontStyle: "italic",
508
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
509
+ },
510
+ },
511
+
512
+ dark: {
513
+ ".cm-mardora-math-marker": {
514
+ color: "#8b949e",
515
+ },
516
+
517
+ ".cm-mardora-math-rendered-block": {
518
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
519
+ },
520
+
521
+ ".cm-mardora-math-error": {
522
+ backgroundColor: "rgba(255, 0, 0, 0.15)",
523
+ color: "#f85149",
524
+ },
525
+ },
526
+ });