@blankdotpage/cake 0.1.7 → 0.1.10
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 -0
- package/dist/cake/clipboard.d.ts.map +1 -0
- package/dist/cake/clipboard.js +391 -0
- package/dist/cake/core/mapping/cursor-source-map.d.ts +1 -0
- package/dist/cake/core/mapping/cursor-source-map.d.ts.map +1 -0
- package/dist/cake/core/mapping/cursor-source-map.js +146 -0
- package/dist/cake/core/runtime.d.ts +3 -0
- package/dist/cake/core/runtime.d.ts.map +1 -0
- package/dist/cake/core/runtime.js +1758 -0
- package/dist/cake/core/types.d.ts +1 -0
- package/dist/cake/core/types.d.ts.map +1 -0
- package/dist/cake/core/types.js +1 -0
- package/dist/cake/dom/dom-map.d.ts +1 -0
- package/dist/cake/dom/dom-map.d.ts.map +1 -0
- package/dist/cake/dom/dom-map.js +151 -0
- package/dist/cake/dom/dom-selection.d.ts +1 -0
- package/dist/cake/dom/dom-selection.d.ts.map +1 -0
- package/dist/cake/dom/dom-selection.js +216 -0
- package/dist/cake/dom/render.d.ts +1 -0
- package/dist/cake/dom/render.d.ts.map +1 -0
- package/dist/cake/dom/render.js +470 -0
- package/dist/cake/dom/types.d.ts +1 -0
- package/dist/cake/dom/types.d.ts.map +1 -0
- package/dist/cake/dom/types.js +1 -0
- package/dist/cake/engine/cake-engine.d.ts +1 -0
- package/dist/cake/engine/cake-engine.d.ts.map +1 -0
- package/dist/cake/engine/cake-engine.js +3589 -0
- package/dist/cake/engine/selection/selection-geometry-dom.d.ts +1 -0
- package/dist/cake/engine/selection/selection-geometry-dom.d.ts.map +1 -0
- package/dist/cake/engine/selection/selection-geometry-dom.js +302 -0
- package/dist/cake/engine/selection/selection-geometry.d.ts +1 -0
- package/dist/cake/engine/selection/selection-geometry.d.ts.map +1 -0
- package/dist/cake/engine/selection/selection-geometry.js +158 -0
- package/dist/cake/engine/selection/selection-layout-dom.d.ts +1 -0
- package/dist/cake/engine/selection/selection-layout-dom.d.ts.map +1 -0
- package/dist/cake/engine/selection/selection-layout-dom.js +781 -0
- package/dist/cake/engine/selection/selection-layout.d.ts +1 -0
- package/dist/cake/engine/selection/selection-layout.d.ts.map +1 -0
- package/dist/cake/engine/selection/selection-layout.js +128 -0
- package/dist/cake/engine/selection/selection-navigation.d.ts +1 -0
- package/dist/cake/engine/selection/selection-navigation.d.ts.map +1 -0
- package/dist/cake/engine/selection/selection-navigation.js +229 -0
- package/dist/cake/engine/selection/visible-text.d.ts +1 -0
- package/dist/cake/engine/selection/visible-text.d.ts.map +1 -0
- package/dist/cake/engine/selection/visible-text.js +66 -0
- package/dist/cake/extensions/blockquote/blockquote.d.ts +1 -0
- package/dist/cake/extensions/blockquote/blockquote.d.ts.map +1 -0
- package/dist/cake/extensions/blockquote/blockquote.js +177 -0
- package/dist/cake/extensions/blockquote/index.d.ts +2 -0
- package/dist/cake/extensions/blockquote/index.d.ts.map +1 -0
- package/dist/cake/extensions/blockquote/index.js +1 -0
- package/dist/cake/extensions/bold/bold.d.ts +1 -0
- package/dist/cake/extensions/bold/bold.d.ts.map +1 -0
- package/dist/cake/extensions/bold/bold.js +113 -0
- package/dist/cake/extensions/bold/index.d.ts +2 -0
- package/dist/cake/extensions/bold/index.d.ts.map +1 -0
- package/dist/cake/extensions/bold/index.js +1 -0
- package/dist/cake/extensions/bundles.d.ts +1 -0
- package/dist/cake/extensions/bundles.d.ts.map +1 -0
- package/dist/cake/extensions/bundles.js +12 -0
- package/dist/cake/extensions/combined-emphasis/combined-emphasis.d.ts +1 -0
- package/dist/cake/extensions/combined-emphasis/combined-emphasis.d.ts.map +1 -0
- package/dist/cake/extensions/combined-emphasis/combined-emphasis.js +42 -0
- package/dist/cake/extensions/combined-emphasis/index.d.ts +2 -0
- package/dist/cake/extensions/combined-emphasis/index.d.ts.map +1 -0
- package/dist/cake/extensions/combined-emphasis/index.js +1 -0
- package/dist/cake/extensions/heading/heading.d.ts +1 -0
- package/dist/cake/extensions/heading/heading.d.ts.map +1 -0
- package/dist/cake/extensions/heading/heading.js +337 -0
- package/dist/cake/extensions/heading/index.d.ts +2 -0
- package/dist/cake/extensions/heading/index.d.ts.map +1 -0
- package/dist/cake/extensions/heading/index.js +1 -0
- package/dist/cake/extensions/image/image.d.ts +1 -0
- package/dist/cake/extensions/image/image.d.ts.map +1 -0
- package/dist/cake/extensions/image/image.js +120 -0
- package/dist/cake/extensions/image/index.d.ts +2 -0
- package/dist/cake/extensions/image/index.d.ts.map +1 -0
- package/dist/cake/extensions/image/index.js +1 -0
- package/dist/cake/extensions/index.d.ts +2 -2
- package/dist/cake/extensions/index.d.ts.map +1 -0
- package/dist/cake/extensions/index.js +25 -0
- package/dist/cake/extensions/italic/index.d.ts +2 -0
- package/dist/cake/extensions/italic/index.d.ts.map +1 -0
- package/dist/cake/extensions/italic/index.js +1 -0
- package/dist/cake/extensions/italic/italic.d.ts +1 -0
- package/dist/cake/extensions/italic/italic.d.ts.map +1 -0
- package/dist/cake/extensions/italic/italic.js +91 -0
- package/dist/cake/extensions/link/index.d.ts +2 -0
- package/dist/cake/extensions/link/index.d.ts.map +1 -0
- package/dist/cake/extensions/link/index.js +1 -0
- package/dist/cake/extensions/link/link-popover.d.ts +1 -0
- package/dist/cake/extensions/link/link-popover.d.ts.map +1 -0
- package/dist/cake/extensions/link/link-popover.js +205 -0
- package/dist/cake/extensions/link/link.d.ts +1 -0
- package/dist/cake/extensions/link/link.d.ts.map +1 -0
- package/dist/cake/extensions/link/link.js +202 -0
- package/dist/cake/extensions/list/index.d.ts +2 -0
- package/dist/cake/extensions/list/index.d.ts.map +1 -0
- package/dist/cake/extensions/list/index.js +1 -0
- package/dist/cake/extensions/list/list-ast.d.ts +1 -0
- package/dist/cake/extensions/list/list-ast.d.ts.map +1 -0
- package/dist/cake/extensions/list/list-ast.js +248 -0
- package/dist/cake/extensions/list/list.d.ts +1 -0
- package/dist/cake/extensions/list/list.d.ts.map +1 -0
- package/dist/cake/extensions/list/list.js +859 -0
- package/dist/cake/extensions/scrollbar/index.d.ts +1 -0
- package/dist/cake/extensions/scrollbar/index.d.ts.map +1 -0
- package/dist/cake/extensions/scrollbar/index.js +216 -0
- package/dist/cake/extensions/strikethrough/index.d.ts +2 -0
- package/dist/cake/extensions/strikethrough/index.d.ts.map +1 -0
- package/dist/cake/extensions/strikethrough/index.js +1 -0
- package/dist/cake/extensions/strikethrough/strikethrough.d.ts +1 -0
- package/dist/cake/extensions/strikethrough/strikethrough.d.ts.map +1 -0
- package/dist/cake/extensions/strikethrough/strikethrough.js +84 -0
- package/dist/cake/extensions/types.d.ts +1 -0
- package/dist/cake/extensions/types.d.ts.map +1 -0
- package/dist/cake/extensions/types.js +1 -0
- package/dist/cake/index.d.ts +1 -0
- package/dist/cake/index.d.ts.map +1 -0
- package/dist/cake/index.js +1 -0
- package/dist/cake/react/CakeEditor.d.ts +1 -0
- package/dist/cake/react/CakeEditor.d.ts.map +1 -0
- package/dist/cake/react/CakeEditor.js +233 -0
- package/dist/cake/shared/platform.d.ts +1 -0
- package/dist/cake/shared/platform.d.ts.map +1 -0
- package/dist/cake/shared/platform.js +19 -0
- package/dist/cake/shared/segmenter.d.ts +1 -0
- package/dist/cake/shared/segmenter.d.ts.map +1 -0
- package/dist/cake/shared/segmenter.js +46 -0
- package/dist/cake/shared/url.d.ts +1 -0
- package/dist/cake/shared/url.d.ts.map +1 -0
- package/dist/cake/shared/url.js +37 -0
- package/dist/cake/shared/word-break.d.ts +1 -0
- package/dist/cake/shared/word-break.d.ts.map +1 -0
- package/dist/cake/shared/word-break.js +178 -0
- package/dist/cake/test/harness.d.ts +1 -0
- package/dist/cake/test/harness.d.ts.map +1 -0
- package/dist/cake/test/harness.js +504 -0
- package/dist/codemirror/markdown-commands.d.ts +1 -0
- package/dist/codemirror/markdown-commands.d.ts.map +1 -0
- package/dist/codemirror/markdown-commands.js +532 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -11740
- package/package.json +8 -6
- package/dist/cake/extensions/pipe-link/pipe-link.d.ts +0 -1
- package/dist/index.cjs +0 -11740
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection-layout.d.ts","sourceRoot":"","sources":["../../../../src/cake/engine/selection/selection-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,GAAG,EAAU,MAAM,kBAAkB,CAAC;AAG3D,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,UAAU,CAAC;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,UAAU,CAAC;IACtB,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,eAAe,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,EAAE,EACjB,QAAQ,EAAE,cAAc,GACvB,WAAW,CAqCb;AAOD,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,EAAE,CAchD;AA6BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,EAAE,CAW1D;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,MAAM,GACb;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAsB7C"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { graphemeSegments } from "../../shared/segmenter";
|
|
2
|
+
export function buildLayoutModel(lines, measurer) {
|
|
3
|
+
const layouts = [];
|
|
4
|
+
let top = measurer.container.top;
|
|
5
|
+
let lineStartOffset = 0;
|
|
6
|
+
lines.forEach((line) => {
|
|
7
|
+
const measurement = measurer.measureLine({
|
|
8
|
+
lineIndex: line.lineIndex,
|
|
9
|
+
lineText: line.text,
|
|
10
|
+
lineLength: line.cursorLength,
|
|
11
|
+
lineHasNewline: line.hasNewline,
|
|
12
|
+
top,
|
|
13
|
+
});
|
|
14
|
+
layouts.push({
|
|
15
|
+
lineIndex: line.lineIndex,
|
|
16
|
+
lineStartOffset,
|
|
17
|
+
lineLength: line.cursorLength,
|
|
18
|
+
lineHasNewline: line.hasNewline,
|
|
19
|
+
lineBox: measurement.lineBox,
|
|
20
|
+
rows: measurement.rows,
|
|
21
|
+
});
|
|
22
|
+
top = measurement.lineBox.top + measurement.lineBox.height;
|
|
23
|
+
lineStartOffset += line.cursorLength + (line.hasNewline ? 1 : 0);
|
|
24
|
+
});
|
|
25
|
+
const height = Math.max(measurer.container.height, top - measurer.container.top);
|
|
26
|
+
return {
|
|
27
|
+
container: {
|
|
28
|
+
...measurer.container,
|
|
29
|
+
height,
|
|
30
|
+
},
|
|
31
|
+
lines: layouts,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function getDocLines(doc) {
|
|
35
|
+
const flattenedLines = flattenBlocksWithAtomicInfo(doc.blocks);
|
|
36
|
+
return flattenedLines.map((line, index) => {
|
|
37
|
+
const cursorToCodeUnit = buildCursorToCodeUnit(line.text);
|
|
38
|
+
const cursorLength = Math.max(0, cursorToCodeUnit.length - 1);
|
|
39
|
+
return {
|
|
40
|
+
lineIndex: index,
|
|
41
|
+
text: line.text,
|
|
42
|
+
cursorLength,
|
|
43
|
+
hasNewline: index < flattenedLines.length - 1,
|
|
44
|
+
cursorToCodeUnit,
|
|
45
|
+
isAtomic: line.isAtomic,
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function flattenBlocksWithAtomicInfo(blocks) {
|
|
50
|
+
const lines = [];
|
|
51
|
+
blocks.forEach((block) => {
|
|
52
|
+
lines.push(...flattenBlockWithAtomicInfo(block));
|
|
53
|
+
});
|
|
54
|
+
if (lines.length === 0) {
|
|
55
|
+
lines.push({ text: "", isAtomic: false });
|
|
56
|
+
}
|
|
57
|
+
return lines;
|
|
58
|
+
}
|
|
59
|
+
function flattenBlockWithAtomicInfo(block) {
|
|
60
|
+
if (block.type === "paragraph") {
|
|
61
|
+
return [
|
|
62
|
+
{ text: block.content.map(flattenInline).join(""), isAtomic: false },
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
if (block.type === "block-wrapper") {
|
|
66
|
+
return flattenBlocksWithAtomicInfo(block.blocks);
|
|
67
|
+
}
|
|
68
|
+
if (block.type === "block-atom") {
|
|
69
|
+
// Atomic blocks are represented as empty lines for layout purposes
|
|
70
|
+
return [{ text: "", isAtomic: true }];
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
export function getLineOffsets(lines) {
|
|
75
|
+
const offsets = [];
|
|
76
|
+
let current = 0;
|
|
77
|
+
lines.forEach((line) => {
|
|
78
|
+
offsets.push(current);
|
|
79
|
+
current += line.cursorLength;
|
|
80
|
+
if (line.hasNewline) {
|
|
81
|
+
current += 1;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return offsets;
|
|
85
|
+
}
|
|
86
|
+
export function resolveOffsetToLine(lines, offset) {
|
|
87
|
+
if (lines.length === 0) {
|
|
88
|
+
return { lineIndex: 0, offsetInLine: 0 };
|
|
89
|
+
}
|
|
90
|
+
const lineOffsets = getLineOffsets(lines);
|
|
91
|
+
const totalLength = lineOffsets[lineOffsets.length - 1] + lines[lines.length - 1].cursorLength;
|
|
92
|
+
const clamped = Math.max(0, Math.min(offset, totalLength));
|
|
93
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
94
|
+
const lineStart = lineOffsets[index];
|
|
95
|
+
const lineEnd = lineStart + lines[index].cursorLength;
|
|
96
|
+
if (clamped <= lineEnd || index === lines.length - 1) {
|
|
97
|
+
return { lineIndex: index, offsetInLine: clamped - lineStart };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const lastIndex = lines.length - 1;
|
|
101
|
+
return {
|
|
102
|
+
lineIndex: lastIndex,
|
|
103
|
+
offsetInLine: lines[lastIndex].cursorLength,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function flattenInline(inline) {
|
|
107
|
+
if (inline.type === "text") {
|
|
108
|
+
return inline.text;
|
|
109
|
+
}
|
|
110
|
+
if (inline.type === "inline-wrapper") {
|
|
111
|
+
return inline.children.map(flattenInline).join("");
|
|
112
|
+
}
|
|
113
|
+
if (inline.type === "inline-atom") {
|
|
114
|
+
return " ";
|
|
115
|
+
}
|
|
116
|
+
return "";
|
|
117
|
+
}
|
|
118
|
+
function buildCursorToCodeUnit(text) {
|
|
119
|
+
const segments = graphemeSegments(text);
|
|
120
|
+
const mapping = [0];
|
|
121
|
+
for (const segment of segments) {
|
|
122
|
+
mapping.push(segment.index + segment.segment.length);
|
|
123
|
+
}
|
|
124
|
+
if (mapping.length === 0) {
|
|
125
|
+
mapping.push(0);
|
|
126
|
+
}
|
|
127
|
+
return mapping;
|
|
128
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection-navigation.d.ts","sourceRoot":"","sources":["../../../../src/cake/engine/selection/selection-navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAa,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG3E,KAAK,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAEvC,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAsIF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,IAAI,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,CAChB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,KACN;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC7E,GAAG,wBAAwB,GAAG,IAAI,CA+JlC"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { resolveOffsetToLine } from "./selection-layout";
|
|
2
|
+
function rectRight(rect) {
|
|
3
|
+
return rect.left + rect.width;
|
|
4
|
+
}
|
|
5
|
+
function clampNumber(value, min, max) {
|
|
6
|
+
return Math.max(min, Math.min(value, max));
|
|
7
|
+
}
|
|
8
|
+
function resolveSelectionAffinity(selection) {
|
|
9
|
+
if (selection.start === selection.end) {
|
|
10
|
+
return selection.affinity ?? "backward";
|
|
11
|
+
}
|
|
12
|
+
return selection.affinity ?? "forward";
|
|
13
|
+
}
|
|
14
|
+
function resolveSelectionAnchorAndFocus(selection) {
|
|
15
|
+
if (selection.start === selection.end) {
|
|
16
|
+
return { anchor: selection.start, focus: selection.start };
|
|
17
|
+
}
|
|
18
|
+
const affinity = resolveSelectionAffinity(selection);
|
|
19
|
+
if (affinity === "backward") {
|
|
20
|
+
return { anchor: selection.end, focus: selection.start };
|
|
21
|
+
}
|
|
22
|
+
return { anchor: selection.start, focus: selection.end };
|
|
23
|
+
}
|
|
24
|
+
function findRowIndexForOffset(rows, offsetInLine, affinity) {
|
|
25
|
+
if (rows.length === 0) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
29
|
+
const row = rows[index];
|
|
30
|
+
if (offsetInLine === row.startOffset) {
|
|
31
|
+
if (affinity === "backward" && index > 0) {
|
|
32
|
+
return index - 1;
|
|
33
|
+
}
|
|
34
|
+
return index;
|
|
35
|
+
}
|
|
36
|
+
if (offsetInLine === row.endOffset) {
|
|
37
|
+
if (affinity === "forward" && index + 1 < rows.length) {
|
|
38
|
+
return index + 1;
|
|
39
|
+
}
|
|
40
|
+
return index;
|
|
41
|
+
}
|
|
42
|
+
if (offsetInLine > row.startOffset && offsetInLine < row.endOffset) {
|
|
43
|
+
return index;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return rows.length - 1;
|
|
47
|
+
}
|
|
48
|
+
function asSingleRow(line) {
|
|
49
|
+
return {
|
|
50
|
+
startOffset: 0,
|
|
51
|
+
endOffset: line.lineLength,
|
|
52
|
+
rect: line.lineBox,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function rowOffsetToX(params) {
|
|
56
|
+
const { row, offsetInLine } = params;
|
|
57
|
+
const rowRight = rectRight(row.rect);
|
|
58
|
+
const clampedOffset = clampNumber(offsetInLine, row.startOffset, row.endOffset);
|
|
59
|
+
if (row.endOffset <= row.startOffset || row.rect.width <= 0) {
|
|
60
|
+
return row.rect.left;
|
|
61
|
+
}
|
|
62
|
+
if (clampedOffset === row.endOffset) {
|
|
63
|
+
return rowRight;
|
|
64
|
+
}
|
|
65
|
+
const rowLength = row.endOffset - row.startOffset;
|
|
66
|
+
const fraction = (clampedOffset - row.startOffset) / rowLength;
|
|
67
|
+
return row.rect.left + row.rect.width * fraction;
|
|
68
|
+
}
|
|
69
|
+
function rowXToOffset(params) {
|
|
70
|
+
const { row, x } = params;
|
|
71
|
+
const rowRight = rectRight(row.rect);
|
|
72
|
+
if (x <= row.rect.left) {
|
|
73
|
+
return { offsetInLine: row.startOffset, affinity: "forward" };
|
|
74
|
+
}
|
|
75
|
+
if (x >= rowRight) {
|
|
76
|
+
return { offsetInLine: row.endOffset, affinity: "backward" };
|
|
77
|
+
}
|
|
78
|
+
const rowLength = row.endOffset - row.startOffset;
|
|
79
|
+
if (rowLength <= 0 || row.rect.width <= 0) {
|
|
80
|
+
return { offsetInLine: row.startOffset, affinity: "forward" };
|
|
81
|
+
}
|
|
82
|
+
const fraction = (x - row.rect.left) / row.rect.width;
|
|
83
|
+
const raw = row.startOffset + fraction * rowLength;
|
|
84
|
+
const rounded = Math.round(raw);
|
|
85
|
+
const offsetInLine = clampNumber(rounded, row.startOffset, row.endOffset);
|
|
86
|
+
return { offsetInLine, affinity: "forward" };
|
|
87
|
+
}
|
|
88
|
+
function resolveTargetLineIndex(params) {
|
|
89
|
+
const delta = params.direction === "down" ? 1 : -1;
|
|
90
|
+
let index = params.fromLineIndex + delta;
|
|
91
|
+
while (index >= 0 && index < params.lines.length) {
|
|
92
|
+
if (!params.lines[index]?.isAtomic) {
|
|
93
|
+
return index;
|
|
94
|
+
}
|
|
95
|
+
index += delta;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
export function moveSelectionVertically(params) {
|
|
100
|
+
const { lines, layout, direction } = params;
|
|
101
|
+
if (layout.lines.length === 0 || lines.length === 0) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const affinity = resolveSelectionAffinity(params.selection);
|
|
105
|
+
const { anchor, focus } = resolveSelectionAnchorAndFocus(params.selection);
|
|
106
|
+
const focusResolved = resolveOffsetToLine(lines, focus);
|
|
107
|
+
const focusLineLayout = layout.lines[focusResolved.lineIndex];
|
|
108
|
+
if (!focusLineLayout) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const focusRows = focusLineLayout.rows.length > 0
|
|
112
|
+
? focusLineLayout.rows
|
|
113
|
+
: [asSingleRow(focusLineLayout)];
|
|
114
|
+
let focusRowIndex = params.focusRowIndex ??
|
|
115
|
+
findRowIndexForOffset(focusRows, focusResolved.offsetInLine, affinity);
|
|
116
|
+
focusRowIndex = clampNumber(focusRowIndex, 0, Math.max(0, focusRows.length - 1));
|
|
117
|
+
const focusRow = focusRows[focusRowIndex] ?? focusRows[focusRows.length - 1];
|
|
118
|
+
if (!focusRow) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const goalX = params.goalX ??
|
|
122
|
+
rowOffsetToX({ row: focusRow, offsetInLine: focusResolved.offsetInLine });
|
|
123
|
+
let targetLineIndex = focusResolved.lineIndex;
|
|
124
|
+
let targetRowIndex = focusRowIndex;
|
|
125
|
+
if (direction === "up") {
|
|
126
|
+
if (focusRowIndex > 0) {
|
|
127
|
+
targetRowIndex = focusRowIndex - 1;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const nextLineIndex = resolveTargetLineIndex({
|
|
131
|
+
lines,
|
|
132
|
+
fromLineIndex: focusResolved.lineIndex,
|
|
133
|
+
direction: "up",
|
|
134
|
+
});
|
|
135
|
+
if (nextLineIndex === null) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
targetLineIndex = nextLineIndex;
|
|
139
|
+
targetRowIndex = Number.POSITIVE_INFINITY;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
if (focusRowIndex + 1 < focusRows.length) {
|
|
144
|
+
targetRowIndex = focusRowIndex + 1;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const nextLineIndex = resolveTargetLineIndex({
|
|
148
|
+
lines,
|
|
149
|
+
fromLineIndex: focusResolved.lineIndex,
|
|
150
|
+
direction: "down",
|
|
151
|
+
});
|
|
152
|
+
if (nextLineIndex === null) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
targetLineIndex = nextLineIndex;
|
|
156
|
+
targetRowIndex = 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const targetLineLayout = layout.lines[targetLineIndex];
|
|
160
|
+
if (!targetLineLayout) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const targetRows = targetLineLayout.rows.length > 0
|
|
164
|
+
? targetLineLayout.rows
|
|
165
|
+
: [asSingleRow(targetLineLayout)];
|
|
166
|
+
const resolvedTargetRowIndex = targetRowIndex === Number.POSITIVE_INFINITY
|
|
167
|
+
? Math.max(0, targetRows.length - 1)
|
|
168
|
+
: clampNumber(targetRowIndex, 0, Math.max(0, targetRows.length - 1));
|
|
169
|
+
const targetRow = targetRows[resolvedTargetRowIndex] ?? targetRows[targetRows.length - 1];
|
|
170
|
+
if (!targetRow) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const targetLineStart = targetLineLayout.lineStartOffset;
|
|
174
|
+
const targetLineEnd = targetLineStart + targetLineLayout.lineLength;
|
|
175
|
+
if (params.hitTestCursorAt) {
|
|
176
|
+
const midY = targetRow.rect.top + targetRow.rect.height / 2;
|
|
177
|
+
const rowLeft = targetRow.rect.left;
|
|
178
|
+
const rowRight = rectRight(targetRow.rect);
|
|
179
|
+
const hitX = rowRight - rowLeft > 1
|
|
180
|
+
? clampNumber(goalX, rowLeft + 0.5, rowRight - 0.5)
|
|
181
|
+
: goalX;
|
|
182
|
+
let hit = params.hitTestCursorAt(hitX, midY);
|
|
183
|
+
// If we're in trailing whitespace, some caret APIs will return the end of
|
|
184
|
+
// the whole line (last visual row). Nudge left until we get a hit that
|
|
185
|
+
// actually lands on the requested visual row.
|
|
186
|
+
if (hit && hit.cursorOffset === focus) {
|
|
187
|
+
for (let attempt = 0; attempt < 80; attempt += 1) {
|
|
188
|
+
const nudgedX = hitX - (attempt + 1) * 1;
|
|
189
|
+
if (nudgedX <= rowLeft + 0.5) {
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
const next = params.hitTestCursorAt(nudgedX, midY);
|
|
193
|
+
const matchesRow = next?.caretTop === undefined ||
|
|
194
|
+
Math.abs(next.caretTop - targetRow.rect.top) <= 2;
|
|
195
|
+
if (next && next.cursorOffset !== focus && matchesRow) {
|
|
196
|
+
hit = next;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const matchesRow = hit?.caretTop === undefined ||
|
|
202
|
+
Math.abs(hit.caretTop - targetRow.rect.top) <= 2;
|
|
203
|
+
if (hit &&
|
|
204
|
+
matchesRow &&
|
|
205
|
+
hit.cursorOffset >= targetLineStart &&
|
|
206
|
+
hit.cursorOffset <= targetLineEnd) {
|
|
207
|
+
const normalizedAffinity = targetLineLayout.lineLength === 0 ? "forward" : hit.affinity;
|
|
208
|
+
const nextSelection = anchor === focus
|
|
209
|
+
? {
|
|
210
|
+
start: hit.cursorOffset,
|
|
211
|
+
end: hit.cursorOffset,
|
|
212
|
+
affinity: normalizedAffinity,
|
|
213
|
+
}
|
|
214
|
+
: { start: anchor, end: hit.cursorOffset, affinity: normalizedAffinity };
|
|
215
|
+
return { selection: nextSelection, goalX };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const rowHit = rowXToOffset({ row: targetRow, x: goalX });
|
|
219
|
+
const nextPos = targetLineStart + rowHit.offsetInLine;
|
|
220
|
+
const normalizedAffinity = targetLineLayout.lineLength === 0 ? "forward" : rowHit.affinity;
|
|
221
|
+
const nextSelection = anchor === focus
|
|
222
|
+
? { start: nextPos, end: nextPos, affinity: normalizedAffinity }
|
|
223
|
+
: {
|
|
224
|
+
start: anchor,
|
|
225
|
+
end: nextPos,
|
|
226
|
+
affinity: normalizedAffinity,
|
|
227
|
+
};
|
|
228
|
+
return { selection: nextSelection, goalX };
|
|
229
|
+
}
|
|
@@ -2,3 +2,4 @@ import { type LineInfo } from "./selection-layout";
|
|
|
2
2
|
export declare function getVisibleText(lines: LineInfo[]): string;
|
|
3
3
|
export declare function visibleOffsetToCursorOffset(lines: LineInfo[], visibleOffset: number): number | null;
|
|
4
4
|
export declare function cursorOffsetToVisibleOffset(lines: LineInfo[], cursorOffset: number): number;
|
|
5
|
+
//# sourceMappingURL=visible-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visible-text.d.ts","sourceRoot":"","sources":["../../../../src/cake/engine/selection/visible-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,oBAAoB,CAAC;AAuB5B,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAKxD;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,QAAQ,EAAE,EACjB,aAAa,EAAE,MAAM,GACpB,MAAM,GAAG,IAAI,CA2Bf;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,QAAQ,EAAE,EACjB,YAAY,EAAE,MAAM,GACnB,MAAM,CAsBR"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { getLineOffsets, resolveOffsetToLine, } from "./selection-layout";
|
|
2
|
+
function cursorOffsetFromCodeUnit(line, codeUnitOffset) {
|
|
3
|
+
const maxCodeUnit = line.cursorToCodeUnit[line.cursorToCodeUnit.length - 1] ?? 0;
|
|
4
|
+
const clamped = Math.max(0, Math.min(codeUnitOffset, maxCodeUnit));
|
|
5
|
+
for (let i = 0; i < line.cursorToCodeUnit.length; i += 1) {
|
|
6
|
+
if (line.cursorToCodeUnit[i] === clamped) {
|
|
7
|
+
return i;
|
|
8
|
+
}
|
|
9
|
+
if (line.cursorToCodeUnit[i] > clamped) {
|
|
10
|
+
return Math.max(0, i - 1);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return line.cursorLength;
|
|
14
|
+
}
|
|
15
|
+
export function getVisibleText(lines) {
|
|
16
|
+
if (lines.length === 0) {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
return lines.map((line) => line.text).join("\n");
|
|
20
|
+
}
|
|
21
|
+
export function visibleOffsetToCursorOffset(lines, visibleOffset) {
|
|
22
|
+
if (lines.length === 0) {
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
const clampedOffset = Math.max(0, visibleOffset);
|
|
26
|
+
const lineOffsets = getLineOffsets(lines);
|
|
27
|
+
let codeUnitIndex = 0;
|
|
28
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
29
|
+
const line = lines[index];
|
|
30
|
+
const lineStart = codeUnitIndex;
|
|
31
|
+
const lineEnd = lineStart + line.text.length;
|
|
32
|
+
if (clampedOffset <= lineEnd || index === lines.length - 1) {
|
|
33
|
+
const offsetInLine = Math.max(0, Math.min(clampedOffset - lineStart, line.text.length));
|
|
34
|
+
const cursorOffsetInLine = cursorOffsetFromCodeUnit(line, offsetInLine);
|
|
35
|
+
const lineStartOffset = lineOffsets[index] ?? 0;
|
|
36
|
+
return lineStartOffset + cursorOffsetInLine;
|
|
37
|
+
}
|
|
38
|
+
codeUnitIndex = lineEnd + (line.hasNewline ? 1 : 0);
|
|
39
|
+
if (line.hasNewline && clampedOffset === codeUnitIndex) {
|
|
40
|
+
const lineStartOffset = lineOffsets[index] ?? 0;
|
|
41
|
+
return lineStartOffset + line.cursorLength + 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
export function cursorOffsetToVisibleOffset(lines, cursorOffset) {
|
|
47
|
+
if (lines.length === 0) {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
const lineOffsets = getLineOffsets(lines);
|
|
51
|
+
const { lineIndex, offsetInLine } = resolveOffsetToLine(lines, cursorOffset);
|
|
52
|
+
let codeUnitIndex = 0;
|
|
53
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
54
|
+
const line = lines[index];
|
|
55
|
+
if (index === lineIndex) {
|
|
56
|
+
const offset = Math.max(0, Math.min(offsetInLine, line.cursorLength));
|
|
57
|
+
return codeUnitIndex + (line.cursorToCodeUnit[offset] ?? 0);
|
|
58
|
+
}
|
|
59
|
+
codeUnitIndex += line.text.length + (line.hasNewline ? 1 : 0);
|
|
60
|
+
}
|
|
61
|
+
const lastLine = lines[lines.length - 1];
|
|
62
|
+
const lastStart = lineOffsets[lineOffsets.length - 1] ?? 0;
|
|
63
|
+
const lastOffset = Math.max(0, cursorOffset - lastStart);
|
|
64
|
+
return (codeUnitIndex +
|
|
65
|
+
(lastLine.cursorToCodeUnit[lastOffset] ?? lastLine.text.length));
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blockquote.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/blockquote/blockquote.ts"],"names":[],"mappings":"AAsIA,eAAO,MAAM,mBAAmB,kCA8F9B,CAAC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { defineExtension, } from "../../core/runtime";
|
|
2
|
+
import { CursorSourceBuilder } from "../../core/mapping/cursor-source-map";
|
|
3
|
+
const BLOCKQUOTE_KIND = "blockquote";
|
|
4
|
+
const PREFIX = "> ";
|
|
5
|
+
const BLOCKQUOTE_PATTERN = /^> /;
|
|
6
|
+
function findLineStartInSource(source, sourceOffset) {
|
|
7
|
+
let lineStart = sourceOffset;
|
|
8
|
+
while (lineStart > 0 && source[lineStart - 1] !== "\n") {
|
|
9
|
+
lineStart--;
|
|
10
|
+
}
|
|
11
|
+
return lineStart;
|
|
12
|
+
}
|
|
13
|
+
function isInsideBlockquote(source, sourcePos) {
|
|
14
|
+
const lineStart = findLineStartInSource(source, sourcePos);
|
|
15
|
+
const lineContent = source.slice(lineStart, source.indexOf("\n", lineStart) === -1
|
|
16
|
+
? source.length
|
|
17
|
+
: source.indexOf("\n", lineStart));
|
|
18
|
+
return BLOCKQUOTE_PATTERN.test(lineContent);
|
|
19
|
+
}
|
|
20
|
+
function handleExitBlockquote(state) {
|
|
21
|
+
const { source, selection, map, runtime } = state;
|
|
22
|
+
const cursorPos = Math.min(selection.start, selection.end);
|
|
23
|
+
const sourcePos = map.cursorToSource(cursorPos, selection.affinity ?? "forward");
|
|
24
|
+
// Only handle if we're inside a blockquote
|
|
25
|
+
if (!isInsideBlockquote(source, sourcePos)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
// Find the end of the current line
|
|
29
|
+
let lineEnd = source.indexOf("\n", sourcePos);
|
|
30
|
+
if (lineEnd === -1) {
|
|
31
|
+
lineEnd = source.length;
|
|
32
|
+
}
|
|
33
|
+
// Insert a newline after the current line (exits the blockquote)
|
|
34
|
+
const newSource = source.slice(0, lineEnd) + "\n" + source.slice(lineEnd);
|
|
35
|
+
// Position cursor at the start of the new line (after the blockquote)
|
|
36
|
+
const next = runtime.createState(newSource);
|
|
37
|
+
const newCursorOffset = lineEnd + 1;
|
|
38
|
+
const caretCursor = next.map.sourceToCursor(newCursorOffset, "forward");
|
|
39
|
+
return {
|
|
40
|
+
source: newSource,
|
|
41
|
+
selection: {
|
|
42
|
+
start: caretCursor.cursorOffset,
|
|
43
|
+
end: caretCursor.cursorOffset,
|
|
44
|
+
affinity: "forward",
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function handleToggleBlockquote(state) {
|
|
49
|
+
const { source, selection, map, runtime } = state;
|
|
50
|
+
// Get the cursor's source position
|
|
51
|
+
const cursorPos = Math.min(selection.start, selection.end);
|
|
52
|
+
const sourcePos = map.cursorToSource(cursorPos, selection.affinity ?? "forward");
|
|
53
|
+
// Find line boundaries in source
|
|
54
|
+
const lineStart = findLineStartInSource(source, sourcePos);
|
|
55
|
+
let lineEnd = source.indexOf("\n", lineStart);
|
|
56
|
+
if (lineEnd === -1) {
|
|
57
|
+
lineEnd = source.length;
|
|
58
|
+
}
|
|
59
|
+
const lineContent = source.slice(lineStart, lineEnd);
|
|
60
|
+
const blockquoteMatch = lineContent.match(BLOCKQUOTE_PATTERN);
|
|
61
|
+
let newSource;
|
|
62
|
+
let newCursorOffset;
|
|
63
|
+
if (blockquoteMatch) {
|
|
64
|
+
// Line is already a blockquote - remove the prefix
|
|
65
|
+
newSource =
|
|
66
|
+
source.slice(0, lineStart) +
|
|
67
|
+
lineContent.slice(PREFIX.length) +
|
|
68
|
+
source.slice(lineEnd);
|
|
69
|
+
// Adjust cursor position - move back by prefix length
|
|
70
|
+
const cursorLineOffset = sourcePos - lineStart;
|
|
71
|
+
if (cursorLineOffset >= PREFIX.length) {
|
|
72
|
+
newCursorOffset = sourcePos - PREFIX.length;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
newCursorOffset = lineStart;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Line is not a blockquote - add the prefix
|
|
80
|
+
newSource =
|
|
81
|
+
source.slice(0, lineStart) + PREFIX + lineContent + source.slice(lineEnd);
|
|
82
|
+
// Cursor moves forward by prefix length
|
|
83
|
+
newCursorOffset = sourcePos + PREFIX.length;
|
|
84
|
+
}
|
|
85
|
+
// Create new state and map cursor through it
|
|
86
|
+
const next = runtime.createState(newSource);
|
|
87
|
+
const caretCursor = next.map.sourceToCursor(newCursorOffset, "forward");
|
|
88
|
+
return {
|
|
89
|
+
source: newSource,
|
|
90
|
+
selection: {
|
|
91
|
+
start: caretCursor.cursorOffset,
|
|
92
|
+
end: caretCursor.cursorOffset,
|
|
93
|
+
affinity: "forward",
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export const blockquoteExtension = defineExtension({
|
|
98
|
+
name: "blockquote",
|
|
99
|
+
onEdit(command, state) {
|
|
100
|
+
if (command.type === "toggle-blockquote") {
|
|
101
|
+
return handleToggleBlockquote(state);
|
|
102
|
+
}
|
|
103
|
+
// Handle insert-hard-line-break (Cmd+Enter) to exit blockquote
|
|
104
|
+
if (command.type === "insert-hard-line-break") {
|
|
105
|
+
return handleExitBlockquote(state);
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
},
|
|
109
|
+
parseBlock(source, start, context) {
|
|
110
|
+
if (source.slice(start, start + PREFIX.length) !== PREFIX) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const blocks = [];
|
|
114
|
+
let pos = start;
|
|
115
|
+
while (pos < source.length) {
|
|
116
|
+
if (source.slice(pos, pos + PREFIX.length) !== PREFIX) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
let lineEnd = source.indexOf("\n", pos);
|
|
120
|
+
if (lineEnd === -1) {
|
|
121
|
+
lineEnd = source.length;
|
|
122
|
+
}
|
|
123
|
+
const contentStart = pos + PREFIX.length;
|
|
124
|
+
const content = context.parseInline(source, contentStart, lineEnd);
|
|
125
|
+
const paragraph = {
|
|
126
|
+
type: "paragraph",
|
|
127
|
+
content,
|
|
128
|
+
};
|
|
129
|
+
blocks.push(paragraph);
|
|
130
|
+
if (lineEnd >= source.length) {
|
|
131
|
+
pos = lineEnd;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
const nextLineStart = lineEnd + 1;
|
|
135
|
+
if (source.slice(nextLineStart, nextLineStart + PREFIX.length) === PREFIX) {
|
|
136
|
+
pos = nextLineStart;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
pos = lineEnd;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
block: {
|
|
144
|
+
type: "block-wrapper",
|
|
145
|
+
kind: BLOCKQUOTE_KIND,
|
|
146
|
+
blocks,
|
|
147
|
+
},
|
|
148
|
+
nextPos: pos,
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
serializeBlock(block, context) {
|
|
152
|
+
if (block.type !== "block-wrapper" || block.kind !== BLOCKQUOTE_KIND) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const builder = new CursorSourceBuilder();
|
|
156
|
+
block.blocks.forEach((child, index) => {
|
|
157
|
+
builder.appendSourceOnly(PREFIX);
|
|
158
|
+
const serialized = context.serializeBlock(child);
|
|
159
|
+
builder.appendSerialized(serialized);
|
|
160
|
+
if (index < block.blocks.length - 1) {
|
|
161
|
+
builder.appendText("\n");
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
return builder.build();
|
|
165
|
+
},
|
|
166
|
+
renderBlock(block, context) {
|
|
167
|
+
if (block.type !== "block-wrapper" || block.kind !== BLOCKQUOTE_KIND) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const element = document.createElement("blockquote");
|
|
171
|
+
element.setAttribute("data-block-wrapper", BLOCKQUOTE_KIND);
|
|
172
|
+
for (const node of context.renderBlocks(block.blocks)) {
|
|
173
|
+
element.append(node);
|
|
174
|
+
}
|
|
175
|
+
return element;
|
|
176
|
+
},
|
|
177
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/blockquote/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./blockquote";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bold.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/bold/bold.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,aAAa,kCAuGxB,CAAC"}
|