@replohq/sandbox-runtime 1.6.8 → 1.7.1

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 (29) hide show
  1. package/_vendor/replo-utils/lib/viewportSnapshot.d.ts +28 -7
  2. package/_vendor/replo-utils/lib/viewportSnapshot.mjs +1 -1
  3. package/_vendor/replo-utils/react/use-viewport-snapshot-responder.d.ts +2 -3
  4. package/_vendor/replo-utils/react/use-viewport-snapshot-responder.mjs +18 -2
  5. package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +1 -0
  6. package/_vendor/schemas/selectModeIframeRpc.d.ts +2 -0
  7. package/_vendor/schemas/selectModeIframeRpc.mjs +11 -6
  8. package/buildMetadata.js +3 -3
  9. package/{chunk-RXYLMSNM.mjs → chunk-3YA3QXUQ.mjs} +27 -9
  10. package/package.json +4 -4
  11. package/select-mode/hooks/useEditModeStateMachine.js +14 -22
  12. package/select-mode/hooks/useEditModeStateMachine.js.map +2 -2
  13. package/select-mode/hooks/useParentMessaging.d.ts +4 -1
  14. package/select-mode/hooks/useParentMessaging.js +2 -2
  15. package/select-mode/hooks/useParentMessaging.js.map +2 -2
  16. package/select-mode/hooks/useSelectModeController.d.ts +4 -1
  17. package/select-mode/hooks/useSelectModeController.js +27 -2
  18. package/select-mode/hooks/useSelectModeController.js.map +2 -2
  19. package/select-mode/hooks/useSelectionInteractions.js +153 -53
  20. package/select-mode/hooks/useSelectionInteractions.js.map +2 -2
  21. package/select-mode/interactions/selectionGeometry.d.ts +25 -0
  22. package/select-mode/interactions/selectionGeometry.js +83 -1
  23. package/select-mode/interactions/selectionGeometry.js.map +2 -2
  24. package/select-mode/selectModeSession.d.ts +9 -1
  25. package/select-mode/selectModeSession.js +15 -1
  26. package/select-mode/selectModeSession.js.map +2 -2
  27. package/select-mode/selectionFrame.d.ts +7 -0
  28. package/select-mode/selectionFrame.js +20 -0
  29. package/select-mode/selectionFrame.js.map +2 -2
@@ -1,5 +1,9 @@
1
1
  import type { SelectableData, SelectModeBoundingRect, SelectModeClickPosition, SelectModeSelectionType } from "../_vendor/schemas/generated/selectMode";
2
2
  import type { DragPosition, ScrollOffset } from "./interactions/selectionGeometry";
