@blankdotpage/cake 0.1.8 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -1
- 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 +1 -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/editor/cake-editor.d.ts +230 -0
- package/dist/cake/editor/cake-editor.d.ts.map +1 -0
- package/dist/cake/editor/cake-editor.js +3589 -0
- package/dist/cake/editor/selection/selection-geometry-dom.d.ts +24 -0
- package/dist/cake/editor/selection/selection-geometry-dom.d.ts.map +1 -0
- package/dist/cake/editor/selection/selection-geometry-dom.js +302 -0
- package/dist/cake/editor/selection/selection-geometry.d.ts +22 -0
- package/dist/cake/editor/selection/selection-geometry.d.ts.map +1 -0
- package/dist/cake/editor/selection/selection-geometry.js +158 -0
- package/dist/cake/editor/selection/selection-layout-dom.d.ts +50 -0
- package/dist/cake/editor/selection/selection-layout-dom.d.ts.map +1 -0
- package/dist/cake/editor/selection/selection-layout-dom.js +781 -0
- package/dist/cake/editor/selection/selection-layout.d.ts +55 -0
- package/dist/cake/editor/selection/selection-layout.d.ts.map +1 -0
- package/dist/cake/editor/selection/selection-layout.js +128 -0
- package/dist/cake/editor/selection/selection-navigation.d.ts +22 -0
- package/dist/cake/editor/selection/selection-navigation.d.ts.map +1 -0
- package/dist/cake/editor/selection/selection-navigation.js +229 -0
- package/dist/cake/editor/selection/visible-text.d.ts +5 -0
- package/dist/cake/editor/selection/visible-text.d.ts.map +1 -0
- package/dist/cake/editor/selection/visible-text.js +66 -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 +3 -3
- 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 +2 -1
- 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 -2
- package/dist/cake/index.d.ts.map +1 -0
- package/dist/cake/index.js +1 -0
- package/dist/cake/react/CakeEditor.d.ts +2 -2
- package/dist/cake/react/CakeEditor.d.ts.map +1 -0
- package/dist/cake/react/CakeEditor.js +225 -0
- package/dist/cake/react/index.d.ts +58 -0
- package/dist/cake/react/index.d.ts.map +1 -0
- package/dist/cake/react/index.js +225 -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 +3 -2
- 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 +2 -3
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -11793
- package/package.json +12 -6
- package/dist/cake/extensions/pipe-link/pipe-link.d.ts +0 -1
- package/dist/index.cjs +0 -11793
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cake/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG;IAChB,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,cAAc,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAEnE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;AAE7D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-map.d.ts","sourceRoot":"","sources":["../../../src/cake/dom/dom-map.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IACvE,WAAW,CACT,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,GACb;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACxD,CAAC;AASF,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAqBtE;AAqDD,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CA2GpD"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { graphemeSegments } from "../shared/segmenter";
|
|
2
|
+
const graphemeCache = new WeakMap();
|
|
3
|
+
export function createTextRun(node, cursorStart) {
|
|
4
|
+
const data = node.data;
|
|
5
|
+
const cached = graphemeCache.get(node);
|
|
6
|
+
if (cached && cached.data === data) {
|
|
7
|
+
const segmentCount = Math.max(0, cached.boundaryOffsets.length - 1);
|
|
8
|
+
return {
|
|
9
|
+
node,
|
|
10
|
+
cursorStart,
|
|
11
|
+
cursorEnd: cursorStart + segmentCount,
|
|
12
|
+
boundaryOffsets: cached.boundaryOffsets,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const segments = graphemeSegments(data);
|
|
16
|
+
const boundaryOffsets = [0];
|
|
17
|
+
for (const segment of segments) {
|
|
18
|
+
boundaryOffsets.push(segment.index + segment.segment.length);
|
|
19
|
+
}
|
|
20
|
+
const cursorEnd = cursorStart + segments.length;
|
|
21
|
+
graphemeCache.set(node, { data, boundaryOffsets });
|
|
22
|
+
return { node, cursorStart, cursorEnd, boundaryOffsets };
|
|
23
|
+
}
|
|
24
|
+
function boundaryIndexForOffset(boundaryOffsets, offset) {
|
|
25
|
+
if (offset <= 0) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
const lastIndex = boundaryOffsets.length - 1;
|
|
29
|
+
if (lastIndex <= 0) {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
const lastBoundary = boundaryOffsets[lastIndex];
|
|
33
|
+
if (offset >= lastBoundary) {
|
|
34
|
+
return lastIndex;
|
|
35
|
+
}
|
|
36
|
+
// Find first boundary >= offset (lower_bound).
|
|
37
|
+
let low = 1;
|
|
38
|
+
let high = lastIndex;
|
|
39
|
+
while (low < high) {
|
|
40
|
+
const mid = (low + high) >>> 1;
|
|
41
|
+
const boundary = boundaryOffsets[mid];
|
|
42
|
+
if (boundary < offset) {
|
|
43
|
+
low = mid + 1;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
high = mid;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const boundary = boundaryOffsets[low];
|
|
50
|
+
return boundary === offset ? low : low - 1;
|
|
51
|
+
}
|
|
52
|
+
function firstRunStartingAfterCursor(runs, cursorOffset) {
|
|
53
|
+
let low = 0;
|
|
54
|
+
let high = runs.length;
|
|
55
|
+
while (low < high) {
|
|
56
|
+
const mid = (low + high) >>> 1;
|
|
57
|
+
if (runs[mid].cursorStart <= cursorOffset) {
|
|
58
|
+
low = mid + 1;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
high = mid;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return low;
|
|
65
|
+
}
|
|
66
|
+
export function createDomMap(runs) {
|
|
67
|
+
const runForNode = new Map();
|
|
68
|
+
const runIndexForNode = new Map();
|
|
69
|
+
runs.forEach((run, index) => {
|
|
70
|
+
runIndexForNode.set(run.node, index);
|
|
71
|
+
});
|
|
72
|
+
for (const run of runs) {
|
|
73
|
+
runForNode.set(run.node, run);
|
|
74
|
+
}
|
|
75
|
+
function domAtCursor(cursorOffset, affinity) {
|
|
76
|
+
if (runs.length === 0) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const nextIndex = firstRunStartingAfterCursor(runs, cursorOffset);
|
|
80
|
+
const runIndex = nextIndex - 1;
|
|
81
|
+
if (runIndex < 0) {
|
|
82
|
+
const first = runs[0];
|
|
83
|
+
return { node: first.node, offset: first.boundaryOffsets[0] };
|
|
84
|
+
}
|
|
85
|
+
const run = runs[runIndex];
|
|
86
|
+
const previous = runIndex > 0 ? runs[runIndex - 1] : null;
|
|
87
|
+
const next = nextIndex < runs.length ? runs[nextIndex] : null;
|
|
88
|
+
if (cursorOffset === run.cursorStart && previous && affinity === "backward") {
|
|
89
|
+
return {
|
|
90
|
+
node: previous.node,
|
|
91
|
+
offset: previous.boundaryOffsets[previous.boundaryOffsets.length - 1],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Cursor lies within this run
|
|
95
|
+
if (cursorOffset <= run.cursorEnd) {
|
|
96
|
+
if (cursorOffset === run.cursorEnd &&
|
|
97
|
+
affinity === "forward" &&
|
|
98
|
+
next &&
|
|
99
|
+
next.cursorStart === cursorOffset) {
|
|
100
|
+
return { node: next.node, offset: next.boundaryOffsets[0] };
|
|
101
|
+
}
|
|
102
|
+
const index = Math.max(0, cursorOffset - run.cursorStart);
|
|
103
|
+
const boundedIndex = Math.min(index, run.boundaryOffsets.length - 1);
|
|
104
|
+
return { node: run.node, offset: run.boundaryOffsets[boundedIndex] };
|
|
105
|
+
}
|
|
106
|
+
// Cursor lies in a gap between runs (e.g., block boundary/newline)
|
|
107
|
+
if (next) {
|
|
108
|
+
const runEndOffset = run.boundaryOffsets[run.boundaryOffsets.length - 1];
|
|
109
|
+
return affinity === "backward"
|
|
110
|
+
? { node: run.node, offset: runEndOffset }
|
|
111
|
+
: { node: next.node, offset: next.boundaryOffsets[0] };
|
|
112
|
+
}
|
|
113
|
+
// Cursor lies after final run
|
|
114
|
+
const last = run;
|
|
115
|
+
return {
|
|
116
|
+
node: last.node,
|
|
117
|
+
offset: last.boundaryOffsets[last.boundaryOffsets.length - 1],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function cursorAtDom(node, offset) {
|
|
121
|
+
const run = runForNode.get(node);
|
|
122
|
+
if (!run) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const runIndex = runIndexForNode.get(node);
|
|
126
|
+
const index = boundaryIndexForOffset(run.boundaryOffsets, offset);
|
|
127
|
+
const cursorOffset = run.cursorStart + index;
|
|
128
|
+
const atStart = offset === 0;
|
|
129
|
+
const atEnd = offset === run.boundaryOffsets[run.boundaryOffsets.length - 1];
|
|
130
|
+
const isNonEmptyRun = run.boundaryOffsets.length > 1;
|
|
131
|
+
// Determine affinity based on position in text run and adjacent runs.
|
|
132
|
+
// Only use "backward" affinity at the end of a run if there's a next run,
|
|
133
|
+
// matching v1 behavior where backward affinity keeps the caret in the
|
|
134
|
+
// current formatting context (e.g., inside a link).
|
|
135
|
+
const hasNextRun = runIndex !== undefined && runIndex + 1 < runs.length;
|
|
136
|
+
const hasPrevRun = runIndex !== undefined && runIndex > 0;
|
|
137
|
+
let affinity = "forward";
|
|
138
|
+
if (atEnd && isNonEmptyRun && hasNextRun) {
|
|
139
|
+
// At end of a run with a next run: use backward affinity to stay
|
|
140
|
+
// in the current run's context (e.g., inside bold/link)
|
|
141
|
+
affinity = "backward";
|
|
142
|
+
}
|
|
143
|
+
else if (atStart && hasPrevRun) {
|
|
144
|
+
// At start of a run with a previous run: use forward affinity
|
|
145
|
+
// to stay in the current run's context
|
|
146
|
+
affinity = "forward";
|
|
147
|
+
}
|
|
148
|
+
return { cursorOffset, affinity };
|
|
149
|
+
}
|
|
150
|
+
return { runs, domAtCursor, cursorAtDom };
|
|
151
|
+
}
|
|
@@ -2,3 +2,4 @@ import type { Selection } from "../core/types";
|
|
|
2
2
|
import type { DomMap } from "./dom-map";
|
|
3
3
|
export declare function applyDomSelection(selection: Selection, map: DomMap): void;
|
|
4
4
|
export declare function readDomSelection(map: DomMap): Selection | null;
|
|
5
|
+
//# sourceMappingURL=dom-selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-selection.d.ts","sourceRoot":"","sources":["../../../src/cake/dom/dom-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,SAAS,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAgHzE;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CA+C9D"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
export function applyDomSelection(selection, map) {
|
|
2
|
+
const domSelection = window.getSelection();
|
|
3
|
+
if (!domSelection) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
const isCollapsed = selection.start === selection.end;
|
|
7
|
+
let anchorCursor = selection.start;
|
|
8
|
+
let focusCursor = selection.end;
|
|
9
|
+
let isForward = true;
|
|
10
|
+
if (!isCollapsed) {
|
|
11
|
+
// Selection values come from two sources:
|
|
12
|
+
// - engine/model helpers (often normalized start<=end with `affinity` as direction)
|
|
13
|
+
// - DOM reads (anchor/focus order, possibly start>end)
|
|
14
|
+
//
|
|
15
|
+
// Reconstruct anchor/focus in a way that preserves direction while keeping
|
|
16
|
+
// the mapping extension-agnostic.
|
|
17
|
+
if (selection.start > selection.end) {
|
|
18
|
+
// DOM-style anchor/focus (start=end? handled above)
|
|
19
|
+
anchorCursor = selection.start;
|
|
20
|
+
focusCursor = selection.end;
|
|
21
|
+
isForward = false;
|
|
22
|
+
}
|
|
23
|
+
else if (selection.affinity === "backward") {
|
|
24
|
+
// Model-style backward selection: anchor is the higher edge.
|
|
25
|
+
anchorCursor = selection.end;
|
|
26
|
+
focusCursor = selection.start;
|
|
27
|
+
isForward = false;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Model-style forward selection (default)
|
|
31
|
+
anchorCursor = selection.start;
|
|
32
|
+
focusCursor = selection.end;
|
|
33
|
+
isForward = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const baseAnchorAffinity = isCollapsed
|
|
37
|
+
? (selection.affinity ?? "forward")
|
|
38
|
+
: isForward
|
|
39
|
+
? "forward"
|
|
40
|
+
: "backward";
|
|
41
|
+
const baseFocusAffinity = isCollapsed
|
|
42
|
+
? (selection.affinity ?? "forward")
|
|
43
|
+
: isForward
|
|
44
|
+
? "backward"
|
|
45
|
+
: "forward";
|
|
46
|
+
const anchorAffinity = normalizeAffinityForBlockBoundary(map, anchorCursor, baseAnchorAffinity, isCollapsed);
|
|
47
|
+
const focusAffinity = normalizeAffinityForBlockBoundary(map, focusCursor, baseFocusAffinity, isCollapsed);
|
|
48
|
+
const anchorPoint = map.domAtCursor(anchorCursor, anchorAffinity);
|
|
49
|
+
const focusPoint = map.domAtCursor(focusCursor, focusAffinity);
|
|
50
|
+
if (!anchorPoint || !focusPoint) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (domSelection.rangeCount > 0 &&
|
|
54
|
+
domSelection.anchorNode === anchorPoint.node &&
|
|
55
|
+
domSelection.anchorOffset === anchorPoint.offset &&
|
|
56
|
+
domSelection.focusNode === focusPoint.node &&
|
|
57
|
+
domSelection.focusOffset === focusPoint.offset) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (isCollapsed) {
|
|
61
|
+
domSelection.collapse(anchorPoint.node, anchorPoint.offset);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Prefer APIs that preserve direction (anchor/focus).
|
|
65
|
+
const selectionWithExtent = domSelection;
|
|
66
|
+
if (typeof selectionWithExtent.setBaseAndExtent === "function") {
|
|
67
|
+
selectionWithExtent.setBaseAndExtent(anchorPoint.node, anchorPoint.offset, focusPoint.node, focusPoint.offset);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (typeof domSelection.extend === "function") {
|
|
71
|
+
domSelection.collapse(anchorPoint.node, anchorPoint.offset);
|
|
72
|
+
domSelection.extend(focusPoint.node, focusPoint.offset);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Fallback: apply the selection as a range in document order.
|
|
76
|
+
domSelection.removeAllRanges();
|
|
77
|
+
const range = document.createRange();
|
|
78
|
+
const rangeStart = isForward ? anchorPoint : focusPoint;
|
|
79
|
+
const rangeEnd = isForward ? focusPoint : anchorPoint;
|
|
80
|
+
range.setStart(rangeStart.node, rangeStart.offset);
|
|
81
|
+
range.setEnd(rangeEnd.node, rangeEnd.offset);
|
|
82
|
+
domSelection.addRange(range);
|
|
83
|
+
}
|
|
84
|
+
export function readDomSelection(map) {
|
|
85
|
+
const domSelection = window.getSelection();
|
|
86
|
+
if (!domSelection || domSelection.rangeCount === 0) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const anchorPoint = resolveTextPoint(domSelection.anchorNode, domSelection.anchorOffset);
|
|
90
|
+
const focusPoint = resolveTextPoint(domSelection.focusNode, domSelection.focusOffset);
|
|
91
|
+
if (!anchorPoint || !focusPoint) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const anchor = map.cursorAtDom(anchorPoint.node, anchorPoint.offset);
|
|
95
|
+
const focus = map.cursorAtDom(focusPoint.node, focusPoint.offset);
|
|
96
|
+
if (!anchor || !focus) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
// Model selection contract:
|
|
100
|
+
// - Always normalize to start <= end
|
|
101
|
+
// - Encode direction in `affinity` for range selections
|
|
102
|
+
// - Preserve caret-side affinity only for collapsed selections
|
|
103
|
+
if (anchor.cursorOffset === focus.cursorOffset) {
|
|
104
|
+
return {
|
|
105
|
+
start: anchor.cursorOffset,
|
|
106
|
+
end: anchor.cursorOffset,
|
|
107
|
+
affinity: focus.affinity,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (anchor.cursorOffset < focus.cursorOffset) {
|
|
111
|
+
return {
|
|
112
|
+
start: anchor.cursorOffset,
|
|
113
|
+
end: focus.cursorOffset,
|
|
114
|
+
affinity: "forward",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
start: focus.cursorOffset,
|
|
119
|
+
end: anchor.cursorOffset,
|
|
120
|
+
affinity: "backward",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function resolveTextPoint(node, offset) {
|
|
124
|
+
if (!node) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
if (node instanceof Text) {
|
|
128
|
+
return { node, offset };
|
|
129
|
+
}
|
|
130
|
+
if (!(node instanceof Element)) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const children = node.childNodes;
|
|
134
|
+
if (children.length === 0) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
if (offset <= 0) {
|
|
138
|
+
const first = findTextNodeAtOrAfter(children, 0);
|
|
139
|
+
return first ? { node: first, offset: 0 } : null;
|
|
140
|
+
}
|
|
141
|
+
if (offset >= children.length) {
|
|
142
|
+
const last = findTextNodeAtOrBefore(children, children.length - 1);
|
|
143
|
+
return last ? { node: last, offset: last.data.length } : null;
|
|
144
|
+
}
|
|
145
|
+
const exact = findFirstTextNode(children[offset]);
|
|
146
|
+
if (exact) {
|
|
147
|
+
return { node: exact, offset: 0 };
|
|
148
|
+
}
|
|
149
|
+
const previous = findTextNodeAtOrBefore(children, offset - 1);
|
|
150
|
+
if (previous) {
|
|
151
|
+
return { node: previous, offset: previous.data.length };
|
|
152
|
+
}
|
|
153
|
+
const next = findTextNodeAtOrAfter(children, offset + 1);
|
|
154
|
+
return next ? { node: next, offset: 0 } : null;
|
|
155
|
+
}
|
|
156
|
+
function normalizeAffinityForBlockBoundary(map, cursorOffset, affinity, isCollapsed) {
|
|
157
|
+
if (isCollapsed || affinity !== "backward") {
|
|
158
|
+
return affinity;
|
|
159
|
+
}
|
|
160
|
+
if (!isBlockBoundaryOffset(map, cursorOffset)) {
|
|
161
|
+
return affinity;
|
|
162
|
+
}
|
|
163
|
+
return "forward";
|
|
164
|
+
}
|
|
165
|
+
function isBlockBoundaryOffset(map, cursorOffset) {
|
|
166
|
+
const runs = map.runs;
|
|
167
|
+
for (let i = 1; i < runs.length; i += 1) {
|
|
168
|
+
const run = runs[i];
|
|
169
|
+
const previous = runs[i - 1];
|
|
170
|
+
if (cursorOffset > previous.cursorEnd && cursorOffset <= run.cursorStart) {
|
|
171
|
+
return run.cursorStart > previous.cursorEnd;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
function findFirstTextNode(node) {
|
|
177
|
+
if (node instanceof Text) {
|
|
178
|
+
return node;
|
|
179
|
+
}
|
|
180
|
+
const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT);
|
|
181
|
+
const next = walker.nextNode();
|
|
182
|
+
return next instanceof Text ? next : null;
|
|
183
|
+
}
|
|
184
|
+
function findLastTextNode(node) {
|
|
185
|
+
if (node instanceof Text) {
|
|
186
|
+
return node;
|
|
187
|
+
}
|
|
188
|
+
const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT);
|
|
189
|
+
let last = null;
|
|
190
|
+
let current = walker.nextNode();
|
|
191
|
+
while (current) {
|
|
192
|
+
if (current instanceof Text) {
|
|
193
|
+
last = current;
|
|
194
|
+
}
|
|
195
|
+
current = walker.nextNode();
|
|
196
|
+
}
|
|
197
|
+
return last;
|
|
198
|
+
}
|
|
199
|
+
function findTextNodeAtOrAfter(nodes, start) {
|
|
200
|
+
for (let i = Math.max(0, start); i < nodes.length; i += 1) {
|
|
201
|
+
const found = findFirstTextNode(nodes[i]);
|
|
202
|
+
if (found) {
|
|
203
|
+
return found;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
function findTextNodeAtOrBefore(nodes, start) {
|
|
209
|
+
for (let i = Math.min(nodes.length - 1, start); i >= 0; i -= 1) {
|
|
210
|
+
const found = findLastTextNode(nodes[i]);
|
|
211
|
+
if (found) {
|
|
212
|
+
return found;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
@@ -12,3 +12,4 @@ export type RenderContentResult = {
|
|
|
12
12
|
export declare function renderDocContent(doc: Doc, extensions: CakeExtension[], root?: HTMLElement): RenderContentResult;
|
|
13
13
|
export declare function renderDoc(doc: Doc, extensions: CakeExtension[]): RenderResult;
|
|
14
14
|
export declare function mergeInlineForRender(inlines: Inline[]): Inline[];
|
|
15
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/cake/dom/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,GAAG,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EACL,YAAY,EAGb,MAAM,WAAW,CAAC;AAEnB,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,IAAI,EAAE,CAAC;IAChB,GAAG,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;CACtC,CAAC;AASF,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,aAAa,EAAE,EAC3B,IAAI,CAAC,EAAE,WAAW,GACjB,mBAAmB,CAmXrB;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,aAAa,EAAE,GAC1B,YAAY,CAkJd;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAiChE"}
|