draftly 1.0.7 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/chunk-3T55CBNZ.cjs +33 -0
- package/dist/chunk-3T55CBNZ.cjs.map +1 -0
- package/dist/chunk-5MC4T7JH.cjs +58 -0
- package/dist/chunk-5MC4T7JH.cjs.map +1 -0
- package/dist/{chunk-KBQDZ5IW.cjs → chunk-CLW73JRX.cjs} +100 -75
- package/dist/chunk-CLW73JRX.cjs.map +1 -0
- package/dist/{chunk-72ZYRGRT.cjs → chunk-EQUQHE2E.cjs} +30 -26
- package/dist/chunk-EQUQHE2E.cjs.map +1 -0
- package/dist/{chunk-HPSMS2WB.js → chunk-I563H35S.js} +101 -75
- package/dist/chunk-I563H35S.js.map +1 -0
- package/dist/chunk-IAXF4SJL.js +55 -0
- package/dist/chunk-IAXF4SJL.js.map +1 -0
- package/dist/chunk-JF3WXXMJ.js +31 -0
- package/dist/chunk-JF3WXXMJ.js.map +1 -0
- package/dist/{chunk-N3WL3XPB.js → chunk-NRPI5O6Y.js} +2603 -604
- package/dist/chunk-NRPI5O6Y.js.map +1 -0
- package/dist/{chunk-2B3A3VSQ.cjs → chunk-OMFUE4AQ.cjs} +2642 -622
- package/dist/chunk-OMFUE4AQ.cjs.map +1 -0
- package/dist/{chunk-DFQYXFOP.js → chunk-TD3L5C45.js} +28 -3
- package/dist/chunk-TD3L5C45.js.map +1 -0
- package/dist/{chunk-CG4M4TC7.js → chunk-UCHBDJ4R.js} +26 -22
- package/dist/chunk-UCHBDJ4R.js.map +1 -0
- package/dist/{chunk-KDEDLC3D.cjs → chunk-W75QUUQC.cjs} +29 -2
- package/dist/chunk-W75QUUQC.cjs.map +1 -0
- package/dist/{draftly-BLnx3uGX.d.cts → draftly-BBL-AdOl.d.cts} +5 -1
- package/dist/{draftly-BLnx3uGX.d.ts → draftly-BBL-AdOl.d.ts} +5 -1
- package/dist/editor/index.cjs +22 -14
- package/dist/editor/index.d.cts +2 -1
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/index.js +2 -2
- package/dist/index.cjs +65 -39
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +6 -4
- package/dist/lib/index.cjs +12 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.d.cts +16 -0
- package/dist/lib/index.d.ts +16 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/plugins/index.cjs +27 -17
- package/dist/plugins/index.d.cts +180 -10
- package/dist/plugins/index.d.ts +180 -10
- package/dist/plugins/index.js +5 -3
- package/dist/preview/index.cjs +16 -11
- package/dist/preview/index.d.cts +19 -4
- package/dist/preview/index.d.ts +19 -4
- package/dist/preview/index.js +3 -2
- package/package.json +8 -1
- package/src/editor/draftly.ts +30 -27
- package/src/editor/plugin.ts +5 -1
- package/src/editor/theme.ts +1 -0
- package/src/editor/utils.ts +33 -0
- package/src/index.ts +5 -4
- package/src/lib/index.ts +2 -0
- package/src/lib/input-handler.ts +45 -0
- package/src/plugins/code-plugin.theme.ts +426 -0
- package/src/plugins/code-plugin.ts +810 -561
- package/src/plugins/emoji-plugin.ts +140 -0
- package/src/plugins/index.ts +63 -57
- package/src/plugins/inline-plugin.ts +305 -291
- package/src/plugins/math-plugin.ts +12 -0
- package/src/plugins/table-plugin.ts +1759 -0
- package/src/preview/context.ts +4 -1
- package/src/preview/css-generator.ts +14 -1
- package/src/preview/index.ts +9 -1
- package/src/preview/preview.ts +2 -1
- package/src/preview/renderer.ts +21 -20
- package/src/preview/syntax-theme.ts +110 -0
- package/src/preview/types.ts +14 -0
- package/dist/chunk-2B3A3VSQ.cjs.map +0 -1
- package/dist/chunk-72ZYRGRT.cjs.map +0 -1
- package/dist/chunk-CG4M4TC7.js.map +0 -1
- package/dist/chunk-DFQYXFOP.js.map +0 -1
- package/dist/chunk-HPSMS2WB.js.map +0 -1
- package/dist/chunk-KBQDZ5IW.cjs.map +0 -1
- package/dist/chunk-KDEDLC3D.cjs.map +0 -1
- package/dist/chunk-N3WL3XPB.js.map +0 -1
|
@@ -1,25 +1,49 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkEQUQHE2E_cjs = require('./chunk-EQUQHE2E.cjs');
|
|
4
|
+
var chunk3T55CBNZ_cjs = require('./chunk-3T55CBNZ.cjs');
|
|
5
|
+
var chunkCLW73JRX_cjs = require('./chunk-CLW73JRX.cjs');
|
|
6
|
+
var chunkW75QUUQC_cjs = require('./chunk-W75QUUQC.cjs');
|
|
5
7
|
var view = require('@codemirror/view');
|
|
6
8
|
var language = require('@codemirror/language');
|
|
7
9
|
var highlight = require('@lezer/highlight');
|
|
10
|
+
var state = require('@codemirror/state');
|
|
11
|
+
var markdown = require('@lezer/markdown');
|
|
8
12
|
var DOMPurify = require('dompurify');
|
|
9
13
|
var katex = require('katex');
|
|
10
14
|
var katexCss = require('katex/dist/katex.min.css?raw');
|
|
11
15
|
var mermaid = require('mermaid');
|
|
12
16
|
var languageData = require('@codemirror/language-data');
|
|
17
|
+
var emoji = require('node-emoji');
|
|
13
18
|
|
|
14
19
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
20
|
|
|
21
|
+
function _interopNamespace(e) {
|
|
22
|
+
if (e && e.__esModule) return e;
|
|
23
|
+
var n = Object.create(null);
|
|
24
|
+
if (e) {
|
|
25
|
+
Object.keys(e).forEach(function (k) {
|
|
26
|
+
if (k !== 'default') {
|
|
27
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
28
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get: function () { return e[k]; }
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
n.default = e;
|
|
36
|
+
return Object.freeze(n);
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
|
|
17
40
|
var katex__default = /*#__PURE__*/_interopDefault(katex);
|
|
18
41
|
var katexCss__default = /*#__PURE__*/_interopDefault(katexCss);
|
|
19
42
|
var mermaid__default = /*#__PURE__*/_interopDefault(mermaid);
|
|
43
|
+
var emoji__namespace = /*#__PURE__*/_interopNamespace(emoji);
|
|
20
44
|
|
|
21
45
|
// src/plugins/paragraph-plugin.ts
|
|
22
|
-
var ParagraphPlugin = class extends
|
|
46
|
+
var ParagraphPlugin = class extends chunkEQUQHE2E_cjs.DraftlyPlugin {
|
|
23
47
|
name = "paragraph";
|
|
24
48
|
version = "1.0.0";
|
|
25
49
|
requiredNodes = ["Paragraph"];
|
|
@@ -36,7 +60,7 @@ var ParagraphPlugin = class extends chunk72ZYRGRT_cjs.DraftlyPlugin {
|
|
|
36
60
|
return `<p class="cm-draftly-paragraph">${children}</p>`;
|
|
37
61
|
}
|
|
38
62
|
};
|
|
39
|
-
var theme =
|
|
63
|
+
var theme = chunkW75QUUQC_cjs.createTheme({
|
|
40
64
|
default: {
|
|
41
65
|
".cm-draftly-paragraph": {
|
|
42
66
|
paddingTop: "0.5em",
|
|
@@ -63,7 +87,7 @@ var headingLineDecorations = {
|
|
|
63
87
|
"heading-5": view.Decoration.line({ class: "cm-draftly-line-h5" }),
|
|
64
88
|
"heading-6": view.Decoration.line({ class: "cm-draftly-line-h6" })
|
|
65
89
|
};
|
|
66
|
-
var HeadingPlugin = class extends
|
|
90
|
+
var HeadingPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
67
91
|
name = "heading";
|
|
68
92
|
version = "1.0.0";
|
|
69
93
|
decorationPriority = 10;
|
|
@@ -135,7 +159,7 @@ var HeadingPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
135
159
|
`;
|
|
136
160
|
}
|
|
137
161
|
};
|
|
138
|
-
var theme2 =
|
|
162
|
+
var theme2 = chunkW75QUUQC_cjs.createTheme({
|
|
139
163
|
default: {
|
|
140
164
|
".cm-draftly-h1": {
|
|
141
165
|
fontSize: "2em",
|
|
@@ -234,7 +258,7 @@ var highlightParser = {
|
|
|
234
258
|
);
|
|
235
259
|
}
|
|
236
260
|
};
|
|
237
|
-
var InlinePlugin = class extends
|
|
261
|
+
var InlinePlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
238
262
|
name = "inline";
|
|
239
263
|
version = "1.0.0";
|
|
240
264
|
decorationPriority = 20;
|
|
@@ -271,36 +295,47 @@ var InlinePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
271
295
|
return [
|
|
272
296
|
{
|
|
273
297
|
key: "Mod-b",
|
|
274
|
-
run:
|
|
298
|
+
run: chunkW75QUUQC_cjs.toggleMarkdownStyle("**"),
|
|
275
299
|
preventDefault: true
|
|
276
300
|
},
|
|
277
301
|
{
|
|
278
302
|
key: "Mod-i",
|
|
279
|
-
run:
|
|
303
|
+
run: chunkW75QUUQC_cjs.toggleMarkdownStyle("*"),
|
|
280
304
|
preventDefault: true
|
|
281
305
|
},
|
|
282
306
|
{
|
|
283
307
|
key: "Mod-Shift-s",
|
|
284
|
-
run:
|
|
308
|
+
run: chunkW75QUUQC_cjs.toggleMarkdownStyle("~~"),
|
|
285
309
|
preventDefault: true
|
|
286
310
|
},
|
|
287
311
|
{
|
|
288
312
|
key: "Mod-,",
|
|
289
|
-
run:
|
|
313
|
+
run: chunkW75QUUQC_cjs.toggleMarkdownStyle("~"),
|
|
290
314
|
preventDefault: true
|
|
291
315
|
},
|
|
292
316
|
{
|
|
293
317
|
key: "Mod-.",
|
|
294
|
-
run:
|
|
318
|
+
run: chunkW75QUUQC_cjs.toggleMarkdownStyle("^"),
|
|
295
319
|
preventDefault: true
|
|
296
320
|
},
|
|
297
321
|
{
|
|
298
322
|
key: "Mod-Shift-h",
|
|
299
|
-
run:
|
|
323
|
+
run: chunkW75QUUQC_cjs.toggleMarkdownStyle("=="),
|
|
300
324
|
preventDefault: true
|
|
301
325
|
}
|
|
302
326
|
];
|
|
303
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Intercepts inline marker typing to wrap selected text.
|
|
330
|
+
*
|
|
331
|
+
* If user types inline markers while text is selected, wraps each selected
|
|
332
|
+
* range with the appropriate marker:
|
|
333
|
+
* - * _ ~ ^ -> marker + selected + marker
|
|
334
|
+
* - = -> ==selected==
|
|
335
|
+
*/
|
|
336
|
+
getExtensions() {
|
|
337
|
+
return [chunk3T55CBNZ_cjs.createWrapSelectionInputHandler({ "*": "*", _: "_", "~": "~", "^": "^", "=": "==" })];
|
|
338
|
+
}
|
|
304
339
|
/**
|
|
305
340
|
* Return markdown parser extensions for highlight syntax (==text==)
|
|
306
341
|
*/
|
|
@@ -372,7 +407,7 @@ var InlinePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
372
407
|
return `<span class="${className}">${children}</span>`;
|
|
373
408
|
}
|
|
374
409
|
};
|
|
375
|
-
var theme3 =
|
|
410
|
+
var theme3 = chunkW75QUUQC_cjs.createTheme({
|
|
376
411
|
default: {
|
|
377
412
|
// Emphasis (italic)
|
|
378
413
|
".cm-draftly-emphasis": {
|
|
@@ -468,7 +503,7 @@ var LinkTooltipWidget = class extends view.WidgetType {
|
|
|
468
503
|
return event.type !== "click" && event.type !== "mouseenter" && event.type !== "mouseleave";
|
|
469
504
|
}
|
|
470
505
|
};
|
|
471
|
-
var LinkPlugin = class extends
|
|
506
|
+
var LinkPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
472
507
|
name = "link";
|
|
473
508
|
version = "1.0.0";
|
|
474
509
|
decorationPriority = 22;
|
|
@@ -672,7 +707,7 @@ var LinkTextWidget = class extends view.WidgetType {
|
|
|
672
707
|
return event.type !== "click" && event.type !== "mouseenter" && event.type !== "mouseleave";
|
|
673
708
|
}
|
|
674
709
|
};
|
|
675
|
-
var theme4 =
|
|
710
|
+
var theme4 = chunkW75QUUQC_cjs.createTheme({
|
|
676
711
|
default: {
|
|
677
712
|
// Link text
|
|
678
713
|
".cm-draftly-link-text": {
|
|
@@ -818,7 +853,7 @@ var TaskCheckboxWidget = class extends view.WidgetType {
|
|
|
818
853
|
}
|
|
819
854
|
}
|
|
820
855
|
};
|
|
821
|
-
var ListPlugin = class extends
|
|
856
|
+
var ListPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
822
857
|
name = "list";
|
|
823
858
|
version = "1.0.0";
|
|
824
859
|
decorationPriority = 20;
|
|
@@ -1021,7 +1056,7 @@ var ListPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1021
1056
|
}
|
|
1022
1057
|
}
|
|
1023
1058
|
};
|
|
1024
|
-
var theme5 =
|
|
1059
|
+
var theme5 = chunkW75QUUQC_cjs.createTheme({
|
|
1025
1060
|
default: {
|
|
1026
1061
|
// Indentation marker positioning
|
|
1027
1062
|
".cm-draftly-list-indent": {
|
|
@@ -1119,126 +1154,1487 @@ var theme5 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
1119
1154
|
}
|
|
1120
1155
|
}
|
|
1121
1156
|
});
|
|
1122
|
-
var
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
var
|
|
1127
|
-
"
|
|
1128
|
-
"
|
|
1157
|
+
var BREAK_TAG = "<br />";
|
|
1158
|
+
var BREAK_TAG_REGEX = /<br\s*\/?>/gi;
|
|
1159
|
+
var DELIMITER_CELL_PATTERN = /^:?-{3,}:?$/;
|
|
1160
|
+
var TABLE_SUB_NODE_NAMES = /* @__PURE__ */ new Set(["TableHeader", "TableDelimiter", "TableRow", "TableCell"]);
|
|
1161
|
+
var TABLE_TEMPLATE = {
|
|
1162
|
+
headers: ["Header 1", "Header 2", "Header 3"],
|
|
1163
|
+
alignments: ["left", "left", "left"],
|
|
1164
|
+
rows: [["", "", ""]]
|
|
1129
1165
|
};
|
|
1130
|
-
var
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1166
|
+
var normalizeAnnotation = state.Annotation.define();
|
|
1167
|
+
var repairSelectionAnnotation = state.Annotation.define();
|
|
1168
|
+
var pipeReplace = view.Decoration.replace({});
|
|
1169
|
+
var delimiterReplace = view.Decoration.replace({});
|
|
1170
|
+
var tableBlockWrapper = view.BlockWrapper.create({
|
|
1171
|
+
tagName: "div",
|
|
1172
|
+
attributes: { class: "cm-draftly-table-wrapper" }
|
|
1173
|
+
});
|
|
1174
|
+
var TableBreakWidget = class extends view.WidgetType {
|
|
1175
|
+
/** Reuses the same widget instance for identical break markers. */
|
|
1176
|
+
eq() {
|
|
1177
|
+
return true;
|
|
1137
1178
|
}
|
|
1179
|
+
/** Renders an inline `<br />` placeholder inside a table cell. */
|
|
1138
1180
|
toDOM() {
|
|
1139
|
-
const
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1181
|
+
const span = document.createElement("span");
|
|
1182
|
+
span.className = "cm-draftly-table-break";
|
|
1183
|
+
span.setAttribute("aria-label", "line break");
|
|
1184
|
+
span.appendChild(document.createElement("br"));
|
|
1185
|
+
return span;
|
|
1143
1186
|
}
|
|
1187
|
+
/** Allows the editor to observe events on the rendered break widget. */
|
|
1144
1188
|
ignoreEvent() {
|
|
1145
1189
|
return false;
|
|
1146
1190
|
}
|
|
1147
1191
|
};
|
|
1148
|
-
var
|
|
1149
|
-
constructor(
|
|
1192
|
+
var TableControlsWidget = class extends view.WidgetType {
|
|
1193
|
+
constructor(onAddRow, onAddColumn) {
|
|
1150
1194
|
super();
|
|
1151
|
-
this.
|
|
1195
|
+
this.onAddRow = onAddRow;
|
|
1196
|
+
this.onAddColumn = onAddColumn;
|
|
1152
1197
|
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1198
|
+
/** Forces the control widget to be recreated so handlers stay current. */
|
|
1199
|
+
eq() {
|
|
1200
|
+
return false;
|
|
1155
1201
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1202
|
+
/** Renders the hover controls used to append rows and columns. */
|
|
1203
|
+
toDOM(view) {
|
|
1204
|
+
const anchor = document.createElement("span");
|
|
1205
|
+
anchor.className = "cm-draftly-table-controls-anchor";
|
|
1206
|
+
anchor.setAttribute("aria-hidden", "true");
|
|
1207
|
+
const rightButton = this.createButton("Add column", "cm-draftly-table-control cm-draftly-table-control-column");
|
|
1208
|
+
rightButton.addEventListener("mousedown", (event) => {
|
|
1209
|
+
event.preventDefault();
|
|
1210
|
+
event.stopPropagation();
|
|
1211
|
+
this.onAddColumn(view);
|
|
1212
|
+
});
|
|
1213
|
+
const bottomButton = this.createButton("Add row", "cm-draftly-table-control cm-draftly-table-control-row");
|
|
1214
|
+
bottomButton.addEventListener("mousedown", (event) => {
|
|
1215
|
+
event.preventDefault();
|
|
1216
|
+
event.stopPropagation();
|
|
1217
|
+
this.onAddRow(view);
|
|
1218
|
+
});
|
|
1219
|
+
anchor.append(rightButton, bottomButton);
|
|
1220
|
+
return anchor;
|
|
1161
1221
|
}
|
|
1222
|
+
/** Lets button events bubble through the widget. */
|
|
1162
1223
|
ignoreEvent() {
|
|
1163
1224
|
return false;
|
|
1164
1225
|
}
|
|
1226
|
+
/** Builds a single control button with the provided label and class. */
|
|
1227
|
+
createButton(label, className) {
|
|
1228
|
+
const button = document.createElement("button");
|
|
1229
|
+
button.type = "button";
|
|
1230
|
+
button.className = className;
|
|
1231
|
+
button.setAttribute("tabindex", "-1");
|
|
1232
|
+
button.setAttribute("aria-label", label);
|
|
1233
|
+
button.textContent = "+";
|
|
1234
|
+
return button;
|
|
1235
|
+
}
|
|
1165
1236
|
};
|
|
1166
|
-
function
|
|
1167
|
-
|
|
1168
|
-
|
|
1237
|
+
function isEscaped(text, index) {
|
|
1238
|
+
let slashCount = 0;
|
|
1239
|
+
for (let i = index - 1; i >= 0 && text[i] === "\\"; i--) {
|
|
1240
|
+
slashCount++;
|
|
1241
|
+
}
|
|
1242
|
+
return slashCount % 2 === 1;
|
|
1243
|
+
}
|
|
1244
|
+
function getPipePositions(lineText) {
|
|
1245
|
+
const positions = [];
|
|
1246
|
+
for (let index = 0; index < lineText.length; index++) {
|
|
1247
|
+
if (lineText[index] === "|" && !isEscaped(lineText, index)) {
|
|
1248
|
+
positions.push(index);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return positions;
|
|
1252
|
+
}
|
|
1253
|
+
function splitTableLine(lineText) {
|
|
1254
|
+
const cells = [];
|
|
1255
|
+
const trimmed = lineText.trim();
|
|
1256
|
+
if (!trimmed.includes("|")) {
|
|
1257
|
+
return [trimmed];
|
|
1258
|
+
}
|
|
1259
|
+
let current = "";
|
|
1260
|
+
for (let index = 0; index < trimmed.length; index++) {
|
|
1261
|
+
const char = trimmed[index];
|
|
1262
|
+
if (char === "|" && !isEscaped(trimmed, index)) {
|
|
1263
|
+
cells.push(current);
|
|
1264
|
+
current = "";
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
current += char;
|
|
1268
|
+
}
|
|
1269
|
+
cells.push(current);
|
|
1270
|
+
if (trimmed.startsWith("|")) {
|
|
1271
|
+
cells.shift();
|
|
1272
|
+
}
|
|
1273
|
+
if (trimmed.endsWith("|")) {
|
|
1274
|
+
cells.pop();
|
|
1275
|
+
}
|
|
1276
|
+
return cells;
|
|
1277
|
+
}
|
|
1278
|
+
function isTableRowLine(lineText) {
|
|
1279
|
+
return getPipePositions(lineText.trim()).length > 0;
|
|
1280
|
+
}
|
|
1281
|
+
function parseAlignment(cell) {
|
|
1282
|
+
const trimmed = cell.trim();
|
|
1283
|
+
const left = trimmed.startsWith(":");
|
|
1284
|
+
const right = trimmed.endsWith(":");
|
|
1285
|
+
if (left && right) return "center";
|
|
1286
|
+
if (right) return "right";
|
|
1287
|
+
return "left";
|
|
1288
|
+
}
|
|
1289
|
+
function parseDelimiterAlignments(lineText) {
|
|
1290
|
+
const cells = splitTableLine(lineText).map((cell) => cell.trim());
|
|
1291
|
+
if (cells.length === 0 || !cells.every((cell) => DELIMITER_CELL_PATTERN.test(cell))) {
|
|
1292
|
+
return null;
|
|
1293
|
+
}
|
|
1294
|
+
return cells.map(parseAlignment);
|
|
1295
|
+
}
|
|
1296
|
+
function splitTableAndTrailingMarkdown(markdown) {
|
|
1297
|
+
const lines = markdown.split("\n");
|
|
1298
|
+
if (lines.length < 2) {
|
|
1299
|
+
return { tableMarkdown: markdown, trailingMarkdown: "" };
|
|
1300
|
+
}
|
|
1301
|
+
const headerLine = lines[0] || "";
|
|
1302
|
+
const delimiterLine = lines[1] || "";
|
|
1303
|
+
if (!isTableRowLine(headerLine) || !parseDelimiterAlignments(delimiterLine)) {
|
|
1304
|
+
return { tableMarkdown: markdown, trailingMarkdown: "" };
|
|
1305
|
+
}
|
|
1306
|
+
let endIndex = 1;
|
|
1307
|
+
for (let index = 2; index < lines.length; index++) {
|
|
1308
|
+
if (!isTableRowLine(lines[index] || "")) {
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
endIndex = index;
|
|
1312
|
+
}
|
|
1169
1313
|
return {
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
isSelfClosing: match[3] === "/" || ["br", "hr", "img", "input", "meta", "link", "area", "base", "col", "embed", "source", "track", "wbr"].includes(
|
|
1173
|
-
match[2].toLowerCase()
|
|
1174
|
-
)
|
|
1314
|
+
tableMarkdown: lines.slice(0, endIndex + 1).join("\n"),
|
|
1315
|
+
trailingMarkdown: lines.slice(endIndex + 1).join("\n")
|
|
1175
1316
|
};
|
|
1176
1317
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1318
|
+
function canonicalizeBreakTags(text) {
|
|
1319
|
+
return text.replace(BREAK_TAG_REGEX, BREAK_TAG);
|
|
1320
|
+
}
|
|
1321
|
+
function escapeUnescapedPipes(text) {
|
|
1322
|
+
let result = "";
|
|
1323
|
+
for (let index = 0; index < text.length; index++) {
|
|
1324
|
+
const char = text[index];
|
|
1325
|
+
if (char === "|" && !isEscaped(text, index)) {
|
|
1326
|
+
result += "\\|";
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
result += char;
|
|
1183
1330
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1331
|
+
return result;
|
|
1332
|
+
}
|
|
1333
|
+
function normalizeCellContent(text) {
|
|
1334
|
+
const normalizedBreaks = canonicalizeBreakTags(text.trim());
|
|
1335
|
+
if (!normalizedBreaks) {
|
|
1336
|
+
return "";
|
|
1337
|
+
}
|
|
1338
|
+
const parts = normalizedBreaks.split(BREAK_TAG_REGEX).map((part) => escapeUnescapedPipes(part.trim()));
|
|
1339
|
+
if (parts.length === 1) {
|
|
1340
|
+
return parts[0] || "";
|
|
1341
|
+
}
|
|
1342
|
+
return parts.join(` ${BREAK_TAG} `).trim();
|
|
1343
|
+
}
|
|
1344
|
+
function renderWidth(text) {
|
|
1345
|
+
return canonicalizeBreakTags(text).replace(BREAK_TAG, " ").replace(/\\\|/g, "|").length;
|
|
1346
|
+
}
|
|
1347
|
+
function padCell(text, width, alignment) {
|
|
1348
|
+
const safeWidth = Math.max(width, renderWidth(text));
|
|
1349
|
+
const difference = safeWidth - renderWidth(text);
|
|
1350
|
+
if (difference <= 0) {
|
|
1351
|
+
return text;
|
|
1352
|
+
}
|
|
1353
|
+
if (alignment === "right") {
|
|
1354
|
+
return " ".repeat(difference) + text;
|
|
1355
|
+
}
|
|
1356
|
+
if (alignment === "center") {
|
|
1357
|
+
const left = Math.floor(difference / 2);
|
|
1358
|
+
const right = difference - left;
|
|
1359
|
+
return " ".repeat(left) + text + " ".repeat(right);
|
|
1360
|
+
}
|
|
1361
|
+
return text + " ".repeat(difference);
|
|
1362
|
+
}
|
|
1363
|
+
function delimiterCell(width, alignment) {
|
|
1364
|
+
const hyphenCount = Math.max(width, 3);
|
|
1365
|
+
if (alignment === "center") {
|
|
1366
|
+
return ":" + "-".repeat(Math.max(1, hyphenCount - 2)) + ":";
|
|
1367
|
+
}
|
|
1368
|
+
if (alignment === "right") {
|
|
1369
|
+
return "-".repeat(Math.max(2, hyphenCount - 1)) + ":";
|
|
1370
|
+
}
|
|
1371
|
+
return "-".repeat(hyphenCount);
|
|
1372
|
+
}
|
|
1373
|
+
function parseTableMarkdown(markdown) {
|
|
1374
|
+
const { tableMarkdown } = splitTableAndTrailingMarkdown(markdown);
|
|
1375
|
+
const lines = tableMarkdown.split("\n");
|
|
1376
|
+
if (lines.length < 2) {
|
|
1377
|
+
return null;
|
|
1378
|
+
}
|
|
1379
|
+
const headers = splitTableLine(lines[0] || "").map((cell) => cell.trim());
|
|
1380
|
+
const alignments = parseDelimiterAlignments(lines[1] || "");
|
|
1381
|
+
if (!alignments) {
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
const rows = lines.slice(2).filter((line) => isTableRowLine(line)).map((line) => splitTableLine(line).map((cell) => cell.trim()));
|
|
1385
|
+
return { headers, alignments, rows };
|
|
1386
|
+
}
|
|
1387
|
+
function normalizeParsedTable(parsed) {
|
|
1388
|
+
const columnCount = Math.max(
|
|
1389
|
+
parsed.headers.length,
|
|
1390
|
+
parsed.alignments.length,
|
|
1391
|
+
...parsed.rows.map((row) => row.length),
|
|
1392
|
+
1
|
|
1393
|
+
);
|
|
1394
|
+
const headers = Array.from({ length: columnCount }, (_, index) => normalizeCellContent(parsed.headers[index] || ""));
|
|
1395
|
+
const alignments = Array.from({ length: columnCount }, (_, index) => parsed.alignments[index] || "left");
|
|
1396
|
+
const rows = parsed.rows.map(
|
|
1397
|
+
(row) => Array.from({ length: columnCount }, (_, index) => normalizeCellContent(row[index] || ""))
|
|
1398
|
+
);
|
|
1399
|
+
return { headers, alignments, rows };
|
|
1400
|
+
}
|
|
1401
|
+
function formatTableMarkdown(parsed) {
|
|
1402
|
+
const normalized = normalizeParsedTable(parsed);
|
|
1403
|
+
const widths = normalized.headers.map(
|
|
1404
|
+
(header, index) => Math.max(renderWidth(header), ...normalized.rows.map((row) => renderWidth(row[index] || "")), 3)
|
|
1405
|
+
);
|
|
1406
|
+
const formatRow = (cells) => `| ${cells.map((cell, index) => padCell(cell, widths[index] || 3, normalized.alignments[index] || "left")).join(" | ")} |`;
|
|
1407
|
+
const headerLine = formatRow(normalized.headers);
|
|
1408
|
+
const delimiterLine = `| ${normalized.alignments.map((alignment, index) => delimiterCell(widths[index] || 3, alignment)).join(" | ")} |`;
|
|
1409
|
+
const bodyLines = normalized.rows.map((row) => formatRow(row));
|
|
1410
|
+
return [headerLine, delimiterLine, ...bodyLines].join("\n");
|
|
1411
|
+
}
|
|
1412
|
+
function buildEmptyRow(columnCount) {
|
|
1413
|
+
return Array.from({ length: columnCount }, () => "");
|
|
1414
|
+
}
|
|
1415
|
+
function createPreviewRenderer(markdown, config) {
|
|
1416
|
+
const plugins = (config?.plugins || []).filter((plugin) => plugin.name !== "paragraph");
|
|
1417
|
+
return new chunkCLW73JRX_cjs.PreviewRenderer(markdown, plugins, config?.markdown || [], config?.theme || "auto" /* AUTO */, true);
|
|
1418
|
+
}
|
|
1419
|
+
function stripSingleParagraph(html) {
|
|
1420
|
+
const trimmed = html.trim();
|
|
1421
|
+
const match = trimmed.match(/^<p\b[^>]*>([\s\S]*)<\/p>$/i);
|
|
1422
|
+
return match?.[1] || trimmed;
|
|
1423
|
+
}
|
|
1424
|
+
async function renderCellToHtml(text, config) {
|
|
1425
|
+
if (!text.trim()) {
|
|
1426
|
+
return " ";
|
|
1427
|
+
}
|
|
1428
|
+
return stripSingleParagraph(await createPreviewRenderer(text, config).render());
|
|
1429
|
+
}
|
|
1430
|
+
async function renderTableToHtml(parsed, config) {
|
|
1431
|
+
const normalized = normalizeParsedTable(parsed);
|
|
1432
|
+
let html = '<div class="cm-draftly-table-widget"><table class="cm-draftly-table cm-draftly-table-preview">';
|
|
1433
|
+
html += '<thead><tr class="cm-draftly-table-row cm-draftly-table-header-row">';
|
|
1434
|
+
for (let index = 0; index < normalized.headers.length; index++) {
|
|
1435
|
+
const alignment = normalized.alignments[index] || "left";
|
|
1436
|
+
const content = await renderCellToHtml(normalized.headers[index] || "", config);
|
|
1437
|
+
html += `<th class="cm-draftly-table-cell cm-draftly-table-th${alignment === "center" ? " cm-draftly-table-cell-center" : alignment === "right" ? " cm-draftly-table-cell-right" : ""}${index === normalized.headers.length - 1 ? " cm-draftly-table-cell-last" : ""}">${content}</th>`;
|
|
1438
|
+
}
|
|
1439
|
+
html += "</tr></thead><tbody>";
|
|
1440
|
+
for (let rowIndex = 0; rowIndex < normalized.rows.length; rowIndex++) {
|
|
1441
|
+
const row = normalized.rows[rowIndex] || [];
|
|
1442
|
+
html += `<tr class="cm-draftly-table-row cm-draftly-table-body-row${rowIndex % 2 === 1 ? " cm-draftly-table-row-even" : ""}${rowIndex === normalized.rows.length - 1 ? " cm-draftly-table-row-last" : ""}">`;
|
|
1443
|
+
for (let index = 0; index < normalized.headers.length; index++) {
|
|
1444
|
+
const alignment = normalized.alignments[index] || "left";
|
|
1445
|
+
const content = await renderCellToHtml(row[index] || "", config);
|
|
1446
|
+
html += `<td class="cm-draftly-table-cell${alignment === "center" ? " cm-draftly-table-cell-center" : alignment === "right" ? " cm-draftly-table-cell-right" : ""}${index === normalized.headers.length - 1 ? " cm-draftly-table-cell-last" : ""}">${content}</td>`;
|
|
1447
|
+
}
|
|
1448
|
+
html += "</tr>";
|
|
1449
|
+
}
|
|
1450
|
+
html += "</tbody></table></div>";
|
|
1451
|
+
return html;
|
|
1452
|
+
}
|
|
1453
|
+
function getVisibleBounds(rawCellText) {
|
|
1454
|
+
const leading = rawCellText.length - rawCellText.trimStart().length;
|
|
1455
|
+
const trailing = rawCellText.length - rawCellText.trimEnd().length;
|
|
1456
|
+
const trimmedLength = rawCellText.trim().length;
|
|
1457
|
+
if (trimmedLength === 0) {
|
|
1458
|
+
const placeholderOffset = Math.min(Math.floor(rawCellText.length / 2), Math.max(rawCellText.length - 1, 0));
|
|
1459
|
+
return {
|
|
1460
|
+
startOffset: placeholderOffset,
|
|
1461
|
+
endOffset: Math.min(placeholderOffset + 1, rawCellText.length)
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
return {
|
|
1465
|
+
startOffset: leading,
|
|
1466
|
+
endOffset: rawCellText.length - trailing
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
function isBodyRowEmpty(row) {
|
|
1470
|
+
return row.every((cell) => normalizeCellContent(cell.rawText) === "");
|
|
1471
|
+
}
|
|
1472
|
+
function buildTableFromInfo(tableInfo) {
|
|
1473
|
+
return {
|
|
1474
|
+
headers: tableInfo.headerCells.map((cell) => normalizeCellContent(cell.rawText)),
|
|
1475
|
+
alignments: [...tableInfo.alignments],
|
|
1476
|
+
rows: tableInfo.bodyCells.map((row) => row.map((cell) => normalizeCellContent(cell.rawText)))
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
function getRowLineIndex(rowIndex) {
|
|
1480
|
+
return rowIndex === 0 ? 0 : rowIndex + 1;
|
|
1481
|
+
}
|
|
1482
|
+
function getCellAnchorInFormattedTable(formattedTable, rowIndex, columnIndex, offset = 0) {
|
|
1483
|
+
const lines = formattedTable.split("\n");
|
|
1484
|
+
const lineIndex = getRowLineIndex(rowIndex);
|
|
1485
|
+
const lineText = lines[lineIndex] || "";
|
|
1486
|
+
const pipes = getPipePositions(lineText);
|
|
1487
|
+
if (pipes.length < columnIndex + 2) {
|
|
1488
|
+
return formattedTable.length;
|
|
1489
|
+
}
|
|
1490
|
+
const rawFrom = pipes[columnIndex] + 1;
|
|
1491
|
+
const rawTo = pipes[columnIndex + 1];
|
|
1492
|
+
const visible = getVisibleBounds(lineText.slice(rawFrom, rawTo));
|
|
1493
|
+
const lineOffset = lines.slice(0, lineIndex).reduce((sum, line) => sum + line.length + 1, 0);
|
|
1494
|
+
return lineOffset + Math.min(rawFrom + visible.startOffset + offset, rawFrom + Math.max(visible.endOffset - 1, visible.startOffset));
|
|
1495
|
+
}
|
|
1496
|
+
function createTableInsert(state, from, to, tableMarkdown) {
|
|
1497
|
+
let insert = tableMarkdown;
|
|
1498
|
+
let prefixLength = 0;
|
|
1499
|
+
const startLine = state.doc.lineAt(from);
|
|
1500
|
+
if (startLine.number === 1 || state.doc.line(startLine.number - 1).text.trim() !== "") {
|
|
1501
|
+
insert = "\n" + insert;
|
|
1502
|
+
prefixLength = 1;
|
|
1503
|
+
}
|
|
1504
|
+
const endLine = state.doc.lineAt(Math.max(from, to));
|
|
1505
|
+
if (endLine.number === state.doc.lines || state.doc.line(endLine.number + 1).text.trim() !== "") {
|
|
1506
|
+
insert += "\n";
|
|
1507
|
+
}
|
|
1508
|
+
return { from, to, insert, prefixLength };
|
|
1509
|
+
}
|
|
1510
|
+
function readTableInfo(state, nodeFrom, nodeTo) {
|
|
1511
|
+
const startLine = state.doc.lineAt(nodeFrom);
|
|
1512
|
+
const endLine = state.doc.lineAt(nodeTo);
|
|
1513
|
+
const delimiterLineNumber = startLine.number + 1;
|
|
1514
|
+
if (delimiterLineNumber > endLine.number) {
|
|
1515
|
+
return null;
|
|
1516
|
+
}
|
|
1517
|
+
const delimiterLine = state.doc.line(delimiterLineNumber);
|
|
1518
|
+
const alignments = parseDelimiterAlignments(delimiterLine.text);
|
|
1519
|
+
if (!alignments) {
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
let effectiveEndLineNumber = delimiterLineNumber;
|
|
1523
|
+
for (let lineNumber = delimiterLineNumber + 1; lineNumber <= endLine.number; lineNumber++) {
|
|
1524
|
+
const line = state.doc.line(lineNumber);
|
|
1525
|
+
if (!isTableRowLine(line.text)) {
|
|
1526
|
+
break;
|
|
1527
|
+
}
|
|
1528
|
+
effectiveEndLineNumber = lineNumber;
|
|
1529
|
+
}
|
|
1530
|
+
const cellsByRow = [];
|
|
1531
|
+
for (let lineNumber = startLine.number; lineNumber <= effectiveEndLineNumber; lineNumber++) {
|
|
1532
|
+
if (lineNumber === delimiterLineNumber) {
|
|
1533
|
+
continue;
|
|
1534
|
+
}
|
|
1535
|
+
const line = state.doc.line(lineNumber);
|
|
1536
|
+
const pipes = getPipePositions(line.text);
|
|
1537
|
+
if (pipes.length < 2) {
|
|
1538
|
+
return null;
|
|
1539
|
+
}
|
|
1540
|
+
const isHeader = lineNumber === startLine.number;
|
|
1541
|
+
const rowIndex = isHeader ? 0 : cellsByRow.length;
|
|
1542
|
+
const cells = [];
|
|
1543
|
+
for (let columnIndex = 0; columnIndex < pipes.length - 1; columnIndex++) {
|
|
1544
|
+
const from = line.from + pipes[columnIndex] + 1;
|
|
1545
|
+
const to = line.from + pipes[columnIndex + 1];
|
|
1546
|
+
const rawText = line.text.slice(pipes[columnIndex] + 1, pipes[columnIndex + 1]);
|
|
1547
|
+
const visible = getVisibleBounds(rawText);
|
|
1548
|
+
cells.push({
|
|
1549
|
+
rowKind: isHeader ? "header" : "body",
|
|
1550
|
+
rowIndex,
|
|
1551
|
+
columnIndex,
|
|
1552
|
+
from,
|
|
1553
|
+
to,
|
|
1554
|
+
contentFrom: from + visible.startOffset,
|
|
1555
|
+
contentTo: from + visible.endOffset,
|
|
1556
|
+
lineFrom: line.from,
|
|
1557
|
+
lineNumber,
|
|
1558
|
+
rawText
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
cellsByRow.push(cells);
|
|
1562
|
+
}
|
|
1563
|
+
if (cellsByRow.length === 0) {
|
|
1564
|
+
return null;
|
|
1565
|
+
}
|
|
1566
|
+
return {
|
|
1567
|
+
from: startLine.from,
|
|
1568
|
+
to: state.doc.line(effectiveEndLineNumber).to,
|
|
1569
|
+
startLineNumber: startLine.number,
|
|
1570
|
+
delimiterLineNumber,
|
|
1571
|
+
endLineNumber: effectiveEndLineNumber,
|
|
1572
|
+
columnCount: cellsByRow[0].length,
|
|
1573
|
+
alignments: Array.from({ length: cellsByRow[0].length }, (_, index) => alignments[index] || "left"),
|
|
1574
|
+
cellsByRow,
|
|
1575
|
+
headerCells: cellsByRow[0],
|
|
1576
|
+
bodyCells: cellsByRow.slice(1)
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
function getTableInfoAtPosition(state, position) {
|
|
1580
|
+
let resolved = null;
|
|
1581
|
+
language.syntaxTree(state).iterate({
|
|
1582
|
+
enter: (node) => {
|
|
1583
|
+
if (resolved || node.name !== "Table") {
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
const info = readTableInfo(state, node.from, node.to);
|
|
1587
|
+
if (info && position >= info.from && position <= info.to) {
|
|
1588
|
+
resolved = info;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
});
|
|
1592
|
+
return resolved;
|
|
1593
|
+
}
|
|
1594
|
+
function findCellAtPosition(tableInfo, position) {
|
|
1595
|
+
for (const row of tableInfo.cellsByRow) {
|
|
1596
|
+
for (const cell of row) {
|
|
1597
|
+
if (position >= cell.from && position <= cell.to) {
|
|
1598
|
+
return cell;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
for (const row of tableInfo.cellsByRow) {
|
|
1603
|
+
for (const cell of row) {
|
|
1604
|
+
if (position >= cell.from - 1 && position <= cell.to + 1) {
|
|
1605
|
+
return cell;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
let nearestCell = null;
|
|
1610
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
1611
|
+
for (const row of tableInfo.cellsByRow) {
|
|
1612
|
+
for (const cell of row) {
|
|
1613
|
+
const distance = Math.min(Math.abs(position - cell.from), Math.abs(position - cell.to));
|
|
1614
|
+
if (distance < nearestDistance) {
|
|
1615
|
+
nearestCell = cell;
|
|
1616
|
+
nearestDistance = distance;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
return nearestCell;
|
|
1621
|
+
}
|
|
1622
|
+
function clampCellPosition(cell, position) {
|
|
1623
|
+
const cellEnd = Math.max(cell.contentFrom, cell.contentTo);
|
|
1624
|
+
return Math.max(cell.contentFrom, Math.min(position, cellEnd));
|
|
1625
|
+
}
|
|
1626
|
+
function collectBreakRanges(tableInfo) {
|
|
1627
|
+
const ranges = [];
|
|
1628
|
+
for (const row of tableInfo.cellsByRow) {
|
|
1629
|
+
for (const cell of row) {
|
|
1630
|
+
let match;
|
|
1631
|
+
const regex = new RegExp(BREAK_TAG_REGEX);
|
|
1632
|
+
while ((match = regex.exec(cell.rawText)) !== null) {
|
|
1633
|
+
ranges.push({
|
|
1634
|
+
from: cell.from + match.index,
|
|
1635
|
+
to: cell.from + match.index + match[0].length
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
return ranges;
|
|
1641
|
+
}
|
|
1642
|
+
var lineDecorations = {
|
|
1643
|
+
header: view.Decoration.line({ class: "cm-draftly-table-row cm-draftly-table-header-row" }),
|
|
1644
|
+
delimiter: view.Decoration.line({ class: "cm-draftly-table-row cm-draftly-table-delimiter-row" }),
|
|
1645
|
+
body: view.Decoration.line({ class: "cm-draftly-table-row cm-draftly-table-body-row" }),
|
|
1646
|
+
even: view.Decoration.line({ class: "cm-draftly-table-row cm-draftly-table-body-row cm-draftly-table-row-even" }),
|
|
1647
|
+
last: view.Decoration.line({ class: "cm-draftly-table-row-last" })
|
|
1648
|
+
};
|
|
1649
|
+
var cellDecorations = {
|
|
1650
|
+
"th-left": view.Decoration.mark({ class: "cm-draftly-table-cell cm-draftly-table-th" }),
|
|
1651
|
+
"th-center": view.Decoration.mark({ class: "cm-draftly-table-cell cm-draftly-table-th cm-draftly-table-cell-center" }),
|
|
1652
|
+
"th-right": view.Decoration.mark({ class: "cm-draftly-table-cell cm-draftly-table-th cm-draftly-table-cell-right" }),
|
|
1653
|
+
"th-left-last": view.Decoration.mark({ class: "cm-draftly-table-cell cm-draftly-table-th cm-draftly-table-cell-last" }),
|
|
1654
|
+
"th-center-last": view.Decoration.mark({
|
|
1655
|
+
class: "cm-draftly-table-cell cm-draftly-table-th cm-draftly-table-cell-center cm-draftly-table-cell-last"
|
|
1656
|
+
}),
|
|
1657
|
+
"th-right-last": view.Decoration.mark({
|
|
1658
|
+
class: "cm-draftly-table-cell cm-draftly-table-th cm-draftly-table-cell-right cm-draftly-table-cell-last"
|
|
1659
|
+
}),
|
|
1660
|
+
"td-left": view.Decoration.mark({ class: "cm-draftly-table-cell" }),
|
|
1661
|
+
"td-center": view.Decoration.mark({ class: "cm-draftly-table-cell cm-draftly-table-cell-center" }),
|
|
1662
|
+
"td-right": view.Decoration.mark({ class: "cm-draftly-table-cell cm-draftly-table-cell-right" }),
|
|
1663
|
+
"td-left-last": view.Decoration.mark({ class: "cm-draftly-table-cell cm-draftly-table-cell-last" }),
|
|
1664
|
+
"td-center-last": view.Decoration.mark({
|
|
1665
|
+
class: "cm-draftly-table-cell cm-draftly-table-cell-center cm-draftly-table-cell-last"
|
|
1666
|
+
}),
|
|
1667
|
+
"td-right-last": view.Decoration.mark({
|
|
1668
|
+
class: "cm-draftly-table-cell cm-draftly-table-cell-right cm-draftly-table-cell-last"
|
|
1669
|
+
})
|
|
1670
|
+
};
|
|
1671
|
+
function getCellDecoration(isHeader, alignment, isLastCell) {
|
|
1672
|
+
const key = `${isHeader ? "th" : "td"}-${alignment}${isLastCell ? "-last" : ""}`;
|
|
1673
|
+
return cellDecorations[key];
|
|
1674
|
+
}
|
|
1675
|
+
var TablePlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
1676
|
+
name = "table";
|
|
1677
|
+
version = "2.0.0";
|
|
1678
|
+
decorationPriority = 20;
|
|
1679
|
+
requiredNodes = ["Table", "TableHeader", "TableDelimiter", "TableRow", "TableCell"];
|
|
1680
|
+
draftlyConfig;
|
|
1681
|
+
pendingNormalizationView = null;
|
|
1682
|
+
pendingPaddingView = null;
|
|
1683
|
+
pendingSelectionRepairView = null;
|
|
1684
|
+
/** Stores the editor config for preview rendering and shared behavior. */
|
|
1685
|
+
onRegister(context) {
|
|
1686
|
+
super.onRegister(context);
|
|
1687
|
+
this.draftlyConfig = context.config;
|
|
1688
|
+
}
|
|
1689
|
+
/** Exposes the plugin theme used for editor and preview styling. */
|
|
1187
1690
|
get theme() {
|
|
1188
1691
|
return theme6;
|
|
1189
1692
|
}
|
|
1693
|
+
/** Enables GFM table parsing for the editor and preview renderer. */
|
|
1694
|
+
getMarkdownConfig() {
|
|
1695
|
+
return markdown.Table;
|
|
1696
|
+
}
|
|
1697
|
+
/** Registers block wrappers and atomic ranges for the table UI. */
|
|
1698
|
+
getExtensions() {
|
|
1699
|
+
return [
|
|
1700
|
+
state.Prec.highest(view.keymap.of(this.buildTableKeymap())),
|
|
1701
|
+
view.EditorView.blockWrappers.of((view) => this.computeBlockWrappers(view)),
|
|
1702
|
+
view.EditorView.atomicRanges.of((view) => this.computeAtomicRanges(view)),
|
|
1703
|
+
view.EditorView.domEventHandlers({
|
|
1704
|
+
keydown: (event, view) => this.handleDomKeydown(view, event)
|
|
1705
|
+
})
|
|
1706
|
+
];
|
|
1707
|
+
}
|
|
1708
|
+
/** Provides the table-specific keyboard shortcuts and navigation. */
|
|
1709
|
+
getKeymap() {
|
|
1710
|
+
return [];
|
|
1711
|
+
}
|
|
1712
|
+
/** Builds the high-priority key bindings used inside tables. */
|
|
1713
|
+
buildTableKeymap() {
|
|
1714
|
+
return [
|
|
1715
|
+
{ key: "Mod-Shift-t", run: (view) => this.insertTable(view), preventDefault: true },
|
|
1716
|
+
{ key: "Mod-Alt-ArrowDown", run: (view) => this.addRow(view), preventDefault: true },
|
|
1717
|
+
{ key: "Mod-Alt-ArrowRight", run: (view) => this.addColumn(view), preventDefault: true },
|
|
1718
|
+
{ key: "Mod-Alt-Backspace", run: (view) => this.removeRow(view), preventDefault: true },
|
|
1719
|
+
{ key: "Mod-Alt-Delete", run: (view) => this.removeColumn(view), preventDefault: true },
|
|
1720
|
+
{ key: "Tab", run: (view) => this.handleTab(view, false) },
|
|
1721
|
+
{ key: "Shift-Tab", run: (view) => this.handleTab(view, true) },
|
|
1722
|
+
{ key: "ArrowLeft", run: (view) => this.handleArrowHorizontal(view, false) },
|
|
1723
|
+
{ key: "ArrowRight", run: (view) => this.handleArrowHorizontal(view, true) },
|
|
1724
|
+
{ key: "ArrowUp", run: (view) => this.handleArrowVertical(view, false) },
|
|
1725
|
+
{ key: "ArrowDown", run: (view) => this.handleArrowVertical(view, true) },
|
|
1726
|
+
{ key: "Enter", run: (view) => this.handleEnter(view) },
|
|
1727
|
+
{ key: "Shift-Enter", run: (view) => this.insertBreakTag(view), preventDefault: true },
|
|
1728
|
+
{ key: "Backspace", run: (view) => this.handleBreakDeletion(view, false) },
|
|
1729
|
+
{ key: "Delete", run: (view) => this.handleBreakDeletion(view, true) }
|
|
1730
|
+
];
|
|
1731
|
+
}
|
|
1732
|
+
/** Schedules an initial normalization pass once the view is ready. */
|
|
1733
|
+
onViewReady(view) {
|
|
1734
|
+
this.scheduleNormalization(view);
|
|
1735
|
+
}
|
|
1736
|
+
/** Re-schedules normalization after user-driven document changes. */
|
|
1737
|
+
onViewUpdate(update) {
|
|
1738
|
+
if (update.docChanged && !update.transactions.some((transaction) => transaction.annotation(normalizeAnnotation))) {
|
|
1739
|
+
this.schedulePadding(update.view);
|
|
1740
|
+
}
|
|
1741
|
+
if (update.selectionSet && !update.transactions.some((transaction) => transaction.annotation(repairSelectionAnnotation))) {
|
|
1742
|
+
this.scheduleSelectionRepair(update.view);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
/** Intercepts table-specific DOM key handling before browser defaults run. */
|
|
1746
|
+
handleDomKeydown(view, event) {
|
|
1747
|
+
if (event.defaultPrevented || event.isComposing || event.altKey || event.metaKey || event.ctrlKey) {
|
|
1748
|
+
return false;
|
|
1749
|
+
}
|
|
1750
|
+
let handled = false;
|
|
1751
|
+
if (event.key === "Tab") {
|
|
1752
|
+
handled = this.handleTab(view, event.shiftKey);
|
|
1753
|
+
} else if (event.key === "Enter" && event.shiftKey) {
|
|
1754
|
+
handled = this.insertBreakTag(view);
|
|
1755
|
+
} else if (event.key === "Enter") {
|
|
1756
|
+
handled = this.handleEnter(view);
|
|
1757
|
+
} else if (event.key === "ArrowLeft") {
|
|
1758
|
+
handled = this.handleArrowHorizontal(view, false);
|
|
1759
|
+
} else if (event.key === "ArrowRight") {
|
|
1760
|
+
handled = this.handleArrowHorizontal(view, true);
|
|
1761
|
+
} else if (event.key === "ArrowUp") {
|
|
1762
|
+
handled = this.handleArrowVertical(view, false);
|
|
1763
|
+
} else if (event.key === "ArrowDown") {
|
|
1764
|
+
handled = this.handleArrowVertical(view, true);
|
|
1765
|
+
} else if (event.key === "Backspace") {
|
|
1766
|
+
handled = this.handleBreakDeletion(view, false);
|
|
1767
|
+
} else if (event.key === "Delete") {
|
|
1768
|
+
handled = this.handleBreakDeletion(view, true);
|
|
1769
|
+
}
|
|
1770
|
+
if (handled) {
|
|
1771
|
+
event.preventDefault();
|
|
1772
|
+
event.stopPropagation();
|
|
1773
|
+
}
|
|
1774
|
+
return handled;
|
|
1775
|
+
}
|
|
1776
|
+
/** Builds the visual table decorations for every parsed table block. */
|
|
1190
1777
|
buildDecorations(ctx) {
|
|
1191
|
-
const { view
|
|
1192
|
-
|
|
1193
|
-
const htmlGroups = [];
|
|
1194
|
-
const htmlTags = [];
|
|
1195
|
-
tree.iterate({
|
|
1778
|
+
const { view, decorations } = ctx;
|
|
1779
|
+
language.syntaxTree(view.state).iterate({
|
|
1196
1780
|
enter: (node) => {
|
|
1197
|
-
|
|
1198
|
-
if (name === "Comment") {
|
|
1199
|
-
decorations.push(htmlMarkDecorations["html-comment"].range(from, to));
|
|
1781
|
+
if (node.name !== "Table") {
|
|
1200
1782
|
return;
|
|
1201
1783
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
if (parsed) {
|
|
1206
|
-
htmlTags.push({
|
|
1207
|
-
from,
|
|
1208
|
-
to,
|
|
1209
|
-
tagName: parsed.tagName,
|
|
1210
|
-
isClosing: parsed.isClosing,
|
|
1211
|
-
isSelfClosing: parsed.isSelfClosing
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1784
|
+
const tableInfo = readTableInfo(view.state, node.from, node.to);
|
|
1785
|
+
if (tableInfo) {
|
|
1786
|
+
this.decorateTable(view, decorations, tableInfo);
|
|
1214
1787
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1788
|
+
}
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
/** Renders the full table node to semantic preview HTML. */
|
|
1792
|
+
async renderToHTML(node, _children, ctx) {
|
|
1793
|
+
if (node.name === "Table") {
|
|
1794
|
+
const content = ctx.sliceDoc(node.from, node.to);
|
|
1795
|
+
const { tableMarkdown, trailingMarkdown } = splitTableAndTrailingMarkdown(content);
|
|
1796
|
+
const parsed = parseTableMarkdown(tableMarkdown);
|
|
1797
|
+
if (!parsed) {
|
|
1798
|
+
return null;
|
|
1799
|
+
}
|
|
1800
|
+
const tableHtml = await renderTableToHtml(parsed, this.draftlyConfig);
|
|
1801
|
+
if (!trailingMarkdown.trim()) {
|
|
1802
|
+
return tableHtml;
|
|
1803
|
+
}
|
|
1804
|
+
return tableHtml + await createPreviewRenderer(trailingMarkdown, this.draftlyConfig).render();
|
|
1805
|
+
}
|
|
1806
|
+
if (TABLE_SUB_NODE_NAMES.has(node.name)) {
|
|
1807
|
+
return "";
|
|
1808
|
+
}
|
|
1809
|
+
return null;
|
|
1810
|
+
}
|
|
1811
|
+
/** Computes the block wrapper ranges used to group table lines. */
|
|
1812
|
+
computeBlockWrappers(view$1) {
|
|
1813
|
+
const wrappers = [];
|
|
1814
|
+
language.syntaxTree(view$1.state).iterate({
|
|
1815
|
+
enter: (node) => {
|
|
1816
|
+
if (node.name !== "Table") {
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
const tableInfo = readTableInfo(view$1.state, node.from, node.to);
|
|
1820
|
+
if (tableInfo) {
|
|
1821
|
+
wrappers.push(tableBlockWrapper.range(tableInfo.from, tableInfo.to));
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
});
|
|
1825
|
+
return view.BlockWrapper.set(wrappers, true);
|
|
1826
|
+
}
|
|
1827
|
+
/** Computes atomic ranges for delimiters and inline break tags. */
|
|
1828
|
+
computeAtomicRanges(view$1) {
|
|
1829
|
+
const ranges = [];
|
|
1830
|
+
language.syntaxTree(view$1.state).iterate({
|
|
1831
|
+
enter: (node) => {
|
|
1832
|
+
if (node.name !== "Table") {
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
const tableInfo = readTableInfo(view$1.state, node.from, node.to);
|
|
1836
|
+
if (!tableInfo) {
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
for (let lineNumber = tableInfo.startLineNumber; lineNumber <= tableInfo.endLineNumber; lineNumber++) {
|
|
1840
|
+
const line = view$1.state.doc.line(lineNumber);
|
|
1841
|
+
if (lineNumber === tableInfo.delimiterLineNumber) {
|
|
1842
|
+
ranges.push(delimiterReplace.range(line.from, line.to));
|
|
1843
|
+
continue;
|
|
1844
|
+
}
|
|
1845
|
+
const pipes = getPipePositions(line.text);
|
|
1846
|
+
for (const pipe of pipes) {
|
|
1847
|
+
ranges.push(pipeReplace.range(line.from + pipe, line.from + pipe + 1));
|
|
1848
|
+
}
|
|
1849
|
+
for (let columnIndex = 0; columnIndex < pipes.length - 1; columnIndex++) {
|
|
1850
|
+
const rawFrom = pipes[columnIndex] + 1;
|
|
1851
|
+
const rawTo = pipes[columnIndex + 1];
|
|
1852
|
+
const rawText = line.text.slice(rawFrom, rawTo);
|
|
1853
|
+
const visible = getVisibleBounds(rawText);
|
|
1854
|
+
if (visible.startOffset > 0) {
|
|
1855
|
+
ranges.push(pipeReplace.range(line.from + rawFrom, line.from + rawFrom + visible.startOffset));
|
|
1856
|
+
}
|
|
1857
|
+
if (visible.endOffset < rawText.length) {
|
|
1858
|
+
ranges.push(pipeReplace.range(line.from + rawFrom + visible.endOffset, line.from + rawTo));
|
|
1859
|
+
}
|
|
1860
|
+
let match;
|
|
1861
|
+
const regex = new RegExp(BREAK_TAG_REGEX);
|
|
1862
|
+
while ((match = regex.exec(rawText)) !== null) {
|
|
1863
|
+
ranges.push(
|
|
1864
|
+
view.Decoration.replace({ widget: new TableBreakWidget() }).range(
|
|
1865
|
+
line.from + rawFrom + match.index,
|
|
1866
|
+
line.from + rawFrom + match.index + match[0].length
|
|
1867
|
+
)
|
|
1868
|
+
);
|
|
1222
1869
|
}
|
|
1223
1870
|
}
|
|
1224
|
-
htmlGroups.push({ from, to });
|
|
1225
1871
|
}
|
|
1226
1872
|
}
|
|
1227
1873
|
});
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1874
|
+
return state.RangeSet.of(ranges, true);
|
|
1875
|
+
}
|
|
1876
|
+
/** Applies row, cell, and control decorations for a single table. */
|
|
1877
|
+
decorateTable(view$1, decorations, tableInfo) {
|
|
1878
|
+
for (let lineNumber = tableInfo.startLineNumber; lineNumber <= tableInfo.endLineNumber; lineNumber++) {
|
|
1879
|
+
const line = view$1.state.doc.line(lineNumber);
|
|
1880
|
+
const isHeader = lineNumber === tableInfo.startLineNumber;
|
|
1881
|
+
const isDelimiter = lineNumber === tableInfo.delimiterLineNumber;
|
|
1882
|
+
const isLastBody = !isHeader && !isDelimiter && lineNumber === tableInfo.endLineNumber;
|
|
1883
|
+
const bodyIndex = isHeader || isDelimiter ? -1 : lineNumber - tableInfo.delimiterLineNumber - 1;
|
|
1884
|
+
if (isHeader) {
|
|
1885
|
+
decorations.push(lineDecorations.header.range(line.from));
|
|
1886
|
+
} else if (isDelimiter) {
|
|
1887
|
+
decorations.push(lineDecorations.delimiter.range(line.from));
|
|
1888
|
+
} else if (bodyIndex % 2 === 1) {
|
|
1889
|
+
decorations.push(lineDecorations.even.range(line.from));
|
|
1890
|
+
} else {
|
|
1891
|
+
decorations.push(lineDecorations.body.range(line.from));
|
|
1892
|
+
}
|
|
1893
|
+
if (isLastBody) {
|
|
1894
|
+
decorations.push(lineDecorations.last.range(line.from));
|
|
1895
|
+
}
|
|
1896
|
+
if (isDelimiter) {
|
|
1897
|
+
decorations.push(delimiterReplace.range(line.from, line.to));
|
|
1898
|
+
continue;
|
|
1899
|
+
}
|
|
1900
|
+
this.decorateLine(decorations, line.from, line.text, tableInfo.alignments, isHeader);
|
|
1901
|
+
}
|
|
1902
|
+
decorations.push(
|
|
1903
|
+
view.Decoration.widget({
|
|
1904
|
+
widget: new TableControlsWidget(
|
|
1905
|
+
(view2) => {
|
|
1906
|
+
const liveTable = getTableInfoAtPosition(view2.state, tableInfo.from);
|
|
1907
|
+
if (liveTable) {
|
|
1908
|
+
this.appendRow(view2, liveTable, liveTable.columnCount - 1);
|
|
1909
|
+
}
|
|
1910
|
+
},
|
|
1911
|
+
(view2) => {
|
|
1912
|
+
const liveTable = getTableInfoAtPosition(view2.state, tableInfo.from);
|
|
1913
|
+
if (liveTable) {
|
|
1914
|
+
this.appendColumn(view2, liveTable);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
),
|
|
1918
|
+
side: 1
|
|
1919
|
+
}).range(tableInfo.to)
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
/** Applies the visual cell decorations for a single table row line. */
|
|
1923
|
+
decorateLine(decorations, lineFrom, lineText, alignments, isHeader) {
|
|
1924
|
+
const pipes = getPipePositions(lineText);
|
|
1925
|
+
if (pipes.length < 2) {
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1928
|
+
for (const pipe of pipes) {
|
|
1929
|
+
decorations.push(pipeReplace.range(lineFrom + pipe, lineFrom + pipe + 1));
|
|
1930
|
+
}
|
|
1931
|
+
for (let columnIndex = 0; columnIndex < pipes.length - 1; columnIndex++) {
|
|
1932
|
+
const rawFrom = pipes[columnIndex] + 1;
|
|
1933
|
+
const rawTo = pipes[columnIndex + 1];
|
|
1934
|
+
const rawText = lineText.slice(rawFrom, rawTo);
|
|
1935
|
+
const visible = getVisibleBounds(rawText);
|
|
1936
|
+
const absoluteFrom = lineFrom + rawFrom;
|
|
1937
|
+
const absoluteTo = lineFrom + rawTo;
|
|
1938
|
+
if (visible.startOffset > 0) {
|
|
1939
|
+
decorations.push(pipeReplace.range(absoluteFrom, absoluteFrom + visible.startOffset));
|
|
1940
|
+
}
|
|
1941
|
+
if (visible.endOffset < rawText.length) {
|
|
1942
|
+
decorations.push(pipeReplace.range(absoluteFrom + visible.endOffset, absoluteTo));
|
|
1943
|
+
}
|
|
1944
|
+
decorations.push(
|
|
1945
|
+
getCellDecoration(isHeader, alignments[columnIndex] || "left", columnIndex === pipes.length - 2).range(
|
|
1946
|
+
absoluteFrom,
|
|
1947
|
+
absoluteTo
|
|
1948
|
+
)
|
|
1949
|
+
);
|
|
1950
|
+
let match;
|
|
1951
|
+
const regex = new RegExp(BREAK_TAG_REGEX);
|
|
1952
|
+
while ((match = regex.exec(rawText)) !== null) {
|
|
1953
|
+
decorations.push(
|
|
1954
|
+
view.Decoration.replace({ widget: new TableBreakWidget() }).range(
|
|
1955
|
+
absoluteFrom + match.index,
|
|
1956
|
+
absoluteFrom + match.index + match[0].length
|
|
1957
|
+
)
|
|
1958
|
+
);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
/** Normalizes every parsed table block back into canonical markdown. */
|
|
1963
|
+
normalizeTables(view) {
|
|
1964
|
+
const changes = [];
|
|
1965
|
+
language.syntaxTree(view.state).iterate({
|
|
1966
|
+
enter: (node) => {
|
|
1967
|
+
if (node.name !== "Table") {
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
const content = view.state.sliceDoc(node.from, node.to);
|
|
1971
|
+
const { tableMarkdown } = splitTableAndTrailingMarkdown(content);
|
|
1972
|
+
const parsed = parseTableMarkdown(tableMarkdown);
|
|
1973
|
+
if (!parsed) {
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
const formatted = formatTableMarkdown(parsed);
|
|
1977
|
+
const change = createTableInsert(view.state, node.from, node.from + tableMarkdown.length, formatted);
|
|
1978
|
+
if (change.insert !== tableMarkdown || change.from !== node.from || change.to !== node.from + tableMarkdown.length) {
|
|
1979
|
+
changes.push({
|
|
1980
|
+
from: change.from,
|
|
1981
|
+
to: change.to,
|
|
1982
|
+
insert: change.insert
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
});
|
|
1987
|
+
if (changes.length > 0) {
|
|
1988
|
+
view.dispatch({
|
|
1989
|
+
changes: changes.sort((left, right) => right.from - left.from),
|
|
1990
|
+
annotations: normalizeAnnotation.of(true)
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
/** Defers table normalization until the current update cycle is finished. */
|
|
1995
|
+
scheduleNormalization(view) {
|
|
1996
|
+
if (this.pendingNormalizationView === view) {
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
this.pendingNormalizationView = view;
|
|
2000
|
+
queueMicrotask(() => {
|
|
2001
|
+
if (this.pendingNormalizationView !== view) {
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
this.pendingNormalizationView = null;
|
|
2005
|
+
this.normalizeTables(view);
|
|
2006
|
+
});
|
|
2007
|
+
}
|
|
2008
|
+
/** Adds missing spacer lines above and below tables after edits. */
|
|
2009
|
+
ensureTablePadding(view) {
|
|
2010
|
+
const changes = [];
|
|
2011
|
+
language.syntaxTree(view.state).iterate({
|
|
2012
|
+
enter: (node) => {
|
|
2013
|
+
if (node.name !== "Table") {
|
|
2014
|
+
return;
|
|
2015
|
+
}
|
|
2016
|
+
const tableInfo = readTableInfo(view.state, node.from, node.to);
|
|
2017
|
+
if (!tableInfo) {
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
const startLine = view.state.doc.lineAt(tableInfo.from);
|
|
2021
|
+
if (startLine.number === 1) {
|
|
2022
|
+
changes.push({ from: startLine.from, to: startLine.from, insert: "\n" });
|
|
2023
|
+
} else {
|
|
2024
|
+
const previousLine = view.state.doc.line(startLine.number - 1);
|
|
2025
|
+
if (previousLine.text.trim() !== "") {
|
|
2026
|
+
changes.push({ from: startLine.from, to: startLine.from, insert: "\n" });
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
const endLine = view.state.doc.lineAt(tableInfo.to);
|
|
2030
|
+
if (endLine.number === view.state.doc.lines) {
|
|
2031
|
+
changes.push({ from: endLine.to, to: endLine.to, insert: "\n" });
|
|
2032
|
+
} else {
|
|
2033
|
+
const nextLine = view.state.doc.line(endLine.number + 1);
|
|
2034
|
+
if (nextLine.text.trim() !== "") {
|
|
2035
|
+
changes.push({ from: endLine.to, to: endLine.to, insert: "\n" });
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
});
|
|
2040
|
+
if (changes.length > 0) {
|
|
2041
|
+
view.dispatch({
|
|
2042
|
+
changes: changes.sort((left, right) => right.from - left.from),
|
|
2043
|
+
annotations: normalizeAnnotation.of(true)
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
/** Schedules a padding-only pass after the current update cycle finishes. */
|
|
2048
|
+
schedulePadding(view) {
|
|
2049
|
+
if (this.pendingPaddingView === view) {
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
this.pendingPaddingView = view;
|
|
2053
|
+
queueMicrotask(() => {
|
|
2054
|
+
if (this.pendingPaddingView !== view) {
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
this.pendingPaddingView = null;
|
|
2058
|
+
this.ensureTablePadding(view);
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
/** Repairs carets that land in hidden table markup instead of editable cell content. */
|
|
2062
|
+
ensureTableSelection(view) {
|
|
2063
|
+
const selection = view.state.selection.main;
|
|
2064
|
+
if (!selection.empty) {
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
const tableInfo = getTableInfoAtPosition(view.state, selection.head);
|
|
2068
|
+
if (!tableInfo) {
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
const cell = findCellAtPosition(tableInfo, selection.head);
|
|
2072
|
+
if (!cell) {
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
const anchor = clampCellPosition(cell, selection.head);
|
|
2076
|
+
if (anchor === selection.head) {
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
view.dispatch({
|
|
2080
|
+
selection: { anchor },
|
|
2081
|
+
annotations: repairSelectionAnnotation.of(true),
|
|
2082
|
+
scrollIntoView: true
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
2085
|
+
/** Schedules table selection repair after the current update finishes. */
|
|
2086
|
+
scheduleSelectionRepair(view) {
|
|
2087
|
+
if (this.pendingSelectionRepairView === view) {
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
this.pendingSelectionRepairView = view;
|
|
2091
|
+
queueMicrotask(() => {
|
|
2092
|
+
if (this.pendingSelectionRepairView !== view) {
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
2095
|
+
this.pendingSelectionRepairView = null;
|
|
2096
|
+
this.ensureTableSelection(view);
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
/** Rewrites a table block and restores the caret to a target cell position. */
|
|
2100
|
+
replaceTable(view, tableInfo, parsed, targetRowIndex, targetColumnIndex, offset = 0) {
|
|
2101
|
+
const formatted = formatTableMarkdown(parsed);
|
|
2102
|
+
const change = createTableInsert(view.state, tableInfo.from, tableInfo.to, formatted);
|
|
2103
|
+
const selection = change.from + change.prefixLength + getCellAnchorInFormattedTable(
|
|
2104
|
+
formatted,
|
|
2105
|
+
Math.max(0, targetRowIndex),
|
|
2106
|
+
Math.max(0, Math.min(targetColumnIndex, Math.max(parsed.headers.length - 1, 0))),
|
|
2107
|
+
Math.max(0, offset)
|
|
2108
|
+
);
|
|
2109
|
+
view.dispatch({
|
|
2110
|
+
changes: { from: change.from, to: change.to, insert: change.insert },
|
|
2111
|
+
selection: { anchor: selection }
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
/** Inserts an empty body row below the given logical row index. */
|
|
2115
|
+
insertRowBelow(view, tableInfo, afterRowIndex, targetColumn) {
|
|
2116
|
+
const parsed = normalizeParsedTable(buildTableFromInfo(tableInfo));
|
|
2117
|
+
const insertBodyIndex = Math.max(0, Math.min(afterRowIndex, parsed.rows.length));
|
|
2118
|
+
parsed.rows.splice(insertBodyIndex, 0, buildEmptyRow(tableInfo.columnCount));
|
|
2119
|
+
this.replaceTable(view, tableInfo, parsed, insertBodyIndex + 1, targetColumn);
|
|
2120
|
+
}
|
|
2121
|
+
/** Inserts a starter table near the current cursor line. */
|
|
2122
|
+
insertTable(view) {
|
|
2123
|
+
const { state } = view;
|
|
2124
|
+
const cursor = state.selection.main.head;
|
|
2125
|
+
const line = state.doc.lineAt(cursor);
|
|
2126
|
+
const insertAt = line.text.trim() ? line.to : line.from;
|
|
2127
|
+
const formatted = formatTableMarkdown(TABLE_TEMPLATE);
|
|
2128
|
+
const change = createTableInsert(state, insertAt, insertAt, formatted);
|
|
2129
|
+
const selection = change.from + change.prefixLength + getCellAnchorInFormattedTable(formatted, 0, 0);
|
|
2130
|
+
view.dispatch({
|
|
2131
|
+
changes: { from: change.from, to: change.to, insert: change.insert },
|
|
2132
|
+
selection: { anchor: selection }
|
|
2133
|
+
});
|
|
2134
|
+
return true;
|
|
2135
|
+
}
|
|
2136
|
+
/** Adds a new empty body row to the active table. */
|
|
2137
|
+
addRow(view) {
|
|
2138
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2139
|
+
if (!tableInfo) {
|
|
2140
|
+
return false;
|
|
2141
|
+
}
|
|
2142
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2143
|
+
this.appendRow(view, tableInfo, cell?.columnIndex || 0);
|
|
2144
|
+
return true;
|
|
2145
|
+
}
|
|
2146
|
+
/** Appends a row and keeps the caret in the requested column. */
|
|
2147
|
+
appendRow(view, tableInfo, targetColumn) {
|
|
2148
|
+
this.insertRowBelow(view, tableInfo, tableInfo.bodyCells.length, targetColumn);
|
|
2149
|
+
}
|
|
2150
|
+
/** Inserts a new column after the current column. */
|
|
2151
|
+
addColumn(view) {
|
|
2152
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2153
|
+
if (!tableInfo) {
|
|
2154
|
+
return false;
|
|
2155
|
+
}
|
|
2156
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2157
|
+
const insertAfter = cell?.columnIndex ?? tableInfo.columnCount - 1;
|
|
2158
|
+
const parsed = normalizeParsedTable(buildTableFromInfo(tableInfo));
|
|
2159
|
+
parsed.headers.splice(insertAfter + 1, 0, "");
|
|
2160
|
+
parsed.alignments.splice(insertAfter + 1, 0, "left");
|
|
2161
|
+
for (const row of parsed.rows) {
|
|
2162
|
+
row.splice(insertAfter + 1, 0, "");
|
|
2163
|
+
}
|
|
2164
|
+
this.replaceTable(view, tableInfo, parsed, cell?.rowIndex || 0, insertAfter + 1);
|
|
2165
|
+
return true;
|
|
2166
|
+
}
|
|
2167
|
+
/** Appends a new column at the far right of the table. */
|
|
2168
|
+
appendColumn(view, tableInfo) {
|
|
2169
|
+
const parsed = normalizeParsedTable(buildTableFromInfo(tableInfo));
|
|
2170
|
+
parsed.headers.push("");
|
|
2171
|
+
parsed.alignments.push("left");
|
|
2172
|
+
for (const row of parsed.rows) {
|
|
2173
|
+
row.push("");
|
|
2174
|
+
}
|
|
2175
|
+
this.replaceTable(view, tableInfo, parsed, 0, parsed.headers.length - 1);
|
|
2176
|
+
}
|
|
2177
|
+
/** Removes the current body row or clears the last remaining row. */
|
|
2178
|
+
removeRow(view) {
|
|
2179
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2180
|
+
if (!tableInfo) {
|
|
2181
|
+
return false;
|
|
2182
|
+
}
|
|
2183
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2184
|
+
if (!cell || cell.rowKind !== "body") {
|
|
2185
|
+
return false;
|
|
2186
|
+
}
|
|
2187
|
+
const parsed = normalizeParsedTable(buildTableFromInfo(tableInfo));
|
|
2188
|
+
const bodyIndex = cell.rowIndex - 1;
|
|
2189
|
+
if (bodyIndex < 0 || bodyIndex >= parsed.rows.length) {
|
|
2190
|
+
return false;
|
|
2191
|
+
}
|
|
2192
|
+
if (parsed.rows.length === 1) {
|
|
2193
|
+
parsed.rows[0] = buildEmptyRow(tableInfo.columnCount);
|
|
2194
|
+
} else {
|
|
2195
|
+
parsed.rows.splice(bodyIndex, 1);
|
|
2196
|
+
}
|
|
2197
|
+
const nextRowIndex = Math.max(1, Math.min(cell.rowIndex, parsed.rows.length));
|
|
2198
|
+
this.replaceTable(view, tableInfo, parsed, nextRowIndex, Math.min(cell.columnIndex, tableInfo.columnCount - 1));
|
|
2199
|
+
return true;
|
|
2200
|
+
}
|
|
2201
|
+
/** Removes the current column when the table has more than one column. */
|
|
2202
|
+
removeColumn(view) {
|
|
2203
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2204
|
+
if (!tableInfo || tableInfo.columnCount <= 1) {
|
|
2205
|
+
return false;
|
|
2206
|
+
}
|
|
2207
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2208
|
+
const removeAt = cell?.columnIndex ?? tableInfo.columnCount - 1;
|
|
2209
|
+
const parsed = normalizeParsedTable(buildTableFromInfo(tableInfo));
|
|
2210
|
+
parsed.headers.splice(removeAt, 1);
|
|
2211
|
+
parsed.alignments.splice(removeAt, 1);
|
|
2212
|
+
for (const row of parsed.rows) {
|
|
2213
|
+
row.splice(removeAt, 1);
|
|
2214
|
+
}
|
|
2215
|
+
this.replaceTable(view, tableInfo, parsed, cell?.rowIndex || 0, Math.min(removeAt, parsed.headers.length - 1));
|
|
2216
|
+
return true;
|
|
2217
|
+
}
|
|
2218
|
+
/** Moves to the next or previous logical cell with Tab navigation. */
|
|
2219
|
+
handleTab(view, backwards) {
|
|
2220
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2221
|
+
if (!tableInfo) {
|
|
2222
|
+
return false;
|
|
2223
|
+
}
|
|
2224
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2225
|
+
if (!cell) {
|
|
2226
|
+
return false;
|
|
2227
|
+
}
|
|
2228
|
+
const cells = tableInfo.cellsByRow.flat();
|
|
2229
|
+
const currentIndex = cells.findIndex((candidate) => candidate.from === cell.from && candidate.to === cell.to);
|
|
2230
|
+
if (currentIndex < 0) {
|
|
2231
|
+
return false;
|
|
2232
|
+
}
|
|
2233
|
+
const nextIndex = backwards ? currentIndex - 1 : currentIndex + 1;
|
|
2234
|
+
if (nextIndex < 0) {
|
|
2235
|
+
return true;
|
|
2236
|
+
}
|
|
2237
|
+
if (nextIndex >= cells.length) {
|
|
2238
|
+
this.appendRow(view, tableInfo, 0);
|
|
2239
|
+
return true;
|
|
2240
|
+
}
|
|
2241
|
+
this.moveSelectionToCell(view, cells[nextIndex]);
|
|
2242
|
+
return true;
|
|
2243
|
+
}
|
|
2244
|
+
/** Moves horizontally between adjacent cells when the caret hits an edge. */
|
|
2245
|
+
handleArrowHorizontal(view, forward) {
|
|
2246
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2247
|
+
if (!tableInfo) {
|
|
2248
|
+
return false;
|
|
2249
|
+
}
|
|
2250
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2251
|
+
if (!cell) {
|
|
2252
|
+
return false;
|
|
2253
|
+
}
|
|
2254
|
+
const cursor = view.state.selection.main.head;
|
|
2255
|
+
const rightEdge = Math.max(cell.contentFrom, cell.contentTo);
|
|
2256
|
+
if (forward && cursor < rightEdge) {
|
|
2257
|
+
return false;
|
|
2258
|
+
}
|
|
2259
|
+
if (!forward && cursor > cell.contentFrom) {
|
|
2260
|
+
return false;
|
|
2261
|
+
}
|
|
2262
|
+
const row = tableInfo.cellsByRow[cell.rowIndex] || [];
|
|
2263
|
+
const nextCell = row[cell.columnIndex + (forward ? 1 : -1)];
|
|
2264
|
+
if (!nextCell) {
|
|
2265
|
+
return false;
|
|
2266
|
+
}
|
|
2267
|
+
this.moveSelectionToCell(view, nextCell);
|
|
2268
|
+
return true;
|
|
2269
|
+
}
|
|
2270
|
+
/** Moves vertically between rows while keeping the current column. */
|
|
2271
|
+
handleArrowVertical(view, forward) {
|
|
2272
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2273
|
+
if (!tableInfo) {
|
|
2274
|
+
return false;
|
|
2275
|
+
}
|
|
2276
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2277
|
+
if (!cell) {
|
|
2278
|
+
return false;
|
|
2279
|
+
}
|
|
2280
|
+
const nextRow = tableInfo.cellsByRow[cell.rowIndex + (forward ? 1 : -1)];
|
|
2281
|
+
if (!nextRow) {
|
|
2282
|
+
return false;
|
|
2283
|
+
}
|
|
2284
|
+
const nextCell = nextRow[cell.columnIndex];
|
|
2285
|
+
if (!nextCell) {
|
|
2286
|
+
return false;
|
|
2287
|
+
}
|
|
2288
|
+
this.moveSelectionToCell(view, nextCell);
|
|
2289
|
+
return true;
|
|
2290
|
+
}
|
|
2291
|
+
/** Advances downward on Enter and manages the trailing empty row behavior. */
|
|
2292
|
+
handleEnter(view) {
|
|
2293
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2294
|
+
if (!tableInfo) {
|
|
2295
|
+
return false;
|
|
2296
|
+
}
|
|
2297
|
+
const cell = this.getCurrentCell(view, tableInfo);
|
|
2298
|
+
if (!cell) {
|
|
2299
|
+
return false;
|
|
2300
|
+
}
|
|
2301
|
+
if (cell.rowKind === "body") {
|
|
2302
|
+
const currentRow = tableInfo.bodyCells[cell.rowIndex - 1];
|
|
2303
|
+
if (currentRow && isBodyRowEmpty(currentRow)) {
|
|
2304
|
+
const parsed = normalizeParsedTable(buildTableFromInfo(tableInfo));
|
|
2305
|
+
parsed.rows.splice(cell.rowIndex - 1, 1);
|
|
2306
|
+
const formatted = formatTableMarkdown(parsed);
|
|
2307
|
+
const change = createTableInsert(view.state, tableInfo.from, tableInfo.to, formatted);
|
|
2308
|
+
const anchor = Math.min(change.from + change.insert.length, view.state.doc.length + change.insert.length);
|
|
2309
|
+
view.dispatch({
|
|
2310
|
+
changes: { from: change.from, to: change.to, insert: change.insert },
|
|
2311
|
+
selection: { anchor }
|
|
2312
|
+
});
|
|
2313
|
+
return true;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
if (cell.rowKind === "body" && cell.rowIndex === tableInfo.cellsByRow.length - 1) {
|
|
2317
|
+
const parsed = normalizeParsedTable(buildTableFromInfo(tableInfo));
|
|
2318
|
+
parsed.rows.push(buildEmptyRow(tableInfo.columnCount));
|
|
2319
|
+
this.replaceTable(view, tableInfo, parsed, parsed.rows.length, cell.columnIndex);
|
|
2320
|
+
return true;
|
|
2321
|
+
}
|
|
2322
|
+
this.insertRowBelow(view, tableInfo, cell.rowIndex, cell.columnIndex);
|
|
2323
|
+
return true;
|
|
2324
|
+
}
|
|
2325
|
+
/** Inserts a canonical `<br />` token inside the current table cell. */
|
|
2326
|
+
insertBreakTag(view) {
|
|
2327
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2328
|
+
if (!tableInfo) {
|
|
2329
|
+
return false;
|
|
2330
|
+
}
|
|
2331
|
+
const selection = view.state.selection.main;
|
|
2332
|
+
view.dispatch({
|
|
2333
|
+
changes: { from: selection.from, to: selection.to, insert: BREAK_TAG },
|
|
2334
|
+
selection: { anchor: selection.from + BREAK_TAG.length }
|
|
2335
|
+
});
|
|
2336
|
+
return true;
|
|
2337
|
+
}
|
|
2338
|
+
/** Deletes a whole `<br />` token when backspace or delete hits it. */
|
|
2339
|
+
handleBreakDeletion(view, forward) {
|
|
2340
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
2341
|
+
if (!tableInfo) {
|
|
2342
|
+
return false;
|
|
2343
|
+
}
|
|
2344
|
+
const selection = view.state.selection.main;
|
|
2345
|
+
const cursor = selection.head;
|
|
2346
|
+
for (const range of collectBreakRanges(tableInfo)) {
|
|
2347
|
+
const within = cursor > range.from && cursor < range.to;
|
|
2348
|
+
const matchesBackspace = !forward && cursor === range.to;
|
|
2349
|
+
const matchesDelete = forward && cursor === range.from;
|
|
2350
|
+
const overlapsSelection = !selection.empty && selection.from <= range.from && selection.to >= range.to;
|
|
2351
|
+
if (within || matchesBackspace || matchesDelete || overlapsSelection) {
|
|
2352
|
+
view.dispatch({
|
|
2353
|
+
changes: { from: range.from, to: range.to, insert: "" },
|
|
2354
|
+
selection: { anchor: range.from }
|
|
2355
|
+
});
|
|
2356
|
+
return true;
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
return false;
|
|
2360
|
+
}
|
|
2361
|
+
/** Moves the current selection anchor into a target cell. */
|
|
2362
|
+
moveSelectionToCell(view, cell, offset = 0) {
|
|
2363
|
+
const end = Math.max(cell.contentFrom, cell.contentTo);
|
|
2364
|
+
view.dispatch({
|
|
2365
|
+
selection: { anchor: Math.min(cell.contentFrom + offset, end) },
|
|
2366
|
+
scrollIntoView: true
|
|
2367
|
+
});
|
|
2368
|
+
}
|
|
2369
|
+
/** Returns the table currently containing the editor cursor. */
|
|
2370
|
+
getTableAtCursor(view) {
|
|
2371
|
+
return getTableInfoAtPosition(view.state, view.state.selection.main.head);
|
|
2372
|
+
}
|
|
2373
|
+
/** Returns the active cell under the current selection head. */
|
|
2374
|
+
getCurrentCell(view, tableInfo) {
|
|
2375
|
+
return findCellAtPosition(tableInfo, view.state.selection.main.head);
|
|
2376
|
+
}
|
|
2377
|
+
};
|
|
2378
|
+
var theme6 = chunkW75QUUQC_cjs.createTheme({
|
|
2379
|
+
default: {
|
|
2380
|
+
".cm-draftly-table-wrapper, .cm-draftly-table-widget": {
|
|
2381
|
+
display: "table",
|
|
2382
|
+
width: "100%",
|
|
2383
|
+
borderCollapse: "separate",
|
|
2384
|
+
borderSpacing: "0",
|
|
2385
|
+
position: "relative",
|
|
2386
|
+
overflow: "visible",
|
|
2387
|
+
border: "1px solid var(--color-border, #d7dee7)",
|
|
2388
|
+
borderRadius: "0.75rem",
|
|
2389
|
+
backgroundColor: "var(--color-background, #ffffff)",
|
|
2390
|
+
"& .cm-draftly-table": {
|
|
2391
|
+
width: "100%",
|
|
2392
|
+
borderCollapse: "separate",
|
|
2393
|
+
borderSpacing: "0",
|
|
2394
|
+
tableLayout: "auto"
|
|
2395
|
+
},
|
|
2396
|
+
"& .cm-draftly-table-row": {
|
|
2397
|
+
display: "table-row !important"
|
|
2398
|
+
},
|
|
2399
|
+
"& .cm-draftly-table-header-row": {
|
|
2400
|
+
backgroundColor: "rgba(15, 23, 42, 0.04)"
|
|
2401
|
+
},
|
|
2402
|
+
"& .cm-draftly-table-row-even": {
|
|
2403
|
+
backgroundColor: "rgba(15, 23, 42, 0.02)"
|
|
2404
|
+
},
|
|
2405
|
+
"& .cm-draftly-table-delimiter-row": {
|
|
2406
|
+
display: "none !important"
|
|
2407
|
+
},
|
|
2408
|
+
"& .cm-draftly-table-cell": {
|
|
2409
|
+
display: "table-cell",
|
|
2410
|
+
minWidth: "4rem",
|
|
2411
|
+
minHeight: "2.5rem",
|
|
2412
|
+
height: "2.75rem",
|
|
2413
|
+
padding: "0.5rem 0.875rem",
|
|
2414
|
+
verticalAlign: "top",
|
|
2415
|
+
borderRight: "1px solid var(--color-border, #d7dee7)",
|
|
2416
|
+
borderBottom: "1px solid var(--color-border, #d7dee7)",
|
|
2417
|
+
whiteSpace: "normal",
|
|
2418
|
+
overflowWrap: "break-word",
|
|
2419
|
+
wordBreak: "normal",
|
|
2420
|
+
lineHeight: "1.6"
|
|
2421
|
+
},
|
|
2422
|
+
"& .cm-draftly-table-body-row": {
|
|
2423
|
+
minHeight: "2.75rem"
|
|
2424
|
+
},
|
|
2425
|
+
"& .cm-draftly-table-cell .cm-draftly-code-inline": {
|
|
2426
|
+
whiteSpace: "normal",
|
|
2427
|
+
overflowWrap: "anywhere"
|
|
2428
|
+
},
|
|
2429
|
+
"& .cm-draftly-table-th": {
|
|
2430
|
+
fontWeight: "600",
|
|
2431
|
+
borderBottomWidth: "2px"
|
|
2432
|
+
},
|
|
2433
|
+
"& .cm-draftly-table-cell-last": {
|
|
2434
|
+
borderRight: "none"
|
|
2435
|
+
},
|
|
2436
|
+
"& .cm-draftly-table-row-last .cm-draftly-table-cell": {
|
|
2437
|
+
borderBottom: "none"
|
|
2438
|
+
},
|
|
2439
|
+
"& .cm-draftly-table-cell-center": {
|
|
2440
|
+
textAlign: "center"
|
|
2441
|
+
},
|
|
2442
|
+
"& .cm-draftly-table-cell-right": {
|
|
2443
|
+
textAlign: "right"
|
|
2444
|
+
},
|
|
2445
|
+
"& .cm-draftly-table-break": {
|
|
2446
|
+
display: "inline"
|
|
2447
|
+
},
|
|
2448
|
+
"& .cm-draftly-table-controls-anchor": {
|
|
2449
|
+
position: "absolute",
|
|
2450
|
+
inset: "0",
|
|
2451
|
+
pointerEvents: "none"
|
|
2452
|
+
},
|
|
2453
|
+
"& .cm-draftly-table-control": {
|
|
2454
|
+
position: "absolute",
|
|
2455
|
+
width: "1.75rem",
|
|
2456
|
+
height: "1.75rem",
|
|
2457
|
+
border: "1px solid var(--color-border, #d7dee7)",
|
|
2458
|
+
borderRadius: "999px",
|
|
2459
|
+
backgroundColor: "var(--color-background, #ffffff)",
|
|
2460
|
+
color: "var(--color-text, #0f172a)",
|
|
2461
|
+
boxShadow: "0 10px 24px rgba(15, 23, 42, 0.12)",
|
|
2462
|
+
display: "inline-flex",
|
|
2463
|
+
alignItems: "center",
|
|
2464
|
+
justifyContent: "center",
|
|
2465
|
+
opacity: "0",
|
|
2466
|
+
pointerEvents: "auto",
|
|
2467
|
+
transition: "opacity 120ms ease, transform 120ms ease, background-color 120ms ease"
|
|
2468
|
+
},
|
|
2469
|
+
"& .cm-draftly-table-control:hover": {
|
|
2470
|
+
backgroundColor: "rgba(15, 23, 42, 0.05)"
|
|
2471
|
+
},
|
|
2472
|
+
"& .cm-draftly-table-control-column": {
|
|
2473
|
+
top: "50%",
|
|
2474
|
+
right: "-0.95rem",
|
|
2475
|
+
transform: "translate(0.35rem, -50%)"
|
|
2476
|
+
},
|
|
2477
|
+
"& .cm-draftly-table-control-row": {
|
|
2478
|
+
left: "50%",
|
|
2479
|
+
bottom: "-0.95rem",
|
|
2480
|
+
transform: "translate(-50%, 0.35rem)"
|
|
2481
|
+
},
|
|
2482
|
+
"&:hover .cm-draftly-table-control, &:focus-within .cm-draftly-table-control": {
|
|
2483
|
+
opacity: "1"
|
|
2484
|
+
},
|
|
2485
|
+
"&:hover .cm-draftly-table-control-column, &:focus-within .cm-draftly-table-control-column": {
|
|
2486
|
+
transform: "translate(0, -50%)"
|
|
2487
|
+
},
|
|
2488
|
+
"&:hover .cm-draftly-table-control-row, &:focus-within .cm-draftly-table-control-row": {
|
|
2489
|
+
transform: "translate(-50%, 0)"
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
},
|
|
2493
|
+
dark: {
|
|
2494
|
+
".cm-draftly-table-wrapper, .cm-draftly-table-widget": {
|
|
2495
|
+
borderColor: "var(--color-border, #30363d)",
|
|
2496
|
+
backgroundColor: "var(--color-background, #0d1117)",
|
|
2497
|
+
"& .cm-draftly-table-header-row": {
|
|
2498
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
2499
|
+
},
|
|
2500
|
+
"& .cm-draftly-table-row-even": {
|
|
2501
|
+
backgroundColor: "rgba(255, 255, 255, 0.025)"
|
|
2502
|
+
},
|
|
2503
|
+
"& .cm-draftly-table-cell": {
|
|
2504
|
+
borderColor: "var(--color-border, #30363d)"
|
|
2505
|
+
},
|
|
2506
|
+
"& .cm-draftly-table-control": {
|
|
2507
|
+
borderColor: "var(--color-border, #30363d)",
|
|
2508
|
+
backgroundColor: "var(--color-background, #161b22)",
|
|
2509
|
+
color: "var(--color-text, #e6edf3)",
|
|
2510
|
+
boxShadow: "0 12px 28px rgba(0, 0, 0, 0.35)"
|
|
2511
|
+
},
|
|
2512
|
+
"& .cm-draftly-table-control:hover": {
|
|
2513
|
+
backgroundColor: "rgba(255, 255, 255, 0.08)"
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
});
|
|
2518
|
+
var htmlMarkDecorations = {
|
|
2519
|
+
"html-tag": view.Decoration.mark({ class: "cm-draftly-html-tag" }),
|
|
2520
|
+
"html-comment": view.Decoration.mark({ class: "cm-draftly-html-comment" })
|
|
2521
|
+
};
|
|
2522
|
+
var htmlLineDecorations = {
|
|
2523
|
+
"html-block": view.Decoration.line({ class: "cm-draftly-line-html-block" }),
|
|
2524
|
+
"hidden-line": view.Decoration.line({ class: "cm-draftly-hidden-line" })
|
|
2525
|
+
};
|
|
2526
|
+
var HTMLPreviewWidget = class extends view.WidgetType {
|
|
2527
|
+
constructor(html) {
|
|
2528
|
+
super();
|
|
2529
|
+
this.html = html;
|
|
2530
|
+
}
|
|
2531
|
+
eq(other) {
|
|
2532
|
+
return other.html === this.html;
|
|
2533
|
+
}
|
|
2534
|
+
toDOM() {
|
|
2535
|
+
const div = document.createElement("div");
|
|
2536
|
+
div.className = "cm-draftly-html-preview";
|
|
2537
|
+
div.innerHTML = DOMPurify__default.default.sanitize(this.html);
|
|
2538
|
+
return div;
|
|
2539
|
+
}
|
|
2540
|
+
ignoreEvent() {
|
|
2541
|
+
return false;
|
|
2542
|
+
}
|
|
2543
|
+
};
|
|
2544
|
+
var InlineHTMLPreviewWidget = class extends view.WidgetType {
|
|
2545
|
+
constructor(html) {
|
|
2546
|
+
super();
|
|
2547
|
+
this.html = html;
|
|
2548
|
+
}
|
|
2549
|
+
eq(other) {
|
|
2550
|
+
return other.html === this.html;
|
|
2551
|
+
}
|
|
2552
|
+
toDOM() {
|
|
2553
|
+
const span = document.createElement("span");
|
|
2554
|
+
span.className = "cm-draftly-inline-html-preview";
|
|
2555
|
+
span.innerHTML = DOMPurify__default.default.sanitize(this.html);
|
|
2556
|
+
return span;
|
|
2557
|
+
}
|
|
2558
|
+
ignoreEvent() {
|
|
2559
|
+
return false;
|
|
2560
|
+
}
|
|
2561
|
+
};
|
|
2562
|
+
function parseHTMLTag(content) {
|
|
2563
|
+
const match = content.match(/^<\s*(\/?)([a-zA-Z][a-zA-Z0-9-]*)[^>]*(\/?)>$/);
|
|
2564
|
+
if (!match) return null;
|
|
2565
|
+
return {
|
|
2566
|
+
tagName: match[2].toLowerCase(),
|
|
2567
|
+
isClosing: match[1] === "/",
|
|
2568
|
+
isSelfClosing: match[3] === "/" || ["br", "hr", "img", "input", "meta", "link", "area", "base", "col", "embed", "source", "track", "wbr"].includes(
|
|
2569
|
+
match[2].toLowerCase()
|
|
2570
|
+
)
|
|
2571
|
+
};
|
|
2572
|
+
}
|
|
2573
|
+
var HTMLPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
2574
|
+
name = "html";
|
|
2575
|
+
version = "1.0.0";
|
|
2576
|
+
decorationPriority = 30;
|
|
2577
|
+
constructor() {
|
|
2578
|
+
super();
|
|
2579
|
+
}
|
|
2580
|
+
/**
|
|
2581
|
+
* Plugin theme
|
|
2582
|
+
*/
|
|
2583
|
+
get theme() {
|
|
2584
|
+
return theme7;
|
|
2585
|
+
}
|
|
2586
|
+
buildDecorations(ctx) {
|
|
2587
|
+
const { view: view$1, decorations } = ctx;
|
|
2588
|
+
const tree = language.syntaxTree(view$1.state);
|
|
2589
|
+
const htmlGroups = [];
|
|
2590
|
+
const htmlTags = [];
|
|
2591
|
+
tree.iterate({
|
|
2592
|
+
enter: (node) => {
|
|
2593
|
+
const { from, to, name } = node;
|
|
2594
|
+
if (name === "Comment") {
|
|
2595
|
+
decorations.push(htmlMarkDecorations["html-comment"].range(from, to));
|
|
2596
|
+
return;
|
|
2597
|
+
}
|
|
2598
|
+
if (name === "HTMLTag") {
|
|
2599
|
+
const content = view$1.state.sliceDoc(from, to);
|
|
2600
|
+
const parsed = parseHTMLTag(content);
|
|
2601
|
+
if (parsed) {
|
|
2602
|
+
htmlTags.push({
|
|
2603
|
+
from,
|
|
2604
|
+
to,
|
|
2605
|
+
tagName: parsed.tagName,
|
|
2606
|
+
isClosing: parsed.isClosing,
|
|
2607
|
+
isSelfClosing: parsed.isSelfClosing
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
if (name === "HTMLBlock") {
|
|
2612
|
+
const last = htmlGroups[htmlGroups.length - 1];
|
|
2613
|
+
if (last) {
|
|
2614
|
+
const gap = view$1.state.sliceDoc(last.to, from);
|
|
2615
|
+
if (!gap.trim()) {
|
|
2616
|
+
last.to = to;
|
|
2617
|
+
return;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
htmlGroups.push({ from, to });
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
});
|
|
2624
|
+
const inlineElements = [];
|
|
2625
|
+
const usedTags = /* @__PURE__ */ new Set();
|
|
2626
|
+
for (let i = 0; i < htmlTags.length; i++) {
|
|
2627
|
+
if (usedTags.has(i)) continue;
|
|
2628
|
+
const openTag = htmlTags[i];
|
|
2629
|
+
if (openTag.isClosing) continue;
|
|
2630
|
+
if (openTag.isSelfClosing) {
|
|
2631
|
+
inlineElements.push({
|
|
2632
|
+
from: openTag.from,
|
|
2633
|
+
to: openTag.to,
|
|
2634
|
+
content: view$1.state.sliceDoc(openTag.from, openTag.to)
|
|
2635
|
+
});
|
|
2636
|
+
usedTags.add(i);
|
|
2637
|
+
continue;
|
|
1242
2638
|
}
|
|
1243
2639
|
const openLine = view$1.state.doc.lineAt(openTag.from);
|
|
1244
2640
|
let depth = 1;
|
|
@@ -1325,7 +2721,7 @@ var HTMLPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1325
2721
|
}
|
|
1326
2722
|
}
|
|
1327
2723
|
};
|
|
1328
|
-
var
|
|
2724
|
+
var theme7 = chunkW75QUUQC_cjs.createTheme({
|
|
1329
2725
|
default: {
|
|
1330
2726
|
".cm-draftly-html-tag": {
|
|
1331
2727
|
color: "#6a737d",
|
|
@@ -1443,7 +2839,7 @@ var ImageWidget = class extends view.WidgetType {
|
|
|
1443
2839
|
return event.type !== "click";
|
|
1444
2840
|
}
|
|
1445
2841
|
};
|
|
1446
|
-
var ImagePlugin = class extends
|
|
2842
|
+
var ImagePlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
1447
2843
|
name = "image";
|
|
1448
2844
|
version = "1.0.0";
|
|
1449
2845
|
decorationPriority = 25;
|
|
@@ -1455,7 +2851,7 @@ var ImagePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1455
2851
|
* Plugin theme
|
|
1456
2852
|
*/
|
|
1457
2853
|
get theme() {
|
|
1458
|
-
return
|
|
2854
|
+
return theme8;
|
|
1459
2855
|
}
|
|
1460
2856
|
/**
|
|
1461
2857
|
* Keyboard shortcuts for image formatting
|
|
@@ -1610,7 +3006,7 @@ var ImagePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1610
3006
|
return html;
|
|
1611
3007
|
}
|
|
1612
3008
|
};
|
|
1613
|
-
var
|
|
3009
|
+
var theme8 = chunkW75QUUQC_cjs.createTheme({
|
|
1614
3010
|
default: {
|
|
1615
3011
|
".cm-draftly-image-block br": {
|
|
1616
3012
|
display: "none"
|
|
@@ -1847,7 +3243,7 @@ var mathBlockParser = {
|
|
|
1847
3243
|
return true;
|
|
1848
3244
|
}
|
|
1849
3245
|
};
|
|
1850
|
-
var MathPlugin = class extends
|
|
3246
|
+
var MathPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
1851
3247
|
name = "math";
|
|
1852
3248
|
version = "1.0.0";
|
|
1853
3249
|
decorationPriority = 25;
|
|
@@ -1859,7 +3255,16 @@ var MathPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1859
3255
|
* Plugin theme
|
|
1860
3256
|
*/
|
|
1861
3257
|
get theme() {
|
|
1862
|
-
return
|
|
3258
|
+
return theme9;
|
|
3259
|
+
}
|
|
3260
|
+
/**
|
|
3261
|
+
* Intercepts dollar typing to wrap selected text as inline math.
|
|
3262
|
+
*
|
|
3263
|
+
* If user types '$' while text is selected, wraps each selected range
|
|
3264
|
+
* with single dollars (selected -> $selected$).
|
|
3265
|
+
*/
|
|
3266
|
+
getExtensions() {
|
|
3267
|
+
return [chunk3T55CBNZ_cjs.createWrapSelectionInputHandler({ "$": "$" })];
|
|
1863
3268
|
}
|
|
1864
3269
|
/**
|
|
1865
3270
|
* Return markdown parser extensions for math syntax
|
|
@@ -1967,7 +3372,7 @@ var MathPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1967
3372
|
return null;
|
|
1968
3373
|
}
|
|
1969
3374
|
};
|
|
1970
|
-
var
|
|
3375
|
+
var theme9 = chunkW75QUUQC_cjs.createTheme({
|
|
1971
3376
|
default: {
|
|
1972
3377
|
".cm-draftly-math-block": {
|
|
1973
3378
|
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
@@ -2154,7 +3559,7 @@ var mermaidBlockParser = {
|
|
|
2154
3559
|
return true;
|
|
2155
3560
|
}
|
|
2156
3561
|
};
|
|
2157
|
-
var MermaidPlugin = class extends
|
|
3562
|
+
var MermaidPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
2158
3563
|
name = "mermaid";
|
|
2159
3564
|
version = "1.0.0";
|
|
2160
3565
|
decorationPriority = 25;
|
|
@@ -2166,7 +3571,7 @@ var MermaidPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2166
3571
|
* Plugin theme
|
|
2167
3572
|
*/
|
|
2168
3573
|
get theme() {
|
|
2169
|
-
return
|
|
3574
|
+
return theme10;
|
|
2170
3575
|
}
|
|
2171
3576
|
/**
|
|
2172
3577
|
* Return markdown parser extensions for mermaid syntax
|
|
@@ -2274,7 +3679,7 @@ var MermaidPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2274
3679
|
return null;
|
|
2275
3680
|
}
|
|
2276
3681
|
};
|
|
2277
|
-
var
|
|
3682
|
+
var theme10 = chunkW75QUUQC_cjs.createTheme({
|
|
2278
3683
|
default: {
|
|
2279
3684
|
// Raw mermaid block lines (monospace)
|
|
2280
3685
|
".cm-draftly-mermaid-block:not(.cm-draftly-mermaid-block-rendered)": {
|
|
@@ -2322,65 +3727,430 @@ var theme9 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
2322
3727
|
color: "#6a737d",
|
|
2323
3728
|
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
2324
3729
|
},
|
|
2325
|
-
// Hidden mermaid syntax (when cursor is not in range)
|
|
2326
|
-
".cm-draftly-mermaid-hidden": {
|
|
2327
|
-
display: "none"
|
|
3730
|
+
// Hidden mermaid syntax (when cursor is not in range)
|
|
3731
|
+
".cm-draftly-mermaid-hidden": {
|
|
3732
|
+
display: "none"
|
|
3733
|
+
},
|
|
3734
|
+
// Rendered mermaid container
|
|
3735
|
+
".cm-draftly-mermaid-rendered": {
|
|
3736
|
+
display: "flex",
|
|
3737
|
+
justifyContent: "center",
|
|
3738
|
+
alignItems: "center",
|
|
3739
|
+
padding: "1em 0",
|
|
3740
|
+
borderRadius: "4px",
|
|
3741
|
+
overflow: "auto"
|
|
3742
|
+
},
|
|
3743
|
+
// SVG inside rendered container
|
|
3744
|
+
".cm-draftly-mermaid-rendered svg": {
|
|
3745
|
+
maxWidth: "100%",
|
|
3746
|
+
height: "auto",
|
|
3747
|
+
aspectRatio: "auto"
|
|
3748
|
+
},
|
|
3749
|
+
// Loading state
|
|
3750
|
+
".cm-draftly-mermaid-loading": {
|
|
3751
|
+
display: "inline-block",
|
|
3752
|
+
padding: "0.5em 1em",
|
|
3753
|
+
color: "#6a737d",
|
|
3754
|
+
fontSize: "0.875em",
|
|
3755
|
+
fontStyle: "italic",
|
|
3756
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
3757
|
+
},
|
|
3758
|
+
// Error styling
|
|
3759
|
+
".cm-draftly-mermaid-error": {
|
|
3760
|
+
display: "inline-block",
|
|
3761
|
+
padding: "0.25em 0.5em",
|
|
3762
|
+
backgroundColor: "rgba(255, 0, 0, 0.1)",
|
|
3763
|
+
color: "#d73a49",
|
|
3764
|
+
borderRadius: "4px",
|
|
3765
|
+
fontSize: "0.875em",
|
|
3766
|
+
fontStyle: "italic",
|
|
3767
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
3768
|
+
}
|
|
3769
|
+
},
|
|
3770
|
+
dark: {
|
|
3771
|
+
".cm-draftly-mermaid-block:not(.cm-draftly-mermaid-block-rendered)": {
|
|
3772
|
+
backgroundColor: "rgba(255, 255, 255, 0.03)"
|
|
3773
|
+
},
|
|
3774
|
+
".cm-draftly-mermaid-marker": {
|
|
3775
|
+
color: "#8b949e"
|
|
3776
|
+
},
|
|
3777
|
+
".cm-draftly-mermaid-loading": {
|
|
3778
|
+
color: "#8b949e"
|
|
3779
|
+
},
|
|
3780
|
+
".cm-draftly-mermaid-error": {
|
|
3781
|
+
backgroundColor: "rgba(255, 0, 0, 0.15)",
|
|
3782
|
+
color: "#f85149"
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
});
|
|
3786
|
+
|
|
3787
|
+
// src/plugins/code-plugin.theme.ts
|
|
3788
|
+
var codePluginTheme = chunkW75QUUQC_cjs.createTheme({
|
|
3789
|
+
default: {
|
|
3790
|
+
// Inline code
|
|
3791
|
+
".cm-draftly-code-inline": {
|
|
3792
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3793
|
+
fontSize: "0.9rem",
|
|
3794
|
+
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
|
3795
|
+
padding: "0.1rem 0.25rem",
|
|
3796
|
+
border: "1px solid var(--color-border)",
|
|
3797
|
+
borderRadius: "3px"
|
|
3798
|
+
},
|
|
3799
|
+
// Fenced code block lines
|
|
3800
|
+
".cm-draftly-code-block-line": {
|
|
3801
|
+
"--radius": "0.375rem",
|
|
3802
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3803
|
+
fontSize: "0.9rem",
|
|
3804
|
+
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
3805
|
+
padding: "0 1rem !important",
|
|
3806
|
+
lineHeight: "1.5",
|
|
3807
|
+
borderLeft: "1px solid var(--color-border)",
|
|
3808
|
+
borderRight: "1px solid var(--color-border)"
|
|
3809
|
+
},
|
|
3810
|
+
// First line of code block
|
|
3811
|
+
".cm-draftly-code-block-line-start": {
|
|
3812
|
+
borderTopLeftRadius: "var(--radius)",
|
|
3813
|
+
borderTopRightRadius: "var(--radius)",
|
|
3814
|
+
position: "relative",
|
|
3815
|
+
overflow: "hidden",
|
|
3816
|
+
borderTop: "1px solid var(--color-border)",
|
|
3817
|
+
paddingBottom: "0.5rem !important"
|
|
3818
|
+
},
|
|
3819
|
+
// Remove top radius when header is present
|
|
3820
|
+
".cm-draftly-code-block-has-header": {
|
|
3821
|
+
padding: "0 !important",
|
|
3822
|
+
paddingBottom: "0.5rem !important"
|
|
3823
|
+
},
|
|
3824
|
+
// Code block header widget
|
|
3825
|
+
".cm-draftly-code-header": {
|
|
3826
|
+
display: "flex",
|
|
3827
|
+
justifyContent: "space-between",
|
|
3828
|
+
alignItems: "center",
|
|
3829
|
+
padding: "0.25rem 1rem",
|
|
3830
|
+
backgroundColor: "rgba(0, 0, 0, 0.06)",
|
|
3831
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3832
|
+
fontSize: "0.85rem",
|
|
3833
|
+
".cm-draftly-code-header-left": {
|
|
3834
|
+
display: "flex",
|
|
3835
|
+
alignItems: "center",
|
|
3836
|
+
gap: "0.5rem",
|
|
3837
|
+
".cm-draftly-code-header-title": {
|
|
3838
|
+
color: "var(--color-text, inherit)",
|
|
3839
|
+
fontWeight: "500"
|
|
3840
|
+
},
|
|
3841
|
+
".cm-draftly-code-header-lang": {
|
|
3842
|
+
color: "#6a737d",
|
|
3843
|
+
opacity: "0.8"
|
|
3844
|
+
}
|
|
3845
|
+
},
|
|
3846
|
+
".cm-draftly-code-header-right": {
|
|
3847
|
+
display: "flex",
|
|
3848
|
+
alignItems: "center",
|
|
3849
|
+
gap: "0.5rem",
|
|
3850
|
+
".cm-draftly-code-copy-btn": {
|
|
3851
|
+
display: "flex",
|
|
3852
|
+
alignItems: "center",
|
|
3853
|
+
justifyContent: "center",
|
|
3854
|
+
padding: "0.25rem",
|
|
3855
|
+
backgroundColor: "transparent",
|
|
3856
|
+
border: "none",
|
|
3857
|
+
borderRadius: "4px",
|
|
3858
|
+
cursor: "pointer",
|
|
3859
|
+
color: "#6a737d",
|
|
3860
|
+
transition: "color 0.2s, background-color 0.2s",
|
|
3861
|
+
"&:hover": {
|
|
3862
|
+
backgroundColor: "rgba(0, 0, 0, 0.1)",
|
|
3863
|
+
color: "var(--color-text, inherit)"
|
|
3864
|
+
},
|
|
3865
|
+
"&.copied": {
|
|
3866
|
+
color: "#22c55e"
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
},
|
|
3871
|
+
// Caption (below code block)
|
|
3872
|
+
".cm-draftly-code-block-has-caption": {
|
|
3873
|
+
padding: "0 !important",
|
|
3874
|
+
paddingTop: "0.5rem !important"
|
|
3875
|
+
},
|
|
3876
|
+
".cm-draftly-code-caption": {
|
|
3877
|
+
textAlign: "center",
|
|
3878
|
+
fontSize: "0.85rem",
|
|
3879
|
+
color: "#6a737d",
|
|
3880
|
+
fontStyle: "italic",
|
|
3881
|
+
padding: "0.25rem 1rem",
|
|
3882
|
+
backgroundColor: "rgba(0, 0, 0, 0.06)"
|
|
3883
|
+
},
|
|
3884
|
+
// Last line of code block
|
|
3885
|
+
".cm-draftly-code-block-line-end": {
|
|
3886
|
+
borderBottomLeftRadius: "var(--radius)",
|
|
3887
|
+
borderBottomRightRadius: "var(--radius)",
|
|
3888
|
+
borderBottom: "1px solid var(--color-border)",
|
|
3889
|
+
paddingTop: "0.5rem !important",
|
|
3890
|
+
"& br": {
|
|
3891
|
+
display: "none"
|
|
3892
|
+
}
|
|
3893
|
+
},
|
|
3894
|
+
// Fence markers (```)
|
|
3895
|
+
".cm-draftly-code-fence": {
|
|
3896
|
+
color: "#6a737d",
|
|
3897
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
3898
|
+
},
|
|
3899
|
+
// Line numbers
|
|
3900
|
+
".cm-draftly-code-line-numbered": {
|
|
3901
|
+
paddingLeft: "calc(var(--line-num-width, 2ch) + 1rem) !important",
|
|
3902
|
+
position: "relative",
|
|
3903
|
+
"&::before": {
|
|
3904
|
+
content: "attr(data-line-num)",
|
|
3905
|
+
position: "absolute",
|
|
3906
|
+
left: "0.5rem",
|
|
3907
|
+
top: "0.2rem",
|
|
3908
|
+
width: "var(--line-num-width, 2ch)",
|
|
3909
|
+
textAlign: "right",
|
|
3910
|
+
color: "#6a737d",
|
|
3911
|
+
opacity: "0.6",
|
|
3912
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3913
|
+
fontSize: "0.85rem",
|
|
3914
|
+
userSelect: "none"
|
|
3915
|
+
}
|
|
3916
|
+
},
|
|
3917
|
+
".cm-draftly-code-line-numbered-diff": {
|
|
3918
|
+
paddingLeft: "calc(var(--line-num-old-width, 2ch) + var(--line-num-new-width, 2ch) + 2.75rem) !important",
|
|
3919
|
+
position: "relative",
|
|
3920
|
+
"&::before": {
|
|
3921
|
+
content: "attr(data-line-num-old)",
|
|
3922
|
+
position: "absolute",
|
|
3923
|
+
left: "0.5rem",
|
|
3924
|
+
top: "0.2rem",
|
|
3925
|
+
width: "var(--line-num-old-width, 2ch)",
|
|
3926
|
+
textAlign: "right",
|
|
3927
|
+
color: "#6a737d",
|
|
3928
|
+
opacity: "0.6",
|
|
3929
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3930
|
+
fontSize: "0.85rem",
|
|
3931
|
+
userSelect: "none"
|
|
3932
|
+
},
|
|
3933
|
+
"&::after": {
|
|
3934
|
+
content: 'attr(data-line-num-new) " " attr(data-diff-marker)',
|
|
3935
|
+
position: "absolute",
|
|
3936
|
+
left: "calc(0.5rem + var(--line-num-old-width, 2ch) + 0.75rem)",
|
|
3937
|
+
top: "0.2rem",
|
|
3938
|
+
width: "calc(var(--line-num-new-width, 2ch) + 2ch)",
|
|
3939
|
+
textAlign: "right",
|
|
3940
|
+
color: "#6a737d",
|
|
3941
|
+
opacity: "0.6",
|
|
3942
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3943
|
+
fontSize: "0.85rem",
|
|
3944
|
+
userSelect: "none"
|
|
3945
|
+
},
|
|
3946
|
+
"&.cm-draftly-code-line-diff-gutter": {
|
|
3947
|
+
paddingLeft: "calc(var(--line-num-width, 2ch) + 2rem) !important",
|
|
3948
|
+
"&::after": {
|
|
3949
|
+
content: "attr(data-diff-marker)",
|
|
3950
|
+
position: "absolute",
|
|
3951
|
+
left: "calc(0.5rem + var(--line-num-width, 2ch) + 0.35rem)",
|
|
3952
|
+
top: "0.1rem",
|
|
3953
|
+
width: "1ch",
|
|
3954
|
+
textAlign: "right",
|
|
3955
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3956
|
+
fontSize: "0.85rem",
|
|
3957
|
+
fontWeight: "700",
|
|
3958
|
+
userSelect: "none"
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
},
|
|
3962
|
+
// Preview: code lines (need block display for full-width highlights)
|
|
3963
|
+
".cm-draftly-code-line": {
|
|
3964
|
+
display: "block",
|
|
3965
|
+
position: "relative",
|
|
3966
|
+
paddingLeft: "1rem",
|
|
3967
|
+
paddingRight: "1rem",
|
|
3968
|
+
lineHeight: "1.5",
|
|
3969
|
+
borderLeft: "3px solid transparent"
|
|
3970
|
+
},
|
|
3971
|
+
// Line highlight
|
|
3972
|
+
".cm-draftly-code-line-highlight": {
|
|
3973
|
+
backgroundColor: "rgba(255, 220, 100, 0.2) !important",
|
|
3974
|
+
borderLeft: "3px solid #f0b429 !important"
|
|
3975
|
+
},
|
|
3976
|
+
".cm-draftly-code-line-diff-add": {
|
|
3977
|
+
color: "inherit",
|
|
3978
|
+
backgroundColor: "rgba(34, 197, 94, 0.12) !important",
|
|
3979
|
+
borderLeft: "3px solid #22c55e !important",
|
|
3980
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
3981
|
+
color: "#16a34a"
|
|
3982
|
+
}
|
|
3983
|
+
},
|
|
3984
|
+
".cm-draftly-code-line-diff-del": {
|
|
3985
|
+
color: "inherit",
|
|
3986
|
+
backgroundColor: "rgba(239, 68, 68, 0.12) !important",
|
|
3987
|
+
borderLeft: "3px solid #ef4444 !important",
|
|
3988
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
3989
|
+
color: "#dc2626"
|
|
3990
|
+
}
|
|
3991
|
+
},
|
|
3992
|
+
".cm-draftly-code-diff-sign-add": {
|
|
3993
|
+
color: "#16a34a",
|
|
3994
|
+
fontWeight: "700"
|
|
3995
|
+
},
|
|
3996
|
+
".cm-draftly-code-diff-sign-del": {
|
|
3997
|
+
color: "#dc2626",
|
|
3998
|
+
fontWeight: "700"
|
|
3999
|
+
},
|
|
4000
|
+
".cm-draftly-code-diff-mod-add": {
|
|
4001
|
+
color: "inherit",
|
|
4002
|
+
backgroundColor: "rgba(34, 197, 94, 0.25)",
|
|
4003
|
+
borderRadius: "2px",
|
|
4004
|
+
padding: "0.1rem 0"
|
|
4005
|
+
},
|
|
4006
|
+
".cm-draftly-code-diff-mod-del": {
|
|
4007
|
+
color: "inherit",
|
|
4008
|
+
backgroundColor: "rgba(239, 68, 68, 0.25)",
|
|
4009
|
+
borderRadius: "2px",
|
|
4010
|
+
padding: "0.1rem 0"
|
|
4011
|
+
},
|
|
4012
|
+
// Text highlight
|
|
4013
|
+
".cm-draftly-code-text-highlight": {
|
|
4014
|
+
color: "inherit",
|
|
4015
|
+
backgroundColor: "rgba(255, 220, 100, 0.4)",
|
|
4016
|
+
borderRadius: "2px",
|
|
4017
|
+
padding: "0.1rem 0"
|
|
4018
|
+
},
|
|
4019
|
+
// Preview: container wrapper
|
|
4020
|
+
".cm-draftly-code-container": {
|
|
4021
|
+
margin: "1rem 0",
|
|
4022
|
+
borderRadius: "var(--radius)",
|
|
4023
|
+
overflow: "hidden",
|
|
4024
|
+
border: "1px solid var(--color-border)",
|
|
4025
|
+
".cm-draftly-code-header": {
|
|
4026
|
+
borderRadius: "0",
|
|
4027
|
+
border: "none",
|
|
4028
|
+
borderBottom: "1px solid var(--color-border)"
|
|
4029
|
+
},
|
|
4030
|
+
".cm-draftly-code-block": {
|
|
4031
|
+
margin: "0",
|
|
4032
|
+
borderRadius: "0",
|
|
4033
|
+
border: "none",
|
|
4034
|
+
whiteSpace: "pre-wrap"
|
|
4035
|
+
},
|
|
4036
|
+
".cm-draftly-code-caption": {
|
|
4037
|
+
borderTop: "1px solid var(--color-border)"
|
|
4038
|
+
}
|
|
4039
|
+
},
|
|
4040
|
+
// Preview: standalone code block (not in container)
|
|
4041
|
+
".cm-draftly-code-block": {
|
|
4042
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
4043
|
+
fontSize: "0.9rem",
|
|
4044
|
+
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
4045
|
+
padding: "1rem",
|
|
4046
|
+
overflow: "auto",
|
|
4047
|
+
position: "relative",
|
|
4048
|
+
borderRadius: "var(--radius)",
|
|
4049
|
+
border: "1px solid var(--color-border)",
|
|
4050
|
+
"&.cm-draftly-code-block-has-header": {
|
|
4051
|
+
borderTopLeftRadius: "0",
|
|
4052
|
+
borderTopRightRadius: "0",
|
|
4053
|
+
borderTop: "none",
|
|
4054
|
+
margin: "0",
|
|
4055
|
+
paddingTop: "0.5rem !important"
|
|
4056
|
+
},
|
|
4057
|
+
"&.cm-draftly-code-block-has-caption": {
|
|
4058
|
+
borderBottomLeftRadius: "0",
|
|
4059
|
+
borderBottomRightRadius: "0",
|
|
4060
|
+
borderBottom: "none",
|
|
4061
|
+
paddingBottom: "0.5rem !important"
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
},
|
|
4065
|
+
dark: {
|
|
4066
|
+
".cm-draftly-code-inline": {
|
|
4067
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
|
4068
|
+
},
|
|
4069
|
+
".cm-draftly-code-block-line": {
|
|
4070
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
4071
|
+
},
|
|
4072
|
+
".cm-draftly-code-fence": {
|
|
4073
|
+
color: "#8b949e"
|
|
4074
|
+
},
|
|
4075
|
+
".cm-draftly-code-block": {
|
|
4076
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
4077
|
+
},
|
|
4078
|
+
".cm-draftly-code-header": {
|
|
4079
|
+
backgroundColor: "rgba(255, 255, 255, 0.08)",
|
|
4080
|
+
".cm-draftly-code-header-lang": {
|
|
4081
|
+
color: "#8b949e"
|
|
4082
|
+
},
|
|
4083
|
+
".cm-draftly-code-copy-btn": {
|
|
4084
|
+
color: "#8b949e",
|
|
4085
|
+
"&:hover": {
|
|
4086
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
},
|
|
4090
|
+
".cm-draftly-code-caption": {
|
|
4091
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
4092
|
+
},
|
|
4093
|
+
".cm-draftly-code-line-numbered": {
|
|
4094
|
+
"&::before": {
|
|
4095
|
+
color: "#8b949e"
|
|
4096
|
+
}
|
|
4097
|
+
},
|
|
4098
|
+
".cm-draftly-code-line-numbered-diff": {
|
|
4099
|
+
"&::before": {
|
|
4100
|
+
color: "#8b949e"
|
|
4101
|
+
},
|
|
4102
|
+
"&::after": {
|
|
4103
|
+
color: "#8b949e"
|
|
4104
|
+
}
|
|
4105
|
+
},
|
|
4106
|
+
".cm-draftly-code-line-diff-gutter": {
|
|
4107
|
+
"&::after": {
|
|
4108
|
+
color: "#8b949e"
|
|
4109
|
+
}
|
|
2328
4110
|
},
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
justifyContent: "center",
|
|
2333
|
-
alignItems: "center",
|
|
2334
|
-
padding: "1em 0",
|
|
2335
|
-
borderRadius: "4px",
|
|
2336
|
-
overflow: "auto"
|
|
4111
|
+
".cm-draftly-code-line-highlight": {
|
|
4112
|
+
backgroundColor: "rgba(255, 220, 100, 0.15) !important",
|
|
4113
|
+
borderLeft: "3px solid #d9a520 !important"
|
|
2337
4114
|
},
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
4115
|
+
".cm-draftly-code-line-diff-add": {
|
|
4116
|
+
backgroundColor: "rgba(34, 197, 94, 0.15) !important",
|
|
4117
|
+
borderLeft: "3px solid #22c55e !important",
|
|
4118
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
4119
|
+
color: "#4ade80"
|
|
4120
|
+
}
|
|
2343
4121
|
},
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
fontStyle: "italic",
|
|
2351
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
4122
|
+
".cm-draftly-code-line-diff-del": {
|
|
4123
|
+
backgroundColor: "rgba(239, 68, 68, 0.15) !important",
|
|
4124
|
+
borderLeft: "3px solid #ef4444 !important",
|
|
4125
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
4126
|
+
color: "#f87171"
|
|
4127
|
+
}
|
|
2352
4128
|
},
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
display: "inline-block",
|
|
2356
|
-
padding: "0.25em 0.5em",
|
|
2357
|
-
backgroundColor: "rgba(255, 0, 0, 0.1)",
|
|
2358
|
-
color: "#d73a49",
|
|
2359
|
-
borderRadius: "4px",
|
|
2360
|
-
fontSize: "0.875em",
|
|
2361
|
-
fontStyle: "italic",
|
|
2362
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
2363
|
-
}
|
|
2364
|
-
},
|
|
2365
|
-
dark: {
|
|
2366
|
-
".cm-draftly-mermaid-block:not(.cm-draftly-mermaid-block-rendered)": {
|
|
2367
|
-
backgroundColor: "rgba(255, 255, 255, 0.03)"
|
|
4129
|
+
".cm-draftly-code-diff-sign-add": {
|
|
4130
|
+
color: "#4ade80"
|
|
2368
4131
|
},
|
|
2369
|
-
".cm-draftly-
|
|
2370
|
-
color: "#
|
|
4132
|
+
".cm-draftly-code-diff-sign-del": {
|
|
4133
|
+
color: "#f87171"
|
|
2371
4134
|
},
|
|
2372
|
-
".cm-draftly-
|
|
2373
|
-
|
|
4135
|
+
".cm-draftly-code-diff-mod-add": {
|
|
4136
|
+
backgroundColor: "rgba(34, 197, 94, 0.3)"
|
|
2374
4137
|
},
|
|
2375
|
-
".cm-draftly-
|
|
2376
|
-
backgroundColor: "rgba(
|
|
2377
|
-
|
|
4138
|
+
".cm-draftly-code-diff-mod-del": {
|
|
4139
|
+
backgroundColor: "rgba(239, 68, 68, 0.3)"
|
|
4140
|
+
},
|
|
4141
|
+
".cm-draftly-code-text-highlight": {
|
|
4142
|
+
backgroundColor: "rgba(255, 220, 100, 0.3)"
|
|
2378
4143
|
}
|
|
2379
4144
|
}
|
|
2380
4145
|
});
|
|
4146
|
+
|
|
4147
|
+
// src/plugins/code-plugin.ts
|
|
2381
4148
|
var COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
2382
4149
|
var CHECK_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
|
|
2383
4150
|
var COPY_RESET_DELAY = 2e3;
|
|
4151
|
+
var CODE_FENCE = "```";
|
|
4152
|
+
var QUOTED_INFO_PATTERN = /(\w+)="([^"]*)"/g;
|
|
4153
|
+
var TEXT_HIGHLIGHT_PATTERN = /\/([^/]+)\/(?:(\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*))?/g;
|
|
2384
4154
|
var codeMarkDecorations = {
|
|
2385
4155
|
// Inline code
|
|
2386
4156
|
"inline-code": view.Decoration.mark({ class: "cm-draftly-code-inline" }),
|
|
@@ -2393,7 +4163,15 @@ var codeMarkDecorations = {
|
|
|
2393
4163
|
"code-hidden": view.Decoration.replace({}),
|
|
2394
4164
|
// Highlights
|
|
2395
4165
|
"code-line-highlight": view.Decoration.line({ class: "cm-draftly-code-line-highlight" }),
|
|
2396
|
-
"code-text-highlight": view.Decoration.mark({ class: "cm-draftly-code-text-highlight" })
|
|
4166
|
+
"code-text-highlight": view.Decoration.mark({ class: "cm-draftly-code-text-highlight" }),
|
|
4167
|
+
// Diff preview
|
|
4168
|
+
"diff-line-add": view.Decoration.line({ class: "cm-draftly-code-line-diff-add" }),
|
|
4169
|
+
"diff-line-del": view.Decoration.line({ class: "cm-draftly-code-line-diff-del" }),
|
|
4170
|
+
"diff-sign-add": view.Decoration.mark({ class: "cm-draftly-code-diff-sign-add" }),
|
|
4171
|
+
"diff-sign-del": view.Decoration.mark({ class: "cm-draftly-code-diff-sign-del" }),
|
|
4172
|
+
"diff-mod-add": view.Decoration.mark({ class: "cm-draftly-code-diff-mod-add" }),
|
|
4173
|
+
"diff-mod-del": view.Decoration.mark({ class: "cm-draftly-code-diff-mod-del" }),
|
|
4174
|
+
"diff-escape-hidden": view.Decoration.replace({})
|
|
2397
4175
|
};
|
|
2398
4176
|
var CodeBlockHeaderWidget = class extends view.WidgetType {
|
|
2399
4177
|
constructor(props, codeContent) {
|
|
@@ -2474,16 +4252,17 @@ var CodeBlockCaptionWidget = class extends view.WidgetType {
|
|
|
2474
4252
|
return false;
|
|
2475
4253
|
}
|
|
2476
4254
|
};
|
|
2477
|
-
var CodePlugin = class extends
|
|
4255
|
+
var CodePlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
2478
4256
|
name = "code";
|
|
2479
4257
|
version = "1.0.0";
|
|
2480
4258
|
decorationPriority = 25;
|
|
2481
4259
|
requiredNodes = ["InlineCode", "FencedCode", "CodeMark", "CodeInfo", "CodeText"];
|
|
4260
|
+
parserCache = /* @__PURE__ */ new Map();
|
|
2482
4261
|
/**
|
|
2483
4262
|
* Plugin theme
|
|
2484
4263
|
*/
|
|
2485
4264
|
get theme() {
|
|
2486
|
-
return
|
|
4265
|
+
return codePluginTheme;
|
|
2487
4266
|
}
|
|
2488
4267
|
/**
|
|
2489
4268
|
* Keyboard shortcuts for code formatting
|
|
@@ -2492,7 +4271,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2492
4271
|
return [
|
|
2493
4272
|
{
|
|
2494
4273
|
key: "Mod-e",
|
|
2495
|
-
run:
|
|
4274
|
+
run: chunkW75QUUQC_cjs.toggleMarkdownStyle("`"),
|
|
2496
4275
|
preventDefault: true
|
|
2497
4276
|
},
|
|
2498
4277
|
{
|
|
@@ -2502,6 +4281,15 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2502
4281
|
}
|
|
2503
4282
|
];
|
|
2504
4283
|
}
|
|
4284
|
+
/**
|
|
4285
|
+
* Intercepts backtick typing to wrap selected text as inline code.
|
|
4286
|
+
*
|
|
4287
|
+
* If user types '`' while text is selected, wraps each selected range
|
|
4288
|
+
* with backticks (selected -> `selected`).
|
|
4289
|
+
*/
|
|
4290
|
+
getExtensions() {
|
|
4291
|
+
return [chunk3T55CBNZ_cjs.createWrapSelectionInputHandler({ "`": "`" })];
|
|
4292
|
+
}
|
|
2505
4293
|
/**
|
|
2506
4294
|
* Toggle code block on current line or selected lines
|
|
2507
4295
|
*/
|
|
@@ -2514,7 +4302,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2514
4302
|
const nextLineNum = endLine.number < state.doc.lines ? endLine.number + 1 : endLine.number;
|
|
2515
4303
|
const prevLine = state.doc.line(prevLineNum);
|
|
2516
4304
|
const nextLine = state.doc.line(nextLineNum);
|
|
2517
|
-
const isWrapped = prevLine.text.trim().startsWith(
|
|
4305
|
+
const isWrapped = prevLine.text.trim().startsWith(CODE_FENCE) && nextLine.text.trim() === CODE_FENCE && prevLineNum !== startLine.number && nextLineNum !== endLine.number;
|
|
2518
4306
|
if (isWrapped) {
|
|
2519
4307
|
view.dispatch({
|
|
2520
4308
|
changes: [
|
|
@@ -2525,8 +4313,10 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2525
4313
|
]
|
|
2526
4314
|
});
|
|
2527
4315
|
} else {
|
|
2528
|
-
const openFence =
|
|
2529
|
-
|
|
4316
|
+
const openFence = `${CODE_FENCE}
|
|
4317
|
+
`;
|
|
4318
|
+
const closeFence = `
|
|
4319
|
+
${CODE_FENCE}`;
|
|
2530
4320
|
view.dispatch({
|
|
2531
4321
|
changes: [
|
|
2532
4322
|
{ from: startLine.from, insert: openFence },
|
|
@@ -2555,6 +4345,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2555
4345
|
* lineNumbers: 5,
|
|
2556
4346
|
* title: "hello.tsx",
|
|
2557
4347
|
* copy: true,
|
|
4348
|
+
* diff: false,
|
|
2558
4349
|
* highlightLines: [2,3,4,5],
|
|
2559
4350
|
* highlightText: [{ pattern: "Hello", instances: [3,4,5] }]
|
|
2560
4351
|
* }
|
|
@@ -2566,14 +4357,21 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2566
4357
|
return props;
|
|
2567
4358
|
}
|
|
2568
4359
|
let remaining = codeInfo.trim();
|
|
2569
|
-
const
|
|
2570
|
-
if (
|
|
2571
|
-
|
|
2572
|
-
|
|
4360
|
+
const firstTokenMatch = remaining.match(/^([^\s]+)/);
|
|
4361
|
+
if (firstTokenMatch && firstTokenMatch[1]) {
|
|
4362
|
+
const firstToken = firstTokenMatch[1];
|
|
4363
|
+
const normalizedToken = firstToken.toLowerCase();
|
|
4364
|
+
const isLineNumberDirective = /^(?:line-numbers|linenumbers|showlinenumbers)(?:\{\d+\})?$/.test(
|
|
4365
|
+
normalizedToken
|
|
4366
|
+
);
|
|
4367
|
+
const isKnownDirective = isLineNumberDirective || normalizedToken === "copy" || normalizedToken === "diff" || normalizedToken.startsWith("{") || normalizedToken.startsWith("/");
|
|
4368
|
+
if (!isKnownDirective) {
|
|
4369
|
+
props.language = firstToken;
|
|
4370
|
+
remaining = remaining.slice(firstToken.length).trim();
|
|
4371
|
+
}
|
|
2573
4372
|
}
|
|
2574
|
-
const quotedPattern = /(\w+)="([^"]*)"/g;
|
|
2575
4373
|
let quotedMatch;
|
|
2576
|
-
while ((quotedMatch =
|
|
4374
|
+
while ((quotedMatch = QUOTED_INFO_PATTERN.exec(remaining)) !== null) {
|
|
2577
4375
|
const key = quotedMatch[1]?.toLowerCase();
|
|
2578
4376
|
const value = quotedMatch[2];
|
|
2579
4377
|
if (key === "title" && value !== void 0) {
|
|
@@ -2582,13 +4380,13 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2582
4380
|
props.caption = value;
|
|
2583
4381
|
}
|
|
2584
4382
|
}
|
|
2585
|
-
remaining = remaining.replace(
|
|
2586
|
-
const lineNumbersMatch = remaining.match(
|
|
4383
|
+
remaining = remaining.replace(QUOTED_INFO_PATTERN, "").trim();
|
|
4384
|
+
const lineNumbersMatch = remaining.match(/\b(?:line-numbers|lineNumbers|showLineNumbers)(?:\{(\d+)\})?/i);
|
|
2587
4385
|
if (lineNumbersMatch) {
|
|
2588
4386
|
if (lineNumbersMatch[1]) {
|
|
2589
|
-
props.
|
|
4387
|
+
props.showLineNumbers = parseInt(lineNumbersMatch[1], 10);
|
|
2590
4388
|
} else {
|
|
2591
|
-
props.
|
|
4389
|
+
props.showLineNumbers = true;
|
|
2592
4390
|
}
|
|
2593
4391
|
remaining = remaining.replace(lineNumbersMatch[0], "").trim();
|
|
2594
4392
|
}
|
|
@@ -2596,52 +4394,27 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2596
4394
|
props.copy = true;
|
|
2597
4395
|
remaining = remaining.replace(/\bcopy\b/, "").trim();
|
|
2598
4396
|
}
|
|
4397
|
+
if (/\bdiff\b/.test(remaining)) {
|
|
4398
|
+
props.diff = true;
|
|
4399
|
+
remaining = remaining.replace(/\bdiff\b/, "").trim();
|
|
4400
|
+
}
|
|
2599
4401
|
const lineHighlightMatch = remaining.match(/\{([^}]+)\}/);
|
|
2600
4402
|
if (lineHighlightMatch && lineHighlightMatch[1]) {
|
|
2601
|
-
const highlightLines = [];
|
|
2602
|
-
const parts = lineHighlightMatch[1].split(",");
|
|
2603
|
-
for (const part of parts) {
|
|
2604
|
-
const trimmed = part.trim();
|
|
2605
|
-
const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/);
|
|
2606
|
-
if (rangeMatch && rangeMatch[1] && rangeMatch[2]) {
|
|
2607
|
-
const start = parseInt(rangeMatch[1], 10);
|
|
2608
|
-
const end = parseInt(rangeMatch[2], 10);
|
|
2609
|
-
for (let i = start; i <= end; i++) {
|
|
2610
|
-
highlightLines.push(i);
|
|
2611
|
-
}
|
|
2612
|
-
} else if (/^\d+$/.test(trimmed)) {
|
|
2613
|
-
highlightLines.push(parseInt(trimmed, 10));
|
|
2614
|
-
}
|
|
2615
|
-
}
|
|
4403
|
+
const highlightLines = this.parseNumberList(lineHighlightMatch[1]);
|
|
2616
4404
|
if (highlightLines.length > 0) {
|
|
2617
4405
|
props.highlightLines = highlightLines;
|
|
2618
4406
|
}
|
|
2619
4407
|
remaining = remaining.replace(lineHighlightMatch[0], "").trim();
|
|
2620
4408
|
}
|
|
2621
|
-
const textHighlightPattern = /\/([^/]+)\/(?:(\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*))?/g;
|
|
2622
4409
|
let textMatch;
|
|
2623
4410
|
const highlightText = [];
|
|
2624
|
-
while ((textMatch =
|
|
4411
|
+
while ((textMatch = TEXT_HIGHLIGHT_PATTERN.exec(remaining)) !== null) {
|
|
2625
4412
|
if (!textMatch[1]) continue;
|
|
2626
4413
|
const highlight = {
|
|
2627
4414
|
pattern: textMatch[1]
|
|
2628
4415
|
};
|
|
2629
4416
|
if (textMatch[2]) {
|
|
2630
|
-
const
|
|
2631
|
-
const instances = [];
|
|
2632
|
-
const instanceParts = instanceStr.split(",");
|
|
2633
|
-
for (const part of instanceParts) {
|
|
2634
|
-
const rangeMatch = part.match(/^(\d+)-(\d+)$/);
|
|
2635
|
-
if (rangeMatch && rangeMatch[1] && rangeMatch[2]) {
|
|
2636
|
-
const start = parseInt(rangeMatch[1], 10);
|
|
2637
|
-
const end = parseInt(rangeMatch[2], 10);
|
|
2638
|
-
for (let i = start; i <= end; i++) {
|
|
2639
|
-
instances.push(i);
|
|
2640
|
-
}
|
|
2641
|
-
} else if (/^\d+$/.test(part)) {
|
|
2642
|
-
instances.push(parseInt(part, 10));
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
4417
|
+
const instances = this.parseNumberList(textMatch[2]);
|
|
2645
4418
|
if (instances.length > 0) {
|
|
2646
4419
|
highlight.instances = instances;
|
|
2647
4420
|
}
|
|
@@ -2658,148 +4431,244 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2658
4431
|
* Handles line numbers, highlights, header/caption widgets, and fence visibility.
|
|
2659
4432
|
*/
|
|
2660
4433
|
buildDecorations(ctx) {
|
|
2661
|
-
const
|
|
2662
|
-
const tree = language.syntaxTree(view$1.state);
|
|
4434
|
+
const tree = language.syntaxTree(ctx.view.state);
|
|
2663
4435
|
tree.iterate({
|
|
2664
4436
|
enter: (node) => {
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
const cursorInRange = ctx.selectionOverlapsRange(from, to);
|
|
2669
|
-
if (!cursorInRange) {
|
|
2670
|
-
for (let child = node.node.firstChild; child; child = child.nextSibling) {
|
|
2671
|
-
if (child.name === "CodeMark") {
|
|
2672
|
-
decorations.push(codeMarkDecorations["inline-mark"].range(child.from, child.to));
|
|
2673
|
-
}
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
4437
|
+
if (node.name === "InlineCode") {
|
|
4438
|
+
this.decorateInlineCode(node, ctx);
|
|
4439
|
+
return;
|
|
2676
4440
|
}
|
|
2677
|
-
if (name === "FencedCode") {
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
codeLineIndex++;
|
|
4441
|
+
if (node.name === "FencedCode") {
|
|
4442
|
+
this.decorateFencedCode(node, ctx);
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
});
|
|
4446
|
+
}
|
|
4447
|
+
decorateInlineCode(node, ctx) {
|
|
4448
|
+
const { from, to } = node;
|
|
4449
|
+
ctx.decorations.push(codeMarkDecorations["inline-code"].range(from, to));
|
|
4450
|
+
if (ctx.selectionOverlapsRange(from, to)) {
|
|
4451
|
+
return;
|
|
4452
|
+
}
|
|
4453
|
+
for (let child = node.node.firstChild; child; child = child.nextSibling) {
|
|
4454
|
+
if (child.name === "CodeMark") {
|
|
4455
|
+
ctx.decorations.push(codeMarkDecorations["inline-mark"].range(child.from, child.to));
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
decorateFencedCode(node, ctx) {
|
|
4460
|
+
const { view: view$1, decorations } = ctx;
|
|
4461
|
+
const nodeLineStart = view$1.state.doc.lineAt(node.from);
|
|
4462
|
+
const nodeLineEnd = view$1.state.doc.lineAt(node.to);
|
|
4463
|
+
const cursorInRange = ctx.selectionOverlapsRange(nodeLineStart.from, nodeLineEnd.to);
|
|
4464
|
+
let infoProps = { language: "" };
|
|
4465
|
+
let codeContent = "";
|
|
4466
|
+
for (let child = node.node.firstChild; child; child = child.nextSibling) {
|
|
4467
|
+
if (child.name === "CodeInfo") {
|
|
4468
|
+
infoProps = this.parseCodeInfo(view$1.state.sliceDoc(child.from, child.to).trim());
|
|
4469
|
+
}
|
|
4470
|
+
if (child.name === "CodeText") {
|
|
4471
|
+
codeContent = view$1.state.sliceDoc(child.from, child.to);
|
|
4472
|
+
}
|
|
4473
|
+
}
|
|
4474
|
+
const codeLines = [];
|
|
4475
|
+
for (let i = nodeLineStart.number + 1; i <= nodeLineEnd.number - 1; i++) {
|
|
4476
|
+
const codeLine = view$1.state.doc.line(i);
|
|
4477
|
+
codeLines.push(view$1.state.sliceDoc(codeLine.from, codeLine.to));
|
|
4478
|
+
}
|
|
4479
|
+
const totalCodeLines = nodeLineEnd.number - nodeLineStart.number - 1;
|
|
4480
|
+
const startLineNum = typeof infoProps.showLineNumbers === "number" ? infoProps.showLineNumbers : 1;
|
|
4481
|
+
const maxLineNum = startLineNum + totalCodeLines - 1;
|
|
4482
|
+
const lineNumWidth = Math.max(String(maxLineNum).length, String(startLineNum).length);
|
|
4483
|
+
const highlightInstanceCounters = new Array(infoProps.highlightText?.length ?? 0).fill(0);
|
|
4484
|
+
const diffStates = infoProps.diff ? this.analyzeDiffLines(codeLines) : [];
|
|
4485
|
+
const diffDisplayLineNumbers = infoProps.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum) : [];
|
|
4486
|
+
const displayLineNumbers = infoProps.diff ? diffDisplayLineNumbers.map((numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index) : codeLines.map((_, index) => startLineNum + index);
|
|
4487
|
+
const diffHighlightLineNumbers = infoProps.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum).map(
|
|
4488
|
+
(numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index
|
|
4489
|
+
) : [];
|
|
4490
|
+
const maxOldDiffLineNum = diffDisplayLineNumbers.reduce((max, numbers) => {
|
|
4491
|
+
const oldLine = numbers.oldLine ?? 0;
|
|
4492
|
+
return oldLine > max ? oldLine : max;
|
|
4493
|
+
}, startLineNum);
|
|
4494
|
+
const maxNewDiffLineNum = diffDisplayLineNumbers.reduce((max, numbers) => {
|
|
4495
|
+
const newLine = numbers.newLine ?? 0;
|
|
4496
|
+
return newLine > max ? newLine : max;
|
|
4497
|
+
}, startLineNum);
|
|
4498
|
+
const diffOldLineNumWidth = Math.max(String(startLineNum).length, String(maxOldDiffLineNum).length);
|
|
4499
|
+
const diffNewLineNumWidth = Math.max(String(startLineNum).length, String(maxNewDiffLineNum).length);
|
|
4500
|
+
const shouldShowHeader = !cursorInRange && (infoProps.title || infoProps.copy || infoProps.language);
|
|
4501
|
+
const shouldShowCaption = !cursorInRange && !!infoProps.caption;
|
|
4502
|
+
if (shouldShowHeader) {
|
|
4503
|
+
decorations.push(
|
|
4504
|
+
view.Decoration.widget({
|
|
4505
|
+
widget: new CodeBlockHeaderWidget(infoProps, codeContent),
|
|
4506
|
+
block: false,
|
|
4507
|
+
side: -1
|
|
4508
|
+
}).range(nodeLineStart.from)
|
|
4509
|
+
);
|
|
4510
|
+
}
|
|
4511
|
+
let codeLineIndex = 0;
|
|
4512
|
+
for (let lineNumber = nodeLineStart.number; lineNumber <= nodeLineEnd.number; lineNumber++) {
|
|
4513
|
+
const line = view$1.state.doc.line(lineNumber);
|
|
4514
|
+
const isFenceLine = lineNumber === nodeLineStart.number || lineNumber === nodeLineEnd.number;
|
|
4515
|
+
const relativeLineNum = displayLineNumbers[codeLineIndex] ?? startLineNum + codeLineIndex;
|
|
4516
|
+
decorations.push(codeMarkDecorations["code-block-line"].range(line.from));
|
|
4517
|
+
if (lineNumber === nodeLineStart.number) {
|
|
4518
|
+
decorations.push(codeMarkDecorations["code-block-line-start"].range(line.from));
|
|
4519
|
+
if (shouldShowHeader) {
|
|
4520
|
+
decorations.push(view.Decoration.line({ class: "cm-draftly-code-block-has-header" }).range(line.from));
|
|
4521
|
+
}
|
|
4522
|
+
}
|
|
4523
|
+
if (lineNumber === nodeLineEnd.number) {
|
|
4524
|
+
decorations.push(codeMarkDecorations["code-block-line-end"].range(line.from));
|
|
4525
|
+
if (shouldShowCaption) {
|
|
4526
|
+
decorations.push(view.Decoration.line({ class: "cm-draftly-code-block-has-caption" }).range(line.from));
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
if (!isFenceLine && infoProps.showLineNumbers && !infoProps.diff) {
|
|
4530
|
+
decorations.push(
|
|
4531
|
+
view.Decoration.line({
|
|
4532
|
+
class: "cm-draftly-code-line-numbered",
|
|
4533
|
+
attributes: {
|
|
4534
|
+
"data-line-num": String(relativeLineNum),
|
|
4535
|
+
style: `--line-num-width: ${lineNumWidth}ch`
|
|
2773
4536
|
}
|
|
2774
|
-
}
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
4537
|
+
}).range(line.from)
|
|
4538
|
+
);
|
|
4539
|
+
}
|
|
4540
|
+
if (!isFenceLine && infoProps.showLineNumbers && infoProps.diff) {
|
|
4541
|
+
const diffLineNumbers = diffDisplayLineNumbers[codeLineIndex];
|
|
4542
|
+
const diffState = diffStates[codeLineIndex];
|
|
4543
|
+
const diffMarker = diffState?.kind === "addition" ? "+" : diffState?.kind === "deletion" ? "-" : " ";
|
|
4544
|
+
decorations.push(
|
|
4545
|
+
view.Decoration.line({
|
|
4546
|
+
class: "cm-draftly-code-line-numbered-diff",
|
|
4547
|
+
attributes: {
|
|
4548
|
+
"data-line-num-old": diffLineNumbers?.oldLine != null ? String(diffLineNumbers.oldLine) : "",
|
|
4549
|
+
"data-line-num-new": diffLineNumbers?.newLine != null ? String(diffLineNumbers.newLine) : "",
|
|
4550
|
+
"data-diff-marker": diffMarker,
|
|
4551
|
+
style: `--line-num-old-width: ${diffOldLineNumWidth}ch; --line-num-new-width: ${diffNewLineNumWidth}ch`
|
|
2782
4552
|
}
|
|
4553
|
+
}).range(line.from)
|
|
4554
|
+
);
|
|
4555
|
+
}
|
|
4556
|
+
if (!isFenceLine && infoProps.diff) {
|
|
4557
|
+
this.decorateDiffLine(
|
|
4558
|
+
line,
|
|
4559
|
+
codeLineIndex,
|
|
4560
|
+
diffStates,
|
|
4561
|
+
cursorInRange,
|
|
4562
|
+
!infoProps.showLineNumbers,
|
|
4563
|
+
decorations
|
|
4564
|
+
);
|
|
4565
|
+
}
|
|
4566
|
+
if (!isFenceLine && infoProps.highlightLines) {
|
|
4567
|
+
const highlightLineNumber = infoProps.diff ? diffHighlightLineNumbers[codeLineIndex] ?? codeLineIndex + 1 : startLineNum + codeLineIndex;
|
|
4568
|
+
if (infoProps.highlightLines.includes(highlightLineNumber)) {
|
|
4569
|
+
decorations.push(codeMarkDecorations["code-line-highlight"].range(line.from));
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
if (!isFenceLine && infoProps.highlightText?.length) {
|
|
4573
|
+
this.decorateTextHighlights(
|
|
4574
|
+
line.from,
|
|
4575
|
+
view$1.state.sliceDoc(line.from, line.to),
|
|
4576
|
+
infoProps.highlightText,
|
|
4577
|
+
highlightInstanceCounters,
|
|
4578
|
+
decorations
|
|
4579
|
+
);
|
|
4580
|
+
}
|
|
4581
|
+
if (!isFenceLine) {
|
|
4582
|
+
codeLineIndex++;
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
this.decorateFenceMarkers(node.node, cursorInRange, decorations);
|
|
4586
|
+
if (!cursorInRange && infoProps.caption) {
|
|
4587
|
+
decorations.push(
|
|
4588
|
+
view.Decoration.widget({
|
|
4589
|
+
widget: new CodeBlockCaptionWidget(infoProps.caption),
|
|
4590
|
+
block: false,
|
|
4591
|
+
side: 1
|
|
4592
|
+
}).range(nodeLineEnd.to)
|
|
4593
|
+
);
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
4596
|
+
decorateFenceMarkers(node, cursorInRange, decorations) {
|
|
4597
|
+
for (let child = node.firstChild; child; child = child.nextSibling) {
|
|
4598
|
+
if (child.name === "CodeMark" || child.name === "CodeInfo") {
|
|
4599
|
+
decorations.push(
|
|
4600
|
+
(cursorInRange ? codeMarkDecorations["code-fence"] : codeMarkDecorations["code-hidden"]).range(
|
|
4601
|
+
child.from,
|
|
4602
|
+
child.to
|
|
4603
|
+
)
|
|
4604
|
+
);
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
}
|
|
4608
|
+
decorateDiffLine(line, codeLineIndex, diffStates, cursorInRange, showDiffMarkerGutter, decorations) {
|
|
4609
|
+
const diffState = diffStates[codeLineIndex];
|
|
4610
|
+
const diffMarker = diffState?.kind === "addition" ? "+" : diffState?.kind === "deletion" ? "-" : " ";
|
|
4611
|
+
if (showDiffMarkerGutter) {
|
|
4612
|
+
decorations.push(
|
|
4613
|
+
view.Decoration.line({
|
|
4614
|
+
class: "cm-draftly-code-line-diff-gutter",
|
|
4615
|
+
attributes: {
|
|
4616
|
+
"data-diff-marker": diffMarker
|
|
2783
4617
|
}
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
4618
|
+
}).range(line.from)
|
|
4619
|
+
);
|
|
4620
|
+
}
|
|
4621
|
+
if (diffState?.kind === "addition") {
|
|
4622
|
+
decorations.push(codeMarkDecorations["diff-line-add"].range(line.from));
|
|
4623
|
+
if (cursorInRange && line.to > line.from) {
|
|
4624
|
+
decorations.push(codeMarkDecorations["diff-sign-add"].range(line.from, line.from + 1));
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
if (diffState?.kind === "deletion") {
|
|
4628
|
+
decorations.push(codeMarkDecorations["diff-line-del"].range(line.from));
|
|
4629
|
+
if (cursorInRange && line.to > line.from) {
|
|
4630
|
+
decorations.push(codeMarkDecorations["diff-sign-del"].range(line.from, line.from + 1));
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
if (!cursorInRange && line.to > line.from && (diffState?.escapedMarker || diffState?.kind === "addition" || diffState?.kind === "deletion")) {
|
|
4634
|
+
decorations.push(codeMarkDecorations["diff-escape-hidden"].range(line.from, line.from + 1));
|
|
4635
|
+
}
|
|
4636
|
+
if (diffState?.modificationRanges?.length) {
|
|
4637
|
+
for (const [start, end] of diffState.modificationRanges) {
|
|
4638
|
+
const rangeFrom = line.from + diffState.contentOffset + start;
|
|
4639
|
+
const rangeTo = line.from + diffState.contentOffset + end;
|
|
4640
|
+
if (rangeTo > rangeFrom) {
|
|
4641
|
+
decorations.push(
|
|
4642
|
+
(diffState.kind === "addition" ? codeMarkDecorations["diff-mod-add"] : codeMarkDecorations["diff-mod-del"]).range(rangeFrom, rangeTo)
|
|
4643
|
+
);
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
decorateTextHighlights(lineFrom, lineText, highlights, instanceCounters, decorations) {
|
|
4649
|
+
for (const [highlightIndex, textHighlight] of highlights.entries()) {
|
|
4650
|
+
try {
|
|
4651
|
+
const regex = new RegExp(textHighlight.pattern, "g");
|
|
4652
|
+
let match;
|
|
4653
|
+
while ((match = regex.exec(lineText)) !== null) {
|
|
4654
|
+
instanceCounters[highlightIndex] = (instanceCounters[highlightIndex] ?? 0) + 1;
|
|
4655
|
+
const globalMatchIndex = instanceCounters[highlightIndex];
|
|
4656
|
+
const shouldHighlight = !textHighlight.instances || textHighlight.instances.includes(globalMatchIndex);
|
|
4657
|
+
if (shouldHighlight) {
|
|
4658
|
+
const matchFrom = lineFrom + match.index;
|
|
4659
|
+
const matchTo = matchFrom + match[0].length;
|
|
4660
|
+
decorations.push(codeMarkDecorations["code-text-highlight"].range(matchFrom, matchTo));
|
|
2793
4661
|
}
|
|
2794
4662
|
}
|
|
4663
|
+
} catch {
|
|
2795
4664
|
}
|
|
2796
|
-
}
|
|
4665
|
+
}
|
|
2797
4666
|
}
|
|
2798
4667
|
/**
|
|
2799
4668
|
* Render code elements to HTML for static preview.
|
|
2800
4669
|
* Applies syntax highlighting using @lezer/highlight.
|
|
2801
4670
|
*/
|
|
2802
|
-
renderToHTML(node,
|
|
4671
|
+
async renderToHTML(node, _children, ctx) {
|
|
2803
4672
|
if (node.name === "CodeMark") {
|
|
2804
4673
|
return "";
|
|
2805
4674
|
}
|
|
@@ -2809,7 +4678,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2809
4678
|
if (match && match[1]) {
|
|
2810
4679
|
content = match[1];
|
|
2811
4680
|
}
|
|
2812
|
-
return `<code class="cm-draftly-code-inline" style="padding: 0.1rem 0.25rem">${
|
|
4681
|
+
return `<code class="cm-draftly-code-inline" style="padding: 0.1rem 0.25rem">${this.escapeHtml(content)}</code>`;
|
|
2813
4682
|
}
|
|
2814
4683
|
if (node.name === "FencedCode") {
|
|
2815
4684
|
const content = ctx.sliceDoc(node.from, node.to);
|
|
@@ -2827,9 +4696,9 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2827
4696
|
html += `<div class="cm-draftly-code-header">`;
|
|
2828
4697
|
html += `<div class="cm-draftly-code-header-left">`;
|
|
2829
4698
|
if (props.title) {
|
|
2830
|
-
html += `<span class="cm-draftly-code-header-title">${
|
|
4699
|
+
html += `<span class="cm-draftly-code-header-title">${this.escapeHtml(props.title)}</span>`;
|
|
2831
4700
|
} else if (props.language) {
|
|
2832
|
-
html += `<span class="cm-draftly-code-header-lang">${
|
|
4701
|
+
html += `<span class="cm-draftly-code-header-lang">${this.escapeHtml(props.language)}</span>`;
|
|
2833
4702
|
}
|
|
2834
4703
|
html += `</div>`;
|
|
2835
4704
|
if (props.copy !== false) {
|
|
@@ -2842,32 +4711,83 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2842
4711
|
}
|
|
2843
4712
|
html += `</div>`;
|
|
2844
4713
|
}
|
|
2845
|
-
const startLineNum = typeof props.
|
|
2846
|
-
const
|
|
4714
|
+
const startLineNum = typeof props.showLineNumbers === "number" ? props.showLineNumbers : 1;
|
|
4715
|
+
const previewHighlightCounters = new Array(props.highlightText?.length ?? 0).fill(0);
|
|
4716
|
+
const diffStates = props.diff ? this.analyzeDiffLines(codeLines) : [];
|
|
4717
|
+
const previewDiffLineNumbers = props.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum) : [];
|
|
4718
|
+
const previewLineNumbers = props.diff ? previewDiffLineNumbers.map((numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index) : codeLines.map((_, index) => startLineNum + index);
|
|
4719
|
+
const previewHighlightLineNumbers = props.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum).map(
|
|
4720
|
+
(numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index
|
|
4721
|
+
) : [];
|
|
4722
|
+
const lineNumWidth = String(Math.max(...previewLineNumbers, startLineNum)).length;
|
|
4723
|
+
const previewOldLineNumWidth = String(
|
|
4724
|
+
Math.max(
|
|
4725
|
+
...previewDiffLineNumbers.map((numbers) => numbers.oldLine ?? 0),
|
|
4726
|
+
startLineNum
|
|
4727
|
+
)
|
|
4728
|
+
).length;
|
|
4729
|
+
const previewNewLineNumWidth = String(
|
|
4730
|
+
Math.max(
|
|
4731
|
+
...previewDiffLineNumbers.map((numbers) => numbers.newLine ?? 0),
|
|
4732
|
+
startLineNum
|
|
4733
|
+
)
|
|
4734
|
+
).length;
|
|
4735
|
+
const previewContentLines = props.diff ? diffStates.map((state) => state.content) : codeLines;
|
|
4736
|
+
const highlightedLines = await this.highlightCodeLines(
|
|
4737
|
+
previewContentLines.join("\n"),
|
|
4738
|
+
props.language || "",
|
|
4739
|
+
ctx.syntaxHighlighters
|
|
4740
|
+
);
|
|
2847
4741
|
const hasHeader = showHeader ? " cm-draftly-code-block-has-header" : "";
|
|
2848
4742
|
const hasCaption = props.caption ? " cm-draftly-code-block-has-caption" : "";
|
|
2849
|
-
html += `<pre class="cm-draftly-code-block${hasHeader}${hasCaption}"${props.language ? ` data-lang="${
|
|
4743
|
+
html += `<pre class="cm-draftly-code-block${hasHeader}${hasCaption}"${props.language ? ` data-lang="${this.escapeAttribute(props.language)}"` : ""}>`;
|
|
2850
4744
|
html += `<code>`;
|
|
2851
4745
|
codeLines.forEach((line, index) => {
|
|
2852
|
-
const lineNum = startLineNum + index;
|
|
2853
|
-
const
|
|
4746
|
+
const lineNum = previewLineNumbers[index] ?? startLineNum + index;
|
|
4747
|
+
const highlightLineNumber = props.diff ? previewHighlightLineNumbers[index] ?? startLineNum + index : startLineNum + index;
|
|
4748
|
+
const isHighlighted = props.highlightLines?.includes(highlightLineNumber);
|
|
4749
|
+
const diffState = props.diff ? diffStates[index] : void 0;
|
|
4750
|
+
const diffLineNumbers = props.diff ? previewDiffLineNumbers[index] : void 0;
|
|
2854
4751
|
const lineClasses = ["cm-draftly-code-line"];
|
|
2855
4752
|
if (isHighlighted) lineClasses.push("cm-draftly-code-line-highlight");
|
|
2856
|
-
if (props.
|
|
4753
|
+
if (props.showLineNumbers) {
|
|
4754
|
+
lineClasses.push(props.diff ? "cm-draftly-code-line-numbered-diff" : "cm-draftly-code-line-numbered");
|
|
4755
|
+
}
|
|
4756
|
+
if (diffState?.kind === "addition") lineClasses.push("cm-draftly-code-line-diff-add");
|
|
4757
|
+
if (diffState?.kind === "deletion") lineClasses.push("cm-draftly-code-line-diff-del");
|
|
2857
4758
|
const lineAttrs = [`class="${lineClasses.join(" ")}"`];
|
|
2858
|
-
if (props.
|
|
4759
|
+
if (props.showLineNumbers && !props.diff) {
|
|
2859
4760
|
lineAttrs.push(`data-line-num="${lineNum}"`);
|
|
2860
4761
|
lineAttrs.push(`style="--line-num-width: ${lineNumWidth}ch"`);
|
|
2861
4762
|
}
|
|
2862
|
-
|
|
4763
|
+
if (props.diff) {
|
|
4764
|
+
const diffMarker = diffState?.kind === "addition" ? "+" : diffState?.kind === "deletion" ? "-" : " ";
|
|
4765
|
+
if (props.showLineNumbers) {
|
|
4766
|
+
lineAttrs.push(`data-line-num-old="${diffLineNumbers?.oldLine != null ? diffLineNumbers.oldLine : ""}"`);
|
|
4767
|
+
lineAttrs.push(`data-line-num-new="${diffLineNumbers?.newLine != null ? diffLineNumbers.newLine : ""}"`);
|
|
4768
|
+
lineAttrs.push(`data-diff-marker="${diffMarker}"`);
|
|
4769
|
+
lineAttrs.push(
|
|
4770
|
+
`style="--line-num-old-width: ${previewOldLineNumWidth}ch; --line-num-new-width: ${previewNewLineNumWidth}ch"`
|
|
4771
|
+
);
|
|
4772
|
+
} else {
|
|
4773
|
+
lineAttrs.push(`data-diff-marker="${diffMarker}"`);
|
|
4774
|
+
lineClasses.push("cm-draftly-code-line-diff-gutter");
|
|
4775
|
+
lineAttrs[0] = `class="${lineClasses.join(" ")}"`;
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
const highlightedLine = highlightedLines[index] ?? this.escapeHtml(previewContentLines[index] ?? line);
|
|
4779
|
+
let lineContent = highlightedLine;
|
|
4780
|
+
if (diffState) {
|
|
4781
|
+
lineContent = this.renderDiffPreviewLine(diffState, highlightedLine);
|
|
4782
|
+
}
|
|
2863
4783
|
if (props.highlightText && props.highlightText.length > 0) {
|
|
2864
|
-
lineContent = this.applyTextHighlights(lineContent, props.highlightText);
|
|
4784
|
+
lineContent = this.applyTextHighlights(lineContent, props.highlightText, previewHighlightCounters);
|
|
2865
4785
|
}
|
|
2866
4786
|
html += `<span ${lineAttrs.join(" ")}>${lineContent || " "}</span>`;
|
|
2867
4787
|
});
|
|
2868
4788
|
html += `</code></pre>`;
|
|
2869
4789
|
if (props.caption) {
|
|
2870
|
-
html += `<div class="cm-draftly-code-caption">${
|
|
4790
|
+
html += `<div class="cm-draftly-code-caption">${this.escapeHtml(props.caption)}</div>`;
|
|
2871
4791
|
}
|
|
2872
4792
|
html += `</div>`;
|
|
2873
4793
|
return html;
|
|
@@ -2877,54 +4797,290 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2877
4797
|
}
|
|
2878
4798
|
return null;
|
|
2879
4799
|
}
|
|
4800
|
+
/** Parse comma-separated numbers and ranges (e.g. "1,3-5") into [1,3,4,5]. */
|
|
4801
|
+
parseNumberList(value) {
|
|
4802
|
+
const result = [];
|
|
4803
|
+
for (const part of value.split(",")) {
|
|
4804
|
+
const trimmed = part.trim();
|
|
4805
|
+
const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/);
|
|
4806
|
+
if (rangeMatch && rangeMatch[1] && rangeMatch[2]) {
|
|
4807
|
+
const start = parseInt(rangeMatch[1], 10);
|
|
4808
|
+
const end = parseInt(rangeMatch[2], 10);
|
|
4809
|
+
for (let i = start; i <= end; i++) {
|
|
4810
|
+
result.push(i);
|
|
4811
|
+
}
|
|
4812
|
+
continue;
|
|
4813
|
+
}
|
|
4814
|
+
if (/^\d+$/.test(trimmed)) {
|
|
4815
|
+
result.push(parseInt(trimmed, 10));
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
return result;
|
|
4819
|
+
}
|
|
2880
4820
|
/**
|
|
2881
4821
|
* Highlight a single line of code using the language's Lezer parser.
|
|
2882
4822
|
* Falls back to sanitized plain text if the language is not supported.
|
|
2883
4823
|
*/
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
4824
|
+
async highlightCodeLines(code, lang, syntaxHighlighters) {
|
|
4825
|
+
const rawLines = code.split("\n");
|
|
4826
|
+
if (!lang || !code) {
|
|
4827
|
+
return rawLines.map((line) => this.escapeHtml(line));
|
|
2887
4828
|
}
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
if (!langDesc || !langDesc.support) {
|
|
2892
|
-
return ctx.sanitize(line);
|
|
4829
|
+
const parser = await this.resolveLanguageParser(lang);
|
|
4830
|
+
if (!parser) {
|
|
4831
|
+
return rawLines.map((line) => this.escapeHtml(line));
|
|
2893
4832
|
}
|
|
2894
4833
|
try {
|
|
2895
|
-
const
|
|
2896
|
-
const
|
|
2897
|
-
let result = "";
|
|
4834
|
+
const tree = parser.parse(code);
|
|
4835
|
+
const highlightedLines = [""];
|
|
2898
4836
|
highlight.highlightCode(
|
|
2899
|
-
|
|
4837
|
+
code,
|
|
2900
4838
|
tree,
|
|
2901
|
-
|
|
4839
|
+
syntaxHighlighters && syntaxHighlighters.length > 0 ? syntaxHighlighters : [],
|
|
2902
4840
|
(text, classes2) => {
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
} else {
|
|
2906
|
-
result += ctx.sanitize(text);
|
|
2907
|
-
}
|
|
4841
|
+
const chunk = classes2 ? `<span class="${this.escapeAttribute(classes2)}">${this.escapeHtml(text)}</span>` : this.escapeHtml(text);
|
|
4842
|
+
highlightedLines[highlightedLines.length - 1] += chunk;
|
|
2908
4843
|
},
|
|
2909
4844
|
() => {
|
|
4845
|
+
highlightedLines.push("");
|
|
2910
4846
|
}
|
|
2911
|
-
// No newlines for single line
|
|
2912
4847
|
);
|
|
2913
|
-
return
|
|
4848
|
+
return rawLines.map((line, index) => highlightedLines[index] || this.escapeHtml(line));
|
|
2914
4849
|
} catch {
|
|
2915
|
-
return
|
|
4850
|
+
return rawLines.map((line) => this.escapeHtml(line));
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4853
|
+
async resolveLanguageParser(lang) {
|
|
4854
|
+
const normalizedLang = this.normalizeLanguage(lang);
|
|
4855
|
+
if (!normalizedLang) return null;
|
|
4856
|
+
const cached = this.parserCache.get(normalizedLang);
|
|
4857
|
+
if (cached) return cached;
|
|
4858
|
+
const parserPromise = (async () => {
|
|
4859
|
+
const langDesc = language.LanguageDescription.matchLanguageName(languageData.languages, normalizedLang, true);
|
|
4860
|
+
if (!langDesc) return null;
|
|
4861
|
+
if (langDesc.support) {
|
|
4862
|
+
return langDesc.support.language.parser;
|
|
4863
|
+
}
|
|
4864
|
+
if (typeof langDesc.load === "function") {
|
|
4865
|
+
try {
|
|
4866
|
+
const support = await langDesc.load();
|
|
4867
|
+
return support.language.parser;
|
|
4868
|
+
} catch {
|
|
4869
|
+
return null;
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
return null;
|
|
4873
|
+
})();
|
|
4874
|
+
this.parserCache.set(normalizedLang, parserPromise);
|
|
4875
|
+
return parserPromise;
|
|
4876
|
+
}
|
|
4877
|
+
normalizeLanguage(lang) {
|
|
4878
|
+
const normalized = lang.trim().toLowerCase();
|
|
4879
|
+
if (!normalized) return "";
|
|
4880
|
+
const normalizedMap = {
|
|
4881
|
+
"c++": "cpp",
|
|
4882
|
+
"c#": "csharp",
|
|
4883
|
+
"f#": "fsharp",
|
|
4884
|
+
py: "python",
|
|
4885
|
+
js: "javascript",
|
|
4886
|
+
ts: "typescript",
|
|
4887
|
+
sh: "shell"
|
|
4888
|
+
};
|
|
4889
|
+
return normalizedMap[normalized] ?? normalized;
|
|
4890
|
+
}
|
|
4891
|
+
escapeHtml(value) {
|
|
4892
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4893
|
+
}
|
|
4894
|
+
escapeAttribute(value) {
|
|
4895
|
+
return this.escapeHtml(value).replace(/`/g, "`");
|
|
4896
|
+
}
|
|
4897
|
+
analyzeDiffLines(lines) {
|
|
4898
|
+
const states = lines.map((line) => this.parseDiffLineState(line));
|
|
4899
|
+
let index = 0;
|
|
4900
|
+
while (index < states.length) {
|
|
4901
|
+
if (states[index]?.kind !== "deletion") {
|
|
4902
|
+
index++;
|
|
4903
|
+
continue;
|
|
4904
|
+
}
|
|
4905
|
+
const deletionStart = index;
|
|
4906
|
+
while (index < states.length && states[index]?.kind === "deletion") {
|
|
4907
|
+
index++;
|
|
4908
|
+
}
|
|
4909
|
+
const deletionEnd = index;
|
|
4910
|
+
const additionStart = index;
|
|
4911
|
+
while (index < states.length && states[index]?.kind === "addition") {
|
|
4912
|
+
index++;
|
|
4913
|
+
}
|
|
4914
|
+
const additionEnd = index;
|
|
4915
|
+
if (additionStart === additionEnd) {
|
|
4916
|
+
continue;
|
|
4917
|
+
}
|
|
4918
|
+
const pairCount = Math.min(deletionEnd - deletionStart, additionEnd - additionStart);
|
|
4919
|
+
for (let pairIndex = 0; pairIndex < pairCount; pairIndex++) {
|
|
4920
|
+
const deletionState = states[deletionStart + pairIndex];
|
|
4921
|
+
const additionState = states[additionStart + pairIndex];
|
|
4922
|
+
if (!deletionState || !additionState) {
|
|
4923
|
+
continue;
|
|
4924
|
+
}
|
|
4925
|
+
const ranges = this.computeChangedRanges(deletionState.content, additionState.content);
|
|
4926
|
+
if (ranges.oldRanges.length > 0) {
|
|
4927
|
+
deletionState.modificationRanges = ranges.oldRanges;
|
|
4928
|
+
}
|
|
4929
|
+
if (ranges.newRanges.length > 0) {
|
|
4930
|
+
additionState.modificationRanges = ranges.newRanges;
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
return states;
|
|
4935
|
+
}
|
|
4936
|
+
computeDiffDisplayLineNumbers(states, startLineNum) {
|
|
4937
|
+
const numbers = [];
|
|
4938
|
+
let oldLineNumber = startLineNum;
|
|
4939
|
+
let newLineNumber = startLineNum;
|
|
4940
|
+
for (const state of states) {
|
|
4941
|
+
if (state.kind === "deletion") {
|
|
4942
|
+
numbers.push({ oldLine: oldLineNumber, newLine: null });
|
|
4943
|
+
oldLineNumber++;
|
|
4944
|
+
continue;
|
|
4945
|
+
}
|
|
4946
|
+
if (state.kind === "addition") {
|
|
4947
|
+
numbers.push({ oldLine: null, newLine: newLineNumber });
|
|
4948
|
+
newLineNumber++;
|
|
4949
|
+
continue;
|
|
4950
|
+
}
|
|
4951
|
+
numbers.push({ oldLine: oldLineNumber, newLine: newLineNumber });
|
|
4952
|
+
oldLineNumber++;
|
|
4953
|
+
newLineNumber++;
|
|
4954
|
+
}
|
|
4955
|
+
return numbers;
|
|
4956
|
+
}
|
|
4957
|
+
parseDiffLineState(line) {
|
|
4958
|
+
const escapedMarker = line.startsWith("\\+") || line.startsWith("\\-");
|
|
4959
|
+
if (escapedMarker) {
|
|
4960
|
+
return {
|
|
4961
|
+
kind: "normal",
|
|
4962
|
+
content: line.slice(1),
|
|
4963
|
+
contentOffset: 1,
|
|
4964
|
+
escapedMarker: true
|
|
4965
|
+
};
|
|
4966
|
+
}
|
|
4967
|
+
if (line.startsWith("+")) {
|
|
4968
|
+
return {
|
|
4969
|
+
kind: "addition",
|
|
4970
|
+
content: line.slice(1),
|
|
4971
|
+
contentOffset: 1,
|
|
4972
|
+
escapedMarker: false
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
if (line.startsWith("-")) {
|
|
4976
|
+
return {
|
|
4977
|
+
kind: "deletion",
|
|
4978
|
+
content: line.slice(1),
|
|
4979
|
+
contentOffset: 1,
|
|
4980
|
+
escapedMarker: false
|
|
4981
|
+
};
|
|
4982
|
+
}
|
|
4983
|
+
return {
|
|
4984
|
+
kind: "normal",
|
|
4985
|
+
content: line,
|
|
4986
|
+
contentOffset: 0,
|
|
4987
|
+
escapedMarker: false
|
|
4988
|
+
};
|
|
4989
|
+
}
|
|
4990
|
+
computeChangedRanges(oldText, newText) {
|
|
4991
|
+
let prefix = 0;
|
|
4992
|
+
while (prefix < oldText.length && prefix < newText.length && oldText[prefix] === newText[prefix]) {
|
|
4993
|
+
prefix++;
|
|
4994
|
+
}
|
|
4995
|
+
let oldSuffix = oldText.length;
|
|
4996
|
+
let newSuffix = newText.length;
|
|
4997
|
+
while (oldSuffix > prefix && newSuffix > prefix && oldText[oldSuffix - 1] === newText[newSuffix - 1]) {
|
|
4998
|
+
oldSuffix--;
|
|
4999
|
+
newSuffix--;
|
|
5000
|
+
}
|
|
5001
|
+
const oldRanges = [];
|
|
5002
|
+
const newRanges = [];
|
|
5003
|
+
if (oldSuffix > prefix) {
|
|
5004
|
+
oldRanges.push([prefix, oldSuffix]);
|
|
5005
|
+
}
|
|
5006
|
+
if (newSuffix > prefix) {
|
|
5007
|
+
newRanges.push([prefix, newSuffix]);
|
|
5008
|
+
}
|
|
5009
|
+
return { oldRanges, newRanges };
|
|
5010
|
+
}
|
|
5011
|
+
renderDiffPreviewLine(diffState, highlightedContent) {
|
|
5012
|
+
const modClass = diffState.kind === "addition" ? "cm-draftly-code-diff-mod-add" : diffState.kind === "deletion" ? "cm-draftly-code-diff-mod-del" : "";
|
|
5013
|
+
const baseHighlightedContent = highlightedContent || this.escapeHtml(diffState.content);
|
|
5014
|
+
const contentHtml = diffState.modificationRanges && modClass ? this.applyRangesToHighlightedHTML(baseHighlightedContent, diffState.modificationRanges, modClass) : baseHighlightedContent;
|
|
5015
|
+
return contentHtml || " ";
|
|
5016
|
+
}
|
|
5017
|
+
applyRangesToHighlightedHTML(htmlContent, ranges, className) {
|
|
5018
|
+
const normalizedRanges = ranges.map(([start, end]) => [Math.max(0, start), Math.max(0, end)]).filter(([start, end]) => end > start).sort((a, b) => a[0] - b[0]);
|
|
5019
|
+
if (normalizedRanges.length === 0 || !htmlContent) {
|
|
5020
|
+
return htmlContent;
|
|
5021
|
+
}
|
|
5022
|
+
const isInsideRange = (position) => {
|
|
5023
|
+
for (const [start, end] of normalizedRanges) {
|
|
5024
|
+
if (position >= start && position < end) return true;
|
|
5025
|
+
if (position < start) return false;
|
|
5026
|
+
}
|
|
5027
|
+
return false;
|
|
5028
|
+
};
|
|
5029
|
+
let result = "";
|
|
5030
|
+
let htmlIndex = 0;
|
|
5031
|
+
let textPosition = 0;
|
|
5032
|
+
let markOpen = false;
|
|
5033
|
+
while (htmlIndex < htmlContent.length) {
|
|
5034
|
+
const char = htmlContent[htmlIndex];
|
|
5035
|
+
if (char === "<") {
|
|
5036
|
+
const tagEnd = htmlContent.indexOf(">", htmlIndex);
|
|
5037
|
+
if (tagEnd === -1) {
|
|
5038
|
+
result += htmlContent.slice(htmlIndex);
|
|
5039
|
+
break;
|
|
5040
|
+
}
|
|
5041
|
+
result += htmlContent.slice(htmlIndex, tagEnd + 1);
|
|
5042
|
+
htmlIndex = tagEnd + 1;
|
|
5043
|
+
continue;
|
|
5044
|
+
}
|
|
5045
|
+
let token = char;
|
|
5046
|
+
if (char === "&") {
|
|
5047
|
+
const entityEnd = htmlContent.indexOf(";", htmlIndex);
|
|
5048
|
+
if (entityEnd !== -1) {
|
|
5049
|
+
token = htmlContent.slice(htmlIndex, entityEnd + 1);
|
|
5050
|
+
htmlIndex = entityEnd + 1;
|
|
5051
|
+
} else {
|
|
5052
|
+
htmlIndex += 1;
|
|
5053
|
+
}
|
|
5054
|
+
} else {
|
|
5055
|
+
htmlIndex += 1;
|
|
5056
|
+
}
|
|
5057
|
+
const shouldMark = isInsideRange(textPosition);
|
|
5058
|
+
if (shouldMark && !markOpen) {
|
|
5059
|
+
result += `<mark class="${className}">`;
|
|
5060
|
+
markOpen = true;
|
|
5061
|
+
}
|
|
5062
|
+
if (!shouldMark && markOpen) {
|
|
5063
|
+
result += "</mark>";
|
|
5064
|
+
markOpen = false;
|
|
5065
|
+
}
|
|
5066
|
+
result += token;
|
|
5067
|
+
textPosition += 1;
|
|
5068
|
+
}
|
|
5069
|
+
if (markOpen) {
|
|
5070
|
+
result += "</mark>";
|
|
2916
5071
|
}
|
|
5072
|
+
return result;
|
|
2917
5073
|
}
|
|
2918
5074
|
/**
|
|
2919
5075
|
* Apply text highlights (regex patterns) to already syntax-highlighted HTML.
|
|
2920
5076
|
* Wraps matched patterns in `<mark>` elements.
|
|
2921
5077
|
*/
|
|
2922
|
-
applyTextHighlights(htmlContent, highlights) {
|
|
5078
|
+
applyTextHighlights(htmlContent, highlights, instanceCounters) {
|
|
2923
5079
|
let result = htmlContent;
|
|
2924
|
-
for (const highlight of highlights) {
|
|
5080
|
+
for (const [highlightIndex, highlight] of highlights.entries()) {
|
|
2925
5081
|
try {
|
|
2926
5082
|
const regex = new RegExp(`(${highlight.pattern})`, "g");
|
|
2927
|
-
let matchCount = 0;
|
|
5083
|
+
let matchCount = instanceCounters?.[highlightIndex] ?? 0;
|
|
2928
5084
|
result = result.replace(regex, (match) => {
|
|
2929
5085
|
matchCount++;
|
|
2930
5086
|
const shouldHighlight = !highlight.instances || highlight.instances.includes(matchCount);
|
|
@@ -2933,252 +5089,15 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2933
5089
|
}
|
|
2934
5090
|
return match;
|
|
2935
5091
|
});
|
|
5092
|
+
if (instanceCounters) {
|
|
5093
|
+
instanceCounters[highlightIndex] = matchCount;
|
|
5094
|
+
}
|
|
2936
5095
|
} catch {
|
|
2937
5096
|
}
|
|
2938
5097
|
}
|
|
2939
5098
|
return result;
|
|
2940
5099
|
}
|
|
2941
5100
|
};
|
|
2942
|
-
var theme10 = chunkKDEDLC3D_cjs.createTheme({
|
|
2943
|
-
default: {
|
|
2944
|
-
// Inline code
|
|
2945
|
-
".cm-draftly-code-inline": {
|
|
2946
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
2947
|
-
fontSize: "0.9rem",
|
|
2948
|
-
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
|
2949
|
-
padding: "0.1rem 0.25rem",
|
|
2950
|
-
border: "1px solid var(--color-border)",
|
|
2951
|
-
borderRadius: "3px"
|
|
2952
|
-
},
|
|
2953
|
-
// Fenced code block lines
|
|
2954
|
-
".cm-draftly-code-block-line": {
|
|
2955
|
-
"--radius": "0.375rem",
|
|
2956
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
2957
|
-
fontSize: "0.9rem",
|
|
2958
|
-
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
2959
|
-
padding: "0 1rem !important",
|
|
2960
|
-
lineHeight: "1.5",
|
|
2961
|
-
borderLeft: "1px solid var(--color-border)",
|
|
2962
|
-
borderRight: "1px solid var(--color-border)"
|
|
2963
|
-
},
|
|
2964
|
-
// First line of code block
|
|
2965
|
-
".cm-draftly-code-block-line-start": {
|
|
2966
|
-
borderTopLeftRadius: "var(--radius)",
|
|
2967
|
-
borderTopRightRadius: "var(--radius)",
|
|
2968
|
-
position: "relative",
|
|
2969
|
-
overflow: "hidden",
|
|
2970
|
-
borderTop: "1px solid var(--color-border)",
|
|
2971
|
-
paddingBottom: "0.5rem !important"
|
|
2972
|
-
},
|
|
2973
|
-
// Remove top radius when header is present
|
|
2974
|
-
".cm-draftly-code-block-has-header": {
|
|
2975
|
-
padding: "0 !important",
|
|
2976
|
-
paddingBottom: "0.5rem !important"
|
|
2977
|
-
},
|
|
2978
|
-
// Code block header widget
|
|
2979
|
-
".cm-draftly-code-header": {
|
|
2980
|
-
display: "flex",
|
|
2981
|
-
justifyContent: "space-between",
|
|
2982
|
-
alignItems: "center",
|
|
2983
|
-
padding: "0.25rem 1rem",
|
|
2984
|
-
backgroundColor: "rgba(0, 0, 0, 0.06)",
|
|
2985
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
2986
|
-
fontSize: "0.85rem"
|
|
2987
|
-
},
|
|
2988
|
-
".cm-draftly-code-header-left": {
|
|
2989
|
-
display: "flex",
|
|
2990
|
-
alignItems: "center",
|
|
2991
|
-
gap: "0.5rem"
|
|
2992
|
-
},
|
|
2993
|
-
".cm-draftly-code-header-title": {
|
|
2994
|
-
color: "var(--color-text, inherit)",
|
|
2995
|
-
fontWeight: "500"
|
|
2996
|
-
},
|
|
2997
|
-
".cm-draftly-code-header-lang": {
|
|
2998
|
-
color: "#6a737d",
|
|
2999
|
-
opacity: "0.8"
|
|
3000
|
-
},
|
|
3001
|
-
".cm-draftly-code-header-right": {
|
|
3002
|
-
display: "flex",
|
|
3003
|
-
alignItems: "center",
|
|
3004
|
-
gap: "0.5rem"
|
|
3005
|
-
},
|
|
3006
|
-
".cm-draftly-code-copy-btn": {
|
|
3007
|
-
display: "flex",
|
|
3008
|
-
alignItems: "center",
|
|
3009
|
-
justifyContent: "center",
|
|
3010
|
-
padding: "0.25rem",
|
|
3011
|
-
backgroundColor: "transparent",
|
|
3012
|
-
border: "none",
|
|
3013
|
-
borderRadius: "4px",
|
|
3014
|
-
cursor: "pointer",
|
|
3015
|
-
color: "#6a737d",
|
|
3016
|
-
transition: "color 0.2s, background-color 0.2s"
|
|
3017
|
-
},
|
|
3018
|
-
".cm-draftly-code-copy-btn:hover": {
|
|
3019
|
-
backgroundColor: "rgba(0, 0, 0, 0.1)",
|
|
3020
|
-
color: "var(--color-text, inherit)"
|
|
3021
|
-
},
|
|
3022
|
-
".cm-draftly-code-copy-btn.copied": {
|
|
3023
|
-
color: "#22c55e"
|
|
3024
|
-
},
|
|
3025
|
-
// Caption (below code block)
|
|
3026
|
-
".cm-draftly-code-block-has-caption": {
|
|
3027
|
-
padding: "0 !important",
|
|
3028
|
-
paddingTop: "0.5rem !important"
|
|
3029
|
-
},
|
|
3030
|
-
".cm-draftly-code-caption": {
|
|
3031
|
-
textAlign: "center",
|
|
3032
|
-
fontSize: "0.85rem",
|
|
3033
|
-
color: "#6a737d",
|
|
3034
|
-
fontStyle: "italic",
|
|
3035
|
-
padding: "0.25rem 1rem",
|
|
3036
|
-
backgroundColor: "rgba(0, 0, 0, 0.06)"
|
|
3037
|
-
},
|
|
3038
|
-
// Last line of code block
|
|
3039
|
-
".cm-draftly-code-block-line-end": {
|
|
3040
|
-
borderBottomLeftRadius: "var(--radius)",
|
|
3041
|
-
borderBottomRightRadius: "var(--radius)",
|
|
3042
|
-
borderBottom: "1px solid var(--color-border)",
|
|
3043
|
-
paddingTop: "0.5rem !important"
|
|
3044
|
-
},
|
|
3045
|
-
".cm-draftly-code-block-line-end br": {
|
|
3046
|
-
display: "none"
|
|
3047
|
-
},
|
|
3048
|
-
// Fence markers (```)
|
|
3049
|
-
".cm-draftly-code-fence": {
|
|
3050
|
-
color: "#6a737d",
|
|
3051
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
3052
|
-
},
|
|
3053
|
-
// Line numbers
|
|
3054
|
-
".cm-draftly-code-line-numbered": {
|
|
3055
|
-
paddingLeft: "calc(var(--line-num-width, 2ch) + 1rem) !important",
|
|
3056
|
-
position: "relative"
|
|
3057
|
-
},
|
|
3058
|
-
".cm-draftly-code-line-numbered::before": {
|
|
3059
|
-
content: "attr(data-line-num)",
|
|
3060
|
-
position: "absolute",
|
|
3061
|
-
left: "0.5rem",
|
|
3062
|
-
top: "0.2rem",
|
|
3063
|
-
width: "var(--line-num-width, 2ch)",
|
|
3064
|
-
textAlign: "right",
|
|
3065
|
-
color: "#6a737d",
|
|
3066
|
-
opacity: "0.6",
|
|
3067
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3068
|
-
fontSize: "0.85rem",
|
|
3069
|
-
userSelect: "none"
|
|
3070
|
-
},
|
|
3071
|
-
// Preview: code lines (need block display for full-width highlights)
|
|
3072
|
-
".cm-draftly-code-line": {
|
|
3073
|
-
display: "block",
|
|
3074
|
-
position: "relative",
|
|
3075
|
-
paddingLeft: "1rem",
|
|
3076
|
-
paddingRight: "1rem",
|
|
3077
|
-
lineHeight: "1.5",
|
|
3078
|
-
borderLeft: "3px solid transparent"
|
|
3079
|
-
},
|
|
3080
|
-
// Line highlight
|
|
3081
|
-
".cm-draftly-code-line-highlight": {
|
|
3082
|
-
backgroundColor: "rgba(255, 220, 100, 0.2) !important",
|
|
3083
|
-
borderLeft: "3px solid #f0b429 !important"
|
|
3084
|
-
},
|
|
3085
|
-
// Text highlight
|
|
3086
|
-
".cm-draftly-code-text-highlight": {
|
|
3087
|
-
backgroundColor: "rgba(255, 220, 100, 0.4)",
|
|
3088
|
-
borderRadius: "2px",
|
|
3089
|
-
padding: "0.1rem 0"
|
|
3090
|
-
},
|
|
3091
|
-
// Preview: container wrapper
|
|
3092
|
-
".cm-draftly-code-container": {
|
|
3093
|
-
margin: "1rem 0",
|
|
3094
|
-
borderRadius: "var(--radius)",
|
|
3095
|
-
overflow: "hidden",
|
|
3096
|
-
border: "1px solid var(--color-border)"
|
|
3097
|
-
},
|
|
3098
|
-
// Preview: header inside container
|
|
3099
|
-
".cm-draftly-code-container .cm-draftly-code-header": {
|
|
3100
|
-
borderRadius: "0",
|
|
3101
|
-
border: "none",
|
|
3102
|
-
borderBottom: "1px solid var(--color-border)"
|
|
3103
|
-
},
|
|
3104
|
-
// Preview: code block inside container
|
|
3105
|
-
".cm-draftly-code-container .cm-draftly-code-block": {
|
|
3106
|
-
margin: "0",
|
|
3107
|
-
borderRadius: "0",
|
|
3108
|
-
border: "none",
|
|
3109
|
-
whiteSpace: "pre-wrap"
|
|
3110
|
-
},
|
|
3111
|
-
// Preview: caption inside container
|
|
3112
|
-
".cm-draftly-code-container .cm-draftly-code-caption": {
|
|
3113
|
-
borderTop: "1px solid var(--color-border)"
|
|
3114
|
-
},
|
|
3115
|
-
// Preview: standalone code block (not in container)
|
|
3116
|
-
".cm-draftly-code-block": {
|
|
3117
|
-
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3118
|
-
fontSize: "0.9rem",
|
|
3119
|
-
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
3120
|
-
padding: "1rem",
|
|
3121
|
-
overflow: "auto",
|
|
3122
|
-
position: "relative",
|
|
3123
|
-
borderRadius: "var(--radius)",
|
|
3124
|
-
border: "1px solid var(--color-border)"
|
|
3125
|
-
},
|
|
3126
|
-
// Preview: code block with header (remove top radius)
|
|
3127
|
-
".cm-draftly-code-block.cm-draftly-code-block-has-header": {
|
|
3128
|
-
borderTopLeftRadius: "0",
|
|
3129
|
-
borderTopRightRadius: "0",
|
|
3130
|
-
borderTop: "none",
|
|
3131
|
-
margin: "0",
|
|
3132
|
-
paddingTop: "0.5rem !important"
|
|
3133
|
-
},
|
|
3134
|
-
// Preview: code block with caption (remove bottom radius)
|
|
3135
|
-
".cm-draftly-code-block.cm-draftly-code-block-has-caption": {
|
|
3136
|
-
borderBottomLeftRadius: "0",
|
|
3137
|
-
borderBottomRightRadius: "0",
|
|
3138
|
-
borderBottom: "none",
|
|
3139
|
-
paddingBottom: "0.5rem !important"
|
|
3140
|
-
}
|
|
3141
|
-
},
|
|
3142
|
-
dark: {
|
|
3143
|
-
".cm-draftly-code-inline": {
|
|
3144
|
-
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
|
3145
|
-
},
|
|
3146
|
-
".cm-draftly-code-block-line": {
|
|
3147
|
-
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
3148
|
-
},
|
|
3149
|
-
".cm-draftly-code-fence": {
|
|
3150
|
-
color: "#8b949e"
|
|
3151
|
-
},
|
|
3152
|
-
".cm-draftly-code-block": {
|
|
3153
|
-
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
3154
|
-
},
|
|
3155
|
-
".cm-draftly-code-header": {
|
|
3156
|
-
backgroundColor: "rgba(255, 255, 255, 0.08)"
|
|
3157
|
-
},
|
|
3158
|
-
".cm-draftly-code-header-lang": {
|
|
3159
|
-
color: "#8b949e"
|
|
3160
|
-
},
|
|
3161
|
-
".cm-draftly-code-copy-btn": {
|
|
3162
|
-
color: "#8b949e"
|
|
3163
|
-
},
|
|
3164
|
-
".cm-draftly-code-copy-btn:hover": {
|
|
3165
|
-
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
|
3166
|
-
},
|
|
3167
|
-
".cm-draftly-code-caption": {
|
|
3168
|
-
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
3169
|
-
},
|
|
3170
|
-
".cm-draftly-code-line-numbered::before": {
|
|
3171
|
-
color: "#8b949e"
|
|
3172
|
-
},
|
|
3173
|
-
".cm-draftly-code-line-highlight": {
|
|
3174
|
-
backgroundColor: "rgba(255, 220, 100, 0.15) !important",
|
|
3175
|
-
borderLeft: "3px solid #d9a520 !important"
|
|
3176
|
-
},
|
|
3177
|
-
".cm-draftly-code-text-highlight": {
|
|
3178
|
-
backgroundColor: "rgba(255, 220, 100, 0.3)"
|
|
3179
|
-
}
|
|
3180
|
-
}
|
|
3181
|
-
});
|
|
3182
5101
|
var quoteMarkDecorations = {
|
|
3183
5102
|
/** Decoration for the > marker */
|
|
3184
5103
|
"quote-mark": view.Decoration.replace({}),
|
|
@@ -3189,7 +5108,7 @@ var quoteLineDecorations = {
|
|
|
3189
5108
|
/** Decoration for blockquote lines */
|
|
3190
5109
|
"quote-line": view.Decoration.line({ class: "cm-draftly-quote-line" })
|
|
3191
5110
|
};
|
|
3192
|
-
var QuotePlugin = class extends
|
|
5111
|
+
var QuotePlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
3193
5112
|
name = "quote";
|
|
3194
5113
|
version = "1.0.0";
|
|
3195
5114
|
decorationPriority = 10;
|
|
@@ -3260,7 +5179,7 @@ var QuotePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
3260
5179
|
`;
|
|
3261
5180
|
}
|
|
3262
5181
|
};
|
|
3263
|
-
var theme11 =
|
|
5182
|
+
var theme11 = chunkW75QUUQC_cjs.createTheme({
|
|
3264
5183
|
default: {
|
|
3265
5184
|
// Line styling with left border
|
|
3266
5185
|
".cm-draftly-quote-line": {
|
|
@@ -3279,7 +5198,7 @@ var theme11 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
3279
5198
|
});
|
|
3280
5199
|
var hrLineDecoration = view.Decoration.line({ class: "cm-draftly-hr-line" });
|
|
3281
5200
|
var hrMarkDecoration = view.Decoration.replace({});
|
|
3282
|
-
var HRPlugin = class extends
|
|
5201
|
+
var HRPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
3283
5202
|
name = "hr";
|
|
3284
5203
|
version = "1.0.0";
|
|
3285
5204
|
decorationPriority = 10;
|
|
@@ -3327,7 +5246,7 @@ var HRPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
3327
5246
|
`;
|
|
3328
5247
|
}
|
|
3329
5248
|
};
|
|
3330
|
-
var theme12 =
|
|
5249
|
+
var theme12 = chunkW75QUUQC_cjs.createTheme({
|
|
3331
5250
|
default: {
|
|
3332
5251
|
// Line styling — displays a centered horizontal line
|
|
3333
5252
|
".cm-draftly-hr-line": {
|
|
@@ -3346,6 +5265,103 @@ var theme12 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
3346
5265
|
}
|
|
3347
5266
|
}
|
|
3348
5267
|
});
|
|
5268
|
+
function shortcodeToEmoji(raw) {
|
|
5269
|
+
const rendered = emoji__namespace.emojify(raw);
|
|
5270
|
+
return rendered !== raw ? rendered : null;
|
|
5271
|
+
}
|
|
5272
|
+
var EmojiWidget = class extends view.WidgetType {
|
|
5273
|
+
constructor(rendered) {
|
|
5274
|
+
super();
|
|
5275
|
+
this.rendered = rendered;
|
|
5276
|
+
}
|
|
5277
|
+
eq(other) {
|
|
5278
|
+
return other.rendered === this.rendered;
|
|
5279
|
+
}
|
|
5280
|
+
toDOM() {
|
|
5281
|
+
const span = document.createElement("span");
|
|
5282
|
+
span.className = "cm-draftly-emoji";
|
|
5283
|
+
span.textContent = this.rendered;
|
|
5284
|
+
return span;
|
|
5285
|
+
}
|
|
5286
|
+
ignoreEvent() {
|
|
5287
|
+
return false;
|
|
5288
|
+
}
|
|
5289
|
+
};
|
|
5290
|
+
var emojiMarkDecorations = {
|
|
5291
|
+
"emoji-source": view.Decoration.mark({ class: "cm-draftly-emoji-source" })
|
|
5292
|
+
};
|
|
5293
|
+
var EmojiPlugin = class extends chunkEQUQHE2E_cjs.DecorationPlugin {
|
|
5294
|
+
name = "emoji";
|
|
5295
|
+
version = "1.0.0";
|
|
5296
|
+
decorationPriority = 20;
|
|
5297
|
+
requiredNodes = ["Emoji", "EmojiMark"];
|
|
5298
|
+
constructor() {
|
|
5299
|
+
super();
|
|
5300
|
+
}
|
|
5301
|
+
/**
|
|
5302
|
+
* Plugin theme
|
|
5303
|
+
*/
|
|
5304
|
+
get theme() {
|
|
5305
|
+
return theme13;
|
|
5306
|
+
}
|
|
5307
|
+
/**
|
|
5308
|
+
* Build emoji decorations by iterating the syntax tree
|
|
5309
|
+
*/
|
|
5310
|
+
buildDecorations(ctx) {
|
|
5311
|
+
const { view: view$1, decorations } = ctx;
|
|
5312
|
+
const tree = language.syntaxTree(view$1.state);
|
|
5313
|
+
tree.iterate({
|
|
5314
|
+
enter: (node) => {
|
|
5315
|
+
const { from, to, name } = node;
|
|
5316
|
+
if (name !== "Emoji") {
|
|
5317
|
+
return;
|
|
5318
|
+
}
|
|
5319
|
+
const raw = view$1.state.sliceDoc(from, to);
|
|
5320
|
+
const rendered = shortcodeToEmoji(raw);
|
|
5321
|
+
if (!rendered) {
|
|
5322
|
+
return;
|
|
5323
|
+
}
|
|
5324
|
+
const cursorInNode = ctx.selectionOverlapsRange(from, to);
|
|
5325
|
+
if (cursorInNode) {
|
|
5326
|
+
decorations.push(emojiMarkDecorations["emoji-source"].range(from, to));
|
|
5327
|
+
return;
|
|
5328
|
+
}
|
|
5329
|
+
decorations.push(
|
|
5330
|
+
view.Decoration.replace({
|
|
5331
|
+
widget: new EmojiWidget(rendered)
|
|
5332
|
+
}).range(from, to)
|
|
5333
|
+
);
|
|
5334
|
+
}
|
|
5335
|
+
});
|
|
5336
|
+
}
|
|
5337
|
+
renderToHTML(node, children, ctx) {
|
|
5338
|
+
if (node.name === "EmojiMark") {
|
|
5339
|
+
return "";
|
|
5340
|
+
}
|
|
5341
|
+
if (node.name !== "Emoji") {
|
|
5342
|
+
return null;
|
|
5343
|
+
}
|
|
5344
|
+
const raw = ctx.sliceDoc(node.from, node.to);
|
|
5345
|
+
const rendered = shortcodeToEmoji(raw);
|
|
5346
|
+
if (!rendered) {
|
|
5347
|
+
return `<span class="cm-draftly-emoji-source">${children}</span>`;
|
|
5348
|
+
}
|
|
5349
|
+
return `<span class="cm-draftly-emoji">${rendered}</span>`;
|
|
5350
|
+
}
|
|
5351
|
+
};
|
|
5352
|
+
var theme13 = chunkW75QUUQC_cjs.createTheme({
|
|
5353
|
+
default: {
|
|
5354
|
+
".cm-draftly-emoji": {
|
|
5355
|
+
fontFamily: '"Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif',
|
|
5356
|
+
fontVariantEmoji: "emoji",
|
|
5357
|
+
lineHeight: "1.2"
|
|
5358
|
+
},
|
|
5359
|
+
".cm-draftly-emoji-source": {
|
|
5360
|
+
fontFamily: "inherit",
|
|
5361
|
+
lineHeight: "inherit"
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5364
|
+
});
|
|
3349
5365
|
|
|
3350
5366
|
// src/plugins/index.ts
|
|
3351
5367
|
var essentialPlugins = [
|
|
@@ -3354,17 +5370,20 @@ var essentialPlugins = [
|
|
|
3354
5370
|
new InlinePlugin(),
|
|
3355
5371
|
new LinkPlugin(),
|
|
3356
5372
|
new ListPlugin(),
|
|
5373
|
+
new TablePlugin(),
|
|
3357
5374
|
new HTMLPlugin(),
|
|
3358
5375
|
new ImagePlugin(),
|
|
3359
5376
|
new MathPlugin(),
|
|
3360
5377
|
new MermaidPlugin(),
|
|
3361
5378
|
new CodePlugin(),
|
|
3362
5379
|
new QuotePlugin(),
|
|
3363
|
-
new HRPlugin()
|
|
5380
|
+
new HRPlugin(),
|
|
5381
|
+
new EmojiPlugin()
|
|
3364
5382
|
];
|
|
3365
5383
|
var allPlugins = [...essentialPlugins];
|
|
3366
5384
|
|
|
3367
5385
|
exports.CodePlugin = CodePlugin;
|
|
5386
|
+
exports.EmojiPlugin = EmojiPlugin;
|
|
3368
5387
|
exports.HRPlugin = HRPlugin;
|
|
3369
5388
|
exports.HTMLPlugin = HTMLPlugin;
|
|
3370
5389
|
exports.HeadingPlugin = HeadingPlugin;
|
|
@@ -3376,7 +5395,8 @@ exports.MathPlugin = MathPlugin;
|
|
|
3376
5395
|
exports.MermaidPlugin = MermaidPlugin;
|
|
3377
5396
|
exports.ParagraphPlugin = ParagraphPlugin;
|
|
3378
5397
|
exports.QuotePlugin = QuotePlugin;
|
|
5398
|
+
exports.TablePlugin = TablePlugin;
|
|
3379
5399
|
exports.allPlugins = allPlugins;
|
|
3380
5400
|
exports.essentialPlugins = essentialPlugins;
|
|
3381
|
-
//# sourceMappingURL=chunk-
|
|
3382
|
-
//# sourceMappingURL=chunk-
|
|
5401
|
+
//# sourceMappingURL=chunk-OMFUE4AQ.cjs.map
|
|
5402
|
+
//# sourceMappingURL=chunk-OMFUE4AQ.cjs.map
|