@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":"index.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/scrollbar/index.tsx"],"names":[],"mappings":"AA2RA,eAAO,MAAM,kBAAkB,kCAK7B,CAAC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { defineExtension } from "../../core/runtime";
|
|
4
|
+
const THUMB_MIN_HEIGHT = 30;
|
|
5
|
+
const SCROLL_HIDE_DELAY = 500;
|
|
6
|
+
const TRACK_PADDING = 8;
|
|
7
|
+
function ScrollbarOverlay({ container }) {
|
|
8
|
+
const [state, setState] = useState({
|
|
9
|
+
scrollTop: 0,
|
|
10
|
+
scrollHeight: 0,
|
|
11
|
+
clientHeight: 0,
|
|
12
|
+
});
|
|
13
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
14
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
15
|
+
const [isScrolling, setIsScrolling] = useState(false);
|
|
16
|
+
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
17
|
+
const dragStartRef = useRef(null);
|
|
18
|
+
const scrollTimeoutRef = useRef(null);
|
|
19
|
+
const { scrollTop, scrollHeight, clientHeight } = state;
|
|
20
|
+
const hasOverflow = scrollHeight > clientHeight;
|
|
21
|
+
const trackHeight = clientHeight - TRACK_PADDING * 2;
|
|
22
|
+
const rawThumbHeight = hasOverflow
|
|
23
|
+
? (clientHeight / scrollHeight) * trackHeight
|
|
24
|
+
: 0;
|
|
25
|
+
const thumbHeight = Math.min(trackHeight, Math.max(THUMB_MIN_HEIGHT, rawThumbHeight));
|
|
26
|
+
const maxScrollTop = scrollHeight - clientHeight;
|
|
27
|
+
const thumbTop = maxScrollTop > 0
|
|
28
|
+
? TRACK_PADDING + (scrollTop / maxScrollTop) * (trackHeight - thumbHeight)
|
|
29
|
+
: TRACK_PADDING;
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
function checkDarkMode() {
|
|
32
|
+
// Check for explicit dark class - blank page adds "dark" class when in dark mode
|
|
33
|
+
// When in light mode, there's no explicit class, so default to light
|
|
34
|
+
const html = document.documentElement;
|
|
35
|
+
setIsDarkMode(html.classList.contains("dark"));
|
|
36
|
+
}
|
|
37
|
+
checkDarkMode();
|
|
38
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
39
|
+
mediaQuery.addEventListener("change", checkDarkMode);
|
|
40
|
+
const observer = new MutationObserver(checkDarkMode);
|
|
41
|
+
observer.observe(document.documentElement, {
|
|
42
|
+
attributes: true,
|
|
43
|
+
attributeFilter: ["class"],
|
|
44
|
+
});
|
|
45
|
+
return () => {
|
|
46
|
+
mediaQuery.removeEventListener("change", checkDarkMode);
|
|
47
|
+
observer.disconnect();
|
|
48
|
+
};
|
|
49
|
+
}, []);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
function update() {
|
|
52
|
+
setState({
|
|
53
|
+
scrollTop: container.scrollTop,
|
|
54
|
+
scrollHeight: container.scrollHeight,
|
|
55
|
+
clientHeight: container.clientHeight,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function handleScroll() {
|
|
59
|
+
update();
|
|
60
|
+
setIsScrolling(true);
|
|
61
|
+
if (scrollTimeoutRef.current) {
|
|
62
|
+
clearTimeout(scrollTimeoutRef.current);
|
|
63
|
+
}
|
|
64
|
+
scrollTimeoutRef.current = setTimeout(() => {
|
|
65
|
+
setIsScrolling(false);
|
|
66
|
+
}, SCROLL_HIDE_DELAY);
|
|
67
|
+
}
|
|
68
|
+
update();
|
|
69
|
+
container.addEventListener("scroll", handleScroll);
|
|
70
|
+
window.addEventListener("resize", update);
|
|
71
|
+
let resizeObserver = null;
|
|
72
|
+
let mutationObserver = null;
|
|
73
|
+
let observedContent = null;
|
|
74
|
+
const observeContent = () => {
|
|
75
|
+
if (!resizeObserver) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const nextContent = container.querySelector(".cake-content");
|
|
79
|
+
if (nextContent === observedContent) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (observedContent) {
|
|
83
|
+
resizeObserver.unobserve(observedContent);
|
|
84
|
+
}
|
|
85
|
+
observedContent = nextContent;
|
|
86
|
+
if (observedContent) {
|
|
87
|
+
resizeObserver.observe(observedContent);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
91
|
+
resizeObserver = new ResizeObserver(update);
|
|
92
|
+
resizeObserver.observe(container);
|
|
93
|
+
observeContent();
|
|
94
|
+
}
|
|
95
|
+
if (typeof MutationObserver !== "undefined") {
|
|
96
|
+
mutationObserver = new MutationObserver(() => {
|
|
97
|
+
observeContent();
|
|
98
|
+
update();
|
|
99
|
+
});
|
|
100
|
+
mutationObserver.observe(container, {
|
|
101
|
+
childList: true,
|
|
102
|
+
subtree: true,
|
|
103
|
+
characterData: true,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return () => {
|
|
107
|
+
container.removeEventListener("scroll", handleScroll);
|
|
108
|
+
window.removeEventListener("resize", update);
|
|
109
|
+
resizeObserver?.disconnect();
|
|
110
|
+
mutationObserver?.disconnect();
|
|
111
|
+
if (scrollTimeoutRef.current) {
|
|
112
|
+
clearTimeout(scrollTimeoutRef.current);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}, [container]);
|
|
116
|
+
const handleTrackClick = useCallback((event) => {
|
|
117
|
+
if (event.target !== event.currentTarget) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const trackRect = event.currentTarget.getBoundingClientRect();
|
|
121
|
+
const clickY = event.clientY - trackRect.top;
|
|
122
|
+
const clickRatio = clickY / trackHeight;
|
|
123
|
+
const targetScrollTop = clickRatio * maxScrollTop;
|
|
124
|
+
container.scrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));
|
|
125
|
+
}, [container, trackHeight, maxScrollTop]);
|
|
126
|
+
const handleThumbMouseDown = useCallback((event) => {
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
event.stopPropagation();
|
|
129
|
+
setIsDragging(true);
|
|
130
|
+
dragStartRef.current = {
|
|
131
|
+
scrollTop: container.scrollTop,
|
|
132
|
+
clientY: event.clientY,
|
|
133
|
+
};
|
|
134
|
+
}, [container]);
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (!isDragging) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const originalUserSelect = document.body.style.userSelect;
|
|
140
|
+
document.body.style.userSelect = "none";
|
|
141
|
+
function handleMouseMove(event) {
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
event.stopPropagation();
|
|
144
|
+
if (!dragStartRef.current) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const deltaY = event.clientY - dragStartRef.current.clientY;
|
|
148
|
+
const scrollableTrack = trackHeight - thumbHeight;
|
|
149
|
+
const scrollRatio = scrollableTrack > 0 ? deltaY / scrollableTrack : 0;
|
|
150
|
+
const deltaScroll = scrollRatio * maxScrollTop;
|
|
151
|
+
container.scrollTop = Math.max(0, Math.min(dragStartRef.current.scrollTop + deltaScroll, maxScrollTop));
|
|
152
|
+
}
|
|
153
|
+
function handleMouseUp(event) {
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
event.stopPropagation();
|
|
156
|
+
setIsDragging(false);
|
|
157
|
+
dragStartRef.current = null;
|
|
158
|
+
}
|
|
159
|
+
document.addEventListener("mousemove", handleMouseMove, { capture: true });
|
|
160
|
+
document.addEventListener("mouseup", handleMouseUp, { capture: true });
|
|
161
|
+
return () => {
|
|
162
|
+
document.removeEventListener("mousemove", handleMouseMove, {
|
|
163
|
+
capture: true,
|
|
164
|
+
});
|
|
165
|
+
document.removeEventListener("mouseup", handleMouseUp, {
|
|
166
|
+
capture: true,
|
|
167
|
+
});
|
|
168
|
+
document.body.style.userSelect = originalUserSelect;
|
|
169
|
+
};
|
|
170
|
+
}, [isDragging, container, trackHeight, thumbHeight, maxScrollTop]);
|
|
171
|
+
if (!hasOverflow || trackHeight < THUMB_MIN_HEIGHT) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const isVisible = isDragging || isHovered || isScrolling;
|
|
175
|
+
const wrapperStyle = {
|
|
176
|
+
position: "absolute",
|
|
177
|
+
inset: 0,
|
|
178
|
+
pointerEvents: "none",
|
|
179
|
+
overflow: "hidden",
|
|
180
|
+
zIndex: 50,
|
|
181
|
+
};
|
|
182
|
+
const trackStyle = {
|
|
183
|
+
position: "absolute",
|
|
184
|
+
top: 0,
|
|
185
|
+
right: 0,
|
|
186
|
+
bottom: 0,
|
|
187
|
+
width: "12px",
|
|
188
|
+
height: clientHeight,
|
|
189
|
+
pointerEvents: "auto",
|
|
190
|
+
};
|
|
191
|
+
const getThumbColor = () => {
|
|
192
|
+
if (isDarkMode) {
|
|
193
|
+
return isDragging ? "rgba(255, 255, 255, 0.5)" : "rgba(255, 255, 255, 0.3)";
|
|
194
|
+
}
|
|
195
|
+
return isDragging ? "rgba(0, 0, 0, 0.5)" : "rgba(0, 0, 0, 0.3)";
|
|
196
|
+
};
|
|
197
|
+
const thumbStyle = {
|
|
198
|
+
position: "absolute",
|
|
199
|
+
right: "2px",
|
|
200
|
+
width: "6px",
|
|
201
|
+
borderRadius: "9999px",
|
|
202
|
+
height: thumbHeight,
|
|
203
|
+
top: thumbTop,
|
|
204
|
+
opacity: isVisible ? 1 : 0,
|
|
205
|
+
backgroundColor: getThumbColor(),
|
|
206
|
+
transition: "opacity 150ms",
|
|
207
|
+
cursor: "pointer",
|
|
208
|
+
};
|
|
209
|
+
return (_jsx("div", { style: wrapperStyle, children: _jsx("div", { "data-testid": "custom-scrollbar", "aria-hidden": "true", style: trackStyle, onClick: handleTrackClick, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: _jsx("div", { "data-testid": "scrollbar-thumb", style: thumbStyle, onMouseDown: handleThumbMouseDown }) }) }));
|
|
210
|
+
}
|
|
211
|
+
export const scrollbarExtension = defineExtension({
|
|
212
|
+
name: "scrollbar",
|
|
213
|
+
renderOverlay(context) {
|
|
214
|
+
return _jsx(ScrollbarOverlay, { container: context.container });
|
|
215
|
+
},
|
|
216
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/strikethrough/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./strikethrough";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strikethrough.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/strikethrough/strikethrough.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,sBAAsB,kCAuFjC,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { defineExtension, } from "../../core/runtime";
|
|
2
|
+
import { CursorSourceBuilder } from "../../core/mapping/cursor-source-map";
|
|
3
|
+
const STRIKE_KIND = "strikethrough";
|
|
4
|
+
export const strikethroughExtension = defineExtension({
|
|
5
|
+
name: "strikethrough",
|
|
6
|
+
toggleInline: { kind: STRIKE_KIND, markers: ["~~"] },
|
|
7
|
+
keybindings: [
|
|
8
|
+
{
|
|
9
|
+
key: "x",
|
|
10
|
+
meta: true,
|
|
11
|
+
shift: true,
|
|
12
|
+
command: { type: "toggle-strikethrough" },
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
key: "x",
|
|
16
|
+
ctrl: true,
|
|
17
|
+
shift: true,
|
|
18
|
+
command: { type: "toggle-strikethrough" },
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
inlineWrapperAffinity: [{ kind: STRIKE_KIND, inclusive: true }],
|
|
22
|
+
onEdit(command) {
|
|
23
|
+
// Handle semantic command by delegating to toggle-inline
|
|
24
|
+
if (command.type === "toggle-strikethrough") {
|
|
25
|
+
return { type: "toggle-inline", marker: "~~" };
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
},
|
|
29
|
+
parseInline(source, start, end, context) {
|
|
30
|
+
if (source.slice(start, start + 2) !== "~~") {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const close = source.indexOf("~~", start + 2);
|
|
34
|
+
if (close === -1 || close >= end) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (close === start + 2 && close + 2 < end) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const children = context.parseInline(source, start + 2, close);
|
|
41
|
+
return {
|
|
42
|
+
inline: {
|
|
43
|
+
type: "inline-wrapper",
|
|
44
|
+
kind: STRIKE_KIND,
|
|
45
|
+
children,
|
|
46
|
+
},
|
|
47
|
+
nextPos: close + 2,
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
serializeInline(inline, context) {
|
|
51
|
+
if (inline.type !== "inline-wrapper" || inline.kind !== STRIKE_KIND) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const builder = new CursorSourceBuilder();
|
|
55
|
+
builder.appendSourceOnly("~~");
|
|
56
|
+
for (const child of inline.children) {
|
|
57
|
+
const serialized = context.serializeInline(child);
|
|
58
|
+
builder.appendSerialized(serialized);
|
|
59
|
+
}
|
|
60
|
+
builder.appendSourceOnly("~~");
|
|
61
|
+
return builder.build();
|
|
62
|
+
},
|
|
63
|
+
normalizeInline(inline) {
|
|
64
|
+
if (inline.type !== "inline-wrapper" || inline.kind !== STRIKE_KIND) {
|
|
65
|
+
return inline;
|
|
66
|
+
}
|
|
67
|
+
if (inline.children.length === 0) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return inline;
|
|
71
|
+
},
|
|
72
|
+
renderInline(inline, context) {
|
|
73
|
+
if (inline.type !== "inline-wrapper" || inline.kind !== STRIKE_KIND) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const element = document.createElement("s");
|
|
77
|
+
for (const child of inline.children) {
|
|
78
|
+
for (const node of context.renderInline(child)) {
|
|
79
|
+
element.append(node);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return element;
|
|
83
|
+
},
|
|
84
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cake/extensions/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cake/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { CakeEditor } from "./react/CakeEditor";
|
|
2
2
|
export type { CakeEditorProps, CakeEditorRef, CakeEditorSelection, CakeEditorUpdate, } from "./react/CakeEditor";
|
|
3
3
|
export type { EditCommand, CoreEditCommand, ExtensionCommand } from "./core/runtime";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cake/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EACV,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CakeEditor } from "./react/CakeEditor";
|
|
@@ -56,3 +56,4 @@ export interface CakeEditorRef {
|
|
|
56
56
|
replaceText: (oldText: string, newText: string) => void;
|
|
57
57
|
}
|
|
58
58
|
export declare const CakeEditor: import("react").ForwardRefExoticComponent<CakeEditorProps & import("react").RefAttributes<CakeEditorRef | null>>;
|
|
59
|
+
//# sourceMappingURL=CakeEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CakeEditor.d.ts","sourceRoot":"","sources":["../../../src/cake/react/CakeEditor.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EAEZ,MAAM,iBAAiB,CAAC;AAkBzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACnC,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,iBAAiB,CAAC,EAAE,CAClB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,UAAU,GAAG,SAAS,KAC9B,IAAI,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjD,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB;;;;;;;;;;;;OAYG;IACH,cAAc,EAAE,CACd,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,KACjC,OAAO,CAAC;IACb,WAAW,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,eAAe,EAAE,MAAM,MAAM,CAAC;IAC9B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AAED,eAAO,MAAM,UAAU,kHAwQrB,CAAC"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, forwardRef, useEffect, useImperativeHandle, useRef, useState, } from "react";
|
|
3
|
+
import { CakeEngine } from "../engine/cake-engine";
|
|
4
|
+
import { bundledExtensions, bundledExtensionsWithoutImage, } from "../extensions";
|
|
5
|
+
function toEngineSelection(selection) {
|
|
6
|
+
if (!selection) {
|
|
7
|
+
return { start: 0, end: 0, affinity: "forward" };
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
start: selection.start,
|
|
11
|
+
end: selection.end,
|
|
12
|
+
affinity: selection.affinity,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export const CakeEditor = forwardRef(function CakeEditor(props, outerRef) {
|
|
16
|
+
const containerRef = useRef(null);
|
|
17
|
+
const engineRef = useRef(null);
|
|
18
|
+
const onChangeRef = useRef(props.onChange);
|
|
19
|
+
const onSelectionChangeRef = useRef(props.onSelectionChange);
|
|
20
|
+
const lastEmittedValueRef = useRef(null);
|
|
21
|
+
const lastEmittedSelectionRef = useRef(null);
|
|
22
|
+
const [contentRoot, setContentRoot] = useState(null);
|
|
23
|
+
// Merge bundled extensions with custom extensions
|
|
24
|
+
const baseExtensions = props.disableImageExtension
|
|
25
|
+
? bundledExtensionsWithoutImage
|
|
26
|
+
: bundledExtensions;
|
|
27
|
+
const allExtensionsRef = useRef([
|
|
28
|
+
...baseExtensions,
|
|
29
|
+
...(props.extensions ?? []),
|
|
30
|
+
]);
|
|
31
|
+
const hasOverlayExtensions = allExtensionsRef.current.some((ext) => ext.renderOverlay);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
onChangeRef.current = props.onChange;
|
|
34
|
+
onSelectionChangeRef.current = props.onSelectionChange;
|
|
35
|
+
}, [props.onChange, props.onSelectionChange]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
engineRef.current?.syncPlaceholder();
|
|
38
|
+
}, [props.placeholder]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const container = containerRef.current;
|
|
41
|
+
if (!container) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const engine = new CakeEngine({
|
|
45
|
+
container,
|
|
46
|
+
value: props.value,
|
|
47
|
+
selection: props.selection ?? undefined,
|
|
48
|
+
extensions: allExtensionsRef.current,
|
|
49
|
+
readOnly: props.disabled ?? false,
|
|
50
|
+
spellCheckEnabled: props.spellCheck ?? false,
|
|
51
|
+
onChange: (value, selection) => {
|
|
52
|
+
lastEmittedValueRef.current = value;
|
|
53
|
+
lastEmittedSelectionRef.current = selection;
|
|
54
|
+
onChangeRef.current(value);
|
|
55
|
+
onSelectionChangeRef.current?.(selection.start, selection.end, selection.affinity);
|
|
56
|
+
},
|
|
57
|
+
onSelectionChange: (selection) => {
|
|
58
|
+
lastEmittedSelectionRef.current = selection;
|
|
59
|
+
onSelectionChangeRef.current?.(selection.start, selection.end, selection.affinity);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
engineRef.current = engine;
|
|
63
|
+
setContentRoot(engine.getContentRoot());
|
|
64
|
+
return () => {
|
|
65
|
+
engine.destroy();
|
|
66
|
+
engineRef.current = null;
|
|
67
|
+
setContentRoot(null);
|
|
68
|
+
};
|
|
69
|
+
}, []);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
const engine = engineRef.current;
|
|
72
|
+
if (!engine) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
engine.setReadOnly(props.disabled ?? false);
|
|
76
|
+
}, [props.disabled]);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const engine = engineRef.current;
|
|
79
|
+
if (!engine) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
engine.setSpellCheckEnabled(props.spellCheck ?? false);
|
|
83
|
+
}, [props.spellCheck]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
const engine = engineRef.current;
|
|
86
|
+
if (!engine) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const nextValue = props.value;
|
|
90
|
+
const nextSelection = props.selection
|
|
91
|
+
? toEngineSelection(props.selection)
|
|
92
|
+
: undefined;
|
|
93
|
+
const lastEmittedValue = lastEmittedValueRef.current;
|
|
94
|
+
// If the value matches what we emitted, don't accept selection changes from props.
|
|
95
|
+
// This prevents stale selection props (from React batching during fast typing)
|
|
96
|
+
// from resetting the engine's selection.
|
|
97
|
+
if (lastEmittedValue === nextValue) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
engine.setValue({
|
|
101
|
+
value: nextValue,
|
|
102
|
+
selection: nextSelection,
|
|
103
|
+
});
|
|
104
|
+
}, [props.value, props.selection]);
|
|
105
|
+
useImperativeHandle(outerRef, () => {
|
|
106
|
+
return {
|
|
107
|
+
element: containerRef.current,
|
|
108
|
+
focus: (selection) => {
|
|
109
|
+
const sel = selection ? toEngineSelection(selection) : undefined;
|
|
110
|
+
engineRef.current?.focus(sel);
|
|
111
|
+
},
|
|
112
|
+
blur: () => {
|
|
113
|
+
engineRef.current?.blur();
|
|
114
|
+
},
|
|
115
|
+
hasFocus: () => {
|
|
116
|
+
return engineRef.current?.hasFocus() ?? false;
|
|
117
|
+
},
|
|
118
|
+
selectAll: () => {
|
|
119
|
+
engineRef.current?.selectAll();
|
|
120
|
+
},
|
|
121
|
+
executeCommand: (command, options) => {
|
|
122
|
+
if (!engineRef.current) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return engineRef.current.executeCommand(command, options);
|
|
126
|
+
},
|
|
127
|
+
applyUpdate: (update) => {
|
|
128
|
+
if (!engineRef.current) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const engine = engineRef.current;
|
|
132
|
+
const selection = update.selection
|
|
133
|
+
? toEngineSelection(update.selection)
|
|
134
|
+
: undefined;
|
|
135
|
+
if (update.value !== undefined) {
|
|
136
|
+
engine.setValue({
|
|
137
|
+
value: update.value,
|
|
138
|
+
selection,
|
|
139
|
+
});
|
|
140
|
+
if (update.focus) {
|
|
141
|
+
engine.focus(selection);
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (update.selection) {
|
|
146
|
+
if (!selection) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
engine.setSelection(selection);
|
|
150
|
+
if (update.focus) {
|
|
151
|
+
engine.focus(selection);
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (update.focus) {
|
|
156
|
+
engine.focus();
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
getValue: () => engineRef.current?.getValue() ?? props.value,
|
|
160
|
+
getSelection: () => {
|
|
161
|
+
const selection = engineRef.current?.getSelection();
|
|
162
|
+
if (!selection) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
return { start: selection.start, end: selection.end };
|
|
166
|
+
},
|
|
167
|
+
getCursorLength: () => engineRef.current?.getCursorLength() ?? 0,
|
|
168
|
+
insertText: (text) => {
|
|
169
|
+
engineRef.current?.insertText(text);
|
|
170
|
+
},
|
|
171
|
+
replaceText: (oldText, newText) => {
|
|
172
|
+
engineRef.current?.replaceText(oldText, newText);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}, [props.value]);
|
|
176
|
+
const containerStyle = props.style
|
|
177
|
+
? { ...props.style }
|
|
178
|
+
: {};
|
|
179
|
+
if (!containerStyle.position) {
|
|
180
|
+
containerStyle.position = "relative";
|
|
181
|
+
}
|
|
182
|
+
const containerClassName = props.className
|
|
183
|
+
? `cake ${props.className}`
|
|
184
|
+
: "cake";
|
|
185
|
+
const overlayContext = containerRef.current && contentRoot
|
|
186
|
+
? {
|
|
187
|
+
container: containerRef.current,
|
|
188
|
+
contentRoot,
|
|
189
|
+
toOverlayRect: (rect) => {
|
|
190
|
+
const containerRect = containerRef.current?.getBoundingClientRect();
|
|
191
|
+
if (!containerRect) {
|
|
192
|
+
return {
|
|
193
|
+
top: rect.top,
|
|
194
|
+
left: rect.left,
|
|
195
|
+
width: rect.width,
|
|
196
|
+
height: rect.height,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
top: rect.top - containerRect.top,
|
|
201
|
+
left: rect.left - containerRect.left,
|
|
202
|
+
width: rect.width,
|
|
203
|
+
height: rect.height,
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
insertText: (text) => {
|
|
207
|
+
engineRef.current?.insertText(text);
|
|
208
|
+
},
|
|
209
|
+
replaceText: (oldText, newText) => {
|
|
210
|
+
engineRef.current?.replaceText(oldText, newText);
|
|
211
|
+
},
|
|
212
|
+
getSelection: () => {
|
|
213
|
+
const selection = engineRef.current?.getSelection();
|
|
214
|
+
if (!selection) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
const focus = selection.start === selection.end
|
|
218
|
+
? selection.start
|
|
219
|
+
: Math.max(selection.start, selection.end);
|
|
220
|
+
return { start: focus, end: focus };
|
|
221
|
+
},
|
|
222
|
+
executeCommand: (command) => {
|
|
223
|
+
return engineRef.current?.executeCommand(command) ?? false;
|
|
224
|
+
},
|
|
225
|
+
}
|
|
226
|
+
: null;
|
|
227
|
+
return (_jsxs("div", { style: { position: "relative", height: "100%" }, children: [_jsx("div", { ref: containerRef, className: containerClassName, style: containerStyle, "data-placeholder": props.placeholder, onBlur: (event) => {
|
|
228
|
+
props.onBlur?.(event.nativeEvent);
|
|
229
|
+
} }), overlayContext && hasOverlayExtensions
|
|
230
|
+
? allExtensionsRef.current.map((extension) => extension.renderOverlay ? (_jsx(Fragment, { children: extension.renderOverlay(overlayContext) }, extension.name)) : null)
|
|
231
|
+
: null] }));
|
|
232
|
+
});
|
|
233
|
+
CakeEditor.displayName = "CakeEditor";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../../src/cake/shared/platform.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,eAAe,6BAAmB,CAAC;AAIhD,wBAAgB,aAAa,IAAI,OAAO,CAEvC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function detectPlatform() {
|
|
2
|
+
if (typeof navigator === "undefined") {
|
|
3
|
+
return "linux";
|
|
4
|
+
}
|
|
5
|
+
const platform = navigator.platform;
|
|
6
|
+
if (/Mac|iPhone|iPad|iPod/.test(platform)) {
|
|
7
|
+
return "mac";
|
|
8
|
+
}
|
|
9
|
+
if (/Win/.test(platform)) {
|
|
10
|
+
return "windows";
|
|
11
|
+
}
|
|
12
|
+
return "linux";
|
|
13
|
+
}
|
|
14
|
+
export const currentPlatform = detectPlatform();
|
|
15
|
+
// Do not compute platform at module-load time for behavior decisions that depend
|
|
16
|
+
// on the current browser environment (tests may override `navigator.platform`).
|
|
17
|
+
export function isMacPlatform() {
|
|
18
|
+
return detectPlatform() === "mac";
|
|
19
|
+
}
|
|
@@ -10,3 +10,4 @@ export declare function graphemeSegments(text: string): GraphemeSegment[];
|
|
|
10
10
|
export declare function wordSegments(text: string, locale?: string): WordSegment[];
|
|
11
11
|
export declare function graphemeClusterLengthBefore(text: string, offset: number): number;
|
|
12
12
|
export declare function graphemeClusterLengthAfter(text: string, offset: number): number;
|
|
13
|
+
//# sourceMappingURL=segmenter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segmenter.d.ts","sourceRoot":"","sources":["../../../src/cake/shared/segmenter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG;IAC1C,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAMF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAEhE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,WAAW,EAAE,CAMvE;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,MAAM,CAqBR;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,MAAM,CAmBR"}
|