@gravity-ui/markdown-editor 14.3.1 → 14.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/build/cjs/bundle/Editor.d.ts +2 -0
  2. package/build/cjs/bundle/Editor.js +9 -2
  3. package/build/cjs/bundle/MarkdownEditorView.js +1 -0
  4. package/build/cjs/bundle/SplitModeView.js +1 -0
  5. package/build/cjs/bundle/config/markup.d.ts +41 -17
  6. package/build/cjs/bundle/config/markup.js +413 -308
  7. package/build/cjs/bundle/config/wysiwyg.d.ts +29 -18
  8. package/build/cjs/bundle/config/wysiwyg.js +526 -310
  9. package/build/cjs/bundle/sticky/sticky.css +1 -1
  10. package/build/cjs/bundle/types.d.ts +24 -0
  11. package/build/cjs/bundle/useMarkdownEditor.js +6 -2
  12. package/build/cjs/bundle/wysiwyg-preset.d.ts +11 -2
  13. package/build/cjs/bundle/wysiwyg-preset.js +1 -0
  14. package/build/cjs/extensions/behavior/Clipboard/utils.d.ts +1 -0
  15. package/build/cjs/extensions/behavior/Clipboard/utils.js +1 -0
  16. package/build/cjs/extensions/markdown/CodeBlock/handle-paste.js +5 -17
  17. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/const.d.ts +4 -0
  18. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/const.js +6 -1
  19. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/index.d.ts +8 -1
  20. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/index.js +11 -5
  21. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/parser.js +5 -1
  22. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/schema.d.ts +1 -1
  23. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/schema.js +8 -3
  24. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/serializer.d.ts +3 -1
  25. package/build/cjs/extensions/yfm/YfmCut/YfmCutSpecs/serializer.js +42 -24
  26. package/build/cjs/extensions/yfm/YfmFile/YfmFileSpecs/const.d.ts +12 -0
  27. package/build/cjs/extensions/yfm/YfmFile/YfmFileSpecs/const.js +30 -11
  28. package/build/cjs/extensions/yfm/YfmFile/YfmFileSpecs/index.d.ts +8 -1
  29. package/build/cjs/extensions/yfm/YfmFile/YfmFileSpecs/index.js +46 -24
  30. package/build/cjs/extensions/yfm/YfmFile/index.d.ts +1 -0
  31. package/build/cjs/extensions/yfm/YfmFile/index.js +1 -0
  32. package/build/cjs/index.d.ts +1 -1
  33. package/build/cjs/index.js +2 -1
  34. package/build/cjs/markup/codemirror/create.d.ts +8 -5
  35. package/build/cjs/markup/codemirror/create.js +43 -5
  36. package/build/cjs/markup/codemirror/directive-facet.d.ts +3 -0
  37. package/build/cjs/markup/codemirror/directive-facet.js +8 -0
  38. package/build/cjs/markup/codemirror/html-to-markdown/converters.d.ts +111 -0
  39. package/build/cjs/markup/codemirror/html-to-markdown/converters.js +214 -0
  40. package/build/cjs/markup/codemirror/html-to-markdown/handlers.d.ts +104 -0
  41. package/build/cjs/markup/codemirror/html-to-markdown/handlers.js +233 -0
  42. package/build/cjs/markup/codemirror/html-to-markdown/helpers.d.ts +1 -0
  43. package/build/cjs/markup/codemirror/html-to-markdown/helpers.js +21 -0
  44. package/build/cjs/markup/codemirror/index.d.ts +1 -0
  45. package/build/cjs/markup/codemirror/index.js +3 -1
  46. package/build/cjs/markup/codemirror/yfm.d.ts +5 -0
  47. package/build/cjs/markup/codemirror/yfm.js +26 -4
  48. package/build/cjs/markup/commands/inline.js +18 -8
  49. package/build/cjs/markup/commands/yfm.js +10 -1
  50. package/build/cjs/utils/clipboard.d.ts +14 -0
  51. package/build/cjs/utils/clipboard.js +36 -1
  52. package/build/cjs/utils/directive.d.ts +28 -0
  53. package/build/cjs/utils/directive.js +55 -0
  54. package/build/cjs/utils/index.d.ts +1 -0
  55. package/build/cjs/version.js +1 -1
  56. package/build/esm/bundle/Editor.d.ts +2 -0
  57. package/build/esm/bundle/Editor.js +9 -2
  58. package/build/esm/bundle/MarkdownEditorView.js +1 -0
  59. package/build/esm/bundle/SplitModeView.js +1 -0
  60. package/build/esm/bundle/config/markup.d.ts +41 -17
  61. package/build/esm/bundle/config/markup.js +411 -307
  62. package/build/esm/bundle/config/wysiwyg.d.ts +29 -18
  63. package/build/esm/bundle/config/wysiwyg.js +499 -284
  64. package/build/esm/bundle/sticky/sticky.css +1 -1
  65. package/build/esm/bundle/types.d.ts +24 -0
  66. package/build/esm/bundle/useMarkdownEditor.js +6 -2
  67. package/build/esm/bundle/wysiwyg-preset.d.ts +11 -2
  68. package/build/esm/bundle/wysiwyg-preset.js +1 -0
  69. package/build/esm/extensions/behavior/Clipboard/utils.d.ts +1 -0
  70. package/build/esm/extensions/behavior/Clipboard/utils.js +1 -0
  71. package/build/esm/extensions/markdown/CodeBlock/handle-paste.js +2 -14
  72. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/const.d.ts +4 -0
  73. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/const.js +5 -0
  74. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/index.d.ts +8 -1
  75. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/index.js +8 -3
  76. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/parser.js +6 -2
  77. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/schema.d.ts +1 -1
  78. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/schema.js +8 -3
  79. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/serializer.d.ts +3 -1
  80. package/build/esm/extensions/yfm/YfmCut/YfmCutSpecs/serializer.js +41 -24
  81. package/build/esm/extensions/yfm/YfmFile/YfmFileSpecs/const.d.ts +12 -0
  82. package/build/esm/extensions/yfm/YfmFile/YfmFileSpecs/const.js +21 -2
  83. package/build/esm/extensions/yfm/YfmFile/YfmFileSpecs/index.d.ts +8 -1
  84. package/build/esm/extensions/yfm/YfmFile/YfmFileSpecs/index.js +32 -10
  85. package/build/esm/extensions/yfm/YfmFile/index.d.ts +1 -0
  86. package/build/esm/extensions/yfm/YfmFile/index.js +2 -1
  87. package/build/esm/index.d.ts +1 -1
  88. package/build/esm/index.js +1 -1
  89. package/build/esm/markup/codemirror/create.d.ts +8 -5
  90. package/build/esm/markup/codemirror/create.js +42 -4
  91. package/build/esm/markup/codemirror/directive-facet.d.ts +3 -0
  92. package/build/esm/markup/codemirror/directive-facet.js +5 -0
  93. package/build/esm/markup/codemirror/html-to-markdown/converters.d.ts +111 -0
  94. package/build/esm/markup/codemirror/html-to-markdown/converters.js +210 -0
  95. package/build/esm/markup/codemirror/html-to-markdown/handlers.d.ts +104 -0
  96. package/build/esm/markup/codemirror/html-to-markdown/handlers.js +215 -0
  97. package/build/esm/markup/codemirror/html-to-markdown/helpers.d.ts +1 -0
  98. package/build/esm/markup/codemirror/html-to-markdown/helpers.js +17 -0
  99. package/build/esm/markup/codemirror/index.d.ts +1 -0
  100. package/build/esm/markup/codemirror/index.js +1 -0
  101. package/build/esm/markup/codemirror/yfm.d.ts +5 -0
  102. package/build/esm/markup/codemirror/yfm.js +25 -3
  103. package/build/esm/markup/commands/inline.js +18 -8
  104. package/build/esm/markup/commands/yfm.js +9 -1
  105. package/build/esm/utils/clipboard.d.ts +14 -0
  106. package/build/esm/utils/clipboard.js +32 -0
  107. package/build/esm/utils/directive.d.ts +28 -0
  108. package/build/esm/utils/directive.js +51 -0
  109. package/build/esm/utils/index.d.ts +1 -0
  110. package/build/esm/version.js +1 -1
  111. package/build/styles.css +1 -1
  112. package/package.json +10 -6
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ImageHandler = exports.TableHandler = exports.TableRowHandler = exports.BrHandler = exports.DivHandler = exports.UnorderedListHandler = exports.OrderedListHandler = exports.GenericHandler = exports.CodeHandler = exports.FormattingHandler = exports.ParagraphHandler = exports.HeaderHandler = exports.LinkHandler = exports.TextNodeHandler = exports.NodeHandler = void 0;
4
+ /**
5
+ * Base handler class implementing the Chain of Responsibility pattern for HTML node processing.
6
+ * Each concrete handler decides whether it can process a node or should pass it to the next handler.
7
+ */
8
+ class NodeHandler {
9
+ constructor() {
10
+ this.next = null;
11
+ }
12
+ /**
13
+ * Sets up the next handler in the chain
14
+ */
15
+ setNext(handler) {
16
+ this.next = handler;
17
+ return handler;
18
+ }
19
+ /**
20
+ * Delegates processing to the next handler in the chain
21
+ */
22
+ handleNext(node, visitor) {
23
+ if (this.next) {
24
+ return this.next.handle(node, visitor);
25
+ }
26
+ return '';
27
+ }
28
+ }
29
+ exports.NodeHandler = NodeHandler;
30
+ /**
31
+ * Handles text nodes, converting them to markdown text
32
+ */
33
+ class TextNodeHandler extends NodeHandler {
34
+ handle(node, visitor) {
35
+ if (node.nodeType === Node.TEXT_NODE) {
36
+ return visitor.visitText(node);
37
+ }
38
+ return this.handleNext(node, visitor);
39
+ }
40
+ }
41
+ exports.TextNodeHandler = TextNodeHandler;
42
+ /**
43
+ * Handles anchor elements, converting them to markdown links
44
+ */
45
+ class LinkHandler extends NodeHandler {
46
+ handle(node, visitor) {
47
+ if (node.nodeType === Node.ELEMENT_NODE &&
48
+ node.tagName.toLowerCase() === 'a') {
49
+ return visitor.visitLink(node);
50
+ }
51
+ return this.handleNext(node, visitor);
52
+ }
53
+ }
54
+ exports.LinkHandler = LinkHandler;
55
+ /**
56
+ * Handles header elements (h1-h6), converting them to markdown headers
57
+ */
58
+ class HeaderHandler extends NodeHandler {
59
+ handle(node, visitor) {
60
+ if (node.nodeType !== Node.ELEMENT_NODE) {
61
+ return this.handleNext(node, visitor);
62
+ }
63
+ const tagName = node.tagName.toLowerCase();
64
+ const headerMatch = tagName.match(/^h([1-6])$/);
65
+ if (headerMatch) {
66
+ const headerLevel = parseInt(headerMatch[1], 10);
67
+ return visitor.visitHeader(node, headerLevel);
68
+ }
69
+ return this.handleNext(node, visitor);
70
+ }
71
+ }
72
+ exports.HeaderHandler = HeaderHandler;
73
+ /**
74
+ * Handles paragraph elements, converting them to markdown paragraphs
75
+ */
76
+ class ParagraphHandler extends NodeHandler {
77
+ handle(node, visitor) {
78
+ if (node.nodeType !== Node.ELEMENT_NODE) {
79
+ return this.handleNext(node, visitor);
80
+ }
81
+ if (node.tagName.toLowerCase() === 'p') {
82
+ return visitor.visitParagraph(node);
83
+ }
84
+ return this.handleNext(node, visitor);
85
+ }
86
+ }
87
+ exports.ParagraphHandler = ParagraphHandler;
88
+ /**
89
+ * Handles text formatting elements (b, strong, i, em), converting them to markdown formatting
90
+ */
91
+ class FormattingHandler extends NodeHandler {
92
+ handle(node, visitor) {
93
+ var _a;
94
+ if (node.nodeType !== Node.ELEMENT_NODE) {
95
+ return this.handleNext(node, visitor);
96
+ }
97
+ const element = node;
98
+ const tagName = element.tagName.toLowerCase();
99
+ const formattingTags = ['b', 'strong', 'i', 'em', 'span'];
100
+ if (formattingTags.includes(tagName) &&
101
+ !['a', 'code', 'pre'].includes(((_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.tagName.toLowerCase()) || '')) {
102
+ return visitor.visitFormatting(element);
103
+ }
104
+ return this.handleNext(node, visitor);
105
+ }
106
+ }
107
+ exports.FormattingHandler = FormattingHandler;
108
+ /**
109
+ * Handles code elements, converting them to markdown code blocks or inline code
110
+ */
111
+ class CodeHandler extends NodeHandler {
112
+ handle(node, visitor) {
113
+ if (node.nodeType !== Node.ELEMENT_NODE) {
114
+ return this.handleNext(node, visitor);
115
+ }
116
+ if (node.tagName.toLowerCase() === 'code' ||
117
+ node.tagName.toLowerCase() === 'pre') {
118
+ return visitor.visitCode(node);
119
+ }
120
+ return this.handleNext(node, visitor);
121
+ }
122
+ }
123
+ exports.CodeHandler = CodeHandler;
124
+ /**
125
+ * Fallback handler for any HTML elements not handled by other specific handlers
126
+ */
127
+ class GenericHandler extends NodeHandler {
128
+ handle(node, visitor) {
129
+ return visitor.visitGeneric(node);
130
+ }
131
+ }
132
+ exports.GenericHandler = GenericHandler;
133
+ /**
134
+ * Handles ordered list elements, converting them to markdown ordered lists
135
+ */
136
+ class OrderedListHandler extends NodeHandler {
137
+ handle(node, visitor) {
138
+ if (node.nodeType === Node.ELEMENT_NODE &&
139
+ node.tagName.toLowerCase() === 'ol') {
140
+ const items = Array.from(node.childNodes)
141
+ .filter((child) => child.nodeType === Node.ELEMENT_NODE &&
142
+ child.tagName.toLowerCase() === 'li')
143
+ .map((item, index) => `${index + 1}. ${visitor.visitGeneric(item)}`)
144
+ .join('\n');
145
+ return items + '\n';
146
+ }
147
+ return this.handleNext(node, visitor);
148
+ }
149
+ }
150
+ exports.OrderedListHandler = OrderedListHandler;
151
+ /**
152
+ * Handles unordered list elements, converting them to markdown unordered lists
153
+ */
154
+ class UnorderedListHandler extends NodeHandler {
155
+ handle(node, visitor) {
156
+ if (node.nodeType === Node.ELEMENT_NODE &&
157
+ node.tagName.toLowerCase() === 'ul') {
158
+ const items = Array.from(node.childNodes)
159
+ .filter((child) => child.nodeType === Node.ELEMENT_NODE &&
160
+ child.tagName.toLowerCase() === 'li')
161
+ .map((item) => `- ${visitor.visitGeneric(item)}`)
162
+ .join('\n');
163
+ return items + '\n';
164
+ }
165
+ return this.handleNext(node, visitor);
166
+ }
167
+ }
168
+ exports.UnorderedListHandler = UnorderedListHandler;
169
+ /**
170
+ * Handles div elements, converting them to markdown paragraphs
171
+ */
172
+ class DivHandler extends NodeHandler {
173
+ handle(node, visitor) {
174
+ if (node.nodeType === Node.ELEMENT_NODE &&
175
+ node.tagName.toLowerCase() === 'div') {
176
+ return visitor.visitDiv(node);
177
+ }
178
+ return this.handleNext(node, visitor);
179
+ }
180
+ }
181
+ exports.DivHandler = DivHandler;
182
+ /**
183
+ * Handles br elements, converting them to markdown newlines
184
+ */
185
+ class BrHandler extends NodeHandler {
186
+ handle(node, visitor) {
187
+ if (node.nodeType === Node.ELEMENT_NODE &&
188
+ node.tagName.toLowerCase() === 'br') {
189
+ return visitor.visitBr();
190
+ }
191
+ return this.handleNext(node, visitor);
192
+ }
193
+ }
194
+ exports.BrHandler = BrHandler;
195
+ /**
196
+ * Handles table row elements, converting them to markdown table rows
197
+ */
198
+ class TableRowHandler extends NodeHandler {
199
+ handle(node, visitor) {
200
+ if (node.nodeType === Node.ELEMENT_NODE &&
201
+ node.tagName.toLowerCase() === 'tr') {
202
+ return visitor.visitTableRow(node);
203
+ }
204
+ return this.handleNext(node, visitor);
205
+ }
206
+ }
207
+ exports.TableRowHandler = TableRowHandler;
208
+ /**
209
+ * Handles table elements, converting them to markdown tables
210
+ */
211
+ class TableHandler extends NodeHandler {
212
+ handle(node, visitor) {
213
+ if (node.nodeType === Node.ELEMENT_NODE &&
214
+ node.tagName.toLowerCase() === 'table') {
215
+ return visitor.visitTable(node);
216
+ }
217
+ return this.handleNext(node, visitor);
218
+ }
219
+ }
220
+ exports.TableHandler = TableHandler;
221
+ /**
222
+ * Handles image elements, converting them to markdown images
223
+ */
224
+ class ImageHandler extends NodeHandler {
225
+ handle(node, visitor) {
226
+ if (node.nodeType === Node.ELEMENT_NODE &&
227
+ node.tagName.toLowerCase() === 'img') {
228
+ return visitor.visitImage(node);
229
+ }
230
+ return this.handleNext(node, visitor);
231
+ }
232
+ }
233
+ exports.ImageHandler = ImageHandler;
@@ -0,0 +1 @@
1
+ export declare function applyFormatting(text: string, element: HTMLElement): string;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyFormatting = void 0;
4
+ function applyFormatting(text, element) {
5
+ // Check for italic formatting (either through tags or CSS)
6
+ const hasItalic = element.tagName.toLowerCase() === 'i' ||
7
+ element.tagName.toLowerCase() === 'em' ||
8
+ element.style.fontStyle === 'italic';
9
+ // Check for bold formatting (either through tags or CSS font-weight)
10
+ const hasBold = element.tagName.toLowerCase() === 'b' ||
11
+ element.tagName.toLowerCase() === 'strong' ||
12
+ parseInt(element.style.fontWeight, 10) >= 600;
13
+ // Apply markdown formatting in specific order
14
+ let formatted = text;
15
+ if (hasItalic)
16
+ formatted = `*${formatted}*`; // Wrap in single asterisks for italic
17
+ if (hasBold)
18
+ formatted = `**${formatted}**`; // Wrap in double asterisks for bold
19
+ return formatted;
20
+ }
21
+ exports.applyFormatting = applyFormatting;
@@ -1,5 +1,6 @@
1
1
  export type { CreateCodemirrorParams } from './create';
2
2
  export { createCodemirror } from './create';
3
3
  export { ReactRendererFacet } from './react-facet';
4
+ export { DirectiveSyntaxFacet } from './directive-facet';
4
5
  export { getImageDimensions, IMG_MAX_HEIGHT } from './files-upload-plugin';
5
6
  export type { YfmLangOptions } from './yfm';
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IMG_MAX_HEIGHT = exports.getImageDimensions = exports.ReactRendererFacet = exports.createCodemirror = void 0;
3
+ exports.IMG_MAX_HEIGHT = exports.getImageDimensions = exports.DirectiveSyntaxFacet = exports.ReactRendererFacet = exports.createCodemirror = void 0;
4
4
  var create_1 = require("./create");
5
5
  Object.defineProperty(exports, "createCodemirror", { enumerable: true, get: function () { return create_1.createCodemirror; } });
6
6
  var react_facet_1 = require("./react-facet");
7
7
  Object.defineProperty(exports, "ReactRendererFacet", { enumerable: true, get: function () { return react_facet_1.ReactRendererFacet; } });
8
+ var directive_facet_1 = require("./directive-facet");
9
+ Object.defineProperty(exports, "DirectiveSyntaxFacet", { enumerable: true, get: function () { return directive_facet_1.DirectiveSyntaxFacet; } });
8
10
  var files_upload_plugin_1 = require("./files-upload-plugin");
9
11
  Object.defineProperty(exports, "getImageDimensions", { enumerable: true, get: function () { return files_upload_plugin_1.getImageDimensions; } });
10
12
  Object.defineProperty(exports, "IMG_MAX_HEIGHT", { enumerable: true, get: function () { return files_upload_plugin_1.IMG_MAX_HEIGHT; } });
@@ -15,6 +15,11 @@ export declare const yfmCutSnippet: (editor: {
15
15
  state: import("@codemirror/state").EditorState;
16
16
  dispatch: (tr: import("@codemirror/state").Transaction) => void;
17
17
  }, completion: Completion | null, from: number, to: number) => void;
18
+ export declare const yfmCutDirectiveSnippetTemplate = ":::cut [#{title}]\n#{}\n:::\n\n";
19
+ export declare const yfmCutDirectiveSnippet: (editor: {
20
+ state: import("@codemirror/state").EditorState;
21
+ dispatch: (tr: import("@codemirror/state").Transaction) => void;
22
+ }, completion: Completion | null, from: number, to: number) => void;
18
23
  export interface LanguageData {
19
24
  autocomplete: CompletionSource;
20
25
  [key: string]: any;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.yfmLang = exports.yfmCutSnippet = exports.yfmCutSnippetTemplate = exports.yfmNoteSnippets = exports.yfmNoteSnippetTemplate = exports.yfmNoteTypes = exports.customTags = void 0;
3
+ exports.yfmLang = exports.yfmCutDirectiveSnippet = exports.yfmCutDirectiveSnippetTemplate = exports.yfmCutSnippet = exports.yfmCutSnippetTemplate = exports.yfmNoteSnippets = exports.yfmNoteSnippetTemplate = exports.yfmNoteTypes = exports.customTags = void 0;
4
4
  const autocomplete_1 = require("@codemirror/autocomplete");
5
5
  const lang_markdown_1 = require("@codemirror/lang-markdown");
6
6
  const highlight_1 = require("@lezer/highlight");
7
7
  const lodash_1 = require("../../lodash");
8
+ const directive_facet_1 = require("./directive-facet");
8
9
  exports.customTags = {
9
10
  underline: highlight_1.Tag.define(),
10
11
  monospace: highlight_1.Tag.define(),
@@ -58,8 +59,11 @@ exports.yfmNoteSnippets = {
58
59
  };
59
60
  exports.yfmCutSnippetTemplate = '{% cut "#{title}" %}\n\n#{}\n\n{% endcut %}\n\n';
60
61
  exports.yfmCutSnippet = (0, autocomplete_1.snippet)(exports.yfmCutSnippetTemplate);
62
+ exports.yfmCutDirectiveSnippetTemplate = ':::cut [#{title}]\n#{}\n:::\n\n';
63
+ exports.yfmCutDirectiveSnippet = (0, autocomplete_1.snippet)(exports.yfmCutDirectiveSnippetTemplate);
61
64
  const mdAutocomplete = {
62
65
  autocomplete: (context) => {
66
+ const directiveContext = context.state.facet(directive_facet_1.DirectiveSyntaxFacet);
63
67
  // TODO: add more actions and re-enable
64
68
  // let word = context.matchBefore(/\/.*/);
65
69
  // if (word) {
@@ -77,13 +81,15 @@ const mdAutocomplete = {
77
81
  // label: '/yfm cut',
78
82
  // displayLabel: 'YFM Cut',
79
83
  // type: 'text',
80
- // apply: yfmCutSnippet,
84
+ // apply: directiveFacet.shouldInsertDirectiveMarkup('yfmCut')
85
+ // ? yfmCutDirectiveSnippet
86
+ // : yfmCutSnippet,
81
87
  // },
82
88
  // ],
83
89
  // };
84
90
  // }
85
91
  const word = context.matchBefore(/^.*/);
86
- if (word === null || word === void 0 ? void 0 : word.text.startsWith('{%')) {
92
+ if (directiveContext.option !== 'only' && (word === null || word === void 0 ? void 0 : word.text.startsWith('{%'))) {
87
93
  return {
88
94
  from: word.from,
89
95
  options: [
@@ -99,11 +105,27 @@ const mdAutocomplete = {
99
105
  label: '{% cut',
100
106
  displayLabel: 'YFM Cut',
101
107
  type: 'text',
102
- apply: exports.yfmCutSnippet,
108
+ apply: directiveContext.shouldInsertDirectiveMarkup('yfmCut')
109
+ ? exports.yfmCutDirectiveSnippet
110
+ : exports.yfmCutSnippet,
103
111
  },
104
112
  ],
105
113
  };
106
114
  }
115
+ if (directiveContext.option !== 'disabled' && (word === null || word === void 0 ? void 0 : word.text.startsWith(':'))) {
116
+ const options = [];
117
+ if (directiveContext.valueFor('yfmCut') !== 'disabled') {
118
+ options.push({
119
+ label: ':::cut',
120
+ displayLabel: 'YFM Cut',
121
+ type: 'text',
122
+ apply: exports.yfmCutDirectiveSnippet,
123
+ });
124
+ }
125
+ if (options.length) {
126
+ return { from: word.from, options };
127
+ }
128
+ }
107
129
  return null;
108
130
  },
109
131
  };
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.insertFiles = exports.insertImages = exports.insertAnchor = exports.insertLink = void 0;
4
4
  const autocomplete_1 = require("@codemirror/autocomplete");
5
+ const codemirror_1 = require("../codemirror");
5
6
  const defaultLinkSnippet = (0, autocomplete_1.snippet)(`[#{2:link}](#{1:url} "#{3:title}")`);
6
7
  const insertLink = ({ state, dispatch }) => {
7
8
  const { from, to, empty } = state.selection.main;
@@ -47,16 +48,25 @@ function insertImages(images) {
47
48
  };
48
49
  }
49
50
  exports.insertImages = insertImages;
51
+ const fileToCurlySyntax = (file) => {
52
+ const attrsStr = Object.entries(file)
53
+ .map(([key, value]) => `${key}="${value.replace('"', '')}"`)
54
+ .join(' ');
55
+ return `{% file ${attrsStr} %}`;
56
+ };
57
+ const fileToDirectiveSyntax = (file) => {
58
+ const { src, name, type } = file;
59
+ let markup = `:file[${name}](${src})`;
60
+ if (type)
61
+ markup += `{type="${type}"}`;
62
+ return markup;
63
+ };
50
64
  const insertFiles = (files) => {
51
65
  return ({ state, dispatch }) => {
52
- const markup = files
53
- .map((attrs) => {
54
- const attrsStr = Object.entries(attrs)
55
- .map(([key, value]) => `${key}="${value.replace('"', '')}"`)
56
- .join(' ');
57
- return `{% file ${attrsStr} %}`;
58
- })
59
- .join(' ');
66
+ const serializer = state.facet(codemirror_1.DirectiveSyntaxFacet).shouldInsertDirectiveMarkup('yfmFile')
67
+ ? fileToDirectiveSyntax
68
+ : fileToCurlySyntax;
69
+ const markup = files.map(serializer).join(' ');
60
70
  const tr = state.changeByRange((range) => {
61
71
  const changes = state.changes({ from: range.from, to: range.to, insert: markup });
62
72
  return { changes, range: range.map(changes) };
@@ -1,8 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.insertYfmTable = exports.insertYfmTabs = exports.wrapToYfmNote = exports.wrapToYfmCut = void 0;
4
+ const directive_facet_1 = require("../codemirror/directive-facet");
4
5
  const helpers_1 = require("./helpers");
5
- exports.wrapToYfmCut = (0, helpers_1.wrapToBlock)(({ lineBreak }) => '{% cut "title" %}' + lineBreak.repeat(2), ({ lineBreak }) => lineBreak.repeat(2) + '{% endcut %}');
6
+ const wrapToYfmCutCurly = (0, helpers_1.wrapToBlock)(({ lineBreak }) => '{% cut "title" %}' + lineBreak.repeat(2), ({ lineBreak }) => lineBreak.repeat(2) + '{% endcut %}');
7
+ const wrapToYfmCutDirective = (0, helpers_1.wrapToBlock)(({ lineBreak }) => ':::cut [title]' + lineBreak, ({ lineBreak }) => lineBreak + ':::');
8
+ const wrapToYfmCut = (target) => {
9
+ const cmd = target.state.facet(directive_facet_1.DirectiveSyntaxFacet).shouldInsertDirectiveMarkup('yfmCut')
10
+ ? wrapToYfmCutDirective
11
+ : wrapToYfmCutCurly;
12
+ return cmd(target);
13
+ };
14
+ exports.wrapToYfmCut = wrapToYfmCut;
6
15
  exports.wrapToYfmNote = (0, helpers_1.wrapToBlock)(({ lineBreak }) => '{% note info %}' + lineBreak.repeat(2), ({ lineBreak }) => lineBreak.repeat(2) + '{% endnote %}');
7
16
  exports.insertYfmTabs = (0, helpers_1.wrapToBlock)(({ lineBreak }) => '{% list tabs %}' + lineBreak.repeat(2) + '- Tab name' + lineBreak.repeat(2), ({ lineBreak }) => lineBreak.repeat(2) + '{% endlist %}', { before: ' ', after: '' });
8
17
  exports.insertYfmTable = (0, helpers_1.wrapToBlock)(({ lineBreak }) => ['#|', '||'].join(lineBreak) + lineBreak, ({ lineBreak }) => lineBreak + ['|', '', '||', '||', '', '|', '', '||', '|#', ''].join(lineBreak));
@@ -3,6 +3,7 @@ export declare enum DataTransferType {
3
3
  Text = "text/plain",
4
4
  Html = "text/html",
5
5
  Yfm = "text/yfm",
6
+ Rtf = "text/rtf",
6
7
  UriList = "text/uri-list",
7
8
  VSCodeData = "vscode-editor-data",
8
9
  Files = "Files"
@@ -10,3 +11,16 @@ export declare enum DataTransferType {
10
11
  export declare function isFilesOnly({ types }: DataTransfer): boolean;
11
12
  export declare function isFilesFromHtml({ types }: DataTransfer): boolean;
12
13
  export declare function isImageFile(file: File): boolean;
14
+ export declare function isVSCode(data: DataTransfer): boolean;
15
+ export declare type VSCodeData = {
16
+ version: number;
17
+ isFromEmptySelection: boolean;
18
+ multicursorText: null | string;
19
+ mode: string;
20
+ [key: string]: unknown;
21
+ };
22
+ export declare function tryParseVSCodeData(data: DataTransfer): VSCodeData | undefined;
23
+ /**
24
+ * Checks if HTML conversion should be skipped based on clipboard contents.
25
+ */
26
+ export declare function shouldSkipHtmlConversion(clipboardData: DataTransfer): boolean;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isImageFile = exports.isFilesFromHtml = exports.isFilesOnly = exports.DataTransferType = void 0;
3
+ exports.shouldSkipHtmlConversion = exports.tryParseVSCodeData = exports.isVSCode = exports.isImageFile = exports.isFilesFromHtml = exports.isFilesOnly = exports.DataTransferType = void 0;
4
4
  /** Сontains all data formats known to us */
5
5
  var DataTransferType;
6
6
  (function (DataTransferType) {
7
7
  DataTransferType["Text"] = "text/plain";
8
8
  DataTransferType["Html"] = "text/html";
9
9
  DataTransferType["Yfm"] = "text/yfm";
10
+ DataTransferType["Rtf"] = "text/rtf";
10
11
  DataTransferType["UriList"] = "text/uri-list";
11
12
  DataTransferType["VSCodeData"] = "vscode-editor-data";
12
13
  DataTransferType["Files"] = "Files";
@@ -25,3 +26,37 @@ function isImageFile(file) {
25
26
  return file.type.startsWith('image/');
26
27
  }
27
28
  exports.isImageFile = isImageFile;
29
+ function isVSCode(data) {
30
+ return data.types.includes(DataTransferType.VSCodeData);
31
+ }
32
+ exports.isVSCode = isVSCode;
33
+ function tryParseVSCodeData(data) {
34
+ try {
35
+ return JSON.parse(data.getData(DataTransferType.VSCodeData));
36
+ }
37
+ catch (e) {
38
+ console.error(e);
39
+ return undefined;
40
+ }
41
+ }
42
+ exports.tryParseVSCodeData = tryParseVSCodeData;
43
+ /**
44
+ * Checks if HTML conversion should be skipped based on clipboard contents.
45
+ */
46
+ function shouldSkipHtmlConversion(clipboardData) {
47
+ const hasHtml = clipboardData.types.includes(DataTransferType.Html);
48
+ // If there's no HTML content, skip conversion
49
+ if (!hasHtml)
50
+ return true;
51
+ // Check for standard HTML clipboard (text/plain + text/html)
52
+ if (clipboardData.types.length === 2)
53
+ return false;
54
+ // Check for WebStorm/Safari case (includes RTF)
55
+ if (clipboardData.types.length === 3) {
56
+ const rtf = clipboardData.getData(DataTransferType.Rtf);
57
+ return rtf.indexOf('\fmodern JetBrains') > 0;
58
+ }
59
+ // Skip conversion for any other cases
60
+ return true;
61
+ }
62
+ exports.shouldSkipHtmlConversion = shouldSkipHtmlConversion;
@@ -0,0 +1,28 @@
1
+ export declare type DirectiveSyntaxValue = 'disabled' | 'enabled' | 'preserve' | 'overwrite' | 'only';
2
+ declare type DirectiveSyntaxMdPluginValue = 'disabled' | 'enabled' | 'only';
3
+ export declare type DirectiveSyntaxOption = DirectiveSyntaxValue | DirectiveSyntaxOptionObj;
4
+ declare type DirectiveSyntaxOptionObj = {
5
+ [K in keyof MarkdownEditor.DirectiveSyntaxAdditionalSupportedExtensions]?: DirectiveSyntaxValue;
6
+ };
7
+ declare global {
8
+ namespace MarkdownEditor {
9
+ /**
10
+ * Add more keys for you additional supported extensions
11
+ */
12
+ interface DirectiveSyntaxAdditionalSupportedExtensions {
13
+ }
14
+ }
15
+ }
16
+ export declare class DirectiveSyntaxContext {
17
+ #private;
18
+ protected set option(value: DirectiveSyntaxOption | undefined);
19
+ get option(): DirectiveSyntaxOption;
20
+ constructor(option: DirectiveSyntaxOption | undefined);
21
+ valueFor(key: keyof DirectiveSyntaxOptionObj): DirectiveSyntaxValue;
22
+ mdPluginValueFor(key: keyof DirectiveSyntaxOptionObj): DirectiveSyntaxMdPluginValue;
23
+ /** helper for wisywig serializer */
24
+ shouldSerializeToDirective(key: keyof DirectiveSyntaxOptionObj, tokenMarkup: unknown): boolean;
25
+ /** helper for markup-mode commands and actions */
26
+ shouldInsertDirectiveMarkup(key: keyof DirectiveSyntaxOptionObj): boolean;
27
+ }
28
+ export {};
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var _DirectiveSyntaxContext_option;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.DirectiveSyntaxContext = void 0;
5
+ const tslib_1 = require("tslib");
6
+ const DIRECTIVE_SYNTAX_DEFAULT = 'disabled';
7
+ class DirectiveSyntaxContext {
8
+ constructor(option) {
9
+ _DirectiveSyntaxContext_option.set(this, void 0);
10
+ this.option = option;
11
+ tslib_1.__classPrivateFieldSet(this, _DirectiveSyntaxContext_option, this.option, "f");
12
+ }
13
+ set option(value) {
14
+ tslib_1.__classPrivateFieldSet(this, _DirectiveSyntaxContext_option, value !== null && value !== void 0 ? value : DIRECTIVE_SYNTAX_DEFAULT, "f");
15
+ }
16
+ get option() {
17
+ return tslib_1.__classPrivateFieldGet(this, _DirectiveSyntaxContext_option, "f");
18
+ }
19
+ valueFor(key) {
20
+ let value;
21
+ if (typeof this.option === 'object')
22
+ value = this.option[key];
23
+ if (typeof this.option === 'string')
24
+ value = this.option;
25
+ return value !== null && value !== void 0 ? value : DIRECTIVE_SYNTAX_DEFAULT;
26
+ }
27
+ mdPluginValueFor(key) {
28
+ const value = this.valueFor(key);
29
+ return value === 'preserve' || value === 'overwrite' ? 'enabled' : value;
30
+ }
31
+ /** helper for wisywig serializer */
32
+ shouldSerializeToDirective(key, tokenMarkup) {
33
+ const option = this.valueFor(key);
34
+ if (option === 'overwrite' || option === 'only')
35
+ return true;
36
+ if (typeof tokenMarkup === 'string') {
37
+ if (tokenMarkup.startsWith(':'))
38
+ return true;
39
+ if (tokenMarkup.startsWith('{'))
40
+ return false;
41
+ }
42
+ if (option === 'preserve')
43
+ return true;
44
+ return false;
45
+ }
46
+ /** helper for markup-mode commands and actions */
47
+ shouldInsertDirectiveMarkup(key) {
48
+ const value = this.valueFor(key);
49
+ if (value === 'disabled' || value === 'enabled')
50
+ return false;
51
+ return true;
52
+ }
53
+ }
54
+ exports.DirectiveSyntaxContext = DirectiveSyntaxContext;
55
+ _DirectiveSyntaxContext_option = new WeakMap();
@@ -19,3 +19,4 @@ export * from './serialize-for-clipboard';
19
19
  export * from './sync-scroll';
20
20
  export * from './upload';
21
21
  export * from './get-proportional-size';
22
+ export type { DirectiveSyntaxValue, DirectiveSyntaxOption } from './directive';
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  /** During build process, the current version will be injected here */
5
- exports.VERSION = typeof '14.3.1' !== 'undefined' ? '14.3.1' : 'unknown';
5
+ exports.VERSION = typeof '14.5.0' !== 'undefined' ? '14.5.0' : 'unknown';
@@ -1,6 +1,7 @@
1
1
  import type { CommonEditor } from '../common';
2
2
  import { ReactRenderStorage } from '../extensions';
3
3
  import { type Receiver } from '../utils';
4
+ import type { DirectiveSyntaxContext } from '../utils/directive';
4
5
  import type { MarkdownEditorMode as EditorMode, MarkdownEditorPreset as EditorPreset, MarkdownEditorOptions } from './types';
5
6
  export declare type ToolbarActionData = {
6
7
  editorMode: EditorMode;
@@ -41,5 +42,6 @@ export declare type ChangeEditorModeOptions = {
41
42
  export declare type EditorOptions = Pick<MarkdownEditorOptions, 'md' | 'initial' | 'handlers' | 'experimental' | 'markupConfig' | 'wysiwygConfig'> & {
42
43
  renderStorage: ReactRenderStorage;
43
44
  preset: EditorPreset;
45
+ directiveSyntax: DirectiveSyntaxContext;
44
46
  };
45
47
  export {};