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,140 @@
1
+ import { Decoration, WidgetType } from "@codemirror/view";
2
+ import { syntaxTree } from "@codemirror/language";
3
+ import { DecorationContext, DecorationPlugin } from "../editor/plugin";
4
+ import { createTheme } from "../editor";
5
+ import { SyntaxNode } from "@lezer/common";
6
+ import * as emoji from "node-emoji";
7
+
8
+ function shortcodeToEmoji(raw: string): string | null {
9
+ const rendered = emoji.emojify(raw);
10
+ return rendered !== raw ? rendered : null;
11
+ }
12
+
13
+ class EmojiWidget extends WidgetType {
14
+ constructor(readonly rendered: string) {
15
+ super();
16
+ }
17
+
18
+ override eq(other: EmojiWidget): boolean {
19
+ return other.rendered === this.rendered;
20
+ }
21
+
22
+ toDOM() {
23
+ const span = document.createElement("span");
24
+ span.className = "cm-mardora-emoji";
25
+ span.textContent = this.rendered;
26
+ return span;
27
+ }
28
+
29
+ override ignoreEvent(): boolean {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Mark decorations for emoji syntax elements
36
+ */
37
+ const emojiMarkDecorations = {
38
+ "emoji-source": Decoration.mark({ class: "cm-mardora-emoji-source" }),
39
+ };
40
+
41
+ /**
42
+ * EmojiPlugin - Decorates markdown emojis
43
+ *
44
+ * Parses and decorates emoji shortcodes like :smile:
45
+ * - Converts valid shortcodes to Unicode emoji when cursor is outside
46
+ * - Keeps raw shortcode visible while editing (cursor inside token)
47
+ */
48
+ export class EmojiPlugin extends DecorationPlugin {
49
+ readonly name = "emoji";
50
+ readonly version = "1.0.0";
51
+ override decorationPriority = 20;
52
+ override readonly requiredNodes = ["Emoji", "EmojiMark"] as const;
53
+
54
+ constructor() {
55
+ super();
56
+ }
57
+
58
+ /**
59
+ * Plugin theme
60
+ */
61
+ override get theme() {
62
+ return theme;
63
+ }
64
+
65
+ /**
66
+ * Build emoji decorations by iterating the syntax tree
67
+ */
68
+ buildDecorations(ctx: DecorationContext): void {
69
+ const { view, decorations } = ctx;
70
+ const tree = syntaxTree(view.state);
71
+
72
+ tree.iterate({
73
+ enter: (node) => {
74
+ const { from, to, name } = node;
75
+
76
+ if (name !== "Emoji") {
77
+ return;
78
+ }
79
+
80
+ const raw = view.state.sliceDoc(from, to);
81
+ const rendered = shortcodeToEmoji(raw);
82
+ if (!rendered) {
83
+ return;
84
+ }
85
+
86
+ const cursorInNode = ctx.selectionOverlapsRange(from, to);
87
+ if (cursorInNode) {
88
+ decorations.push(emojiMarkDecorations["emoji-source"].range(from, to));
89
+ return;
90
+ }
91
+
92
+ decorations.push(
93
+ Decoration.replace({
94
+ widget: new EmojiWidget(rendered),
95
+ }).range(from, to)
96
+ );
97
+ },
98
+ });
99
+ }
100
+
101
+ override renderToHTML(
102
+ node: SyntaxNode,
103
+ children: string,
104
+ ctx: {
105
+ sliceDoc(from: number, to: number): string;
106
+ sanitize(html: string): string;
107
+ syntaxHighlighters?: readonly import("@lezer/highlight").Highlighter[];
108
+ }
109
+ ): string | null {
110
+ if (node.name === "EmojiMark") {
111
+ return "";
112
+ }
113
+
114
+ if (node.name !== "Emoji") {
115
+ return null;
116
+ }
117
+
118
+ const raw = ctx.sliceDoc(node.from, node.to);
119
+ const rendered = shortcodeToEmoji(raw);
120
+ if (!rendered) {
121
+ return `<span class="cm-mardora-emoji-source">${children}</span>`;
122
+ }
123
+
124
+ return `<span class="cm-mardora-emoji">${rendered}</span>`;
125
+ }
126
+ }
127
+
128
+ const theme = createTheme({
129
+ default: {
130
+ ".cm-mardora-emoji": {
131
+ fontFamily: '"Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif',
132
+ fontVariantEmoji: "emoji",
133
+ lineHeight: "1.2",
134
+ },
135
+ ".cm-mardora-emoji-source": {
136
+ fontFamily: "inherit",
137
+ lineHeight: "inherit",
138
+ },
139
+ },
140
+ });
@@ -0,0 +1,194 @@
1
+ import { Decoration } from "@codemirror/view";
2
+ import { syntaxTree } from "@codemirror/language";
3
+ import { DecorationContext, DecorationPlugin } from "../editor/plugin";
4
+ import { createTheme } from "../editor";
5
+ import { SyntaxNode } from "@lezer/common";
6
+ import type { PreviewContext } from "../preview/types";
7
+
8
+ /**
9
+ * Node types for ATX headings in markdown
10
+ */
11
+ const HEADING_TYPES = ["ATXHeading1", "ATXHeading2", "ATXHeading3", "ATXHeading4", "ATXHeading5", "ATXHeading6"];
12
+
13
+ /**
14
+ * Mark decorations for heading content
15
+ */
16
+ const headingMarkDecorations = {
17
+ "heading-1": Decoration.mark({ class: "cm-mardora-h1" }),
18
+ "heading-2": Decoration.mark({ class: "cm-mardora-h2" }),
19
+ "heading-3": Decoration.mark({ class: "cm-mardora-h3" }),
20
+ "heading-4": Decoration.mark({ class: "cm-mardora-h4" }),
21
+ "heading-5": Decoration.mark({ class: "cm-mardora-h5" }),
22
+ "heading-6": Decoration.mark({ class: "cm-mardora-h6" }),
23
+ "header-mark-class": Decoration.mark({ class: "cm-mardora-header-mark" }),
24
+ "heading-mark": Decoration.replace({}),
25
+ };
26
+
27
+ /**
28
+ * Line decorations for heading lines
29
+ */
30
+ const headingLineDecorations = {
31
+ "heading-1": Decoration.line({ class: "cm-mardora-line-h1" }),
32
+ "heading-2": Decoration.line({ class: "cm-mardora-line-h2" }),
33
+ "heading-3": Decoration.line({ class: "cm-mardora-line-h3" }),
34
+ "heading-4": Decoration.line({ class: "cm-mardora-line-h4" }),
35
+ "heading-5": Decoration.line({ class: "cm-mardora-line-h5" }),
36
+ "heading-6": Decoration.line({ class: "cm-mardora-line-h6" }),
37
+ };
38
+
39
+ /**
40
+ * HeadingPlugin - Decorates markdown headings
41
+ *
42
+ * Adds visual styling to ATX headings (# through ######)
43
+ * - Line decorations for the entire heading line
44
+ * - Mark decorations for heading content
45
+ * - Hides # markers when cursor is not in the heading
46
+ */
47
+ export class HeadingPlugin extends DecorationPlugin {
48
+ readonly name = "heading";
49
+ readonly version = "1.0.0";
50
+ override decorationPriority = 10;
51
+ override readonly requiredNodes = [
52
+ "ATXHeading1",
53
+ "ATXHeading2",
54
+ "ATXHeading3",
55
+ "ATXHeading4",
56
+ "ATXHeading5",
57
+ "ATXHeading6",
58
+ "HeaderMark",
59
+ ] as const;
60
+
61
+ /**
62
+ * Constructor - calls super constructor
63
+ */
64
+ constructor() {
65
+ super();
66
+ }
67
+
68
+ /**
69
+ * Plugin theme
70
+ */
71
+ override get theme() {
72
+ return theme;
73
+ }
74
+
75
+ /**
76
+ * Build heading decorations by iterating the syntax tree
77
+ */
78
+ buildDecorations(ctx: DecorationContext): void {
79
+ const { view, decorations } = ctx;
80
+ const tree = syntaxTree(view.state);
81
+
82
+ tree.iterate({
83
+ enter: (node) => {
84
+ const { from, to, name } = node;
85
+
86
+ if (!HEADING_TYPES.includes(name)) {
87
+ return;
88
+ }
89
+
90
+ const level = parseInt(name.slice(-1), 10);
91
+ const headingClass = `heading-${level}` as keyof typeof headingMarkDecorations;
92
+ const lineClass = `heading-${level}` as keyof typeof headingLineDecorations;
93
+
94
+ // Add line decoration
95
+ const line = view.state.doc.lineAt(from);
96
+ decorations.push(headingLineDecorations[lineClass].range(line.from));
97
+
98
+ // Add mark decoration for the heading content
99
+ decorations.push(headingMarkDecorations[headingClass].range(from, to));
100
+
101
+ // Find and hide the heading marker (#). Heading level changes are handled by the selection toolbar.
102
+ const headingMark = node.node.getChild("HeaderMark");
103
+ if (headingMark) {
104
+ const markEnd = Math.min(headingMark.to + 1, line.to);
105
+ // Clamp to line end so replace decoration never spans a newline.
106
+ decorations.push(headingMarkDecorations["heading-mark"].range(headingMark.from, markEnd));
107
+ }
108
+ },
109
+ });
110
+ }
111
+
112
+ override renderToHTML(node: SyntaxNode, children: string, ctx: PreviewContext): string | null {
113
+ if (node.name === "HeaderMark") {
114
+ return "";
115
+ }
116
+
117
+ if (!HEADING_TYPES.includes(node.name)) {
118
+ return null;
119
+ }
120
+
121
+ const level = parseInt(node.name.slice(-1), 10);
122
+ const lineClass = headingLineDecorations[`heading-${level}` as keyof typeof headingLineDecorations].spec.class;
123
+ const headingClass = headingMarkDecorations[`heading-${level}` as keyof typeof headingMarkDecorations].spec.class;
124
+ const id = level >= 2 ? ctx.headingIdForNode?.(node) : null;
125
+ const idAttr = id ? ` id="${id}"` : "";
126
+
127
+ return `<div class="${lineClass}">
128
+ <h${level}${idAttr} class="${headingClass}">${children}</h${level}>
129
+ </div>\n`;
130
+ }
131
+ }
132
+
133
+ const theme = createTheme({
134
+ default: {
135
+ ".cm-mardora-h1": {
136
+ fontSize: "2em",
137
+ fontWeight: "bold",
138
+ fontFamily: "sans-serif",
139
+ textDecoration: "none",
140
+ },
141
+
142
+ ".cm-mardora-h2": {
143
+ fontSize: "1.75em",
144
+ fontWeight: "bold",
145
+ fontFamily: "sans-serif",
146
+ textDecoration: "none",
147
+ },
148
+
149
+ ".cm-mardora-h3": {
150
+ fontSize: "1.5em",
151
+ fontWeight: "bold",
152
+ fontFamily: "sans-serif",
153
+ textDecoration: "none",
154
+ },
155
+
156
+ ".cm-mardora-h4": {
157
+ fontSize: "1.25em",
158
+ fontWeight: "bold",
159
+ fontFamily: "sans-serif",
160
+ textDecoration: "none",
161
+ },
162
+
163
+ ".cm-mardora-h5": {
164
+ fontSize: "1em",
165
+ fontWeight: "bold",
166
+ fontFamily: "sans-serif",
167
+ textDecoration: "none",
168
+ },
169
+
170
+ ".cm-mardora-h6": {
171
+ fontSize: "0.75em",
172
+ fontWeight: "bold",
173
+ fontFamily: "sans-serif",
174
+ textDecoration: "none",
175
+ },
176
+
177
+ // Heading line styles
178
+ ".cm-mardora-line-h1": {
179
+ paddingTop: "1.5em",
180
+ paddingBottom: "0.5em",
181
+ },
182
+ ".cm-mardora-line-h2": {
183
+ paddingTop: "1.25em",
184
+ paddingBottom: "0.5em",
185
+ },
186
+ ".cm-mardora-line-h3, .cm-mardora-line-h4, .cm-mardora-line-h5, .cm-mardora-line-h6": {
187
+ paddingTop: "1em",
188
+ paddingBottom: "0.5em",
189
+ },
190
+ ".cm-mardora-header-mark": {
191
+ opacity: 0.5,
192
+ },
193
+ },
194
+ });
@@ -0,0 +1,102 @@
1
+ import { Decoration } from "@codemirror/view";
2
+ import { syntaxTree } from "@codemirror/language";
3
+ import { DecorationContext, DecorationPlugin } from "../editor/plugin";
4
+ import { createTheme } from "../editor";
5
+ import { SyntaxNode } from "@lezer/common";
6
+
7
+ /**
8
+ * Line decoration for horizontal rule lines
9
+ */
10
+ const hrLineDecoration = Decoration.line({ class: "cm-mardora-hr-line" });
11
+
12
+ /**
13
+ * Mark decoration to hide raw markers (---, ***, ___) when unfocused
14
+ */
15
+ const hrMarkDecoration = Decoration.replace({});
16
+
17
+ /**
18
+ * HRPlugin - Decorates markdown horizontal rules
19
+ *
20
+ * Adds visual styling to thematic breaks (---, ***, ___)
21
+ * - Line decoration that renders a centered horizontal line
22
+ * - Hides raw marker characters when the cursor is not on the line
23
+ */
24
+ export class HRPlugin extends DecorationPlugin {
25
+ readonly name = "hr";
26
+ readonly version = "1.0.0";
27
+ override decorationPriority = 10;
28
+ override readonly requiredNodes = ["HorizontalRule"] as const;
29
+
30
+ /**
31
+ * Constructor - calls super constructor
32
+ */
33
+ constructor() {
34
+ super();
35
+ }
36
+
37
+ /**
38
+ * Plugin theme
39
+ */
40
+ override get theme() {
41
+ return theme;
42
+ }
43
+
44
+ /**
45
+ * Build horizontal rule decorations by iterating the syntax tree
46
+ */
47
+ buildDecorations(ctx: DecorationContext): void {
48
+ const { view, decorations } = ctx;
49
+ const tree = syntaxTree(view.state);
50
+
51
+ tree.iterate({
52
+ enter: (node) => {
53
+ const { from, to, name } = node;
54
+
55
+ if (name !== "HorizontalRule") {
56
+ return;
57
+ }
58
+
59
+ // Add line decoration for the horizontal rule styling
60
+ const line = view.state.doc.lineAt(from);
61
+ decorations.push(hrLineDecoration.range(line.from));
62
+
63
+ // Hide the raw markers when cursor is not on the line
64
+ const cursorInNode = ctx.selectionOverlapsRange(from, to);
65
+ if (!cursorInNode) {
66
+ // Clamp to line end so replace decoration never spans a newline
67
+ const markEnd = Math.min(to, line.to);
68
+ decorations.push(hrMarkDecoration.range(from, markEnd));
69
+ }
70
+ },
71
+ });
72
+ }
73
+
74
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
75
+ override renderToHTML(node: SyntaxNode, _children: string): string | null {
76
+ if (node.name !== "HorizontalRule") {
77
+ return null;
78
+ }
79
+
80
+ return `<hr class="cm-mardora-hr-line" />\n`;
81
+ }
82
+ }
83
+
84
+ const theme = createTheme({
85
+ default: {
86
+ // Line styling — displays a centered horizontal line
87
+ ".cm-mardora-hr-line": {
88
+ display: "flex",
89
+ alignItems: "center",
90
+ paddingTop: "0.75em",
91
+ paddingBottom: "0.75em",
92
+ border: "none",
93
+ "&::after": {
94
+ content: '""',
95
+ flex: "1",
96
+ height: "2px",
97
+ background: "currentColor",
98
+ opacity: "0.3",
99
+ },
100
+ },
101
+ },
102
+ });