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