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,279 @@
1
+ import type {
2
+ InlineFormatInput,
3
+ LinkChangeInput,
4
+ ParsedSelectionLink,
5
+ SelectionToolbarListKind,
6
+ SelectionToolbarBlockType,
7
+ TextChange,
8
+ TextCommandResult,
9
+ } from "./types";
10
+
11
+ const markdownLinkPattern = /^\[([^\]]*)\]\(([^)]*)\)$/;
12
+ const urlPattern = /^(https?:\/\/|www\.)[^\s]+$/i;
13
+ const listMarkerPattern = /^(\s*)([-*+]|\d+\.)\s(\[[ xX]\]\s)?/;
14
+ const headingMarkerPattern = /^(\s*)(#{1,6})(?:[ \t]+|$)/;
15
+
16
+ function selectedText(input: Pick<InlineFormatInput, "doc" | "from" | "to">): string {
17
+ return input.doc.slice(input.from, input.to);
18
+ }
19
+
20
+ function escapeRegExp(value: string): string {
21
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22
+ }
23
+
24
+ function buildHtmlWrapper(input: InlineFormatInput): { open: string; close: string } {
25
+ if (input.htmlTag) {
26
+ return { open: `<${input.htmlTag}>`, close: `</${input.htmlTag}>` };
27
+ }
28
+ if (input.spanStyle) {
29
+ return { open: `<span style="${input.spanStyle.property}: ${input.spanStyle.value}">`, close: "</span>" };
30
+ }
31
+ const marker = input.marker ?? "";
32
+ return { open: marker, close: marker };
33
+ }
34
+
35
+ export function buildInlineFormatChange(input: InlineFormatInput): TextCommandResult {
36
+ const text = selectedText(input);
37
+ const { open, close } = buildHtmlWrapper(input);
38
+
39
+ if (input.clear) {
40
+ const tagPattern = input.spanStyle
41
+ ? new RegExp(
42
+ `^<span style="${escapeRegExp(input.spanStyle.property)}: ${
43
+ input.spanStyle.value ? escapeRegExp(input.spanStyle.value) : "#[0-9a-fA-F]{6}"
44
+ }">([\\s\\S]*)<\\/span>$`
45
+ )
46
+ : input.htmlTag
47
+ ? new RegExp(`^<${input.htmlTag}>([\\s\\S]*)<\\/${input.htmlTag}>$`)
48
+ : null;
49
+ const match = tagPattern ? text.match(tagPattern) : null;
50
+ const insert = match?.[1] ?? text;
51
+ return {
52
+ changes: { from: input.from, to: input.to, insert },
53
+ selection: { anchor: input.from, head: input.from + insert.length },
54
+ };
55
+ }
56
+
57
+ const beforeFrom = Math.max(0, input.from - open.length);
58
+ const afterTo = Math.min(input.doc.length, input.to + close.length);
59
+ const before = input.doc.slice(beforeFrom, input.from);
60
+ const after = input.doc.slice(input.to, afterTo);
61
+
62
+ if (before === open && after === close) {
63
+ return {
64
+ changes: [
65
+ { from: beforeFrom, to: input.from, insert: "" },
66
+ { from: input.to, to: afterTo, insert: "" },
67
+ ],
68
+ selection: { anchor: beforeFrom, head: beforeFrom + text.length },
69
+ };
70
+ }
71
+
72
+ const insert = `${open}${text}${close}`;
73
+ return {
74
+ changes: { from: input.from, to: input.to, insert },
75
+ selection: { anchor: input.from + open.length, head: input.from + open.length + text.length },
76
+ };
77
+ }
78
+
79
+ export function parseSelectedLink(text: string): ParsedSelectionLink {
80
+ const linkMatch = text.match(markdownLinkPattern);
81
+ if (linkMatch) {
82
+ return { kind: "markdown-link", title: linkMatch[1] ?? "", url: linkMatch[2] ?? "" };
83
+ }
84
+ if (urlPattern.test(text)) {
85
+ return { kind: "url", title: "", url: text };
86
+ }
87
+ return { kind: "text", title: text, url: "" };
88
+ }
89
+
90
+ export function buildLinkChange(input: LinkChangeInput): TextCommandResult {
91
+ if (input.remove) {
92
+ return {
93
+ changes: { from: input.from, to: input.to, insert: input.title },
94
+ selection: { anchor: input.from, head: input.from + input.title.length },
95
+ };
96
+ }
97
+
98
+ if (!input.url.trim()) {
99
+ throw new Error("Link URL is required");
100
+ }
101
+
102
+ const insert = `[${input.title}](${input.url})`;
103
+ return {
104
+ changes: { from: input.from, to: input.to, insert },
105
+ selection: { anchor: input.from, head: input.from + insert.length },
106
+ };
107
+ }
108
+
109
+ function lineRanges(doc: string, from: number, to: number): Array<{ from: number; text: string }> {
110
+ const ranges: Array<{ from: number; text: string }> = [];
111
+ let position = 0;
112
+
113
+ for (const text of doc.split("\n")) {
114
+ const lineFrom = position;
115
+ const lineTo = position + text.length;
116
+ if (lineTo >= from && lineFrom <= to) {
117
+ ranges.push({ from: lineFrom, text });
118
+ }
119
+ position = lineTo + 1;
120
+ }
121
+
122
+ return ranges;
123
+ }
124
+
125
+ function markerFor(kind: SelectionToolbarListKind, order: number): string {
126
+ if (kind === "ordered") return `${order}. `;
127
+ if (kind === "task") return "- [ ] ";
128
+ return "- ";
129
+ }
130
+
131
+ export function buildListChange(input: { doc: string; from: number; to: number; kind: SelectionToolbarListKind }): {
132
+ changes: TextChange[];
133
+ } {
134
+ const changes: TextChange[] = [];
135
+ let order = 1;
136
+
137
+ for (const line of lineRanges(input.doc, input.from, input.to)) {
138
+ const match = line.text.match(listMarkerPattern);
139
+ const actualMarker = markerFor(input.kind, order);
140
+
141
+ if (match) {
142
+ const indent = match[1] ?? "";
143
+ const isOrdered = /^\d+\.$/.test(match[2] ?? "");
144
+ const isUnordered = /^[-*+]$/.test(match[2] ?? "");
145
+ const hasTask = !!match[3];
146
+ const same =
147
+ (input.kind === "ordered" && isOrdered && !hasTask) ||
148
+ (input.kind === "unordered" && isUnordered && !hasTask) ||
149
+ (input.kind === "task" && hasTask);
150
+
151
+ changes.push({
152
+ from: line.from,
153
+ to: line.from + match[0].length,
154
+ insert: same ? indent : indent + actualMarker,
155
+ });
156
+ } else {
157
+ const indentLength = line.text.match(/^(\s*)/)?.[1]?.length ?? 0;
158
+ changes.push({ from: line.from + indentLength, to: line.from + indentLength, insert: actualMarker });
159
+ }
160
+
161
+ if (input.kind === "ordered") order += 1;
162
+ }
163
+
164
+ return { changes };
165
+ }
166
+
167
+ function headingLevelForLine(text: string): number {
168
+ return text.match(headingMarkerPattern)?.[2]?.length ?? 0;
169
+ }
170
+
171
+ function escapePlainTextBlockStart(text: string): string {
172
+ if (/^\d+[.)]\s/.test(text)) {
173
+ return text.replace(/^(\d+)([.)])/, "$1\\$2");
174
+ }
175
+ if (/^[-*+]\s/.test(text) || /^#{1,6}(\s|$)/.test(text) || /^>\s?/.test(text)) {
176
+ return `\\${text}`;
177
+ }
178
+ return text;
179
+ }
180
+
181
+ function unescapePlainTextBlockStart(text: string): string {
182
+ if (/^\d+\\[.)]\s/.test(text)) {
183
+ return text.replace(/^(\d+)\\([.)])/, "$1$2");
184
+ }
185
+ if (/^\\([-*+#>])/.test(text)) {
186
+ return text.slice(1);
187
+ }
188
+ return text;
189
+ }
190
+
191
+ export function detectSelectionBlockType(input: { doc: string; from: number; to: number }): SelectionToolbarBlockType {
192
+ const line = lineRanges(input.doc, input.from, input.to)[0];
193
+ const level = line ? headingLevelForLine(line.text) : 0;
194
+ return level > 0 ? (`heading-${level}` as SelectionToolbarBlockType) : "text";
195
+ }
196
+
197
+ export function buildBlockTypeChange(input: {
198
+ doc: string;
199
+ from: number;
200
+ to: number;
201
+ level: 0 | 1 | 2 | 3 | 4 | 5 | 6;
202
+ }): TextCommandResult {
203
+ const changes: TextChange[] = [];
204
+ const lines = lineRanges(input.doc, input.from, input.to);
205
+ let accumulatedDelta = 0;
206
+ let selectionAnchor: number | null = null;
207
+ let selectionHead: number | null = null;
208
+
209
+ for (const line of lines) {
210
+ const lineTo = line.from + line.text.length;
211
+ const headingMatch = line.text.match(headingMarkerPattern);
212
+ const indent = headingMatch?.[1] ?? line.text.match(/^(\s*)/)?.[1] ?? "";
213
+ const oldPrefixLength = headingMatch ? headingMatch[0].length : indent.length;
214
+ const content = line.text.slice(oldPrefixLength);
215
+
216
+ if (input.level === 0 && headingMatch) {
217
+ const escapedContent = escapePlainTextBlockStart(content);
218
+ if (escapedContent !== content) {
219
+ const insert = `${indent}${escapedContent}`;
220
+ const delta = insert.length - line.text.length;
221
+ changes.push({
222
+ from: line.from,
223
+ to: lineTo,
224
+ insert,
225
+ });
226
+
227
+ const newContentFrom = line.from + accumulatedDelta + indent.length;
228
+ const newContentTo = lineTo + accumulatedDelta + delta;
229
+ selectionAnchor ??= newContentFrom;
230
+ selectionHead = newContentTo;
231
+ accumulatedDelta += delta;
232
+ continue;
233
+ }
234
+ }
235
+
236
+ const newPrefix = input.level === 0 ? indent : `${indent}${"#".repeat(input.level)} `;
237
+ const delta = newPrefix.length - oldPrefixLength;
238
+ const headingContent = input.level > 0 ? unescapePlainTextBlockStart(content) : content;
239
+
240
+ if (input.level > 0 && headingContent !== content) {
241
+ const insert = `${newPrefix}${headingContent}`;
242
+ const lineDelta = insert.length - line.text.length;
243
+ changes.push({
244
+ from: line.from,
245
+ to: lineTo,
246
+ insert,
247
+ });
248
+
249
+ const newContentFrom = line.from + accumulatedDelta + newPrefix.length;
250
+ const newContentTo = lineTo + accumulatedDelta + lineDelta;
251
+ selectionAnchor ??= newContentFrom;
252
+ selectionHead = newContentTo;
253
+ accumulatedDelta += lineDelta;
254
+ continue;
255
+ }
256
+
257
+ if (newPrefix !== line.text.slice(0, oldPrefixLength)) {
258
+ changes.push({
259
+ from: line.from,
260
+ to: line.from + oldPrefixLength,
261
+ insert: newPrefix,
262
+ });
263
+ }
264
+
265
+ const newContentFrom = line.from + accumulatedDelta + newPrefix.length;
266
+ const newContentTo = lineTo + accumulatedDelta + delta;
267
+ selectionAnchor ??= newContentFrom;
268
+ selectionHead = newContentTo;
269
+ accumulatedDelta += delta;
270
+ }
271
+
272
+ return {
273
+ changes,
274
+ selection: {
275
+ anchor: selectionAnchor ?? input.from,
276
+ head: selectionHead ?? input.to,
277
+ },
278
+ };
279
+ }