@kungal/editor-core 0.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.
@@ -0,0 +1,1062 @@
1
+ 'use strict';
2
+
3
+ var commonmark = require('@milkdown/kit/preset/commonmark');
4
+ var gfm = require('@milkdown/kit/preset/gfm');
5
+ var history = require('@milkdown/kit/plugin/history');
6
+ var listener = require('@milkdown/kit/plugin/listener');
7
+ var clipboard = require('@milkdown/kit/plugin/clipboard');
8
+ var indent = require('@milkdown/kit/plugin/indent');
9
+ var trailing = require('@milkdown/kit/plugin/trailing');
10
+ var exception = require('@milkdown/kit/exception');
11
+ var inputrules = require('@milkdown/kit/prose/inputrules');
12
+ var utils = require('@milkdown/kit/utils');
13
+ var unistUtilVisit = require('unist-util-visit');
14
+ var core = require('@milkdown/kit/core');
15
+ var prose = require('@milkdown/kit/prose');
16
+ var state = require('@milkdown/kit/prose/state');
17
+ var katex = require('katex');
18
+ var remarkMath = require('remark-math');
19
+ var codeBlock = require('@milkdown/kit/component/code-block');
20
+ var commands = require('@codemirror/commands');
21
+ var view = require('@codemirror/view');
22
+ var languageData = require('@codemirror/language-data');
23
+ var codemirror = require('codemirror');
24
+ var language = require('@codemirror/language');
25
+ var highlight = require('@lezer/highlight');
26
+ var upload = require('@milkdown/kit/plugin/upload');
27
+ var view$1 = require('@milkdown/kit/prose/view');
28
+
29
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
30
+
31
+ var katex__default = /*#__PURE__*/_interopDefault(katex);
32
+ var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
33
+
34
+ // src/preset/index.ts
35
+ var spoilerAttr = utils.$nodeAttr("kun-spoiler", () => ({
36
+ container: {
37
+ class: "kun-spoiler",
38
+ style: "background: var(--color-default-500); border-radius: var(--radius-sm); padding: 0 4px; cursor: pointer;"
39
+ }
40
+ }));
41
+ var spoilerSchema = utils.$nodeSchema("kun-spoiler", (ctx) => ({
42
+ group: "inline",
43
+ inline: true,
44
+ content: "inline*",
45
+ marks: "",
46
+ attrs: {
47
+ revealed: {
48
+ default: false
49
+ }
50
+ },
51
+ parseDOM: [
52
+ {
53
+ tag: 'span[data-type="kun-spoiler"]',
54
+ getAttrs: (dom) => {
55
+ if (!(dom instanceof HTMLElement)) throw exception.expectDomTypeError(dom);
56
+ return {
57
+ revealed: dom.getAttribute("data-revealed") === "true"
58
+ };
59
+ }
60
+ }
61
+ ],
62
+ toDOM: (node) => {
63
+ const attrs = ctx.get(spoilerAttr.key)(node);
64
+ return [
65
+ "span",
66
+ {
67
+ ...attrs.container,
68
+ "data-type": "kun-spoiler",
69
+ "data-revealed": node.attrs.revealed
70
+ },
71
+ 0
72
+ ];
73
+ },
74
+ parseMarkdown: {
75
+ match: ({ type }) => type === "kun-spoiler",
76
+ runner: (state, node, type) => {
77
+ state.openNode(type);
78
+ state.next(node.children || []);
79
+ state.closeNode();
80
+ }
81
+ },
82
+ toMarkdown: {
83
+ match: (node) => node.type.name === "kun-spoiler",
84
+ runner: (state, node) => {
85
+ state.addNode("text", void 0, "||");
86
+ state.next(node.content);
87
+ state.addNode("text", void 0, "||");
88
+ }
89
+ }
90
+ }));
91
+ var insertKunSpoilerCommand = utils.$command(
92
+ "InsertKunSpoiler",
93
+ (ctx) => () => (state, dispatch) => {
94
+ if (!dispatch) {
95
+ return true;
96
+ }
97
+ const node = spoilerSchema.type(ctx).create();
98
+ if (!node) {
99
+ return true;
100
+ }
101
+ dispatch(state.tr.replaceSelectionWith(node).scrollIntoView());
102
+ return true;
103
+ }
104
+ );
105
+ var insertSpoilerInputRule = utils.$inputRule(
106
+ () => new inputrules.InputRule(/(?:^|\s)\|\|(.*?)\|\|$/, (state, match, start, end) => {
107
+ const [fullMatch, content] = match;
108
+ if (!content) return null;
109
+ const startPos = start + (fullMatch.startsWith(" ") ? 1 : 0);
110
+ const { tr } = state;
111
+ const schema = state.schema;
112
+ const spoilerNodeType = schema.nodes["kun-spoiler"];
113
+ if (!spoilerNodeType) return null;
114
+ const spoilerNode = spoilerNodeType.create(
115
+ { revealed: false },
116
+ schema.text(content)
117
+ );
118
+ const zeroWidthSpace = schema.text("\u200B");
119
+ return tr.replaceWith(startPos, end, [spoilerNode, zeroWidthSpace]).setStoredMarks([]).scrollIntoView();
120
+ })
121
+ );
122
+ var remarkSpoilerPlugin = utils.$remark("remarkSpoiler", () => () => {
123
+ const transformer = (tree) => {
124
+ unistUtilVisit.visit(tree, "text", (node, index, parent) => {
125
+ if (typeof node.value !== "string" || !parent) {
126
+ return;
127
+ }
128
+ if (!node.value.includes("||")) {
129
+ return;
130
+ }
131
+ const regex = /\|\|(.*?)\|\|/g;
132
+ const newNodes = [];
133
+ let lastIndex = 0;
134
+ for (const match of node.value.matchAll(regex)) {
135
+ const [full, content] = match;
136
+ const matchIndex = match.index ?? 0;
137
+ if (matchIndex > lastIndex) {
138
+ newNodes.push({
139
+ type: "text",
140
+ value: node.value.slice(lastIndex, matchIndex)
141
+ });
142
+ }
143
+ if (content) {
144
+ newNodes.push({
145
+ type: "kun-spoiler",
146
+ children: [{ type: "text", value: content }]
147
+ });
148
+ }
149
+ lastIndex = matchIndex + full.length;
150
+ }
151
+ if (lastIndex < node.value.length) {
152
+ newNodes.push({ type: "text", value: node.value.slice(lastIndex) });
153
+ }
154
+ if (newNodes.length > 0 && typeof index === "number") {
155
+ parent.children?.splice(index, 1, ...newNodes);
156
+ }
157
+ });
158
+ };
159
+ return transformer;
160
+ });
161
+ var createSpoilerPlugin = () => [
162
+ spoilerAttr,
163
+ spoilerSchema,
164
+ insertSpoilerInputRule,
165
+ insertKunSpoilerCommand,
166
+ remarkSpoilerPlugin
167
+ ].flat();
168
+ var hasMark = (state, type) => {
169
+ if (!type) {
170
+ return false;
171
+ }
172
+ const { from, $from, to, empty } = state.selection;
173
+ if (empty) {
174
+ return !!type.isInSet(state.storedMarks || $from.marks());
175
+ }
176
+ return state.doc.rangeHasMark(from, to, type);
177
+ };
178
+ var stopLinkCommand = utils.$command("StopLink", (ctx) => () => {
179
+ return (state, dispatch) => {
180
+ const markType = commonmark.linkSchema.type(ctx);
181
+ const checkMark = hasMark(state, markType);
182
+ if (checkMark) {
183
+ dispatch?.(state.tr.removeStoredMark(markType));
184
+ }
185
+ return false;
186
+ };
187
+ });
188
+ var linkCustomKeymap = utils.$useKeymap("linkCustomKeymap", {
189
+ StopLink: {
190
+ shortcuts: ["Space"],
191
+ command: (ctx) => {
192
+ const commands = ctx.get(core.commandsCtx);
193
+ return () => commands.call(stopLinkCommand.key);
194
+ }
195
+ }
196
+ });
197
+ var createStopLinkPlugin = () => [stopLinkCommand, linkCustomKeymap].flat();
198
+ var blockKatexSchema = commonmark.codeBlockSchema.extendSchema((prev) => {
199
+ return (ctx) => {
200
+ const baseSchema = prev(ctx);
201
+ return {
202
+ ...baseSchema,
203
+ toMarkdown: {
204
+ match: baseSchema.toMarkdown.match,
205
+ runner: (state, node) => {
206
+ const language = node.attrs.language ?? "";
207
+ if (language.toLowerCase() === "latex") {
208
+ state.addNode(
209
+ "math",
210
+ void 0,
211
+ node.content.firstChild?.text || ""
212
+ );
213
+ } else {
214
+ return baseSchema.toMarkdown.runner(state, node);
215
+ }
216
+ }
217
+ }
218
+ };
219
+ };
220
+ });
221
+ var mathInlineId = "math_inline";
222
+ var mathInlineSchema = utils.$nodeSchema(mathInlineId, () => ({
223
+ group: "inline",
224
+ inline: true,
225
+ draggable: true,
226
+ atom: true,
227
+ attrs: {
228
+ value: {
229
+ default: ""
230
+ }
231
+ },
232
+ parseDOM: [
233
+ {
234
+ tag: `span[data-type="${mathInlineId}"]`,
235
+ getAttrs: (dom) => {
236
+ return {
237
+ value: dom.dataset.value ?? ""
238
+ };
239
+ }
240
+ }
241
+ ],
242
+ toDOM: (node) => {
243
+ const code = node.attrs.value;
244
+ const dom = document.createElement("span");
245
+ dom.dataset.type = mathInlineId;
246
+ dom.dataset.value = code;
247
+ katex__default.default.render(code, dom, {
248
+ throwOnError: false
249
+ });
250
+ return dom;
251
+ },
252
+ parseMarkdown: {
253
+ match: (node) => node.type === "inlineMath",
254
+ runner: (state, node, type) => {
255
+ state.addNode(type, { value: node.value });
256
+ }
257
+ },
258
+ toMarkdown: {
259
+ match: (node) => node.type.name === mathInlineId,
260
+ runner: (state, node) => {
261
+ state.addNode("inlineMath", void 0, node.attrs.value);
262
+ }
263
+ }
264
+ }));
265
+
266
+ // src/plugins/katex/command.ts
267
+ var toggleLatexCommand = utils.$command("ToggleLatex", (ctx) => {
268
+ return () => (state$1, dispatch) => {
269
+ const {
270
+ hasNode: hasLatex,
271
+ pos: latexPos,
272
+ target: latexNode
273
+ } = prose.findNodeInSelection(state$1, mathInlineSchema.type(ctx));
274
+ const { selection, doc, tr } = state$1;
275
+ if (!hasLatex) {
276
+ const text = doc.textBetween(selection.from, selection.to);
277
+ const _tr2 = tr.replaceSelectionWith(
278
+ mathInlineSchema.type(ctx).create({
279
+ value: text
280
+ })
281
+ );
282
+ if (dispatch) {
283
+ dispatch(
284
+ _tr2.setSelection(state.NodeSelection.create(_tr2.doc, selection.from))
285
+ );
286
+ }
287
+ return true;
288
+ }
289
+ const { from, to } = selection;
290
+ if (!latexNode || latexPos < 0) return false;
291
+ let _tr = tr.delete(latexPos, latexPos + 1);
292
+ const content = latexNode.attrs.value;
293
+ _tr = _tr.insertText(content, latexPos);
294
+ if (dispatch) {
295
+ dispatch(
296
+ _tr.setSelection(
297
+ state.TextSelection.create(_tr.doc, from, to + content.length - 1)
298
+ )
299
+ );
300
+ }
301
+ return true;
302
+ };
303
+ });
304
+ var mathInlineInputRule = utils.$inputRule(
305
+ (ctx) => prose.nodeRule(/(?:\$)([^$]+)(?:\$)$/, mathInlineSchema.type(ctx), {
306
+ getAttr: (match) => ({ value: match[1] ?? "" }),
307
+ beforeDispatch: ({ tr, start }) => {
308
+ const posAfter = start + 1;
309
+ tr.insertText("\u200B", posAfter, posAfter);
310
+ tr.setSelection(state.TextSelection.create(tr.doc, posAfter + 1));
311
+ }
312
+ })
313
+ );
314
+ var mathBlockInputRule = utils.$inputRule(
315
+ (ctx) => inputrules.textblockTypeInputRule(/^\$\$[\s\n]$/, commonmark.codeBlockSchema.type(ctx), () => ({
316
+ language: "LaTeX"
317
+ }))
318
+ );
319
+ var remarkMathPlugin = utils.$remark(
320
+ "remarkMath",
321
+ () => remarkMath__default.default
322
+ );
323
+ var visitMathBlock = (ast) => {
324
+ return unistUtilVisit.visit(
325
+ ast,
326
+ "math",
327
+ (node, index, parent) => {
328
+ const { value } = node;
329
+ const newNode = {
330
+ type: "code",
331
+ lang: "LaTeX",
332
+ value
333
+ };
334
+ parent.children.splice(index, 1, newNode);
335
+ }
336
+ );
337
+ };
338
+ var remarkMathBlockPlugin = utils.$remark(
339
+ "remarkMathBlock",
340
+ () => () => visitMathBlock
341
+ );
342
+
343
+ // src/plugins/katex/index.ts
344
+ var createKatexPlugins = () => [
345
+ remarkMathPlugin,
346
+ remarkMathBlockPlugin,
347
+ mathInlineSchema,
348
+ mathInlineInputRule,
349
+ mathBlockInputRule,
350
+ blockKatexSchema,
351
+ toggleLatexCommand
352
+ ].flat();
353
+ var colors = {
354
+ primary: "var(--color-primary)",
355
+ selected: "color-mix(in oklab,var(--color-primary)10%,transparent)",
356
+ primaryLight: "var(--color-primary-400)",
357
+ secondary: "var(--color-secondary)",
358
+ success: "var(--color-success)",
359
+ warning: "var(--color-warning)",
360
+ warningLight: "var(--color-warning-400)",
361
+ danger: "var(--color-danger)",
362
+ foreground: "var(--color-foreground)",
363
+ background: "var(--color-background)",
364
+ backgroundAlpha: "var(--color-background) / 0.7",
365
+ overlayLight: "var(--color-default-100)",
366
+ divider: "var(--color-default-100)",
367
+ content1: "var(--color-content1)",
368
+ content2: "var(--color-content2)",
369
+ content3: "var(--color-content3)"};
370
+ var kunCMTheme = () => {
371
+ return view.EditorView.theme({
372
+ "&": {
373
+ backgroundColor: colors.backgroundAlpha,
374
+ borderRadius: "0.75rem",
375
+ lineHeight: "1.5",
376
+ scrollbarWidth: "none",
377
+ minHeight: "300px"
378
+ },
379
+ "&.cm-focused": {
380
+ outline: "none"
381
+ },
382
+ ".cm-scroller": {
383
+ lineHeight: "1.5",
384
+ maxWidth: "100%",
385
+ scrollbarWidth: "none"
386
+ },
387
+ ".cm-content": {
388
+ padding: "1rem 0.5rem",
389
+ maxWidth: "100%"
390
+ },
391
+ ".cm-line": {
392
+ padding: "0.2rem 0",
393
+ borderRadius: "0.375rem",
394
+ maxWidth: "100%",
395
+ fontSize: "1rem",
396
+ "&:hover": {
397
+ backgroundColor: colors.overlayLight
398
+ }
399
+ },
400
+ "&.cm-focused .cm-cursor": {
401
+ borderLeftColor: colors.primary,
402
+ borderLeftWidth: "2px"
403
+ },
404
+ ".cm-panels": {
405
+ backgroundColor: colors.background,
406
+ color: colors.foreground,
407
+ borderRadius: "0.5rem",
408
+ margin: "0.5rem"
409
+ },
410
+ ".cm-panels.cm-panels-top": {
411
+ borderBottom: `1px solid ${colors.divider}`
412
+ },
413
+ ".cm-panels.cm-panels-bottom": {
414
+ borderTop: `1px solid ${colors.divider}`
415
+ },
416
+ ".cm-searchMatch": {
417
+ backgroundColor: `${colors.primaryLight}50`,
418
+ outline: `1px solid ${colors.primaryLight}`,
419
+ borderRadius: "2px"
420
+ },
421
+ ".cm-searchMatch.cm-searchMatch-selected": {
422
+ backgroundColor: `${colors.primary}40`
423
+ },
424
+ ".cm-activeLine": {
425
+ backgroundColor: `${colors.content1}30`,
426
+ borderRadius: "0.375rem"
427
+ },
428
+ ".cm-selectionMatch": {
429
+ backgroundColor: `${colors.primary}20`,
430
+ borderRadius: "2px"
431
+ },
432
+ ".cm-matchingBracket, .cm-nonmatchingBracket": {
433
+ backgroundColor: `${colors.warning}30`,
434
+ outline: "none",
435
+ borderRadius: "2px",
436
+ padding: "0 1px",
437
+ fontWeight: "600"
438
+ },
439
+ ".cm-gutters": {
440
+ backgroundColor: "transparent",
441
+ border: "none",
442
+ borderRadius: "0",
443
+ fontSize: "1rem",
444
+ padding: "0"
445
+ },
446
+ ".cm-lineNumbers": {
447
+ color: colors.content3
448
+ },
449
+ "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": {
450
+ backgroundColor: colors.selected
451
+ },
452
+ ".cm-activeLineGutter": {
453
+ backgroundColor: colors.selected
454
+ },
455
+ ".cm-foldGutter": {
456
+ color: colors.content3
457
+ },
458
+ ".cm-tooltip": {
459
+ backgroundColor: colors.background,
460
+ border: `1px solid ${colors.divider}`,
461
+ borderRadius: "0.5rem",
462
+ boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
463
+ overflow: "hidden"
464
+ },
465
+ ".cm-tooltip-autocomplete": {
466
+ "& > ul": {
467
+ fontSize: "0.9rem",
468
+ maxHeight: "20rem"
469
+ },
470
+ "& > ul > li": {
471
+ padding: "0.375rem 0.75rem",
472
+ borderRadius: "0.25rem"
473
+ },
474
+ "& > ul > li[aria-selected]": {
475
+ backgroundColor: colors.content1,
476
+ color: colors.foreground
477
+ }
478
+ },
479
+ "&::-webkit-scrollbar": {
480
+ width: "6px",
481
+ height: "6px"
482
+ },
483
+ "&::-webkit-scrollbar-track": {
484
+ background: "transparent"
485
+ },
486
+ "&::-webkit-scrollbar-thumb": {
487
+ backgroundColor: colors.content3,
488
+ borderRadius: "3px",
489
+ "&:hover": {
490
+ backgroundColor: colors.content2
491
+ }
492
+ }
493
+ });
494
+ };
495
+ var kunCMHighlightStyle = () => language.HighlightStyle.define([
496
+ // Keywords and control flow
497
+ { tag: highlight.tags.keyword, color: colors.primary, fontWeight: "600" },
498
+ { tag: highlight.tags.controlKeyword, color: colors.primary, fontWeight: "600" },
499
+ { tag: highlight.tags.moduleKeyword, color: colors.primary, fontWeight: "600" },
500
+ // Variables and properties
501
+ { tag: [highlight.tags.propertyName, highlight.tags.macroName], color: colors.secondary },
502
+ { tag: highlight.tags.variableName, color: colors.foreground },
503
+ {
504
+ tag: highlight.tags.definition(highlight.tags.variableName),
505
+ color: colors.secondary,
506
+ fontWeight: "600"
507
+ },
508
+ // Functions
509
+ {
510
+ tag: [highlight.tags.function(highlight.tags.variableName), highlight.tags.labelName],
511
+ color: colors.success,
512
+ fontWeight: "500"
513
+ },
514
+ {
515
+ tag: highlight.tags.definition(highlight.tags.function(highlight.tags.variableName)),
516
+ color: colors.success,
517
+ fontWeight: "600"
518
+ },
519
+ // Types and classes
520
+ {
521
+ tag: [highlight.tags.typeName, highlight.tags.className, highlight.tags.namespace],
522
+ color: colors.warning,
523
+ fontWeight: "500"
524
+ },
525
+ { tag: [highlight.tags.annotation, highlight.tags.modifier], color: colors.warningLight },
526
+ // Constants and literals
527
+ {
528
+ tag: [highlight.tags.number, highlight.tags.bool, highlight.tags.null],
529
+ color: colors.secondary,
530
+ fontWeight: "500"
531
+ },
532
+ { tag: highlight.tags.string, color: colors.success },
533
+ { tag: highlight.tags.regexp, color: colors.warning },
534
+ // Special syntax
535
+ { tag: [highlight.tags.meta, highlight.tags.comment], color: colors.foreground, fontStyle: "italic" },
536
+ { tag: highlight.tags.tagName, color: colors.primary, fontWeight: "500" },
537
+ { tag: highlight.tags.attributeName, color: colors.warning },
538
+ // Markdown specific
539
+ { tag: highlight.tags.heading, color: colors.primary, fontWeight: "700" },
540
+ {
541
+ tag: [highlight.tags.url, highlight.tags.link],
542
+ color: colors.success,
543
+ textDecoration: "underline"
544
+ },
545
+ { tag: highlight.tags.emphasis, fontStyle: "italic" },
546
+ { tag: highlight.tags.strong, fontWeight: "700" },
547
+ // Special cases
548
+ {
549
+ tag: highlight.tags.invalid,
550
+ color: colors.danger,
551
+ borderBottom: `2px dotted ${colors.danger}`
552
+ },
553
+ { tag: highlight.tags.changed, color: colors.warning },
554
+ { tag: highlight.tags.inserted, color: colors.success },
555
+ { tag: highlight.tags.deleted, color: colors.danger }
556
+ ]);
557
+ var kunCM = () => [
558
+ kunCMTheme(),
559
+ language.syntaxHighlighting(kunCMHighlightStyle())
560
+ ];
561
+
562
+ // src/plugins/code-block/icons.ts
563
+ var chevronDownIcon = `
564
+ <svg
565
+ xmlns="http://www.w3.org/2000/svg"
566
+ fill="none"
567
+ viewBox="0 0 24 24"
568
+ stroke-width="1.5"
569
+ stroke="currentColor"
570
+ class="w-6 h-6"
571
+ >
572
+ <path
573
+ stroke-linecap="round"
574
+ stroke-linejoin="round"
575
+ d="M19.5 8.25l-7.5 7.5-7.5-7.5"
576
+ />
577
+ </svg>
578
+ `;
579
+ var clearIcon = `
580
+ <svg
581
+ xmlns="http://www.w3.org/2000/svg"
582
+ width="24"
583
+ height="24"
584
+ viewBox="0 0 24 24"
585
+ >
586
+ <g clip-path="url(#clip0_1098_15553)">
587
+ <path
588
+ d="M18.3007 5.70973C17.9107 5.31973 17.2807 5.31973 16.8907 5.70973L12.0007 10.5897L7.1107 5.69973C6.7207 5.30973 6.0907 5.30973 5.7007 5.69973C5.3107 6.08973 5.3107 6.71973 5.7007 7.10973L10.5907 11.9997L5.7007 16.8897C5.3107 17.2797 5.3107 17.9097 5.7007 18.2997C6.0907 18.6897 6.7207 18.6897 7.1107 18.2997L12.0007 13.4097L16.8907 18.2997C17.2807 18.6897 17.9107 18.6897 18.3007 18.2997C18.6907 17.9097 18.6907 17.2797 18.3007 16.8897L13.4107 11.9997L18.3007 7.10973C18.6807 6.72973 18.6807 6.08973 18.3007 5.70973Z"
589
+ />
590
+ </g>
591
+ <defs>
592
+ <clipPath id="clip0_1098_15553">
593
+ <rect width="24" height="24" />
594
+ </clipPath>
595
+ </defs>
596
+ </svg>
597
+ `;
598
+ var copyIcon = `
599
+ <svg
600
+ xmlns="http://www.w3.org/2000/svg"
601
+ height="24px"
602
+ viewBox="0 -960 960 960"
603
+ width="24px"
604
+ fill="none"
605
+ >
606
+ <path
607
+ d="M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z"
608
+ />
609
+ </svg>
610
+ `;
611
+ var editIcon = `
612
+ <svg
613
+ xmlns="http://www.w3.org/2000/svg"
614
+ width="24"
615
+ height="24"
616
+ viewBox="0 0 24 24"
617
+ >
618
+ <g clip-path="url(#clip0_1013_1585)">
619
+ <path
620
+ d="M14.06 9.02L14.98 9.94L5.92 19H5V18.08L14.06 9.02ZM17.66 3C17.41 3 17.15 3.1 16.96 3.29L15.13 5.12L18.88 8.87L20.71 7.04C21.1 6.65 21.1 6.02 20.71 5.63L18.37 3.29C18.17 3.09 17.92 3 17.66 3ZM14.06 6.19L3 17.25V21H6.75L17.81 9.94L14.06 6.19Z"
621
+ />
622
+ </g>
623
+ <defs>
624
+ <clipPath id="clip0_1013_1585">
625
+ <rect width="24" height="24" />
626
+ </clipPath>
627
+ </defs>
628
+ </svg>
629
+ `;
630
+ var searchIcon = `
631
+ <svg
632
+ xmlns="http://www.w3.org/2000/svg"
633
+ fill="none"
634
+ viewBox="0 0 24 24"
635
+ stroke-width="1.5"
636
+ stroke="currentColor"
637
+ class="w-6 h-6"
638
+ >
639
+ <path
640
+ stroke-linecap="round"
641
+ stroke-linejoin="round"
642
+ d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
643
+ />
644
+ </svg>
645
+ `;
646
+ var visibilityOffIcon = `
647
+ <svg
648
+ xmlns="http://www.w3.org/2000/svg"
649
+ height="24px"
650
+ viewBox="0 -960 960 960"
651
+ width="24px"
652
+ >
653
+ <path
654
+ d="m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z"
655
+ />
656
+ </svg>
657
+ `;
658
+
659
+ // src/plugins/code-block/index.ts
660
+ var LABELS = {
661
+ "zh-cn": {
662
+ searchPlaceholder: "\u641C\u7D22\u5492\u6587",
663
+ copyText: "\u590D\u5236\u5492\u6587",
664
+ noResultText: "\u65E0\u7ED3\u679C",
665
+ previewLoading: "\u52A0\u8F7D\u4E2D...",
666
+ edit: "\u7F16\u8F91",
667
+ hide: "\u9690\u85CF"
668
+ },
669
+ "en-us": {
670
+ searchPlaceholder: "Search language",
671
+ copyText: "Copy",
672
+ noResultText: "No results",
673
+ previewLoading: "Loading...",
674
+ edit: "Edit",
675
+ hide: "Hide"
676
+ }
677
+ };
678
+ var labelsFor = (locale) => locale && locale.toLowerCase().startsWith("en") ? LABELS["en-us"] : LABELS["zh-cn"];
679
+ var applyCodeBlockConfig = (ctx, options = {}) => {
680
+ const labels = labelsFor(options.locale);
681
+ const onCopy = options.onCopy ?? (() => {
682
+ });
683
+ ctx.update(codeBlock.codeBlockConfig.key, (prev) => ({
684
+ ...prev,
685
+ extensions: [
686
+ kunCM(),
687
+ view.EditorView.lineWrapping,
688
+ view.keymap.of(commands.defaultKeymap.concat(commands.indentWithTab)),
689
+ codemirror.basicSetup,
690
+ ...options.extensions ?? []
691
+ ],
692
+ languages: languageData.languages,
693
+ expandIcon: chevronDownIcon,
694
+ searchIcon,
695
+ clearSearchIcon: clearIcon,
696
+ searchPlaceholder: labels.searchPlaceholder,
697
+ copyText: labels.copyText,
698
+ copyIcon,
699
+ onCopy,
700
+ noResultText: labels.noResultText,
701
+ previewLoading: labels.previewLoading,
702
+ // Render `latex` code blocks as rendered math; defer everything else to the
703
+ // component default.
704
+ renderPreview: (language, content, applyPreview) => {
705
+ if (language.toLowerCase() === "latex" && content.length > 0) {
706
+ return katex__default.default.renderToString(content, {
707
+ ...options.katexOptions,
708
+ throwOnError: false,
709
+ displayMode: true
710
+ });
711
+ }
712
+ return prev.renderPreview(language, content, applyPreview);
713
+ },
714
+ previewToggleButton: (previewOnlyMode) => {
715
+ const icon = previewOnlyMode ? editIcon : visibilityOffIcon;
716
+ const text = previewOnlyMode ? labels.edit : labels.hide;
717
+ return [icon, text].map((v) => v.trim()).join(" ");
718
+ }
719
+ }));
720
+ };
721
+ var codeBlockConfigPlugin = (options) => (ctx) => () => {
722
+ applyCodeBlockConfig(ctx, options);
723
+ };
724
+ var createCodeBlockPlugins = (options = {}) => [...codeBlock.codeBlockComponent, codeBlockConfigPlugin(options)];
725
+
726
+ // src/index.ts
727
+ var MENTION_SCHEME = "kungal-user:";
728
+ var QUOTE_SCHEME = "kungal-reply:";
729
+
730
+ // src/plugins/mention/index.ts
731
+ var mentionId = "mention";
732
+ var mentionSchema = utils.$nodeSchema(mentionId, () => ({
733
+ group: "inline",
734
+ inline: true,
735
+ atom: true,
736
+ attrs: {
737
+ userId: { default: 0 },
738
+ name: { default: "" }
739
+ },
740
+ parseDOM: [
741
+ {
742
+ // Pasted rendered content (server emits <a class="kun-mention" data-uid>).
743
+ tag: "a.kun-mention",
744
+ getAttrs: (dom) => {
745
+ const el = dom;
746
+ return {
747
+ userId: Number.parseInt(el.dataset.uid ?? "0", 10) || 0,
748
+ name: (el.textContent ?? "").replace(/^@/, "")
749
+ };
750
+ }
751
+ }
752
+ ],
753
+ toDOM: (node) => {
754
+ const span = document.createElement("span");
755
+ span.className = "kun-mention";
756
+ span.dataset.uid = String(node.attrs.userId);
757
+ span.setAttribute("contenteditable", "false");
758
+ span.textContent = `@${node.attrs.name}`;
759
+ return span;
760
+ },
761
+ parseMarkdown: {
762
+ match: (node) => node.type === mentionId,
763
+ runner: (state, node, type) => {
764
+ const n = node;
765
+ state.addNode(type, { userId: n.userId ?? 0, name: n.name ?? "" });
766
+ }
767
+ },
768
+ toMarkdown: {
769
+ match: (node) => node.type.name === mentionId,
770
+ runner: (state, node) => {
771
+ state.openNode("link", void 0, {
772
+ url: `${MENTION_SCHEME}${node.attrs.userId}`
773
+ });
774
+ state.addNode("text", void 0, `@${node.attrs.name}`);
775
+ state.closeNode();
776
+ }
777
+ }
778
+ }));
779
+ var remarkMentionPlugin = utils.$remark("remarkMention", () => () => {
780
+ const transformer = (tree) => {
781
+ unistUtilVisit.visit(tree, "link", (node, index, parent) => {
782
+ if (typeof node.url !== "string" || !node.url.startsWith(MENTION_SCHEME)) {
783
+ return;
784
+ }
785
+ const userId = Number.parseInt(node.url.slice(MENTION_SCHEME.length), 10);
786
+ if (!Number.isInteger(userId) || userId <= 0) {
787
+ return;
788
+ }
789
+ const first = node.children?.[0];
790
+ const name = (typeof first?.value === "string" ? first.value : "").replace(
791
+ /^@/,
792
+ ""
793
+ );
794
+ if (typeof index === "number" && parent.children) {
795
+ parent.children.splice(index, 1, {
796
+ type: mentionId,
797
+ userId,
798
+ name
799
+ });
800
+ }
801
+ });
802
+ };
803
+ return transformer;
804
+ });
805
+ var insertMentionCommand = utils.$command(
806
+ "InsertKunMention",
807
+ (ctx) => (payload) => (state, dispatch) => {
808
+ if (!payload || !dispatch) {
809
+ return false;
810
+ }
811
+ const { userId, name } = payload;
812
+ if (!Number.isInteger(userId) || userId <= 0) {
813
+ return false;
814
+ }
815
+ const node = mentionSchema.type(ctx).create({ userId, name });
816
+ if (!node) {
817
+ return false;
818
+ }
819
+ const tr = state.tr.replaceSelectionWith(node);
820
+ tr.insertText(" ");
821
+ dispatch(tr.scrollIntoView());
822
+ return true;
823
+ }
824
+ );
825
+ var createMentionPlugin = () => [mentionSchema, remarkMentionPlugin, insertMentionCommand].flat();
826
+ var quoteId = "quote";
827
+ var quoteSchema = utils.$nodeSchema(quoteId, () => ({
828
+ group: "inline",
829
+ inline: true,
830
+ atom: true,
831
+ attrs: {
832
+ refId: { default: "" },
833
+ label: { default: "" }
834
+ },
835
+ parseDOM: [
836
+ {
837
+ // Pasted rendered content (server emits <span class="kun-quote" data-ref-id>).
838
+ tag: "span.kun-quote",
839
+ getAttrs: (dom) => {
840
+ const el = dom;
841
+ return {
842
+ refId: el.dataset.refId ?? "",
843
+ label: el.textContent ?? ""
844
+ };
845
+ }
846
+ }
847
+ ],
848
+ toDOM: (node) => {
849
+ const span = document.createElement("span");
850
+ span.className = "kun-quote";
851
+ span.dataset.refId = String(node.attrs.refId);
852
+ span.setAttribute("contenteditable", "false");
853
+ span.textContent = String(node.attrs.label);
854
+ return span;
855
+ },
856
+ parseMarkdown: {
857
+ match: (node) => node.type === quoteId,
858
+ runner: (state, node, type) => {
859
+ const n = node;
860
+ state.addNode(type, { refId: n.refId ?? "", label: n.label ?? "" });
861
+ }
862
+ },
863
+ toMarkdown: {
864
+ match: (node) => node.type.name === quoteId,
865
+ runner: (state, node) => {
866
+ state.openNode("link", void 0, {
867
+ url: `${QUOTE_SCHEME}${node.attrs.refId}`
868
+ });
869
+ state.addNode("text", void 0, String(node.attrs.label));
870
+ state.closeNode();
871
+ }
872
+ }
873
+ }));
874
+ var remarkQuotePlugin = utils.$remark("remarkQuote", () => () => {
875
+ const transformer = (tree) => {
876
+ unistUtilVisit.visit(tree, "link", (node, index, parent) => {
877
+ if (typeof node.url !== "string" || !node.url.startsWith(QUOTE_SCHEME)) {
878
+ return;
879
+ }
880
+ const refId = node.url.slice(QUOTE_SCHEME.length);
881
+ if (!refId) {
882
+ return;
883
+ }
884
+ const first = node.children?.[0];
885
+ const label = typeof first?.value === "string" ? first.value : "";
886
+ if (typeof index === "number" && parent.children) {
887
+ parent.children.splice(index, 1, {
888
+ type: quoteId,
889
+ refId,
890
+ label
891
+ });
892
+ }
893
+ });
894
+ };
895
+ return transformer;
896
+ });
897
+ var insertQuoteCommand = utils.$command(
898
+ "InsertKunQuote",
899
+ (ctx) => (payload) => (state, dispatch) => {
900
+ if (!payload || !dispatch) {
901
+ return false;
902
+ }
903
+ const { refId, label } = payload;
904
+ if (!refId) {
905
+ return false;
906
+ }
907
+ const node = quoteSchema.type(ctx).create({ refId, label });
908
+ if (!node) {
909
+ return false;
910
+ }
911
+ const tr = state.tr.replaceSelectionWith(node);
912
+ tr.insertText(" ");
913
+ dispatch(tr.scrollIntoView());
914
+ return true;
915
+ }
916
+ );
917
+ var createQuotePlugin = () => [quoteSchema, remarkQuotePlugin, insertQuoteCommand].flat();
918
+ var uploadingLabel = (locale) => locale && locale.toLowerCase().startsWith("en") ? "Uploading\u2026" : "\u6B63\u5728\u4E0A\u4F20\u4E2D...";
919
+ var uploadFailedLabel = (locale) => locale && locale.toLowerCase().startsWith("en") ? "Image upload failed" : "\u56FE\u7247\u4E0A\u4F20\u5931\u8D25";
920
+ var createUploader = (uploadImage, options = {}) => {
921
+ return async (files, schema) => {
922
+ const images = [];
923
+ for (let i = 0; i < files.length; i++) {
924
+ const file = files.item(i);
925
+ if (!file || !file.type.startsWith("image/")) {
926
+ continue;
927
+ }
928
+ images.push(file);
929
+ }
930
+ const nodes = await Promise.all(
931
+ images.map(async (image) => {
932
+ try {
933
+ const src = await uploadImage(image);
934
+ return schema.nodes.image.createAndFill({
935
+ src,
936
+ alt: image.name
937
+ });
938
+ } catch {
939
+ options.notify?.(uploadFailedLabel(options.locale), "error");
940
+ return null;
941
+ }
942
+ })
943
+ );
944
+ return nodes.filter((node) => node !== null);
945
+ };
946
+ };
947
+ var createUploadWidgetFactory = (options = {}) => {
948
+ return (pos, spec) => {
949
+ const widgetDOM = document.createElement("span");
950
+ widgetDOM.textContent = uploadingLabel(options.locale);
951
+ widgetDOM.style.color = "var(--color-primary)";
952
+ return view$1.Decoration.widget(pos, widgetDOM, spec);
953
+ };
954
+ };
955
+ var applyUploadConfig = (ctx, uploadImage, options = {}) => {
956
+ ctx.update(upload.uploadConfig.key, (prev) => ({
957
+ ...prev,
958
+ uploader: createUploader(uploadImage, options),
959
+ uploadWidgetFactory: createUploadWidgetFactory(options)
960
+ }));
961
+ };
962
+ var uploadConfigPlugin = (uploadImage, options) => (ctx) => () => {
963
+ applyUploadConfig(ctx, uploadImage, options);
964
+ };
965
+ var createUploadPlugin = (uploadImage, options = {}) => [...upload.upload, uploadConfigPlugin(uploadImage, options)];
966
+
967
+ // src/preset/index.ts
968
+ var createKunEditorPlugins = (adapters = {}, features = {}, options = {}) => {
969
+ const {
970
+ spoiler = true,
971
+ katex: katex3 = true,
972
+ codeBlock = true,
973
+ mention = true,
974
+ quote = false
975
+ } = features;
976
+ const plugins = [
977
+ commonmark.commonmark,
978
+ gfm.gfm,
979
+ history.history,
980
+ listener.listener,
981
+ clipboard.clipboard,
982
+ indent.indent,
983
+ trailing.trailing
984
+ ];
985
+ if (codeBlock) {
986
+ plugins.push(
987
+ createCodeBlockPlugins({
988
+ locale: options.locale,
989
+ katexOptions: options.katexOptions
990
+ })
991
+ );
992
+ }
993
+ if (katex3) {
994
+ plugins.push(createKatexPlugins());
995
+ }
996
+ if (spoiler) {
997
+ plugins.push(createSpoilerPlugin());
998
+ }
999
+ if (mention) {
1000
+ plugins.push(createMentionPlugin());
1001
+ }
1002
+ if (quote) {
1003
+ plugins.push(createQuotePlugin());
1004
+ }
1005
+ if (adapters.uploadImage) {
1006
+ plugins.push(
1007
+ createUploadPlugin(adapters.uploadImage, {
1008
+ locale: options.locale,
1009
+ notify: adapters.notify
1010
+ })
1011
+ );
1012
+ }
1013
+ plugins.push(createStopLinkPlugin());
1014
+ return plugins.flat();
1015
+ };
1016
+
1017
+ exports.applyCodeBlockConfig = applyCodeBlockConfig;
1018
+ exports.applyUploadConfig = applyUploadConfig;
1019
+ exports.blockKatexSchema = blockKatexSchema;
1020
+ exports.chevronDownIcon = chevronDownIcon;
1021
+ exports.clearIcon = clearIcon;
1022
+ exports.copyIcon = copyIcon;
1023
+ exports.createCodeBlockPlugins = createCodeBlockPlugins;
1024
+ exports.createKatexPlugins = createKatexPlugins;
1025
+ exports.createKunEditorPlugins = createKunEditorPlugins;
1026
+ exports.createMentionPlugin = createMentionPlugin;
1027
+ exports.createQuotePlugin = createQuotePlugin;
1028
+ exports.createSpoilerPlugin = createSpoilerPlugin;
1029
+ exports.createStopLinkPlugin = createStopLinkPlugin;
1030
+ exports.createUploadPlugin = createUploadPlugin;
1031
+ exports.createUploadWidgetFactory = createUploadWidgetFactory;
1032
+ exports.createUploader = createUploader;
1033
+ exports.editIcon = editIcon;
1034
+ exports.insertKunSpoilerCommand = insertKunSpoilerCommand;
1035
+ exports.insertMentionCommand = insertMentionCommand;
1036
+ exports.insertQuoteCommand = insertQuoteCommand;
1037
+ exports.insertSpoilerInputRule = insertSpoilerInputRule;
1038
+ exports.kunCM = kunCM;
1039
+ exports.kunCMHighlightStyle = kunCMHighlightStyle;
1040
+ exports.kunCMTheme = kunCMTheme;
1041
+ exports.linkCustomKeymap = linkCustomKeymap;
1042
+ exports.mathBlockInputRule = mathBlockInputRule;
1043
+ exports.mathInlineId = mathInlineId;
1044
+ exports.mathInlineInputRule = mathInlineInputRule;
1045
+ exports.mathInlineSchema = mathInlineSchema;
1046
+ exports.mentionId = mentionId;
1047
+ exports.mentionSchema = mentionSchema;
1048
+ exports.quoteId = quoteId;
1049
+ exports.quoteSchema = quoteSchema;
1050
+ exports.remarkMathBlockPlugin = remarkMathBlockPlugin;
1051
+ exports.remarkMathPlugin = remarkMathPlugin;
1052
+ exports.remarkMentionPlugin = remarkMentionPlugin;
1053
+ exports.remarkQuotePlugin = remarkQuotePlugin;
1054
+ exports.remarkSpoilerPlugin = remarkSpoilerPlugin;
1055
+ exports.searchIcon = searchIcon;
1056
+ exports.spoilerAttr = spoilerAttr;
1057
+ exports.spoilerSchema = spoilerSchema;
1058
+ exports.stopLinkCommand = stopLinkCommand;
1059
+ exports.toggleLatexCommand = toggleLatexCommand;
1060
+ exports.visibilityOffIcon = visibilityOffIcon;
1061
+ //# sourceMappingURL=index.cjs.map
1062
+ //# sourceMappingURL=index.cjs.map