3
+ export type SelectModeAreaItem = {
4
+ data: SelectableData;
5
+ element: Element;
6
+ };
3
7
  export type SelectModeInteractionSession = {
4
8
  type: Extract<SelectModeSelectionType, "none">;
5
9
  } | {
@@ -17,6 +21,10 @@ export type SelectModeInteractionSession = {
17
21
  } | {
18
22
  type: Extract<SelectModeSelectionType, "area">;
19
23
  pageRect: SelectModeBoundingRect;
20
- items: SelectableData[];
24
+ items: SelectModeAreaItem[];
21
25
  };
22
26
  export declare const IDLE_SESSION: SelectModeInteractionSession;
27
+ export declare function getConnectedSelectedElement({ data, element, }: {
28
+ data: SelectableData;
29
+ element: Element;
30
+ }): Element | null;
@@ -1,7 +1,21 @@
1
1
  const IDLE_SESSION = {
2
2
  type: "none"
3
3
  };
4
+ function getConnectedSelectedElement({
5
+ data,
6
+ element
7
+ }) {
8
+ if (element.isConnected) {
9
+ return element;
10
+ }
11
+ if (data.kind !== "react-element") {
12
+ return null;
13
+ }
14
+ const resolved = document.querySelector(data.selector);
15
+ return resolved instanceof Element ? resolved : null;
16
+ }
4
17
  export {
5
- IDLE_SESSION
18
+ IDLE_SESSION,
19
+ getConnectedSelectedElement
6
20
  };
7
21
  //# sourceMappingURL=selectModeSession.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../select-mode/selectModeSession.ts"],
4
- "sourcesContent": ["import type {\n SelectableData,\n SelectModeBoundingRect,\n SelectModeClickPosition,\n SelectModeSelectionType,\n} from \"schemas/generated/selectMode\";\nimport type {\n DragPosition,\n ScrollOffset,\n} from \"./interactions/selectionGeometry\";\n\n// NOTE (Kevin O'Connell, 2026-04-22, REPL-26014): SDK-internal liveness\n// state for the active drag/select interaction. Looks like a near-\n// duplicate of agent-ui's `SelectModeSelection` (now in\n// `schemas/selectMode.ts`), but deliberately not lifted into\n// `packages/schemas` for two reasons:\n//\n// 1. The `element` variant carries `element: Element` \u2014 a live DOM\n// ref. Zod has no way to model that; `z.custom<Element>()` would\n// regress to `any` in the generated `.ts` (see the `ZodCustom`\n// branch in `packages/schemas/zod/generateTypeDefinition.ts`),\n// which would lose the strong typing the rest of the SDK relies\n// on when it reads `session.element.getBoundingClientRect()`,\n// etc.\n// 2. There is no second consumer. This type is used only inside\n// `packages/sandbox-runtime/select-mode/`; the parent side\n// (agent-ui) consumes the serialized `SelectModeSelection`\n// instead. Lifting it would move a single-package-internal type\n// into a shared package without any cross-package reader.\n//\n// What we *do* share with the schema is the discriminator vocabulary:\n// the literals come from `SelectModeSelectionType` (generated from\n// `selectModeSelectionTypeSchema` in `schemas/selectMode.ts`), so\n// adding or renaming a selection variant is a TS error here, in\n// `SelectModeSelection`, and in `SelectModeEditSelectionMetadata`.\nexport type SelectModeInteractionSession =\n | { type: Extract<SelectModeSelectionType, \"none\"> }\n | {\n type: Extract<SelectModeSelectionType, \"drag\">;\n dragStart: DragPosition;\n dragCurrent: DragPosition;\n scrollOffset: ScrollOffset;\n hasExceededThreshold: boolean;\n }\n | {\n type: Extract<SelectModeSelectionType, \"element\">;\n element: Element;\n // Live members of the element's repetition group, resolved via fiber\n // traversal at commit time. Kept as DOM refs so scroll sync can\n // re-measure them directly instead of re-resolving CSS selectors\n // against a possibly-mutated document on every frame.\n siblingElements: HTMLElement[];\n clickPosition: SelectModeClickPosition | null;\n data: SelectableData;\n }\n | {\n type: Extract<SelectModeSelectionType, \"area\">;\n pageRect: SelectModeBoundingRect;\n items: SelectableData[];\n };\n\nexport const IDLE_SESSION: SelectModeInteractionSession = {\n type: \"none\",\n};\n"],
5
- "mappings": "AA6DO,MAAM,eAA6C;AAAA,EACxD,MAAM;AACR;",
4
+ "sourcesContent": ["import type {\n SelectableData,\n SelectModeBoundingRect,\n SelectModeClickPosition,\n SelectModeSelectionType,\n} from \"schemas/generated/selectMode\";\nimport type {\n DragPosition,\n ScrollOffset,\n} from \"./interactions/selectionGeometry\";\n\n// NOTE (Kevin O'Connell, 2026-04-22, REPL-26014): SDK-internal liveness\n// state for the active drag/select interaction. Looks like a near-\n// duplicate of agent-ui's `SelectModeSelection` (now in\n// `schemas/selectMode.ts`), but deliberately not lifted into\n// `packages/schemas` for two reasons:\n//\n// 1. The `element` variant carries `element: Element` \u2014 a live DOM\n// ref. Zod has no way to model that; `z.custom<Element>()` would\n// regress to `any` in the generated `.ts` (see the `ZodCustom`\n// branch in `packages/schemas/zod/generateTypeDefinition.ts`),\n// which would lose the strong typing the rest of the SDK relies\n// on when it reads `session.element.getBoundingClientRect()`,\n// etc.\n// 2. There is no second consumer. This type is used only inside\n// `packages/sandbox-runtime/select-mode/`; the parent side\n// (agent-ui) consumes the serialized `SelectModeSelection`\n// instead. Lifting it would move a single-package-internal type\n// into a shared package without any cross-package reader.\n//\n// What we *do* share with the schema is the discriminator vocabulary:\n// the literals come from `SelectModeSelectionType` (generated from\n// `selectModeSelectionTypeSchema` in `schemas/selectMode.ts`), so\n// adding or renaming a selection variant is a TS error here, in\n// `SelectModeSelection`, and in `SelectModeEditSelectionMetadata`.\nexport type SelectModeAreaItem = {\n data: SelectableData;\n element: Element;\n};\n\nexport type SelectModeInteractionSession =\n | { type: Extract<SelectModeSelectionType, \"none\"> }\n | {\n type: Extract<SelectModeSelectionType, \"drag\">;\n dragStart: DragPosition;\n dragCurrent: DragPosition;\n scrollOffset: ScrollOffset;\n hasExceededThreshold: boolean;\n }\n | {\n type: Extract<SelectModeSelectionType, \"element\">;\n element: Element;\n // Live members of the element's repetition group, resolved via fiber\n // traversal at commit time. Kept as DOM refs so scroll sync can\n // re-measure them directly instead of re-resolving CSS selectors\n // against a possibly-mutated document on every frame.\n siblingElements: HTMLElement[];\n clickPosition: SelectModeClickPosition | null;\n data: SelectableData;\n }\n | {\n type: Extract<SelectModeSelectionType, \"area\">;\n pageRect: SelectModeBoundingRect;\n items: SelectModeAreaItem[];\n };\n\nexport const IDLE_SESSION: SelectModeInteractionSession = {\n type: \"none\",\n};\n\nexport function getConnectedSelectedElement({\n data,\n element,\n}: {\n data: SelectableData;\n element: Element;\n}): Element | null {\n if (element.isConnected) {\n return element;\n }\n if (data.kind !== \"react-element\") {\n return null;\n }\n const resolved = document.querySelector(data.selector);\n return resolved instanceof Element ? resolved : null;\n}\n"],
5
+ "mappings": "AAkEO,MAAM,eAA6C;AAAA,EACxD,MAAM;AACR;AAEO,SAAS,4BAA4B;AAAA,EAC1C;AAAA,EACA;AACF,GAGmB;AACjB,MAAI,QAAQ,aAAa;AACvB,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,iBAAiB;AACjC,WAAO;AAAA,EACT;AACA,QAAM,WAAW,SAAS,cAAc,KAAK,QAAQ;AACrD,SAAO,oBAAoB,UAAU,WAAW;AAClD;",
6
6
  "names": []
7
7
  }
