@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.
Files changed (33) hide show
  1. package/_vendor/replo-utils/lib/fonts.mjs +18 -6
  2. package/_vendor/schemas/generated/selectMode.d.ts +14 -0
  3. package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +12 -2
  4. package/_vendor/schemas/selectMode.d.ts +24 -0
  5. package/_vendor/schemas/selectMode.mjs +1 -1
  6. package/_vendor/schemas/selectModeIframeRpc.d.ts +49 -0
  7. package/_vendor/schemas/selectModeIframeRpc.mjs +18 -2
  8. package/_vendor/schemas/selectModeImage.mjs +6 -2
  9. package/buildMetadata.js +3 -3
  10. package/{chunk-XWNBKE63.mjs → chunk-PJBGUXBG.mjs} +6 -1
  11. package/design-library-preview/DesignLibraryPreview.js +18 -6
  12. package/package.json +4 -4
  13. package/select-mode/EditorSelection.js +21 -4
  14. package/select-mode/SelectionFrames.js +56 -23
  15. package/select-mode/descriptor/elementDescriptor.d.ts +2 -1
  16. package/select-mode/descriptor/elementDescriptor.js +22 -14
  17. package/select-mode/hooks/useOptimisticOverrides.js +18 -6
  18. package/select-mode/hooks/useParentMessaging.d.ts +7 -1
  19. package/select-mode/hooks/useParentMessaging.js +6 -0
  20. package/select-mode/hooks/useSelectionHover.js +38 -15
  21. package/select-mode/hooks/useSelectionInteractions.js +9 -37
  22. package/select-mode/hooks/useSelectionScrollSync.js +5 -1
  23. package/select-mode/iframeRpcChannel.d.ts +10 -0
  24. package/select-mode/iframeRpcChannel.js +2 -0
  25. package/select-mode/imageOverridePreview.js +14 -5
  26. package/select-mode/imageSources.js +2 -1
  27. package/select-mode/inlineEditFeedback.js +9 -3
  28. package/select-mode/interactions/sectionGeometry.d.ts +3 -0
  29. package/select-mode/interactions/sectionGeometry.js +200 -0
  30. package/select-mode/selectModeStore.d.ts +36 -8
  31. package/select-mode/selectModeStore.js +141 -21
  32. package/select-mode/selectionFrame.d.ts +3 -1
  33. package/select-mode/selectionFrame.js +4 -0
@@ -184,16 +184,28 @@ function describeFontFile(fileName) {
184
184
  }
185
185
  function fontFormatFromExtension(extension) {
186
186
  const normalized = extension.toLowerCase().replace(/^\./u, "");
187
- if (normalized === "woff2") return "woff2";
188
- if (normalized === "woff") return "woff";
189
- if (normalized === "otf") return "opentype";
190
- if (normalized === "ttf") return "truetype";
187
+ if (normalized === "woff2") {
188
+ return "woff2";
189
+ }
190
+ if (normalized === "woff") {
191
+ return "woff";
192
+ }
193
+ if (normalized === "otf") {
194
+ return "opentype";
195
+ }
196
+ if (normalized === "ttf") {
197
+ return "truetype";
198
+ }
191
199
  return "woff2";
192
200
  }
193
201
  function fontFormatFromMimeType(mimeType) {
194
202
  const normalized = mimeType.toLowerCase();
195
- if (normalized.includes("woff2")) return "woff2";
196
- if (normalized.includes("woff")) return "woff";
203
+ if (normalized.includes("woff2")) {
204
+ return "woff2";
205
+ }
206
+ if (normalized.includes("woff")) {
207
+ return "woff";
208
+ }
197
209
  if (normalized.includes("otf") || normalized.includes("opentype")) {
198
210
  return "opentype";
199
211
  }
@@ -34,6 +34,17 @@ export type SelectModeBoundingRect = {
34
34
  width: number;
35
35
  height: number;
36
36
  };
37
+ export type SelectModeHoverRect = {
38
+ x: number;
39
+ y: number;
40
+ left: number;
41
+ top: number;
42
+ right: number;
43
+ bottom: number;
44
+ width: number;
45
+ height: number;
46
+ isSection?: boolean;
47
+ };
37
48
  export type SelectModeSelectionRect = {
38
49
  id: string;
39
50
  rect: SelectModeBoundingRect;
@@ -77,6 +88,9 @@ export type SelectModeImage = {
77
88
  export type SelectedElement = {
78
89
  kind: "react-element";
79
90
  selector: string;
91
+ section?: {
92
+ selector: string;
93
+ };
80
94
  tagName: string;
81
95
  elementType: string;
82
96
  textContent: string | null;
@@ -1,4 +1,4 @@
1
- import type { SelectModeBoundingRect, DisplayMode, SelectModeSelectionType, SelectModeOptimisticUpdatePayload, SelectModeFormatCommand, SelectableData, SelectModeClickPosition, SelectModeSelectionRect, SelectModeTiptapActiveMarks } from "./selectMode";
1
+ import type { SelectModeBoundingRect, DisplayMode, SelectModeSelectionType, SelectModeOptimisticUpdatePayload, SelectModeFormatCommand, SelectableData, SelectModeHoverRect, SelectModeClickPosition, SelectModeSelectionRect, SelectModeTiptapActiveMarks } from "./selectMode";
2
2
  export type InlineEditFeedback = {
3
3
  status: "pending" | "unavailable" | "failed";
4
4
  rect: SelectModeBoundingRect;
@@ -11,6 +11,16 @@ export type IframeRuntimeBuildMetadata = {
11
11
  builtAt: string | null;
12
12
  };
13
13
  export type SelectModeParentMessage = {
14
+ method: "expandToSection";
15
+ data: {
16
+ targetSelector: string;
17
+ };
18
+ } | {
19
+ method: "setSectionPreview";
20
+ data: {
21
+ targetSelector: string | null;
22
+ };
23
+ } | {
14
24
  method: "setDisplayMode";
15
25
  data: {
16
26
  displayMode: DisplayMode;
@@ -67,7 +77,7 @@ export type SelectModeIframeMessage = {
67
77
  } | {
68
78
  method: "hoverElement";
69
79
  data: {
70
- rect: SelectModeBoundingRect | null;
80
+ rect: SelectModeHoverRect | null;
71
81
  };
72
82
  } | {
73
83
  method: "selectedElementRectUpdate";
@@ -46,6 +46,17 @@ export declare const selectModeBoundingRectSchema: z.ZodObject<{
46
46
  width: z.ZodNumber;
47
47
  height: z.ZodNumber;
48
48
  }, z.core.$strip>;
49
+ export declare const selectModeHoverRectSchema: z.ZodObject<{
50
+ x: z.ZodNumber;
51
+ y: z.ZodNumber;
52
+ left: z.ZodNumber;
53
+ top: z.ZodNumber;
54
+ right: z.ZodNumber;
55
+ bottom: z.ZodNumber;
56
+ width: z.ZodNumber;
57
+ height: z.ZodNumber;
58
+ isSection: z.ZodOptional<z.ZodBoolean>;
59
+ }, z.core.$strip>;
49
60
  export declare const selectModeSelectionRectSchema: z.ZodObject<{
50
61
  id: z.ZodString;
51
62
  rect: z.ZodObject<{
@@ -128,6 +139,9 @@ export declare const selectModeImageSchema: z.ZodObject<{
128
139
  export declare const selectedElementSchema: z.ZodObject<{
129
140
  kind: z.ZodLiteral<"react-element">;
130
141
  selector: z.ZodString;
142
+ section: z.ZodOptional<z.ZodObject<{
143
+ selector: z.ZodString;
144
+ }, z.core.$strip>>;
131
145
  tagName: z.ZodString;
132
146
  elementType: z.ZodString;
133
147
  textContent: z.ZodNullable<z.ZodString>;
@@ -226,6 +240,9 @@ export declare const selectableDataPayloadSchema: z.ZodDiscriminatedUnion<[z.Zod
226
240
  export declare const selectableDataSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
227
241
  kind: z.ZodLiteral<"react-element">;
228
242
  selector: z.ZodString;
243
+ section: z.ZodOptional<z.ZodObject<{
244
+ selector: z.ZodString;
245
+ }, z.core.$strip>>;
229
246
  tagName: z.ZodString;
230
247
  elementType: z.ZodString;
231
248
  textContent: z.ZodNullable<z.ZodString>;
@@ -314,6 +331,7 @@ export type SelectModeBoundingRect = z.infer<typeof selectModeBoundingRectSchema
314
331
  export type SelectModeClickPosition = z.infer<typeof selectModeClickPositionSchema>;
315
332
  export type SelectableData = z.infer<typeof selectableDataSchema>;
316
333
  export type SelectableDataPayload = z.infer<typeof selectableDataPayloadSchema>;
334
+ export declare function isSelectedSection(data: SelectableData): boolean;
317
335
  export declare function transformSelectedElement({ element, offset, scale, }: {
318
336
  element: z.infer<typeof selectedElementSchema>;
319
337
  offset: RectOffset;
@@ -418,6 +436,9 @@ export declare const selectModeSelectionSchema: z.ZodDiscriminatedUnion<[z.ZodOb
418
436
  data: z.ZodDiscriminatedUnion<[z.ZodObject<{
419
437
  kind: z.ZodLiteral<"react-element">;
420
438
  selector: z.ZodString;
439
+ section: z.ZodOptional<z.ZodObject<{
440
+ selector: z.ZodString;
441
+ }, z.core.$strip>>;
421
442
  tagName: z.ZodString;
422
443
  elementType: z.ZodString;
423
444
  textContent: z.ZodNullable<z.ZodString>;
@@ -517,6 +538,9 @@ export declare const selectModeSelectionSchema: z.ZodDiscriminatedUnion<[z.ZodOb
517
538
  items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
518
539
  kind: z.ZodLiteral<"react-element">;
519
540
  selector: z.ZodString;
541
+ section: z.ZodOptional<z.ZodObject<{
542
+ selector: z.ZodString;
543
+ }, z.core.$strip>>;
520
544
  tagName: z.ZodString;
521
545
  elementType: z.ZodString;
522
546
  textContent: z.ZodNullable<z.ZodString>;
@@ -1,4 +1,4 @@
1
- export { SELECT_MODE_SELECTABLE_ATTRIBUTE, SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE, displayModeSchema, getIframeOffset, readSelectablePayload, selectModeBoundingRectSchema, selectModeClickPositionSchema, selectModeDefinedStyleSchema, selectModeFiberChainEntrySchema, selectModeFormatCommandSchema, selectModeImageSchema, selectModeImageScopeSchema, selectModeImageSourceSchema, selectModeInlineTextStatusSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionRectSchema, selectModeSelectionSchema, selectModeSelectionTypeSchema, selectModeSourceLocationSchema, selectModeStyleAtRuleSchema, selectModeStyleVariantSchema, selectModeTextMetricsSchema, selectModeTiptapActiveMarksSchema, selectableDataPayloadSchema, selectableDataSchema, selectablePlanDataSchema, selectablePlanPayloadSchema, selectedElementSchema, transformPoint, transformRect, transformSelectableData, transformSelectedElement } from '../../chunk-XWNBKE63.mjs';
1
+ export { SELECT_MODE_SELECTABLE_ATTRIBUTE, SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE, displayModeSchema, getIframeOffset, isSelectedSection, readSelectablePayload, selectModeBoundingRectSchema, selectModeClickPositionSchema, selectModeDefinedStyleSchema, selectModeFiberChainEntrySchema, selectModeFormatCommandSchema, selectModeHoverRectSchema, selectModeImageSchema, selectModeImageScopeSchema, selectModeImageSourceSchema, selectModeInlineTextStatusSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionRectSchema, selectModeSelectionSchema, selectModeSelectionTypeSchema, selectModeSourceLocationSchema, selectModeStyleAtRuleSchema, selectModeStyleVariantSchema, selectModeTextMetricsSchema, selectModeTiptapActiveMarksSchema, selectableDataPayloadSchema, selectableDataSchema, selectablePlanDataSchema, selectablePlanPayloadSchema, selectedElementSchema, transformPoint, transformRect, transformSelectableData, transformSelectedElement } from '../../chunk-PJBGUXBG.mjs';
2
2
  import '../../chunk-JUKCUPQ6.mjs';
3
3
  import '../../chunk-FLYEIRFK.mjs';
4
4
  import '../../chunk-TESFJQID.mjs';
@@ -37,6 +37,7 @@ export declare const selectModeEventInputSchemas: {
37
37
  bottom: z.ZodNumber;
38
38
  width: z.ZodNumber;
39
39
  height: z.ZodNumber;
40
+ isSection: z.ZodOptional<z.ZodBoolean>;
40
41
  }, z.core.$strip>>;
41
42
  }, z.core.$strip>;
42
43
  areaSelection: z.ZodObject<{
@@ -53,6 +54,9 @@ export declare const selectModeEventInputSchemas: {
53
54
  items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
54
55
  kind: z.ZodLiteral<"react-element">;
55
56
  selector: z.ZodString;
57
+ section: z.ZodOptional<z.ZodObject<{
58
+ selector: z.ZodString;
59
+ }, z.core.$strip>>;
56
60
  tagName: z.ZodString;
57
61
  elementType: z.ZodString;
58
62
  textContent: z.ZodNullable<z.ZodString>;
@@ -175,10 +179,25 @@ export declare const selectModeEventInputSchemas: {
175
179
  }, z.core.$strip>;
176
180
  };
177
181
  export declare const websiteBuilderToPreviewIframeMethodConfig: {
182
+ expandToSection: {
183
+ inputSchema: z.ZodObject<{
184
+ targetSelector: z.ZodString;
185
+ }, z.core.$strip>;
186
+ outputSchema: z.ZodVoid;
187
+ };
188
+ setSectionPreview: {
189
+ inputSchema: z.ZodObject<{
190
+ targetSelector: z.ZodNullable<z.ZodString>;
191
+ }, z.core.$strip>;
192
+ outputSchema: z.ZodVoid;
193
+ };
178
194
  symbolicateSelectedElement: {
179
195
  inputSchema: z.ZodObject<{
180
196
  kind: z.ZodLiteral<"react-element">;
181
197
  selector: z.ZodString;
198
+ section: z.ZodOptional<z.ZodObject<{
199
+ selector: z.ZodString;
200
+ }, z.core.$strip>>;
182
201
  tagName: z.ZodString;
183
202
  elementType: z.ZodString;
184
203
  textContent: z.ZodNullable<z.ZodString>;
@@ -252,6 +271,9 @@ export declare const websiteBuilderToPreviewIframeMethodConfig: {
252
271
  outputSchema: z.ZodObject<{
253
272
  kind: z.ZodLiteral<"react-element">;
254
273
  selector: z.ZodString;
274
+ section: z.ZodOptional<z.ZodObject<{
275
+ selector: z.ZodString;
276
+ }, z.core.$strip>>;
255
277
  tagName: z.ZodString;
256
278
  elementType: z.ZodString;
257
279
  textContent: z.ZodNullable<z.ZodString>;
@@ -444,6 +466,9 @@ export declare const previewIframeToWebsiteBuilderMethodConfig: {
444
466
  element: z.ZodObject<{
445
467
  kind: z.ZodLiteral<"react-element">;
446
468
  selector: z.ZodString;
469
+ section: z.ZodOptional<z.ZodObject<{
470
+ selector: z.ZodString;
471
+ }, z.core.$strip>>;
447
472
  tagName: z.ZodString;
448
473
  elementType: z.ZodString;
449
474
  textContent: z.ZodNullable<z.ZodString>;
@@ -535,6 +560,9 @@ export declare const previewIframeToWebsiteBuilderMethodConfig: {
535
560
  data: z.ZodDiscriminatedUnion<[z.ZodObject<{
536
561
  kind: z.ZodLiteral<"react-element">;
537
562
  selector: z.ZodString;
563
+ section: z.ZodOptional<z.ZodObject<{
564
+ selector: z.ZodString;
565
+ }, z.core.$strip>>;
538
566
  tagName: z.ZodString;
539
567
  elementType: z.ZodString;
540
568
  textContent: z.ZodNullable<z.ZodString>;
@@ -633,6 +661,7 @@ export declare const previewIframeToWebsiteBuilderMethodConfig: {
633
661
  bottom: z.ZodNumber;
634
662
  width: z.ZodNumber;
635
663
  height: z.ZodNumber;
664
+ isSection: z.ZodOptional<z.ZodBoolean>;
636
665
  }, z.core.$strip>>;
637
666
  }, z.core.$strip>;
638
667
  outputSchema: z.ZodVoid;
@@ -714,6 +743,9 @@ export declare const previewIframeToWebsiteBuilderMethodConfig: {
714
743
  items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
715
744
  kind: z.ZodLiteral<"react-element">;
716
745
  selector: z.ZodString;
746
+ section: z.ZodOptional<z.ZodObject<{
747
+ selector: z.ZodString;
748
+ }, z.core.$strip>>;
717
749
  tagName: z.ZodString;
718
750
  elementType: z.ZodString;
719
751
  textContent: z.ZodNullable<z.ZodString>;
@@ -851,6 +883,16 @@ export declare const previewIframeToWebsiteBuilderMethodConfig: {
851
883
  };
852
884
  };
853
885
  export declare const selectModeParentMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
886
+ method: z.ZodLiteral<"expandToSection">;
887
+ data: z.ZodObject<{
888
+ targetSelector: z.ZodString;
889
+ }, z.core.$strip>;
890
+ }, z.core.$strip>, z.ZodObject<{
891
+ method: z.ZodLiteral<"setSectionPreview">;
892
+ data: z.ZodObject<{
893
+ targetSelector: z.ZodNullable<z.ZodString>;
894
+ }, z.core.$strip>;
895
+ }, z.core.$strip>, z.ZodObject<{
854
896
  method: z.ZodLiteral<"setDisplayMode">;
855
897
  data: z.ZodObject<{
856
898
  displayMode: z.ZodEnum<{
@@ -961,6 +1003,9 @@ export declare const selectModeIframeMessageSchema: z.ZodDiscriminatedUnion<[z.Z
961
1003
  data: z.ZodDiscriminatedUnion<[z.ZodObject<{
962
1004
  kind: z.ZodLiteral<"react-element">;
963
1005
  selector: z.ZodString;
1006
+ section: z.ZodOptional<z.ZodObject<{
1007
+ selector: z.ZodString;
1008
+ }, z.core.$strip>>;
964
1009
  tagName: z.ZodString;
965
1010
  elementType: z.ZodString;
966
1011
  textContent: z.ZodNullable<z.ZodString>;
@@ -1058,6 +1103,7 @@ export declare const selectModeIframeMessageSchema: z.ZodDiscriminatedUnion<[z.Z
1058
1103
  bottom: z.ZodNumber;
1059
1104
  width: z.ZodNumber;
1060
1105
  height: z.ZodNumber;
1106
+ isSection: z.ZodOptional<z.ZodBoolean>;
1061
1107
  }, z.core.$strip>>;
1062
1108
  }, z.core.$strip>;
1063
1109
  }, z.core.$strip>, z.ZodObject<{
@@ -1135,6 +1181,9 @@ export declare const selectModeIframeMessageSchema: z.ZodDiscriminatedUnion<[z.Z
1135
1181
  items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
1136
1182
  kind: z.ZodLiteral<"react-element">;
1137
1183
  selector: z.ZodString;
1184
+ section: z.ZodOptional<z.ZodObject<{
1185
+ selector: z.ZodString;
1186
+ }, z.core.$strip>>;
1138
1187
  tagName: z.ZodString;
1139
1188
  elementType: z.ZodString;
1140
1189
  textContent: z.ZodNullable<z.ZodString>;
@@ -1,4 +1,4 @@
1
- import { selectModeBoundingRectSchema, selectModeTiptapActiveMarksSchema, selectModeSelectionRectSchema, selectableDataSchema, selectModeFormatCommandSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionTypeSchema, displayModeSchema, selectModeClickPositionSchema, selectedElementSchema } from '../../chunk-XWNBKE63.mjs';
1
+ import { selectModeBoundingRectSchema, selectModeTiptapActiveMarksSchema, selectModeSelectionRectSchema, selectableDataSchema, selectModeHoverRectSchema, selectModeFormatCommandSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionTypeSchema, displayModeSchema, selectModeClickPositionSchema, selectedElementSchema } from '../../chunk-PJBGUXBG.mjs';
2
2
  import '../../chunk-JUKCUPQ6.mjs';
3
3
  import '../../chunk-FLYEIRFK.mjs';
4
4
  import '../../chunk-TESFJQID.mjs';
@@ -20,7 +20,7 @@ var iframeRuntimeBuildMetadataSchema = z.object({
20
20
  }).describe("IframeRuntimeBuildMetadata");
21
21
  var selectModeEventInputSchemas = {
22
22
  hover: z.object({
23
- rect: selectModeBoundingRectSchema.nullable()
23
+ rect: selectModeHoverRectSchema.nullable()
24
24
  }),
25
25
  areaSelection: z.object({
26
26
  rect: selectModeBoundingRectSchema,
@@ -37,6 +37,14 @@ var selectModeEventInputSchemas = {
37
37
  })
38
38
  };
39
39
  var websiteBuilderToPreviewIframeMethodConfig = {
40
+ expandToSection: {
41
+ inputSchema: z.object({ targetSelector: z.string() }),
42
+ outputSchema: z.void()
43
+ },
44
+ setSectionPreview: {
45
+ inputSchema: z.object({ targetSelector: z.string().nullable() }),
46
+ outputSchema: z.void()
47
+ },
40
48
  symbolicateSelectedElement: {
41
49
  inputSchema: selectedElementSchema,
42
50
  outputSchema: selectedElementSchema,
@@ -168,6 +176,14 @@ var previewIframeToWebsiteBuilderMethodConfig = {
168
176
  }
169
177
  };
170
178
  var selectModeParentMessageSchema = z.discriminatedUnion("method", [
179
+ z.object({
180
+ method: z.literal("expandToSection"),
181
+ data: websiteBuilderToPreviewIframeMethodConfig.expandToSection.inputSchema
182
+ }),
183
+ z.object({
184
+ method: z.literal("setSectionPreview"),
185
+ data: websiteBuilderToPreviewIframeMethodConfig.setSectionPreview.inputSchema
186
+ }),
171
187
  z.object({
172
188
  method: z.literal("setDisplayMode"),
173
189
  data: websiteBuilderToPreviewIframeMethodConfig.setDisplayMode.inputSchema
@@ -1,8 +1,12 @@
1
1
  function getImageEditSnapshot(image, baseURI) {
2
- if (!image) return null;
2
+ if (!image) {
3
+ return null;
4
+ }
3
5
  const baseUrl = baseURI ?? (URL.canParse(image.currentSrc) ? image.currentSrc : "https://replo.invalid");
4
6
  const normalizeUrl = (url) => {
5
- if (!url) return url;
7
+ if (!url) {
8
+ return url;
9
+ }
6
10
  try {
7
11
  const parsed = new URL(url, baseUrl);
8
12
  const original = parsed.pathname.endsWith("/_next/image") ? parsed.searchParams.get("url") : null;
package/buildMetadata.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export const BUILD_METADATA = {
2
2
  "packageName": "@replohq/sandbox-runtime",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "branch": "HEAD",
5
- "commit": "455eef2903f4cc6a8f457d5ec77be1e1dc95aad9",
6
- "builtAt": "2026-09-25T00:24:57.880Z"
5
+ "commit": "604d707e41cac581b43e134371e5e9a0f78fa2b7",
6
+ "builtAt": "2026-09-25T19:36:00.140Z"
7
7
  };
@@ -48,6 +48,7 @@ var selectModeBoundingRectSchema = z.object({
48
48
  width: z.number(),
49
49
  height: z.number()
50
50
  }).describe("SelectModeBoundingRect");
51
+ var selectModeHoverRectSchema = selectModeBoundingRectSchema.extend({ isSection: z.boolean().optional() }).describe("SelectModeHoverRect");
51
52
  var selectModeSelectionRectSchema = z.object({
52
53
  id: z.string(),
53
54
  rect: selectModeBoundingRectSchema
@@ -122,6 +123,7 @@ var selectModeImageSchema = z.object({
122
123
  var selectedElementSchema = z.object({
123
124
  kind: z.literal("react-element"),
124
125
  selector: z.string(),
126
+ section: z.object({ selector: z.string() }).optional(),
125
127
  tagName: z.string(),
126
128
  elementType: z.string(),
127
129
  textContent: z.string().nullable(),
@@ -145,6 +147,9 @@ var selectablePlanDataSchema = z.object({
145
147
  var selectablePlanPayloadSchema = selectablePlanDataSchema.omit({ rect: true }).describe("SelectablePlanPayload");
146
148
  var selectableDataPayloadSchema = z.discriminatedUnion("kind", [selectablePlanPayloadSchema]).describe("SelectableDataPayload");
147
149
  var selectableDataSchema = z.discriminatedUnion("kind", [selectedElementSchema, selectablePlanDataSchema]).describe("SelectableData");
150
+ function isSelectedSection(data) {
151
+ return data.kind === "react-element" && data.selector === data.section?.selector;
152
+ }
148
153
  function transformSelectedElement({
149
154
  element,
150
155
  offset,
@@ -232,4 +237,4 @@ var selectModeSelectionSchema = z.discriminatedUnion("type", [
232
237
  })
233
238
  ]).describe("SelectModeSelection");
234
239
 
235
- export { SELECT_MODE_SELECTABLE_ATTRIBUTE, SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE, displayModeSchema, getIframeOffset, readSelectablePayload, selectModeBoundingRectSchema, selectModeClickPositionSchema, selectModeDefinedStyleSchema, selectModeFiberChainEntrySchema, selectModeFormatCommandSchema, selectModeImageSchema, selectModeImageScopeSchema, selectModeImageSourceSchema, selectModeInlineTextStatusSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionRectSchema, selectModeSelectionSchema, selectModeSelectionTypeSchema, selectModeSourceLocationSchema, selectModeStyleAtRuleSchema, selectModeStyleVariantSchema, selectModeTextMetricsSchema, selectModeTiptapActiveMarksSchema, selectableDataPayloadSchema, selectableDataSchema, selectablePlanDataSchema, selectablePlanPayloadSchema, selectedElementSchema, transformPoint, transformRect, transformSelectableData, transformSelectedElement };
240
+ export { SELECT_MODE_SELECTABLE_ATTRIBUTE, SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE, displayModeSchema, getIframeOffset, isSelectedSection, readSelectablePayload, selectModeBoundingRectSchema, selectModeClickPositionSchema, selectModeDefinedStyleSchema, selectModeFiberChainEntrySchema, selectModeFormatCommandSchema, selectModeHoverRectSchema, selectModeImageSchema, selectModeImageScopeSchema, selectModeImageSourceSchema, selectModeInlineTextStatusSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionRectSchema, selectModeSelectionSchema, selectModeSelectionTypeSchema, selectModeSourceLocationSchema, selectModeStyleAtRuleSchema, selectModeStyleVariantSchema, selectModeTextMetricsSchema, selectModeTiptapActiveMarksSchema, selectableDataPayloadSchema, selectableDataSchema, selectablePlanDataSchema, selectablePlanPayloadSchema, selectedElementSchema, transformPoint, transformRect, transformSelectableData, transformSelectedElement };
@@ -14,9 +14,13 @@ function DesignLibraryPreview() {
14
14
  const ownsDefaultFont = useRef(false);
15
15
  useEffect(() => {
16
16
  const handleMessage = (event) => {
17
- if (!isAllowedEditorMessage(event)) return;
17
+ if (!isAllowedEditorMessage(event)) {
18
+ return;
19
+ }
18
20
  const parsed = designLibraryPreviewMessageSchema.safeParse(event.data);
19
- if (!parsed.success) return;
21
+ if (!parsed.success) {
22
+ return;
23
+ }
20
24
  const { cssVars, fonts, defaultFontCssVar } = parsed.data;
21
25
  const root = document.documentElement;
22
26
  const nextVars = { ...cssVars };
@@ -25,7 +29,9 @@ function DesignLibraryPreview() {
25
29
  }
26
30
  const owned = ownedKeys.current ?? /* @__PURE__ */ new Set();
27
31
  for (const key of owned) {
28
- if (!(key in nextVars)) root.style.removeProperty(key);
32
+ if (!(key in nextVars)) {
33
+ root.style.removeProperty(key);
34
+ }
29
35
  }
30
36
  ownedKeys.current = new Set(Object.keys(nextVars));
31
37
  for (const [key, value] of Object.entries(nextVars)) {
@@ -44,7 +50,9 @@ function DesignLibraryPreview() {
44
50
  }
45
51
  }
46
52
  for (const href of nextHrefs) {
47
- if (links.has(href)) continue;
53
+ if (links.has(href)) {
54
+ continue;
55
+ }
48
56
  const link = document.createElement("link");
49
57
  link.rel = "stylesheet";
50
58
  link.href = href;
@@ -62,9 +70,13 @@ function DesignLibraryPreview() {
62
70
  }
63
71
  }
64
72
  for (const font of customFonts) {
65
- if (!font.faceUrl) continue;
73
+ if (!font.faceUrl) {
74
+ continue;
75
+ }
66
76
  const existing = faces.get(font.family);
67
- if (existing?.url === font.faceUrl) continue;
77
+ if (existing?.url === font.faceUrl) {
78
+ continue;
79
+ }
68
80
  existing?.style.remove();
69
81
  const style = document.createElement("style");
70
82
  style.dataset[FONT_LINK_DATA_KEY] = "";
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@replohq/sandbox-runtime",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "reploBuild": {
5
5
  "packageName": "@replohq/sandbox-runtime",
6
- "version": "1.9.0",
6
+ "version": "1.10.0",
7
7
  "branch": "HEAD",
8
- "commit": "455eef2903f4cc6a8f457d5ec77be1e1dc95aad9",
9
- "builtAt": "2026-09-25T00:24:57.880Z"
8
+ "commit": "604d707e41cac581b43e134371e5e9a0f78fa2b7",
9
+ "builtAt": "2026-09-25T19:36:00.140Z"
10
10
  },
11
11
  "description": "Replo sandbox runtime — editor integration for agent-built Next.js sites.",
12
12
  "license": "SEE LICENSE IN LICENSE",
@@ -18,6 +18,8 @@ function EditorSelection() {
18
18
  const store = useSelectModeStore();
19
19
  const displayMode = useDisplayMode();
20
20
  const {
21
+ expandToSection,
22
+ setSectionPreview,
21
23
  formatCommand,
22
24
  postSelectedElementSnapshot,
23
25
  revertInlineEdit,
@@ -38,7 +40,9 @@ function EditorSelection() {
38
40
  const scheduleSnapshot = () => {
39
41
  clearTimeout(refreshTimeout);
40
42
  refreshTimeout = setTimeout(() => {
41
- if (store.getState().editingElement) return;
43
+ if (store.getState().editingElement) {
44
+ return;
45
+ }
42
46
  if (postSelectedElementSnapshot()) {
43
47
  clearTimeout(missingTimeout);
44
48
  missingTimeout = void 0;
@@ -54,15 +58,26 @@ function EditorSelection() {
54
58
  }, 250);
55
59
  };
56
60
  const observer = new MutationObserver((records) => {
57
- const session = store.getState().interactionSession;
58
- if (store.getState().editingElement || session.type !== "element") return;
61
+ const {
62
+ actions,
63
+ editingElement,
64
+ interactionSession: session,
65
+ sectionPreviewElement
66
+ } = store.getState();
67
+ if (sectionPreviewElement && !sectionPreviewElement.isConnected) {
68
+ actions.setSectionPreview({ targetSelector: null });
69
+ }
70
+ if (editingElement || session.type !== "element") {
71
+ return;
72
+ }
59
73
  if (!session.element.isConnected || records.some((record) => session.element.contains(record.target))) {
60
74
  scheduleSnapshot();
61
75
  }
62
76
  });
63
77
  const watchRender = () => {
64
- if (store.getState().editingElement || store.getState().interactionSession.type !== "element")
78
+ if (store.getState().editingElement || store.getState().interactionSession.type !== "element") {
65
79
  return;
80
+ }
66
81
  clearTimeout(observationTimeout);
67
82
  observer.observe(document.body, {
68
83
  subtree: true,
@@ -118,6 +133,8 @@ function EditorSelection() {
118
133
  useParentMessaging({
119
134
  applyOptimisticUpdate,
120
135
  markCommitted,
136
+ onExpandToSection: expandToSection,
137
+ onSetSectionPreview: setSectionPreview,
121
138
  onExitEditMode: revertInlineEdit,
122
139
  onFormatCommand: formatCommand,
123
140
  resolveSessionOverrides,
@@ -1,13 +1,17 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { createPortal } from "react-dom";
4
+ import { getDocumentScrollOffset } from "./interactions/selectionGeometry";
4
5
  import {
6
+ SECTION_SELECTION_FRAME_BACKGROUND,
7
+ SECTION_SELECTION_FRAME_BORDER_HEX,
5
8
  SELECTION_FRAME_BORDER_HEX,
6
9
  SELECTION_FRAME_EDITING_BORDER_HEX,
7
10
  SELECTION_FRAMES_CONTAINER_ID
8
11
  } from "./selectionFrame";
9
12
  import {
10
13
  useIsSelectionFrameEditing,
14
+ useSectionHoverRect,
11
15
  useSelectionFrames
12
16
  } from "./selectModeStore";
13
17
  const CONTAINER_STYLE = {
@@ -24,32 +28,61 @@ const CONTAINER_STYLE = {
24
28
  function SelectionFrames() {
25
29
  const frames = useSelectionFrames();
26
30
  const isEditing = useIsSelectionFrameEditing();
27
- if (typeof document === "undefined" || !document.body || frames.length === 0) {
31
+ const sectionHoverRect = useSectionHoverRect();
32
+ if (typeof document === "undefined" || !document.body || frames.length === 0 && !sectionHoverRect) {
28
33
  return null;
29
34
  }
30
- const borderColor = isEditing ? SELECTION_FRAME_EDITING_BORDER_HEX : SELECTION_FRAME_BORDER_HEX;
35
+ const elementBorderColor = isEditing ? SELECTION_FRAME_EDITING_BORDER_HEX : SELECTION_FRAME_BORDER_HEX;
36
+ const scrollOffset = getDocumentScrollOffset();
37
+ const sectionLabelPosition = sectionHoverRect ? {
38
+ x: sectionHoverRect.x + scrollOffset.left,
39
+ y: sectionHoverRect.y + scrollOffset.top
40
+ } : frames.find((frame) => frame.variant === "section")?.pageRect;
31
41
  return createPortal(
32
- /* @__PURE__ */ jsx("div", { id: SELECTION_FRAMES_CONTAINER_ID, "aria-hidden": true, style: CONTAINER_STYLE, children: frames.map((frame, index) => /* @__PURE__ */ jsx(
33
- "div",
34
- {
35
- "aria-hidden": true,
36
- style: {
37
- position: "absolute",
38
- boxSizing: "border-box",
39
- borderRadius: 2,
40
- pointerEvents: "none",
41
- margin: 0,
42
- padding: 0,
43
- left: frame.pageRect.x,
44
- top: frame.pageRect.y,
45
- width: frame.pageRect.width,
46
- height: frame.pageRect.height,
47
- border: `2px solid ${borderColor}`,
48
- background: frame.variant === "area" ? "rgba(192, 38, 211, 0.08)" : "transparent"
42
+ /* @__PURE__ */ jsxs("div", { id: SELECTION_FRAMES_CONTAINER_ID, "aria-hidden": true, style: CONTAINER_STYLE, children: [
43
+ frames.map((frame, index) => /* @__PURE__ */ jsx(
44
+ "div",
45
+ {
46
+ "aria-hidden": true,
47
+ "data-variant": frame.variant,
48
+ style: {
49
+ position: "absolute",
50
+ boxSizing: "border-box",
51
+ borderRadius: 2,
52
+ pointerEvents: "none",
53
+ margin: 0,
54
+ padding: 0,
55
+ left: frame.pageRect.x,
56
+ top: frame.pageRect.y,
57
+ width: frame.pageRect.width,
58
+ height: frame.pageRect.height,
59
+ border: `2px solid ${frame.variant === "section" ? SECTION_SELECTION_FRAME_BORDER_HEX : elementBorderColor}`,
60
+ background: {
61
+ area: "rgba(192, 38, 211, 0.08)",
62
+ element: "transparent",
63
+ section: SECTION_SELECTION_FRAME_BACKGROUND
64
+ }[frame.variant]
65
+ }
66
+ },
67
+ `${frame.variant}-${index}`
68
+ )),
69
+ sectionLabelPosition && /* @__PURE__ */ jsx(
70
+ "span",
71
+ {
72
+ style: {
73
+ position: "absolute",
74
+ top: sectionLabelPosition.y + 6,
75
+ left: sectionLabelPosition.x + 6,
76
+ padding: "3px 6px",
77
+ borderRadius: 4,
78
+ background: "#2563eb",
79
+ color: "white",
80
+ font: "500 12px/16px system-ui"
81
+ },
82
+ children: "Section"
49
83
  }
50
- },
51
- `${frame.variant}-${index}`
52
- )) }),
84
+ )
85
+ ] }),
53
86
  document.body
54
87
  );
55
88
  }
@@ -17,8 +17,9 @@ export declare function buildSelector(element: Element): string;
17
17
  * about a selection: identification, geometry, source location, and a
18
18
  * style-inlined HTML snippet.
19
19
  */
20
- export declare function buildElementDescriptor({ element, clickPosition, siblingSelectors, }: {
20
+ export declare function buildElementDescriptor({ element, clickPosition, siblingSelectors, section, }: {
21
21
  element: Element;
22
22
  clickPosition: SelectModeClickPosition;
23
23
  siblingSelectors?: string[];
24
+ section?: Element | null;
24
25
  }): SelectableData;