draftly 1.0.0-alpha.2 → 2.0.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/README.md +12 -0
- package/dist/chunk-3T55CBNZ.cjs +33 -0
- package/dist/chunk-3T55CBNZ.cjs.map +1 -0
- package/dist/chunk-5MC4T7JH.cjs +58 -0
- package/dist/chunk-5MC4T7JH.cjs.map +1 -0
- package/dist/{chunk-72ZYRGRT.cjs → chunk-BWJLMREN.cjs} +11 -9
- package/dist/chunk-BWJLMREN.cjs.map +1 -0
- package/dist/{chunk-KBQDZ5IW.cjs → chunk-CLW73JRX.cjs} +100 -75
- package/dist/chunk-CLW73JRX.cjs.map +1 -0
- package/dist/{chunk-DFQYXFOP.js → chunk-EEHILRG5.js} +26 -3
- package/dist/chunk-EEHILRG5.js.map +1 -0
- package/dist/{chunk-HPSMS2WB.js → chunk-I563H35S.js} +101 -75
- package/dist/chunk-I563H35S.js.map +1 -0
- package/dist/chunk-IAXF4SJL.js +55 -0
- package/dist/chunk-IAXF4SJL.js.map +1 -0
- package/dist/chunk-JF3WXXMJ.js +31 -0
- package/dist/chunk-JF3WXXMJ.js.map +1 -0
- package/dist/{chunk-N3WL3XPB.js → chunk-L2XSK57Y.js} +1761 -478
- package/dist/chunk-L2XSK57Y.js.map +1 -0
- package/dist/{chunk-KDEDLC3D.cjs → chunk-TBVZEK2H.cjs} +27 -2
- package/dist/chunk-TBVZEK2H.cjs.map +1 -0
- package/dist/{chunk-2B3A3VSQ.cjs → chunk-W5ALMXG2.cjs} +1808 -504
- package/dist/chunk-W5ALMXG2.cjs.map +1 -0
- package/dist/{chunk-CG4M4TC7.js → chunk-ZUI3GI3W.js} +7 -5
- package/dist/chunk-ZUI3GI3W.js.map +1 -0
- package/dist/{draftly-BLnx3uGX.d.cts → draftly-BBL-AdOl.d.cts} +5 -1
- package/dist/{draftly-BLnx3uGX.d.ts → draftly-BBL-AdOl.d.ts} +5 -1
- package/dist/editor/index.cjs +22 -14
- package/dist/editor/index.d.cts +2 -1
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/index.js +2 -2
- package/dist/index.cjs +65 -39
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +6 -4
- 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/plugins/index.cjs +27 -17
- package/dist/plugins/index.d.cts +144 -9
- package/dist/plugins/index.d.ts +144 -9
- package/dist/plugins/index.js +5 -3
- package/dist/preview/index.cjs +16 -11
- package/dist/preview/index.d.cts +19 -4
- package/dist/preview/index.d.ts +19 -4
- package/dist/preview/index.js +3 -2
- package/package.json +8 -1
- package/src/editor/draftly.ts +1 -0
- package/src/editor/plugin.ts +5 -1
- package/src/editor/theme.ts +1 -0
- package/src/editor/utils.ts +31 -0
- package/src/index.ts +5 -4
- package/src/lib/index.ts +2 -0
- package/src/lib/input-handler.ts +45 -0
- package/src/plugins/code-plugin.theme.ts +426 -0
- package/src/plugins/code-plugin.ts +810 -561
- package/src/plugins/emoji-plugin.ts +140 -0
- package/src/plugins/index.ts +63 -57
- package/src/plugins/inline-plugin.ts +305 -291
- package/src/plugins/math-plugin.ts +12 -0
- package/src/plugins/table-plugin.ts +900 -0
- package/src/preview/context.ts +4 -1
- package/src/preview/css-generator.ts +14 -1
- package/src/preview/index.ts +9 -1
- package/src/preview/preview.ts +2 -1
- package/src/preview/renderer.ts +21 -20
- package/src/preview/syntax-theme.ts +110 -0
- package/src/preview/types.ts +14 -0
- package/dist/chunk-2B3A3VSQ.cjs.map +0 -1
- package/dist/chunk-72ZYRGRT.cjs.map +0 -1
- package/dist/chunk-CG4M4TC7.js.map +0 -1
- package/dist/chunk-DFQYXFOP.js.map +0 -1
- package/dist/chunk-HPSMS2WB.js.map +0 -1
- package/dist/chunk-KBQDZ5IW.cjs.map +0 -1
- package/dist/chunk-KDEDLC3D.cjs.map +0 -1
- package/dist/chunk-N3WL3XPB.js.map +0 -1
|
@@ -1,291 +1,305 @@
|
|
|
1
|
-
import { Decoration, KeyBinding } 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 { toggleMarkdownStyle } from "../editor/utils";
|
|
7
|
-
import { tags } from "@lezer/highlight";
|
|
8
|
-
import type { MarkdownConfig, InlineParser } from "@lezer/markdown";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
if (cx.char(pos +
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* -
|
|
88
|
-
* -
|
|
89
|
-
* -
|
|
90
|
-
* -
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
1
|
+
import { Decoration, KeyBinding } 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 { toggleMarkdownStyle } from "../editor/utils";
|
|
7
|
+
import { tags } from "@lezer/highlight";
|
|
8
|
+
import type { MarkdownConfig, InlineParser } from "@lezer/markdown";
|
|
9
|
+
import { Extension } from "@codemirror/state";
|
|
10
|
+
import { createWrapSelectionInputHandler } from "../lib";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Node types for inline styling in markdown
|
|
14
|
+
*/
|
|
15
|
+
const INLINE_TYPES = {
|
|
16
|
+
Emphasis: "emphasis",
|
|
17
|
+
StrongEmphasis: "strong",
|
|
18
|
+
Strikethrough: "strikethrough",
|
|
19
|
+
Subscript: "subscript",
|
|
20
|
+
Superscript: "superscript",
|
|
21
|
+
Highlight: "highlight",
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Mark decorations for inline content
|
|
26
|
+
*/
|
|
27
|
+
const inlineMarkDecorations = {
|
|
28
|
+
emphasis: Decoration.mark({ class: "cm-draftly-emphasis" }),
|
|
29
|
+
strong: Decoration.mark({ class: "cm-draftly-strong" }),
|
|
30
|
+
strikethrough: Decoration.mark({ class: "cm-draftly-strikethrough" }),
|
|
31
|
+
subscript: Decoration.mark({ class: "cm-draftly-subscript" }),
|
|
32
|
+
superscript: Decoration.mark({ class: "cm-draftly-superscript" }),
|
|
33
|
+
highlight: Decoration.mark({ class: "cm-draftly-highlight" }),
|
|
34
|
+
// Markers (* _ ~~ ^ ~ ==)
|
|
35
|
+
"inline-mark": Decoration.replace({}),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Character code for '='
|
|
39
|
+
const EQUALS = 61;
|
|
40
|
+
|
|
41
|
+
// Punctuation regex for flanking checks (matches Unicode punctuation)
|
|
42
|
+
// eslint-disable-next-line no-useless-escape
|
|
43
|
+
let Punctuation = /[!"#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~\xA1\u2010-\u2027]/;
|
|
44
|
+
try {
|
|
45
|
+
Punctuation = new RegExp("[\\p{S}|\\p{P}]", "u");
|
|
46
|
+
} catch {
|
|
47
|
+
// Fallback regex is used above for environments without Unicode support
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Delimiter type for highlight markers — enables nested inline parsing
|
|
51
|
+
const HighlightDelim = { resolve: "Highlight", mark: "HighlightMark" };
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Inline parser for highlight syntax: ==text==
|
|
55
|
+
* Uses addDelimiter (like Strikethrough) so nested inline styles work.
|
|
56
|
+
*/
|
|
57
|
+
const highlightParser: InlineParser = {
|
|
58
|
+
name: "Highlight",
|
|
59
|
+
parse(cx, next, pos) {
|
|
60
|
+
// Must start with ==
|
|
61
|
+
if (next !== EQUALS || cx.char(pos + 1) !== EQUALS) return -1;
|
|
62
|
+
// Don't match === (or more)
|
|
63
|
+
if (cx.char(pos + 2) === EQUALS) return -1;
|
|
64
|
+
|
|
65
|
+
// Flanking checks (same logic as Strikethrough)
|
|
66
|
+
const before = cx.slice(pos - 1, pos);
|
|
67
|
+
const after = cx.slice(pos + 2, pos + 3);
|
|
68
|
+
const sBefore = /\s|^$/.test(before),
|
|
69
|
+
sAfter = /\s|^$/.test(after);
|
|
70
|
+
const pBefore = Punctuation.test(before),
|
|
71
|
+
pAfter = Punctuation.test(after);
|
|
72
|
+
|
|
73
|
+
return cx.addDelimiter(
|
|
74
|
+
HighlightDelim,
|
|
75
|
+
pos,
|
|
76
|
+
pos + 2,
|
|
77
|
+
!sAfter && (!pAfter || sBefore || pBefore),
|
|
78
|
+
!sBefore && (!pBefore || sAfter || pAfter)
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* InlinePlugin - Decorates inline markdown formatting
|
|
85
|
+
*
|
|
86
|
+
* Adds visual styling to inline elements:
|
|
87
|
+
* - Emphasis (italic) - *text* or _text_
|
|
88
|
+
* - Strong (bold) - **text** or __text__
|
|
89
|
+
* - Strikethrough - ~~text~~
|
|
90
|
+
* - Subscript - ~text~
|
|
91
|
+
* - Superscript - ^text^
|
|
92
|
+
* - Highlight - ==text==
|
|
93
|
+
*
|
|
94
|
+
* Hides formatting markers when cursor is not in the element
|
|
95
|
+
*/
|
|
96
|
+
export class InlinePlugin extends DecorationPlugin {
|
|
97
|
+
readonly name = "inline";
|
|
98
|
+
readonly version = "1.0.0";
|
|
99
|
+
override decorationPriority = 20;
|
|
100
|
+
override readonly requiredNodes = [
|
|
101
|
+
"Emphasis",
|
|
102
|
+
"StrongEmphasis",
|
|
103
|
+
"Strikethrough",
|
|
104
|
+
"Subscript",
|
|
105
|
+
"Superscript",
|
|
106
|
+
"Highlight",
|
|
107
|
+
"EmphasisMark",
|
|
108
|
+
"StrikethroughMark",
|
|
109
|
+
"SubscriptMark",
|
|
110
|
+
"SuperscriptMark",
|
|
111
|
+
"HighlightMark",
|
|
112
|
+
] as const;
|
|
113
|
+
marks: string[] = [];
|
|
114
|
+
|
|
115
|
+
constructor() {
|
|
116
|
+
super();
|
|
117
|
+
|
|
118
|
+
for (const mark of Object.keys(INLINE_TYPES)) {
|
|
119
|
+
this.marks.push(...this.getMarkerNames(mark));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Plugin theme
|
|
125
|
+
*/
|
|
126
|
+
override get theme() {
|
|
127
|
+
return theme;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Keyboard shortcuts for inline formatting
|
|
132
|
+
*/
|
|
133
|
+
override getKeymap(): KeyBinding[] {
|
|
134
|
+
return [
|
|
135
|
+
{
|
|
136
|
+
key: "Mod-b",
|
|
137
|
+
run: toggleMarkdownStyle("**"),
|
|
138
|
+
preventDefault: true,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
key: "Mod-i",
|
|
142
|
+
run: toggleMarkdownStyle("*"),
|
|
143
|
+
preventDefault: true,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
key: "Mod-Shift-s",
|
|
147
|
+
run: toggleMarkdownStyle("~~"),
|
|
148
|
+
preventDefault: true,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
key: "Mod-,",
|
|
152
|
+
run: toggleMarkdownStyle("~"),
|
|
153
|
+
preventDefault: true,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
key: "Mod-.",
|
|
157
|
+
run: toggleMarkdownStyle("^"),
|
|
158
|
+
preventDefault: true,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
key: "Mod-Shift-h",
|
|
162
|
+
run: toggleMarkdownStyle("=="),
|
|
163
|
+
preventDefault: true,
|
|
164
|
+
},
|
|
165
|
+
];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Intercepts inline marker typing to wrap selected text.
|
|
170
|
+
*
|
|
171
|
+
* If user types inline markers while text is selected, wraps each selected
|
|
172
|
+
* range with the appropriate marker:
|
|
173
|
+
* - * _ ~ ^ -> marker + selected + marker
|
|
174
|
+
* - = -> ==selected==
|
|
175
|
+
*/
|
|
176
|
+
override getExtensions(): Extension[] {
|
|
177
|
+
return [createWrapSelectionInputHandler({ "*": "*", _: "_", "~": "~", "^": "^", "=": "==" })];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Return markdown parser extensions for highlight syntax (==text==)
|
|
182
|
+
*/
|
|
183
|
+
override getMarkdownConfig(): MarkdownConfig {
|
|
184
|
+
return {
|
|
185
|
+
defineNodes: [
|
|
186
|
+
{ name: "Highlight", style: tags.emphasis },
|
|
187
|
+
{ name: "HighlightMark", style: tags.processingInstruction },
|
|
188
|
+
],
|
|
189
|
+
parseInline: [highlightParser],
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Build inline decorations by iterating the syntax tree
|
|
195
|
+
*/
|
|
196
|
+
buildDecorations(ctx: DecorationContext): void {
|
|
197
|
+
const { view, decorations } = ctx;
|
|
198
|
+
const tree = syntaxTree(view.state);
|
|
199
|
+
|
|
200
|
+
tree.iterate({
|
|
201
|
+
enter: (node) => {
|
|
202
|
+
const { from, to, name } = node;
|
|
203
|
+
|
|
204
|
+
// Check if this is an inline type we handle
|
|
205
|
+
const inlineType = INLINE_TYPES[name as keyof typeof INLINE_TYPES];
|
|
206
|
+
if (!inlineType) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Add mark decoration for the content
|
|
211
|
+
decorations.push(inlineMarkDecorations[inlineType].range(from, to));
|
|
212
|
+
|
|
213
|
+
// Only hide markers when cursor is not in the element
|
|
214
|
+
const cursorInNode = ctx.selectionOverlapsRange(from, to);
|
|
215
|
+
if (!cursorInNode) {
|
|
216
|
+
// Get the appropriate marker children based on type
|
|
217
|
+
const markerNames = this.getMarkerNames(name);
|
|
218
|
+
for (const markerName of markerNames) {
|
|
219
|
+
const marks = node.node.getChildren(markerName);
|
|
220
|
+
for (const mark of marks) {
|
|
221
|
+
decorations.push(inlineMarkDecorations["inline-mark"].range(mark.from, mark.to));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get the marker node names for a given inline type
|
|
231
|
+
*/
|
|
232
|
+
private getMarkerNames(nodeType: string): string[] {
|
|
233
|
+
switch (nodeType) {
|
|
234
|
+
case "Emphasis":
|
|
235
|
+
case "StrongEmphasis":
|
|
236
|
+
return ["EmphasisMark"];
|
|
237
|
+
case "Strikethrough":
|
|
238
|
+
return ["StrikethroughMark"];
|
|
239
|
+
case "Subscript":
|
|
240
|
+
return ["SubscriptMark"];
|
|
241
|
+
case "Superscript":
|
|
242
|
+
return ["SuperscriptMark"];
|
|
243
|
+
case "Highlight":
|
|
244
|
+
return ["HighlightMark"];
|
|
245
|
+
default:
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
override renderToHTML(node: SyntaxNode, children: string): string | null {
|
|
251
|
+
if (this.marks.includes(node.name)) {
|
|
252
|
+
return "";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const inlineType = INLINE_TYPES[node.name as keyof typeof INLINE_TYPES];
|
|
256
|
+
if (!inlineType) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
const className = inlineMarkDecorations[inlineType].spec.class as string;
|
|
260
|
+
|
|
261
|
+
return `<span class="${className}">${children}</span>`;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Theme for inline styling
|
|
267
|
+
*/
|
|
268
|
+
const theme = createTheme({
|
|
269
|
+
default: {
|
|
270
|
+
// Emphasis (italic)
|
|
271
|
+
".cm-draftly-emphasis": {
|
|
272
|
+
fontStyle: "italic",
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
// Strong (bold)
|
|
276
|
+
".cm-draftly-strong": {
|
|
277
|
+
fontWeight: "bold",
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
// Strikethrough
|
|
281
|
+
".cm-draftly-strikethrough": {
|
|
282
|
+
textDecoration: "line-through",
|
|
283
|
+
opacity: "0.7",
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
// Subscript
|
|
287
|
+
".cm-draftly-subscript": {
|
|
288
|
+
fontSize: "0.75em",
|
|
289
|
+
verticalAlign: "sub",
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
// Superscript
|
|
293
|
+
".cm-draftly-superscript": {
|
|
294
|
+
fontSize: "0.75em",
|
|
295
|
+
verticalAlign: "super",
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
// Highlight
|
|
299
|
+
".cm-draftly-highlight": {
|
|
300
|
+
backgroundColor: "rgba(255, 213, 0, 0.35)",
|
|
301
|
+
borderRadius: "2px",
|
|
302
|
+
padding: "1px 2px",
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Decoration, EditorView, WidgetType } from "@codemirror/view";
|
|
2
|
+
import { Extension } from "@codemirror/state";
|
|
2
3
|
import { syntaxTree } from "@codemirror/language";
|
|
3
4
|
import { DecorationContext, DecorationPlugin } from "../editor/plugin";
|
|
4
5
|
import { createTheme } from "../editor";
|
|
@@ -6,6 +7,7 @@ import { SyntaxNode } from "@lezer/common";
|
|
|
6
7
|
import { tags } from "@lezer/highlight";
|
|
7
8
|
import type { MarkdownConfig, InlineParser, BlockParser, Line, BlockContext } from "@lezer/markdown";
|
|
8
9
|
import katex from "katex";
|
|
10
|
+
import { createWrapSelectionInputHandler } from "../lib";
|
|
9
11
|
// @ts-expect-error - raw import for CSS as string
|
|
10
12
|
import katexCss from "katex/dist/katex.min.css?raw";
|
|
11
13
|
|
|
@@ -279,6 +281,16 @@ export class MathPlugin extends DecorationPlugin {
|
|
|
279
281
|
return theme;
|
|
280
282
|
}
|
|
281
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
|
+
|
|
282
294
|
/**
|
|
283
295
|
* Return markdown parser extensions for math syntax
|
|
284
296
|
*/
|