@replohq/sandbox-runtime 1.8.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.
Files changed (47) hide show
  1. package/PageCaptureResponder.d.ts +1 -0
  2. package/PageCaptureResponder.js +12 -0
  3. package/_vendor/replo-utils/lib/crypto.mjs +1 -0
  4. package/_vendor/replo-utils/lib/fonts.mjs +18 -6
  5. package/_vendor/replo-utils/lib/math.mjs +1 -1
  6. package/_vendor/replo-utils/lib/pageCapture.d.ts +34 -0
  7. package/_vendor/replo-utils/lib/pageCapture.mjs +52 -0
  8. package/_vendor/schemas/generated/selectMode.d.ts +14 -0
  9. package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +12 -2
  10. package/_vendor/schemas/iframeRpcChannel.mjs +1 -1
  11. package/_vendor/schemas/selectMode.d.ts +26 -2
  12. package/_vendor/schemas/selectMode.mjs +1 -1
  13. package/_vendor/schemas/selectModeIframeRpc.d.ts +53 -4
  14. package/_vendor/schemas/selectModeIframeRpc.mjs +18 -2
  15. package/_vendor/schemas/selectModeImage.mjs +6 -2
  16. package/buildMetadata.js +3 -3
  17. package/capturePage.d.ts +11 -0
  18. package/capturePage.js +261 -0
  19. package/chunk-LIPH4O4F.mjs +67 -0
  20. package/{chunk-XWNBKE63.mjs → chunk-PJBGUXBG.mjs} +6 -1
  21. package/design-library-preview/DesignLibraryPreview.js +18 -6
  22. package/package.json +5 -4
  23. package/sandbox-runtime.js +2 -0
  24. package/select-mode/EditorSelection.js +21 -4
  25. package/select-mode/SelectionFrames.js +56 -23
  26. package/select-mode/descriptor/elementDescriptor.d.ts +2 -1
  27. package/select-mode/descriptor/elementDescriptor.js +22 -14
  28. package/select-mode/hooks/useOptimisticOverrides.js +18 -6
  29. package/select-mode/hooks/useParentMessaging.d.ts +7 -1
  30. package/select-mode/hooks/useParentMessaging.js +6 -0
  31. package/select-mode/hooks/useSelectionHover.js +38 -15
  32. package/select-mode/hooks/useSelectionInteractions.js +9 -37
  33. package/select-mode/hooks/useSelectionScrollSync.js +5 -1
  34. package/select-mode/iframeRpcChannel.d.ts +10 -0
  35. package/select-mode/iframeRpcChannel.js +2 -0
  36. package/select-mode/imageOverridePreview.js +14 -5
  37. package/select-mode/imageSources.js +2 -1
  38. package/select-mode/inlineEditFeedback.js +9 -3
  39. package/select-mode/interactions/sectionGeometry.d.ts +3 -0
  40. package/select-mode/interactions/sectionGeometry.js +200 -0
  41. package/select-mode/selectModeStore.d.ts +36 -8
  42. package/select-mode/selectModeStore.js +141 -21
  43. package/select-mode/selectionFrame.d.ts +3 -1
  44. package/select-mode/selectionFrame.js +4 -0
  45. package/startPageCaptureResponder.d.ts +32 -0
  46. package/startPageCaptureResponder.js +87 -0
  47. package/chunk-SGKQ5HGT.mjs +0 -7
@@ -30,12 +30,20 @@ function getSelectableDataFromElement(element) {
30
30
  rect: getElementBoundingRect(selectableElement)
31
31
  };
32
32
  }
33
- function identifyElement(element) {
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
- const trimmedText2 = element.textContent?.trim();
37
- if (trimmedText2) {
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
- const trimmedText2 = element.textContent?.trim();
53
- if (trimmedText2) {
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
- const trimmedText2 = element.textContent?.trim();
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: element.textContent?.trim()?.slice(0, 200) ?? null,
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") return;
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") return;
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") continue;
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)) continue;
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)) continue;
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") return true;
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 { lastPostedHoverRect, actions } = store.getState();
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
- actions.setLastPostedHoverRect(rect);
21
- getWebsiteBuilderRpc()?.hoverElement({ rect });
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
- postHoveredElement(null);
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", handlePointerOver, true);
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", handlePointerOver, true);
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 = buildElementDescriptor({
297
+ const data = actions().commitElementSelection({
305
298
  element: selectionElement,
306
299
  clickPosition,
307
- siblingSelectors: siblingElements.map(buildSelector)
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) return;
16
+ if (disposed) {
17
+ return;
18
+ }
17
19
  const url = resolver.currentSrc || resolver.src;
18
- if (!url) return;
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) 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) document.body.append(picture);
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) return;
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") report();
39
+ if (status !== "pending") {
40
+ report();
41
+ }
38
42
  return () => {
39
43
  stopped = true;
40
- if (timer !== null) clearTimeout(timer);
44
+ if (timer !== null) {
45
+ clearTimeout(timer);
46
+ }
41
47
  cancelAnimationFrame(animationFrame);
42
48
  getWebsiteBuilderRpc()?.inlineEditFeedbackChanged({ feedback: null });
43
49
  };
@@ -0,0 +1,3 @@
1
+ export declare const CONTAINER_TAGS: Set<string>;
2
+ /** Suggests a visual section from live layout, not a React/source component boundary. */
3
+ export declare function findContainingSection(element: Element): Element | null;