@replohq/sandbox-runtime 1.24.1 → 1.24.2

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/buildMetadata.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export const BUILD_METADATA = {
2
2
  "packageName": "@replohq/sandbox-runtime",
3
- "version": "1.24.1",
3
+ "version": "1.24.2",
4
4
  "branch": "HEAD",
5
- "commit": "043ae54a4a52039285aac996cc7b2b67a922dfdd",
6
- "builtAt": "2026-11-03T00:13:53.913Z"
5
+ "commit": "a3a1a0505f42cea89e63bbfa5628b1d35558fc76",
6
+ "builtAt": "2026-11-03T19:15:42.310Z"
7
7
  };
@@ -3,7 +3,7 @@ import type { CommentOverlayAnchorStatus, CommentOverlayPin, CommentOverlayRect
3
3
  import type { DisplayMode } from "../_vendor/schemas/generated/selectMode";
4
4
  import type { ElementSource } from "./capture";
5
5
  export declare const OVERLAY_Z_INDEX = 2147483645;
6
- export declare const HIGHLIGHT_BACKGROUND = "rgba(250, 204, 21, 0.28)";
6
+ export declare const HIGHLIGHT_BACKGROUND = "color-mix(in srgb, var(--replo-comment-accent) 12%, transparent)";
7
7
  export declare const BADGE_SIZE_PX = 32;
8
8
  export declare const RERESOLVE_DEBOUNCE_MS = 250;
9
9
  export type CommentsOverlayCallbacks = {
@@ -2,8 +2,9 @@ import { captureAnchor, getAnchorElement } from "./capture";
2
2
  import { isResolutionVisible, resolveAnchor } from "./resolve";
3
3
  import { OVERLAY_ROOT_ATTRIBUTE } from "./textQuote";
4
4
  const OVERLAY_Z_INDEX = 2147483645;
5
- const HIGHLIGHT_BACKGROUND = "rgba(250, 204, 21, 0.28)";
6
- const QUOTE_UNDERLINE = "2px solid rgba(250, 204, 21, 0.9)";
5
+ const HIGHLIGHT_BACKGROUND = "color-mix(in srgb, var(--replo-comment-accent) 12%, transparent)";
6
+ const SOFT_OUTLINE_COLOR = "color-mix(in srgb, var(--replo-comment-accent) 55%, transparent)";
7
+ const HIGHLIGHT_OUTLINE = "1.5px solid var(--replo-comment-accent)";
7
8
  const BADGE_SIZE_PX = 32;
8
9
  const BADGE_HIT_TARGET_PX = 44;
9
10
  const BADGE_HIT_TARGET_WIDTH_PX = 64;
@@ -11,7 +12,7 @@ const COMPACT_GUTTER_MAX_WIDTH_PX = 600;
11
12
  const RERESOLVE_DEBOUNCE_MS = 250;
12
13
  const SELECTION_PROMPT_DEBOUNCE_MS = 150;
13
14
  const TEXT_PICK_CLICK_SUPPRESS_MS = 750;
14
- const HOVER_OUTLINE_STYLE = "position:absolute;pointer-events:none;box-sizing:border-box;border:1px solid rgba(37,99,235,.45);background:rgba(37,99,235,.025);border-radius:3px";
15
+ const HOVER_OUTLINE_STYLE = `position:absolute;pointer-events:none;box-sizing:border-box;border:${HIGHLIGHT_OUTLINE};background:transparent;border-radius:4px`;
15
16
  const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
16
17
  const EDITABLE_SELECTOR = "input, textarea, select, [contenteditable]:not([contenteditable='false'])";
17
18
  function getReportedStatus(resolution) {
@@ -31,11 +32,8 @@ function createCommentsOverlay(options) {
31
32
  let pins = [];
32
33
  let resolutions = /* @__PURE__ */ new Map();
33
34
  const boundElements = /* @__PURE__ */ new Map();
34
- let focusedThreadId = null;
35
+ let selection = null;
35
36
  let hoveredBadgeThreadId = null;
36
- let draftAnchor = null;
37
- let draftResolution = null;
38
- let draftElement = null;
39
37
  let statusesKey = "";
40
38
  let hoveredElement = null;
41
39
  let hoverOutline = null;
@@ -52,7 +50,7 @@ function createCommentsOverlay(options) {
52
50
  let isDestroyed = false;
53
51
  const root = document.createElement("div");
54
52
  root.setAttribute(OVERLAY_ROOT_ATTRIBUTE, "true");
55
- root.style.cssText = `position:fixed;inset:0;z-index:${OVERLAY_Z_INDEX};pointer-events:none;overflow:hidden`;
53
+ root.style.cssText = `position:fixed;inset:0;z-index:${OVERLAY_Z_INDEX};pointer-events:none;overflow:hidden;--replo-comment-accent:light-dark(#7861bf,#b09be8);--replo-comment-surface:light-dark(#f0eafa,#372e4d);--replo-comment-text:light-dark(#7058b4,#b09be8);--replo-comment-on-accent:light-dark(#fff,#20182f)`;
56
54
  document.documentElement.append(root);
57
55
  const isInOverlay = (node) => {
58
56
  return node instanceof Node && root.contains(node);
@@ -66,22 +64,22 @@ function createCommentsOverlay(options) {
66
64
  const isPageElement = (node) => {
67
65
  return node instanceof Element && node !== document.body && node !== document.documentElement && !isInOverlay(node);
68
66
  };
69
- const isEditableSelection = (selection) => {
70
- const node = selection.anchorNode;
67
+ const isEditableSelection = (selection2) => {
68
+ const node = selection2.anchorNode;
71
69
  const element = node instanceof Element ? node : node?.parentElement;
72
70
  return Boolean(
73
71
  element?.closest(EDITABLE_SELECTOR) || document.activeElement?.matches(EDITABLE_SELECTOR)
74
72
  );
75
73
  };
76
74
  const getUsableSelectionRange = () => {
77
- const selection = window.getSelection();
78
- if (!selection || selection.isCollapsed || selection.rangeCount === 0) {
75
+ const selection2 = window.getSelection();
76
+ if (!selection2 || selection2.isCollapsed || selection2.rangeCount === 0) {
79
77
  return null;
80
78
  }
81
- if (isEditableSelection(selection)) {
79
+ if (isEditableSelection(selection2)) {
82
80
  return null;
83
81
  }
84
- const range = selection.getRangeAt(0);
82
+ const range = selection2.getRangeAt(0);
85
83
  if (!range.toString().trim() || isInOverlay(range.commonAncestorContainer)) {
86
84
  return null;
87
85
  }
@@ -132,11 +130,12 @@ function createCommentsOverlay(options) {
132
130
  }
133
131
  }
134
132
  resolutions = next;
135
- draftResolution = draftAnchor ? resolveAnchor(draftAnchor, document, {
136
- previous: draftElement,
137
- getSource: cachedGetSource
138
- }) : null;
139
- draftElement = draftResolution?.element ?? null;
133
+ if (selection?.kind === "draft") {
134
+ selection.resolution = resolveAnchor(selection.anchor, document, {
135
+ previous: selection.resolution?.element ?? null,
136
+ getSource: cachedGetSource
137
+ });
138
+ }
140
139
  const statuses = getElementAnchors().map(({ pin }) => {
141
140
  return {
142
141
  threadId: pin.threadId,
@@ -157,7 +156,7 @@ function createCommentsOverlay(options) {
157
156
  resolveTimer = setTimeout(resolveAll, RERESOLVE_DEBOUNCE_MS);
158
157
  };
159
158
  const paintHighlight = (resolution, threadId) => {
160
- const isQuote = Boolean(resolution.range);
159
+ const isOutlined = threadId === null || threadId === hoveredBadgeThreadId || selection?.kind === "thread" && threadId === selection.threadId;
161
160
  for (const rect of getResolutionRects(resolution)) {
162
161
  if (rect.width <= 0 || rect.height <= 0 || rect.bottom < 0 || rect.top > window.innerHeight) {
163
162
  continue;
@@ -168,10 +167,7 @@ function createCommentsOverlay(options) {
168
167
  } else {
169
168
  highlight.dataset.commentDraft = "true";
170
169
  }
171
- highlight.style.cssText = `position:absolute;pointer-events:none;background:${HIGHLIGHT_BACKGROUND};border-radius:2px;box-sizing:border-box`;
172
- if (isQuote) {
173
- highlight.style.borderBottom = QUOTE_UNDERLINE;
174
- }
170
+ highlight.style.cssText = `position:absolute;pointer-events:none;background:${threadId ? HIGHLIGHT_BACKGROUND : "transparent"};border:${isOutlined ? HIGHLIGHT_OUTLINE : "0"};border-radius:4px;box-sizing:border-box`;
175
171
  highlight.style.left = `${rect.left}px`;
176
172
  highlight.style.top = `${rect.top}px`;
177
173
  highlight.style.width = `${rect.width}px`;
@@ -180,7 +176,7 @@ function createCommentsOverlay(options) {
180
176
  }
181
177
  };
182
178
  const isHighlightShown = (threadId) => {
183
- return mode === "comment" || threadId === focusedThreadId || threadId === hoveredBadgeThreadId;
179
+ return mode === "comment" || selection?.kind === "thread" && threadId === selection.threadId || threadId === hoveredBadgeThreadId;
184
180
  };
185
181
  const createIcon = (size, path) => {
186
182
  const icon = document.createElementNS(SVG_NAMESPACE, "svg");
@@ -320,7 +316,7 @@ function createCommentsOverlay(options) {
320
316
  };
321
317
  for (const pin of pins) {
322
318
  const resolution = resolutions.get(pin.threadId);
323
- const isFocused = pin.threadId === focusedThreadId;
319
+ const isFocused = selection?.kind === "thread" && pin.threadId === selection.threadId;
324
320
  if (!resolution || pin.status === "resolved" && !isFocused || !isResolutionVisible(resolution)) {
325
321
  continue;
326
322
  }
@@ -350,12 +346,16 @@ function createCommentsOverlay(options) {
350
346
  badge.style.top = `${position.top}px`;
351
347
  const isActive = isFocused || pin.threadId === hoveredBadgeThreadId;
352
348
  const dot = document.createElement("span");
353
- dot.style.cssText = `display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;min-width:48px;height:${BADGE_SIZE_PX}px;padding:0 6px;border-radius:8px;border:1px solid rgba(0,0,0,.12);background:#ffeb80;color:#171717;box-shadow:0 1px 3px rgba(0,0,0,.12);font:600 14px/1 system-ui,-apple-system,sans-serif;font-variant-numeric:tabular-nums;white-space:nowrap`;
349
+ dot.style.cssText = `display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;min-width:48px;height:${BADGE_SIZE_PX}px;padding:0 6px;border-radius:999px;border:1px solid ${SOFT_OUTLINE_COLOR};background:var(--replo-comment-surface);color:var(--replo-comment-text);box-shadow:0 1px 3px rgba(0,0,0,.08);font:600 14px/1 system-ui,-apple-system,sans-serif;font-variant-numeric:tabular-nums;white-space:nowrap`;
354
350
  if (isCompact) {
355
351
  dot.style.marginRight = "3px";
356
352
  }
357
353
  if (isActive) {
358
- dot.style.borderColor = "rgba(0,0,0,.4)";
354
+ dot.style.borderColor = "var(--replo-comment-accent)";
355
+ }
356
+ if (isFocused) {
357
+ dot.style.background = "var(--replo-comment-accent)";
358
+ dot.style.color = "var(--replo-comment-on-accent)";
359
359
  }
360
360
  if (resolution.status === "ambiguous") {
361
361
  dot.style.borderStyle = "dashed";
@@ -380,8 +380,8 @@ function createCommentsOverlay(options) {
380
380
  child.remove();
381
381
  }
382
382
  }
383
- if (draftResolution && isResolutionVisible(draftResolution)) {
384
- paintHighlight(draftResolution, null);
383
+ if (selection?.kind === "draft" && selection.resolution && isResolutionVisible(selection.resolution)) {
384
+ paintHighlight(selection.resolution, null);
385
385
  }
386
386
  paintBadges();
387
387
  paintHover();
@@ -409,21 +409,23 @@ function createCommentsOverlay(options) {
409
409
  const anchor = captureAnchor(target, point);
410
410
  const range = "tagName" in target ? void 0 : target;
411
411
  const rect = (range ?? element).getBoundingClientRect();
412
- draftAnchor = anchor;
413
- draftElement = element;
414
- draftResolution = {
415
- status: "attached",
416
- element,
417
- ...range ? { range } : {}
412
+ selection = {
413
+ kind: "draft",
414
+ anchor,
415
+ resolution: {
416
+ status: "attached",
417
+ element,
418
+ ...range ? { range } : {}
419
+ }
418
420
  };
419
421
  hoveredElement = null;
420
422
  void finishAnchor(anchor).then((prepared) => report(prepared, rect));
421
423
  schedulePaint();
422
424
  };
423
425
  const clearDraft = () => {
424
- draftAnchor = null;
425
- draftResolution = null;
426
- draftElement = null;
426
+ if (selection?.kind === "draft") {
427
+ selection = null;
428
+ }
427
429
  };
428
430
  const refreshSelectionPrompt = () => {
429
431
  selectionTimer = null;
@@ -595,12 +597,12 @@ function createCommentsOverlay(options) {
595
597
  if (event.key !== "Escape") {
596
598
  return;
597
599
  }
598
- if (mode === "comment" || draftAnchor) {
600
+ if (mode === "comment" || selection?.kind === "draft") {
599
601
  if (mode === "comment") {
600
602
  event.preventDefault();
601
603
  event.stopImmediatePropagation();
602
604
  }
603
- if (draftAnchor) {
605
+ if (selection?.kind === "draft") {
604
606
  clearDraft();
605
607
  options.onPickCancelled();
606
608
  schedulePaint();
@@ -713,7 +715,9 @@ function createCommentsOverlay(options) {
713
715
  mode = nextMode;
714
716
  selectionPrompt = null;
715
717
  hoveredElement = null;
716
- focusedThreadId = null;
718
+ if (selection?.kind === "thread") {
719
+ selection = null;
720
+ }
717
721
  setCursor(nextMode, previousMode);
718
722
  if (previousMode === "comment") {
719
723
  window.getSelection()?.removeAllRanges();
@@ -731,7 +735,7 @@ function createCommentsOverlay(options) {
731
735
  resolveAll();
732
736
  },
733
737
  focusThread: (threadId) => {
734
- focusedThreadId = threadId;
738
+ selection = { kind: "thread", threadId };
735
739
  const resolution = resolutions.get(threadId);
736
740
  const target = resolution?.range?.startContainer.parentElement ?? resolution?.element ?? null;
737
741
  if (resolution && isResolutionVisible(resolution)) {
@@ -748,7 +752,11 @@ function createCommentsOverlay(options) {
748
752
  schedulePaint();
749
753
  },
750
754
  setDraftAnchor: (anchor) => {
751
- draftAnchor = anchor?.type === "element" ? anchor : null;
755
+ if (anchor?.type === "element") {
756
+ selection = { kind: "draft", anchor, resolution: null };
757
+ } else {
758
+ clearDraft();
759
+ }
752
760
  resolveAll();
753
761
  },
754
762
  refresh: resolveAll,
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@replohq/sandbox-runtime",
3
- "version": "1.24.1",
3
+ "version": "1.24.2",
4
4
  "reploBuild": {
5
5
  "packageName": "@replohq/sandbox-runtime",
6
- "version": "1.24.1",
6
+ "version": "1.24.2",
7
7
  "branch": "HEAD",
8
- "commit": "043ae54a4a52039285aac996cc7b2b67a922dfdd",
9
- "builtAt": "2026-11-03T00:13:53.913Z"
8
+ "commit": "a3a1a0505f42cea89e63bbfa5628b1d35558fc76",
9
+ "builtAt": "2026-11-03T19:15:42.310Z"
10
10
  },
11
11
  "description": "Replo sandbox runtime — editor integration for agent-built Next.js sites.",
12
12
  "license": "SEE LICENSE IN LICENSE",