camox 0.31.5 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/components/lexical/InlineLexicalEditor.js +79 -11
- package/dist/core/components/lexical/SelectionBroadcaster.js +106 -20
- package/dist/core/components/lexical/SidebarLexicalEditor.js +442 -8
- package/dist/core/components/lexical/TextLinkPopover.js +327 -0
- package/dist/core/components/lexical/editorConfig.js +11 -5
- package/dist/core/createApp.d.ts +9 -0
- package/dist/core/createBlock.d.ts +6 -1
- package/dist/core/createBlock.js +31 -20
- package/dist/core/lib/lexicalReact.d.ts +26 -0
- package/dist/core/lib/lexicalReact.js +50 -15
- package/dist/core/lib/lexicalState.js +34 -0
- package/dist/core/lib/textLinks.js +28 -0
- package/dist/features/preview/components/FieldToolbar.js +141 -71
- package/dist/features/vite/vite.js +2 -0
- package/dist/studio.css +1 -1
- package/package.json +5 -4
- package/skills/camox-block/SKILL.md +23 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useFrame } from "../../../features/preview/components/Frame.js";
|
|
2
|
+
import { isHttpTextLinkTarget } from "../../lib/textLinks.js";
|
|
2
3
|
import { lexicalStateToMarkdown } from "../../lib/lexicalState.js";
|
|
3
4
|
import { createEditorConfig, normalizeLexicalState } from "./editorConfig.js";
|
|
4
5
|
import { InlineContentEditable } from "./InlineContentEditable.js";
|
|
@@ -6,19 +7,21 @@ import { SelectionBroadcaster } from "./SelectionBroadcaster.js";
|
|
|
6
7
|
import { c } from "react/compiler-runtime";
|
|
7
8
|
import * as React from "react";
|
|
8
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { TOGGLE_LINK_COMMAND } from "@lexical/link";
|
|
9
11
|
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
10
12
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
11
13
|
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
|
|
14
|
+
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
12
15
|
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
|
|
13
16
|
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
14
|
-
import { COMMAND_PRIORITY_LOW, INSERT_LINE_BREAK_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND } from "lexical";
|
|
17
|
+
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_LOW, INSERT_LINE_BREAK_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, PASTE_COMMAND } from "lexical";
|
|
15
18
|
|
|
16
19
|
//#region src/core/components/lexical/InlineLexicalEditor.tsx
|
|
17
20
|
function ExternalStateSync(t0) {
|
|
18
21
|
const $ = c(8);
|
|
19
|
-
if ($[0] !== "
|
|
22
|
+
if ($[0] !== "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2") {
|
|
20
23
|
for (let $i = 0; $i < 8; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
21
|
-
$[0] = "
|
|
24
|
+
$[0] = "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2";
|
|
22
25
|
}
|
|
23
26
|
const { externalState } = t0;
|
|
24
27
|
const [editor] = useLexicalComposerContext();
|
|
@@ -75,9 +78,9 @@ function ExternalStateSync(t0) {
|
|
|
75
78
|
}
|
|
76
79
|
function EscapeHandler() {
|
|
77
80
|
const $ = c(4);
|
|
78
|
-
if ($[0] !== "
|
|
81
|
+
if ($[0] !== "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2") {
|
|
79
82
|
for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
80
|
-
$[0] = "
|
|
83
|
+
$[0] = "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2";
|
|
81
84
|
}
|
|
82
85
|
const [editor] = useLexicalComposerContext();
|
|
83
86
|
let t0;
|
|
@@ -100,9 +103,9 @@ function EscapeHandler() {
|
|
|
100
103
|
}
|
|
101
104
|
function EnterAsLineBreakHandler() {
|
|
102
105
|
const $ = c(4);
|
|
103
|
-
if ($[0] !== "
|
|
106
|
+
if ($[0] !== "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2") {
|
|
104
107
|
for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
105
|
-
$[0] = "
|
|
108
|
+
$[0] = "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2";
|
|
106
109
|
}
|
|
107
110
|
const [editor] = useLexicalComposerContext();
|
|
108
111
|
let t0;
|
|
@@ -124,11 +127,42 @@ function EnterAsLineBreakHandler() {
|
|
|
124
127
|
React.useEffect(t0, t1);
|
|
125
128
|
return null;
|
|
126
129
|
}
|
|
130
|
+
function PasteUrlAsLinkHandler() {
|
|
131
|
+
const $ = c(4);
|
|
132
|
+
if ($[0] !== "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2") {
|
|
133
|
+
for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
134
|
+
$[0] = "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2";
|
|
135
|
+
}
|
|
136
|
+
const [editor] = useLexicalComposerContext();
|
|
137
|
+
let t0;
|
|
138
|
+
let t1;
|
|
139
|
+
if ($[1] !== editor) {
|
|
140
|
+
t0 = () => editor.registerCommand(PASTE_COMMAND, (event) => {
|
|
141
|
+
const selection = $getSelection();
|
|
142
|
+
if (!$isRangeSelection(selection) || selection.isCollapsed()) return false;
|
|
143
|
+
if (!("clipboardData" in event) || !event.clipboardData) return false;
|
|
144
|
+
const url = event.clipboardData.getData("text/plain").trim();
|
|
145
|
+
if (!url || !isHttpTextLinkTarget(url)) return false;
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, url);
|
|
148
|
+
return true;
|
|
149
|
+
}, COMMAND_PRIORITY_LOW);
|
|
150
|
+
t1 = [editor];
|
|
151
|
+
$[1] = editor;
|
|
152
|
+
$[2] = t0;
|
|
153
|
+
$[3] = t1;
|
|
154
|
+
} else {
|
|
155
|
+
t0 = $[2];
|
|
156
|
+
t1 = $[3];
|
|
157
|
+
}
|
|
158
|
+
React.useEffect(t0, t1);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
127
161
|
function FocusBlurHandler(t0) {
|
|
128
162
|
const $ = c(6);
|
|
129
|
-
if ($[0] !== "
|
|
163
|
+
if ($[0] !== "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2") {
|
|
130
164
|
for (let $i = 0; $i < 6; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
131
|
-
$[0] = "
|
|
165
|
+
$[0] = "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2";
|
|
132
166
|
}
|
|
133
167
|
const { onFocus, onBlur } = t0;
|
|
134
168
|
const [editor] = useLexicalComposerContext();
|
|
@@ -161,6 +195,37 @@ function FocusBlurHandler(t0) {
|
|
|
161
195
|
React.useEffect(t1, t2);
|
|
162
196
|
return null;
|
|
163
197
|
}
|
|
198
|
+
function LinkStyleInjector() {
|
|
199
|
+
const $ = c(4);
|
|
200
|
+
if ($[0] !== "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2") {
|
|
201
|
+
for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
202
|
+
$[0] = "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2";
|
|
203
|
+
}
|
|
204
|
+
const [editor] = useLexicalComposerContext();
|
|
205
|
+
let t0;
|
|
206
|
+
let t1;
|
|
207
|
+
if ($[1] !== editor) {
|
|
208
|
+
t0 = () => editor.registerRootListener(_temp);
|
|
209
|
+
t1 = [editor];
|
|
210
|
+
$[1] = editor;
|
|
211
|
+
$[2] = t0;
|
|
212
|
+
$[3] = t1;
|
|
213
|
+
} else {
|
|
214
|
+
t0 = $[2];
|
|
215
|
+
t1 = $[3];
|
|
216
|
+
}
|
|
217
|
+
React.useEffect(t0, t1);
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
function _temp(root) {
|
|
221
|
+
if (!root) return;
|
|
222
|
+
const doc = root.ownerDocument;
|
|
223
|
+
if (doc.getElementById("camox-editable-text-link-styles")) return;
|
|
224
|
+
const style = doc.createElement("style");
|
|
225
|
+
style.id = "camox-editable-text-link-styles";
|
|
226
|
+
style.textContent = ".camox-text-link { text-decoration-line: underline; }";
|
|
227
|
+
doc.head.appendChild(style);
|
|
228
|
+
}
|
|
164
229
|
function InlineLexicalEditor({ initialState, externalState, onChange, onFocus, onBlur }) {
|
|
165
230
|
const { window: iframeWindow } = useFrame();
|
|
166
231
|
const timerRef = React.useRef(null);
|
|
@@ -203,22 +268,25 @@ function InlineLexicalEditor({ initialState, externalState, onChange, onFocus, o
|
|
|
203
268
|
ignoreSelectionChange: true
|
|
204
269
|
}),
|
|
205
270
|
/* @__PURE__ */ jsx(HistoryPlugin, {}),
|
|
271
|
+
/* @__PURE__ */ jsx(LinkPlugin, {}),
|
|
206
272
|
/* @__PURE__ */ jsx(ExternalStateSync, { externalState }),
|
|
207
273
|
/* @__PURE__ */ jsx(EscapeHandler, {}),
|
|
208
274
|
/* @__PURE__ */ jsx(EnterAsLineBreakHandler, {}),
|
|
275
|
+
/* @__PURE__ */ jsx(PasteUrlAsLinkHandler, {}),
|
|
209
276
|
/* @__PURE__ */ jsx(FocusBlurHandler, {
|
|
210
277
|
onFocus: handleFocus,
|
|
211
278
|
onBlur: handleBlur
|
|
212
279
|
}),
|
|
280
|
+
/* @__PURE__ */ jsx(LinkStyleInjector, {}),
|
|
213
281
|
iframeWindow && /* @__PURE__ */ jsx(SelectionBroadcaster, { targetWindow: iframeWindow })
|
|
214
282
|
]
|
|
215
283
|
});
|
|
216
284
|
}
|
|
217
285
|
function LexicalErrorBoundary(t0) {
|
|
218
286
|
const $ = c(3);
|
|
219
|
-
if ($[0] !== "
|
|
287
|
+
if ($[0] !== "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2") {
|
|
220
288
|
for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
221
|
-
$[0] = "
|
|
289
|
+
$[0] = "c4ca5d751d9d53a7ad565939bb5b4c4c82ea51c5bc23aeca481e23d8515243a2";
|
|
222
290
|
}
|
|
223
291
|
const { children } = t0;
|
|
224
292
|
let t1;
|
|
@@ -2,18 +2,33 @@ import { isOverlayMessage, postOverlayMessage } from "../../../features/preview/
|
|
|
2
2
|
import { TEXT_MODIFIERS } from "../../lib/modifiers.js";
|
|
3
3
|
import { c } from "react/compiler-runtime";
|
|
4
4
|
import * as React from "react";
|
|
5
|
+
import { $createLinkNode, TOGGLE_LINK_COMMAND } from "@lexical/link";
|
|
5
6
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
6
|
-
import { $getSelection, $isRangeSelection, FORMAT_TEXT_COMMAND } from "lexical";
|
|
7
|
+
import { $createTextNode, $getSelection, $isRangeSelection, $setSelection, FORMAT_TEXT_COMMAND } from "lexical";
|
|
7
8
|
|
|
8
9
|
//#region src/core/components/lexical/SelectionBroadcaster.tsx
|
|
10
|
+
function getLinkTargetFromSelection() {
|
|
11
|
+
const selection = $getSelection();
|
|
12
|
+
if (!$isRangeSelection(selection)) return null;
|
|
13
|
+
let node = selection.anchor.getNode();
|
|
14
|
+
while (node) {
|
|
15
|
+
if (node.getType?.() === "link") {
|
|
16
|
+
const url = node.getURL?.();
|
|
17
|
+
return typeof url === "string" ? url : null;
|
|
18
|
+
}
|
|
19
|
+
node = node.getParent?.();
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
9
23
|
function SelectionBroadcaster(t0) {
|
|
10
|
-
const $ = c(
|
|
11
|
-
if ($[0] !== "
|
|
12
|
-
for (let $i = 0; $i <
|
|
13
|
-
$[0] = "
|
|
24
|
+
const $ = c(18);
|
|
25
|
+
if ($[0] !== "e89fc1c958f4e83679744b18d31c960a1ed541e1ba675eee3f5a0ecee772b5f2") {
|
|
26
|
+
for (let $i = 0; $i < 18; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
27
|
+
$[0] = "e89fc1c958f4e83679744b18d31c960a1ed541e1ba675eee3f5a0ecee772b5f2";
|
|
14
28
|
}
|
|
15
29
|
const { targetWindow } = t0;
|
|
16
30
|
const [editor] = useLexicalComposerContext();
|
|
31
|
+
const lastTextSelectionRef = React.useRef(null);
|
|
17
32
|
let t1;
|
|
18
33
|
if ($[1] !== editor || $[2] !== targetWindow) {
|
|
19
34
|
t1 = () => {
|
|
@@ -22,23 +37,30 @@ function SelectionBroadcaster(t0) {
|
|
|
22
37
|
postOverlayMessage({
|
|
23
38
|
type: "CAMOX_TEXT_SELECTION_STATE",
|
|
24
39
|
hasSelection: false,
|
|
25
|
-
activeFormats: 0
|
|
40
|
+
activeFormats: 0,
|
|
41
|
+
linkTarget: null,
|
|
42
|
+
selectedText: ""
|
|
26
43
|
});
|
|
27
44
|
return;
|
|
28
45
|
}
|
|
29
46
|
let format = 0;
|
|
47
|
+
let linkTarget = null;
|
|
30
48
|
editor.getEditorState().read(() => {
|
|
31
49
|
const selection = $getSelection();
|
|
32
50
|
if (!$isRangeSelection(selection)) return;
|
|
51
|
+
lastTextSelectionRef.current = selection.clone();
|
|
33
52
|
for (const modifier of Object.values(TEXT_MODIFIERS)) {
|
|
34
53
|
const key = modifier === TEXT_MODIFIERS.bold ? "bold" : "italic";
|
|
35
54
|
if (selection.hasFormat(key)) format = format | modifier.formatFlag;
|
|
36
55
|
}
|
|
56
|
+
linkTarget = getLinkTargetFromSelection();
|
|
37
57
|
});
|
|
38
58
|
postOverlayMessage({
|
|
39
59
|
type: "CAMOX_TEXT_SELECTION_STATE",
|
|
40
60
|
hasSelection: true,
|
|
41
|
-
activeFormats: format
|
|
61
|
+
activeFormats: format,
|
|
62
|
+
linkTarget,
|
|
63
|
+
selectedText: nativeSelection?.toString() ?? ""
|
|
42
64
|
});
|
|
43
65
|
};
|
|
44
66
|
$[1] = editor;
|
|
@@ -68,21 +90,33 @@ function SelectionBroadcaster(t0) {
|
|
|
68
90
|
let t4;
|
|
69
91
|
let t5;
|
|
70
92
|
if ($[8] !== broadcastSelection || $[9] !== editor || $[10] !== targetWindow) {
|
|
71
|
-
t4 = () => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
if (!
|
|
78
|
-
|
|
93
|
+
t4 = () => editor.registerRootListener((root) => {
|
|
94
|
+
if (!root) return;
|
|
95
|
+
const handleLinkClick = (event) => {
|
|
96
|
+
const target = event.target;
|
|
97
|
+
if (!(target instanceof HTMLElement)) return;
|
|
98
|
+
const anchor = target.closest("a");
|
|
99
|
+
if (!anchor || !root.contains(anchor)) return;
|
|
100
|
+
const href = anchor.getAttribute("href");
|
|
101
|
+
if (!href) return;
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
event.stopPropagation();
|
|
104
|
+
const range = targetWindow.document.createRange();
|
|
105
|
+
range.selectNodeContents(anchor);
|
|
106
|
+
const selection_0 = targetWindow.getSelection();
|
|
107
|
+
selection_0?.removeAllRanges();
|
|
108
|
+
selection_0?.addRange(range);
|
|
79
109
|
root.focus();
|
|
80
|
-
|
|
81
|
-
|
|
110
|
+
broadcastSelection();
|
|
111
|
+
postOverlayMessage({
|
|
112
|
+
type: "CAMOX_OPEN_TEXT_LINK_POPOVER",
|
|
113
|
+
target: href,
|
|
114
|
+
text: selection_0?.toString() ?? ""
|
|
115
|
+
});
|
|
82
116
|
};
|
|
83
|
-
|
|
84
|
-
return () =>
|
|
85
|
-
};
|
|
117
|
+
root.addEventListener("click", handleLinkClick);
|
|
118
|
+
return () => root.removeEventListener("click", handleLinkClick);
|
|
119
|
+
});
|
|
86
120
|
t5 = [
|
|
87
121
|
editor,
|
|
88
122
|
targetWindow,
|
|
@@ -98,6 +132,58 @@ function SelectionBroadcaster(t0) {
|
|
|
98
132
|
t5 = $[12];
|
|
99
133
|
}
|
|
100
134
|
React.useEffect(t4, t5);
|
|
135
|
+
let t6;
|
|
136
|
+
let t7;
|
|
137
|
+
if ($[13] !== broadcastSelection || $[14] !== editor || $[15] !== targetWindow) {
|
|
138
|
+
t6 = () => {
|
|
139
|
+
const handleMessage = (event_0) => {
|
|
140
|
+
const data = event_0.data;
|
|
141
|
+
if (!isOverlayMessage(data) || data.type !== "CAMOX_FORMAT_TEXT" && data.type !== "CAMOX_TOGGLE_TEXT_LINK") return;
|
|
142
|
+
const root_0 = editor.getRootElement();
|
|
143
|
+
const nativeSelection_0 = targetWindow.getSelection();
|
|
144
|
+
if (!root_0 || !nativeSelection_0 || nativeSelection_0.rangeCount === 0) return;
|
|
145
|
+
if (!root_0.contains(nativeSelection_0.anchorNode)) return;
|
|
146
|
+
root_0.focus();
|
|
147
|
+
editor.update(() => {
|
|
148
|
+
const selection_1 = $getSelection();
|
|
149
|
+
if ($isRangeSelection(selection_1) && !selection_1.isCollapsed()) {
|
|
150
|
+
lastTextSelectionRef.current = selection_1.clone();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (lastTextSelectionRef.current) $setSelection(lastTextSelectionRef.current.clone());
|
|
154
|
+
});
|
|
155
|
+
if (data.type === "CAMOX_FORMAT_TEXT") editor.dispatchCommand(FORMAT_TEXT_COMMAND, data.formatKey);
|
|
156
|
+
else if (data.target === null) editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
|
|
157
|
+
else if (typeof data.text === "string") {
|
|
158
|
+
const target_0 = data.target;
|
|
159
|
+
editor.update(() => {
|
|
160
|
+
const selection_2 = $getSelection();
|
|
161
|
+
if (!$isRangeSelection(selection_2)) return;
|
|
162
|
+
const linkNode = $createLinkNode(target_0);
|
|
163
|
+
linkNode.append($createTextNode(data.text));
|
|
164
|
+
selection_2.insertNodes([linkNode]);
|
|
165
|
+
});
|
|
166
|
+
} else editor.dispatchCommand(TOGGLE_LINK_COMMAND, data.target);
|
|
167
|
+
setTimeout(broadcastSelection, 10);
|
|
168
|
+
};
|
|
169
|
+
targetWindow.addEventListener("message", handleMessage);
|
|
170
|
+
return () => targetWindow.removeEventListener("message", handleMessage);
|
|
171
|
+
};
|
|
172
|
+
t7 = [
|
|
173
|
+
editor,
|
|
174
|
+
targetWindow,
|
|
175
|
+
broadcastSelection
|
|
176
|
+
];
|
|
177
|
+
$[13] = broadcastSelection;
|
|
178
|
+
$[14] = editor;
|
|
179
|
+
$[15] = targetWindow;
|
|
180
|
+
$[16] = t6;
|
|
181
|
+
$[17] = t7;
|
|
182
|
+
} else {
|
|
183
|
+
t6 = $[16];
|
|
184
|
+
t7 = $[17];
|
|
185
|
+
}
|
|
186
|
+
React.useEffect(t6, t7);
|
|
101
187
|
return null;
|
|
102
188
|
}
|
|
103
189
|
|