@prosemark/core 0.0.0 → 0.0.3

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/dist/main.js ADDED
@@ -0,0 +1,875 @@
1
+ import { Decoration, EditorView, EditorView as EditorView$1, ViewPlugin, WidgetType, dropCursor, keymap } from "@codemirror/view";
2
+ import { CharCategory, EditorSelection, EditorState, Facet, RangeSetBuilder, StateField, findClusterBreak } from "@codemirror/state";
3
+ import { HighlightStyle, bracketMatching, foldGutter, foldKeymap, indentOnInput, syntaxHighlighting, syntaxTree } from "@codemirror/language";
4
+ import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
5
+ import { searchKeymap } from "@codemirror/search";
6
+ import { autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap } from "@codemirror/autocomplete";
7
+ import { lintKeymap } from "@codemirror/lint";
8
+ import { Tag, styleTags, tags } from "@lezer/highlight";
9
+ import * as emoji from "node-emoji";
10
+
11
+ //#region lib/utils.ts
12
+ function stateWORDAt(state, pos) {
13
+ const { text, from, length } = state.doc.lineAt(pos);
14
+ const cat = state.charCategorizer(pos);
15
+ let start = pos - from, end = pos - from;
16
+ while (start > 0) {
17
+ const prev = findClusterBreak(text, start, false);
18
+ if (cat(text.slice(prev, start)) === CharCategory.Space) break;
19
+ start = prev;
20
+ }
21
+ while (end < length) {
22
+ const next = findClusterBreak(text, end);
23
+ if (cat(text.slice(end, next)) === CharCategory.Space) break;
24
+ end = next;
25
+ }
26
+ return start == end ? null : EditorSelection.range(start + from, end + from);
27
+ }
28
+ function rangeTouchesRange(a, b) {
29
+ return a.from <= b.to && b.from <= a.to;
30
+ }
31
+ function selectionTouchesRange(selection, b) {
32
+ return selection.some((range) => rangeTouchesRange(range, b));
33
+ }
34
+ function iterChildren(cursor, enter) {
35
+ if (!cursor.firstChild()) return;
36
+ do
37
+ if (enter(cursor)) break;
38
+ while (cursor.nextSibling());
39
+ console.assert(cursor.parent());
40
+ }
41
+ function eventHandlersWithClass(handlers) {
42
+ return Object.fromEntries(Object.entries(handlers).filter(([_event, handlers$1]) => !!handlers$1).map(([event, handlers$1]) => [event, function(ev, view) {
43
+ const res = [];
44
+ for (const className in handlers$1) if (ev.composedPath().some((el) => {
45
+ if (!(el instanceof Element)) return false;
46
+ return el.classList.contains(className);
47
+ })) res.push(handlers$1[className]?.call(this, ev, view));
48
+ return res.some((res$1) => !!res$1);
49
+ }]));
50
+ }
51
+
52
+ //#endregion
53
+ //#region lib/hide/core.ts
54
+ const hideTheme = EditorView.theme({ ".cm-hidden-token": { fontSize: "0px" } });
55
+ const hideInlineDecoration = Decoration.mark({ class: "cm-hidden-token" });
56
+ const hideBlockDecoration = Decoration.replace({ block: true });
57
+ const buildDecorations$1 = (state) => {
58
+ const decorations = [];
59
+ const specs = state.facet(hidableNodeFacet);
60
+ syntaxTree(state).iterate({ enter: (node) => {
61
+ if (state.selection.ranges.some((range) => rangeTouchesRange(node, range))) return;
62
+ for (const spec of specs) {
63
+ if (spec.nodeName instanceof Function) {
64
+ if (!spec.nodeName(node.type.name)) continue;
65
+ } else if (spec.nodeName instanceof Array) {
66
+ if (!spec.nodeName.includes(node.type.name)) continue;
67
+ } else if (node.type.name !== spec.nodeName) continue;
68
+ if (spec.unhideZone) {
69
+ const res = spec.unhideZone(state, node);
70
+ if (state.selection.ranges.some((range) => rangeTouchesRange(res, range))) return;
71
+ }
72
+ if (spec.onHide) {
73
+ const res = spec.onHide(state, node);
74
+ if (res instanceof Array) decorations.push(...res);
75
+ else if (res) decorations.push(res);
76
+ }
77
+ if (spec.subNodeNameToHide) {
78
+ let names;
79
+ if (!Array.isArray(spec.subNodeNameToHide)) names = [spec.subNodeNameToHide];
80
+ else names = spec.subNodeNameToHide;
81
+ const cursor = node.node.cursor();
82
+ console.assert(cursor.firstChild(), "A hide node must have children");
83
+ do
84
+ if (names.includes(cursor.type.name)) decorations.push((spec.block ? hideBlockDecoration : hideInlineDecoration).range(cursor.from, cursor.to));
85
+ while (cursor.nextSibling());
86
+ }
87
+ }
88
+ } });
89
+ return Decoration.set(decorations, true);
90
+ };
91
+ const hideExtension = StateField.define({
92
+ create(state) {
93
+ return buildDecorations$1(state);
94
+ },
95
+ update(deco, tr) {
96
+ if (tr.docChanged || tr.selection) return buildDecorations$1(tr.state);
97
+ return deco.map(tr.changes);
98
+ },
99
+ provide: (f) => [EditorView.decorations.from(f), hideTheme]
100
+ });
101
+ const hidableNodeFacet = Facet.define({
102
+ combine(value) {
103
+ return [...value];
104
+ },
105
+ enables: hideExtension
106
+ });
107
+
108
+ //#endregion
109
+ //#region lib/markdownTags.ts
110
+ const markdownTags = {
111
+ headerMark: Tag.define(),
112
+ inlineCode: Tag.define(),
113
+ fencedCode: Tag.define(),
114
+ linkURL: Tag.define(),
115
+ escapeMark: Tag.define(),
116
+ emoji: Tag.define(),
117
+ emojiMark: Tag.define(),
118
+ listMark: Tag.define()
119
+ };
120
+
121
+ //#endregion
122
+ //#region lib/hide/index.ts
123
+ const renderedLinkDecoration = Decoration.mark({ class: "cm-rendered-link" });
124
+ const defaultHidableSpecs = [
125
+ {
126
+ nodeName: (name) => name.startsWith("ATXHeading"),
127
+ onHide: (_view, node) => {
128
+ const headerMark = node.node.firstChild;
129
+ return hideInlineDecoration.range(headerMark.from, Math.min(headerMark.to + 1, node.to));
130
+ }
131
+ },
132
+ {
133
+ nodeName: (name) => name.startsWith("SetextHeading"),
134
+ subNodeNameToHide: "HeaderMark",
135
+ block: true
136
+ },
137
+ {
138
+ nodeName: ["StrongEmphasis", "Emphasis"],
139
+ subNodeNameToHide: "EmphasisMark"
140
+ },
141
+ {
142
+ nodeName: "InlineCode",
143
+ subNodeNameToHide: "CodeMark"
144
+ },
145
+ {
146
+ nodeName: "Link",
147
+ subNodeNameToHide: ["LinkMark", "URL"],
148
+ onHide: (_state, node) => {
149
+ return renderedLinkDecoration.range(node.from, node.to);
150
+ }
151
+ },
152
+ {
153
+ nodeName: "Strikethrough",
154
+ subNodeNameToHide: "StrikethroughMark"
155
+ },
156
+ {
157
+ nodeName: "Escape",
158
+ subNodeNameToHide: "EscapeMark",
159
+ unhideZone: (state, node) => {
160
+ const WORDAt = stateWORDAt(state, node.from);
161
+ if (WORDAt && WORDAt.to > node.from + 1) return WORDAt;
162
+ return state.doc.lineAt(node.from);
163
+ }
164
+ },
165
+ {
166
+ nodeName: "FencedCode",
167
+ subNodeNameToHide: ["CodeMark", "CodeInfo"]
168
+ },
169
+ {
170
+ nodeName: "Blockquote",
171
+ subNodeNameToHide: "QuoteMark"
172
+ }
173
+ ];
174
+ const defaultHideExtensions = defaultHidableSpecs.map((spec) => hidableNodeFacet.of(spec));
175
+ const escapeMarkdownSyntaxExtension = {
176
+ defineNodes: [{
177
+ name: "EscapeMark",
178
+ style: markdownTags.escapeMark
179
+ }],
180
+ parseInline: [{
181
+ name: "EscapeMark",
182
+ parse: (cx, next, pos) => {
183
+ if (next !== 92) return -1;
184
+ return cx.addElement(cx.elt("Escape", pos, pos + 2, [cx.elt("EscapeMark", pos, pos + 1)]));
185
+ },
186
+ before: "Escape"
187
+ }]
188
+ };
189
+
190
+ //#endregion
191
+ //#region lib/fold/core.ts
192
+ const buildDecorations = (state) => {
193
+ const decorations = [];
194
+ const specs = state.facet(foldableSyntaxFacet);
195
+ syntaxTree(state).iterate({ enter: (node) => {
196
+ if (selectionTouchesRange(state.selection.ranges, node)) return;
197
+ for (const spec of specs) {
198
+ const lineage = [];
199
+ let node_ = node;
200
+ while (node_) {
201
+ lineage.push(node_.name);
202
+ node_ = node_.node.parent;
203
+ }
204
+ const path = lineage.reverse().join("/");
205
+ if (spec.nodePath instanceof Function) {
206
+ if (!spec.nodePath(path)) continue;
207
+ } else if (spec.nodePath instanceof Array) {
208
+ if (!spec.nodePath.some((testPath) => path.endsWith(testPath))) continue;
209
+ } else if (!path.endsWith(spec.nodePath)) continue;
210
+ if (spec.unfoldZone) {
211
+ if (selectionTouchesRange(state.selection.ranges, spec.unfoldZone(state, node))) return;
212
+ }
213
+ if (spec.onFold) {
214
+ const res = spec.onFold(state, node);
215
+ if (res instanceof Array) decorations.push(...res);
216
+ else if (res) decorations.push(res);
217
+ }
218
+ }
219
+ } });
220
+ return Decoration.set(decorations, true);
221
+ };
222
+ const foldDecorationExtension = StateField.define({
223
+ create(state) {
224
+ return buildDecorations(state);
225
+ },
226
+ update(deco, tr) {
227
+ if (tr.docChanged || tr.selection) return buildDecorations(tr.state);
228
+ return deco.map(tr.changes);
229
+ },
230
+ provide: (f) => [EditorView.decorations.from(f)]
231
+ });
232
+ const foldExtension = [foldDecorationExtension];
233
+ const foldableSyntaxFacet = Facet.define({
234
+ combine(value) {
235
+ return [...value];
236
+ },
237
+ enables: foldExtension
238
+ });
239
+ const selectAllDecorationsOnSelectExtension = (widgetClass) => EditorView.domEventHandlers(eventHandlersWithClass({ mousedown: { [widgetClass]: (e, view) => {
240
+ const ranges = view.state.selection.ranges;
241
+ if (ranges.length === 0 || ranges[0]?.anchor !== ranges[0]?.head) return;
242
+ const target = e.target;
243
+ const pos = view.posAtDOM(target);
244
+ view.state.field(foldDecorationExtension).between(pos, pos, (from, to) => {
245
+ setTimeout(() => {
246
+ view.dispatch({ selection: EditorSelection.single(to, from) });
247
+ }, 0);
248
+ return false;
249
+ });
250
+ } } }));
251
+
252
+ //#endregion
253
+ //#region lib/fold/bulletList.ts
254
+ var BulletPoint = class extends WidgetType {
255
+ toDOM() {
256
+ const span = document.createElement("span");
257
+ span.className = "cm-rendered-list-mark";
258
+ span.innerHTML = "•";
259
+ return span;
260
+ }
261
+ ignoreEvent(_event) {
262
+ return false;
263
+ }
264
+ };
265
+ const bulletListExtension = foldableSyntaxFacet.of({
266
+ nodePath: "BulletList/ListItem/ListMark",
267
+ onFold: (_state, node) => {
268
+ const cursor = node.node.cursor();
269
+ if (cursor.nextSibling() && cursor.name === "Task") return;
270
+ return Decoration.replace({ widget: new BulletPoint() }).range(node.from, node.to);
271
+ }
272
+ });
273
+
274
+ //#endregion
275
+ //#region lib/fold/emoji.ts
276
+ const emojiDelimiter = {
277
+ resolve: "Emoji",
278
+ mark: "EmojiMark"
279
+ };
280
+ const emojiMarkdownSyntaxExtension = {
281
+ defineNodes: [{
282
+ name: "Emoji",
283
+ style: markdownTags.emoji
284
+ }, {
285
+ name: "EmojiMark",
286
+ style: markdownTags.emojiMark
287
+ }],
288
+ parseInline: [{
289
+ name: "Emoji",
290
+ parse: (cx, next, pos) => {
291
+ if (next !== 58) return -1;
292
+ const open = /^\w+:/.test(cx.slice(pos + 1, cx.end));
293
+ const close = /:\w+$/.test(cx.slice(cx.offset, pos));
294
+ if (!open && !close) return -1;
295
+ return cx.addDelimiter(emojiDelimiter, pos, pos + 1, open, close);
296
+ },
297
+ before: "Emphasis"
298
+ }]
299
+ };
300
+ var EmojiWidget = class extends WidgetType {
301
+ constructor(emoji$1) {
302
+ super();
303
+ this.emoji = emoji$1;
304
+ }
305
+ toDOM() {
306
+ const span = document.createElement("span");
307
+ span.className = "cm-emoji";
308
+ span.innerHTML = this.emoji;
309
+ return span;
310
+ }
311
+ };
312
+ const emojiExtension = foldableSyntaxFacet.of({
313
+ nodePath: "Emoji",
314
+ onFold: (state, node) => {
315
+ const emojiName = state.doc.sliceString(node.from + 1, node.to - 1);
316
+ const emoji_ = emoji.get(emojiName);
317
+ if (!emoji_) return;
318
+ return Decoration.replace({ widget: new EmojiWidget(emoji_) }).range(node.from, node.to);
319
+ }
320
+ });
321
+
322
+ //#endregion
323
+ //#region lib/fold/horizontalRule.ts
324
+ var HorizontalRuleWidget = class extends WidgetType {
325
+ toDOM() {
326
+ const div = document.createElement("div");
327
+ div.className = "cm-horizontal-rule-container";
328
+ const hr = document.createElement("hr");
329
+ div.appendChild(hr);
330
+ return div;
331
+ }
332
+ ignoreEvent(_event) {
333
+ return false;
334
+ }
335
+ destroy(dom) {
336
+ dom.remove();
337
+ }
338
+ };
339
+ const horizontalRuleTheme = EditorView.theme({ ".cm-horizontal-rule-container": {
340
+ height: "1.4em",
341
+ display: "flow-root",
342
+ "align-items": "center",
343
+ padding: "0 2px 0 6px"
344
+ } });
345
+ const horizonalRuleExtension = [
346
+ foldableSyntaxFacet.of({
347
+ nodePath: "HorizontalRule",
348
+ onFold: (_state, node) => {
349
+ return Decoration.replace({
350
+ widget: new HorizontalRuleWidget(),
351
+ block: true,
352
+ inclusiveStart: true
353
+ }).range(node.from, node.to);
354
+ }
355
+ }),
356
+ horizontalRuleTheme,
357
+ selectAllDecorationsOnSelectExtension("cm-horizontal-rule-container")
358
+ ];
359
+
360
+ //#endregion
361
+ //#region lib/fold/image.ts
362
+ var ImageWidget = class extends WidgetType {
363
+ constructor(url) {
364
+ super();
365
+ this.url = url;
366
+ }
367
+ toDOM() {
368
+ const span = document.createElement("span");
369
+ span.className = "cm-image";
370
+ if (this.url) span.innerHTML = `<img src="${this.url}" />`;
371
+ return span;
372
+ }
373
+ ignoreEvent(_event) {
374
+ return false;
375
+ }
376
+ };
377
+ const imageExtension = [foldableSyntaxFacet.of({
378
+ nodePath: "Image",
379
+ onFold: (state, node) => {
380
+ let imageUrl;
381
+ iterChildren(node.node.cursor(), (node$1) => {
382
+ if (node$1.name === "URL") imageUrl = state.doc.sliceString(node$1.from, node$1.to);
383
+ });
384
+ if (imageUrl) return Decoration.replace({ widget: new ImageWidget(imageUrl) }).range(node.from, node.to);
385
+ }
386
+ }), selectAllDecorationsOnSelectExtension("cm-image")];
387
+
388
+ //#endregion
389
+ //#region lib/fold/task.ts
390
+ var Checkbox = class extends WidgetType {
391
+ value;
392
+ constructor(value) {
393
+ super();
394
+ this.value = value;
395
+ }
396
+ toDOM() {
397
+ const el = document.createElement("input");
398
+ el.type = "checkbox";
399
+ el.className = "cm-checkbox";
400
+ el.checked = this.value;
401
+ return el;
402
+ }
403
+ ignoreEvent(_event) {
404
+ return false;
405
+ }
406
+ };
407
+ const taskExtension = [foldableSyntaxFacet.of({
408
+ nodePath: "BulletList/ListItem/Task/TaskMarker",
409
+ onFold: (state, node) => {
410
+ const value = state.doc.sliceString(node.from + 1, node.to - 1).toLowerCase() === "x";
411
+ return Decoration.replace({ widget: new Checkbox(value) }).range(node.from - 2, node.to);
412
+ },
413
+ unfoldZone: (_state, node) => ({
414
+ from: node.from - 2,
415
+ to: node.to
416
+ })
417
+ }), EditorView.domEventHandlers(eventHandlersWithClass({ mousedown: { "cm-checkbox": (ev, view) => {
418
+ const pos = view.posAtDOM(ev.target);
419
+ const change = {
420
+ from: pos + 3,
421
+ to: pos + 4,
422
+ insert: ev.target.checked ? " " : "x"
423
+ };
424
+ view.dispatch({ changes: change });
425
+ return true;
426
+ } } }))];
427
+
428
+ //#endregion
429
+ //#region lib/fold/blockQuote.ts
430
+ var BlockQuoteVerticalLine = class extends WidgetType {
431
+ toDOM() {
432
+ const span = document.createElement("span");
433
+ span.className = "cm-blockquote-vertical-line";
434
+ return span;
435
+ }
436
+ ignoreEvent(_event) {
437
+ return false;
438
+ }
439
+ };
440
+ const blockQuoteExtension = foldableSyntaxFacet.of({
441
+ nodePath: (nodePath) => nodePath.endsWith("Blockquote/QuoteMark") || nodePath.endsWith("Blockquote/Paragraph/QuoteMark"),
442
+ onFold: (_state, node) => {
443
+ return Decoration.replace({ widget: new BlockQuoteVerticalLine() }).range(node.from, node.to);
444
+ }
445
+ });
446
+
447
+ //#endregion
448
+ //#region lib/syntaxHighlighting.ts
449
+ const additionalMarkdownSyntaxTags = {
450
+ defineNodes: [],
451
+ props: [styleTags({
452
+ HeaderMark: markdownTags.headerMark,
453
+ FencedCode: markdownTags.fencedCode,
454
+ InlineCode: markdownTags.inlineCode,
455
+ URL: markdownTags.linkURL,
456
+ ListMark: markdownTags.listMark
457
+ })]
458
+ };
459
+ const headingTagStyles = (fontSizes) => fontSizes.map((fontSize, i) => ({
460
+ tag: tags[`heading${(i + 1).toString()}`],
461
+ fontSize,
462
+ fontWeight: "bold"
463
+ }));
464
+ const baseSyntaxHighlights = syntaxHighlighting(HighlightStyle.define([
465
+ ...headingTagStyles([
466
+ "1.6em",
467
+ "1.4em",
468
+ "1.2em",
469
+ null,
470
+ null,
471
+ null
472
+ ]),
473
+ {
474
+ tag: markdownTags.headerMark,
475
+ color: "var(--pm-header-mark-color)"
476
+ },
477
+ {
478
+ tag: tags.strong,
479
+ fontWeight: "bold"
480
+ },
481
+ {
482
+ tag: tags.emphasis,
483
+ fontStyle: "italic"
484
+ },
485
+ {
486
+ tag: tags.strikethrough,
487
+ textDecoration: "line-through"
488
+ },
489
+ {
490
+ tag: tags.meta,
491
+ color: "var(--pm-muted-color)"
492
+ },
493
+ {
494
+ tag: tags.comment,
495
+ color: "var(--pm-muted-color)"
496
+ },
497
+ {
498
+ tag: markdownTags.listMark,
499
+ color: "var(--pm-muted-color)"
500
+ },
501
+ {
502
+ tag: markdownTags.escapeMark,
503
+ color: "var(--pm-muted-color)"
504
+ },
505
+ {
506
+ tag: markdownTags.inlineCode,
507
+ fontFamily: "monospace",
508
+ padding: "0.2rem",
509
+ borderRadius: "0.4rem",
510
+ fontSize: "0.8rem",
511
+ backgroundColor: "var(--pm-code-background-color)"
512
+ },
513
+ {
514
+ tag: markdownTags.linkURL,
515
+ color: "var(--pm-link-color)",
516
+ textDecoration: "underline",
517
+ cursor: "pointer"
518
+ }
519
+ ]));
520
+ const baseTheme = EditorView.theme({
521
+ ".cm-content": {
522
+ fontFamily: "var(--font)",
523
+ fontSize: "0.9rem",
524
+ caretColor: "var(--pm-cursor-color)"
525
+ },
526
+ ".cm-editor .cm-cursor, .cm-editor .cm-dropCursor": { borderLeftColor: "var(--pm-cursor-color)" },
527
+ "&.cm-focused": { outline: "none" },
528
+ ".cm-gutters": {
529
+ backgroundColor: "transparent",
530
+ border: "none"
531
+ },
532
+ ".cm-rendered-link": {
533
+ textDecoration: "underline",
534
+ cursor: "pointer",
535
+ color: "var(--pm-link-color)"
536
+ },
537
+ ".cm-rendered-list-mark": {
538
+ color: "var(--pm-muted-color)",
539
+ margin: "0 0.2em"
540
+ },
541
+ ".cm-blockquote-vertical-line": {
542
+ display: "inline-block",
543
+ width: "4px",
544
+ marginRight: "4px",
545
+ marginLeft: "4px",
546
+ height: "1.4em",
547
+ verticalAlign: "bottom",
548
+ backgroundColor: "var(--pm-blockquote-vertical-line-background-color)"
549
+ }
550
+ });
551
+ const generalSyntaxHighlights = syntaxHighlighting(HighlightStyle.define([
552
+ {
553
+ tag: tags.link,
554
+ color: "var(--pm-syntax-link)"
555
+ },
556
+ {
557
+ tag: tags.keyword,
558
+ color: "var(--pm-syntax-keyword)"
559
+ },
560
+ {
561
+ tag: [
562
+ tags.atom,
563
+ tags.bool,
564
+ tags.url,
565
+ tags.contentSeparator,
566
+ tags.labelName
567
+ ],
568
+ color: "var(--pm-syntax-atom)"
569
+ },
570
+ {
571
+ tag: [tags.literal, tags.inserted],
572
+ color: "var(--pm-syntax-literal)"
573
+ },
574
+ {
575
+ tag: [tags.string, tags.deleted],
576
+ color: "var(--pm-syntax-string)"
577
+ },
578
+ {
579
+ tag: [
580
+ tags.regexp,
581
+ tags.escape,
582
+ tags.special(tags.string)
583
+ ],
584
+ color: "var(--pm-syntax-regexp)"
585
+ },
586
+ {
587
+ tag: tags.definition(tags.variableName),
588
+ color: "var(--pm-syntax-definition-variable)"
589
+ },
590
+ {
591
+ tag: tags.local(tags.variableName),
592
+ color: "var(--pm-syntax-local-variable)"
593
+ },
594
+ {
595
+ tag: [tags.typeName, tags.namespace],
596
+ color: "var(--pm-syntax-type-namespace)"
597
+ },
598
+ {
599
+ tag: tags.className,
600
+ color: "var(--pm-syntax-class-name)"
601
+ },
602
+ {
603
+ tag: [tags.special(tags.variableName), tags.macroName],
604
+ color: "var(--pm-syntax-special-variable-macro)"
605
+ },
606
+ {
607
+ tag: tags.definition(tags.propertyName),
608
+ color: "var(--pm-syntax-definition-property)"
609
+ },
610
+ {
611
+ tag: tags.comment,
612
+ color: "var(--pm-syntax-comment)"
613
+ },
614
+ {
615
+ tag: tags.invalid,
616
+ color: "var(--pm-syntax-invalid)"
617
+ }
618
+ ]));
619
+ const lightTheme = EditorView.theme({ ".cm-content": {
620
+ "--pm-cursor-color": "black",
621
+ "--pm-header-mark-color": "oklch(82.8% 0.111 230.318)",
622
+ "--pm-link-color": "oklch(58.8% 0.158 241.966)",
623
+ "--pm-muted-color": "oklch(37.2% 0.044 257.287)",
624
+ "--pm-code-background-color": "oklch(92.9% 0.013 255.508)",
625
+ "--pm-code-btn-background-color": "oklch(86.9% 0.022 252.894)",
626
+ "--pm-code-btn-hover-background-color": "oklch(70.4% 0.04 256.788)",
627
+ "--pm-blockquote-vertical-line-background-color": "oklch(70.4% 0.04 256.788)",
628
+ "--pm-syntax-link": "oklch(62.75% 0.188 259.38)",
629
+ "--pm-syntax-keyword": "oklch(58.13% 0.248 297.57)",
630
+ "--pm-syntax-atom": "oklch(51.29% 0.219 260.63)",
631
+ "--pm-syntax-literal": "oklch(57.38% 0.111 170.31)",
632
+ "--pm-syntax-string": "oklch(54.86% 0.184 25.53)",
633
+ "--pm-syntax-regexp": "oklch(65.88% 0.184 43.8)",
634
+ "--pm-syntax-definition-variable": "oklch(45.32% 0.171 260.3)",
635
+ "--pm-syntax-local-variable": "oklch(64.13% 0.09 184.42)",
636
+ "--pm-syntax-type-namespace": "oklch(49.1% 0.091 165.52)",
637
+ "--pm-syntax-class-name": "oklch(64.42% 0.11 168.83)",
638
+ "--pm-syntax-special-variable-macro": "oklch(52.58% 0.212 282.71)",
639
+ "--pm-syntax-definition-property": "oklch(42.1% 0.142 260.08)",
640
+ "--pm-syntax-comment": "oklch(62.79% 0.022 252.89)",
641
+ "--pm-syntax-invalid": "oklch(64.62% 0.203 29.2)"
642
+ } });
643
+
644
+ //#endregion
645
+ //#region lib/clickLink.ts
646
+ function getUrlFromLink(view, pos) {
647
+ const tree = syntaxTree(view.state);
648
+ let url;
649
+ tree.iterate({
650
+ to: pos,
651
+ from: pos,
652
+ enter(node) {
653
+ if (node.name !== "Link") return;
654
+ iterChildren(node.node.cursor(), (cursor) => {
655
+ if (cursor.name === "URL") {
656
+ url = view.state.doc.sliceString(cursor.from, cursor.to);
657
+ return true;
658
+ }
659
+ });
660
+ return true;
661
+ }
662
+ });
663
+ return url;
664
+ }
665
+ const clickLinkHandler = Facet.define();
666
+ const defaultClickLinkHandler = clickLinkHandler.of((url) => {
667
+ window.open(url, "_blank");
668
+ });
669
+ const clickFullLinkExtension = EditorView$1.domEventHandlers(eventHandlersWithClass({ mousedown: { "cm-rendered-link": (e, view) => {
670
+ const pos = view.posAtCoords(e);
671
+ if (pos === null) return;
672
+ const url = getUrlFromLink(view, pos);
673
+ if (!url) return;
674
+ view.state.facet(clickLinkHandler).map((handler) => {
675
+ handler(url);
676
+ });
677
+ } } }));
678
+ const getRawUrl = (view, pos) => {
679
+ const tree = syntaxTree(view.state);
680
+ let url;
681
+ tree.iterate({
682
+ to: pos,
683
+ from: pos,
684
+ enter(node) {
685
+ if (node.name !== "URL") return;
686
+ if (node.node.parent?.name === "Link") return;
687
+ url = view.state.doc.sliceString(node.from, node.to);
688
+ return true;
689
+ }
690
+ });
691
+ return url;
692
+ };
693
+ const addClassToUrl = syntaxHighlighting(HighlightStyle.define([{
694
+ tag: markdownTags.linkURL,
695
+ class: "cm-url"
696
+ }]));
697
+ const clickRawUrlExtension = EditorView$1.domEventHandlers(eventHandlersWithClass({ mousedown: { "cm-url": (e, view) => {
698
+ const pos = view.posAtCoords(e);
699
+ if (pos === null) return;
700
+ const url = getRawUrl(view, pos);
701
+ if (!url) return;
702
+ view.state.facet(clickLinkHandler).map((handler) => {
703
+ handler(url);
704
+ });
705
+ } } }));
706
+ const clickLinkExtension = [
707
+ clickFullLinkExtension,
708
+ addClassToUrl,
709
+ clickRawUrlExtension
710
+ ];
711
+
712
+ //#endregion
713
+ //#region lib/codeFenceExtension.ts
714
+ const codeBlockDecorations = (view) => {
715
+ const builder = new RangeSetBuilder();
716
+ const visited = /* @__PURE__ */ new Set();
717
+ for (const { from, to } of view.visibleRanges) syntaxTree(view.state).iterate({
718
+ from,
719
+ to,
720
+ enter: (node) => {
721
+ if (node.name === "FencedCode") {
722
+ const key = JSON.stringify([node.from, node.to]);
723
+ if (visited.has(key)) return;
724
+ visited.add(key);
725
+ let lang = "";
726
+ const codeInfoNode = node.node.getChild("CodeInfo");
727
+ if (codeInfoNode) lang = view.state.doc.sliceString(codeInfoNode.from, codeInfoNode.to).toUpperCase();
728
+ for (let pos = node.from; pos <= node.to;) {
729
+ const line = view.state.doc.lineAt(pos);
730
+ const isFirstLine = pos === node.from;
731
+ const isLastLine = line.to >= node.to;
732
+ builder.add(line.from, line.from, Decoration.line({ class: `cm-fenced-code-line ${isFirstLine ? "cm-fenced-code-line-first" : ""} ${isLastLine ? "cm-fenced-code-line-last" : ""}` }));
733
+ if (isFirstLine) builder.add(line.from, line.from, Decoration.widget({ widget: new CodeBlockInfoWidget(lang, view.state.doc.sliceString(line.to + 1, node.to - 4)) }));
734
+ pos = line.to + 1;
735
+ }
736
+ }
737
+ }
738
+ });
739
+ return builder.finish();
740
+ };
741
+ var CodeBlockInfoWidget = class extends WidgetType {
742
+ constructor(lang, code) {
743
+ super();
744
+ this.lang = lang;
745
+ this.code = code;
746
+ }
747
+ eq(other) {
748
+ return other.lang === this.lang && other.code === this.code;
749
+ }
750
+ toDOM() {
751
+ const container = document.createElement("div");
752
+ container.className = "cm-code-block-info";
753
+ const langContainer = document.createElement("span");
754
+ langContainer.className = "cm-code-block-lang-container";
755
+ langContainer.innerText = this.lang;
756
+ container.appendChild(langContainer);
757
+ const copyButton = document.createElement("button");
758
+ copyButton.className = "cm-code-block-copy-button";
759
+ copyButton.innerHTML = `
760
+ <svg xmlns="http://www.w3.org/2000/svg"
761
+ width="16" height="16" viewBox="0 0 24 24"
762
+ fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
763
+ class="lucide lucide-copy-icon lucide-copy">
764
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
765
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>
766
+ </svg>`;
767
+ copyButton.onclick = () => {
768
+ navigator.clipboard.writeText(this.code);
769
+ };
770
+ container.appendChild(copyButton);
771
+ return container;
772
+ }
773
+ };
774
+ const codeBlockDecorationsExtension = ViewPlugin.fromClass(class {
775
+ decorations;
776
+ constructor(view) {
777
+ this.decorations = codeBlockDecorations(view);
778
+ }
779
+ update(update) {
780
+ if (update.docChanged || update.viewportChanged) this.decorations = codeBlockDecorations(update.view);
781
+ }
782
+ }, { decorations: (v) => v.decorations });
783
+ const codeFenceTheme = EditorView.theme({
784
+ ".cm-fenced-code-line": {
785
+ display: "block",
786
+ marginLeft: "6px",
787
+ backgroundColor: "var(--pm-code-background-color)"
788
+ },
789
+ ".cm-activeLine.cm-fenced-code-line": { backgroundColor: "var(--pm-code-background-color)" },
790
+ ".cm-fenced-code-line-first": {
791
+ borderTopLeftRadius: "0.4rem",
792
+ borderTopRightRadius: "0.4rem"
793
+ },
794
+ ".cm-fenced-code-line-last": {
795
+ borderBottomLeftRadius: "0.4rem",
796
+ borderBottomRightRadius: "0.4rem"
797
+ },
798
+ ".cm-code-block-info": {
799
+ float: "right",
800
+ padding: "0.2rem",
801
+ display: "flex",
802
+ gap: "0.3rem",
803
+ alignItems: "center"
804
+ },
805
+ ".cm-code-block-lang-container": {
806
+ fontSize: "0.8rem",
807
+ color: "var(--pm-muted-color)"
808
+ },
809
+ ".cm-code-block-copy-button": {
810
+ display: "flex",
811
+ alignItems: "center",
812
+ justifyContent: "center",
813
+ border: "none",
814
+ padding: "0.2rem",
815
+ borderRadius: "0.2rem",
816
+ cursor: "pointer",
817
+ backgroundColor: "var(--pm-code-btn-background-color)",
818
+ color: "var(--pm-muted-color)"
819
+ },
820
+ ".cm-code-block-copy-button:hover": { backgroundColor: "var(--pm-code-btn-hover-background-color)" },
821
+ ".cm-code-block-copy-button svg": {
822
+ width: "16px",
823
+ height: "16px"
824
+ }
825
+ });
826
+
827
+ //#endregion
828
+ //#region lib/basicSetup.ts
829
+ const prosemarkMarkdownSyntaxExtensions = [
830
+ additionalMarkdownSyntaxTags,
831
+ escapeMarkdownSyntaxExtension,
832
+ emojiMarkdownSyntaxExtension
833
+ ];
834
+ const defaultFoldableSyntaxExtensions = [
835
+ blockQuoteExtension,
836
+ bulletListExtension,
837
+ taskExtension,
838
+ imageExtension,
839
+ emojiExtension,
840
+ horizonalRuleExtension
841
+ ];
842
+ const prosemarkBasicSetup = () => [
843
+ history(),
844
+ dropCursor(),
845
+ indentOnInput(),
846
+ bracketMatching(),
847
+ closeBrackets(),
848
+ autocompletion(),
849
+ keymap.of([
850
+ ...closeBracketsKeymap,
851
+ ...defaultKeymap,
852
+ ...searchKeymap,
853
+ ...historyKeymap,
854
+ ...foldKeymap,
855
+ ...completionKeymap,
856
+ ...lintKeymap,
857
+ indentWithTab
858
+ ]),
859
+ foldGutter(),
860
+ EditorView.lineWrapping,
861
+ defaultHideExtensions,
862
+ defaultFoldableSyntaxExtensions,
863
+ clickLinkExtension,
864
+ codeBlockDecorationsExtension
865
+ ];
866
+ const prosemarkBaseThemeSetup = () => [
867
+ baseSyntaxHighlights,
868
+ generalSyntaxHighlights,
869
+ baseTheme,
870
+ codeFenceTheme
871
+ ];
872
+ const prosemarkLightThemeSetup = () => lightTheme;
873
+
874
+ //#endregion
875
+ export { additionalMarkdownSyntaxTags, baseSyntaxHighlights, baseTheme, blockQuoteExtension, bulletListExtension, clickLinkExtension, clickLinkHandler, codeBlockDecorationsExtension, codeFenceTheme, defaultClickLinkHandler, defaultFoldableSyntaxExtensions, defaultHideExtensions, emojiExtension, emojiMarkdownSyntaxExtension, escapeMarkdownSyntaxExtension, eventHandlersWithClass, foldDecorationExtension, foldableSyntaxFacet, generalSyntaxHighlights, horizonalRuleExtension, imageExtension, lightTheme, markdownTags, prosemarkBaseThemeSetup, prosemarkBasicSetup, prosemarkLightThemeSetup, prosemarkMarkdownSyntaxExtensions, selectAllDecorationsOnSelectExtension, taskExtension };