draftly 1.0.7 → 2.0.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-72ZYRGRT.cjs → chunk-BWJLMREN.cjs} +11 -9
- package/dist/chunk-BWJLMREN.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-DFQYXFOP.js → chunk-EEHILRG5.js} +26 -3
- package/dist/chunk-EEHILRG5.js.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-L2XSK57Y.js} +1761 -478
- package/dist/chunk-L2XSK57Y.js.map +1 -0
- package/dist/{chunk-KDEDLC3D.cjs → chunk-TBVZEK2H.cjs} +27 -2
- package/dist/chunk-TBVZEK2H.cjs.map +1 -0
- package/dist/{chunk-2B3A3VSQ.cjs → chunk-W5ALMXG2.cjs} +1808 -504
- package/dist/chunk-W5ALMXG2.cjs.map +1 -0
- package/dist/{chunk-CG4M4TC7.js → chunk-ZUI3GI3W.js} +7 -5
- package/dist/chunk-ZUI3GI3W.js.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 +144 -9
- package/dist/plugins/index.d.ts +144 -9
- 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 +1 -0
- package/src/editor/plugin.ts +5 -1
- package/src/editor/theme.ts +1 -0
- package/src/editor/utils.ts +31 -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 +900 -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,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkBWJLMREN_cjs = require('./chunk-BWJLMREN.cjs');
|
|
4
|
+
var chunk3T55CBNZ_cjs = require('./chunk-3T55CBNZ.cjs');
|
|
5
|
+
var chunkCLW73JRX_cjs = require('./chunk-CLW73JRX.cjs');
|
|
6
|
+
var chunkTBVZEK2H_cjs = require('./chunk-TBVZEK2H.cjs');
|
|
5
7
|
var view = require('@codemirror/view');
|
|
6
8
|
var language = require('@codemirror/language');
|
|
7
9
|
var highlight = require('@lezer/highlight');
|
|
@@ -10,16 +12,36 @@ var katex = require('katex');
|
|
|
10
12
|
var katexCss = require('katex/dist/katex.min.css?raw');
|
|
11
13
|
var mermaid = require('mermaid');
|
|
12
14
|
var languageData = require('@codemirror/language-data');
|
|
15
|
+
var emoji = require('node-emoji');
|
|
13
16
|
|
|
14
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
18
|
|
|
19
|
+
function _interopNamespace(e) {
|
|
20
|
+
if (e && e.__esModule) return e;
|
|
21
|
+
var n = Object.create(null);
|
|
22
|
+
if (e) {
|
|
23
|
+
Object.keys(e).forEach(function (k) {
|
|
24
|
+
if (k !== 'default') {
|
|
25
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
26
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return e[k]; }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
n.default = e;
|
|
34
|
+
return Object.freeze(n);
|
|
35
|
+
}
|
|
36
|
+
|
|
16
37
|
var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
|
|
17
38
|
var katex__default = /*#__PURE__*/_interopDefault(katex);
|
|
18
39
|
var katexCss__default = /*#__PURE__*/_interopDefault(katexCss);
|
|
19
40
|
var mermaid__default = /*#__PURE__*/_interopDefault(mermaid);
|
|
41
|
+
var emoji__namespace = /*#__PURE__*/_interopNamespace(emoji);
|
|
20
42
|
|
|
21
43
|
// src/plugins/paragraph-plugin.ts
|
|
22
|
-
var ParagraphPlugin = class extends
|
|
44
|
+
var ParagraphPlugin = class extends chunkBWJLMREN_cjs.DraftlyPlugin {
|
|
23
45
|
name = "paragraph";
|
|
24
46
|
version = "1.0.0";
|
|
25
47
|
requiredNodes = ["Paragraph"];
|
|
@@ -36,7 +58,7 @@ var ParagraphPlugin = class extends chunk72ZYRGRT_cjs.DraftlyPlugin {
|
|
|
36
58
|
return `<p class="cm-draftly-paragraph">${children}</p>`;
|
|
37
59
|
}
|
|
38
60
|
};
|
|
39
|
-
var theme =
|
|
61
|
+
var theme = chunkTBVZEK2H_cjs.createTheme({
|
|
40
62
|
default: {
|
|
41
63
|
".cm-draftly-paragraph": {
|
|
42
64
|
paddingTop: "0.5em",
|
|
@@ -63,7 +85,7 @@ var headingLineDecorations = {
|
|
|
63
85
|
"heading-5": view.Decoration.line({ class: "cm-draftly-line-h5" }),
|
|
64
86
|
"heading-6": view.Decoration.line({ class: "cm-draftly-line-h6" })
|
|
65
87
|
};
|
|
66
|
-
var HeadingPlugin = class extends
|
|
88
|
+
var HeadingPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
67
89
|
name = "heading";
|
|
68
90
|
version = "1.0.0";
|
|
69
91
|
decorationPriority = 10;
|
|
@@ -135,7 +157,7 @@ var HeadingPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
135
157
|
`;
|
|
136
158
|
}
|
|
137
159
|
};
|
|
138
|
-
var theme2 =
|
|
160
|
+
var theme2 = chunkTBVZEK2H_cjs.createTheme({
|
|
139
161
|
default: {
|
|
140
162
|
".cm-draftly-h1": {
|
|
141
163
|
fontSize: "2em",
|
|
@@ -234,7 +256,7 @@ var highlightParser = {
|
|
|
234
256
|
);
|
|
235
257
|
}
|
|
236
258
|
};
|
|
237
|
-
var InlinePlugin = class extends
|
|
259
|
+
var InlinePlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
238
260
|
name = "inline";
|
|
239
261
|
version = "1.0.0";
|
|
240
262
|
decorationPriority = 20;
|
|
@@ -271,36 +293,47 @@ var InlinePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
271
293
|
return [
|
|
272
294
|
{
|
|
273
295
|
key: "Mod-b",
|
|
274
|
-
run:
|
|
296
|
+
run: chunkTBVZEK2H_cjs.toggleMarkdownStyle("**"),
|
|
275
297
|
preventDefault: true
|
|
276
298
|
},
|
|
277
299
|
{
|
|
278
300
|
key: "Mod-i",
|
|
279
|
-
run:
|
|
301
|
+
run: chunkTBVZEK2H_cjs.toggleMarkdownStyle("*"),
|
|
280
302
|
preventDefault: true
|
|
281
303
|
},
|
|
282
304
|
{
|
|
283
305
|
key: "Mod-Shift-s",
|
|
284
|
-
run:
|
|
306
|
+
run: chunkTBVZEK2H_cjs.toggleMarkdownStyle("~~"),
|
|
285
307
|
preventDefault: true
|
|
286
308
|
},
|
|
287
309
|
{
|
|
288
310
|
key: "Mod-,",
|
|
289
|
-
run:
|
|
311
|
+
run: chunkTBVZEK2H_cjs.toggleMarkdownStyle("~"),
|
|
290
312
|
preventDefault: true
|
|
291
313
|
},
|
|
292
314
|
{
|
|
293
315
|
key: "Mod-.",
|
|
294
|
-
run:
|
|
316
|
+
run: chunkTBVZEK2H_cjs.toggleMarkdownStyle("^"),
|
|
295
317
|
preventDefault: true
|
|
296
318
|
},
|
|
297
319
|
{
|
|
298
320
|
key: "Mod-Shift-h",
|
|
299
|
-
run:
|
|
321
|
+
run: chunkTBVZEK2H_cjs.toggleMarkdownStyle("=="),
|
|
300
322
|
preventDefault: true
|
|
301
323
|
}
|
|
302
324
|
];
|
|
303
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Intercepts inline marker typing to wrap selected text.
|
|
328
|
+
*
|
|
329
|
+
* If user types inline markers while text is selected, wraps each selected
|
|
330
|
+
* range with the appropriate marker:
|
|
331
|
+
* - * _ ~ ^ -> marker + selected + marker
|
|
332
|
+
* - = -> ==selected==
|
|
333
|
+
*/
|
|
334
|
+
getExtensions() {
|
|
335
|
+
return [chunk3T55CBNZ_cjs.createWrapSelectionInputHandler({ "*": "*", _: "_", "~": "~", "^": "^", "=": "==" })];
|
|
336
|
+
}
|
|
304
337
|
/**
|
|
305
338
|
* Return markdown parser extensions for highlight syntax (==text==)
|
|
306
339
|
*/
|
|
@@ -372,7 +405,7 @@ var InlinePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
372
405
|
return `<span class="${className}">${children}</span>`;
|
|
373
406
|
}
|
|
374
407
|
};
|
|
375
|
-
var theme3 =
|
|
408
|
+
var theme3 = chunkTBVZEK2H_cjs.createTheme({
|
|
376
409
|
default: {
|
|
377
410
|
// Emphasis (italic)
|
|
378
411
|
".cm-draftly-emphasis": {
|
|
@@ -468,7 +501,7 @@ var LinkTooltipWidget = class extends view.WidgetType {
|
|
|
468
501
|
return event.type !== "click" && event.type !== "mouseenter" && event.type !== "mouseleave";
|
|
469
502
|
}
|
|
470
503
|
};
|
|
471
|
-
var LinkPlugin = class extends
|
|
504
|
+
var LinkPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
472
505
|
name = "link";
|
|
473
506
|
version = "1.0.0";
|
|
474
507
|
decorationPriority = 22;
|
|
@@ -672,7 +705,7 @@ var LinkTextWidget = class extends view.WidgetType {
|
|
|
672
705
|
return event.type !== "click" && event.type !== "mouseenter" && event.type !== "mouseleave";
|
|
673
706
|
}
|
|
674
707
|
};
|
|
675
|
-
var theme4 =
|
|
708
|
+
var theme4 = chunkTBVZEK2H_cjs.createTheme({
|
|
676
709
|
default: {
|
|
677
710
|
// Link text
|
|
678
711
|
".cm-draftly-link-text": {
|
|
@@ -818,7 +851,7 @@ var TaskCheckboxWidget = class extends view.WidgetType {
|
|
|
818
851
|
}
|
|
819
852
|
}
|
|
820
853
|
};
|
|
821
|
-
var ListPlugin = class extends
|
|
854
|
+
var ListPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
822
855
|
name = "list";
|
|
823
856
|
version = "1.0.0";
|
|
824
857
|
decorationPriority = 20;
|
|
@@ -1021,7 +1054,7 @@ var ListPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1021
1054
|
}
|
|
1022
1055
|
}
|
|
1023
1056
|
};
|
|
1024
|
-
var theme5 =
|
|
1057
|
+
var theme5 = chunkTBVZEK2H_cjs.createTheme({
|
|
1025
1058
|
default: {
|
|
1026
1059
|
// Indentation marker positioning
|
|
1027
1060
|
".cm-draftly-list-indent": {
|
|
@@ -1119,6 +1152,653 @@ var theme5 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
1119
1152
|
}
|
|
1120
1153
|
}
|
|
1121
1154
|
});
|
|
1155
|
+
function parseAlignment(cell) {
|
|
1156
|
+
const trimmed = cell.trim();
|
|
1157
|
+
const left = trimmed.startsWith(":");
|
|
1158
|
+
const right = trimmed.endsWith(":");
|
|
1159
|
+
if (left && right) return "center";
|
|
1160
|
+
if (right) return "right";
|
|
1161
|
+
return "left";
|
|
1162
|
+
}
|
|
1163
|
+
function parseTableMarkdown(markdown) {
|
|
1164
|
+
const lines = markdown.split("\n").filter((l) => l.trim().length > 0);
|
|
1165
|
+
if (lines.length < 2) return null;
|
|
1166
|
+
const parseCells = (line) => {
|
|
1167
|
+
let trimmed = line.trim();
|
|
1168
|
+
if (trimmed.startsWith("|")) trimmed = trimmed.slice(1);
|
|
1169
|
+
if (trimmed.endsWith("|")) trimmed = trimmed.slice(0, -1);
|
|
1170
|
+
return trimmed.split("|").map((c) => c.trim());
|
|
1171
|
+
};
|
|
1172
|
+
const headers = parseCells(lines[0]);
|
|
1173
|
+
const delimiterCells = parseCells(lines[1]);
|
|
1174
|
+
const isDelimiter = delimiterCells.every((c) => /^:?-+:?$/.test(c.trim()));
|
|
1175
|
+
if (!isDelimiter) return null;
|
|
1176
|
+
const alignments = delimiterCells.map(parseAlignment);
|
|
1177
|
+
const rows = [];
|
|
1178
|
+
for (let i = 2; i < lines.length; i++) {
|
|
1179
|
+
rows.push(parseCells(lines[i]));
|
|
1180
|
+
}
|
|
1181
|
+
return { headers, alignments, rows };
|
|
1182
|
+
}
|
|
1183
|
+
function isRowEmpty(rowText) {
|
|
1184
|
+
const trimmed = rowText.trim();
|
|
1185
|
+
if (!trimmed.startsWith("|")) return false;
|
|
1186
|
+
let inner = trimmed;
|
|
1187
|
+
if (inner.startsWith("|")) inner = inner.slice(1);
|
|
1188
|
+
if (inner.endsWith("|")) inner = inner.slice(0, -1);
|
|
1189
|
+
return inner.split("|").every((cell) => cell.trim() === "");
|
|
1190
|
+
}
|
|
1191
|
+
async function renderCellWithPreviewRenderer(text, config) {
|
|
1192
|
+
if (!text.trim()) {
|
|
1193
|
+
return " ";
|
|
1194
|
+
}
|
|
1195
|
+
const renderer = new chunkCLW73JRX_cjs.PreviewRenderer(
|
|
1196
|
+
text,
|
|
1197
|
+
config?.plugins || [],
|
|
1198
|
+
config?.markdown || [],
|
|
1199
|
+
config?.theme || "auto" /* AUTO */,
|
|
1200
|
+
true
|
|
1201
|
+
);
|
|
1202
|
+
const html = await renderer.render();
|
|
1203
|
+
const paragraphMatch = html.match(/^\s*<p>([\s\S]*)<\/p>\s*$/i);
|
|
1204
|
+
if (paragraphMatch && paragraphMatch[1] !== void 0) {
|
|
1205
|
+
return paragraphMatch[1];
|
|
1206
|
+
}
|
|
1207
|
+
return html;
|
|
1208
|
+
}
|
|
1209
|
+
function getColumnAlignment(alignments, index) {
|
|
1210
|
+
return alignments[index] || "left";
|
|
1211
|
+
}
|
|
1212
|
+
function getColumnCount(headers, row) {
|
|
1213
|
+
return Math.max(headers.length, row.length);
|
|
1214
|
+
}
|
|
1215
|
+
async function renderTableToHtml(parsed, config) {
|
|
1216
|
+
const { headers, alignments, rows } = parsed;
|
|
1217
|
+
let html = '<div class="cm-draftly-table-widget">';
|
|
1218
|
+
html += '<table class="cm-draftly-table">';
|
|
1219
|
+
html += "<thead><tr>";
|
|
1220
|
+
for (let i = 0; i < headers.length; i++) {
|
|
1221
|
+
const cell = headers[i] || "";
|
|
1222
|
+
const align = getColumnAlignment(alignments, i);
|
|
1223
|
+
const rendered = await renderCellWithPreviewRenderer(cell, config);
|
|
1224
|
+
html += `<th style="text-align: ${align}">${rendered}</th>`;
|
|
1225
|
+
}
|
|
1226
|
+
html += "</tr></thead>";
|
|
1227
|
+
html += "<tbody>";
|
|
1228
|
+
for (const row of rows) {
|
|
1229
|
+
html += "<tr>";
|
|
1230
|
+
const colCount = getColumnCount(headers, row);
|
|
1231
|
+
for (let i = 0; i < colCount; i++) {
|
|
1232
|
+
const align = getColumnAlignment(alignments, i);
|
|
1233
|
+
const cell = row[i] || "";
|
|
1234
|
+
const rendered = await renderCellWithPreviewRenderer(cell, config);
|
|
1235
|
+
html += `<td style="text-align: ${align}">${rendered}</td>`;
|
|
1236
|
+
}
|
|
1237
|
+
html += "</tr>";
|
|
1238
|
+
}
|
|
1239
|
+
html += "</tbody>";
|
|
1240
|
+
html += "</table></div>";
|
|
1241
|
+
return html;
|
|
1242
|
+
}
|
|
1243
|
+
var TableWidget = class extends view.WidgetType {
|
|
1244
|
+
constructor(tableMarkdown, from, to, config) {
|
|
1245
|
+
super();
|
|
1246
|
+
this.tableMarkdown = tableMarkdown;
|
|
1247
|
+
this.from = from;
|
|
1248
|
+
this.to = to;
|
|
1249
|
+
this.config = config;
|
|
1250
|
+
}
|
|
1251
|
+
eq(other) {
|
|
1252
|
+
return other.tableMarkdown === this.tableMarkdown && other.from === this.from && other.to === this.to && other.config === this.config;
|
|
1253
|
+
}
|
|
1254
|
+
toDOM(view) {
|
|
1255
|
+
const wrapper = document.createElement("div");
|
|
1256
|
+
wrapper.className = "cm-draftly-table-widget";
|
|
1257
|
+
const parsed = parseTableMarkdown(this.tableMarkdown);
|
|
1258
|
+
if (!parsed) {
|
|
1259
|
+
wrapper.textContent = "[Invalid table]";
|
|
1260
|
+
return wrapper;
|
|
1261
|
+
}
|
|
1262
|
+
const { headers, alignments, rows } = parsed;
|
|
1263
|
+
const table = document.createElement("table");
|
|
1264
|
+
table.className = "cm-draftly-table";
|
|
1265
|
+
const thead = document.createElement("thead");
|
|
1266
|
+
const headerRow = document.createElement("tr");
|
|
1267
|
+
headers.forEach((h, i) => {
|
|
1268
|
+
const th = document.createElement("th");
|
|
1269
|
+
th.innerHTML = " ";
|
|
1270
|
+
this.renderCellAsync(h, th);
|
|
1271
|
+
const align = alignments[i];
|
|
1272
|
+
if (align) th.style.textAlign = align;
|
|
1273
|
+
headerRow.appendChild(th);
|
|
1274
|
+
});
|
|
1275
|
+
thead.appendChild(headerRow);
|
|
1276
|
+
table.appendChild(thead);
|
|
1277
|
+
const tbody = document.createElement("tbody");
|
|
1278
|
+
rows.forEach((row) => {
|
|
1279
|
+
const tr = document.createElement("tr");
|
|
1280
|
+
const colCount = getColumnCount(headers, row);
|
|
1281
|
+
for (let i = 0; i < colCount; i++) {
|
|
1282
|
+
const td = document.createElement("td");
|
|
1283
|
+
td.innerHTML = " ";
|
|
1284
|
+
this.renderCellAsync(row[i] || "", td);
|
|
1285
|
+
const align = getColumnAlignment(alignments, i);
|
|
1286
|
+
td.style.textAlign = align;
|
|
1287
|
+
tr.appendChild(td);
|
|
1288
|
+
}
|
|
1289
|
+
tbody.appendChild(tr);
|
|
1290
|
+
});
|
|
1291
|
+
table.appendChild(tbody);
|
|
1292
|
+
wrapper.appendChild(table);
|
|
1293
|
+
wrapper.addEventListener("click", (e) => {
|
|
1294
|
+
e.preventDefault();
|
|
1295
|
+
e.stopPropagation();
|
|
1296
|
+
view.dispatch({
|
|
1297
|
+
selection: { anchor: this.from },
|
|
1298
|
+
scrollIntoView: true
|
|
1299
|
+
});
|
|
1300
|
+
view.focus();
|
|
1301
|
+
});
|
|
1302
|
+
return wrapper;
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Render cell content asynchronously using PreviewRenderer
|
|
1306
|
+
*/
|
|
1307
|
+
async renderCellAsync(text, element) {
|
|
1308
|
+
if (!text.trim()) {
|
|
1309
|
+
element.innerHTML = " ";
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
try {
|
|
1313
|
+
element.innerHTML = await renderCellWithPreviewRenderer(text, this.config);
|
|
1314
|
+
} catch (error) {
|
|
1315
|
+
console.error("Failed to render table cell:", error);
|
|
1316
|
+
element.textContent = text;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
ignoreEvent(event) {
|
|
1320
|
+
return event.type !== "click";
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
var tableMarkDecorations = {
|
|
1324
|
+
"table-line": view.Decoration.line({ class: "cm-draftly-table-line" }),
|
|
1325
|
+
"table-line-start": view.Decoration.line({ class: "cm-draftly-table-line-start" }),
|
|
1326
|
+
"table-line-end": view.Decoration.line({ class: "cm-draftly-table-line-end" }),
|
|
1327
|
+
"table-delimiter": view.Decoration.line({ class: "cm-draftly-table-delimiter-line" }),
|
|
1328
|
+
"table-rendered": view.Decoration.line({ class: "cm-draftly-table-rendered" }),
|
|
1329
|
+
// "table-hidden": Decoration.mark({ class: "cm-draftly-table-hidden" }),
|
|
1330
|
+
"table-hidden": view.Decoration.replace({})
|
|
1331
|
+
};
|
|
1332
|
+
var TablePlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
1333
|
+
name = "table";
|
|
1334
|
+
version = "1.0.0";
|
|
1335
|
+
decorationPriority = 20;
|
|
1336
|
+
requiredNodes = ["Table", "TableHeader", "TableDelimiter", "TableRow", "TableCell"];
|
|
1337
|
+
/** Configuration stored from onRegister */
|
|
1338
|
+
draftlyConfig;
|
|
1339
|
+
onRegister(context) {
|
|
1340
|
+
super.onRegister(context);
|
|
1341
|
+
this.draftlyConfig = context.config;
|
|
1342
|
+
}
|
|
1343
|
+
get theme() {
|
|
1344
|
+
return theme6;
|
|
1345
|
+
}
|
|
1346
|
+
// ============================================
|
|
1347
|
+
// Keymaps
|
|
1348
|
+
// ============================================
|
|
1349
|
+
getKeymap() {
|
|
1350
|
+
return [
|
|
1351
|
+
{
|
|
1352
|
+
key: "Mod-Shift-t",
|
|
1353
|
+
run: (view) => this.insertTable(view),
|
|
1354
|
+
preventDefault: true
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
key: "Mod-Enter",
|
|
1358
|
+
run: (view) => this.addRow(view),
|
|
1359
|
+
preventDefault: true
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
key: "Mod-Shift-Enter",
|
|
1363
|
+
run: (view) => this.addColumn(view),
|
|
1364
|
+
preventDefault: true
|
|
1365
|
+
},
|
|
1366
|
+
{
|
|
1367
|
+
key: "Enter",
|
|
1368
|
+
run: (view) => this.handleEnter(view)
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
key: "Tab",
|
|
1372
|
+
run: (view) => this.handleTab(view, false)
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
key: "Shift-Tab",
|
|
1376
|
+
run: (view) => this.handleTab(view, true)
|
|
1377
|
+
}
|
|
1378
|
+
];
|
|
1379
|
+
}
|
|
1380
|
+
// ============================================
|
|
1381
|
+
// Decorations
|
|
1382
|
+
// ============================================
|
|
1383
|
+
buildDecorations(ctx) {
|
|
1384
|
+
const { view: view$1, decorations } = ctx;
|
|
1385
|
+
const tree = language.syntaxTree(view$1.state);
|
|
1386
|
+
tree.iterate({
|
|
1387
|
+
enter: (node) => {
|
|
1388
|
+
if (node.name !== "Table") return;
|
|
1389
|
+
const { from, to } = node;
|
|
1390
|
+
const nodeLineStart = view$1.state.doc.lineAt(from);
|
|
1391
|
+
const nodeLineEnd = view$1.state.doc.lineAt(to);
|
|
1392
|
+
const cursorInRange = ctx.selectionOverlapsRange(nodeLineStart.from, nodeLineEnd.to);
|
|
1393
|
+
if (cursorInRange) {
|
|
1394
|
+
for (let i = nodeLineStart.number; i <= nodeLineEnd.number; i++) {
|
|
1395
|
+
const line = view$1.state.doc.line(i);
|
|
1396
|
+
decorations.push(tableMarkDecorations["table-line"].range(line.from));
|
|
1397
|
+
if (i === nodeLineStart.number) {
|
|
1398
|
+
decorations.push(tableMarkDecorations["table-line-start"].range(line.from));
|
|
1399
|
+
}
|
|
1400
|
+
if (i === nodeLineEnd.number) {
|
|
1401
|
+
decorations.push(tableMarkDecorations["table-line-end"].range(line.from));
|
|
1402
|
+
}
|
|
1403
|
+
if (i === nodeLineStart.number + 1) {
|
|
1404
|
+
decorations.push(tableMarkDecorations["table-delimiter"].range(line.from));
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
} else {
|
|
1408
|
+
const tableContent = view$1.state.sliceDoc(from, to);
|
|
1409
|
+
for (let i = nodeLineStart.number; i <= nodeLineEnd.number; i++) {
|
|
1410
|
+
const line = view$1.state.doc.line(i);
|
|
1411
|
+
decorations.push(tableMarkDecorations["table-rendered"].range(line.from));
|
|
1412
|
+
decorations.push(tableMarkDecorations["table-hidden"].range(line.from, line.to));
|
|
1413
|
+
}
|
|
1414
|
+
decorations.push(
|
|
1415
|
+
view.Decoration.widget({
|
|
1416
|
+
widget: new TableWidget(tableContent, from, to, this.draftlyConfig),
|
|
1417
|
+
side: 1,
|
|
1418
|
+
block: false
|
|
1419
|
+
}).range(to)
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
// ============================================
|
|
1426
|
+
// Keymap Handlers
|
|
1427
|
+
// ============================================
|
|
1428
|
+
/**
|
|
1429
|
+
* Insert a new 3×3 table at cursor position
|
|
1430
|
+
*/
|
|
1431
|
+
insertTable(view) {
|
|
1432
|
+
const { state } = view;
|
|
1433
|
+
const cursor = state.selection.main.head;
|
|
1434
|
+
const line = state.doc.lineAt(cursor);
|
|
1435
|
+
const insertPos = line.text.trim() ? line.to : line.from;
|
|
1436
|
+
const template = [
|
|
1437
|
+
"| Header 1 | Header 2 | Header 3 |",
|
|
1438
|
+
"| -------- | -------- | -------- |",
|
|
1439
|
+
"| | | |"
|
|
1440
|
+
].join("\n");
|
|
1441
|
+
const prefix = line.text.trim() ? "\n" : "";
|
|
1442
|
+
const suffix = "\n";
|
|
1443
|
+
view.dispatch({
|
|
1444
|
+
changes: {
|
|
1445
|
+
from: insertPos,
|
|
1446
|
+
insert: prefix + template + suffix
|
|
1447
|
+
},
|
|
1448
|
+
selection: {
|
|
1449
|
+
anchor: insertPos + prefix.length + 2
|
|
1450
|
+
// Position cursor in first header cell
|
|
1451
|
+
}
|
|
1452
|
+
});
|
|
1453
|
+
return true;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Add a new row below the current row (Mod-Enter)
|
|
1457
|
+
*/
|
|
1458
|
+
addRow(view) {
|
|
1459
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
1460
|
+
if (!tableInfo) return false;
|
|
1461
|
+
const { state } = view;
|
|
1462
|
+
const cursor = state.selection.main.head;
|
|
1463
|
+
const currentLine = state.doc.lineAt(cursor);
|
|
1464
|
+
const parsed = parseTableMarkdown(state.sliceDoc(tableInfo.from, tableInfo.to));
|
|
1465
|
+
if (!parsed) return false;
|
|
1466
|
+
const colCount = parsed.headers.length;
|
|
1467
|
+
const emptyRow = "| " + Array.from({ length: colCount }, () => " ").join(" | ") + " |";
|
|
1468
|
+
view.dispatch({
|
|
1469
|
+
changes: {
|
|
1470
|
+
from: currentLine.to,
|
|
1471
|
+
insert: "\n" + emptyRow
|
|
1472
|
+
},
|
|
1473
|
+
selection: {
|
|
1474
|
+
anchor: currentLine.to + 3
|
|
1475
|
+
// Position in first cell of new row
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
return true;
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Add a new column after the current column (Mod-Shift-Enter)
|
|
1482
|
+
*/
|
|
1483
|
+
addColumn(view) {
|
|
1484
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
1485
|
+
if (!tableInfo) return false;
|
|
1486
|
+
const { state } = view;
|
|
1487
|
+
const cursor = state.selection.main.head;
|
|
1488
|
+
const currentLine = state.doc.lineAt(cursor);
|
|
1489
|
+
const lineText = currentLine.text;
|
|
1490
|
+
const cursorInLine = cursor - currentLine.from;
|
|
1491
|
+
let colIndex = -1;
|
|
1492
|
+
for (let i = 0; i < cursorInLine; i++) {
|
|
1493
|
+
if (lineText[i] === "|") colIndex++;
|
|
1494
|
+
}
|
|
1495
|
+
colIndex = Math.max(0, colIndex);
|
|
1496
|
+
const tableText = state.sliceDoc(tableInfo.from, tableInfo.to);
|
|
1497
|
+
const lines = tableText.split("\n");
|
|
1498
|
+
const newLines = lines.map((line, lineIdx) => {
|
|
1499
|
+
const cells = this.splitLineToCells(line);
|
|
1500
|
+
const insertAfter = Math.min(colIndex, cells.length - 1);
|
|
1501
|
+
if (lineIdx === 1) {
|
|
1502
|
+
cells.splice(insertAfter + 1, 0, " -------- ");
|
|
1503
|
+
} else {
|
|
1504
|
+
cells.splice(insertAfter + 1, 0, " ");
|
|
1505
|
+
}
|
|
1506
|
+
return "|" + cells.join("|") + "|";
|
|
1507
|
+
});
|
|
1508
|
+
view.dispatch({
|
|
1509
|
+
changes: {
|
|
1510
|
+
from: tableInfo.from,
|
|
1511
|
+
to: tableInfo.to,
|
|
1512
|
+
insert: newLines.join("\n")
|
|
1513
|
+
}
|
|
1514
|
+
});
|
|
1515
|
+
return true;
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Handle Enter key inside a table.
|
|
1519
|
+
* - Last cell of last row: create a new row
|
|
1520
|
+
* - Empty last row: remove it and move cursor after table
|
|
1521
|
+
*/
|
|
1522
|
+
handleEnter(view) {
|
|
1523
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
1524
|
+
if (!tableInfo) return false;
|
|
1525
|
+
const { state } = view;
|
|
1526
|
+
const cursor = state.selection.main.head;
|
|
1527
|
+
const cursorLine = state.doc.lineAt(cursor);
|
|
1528
|
+
const tableEndLine = state.doc.lineAt(tableInfo.to);
|
|
1529
|
+
if (cursorLine.number !== tableEndLine.number) return false;
|
|
1530
|
+
const lineText = cursorLine.text;
|
|
1531
|
+
const cursorOffset = cursor - cursorLine.from;
|
|
1532
|
+
const pipes = [];
|
|
1533
|
+
for (let i = 0; i < lineText.length; i++) {
|
|
1534
|
+
if (lineText[i] === "|") pipes.push(i);
|
|
1535
|
+
}
|
|
1536
|
+
if (pipes.length < 2) return false;
|
|
1537
|
+
const lastCellStart = pipes[pipes.length - 2];
|
|
1538
|
+
if (cursorOffset < lastCellStart) return false;
|
|
1539
|
+
if (isRowEmpty(lineText)) {
|
|
1540
|
+
const removeFrom = cursorLine.from - 1;
|
|
1541
|
+
const removeTo = cursorLine.to;
|
|
1542
|
+
view.dispatch({
|
|
1543
|
+
changes: { from: Math.max(0, removeFrom), to: removeTo },
|
|
1544
|
+
selection: {
|
|
1545
|
+
anchor: Math.min(Math.max(0, removeFrom) + 1, view.state.doc.length)
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
return true;
|
|
1549
|
+
}
|
|
1550
|
+
const parsed = parseTableMarkdown(state.sliceDoc(tableInfo.from, tableInfo.to));
|
|
1551
|
+
if (!parsed) return false;
|
|
1552
|
+
const colCount = parsed.headers.length;
|
|
1553
|
+
const emptyRow = "| " + Array.from({ length: colCount }, () => " ").join(" | ") + " |";
|
|
1554
|
+
view.dispatch({
|
|
1555
|
+
changes: {
|
|
1556
|
+
from: cursorLine.to,
|
|
1557
|
+
insert: "\n" + emptyRow
|
|
1558
|
+
},
|
|
1559
|
+
selection: {
|
|
1560
|
+
anchor: cursorLine.to + 3
|
|
1561
|
+
// Position in first cell of new row
|
|
1562
|
+
}
|
|
1563
|
+
});
|
|
1564
|
+
return true;
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* Handle Tab key inside a table — move to next/previous cell
|
|
1568
|
+
*/
|
|
1569
|
+
handleTab(view, backwards) {
|
|
1570
|
+
const tableInfo = this.getTableAtCursor(view);
|
|
1571
|
+
if (!tableInfo) return false;
|
|
1572
|
+
const { state } = view;
|
|
1573
|
+
const cursor = state.selection.main.head;
|
|
1574
|
+
const tableText = state.sliceDoc(tableInfo.from, tableInfo.to);
|
|
1575
|
+
const lines = tableText.split("\n");
|
|
1576
|
+
const cellPositions = [];
|
|
1577
|
+
for (let li = 0; li < lines.length; li++) {
|
|
1578
|
+
if (li === 1) continue;
|
|
1579
|
+
const line = lines[li];
|
|
1580
|
+
const lineFrom = tableInfo.from + lines.slice(0, li).reduce((sum, l) => sum + l.length + 1, 0);
|
|
1581
|
+
const pipes = [];
|
|
1582
|
+
for (let i = 0; i < line.length; i++) {
|
|
1583
|
+
if (line[i] === "|") pipes.push(i);
|
|
1584
|
+
}
|
|
1585
|
+
for (let p = 0; p < pipes.length - 1; p++) {
|
|
1586
|
+
const cellStart = pipes[p] + 1;
|
|
1587
|
+
const cellEnd = pipes[p + 1];
|
|
1588
|
+
cellPositions.push({
|
|
1589
|
+
lineFrom,
|
|
1590
|
+
start: cellStart,
|
|
1591
|
+
end: cellEnd
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
let currentCellIdx = -1;
|
|
1596
|
+
for (let i = 0; i < cellPositions.length; i++) {
|
|
1597
|
+
const cell = cellPositions[i];
|
|
1598
|
+
const absStart = cell.lineFrom + cell.start;
|
|
1599
|
+
const absEnd = cell.lineFrom + cell.end;
|
|
1600
|
+
if (cursor >= absStart && cursor <= absEnd) {
|
|
1601
|
+
currentCellIdx = i;
|
|
1602
|
+
break;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
if (currentCellIdx === -1) return false;
|
|
1606
|
+
const nextIdx = backwards ? currentCellIdx - 1 : currentCellIdx + 1;
|
|
1607
|
+
if (nextIdx < 0 || nextIdx >= cellPositions.length) return false;
|
|
1608
|
+
const nextCell = cellPositions[nextIdx];
|
|
1609
|
+
const cellText = state.sliceDoc(nextCell.lineFrom + nextCell.start, nextCell.lineFrom + nextCell.end);
|
|
1610
|
+
const trimStart = cellText.length - cellText.trimStart().length;
|
|
1611
|
+
const trimEnd = cellText.length - cellText.trimEnd().length;
|
|
1612
|
+
const selectFrom = nextCell.lineFrom + nextCell.start + (trimStart > 0 ? 1 : 0);
|
|
1613
|
+
const selectTo = nextCell.lineFrom + nextCell.end - (trimEnd > 0 ? 1 : 0);
|
|
1614
|
+
view.dispatch({
|
|
1615
|
+
selection: {
|
|
1616
|
+
anchor: selectFrom,
|
|
1617
|
+
head: selectTo
|
|
1618
|
+
},
|
|
1619
|
+
scrollIntoView: true
|
|
1620
|
+
});
|
|
1621
|
+
return true;
|
|
1622
|
+
}
|
|
1623
|
+
// ============================================
|
|
1624
|
+
// Helpers
|
|
1625
|
+
// ============================================
|
|
1626
|
+
/**
|
|
1627
|
+
* Find the Table node at the cursor position
|
|
1628
|
+
*/
|
|
1629
|
+
getTableAtCursor(view) {
|
|
1630
|
+
const tree = language.syntaxTree(view.state);
|
|
1631
|
+
const cursor = view.state.selection.main.head;
|
|
1632
|
+
let result = null;
|
|
1633
|
+
tree.iterate({
|
|
1634
|
+
enter: (node) => {
|
|
1635
|
+
if (node.name === "Table" && cursor >= node.from && cursor <= node.to) {
|
|
1636
|
+
result = { from: node.from, to: node.to };
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
return result;
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Split a table line into cells (keeping the whitespace around content)
|
|
1644
|
+
*/
|
|
1645
|
+
splitLineToCells(line) {
|
|
1646
|
+
let trimmed = line.trim();
|
|
1647
|
+
if (trimmed.startsWith("|")) trimmed = trimmed.slice(1);
|
|
1648
|
+
if (trimmed.endsWith("|")) trimmed = trimmed.slice(0, -1);
|
|
1649
|
+
return trimmed.split("|");
|
|
1650
|
+
}
|
|
1651
|
+
// ============================================
|
|
1652
|
+
// Preview Rendering
|
|
1653
|
+
// ============================================
|
|
1654
|
+
async renderToHTML(node, _children, _ctx) {
|
|
1655
|
+
if (node.name === "Table") {
|
|
1656
|
+
const content = _ctx.sliceDoc(node.from, node.to);
|
|
1657
|
+
const parsed = parseTableMarkdown(content);
|
|
1658
|
+
if (!parsed) return null;
|
|
1659
|
+
return await renderTableToHtml(parsed, this.draftlyConfig);
|
|
1660
|
+
}
|
|
1661
|
+
if (node.name === "TableHeader" || node.name === "TableDelimiter" || node.name === "TableRow" || node.name === "TableCell") {
|
|
1662
|
+
return "";
|
|
1663
|
+
}
|
|
1664
|
+
return null;
|
|
1665
|
+
}
|
|
1666
|
+
};
|
|
1667
|
+
var theme6 = chunkTBVZEK2H_cjs.createTheme({
|
|
1668
|
+
default: {
|
|
1669
|
+
// Raw table lines — monospace when cursor is inside
|
|
1670
|
+
".cm-draftly-table-line": {
|
|
1671
|
+
"--radius": "0.375rem",
|
|
1672
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
1673
|
+
fontSize: "0.9rem",
|
|
1674
|
+
backgroundColor: "rgba(0, 0, 0, 0.02)",
|
|
1675
|
+
padding: "0 0.75rem !important",
|
|
1676
|
+
lineHeight: "1.6",
|
|
1677
|
+
borderLeft: "1px solid var(--color-border, #e2e8f0)",
|
|
1678
|
+
borderRight: "1px solid var(--color-border, #e2e8f0)"
|
|
1679
|
+
},
|
|
1680
|
+
".cm-draftly-table-line-start": {
|
|
1681
|
+
borderTopLeftRadius: "var(--radius)",
|
|
1682
|
+
borderTopRightRadius: "var(--radius)",
|
|
1683
|
+
borderTop: "1px solid var(--color-border, #e2e8f0)"
|
|
1684
|
+
},
|
|
1685
|
+
".cm-draftly-table-line-end": {
|
|
1686
|
+
borderBottomLeftRadius: "var(--radius)",
|
|
1687
|
+
borderBottomRightRadius: "var(--radius)",
|
|
1688
|
+
borderBottom: "1px solid var(--color-border, #e2e8f0)"
|
|
1689
|
+
},
|
|
1690
|
+
".cm-draftly-table-delimiter-line": {
|
|
1691
|
+
opacity: "0.5"
|
|
1692
|
+
},
|
|
1693
|
+
// Hidden table text (when cursor is not in range)
|
|
1694
|
+
".cm-draftly-table-hidden": {
|
|
1695
|
+
display: "none"
|
|
1696
|
+
},
|
|
1697
|
+
// Line decoration for rendered state — hide line breaks
|
|
1698
|
+
".cm-draftly-table-rendered": {
|
|
1699
|
+
padding: "0 !important"
|
|
1700
|
+
},
|
|
1701
|
+
".cm-draftly-table-rendered br": {
|
|
1702
|
+
display: "none"
|
|
1703
|
+
},
|
|
1704
|
+
// Rendered table widget container
|
|
1705
|
+
".cm-draftly-table-widget": {
|
|
1706
|
+
cursor: "pointer",
|
|
1707
|
+
overflow: "auto",
|
|
1708
|
+
padding: "0.5rem 0"
|
|
1709
|
+
},
|
|
1710
|
+
// Table element
|
|
1711
|
+
".cm-draftly-table": {
|
|
1712
|
+
width: "100%",
|
|
1713
|
+
borderCollapse: "separate",
|
|
1714
|
+
borderSpacing: "0",
|
|
1715
|
+
borderRadius: "0.5rem",
|
|
1716
|
+
overflow: "hidden",
|
|
1717
|
+
border: "1px solid var(--color-border, #e2e8f0)",
|
|
1718
|
+
fontFamily: "var(--font-sans, sans-serif)",
|
|
1719
|
+
fontSize: "0.9375rem",
|
|
1720
|
+
lineHeight: "1.5"
|
|
1721
|
+
},
|
|
1722
|
+
// Table header
|
|
1723
|
+
".cm-draftly-table thead th": {
|
|
1724
|
+
padding: "0rem 0.875rem",
|
|
1725
|
+
fontWeight: "600",
|
|
1726
|
+
borderBottom: "2px solid var(--color-border, #e2e8f0)",
|
|
1727
|
+
backgroundColor: "rgba(0, 0, 0, 0.03)"
|
|
1728
|
+
},
|
|
1729
|
+
// Table cells
|
|
1730
|
+
".cm-draftly-table td": {
|
|
1731
|
+
padding: "0rem 0.875rem",
|
|
1732
|
+
borderBottom: "1px solid var(--color-border, #e2e8f0)",
|
|
1733
|
+
borderRight: "1px solid var(--color-border, #e2e8f0)"
|
|
1734
|
+
},
|
|
1735
|
+
// Remove right border on last cell
|
|
1736
|
+
".cm-draftly-table td:last-child, .cm-draftly-table th:last-child": {
|
|
1737
|
+
borderRight: "none"
|
|
1738
|
+
},
|
|
1739
|
+
// Remove bottom border on last row
|
|
1740
|
+
".cm-draftly-table tbody tr:last-child td": {
|
|
1741
|
+
borderBottom: "none"
|
|
1742
|
+
},
|
|
1743
|
+
// Alternate row colors
|
|
1744
|
+
".cm-draftly-table tbody tr:nth-child(even)": {
|
|
1745
|
+
backgroundColor: "rgba(0, 0, 0, 0.02)"
|
|
1746
|
+
},
|
|
1747
|
+
// Header cells right border
|
|
1748
|
+
".cm-draftly-table thead th:not(:last-child)": {
|
|
1749
|
+
borderRight: "1px solid var(--color-border, #e2e8f0)"
|
|
1750
|
+
},
|
|
1751
|
+
// Hover effect on rows
|
|
1752
|
+
".cm-draftly-table tbody tr:hover": {
|
|
1753
|
+
backgroundColor: "rgba(0, 0, 0, 0.04)"
|
|
1754
|
+
},
|
|
1755
|
+
// Inline code in table cells
|
|
1756
|
+
".cm-draftly-table-inline-code": {
|
|
1757
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
1758
|
+
fontSize: "0.85em",
|
|
1759
|
+
padding: "0.1em 0.35em",
|
|
1760
|
+
borderRadius: "0.25rem",
|
|
1761
|
+
backgroundColor: "rgba(0, 0, 0, 0.06)"
|
|
1762
|
+
},
|
|
1763
|
+
// Links in table cells
|
|
1764
|
+
".cm-draftly-table-link": {
|
|
1765
|
+
color: "var(--color-link, #0969da)",
|
|
1766
|
+
textDecoration: "none"
|
|
1767
|
+
},
|
|
1768
|
+
".cm-draftly-table-link:hover": {
|
|
1769
|
+
textDecoration: "underline"
|
|
1770
|
+
},
|
|
1771
|
+
// Math in table cells
|
|
1772
|
+
".cm-draftly-table-math": {
|
|
1773
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
1774
|
+
fontSize: "0.9em",
|
|
1775
|
+
color: "#6a737d"
|
|
1776
|
+
}
|
|
1777
|
+
},
|
|
1778
|
+
dark: {
|
|
1779
|
+
".cm-draftly-table-line": {
|
|
1780
|
+
backgroundColor: "rgba(255, 255, 255, 0.03)"
|
|
1781
|
+
},
|
|
1782
|
+
".cm-draftly-table thead th": {
|
|
1783
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
1784
|
+
},
|
|
1785
|
+
".cm-draftly-table tbody tr:nth-child(even)": {
|
|
1786
|
+
backgroundColor: "rgba(255, 255, 255, 0.02)"
|
|
1787
|
+
},
|
|
1788
|
+
".cm-draftly-table tbody tr:hover": {
|
|
1789
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
1790
|
+
},
|
|
1791
|
+
".cm-draftly-table-inline-code": {
|
|
1792
|
+
backgroundColor: "rgba(255, 255, 255, 0.08)"
|
|
1793
|
+
},
|
|
1794
|
+
".cm-draftly-table-link": {
|
|
1795
|
+
color: "var(--color-link, #58a6ff)"
|
|
1796
|
+
},
|
|
1797
|
+
".cm-draftly-table-math": {
|
|
1798
|
+
color: "#8b949e"
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
});
|
|
1122
1802
|
var htmlMarkDecorations = {
|
|
1123
1803
|
"html-tag": view.Decoration.mark({ class: "cm-draftly-html-tag" }),
|
|
1124
1804
|
"html-comment": view.Decoration.mark({ class: "cm-draftly-html-comment" })
|
|
@@ -1174,7 +1854,7 @@ function parseHTMLTag(content) {
|
|
|
1174
1854
|
)
|
|
1175
1855
|
};
|
|
1176
1856
|
}
|
|
1177
|
-
var HTMLPlugin = class extends
|
|
1857
|
+
var HTMLPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
1178
1858
|
name = "html";
|
|
1179
1859
|
version = "1.0.0";
|
|
1180
1860
|
decorationPriority = 30;
|
|
@@ -1185,7 +1865,7 @@ var HTMLPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1185
1865
|
* Plugin theme
|
|
1186
1866
|
*/
|
|
1187
1867
|
get theme() {
|
|
1188
|
-
return
|
|
1868
|
+
return theme7;
|
|
1189
1869
|
}
|
|
1190
1870
|
buildDecorations(ctx) {
|
|
1191
1871
|
const { view: view$1, decorations } = ctx;
|
|
@@ -1325,7 +2005,7 @@ var HTMLPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1325
2005
|
}
|
|
1326
2006
|
}
|
|
1327
2007
|
};
|
|
1328
|
-
var
|
|
2008
|
+
var theme7 = chunkTBVZEK2H_cjs.createTheme({
|
|
1329
2009
|
default: {
|
|
1330
2010
|
".cm-draftly-html-tag": {
|
|
1331
2011
|
color: "#6a737d",
|
|
@@ -1443,7 +2123,7 @@ var ImageWidget = class extends view.WidgetType {
|
|
|
1443
2123
|
return event.type !== "click";
|
|
1444
2124
|
}
|
|
1445
2125
|
};
|
|
1446
|
-
var ImagePlugin = class extends
|
|
2126
|
+
var ImagePlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
1447
2127
|
name = "image";
|
|
1448
2128
|
version = "1.0.0";
|
|
1449
2129
|
decorationPriority = 25;
|
|
@@ -1455,7 +2135,7 @@ var ImagePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1455
2135
|
* Plugin theme
|
|
1456
2136
|
*/
|
|
1457
2137
|
get theme() {
|
|
1458
|
-
return
|
|
2138
|
+
return theme8;
|
|
1459
2139
|
}
|
|
1460
2140
|
/**
|
|
1461
2141
|
* Keyboard shortcuts for image formatting
|
|
@@ -1610,7 +2290,7 @@ var ImagePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1610
2290
|
return html;
|
|
1611
2291
|
}
|
|
1612
2292
|
};
|
|
1613
|
-
var
|
|
2293
|
+
var theme8 = chunkTBVZEK2H_cjs.createTheme({
|
|
1614
2294
|
default: {
|
|
1615
2295
|
".cm-draftly-image-block br": {
|
|
1616
2296
|
display: "none"
|
|
@@ -1847,7 +2527,7 @@ var mathBlockParser = {
|
|
|
1847
2527
|
return true;
|
|
1848
2528
|
}
|
|
1849
2529
|
};
|
|
1850
|
-
var MathPlugin = class extends
|
|
2530
|
+
var MathPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
1851
2531
|
name = "math";
|
|
1852
2532
|
version = "1.0.0";
|
|
1853
2533
|
decorationPriority = 25;
|
|
@@ -1859,7 +2539,16 @@ var MathPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1859
2539
|
* Plugin theme
|
|
1860
2540
|
*/
|
|
1861
2541
|
get theme() {
|
|
1862
|
-
return
|
|
2542
|
+
return theme9;
|
|
2543
|
+
}
|
|
2544
|
+
/**
|
|
2545
|
+
* Intercepts dollar typing to wrap selected text as inline math.
|
|
2546
|
+
*
|
|
2547
|
+
* If user types '$' while text is selected, wraps each selected range
|
|
2548
|
+
* with single dollars (selected -> $selected$).
|
|
2549
|
+
*/
|
|
2550
|
+
getExtensions() {
|
|
2551
|
+
return [chunk3T55CBNZ_cjs.createWrapSelectionInputHandler({ "$": "$" })];
|
|
1863
2552
|
}
|
|
1864
2553
|
/**
|
|
1865
2554
|
* Return markdown parser extensions for math syntax
|
|
@@ -1967,7 +2656,7 @@ var MathPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
1967
2656
|
return null;
|
|
1968
2657
|
}
|
|
1969
2658
|
};
|
|
1970
|
-
var
|
|
2659
|
+
var theme9 = chunkTBVZEK2H_cjs.createTheme({
|
|
1971
2660
|
default: {
|
|
1972
2661
|
".cm-draftly-math-block": {
|
|
1973
2662
|
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
@@ -2154,7 +2843,7 @@ var mermaidBlockParser = {
|
|
|
2154
2843
|
return true;
|
|
2155
2844
|
}
|
|
2156
2845
|
};
|
|
2157
|
-
var MermaidPlugin = class extends
|
|
2846
|
+
var MermaidPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
2158
2847
|
name = "mermaid";
|
|
2159
2848
|
version = "1.0.0";
|
|
2160
2849
|
decorationPriority = 25;
|
|
@@ -2166,7 +2855,7 @@ var MermaidPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2166
2855
|
* Plugin theme
|
|
2167
2856
|
*/
|
|
2168
2857
|
get theme() {
|
|
2169
|
-
return
|
|
2858
|
+
return theme10;
|
|
2170
2859
|
}
|
|
2171
2860
|
/**
|
|
2172
2861
|
* Return markdown parser extensions for mermaid syntax
|
|
@@ -2274,7 +2963,7 @@ var MermaidPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2274
2963
|
return null;
|
|
2275
2964
|
}
|
|
2276
2965
|
};
|
|
2277
|
-
var
|
|
2966
|
+
var theme10 = chunkTBVZEK2H_cjs.createTheme({
|
|
2278
2967
|
default: {
|
|
2279
2968
|
// Raw mermaid block lines (monospace)
|
|
2280
2969
|
".cm-draftly-mermaid-block:not(.cm-draftly-mermaid-block-rendered)": {
|
|
@@ -2378,22 +3067,395 @@ var theme9 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
2378
3067
|
}
|
|
2379
3068
|
}
|
|
2380
3069
|
});
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
var
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
3070
|
+
|
|
3071
|
+
// src/plugins/code-plugin.theme.ts
|
|
3072
|
+
var codePluginTheme = chunkTBVZEK2H_cjs.createTheme({
|
|
3073
|
+
default: {
|
|
3074
|
+
// Inline code
|
|
3075
|
+
".cm-draftly-code-inline": {
|
|
3076
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3077
|
+
fontSize: "0.9rem",
|
|
3078
|
+
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
|
3079
|
+
padding: "0.1rem 0.25rem",
|
|
3080
|
+
border: "1px solid var(--color-border)",
|
|
3081
|
+
borderRadius: "3px"
|
|
3082
|
+
},
|
|
3083
|
+
// Fenced code block lines
|
|
3084
|
+
".cm-draftly-code-block-line": {
|
|
3085
|
+
"--radius": "0.375rem",
|
|
3086
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3087
|
+
fontSize: "0.9rem",
|
|
3088
|
+
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
3089
|
+
padding: "0 1rem !important",
|
|
3090
|
+
lineHeight: "1.5",
|
|
3091
|
+
borderLeft: "1px solid var(--color-border)",
|
|
3092
|
+
borderRight: "1px solid var(--color-border)"
|
|
3093
|
+
},
|
|
3094
|
+
// First line of code block
|
|
3095
|
+
".cm-draftly-code-block-line-start": {
|
|
3096
|
+
borderTopLeftRadius: "var(--radius)",
|
|
3097
|
+
borderTopRightRadius: "var(--radius)",
|
|
3098
|
+
position: "relative",
|
|
3099
|
+
overflow: "hidden",
|
|
3100
|
+
borderTop: "1px solid var(--color-border)",
|
|
3101
|
+
paddingBottom: "0.5rem !important"
|
|
3102
|
+
},
|
|
3103
|
+
// Remove top radius when header is present
|
|
3104
|
+
".cm-draftly-code-block-has-header": {
|
|
3105
|
+
padding: "0 !important",
|
|
3106
|
+
paddingBottom: "0.5rem !important"
|
|
3107
|
+
},
|
|
3108
|
+
// Code block header widget
|
|
3109
|
+
".cm-draftly-code-header": {
|
|
3110
|
+
display: "flex",
|
|
3111
|
+
justifyContent: "space-between",
|
|
3112
|
+
alignItems: "center",
|
|
3113
|
+
padding: "0.25rem 1rem",
|
|
3114
|
+
backgroundColor: "rgba(0, 0, 0, 0.06)",
|
|
3115
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3116
|
+
fontSize: "0.85rem",
|
|
3117
|
+
".cm-draftly-code-header-left": {
|
|
3118
|
+
display: "flex",
|
|
3119
|
+
alignItems: "center",
|
|
3120
|
+
gap: "0.5rem",
|
|
3121
|
+
".cm-draftly-code-header-title": {
|
|
3122
|
+
color: "var(--color-text, inherit)",
|
|
3123
|
+
fontWeight: "500"
|
|
3124
|
+
},
|
|
3125
|
+
".cm-draftly-code-header-lang": {
|
|
3126
|
+
color: "#6a737d",
|
|
3127
|
+
opacity: "0.8"
|
|
3128
|
+
}
|
|
3129
|
+
},
|
|
3130
|
+
".cm-draftly-code-header-right": {
|
|
3131
|
+
display: "flex",
|
|
3132
|
+
alignItems: "center",
|
|
3133
|
+
gap: "0.5rem",
|
|
3134
|
+
".cm-draftly-code-copy-btn": {
|
|
3135
|
+
display: "flex",
|
|
3136
|
+
alignItems: "center",
|
|
3137
|
+
justifyContent: "center",
|
|
3138
|
+
padding: "0.25rem",
|
|
3139
|
+
backgroundColor: "transparent",
|
|
3140
|
+
border: "none",
|
|
3141
|
+
borderRadius: "4px",
|
|
3142
|
+
cursor: "pointer",
|
|
3143
|
+
color: "#6a737d",
|
|
3144
|
+
transition: "color 0.2s, background-color 0.2s",
|
|
3145
|
+
"&:hover": {
|
|
3146
|
+
backgroundColor: "rgba(0, 0, 0, 0.1)",
|
|
3147
|
+
color: "var(--color-text, inherit)"
|
|
3148
|
+
},
|
|
3149
|
+
"&.copied": {
|
|
3150
|
+
color: "#22c55e"
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
},
|
|
3155
|
+
// Caption (below code block)
|
|
3156
|
+
".cm-draftly-code-block-has-caption": {
|
|
3157
|
+
padding: "0 !important",
|
|
3158
|
+
paddingTop: "0.5rem !important"
|
|
3159
|
+
},
|
|
3160
|
+
".cm-draftly-code-caption": {
|
|
3161
|
+
textAlign: "center",
|
|
3162
|
+
fontSize: "0.85rem",
|
|
3163
|
+
color: "#6a737d",
|
|
3164
|
+
fontStyle: "italic",
|
|
3165
|
+
padding: "0.25rem 1rem",
|
|
3166
|
+
backgroundColor: "rgba(0, 0, 0, 0.06)"
|
|
3167
|
+
},
|
|
3168
|
+
// Last line of code block
|
|
3169
|
+
".cm-draftly-code-block-line-end": {
|
|
3170
|
+
borderBottomLeftRadius: "var(--radius)",
|
|
3171
|
+
borderBottomRightRadius: "var(--radius)",
|
|
3172
|
+
borderBottom: "1px solid var(--color-border)",
|
|
3173
|
+
paddingTop: "0.5rem !important",
|
|
3174
|
+
"& br": {
|
|
3175
|
+
display: "none"
|
|
3176
|
+
}
|
|
3177
|
+
},
|
|
3178
|
+
// Fence markers (```)
|
|
3179
|
+
".cm-draftly-code-fence": {
|
|
3180
|
+
color: "#6a737d",
|
|
3181
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)"
|
|
3182
|
+
},
|
|
3183
|
+
// Line numbers
|
|
3184
|
+
".cm-draftly-code-line-numbered": {
|
|
3185
|
+
paddingLeft: "calc(var(--line-num-width, 2ch) + 1rem) !important",
|
|
3186
|
+
position: "relative",
|
|
3187
|
+
"&::before": {
|
|
3188
|
+
content: "attr(data-line-num)",
|
|
3189
|
+
position: "absolute",
|
|
3190
|
+
left: "0.5rem",
|
|
3191
|
+
top: "0.2rem",
|
|
3192
|
+
width: "var(--line-num-width, 2ch)",
|
|
3193
|
+
textAlign: "right",
|
|
3194
|
+
color: "#6a737d",
|
|
3195
|
+
opacity: "0.6",
|
|
3196
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3197
|
+
fontSize: "0.85rem",
|
|
3198
|
+
userSelect: "none"
|
|
3199
|
+
}
|
|
3200
|
+
},
|
|
3201
|
+
".cm-draftly-code-line-numbered-diff": {
|
|
3202
|
+
paddingLeft: "calc(var(--line-num-old-width, 2ch) + var(--line-num-new-width, 2ch) + 2.75rem) !important",
|
|
3203
|
+
position: "relative",
|
|
3204
|
+
"&::before": {
|
|
3205
|
+
content: "attr(data-line-num-old)",
|
|
3206
|
+
position: "absolute",
|
|
3207
|
+
left: "0.5rem",
|
|
3208
|
+
top: "0.2rem",
|
|
3209
|
+
width: "var(--line-num-old-width, 2ch)",
|
|
3210
|
+
textAlign: "right",
|
|
3211
|
+
color: "#6a737d",
|
|
3212
|
+
opacity: "0.6",
|
|
3213
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3214
|
+
fontSize: "0.85rem",
|
|
3215
|
+
userSelect: "none"
|
|
3216
|
+
},
|
|
3217
|
+
"&::after": {
|
|
3218
|
+
content: 'attr(data-line-num-new) " " attr(data-diff-marker)',
|
|
3219
|
+
position: "absolute",
|
|
3220
|
+
left: "calc(0.5rem + var(--line-num-old-width, 2ch) + 0.75rem)",
|
|
3221
|
+
top: "0.2rem",
|
|
3222
|
+
width: "calc(var(--line-num-new-width, 2ch) + 2ch)",
|
|
3223
|
+
textAlign: "right",
|
|
3224
|
+
color: "#6a737d",
|
|
3225
|
+
opacity: "0.6",
|
|
3226
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3227
|
+
fontSize: "0.85rem",
|
|
3228
|
+
userSelect: "none"
|
|
3229
|
+
},
|
|
3230
|
+
"&.cm-draftly-code-line-diff-gutter": {
|
|
3231
|
+
paddingLeft: "calc(var(--line-num-width, 2ch) + 2rem) !important",
|
|
3232
|
+
"&::after": {
|
|
3233
|
+
content: "attr(data-diff-marker)",
|
|
3234
|
+
position: "absolute",
|
|
3235
|
+
left: "calc(0.5rem + var(--line-num-width, 2ch) + 0.35rem)",
|
|
3236
|
+
top: "0.1rem",
|
|
3237
|
+
width: "1ch",
|
|
3238
|
+
textAlign: "right",
|
|
3239
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3240
|
+
fontSize: "0.85rem",
|
|
3241
|
+
fontWeight: "700",
|
|
3242
|
+
userSelect: "none"
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
},
|
|
3246
|
+
// Preview: code lines (need block display for full-width highlights)
|
|
3247
|
+
".cm-draftly-code-line": {
|
|
3248
|
+
display: "block",
|
|
3249
|
+
position: "relative",
|
|
3250
|
+
paddingLeft: "1rem",
|
|
3251
|
+
paddingRight: "1rem",
|
|
3252
|
+
lineHeight: "1.5",
|
|
3253
|
+
borderLeft: "3px solid transparent"
|
|
3254
|
+
},
|
|
3255
|
+
// Line highlight
|
|
3256
|
+
".cm-draftly-code-line-highlight": {
|
|
3257
|
+
backgroundColor: "rgba(255, 220, 100, 0.2) !important",
|
|
3258
|
+
borderLeft: "3px solid #f0b429 !important"
|
|
3259
|
+
},
|
|
3260
|
+
".cm-draftly-code-line-diff-add": {
|
|
3261
|
+
color: "inherit",
|
|
3262
|
+
backgroundColor: "rgba(34, 197, 94, 0.12) !important",
|
|
3263
|
+
borderLeft: "3px solid #22c55e !important",
|
|
3264
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
3265
|
+
color: "#16a34a"
|
|
3266
|
+
}
|
|
3267
|
+
},
|
|
3268
|
+
".cm-draftly-code-line-diff-del": {
|
|
3269
|
+
color: "inherit",
|
|
3270
|
+
backgroundColor: "rgba(239, 68, 68, 0.12) !important",
|
|
3271
|
+
borderLeft: "3px solid #ef4444 !important",
|
|
3272
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
3273
|
+
color: "#dc2626"
|
|
3274
|
+
}
|
|
3275
|
+
},
|
|
3276
|
+
".cm-draftly-code-diff-sign-add": {
|
|
3277
|
+
color: "#16a34a",
|
|
3278
|
+
fontWeight: "700"
|
|
3279
|
+
},
|
|
3280
|
+
".cm-draftly-code-diff-sign-del": {
|
|
3281
|
+
color: "#dc2626",
|
|
3282
|
+
fontWeight: "700"
|
|
3283
|
+
},
|
|
3284
|
+
".cm-draftly-code-diff-mod-add": {
|
|
3285
|
+
color: "inherit",
|
|
3286
|
+
backgroundColor: "rgba(34, 197, 94, 0.25)",
|
|
3287
|
+
borderRadius: "2px",
|
|
3288
|
+
padding: "0.1rem 0"
|
|
3289
|
+
},
|
|
3290
|
+
".cm-draftly-code-diff-mod-del": {
|
|
3291
|
+
color: "inherit",
|
|
3292
|
+
backgroundColor: "rgba(239, 68, 68, 0.25)",
|
|
3293
|
+
borderRadius: "2px",
|
|
3294
|
+
padding: "0.1rem 0"
|
|
3295
|
+
},
|
|
3296
|
+
// Text highlight
|
|
3297
|
+
".cm-draftly-code-text-highlight": {
|
|
3298
|
+
color: "inherit",
|
|
3299
|
+
backgroundColor: "rgba(255, 220, 100, 0.4)",
|
|
3300
|
+
borderRadius: "2px",
|
|
3301
|
+
padding: "0.1rem 0"
|
|
3302
|
+
},
|
|
3303
|
+
// Preview: container wrapper
|
|
3304
|
+
".cm-draftly-code-container": {
|
|
3305
|
+
margin: "1rem 0",
|
|
3306
|
+
borderRadius: "var(--radius)",
|
|
3307
|
+
overflow: "hidden",
|
|
3308
|
+
border: "1px solid var(--color-border)",
|
|
3309
|
+
".cm-draftly-code-header": {
|
|
3310
|
+
borderRadius: "0",
|
|
3311
|
+
border: "none",
|
|
3312
|
+
borderBottom: "1px solid var(--color-border)"
|
|
3313
|
+
},
|
|
3314
|
+
".cm-draftly-code-block": {
|
|
3315
|
+
margin: "0",
|
|
3316
|
+
borderRadius: "0",
|
|
3317
|
+
border: "none",
|
|
3318
|
+
whiteSpace: "pre-wrap"
|
|
3319
|
+
},
|
|
3320
|
+
".cm-draftly-code-caption": {
|
|
3321
|
+
borderTop: "1px solid var(--color-border)"
|
|
3322
|
+
}
|
|
3323
|
+
},
|
|
3324
|
+
// Preview: standalone code block (not in container)
|
|
3325
|
+
".cm-draftly-code-block": {
|
|
3326
|
+
fontFamily: "var(--font-jetbrains-mono, monospace)",
|
|
3327
|
+
fontSize: "0.9rem",
|
|
3328
|
+
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
3329
|
+
padding: "1rem",
|
|
3330
|
+
overflow: "auto",
|
|
3331
|
+
position: "relative",
|
|
3332
|
+
borderRadius: "var(--radius)",
|
|
3333
|
+
border: "1px solid var(--color-border)",
|
|
3334
|
+
"&.cm-draftly-code-block-has-header": {
|
|
3335
|
+
borderTopLeftRadius: "0",
|
|
3336
|
+
borderTopRightRadius: "0",
|
|
3337
|
+
borderTop: "none",
|
|
3338
|
+
margin: "0",
|
|
3339
|
+
paddingTop: "0.5rem !important"
|
|
3340
|
+
},
|
|
3341
|
+
"&.cm-draftly-code-block-has-caption": {
|
|
3342
|
+
borderBottomLeftRadius: "0",
|
|
3343
|
+
borderBottomRightRadius: "0",
|
|
3344
|
+
borderBottom: "none",
|
|
3345
|
+
paddingBottom: "0.5rem !important"
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
},
|
|
3349
|
+
dark: {
|
|
3350
|
+
".cm-draftly-code-inline": {
|
|
3351
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
|
3352
|
+
},
|
|
3353
|
+
".cm-draftly-code-block-line": {
|
|
3354
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
3355
|
+
},
|
|
3356
|
+
".cm-draftly-code-fence": {
|
|
3357
|
+
color: "#8b949e"
|
|
3358
|
+
},
|
|
3359
|
+
".cm-draftly-code-block": {
|
|
3360
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
3361
|
+
},
|
|
3362
|
+
".cm-draftly-code-header": {
|
|
3363
|
+
backgroundColor: "rgba(255, 255, 255, 0.08)",
|
|
3364
|
+
".cm-draftly-code-header-lang": {
|
|
3365
|
+
color: "#8b949e"
|
|
3366
|
+
},
|
|
3367
|
+
".cm-draftly-code-copy-btn": {
|
|
3368
|
+
color: "#8b949e",
|
|
3369
|
+
"&:hover": {
|
|
3370
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)"
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
},
|
|
3374
|
+
".cm-draftly-code-caption": {
|
|
3375
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)"
|
|
3376
|
+
},
|
|
3377
|
+
".cm-draftly-code-line-numbered": {
|
|
3378
|
+
"&::before": {
|
|
3379
|
+
color: "#8b949e"
|
|
3380
|
+
}
|
|
3381
|
+
},
|
|
3382
|
+
".cm-draftly-code-line-numbered-diff": {
|
|
3383
|
+
"&::before": {
|
|
3384
|
+
color: "#8b949e"
|
|
3385
|
+
},
|
|
3386
|
+
"&::after": {
|
|
3387
|
+
color: "#8b949e"
|
|
3388
|
+
}
|
|
3389
|
+
},
|
|
3390
|
+
".cm-draftly-code-line-diff-gutter": {
|
|
3391
|
+
"&::after": {
|
|
3392
|
+
color: "#8b949e"
|
|
3393
|
+
}
|
|
3394
|
+
},
|
|
3395
|
+
".cm-draftly-code-line-highlight": {
|
|
3396
|
+
backgroundColor: "rgba(255, 220, 100, 0.15) !important",
|
|
3397
|
+
borderLeft: "3px solid #d9a520 !important"
|
|
3398
|
+
},
|
|
3399
|
+
".cm-draftly-code-line-diff-add": {
|
|
3400
|
+
backgroundColor: "rgba(34, 197, 94, 0.15) !important",
|
|
3401
|
+
borderLeft: "3px solid #22c55e !important",
|
|
3402
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
3403
|
+
color: "#4ade80"
|
|
3404
|
+
}
|
|
3405
|
+
},
|
|
3406
|
+
".cm-draftly-code-line-diff-del": {
|
|
3407
|
+
backgroundColor: "rgba(239, 68, 68, 0.15) !important",
|
|
3408
|
+
borderLeft: "3px solid #ef4444 !important",
|
|
3409
|
+
"&.cm-draftly-code-line-diff-gutter::after": {
|
|
3410
|
+
color: "#f87171"
|
|
3411
|
+
}
|
|
3412
|
+
},
|
|
3413
|
+
".cm-draftly-code-diff-sign-add": {
|
|
3414
|
+
color: "#4ade80"
|
|
3415
|
+
},
|
|
3416
|
+
".cm-draftly-code-diff-sign-del": {
|
|
3417
|
+
color: "#f87171"
|
|
3418
|
+
},
|
|
3419
|
+
".cm-draftly-code-diff-mod-add": {
|
|
3420
|
+
backgroundColor: "rgba(34, 197, 94, 0.3)"
|
|
3421
|
+
},
|
|
3422
|
+
".cm-draftly-code-diff-mod-del": {
|
|
3423
|
+
backgroundColor: "rgba(239, 68, 68, 0.3)"
|
|
3424
|
+
},
|
|
3425
|
+
".cm-draftly-code-text-highlight": {
|
|
3426
|
+
backgroundColor: "rgba(255, 220, 100, 0.3)"
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
});
|
|
3430
|
+
|
|
3431
|
+
// src/plugins/code-plugin.ts
|
|
3432
|
+
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>`;
|
|
3433
|
+
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>`;
|
|
3434
|
+
var COPY_RESET_DELAY = 2e3;
|
|
3435
|
+
var CODE_FENCE = "```";
|
|
3436
|
+
var QUOTED_INFO_PATTERN = /(\w+)="([^"]*)"/g;
|
|
3437
|
+
var TEXT_HIGHLIGHT_PATTERN = /\/([^/]+)\/(?:(\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*))?/g;
|
|
3438
|
+
var codeMarkDecorations = {
|
|
3439
|
+
// Inline code
|
|
3440
|
+
"inline-code": view.Decoration.mark({ class: "cm-draftly-code-inline" }),
|
|
3441
|
+
"inline-mark": view.Decoration.replace({}),
|
|
3442
|
+
// Fenced code block
|
|
3443
|
+
"code-block-line": view.Decoration.line({ class: "cm-draftly-code-block-line" }),
|
|
3444
|
+
"code-block-line-start": view.Decoration.line({ class: "cm-draftly-code-block-line-start" }),
|
|
3445
|
+
"code-block-line-end": view.Decoration.line({ class: "cm-draftly-code-block-line-end" }),
|
|
3446
|
+
"code-fence": view.Decoration.mark({ class: "cm-draftly-code-fence" }),
|
|
3447
|
+
"code-hidden": view.Decoration.replace({}),
|
|
2394
3448
|
// Highlights
|
|
2395
3449
|
"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" })
|
|
3450
|
+
"code-text-highlight": view.Decoration.mark({ class: "cm-draftly-code-text-highlight" }),
|
|
3451
|
+
// Diff preview
|
|
3452
|
+
"diff-line-add": view.Decoration.line({ class: "cm-draftly-code-line-diff-add" }),
|
|
3453
|
+
"diff-line-del": view.Decoration.line({ class: "cm-draftly-code-line-diff-del" }),
|
|
3454
|
+
"diff-sign-add": view.Decoration.mark({ class: "cm-draftly-code-diff-sign-add" }),
|
|
3455
|
+
"diff-sign-del": view.Decoration.mark({ class: "cm-draftly-code-diff-sign-del" }),
|
|
3456
|
+
"diff-mod-add": view.Decoration.mark({ class: "cm-draftly-code-diff-mod-add" }),
|
|
3457
|
+
"diff-mod-del": view.Decoration.mark({ class: "cm-draftly-code-diff-mod-del" }),
|
|
3458
|
+
"diff-escape-hidden": view.Decoration.replace({})
|
|
2397
3459
|
};
|
|
2398
3460
|
var CodeBlockHeaderWidget = class extends view.WidgetType {
|
|
2399
3461
|
constructor(props, codeContent) {
|
|
@@ -2474,16 +3536,17 @@ var CodeBlockCaptionWidget = class extends view.WidgetType {
|
|
|
2474
3536
|
return false;
|
|
2475
3537
|
}
|
|
2476
3538
|
};
|
|
2477
|
-
var CodePlugin = class extends
|
|
3539
|
+
var CodePlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
2478
3540
|
name = "code";
|
|
2479
3541
|
version = "1.0.0";
|
|
2480
3542
|
decorationPriority = 25;
|
|
2481
3543
|
requiredNodes = ["InlineCode", "FencedCode", "CodeMark", "CodeInfo", "CodeText"];
|
|
3544
|
+
parserCache = /* @__PURE__ */ new Map();
|
|
2482
3545
|
/**
|
|
2483
3546
|
* Plugin theme
|
|
2484
3547
|
*/
|
|
2485
3548
|
get theme() {
|
|
2486
|
-
return
|
|
3549
|
+
return codePluginTheme;
|
|
2487
3550
|
}
|
|
2488
3551
|
/**
|
|
2489
3552
|
* Keyboard shortcuts for code formatting
|
|
@@ -2492,7 +3555,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2492
3555
|
return [
|
|
2493
3556
|
{
|
|
2494
3557
|
key: "Mod-e",
|
|
2495
|
-
run:
|
|
3558
|
+
run: chunkTBVZEK2H_cjs.toggleMarkdownStyle("`"),
|
|
2496
3559
|
preventDefault: true
|
|
2497
3560
|
},
|
|
2498
3561
|
{
|
|
@@ -2502,6 +3565,15 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2502
3565
|
}
|
|
2503
3566
|
];
|
|
2504
3567
|
}
|
|
3568
|
+
/**
|
|
3569
|
+
* Intercepts backtick typing to wrap selected text as inline code.
|
|
3570
|
+
*
|
|
3571
|
+
* If user types '`' while text is selected, wraps each selected range
|
|
3572
|
+
* with backticks (selected -> `selected`).
|
|
3573
|
+
*/
|
|
3574
|
+
getExtensions() {
|
|
3575
|
+
return [chunk3T55CBNZ_cjs.createWrapSelectionInputHandler({ "`": "`" })];
|
|
3576
|
+
}
|
|
2505
3577
|
/**
|
|
2506
3578
|
* Toggle code block on current line or selected lines
|
|
2507
3579
|
*/
|
|
@@ -2514,7 +3586,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2514
3586
|
const nextLineNum = endLine.number < state.doc.lines ? endLine.number + 1 : endLine.number;
|
|
2515
3587
|
const prevLine = state.doc.line(prevLineNum);
|
|
2516
3588
|
const nextLine = state.doc.line(nextLineNum);
|
|
2517
|
-
const isWrapped = prevLine.text.trim().startsWith(
|
|
3589
|
+
const isWrapped = prevLine.text.trim().startsWith(CODE_FENCE) && nextLine.text.trim() === CODE_FENCE && prevLineNum !== startLine.number && nextLineNum !== endLine.number;
|
|
2518
3590
|
if (isWrapped) {
|
|
2519
3591
|
view.dispatch({
|
|
2520
3592
|
changes: [
|
|
@@ -2525,8 +3597,10 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2525
3597
|
]
|
|
2526
3598
|
});
|
|
2527
3599
|
} else {
|
|
2528
|
-
const openFence =
|
|
2529
|
-
|
|
3600
|
+
const openFence = `${CODE_FENCE}
|
|
3601
|
+
`;
|
|
3602
|
+
const closeFence = `
|
|
3603
|
+
${CODE_FENCE}`;
|
|
2530
3604
|
view.dispatch({
|
|
2531
3605
|
changes: [
|
|
2532
3606
|
{ from: startLine.from, insert: openFence },
|
|
@@ -2555,6 +3629,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2555
3629
|
* lineNumbers: 5,
|
|
2556
3630
|
* title: "hello.tsx",
|
|
2557
3631
|
* copy: true,
|
|
3632
|
+
* diff: false,
|
|
2558
3633
|
* highlightLines: [2,3,4,5],
|
|
2559
3634
|
* highlightText: [{ pattern: "Hello", instances: [3,4,5] }]
|
|
2560
3635
|
* }
|
|
@@ -2566,14 +3641,21 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2566
3641
|
return props;
|
|
2567
3642
|
}
|
|
2568
3643
|
let remaining = codeInfo.trim();
|
|
2569
|
-
const
|
|
2570
|
-
if (
|
|
2571
|
-
|
|
2572
|
-
|
|
3644
|
+
const firstTokenMatch = remaining.match(/^([^\s]+)/);
|
|
3645
|
+
if (firstTokenMatch && firstTokenMatch[1]) {
|
|
3646
|
+
const firstToken = firstTokenMatch[1];
|
|
3647
|
+
const normalizedToken = firstToken.toLowerCase();
|
|
3648
|
+
const isLineNumberDirective = /^(?:line-numbers|linenumbers|showlinenumbers)(?:\{\d+\})?$/.test(
|
|
3649
|
+
normalizedToken
|
|
3650
|
+
);
|
|
3651
|
+
const isKnownDirective = isLineNumberDirective || normalizedToken === "copy" || normalizedToken === "diff" || normalizedToken.startsWith("{") || normalizedToken.startsWith("/");
|
|
3652
|
+
if (!isKnownDirective) {
|
|
3653
|
+
props.language = firstToken;
|
|
3654
|
+
remaining = remaining.slice(firstToken.length).trim();
|
|
3655
|
+
}
|
|
2573
3656
|
}
|
|
2574
|
-
const quotedPattern = /(\w+)="([^"]*)"/g;
|
|
2575
3657
|
let quotedMatch;
|
|
2576
|
-
while ((quotedMatch =
|
|
3658
|
+
while ((quotedMatch = QUOTED_INFO_PATTERN.exec(remaining)) !== null) {
|
|
2577
3659
|
const key = quotedMatch[1]?.toLowerCase();
|
|
2578
3660
|
const value = quotedMatch[2];
|
|
2579
3661
|
if (key === "title" && value !== void 0) {
|
|
@@ -2582,13 +3664,13 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2582
3664
|
props.caption = value;
|
|
2583
3665
|
}
|
|
2584
3666
|
}
|
|
2585
|
-
remaining = remaining.replace(
|
|
2586
|
-
const lineNumbersMatch = remaining.match(
|
|
3667
|
+
remaining = remaining.replace(QUOTED_INFO_PATTERN, "").trim();
|
|
3668
|
+
const lineNumbersMatch = remaining.match(/\b(?:line-numbers|lineNumbers|showLineNumbers)(?:\{(\d+)\})?/i);
|
|
2587
3669
|
if (lineNumbersMatch) {
|
|
2588
3670
|
if (lineNumbersMatch[1]) {
|
|
2589
|
-
props.
|
|
3671
|
+
props.showLineNumbers = parseInt(lineNumbersMatch[1], 10);
|
|
2590
3672
|
} else {
|
|
2591
|
-
props.
|
|
3673
|
+
props.showLineNumbers = true;
|
|
2592
3674
|
}
|
|
2593
3675
|
remaining = remaining.replace(lineNumbersMatch[0], "").trim();
|
|
2594
3676
|
}
|
|
@@ -2596,52 +3678,27 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2596
3678
|
props.copy = true;
|
|
2597
3679
|
remaining = remaining.replace(/\bcopy\b/, "").trim();
|
|
2598
3680
|
}
|
|
3681
|
+
if (/\bdiff\b/.test(remaining)) {
|
|
3682
|
+
props.diff = true;
|
|
3683
|
+
remaining = remaining.replace(/\bdiff\b/, "").trim();
|
|
3684
|
+
}
|
|
2599
3685
|
const lineHighlightMatch = remaining.match(/\{([^}]+)\}/);
|
|
2600
3686
|
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
|
-
}
|
|
3687
|
+
const highlightLines = this.parseNumberList(lineHighlightMatch[1]);
|
|
2616
3688
|
if (highlightLines.length > 0) {
|
|
2617
3689
|
props.highlightLines = highlightLines;
|
|
2618
3690
|
}
|
|
2619
3691
|
remaining = remaining.replace(lineHighlightMatch[0], "").trim();
|
|
2620
3692
|
}
|
|
2621
|
-
const textHighlightPattern = /\/([^/]+)\/(?:(\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*))?/g;
|
|
2622
3693
|
let textMatch;
|
|
2623
3694
|
const highlightText = [];
|
|
2624
|
-
while ((textMatch =
|
|
3695
|
+
while ((textMatch = TEXT_HIGHLIGHT_PATTERN.exec(remaining)) !== null) {
|
|
2625
3696
|
if (!textMatch[1]) continue;
|
|
2626
3697
|
const highlight = {
|
|
2627
3698
|
pattern: textMatch[1]
|
|
2628
3699
|
};
|
|
2629
3700
|
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
|
-
}
|
|
3701
|
+
const instances = this.parseNumberList(textMatch[2]);
|
|
2645
3702
|
if (instances.length > 0) {
|
|
2646
3703
|
highlight.instances = instances;
|
|
2647
3704
|
}
|
|
@@ -2658,148 +3715,244 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2658
3715
|
* Handles line numbers, highlights, header/caption widgets, and fence visibility.
|
|
2659
3716
|
*/
|
|
2660
3717
|
buildDecorations(ctx) {
|
|
2661
|
-
const
|
|
2662
|
-
const tree = language.syntaxTree(view$1.state);
|
|
3718
|
+
const tree = language.syntaxTree(ctx.view.state);
|
|
2663
3719
|
tree.iterate({
|
|
2664
3720
|
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
|
-
}
|
|
3721
|
+
if (node.name === "InlineCode") {
|
|
3722
|
+
this.decorateInlineCode(node, ctx);
|
|
3723
|
+
return;
|
|
2676
3724
|
}
|
|
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++;
|
|
3725
|
+
if (node.name === "FencedCode") {
|
|
3726
|
+
this.decorateFencedCode(node, ctx);
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
});
|
|
3730
|
+
}
|
|
3731
|
+
decorateInlineCode(node, ctx) {
|
|
3732
|
+
const { from, to } = node;
|
|
3733
|
+
ctx.decorations.push(codeMarkDecorations["inline-code"].range(from, to));
|
|
3734
|
+
if (ctx.selectionOverlapsRange(from, to)) {
|
|
3735
|
+
return;
|
|
3736
|
+
}
|
|
3737
|
+
for (let child = node.node.firstChild; child; child = child.nextSibling) {
|
|
3738
|
+
if (child.name === "CodeMark") {
|
|
3739
|
+
ctx.decorations.push(codeMarkDecorations["inline-mark"].range(child.from, child.to));
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
decorateFencedCode(node, ctx) {
|
|
3744
|
+
const { view: view$1, decorations } = ctx;
|
|
3745
|
+
const nodeLineStart = view$1.state.doc.lineAt(node.from);
|
|
3746
|
+
const nodeLineEnd = view$1.state.doc.lineAt(node.to);
|
|
3747
|
+
const cursorInRange = ctx.selectionOverlapsRange(nodeLineStart.from, nodeLineEnd.to);
|
|
3748
|
+
let infoProps = { language: "" };
|
|
3749
|
+
let codeContent = "";
|
|
3750
|
+
for (let child = node.node.firstChild; child; child = child.nextSibling) {
|
|
3751
|
+
if (child.name === "CodeInfo") {
|
|
3752
|
+
infoProps = this.parseCodeInfo(view$1.state.sliceDoc(child.from, child.to).trim());
|
|
3753
|
+
}
|
|
3754
|
+
if (child.name === "CodeText") {
|
|
3755
|
+
codeContent = view$1.state.sliceDoc(child.from, child.to);
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
const codeLines = [];
|
|
3759
|
+
for (let i = nodeLineStart.number + 1; i <= nodeLineEnd.number - 1; i++) {
|
|
3760
|
+
const codeLine = view$1.state.doc.line(i);
|
|
3761
|
+
codeLines.push(view$1.state.sliceDoc(codeLine.from, codeLine.to));
|
|
3762
|
+
}
|
|
3763
|
+
const totalCodeLines = nodeLineEnd.number - nodeLineStart.number - 1;
|
|
3764
|
+
const startLineNum = typeof infoProps.showLineNumbers === "number" ? infoProps.showLineNumbers : 1;
|
|
3765
|
+
const maxLineNum = startLineNum + totalCodeLines - 1;
|
|
3766
|
+
const lineNumWidth = Math.max(String(maxLineNum).length, String(startLineNum).length);
|
|
3767
|
+
const highlightInstanceCounters = new Array(infoProps.highlightText?.length ?? 0).fill(0);
|
|
3768
|
+
const diffStates = infoProps.diff ? this.analyzeDiffLines(codeLines) : [];
|
|
3769
|
+
const diffDisplayLineNumbers = infoProps.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum) : [];
|
|
3770
|
+
const displayLineNumbers = infoProps.diff ? diffDisplayLineNumbers.map((numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index) : codeLines.map((_, index) => startLineNum + index);
|
|
3771
|
+
const diffHighlightLineNumbers = infoProps.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum).map(
|
|
3772
|
+
(numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index
|
|
3773
|
+
) : [];
|
|
3774
|
+
const maxOldDiffLineNum = diffDisplayLineNumbers.reduce((max, numbers) => {
|
|
3775
|
+
const oldLine = numbers.oldLine ?? 0;
|
|
3776
|
+
return oldLine > max ? oldLine : max;
|
|
3777
|
+
}, startLineNum);
|
|
3778
|
+
const maxNewDiffLineNum = diffDisplayLineNumbers.reduce((max, numbers) => {
|
|
3779
|
+
const newLine = numbers.newLine ?? 0;
|
|
3780
|
+
return newLine > max ? newLine : max;
|
|
3781
|
+
}, startLineNum);
|
|
3782
|
+
const diffOldLineNumWidth = Math.max(String(startLineNum).length, String(maxOldDiffLineNum).length);
|
|
3783
|
+
const diffNewLineNumWidth = Math.max(String(startLineNum).length, String(maxNewDiffLineNum).length);
|
|
3784
|
+
const shouldShowHeader = !cursorInRange && (infoProps.title || infoProps.copy || infoProps.language);
|
|
3785
|
+
const shouldShowCaption = !cursorInRange && !!infoProps.caption;
|
|
3786
|
+
if (shouldShowHeader) {
|
|
3787
|
+
decorations.push(
|
|
3788
|
+
view.Decoration.widget({
|
|
3789
|
+
widget: new CodeBlockHeaderWidget(infoProps, codeContent),
|
|
3790
|
+
block: false,
|
|
3791
|
+
side: -1
|
|
3792
|
+
}).range(nodeLineStart.from)
|
|
3793
|
+
);
|
|
3794
|
+
}
|
|
3795
|
+
let codeLineIndex = 0;
|
|
3796
|
+
for (let lineNumber = nodeLineStart.number; lineNumber <= nodeLineEnd.number; lineNumber++) {
|
|
3797
|
+
const line = view$1.state.doc.line(lineNumber);
|
|
3798
|
+
const isFenceLine = lineNumber === nodeLineStart.number || lineNumber === nodeLineEnd.number;
|
|
3799
|
+
const relativeLineNum = displayLineNumbers[codeLineIndex] ?? startLineNum + codeLineIndex;
|
|
3800
|
+
decorations.push(codeMarkDecorations["code-block-line"].range(line.from));
|
|
3801
|
+
if (lineNumber === nodeLineStart.number) {
|
|
3802
|
+
decorations.push(codeMarkDecorations["code-block-line-start"].range(line.from));
|
|
3803
|
+
if (shouldShowHeader) {
|
|
3804
|
+
decorations.push(view.Decoration.line({ class: "cm-draftly-code-block-has-header" }).range(line.from));
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
if (lineNumber === nodeLineEnd.number) {
|
|
3808
|
+
decorations.push(codeMarkDecorations["code-block-line-end"].range(line.from));
|
|
3809
|
+
if (shouldShowCaption) {
|
|
3810
|
+
decorations.push(view.Decoration.line({ class: "cm-draftly-code-block-has-caption" }).range(line.from));
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
if (!isFenceLine && infoProps.showLineNumbers && !infoProps.diff) {
|
|
3814
|
+
decorations.push(
|
|
3815
|
+
view.Decoration.line({
|
|
3816
|
+
class: "cm-draftly-code-line-numbered",
|
|
3817
|
+
attributes: {
|
|
3818
|
+
"data-line-num": String(relativeLineNum),
|
|
3819
|
+
style: `--line-num-width: ${lineNumWidth}ch`
|
|
2773
3820
|
}
|
|
2774
|
-
}
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
3821
|
+
}).range(line.from)
|
|
3822
|
+
);
|
|
3823
|
+
}
|
|
3824
|
+
if (!isFenceLine && infoProps.showLineNumbers && infoProps.diff) {
|
|
3825
|
+
const diffLineNumbers = diffDisplayLineNumbers[codeLineIndex];
|
|
3826
|
+
const diffState = diffStates[codeLineIndex];
|
|
3827
|
+
const diffMarker = diffState?.kind === "addition" ? "+" : diffState?.kind === "deletion" ? "-" : " ";
|
|
3828
|
+
decorations.push(
|
|
3829
|
+
view.Decoration.line({
|
|
3830
|
+
class: "cm-draftly-code-line-numbered-diff",
|
|
3831
|
+
attributes: {
|
|
3832
|
+
"data-line-num-old": diffLineNumbers?.oldLine != null ? String(diffLineNumbers.oldLine) : "",
|
|
3833
|
+
"data-line-num-new": diffLineNumbers?.newLine != null ? String(diffLineNumbers.newLine) : "",
|
|
3834
|
+
"data-diff-marker": diffMarker,
|
|
3835
|
+
style: `--line-num-old-width: ${diffOldLineNumWidth}ch; --line-num-new-width: ${diffNewLineNumWidth}ch`
|
|
2782
3836
|
}
|
|
3837
|
+
}).range(line.from)
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
3840
|
+
if (!isFenceLine && infoProps.diff) {
|
|
3841
|
+
this.decorateDiffLine(
|
|
3842
|
+
line,
|
|
3843
|
+
codeLineIndex,
|
|
3844
|
+
diffStates,
|
|
3845
|
+
cursorInRange,
|
|
3846
|
+
!infoProps.showLineNumbers,
|
|
3847
|
+
decorations
|
|
3848
|
+
);
|
|
3849
|
+
}
|
|
3850
|
+
if (!isFenceLine && infoProps.highlightLines) {
|
|
3851
|
+
const highlightLineNumber = infoProps.diff ? diffHighlightLineNumbers[codeLineIndex] ?? codeLineIndex + 1 : startLineNum + codeLineIndex;
|
|
3852
|
+
if (infoProps.highlightLines.includes(highlightLineNumber)) {
|
|
3853
|
+
decorations.push(codeMarkDecorations["code-line-highlight"].range(line.from));
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
if (!isFenceLine && infoProps.highlightText?.length) {
|
|
3857
|
+
this.decorateTextHighlights(
|
|
3858
|
+
line.from,
|
|
3859
|
+
view$1.state.sliceDoc(line.from, line.to),
|
|
3860
|
+
infoProps.highlightText,
|
|
3861
|
+
highlightInstanceCounters,
|
|
3862
|
+
decorations
|
|
3863
|
+
);
|
|
3864
|
+
}
|
|
3865
|
+
if (!isFenceLine) {
|
|
3866
|
+
codeLineIndex++;
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
this.decorateFenceMarkers(node.node, cursorInRange, decorations);
|
|
3870
|
+
if (!cursorInRange && infoProps.caption) {
|
|
3871
|
+
decorations.push(
|
|
3872
|
+
view.Decoration.widget({
|
|
3873
|
+
widget: new CodeBlockCaptionWidget(infoProps.caption),
|
|
3874
|
+
block: false,
|
|
3875
|
+
side: 1
|
|
3876
|
+
}).range(nodeLineEnd.to)
|
|
3877
|
+
);
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
decorateFenceMarkers(node, cursorInRange, decorations) {
|
|
3881
|
+
for (let child = node.firstChild; child; child = child.nextSibling) {
|
|
3882
|
+
if (child.name === "CodeMark" || child.name === "CodeInfo") {
|
|
3883
|
+
decorations.push(
|
|
3884
|
+
(cursorInRange ? codeMarkDecorations["code-fence"] : codeMarkDecorations["code-hidden"]).range(
|
|
3885
|
+
child.from,
|
|
3886
|
+
child.to
|
|
3887
|
+
)
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
decorateDiffLine(line, codeLineIndex, diffStates, cursorInRange, showDiffMarkerGutter, decorations) {
|
|
3893
|
+
const diffState = diffStates[codeLineIndex];
|
|
3894
|
+
const diffMarker = diffState?.kind === "addition" ? "+" : diffState?.kind === "deletion" ? "-" : " ";
|
|
3895
|
+
if (showDiffMarkerGutter) {
|
|
3896
|
+
decorations.push(
|
|
3897
|
+
view.Decoration.line({
|
|
3898
|
+
class: "cm-draftly-code-line-diff-gutter",
|
|
3899
|
+
attributes: {
|
|
3900
|
+
"data-diff-marker": diffMarker
|
|
2783
3901
|
}
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
3902
|
+
}).range(line.from)
|
|
3903
|
+
);
|
|
3904
|
+
}
|
|
3905
|
+
if (diffState?.kind === "addition") {
|
|
3906
|
+
decorations.push(codeMarkDecorations["diff-line-add"].range(line.from));
|
|
3907
|
+
if (cursorInRange && line.to > line.from) {
|
|
3908
|
+
decorations.push(codeMarkDecorations["diff-sign-add"].range(line.from, line.from + 1));
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
if (diffState?.kind === "deletion") {
|
|
3912
|
+
decorations.push(codeMarkDecorations["diff-line-del"].range(line.from));
|
|
3913
|
+
if (cursorInRange && line.to > line.from) {
|
|
3914
|
+
decorations.push(codeMarkDecorations["diff-sign-del"].range(line.from, line.from + 1));
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
if (!cursorInRange && line.to > line.from && (diffState?.escapedMarker || diffState?.kind === "addition" || diffState?.kind === "deletion")) {
|
|
3918
|
+
decorations.push(codeMarkDecorations["diff-escape-hidden"].range(line.from, line.from + 1));
|
|
3919
|
+
}
|
|
3920
|
+
if (diffState?.modificationRanges?.length) {
|
|
3921
|
+
for (const [start, end] of diffState.modificationRanges) {
|
|
3922
|
+
const rangeFrom = line.from + diffState.contentOffset + start;
|
|
3923
|
+
const rangeTo = line.from + diffState.contentOffset + end;
|
|
3924
|
+
if (rangeTo > rangeFrom) {
|
|
3925
|
+
decorations.push(
|
|
3926
|
+
(diffState.kind === "addition" ? codeMarkDecorations["diff-mod-add"] : codeMarkDecorations["diff-mod-del"]).range(rangeFrom, rangeTo)
|
|
3927
|
+
);
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
decorateTextHighlights(lineFrom, lineText, highlights, instanceCounters, decorations) {
|
|
3933
|
+
for (const [highlightIndex, textHighlight] of highlights.entries()) {
|
|
3934
|
+
try {
|
|
3935
|
+
const regex = new RegExp(textHighlight.pattern, "g");
|
|
3936
|
+
let match;
|
|
3937
|
+
while ((match = regex.exec(lineText)) !== null) {
|
|
3938
|
+
instanceCounters[highlightIndex] = (instanceCounters[highlightIndex] ?? 0) + 1;
|
|
3939
|
+
const globalMatchIndex = instanceCounters[highlightIndex];
|
|
3940
|
+
const shouldHighlight = !textHighlight.instances || textHighlight.instances.includes(globalMatchIndex);
|
|
3941
|
+
if (shouldHighlight) {
|
|
3942
|
+
const matchFrom = lineFrom + match.index;
|
|
3943
|
+
const matchTo = matchFrom + match[0].length;
|
|
3944
|
+
decorations.push(codeMarkDecorations["code-text-highlight"].range(matchFrom, matchTo));
|
|
2793
3945
|
}
|
|
2794
3946
|
}
|
|
3947
|
+
} catch {
|
|
2795
3948
|
}
|
|
2796
|
-
}
|
|
3949
|
+
}
|
|
2797
3950
|
}
|
|
2798
3951
|
/**
|
|
2799
3952
|
* Render code elements to HTML for static preview.
|
|
2800
3953
|
* Applies syntax highlighting using @lezer/highlight.
|
|
2801
3954
|
*/
|
|
2802
|
-
renderToHTML(node,
|
|
3955
|
+
async renderToHTML(node, _children, ctx) {
|
|
2803
3956
|
if (node.name === "CodeMark") {
|
|
2804
3957
|
return "";
|
|
2805
3958
|
}
|
|
@@ -2809,7 +3962,7 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2809
3962
|
if (match && match[1]) {
|
|
2810
3963
|
content = match[1];
|
|
2811
3964
|
}
|
|
2812
|
-
return `<code class="cm-draftly-code-inline" style="padding: 0.1rem 0.25rem">${
|
|
3965
|
+
return `<code class="cm-draftly-code-inline" style="padding: 0.1rem 0.25rem">${this.escapeHtml(content)}</code>`;
|
|
2813
3966
|
}
|
|
2814
3967
|
if (node.name === "FencedCode") {
|
|
2815
3968
|
const content = ctx.sliceDoc(node.from, node.to);
|
|
@@ -2827,9 +3980,9 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2827
3980
|
html += `<div class="cm-draftly-code-header">`;
|
|
2828
3981
|
html += `<div class="cm-draftly-code-header-left">`;
|
|
2829
3982
|
if (props.title) {
|
|
2830
|
-
html += `<span class="cm-draftly-code-header-title">${
|
|
3983
|
+
html += `<span class="cm-draftly-code-header-title">${this.escapeHtml(props.title)}</span>`;
|
|
2831
3984
|
} else if (props.language) {
|
|
2832
|
-
html += `<span class="cm-draftly-code-header-lang">${
|
|
3985
|
+
html += `<span class="cm-draftly-code-header-lang">${this.escapeHtml(props.language)}</span>`;
|
|
2833
3986
|
}
|
|
2834
3987
|
html += `</div>`;
|
|
2835
3988
|
if (props.copy !== false) {
|
|
@@ -2842,32 +3995,83 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2842
3995
|
}
|
|
2843
3996
|
html += `</div>`;
|
|
2844
3997
|
}
|
|
2845
|
-
const startLineNum = typeof props.
|
|
2846
|
-
const
|
|
3998
|
+
const startLineNum = typeof props.showLineNumbers === "number" ? props.showLineNumbers : 1;
|
|
3999
|
+
const previewHighlightCounters = new Array(props.highlightText?.length ?? 0).fill(0);
|
|
4000
|
+
const diffStates = props.diff ? this.analyzeDiffLines(codeLines) : [];
|
|
4001
|
+
const previewDiffLineNumbers = props.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum) : [];
|
|
4002
|
+
const previewLineNumbers = props.diff ? previewDiffLineNumbers.map((numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index) : codeLines.map((_, index) => startLineNum + index);
|
|
4003
|
+
const previewHighlightLineNumbers = props.diff ? this.computeDiffDisplayLineNumbers(diffStates, startLineNum).map(
|
|
4004
|
+
(numbers, index) => numbers.newLine ?? numbers.oldLine ?? startLineNum + index
|
|
4005
|
+
) : [];
|
|
4006
|
+
const lineNumWidth = String(Math.max(...previewLineNumbers, startLineNum)).length;
|
|
4007
|
+
const previewOldLineNumWidth = String(
|
|
4008
|
+
Math.max(
|
|
4009
|
+
...previewDiffLineNumbers.map((numbers) => numbers.oldLine ?? 0),
|
|
4010
|
+
startLineNum
|
|
4011
|
+
)
|
|
4012
|
+
).length;
|
|
4013
|
+
const previewNewLineNumWidth = String(
|
|
4014
|
+
Math.max(
|
|
4015
|
+
...previewDiffLineNumbers.map((numbers) => numbers.newLine ?? 0),
|
|
4016
|
+
startLineNum
|
|
4017
|
+
)
|
|
4018
|
+
).length;
|
|
4019
|
+
const previewContentLines = props.diff ? diffStates.map((state) => state.content) : codeLines;
|
|
4020
|
+
const highlightedLines = await this.highlightCodeLines(
|
|
4021
|
+
previewContentLines.join("\n"),
|
|
4022
|
+
props.language || "",
|
|
4023
|
+
ctx.syntaxHighlighters
|
|
4024
|
+
);
|
|
2847
4025
|
const hasHeader = showHeader ? " cm-draftly-code-block-has-header" : "";
|
|
2848
4026
|
const hasCaption = props.caption ? " cm-draftly-code-block-has-caption" : "";
|
|
2849
|
-
html += `<pre class="cm-draftly-code-block${hasHeader}${hasCaption}"${props.language ? ` data-lang="${
|
|
4027
|
+
html += `<pre class="cm-draftly-code-block${hasHeader}${hasCaption}"${props.language ? ` data-lang="${this.escapeAttribute(props.language)}"` : ""}>`;
|
|
2850
4028
|
html += `<code>`;
|
|
2851
4029
|
codeLines.forEach((line, index) => {
|
|
2852
|
-
const lineNum = startLineNum + index;
|
|
2853
|
-
const
|
|
4030
|
+
const lineNum = previewLineNumbers[index] ?? startLineNum + index;
|
|
4031
|
+
const highlightLineNumber = props.diff ? previewHighlightLineNumbers[index] ?? startLineNum + index : startLineNum + index;
|
|
4032
|
+
const isHighlighted = props.highlightLines?.includes(highlightLineNumber);
|
|
4033
|
+
const diffState = props.diff ? diffStates[index] : void 0;
|
|
4034
|
+
const diffLineNumbers = props.diff ? previewDiffLineNumbers[index] : void 0;
|
|
2854
4035
|
const lineClasses = ["cm-draftly-code-line"];
|
|
2855
4036
|
if (isHighlighted) lineClasses.push("cm-draftly-code-line-highlight");
|
|
2856
|
-
if (props.
|
|
4037
|
+
if (props.showLineNumbers) {
|
|
4038
|
+
lineClasses.push(props.diff ? "cm-draftly-code-line-numbered-diff" : "cm-draftly-code-line-numbered");
|
|
4039
|
+
}
|
|
4040
|
+
if (diffState?.kind === "addition") lineClasses.push("cm-draftly-code-line-diff-add");
|
|
4041
|
+
if (diffState?.kind === "deletion") lineClasses.push("cm-draftly-code-line-diff-del");
|
|
2857
4042
|
const lineAttrs = [`class="${lineClasses.join(" ")}"`];
|
|
2858
|
-
if (props.
|
|
4043
|
+
if (props.showLineNumbers && !props.diff) {
|
|
2859
4044
|
lineAttrs.push(`data-line-num="${lineNum}"`);
|
|
2860
4045
|
lineAttrs.push(`style="--line-num-width: ${lineNumWidth}ch"`);
|
|
2861
4046
|
}
|
|
2862
|
-
|
|
4047
|
+
if (props.diff) {
|
|
4048
|
+
const diffMarker = diffState?.kind === "addition" ? "+" : diffState?.kind === "deletion" ? "-" : " ";
|
|
4049
|
+
if (props.showLineNumbers) {
|
|
4050
|
+
lineAttrs.push(`data-line-num-old="${diffLineNumbers?.oldLine != null ? diffLineNumbers.oldLine : ""}"`);
|
|
4051
|
+
lineAttrs.push(`data-line-num-new="${diffLineNumbers?.newLine != null ? diffLineNumbers.newLine : ""}"`);
|
|
4052
|
+
lineAttrs.push(`data-diff-marker="${diffMarker}"`);
|
|
4053
|
+
lineAttrs.push(
|
|
4054
|
+
`style="--line-num-old-width: ${previewOldLineNumWidth}ch; --line-num-new-width: ${previewNewLineNumWidth}ch"`
|
|
4055
|
+
);
|
|
4056
|
+
} else {
|
|
4057
|
+
lineAttrs.push(`data-diff-marker="${diffMarker}"`);
|
|
4058
|
+
lineClasses.push("cm-draftly-code-line-diff-gutter");
|
|
4059
|
+
lineAttrs[0] = `class="${lineClasses.join(" ")}"`;
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
const highlightedLine = highlightedLines[index] ?? this.escapeHtml(previewContentLines[index] ?? line);
|
|
4063
|
+
let lineContent = highlightedLine;
|
|
4064
|
+
if (diffState) {
|
|
4065
|
+
lineContent = this.renderDiffPreviewLine(diffState, highlightedLine);
|
|
4066
|
+
}
|
|
2863
4067
|
if (props.highlightText && props.highlightText.length > 0) {
|
|
2864
|
-
lineContent = this.applyTextHighlights(lineContent, props.highlightText);
|
|
4068
|
+
lineContent = this.applyTextHighlights(lineContent, props.highlightText, previewHighlightCounters);
|
|
2865
4069
|
}
|
|
2866
4070
|
html += `<span ${lineAttrs.join(" ")}>${lineContent || " "}</span>`;
|
|
2867
4071
|
});
|
|
2868
4072
|
html += `</code></pre>`;
|
|
2869
4073
|
if (props.caption) {
|
|
2870
|
-
html += `<div class="cm-draftly-code-caption">${
|
|
4074
|
+
html += `<div class="cm-draftly-code-caption">${this.escapeHtml(props.caption)}</div>`;
|
|
2871
4075
|
}
|
|
2872
4076
|
html += `</div>`;
|
|
2873
4077
|
return html;
|
|
@@ -2877,54 +4081,290 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2877
4081
|
}
|
|
2878
4082
|
return null;
|
|
2879
4083
|
}
|
|
4084
|
+
/** Parse comma-separated numbers and ranges (e.g. "1,3-5") into [1,3,4,5]. */
|
|
4085
|
+
parseNumberList(value) {
|
|
4086
|
+
const result = [];
|
|
4087
|
+
for (const part of value.split(",")) {
|
|
4088
|
+
const trimmed = part.trim();
|
|
4089
|
+
const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/);
|
|
4090
|
+
if (rangeMatch && rangeMatch[1] && rangeMatch[2]) {
|
|
4091
|
+
const start = parseInt(rangeMatch[1], 10);
|
|
4092
|
+
const end = parseInt(rangeMatch[2], 10);
|
|
4093
|
+
for (let i = start; i <= end; i++) {
|
|
4094
|
+
result.push(i);
|
|
4095
|
+
}
|
|
4096
|
+
continue;
|
|
4097
|
+
}
|
|
4098
|
+
if (/^\d+$/.test(trimmed)) {
|
|
4099
|
+
result.push(parseInt(trimmed, 10));
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
return result;
|
|
4103
|
+
}
|
|
2880
4104
|
/**
|
|
2881
4105
|
* Highlight a single line of code using the language's Lezer parser.
|
|
2882
4106
|
* Falls back to sanitized plain text if the language is not supported.
|
|
2883
4107
|
*/
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
4108
|
+
async highlightCodeLines(code, lang, syntaxHighlighters) {
|
|
4109
|
+
const rawLines = code.split("\n");
|
|
4110
|
+
if (!lang || !code) {
|
|
4111
|
+
return rawLines.map((line) => this.escapeHtml(line));
|
|
2887
4112
|
}
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
if (!langDesc || !langDesc.support) {
|
|
2892
|
-
return ctx.sanitize(line);
|
|
4113
|
+
const parser = await this.resolveLanguageParser(lang);
|
|
4114
|
+
if (!parser) {
|
|
4115
|
+
return rawLines.map((line) => this.escapeHtml(line));
|
|
2893
4116
|
}
|
|
2894
4117
|
try {
|
|
2895
|
-
const
|
|
2896
|
-
const
|
|
2897
|
-
let result = "";
|
|
4118
|
+
const tree = parser.parse(code);
|
|
4119
|
+
const highlightedLines = [""];
|
|
2898
4120
|
highlight.highlightCode(
|
|
2899
|
-
|
|
4121
|
+
code,
|
|
2900
4122
|
tree,
|
|
2901
|
-
|
|
4123
|
+
syntaxHighlighters && syntaxHighlighters.length > 0 ? syntaxHighlighters : [],
|
|
2902
4124
|
(text, classes2) => {
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
} else {
|
|
2906
|
-
result += ctx.sanitize(text);
|
|
2907
|
-
}
|
|
4125
|
+
const chunk = classes2 ? `<span class="${this.escapeAttribute(classes2)}">${this.escapeHtml(text)}</span>` : this.escapeHtml(text);
|
|
4126
|
+
highlightedLines[highlightedLines.length - 1] += chunk;
|
|
2908
4127
|
},
|
|
2909
4128
|
() => {
|
|
4129
|
+
highlightedLines.push("");
|
|
2910
4130
|
}
|
|
2911
|
-
// No newlines for single line
|
|
2912
4131
|
);
|
|
2913
|
-
return
|
|
4132
|
+
return rawLines.map((line, index) => highlightedLines[index] || this.escapeHtml(line));
|
|
2914
4133
|
} catch {
|
|
2915
|
-
return
|
|
4134
|
+
return rawLines.map((line) => this.escapeHtml(line));
|
|
2916
4135
|
}
|
|
2917
4136
|
}
|
|
4137
|
+
async resolveLanguageParser(lang) {
|
|
4138
|
+
const normalizedLang = this.normalizeLanguage(lang);
|
|
4139
|
+
if (!normalizedLang) return null;
|
|
4140
|
+
const cached = this.parserCache.get(normalizedLang);
|
|
4141
|
+
if (cached) return cached;
|
|
4142
|
+
const parserPromise = (async () => {
|
|
4143
|
+
const langDesc = language.LanguageDescription.matchLanguageName(languageData.languages, normalizedLang, true);
|
|
4144
|
+
if (!langDesc) return null;
|
|
4145
|
+
if (langDesc.support) {
|
|
4146
|
+
return langDesc.support.language.parser;
|
|
4147
|
+
}
|
|
4148
|
+
if (typeof langDesc.load === "function") {
|
|
4149
|
+
try {
|
|
4150
|
+
const support = await langDesc.load();
|
|
4151
|
+
return support.language.parser;
|
|
4152
|
+
} catch {
|
|
4153
|
+
return null;
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
return null;
|
|
4157
|
+
})();
|
|
4158
|
+
this.parserCache.set(normalizedLang, parserPromise);
|
|
4159
|
+
return parserPromise;
|
|
4160
|
+
}
|
|
4161
|
+
normalizeLanguage(lang) {
|
|
4162
|
+
const normalized = lang.trim().toLowerCase();
|
|
4163
|
+
if (!normalized) return "";
|
|
4164
|
+
const normalizedMap = {
|
|
4165
|
+
"c++": "cpp",
|
|
4166
|
+
"c#": "csharp",
|
|
4167
|
+
"f#": "fsharp",
|
|
4168
|
+
py: "python",
|
|
4169
|
+
js: "javascript",
|
|
4170
|
+
ts: "typescript",
|
|
4171
|
+
sh: "shell"
|
|
4172
|
+
};
|
|
4173
|
+
return normalizedMap[normalized] ?? normalized;
|
|
4174
|
+
}
|
|
4175
|
+
escapeHtml(value) {
|
|
4176
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4177
|
+
}
|
|
4178
|
+
escapeAttribute(value) {
|
|
4179
|
+
return this.escapeHtml(value).replace(/`/g, "`");
|
|
4180
|
+
}
|
|
4181
|
+
analyzeDiffLines(lines) {
|
|
4182
|
+
const states = lines.map((line) => this.parseDiffLineState(line));
|
|
4183
|
+
let index = 0;
|
|
4184
|
+
while (index < states.length) {
|
|
4185
|
+
if (states[index]?.kind !== "deletion") {
|
|
4186
|
+
index++;
|
|
4187
|
+
continue;
|
|
4188
|
+
}
|
|
4189
|
+
const deletionStart = index;
|
|
4190
|
+
while (index < states.length && states[index]?.kind === "deletion") {
|
|
4191
|
+
index++;
|
|
4192
|
+
}
|
|
4193
|
+
const deletionEnd = index;
|
|
4194
|
+
const additionStart = index;
|
|
4195
|
+
while (index < states.length && states[index]?.kind === "addition") {
|
|
4196
|
+
index++;
|
|
4197
|
+
}
|
|
4198
|
+
const additionEnd = index;
|
|
4199
|
+
if (additionStart === additionEnd) {
|
|
4200
|
+
continue;
|
|
4201
|
+
}
|
|
4202
|
+
const pairCount = Math.min(deletionEnd - deletionStart, additionEnd - additionStart);
|
|
4203
|
+
for (let pairIndex = 0; pairIndex < pairCount; pairIndex++) {
|
|
4204
|
+
const deletionState = states[deletionStart + pairIndex];
|
|
4205
|
+
const additionState = states[additionStart + pairIndex];
|
|
4206
|
+
if (!deletionState || !additionState) {
|
|
4207
|
+
continue;
|
|
4208
|
+
}
|
|
4209
|
+
const ranges = this.computeChangedRanges(deletionState.content, additionState.content);
|
|
4210
|
+
if (ranges.oldRanges.length > 0) {
|
|
4211
|
+
deletionState.modificationRanges = ranges.oldRanges;
|
|
4212
|
+
}
|
|
4213
|
+
if (ranges.newRanges.length > 0) {
|
|
4214
|
+
additionState.modificationRanges = ranges.newRanges;
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
return states;
|
|
4219
|
+
}
|
|
4220
|
+
computeDiffDisplayLineNumbers(states, startLineNum) {
|
|
4221
|
+
const numbers = [];
|
|
4222
|
+
let oldLineNumber = startLineNum;
|
|
4223
|
+
let newLineNumber = startLineNum;
|
|
4224
|
+
for (const state of states) {
|
|
4225
|
+
if (state.kind === "deletion") {
|
|
4226
|
+
numbers.push({ oldLine: oldLineNumber, newLine: null });
|
|
4227
|
+
oldLineNumber++;
|
|
4228
|
+
continue;
|
|
4229
|
+
}
|
|
4230
|
+
if (state.kind === "addition") {
|
|
4231
|
+
numbers.push({ oldLine: null, newLine: newLineNumber });
|
|
4232
|
+
newLineNumber++;
|
|
4233
|
+
continue;
|
|
4234
|
+
}
|
|
4235
|
+
numbers.push({ oldLine: oldLineNumber, newLine: newLineNumber });
|
|
4236
|
+
oldLineNumber++;
|
|
4237
|
+
newLineNumber++;
|
|
4238
|
+
}
|
|
4239
|
+
return numbers;
|
|
4240
|
+
}
|
|
4241
|
+
parseDiffLineState(line) {
|
|
4242
|
+
const escapedMarker = line.startsWith("\\+") || line.startsWith("\\-");
|
|
4243
|
+
if (escapedMarker) {
|
|
4244
|
+
return {
|
|
4245
|
+
kind: "normal",
|
|
4246
|
+
content: line.slice(1),
|
|
4247
|
+
contentOffset: 1,
|
|
4248
|
+
escapedMarker: true
|
|
4249
|
+
};
|
|
4250
|
+
}
|
|
4251
|
+
if (line.startsWith("+")) {
|
|
4252
|
+
return {
|
|
4253
|
+
kind: "addition",
|
|
4254
|
+
content: line.slice(1),
|
|
4255
|
+
contentOffset: 1,
|
|
4256
|
+
escapedMarker: false
|
|
4257
|
+
};
|
|
4258
|
+
}
|
|
4259
|
+
if (line.startsWith("-")) {
|
|
4260
|
+
return {
|
|
4261
|
+
kind: "deletion",
|
|
4262
|
+
content: line.slice(1),
|
|
4263
|
+
contentOffset: 1,
|
|
4264
|
+
escapedMarker: false
|
|
4265
|
+
};
|
|
4266
|
+
}
|
|
4267
|
+
return {
|
|
4268
|
+
kind: "normal",
|
|
4269
|
+
content: line,
|
|
4270
|
+
contentOffset: 0,
|
|
4271
|
+
escapedMarker: false
|
|
4272
|
+
};
|
|
4273
|
+
}
|
|
4274
|
+
computeChangedRanges(oldText, newText) {
|
|
4275
|
+
let prefix = 0;
|
|
4276
|
+
while (prefix < oldText.length && prefix < newText.length && oldText[prefix] === newText[prefix]) {
|
|
4277
|
+
prefix++;
|
|
4278
|
+
}
|
|
4279
|
+
let oldSuffix = oldText.length;
|
|
4280
|
+
let newSuffix = newText.length;
|
|
4281
|
+
while (oldSuffix > prefix && newSuffix > prefix && oldText[oldSuffix - 1] === newText[newSuffix - 1]) {
|
|
4282
|
+
oldSuffix--;
|
|
4283
|
+
newSuffix--;
|
|
4284
|
+
}
|
|
4285
|
+
const oldRanges = [];
|
|
4286
|
+
const newRanges = [];
|
|
4287
|
+
if (oldSuffix > prefix) {
|
|
4288
|
+
oldRanges.push([prefix, oldSuffix]);
|
|
4289
|
+
}
|
|
4290
|
+
if (newSuffix > prefix) {
|
|
4291
|
+
newRanges.push([prefix, newSuffix]);
|
|
4292
|
+
}
|
|
4293
|
+
return { oldRanges, newRanges };
|
|
4294
|
+
}
|
|
4295
|
+
renderDiffPreviewLine(diffState, highlightedContent) {
|
|
4296
|
+
const modClass = diffState.kind === "addition" ? "cm-draftly-code-diff-mod-add" : diffState.kind === "deletion" ? "cm-draftly-code-diff-mod-del" : "";
|
|
4297
|
+
const baseHighlightedContent = highlightedContent || this.escapeHtml(diffState.content);
|
|
4298
|
+
const contentHtml = diffState.modificationRanges && modClass ? this.applyRangesToHighlightedHTML(baseHighlightedContent, diffState.modificationRanges, modClass) : baseHighlightedContent;
|
|
4299
|
+
return contentHtml || " ";
|
|
4300
|
+
}
|
|
4301
|
+
applyRangesToHighlightedHTML(htmlContent, ranges, className) {
|
|
4302
|
+
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]);
|
|
4303
|
+
if (normalizedRanges.length === 0 || !htmlContent) {
|
|
4304
|
+
return htmlContent;
|
|
4305
|
+
}
|
|
4306
|
+
const isInsideRange = (position) => {
|
|
4307
|
+
for (const [start, end] of normalizedRanges) {
|
|
4308
|
+
if (position >= start && position < end) return true;
|
|
4309
|
+
if (position < start) return false;
|
|
4310
|
+
}
|
|
4311
|
+
return false;
|
|
4312
|
+
};
|
|
4313
|
+
let result = "";
|
|
4314
|
+
let htmlIndex = 0;
|
|
4315
|
+
let textPosition = 0;
|
|
4316
|
+
let markOpen = false;
|
|
4317
|
+
while (htmlIndex < htmlContent.length) {
|
|
4318
|
+
const char = htmlContent[htmlIndex];
|
|
4319
|
+
if (char === "<") {
|
|
4320
|
+
const tagEnd = htmlContent.indexOf(">", htmlIndex);
|
|
4321
|
+
if (tagEnd === -1) {
|
|
4322
|
+
result += htmlContent.slice(htmlIndex);
|
|
4323
|
+
break;
|
|
4324
|
+
}
|
|
4325
|
+
result += htmlContent.slice(htmlIndex, tagEnd + 1);
|
|
4326
|
+
htmlIndex = tagEnd + 1;
|
|
4327
|
+
continue;
|
|
4328
|
+
}
|
|
4329
|
+
let token = char;
|
|
4330
|
+
if (char === "&") {
|
|
4331
|
+
const entityEnd = htmlContent.indexOf(";", htmlIndex);
|
|
4332
|
+
if (entityEnd !== -1) {
|
|
4333
|
+
token = htmlContent.slice(htmlIndex, entityEnd + 1);
|
|
4334
|
+
htmlIndex = entityEnd + 1;
|
|
4335
|
+
} else {
|
|
4336
|
+
htmlIndex += 1;
|
|
4337
|
+
}
|
|
4338
|
+
} else {
|
|
4339
|
+
htmlIndex += 1;
|
|
4340
|
+
}
|
|
4341
|
+
const shouldMark = isInsideRange(textPosition);
|
|
4342
|
+
if (shouldMark && !markOpen) {
|
|
4343
|
+
result += `<mark class="${className}">`;
|
|
4344
|
+
markOpen = true;
|
|
4345
|
+
}
|
|
4346
|
+
if (!shouldMark && markOpen) {
|
|
4347
|
+
result += "</mark>";
|
|
4348
|
+
markOpen = false;
|
|
4349
|
+
}
|
|
4350
|
+
result += token;
|
|
4351
|
+
textPosition += 1;
|
|
4352
|
+
}
|
|
4353
|
+
if (markOpen) {
|
|
4354
|
+
result += "</mark>";
|
|
4355
|
+
}
|
|
4356
|
+
return result;
|
|
4357
|
+
}
|
|
2918
4358
|
/**
|
|
2919
4359
|
* Apply text highlights (regex patterns) to already syntax-highlighted HTML.
|
|
2920
4360
|
* Wraps matched patterns in `<mark>` elements.
|
|
2921
4361
|
*/
|
|
2922
|
-
applyTextHighlights(htmlContent, highlights) {
|
|
4362
|
+
applyTextHighlights(htmlContent, highlights, instanceCounters) {
|
|
2923
4363
|
let result = htmlContent;
|
|
2924
|
-
for (const highlight of highlights) {
|
|
4364
|
+
for (const [highlightIndex, highlight] of highlights.entries()) {
|
|
2925
4365
|
try {
|
|
2926
4366
|
const regex = new RegExp(`(${highlight.pattern})`, "g");
|
|
2927
|
-
let matchCount = 0;
|
|
4367
|
+
let matchCount = instanceCounters?.[highlightIndex] ?? 0;
|
|
2928
4368
|
result = result.replace(regex, (match) => {
|
|
2929
4369
|
matchCount++;
|
|
2930
4370
|
const shouldHighlight = !highlight.instances || highlight.instances.includes(matchCount);
|
|
@@ -2933,252 +4373,15 @@ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
2933
4373
|
}
|
|
2934
4374
|
return match;
|
|
2935
4375
|
});
|
|
4376
|
+
if (instanceCounters) {
|
|
4377
|
+
instanceCounters[highlightIndex] = matchCount;
|
|
4378
|
+
}
|
|
2936
4379
|
} catch {
|
|
2937
4380
|
}
|
|
2938
4381
|
}
|
|
2939
4382
|
return result;
|
|
2940
4383
|
}
|
|
2941
4384
|
};
|
|
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
4385
|
var quoteMarkDecorations = {
|
|
3183
4386
|
/** Decoration for the > marker */
|
|
3184
4387
|
"quote-mark": view.Decoration.replace({}),
|
|
@@ -3189,7 +4392,7 @@ var quoteLineDecorations = {
|
|
|
3189
4392
|
/** Decoration for blockquote lines */
|
|
3190
4393
|
"quote-line": view.Decoration.line({ class: "cm-draftly-quote-line" })
|
|
3191
4394
|
};
|
|
3192
|
-
var QuotePlugin = class extends
|
|
4395
|
+
var QuotePlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
3193
4396
|
name = "quote";
|
|
3194
4397
|
version = "1.0.0";
|
|
3195
4398
|
decorationPriority = 10;
|
|
@@ -3260,7 +4463,7 @@ var QuotePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
3260
4463
|
`;
|
|
3261
4464
|
}
|
|
3262
4465
|
};
|
|
3263
|
-
var theme11 =
|
|
4466
|
+
var theme11 = chunkTBVZEK2H_cjs.createTheme({
|
|
3264
4467
|
default: {
|
|
3265
4468
|
// Line styling with left border
|
|
3266
4469
|
".cm-draftly-quote-line": {
|
|
@@ -3279,7 +4482,7 @@ var theme11 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
3279
4482
|
});
|
|
3280
4483
|
var hrLineDecoration = view.Decoration.line({ class: "cm-draftly-hr-line" });
|
|
3281
4484
|
var hrMarkDecoration = view.Decoration.replace({});
|
|
3282
|
-
var HRPlugin = class extends
|
|
4485
|
+
var HRPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
3283
4486
|
name = "hr";
|
|
3284
4487
|
version = "1.0.0";
|
|
3285
4488
|
decorationPriority = 10;
|
|
@@ -3327,7 +4530,7 @@ var HRPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
|
|
|
3327
4530
|
`;
|
|
3328
4531
|
}
|
|
3329
4532
|
};
|
|
3330
|
-
var theme12 =
|
|
4533
|
+
var theme12 = chunkTBVZEK2H_cjs.createTheme({
|
|
3331
4534
|
default: {
|
|
3332
4535
|
// Line styling — displays a centered horizontal line
|
|
3333
4536
|
".cm-draftly-hr-line": {
|
|
@@ -3346,6 +4549,103 @@ var theme12 = chunkKDEDLC3D_cjs.createTheme({
|
|
|
3346
4549
|
}
|
|
3347
4550
|
}
|
|
3348
4551
|
});
|
|
4552
|
+
function shortcodeToEmoji(raw) {
|
|
4553
|
+
const rendered = emoji__namespace.emojify(raw);
|
|
4554
|
+
return rendered !== raw ? rendered : null;
|
|
4555
|
+
}
|
|
4556
|
+
var EmojiWidget = class extends view.WidgetType {
|
|
4557
|
+
constructor(rendered) {
|
|
4558
|
+
super();
|
|
4559
|
+
this.rendered = rendered;
|
|
4560
|
+
}
|
|
4561
|
+
eq(other) {
|
|
4562
|
+
return other.rendered === this.rendered;
|
|
4563
|
+
}
|
|
4564
|
+
toDOM() {
|
|
4565
|
+
const span = document.createElement("span");
|
|
4566
|
+
span.className = "cm-draftly-emoji";
|
|
4567
|
+
span.textContent = this.rendered;
|
|
4568
|
+
return span;
|
|
4569
|
+
}
|
|
4570
|
+
ignoreEvent() {
|
|
4571
|
+
return false;
|
|
4572
|
+
}
|
|
4573
|
+
};
|
|
4574
|
+
var emojiMarkDecorations = {
|
|
4575
|
+
"emoji-source": view.Decoration.mark({ class: "cm-draftly-emoji-source" })
|
|
4576
|
+
};
|
|
4577
|
+
var EmojiPlugin = class extends chunkBWJLMREN_cjs.DecorationPlugin {
|
|
4578
|
+
name = "emoji";
|
|
4579
|
+
version = "1.0.0";
|
|
4580
|
+
decorationPriority = 20;
|
|
4581
|
+
requiredNodes = ["Emoji", "EmojiMark"];
|
|
4582
|
+
constructor() {
|
|
4583
|
+
super();
|
|
4584
|
+
}
|
|
4585
|
+
/**
|
|
4586
|
+
* Plugin theme
|
|
4587
|
+
*/
|
|
4588
|
+
get theme() {
|
|
4589
|
+
return theme13;
|
|
4590
|
+
}
|
|
4591
|
+
/**
|
|
4592
|
+
* Build emoji decorations by iterating the syntax tree
|
|
4593
|
+
*/
|
|
4594
|
+
buildDecorations(ctx) {
|
|
4595
|
+
const { view: view$1, decorations } = ctx;
|
|
4596
|
+
const tree = language.syntaxTree(view$1.state);
|
|
4597
|
+
tree.iterate({
|
|
4598
|
+
enter: (node) => {
|
|
4599
|
+
const { from, to, name } = node;
|
|
4600
|
+
if (name !== "Emoji") {
|
|
4601
|
+
return;
|
|
4602
|
+
}
|
|
4603
|
+
const raw = view$1.state.sliceDoc(from, to);
|
|
4604
|
+
const rendered = shortcodeToEmoji(raw);
|
|
4605
|
+
if (!rendered) {
|
|
4606
|
+
return;
|
|
4607
|
+
}
|
|
4608
|
+
const cursorInNode = ctx.selectionOverlapsRange(from, to);
|
|
4609
|
+
if (cursorInNode) {
|
|
4610
|
+
decorations.push(emojiMarkDecorations["emoji-source"].range(from, to));
|
|
4611
|
+
return;
|
|
4612
|
+
}
|
|
4613
|
+
decorations.push(
|
|
4614
|
+
view.Decoration.replace({
|
|
4615
|
+
widget: new EmojiWidget(rendered)
|
|
4616
|
+
}).range(from, to)
|
|
4617
|
+
);
|
|
4618
|
+
}
|
|
4619
|
+
});
|
|
4620
|
+
}
|
|
4621
|
+
renderToHTML(node, children, ctx) {
|
|
4622
|
+
if (node.name === "EmojiMark") {
|
|
4623
|
+
return "";
|
|
4624
|
+
}
|
|
4625
|
+
if (node.name !== "Emoji") {
|
|
4626
|
+
return null;
|
|
4627
|
+
}
|
|
4628
|
+
const raw = ctx.sliceDoc(node.from, node.to);
|
|
4629
|
+
const rendered = shortcodeToEmoji(raw);
|
|
4630
|
+
if (!rendered) {
|
|
4631
|
+
return `<span class="cm-draftly-emoji-source">${children}</span>`;
|
|
4632
|
+
}
|
|
4633
|
+
return `<span class="cm-draftly-emoji">${rendered}</span>`;
|
|
4634
|
+
}
|
|
4635
|
+
};
|
|
4636
|
+
var theme13 = chunkTBVZEK2H_cjs.createTheme({
|
|
4637
|
+
default: {
|
|
4638
|
+
".cm-draftly-emoji": {
|
|
4639
|
+
fontFamily: '"Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif',
|
|
4640
|
+
fontVariantEmoji: "emoji",
|
|
4641
|
+
lineHeight: "1.2"
|
|
4642
|
+
},
|
|
4643
|
+
".cm-draftly-emoji-source": {
|
|
4644
|
+
fontFamily: "inherit",
|
|
4645
|
+
lineHeight: "inherit"
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
});
|
|
3349
4649
|
|
|
3350
4650
|
// src/plugins/index.ts
|
|
3351
4651
|
var essentialPlugins = [
|
|
@@ -3354,17 +4654,20 @@ var essentialPlugins = [
|
|
|
3354
4654
|
new InlinePlugin(),
|
|
3355
4655
|
new LinkPlugin(),
|
|
3356
4656
|
new ListPlugin(),
|
|
4657
|
+
new TablePlugin(),
|
|
3357
4658
|
new HTMLPlugin(),
|
|
3358
4659
|
new ImagePlugin(),
|
|
3359
4660
|
new MathPlugin(),
|
|
3360
4661
|
new MermaidPlugin(),
|
|
3361
4662
|
new CodePlugin(),
|
|
3362
4663
|
new QuotePlugin(),
|
|
3363
|
-
new HRPlugin()
|
|
4664
|
+
new HRPlugin(),
|
|
4665
|
+
new EmojiPlugin()
|
|
3364
4666
|
];
|
|
3365
4667
|
var allPlugins = [...essentialPlugins];
|
|
3366
4668
|
|
|
3367
4669
|
exports.CodePlugin = CodePlugin;
|
|
4670
|
+
exports.EmojiPlugin = EmojiPlugin;
|
|
3368
4671
|
exports.HRPlugin = HRPlugin;
|
|
3369
4672
|
exports.HTMLPlugin = HTMLPlugin;
|
|
3370
4673
|
exports.HeadingPlugin = HeadingPlugin;
|
|
@@ -3376,7 +4679,8 @@ exports.MathPlugin = MathPlugin;
|
|
|
3376
4679
|
exports.MermaidPlugin = MermaidPlugin;
|
|
3377
4680
|
exports.ParagraphPlugin = ParagraphPlugin;
|
|
3378
4681
|
exports.QuotePlugin = QuotePlugin;
|
|
4682
|
+
exports.TablePlugin = TablePlugin;
|
|
3379
4683
|
exports.allPlugins = allPlugins;
|
|
3380
4684
|
exports.essentialPlugins = essentialPlugins;
|
|
3381
|
-
//# sourceMappingURL=chunk-
|
|
3382
|
-
//# sourceMappingURL=chunk-
|
|
4685
|
+
//# sourceMappingURL=chunk-W5ALMXG2.cjs.map
|
|
4686
|
+
//# sourceMappingURL=chunk-W5ALMXG2.cjs.map
|