@replohq/sandbox-runtime 1.9.0 → 1.10.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/_vendor/replo-utils/lib/fonts.mjs +18 -6
- package/_vendor/schemas/generated/selectMode.d.ts +14 -0
- package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +12 -2
- package/_vendor/schemas/selectMode.d.ts +24 -0
- package/_vendor/schemas/selectMode.mjs +1 -1
- package/_vendor/schemas/selectModeIframeRpc.d.ts +49 -0
- package/_vendor/schemas/selectModeIframeRpc.mjs +18 -2
- package/_vendor/schemas/selectModeImage.mjs +6 -2
- package/buildMetadata.js +3 -3
- package/{chunk-XWNBKE63.mjs → chunk-PJBGUXBG.mjs} +6 -1
- package/design-library-preview/DesignLibraryPreview.js +18 -6
- package/package.json +4 -4
- package/select-mode/EditorSelection.js +21 -4
- package/select-mode/SelectionFrames.js +56 -23
- package/select-mode/descriptor/elementDescriptor.d.ts +2 -1
- package/select-mode/descriptor/elementDescriptor.js +22 -14
- package/select-mode/hooks/useOptimisticOverrides.js +18 -6
- package/select-mode/hooks/useParentMessaging.d.ts +7 -1
- package/select-mode/hooks/useParentMessaging.js +6 -0
- package/select-mode/hooks/useSelectionHover.js +38 -15
- package/select-mode/hooks/useSelectionInteractions.js +9 -37
- package/select-mode/hooks/useSelectionScrollSync.js +5 -1
- package/select-mode/iframeRpcChannel.d.ts +10 -0
- package/select-mode/iframeRpcChannel.js +2 -0
- package/select-mode/imageOverridePreview.js +14 -5
- package/select-mode/imageSources.js +2 -1
- package/select-mode/inlineEditFeedback.js +9 -3
- package/select-mode/interactions/sectionGeometry.d.ts +3 -0
- package/select-mode/interactions/sectionGeometry.js +200 -0
- package/select-mode/selectModeStore.d.ts +36 -8
- package/select-mode/selectModeStore.js +141 -21
- package/select-mode/selectionFrame.d.ts +3 -1
- package/select-mode/selectionFrame.js +4 -0
|
@@ -30,12 +30,20 @@ function getSelectableDataFromElement(element) {
|
|
|
30
30
|
rect: getElementBoundingRect(selectableElement)
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
function
|
|
33
|
+
function getRenderedText(element) {
|
|
34
|
+
if (element instanceof HTMLElement) {
|
|
35
|
+
return (element.innerText ?? element.textContent)?.trim() ?? null;
|
|
36
|
+
}
|
|
37
|
+
return element.textContent?.trim() ?? null;
|
|
38
|
+
}
|
|
39
|
+
function identifyElement({
|
|
40
|
+
element,
|
|
41
|
+
trimmedText
|
|
42
|
+
}) {
|
|
34
43
|
const tagName = element.tagName.toLowerCase();
|
|
35
44
|
if (tagName === "button" || element.getAttribute("role") === "button" || tagName === "input") {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return `${tagName}: "${trimmedText2.slice(0, 60)}"`;
|
|
45
|
+
if (trimmedText) {
|
|
46
|
+
return `${tagName}: "${trimmedText.slice(0, 60)}"`;
|
|
39
47
|
}
|
|
40
48
|
const ariaLabel = element.getAttribute("aria-label");
|
|
41
49
|
if (ariaLabel) {
|
|
@@ -49,9 +57,8 @@ function identifyElement(element) {
|
|
|
49
57
|
return tagName;
|
|
50
58
|
}
|
|
51
59
|
if (tagName === "a") {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return `link: "${trimmedText2.slice(0, 60)}"`;
|
|
60
|
+
if (trimmedText) {
|
|
61
|
+
return `link: "${trimmedText.slice(0, 60)}"`;
|
|
55
62
|
}
|
|
56
63
|
const href = element.getAttribute("href");
|
|
57
64
|
if (href) {
|
|
@@ -72,8 +79,7 @@ function identifyElement(element) {
|
|
|
72
79
|
return "image";
|
|
73
80
|
}
|
|
74
81
|
if (/^h[1-6]$/.test(tagName)) {
|
|
75
|
-
|
|
76
|
-
return trimmedText2 ? `heading(${tagName}): "${trimmedText2.slice(0, 60)}"` : tagName;
|
|
82
|
+
return trimmedText ? `heading(${tagName}): "${trimmedText.slice(0, 60)}"` : tagName;
|
|
77
83
|
}
|
|
78
84
|
if (["div", "main", "section", "article", "header", "footer", "nav"].includes(
|
|
79
85
|
tagName
|
|
@@ -83,7 +89,6 @@ function identifyElement(element) {
|
|
|
83
89
|
return role2;
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
|
-
const trimmedText = element.textContent?.trim();
|
|
87
92
|
if (trimmedText && trimmedText.length < 120) {
|
|
88
93
|
const role2 = element.getAttribute("role");
|
|
89
94
|
const label = role2 ?? tagName;
|
|
@@ -168,7 +173,8 @@ function getTextMetrics(element) {
|
|
|
168
173
|
function buildElementDescriptor({
|
|
169
174
|
element,
|
|
170
175
|
clickPosition,
|
|
171
|
-
siblingSelectors = []
|
|
176
|
+
siblingSelectors = [],
|
|
177
|
+
section
|
|
172
178
|
}) {
|
|
173
179
|
const selectableData = getSelectableDataFromElement(element);
|
|
174
180
|
if (selectableData) {
|
|
@@ -177,12 +183,13 @@ function buildElementDescriptor({
|
|
|
177
183
|
const textMetrics = getTextMetrics(element);
|
|
178
184
|
const fiberChain = element instanceof HTMLElement ? getFiberChain(element) : [];
|
|
179
185
|
const sourceLocation = fiberChain[0]?.sourceLocation;
|
|
186
|
+
const trimmedText = getRenderedText(element);
|
|
180
187
|
return {
|
|
181
188
|
kind: "react-element",
|
|
182
189
|
selector: buildSelector(element),
|
|
183
190
|
tagName: element.tagName.toLowerCase(),
|
|
184
|
-
elementType: identifyElement(element),
|
|
185
|
-
textContent:
|
|
191
|
+
elementType: identifyElement({ element, trimmedText }),
|
|
192
|
+
textContent: trimmedText?.slice(0, 200) ?? null,
|
|
186
193
|
rect: getElementBoundingRect(element),
|
|
187
194
|
textMetrics,
|
|
188
195
|
outerHTML: element.outerHTML.slice(0, 4e3),
|
|
@@ -192,7 +199,8 @@ function buildElementDescriptor({
|
|
|
192
199
|
clickPosition,
|
|
193
200
|
sourceLocation,
|
|
194
201
|
fiberChain,
|
|
195
|
-
siblingSelectors
|
|
202
|
+
siblingSelectors,
|
|
203
|
+
...section ? { section: { selector: buildSelector(section) } } : {}
|
|
196
204
|
};
|
|
197
205
|
}
|
|
198
206
|
export {
|
|
@@ -91,7 +91,9 @@ function applyPayload({
|
|
|
91
91
|
payload,
|
|
92
92
|
token
|
|
93
93
|
}) {
|
|
94
|
-
if (payload.kind === "image")
|
|
94
|
+
if (payload.kind === "image") {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
95
97
|
if (payload.kind === "css") {
|
|
96
98
|
addToken(element, token);
|
|
97
99
|
return;
|
|
@@ -201,7 +203,9 @@ function reapplyOverride({
|
|
|
201
203
|
override,
|
|
202
204
|
skipElement
|
|
203
205
|
}) {
|
|
204
|
-
if (override.payload.kind === "image")
|
|
206
|
+
if (override.payload.kind === "image") {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
205
209
|
for (const target of override.targets) {
|
|
206
210
|
const element = resolveTarget(target);
|
|
207
211
|
if (!element || skipElement && element.contains(skipElement)) {
|
|
@@ -220,10 +224,14 @@ function reapplyOverride({
|
|
|
220
224
|
function syncImagePreviews() {
|
|
221
225
|
const configurations = /* @__PURE__ */ new Map();
|
|
222
226
|
for (const override of getOverrideList()) {
|
|
223
|
-
if (override.payload.kind !== "image")
|
|
227
|
+
if (override.payload.kind !== "image") {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
224
230
|
for (const target of override.targets) {
|
|
225
231
|
const element = resolveTarget(target);
|
|
226
|
-
if (!(element instanceof HTMLImageElement))
|
|
232
|
+
if (!(element instanceof HTMLImageElement)) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
227
235
|
const previous = configurations.get(element);
|
|
228
236
|
configurations.set(element, {
|
|
229
237
|
image: override.payload.image,
|
|
@@ -232,7 +240,9 @@ function syncImagePreviews() {
|
|
|
232
240
|
}
|
|
233
241
|
}
|
|
234
242
|
for (const [element, preview] of imagePreviews) {
|
|
235
|
-
if (configurations.has(element))
|
|
243
|
+
if (configurations.has(element)) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
236
246
|
preview.dispose();
|
|
237
247
|
imagePreviews.delete(element);
|
|
238
248
|
}
|
|
@@ -253,7 +263,9 @@ function syncImagePreviews() {
|
|
|
253
263
|
}
|
|
254
264
|
setOverrideList(
|
|
255
265
|
getOverrideList().filter((entry) => {
|
|
256
|
-
if (entry.payload.kind !== "image")
|
|
266
|
+
if (entry.payload.kind !== "image") {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
257
269
|
entry.targets = entry.targets.filter((target) => {
|
|
258
270
|
const element = resolveTarget(target);
|
|
259
271
|
return !element || !acknowledged.has(element);
|
|
@@ -16,7 +16,7 @@ import type { DisplayMode, SelectModeFormatCommand, SelectModeOptimisticUpdatePa
|
|
|
16
16
|
* the initial `setDisplayMode` — without this handshake the parent would
|
|
17
17
|
* race the iframe's mount and the first message could be lost.
|
|
18
18
|
*/
|
|
19
|
-
export declare function useParentMessaging({ applyOptimisticUpdate, markCommitted, resolveSessionOverrides, onEnterEditMode, onExitEditMode, onFormatCommand, revertOverride, setDisplayMode, setSelectionType, }: {
|
|
19
|
+
export declare function useParentMessaging({ applyOptimisticUpdate, markCommitted, resolveSessionOverrides, onExpandToSection, onSetSectionPreview, onEnterEditMode, onExitEditMode, onFormatCommand, revertOverride, setDisplayMode, setSelectionType, }: {
|
|
20
20
|
applyOptimisticUpdate?: (input: {
|
|
21
21
|
editId: string;
|
|
22
22
|
payload: SelectModeOptimisticUpdatePayload;
|
|
@@ -25,6 +25,12 @@ export declare function useParentMessaging({ applyOptimisticUpdate, markCommitte
|
|
|
25
25
|
}) => void;
|
|
26
26
|
markCommitted?: (editId: string, sessionId: string) => void;
|
|
27
27
|
resolveSessionOverrides?: (sessionId: string, outcome: "persisted" | "failed") => void;
|
|
28
|
+
onExpandToSection?: (input: {
|
|
29
|
+
targetSelector: string;
|
|
30
|
+
}) => void;
|
|
31
|
+
onSetSectionPreview?: (input: {
|
|
32
|
+
targetSelector: string | null;
|
|
33
|
+
}) => void;
|
|
28
34
|
onEnterEditMode?: () => void;
|
|
29
35
|
onExitEditMode?: () => void;
|
|
30
36
|
onFormatCommand?: (command: SelectModeFormatCommand) => void;
|
|
@@ -27,6 +27,8 @@ function useParentMessaging({
|
|
|
27
27
|
applyOptimisticUpdate,
|
|
28
28
|
markCommitted,
|
|
29
29
|
resolveSessionOverrides,
|
|
30
|
+
onExpandToSection,
|
|
31
|
+
onSetSectionPreview,
|
|
30
32
|
onEnterEditMode,
|
|
31
33
|
onExitEditMode,
|
|
32
34
|
onFormatCommand,
|
|
@@ -37,6 +39,8 @@ function useParentMessaging({
|
|
|
37
39
|
useIframeRpcChannel(useMemo(() => getSelectModeIframeRpcChannel(), []));
|
|
38
40
|
useEffect(() => {
|
|
39
41
|
setSelectModeParentHandlers({
|
|
42
|
+
expandToSection: (input) => onExpandToSection?.(input),
|
|
43
|
+
setSectionPreview: (input) => onSetSectionPreview?.(input),
|
|
40
44
|
setDisplayMode: ({ displayMode }) => {
|
|
41
45
|
setDisplayMode(displayMode);
|
|
42
46
|
},
|
|
@@ -83,6 +87,8 @@ function useParentMessaging({
|
|
|
83
87
|
applyOptimisticUpdate,
|
|
84
88
|
markCommitted,
|
|
85
89
|
resolveSessionOverrides,
|
|
90
|
+
onExpandToSection,
|
|
91
|
+
onSetSectionPreview,
|
|
86
92
|
onEnterEditMode,
|
|
87
93
|
onExitEditMode,
|
|
88
94
|
onFormatCommand,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
import { getNearestSelectableElement } from "../descriptor/elementDescriptor";
|
|
3
3
|
import { getWebsiteBuilderRpc } from "../iframeRpcChannel";
|
|
4
|
+
import {
|
|
5
|
+
CONTAINER_TAGS,
|
|
6
|
+
findContainingSection
|
|
7
|
+
} from "../interactions/sectionGeometry";
|
|
4
8
|
import { getElementBoundingRect } from "../interactions/selectionGeometry";
|
|
5
9
|
import { useDisplayMode, useSelectModeStore } from "../selectModeStore";
|
|
6
10
|
function useSelectionHover() {
|
|
@@ -11,16 +15,30 @@ function useSelectionHover() {
|
|
|
11
15
|
return;
|
|
12
16
|
}
|
|
13
17
|
const postHoveredElement = (element) => {
|
|
14
|
-
const {
|
|
18
|
+
const { lastPostedHover, actions } = store.getState();
|
|
19
|
+
const lastPostedHoverRect = lastPostedHover?.rect;
|
|
15
20
|
const rect = element ? getElementBoundingRect(element) : null;
|
|
16
|
-
const isUnchanged = lastPostedHoverRect !== void 0 && (rect === lastPostedHoverRect || rect !== null && lastPostedHoverRect !== null && rect.x === lastPostedHoverRect.x && rect.y === lastPostedHoverRect.y && rect.width === lastPostedHoverRect.width && rect.height === lastPostedHoverRect.height);
|
|
21
|
+
const isUnchanged = lastPostedHover?.element === element && lastPostedHoverRect !== void 0 && (rect === lastPostedHoverRect || rect !== null && lastPostedHoverRect !== null && rect.x === lastPostedHoverRect.x && rect.y === lastPostedHoverRect.y && rect.width === lastPostedHoverRect.width && rect.height === lastPostedHoverRect.height);
|
|
17
22
|
if (isUnchanged) {
|
|
18
23
|
return;
|
|
19
24
|
}
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
const hoverRect = rect && element ? {
|
|
26
|
+
...rect,
|
|
27
|
+
isSection: element === store.getState().sectionPreviewElement || CONTAINER_TAGS.has(element.tagName) && findContainingSection(element) === element
|
|
28
|
+
} : null;
|
|
29
|
+
actions.setLastPostedHover({ element, rect: hoverRect });
|
|
30
|
+
getWebsiteBuilderRpc()?.hoverElement({ rect: hoverRect });
|
|
22
31
|
};
|
|
23
32
|
const syncCurrentHover = (pointerClientPosition = store.getState().lastPointerClientPosition) => {
|
|
33
|
+
const previewSection = store.getState().sectionPreviewElement;
|
|
34
|
+
if (previewSection) {
|
|
35
|
+
if (previewSection.isConnected) {
|
|
36
|
+
postHoveredElement(previewSection);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
store.getState().actions.setSectionPreview({ targetSelector: null });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
24
42
|
let hoveredElement = null;
|
|
25
43
|
if (pointerClientPosition) {
|
|
26
44
|
const isPointerWithinViewport = pointerClientPosition.x >= 0 && pointerClientPosition.y >= 0 && pointerClientPosition.x <= window.innerWidth && pointerClientPosition.y <= window.innerHeight;
|
|
@@ -59,14 +77,6 @@ function useSelectionHover() {
|
|
|
59
77
|
}
|
|
60
78
|
syncCurrentHover(position);
|
|
61
79
|
};
|
|
62
|
-
const handlePointerOver = (event) => {
|
|
63
|
-
const position = { x: event.clientX, y: event.clientY };
|
|
64
|
-
store.getState().actions.setLastPointerClientPosition(position);
|
|
65
|
-
if (store.getState().interactionSession.type === "drag") {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
syncCurrentHover(position);
|
|
69
|
-
};
|
|
70
80
|
const handlePointerOut = (event) => {
|
|
71
81
|
if (store.getState().interactionSession.type === "drag") {
|
|
72
82
|
return;
|
|
@@ -81,11 +91,20 @@ function useSelectionHover() {
|
|
|
81
91
|
cancelAnimationFrame(hoverSyncAnimationFrameId);
|
|
82
92
|
actions.setHoverSyncAnimationFrameId(null);
|
|
83
93
|
}
|
|
84
|
-
|
|
94
|
+
if (store.getState().sectionPreviewElement) {
|
|
95
|
+
syncCurrentHover(null);
|
|
96
|
+
} else {
|
|
97
|
+
postHoveredElement(null);
|
|
98
|
+
}
|
|
85
99
|
};
|
|
100
|
+
const stopPreviewObservation = store.subscribe((state, previous) => {
|
|
101
|
+
if (state.sectionPreviewElement !== previous.sectionPreviewElement) {
|
|
102
|
+
syncCurrentHover();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
86
105
|
syncCurrentHover();
|
|
87
106
|
document.addEventListener("pointermove", handlePointerMove, true);
|
|
88
|
-
document.addEventListener("pointerover",
|
|
107
|
+
document.addEventListener("pointerover", handlePointerMove, true);
|
|
89
108
|
document.addEventListener("pointerout", handlePointerOut, true);
|
|
90
109
|
document.addEventListener("scroll", scheduleHoverSync, true);
|
|
91
110
|
document.addEventListener("wheel", scheduleHoverSync, {
|
|
@@ -94,13 +113,17 @@ function useSelectionHover() {
|
|
|
94
113
|
});
|
|
95
114
|
window.addEventListener("resize", scheduleHoverSync);
|
|
96
115
|
return () => {
|
|
116
|
+
stopPreviewObservation();
|
|
117
|
+
store.getState().actions.setSectionPreview({ targetSelector: null });
|
|
118
|
+
postHoveredElement(null);
|
|
119
|
+
store.getState().actions.setLastPostedHover(void 0);
|
|
97
120
|
const { hoverSyncAnimationFrameId } = store.getState();
|
|
98
121
|
if (hoverSyncAnimationFrameId !== null) {
|
|
99
122
|
cancelAnimationFrame(hoverSyncAnimationFrameId);
|
|
100
123
|
store.getState().actions.setHoverSyncAnimationFrameId(null);
|
|
101
124
|
}
|
|
102
125
|
document.removeEventListener("pointermove", handlePointerMove, true);
|
|
103
|
-
document.removeEventListener("pointerover",
|
|
126
|
+
document.removeEventListener("pointerover", handlePointerMove, true);
|
|
104
127
|
document.removeEventListener("pointerout", handlePointerOut, true);
|
|
105
128
|
document.removeEventListener("scroll", scheduleHoverSync, true);
|
|
106
129
|
document.removeEventListener("wheel", scheduleHoverSync, {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
import {
|
|
3
3
|
buildElementDescriptor,
|
|
4
|
-
buildSelector,
|
|
5
4
|
getNearestSelectableElement
|
|
6
5
|
} from "../descriptor/elementDescriptor";
|
|
7
6
|
import { getWebsiteBuilderRpc } from "../iframeRpcChannel";
|
|
@@ -27,7 +26,6 @@ import {
|
|
|
27
26
|
} from "../selectModeSession";
|
|
28
27
|
import { useDisplayMode, useSelectModeStore } from "../selectModeStore";
|
|
29
28
|
import { symbolicateSelectedElement } from "../symbolicate";
|
|
30
|
-
import { getRepetitionSiblingElements } from "./useSiblingResolution";
|
|
31
29
|
const DOUBLE_CLICK_THRESHOLD_MS = 500;
|
|
32
30
|
function getSelectedElementsFromSession(session) {
|
|
33
31
|
if (session.type === "element") {
|
|
@@ -72,8 +70,8 @@ function useSelectionInteractions() {
|
|
|
72
70
|
actions().hideSelectionFrames();
|
|
73
71
|
};
|
|
74
72
|
const showAreaSelectionFrames = actions().showAreaSelectionFrames;
|
|
75
|
-
const showElementSelectionFrames = actions().showElementSelectionFrames;
|
|
76
73
|
const editingPointerIds = store().editingPointerIds;
|
|
74
|
+
let committedDataAtPointerDown = null;
|
|
77
75
|
const clearCommittedSelection = ({
|
|
78
76
|
rect
|
|
79
77
|
}) => {
|
|
@@ -186,6 +184,8 @@ function useSelectionInteractions() {
|
|
|
186
184
|
event.preventDefault();
|
|
187
185
|
event.stopPropagation();
|
|
188
186
|
const scrollOffset = getDocumentScrollOffset();
|
|
187
|
+
const session = interactionSessionRef.current;
|
|
188
|
+
committedDataAtPointerDown = session.type === "element" ? session.data : null;
|
|
189
189
|
actions().setCommittedSelectionAtPointerDown(
|
|
190
190
|
getSelectedElementsFromSession(interactionSessionRef.current)
|
|
191
191
|
);
|
|
@@ -277,7 +277,6 @@ function useSelectionInteractions() {
|
|
|
277
277
|
selectionElement,
|
|
278
278
|
pointerEvent
|
|
279
279
|
}) => {
|
|
280
|
-
const targetRect = selectionElement.getBoundingClientRect();
|
|
281
280
|
const clickPosition = getElementAnchor({
|
|
282
281
|
element: selectionElement,
|
|
283
282
|
selectionRect: getPointRect({
|
|
@@ -285,12 +284,6 @@ function useSelectionInteractions() {
|
|
|
285
284
|
y: pointerEvent.clientY
|
|
286
285
|
})
|
|
287
286
|
});
|
|
288
|
-
const scrollOffset = getDocumentScrollOffset();
|
|
289
|
-
const siblingElements = selectionElement instanceof HTMLElement ? getRepetitionSiblingElements({ element: selectionElement }) : [];
|
|
290
|
-
showElementSelectionFrames({
|
|
291
|
-
elements: [selectionElement, ...siblingElements],
|
|
292
|
-
scrollOffset
|
|
293
|
-
});
|
|
294
287
|
const now = pointerEvent.timeStamp;
|
|
295
288
|
const previousClick = store().lastClick;
|
|
296
289
|
if (previousClick && previousClick.target === selectionElement && now - previousClick.time <= DOUBLE_CLICK_THRESHOLD_MS && isTextEditableElement(selectionElement)) {
|
|
@@ -301,41 +294,20 @@ function useSelectionInteractions() {
|
|
|
301
294
|
});
|
|
302
295
|
return;
|
|
303
296
|
}
|
|
304
|
-
const data =
|
|
297
|
+
const data = actions().commitElementSelection({
|
|
305
298
|
element: selectionElement,
|
|
306
299
|
clickPosition,
|
|
307
|
-
|
|
300
|
+
isPendingClickOnSelection: (descriptor) => {
|
|
301
|
+
const session = interactionSessionRef.current;
|
|
302
|
+
const committedSelectionAtPointerDown = store().committedSelectionAtPointerDown;
|
|
303
|
+
return session.type === "drag" && !session.hasExceededThreshold && committedDataAtPointerDown === descriptor && committedSelectionAtPointerDown.length === 1 && committedSelectionAtPointerDown[0] === selectionElement;
|
|
304
|
+
}
|
|
308
305
|
});
|
|
309
306
|
actions().setLastClick({
|
|
310
307
|
descriptorPromise: Promise.resolve(data),
|
|
311
308
|
target: selectionElement,
|
|
312
309
|
time: now
|
|
313
310
|
});
|
|
314
|
-
if (!selectionElement.isConnected) {
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
interactionSessionRef.current = {
|
|
318
|
-
type: "element",
|
|
319
|
-
element: selectionElement,
|
|
320
|
-
siblingElements,
|
|
321
|
-
clickPosition: {
|
|
322
|
-
x: clickPosition.x - targetRect.left,
|
|
323
|
-
y: clickPosition.y - targetRect.top
|
|
324
|
-
},
|
|
325
|
-
data
|
|
326
|
-
};
|
|
327
|
-
void maybeSymbolicate(data).then((symbolicated) => {
|
|
328
|
-
const session = interactionSessionRef.current;
|
|
329
|
-
const committedSelectionAtPointerDown = store().committedSelectionAtPointerDown;
|
|
330
|
-
const isPendingClickOnSelection = session.type === "drag" && !session.hasExceededThreshold && committedSelectionAtPointerDown.length === 1 && committedSelectionAtPointerDown[0] === selectionElement;
|
|
331
|
-
if (!isPendingClickOnSelection && !isSelectionStillCurrent({
|
|
332
|
-
session: interactionSessionRef.current,
|
|
333
|
-
selection: { type: "element", element: selectionElement }
|
|
334
|
-
})) {
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
getWebsiteBuilderRpc()?.elementSelected({ data: symbolicated });
|
|
338
|
-
});
|
|
339
311
|
};
|
|
340
312
|
const commitClickSelection = ({
|
|
341
313
|
targetElement,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
|
+
import { isSelectedSection } from "../../_vendor/schemas/selectMode.mjs";
|
|
2
3
|
import { getWebsiteBuilderRpc } from "../iframeRpcChannel";
|
|
3
4
|
import {
|
|
4
5
|
getDocumentScrollOffset,
|
|
@@ -37,7 +38,8 @@ function useSelectionScrollSync() {
|
|
|
37
38
|
interactionSession.element,
|
|
38
39
|
...interactionSession.siblingElements
|
|
39
40
|
],
|
|
40
|
-
scrollOffset
|
|
41
|
+
scrollOffset,
|
|
42
|
+
isSection: isSelectedSection(interactionSession.data)
|
|
41
43
|
});
|
|
42
44
|
getWebsiteBuilderRpc()?.selectedElementRectUpdate({
|
|
43
45
|
rect: boundingRect,
|
|
@@ -57,8 +59,10 @@ function useSelectionScrollSync() {
|
|
|
57
59
|
);
|
|
58
60
|
};
|
|
59
61
|
document.addEventListener("scroll", handleScroll, true);
|
|
62
|
+
window.addEventListener("resize", handleScroll);
|
|
60
63
|
return () => {
|
|
61
64
|
document.removeEventListener("scroll", handleScroll, true);
|
|
65
|
+
window.removeEventListener("resize", handleScroll);
|
|
62
66
|
const { scrollSyncAnimationFrameId, actions } = store.getState();
|
|
63
67
|
if (scrollSyncAnimationFrameId !== null) {
|
|
64
68
|
cancelAnimationFrame(scrollSyncAnimationFrameId);
|
|
@@ -13,6 +13,9 @@ export declare function getSelectModeIframeRpcChannel(): import("../_vendor/sche
|
|
|
13
13
|
element: import("zod").ZodObject<{
|
|
14
14
|
kind: import("zod").ZodLiteral<"react-element">;
|
|
15
15
|
selector: import("zod").ZodString;
|
|
16
|
+
section: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
17
|
+
selector: import("zod").ZodString;
|
|
18
|
+
}, import("zod/v4/core").$strip>>;
|
|
16
19
|
tagName: import("zod").ZodString;
|
|
17
20
|
elementType: import("zod").ZodString;
|
|
18
21
|
textContent: import("zod").ZodNullable<import("zod").ZodString>;
|
|
@@ -104,6 +107,9 @@ export declare function getSelectModeIframeRpcChannel(): import("../_vendor/sche
|
|
|
104
107
|
data: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
105
108
|
kind: import("zod").ZodLiteral<"react-element">;
|
|
106
109
|
selector: import("zod").ZodString;
|
|
110
|
+
section: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
111
|
+
selector: import("zod").ZodString;
|
|
112
|
+
}, import("zod/v4/core").$strip>>;
|
|
107
113
|
tagName: import("zod").ZodString;
|
|
108
114
|
elementType: import("zod").ZodString;
|
|
109
115
|
textContent: import("zod").ZodNullable<import("zod").ZodString>;
|
|
@@ -202,6 +208,7 @@ export declare function getSelectModeIframeRpcChannel(): import("../_vendor/sche
|
|
|
202
208
|
bottom: import("zod").ZodNumber;
|
|
203
209
|
width: import("zod").ZodNumber;
|
|
204
210
|
height: import("zod").ZodNumber;
|
|
211
|
+
isSection: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
205
212
|
}, import("zod/v4/core").$strip>>;
|
|
206
213
|
}, import("zod/v4/core").$strip>;
|
|
207
214
|
outputSchema: import("zod").ZodVoid;
|
|
@@ -283,6 +290,9 @@ export declare function getSelectModeIframeRpcChannel(): import("../_vendor/sche
|
|
|
283
290
|
items: import("zod").ZodArray<import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
284
291
|
kind: import("zod").ZodLiteral<"react-element">;
|
|
285
292
|
selector: import("zod").ZodString;
|
|
293
|
+
section: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
294
|
+
selector: import("zod").ZodString;
|
|
295
|
+
}, import("zod/v4/core").$strip>>;
|
|
286
296
|
tagName: import("zod").ZodString;
|
|
287
297
|
elementType: import("zod").ZodString;
|
|
288
298
|
textContent: import("zod").ZodNullable<import("zod").ZodString>;
|
|
@@ -25,6 +25,8 @@ function createSelectModeIframeRpcChannel() {
|
|
|
25
25
|
outgoingMethods: previewIframeToWebsiteBuilderMethodConfig,
|
|
26
26
|
incomingMethods: websiteBuilderToPreviewIframeMethodConfig,
|
|
27
27
|
handlers: {
|
|
28
|
+
expandToSection: (input) => messagingHandlers?.expandToSection(input),
|
|
29
|
+
setSectionPreview: (input) => messagingHandlers?.setSectionPreview(input),
|
|
28
30
|
setDisplayMode: (input) => {
|
|
29
31
|
messagingHandlers?.setDisplayMode(input);
|
|
30
32
|
},
|
|
@@ -13,11 +13,17 @@ function createImagePreview(image) {
|
|
|
13
13
|
let configuration = "";
|
|
14
14
|
let disposed = false;
|
|
15
15
|
function paint() {
|
|
16
|
-
if (disposed)
|
|
16
|
+
if (disposed) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
17
19
|
const url = resolver.currentSrc || resolver.src;
|
|
18
|
-
if (!url)
|
|
20
|
+
if (!url) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
19
23
|
const rule = `[data-replo-image-preview="${token}"] { content: url(${JSON.stringify(url)}) !important; }`;
|
|
20
|
-
if (style.textContent !== rule)
|
|
24
|
+
if (style.textContent !== rule) {
|
|
25
|
+
style.textContent = rule;
|
|
26
|
+
}
|
|
21
27
|
}
|
|
22
28
|
resolver.addEventListener("load", paint);
|
|
23
29
|
return {
|
|
@@ -50,7 +56,9 @@ function createImagePreview(image) {
|
|
|
50
56
|
resolveMetadata(config.sizes, image.sizes)
|
|
51
57
|
);
|
|
52
58
|
picture.replaceChildren(...sources, resolver);
|
|
53
|
-
if (!picture.isConnected)
|
|
59
|
+
if (!picture.isConnected) {
|
|
60
|
+
document.body.append(picture);
|
|
61
|
+
}
|
|
54
62
|
}
|
|
55
63
|
paint();
|
|
56
64
|
},
|
|
@@ -64,8 +72,9 @@ function createImagePreview(image) {
|
|
|
64
72
|
resolver.removeEventListener("load", paint);
|
|
65
73
|
picture.remove();
|
|
66
74
|
style.remove();
|
|
67
|
-
if (image.dataset.reploImagePreview === token)
|
|
75
|
+
if (image.dataset.reploImagePreview === token) {
|
|
68
76
|
delete image.dataset.reploImagePreview;
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
79
|
};
|
|
71
80
|
}
|
|
@@ -24,8 +24,9 @@ function getPreviewUrl({
|
|
|
24
24
|
srcSet,
|
|
25
25
|
baseURI
|
|
26
26
|
}) {
|
|
27
|
-
if (src.length > MAX_IMAGE_METADATA_LENGTH || srcSet.length > MAX_IMAGE_METADATA_LENGTH)
|
|
27
|
+
if (src.length > MAX_IMAGE_METADATA_LENGTH || srcSet.length > MAX_IMAGE_METADATA_LENGTH) {
|
|
28
28
|
return null;
|
|
29
|
+
}
|
|
29
30
|
const candidate = src || srcSet.trim().split(/\s+/)[0]?.replace(/,+$/, "");
|
|
30
31
|
if (!candidate) {
|
|
31
32
|
return null;
|
|
@@ -8,7 +8,9 @@ function reportInlineEditFeedback({
|
|
|
8
8
|
let stopped = false;
|
|
9
9
|
let previousRect = "";
|
|
10
10
|
const report = () => {
|
|
11
|
-
if (stopped)
|
|
11
|
+
if (stopped) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
12
14
|
if (!element.isConnected) {
|
|
13
15
|
onDisconnected();
|
|
14
16
|
return;
|
|
@@ -34,10 +36,14 @@ function reportInlineEditFeedback({
|
|
|
34
36
|
animationFrame = requestAnimationFrame(report);
|
|
35
37
|
};
|
|
36
38
|
const timer = status === "pending" ? window.setTimeout(report, 150) : null;
|
|
37
|
-
if (status !== "pending")
|
|
39
|
+
if (status !== "pending") {
|
|
40
|
+
report();
|
|
41
|
+
}
|
|
38
42
|
return () => {
|
|
39
43
|
stopped = true;
|
|
40
|
-
if (timer !== null)
|
|
44
|
+
if (timer !== null) {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
}
|
|
41
47
|
cancelAnimationFrame(animationFrame);
|
|
42
48
|
getWebsiteBuilderRpc()?.inlineEditFeedbackChanged({ feedback: null });
|
|
43
49
|
};
|