@@ -70,6 +70,13 @@ export declare function showElementSelectionFrames({ elements, scrollOffset, }:
70
70
  top: number;
71
71
  };
72
72
  }): void;
73
+ export declare function showAreaSelectionFrames({ elements, scrollOffset, }: {
74
+ elements: Element[];
75
+ scrollOffset: {
76
+ left: number;
77
+ top: number;
78
+ };
79
+ }): void;
73
80
  /**
74
81
  * @author Kevin O'Connell 2026-05-26
75
82
  */
@@ -126,6 +126,25 @@ function showElementSelectionFrames({
126
126
  })
127
127
  });
128
128
  }
129
+ function showAreaSelectionFrames({
130
+ elements,
131
+ scrollOffset
132
+ }) {
133
+ showSelectionFrames({
134
+ frames: elements.map((element) => {
135
+ const rect = element.getBoundingClientRect();
136
+ return {
137
+ variant: "area",
138
+ pageRect: {
139
+ x: rect.left + scrollOffset.left,
140
+ y: rect.top + scrollOffset.top,
141
+ width: rect.width,
142
+ height: rect.height
143
+ }
144
+ };
145
+ })
146
+ });
147
+ }
129
148
  function hideSelectionFrame() {
130
149
  if (typeof document === "undefined") {
131
150
  return;
@@ -139,6 +158,7 @@ export {
139
158
  getOrCreateFramesLayerContainer,
140
159
  hideSelectionFrame,
141
160
  setSelectionFrameEditing,
161
+ showAreaSelectionFrames,
142
162
  showElementSelectionFrames,
143
163
  showSelectionFrames
144
164
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../select-mode/selectionFrame.ts"],
4
- "sourcesContent": ["/**\n * In-iframe selection frame renderer.\n *\n * Lives in the canopy iframe (not in agent-ui) because the previous\n * parent-side overlay had to be re-anchored on every scroll frame via\n * postMessage hop -> Zustand update -> React reconciliation, which\n * shows up as visible lag when the user scrolls quickly.\n *\n * By rendering directly inside the canopy iframe's document we get two\n * properties for free:\n *\n * 1. `position: absolute` + page coordinates means the document's own\n * scroll naturally translates the frames \u2014 zero JavaScript per\n * scroll frame, the browser composites them with the underlying page\n * content.\n * 2. No bridge serialization: the only cost when selection commits is\n * a handful of style writes on the frame nodes.\n *\n * A click resolves to one frame per repeated element; an area drag resolves\n * to one frame per captured element. The renderer keeps a pool of nodes under\n * a shared container and reconciles it on each call.\n *\n * The canopy iframe loads a customer page and doesn't include lattice /\n * tailwind, so styling is intentionally vanilla inline CSS rather than\n * Tailwind classes.\n *\n * @author Noah Gilmore 2026-07-26\n */\n\n// Matches `--color-fuchsia` (Tailwind v4 `fuchsia-600`) used by agent-ui\n// so the in-iframe frame is visually consistent with the rest of the\n// select-mode UI.\nconst FUCHSIA_HEX = \"#c026d3\";\n\n// Brighter fuchsia (`fuchsia-400`) used while a text block is being inline\n// edited, so the active edit target stands out from a plain selection.\nconst EDITING_FUCHSIA_HEX = \"#e879f9\";\n\nconst FRAMES_CONTAINER_ID = \"replo-select-mode-selection-frames\";\n\n// Whether an inline text edit is in progress. Module-level so every frame\n// redraw (including the scroll-sync hot path) picks up the brighter color\n// without threading the flag through each call.\nlet isEditing = false;\n\nfunction getFrameBorderHex(): string {\n return isEditing ? EDITING_FUCHSIA_HEX : FUCHSIA_HEX;\n}\n\ntype SelectionFrameVariant = \"element\" | \"area\";\n\ntype SelectionFramePageRect = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\ntype SelectionFrameSpec = {\n pageRect: SelectionFramePageRect;\n variant: SelectionFrameVariant;\n};\n\nfunction applyVariantStyle({\n frame,\n variant,\n}: {\n frame: HTMLDivElement;\n variant: SelectionFrameVariant;\n}) {\n // Both variants use the same bright fuchsia border so a single click and\n // each member of an area selection read as equally \"selected\"; the area\n // members carry a faint fill so a cluster still reads as a group. While\n // inline editing, the border brightens to mark the active edit target.\n frame.style.border = `2px solid ${getFrameBorderHex()}`;\n frame.style.background =\n variant === \"area\" ? \"rgba(192, 38, 211, 0.08)\" : \"transparent\";\n}\n\n/**\n * Toggle the brighter inline-edit border and re-color any frames already on\n * screen so the change is immediate, not deferred to the next redraw.\n */\nexport function setSelectionFrameEditing(editing: boolean) {\n if (isEditing === editing) {\n return;\n }\n isEditing = editing;\n if (typeof document === \"undefined\") {\n return;\n }\n const container = document.getElementById(FRAMES_CONTAINER_ID);\n if (!(container instanceof HTMLDivElement)) {\n return;\n }\n for (const child of container.children) {\n if (child instanceof HTMLDivElement) {\n child.style.borderColor = getFrameBorderHex();\n }\n }\n}\n\n/**\n * Shared body-level layer container for in-iframe editor overlays (selection\n * frames, annotation frames). Zero-size and pointer-transparent so it never\n * affects the page; children opt into pointer events individually.\n */\nexport function getOrCreateFramesLayerContainer({\n id,\n zIndex,\n}: {\n id: string;\n zIndex: number;\n}): HTMLDivElement | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const existing = document.getElementById(id);\n if (existing instanceof HTMLDivElement) {\n return existing;\n }\n if (!document.body) {\n return null;\n }\n const container = document.createElement(\"div\");\n container.id = id;\n container.setAttribute(\"aria-hidden\", \"true\");\n container.style.cssText = [\n \"position: absolute\",\n \"top: 0\",\n \"left: 0\",\n \"width: 0\",\n \"height: 0\",\n \"margin: 0\",\n \"padding: 0\",\n \"pointer-events: none\",\n `z-index: ${zIndex}`,\n ].join(\";\");\n document.body.append(container);\n return container;\n}\n\nfunction getOrCreateContainer(): HTMLDivElement | null {\n return getOrCreateFramesLayerContainer({\n id: FRAMES_CONTAINER_ID,\n zIndex: 2147483646,\n });\n}\n\nfunction createFrameNode(): HTMLDivElement {\n const frame = document.createElement(\"div\");\n frame.setAttribute(\"aria-hidden\", \"true\");\n frame.style.cssText = [\n \"position: absolute\",\n \"top: 0\",\n \"left: 0\",\n \"box-sizing: border-box\",\n \"border-radius: 2px\",\n \"pointer-events: none\",\n \"margin: 0\",\n \"padding: 0\",\n ].join(\";\");\n return frame;\n}\n\n/**\n * Position selection frames at the given *page* coordinates, one node per\n * spec. Page coords don't shift during scroll, so the caller is free to\n * call this once at commit time and let the browser handle the rest of the\n * scroll lifetime. Reconciles the node pool against `frames.length` so group\n * updates reuse the existing nodes when the repetition count stays stable.\n *\n * @author Noah Gilmore 2026-07-26\n */\nexport function showSelectionFrames({\n frames,\n}: {\n frames: SelectionFrameSpec[];\n}) {\n const container = getOrCreateContainer();\n if (!container) {\n return;\n }\n\n while (container.childElementCount > frames.length) {\n container.lastElementChild?.remove();\n }\n while (container.childElementCount < frames.length) {\n container.append(createFrameNode());\n }\n\n frames.forEach((spec, index) => {\n const frame = container.children[index];\n if (!(frame instanceof HTMLDivElement)) {\n return;\n }\n applyVariantStyle({ frame, variant: spec.variant });\n frame.style.left = `${spec.pageRect.x}px`;\n frame.style.top = `${spec.pageRect.y}px`;\n frame.style.width = `${spec.pageRect.width}px`;\n frame.style.height = `${spec.pageRect.height}px`;\n });\n}\n\nexport function showElementSelectionFrames({\n elements,\n scrollOffset,\n}: {\n elements: Element[];\n scrollOffset: { left: number; top: number };\n}) {\n showSelectionFrames({\n frames: elements.map((element) => {\n const rect = element.getBoundingClientRect();\n return {\n variant: \"element\",\n pageRect: {\n x: rect.left + scrollOffset.left,\n y: rect.top + scrollOffset.top,\n width: rect.width,\n height: rect.height,\n },\n };\n }),\n });\n}\n\n/**\n * @author Kevin O'Connell 2026-05-26\n */\nexport function hideSelectionFrame() {\n if (typeof document === \"undefined\") {\n return;\n }\n const container = document.getElementById(FRAMES_CONTAINER_ID);\n if (container instanceof HTMLDivElement) {\n container.replaceChildren();\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * In-iframe selection frame renderer.\n *\n * Lives in the canopy iframe (not in agent-ui) because the previous\n * parent-side overlay had to be re-anchored on every scroll frame via\n * postMessage hop -> Zustand update -> React reconciliation, which\n * shows up as visible lag when the user scrolls quickly.\n *\n * By rendering directly inside the canopy iframe's document we get two\n * properties for free:\n *\n * 1. `position: absolute` + page coordinates means the document's own\n * scroll naturally translates the frames \u2014 zero JavaScript per\n * scroll frame, the browser composites them with the underlying page\n * content.\n * 2. No bridge serialization: the only cost when selection commits is\n * a handful of style writes on the frame nodes.\n *\n * A click resolves to one frame per repeated element; an area drag resolves\n * to one frame per captured element. The renderer keeps a pool of nodes under\n * a shared container and reconciles it on each call.\n *\n * The canopy iframe loads a customer page and doesn't include lattice /\n * tailwind, so styling is intentionally vanilla inline CSS rather than\n * Tailwind classes.\n *\n * @author Noah Gilmore 2026-07-26\n */\n\n// Matches `--color-fuchsia` (Tailwind v4 `fuchsia-600`) used by agent-ui\n// so the in-iframe frame is visually consistent with the rest of the\n// select-mode UI.\nconst FUCHSIA_HEX = \"#c026d3\";\n\n// Brighter fuchsia (`fuchsia-400`) used while a text block is being inline\n// edited, so the active edit target stands out from a plain selection.\nconst EDITING_FUCHSIA_HEX = \"#e879f9\";\n\nconst FRAMES_CONTAINER_ID = \"replo-select-mode-selection-frames\";\n\n// Whether an inline text edit is in progress. Module-level so every frame\n// redraw (including the scroll-sync hot path) picks up the brighter color\n// without threading the flag through each call.\nlet isEditing = false;\n\nfunction getFrameBorderHex(): string {\n return isEditing ? EDITING_FUCHSIA_HEX : FUCHSIA_HEX;\n}\n\ntype SelectionFrameVariant = \"element\" | \"area\";\n\ntype SelectionFramePageRect = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\ntype SelectionFrameSpec = {\n pageRect: SelectionFramePageRect;\n variant: SelectionFrameVariant;\n};\n\nfunction applyVariantStyle({\n frame,\n variant,\n}: {\n frame: HTMLDivElement;\n variant: SelectionFrameVariant;\n}) {\n // Both variants use the same bright fuchsia border so a single click and\n // each member of an area selection read as equally \"selected\"; the area\n // members carry a faint fill so a cluster still reads as a group. While\n // inline editing, the border brightens to mark the active edit target.\n frame.style.border = `2px solid ${getFrameBorderHex()}`;\n frame.style.background =\n variant === \"area\" ? \"rgba(192, 38, 211, 0.08)\" : \"transparent\";\n}\n\n/**\n * Toggle the brighter inline-edit border and re-color any frames already on\n * screen so the change is immediate, not deferred to the next redraw.\n */\nexport function setSelectionFrameEditing(editing: boolean) {\n if (isEditing === editing) {\n return;\n }\n isEditing = editing;\n if (typeof document === \"undefined\") {\n return;\n }\n const container = document.getElementById(FRAMES_CONTAINER_ID);\n if (!(container instanceof HTMLDivElement)) {\n return;\n }\n for (const child of container.children) {\n if (child instanceof HTMLDivElement) {\n child.style.borderColor = getFrameBorderHex();\n }\n }\n}\n\n/**\n * Shared body-level layer container for in-iframe editor overlays (selection\n * frames, annotation frames). Zero-size and pointer-transparent so it never\n * affects the page; children opt into pointer events individually.\n */\nexport function getOrCreateFramesLayerContainer({\n id,\n zIndex,\n}: {\n id: string;\n zIndex: number;\n}): HTMLDivElement | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const existing = document.getElementById(id);\n if (existing instanceof HTMLDivElement) {\n return existing;\n }\n if (!document.body) {\n return null;\n }\n const container = document.createElement(\"div\");\n container.id = id;\n container.setAttribute(\"aria-hidden\", \"true\");\n container.style.cssText = [\n \"position: absolute\",\n \"top: 0\",\n \"left: 0\",\n \"width: 0\",\n \"height: 0\",\n \"margin: 0\",\n \"padding: 0\",\n \"pointer-events: none\",\n `z-index: ${zIndex}`,\n ].join(\";\");\n document.body.append(container);\n return container;\n}\n\nfunction getOrCreateContainer(): HTMLDivElement | null {\n return getOrCreateFramesLayerContainer({\n id: FRAMES_CONTAINER_ID,\n zIndex: 2147483646,\n });\n}\n\nfunction createFrameNode(): HTMLDivElement {\n const frame = document.createElement(\"div\");\n frame.setAttribute(\"aria-hidden\", \"true\");\n frame.style.cssText = [\n \"position: absolute\",\n \"top: 0\",\n \"left: 0\",\n \"box-sizing: border-box\",\n \"border-radius: 2px\",\n \"pointer-events: none\",\n \"margin: 0\",\n \"padding: 0\",\n ].join(\";\");\n return frame;\n}\n\n/**\n * Position selection frames at the given *page* coordinates, one node per\n * spec. Page coords don't shift during scroll, so the caller is free to\n * call this once at commit time and let the browser handle the rest of the\n * scroll lifetime. Reconciles the node pool against `frames.length` so group\n * updates reuse the existing nodes when the repetition count stays stable.\n *\n * @author Noah Gilmore 2026-07-26\n */\nexport function showSelectionFrames({\n frames,\n}: {\n frames: SelectionFrameSpec[];\n}) {\n const container = getOrCreateContainer();\n if (!container) {\n return;\n }\n\n while (container.childElementCount > frames.length) {\n container.lastElementChild?.remove();\n }\n while (container.childElementCount < frames.length) {\n container.append(createFrameNode());\n }\n\n frames.forEach((spec, index) => {\n const frame = container.children[index];\n if (!(frame instanceof HTMLDivElement)) {\n return;\n }\n applyVariantStyle({ frame, variant: spec.variant });\n frame.style.left = `${spec.pageRect.x}px`;\n frame.style.top = `${spec.pageRect.y}px`;\n frame.style.width = `${spec.pageRect.width}px`;\n frame.style.height = `${spec.pageRect.height}px`;\n });\n}\n\nexport function showElementSelectionFrames({\n elements,\n scrollOffset,\n}: {\n elements: Element[];\n scrollOffset: { left: number; top: number };\n}) {\n showSelectionFrames({\n frames: elements.map((element) => {\n const rect = element.getBoundingClientRect();\n return {\n variant: \"element\",\n pageRect: {\n x: rect.left + scrollOffset.left,\n y: rect.top + scrollOffset.top,\n width: rect.width,\n height: rect.height,\n },\n };\n }),\n });\n}\n\nexport function showAreaSelectionFrames({\n elements,\n scrollOffset,\n}: {\n elements: Element[];\n scrollOffset: { left: number; top: number };\n}) {\n showSelectionFrames({\n frames: elements.map((element) => {\n const rect = element.getBoundingClientRect();\n return {\n variant: \"area\",\n pageRect: {\n x: rect.left + scrollOffset.left,\n y: rect.top + scrollOffset.top,\n width: rect.width,\n height: rect.height,\n },\n };\n }),\n });\n}\n\n/**\n * @author Kevin O'Connell 2026-05-26\n */\nexport function hideSelectionFrame() {\n if (typeof document === \"undefined\") {\n return;\n }\n const container = document.getElementById(FRAMES_CONTAINER_ID);\n if (container instanceof HTMLDivElement) {\n container.replaceChildren();\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }