@blankdotpage/cake 0.1.1 → 0.1.3
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/dist/cake/clipboard.d.ts +1 -1
- package/dist/cake/core/runtime.d.ts +51 -13
- package/dist/cake/dom/render.d.ts +1 -1
- package/dist/cake/engine/cake-engine.d.ts +14 -0
- package/dist/cake/engine/selection/selection-geometry.d.ts +1 -0
- package/dist/cake/engine/selection/selection-layout-dom.d.ts +7 -0
- package/dist/cake/extensions/blockquote/blockquote.d.ts +1 -2
- package/dist/cake/extensions/bold/bold.d.ts +1 -2
- package/dist/cake/extensions/combined-emphasis/combined-emphasis.d.ts +1 -2
- package/dist/cake/extensions/heading/heading.d.ts +1 -2
- package/dist/cake/extensions/image/image.d.ts +1 -2
- package/dist/cake/extensions/index.d.ts +1 -0
- package/dist/cake/extensions/italic/italic.d.ts +1 -2
- package/dist/cake/extensions/link/link-popover.d.ts +6 -0
- package/dist/cake/extensions/link/link.d.ts +15 -2
- package/dist/cake/extensions/list/list.d.ts +11 -2
- package/dist/cake/extensions/pipe-link/pipe-link.d.ts +1 -2
- package/dist/cake/extensions/scrollbar/index.d.ts +1 -2
- package/dist/cake/extensions/strikethrough/strikethrough.d.ts +1 -2
- package/dist/cake/react/CakeEditor.d.ts +2 -0
- package/dist/cake/test/harness.d.ts +12 -0
- package/dist/index.cjs +1455 -422
- package/dist/index.js +1455 -422
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,44 +1,53 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require$$0 = require("react");
|
|
4
|
-
const reactDom = require("react-dom");
|
|
5
4
|
const lucideReact = require("lucide-react");
|
|
6
5
|
const TurndownService = require("turndown");
|
|
7
6
|
const state = require("@codemirror/state");
|
|
8
|
-
var
|
|
9
|
-
var
|
|
7
|
+
var jsxRuntime = { exports: {} };
|
|
8
|
+
var reactJsxRuntime_production_min = {};
|
|
10
9
|
/**
|
|
11
10
|
* @license React
|
|
12
|
-
* react-jsx-
|
|
11
|
+
* react-jsx-runtime.production.min.js
|
|
13
12
|
*
|
|
14
13
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
15
14
|
*
|
|
16
15
|
* This source code is licensed under the MIT license found in the
|
|
17
16
|
* LICENSE file in the root directory of this source tree.
|
|
18
17
|
*/
|
|
19
|
-
var
|
|
20
|
-
function
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
var
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
var hasRequiredReactJsxRuntime_production_min;
|
|
19
|
+
function requireReactJsxRuntime_production_min() {
|
|
20
|
+
if (hasRequiredReactJsxRuntime_production_min) return reactJsxRuntime_production_min;
|
|
21
|
+
hasRequiredReactJsxRuntime_production_min = 1;
|
|
22
|
+
var f = require$$0, k = Symbol.for("react.element"), l = Symbol.for("react.fragment"), m = Object.prototype.hasOwnProperty, n = f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner, p = { key: true, ref: true, __self: true, __source: true };
|
|
23
|
+
function q(c, a, g) {
|
|
24
|
+
var b, d = {}, e = null, h = null;
|
|
25
|
+
void 0 !== g && (e = "" + g);
|
|
26
|
+
void 0 !== a.key && (e = "" + a.key);
|
|
27
|
+
void 0 !== a.ref && (h = a.ref);
|
|
28
|
+
for (b in a) m.call(a, b) && !p.hasOwnProperty(b) && (d[b] = a[b]);
|
|
29
|
+
if (c && c.defaultProps) for (b in a = c.defaultProps, a) void 0 === d[b] && (d[b] = a[b]);
|
|
30
|
+
return { $$typeof: k, type: c, key: e, ref: h, props: d, _owner: n.current };
|
|
31
|
+
}
|
|
32
|
+
reactJsxRuntime_production_min.Fragment = l;
|
|
33
|
+
reactJsxRuntime_production_min.jsx = q;
|
|
34
|
+
reactJsxRuntime_production_min.jsxs = q;
|
|
35
|
+
return reactJsxRuntime_production_min;
|
|
36
|
+
}
|
|
37
|
+
var reactJsxRuntime_development = {};
|
|
29
38
|
/**
|
|
30
39
|
* @license React
|
|
31
|
-
* react-jsx-
|
|
40
|
+
* react-jsx-runtime.development.js
|
|
32
41
|
*
|
|
33
42
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
34
43
|
*
|
|
35
44
|
* This source code is licensed under the MIT license found in the
|
|
36
45
|
* LICENSE file in the root directory of this source tree.
|
|
37
46
|
*/
|
|
38
|
-
var
|
|
39
|
-
function
|
|
40
|
-
if (
|
|
41
|
-
|
|
47
|
+
var hasRequiredReactJsxRuntime_development;
|
|
48
|
+
function requireReactJsxRuntime_development() {
|
|
49
|
+
if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development;
|
|
50
|
+
hasRequiredReactJsxRuntime_development = 1;
|
|
42
51
|
if (process.env.NODE_ENV !== "production") {
|
|
43
52
|
(function() {
|
|
44
53
|
var React = require$$0;
|
|
@@ -525,10 +534,6 @@ function requireReactJsxDevRuntime_development() {
|
|
|
525
534
|
};
|
|
526
535
|
var specialPropKeyWarningShown;
|
|
527
536
|
var specialPropRefWarningShown;
|
|
528
|
-
var didWarnAboutStringRefs;
|
|
529
|
-
{
|
|
530
|
-
didWarnAboutStringRefs = {};
|
|
531
|
-
}
|
|
532
537
|
function hasValidRef(config) {
|
|
533
538
|
{
|
|
534
539
|
if (hasOwnProperty.call(config, "ref")) {
|
|
@@ -553,13 +558,7 @@ function requireReactJsxDevRuntime_development() {
|
|
|
553
558
|
}
|
|
554
559
|
function warnIfStringRefCannotBeAutoConverted(config, self) {
|
|
555
560
|
{
|
|
556
|
-
if (typeof config.ref === "string" && ReactCurrentOwner.current && self
|
|
557
|
-
var componentName = getComponentNameFromType(ReactCurrentOwner.current.type);
|
|
558
|
-
if (!didWarnAboutStringRefs[componentName]) {
|
|
559
|
-
error('Component "%s" contains the string ref "%s". Support for string refs will be removed in a future major release. This case cannot be automatically converted to an arrow function. We ask you to manually fix this case by using useRef() or createRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref', getComponentNameFromType(ReactCurrentOwner.current.type), config.ref);
|
|
560
|
-
didWarnAboutStringRefs[componentName] = true;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
561
|
+
if (typeof config.ref === "string" && ReactCurrentOwner.current && self) ;
|
|
563
562
|
}
|
|
564
563
|
}
|
|
565
564
|
function defineKeyPropWarningGetter(props, displayName) {
|
|
@@ -713,11 +712,6 @@ function requireReactJsxDevRuntime_development() {
|
|
|
713
712
|
}
|
|
714
713
|
function getSourceInfoErrorAddendum(source) {
|
|
715
714
|
{
|
|
716
|
-
if (source !== void 0) {
|
|
717
|
-
var fileName = source.fileName.replace(/^.*[\\\/]/, "");
|
|
718
|
-
var lineNumber = source.lineNumber;
|
|
719
|
-
return "\n\nCheck your code at " + fileName + ":" + lineNumber + ".";
|
|
720
|
-
}
|
|
721
715
|
return "";
|
|
722
716
|
}
|
|
723
717
|
}
|
|
@@ -843,7 +837,7 @@ function requireReactJsxDevRuntime_development() {
|
|
|
843
837
|
if (type === void 0 || typeof type === "object" && type !== null && Object.keys(type).length === 0) {
|
|
844
838
|
info += " You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.";
|
|
845
839
|
}
|
|
846
|
-
var sourceInfo = getSourceInfoErrorAddendum(
|
|
840
|
+
var sourceInfo = getSourceInfoErrorAddendum();
|
|
847
841
|
if (sourceInfo) {
|
|
848
842
|
info += sourceInfo;
|
|
849
843
|
} else {
|
|
@@ -907,19 +901,31 @@ function requireReactJsxDevRuntime_development() {
|
|
|
907
901
|
return element;
|
|
908
902
|
}
|
|
909
903
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
904
|
+
function jsxWithValidationStatic(type, props, key) {
|
|
905
|
+
{
|
|
906
|
+
return jsxWithValidation(type, props, key, true);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
function jsxWithValidationDynamic(type, props, key) {
|
|
910
|
+
{
|
|
911
|
+
return jsxWithValidation(type, props, key, false);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
var jsx = jsxWithValidationDynamic;
|
|
915
|
+
var jsxs = jsxWithValidationStatic;
|
|
916
|
+
reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE;
|
|
917
|
+
reactJsxRuntime_development.jsx = jsx;
|
|
918
|
+
reactJsxRuntime_development.jsxs = jsxs;
|
|
913
919
|
})();
|
|
914
920
|
}
|
|
915
|
-
return
|
|
921
|
+
return reactJsxRuntime_development;
|
|
916
922
|
}
|
|
917
923
|
if (process.env.NODE_ENV === "production") {
|
|
918
|
-
|
|
924
|
+
jsxRuntime.exports = requireReactJsxRuntime_production_min();
|
|
919
925
|
} else {
|
|
920
|
-
|
|
926
|
+
jsxRuntime.exports = requireReactJsxRuntime_development();
|
|
921
927
|
}
|
|
922
|
-
var
|
|
928
|
+
var jsxRuntimeExports = jsxRuntime.exports;
|
|
923
929
|
const graphemeSegmenter = new Intl.Segmenter(void 0, {
|
|
924
930
|
granularity: "grapheme"
|
|
925
931
|
});
|
|
@@ -993,15 +999,36 @@ class CursorSourceBuilder {
|
|
|
993
999
|
if (!text) {
|
|
994
1000
|
return;
|
|
995
1001
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1002
|
+
let isAllAscii = true;
|
|
1003
|
+
for (let i = 0; i < text.length; i++) {
|
|
1004
|
+
if (text.charCodeAt(i) >= 128) {
|
|
1005
|
+
isAllAscii = false;
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (isAllAscii) {
|
|
1010
|
+
for (let i = 0; i < text.length; i++) {
|
|
1011
|
+
const char = text[i];
|
|
1012
|
+
this.sourceParts.push(char);
|
|
1013
|
+
this.sourceLengthValue += 1;
|
|
1014
|
+
const sourceLength = this.sourceLengthValue;
|
|
1015
|
+
this.cursorLength += 1;
|
|
1016
|
+
this.boundaries.push({
|
|
1017
|
+
sourceBackward: sourceLength,
|
|
1018
|
+
sourceForward: sourceLength
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
for (const segment of graphemeSegments(text)) {
|
|
1023
|
+
this.sourceParts.push(segment.segment);
|
|
1024
|
+
this.sourceLengthValue += segment.segment.length;
|
|
1025
|
+
const sourceLength = this.sourceLengthValue;
|
|
1026
|
+
this.cursorLength += 1;
|
|
1027
|
+
this.boundaries.push({
|
|
1028
|
+
sourceBackward: sourceLength,
|
|
1029
|
+
sourceForward: sourceLength
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1005
1032
|
}
|
|
1006
1033
|
}
|
|
1007
1034
|
appendCursorAtom(sourceText, cursorUnits = 1) {
|
|
@@ -1051,6 +1078,15 @@ class CursorSourceBuilder {
|
|
|
1051
1078
|
};
|
|
1052
1079
|
}
|
|
1053
1080
|
}
|
|
1081
|
+
function isStructuralEdit(command) {
|
|
1082
|
+
return command.type === "insert" || command.type === "delete-backward" || command.type === "delete-forward" || command.type === "insert-line-break" || command.type === "exit-block-wrapper";
|
|
1083
|
+
}
|
|
1084
|
+
function isApplyEditCommand(command) {
|
|
1085
|
+
return command.type === "insert" || command.type === "insert-line-break" || command.type === "delete-backward" || command.type === "delete-forward";
|
|
1086
|
+
}
|
|
1087
|
+
function defineExtension(extension) {
|
|
1088
|
+
return extension;
|
|
1089
|
+
}
|
|
1054
1090
|
const defaultSelection$1 = { start: 0, end: 0, affinity: "forward" };
|
|
1055
1091
|
function createRuntime(extensions) {
|
|
1056
1092
|
const toggleMarkerToKind = /* @__PURE__ */ new Map();
|
|
@@ -1292,7 +1328,7 @@ function createRuntime(extensions) {
|
|
|
1292
1328
|
}
|
|
1293
1329
|
}
|
|
1294
1330
|
const selection = normalizeSelection$1(state2.selection);
|
|
1295
|
-
if (command
|
|
1331
|
+
if (isStructuralEdit(command)) {
|
|
1296
1332
|
const structural = applyStructuralEdit(command, state2.doc, selection);
|
|
1297
1333
|
if (!structural) {
|
|
1298
1334
|
if (command.type === "delete-backward" || command.type === "delete-forward") {
|
|
@@ -1334,6 +1370,39 @@ function createRuntime(extensions) {
|
|
|
1334
1370
|
}
|
|
1335
1371
|
};
|
|
1336
1372
|
}
|
|
1373
|
+
if (command.type === "insert" || command.type === "insert-line-break") {
|
|
1374
|
+
const cursorLength = state2.map.cursorLength;
|
|
1375
|
+
const cursorStart = Math.max(
|
|
1376
|
+
0,
|
|
1377
|
+
Math.min(cursorLength, Math.min(selection.start, selection.end))
|
|
1378
|
+
);
|
|
1379
|
+
const cursorEnd = Math.max(
|
|
1380
|
+
0,
|
|
1381
|
+
Math.min(cursorLength, Math.max(selection.start, selection.end))
|
|
1382
|
+
);
|
|
1383
|
+
const range = { start: cursorStart, end: cursorEnd };
|
|
1384
|
+
const fullDocReplace = range.start === 0 && range.end === cursorLength;
|
|
1385
|
+
const from = fullDocReplace ? 0 : state2.map.cursorToSource(range.start, "backward");
|
|
1386
|
+
const to = fullDocReplace ? state2.source.length : state2.map.cursorToSource(range.end, "forward");
|
|
1387
|
+
const fromClamped = Math.max(0, Math.min(from, state2.source.length));
|
|
1388
|
+
const toClamped = Math.max(
|
|
1389
|
+
fromClamped,
|
|
1390
|
+
Math.min(to, state2.source.length)
|
|
1391
|
+
);
|
|
1392
|
+
const insertText = command.type === "insert" ? command.text : "\n";
|
|
1393
|
+
const nextSource = state2.source.slice(0, fromClamped) + insertText + state2.source.slice(toClamped);
|
|
1394
|
+
const next2 = createState(nextSource);
|
|
1395
|
+
const caretSource2 = fromClamped + insertText.length;
|
|
1396
|
+
const caretCursor2 = next2.map.sourceToCursor(caretSource2, "forward");
|
|
1397
|
+
return {
|
|
1398
|
+
...next2,
|
|
1399
|
+
selection: {
|
|
1400
|
+
start: caretCursor2.cursorOffset,
|
|
1401
|
+
end: caretCursor2.cursorOffset,
|
|
1402
|
+
affinity: caretCursor2.affinity
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1337
1406
|
return state2;
|
|
1338
1407
|
}
|
|
1339
1408
|
const interim = createStateFromDoc(structural.doc);
|
|
@@ -2411,13 +2480,150 @@ function createRuntime(extensions) {
|
|
|
2411
2480
|
const endInLine = lineIndex === endLoc.lineIndex ? endLoc.offsetInLine : line.cursorLength;
|
|
2412
2481
|
const selectedRuns = sliceRuns(runs, startInLine, endInLine).selected;
|
|
2413
2482
|
const content = runsToInlines(normalizeRuns(selectedRuns));
|
|
2414
|
-
|
|
2483
|
+
const paragraph = { type: "paragraph", content };
|
|
2484
|
+
if (line.path.length > 1) {
|
|
2485
|
+
const wrapperPath = line.path.slice(0, -1);
|
|
2486
|
+
const wrapper = getBlockAtPath(state2.doc.blocks, wrapperPath);
|
|
2487
|
+
if (wrapper && wrapper.type === "block-wrapper") {
|
|
2488
|
+
blocks.push({
|
|
2489
|
+
type: "block-wrapper",
|
|
2490
|
+
kind: wrapper.kind,
|
|
2491
|
+
data: wrapper.data,
|
|
2492
|
+
blocks: [paragraph]
|
|
2493
|
+
});
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
blocks.push(paragraph);
|
|
2415
2498
|
}
|
|
2416
2499
|
const sliceDoc = {
|
|
2417
2500
|
blocks: blocks.length > 0 ? blocks : [{ type: "paragraph", content: [] }]
|
|
2418
2501
|
};
|
|
2419
2502
|
return serialize(normalize(sliceDoc)).source;
|
|
2420
2503
|
}
|
|
2504
|
+
function escapeHtml(text) {
|
|
2505
|
+
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2506
|
+
}
|
|
2507
|
+
function runsToHtml(runs) {
|
|
2508
|
+
var _a;
|
|
2509
|
+
let html = "";
|
|
2510
|
+
for (const run of runs) {
|
|
2511
|
+
let content = escapeHtml(run.text);
|
|
2512
|
+
const sortedMarks = [...run.marks].reverse();
|
|
2513
|
+
for (const mark of sortedMarks) {
|
|
2514
|
+
if (mark.kind === "bold") {
|
|
2515
|
+
content = `<strong>${content}</strong>`;
|
|
2516
|
+
} else if (mark.kind === "italic") {
|
|
2517
|
+
content = `<em>${content}</em>`;
|
|
2518
|
+
} else if (mark.kind === "strikethrough") {
|
|
2519
|
+
content = `<s>${content}</s>`;
|
|
2520
|
+
} else if (mark.kind === "link") {
|
|
2521
|
+
const url = ((_a = mark.data) == null ? void 0 : _a.url) ?? "";
|
|
2522
|
+
content = `<a href="${escapeHtml(url)}">${content}</a>`;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
html += content;
|
|
2526
|
+
}
|
|
2527
|
+
return html;
|
|
2528
|
+
}
|
|
2529
|
+
function serializeSelectionToHtml(state2, selection) {
|
|
2530
|
+
const normalized = normalizeSelection$1(selection);
|
|
2531
|
+
const lines = flattenDocToLines(state2.doc);
|
|
2532
|
+
const docCursorLength = cursorLengthForLines(lines);
|
|
2533
|
+
const cursorStart = Math.max(
|
|
2534
|
+
0,
|
|
2535
|
+
Math.min(docCursorLength, Math.min(normalized.start, normalized.end))
|
|
2536
|
+
);
|
|
2537
|
+
const cursorEnd = Math.max(
|
|
2538
|
+
0,
|
|
2539
|
+
Math.min(docCursorLength, Math.max(normalized.start, normalized.end))
|
|
2540
|
+
);
|
|
2541
|
+
if (cursorStart === cursorEnd) {
|
|
2542
|
+
return "";
|
|
2543
|
+
}
|
|
2544
|
+
const startLoc = resolveCursorToLine(lines, cursorStart);
|
|
2545
|
+
const endLoc = resolveCursorToLine(lines, cursorEnd);
|
|
2546
|
+
let html = "";
|
|
2547
|
+
let activeList = null;
|
|
2548
|
+
const closeList = () => {
|
|
2549
|
+
if (activeList) {
|
|
2550
|
+
html += `</${activeList.type}>`;
|
|
2551
|
+
activeList = null;
|
|
2552
|
+
}
|
|
2553
|
+
};
|
|
2554
|
+
const openList = (type, indent) => {
|
|
2555
|
+
if (activeList && activeList.type === type && activeList.indent === indent) {
|
|
2556
|
+
return;
|
|
2557
|
+
}
|
|
2558
|
+
closeList();
|
|
2559
|
+
html += `<${type}>`;
|
|
2560
|
+
activeList = { type, indent };
|
|
2561
|
+
};
|
|
2562
|
+
for (let lineIndex = startLoc.lineIndex; lineIndex <= endLoc.lineIndex; lineIndex += 1) {
|
|
2563
|
+
const line = lines[lineIndex];
|
|
2564
|
+
if (!line) {
|
|
2565
|
+
continue;
|
|
2566
|
+
}
|
|
2567
|
+
const block = getBlockAtPath(state2.doc.blocks, line.path);
|
|
2568
|
+
if (!block || block.type !== "paragraph") {
|
|
2569
|
+
continue;
|
|
2570
|
+
}
|
|
2571
|
+
const runs = paragraphToRuns(block);
|
|
2572
|
+
const startInLine = lineIndex === startLoc.lineIndex ? startLoc.offsetInLine : 0;
|
|
2573
|
+
const endInLine = lineIndex === endLoc.lineIndex ? endLoc.offsetInLine : line.cursorLength;
|
|
2574
|
+
const selectedRuns = sliceRuns(runs, startInLine, endInLine).selected;
|
|
2575
|
+
let wrapperKind = null;
|
|
2576
|
+
let wrapperData;
|
|
2577
|
+
if (line.path.length > 1) {
|
|
2578
|
+
const wrapperPath = line.path.slice(0, -1);
|
|
2579
|
+
const wrapper = getBlockAtPath(state2.doc.blocks, wrapperPath);
|
|
2580
|
+
if (wrapper && wrapper.type === "block-wrapper") {
|
|
2581
|
+
wrapperKind = wrapper.kind;
|
|
2582
|
+
wrapperData = wrapper.data;
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
const plainText = runs.map((r) => r.text).join("");
|
|
2586
|
+
const listMatch = plainText.match(/^(\s*)([-*+]|\d+\.)( )(.*)$/);
|
|
2587
|
+
let lineHtml;
|
|
2588
|
+
if (listMatch && !wrapperKind) {
|
|
2589
|
+
const prefixLength = listMatch[1].length + listMatch[2].length + listMatch[3].length;
|
|
2590
|
+
const contentRuns = sliceRuns(runs, prefixLength, runs.reduce((sum, r) => sum + r.text.length, 0)).selected;
|
|
2591
|
+
lineHtml = runsToHtml(normalizeRuns(contentRuns));
|
|
2592
|
+
} else {
|
|
2593
|
+
lineHtml = runsToHtml(normalizeRuns(selectedRuns));
|
|
2594
|
+
}
|
|
2595
|
+
if (wrapperKind === "heading") {
|
|
2596
|
+
closeList();
|
|
2597
|
+
const level = Math.min(
|
|
2598
|
+
(wrapperData == null ? void 0 : wrapperData.level) ?? 1,
|
|
2599
|
+
6
|
|
2600
|
+
);
|
|
2601
|
+
html += `<h${level} style="margin:0">${lineHtml}</h${level}>`;
|
|
2602
|
+
} else if (wrapperKind === "bullet-list") {
|
|
2603
|
+
openList("ul", 0);
|
|
2604
|
+
html += `<li>${lineHtml}</li>`;
|
|
2605
|
+
} else if (wrapperKind === "numbered-list") {
|
|
2606
|
+
openList("ol", 0);
|
|
2607
|
+
html += `<li>${lineHtml}</li>`;
|
|
2608
|
+
} else if (wrapperKind === "blockquote") {
|
|
2609
|
+
closeList();
|
|
2610
|
+
html += `<blockquote>${lineHtml}</blockquote>`;
|
|
2611
|
+
} else if (listMatch) {
|
|
2612
|
+
const isNumbered = /^\d+\.$/.test(listMatch[2]);
|
|
2613
|
+
const indent = Math.floor(listMatch[1].length / 2);
|
|
2614
|
+
openList(isNumbered ? "ol" : "ul", indent);
|
|
2615
|
+
html += `<li>${lineHtml}</li>`;
|
|
2616
|
+
} else {
|
|
2617
|
+
closeList();
|
|
2618
|
+
html += `<div>${lineHtml}</div>`;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
closeList();
|
|
2622
|
+
if (!html) {
|
|
2623
|
+
return "";
|
|
2624
|
+
}
|
|
2625
|
+
return `<div>${html}</div>`;
|
|
2626
|
+
}
|
|
2421
2627
|
const runtime = {
|
|
2422
2628
|
extensions,
|
|
2423
2629
|
parse,
|
|
@@ -2425,6 +2631,7 @@ function createRuntime(extensions) {
|
|
|
2425
2631
|
createState,
|
|
2426
2632
|
updateSelection,
|
|
2427
2633
|
serializeSelection,
|
|
2634
|
+
serializeSelectionToHtml,
|
|
2428
2635
|
applyEdit
|
|
2429
2636
|
};
|
|
2430
2637
|
return runtime;
|
|
@@ -2438,7 +2645,20 @@ function parseLiteralBlock(source, start, context) {
|
|
|
2438
2645
|
return { block: { type: "paragraph", content }, nextPos: end };
|
|
2439
2646
|
}
|
|
2440
2647
|
function parseLiteralInline(source, start, end) {
|
|
2441
|
-
const
|
|
2648
|
+
const code = source.charCodeAt(start);
|
|
2649
|
+
if (code < 128) {
|
|
2650
|
+
const text2 = source[start] ?? "";
|
|
2651
|
+
return { inline: { type: "text", text: text2 }, nextPos: start + 1 };
|
|
2652
|
+
}
|
|
2653
|
+
if (code >= 55296 && code <= 56319) {
|
|
2654
|
+
const lowCode = source.charCodeAt(start + 1);
|
|
2655
|
+
if (lowCode >= 56320 && lowCode <= 57343) {
|
|
2656
|
+
const segment2 = graphemeSegments(source.slice(start, Math.min(start + 10, end)))[0];
|
|
2657
|
+
const text2 = segment2 ? segment2.segment : source.slice(start, start + 2);
|
|
2658
|
+
return { inline: { type: "text", text: text2 }, nextPos: start + text2.length };
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
const segment = graphemeSegments(source.slice(start, Math.min(start + 10, end)))[0];
|
|
2442
2662
|
const text = segment ? segment.segment : source[start] ?? "";
|
|
2443
2663
|
return { inline: { type: "text", text }, nextPos: start + text.length };
|
|
2444
2664
|
}
|
|
@@ -2481,29 +2701,66 @@ function normalizeSelection$1(selection) {
|
|
|
2481
2701
|
affinity: isRange ? "backward" : selection.affinity
|
|
2482
2702
|
};
|
|
2483
2703
|
}
|
|
2704
|
+
const graphemeCache = /* @__PURE__ */ new WeakMap();
|
|
2484
2705
|
function createTextRun(node, cursorStart) {
|
|
2485
|
-
const
|
|
2706
|
+
const data = node.data;
|
|
2707
|
+
const cached = graphemeCache.get(node);
|
|
2708
|
+
if (cached && cached.data === data) {
|
|
2709
|
+
const segmentCount = Math.max(0, cached.boundaryOffsets.length - 1);
|
|
2710
|
+
return {
|
|
2711
|
+
node,
|
|
2712
|
+
cursorStart,
|
|
2713
|
+
cursorEnd: cursorStart + segmentCount,
|
|
2714
|
+
boundaryOffsets: cached.boundaryOffsets
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
const segments = graphemeSegments(data);
|
|
2486
2718
|
const boundaryOffsets = [0];
|
|
2487
2719
|
for (const segment of segments) {
|
|
2488
2720
|
boundaryOffsets.push(segment.index + segment.segment.length);
|
|
2489
2721
|
}
|
|
2490
2722
|
const cursorEnd = cursorStart + segments.length;
|
|
2723
|
+
graphemeCache.set(node, { data, boundaryOffsets });
|
|
2491
2724
|
return { node, cursorStart, cursorEnd, boundaryOffsets };
|
|
2492
2725
|
}
|
|
2493
2726
|
function boundaryIndexForOffset(boundaryOffsets, offset) {
|
|
2494
2727
|
if (offset <= 0) {
|
|
2495
2728
|
return 0;
|
|
2496
2729
|
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2730
|
+
const lastIndex = boundaryOffsets.length - 1;
|
|
2731
|
+
if (lastIndex <= 0) {
|
|
2732
|
+
return 0;
|
|
2733
|
+
}
|
|
2734
|
+
const lastBoundary = boundaryOffsets[lastIndex];
|
|
2735
|
+
if (offset >= lastBoundary) {
|
|
2736
|
+
return lastIndex;
|
|
2737
|
+
}
|
|
2738
|
+
let low = 1;
|
|
2739
|
+
let high = lastIndex;
|
|
2740
|
+
while (low < high) {
|
|
2741
|
+
const mid = low + high >>> 1;
|
|
2742
|
+
const boundary2 = boundaryOffsets[mid];
|
|
2743
|
+
if (boundary2 < offset) {
|
|
2744
|
+
low = mid + 1;
|
|
2745
|
+
} else {
|
|
2746
|
+
high = mid;
|
|
2501
2747
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2748
|
+
}
|
|
2749
|
+
const boundary = boundaryOffsets[low];
|
|
2750
|
+
return boundary === offset ? low : low - 1;
|
|
2751
|
+
}
|
|
2752
|
+
function firstRunStartingAfterCursor(runs, cursorOffset) {
|
|
2753
|
+
let low = 0;
|
|
2754
|
+
let high = runs.length;
|
|
2755
|
+
while (low < high) {
|
|
2756
|
+
const mid = low + high >>> 1;
|
|
2757
|
+
if (runs[mid].cursorStart <= cursorOffset) {
|
|
2758
|
+
low = mid + 1;
|
|
2759
|
+
} else {
|
|
2760
|
+
high = mid;
|
|
2504
2761
|
}
|
|
2505
2762
|
}
|
|
2506
|
-
return
|
|
2763
|
+
return low;
|
|
2507
2764
|
}
|
|
2508
2765
|
function createDomMap(runs) {
|
|
2509
2766
|
const runForNode = /* @__PURE__ */ new Map();
|
|
@@ -2518,33 +2775,34 @@ function createDomMap(runs) {
|
|
|
2518
2775
|
if (runs.length === 0) {
|
|
2519
2776
|
return null;
|
|
2520
2777
|
}
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
const
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
if (cursorOffset === run.cursorEnd && affinity === "forward" && next && next.cursorStart === cursorOffset) {
|
|
2540
|
-
return { node: next.node, offset: next.boundaryOffsets[0] };
|
|
2541
|
-
}
|
|
2542
|
-
const index = Math.max(0, cursorOffset - run.cursorStart);
|
|
2543
|
-
const boundedIndex = Math.min(index, run.boundaryOffsets.length - 1);
|
|
2544
|
-
return { node: run.node, offset: run.boundaryOffsets[boundedIndex] };
|
|
2778
|
+
const nextIndex = firstRunStartingAfterCursor(runs, cursorOffset);
|
|
2779
|
+
const runIndex = nextIndex - 1;
|
|
2780
|
+
if (runIndex < 0) {
|
|
2781
|
+
const first = runs[0];
|
|
2782
|
+
return { node: first.node, offset: first.boundaryOffsets[0] };
|
|
2783
|
+
}
|
|
2784
|
+
const run = runs[runIndex];
|
|
2785
|
+
const previous = runIndex > 0 ? runs[runIndex - 1] : null;
|
|
2786
|
+
const next = nextIndex < runs.length ? runs[nextIndex] : null;
|
|
2787
|
+
if (cursorOffset === run.cursorStart && previous && affinity === "backward") {
|
|
2788
|
+
return {
|
|
2789
|
+
node: previous.node,
|
|
2790
|
+
offset: previous.boundaryOffsets[previous.boundaryOffsets.length - 1]
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
if (cursorOffset <= run.cursorEnd) {
|
|
2794
|
+
if (cursorOffset === run.cursorEnd && affinity === "forward" && next && next.cursorStart === cursorOffset) {
|
|
2795
|
+
return { node: next.node, offset: next.boundaryOffsets[0] };
|
|
2545
2796
|
}
|
|
2797
|
+
const index = Math.max(0, cursorOffset - run.cursorStart);
|
|
2798
|
+
const boundedIndex = Math.min(index, run.boundaryOffsets.length - 1);
|
|
2799
|
+
return { node: run.node, offset: run.boundaryOffsets[boundedIndex] };
|
|
2546
2800
|
}
|
|
2547
|
-
|
|
2801
|
+
if (next) {
|
|
2802
|
+
const runEndOffset = run.boundaryOffsets[run.boundaryOffsets.length - 1];
|
|
2803
|
+
return affinity === "backward" ? { node: run.node, offset: runEndOffset } : { node: next.node, offset: next.boundaryOffsets[0] };
|
|
2804
|
+
}
|
|
2805
|
+
const last = run;
|
|
2548
2806
|
return {
|
|
2549
2807
|
node: last.node,
|
|
2550
2808
|
offset: last.boundaryOffsets[last.boundaryOffsets.length - 1]
|
|
@@ -2579,7 +2837,7 @@ function normalizeNodes(result) {
|
|
|
2579
2837
|
}
|
|
2580
2838
|
return Array.isArray(result) ? result : [result];
|
|
2581
2839
|
}
|
|
2582
|
-
function renderDocContent(doc, extensions,
|
|
2840
|
+
function renderDocContent(doc, extensions, root) {
|
|
2583
2841
|
const runs = [];
|
|
2584
2842
|
let cursorOffset = 0;
|
|
2585
2843
|
let lineIndex = 0;
|
|
@@ -2599,7 +2857,60 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2599
2857
|
lineIndex += 1;
|
|
2600
2858
|
}
|
|
2601
2859
|
};
|
|
2602
|
-
function
|
|
2860
|
+
function getBlockKey(block) {
|
|
2861
|
+
if (block.type === "paragraph") {
|
|
2862
|
+
return "paragraph";
|
|
2863
|
+
}
|
|
2864
|
+
if (block.type === "block-wrapper") {
|
|
2865
|
+
return `block-wrapper:${block.kind}`;
|
|
2866
|
+
}
|
|
2867
|
+
if (block.type === "block-atom") {
|
|
2868
|
+
return `block-atom:${block.kind}`;
|
|
2869
|
+
}
|
|
2870
|
+
return "unknown";
|
|
2871
|
+
}
|
|
2872
|
+
function getElementKey(element) {
|
|
2873
|
+
if (element.hasAttribute("data-block")) {
|
|
2874
|
+
const blockType = element.getAttribute("data-block") ?? "unknown";
|
|
2875
|
+
const lineKind = element instanceof HTMLElement ? element.dataset.lineKind : null;
|
|
2876
|
+
if (lineKind && lineKind !== blockType) {
|
|
2877
|
+
return lineKind;
|
|
2878
|
+
}
|
|
2879
|
+
return blockType;
|
|
2880
|
+
}
|
|
2881
|
+
if (element.hasAttribute("data-block-wrapper")) {
|
|
2882
|
+
return `block-wrapper:${element.getAttribute("data-block-wrapper")}`;
|
|
2883
|
+
}
|
|
2884
|
+
if (element.hasAttribute("data-block-atom")) {
|
|
2885
|
+
return `block-atom:${element.getAttribute("data-block-atom")}`;
|
|
2886
|
+
}
|
|
2887
|
+
return "unknown";
|
|
2888
|
+
}
|
|
2889
|
+
function getInlineKey(inline) {
|
|
2890
|
+
if (inline.type === "text") {
|
|
2891
|
+
return "text";
|
|
2892
|
+
}
|
|
2893
|
+
if (inline.type === "inline-wrapper") {
|
|
2894
|
+
return `inline-wrapper:${inline.kind}`;
|
|
2895
|
+
}
|
|
2896
|
+
if (inline.type === "inline-atom") {
|
|
2897
|
+
return `inline-atom:${inline.kind}`;
|
|
2898
|
+
}
|
|
2899
|
+
return "unknown";
|
|
2900
|
+
}
|
|
2901
|
+
function getInlineElementKey(element) {
|
|
2902
|
+
if (element.classList.contains("cake-text")) {
|
|
2903
|
+
return "text";
|
|
2904
|
+
}
|
|
2905
|
+
if (element.hasAttribute("data-inline")) {
|
|
2906
|
+
return `inline-wrapper:${element.getAttribute("data-inline")}`;
|
|
2907
|
+
}
|
|
2908
|
+
if (element.hasAttribute("data-inline-atom")) {
|
|
2909
|
+
return `inline-atom:${element.getAttribute("data-inline-atom")}`;
|
|
2910
|
+
}
|
|
2911
|
+
return "unknown";
|
|
2912
|
+
}
|
|
2913
|
+
function reconcileInline(inline, existing) {
|
|
2603
2914
|
for (const extension of extensions) {
|
|
2604
2915
|
const render = extension.renderInline;
|
|
2605
2916
|
if (!render) {
|
|
@@ -2611,6 +2922,17 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2611
2922
|
}
|
|
2612
2923
|
}
|
|
2613
2924
|
if (inline.type === "text") {
|
|
2925
|
+
const canReuse = existing && existing instanceof HTMLSpanElement && getInlineElementKey(existing) === "text";
|
|
2926
|
+
if (canReuse) {
|
|
2927
|
+
const textNode = existing.firstChild;
|
|
2928
|
+
if (textNode instanceof Text) {
|
|
2929
|
+
if (textNode.textContent !== inline.text) {
|
|
2930
|
+
textNode.textContent = inline.text;
|
|
2931
|
+
}
|
|
2932
|
+
createTextRun$1(textNode);
|
|
2933
|
+
return [existing];
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2614
2936
|
const element = document.createElement("span");
|
|
2615
2937
|
element.className = "cake-text";
|
|
2616
2938
|
const node = document.createTextNode(inline.text);
|
|
@@ -2619,16 +2941,29 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2619
2941
|
return [element];
|
|
2620
2942
|
}
|
|
2621
2943
|
if (inline.type === "inline-wrapper") {
|
|
2944
|
+
const canReuse = existing && existing instanceof HTMLSpanElement && getInlineElementKey(existing) === getInlineKey(inline);
|
|
2945
|
+
if (canReuse) {
|
|
2946
|
+
reconcileInlineChildren(existing, inline.children);
|
|
2947
|
+
return [existing];
|
|
2948
|
+
}
|
|
2622
2949
|
const element = document.createElement("span");
|
|
2623
2950
|
element.setAttribute("data-inline", inline.kind);
|
|
2624
2951
|
for (const child of inline.children) {
|
|
2625
|
-
for (const node of
|
|
2952
|
+
for (const node of reconcileInline(child, null)) {
|
|
2626
2953
|
element.append(node);
|
|
2627
2954
|
}
|
|
2628
2955
|
}
|
|
2629
2956
|
return [element];
|
|
2630
2957
|
}
|
|
2631
2958
|
if (inline.type === "inline-atom") {
|
|
2959
|
+
const canReuse = existing && existing instanceof HTMLSpanElement && getInlineElementKey(existing) === getInlineKey(inline);
|
|
2960
|
+
if (canReuse) {
|
|
2961
|
+
const textNode = existing.firstChild;
|
|
2962
|
+
if (textNode instanceof Text) {
|
|
2963
|
+
createTextRun$1(textNode);
|
|
2964
|
+
return [existing];
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2632
2967
|
const element = document.createElement("span");
|
|
2633
2968
|
element.setAttribute("data-inline-atom", inline.kind);
|
|
2634
2969
|
const node = document.createTextNode(" ");
|
|
@@ -2638,7 +2973,25 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2638
2973
|
}
|
|
2639
2974
|
return [];
|
|
2640
2975
|
}
|
|
2641
|
-
function
|
|
2976
|
+
function reconcileInlineChildren(parent, inlines) {
|
|
2977
|
+
const mergedInlines = mergeInlineForRender(inlines);
|
|
2978
|
+
const existingChildren2 = Array.from(parent.children);
|
|
2979
|
+
const newChildren = [];
|
|
2980
|
+
mergedInlines.forEach((inline, i) => {
|
|
2981
|
+
const existingChild = existingChildren2[i] ?? null;
|
|
2982
|
+
const canReuse = existingChild && getInlineElementKey(existingChild) === getInlineKey(inline);
|
|
2983
|
+
const nodes = reconcileInline(inline, canReuse ? existingChild : null);
|
|
2984
|
+
newChildren.push(...nodes);
|
|
2985
|
+
});
|
|
2986
|
+
if (newChildren.length === existingChildren2.length && newChildren.every((node, i) => node === existingChildren2[i])) {
|
|
2987
|
+
return;
|
|
2988
|
+
}
|
|
2989
|
+
parent.replaceChildren(...newChildren);
|
|
2990
|
+
}
|
|
2991
|
+
function renderInline(inline) {
|
|
2992
|
+
return reconcileInline(inline, null);
|
|
2993
|
+
}
|
|
2994
|
+
function reconcileBlock(block, existing) {
|
|
2642
2995
|
for (const extension of extensions) {
|
|
2643
2996
|
const render = extension.renderBlock;
|
|
2644
2997
|
if (!render) {
|
|
@@ -2650,12 +3003,35 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2650
3003
|
}
|
|
2651
3004
|
}
|
|
2652
3005
|
if (block.type === "paragraph") {
|
|
3006
|
+
const canReuse = existing && existing instanceof HTMLDivElement && getElementKey(existing) === "paragraph";
|
|
3007
|
+
const currentLineIndex = context.getLineIndex();
|
|
3008
|
+
context.incrementLineIndex();
|
|
3009
|
+
if (canReuse) {
|
|
3010
|
+
existing.setAttribute("data-line-index", String(currentLineIndex));
|
|
3011
|
+
if (block.content.length === 0) {
|
|
3012
|
+
const firstChild = existing.firstChild;
|
|
3013
|
+
if (firstChild instanceof Text && existing.querySelector("br")) {
|
|
3014
|
+
if (firstChild.textContent !== "") {
|
|
3015
|
+
firstChild.textContent = "";
|
|
3016
|
+
}
|
|
3017
|
+
createTextRun$1(firstChild);
|
|
3018
|
+
return [existing];
|
|
3019
|
+
}
|
|
3020
|
+
existing.replaceChildren();
|
|
3021
|
+
const textNode = document.createTextNode("");
|
|
3022
|
+
createTextRun$1(textNode);
|
|
3023
|
+
existing.append(textNode);
|
|
3024
|
+
existing.append(document.createElement("br"));
|
|
3025
|
+
return [existing];
|
|
3026
|
+
}
|
|
3027
|
+
reconcileInlineChildren(existing, block.content);
|
|
3028
|
+
return [existing];
|
|
3029
|
+
}
|
|
2653
3030
|
const element = document.createElement("div");
|
|
2654
3031
|
element.setAttribute("data-block", "paragraph");
|
|
2655
|
-
element.setAttribute("data-line-index", String(
|
|
3032
|
+
element.setAttribute("data-line-index", String(currentLineIndex));
|
|
2656
3033
|
element.classList.add("cake-line");
|
|
2657
3034
|
element.dataset.lineKind = "paragraph";
|
|
2658
|
-
context.incrementLineIndex();
|
|
2659
3035
|
if (block.content.length === 0) {
|
|
2660
3036
|
const textNode = document.createTextNode("");
|
|
2661
3037
|
createTextRun$1(textNode);
|
|
@@ -2664,7 +3040,7 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2664
3040
|
} else {
|
|
2665
3041
|
const mergedContent = mergeInlineForRender(block.content);
|
|
2666
3042
|
for (const inline of mergedContent) {
|
|
2667
|
-
for (const node of
|
|
3043
|
+
for (const node of reconcileInline(inline, null)) {
|
|
2668
3044
|
element.append(node);
|
|
2669
3045
|
}
|
|
2670
3046
|
}
|
|
@@ -2672,6 +3048,11 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2672
3048
|
return [element];
|
|
2673
3049
|
}
|
|
2674
3050
|
if (block.type === "block-wrapper") {
|
|
3051
|
+
const canReuse = existing && existing instanceof HTMLDivElement && getElementKey(existing) === getBlockKey(block);
|
|
3052
|
+
if (canReuse) {
|
|
3053
|
+
reconcileBlockChildren(existing, block.blocks);
|
|
3054
|
+
return [existing];
|
|
3055
|
+
}
|
|
2675
3056
|
const element = document.createElement("div");
|
|
2676
3057
|
element.setAttribute("data-block-wrapper", block.kind);
|
|
2677
3058
|
for (const node of renderBlocks(block.blocks)) {
|
|
@@ -2680,15 +3061,41 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2680
3061
|
return [element];
|
|
2681
3062
|
}
|
|
2682
3063
|
if (block.type === "block-atom") {
|
|
3064
|
+
const canReuse = existing && existing instanceof HTMLDivElement && getElementKey(existing) === getBlockKey(block);
|
|
3065
|
+
const currentLineIndex = context.getLineIndex();
|
|
3066
|
+
context.incrementLineIndex();
|
|
3067
|
+
if (canReuse) {
|
|
3068
|
+
existing.setAttribute("data-line-index", String(currentLineIndex));
|
|
3069
|
+
return [existing];
|
|
3070
|
+
}
|
|
2683
3071
|
const element = document.createElement("div");
|
|
2684
3072
|
element.setAttribute("data-block-atom", block.kind);
|
|
2685
|
-
element.setAttribute("data-line-index", String(
|
|
3073
|
+
element.setAttribute("data-line-index", String(currentLineIndex));
|
|
2686
3074
|
element.classList.add("cake-line");
|
|
2687
|
-
context.incrementLineIndex();
|
|
2688
3075
|
return [element];
|
|
2689
3076
|
}
|
|
2690
3077
|
return [];
|
|
2691
3078
|
}
|
|
3079
|
+
function reconcileBlockChildren(parent, blocks) {
|
|
3080
|
+
const existingChildren2 = Array.from(parent.children);
|
|
3081
|
+
const newChildren = [];
|
|
3082
|
+
blocks.forEach((block, index) => {
|
|
3083
|
+
const existingChild = existingChildren2[index] ?? null;
|
|
3084
|
+
const canReuse = existingChild && getElementKey(existingChild) === getBlockKey(block);
|
|
3085
|
+
const nodes = reconcileBlock(block, canReuse ? existingChild : null);
|
|
3086
|
+
newChildren.push(...nodes);
|
|
3087
|
+
if (index < blocks.length - 1) {
|
|
3088
|
+
cursorOffset += 1;
|
|
3089
|
+
}
|
|
3090
|
+
});
|
|
3091
|
+
if (newChildren.length === existingChildren2.length && newChildren.every((node, i) => node === existingChildren2[i])) {
|
|
3092
|
+
return;
|
|
3093
|
+
}
|
|
3094
|
+
parent.replaceChildren(...newChildren);
|
|
3095
|
+
}
|
|
3096
|
+
function renderBlock(block) {
|
|
3097
|
+
return reconcileBlock(block, null);
|
|
3098
|
+
}
|
|
2692
3099
|
function renderBlocks(blocks) {
|
|
2693
3100
|
const nodes = [];
|
|
2694
3101
|
blocks.forEach((block, index) => {
|
|
@@ -2699,10 +3106,17 @@ function renderDocContent(doc, extensions, _root) {
|
|
|
2699
3106
|
});
|
|
2700
3107
|
return nodes;
|
|
2701
3108
|
}
|
|
3109
|
+
const existingChildren = root ? Array.from(root.children) : [];
|
|
2702
3110
|
const contentNodes = [];
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
3111
|
+
doc.blocks.forEach((block, index) => {
|
|
3112
|
+
const existingChild = existingChildren[index] ?? null;
|
|
3113
|
+
const canReuse = existingChild && getElementKey(existingChild) === getBlockKey(block);
|
|
3114
|
+
const nodes = reconcileBlock(block, canReuse ? existingChild : null);
|
|
3115
|
+
contentNodes.push(...nodes);
|
|
3116
|
+
if (index < doc.blocks.length - 1) {
|
|
3117
|
+
cursorOffset += 1;
|
|
3118
|
+
}
|
|
3119
|
+
});
|
|
2706
3120
|
return { content: contentNodes, map: createDomMap(runs) };
|
|
2707
3121
|
}
|
|
2708
3122
|
function mergeInlineForRender(inlines) {
|
|
@@ -2776,7 +3190,9 @@ function applyDomSelection(selection, map) {
|
|
|
2776
3190
|
if (!anchorPoint || !focusPoint) {
|
|
2777
3191
|
return;
|
|
2778
3192
|
}
|
|
2779
|
-
domSelection.
|
|
3193
|
+
if (domSelection.rangeCount > 0 && domSelection.anchorNode === anchorPoint.node && domSelection.anchorOffset === anchorPoint.offset && domSelection.focusNode === focusPoint.node && domSelection.focusOffset === focusPoint.offset) {
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
2780
3196
|
if (isCollapsed) {
|
|
2781
3197
|
domSelection.collapse(anchorPoint.node, anchorPoint.offset);
|
|
2782
3198
|
return;
|
|
@@ -2796,6 +3212,7 @@ function applyDomSelection(selection, map) {
|
|
|
2796
3212
|
domSelection.extend(focusPoint.node, focusPoint.offset);
|
|
2797
3213
|
return;
|
|
2798
3214
|
}
|
|
3215
|
+
domSelection.removeAllRanges();
|
|
2799
3216
|
const range = document.createRange();
|
|
2800
3217
|
const rangeStart = isForward ? anchorPoint : focusPoint;
|
|
2801
3218
|
const rangeEnd = isForward ? focusPoint : anchorPoint;
|
|
@@ -2939,7 +3356,7 @@ function findTextNodeAtOrBefore$1(nodes, start) {
|
|
|
2939
3356
|
return null;
|
|
2940
3357
|
}
|
|
2941
3358
|
const BOLD_KIND$1 = "bold";
|
|
2942
|
-
const boldExtension = {
|
|
3359
|
+
const boldExtension = defineExtension({
|
|
2943
3360
|
name: "bold",
|
|
2944
3361
|
toggleInline: { kind: BOLD_KIND$1, markers: ["**"] },
|
|
2945
3362
|
keybindings: [
|
|
@@ -3022,7 +3439,7 @@ const boldExtension = {
|
|
|
3022
3439
|
}
|
|
3023
3440
|
return element;
|
|
3024
3441
|
}
|
|
3025
|
-
};
|
|
3442
|
+
});
|
|
3026
3443
|
function countSingleAsterisks(source, start, end) {
|
|
3027
3444
|
let count = 0;
|
|
3028
3445
|
for (let i = start; i < end; i += 1) {
|
|
@@ -3041,7 +3458,7 @@ function countSingleAsterisks(source, start, end) {
|
|
|
3041
3458
|
const BOLD_KIND = "bold";
|
|
3042
3459
|
const ITALIC_KIND$1 = "italic";
|
|
3043
3460
|
const MARKERS = ["***", "___"];
|
|
3044
|
-
const combinedEmphasisExtension = {
|
|
3461
|
+
const combinedEmphasisExtension = defineExtension({
|
|
3045
3462
|
name: "combined-emphasis",
|
|
3046
3463
|
parseInline(source, start, end, context) {
|
|
3047
3464
|
const marker = MARKERS.find((m) => source.slice(start, start + 3) === m);
|
|
@@ -3075,7 +3492,7 @@ const combinedEmphasisExtension = {
|
|
|
3075
3492
|
nextPos: close + 3
|
|
3076
3493
|
};
|
|
3077
3494
|
}
|
|
3078
|
-
};
|
|
3495
|
+
});
|
|
3079
3496
|
function ensureHttpsProtocol(url) {
|
|
3080
3497
|
const trimmedUrl = url.trim();
|
|
3081
3498
|
if (!trimmedUrl) {
|
|
@@ -3123,7 +3540,7 @@ function getPopoverPosition(params) {
|
|
|
3123
3540
|
};
|
|
3124
3541
|
}
|
|
3125
3542
|
function CakeLinkPopover(params) {
|
|
3126
|
-
const { container, contentRoot, toOverlayRect } = params;
|
|
3543
|
+
const { container, contentRoot, toOverlayRect, getSelection, executeCommand } = params;
|
|
3127
3544
|
const anchorRef = require$$0.useRef(null);
|
|
3128
3545
|
const popoverRef = require$$0.useRef(null);
|
|
3129
3546
|
const inputRef = require$$0.useRef(null);
|
|
@@ -3224,13 +3641,13 @@ function CakeLinkPopover(params) {
|
|
|
3224
3641
|
if (state2.status !== "open") {
|
|
3225
3642
|
return;
|
|
3226
3643
|
}
|
|
3227
|
-
container.addEventListener("scroll",
|
|
3644
|
+
container.addEventListener("scroll", close, { passive: true });
|
|
3228
3645
|
window.addEventListener("resize", reposition);
|
|
3229
3646
|
return () => {
|
|
3230
|
-
container.removeEventListener("scroll",
|
|
3647
|
+
container.removeEventListener("scroll", close);
|
|
3231
3648
|
window.removeEventListener("resize", reposition);
|
|
3232
3649
|
};
|
|
3233
|
-
}, [container, reposition, state2.status]);
|
|
3650
|
+
}, [close, container, reposition, state2.status]);
|
|
3234
3651
|
const handleMouseDown = require$$0.useCallback(
|
|
3235
3652
|
(event) => {
|
|
3236
3653
|
event.stopPropagation();
|
|
@@ -3287,6 +3704,12 @@ function CakeLinkPopover(params) {
|
|
|
3287
3704
|
window.open(displayUrl, "_blank", "noopener,noreferrer");
|
|
3288
3705
|
};
|
|
3289
3706
|
const handleUnlink = () => {
|
|
3707
|
+
const selection = getSelection();
|
|
3708
|
+
if (!selection) {
|
|
3709
|
+
close();
|
|
3710
|
+
return;
|
|
3711
|
+
}
|
|
3712
|
+
executeCommand({ type: "unlink", start: selection.start, end: selection.end });
|
|
3290
3713
|
close();
|
|
3291
3714
|
};
|
|
3292
3715
|
const handleInputKeyDown = (event) => {
|
|
@@ -3299,7 +3722,7 @@ function CakeLinkPopover(params) {
|
|
|
3299
3722
|
handleCancel();
|
|
3300
3723
|
}
|
|
3301
3724
|
};
|
|
3302
|
-
return /* @__PURE__ */
|
|
3725
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3303
3726
|
"div",
|
|
3304
3727
|
{
|
|
3305
3728
|
className: "cake-link-popover",
|
|
@@ -3312,7 +3735,7 @@ function CakeLinkPopover(params) {
|
|
|
3312
3735
|
},
|
|
3313
3736
|
onMouseDown: handleMouseDown,
|
|
3314
3737
|
onClick: (event) => event.stopPropagation(),
|
|
3315
|
-
children: state2.isEditing ? /* @__PURE__ */
|
|
3738
|
+
children: state2.isEditing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3316
3739
|
"form",
|
|
3317
3740
|
{
|
|
3318
3741
|
className: "cake-link-editor",
|
|
@@ -3321,7 +3744,7 @@ function CakeLinkPopover(params) {
|
|
|
3321
3744
|
handleSave();
|
|
3322
3745
|
},
|
|
3323
3746
|
children: [
|
|
3324
|
-
/* @__PURE__ */
|
|
3747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3325
3748
|
"input",
|
|
3326
3749
|
{
|
|
3327
3750
|
className: "cake-link-input",
|
|
@@ -3338,56 +3761,24 @@ function CakeLinkPopover(params) {
|
|
|
3338
3761
|
},
|
|
3339
3762
|
onKeyDown: handleInputKeyDown,
|
|
3340
3763
|
placeholder: "https://"
|
|
3341
|
-
}
|
|
3342
|
-
void 0,
|
|
3343
|
-
false,
|
|
3344
|
-
{
|
|
3345
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3346
|
-
lineNumber: 281,
|
|
3347
|
-
columnNumber: 11
|
|
3348
|
-
},
|
|
3349
|
-
this
|
|
3764
|
+
}
|
|
3350
3765
|
),
|
|
3351
|
-
/* @__PURE__ */
|
|
3352
|
-
|
|
3353
|
-
lineNumber: 297,
|
|
3354
|
-
columnNumber: 11
|
|
3355
|
-
}, this),
|
|
3356
|
-
/* @__PURE__ */ jsxDevRuntimeExports.jsxDEV(
|
|
3766
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "submit", className: "cake-link-save", children: "Save" }),
|
|
3767
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3357
3768
|
"button",
|
|
3358
3769
|
{
|
|
3359
3770
|
type: "button",
|
|
3360
3771
|
className: "cake-link-cancel",
|
|
3361
3772
|
onClick: handleCancel,
|
|
3362
3773
|
children: "Cancel"
|
|
3363
|
-
}
|
|
3364
|
-
void 0,
|
|
3365
|
-
false,
|
|
3366
|
-
{
|
|
3367
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3368
|
-
lineNumber: 300,
|
|
3369
|
-
columnNumber: 11
|
|
3370
|
-
},
|
|
3371
|
-
this
|
|
3774
|
+
}
|
|
3372
3775
|
)
|
|
3373
3776
|
]
|
|
3374
|
-
}
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
{
|
|
3378
|
-
|
|
3379
|
-
lineNumber: 274,
|
|
3380
|
-
columnNumber: 9
|
|
3381
|
-
},
|
|
3382
|
-
this
|
|
3383
|
-
) : /* @__PURE__ */ jsxDevRuntimeExports.jsxDEV(jsxDevRuntimeExports.Fragment, { children: [
|
|
3384
|
-
/* @__PURE__ */ jsxDevRuntimeExports.jsxDEV("div", { className: "cake-link-url", title: displayUrl, children: displayUrl }, void 0, false, {
|
|
3385
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3386
|
-
lineNumber: 310,
|
|
3387
|
-
columnNumber: 11
|
|
3388
|
-
}, this),
|
|
3389
|
-
/* @__PURE__ */ jsxDevRuntimeExports.jsxDEV("div", { className: "cake-link-actions", children: [
|
|
3390
|
-
/* @__PURE__ */ jsxDevRuntimeExports.jsxDEV(
|
|
3777
|
+
}
|
|
3778
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
3779
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "cake-link-url", title: displayUrl, children: displayUrl }),
|
|
3780
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "cake-link-actions", children: [
|
|
3781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3391
3782
|
"button",
|
|
3392
3783
|
{
|
|
3393
3784
|
type: "button",
|
|
@@ -3395,22 +3786,10 @@ function CakeLinkPopover(params) {
|
|
|
3395
3786
|
onClick: handleEdit,
|
|
3396
3787
|
title: "Edit link",
|
|
3397
3788
|
"aria-label": "Edit link",
|
|
3398
|
-
children: /* @__PURE__ */
|
|
3399
|
-
|
|
3400
|
-
lineNumber: 321,
|
|
3401
|
-
columnNumber: 15
|
|
3402
|
-
}, this)
|
|
3403
|
-
},
|
|
3404
|
-
void 0,
|
|
3405
|
-
false,
|
|
3406
|
-
{
|
|
3407
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3408
|
-
lineNumber: 314,
|
|
3409
|
-
columnNumber: 13
|
|
3410
|
-
},
|
|
3411
|
-
this
|
|
3789
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Pencil, { className: "cake-link-icon" })
|
|
3790
|
+
}
|
|
3412
3791
|
),
|
|
3413
|
-
/* @__PURE__ */
|
|
3792
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3414
3793
|
"button",
|
|
3415
3794
|
{
|
|
3416
3795
|
type: "button",
|
|
@@ -3418,22 +3797,10 @@ function CakeLinkPopover(params) {
|
|
|
3418
3797
|
onClick: handleOpen,
|
|
3419
3798
|
title: "Open link",
|
|
3420
3799
|
"aria-label": "Open link",
|
|
3421
|
-
children: /* @__PURE__ */
|
|
3422
|
-
|
|
3423
|
-
lineNumber: 330,
|
|
3424
|
-
columnNumber: 15
|
|
3425
|
-
}, this)
|
|
3426
|
-
},
|
|
3427
|
-
void 0,
|
|
3428
|
-
false,
|
|
3429
|
-
{
|
|
3430
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3431
|
-
lineNumber: 323,
|
|
3432
|
-
columnNumber: 13
|
|
3433
|
-
},
|
|
3434
|
-
this
|
|
3800
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.ExternalLink, { className: "cake-link-icon" })
|
|
3801
|
+
}
|
|
3435
3802
|
),
|
|
3436
|
-
/* @__PURE__ */
|
|
3803
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3437
3804
|
"button",
|
|
3438
3805
|
{
|
|
3439
3806
|
type: "button",
|
|
@@ -3441,40 +3808,12 @@ function CakeLinkPopover(params) {
|
|
|
3441
3808
|
onClick: handleUnlink,
|
|
3442
3809
|
title: "Remove link",
|
|
3443
3810
|
"aria-label": "Remove link",
|
|
3444
|
-
children: /* @__PURE__ */
|
|
3445
|
-
|
|
3446
|
-
lineNumber: 339,
|
|
3447
|
-
columnNumber: 15
|
|
3448
|
-
}, this)
|
|
3449
|
-
},
|
|
3450
|
-
void 0,
|
|
3451
|
-
false,
|
|
3452
|
-
{
|
|
3453
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3454
|
-
lineNumber: 332,
|
|
3455
|
-
columnNumber: 13
|
|
3456
|
-
},
|
|
3457
|
-
this
|
|
3811
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Unlink, { className: "cake-link-icon" })
|
|
3812
|
+
}
|
|
3458
3813
|
)
|
|
3459
|
-
] }
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
columnNumber: 11
|
|
3463
|
-
}, this)
|
|
3464
|
-
] }, void 0, true, {
|
|
3465
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3466
|
-
lineNumber: 309,
|
|
3467
|
-
columnNumber: 9
|
|
3468
|
-
}, this)
|
|
3469
|
-
},
|
|
3470
|
-
void 0,
|
|
3471
|
-
false,
|
|
3472
|
-
{
|
|
3473
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link-popover.tsx",
|
|
3474
|
-
lineNumber: 261,
|
|
3475
|
-
columnNumber: 5
|
|
3476
|
-
},
|
|
3477
|
-
this
|
|
3814
|
+
] })
|
|
3815
|
+
] })
|
|
3816
|
+
}
|
|
3478
3817
|
);
|
|
3479
3818
|
}
|
|
3480
3819
|
function buildLayoutModel(lines, measurer) {
|
|
@@ -3674,7 +4013,7 @@ function cursorOffsetToVisibleOffset(lines, cursorOffset) {
|
|
|
3674
4013
|
return codeUnitIndex + (lastLine.cursorToCodeUnit[lastOffset] ?? lastLine.text.length);
|
|
3675
4014
|
}
|
|
3676
4015
|
const LINK_KIND = "link";
|
|
3677
|
-
const linkExtension = {
|
|
4016
|
+
const linkExtension = defineExtension({
|
|
3678
4017
|
name: "link",
|
|
3679
4018
|
inlineWrapperAffinity: [{ kind: LINK_KIND, inclusive: false }],
|
|
3680
4019
|
keybindings: [
|
|
@@ -3702,6 +4041,39 @@ const linkExtension = {
|
|
|
3702
4041
|
}
|
|
3703
4042
|
],
|
|
3704
4043
|
onEdit(command, state2) {
|
|
4044
|
+
if (command.type === "unlink") {
|
|
4045
|
+
const cursorPos = command.start;
|
|
4046
|
+
const sourcePos = state2.map.cursorToSource(cursorPos, "forward");
|
|
4047
|
+
const source = state2.source;
|
|
4048
|
+
let linkStart = sourcePos;
|
|
4049
|
+
while (linkStart > 0 && source[linkStart] !== "[") {
|
|
4050
|
+
linkStart--;
|
|
4051
|
+
}
|
|
4052
|
+
if (source[linkStart] !== "[") {
|
|
4053
|
+
return null;
|
|
4054
|
+
}
|
|
4055
|
+
const labelClose = source.indexOf("](", linkStart + 1);
|
|
4056
|
+
if (labelClose === -1) {
|
|
4057
|
+
return null;
|
|
4058
|
+
}
|
|
4059
|
+
const urlClose = source.indexOf(")", labelClose + 2);
|
|
4060
|
+
if (urlClose === -1) {
|
|
4061
|
+
return null;
|
|
4062
|
+
}
|
|
4063
|
+
const label2 = source.slice(linkStart + 1, labelClose);
|
|
4064
|
+
const nextSource2 = source.slice(0, linkStart) + label2 + source.slice(urlClose + 1);
|
|
4065
|
+
const newState = state2.runtime.createState(nextSource2);
|
|
4066
|
+
const labelEndSource = linkStart + label2.length;
|
|
4067
|
+
const newCursor = newState.map.sourceToCursor(labelEndSource, "forward");
|
|
4068
|
+
return {
|
|
4069
|
+
source: nextSource2,
|
|
4070
|
+
selection: {
|
|
4071
|
+
start: newCursor.cursorOffset,
|
|
4072
|
+
end: newCursor.cursorOffset,
|
|
4073
|
+
affinity: "forward"
|
|
4074
|
+
}
|
|
4075
|
+
};
|
|
4076
|
+
}
|
|
3705
4077
|
if (command.type !== "wrap-link") {
|
|
3706
4078
|
return null;
|
|
3707
4079
|
}
|
|
@@ -3823,26 +4195,20 @@ const linkExtension = {
|
|
|
3823
4195
|
if (!context.contentRoot || !context.toOverlayRect) {
|
|
3824
4196
|
return null;
|
|
3825
4197
|
}
|
|
3826
|
-
return /* @__PURE__ */
|
|
4198
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3827
4199
|
CakeLinkPopover,
|
|
3828
4200
|
{
|
|
3829
4201
|
container: context.container,
|
|
3830
4202
|
contentRoot: context.contentRoot,
|
|
3831
|
-
toOverlayRect: context.toOverlayRect
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
{
|
|
3836
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/link/link.tsx",
|
|
3837
|
-
lineNumber: 179,
|
|
3838
|
-
columnNumber: 7
|
|
3839
|
-
},
|
|
3840
|
-
this
|
|
4203
|
+
toOverlayRect: context.toOverlayRect,
|
|
4204
|
+
getSelection: context.getSelection,
|
|
4205
|
+
executeCommand: context.executeCommand
|
|
4206
|
+
}
|
|
3841
4207
|
);
|
|
3842
4208
|
}
|
|
3843
|
-
};
|
|
4209
|
+
});
|
|
3844
4210
|
const PIPE_LINK_KIND = "pipe-link";
|
|
3845
|
-
const pipeLinkExtension = {
|
|
4211
|
+
const pipeLinkExtension = defineExtension({
|
|
3846
4212
|
name: "pipe-link",
|
|
3847
4213
|
parseInline(source, start, end) {
|
|
3848
4214
|
if (source[start] !== "|") {
|
|
@@ -3913,10 +4279,10 @@ const pipeLinkExtension = {
|
|
|
3913
4279
|
}
|
|
3914
4280
|
return element;
|
|
3915
4281
|
}
|
|
3916
|
-
};
|
|
4282
|
+
});
|
|
3917
4283
|
const BLOCKQUOTE_KIND = "blockquote";
|
|
3918
4284
|
const PREFIX = "> ";
|
|
3919
|
-
const blockquoteExtension = {
|
|
4285
|
+
const blockquoteExtension = defineExtension({
|
|
3920
4286
|
name: "blockquote",
|
|
3921
4287
|
parseBlock(source, start, context) {
|
|
3922
4288
|
if (source.slice(start, start + PREFIX.length) !== PREFIX) {
|
|
@@ -3985,9 +4351,9 @@ const blockquoteExtension = {
|
|
|
3985
4351
|
}
|
|
3986
4352
|
return element;
|
|
3987
4353
|
}
|
|
3988
|
-
};
|
|
4354
|
+
});
|
|
3989
4355
|
const ITALIC_KIND = "italic";
|
|
3990
|
-
const italicExtension = {
|
|
4356
|
+
const italicExtension = defineExtension({
|
|
3991
4357
|
name: "italic",
|
|
3992
4358
|
toggleInline: { kind: ITALIC_KIND, markers: ["*", "_"] },
|
|
3993
4359
|
keybindings: [
|
|
@@ -4057,7 +4423,7 @@ const italicExtension = {
|
|
|
4057
4423
|
}
|
|
4058
4424
|
return element;
|
|
4059
4425
|
}
|
|
4060
|
-
};
|
|
4426
|
+
});
|
|
4061
4427
|
const HEADING_KIND = "heading";
|
|
4062
4428
|
const HEADING_PATTERN = /^(#{1,3}) /;
|
|
4063
4429
|
function findLineStartInSource(source, sourceOffset) {
|
|
@@ -4158,7 +4524,7 @@ function shouldExitHeadingOnLineBreak(state2) {
|
|
|
4158
4524
|
const contentStart = lineStart + marker.length;
|
|
4159
4525
|
return sourcePos >= contentStart && sourcePos <= lineEnd;
|
|
4160
4526
|
}
|
|
4161
|
-
const headingExtension = {
|
|
4527
|
+
const headingExtension = defineExtension({
|
|
4162
4528
|
name: "heading",
|
|
4163
4529
|
onEdit(command, state2) {
|
|
4164
4530
|
if (command.type === "delete-backward") {
|
|
@@ -4299,7 +4665,7 @@ const headingExtension = {
|
|
|
4299
4665
|
}
|
|
4300
4666
|
return lineElement;
|
|
4301
4667
|
}
|
|
4302
|
-
};
|
|
4668
|
+
});
|
|
4303
4669
|
const IMAGE_KIND = "image";
|
|
4304
4670
|
const IMAGE_PATTERN = /^!\[([^\]]*)\]\(([^)]*)\)$/;
|
|
4305
4671
|
const UPLOADING_PATTERN = /^!\[uploading:([^\]]+)\]\(\)$/;
|
|
@@ -4317,7 +4683,7 @@ function isImageData(data) {
|
|
|
4317
4683
|
}
|
|
4318
4684
|
return false;
|
|
4319
4685
|
}
|
|
4320
|
-
const imageExtension = {
|
|
4686
|
+
const imageExtension = defineExtension({
|
|
4321
4687
|
name: "image",
|
|
4322
4688
|
parseBlock(source, start) {
|
|
4323
4689
|
let lineEnd = source.indexOf("\n", start);
|
|
@@ -4412,7 +4778,7 @@ const imageExtension = {
|
|
|
4412
4778
|
}
|
|
4413
4779
|
return element;
|
|
4414
4780
|
}
|
|
4415
|
-
};
|
|
4781
|
+
});
|
|
4416
4782
|
const LIST_LINE_REGEX$2 = /^(\s*)([-*+]|\d+\.)( )(.*)$/;
|
|
4417
4783
|
const INDENT_SIZE = 2;
|
|
4418
4784
|
function parseMarkerType(marker) {
|
|
@@ -5231,7 +5597,7 @@ function getParagraphText(block) {
|
|
|
5231
5597
|
}
|
|
5232
5598
|
return text;
|
|
5233
5599
|
}
|
|
5234
|
-
const listExtension = {
|
|
5600
|
+
const listExtension = defineExtension({
|
|
5235
5601
|
name: "list",
|
|
5236
5602
|
keybindings: [
|
|
5237
5603
|
{
|
|
@@ -5324,7 +5690,7 @@ const listExtension = {
|
|
|
5324
5690
|
}
|
|
5325
5691
|
return element;
|
|
5326
5692
|
}
|
|
5327
|
-
};
|
|
5693
|
+
});
|
|
5328
5694
|
const THUMB_MIN_HEIGHT = 30;
|
|
5329
5695
|
const SCROLL_HIDE_DELAY = 500;
|
|
5330
5696
|
const TRACK_PADDING = 8;
|
|
@@ -5337,6 +5703,7 @@ function ScrollbarOverlay({ container }) {
|
|
|
5337
5703
|
const [isDragging, setIsDragging] = require$$0.useState(false);
|
|
5338
5704
|
const [isHovered, setIsHovered] = require$$0.useState(false);
|
|
5339
5705
|
const [isScrolling, setIsScrolling] = require$$0.useState(false);
|
|
5706
|
+
const [isDarkMode, setIsDarkMode] = require$$0.useState(false);
|
|
5340
5707
|
const dragStartRef = require$$0.useRef(
|
|
5341
5708
|
null
|
|
5342
5709
|
);
|
|
@@ -5351,6 +5718,24 @@ function ScrollbarOverlay({ container }) {
|
|
|
5351
5718
|
);
|
|
5352
5719
|
const maxScrollTop = scrollHeight - clientHeight;
|
|
5353
5720
|
const thumbTop = maxScrollTop > 0 ? TRACK_PADDING + scrollTop / maxScrollTop * (trackHeight - thumbHeight) : TRACK_PADDING;
|
|
5721
|
+
require$$0.useEffect(() => {
|
|
5722
|
+
function checkDarkMode() {
|
|
5723
|
+
const html = document.documentElement;
|
|
5724
|
+
setIsDarkMode(html.classList.contains("dark"));
|
|
5725
|
+
}
|
|
5726
|
+
checkDarkMode();
|
|
5727
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
5728
|
+
mediaQuery.addEventListener("change", checkDarkMode);
|
|
5729
|
+
const observer = new MutationObserver(checkDarkMode);
|
|
5730
|
+
observer.observe(document.documentElement, {
|
|
5731
|
+
attributes: true,
|
|
5732
|
+
attributeFilter: ["class"]
|
|
5733
|
+
});
|
|
5734
|
+
return () => {
|
|
5735
|
+
mediaQuery.removeEventListener("change", checkDarkMode);
|
|
5736
|
+
observer.disconnect();
|
|
5737
|
+
};
|
|
5738
|
+
}, []);
|
|
5354
5739
|
require$$0.useEffect(() => {
|
|
5355
5740
|
function update() {
|
|
5356
5741
|
setState({
|
|
@@ -5488,6 +5873,13 @@ function ScrollbarOverlay({ container }) {
|
|
|
5488
5873
|
return null;
|
|
5489
5874
|
}
|
|
5490
5875
|
const isVisible = isDragging || isHovered || isScrolling;
|
|
5876
|
+
const wrapperStyle = {
|
|
5877
|
+
position: "absolute",
|
|
5878
|
+
inset: 0,
|
|
5879
|
+
pointerEvents: "none",
|
|
5880
|
+
overflow: "hidden",
|
|
5881
|
+
zIndex: 50
|
|
5882
|
+
};
|
|
5491
5883
|
const trackStyle = {
|
|
5492
5884
|
position: "absolute",
|
|
5493
5885
|
top: 0,
|
|
@@ -5497,6 +5889,12 @@ function ScrollbarOverlay({ container }) {
|
|
|
5497
5889
|
height: clientHeight,
|
|
5498
5890
|
pointerEvents: "auto"
|
|
5499
5891
|
};
|
|
5892
|
+
const getThumbColor = () => {
|
|
5893
|
+
if (isDarkMode) {
|
|
5894
|
+
return isDragging ? "rgba(255, 255, 255, 0.5)" : "rgba(255, 255, 255, 0.3)";
|
|
5895
|
+
}
|
|
5896
|
+
return isDragging ? "rgba(0, 0, 0, 0.5)" : "rgba(0, 0, 0, 0.3)";
|
|
5897
|
+
};
|
|
5500
5898
|
const thumbStyle = {
|
|
5501
5899
|
position: "absolute",
|
|
5502
5900
|
right: "2px",
|
|
@@ -5504,58 +5902,39 @@ function ScrollbarOverlay({ container }) {
|
|
|
5504
5902
|
borderRadius: "9999px",
|
|
5505
5903
|
height: thumbHeight,
|
|
5506
5904
|
top: thumbTop,
|
|
5507
|
-
opacity: isVisible ? 1 : 0
|
|
5905
|
+
opacity: isVisible ? 1 : 0,
|
|
5906
|
+
backgroundColor: getThumbColor(),
|
|
5907
|
+
transition: "opacity 150ms",
|
|
5908
|
+
cursor: "pointer"
|
|
5508
5909
|
};
|
|
5509
|
-
return /* @__PURE__ */
|
|
5910
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: wrapperStyle, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5510
5911
|
"div",
|
|
5511
5912
|
{
|
|
5512
5913
|
"data-testid": "custom-scrollbar",
|
|
5513
5914
|
"aria-hidden": "true",
|
|
5514
|
-
className: "pointer-events-auto absolute top-0 right-0 bottom-0 z-50 w-3",
|
|
5515
5915
|
style: trackStyle,
|
|
5516
5916
|
onClick: handleTrackClick,
|
|
5517
5917
|
onMouseEnter: () => setIsHovered(true),
|
|
5518
5918
|
onMouseLeave: () => setIsHovered(false),
|
|
5519
|
-
children: /* @__PURE__ */
|
|
5919
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5520
5920
|
"div",
|
|
5521
5921
|
{
|
|
5522
5922
|
"data-testid": "scrollbar-thumb",
|
|
5523
|
-
className: `absolute right-0.5 w-1.5 cursor-pointer rounded-full transition-opacity duration-150 ${isDragging ? "bg-black/50 dark:bg-white/50" : "bg-black/30 dark:bg-white/30"}`,
|
|
5524
5923
|
style: thumbStyle,
|
|
5525
5924
|
onMouseDown: handleThumbMouseDown
|
|
5526
|
-
}
|
|
5527
|
-
void 0,
|
|
5528
|
-
false,
|
|
5529
|
-
{
|
|
5530
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/scrollbar/index.tsx",
|
|
5531
|
-
lineNumber: 230,
|
|
5532
|
-
columnNumber: 7
|
|
5533
|
-
},
|
|
5534
|
-
this
|
|
5925
|
+
}
|
|
5535
5926
|
)
|
|
5536
|
-
}
|
|
5537
|
-
|
|
5538
|
-
false,
|
|
5539
|
-
{
|
|
5540
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/scrollbar/index.tsx",
|
|
5541
|
-
lineNumber: 221,
|
|
5542
|
-
columnNumber: 5
|
|
5543
|
-
},
|
|
5544
|
-
this
|
|
5545
|
-
);
|
|
5927
|
+
}
|
|
5928
|
+
) });
|
|
5546
5929
|
}
|
|
5547
|
-
const scrollbarExtension = {
|
|
5930
|
+
const scrollbarExtension = defineExtension({
|
|
5548
5931
|
name: "scrollbar",
|
|
5549
5932
|
renderOverlay(context) {
|
|
5550
|
-
return /* @__PURE__ */
|
|
5551
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/extensions/scrollbar/index.tsx",
|
|
5552
|
-
lineNumber: 247,
|
|
5553
|
-
columnNumber: 12
|
|
5554
|
-
}, this);
|
|
5933
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollbarOverlay, { container: context.container });
|
|
5555
5934
|
}
|
|
5556
|
-
};
|
|
5935
|
+
});
|
|
5557
5936
|
const STRIKE_KIND = "strikethrough";
|
|
5558
|
-
const strikethroughExtension = {
|
|
5937
|
+
const strikethroughExtension = defineExtension({
|
|
5559
5938
|
name: "strikethrough",
|
|
5560
5939
|
toggleInline: { kind: STRIKE_KIND, markers: ["~~"] },
|
|
5561
5940
|
keybindings: [
|
|
@@ -5628,8 +6007,8 @@ const strikethroughExtension = {
|
|
|
5628
6007
|
}
|
|
5629
6008
|
return element;
|
|
5630
6009
|
}
|
|
5631
|
-
};
|
|
5632
|
-
const
|
|
6010
|
+
});
|
|
6011
|
+
const bundledExtensionsWithoutImage = [
|
|
5633
6012
|
blockquoteExtension,
|
|
5634
6013
|
headingExtension,
|
|
5635
6014
|
listExtension,
|
|
@@ -5638,7 +6017,10 @@ const bundledExtensions = [
|
|
|
5638
6017
|
italicExtension,
|
|
5639
6018
|
strikethroughExtension,
|
|
5640
6019
|
pipeLinkExtension,
|
|
5641
|
-
linkExtension
|
|
6020
|
+
linkExtension
|
|
6021
|
+
];
|
|
6022
|
+
const bundledExtensions = [
|
|
6023
|
+
...bundledExtensionsWithoutImage,
|
|
5642
6024
|
imageExtension
|
|
5643
6025
|
];
|
|
5644
6026
|
function toLayoutRect(params) {
|
|
@@ -5698,6 +6080,46 @@ function cursorOffsetToCodeUnit(cursorToCodeUnit, offset) {
|
|
|
5698
6080
|
const clamped = Math.max(0, Math.min(offset, cursorToCodeUnit.length - 1));
|
|
5699
6081
|
return cursorToCodeUnit[clamped] ?? 0;
|
|
5700
6082
|
}
|
|
6083
|
+
function createDomPositionResolver(lineElement) {
|
|
6084
|
+
const textNodes = [];
|
|
6085
|
+
const cumulativeEnds = [];
|
|
6086
|
+
const walker = createTextWalker(lineElement);
|
|
6087
|
+
let current = walker.nextNode();
|
|
6088
|
+
let total = 0;
|
|
6089
|
+
while (current) {
|
|
6090
|
+
if (current instanceof Text) {
|
|
6091
|
+
const length = current.data.length;
|
|
6092
|
+
textNodes.push(current);
|
|
6093
|
+
total += length;
|
|
6094
|
+
cumulativeEnds.push(total);
|
|
6095
|
+
}
|
|
6096
|
+
current = walker.nextNode();
|
|
6097
|
+
}
|
|
6098
|
+
if (textNodes.length === 0) {
|
|
6099
|
+
return () => {
|
|
6100
|
+
if (!lineElement.textContent) {
|
|
6101
|
+
return { node: lineElement, offset: 0 };
|
|
6102
|
+
}
|
|
6103
|
+
return { node: lineElement, offset: lineElement.childNodes.length };
|
|
6104
|
+
};
|
|
6105
|
+
}
|
|
6106
|
+
return (offsetInLine) => {
|
|
6107
|
+
const clamped = Math.max(0, Math.min(offsetInLine, total));
|
|
6108
|
+
let low = 0;
|
|
6109
|
+
let high = cumulativeEnds.length - 1;
|
|
6110
|
+
while (low < high) {
|
|
6111
|
+
const mid = low + high >>> 1;
|
|
6112
|
+
if ((cumulativeEnds[mid] ?? 0) < clamped) {
|
|
6113
|
+
low = mid + 1;
|
|
6114
|
+
} else {
|
|
6115
|
+
high = mid;
|
|
6116
|
+
}
|
|
6117
|
+
}
|
|
6118
|
+
const node = textNodes[low] ?? lineElement;
|
|
6119
|
+
const prevEnd = low > 0 ? cumulativeEnds[low - 1] ?? 0 : 0;
|
|
6120
|
+
return { node, offset: clamped - prevEnd };
|
|
6121
|
+
};
|
|
6122
|
+
}
|
|
5701
6123
|
function measureCharacterRect(params) {
|
|
5702
6124
|
if (params.lineLength <= 0) {
|
|
5703
6125
|
return null;
|
|
@@ -5710,101 +6132,155 @@ function measureCharacterRect(params) {
|
|
|
5710
6132
|
params.cursorToCodeUnit,
|
|
5711
6133
|
Math.min(params.offset + 1, params.lineLength)
|
|
5712
6134
|
);
|
|
5713
|
-
const startPosition = resolveDomPosition(
|
|
5714
|
-
const endPosition = resolveDomPosition(
|
|
5715
|
-
|
|
5716
|
-
range.
|
|
5717
|
-
range.
|
|
5718
|
-
const rects = range.getClientRects();
|
|
6135
|
+
const startPosition = params.resolveDomPosition(startCodeUnit);
|
|
6136
|
+
const endPosition = params.resolveDomPosition(endCodeUnit);
|
|
6137
|
+
params.range.setStart(startPosition.node, startPosition.offset);
|
|
6138
|
+
params.range.setEnd(endPosition.node, endPosition.offset);
|
|
6139
|
+
const rects = params.range.getClientRects();
|
|
5719
6140
|
if (rects.length > 0) {
|
|
5720
6141
|
return rects[0] ?? null;
|
|
5721
6142
|
}
|
|
5722
|
-
const rect = range.getBoundingClientRect();
|
|
6143
|
+
const rect = params.range.getBoundingClientRect();
|
|
5723
6144
|
if (rect.width === 0 && rect.height === 0) {
|
|
5724
6145
|
return null;
|
|
5725
6146
|
}
|
|
5726
6147
|
return rect;
|
|
5727
6148
|
}
|
|
5728
6149
|
function measureLineRows(params) {
|
|
6150
|
+
var _a, _b;
|
|
6151
|
+
const fallbackLineBox = toLayoutRect({
|
|
6152
|
+
rect: params.lineRect,
|
|
6153
|
+
containerRect: params.containerRect,
|
|
6154
|
+
scroll: params.scroll
|
|
6155
|
+
});
|
|
5729
6156
|
if (params.lineLength === 0) {
|
|
5730
|
-
const lineBox = toLayoutRect({
|
|
5731
|
-
rect: params.lineRect,
|
|
5732
|
-
containerRect: params.containerRect,
|
|
5733
|
-
scroll: params.scroll
|
|
5734
|
-
});
|
|
5735
6157
|
return [
|
|
5736
6158
|
{
|
|
5737
6159
|
startOffset: 0,
|
|
5738
6160
|
endOffset: 0,
|
|
5739
|
-
rect: { ...
|
|
6161
|
+
rect: { ...fallbackLineBox, width: 0 }
|
|
5740
6162
|
}
|
|
5741
6163
|
];
|
|
5742
6164
|
}
|
|
5743
|
-
const
|
|
5744
|
-
const
|
|
5745
|
-
const
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
);
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
const fullLineRects = groupDomRectsByRow(
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
const fallbackLineBox = toLayoutRect({
|
|
5755
|
-
rect: params.lineRect,
|
|
5756
|
-
containerRect: params.containerRect,
|
|
5757
|
-
scroll: params.scroll
|
|
5758
|
-
});
|
|
5759
|
-
const charRect = measureCharacterRect({
|
|
5760
|
-
lineElement: params.lineElement,
|
|
5761
|
-
offset: 0,
|
|
5762
|
-
lineLength: params.lineLength,
|
|
5763
|
-
cursorToCodeUnit: params.cursorToCodeUnit
|
|
5764
|
-
});
|
|
5765
|
-
const charWidth = (charRect == null ? void 0 : charRect.width) ?? 0;
|
|
5766
|
-
if (fullLineRects.length === 0 || charWidth <= 0) {
|
|
5767
|
-
const rows2 = [
|
|
6165
|
+
const WRAP_THRESHOLD_PX = 3;
|
|
6166
|
+
const resolvePosition = createDomPositionResolver(params.lineElement);
|
|
6167
|
+
const scratchRange = document.createRange();
|
|
6168
|
+
const topCache = /* @__PURE__ */ new Map();
|
|
6169
|
+
const fullLineStart = resolvePosition(0);
|
|
6170
|
+
const fullLineEnd = resolvePosition(params.codeUnitLength);
|
|
6171
|
+
scratchRange.setStart(fullLineStart.node, fullLineStart.offset);
|
|
6172
|
+
scratchRange.setEnd(fullLineEnd.node, fullLineEnd.offset);
|
|
6173
|
+
const fullLineRects = groupDomRectsByRow(Array.from(scratchRange.getClientRects()));
|
|
6174
|
+
if (fullLineRects.length === 0) {
|
|
6175
|
+
return [
|
|
5768
6176
|
{
|
|
5769
6177
|
startOffset: 0,
|
|
5770
6178
|
endOffset: params.lineLength,
|
|
5771
6179
|
rect: fallbackLineBox
|
|
5772
6180
|
}
|
|
5773
6181
|
];
|
|
5774
|
-
|
|
6182
|
+
}
|
|
6183
|
+
function offsetToTop(offset) {
|
|
6184
|
+
if (topCache.has(offset)) {
|
|
6185
|
+
return topCache.get(offset) ?? null;
|
|
6186
|
+
}
|
|
6187
|
+
const rect = measureCharacterRect({
|
|
6188
|
+
lineElement: params.lineElement,
|
|
6189
|
+
offset,
|
|
6190
|
+
lineLength: params.lineLength,
|
|
6191
|
+
cursorToCodeUnit: params.cursorToCodeUnit,
|
|
6192
|
+
resolveDomPosition: resolvePosition,
|
|
6193
|
+
range: scratchRange
|
|
6194
|
+
});
|
|
6195
|
+
const top = rect ? rect.top : null;
|
|
6196
|
+
topCache.set(offset, top);
|
|
6197
|
+
return top;
|
|
6198
|
+
}
|
|
6199
|
+
function findFirstMeasurableOffset(from) {
|
|
6200
|
+
for (let offset = Math.max(0, from); offset < params.lineLength; offset++) {
|
|
6201
|
+
if (offsetToTop(offset) !== null) {
|
|
6202
|
+
return offset;
|
|
6203
|
+
}
|
|
6204
|
+
}
|
|
6205
|
+
return null;
|
|
6206
|
+
}
|
|
6207
|
+
function findNextRowStartOffset(fromExclusive, rowTop) {
|
|
6208
|
+
const lastIndex = params.lineLength - 1;
|
|
6209
|
+
if (fromExclusive > lastIndex) {
|
|
6210
|
+
return null;
|
|
6211
|
+
}
|
|
6212
|
+
const isNewRowAt = (offset) => {
|
|
6213
|
+
const top = offsetToTop(offset);
|
|
6214
|
+
return top !== null && Math.abs(top - rowTop) > WRAP_THRESHOLD_PX;
|
|
6215
|
+
};
|
|
6216
|
+
let step = 1;
|
|
6217
|
+
let lastSame = fromExclusive - 1;
|
|
6218
|
+
let probe = fromExclusive;
|
|
6219
|
+
while (probe <= lastIndex) {
|
|
6220
|
+
if (isNewRowAt(probe)) {
|
|
6221
|
+
break;
|
|
6222
|
+
}
|
|
6223
|
+
lastSame = probe;
|
|
6224
|
+
probe += step;
|
|
6225
|
+
step *= 2;
|
|
6226
|
+
}
|
|
6227
|
+
if (probe > lastIndex) {
|
|
6228
|
+
probe = lastIndex;
|
|
6229
|
+
if (!isNewRowAt(probe)) {
|
|
6230
|
+
return null;
|
|
6231
|
+
}
|
|
6232
|
+
}
|
|
6233
|
+
let low = Math.max(fromExclusive, lastSame + 1);
|
|
6234
|
+
let high = probe;
|
|
6235
|
+
while (low < high) {
|
|
6236
|
+
const mid = low + high >>> 1;
|
|
6237
|
+
if (isNewRowAt(mid)) {
|
|
6238
|
+
high = mid;
|
|
6239
|
+
} else {
|
|
6240
|
+
low = mid + 1;
|
|
6241
|
+
}
|
|
6242
|
+
}
|
|
6243
|
+
return low < params.lineLength ? low : null;
|
|
6244
|
+
}
|
|
6245
|
+
const rows = [];
|
|
6246
|
+
const firstMeasurable = findFirstMeasurableOffset(0);
|
|
6247
|
+
if (firstMeasurable === null) {
|
|
6248
|
+
return [
|
|
5775
6249
|
{
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
top: fallbackLineBox.top,
|
|
5780
|
-
height: fallbackLineBox.height
|
|
5781
|
-
}
|
|
6250
|
+
startOffset: 0,
|
|
6251
|
+
endOffset: params.lineLength,
|
|
6252
|
+
rect: fallbackLineBox
|
|
5782
6253
|
}
|
|
5783
|
-
]
|
|
6254
|
+
];
|
|
5784
6255
|
}
|
|
5785
|
-
let
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
const
|
|
5791
|
-
const
|
|
5792
|
-
|
|
5793
|
-
|
|
6256
|
+
let currentRowStart = 0;
|
|
6257
|
+
let currentRowTop = ((_a = fullLineRects[0]) == null ? void 0 : _a.top) ?? params.lineRect.top;
|
|
6258
|
+
let searchFrom = firstMeasurable + 1;
|
|
6259
|
+
let rowIndex = 0;
|
|
6260
|
+
while (currentRowStart < params.lineLength) {
|
|
6261
|
+
const nextRowStart = findNextRowStartOffset(searchFrom, currentRowTop);
|
|
6262
|
+
const currentRowEnd = nextRowStart ?? params.lineLength;
|
|
6263
|
+
const domRect = fullLineRects[rowIndex] ?? params.lineRect;
|
|
6264
|
+
rows.push({
|
|
6265
|
+
startOffset: currentRowStart,
|
|
6266
|
+
endOffset: currentRowEnd,
|
|
5794
6267
|
rect: toLayoutRect({
|
|
5795
|
-
rect,
|
|
6268
|
+
rect: domRect,
|
|
5796
6269
|
containerRect: params.containerRect,
|
|
5797
6270
|
scroll: params.scroll
|
|
5798
6271
|
})
|
|
5799
|
-
};
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
6272
|
+
});
|
|
6273
|
+
if (nextRowStart === null) {
|
|
6274
|
+
break;
|
|
6275
|
+
}
|
|
6276
|
+
currentRowStart = nextRowStart;
|
|
6277
|
+
rowIndex += 1;
|
|
6278
|
+
const nextMeasurable = findFirstMeasurableOffset(currentRowStart);
|
|
6279
|
+
if (nextMeasurable === null) {
|
|
6280
|
+
break;
|
|
6281
|
+
}
|
|
6282
|
+
currentRowTop = ((_b = fullLineRects[rowIndex]) == null ? void 0 : _b.top) ?? currentRowTop;
|
|
6283
|
+
searchFrom = nextMeasurable + 1;
|
|
5808
6284
|
}
|
|
5809
6285
|
if (rows.length === 1) {
|
|
5810
6286
|
rows[0] = {
|
|
@@ -5876,6 +6352,44 @@ function measureLayoutModelFromDom(params) {
|
|
|
5876
6352
|
}
|
|
5877
6353
|
return buildLayoutModel(params.lines, measurer);
|
|
5878
6354
|
}
|
|
6355
|
+
function measureLayoutModelRangeFromDom(params) {
|
|
6356
|
+
const measurer = createDomLayoutMeasurer({
|
|
6357
|
+
root: params.root,
|
|
6358
|
+
container: params.container,
|
|
6359
|
+
lines: params.lines
|
|
6360
|
+
});
|
|
6361
|
+
if (!measurer) {
|
|
6362
|
+
return null;
|
|
6363
|
+
}
|
|
6364
|
+
const clampedStart = Math.max(0, Math.min(params.startLineIndex, params.lines.length - 1));
|
|
6365
|
+
const clampedEnd = Math.max(clampedStart, Math.min(params.endLineIndex, params.lines.length - 1));
|
|
6366
|
+
const lineOffsets = getLineOffsets(params.lines);
|
|
6367
|
+
let lineStartOffset = lineOffsets[clampedStart] ?? 0;
|
|
6368
|
+
const layouts = [];
|
|
6369
|
+
for (let lineIndex = clampedStart; lineIndex <= clampedEnd; lineIndex += 1) {
|
|
6370
|
+
const lineInfo = params.lines[lineIndex];
|
|
6371
|
+
if (!lineInfo) {
|
|
6372
|
+
continue;
|
|
6373
|
+
}
|
|
6374
|
+
const measurement = measurer.measureLine({
|
|
6375
|
+
lineIndex: lineInfo.lineIndex,
|
|
6376
|
+
lineText: lineInfo.text,
|
|
6377
|
+
lineLength: lineInfo.cursorLength,
|
|
6378
|
+
lineHasNewline: lineInfo.hasNewline,
|
|
6379
|
+
top: 0
|
|
6380
|
+
});
|
|
6381
|
+
layouts.push({
|
|
6382
|
+
lineIndex: lineInfo.lineIndex,
|
|
6383
|
+
lineStartOffset,
|
|
6384
|
+
lineLength: lineInfo.cursorLength,
|
|
6385
|
+
lineHasNewline: lineInfo.hasNewline,
|
|
6386
|
+
lineBox: measurement.lineBox,
|
|
6387
|
+
rows: measurement.rows
|
|
6388
|
+
});
|
|
6389
|
+
lineStartOffset += lineInfo.cursorLength + (lineInfo.hasNewline ? 1 : 0);
|
|
6390
|
+
}
|
|
6391
|
+
return { container: measurer.container, lines: layouts };
|
|
6392
|
+
}
|
|
5879
6393
|
function getLineElement(root, lineIndex) {
|
|
5880
6394
|
return root.querySelector(`[data-line-index="${lineIndex}"]`);
|
|
5881
6395
|
}
|
|
@@ -6069,7 +6583,7 @@ function computeSelectionRects(layout, selection, measurer) {
|
|
|
6069
6583
|
return rects;
|
|
6070
6584
|
}
|
|
6071
6585
|
function computeCaretRect(caret) {
|
|
6072
|
-
const height = caret.
|
|
6586
|
+
const height = caret.fontSize * 1.2;
|
|
6073
6587
|
const contentHeight = caret.lineRect.height > 0 ? Math.max(
|
|
6074
6588
|
0,
|
|
6075
6589
|
caret.lineRect.height - caret.padding.top - caret.padding.bottom
|
|
@@ -6091,7 +6605,17 @@ function getSelectionGeometry(params) {
|
|
|
6091
6605
|
end: selection.start,
|
|
6092
6606
|
affinity: selection.affinity
|
|
6093
6607
|
};
|
|
6094
|
-
const layout = shouldMeasureLayout(normalized) ?
|
|
6608
|
+
const layout = shouldMeasureLayout(normalized) ? (() => {
|
|
6609
|
+
const startLine2 = resolveOffsetToLine(docLines, normalized.start);
|
|
6610
|
+
const endLine = resolveOffsetToLine(docLines, normalized.end);
|
|
6611
|
+
return measureLayoutModelRangeFromDom({
|
|
6612
|
+
lines: docLines,
|
|
6613
|
+
root,
|
|
6614
|
+
container,
|
|
6615
|
+
startLineIndex: startLine2.lineIndex,
|
|
6616
|
+
endLineIndex: endLine.lineIndex
|
|
6617
|
+
});
|
|
6618
|
+
})() : null;
|
|
6095
6619
|
const containerRect = container.getBoundingClientRect();
|
|
6096
6620
|
const scroll = { top: container.scrollTop, left: container.scrollLeft };
|
|
6097
6621
|
const startLine = resolveOffsetToLine(docLines, normalized.start);
|
|
@@ -6123,6 +6647,7 @@ function getSelectionGeometry(params) {
|
|
|
6123
6647
|
scroll
|
|
6124
6648
|
}),
|
|
6125
6649
|
lineLength: lineInfo.cursorLength,
|
|
6650
|
+
fontSize: getComputedFontSize(lineElement),
|
|
6126
6651
|
padding: getComputedVerticalPadding(lineElement)
|
|
6127
6652
|
};
|
|
6128
6653
|
const caretRect = computeCaretRect(caretMeasurement);
|
|
@@ -6166,6 +6691,7 @@ function getSelectionGeometry(params) {
|
|
|
6166
6691
|
scroll
|
|
6167
6692
|
}),
|
|
6168
6693
|
lineLength: lineInfo.cursorLength,
|
|
6694
|
+
fontSize: getComputedFontSize(focusLineElement),
|
|
6169
6695
|
padding: getComputedVerticalPadding(focusLineElement)
|
|
6170
6696
|
};
|
|
6171
6697
|
focusRect = computeCaretRect(caretMeasurement);
|
|
@@ -6292,6 +6818,11 @@ function getComputedVerticalPadding(lineElement) {
|
|
|
6292
6818
|
bottom: Number.isFinite(bottom) ? bottom : 0
|
|
6293
6819
|
};
|
|
6294
6820
|
}
|
|
6821
|
+
function getComputedFontSize(lineElement) {
|
|
6822
|
+
const fontSize = window.getComputedStyle(lineElement).fontSize;
|
|
6823
|
+
const parsed = Number.parseFloat(fontSize);
|
|
6824
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 16;
|
|
6825
|
+
}
|
|
6295
6826
|
function rectRight(rect) {
|
|
6296
6827
|
return rect.left + rect.width;
|
|
6297
6828
|
}
|
|
@@ -6689,6 +7220,36 @@ function nextWordBreak(text, offset) {
|
|
|
6689
7220
|
}
|
|
6690
7221
|
return text.length;
|
|
6691
7222
|
}
|
|
7223
|
+
const MAX_HTML_INPUT_LENGTH = 5e5;
|
|
7224
|
+
const MAX_MARKDOWN_OUTPUT_LENGTH = 1e5;
|
|
7225
|
+
function isHTMLElement(node) {
|
|
7226
|
+
return node !== null && node.nodeType === Node.ELEMENT_NODE;
|
|
7227
|
+
}
|
|
7228
|
+
function isElement(node) {
|
|
7229
|
+
return node !== null && node.nodeType === Node.ELEMENT_NODE;
|
|
7230
|
+
}
|
|
7231
|
+
const CLEANUP_PATTERNS = {
|
|
7232
|
+
unescapeHeaders: /^\\(#{1,6})\s+/gm,
|
|
7233
|
+
unescapeBlockquote: /^\\>/gm,
|
|
7234
|
+
unescapeMarkdown: /\\([*_`~[\]])/g,
|
|
7235
|
+
unescapeListBullets: /^(\s*)\\([-*+])(\s+)/gm,
|
|
7236
|
+
unescapeListNumbers: /^(\s*)(\d+)\\\.(\s+)/gm,
|
|
7237
|
+
normalizeBullets: /^(\s*)[-*+](\s{2,})/gm,
|
|
7238
|
+
normalizeNumbers: /^[\s]*\d+\.[\s]+/gm,
|
|
7239
|
+
normalizeHeaders: /^(#{1,6})[\s]{2,}/gm,
|
|
7240
|
+
removeTrailingSpaces: /[ \t]+$/gm,
|
|
7241
|
+
headersInBlockquotes: /^>\s*(#{1,6}\s+.*)/gm,
|
|
7242
|
+
excessiveNewlines: /\n{3,}/g,
|
|
7243
|
+
interlacedTableGaps: /(\|[^\n]*\|)\s*\n\s*\n+\s*(\|[^\n]*\|)/g,
|
|
7244
|
+
complexTableGaps: /(\|[^\n]*\|)(\s*\n){2,}(\|[^\n]*\|)/g
|
|
7245
|
+
};
|
|
7246
|
+
const HTML_PREPROCESSING_PATTERNS = {
|
|
7247
|
+
removeStyleAndDataAttrs: /\s(?:style|data-[^=]*|id)="[^"]*"/gi,
|
|
7248
|
+
removeNonCodeClasses: /\sclass="(?![^"]*(?:language-|hljs))[^"]*"/gi,
|
|
7249
|
+
removeEmptyElements: /<(\w+)[^>]*>\s*<\/\1>/gi,
|
|
7250
|
+
normalizeSpaces: /[ \t]{2,}/g,
|
|
7251
|
+
reduceBlankLines: /\n\s*\n/g
|
|
7252
|
+
};
|
|
6692
7253
|
const turndownService = new TurndownService({
|
|
6693
7254
|
headingStyle: "atx",
|
|
6694
7255
|
bulletListMarker: "-",
|
|
@@ -6706,6 +7267,13 @@ turndownService.addRule("strikethrough", {
|
|
|
6706
7267
|
turndownService.addRule("codeBlock", {
|
|
6707
7268
|
filter: "pre",
|
|
6708
7269
|
replacement: (content, node) => {
|
|
7270
|
+
if (!isHTMLElement(node)) {
|
|
7271
|
+
return `
|
|
7272
|
+
\`\`\`
|
|
7273
|
+
${content}
|
|
7274
|
+
\`\`\`
|
|
7275
|
+
`;
|
|
7276
|
+
}
|
|
6709
7277
|
const codeElement = node.querySelector("code");
|
|
6710
7278
|
if (codeElement) {
|
|
6711
7279
|
const className = codeElement.className || "";
|
|
@@ -6724,12 +7292,308 @@ ${content}
|
|
|
6724
7292
|
`;
|
|
6725
7293
|
}
|
|
6726
7294
|
});
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
7295
|
+
turndownService.addRule("tableRow", {
|
|
7296
|
+
filter: "tr",
|
|
7297
|
+
replacement: (_content, node) => {
|
|
7298
|
+
var _a;
|
|
7299
|
+
if (!isHTMLElement(node)) {
|
|
7300
|
+
return "";
|
|
7301
|
+
}
|
|
7302
|
+
const isHeaderRow = ((_a = node.parentNode) == null ? void 0 : _a.nodeName) === "THEAD";
|
|
7303
|
+
const cells = Array.from(node.querySelectorAll("td, th"));
|
|
7304
|
+
const cellContents = cells.map((cell) => {
|
|
7305
|
+
const text = cell.textContent || "";
|
|
7306
|
+
return text.replace(/\|/g, "\\|").trim();
|
|
7307
|
+
});
|
|
7308
|
+
let result = "| " + cellContents.join(" | ") + " |\n";
|
|
7309
|
+
if (isHeaderRow) {
|
|
7310
|
+
const separators = cells.map((cell) => {
|
|
7311
|
+
const align = cell.getAttribute("align");
|
|
7312
|
+
if (align === "center") {
|
|
7313
|
+
return ":-------------:";
|
|
7314
|
+
}
|
|
7315
|
+
if (align === "right") {
|
|
7316
|
+
return "-------------:";
|
|
7317
|
+
}
|
|
7318
|
+
return "-------------";
|
|
7319
|
+
});
|
|
7320
|
+
result += "| " + separators.join(" | ") + " |\n";
|
|
7321
|
+
}
|
|
7322
|
+
return result;
|
|
7323
|
+
}
|
|
7324
|
+
});
|
|
7325
|
+
turndownService.addRule("taskList", {
|
|
7326
|
+
filter: (node) => {
|
|
7327
|
+
if (!isHTMLElement(node)) {
|
|
7328
|
+
return false;
|
|
7329
|
+
}
|
|
7330
|
+
if (node.nodeName !== "LI") {
|
|
7331
|
+
return false;
|
|
7332
|
+
}
|
|
7333
|
+
if (node.querySelector('input[type="checkbox"]') !== null) {
|
|
7334
|
+
return true;
|
|
7335
|
+
}
|
|
7336
|
+
const textContent = node.textContent || "";
|
|
7337
|
+
const hasCheckboxSymbols = /^[\s]*[☐☑✓✗[\]]/m.test(textContent) || /^[\s]*\[[ x]\]/m.test(textContent);
|
|
7338
|
+
const hasCheckboxClass = Boolean(
|
|
7339
|
+
node.className && (node.className.includes("task") || node.className.includes("checkbox") || node.className.includes("todo"))
|
|
7340
|
+
);
|
|
7341
|
+
return hasCheckboxSymbols || hasCheckboxClass;
|
|
7342
|
+
},
|
|
7343
|
+
replacement: (content, node) => {
|
|
7344
|
+
if (!isHTMLElement(node)) {
|
|
7345
|
+
return content;
|
|
7346
|
+
}
|
|
7347
|
+
const checkbox = node.querySelector('input[type="checkbox"]');
|
|
7348
|
+
const isCheckbox = checkbox instanceof HTMLInputElement && checkbox.type === "checkbox";
|
|
7349
|
+
let isChecked = false;
|
|
7350
|
+
if (isCheckbox) {
|
|
7351
|
+
isChecked = checkbox.checked;
|
|
7352
|
+
} else {
|
|
7353
|
+
const textContent2 = node.textContent || "";
|
|
7354
|
+
isChecked = /^[\s]*[☑✓✗]/.test(textContent2) || /^[\s]*\[x\]/i.test(textContent2);
|
|
7355
|
+
}
|
|
7356
|
+
const prefix = isChecked ? "- [x] " : "- [ ] ";
|
|
7357
|
+
let textContent = content;
|
|
7358
|
+
textContent = textContent.replace(/^\s*\[[ x]\]\s*/gi, "");
|
|
7359
|
+
textContent = textContent.replace(/^\s*[☐☑✓✗]\s*/g, "");
|
|
7360
|
+
textContent = textContent.replace(/^\s*\[[x ]\]\s*/gi, "");
|
|
7361
|
+
textContent = textContent.replace(/^\s*\\?\[[ x]\\?\]\s*/gi, "");
|
|
7362
|
+
textContent = textContent.replace(/\\?\[\\?\s*\\?\]\\?\s*/g, "");
|
|
7363
|
+
return prefix + textContent.trim() + "\n";
|
|
7364
|
+
}
|
|
7365
|
+
});
|
|
7366
|
+
turndownService.addRule("list", {
|
|
7367
|
+
filter: ["ul", "ol"],
|
|
7368
|
+
replacement: (content, node) => {
|
|
7369
|
+
const parent = node.parentNode;
|
|
7370
|
+
const isNested = isElement(parent) && parent.tagName === "LI";
|
|
7371
|
+
if (isNested) {
|
|
7372
|
+
return "\n" + content;
|
|
7373
|
+
}
|
|
7374
|
+
return "\n" + content + "\n";
|
|
7375
|
+
}
|
|
7376
|
+
});
|
|
7377
|
+
turndownService.addRule("blockquote", {
|
|
7378
|
+
filter: "blockquote",
|
|
7379
|
+
replacement: (content) => {
|
|
7380
|
+
const lines = content.trim().split("\n");
|
|
7381
|
+
const processedLines = lines.map((line) => {
|
|
7382
|
+
const trimmed = line.trim();
|
|
7383
|
+
if (!trimmed) {
|
|
7384
|
+
return ">";
|
|
7385
|
+
}
|
|
7386
|
+
const existingQuotes = trimmed.match(/^(>\s*)+/);
|
|
7387
|
+
if (existingQuotes) {
|
|
7388
|
+
return existingQuotes[0] + " " + trimmed;
|
|
7389
|
+
}
|
|
7390
|
+
return "> " + trimmed;
|
|
7391
|
+
});
|
|
7392
|
+
return "\n" + processedLines.join("\n") + "\n";
|
|
7393
|
+
}
|
|
7394
|
+
});
|
|
7395
|
+
turndownService.addRule("horizontalRule", {
|
|
7396
|
+
filter: "hr",
|
|
7397
|
+
replacement: () => "\n---\n"
|
|
7398
|
+
});
|
|
7399
|
+
turndownService.addRule("inlineCode", {
|
|
7400
|
+
filter: (node) => {
|
|
7401
|
+
const parent = node.parentNode;
|
|
7402
|
+
return node.nodeName === "CODE" && !(isElement(parent) && parent.tagName === "PRE");
|
|
7403
|
+
},
|
|
7404
|
+
replacement: (content) => {
|
|
7405
|
+
const backtickCount = Math.max(
|
|
7406
|
+
1,
|
|
7407
|
+
(content.match(/`+/g) || []).reduce(
|
|
7408
|
+
(max, match) => Math.max(max, match.length),
|
|
7409
|
+
0
|
|
7410
|
+
) + 1
|
|
7411
|
+
);
|
|
7412
|
+
const delimiter = "`".repeat(backtickCount);
|
|
7413
|
+
return delimiter + content + delimiter;
|
|
7414
|
+
}
|
|
7415
|
+
});
|
|
7416
|
+
turndownService.addRule("image", {
|
|
7417
|
+
filter: "img",
|
|
7418
|
+
replacement: (_content, node) => {
|
|
7419
|
+
if (!isHTMLElement(node)) {
|
|
7420
|
+
return "";
|
|
7421
|
+
}
|
|
7422
|
+
const src = node.getAttribute("src") || "";
|
|
7423
|
+
const alt = node.getAttribute("alt") || "";
|
|
7424
|
+
const title = node.getAttribute("title");
|
|
7425
|
+
if (title) {
|
|
7426
|
+
return ``;
|
|
7427
|
+
}
|
|
7428
|
+
return ``;
|
|
7429
|
+
}
|
|
7430
|
+
});
|
|
7431
|
+
turndownService.addRule("highlight", {
|
|
7432
|
+
filter: (node) => {
|
|
7433
|
+
var _a, _b;
|
|
7434
|
+
if (!isHTMLElement(node)) {
|
|
7435
|
+
return false;
|
|
7436
|
+
}
|
|
7437
|
+
return node.nodeName === "MARK" || node.nodeName === "SPAN" && (((_a = node.style) == null ? void 0 : _a.backgroundColor) === "yellow" || ((_b = node.className) == null ? void 0 : _b.includes("highlight")));
|
|
7438
|
+
},
|
|
7439
|
+
replacement: (content) => `==${content}==`
|
|
7440
|
+
});
|
|
7441
|
+
turndownService.addRule("headerWithId", {
|
|
7442
|
+
filter: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
|
7443
|
+
replacement: (content, node) => {
|
|
7444
|
+
if (!isHTMLElement(node)) {
|
|
7445
|
+
return content;
|
|
7446
|
+
}
|
|
7447
|
+
const rawLevel = parseInt(node.nodeName.charAt(1));
|
|
7448
|
+
const level = Math.min(rawLevel, 3);
|
|
7449
|
+
const hashes = "#".repeat(level);
|
|
7450
|
+
const id = node.getAttribute("id");
|
|
7451
|
+
if (id) {
|
|
7452
|
+
return `
|
|
7453
|
+
${hashes} ${content} {#${id}}
|
|
7454
|
+
`;
|
|
7455
|
+
}
|
|
7456
|
+
return `
|
|
7457
|
+
${hashes} ${content}
|
|
7458
|
+
`;
|
|
7459
|
+
}
|
|
7460
|
+
});
|
|
7461
|
+
function processTextNodes(element) {
|
|
7462
|
+
const spans = Array.from(element.querySelectorAll("span"));
|
|
7463
|
+
spans.forEach((span) => {
|
|
7464
|
+
var _a;
|
|
7465
|
+
const textContent = span.textContent || "";
|
|
7466
|
+
const textNode = document.createTextNode(textContent);
|
|
7467
|
+
(_a = span.parentNode) == null ? void 0 : _a.replaceChild(textNode, span);
|
|
7468
|
+
});
|
|
7469
|
+
}
|
|
7470
|
+
function detectSourceApp(html) {
|
|
7471
|
+
const detectionPatterns = {
|
|
7472
|
+
notion: ["notion-", "notranslate"],
|
|
7473
|
+
github: ["github.com", "js-file-line-container"],
|
|
7474
|
+
slack: ["slack-", "c-message"],
|
|
7475
|
+
"google-docs": ["docs.google.com", "kix-"]
|
|
7476
|
+
};
|
|
7477
|
+
for (const [app, patterns] of Object.entries(detectionPatterns)) {
|
|
7478
|
+
if (patterns.some((pattern) => html.includes(pattern))) {
|
|
7479
|
+
return app;
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
return "unknown";
|
|
7483
|
+
}
|
|
7484
|
+
function preprocessForApp(html, app) {
|
|
7485
|
+
switch (app) {
|
|
7486
|
+
case "notion":
|
|
7487
|
+
return html.replace(/<div[^>]*class="[^"]*notion-[^"]*"[^>]*>/gi, "<div>").replace(/<span[^>]*class="[^"]*notion-[^"]*"[^>]*>/gi, "<span>").replace(/<details[^>]*>/gi, "<div>").replace(/<\/details>/gi, "</div>").replace(/<summary[^>]*>/gi, "<strong>").replace(/<\/summary>/gi, "</strong>");
|
|
7488
|
+
case "github":
|
|
7489
|
+
return html.replace(/<td[^>]*class="[^"]*blob-num[^"]*"[^>]*>.*?<\/td>/gi, "").replace(/<span[^>]*class="[^"]*pl-[^"]*"[^>]*>/gi, "<span>").replace(/<span[^>]*class="[^"]*highlight[^"]*"[^>]*>/gi, "<span>");
|
|
7490
|
+
case "slack":
|
|
7491
|
+
return html.replace(/<span[^>]*class="[^"]*c-member[^"]*"[^>]*>/gi, "<span>").replace(/<span[^>]*data-stringify-type="mention"[^>]*>/gi, "<span>").replace(
|
|
7492
|
+
/<span[^>]*class="[^"]*c-emoji[^"]*"[^>]*>([^<]*)<\/span>/gi,
|
|
7493
|
+
"$1"
|
|
7494
|
+
);
|
|
7495
|
+
case "google-docs":
|
|
7496
|
+
return html.replace(
|
|
7497
|
+
/<span[^>]*style="[^"]*font-weight:[^;"]*bold[^"]*"[^>]*>/gi,
|
|
7498
|
+
"<strong>"
|
|
7499
|
+
).replace(
|
|
7500
|
+
/<span[^>]*style="[^"]*font-style:[^;"]*italic[^"]*"[^>]*>/gi,
|
|
7501
|
+
"<em>"
|
|
7502
|
+
).replace(/<\/span>/gi, "").replace(/<p[^>]*style="[^"]*"[^>]*>/gi, "<p>");
|
|
7503
|
+
default:
|
|
7504
|
+
return html;
|
|
7505
|
+
}
|
|
7506
|
+
}
|
|
7507
|
+
function cleanupMarkdown(markdown) {
|
|
7508
|
+
return markdown.replace(CLEANUP_PATTERNS.unescapeHeaders, "$1 ").replace(CLEANUP_PATTERNS.unescapeBlockquote, ">").replace(CLEANUP_PATTERNS.unescapeMarkdown, "$1").replace(CLEANUP_PATTERNS.unescapeListBullets, "$1$2$3").replace(CLEANUP_PATTERNS.unescapeListNumbers, "$1$2.$3").replace(CLEANUP_PATTERNS.normalizeBullets, "$1- ").replace(CLEANUP_PATTERNS.normalizeNumbers, (match) => {
|
|
7509
|
+
var _a;
|
|
7510
|
+
const num = ((_a = match.match(/\d+/)) == null ? void 0 : _a[0]) || "1";
|
|
7511
|
+
return `${num}. `;
|
|
7512
|
+
}).replace(CLEANUP_PATTERNS.normalizeHeaders, "$1 ").replace(CLEANUP_PATTERNS.removeTrailingSpaces, "").replace(CLEANUP_PATTERNS.headersInBlockquotes, "\n$1").replace(CLEANUP_PATTERNS.excessiveNewlines, "\n\n").replace(CLEANUP_PATTERNS.interlacedTableGaps, "$1\n$2").replace(CLEANUP_PATTERNS.complexTableGaps, "$1\n$3").replace(/\*\*\[([^\]]+?)\]\(([^)]+?)\)\*\*/g, "[**$1**]($2)").replace(/__\[([^\]]+?)\]\(([^)]+?)\)__/g, "[**$1**]($2)").replace(/\*\[([^\]]+?)\]\(([^)]+?)\)\*/g, "[*$1*]($2)").replace(/_\[([^\]]+?)\]\(([^)]+?)\)_/g, "[*$1*]($2)").trim();
|
|
7513
|
+
}
|
|
7514
|
+
function preprocessHtml(html) {
|
|
7515
|
+
const sourceApp = detectSourceApp(html);
|
|
7516
|
+
let processedHtml = preprocessForApp(html, sourceApp);
|
|
7517
|
+
const parser = new DOMParser();
|
|
7518
|
+
const doc = parser.parseFromString(processedHtml, "text/html");
|
|
7519
|
+
if (doc.body) {
|
|
7520
|
+
processTextNodes(doc.body);
|
|
7521
|
+
processedHtml = doc.body.innerHTML;
|
|
7522
|
+
}
|
|
7523
|
+
return processedHtml.replace(HTML_PREPROCESSING_PATTERNS.removeStyleAndDataAttrs, "").replace(HTML_PREPROCESSING_PATTERNS.removeNonCodeClasses, "").replace(HTML_PREPROCESSING_PATTERNS.removeEmptyElements, "").replace(HTML_PREPROCESSING_PATTERNS.normalizeSpaces, " ").replace(HTML_PREPROCESSING_PATTERNS.reduceBlankLines, "\n\n").trim();
|
|
7524
|
+
}
|
|
7525
|
+
function sanitizeContent(content) {
|
|
7526
|
+
return content.replace(/<script[^>]*>.*?<\/script>/gi, "").replace(
|
|
7527
|
+
/<(?:iframe|object|embed)[^>]*>.*?<\/(?:iframe|object|embed)>/gi,
|
|
7528
|
+
""
|
|
7529
|
+
);
|
|
7530
|
+
}
|
|
7531
|
+
function limitContentLength(content, maxLength = MAX_MARKDOWN_OUTPUT_LENGTH) {
|
|
7532
|
+
return content.substring(0, maxLength);
|
|
7533
|
+
}
|
|
7534
|
+
function sanitizeMarkdown(markdown) {
|
|
7535
|
+
return limitContentLength(sanitizeContent(markdown));
|
|
7536
|
+
}
|
|
7537
|
+
function shouldProcessPaste(htmlContent) {
|
|
7538
|
+
if (htmlContent.length > MAX_HTML_INPUT_LENGTH) {
|
|
7539
|
+
console.warn("HTML content too large for paste processing");
|
|
7540
|
+
return false;
|
|
7541
|
+
}
|
|
7542
|
+
const hasFormatting = /<(?:strong|b|em|i|u|s|del|strike|code|pre|h[1-6]|blockquote|ul|ol|li|table|tr|td|th|a|img|mark|span|div)[\s>]/i.test(
|
|
7543
|
+
htmlContent
|
|
7544
|
+
);
|
|
7545
|
+
if (!hasFormatting) {
|
|
7546
|
+
return false;
|
|
7547
|
+
}
|
|
7548
|
+
if (/<img\s/i.test(htmlContent)) {
|
|
7549
|
+
return true;
|
|
7550
|
+
}
|
|
7551
|
+
const strippedContent = htmlContent.replace(/<[^>]*>/g, "").trim();
|
|
7552
|
+
if (!strippedContent || strippedContent.length < 3) {
|
|
7553
|
+
return false;
|
|
7554
|
+
}
|
|
7555
|
+
return true;
|
|
7556
|
+
}
|
|
7557
|
+
function normalizeListPrefixes(content) {
|
|
7558
|
+
const lines = content.split("\n");
|
|
7559
|
+
let currentListType = null;
|
|
7560
|
+
let currentNumber = 1;
|
|
7561
|
+
return lines.map((line) => {
|
|
7562
|
+
const match = line.match(/^(\s*)([-*+]|\d+\.)( +)(.*)$/);
|
|
7563
|
+
if (match) {
|
|
7564
|
+
const [, indent, marker, , listContent] = match;
|
|
7565
|
+
if (currentListType === null) {
|
|
7566
|
+
currentListType = /\d+\./.test(marker) ? "numbered" : "bullet";
|
|
7567
|
+
}
|
|
7568
|
+
const newMarker = currentListType === "bullet" ? "-" : `${currentNumber}.`;
|
|
7569
|
+
if (currentListType === "numbered") {
|
|
7570
|
+
currentNumber += 1;
|
|
7571
|
+
}
|
|
7572
|
+
return `${indent}${newMarker} ${listContent}`;
|
|
7573
|
+
}
|
|
7574
|
+
return line;
|
|
7575
|
+
}).join("\n");
|
|
7576
|
+
}
|
|
7577
|
+
function convertHtmlToMarkdown(html) {
|
|
7578
|
+
try {
|
|
7579
|
+
const processedHtml = preprocessHtml(html);
|
|
7580
|
+
const markdown = turndownService.turndown(processedHtml);
|
|
7581
|
+
return cleanupMarkdown(markdown);
|
|
7582
|
+
} catch (error) {
|
|
7583
|
+
console.error("Error converting HTML to markdown:", error);
|
|
6730
7584
|
return "";
|
|
6731
7585
|
}
|
|
6732
|
-
|
|
7586
|
+
}
|
|
7587
|
+
function htmlToMarkdownForPaste(htmlContent) {
|
|
7588
|
+
if (!shouldProcessPaste(htmlContent)) {
|
|
7589
|
+
return null;
|
|
7590
|
+
}
|
|
7591
|
+
const markdown = convertHtmlToMarkdown(htmlContent);
|
|
7592
|
+
if (!markdown.trim()) {
|
|
7593
|
+
return null;
|
|
7594
|
+
}
|
|
7595
|
+
const normalizedMarkdown = normalizeListPrefixes(markdown);
|
|
7596
|
+
return sanitizeMarkdown(normalizedMarkdown).replace(/\r\n?/g, "\n");
|
|
6733
7597
|
}
|
|
6734
7598
|
const defaultSelection = { start: 0, end: 0, affinity: "forward" };
|
|
6735
7599
|
const COMPOSITION_COMMIT_CLEAR_DELAY_MS = 50;
|
|
@@ -6759,10 +7623,13 @@ class CakeEngine {
|
|
|
6759
7623
|
this.caretBlinkTimeoutId = null;
|
|
6760
7624
|
this.overlayUpdateId = null;
|
|
6761
7625
|
this.scrollCaretIntoViewId = null;
|
|
7626
|
+
this.selectionRectElements = [];
|
|
7627
|
+
this.lastSelectionRects = null;
|
|
6762
7628
|
this.extensionsRoot = null;
|
|
6763
7629
|
this.placeholderRoot = null;
|
|
6764
7630
|
this.lastFocusRect = null;
|
|
6765
7631
|
this.verticalNavGoalX = null;
|
|
7632
|
+
this.lastRenderPerf = null;
|
|
6766
7633
|
this.history = {
|
|
6767
7634
|
undoStack: [],
|
|
6768
7635
|
redoStack: [],
|
|
@@ -6816,6 +7683,9 @@ class CakeEngine {
|
|
|
6816
7683
|
set state(value) {
|
|
6817
7684
|
this._state = value;
|
|
6818
7685
|
}
|
|
7686
|
+
getLastRenderPerf() {
|
|
7687
|
+
return this.lastRenderPerf;
|
|
7688
|
+
}
|
|
6819
7689
|
isEventTargetInContentRoot(target) {
|
|
6820
7690
|
if (target === this.container) {
|
|
6821
7691
|
return true;
|
|
@@ -6852,6 +7722,9 @@ class CakeEngine {
|
|
|
6852
7722
|
getSelection() {
|
|
6853
7723
|
return this.state.selection;
|
|
6854
7724
|
}
|
|
7725
|
+
getCursorLength() {
|
|
7726
|
+
return this.state.map.cursorLength;
|
|
7727
|
+
}
|
|
6855
7728
|
getFocusRect() {
|
|
6856
7729
|
return this.lastFocusRect;
|
|
6857
7730
|
}
|
|
@@ -6906,12 +7779,18 @@ class CakeEngine {
|
|
|
6906
7779
|
if (!this.isComposing) {
|
|
6907
7780
|
this.applySelection(this.state.selection);
|
|
6908
7781
|
}
|
|
7782
|
+
this.scheduleScrollCaretIntoView();
|
|
6909
7783
|
}
|
|
6910
7784
|
setValue({ value, selection }) {
|
|
6911
|
-
const
|
|
6912
|
-
if (
|
|
7785
|
+
const valueChanged = value !== this.state.source;
|
|
7786
|
+
if (!valueChanged && selection === void 0) {
|
|
7787
|
+
return;
|
|
7788
|
+
}
|
|
7789
|
+
if (!valueChanged && selection !== void 0) {
|
|
7790
|
+
this.setSelection(selection);
|
|
6913
7791
|
return;
|
|
6914
7792
|
}
|
|
7793
|
+
const nextSelection = selection ?? this.state.selection;
|
|
6915
7794
|
this.state = this.runtime.createState(value, nextSelection);
|
|
6916
7795
|
this.render();
|
|
6917
7796
|
}
|
|
@@ -6976,7 +7855,7 @@ class CakeEngine {
|
|
|
6976
7855
|
}
|
|
6977
7856
|
executeCommand(command) {
|
|
6978
7857
|
var _a;
|
|
6979
|
-
const shouldOpenLinkPopover =
|
|
7858
|
+
const shouldOpenLinkPopover = "openPopover" in command && command.openPopover === true;
|
|
6980
7859
|
const nextState = this.runtime.applyEdit(command, this.state);
|
|
6981
7860
|
if (nextState === this.state) {
|
|
6982
7861
|
return false;
|
|
@@ -7151,6 +8030,14 @@ class CakeEngine {
|
|
|
7151
8030
|
this.patchedCaretRangeFromPoint = null;
|
|
7152
8031
|
}
|
|
7153
8032
|
render() {
|
|
8033
|
+
const perfEnabled = this.container.dataset.cakePerf === "1";
|
|
8034
|
+
let perfStart = 0;
|
|
8035
|
+
let renderStart = 0;
|
|
8036
|
+
let renderAndMapMs = 0;
|
|
8037
|
+
let applySelectionMs = 0;
|
|
8038
|
+
if (perfEnabled) {
|
|
8039
|
+
perfStart = performance.now();
|
|
8040
|
+
}
|
|
7154
8041
|
if (!this.contentRoot) {
|
|
7155
8042
|
const containerPosition = window.getComputedStyle(
|
|
7156
8043
|
this.container
|
|
@@ -7166,16 +8053,40 @@ class CakeEngine {
|
|
|
7166
8053
|
this.container.replaceChildren(this.contentRoot, overlay, extensionsRoot);
|
|
7167
8054
|
this.attachDragListeners();
|
|
7168
8055
|
}
|
|
8056
|
+
if (perfEnabled) {
|
|
8057
|
+
renderStart = performance.now();
|
|
8058
|
+
}
|
|
7169
8059
|
const { content, map } = renderDocContent(
|
|
7170
8060
|
this.state.doc,
|
|
7171
8061
|
this.extensions,
|
|
7172
8062
|
this.contentRoot
|
|
7173
8063
|
);
|
|
7174
|
-
this.contentRoot.
|
|
8064
|
+
const existingChildren = Array.from(this.contentRoot.childNodes);
|
|
8065
|
+
const needsUpdate = content.length !== existingChildren.length || content.some((node, i) => node !== existingChildren[i]);
|
|
8066
|
+
if (needsUpdate) {
|
|
8067
|
+
this.contentRoot.replaceChildren(...content);
|
|
8068
|
+
}
|
|
7175
8069
|
this.domMap = map;
|
|
7176
|
-
|
|
7177
|
-
|
|
8070
|
+
if (perfEnabled) {
|
|
8071
|
+
renderAndMapMs = performance.now() - renderStart;
|
|
8072
|
+
}
|
|
8073
|
+
if (!this.isComposing && this.hasFocus()) {
|
|
8074
|
+
const selectionStart = perfEnabled ? performance.now() : 0;
|
|
7178
8075
|
this.applySelection(this.state.selection);
|
|
8076
|
+
if (perfEnabled) {
|
|
8077
|
+
applySelectionMs = performance.now() - selectionStart;
|
|
8078
|
+
}
|
|
8079
|
+
}
|
|
8080
|
+
if (perfEnabled) {
|
|
8081
|
+
const totalMs = performance.now() - perfStart;
|
|
8082
|
+
this.lastRenderPerf = {
|
|
8083
|
+
totalMs,
|
|
8084
|
+
renderAndMapMs,
|
|
8085
|
+
applySelectionMs,
|
|
8086
|
+
didUpdateDom: needsUpdate,
|
|
8087
|
+
blockCount: this.state.doc.blocks.length,
|
|
8088
|
+
runCount: map.runs.length
|
|
8089
|
+
};
|
|
7179
8090
|
}
|
|
7180
8091
|
this.updatePlaceholder();
|
|
7181
8092
|
this.scheduleOverlayUpdate();
|
|
@@ -7425,22 +8336,31 @@ class CakeEngine {
|
|
|
7425
8336
|
this.suppressSelectionChange = false;
|
|
7426
8337
|
return;
|
|
7427
8338
|
}
|
|
7428
|
-
const
|
|
7429
|
-
|
|
7430
|
-
if (
|
|
8339
|
+
const pendingHit = this.pendingClickHit;
|
|
8340
|
+
const selection = this.state.selection;
|
|
8341
|
+
if (pendingHit && selection.start !== selection.end) {
|
|
7431
8342
|
const newSelection = {
|
|
7432
|
-
start:
|
|
7433
|
-
end:
|
|
7434
|
-
affinity:
|
|
8343
|
+
start: pendingHit.cursorOffset,
|
|
8344
|
+
end: pendingHit.cursorOffset,
|
|
8345
|
+
affinity: pendingHit.affinity
|
|
7435
8346
|
};
|
|
8347
|
+
this.pendingClickHit = null;
|
|
8348
|
+
this.suppressSelectionChange = true;
|
|
7436
8349
|
this.state = this.runtime.updateSelection(this.state, newSelection, {
|
|
7437
8350
|
kind: "dom"
|
|
7438
8351
|
});
|
|
7439
8352
|
this.applySelection(this.state.selection);
|
|
7440
8353
|
(_b = this.onSelectionChange) == null ? void 0 : _b.call(this, this.state.selection);
|
|
7441
8354
|
this.scheduleOverlayUpdate();
|
|
8355
|
+
setTimeout(() => {
|
|
8356
|
+
this.suppressSelectionChange = false;
|
|
8357
|
+
}, 0);
|
|
8358
|
+
return;
|
|
7442
8359
|
}
|
|
7443
|
-
this.
|
|
8360
|
+
this.pendingClickHit = null;
|
|
8361
|
+
setTimeout(() => {
|
|
8362
|
+
this.suppressSelectionChange = false;
|
|
8363
|
+
}, 0);
|
|
7444
8364
|
return;
|
|
7445
8365
|
}
|
|
7446
8366
|
this.pendingClickHit = null;
|
|
@@ -7767,6 +8687,13 @@ class CakeEngine {
|
|
|
7767
8687
|
}
|
|
7768
8688
|
event.preventDefault();
|
|
7769
8689
|
clipboardData.setData("text/plain", text);
|
|
8690
|
+
const html = this.runtime.serializeSelectionToHtml(
|
|
8691
|
+
this.state,
|
|
8692
|
+
this.state.selection
|
|
8693
|
+
);
|
|
8694
|
+
if (html) {
|
|
8695
|
+
clipboardData.setData("text/html", html);
|
|
8696
|
+
}
|
|
7770
8697
|
}
|
|
7771
8698
|
handleCut(event) {
|
|
7772
8699
|
if (this.readOnly) {
|
|
@@ -7811,7 +8738,7 @@ class CakeEngine {
|
|
|
7811
8738
|
if (!command) {
|
|
7812
8739
|
continue;
|
|
7813
8740
|
}
|
|
7814
|
-
if (command
|
|
8741
|
+
if (isApplyEditCommand(command)) {
|
|
7815
8742
|
this.applyEdit(command);
|
|
7816
8743
|
} else {
|
|
7817
8744
|
this.executeCommand(command);
|
|
@@ -8331,6 +9258,39 @@ class CakeEngine {
|
|
|
8331
9258
|
return { start: target, end: target, affinity: direction };
|
|
8332
9259
|
}
|
|
8333
9260
|
const currentPos = selection.start;
|
|
9261
|
+
const currentAffinity = selection.affinity ?? "forward";
|
|
9262
|
+
const measurement = this.getLayoutForNavigation();
|
|
9263
|
+
if (measurement) {
|
|
9264
|
+
const { lines, layout } = measurement;
|
|
9265
|
+
const { rowStart, rowEnd } = getVisualRowBoundaries({
|
|
9266
|
+
lines,
|
|
9267
|
+
layout,
|
|
9268
|
+
offset: currentPos,
|
|
9269
|
+
affinity: currentAffinity
|
|
9270
|
+
});
|
|
9271
|
+
if (direction === "backward" && currentPos === rowStart && currentAffinity === "forward" && currentPos > 0) {
|
|
9272
|
+
const prevBoundaries = getVisualRowBoundaries({
|
|
9273
|
+
lines,
|
|
9274
|
+
layout,
|
|
9275
|
+
offset: currentPos,
|
|
9276
|
+
affinity: "backward"
|
|
9277
|
+
});
|
|
9278
|
+
if (prevBoundaries.rowEnd !== rowEnd || prevBoundaries.rowStart !== rowStart) {
|
|
9279
|
+
return { start: currentPos, end: currentPos, affinity: "backward" };
|
|
9280
|
+
}
|
|
9281
|
+
}
|
|
9282
|
+
if (direction === "forward" && currentPos === rowEnd && currentAffinity === "backward" && currentPos < this.state.map.cursorLength) {
|
|
9283
|
+
const nextBoundaries = getVisualRowBoundaries({
|
|
9284
|
+
lines,
|
|
9285
|
+
layout,
|
|
9286
|
+
offset: currentPos,
|
|
9287
|
+
affinity: "forward"
|
|
9288
|
+
});
|
|
9289
|
+
if (nextBoundaries.rowEnd !== rowEnd || nextBoundaries.rowStart !== rowStart) {
|
|
9290
|
+
return { start: currentPos, end: currentPos, affinity: "forward" };
|
|
9291
|
+
}
|
|
9292
|
+
}
|
|
9293
|
+
}
|
|
8334
9294
|
const nextPos = this.moveOffsetByChar(currentPos, direction);
|
|
8335
9295
|
if (nextPos === null) {
|
|
8336
9296
|
return null;
|
|
@@ -9020,6 +9980,7 @@ class CakeEngine {
|
|
|
9020
9980
|
}
|
|
9021
9981
|
this.overlayUpdateId = window.requestAnimationFrame(() => {
|
|
9022
9982
|
this.overlayUpdateId = null;
|
|
9983
|
+
this.updateExtensionsOverlayPosition();
|
|
9023
9984
|
this.updateSelectionOverlay();
|
|
9024
9985
|
});
|
|
9025
9986
|
}
|
|
@@ -9049,12 +10010,34 @@ class CakeEngine {
|
|
|
9049
10010
|
overlay.style.zIndex = "2";
|
|
9050
10011
|
const caret = document.createElement("div");
|
|
9051
10012
|
caret.className = "cake-caret";
|
|
10013
|
+
caret.style.position = "absolute";
|
|
9052
10014
|
caret.style.display = "none";
|
|
9053
10015
|
overlay.append(caret);
|
|
9054
10016
|
this.overlayRoot = overlay;
|
|
9055
10017
|
this.caretElement = caret;
|
|
10018
|
+
this.selectionRectElements = [];
|
|
10019
|
+
this.lastSelectionRects = null;
|
|
9056
10020
|
return overlay;
|
|
9057
10021
|
}
|
|
10022
|
+
selectionRectsEqual(prev, next) {
|
|
10023
|
+
if (!prev) {
|
|
10024
|
+
return false;
|
|
10025
|
+
}
|
|
10026
|
+
if (prev.length !== next.length) {
|
|
10027
|
+
return false;
|
|
10028
|
+
}
|
|
10029
|
+
for (let index = 0; index < prev.length; index += 1) {
|
|
10030
|
+
const a = prev[index];
|
|
10031
|
+
const b = next[index];
|
|
10032
|
+
if (!a || !b) {
|
|
10033
|
+
return false;
|
|
10034
|
+
}
|
|
10035
|
+
if (a.top !== b.top || a.left !== b.left || a.width !== b.width || a.height !== b.height) {
|
|
10036
|
+
return false;
|
|
10037
|
+
}
|
|
10038
|
+
}
|
|
10039
|
+
return true;
|
|
10040
|
+
}
|
|
9058
10041
|
ensureExtensionsRoot() {
|
|
9059
10042
|
if (this.extensionsRoot) {
|
|
9060
10043
|
return this.extensionsRoot;
|
|
@@ -9076,8 +10059,8 @@ class CakeEngine {
|
|
|
9076
10059
|
if (!this.extensionsRoot) {
|
|
9077
10060
|
return;
|
|
9078
10061
|
}
|
|
9079
|
-
const scrollTop = this.container.scrollTop;
|
|
9080
|
-
const scrollLeft = this.container.scrollLeft;
|
|
10062
|
+
const scrollTop = Math.max(0, this.container.scrollTop);
|
|
10063
|
+
const scrollLeft = Math.max(0, this.container.scrollLeft);
|
|
9081
10064
|
if (scrollTop === 0 && scrollLeft === 0) {
|
|
9082
10065
|
this.extensionsRoot.style.transform = "";
|
|
9083
10066
|
return;
|
|
@@ -9115,21 +10098,34 @@ class CakeEngine {
|
|
|
9115
10098
|
if (!this.overlayRoot || !this.caretElement) {
|
|
9116
10099
|
return;
|
|
9117
10100
|
}
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
10101
|
+
if (this.selectionRectsEqual(this.lastSelectionRects, rects)) {
|
|
10102
|
+
return;
|
|
10103
|
+
}
|
|
10104
|
+
this.lastSelectionRects = rects;
|
|
10105
|
+
while (this.selectionRectElements.length > rects.length) {
|
|
10106
|
+
const element = this.selectionRectElements.pop();
|
|
10107
|
+
element == null ? void 0 : element.remove();
|
|
10108
|
+
}
|
|
10109
|
+
if (this.selectionRectElements.length < rects.length) {
|
|
10110
|
+
const fragment = document.createDocumentFragment();
|
|
10111
|
+
while (this.selectionRectElements.length < rects.length) {
|
|
10112
|
+
const element = document.createElement("div");
|
|
10113
|
+
element.className = "cake-selection-rect";
|
|
10114
|
+
fragment.append(element);
|
|
10115
|
+
this.selectionRectElements.push(element);
|
|
10116
|
+
}
|
|
10117
|
+
this.overlayRoot.insertBefore(fragment, this.caretElement);
|
|
10118
|
+
}
|
|
10119
|
+
rects.forEach((rect, index) => {
|
|
10120
|
+
const element = this.selectionRectElements[index];
|
|
10121
|
+
if (!element) {
|
|
10122
|
+
return;
|
|
10123
|
+
}
|
|
9126
10124
|
element.style.top = `${rect.top}px`;
|
|
9127
10125
|
element.style.left = `${rect.left}px`;
|
|
9128
10126
|
element.style.width = `${rect.width}px`;
|
|
9129
10127
|
element.style.height = `${rect.height}px`;
|
|
9130
|
-
fragment.append(element);
|
|
9131
10128
|
});
|
|
9132
|
-
this.overlayRoot.insertBefore(fragment, this.caretElement);
|
|
9133
10129
|
}
|
|
9134
10130
|
updateCaret(position) {
|
|
9135
10131
|
if (!this.caretElement) {
|
|
@@ -9296,7 +10292,7 @@ class CakeEngine {
|
|
|
9296
10292
|
return { cursorOffset: cursor.cursorOffset, affinity: "backward" };
|
|
9297
10293
|
}
|
|
9298
10294
|
handlePointerDown(event) {
|
|
9299
|
-
var _a;
|
|
10295
|
+
var _a, _b, _c;
|
|
9300
10296
|
if (!this.isEventTargetInContentRoot(event.target)) {
|
|
9301
10297
|
return;
|
|
9302
10298
|
}
|
|
@@ -9361,13 +10357,51 @@ class CakeEngine {
|
|
|
9361
10357
|
}
|
|
9362
10358
|
}
|
|
9363
10359
|
}
|
|
9364
|
-
if (
|
|
9365
|
-
this.suppressSelectionChange = true;
|
|
10360
|
+
if (!event.shiftKey) {
|
|
9366
10361
|
const hit2 = this.hitTestFromClientPoint(event.clientX, event.clientY);
|
|
9367
|
-
if (hit2) {
|
|
10362
|
+
if (!hit2) {
|
|
10363
|
+
return;
|
|
10364
|
+
}
|
|
10365
|
+
if (selection.start !== selection.end) {
|
|
10366
|
+
const selStart2 = Math.min(selection.start, selection.end);
|
|
10367
|
+
const selEnd2 = Math.max(selection.start, selection.end);
|
|
10368
|
+
const clickedInsideSelection2 = hit2.cursorOffset >= selStart2 && hit2.cursorOffset <= selEnd2;
|
|
10369
|
+
if (clickedInsideSelection2) {
|
|
10370
|
+
this.suppressSelectionChange = false;
|
|
10371
|
+
this.blockTrustedTextDrag = true;
|
|
10372
|
+
this.pendingClickHit = hit2;
|
|
10373
|
+
} else {
|
|
10374
|
+
this.suppressSelectionChange = true;
|
|
10375
|
+
this.pendingClickHit = hit2;
|
|
10376
|
+
const newSelection = {
|
|
10377
|
+
start: hit2.cursorOffset,
|
|
10378
|
+
end: hit2.cursorOffset,
|
|
10379
|
+
affinity: hit2.affinity
|
|
10380
|
+
};
|
|
10381
|
+
this.state = this.runtime.updateSelection(this.state, newSelection, {
|
|
10382
|
+
kind: "dom"
|
|
10383
|
+
});
|
|
10384
|
+
this.applySelection(this.state.selection);
|
|
10385
|
+
(_b = this.onSelectionChange) == null ? void 0 : _b.call(this, this.state.selection);
|
|
10386
|
+
this.scheduleOverlayUpdate();
|
|
10387
|
+
return;
|
|
10388
|
+
}
|
|
10389
|
+
} else {
|
|
10390
|
+
this.suppressSelectionChange = true;
|
|
9368
10391
|
this.pendingClickHit = hit2;
|
|
10392
|
+
const newSelection = {
|
|
10393
|
+
start: hit2.cursorOffset,
|
|
10394
|
+
end: hit2.cursorOffset,
|
|
10395
|
+
affinity: hit2.affinity
|
|
10396
|
+
};
|
|
10397
|
+
this.state = this.runtime.updateSelection(this.state, newSelection, {
|
|
10398
|
+
kind: "dom"
|
|
10399
|
+
});
|
|
10400
|
+
this.applySelection(this.state.selection);
|
|
10401
|
+
(_c = this.onSelectionChange) == null ? void 0 : _c.call(this, this.state.selection);
|
|
10402
|
+
this.scheduleOverlayUpdate();
|
|
10403
|
+
return;
|
|
9369
10404
|
}
|
|
9370
|
-
return;
|
|
9371
10405
|
}
|
|
9372
10406
|
this.suppressSelectionChange = false;
|
|
9373
10407
|
const selStart = Math.min(selection.start, selection.end);
|
|
@@ -9479,10 +10513,6 @@ class CakeEngine {
|
|
|
9479
10513
|
}
|
|
9480
10514
|
handlePointerUp(event) {
|
|
9481
10515
|
this.blockTrustedTextDrag = false;
|
|
9482
|
-
if (this.pendingClickHit) {
|
|
9483
|
-
this.pendingClickHit = null;
|
|
9484
|
-
this.suppressSelectionChange = false;
|
|
9485
|
-
}
|
|
9486
10516
|
if (this.selectionDragState) {
|
|
9487
10517
|
if (event.pointerId !== this.selectionDragState.pointerId) {
|
|
9488
10518
|
return;
|
|
@@ -9982,7 +11012,7 @@ function findOffsetInTextNode(textNode, clientX, clientY) {
|
|
|
9982
11012
|
let closestDistance = Infinity;
|
|
9983
11013
|
let closestYDistance = Infinity;
|
|
9984
11014
|
let closestCaretX = 0;
|
|
9985
|
-
let
|
|
11015
|
+
let selectedViaRightEdge = false;
|
|
9986
11016
|
const rowInfo = /* @__PURE__ */ new Map();
|
|
9987
11017
|
const range = document.createRange();
|
|
9988
11018
|
let lastCharRect = null;
|
|
@@ -10051,15 +11081,28 @@ function findOffsetInTextNode(textNode, clientX, clientY) {
|
|
|
10051
11081
|
closestDistance = xDistance;
|
|
10052
11082
|
closestOffset = i;
|
|
10053
11083
|
closestCaretX = caretX;
|
|
10054
|
-
|
|
11084
|
+
bestRect.top;
|
|
10055
11085
|
closestYDistance = yDistance;
|
|
11086
|
+
selectedViaRightEdge = false;
|
|
11087
|
+
}
|
|
11088
|
+
if (i < text.length) {
|
|
11089
|
+
const rightEdgeX = bestRect.right;
|
|
11090
|
+
const rightEdgeDistance = Math.abs(clientX - rightEdgeX);
|
|
11091
|
+
if (rightEdgeDistance < closestDistance) {
|
|
11092
|
+
closestDistance = rightEdgeDistance;
|
|
11093
|
+
closestOffset = i + 1;
|
|
11094
|
+
closestCaretX = rightEdgeX;
|
|
11095
|
+
bestRect.top;
|
|
11096
|
+
closestYDistance = yDistance;
|
|
11097
|
+
selectedViaRightEdge = true;
|
|
11098
|
+
}
|
|
10056
11099
|
}
|
|
10057
11100
|
} else if (yDistance < closestYDistance || yDistance === closestYDistance && xDistance < closestDistance) {
|
|
10058
11101
|
closestYDistance = yDistance;
|
|
10059
11102
|
closestDistance = xDistance;
|
|
10060
11103
|
closestOffset = i;
|
|
10061
11104
|
closestCaretX = caretX;
|
|
10062
|
-
|
|
11105
|
+
bestRect.top;
|
|
10063
11106
|
}
|
|
10064
11107
|
}
|
|
10065
11108
|
let closestRow = null;
|
|
@@ -10084,11 +11127,11 @@ function findOffsetInTextNode(textNode, clientX, clientY) {
|
|
|
10084
11127
|
if (clientX < closestRow.left) {
|
|
10085
11128
|
closestOffset = closestRow.startOffset;
|
|
10086
11129
|
closestCaretX = closestRow.left;
|
|
10087
|
-
|
|
11130
|
+
closestRow.top;
|
|
10088
11131
|
} else if (clientX > closestRow.right) {
|
|
10089
|
-
closestOffset = closestRow.endOffset;
|
|
11132
|
+
closestOffset = Math.min(closestRow.endOffset + 1, text.length);
|
|
10090
11133
|
closestCaretX = closestRow.right;
|
|
10091
|
-
|
|
11134
|
+
closestRow.top;
|
|
10092
11135
|
} else if (clientY < closestRow.top || clientY > closestRow.bottom) {
|
|
10093
11136
|
let bestXDistance = Infinity;
|
|
10094
11137
|
const range2 = document.createRange();
|
|
@@ -10108,12 +11151,12 @@ function findOffsetInTextNode(textNode, clientX, clientY) {
|
|
|
10108
11151
|
bestXDistance = xDist;
|
|
10109
11152
|
closestOffset = i;
|
|
10110
11153
|
closestCaretX = rect.left;
|
|
10111
|
-
|
|
11154
|
+
closestRow.top;
|
|
10112
11155
|
}
|
|
10113
11156
|
}
|
|
10114
11157
|
}
|
|
10115
11158
|
}
|
|
10116
|
-
const pastRowEnd = closestRow !== null && clientX > closestRow.right
|
|
11159
|
+
const pastRowEnd = selectedViaRightEdge || closestRow !== null && clientX > closestRow.right;
|
|
10117
11160
|
if (Math.abs(clientX - closestCaretX) <= 2 && closestOffset < text.length && text[closestOffset] === "\n") {
|
|
10118
11161
|
closestOffset = Math.max(0, closestOffset - 1);
|
|
10119
11162
|
}
|
|
@@ -10566,8 +11609,9 @@ const CakeEditor = require$$0.forwardRef(
|
|
|
10566
11609
|
const lastEmittedSelectionRef = require$$0.useRef(null);
|
|
10567
11610
|
const [overlayRoot, setOverlayRoot] = require$$0.useState(null);
|
|
10568
11611
|
const [contentRoot, setContentRoot] = require$$0.useState(null);
|
|
11612
|
+
const baseExtensions = props.disableImageExtension ? bundledExtensionsWithoutImage : bundledExtensions;
|
|
10569
11613
|
const allExtensionsRef = require$$0.useRef([
|
|
10570
|
-
...
|
|
11614
|
+
...baseExtensions,
|
|
10571
11615
|
...props.extensions ?? []
|
|
10572
11616
|
]);
|
|
10573
11617
|
require$$0.useEffect(() => {
|
|
@@ -10725,6 +11769,10 @@ const CakeEditor = require$$0.forwardRef(
|
|
|
10725
11769
|
}
|
|
10726
11770
|
return { start: selection.start, end: selection.end };
|
|
10727
11771
|
},
|
|
11772
|
+
getCursorLength: () => {
|
|
11773
|
+
var _a;
|
|
11774
|
+
return ((_a = engineRef.current) == null ? void 0 : _a.getCursorLength()) ?? 0;
|
|
11775
|
+
},
|
|
10728
11776
|
insertText: (text) => {
|
|
10729
11777
|
var _a;
|
|
10730
11778
|
(_a = engineRef.current) == null ? void 0 : _a.insertText(text);
|
|
@@ -10740,10 +11788,10 @@ const CakeEditor = require$$0.forwardRef(
|
|
|
10740
11788
|
containerStyle.position = "relative";
|
|
10741
11789
|
}
|
|
10742
11790
|
const containerClassName = props.className ? `cake ${props.className}` : "cake";
|
|
10743
|
-
const overlayContext =
|
|
11791
|
+
const overlayContext = containerRef.current && contentRoot ? {
|
|
10744
11792
|
container: containerRef.current,
|
|
10745
11793
|
contentRoot,
|
|
10746
|
-
overlayRoot,
|
|
11794
|
+
overlayRoot: overlayRoot ?? void 0,
|
|
10747
11795
|
toOverlayRect: (rect) => {
|
|
10748
11796
|
var _a;
|
|
10749
11797
|
const containerRect = (_a = containerRef.current) == null ? void 0 : _a.getBoundingClientRect();
|
|
@@ -10778,10 +11826,17 @@ const CakeEditor = require$$0.forwardRef(
|
|
|
10778
11826
|
}
|
|
10779
11827
|
const focus = selection.start === selection.end ? selection.start : Math.max(selection.start, selection.end);
|
|
10780
11828
|
return { start: focus, end: focus };
|
|
11829
|
+
},
|
|
11830
|
+
executeCommand: (command) => {
|
|
11831
|
+
var _a;
|
|
11832
|
+
return ((_a = engineRef.current) == null ? void 0 : _a.executeCommand(command)) ?? false;
|
|
10781
11833
|
}
|
|
10782
11834
|
} : null;
|
|
10783
|
-
|
|
10784
|
-
|
|
11835
|
+
const hasOverlayExtensions = allExtensionsRef.current.some(
|
|
11836
|
+
(ext) => ext.renderOverlay
|
|
11837
|
+
);
|
|
11838
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { position: "relative", height: "100%" }, children: [
|
|
11839
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10785
11840
|
"div",
|
|
10786
11841
|
{
|
|
10787
11842
|
ref: containerRef,
|
|
@@ -10792,35 +11847,12 @@ const CakeEditor = require$$0.forwardRef(
|
|
|
10792
11847
|
var _a;
|
|
10793
11848
|
(_a = props.onBlur) == null ? void 0 : _a.call(props, event.nativeEvent);
|
|
10794
11849
|
}
|
|
10795
|
-
}
|
|
10796
|
-
void 0,
|
|
10797
|
-
false,
|
|
10798
|
-
{
|
|
10799
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/react/CakeEditor.tsx",
|
|
10800
|
-
lineNumber: 351,
|
|
10801
|
-
columnNumber: 9
|
|
10802
|
-
},
|
|
10803
|
-
this
|
|
11850
|
+
}
|
|
10804
11851
|
),
|
|
10805
|
-
|
|
10806
|
-
/* @__PURE__ */
|
|
10807
|
-
(extension) => extension.renderOverlay ? /* @__PURE__ */ jsxDevRuntimeExports.jsxDEV(require$$0.Fragment, { children: extension.renderOverlay(overlayContext) }, extension.name, false, {
|
|
10808
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/react/CakeEditor.tsx",
|
|
10809
|
-
lineNumber: 365,
|
|
10810
|
-
columnNumber: 21
|
|
10811
|
-
}, this) : null
|
|
10812
|
-
) }, void 0, false, {
|
|
10813
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/react/CakeEditor.tsx",
|
|
10814
|
-
lineNumber: 362,
|
|
10815
|
-
columnNumber: 15
|
|
10816
|
-
}, this),
|
|
10817
|
-
overlayRoot
|
|
11852
|
+
overlayContext && hasOverlayExtensions ? allExtensionsRef.current.map(
|
|
11853
|
+
(extension) => extension.renderOverlay ? /* @__PURE__ */ jsxRuntimeExports.jsx(require$$0.Fragment, { children: extension.renderOverlay(overlayContext) }, extension.name) : null
|
|
10818
11854
|
) : null
|
|
10819
|
-
] }
|
|
10820
|
-
fileName: "/Users/moboudra/dev/blankpage/cake/src/cake/react/CakeEditor.tsx",
|
|
10821
|
-
lineNumber: 350,
|
|
10822
|
-
columnNumber: 7
|
|
10823
|
-
}, this);
|
|
11855
|
+
] });
|
|
10824
11856
|
}
|
|
10825
11857
|
);
|
|
10826
11858
|
CakeEditor.displayName = "CakeEditor";
|
|
@@ -10829,6 +11861,7 @@ exports.CakeEngine = CakeEngine;
|
|
|
10829
11861
|
exports.blockquoteExtension = blockquoteExtension;
|
|
10830
11862
|
exports.boldExtension = boldExtension;
|
|
10831
11863
|
exports.bundledExtensions = bundledExtensions;
|
|
11864
|
+
exports.bundledExtensionsWithoutImage = bundledExtensionsWithoutImage;
|
|
10832
11865
|
exports.combinedEmphasisExtension = combinedEmphasisExtension;
|
|
10833
11866
|
exports.headingExtension = headingExtension;
|
|
10834
11867
|
exports.imageExtension = imageExtension;
|