@replohq/sandbox-runtime 1.6.1 → 1.6.3

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.
@@ -1,4 +1,8 @@
1
- import type { DisplayMode, SelectModeSelectionType, SelectModeOptimisticUpdatePayload, SelectModeFormatCommand, SelectableData, SelectModeBoundingRect, SelectModeClickPosition, SelectModeSelectionRect, SelectModeTiptapActiveMarks } from "./selectMode";
1
+ import type { SelectedElement, DisplayMode, SelectModeSelectionType, SelectModeOptimisticUpdatePayload, SelectModeFormatCommand, SelectableData, SelectModeBoundingRect, SelectModeClickPosition, SelectModeSelectionRect, SelectModeTiptapActiveMarks } from "./selectMode";
2
+ export type SelectedComponentEditRequest = {
3
+ siteId: string;
4
+ element: SelectedElement;
5
+ };
2
6
  export type IframeRuntimeBuildMetadata = {
3
7
  packageName: string;
4
8
  version: string;
@@ -7,6 +11,9 @@ export type IframeRuntimeBuildMetadata = {
7
11
  builtAt: string | null;
8
12
  };
9
13
  export type SelectModeParentMessage = {
14
+ method: "editSelectedComponent";
15
+ data: SelectedComponentEditRequest;
16
+ } | {
10
17
  method: "setDisplayMode";
11
18
  data: {
12
19
  displayMode: DisplayMode;
@@ -9,6 +9,68 @@ export declare const iframeRuntimeBuildMetadataSchema: z.ZodObject<{
9
9
  commit: z.ZodNullable<z.ZodString>;
10
10
  builtAt: z.ZodNullable<z.ZodString>;
11
11
  }, z.core.$strip>;
12
+ export declare const selectedComponentEditRequestSchema: z.ZodObject<{
13
+ siteId: z.ZodUUID;
14
+ element: z.ZodObject<{
15
+ kind: z.ZodLiteral<"react-element">;
16
+ selector: z.ZodString;
17
+ tagName: z.ZodString;
18
+ elementType: z.ZodString;
19
+ textContent: z.ZodNullable<z.ZodString>;
20
+ rect: z.ZodObject<{
21
+ x: z.ZodNumber;
22
+ y: z.ZodNumber;
23
+ left: z.ZodNumber;
24
+ top: z.ZodNumber;
25
+ right: z.ZodNumber;
26
+ bottom: z.ZodNumber;
27
+ width: z.ZodNumber;
28
+ height: z.ZodNumber;
29
+ }, z.core.$strip>;
30
+ textMetrics: z.ZodNullable<z.ZodObject<{
31
+ tightWidth: z.ZodNumber;
32
+ lineCount: z.ZodNumber;
33
+ lineHeight: z.ZodNumber;
34
+ }, z.core.$strip>>;
35
+ outerHTML: z.ZodString;
36
+ definedStyles: z.ZodDefault<z.ZodArray<z.ZodObject<{
37
+ property: z.ZodString;
38
+ variant: z.ZodNullable<z.ZodObject<{
39
+ atRules: z.ZodArray<z.ZodObject<{
40
+ type: z.ZodString;
41
+ text: z.ZodString;
42
+ }, z.core.$strip>>;
43
+ pseudo: z.ZodNullable<z.ZodString>;
44
+ }, z.core.$strip>>;
45
+ className: z.ZodNullable<z.ZodString>;
46
+ raw: z.ZodString;
47
+ resolved: z.ZodString;
48
+ }, z.core.$strip>>>;
49
+ inheritedStyles: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
50
+ clickPosition: z.ZodObject<{
51
+ x: z.ZodNumber;
52
+ y: z.ZodNumber;
53
+ }, z.core.$strip>;
54
+ sourceLocation: z.ZodOptional<z.ZodObject<{
55
+ filePath: z.ZodString;
56
+ lineNumber: z.ZodNumber;
57
+ columnNumber: z.ZodOptional<z.ZodNumber>;
58
+ componentName: z.ZodOptional<z.ZodString>;
59
+ }, z.core.$strip>>;
60
+ fiberChain: z.ZodDefault<z.ZodArray<z.ZodObject<{
61
+ sourceLocation: z.ZodObject<{
62
+ filePath: z.ZodString;
63
+ lineNumber: z.ZodNumber;
64
+ columnNumber: z.ZodOptional<z.ZodNumber>;
65
+ componentName: z.ZodOptional<z.ZodString>;
66
+ }, z.core.$strip>;
67
+ tagName: z.ZodOptional<z.ZodString>;
68
+ componentName: z.ZodOptional<z.ZodString>;
69
+ props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
70
+ }, z.core.$strip>>>;
71
+ siblingSelectors: z.ZodDefault<z.ZodArray<z.ZodString>>;
72
+ }, z.core.$strip>;
73
+ }, z.core.$strip>;
12
74
  export declare const websiteBuilderToCanopyMethodConfig: {
13
75
  symbolicateSelectedElement: {
14
76
  inputSchema: z.ZodObject<{
@@ -572,6 +634,70 @@ export declare const canopyToWebsiteBuilderMethodConfig: {
572
634
  };
573
635
  };
574
636
  export declare const selectModeParentMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
637
+ method: z.ZodLiteral<"editSelectedComponent">;
638
+ data: z.ZodObject<{
639
+ siteId: z.ZodUUID;
640
+ element: z.ZodObject<{
641
+ kind: z.ZodLiteral<"react-element">;
642
+ selector: z.ZodString;
643
+ tagName: z.ZodString;
644
+ elementType: z.ZodString;
645
+ textContent: z.ZodNullable<z.ZodString>;
646
+ rect: z.ZodObject<{
647
+ x: z.ZodNumber;
648
+ y: z.ZodNumber;
649
+ left: z.ZodNumber;
650
+ top: z.ZodNumber;
651
+ right: z.ZodNumber;
652
+ bottom: z.ZodNumber;
653
+ width: z.ZodNumber;
654
+ height: z.ZodNumber;
655
+ }, z.core.$strip>;
656
+ textMetrics: z.ZodNullable<z.ZodObject<{
657
+ tightWidth: z.ZodNumber;
658
+ lineCount: z.ZodNumber;
659
+ lineHeight: z.ZodNumber;
660
+ }, z.core.$strip>>;
661
+ outerHTML: z.ZodString;
662
+ definedStyles: z.ZodDefault<z.ZodArray<z.ZodObject<{
663
+ property: z.ZodString;
664
+ variant: z.ZodNullable<z.ZodObject<{
665
+ atRules: z.ZodArray<z.ZodObject<{
666
+ type: z.ZodString;
667
+ text: z.ZodString;
668
+ }, z.core.$strip>>;
669
+ pseudo: z.ZodNullable<z.ZodString>;
670
+ }, z.core.$strip>>;
671
+ className: z.ZodNullable<z.ZodString>;
672
+ raw: z.ZodString;
673
+ resolved: z.ZodString;
674
+ }, z.core.$strip>>>;
675
+ inheritedStyles: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
676
+ clickPosition: z.ZodObject<{
677
+ x: z.ZodNumber;
678
+ y: z.ZodNumber;
679
+ }, z.core.$strip>;
680
+ sourceLocation: z.ZodOptional<z.ZodObject<{
681
+ filePath: z.ZodString;
682
+ lineNumber: z.ZodNumber;
683
+ columnNumber: z.ZodOptional<z.ZodNumber>;
684
+ componentName: z.ZodOptional<z.ZodString>;
685
+ }, z.core.$strip>>;
686
+ fiberChain: z.ZodDefault<z.ZodArray<z.ZodObject<{
687
+ sourceLocation: z.ZodObject<{
688
+ filePath: z.ZodString;
689
+ lineNumber: z.ZodNumber;
690
+ columnNumber: z.ZodOptional<z.ZodNumber>;
691
+ componentName: z.ZodOptional<z.ZodString>;
692
+ }, z.core.$strip>;
693
+ tagName: z.ZodOptional<z.ZodString>;
694
+ componentName: z.ZodOptional<z.ZodString>;
695
+ props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
696
+ }, z.core.$strip>>>;
697
+ siblingSelectors: z.ZodDefault<z.ZodArray<z.ZodString>>;
698
+ }, z.core.$strip>;
699
+ }, z.core.$strip>;
700
+ }, z.core.$strip>, z.ZodObject<{
575
701
  method: z.ZodLiteral<"setDisplayMode">;
576
702
  data: z.ZodObject<{
577
703
  displayMode: z.ZodEnum<{
@@ -1,4 +1,4 @@
1
- import { selectModeFormatCommandSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionTypeSchema, displayModeSchema, selectModeTiptapActiveMarksSchema, selectModeBoundingRectSchema, selectableDataSchema, selectModeSelectionRectSchema, selectModeClickPositionSchema, selectedElementSchema } from '../../chunk-UOBGRB5I.mjs';
1
+ import { selectedElementSchema, selectModeFormatCommandSchema, selectModeOptimisticUpdatePayloadSchema, selectModeSelectionTypeSchema, displayModeSchema, selectModeTiptapActiveMarksSchema, selectModeBoundingRectSchema, selectableDataSchema, selectModeSelectionRectSchema, selectModeClickPositionSchema } from '../../chunk-UOBGRB5I.mjs';
2
2
  import '../../chunk-JUKCUPQ6.mjs';
3
3
  import '../../chunk-FLYEIRFK.mjs';
4
4
  import '../../chunk-TESFJQID.mjs';
@@ -14,6 +14,10 @@ var iframeRuntimeBuildMetadataSchema = z.object({
14
14
  commit: z.string().nullable(),
15
15
  builtAt: z.string().nullable()
16
16
  }).describe("IframeRuntimeBuildMetadata");
17
+ var selectedComponentEditRequestSchema = z.object({
18
+ siteId: z.uuid(),
19
+ element: selectedElementSchema
20
+ }).describe("SelectedComponentEditRequest");
17
21
  var websiteBuilderToCanopyMethodConfig = {
18
22
  symbolicateSelectedElement: {
19
23
  inputSchema: selectedElementSchema,
@@ -158,6 +162,10 @@ var canopyToWebsiteBuilderMethodConfig = {
158
162
  }
159
163
  };
160
164
  var selectModeParentMessageSchema = z.discriminatedUnion("method", [
165
+ z.object({
166
+ method: z.literal("editSelectedComponent"),
167
+ data: selectedComponentEditRequestSchema
168
+ }),
161
169
  z.object({
162
170
  method: z.literal("setDisplayMode"),
163
171
  data: websiteBuilderToCanopyMethodConfig.setDisplayMode.inputSchema
@@ -235,4 +243,4 @@ var selectModeIframeMessageSchema = z.discriminatedUnion("method", [
235
243
  })
236
244
  ]).describe("SelectModeIframeMessage");
237
245
 
238
- export { SELECT_MODE_IFRAME_RPC_CHANNEL_ID, SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION, canopyToWebsiteBuilderMethodConfig, iframeRuntimeBuildMetadataSchema, selectModeIframeMessageSchema, selectModeParentMessageSchema, websiteBuilderToCanopyMethodConfig };
246
+ export { SELECT_MODE_IFRAME_RPC_CHANNEL_ID, SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION, canopyToWebsiteBuilderMethodConfig, iframeRuntimeBuildMetadataSchema, selectModeIframeMessageSchema, selectModeParentMessageSchema, selectedComponentEditRequestSchema, websiteBuilderToCanopyMethodConfig };
package/buildMetadata.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export const BUILD_METADATA = {
2
2
  "packageName": "@replohq/sandbox-runtime",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "branch": "HEAD",
5
- "commit": "8fe4f3856e244e9c0a553822d9b46a150ff1bb95",
6
- "builtAt": "2026-09-11T21:19:34.866Z"
5
+ "commit": "3a054dd649b4ff6bd4ec2ae3e9777849fea36097",
6
+ "builtAt": "2026-09-11T23:08:46.060Z"
7
7
  };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@replohq/sandbox-runtime",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "reploBuild": {
5
5
  "packageName": "@replohq/sandbox-runtime",
6
- "version": "1.6.1",
6
+ "version": "1.6.3",
7
7
  "branch": "HEAD",
8
- "commit": "8fe4f3856e244e9c0a553822d9b46a150ff1bb95",
9
- "builtAt": "2026-09-11T21:19:34.866Z"
8
+ "commit": "3a054dd649b4ff6bd4ec2ae3e9777849fea36097",
9
+ "builtAt": "2026-09-11T23:08:46.060Z"
10
10
  },
11
11
  "description": "Replo sandbox runtime — editor integration for agent-built Next.js sites.",
12
12
  "license": "SEE LICENSE IN LICENSE",
@@ -5,7 +5,7 @@ export interface DebugSource {
5
5
  }
6
6
  export interface ReactFiber {
7
7
  _debugStack?: unknown;
8
- _debugOwner?: ReactFiber;
8
+ _debugOwner?: ReactFiber | ReactServerOwner;
9
9
  type?: {
10
10
  name?: string;
11
11
  displayName?: string;
@@ -18,6 +18,12 @@ export interface ReactFiber {
18
18
  memoizedProps?: Record<string, unknown>;
19
19
  pendingProps?: Record<string, unknown>;
20
20
  }
21
+ interface ReactServerOwner {
22
+ name: string;
23
+ debugStack?: unknown;
24
+ owner?: ReactFiber | ReactServerOwner;
25
+ props?: Record<string, unknown>;
26
+ }
21
27
  export declare function getFiberFromElement(element: HTMLElement): ReactFiber | null;
22
28
  export declare function getComponentName(fiber: ReactFiber | null | undefined): string | undefined;
23
29
  export declare function findDebugSource(fiber: ReactFiber): {
@@ -42,3 +48,4 @@ export declare function getFiberChain(element: HTMLElement): {
42
48
  componentName: string | undefined;
43
49
  props: Record<string, unknown> | undefined;
44
50
  }[];
51
+ export {};
@@ -130,7 +130,9 @@ function findDebugSource(fiber) {
130
130
  let depth = 0;
131
131
  const maxDepth = 50;
132
132
  while (current && depth < maxDepth) {
133
- const debugStackSource = parseDebugStackSource(current._debugStack) ?? parseDebugStackSource(current._debugOwner?._debugStack);
133
+ const debugStackSource = parseDebugStackSource(current._debugStack) ?? parseDebugStackSource(
134
+ current._debugOwner && "_debugStack" in current._debugOwner ? current._debugOwner._debugStack : null
135
+ );
134
136
  if (debugStackSource) {
135
137
  return {
136
138
  source: debugStackSource,
@@ -423,6 +425,7 @@ function getFiberChain(element) {
423
425
  const rootFiber = getFiberFromElement(element);
424
426
  const fiberChain = [];
425
427
  const seenKeys = /* @__PURE__ */ new Set();
428
+ const seenOwners = /* @__PURE__ */ new Set();
426
429
  let currentFiber = rootFiber;
427
430
  let depth = 0;
428
431
  while (currentFiber && depth < MAX_FIBER_CHAIN_DEPTH) {
@@ -454,6 +457,39 @@ function getFiberChain(element) {
454
457
  });
455
458
  }
456
459
  }
460
+ let owner = currentFiber._debugOwner;
461
+ while (owner && seenOwners.size < MAX_FIBER_CHAIN_DEPTH && !seenOwners.has(owner)) {
462
+ seenOwners.add(owner);
463
+ if ("name" in owner) {
464
+ const ownerSource = parseDebugStackSource(owner.debugStack);
465
+ if (ownerSource) {
466
+ const key = [
467
+ ownerSource.fileName,
468
+ ownerSource.lineNumber,
469
+ ownerSource.columnNumber ?? "",
470
+ "",
471
+ owner.name
472
+ ].join(":");
473
+ if (!seenKeys.has(key)) {
474
+ seenKeys.add(key);
475
+ fiberChain.push({
476
+ sourceLocation: {
477
+ filePath: ownerSource.fileName,
478
+ lineNumber: ownerSource.lineNumber,
479
+ columnNumber: ownerSource.columnNumber,
480
+ componentName: owner.name
481
+ },
482
+ tagName: void 0,
483
+ componentName: owner.name,
484
+ props: getSerializableProps(owner.props)
485
+ });
486
+ }
487
+ }
488
+ owner = owner.owner;
489
+ } else {
490
+ owner = owner._debugOwner;
491
+ }
492
+ }
457
493
  currentFiber = currentFiber.return;
458
494
  depth += 1;
459
495
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../select-mode/fiber.ts"],
4
- "sourcesContent": ["// =============================================================================\n// React Fiber / Source Location Utilities\n// =============================================================================\n\nimport { z } from \"zod\";\n\nexport interface DebugSource {\n fileName: string;\n lineNumber: number;\n columnNumber?: number;\n}\n\nexport interface ReactFiber {\n _debugStack?: unknown;\n _debugOwner?: ReactFiber;\n type?:\n | { name?: string; displayName?: string }\n | string\n | ((...args: unknown[]) => unknown)\n | null;\n return?: ReactFiber | null;\n child?: ReactFiber | null;\n sibling?: ReactFiber | null;\n alternate?: ReactFiber | null;\n stateNode?: unknown;\n memoizedProps?: Record<string, unknown>;\n pendingProps?: Record<string, unknown>;\n}\n\nconst MAX_FIBER_CHAIN_DEPTH = 80;\nconst MAX_SERIALIZED_PROP_COUNT = 24;\nconst MAX_SERIALIZED_STRING_LENGTH = 500;\nconst MAX_SIBLING_SCAN = 5000;\nconst MAX_SUBTREE_SCAN = 5000;\nconst MAX_ROOT_CLIMB_DEPTH = 1000;\nconst MAX_CURRENT_TREE_SCAN = 50_000;\n\n// Frames produced by React's own JSX runtime \u2014 these come first in\n// `_debugStack.stack` because the `Error` is constructed inside `jsxDEV`. We\n// want the frame *above* them, which is the actual JSX call site.\n//\n// Turbopack rewrites `node_modules/next/dist/compiled/react-server-dom-*` and\n// friends into mangled chunk paths like\n// `_next/static/chunks/<hash>_next_dist_compiled_react-server-dom-turbopack_<hash>._.js`,\n// so we match both the human-readable module paths and the chunk-name forms.\n// Without this, `_debugStack`'s top frame inside React's RSC runtime gets\n// surfaced as the \"host\" source location for every text node on the page \u2014\n// which then symbolicates back to bundled React, not user code.\nconst REACT_INTERNAL_FRAME_PATTERNS = [\n /react.*jsx-dev-runtime/,\n /react.*jsx-runtime/,\n /react-dom\\//,\n /react\\/cjs\\/react\\./,\n /react-server-dom/,\n /react_server_dom/,\n /next[/_.]dist[/_.]compiled/,\n /\\/node_modules\\/(next|react|react-dom)\\//,\n];\n\nfunction isReactInternalFrame(fileName: string): boolean {\n return REACT_INTERNAL_FRAME_PATTERNS.some((pattern) => {\n return pattern.test(fileName);\n });\n}\n\n// React constructs the `_debugStack` Error inside its JSX runtime (`jsxDEV`,\n// `jsx`, `jsxs`), so those frames sit *above* the real JSX call site we want.\n// The file-based check above skips them when their path is recognizable, but\n// Turbopack mangles the client JSX-runtime chunk to an opaque name like\n// `node_modules__pnpm_<hash>._.js` (no \"react\"/\"jsx-dev-runtime\" substring),\n// so the top `jsxDEV` frame slips through and gets surfaced as the element's\n// source \u2014 which then symbolicates back to bundled React, not user code.\n// Matching by function name is stable across Turbopack's chunk hashing.\n// NOTE (Noah, 2026-07-27): Only bites client components; server-component\n// frames carry a recognizable `react-server-dom-*` path.\nconst REACT_INTERNAL_METHOD_PATTERNS = [\n /(?:^|\\.)jsxDEV(?:Impl)?$/,\n /(?:^|\\.)jsxs?$/,\n /(?:^|\\.)fakeJSXCallSite$/,\n];\n\n// React invokes user components inside a sentinel-named function\n// (`react_stack_bottom_frame`, hyphenated in some builds) precisely so tools\n// can tell user frames from React internals: every frame at or below the\n// sentinel is React/scheduler/bootstrap code. Cutting there is robust even\n// when Turbopack mangles those frames' chunk paths beyond what\n// REACT_INTERNAL_FRAME_PATTERNS recognizes. (Sentinel treatment adapted from\n// bippy, MIT, https://github.com/aidenybai/bippy.)\nconst REACT_STACK_BOTTOM_FRAME_PATTERN = /react[-_]stack[-_]bottom[-_]frame/;\n\nfunction isReactInternalMethod(methodName: string | null): boolean {\n if (!methodName) {\n return false;\n }\n return REACT_INTERNAL_METHOD_PATTERNS.some((pattern) => {\n return pattern.test(methodName);\n });\n}\n\nfunction parseDebugStackSource(debugStack: unknown): DebugSource | null {\n let stackText: string | null = null;\n\n if (typeof debugStack === \"string\") {\n stackText = debugStack;\n } else if (\n typeof debugStack === \"object\" &&\n debugStack &&\n \"stack\" in debugStack\n ) {\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n const stack = (debugStack as { stack?: unknown }).stack;\n if (typeof stack === \"string\") {\n stackText = stack;\n }\n }\n\n if (!stackText) {\n return null;\n }\n\n for (const rawLine of stackText.split(\"\\n\")) {\n const line = rawLine.trim();\n if (!line) {\n continue;\n }\n\n if (REACT_STACK_BOTTOM_FRAME_PATTERN.test(line)) {\n // Everything from the sentinel down is React internals \u2014 a frame down\n // there can only be a false positive.\n return null;\n }\n\n // Prefer the framed form `at <method> (<file>:<line>:<col>)` (V8) or\n // `<method>@<file>:<line>:<col>` (JavaScriptCore/SpiderMonkey \u2014 Safari\n // and Firefox editors drive the same in-iframe code) so we can read the\n // function name and skip React's JSX-runtime frames even when Turbopack\n // has mangled their chunk file name beyond recognition.\n const framedMatch =\n line.match(/^at\\s+(.+?)\\s+\\((.*):(\\d+):(\\d+)\\)$/) ??\n // Method names never contain `/`, which keeps `@`-versioned path\n // segments (`.pnpm/react@19.2.4/\u2026`) from being read as a method.\n line.match(/^([^@/]*)@(.+):(\\d+):(\\d+)$/);\n const stackFrameMatch =\n framedMatch ??\n line.match(/^at\\s+(?:.*\\()?(.*):(\\d+):(\\d+)\\)?$/) ??\n line.match(/^(.*):(\\d+):(\\d+)$/);\n\n if (!stackFrameMatch) {\n continue;\n }\n\n const methodName = framedMatch ? framedMatch[1]!.trim() : null;\n const fileOffset = framedMatch ? 2 : 1;\n const fileName = stackFrameMatch[fileOffset]?.trim();\n const lineNumber = Number.parseInt(\n stackFrameMatch[fileOffset + 1] ?? \"\",\n 10,\n );\n const columnNumber = Number.parseInt(\n stackFrameMatch[fileOffset + 2] ?? \"\",\n 10,\n );\n\n if (\n !fileName ||\n !Number.isFinite(lineNumber) ||\n !Number.isFinite(columnNumber)\n ) {\n continue;\n }\n\n if (isReactInternalFrame(fileName) || isReactInternalMethod(methodName)) {\n continue;\n }\n\n return {\n fileName,\n lineNumber,\n columnNumber,\n };\n }\n\n return null;\n}\n\nexport function getFiberFromElement(element: HTMLElement): ReactFiber | null {\n if (!element || typeof element !== \"object\") {\n return null;\n }\n\n const symbolKeys = Object.getOwnPropertySymbols(element);\n const fiberSymbolKey = symbolKeys.find((symbolKey) => {\n return symbolKey.toString().includes(\"reactFiber\");\n });\n if (fiberSymbolKey) {\n return (\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n (element as unknown as Record<symbol, ReactFiber>)[fiberSymbolKey] ?? null\n );\n }\n\n const keys = Object.keys(element);\n const fiberKey = keys.find((key) => key.startsWith(\"__reactFiber$\"));\n if (fiberKey) {\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n return (element as unknown as Record<string, ReactFiber>)[fiberKey] ?? null;\n }\n return null;\n}\n\nexport function getComponentName(\n fiber: ReactFiber | null | undefined,\n): string | undefined {\n if (!fiber?.type) {\n return undefined;\n }\n\n if (typeof fiber.type === \"string\") {\n return undefined;\n }\n\n if (typeof fiber.type === \"function\") {\n return fiber.type.name || undefined;\n }\n\n if (typeof fiber.type === \"object\") {\n return fiber.type.displayName ?? fiber.type.name ?? undefined;\n }\n\n return undefined;\n}\n\n// The per-element source pointer is `fiber._debugStack`, an `Error`\n// constructed inside `jsxDEV` at the JSX call site (dev builds only). We pull\n// the topmost non-React frame out of that stack; it references a compiled\n// SSR/client chunk (e.g. `.next-dev/.../ssr/*.js`).\n// `symbolicateSelectedElement` later resolves those compiled frames to\n// original `.tsx` locations via Next.js's `/__nextjs_original-stack-frames`\n// dev-server endpoint.\nexport function findDebugSource(\n fiber: ReactFiber,\n): { source: DebugSource; componentName?: string } | null {\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n const maxDepth = 50;\n\n while (current && depth < maxDepth) {\n const debugStackSource =\n parseDebugStackSource(current._debugStack) ??\n parseDebugStackSource(current._debugOwner?._debugStack);\n if (debugStackSource) {\n return {\n source: debugStackSource,\n componentName: getComponentName(current),\n };\n }\n\n current = current.return;\n depth++;\n }\n\n return null;\n}\n\nexport function getSourceLocation(element: HTMLElement) {\n let currentElement: HTMLElement | null = element;\n\n while (currentElement) {\n const fiber = getFiberFromElement(currentElement);\n if (fiber) {\n const debugInfo = findDebugSource(fiber);\n if (debugInfo?.source) {\n return {\n filePath: debugInfo.source.fileName,\n lineNumber: debugInfo.source.lineNumber,\n columnNumber: debugInfo.source.columnNumber,\n componentName: debugInfo.componentName ?? undefined,\n };\n }\n }\n\n currentElement = currentElement.parentElement;\n }\n\n return undefined;\n}\n\nfunction getDebugSource(fiber: ReactFiber): DebugSource | undefined {\n return findDebugSource(fiber)?.source;\n}\n\nfunction getTagName(fiber: ReactFiber): string | undefined {\n return z.string().safeParse(fiber.type).data?.toLowerCase();\n}\n\n// Resolving a fiber's source requires parsing `_debugStack` in React 19, which\n// is expensive. Cache per fiber object. React reuses fiber objects across\n// updates (current/alternate double-buffering), but a fiber's JSX source\n// location is fixed for its lifetime, so the cached key stays valid. Entries\n// are dropped only when the fiber is GC'd (unmount / remount / navigation).\n// Known caveat: a fast-refresh edit that shifts line numbers can leave\n// long-lived fibers keyed against the old revision while newly mounted\n// siblings key against the new one, temporarily splitting a repetition\n// group. Dev-only, and it self-heals on remount.\nconst fiberSourceKeyCache = new WeakMap<ReactFiber, string | null>();\n\nfunction getFiberSourceKey(fiber: ReactFiber): string | null {\n const cached = fiberSourceKeyCache.get(fiber);\n if (cached !== undefined) {\n return cached;\n }\n const source = getDebugSource(fiber);\n const key = source\n ? `${source.fileName}:${source.lineNumber}:${source.columnNumber ?? \"\"}`\n : null;\n fiberSourceKeyCache.set(fiber, key);\n return key;\n}\n\n// A repetition group is >=2 sibling fibers under one parent that share the\n// clicked fiber's element `type` and JSX source location \u2014 i.e. the instances\n// produced by a single `.map()`/loop. Returns null when the fiber is not part\n// of such a group (source parsing is bounded to the direct siblings scanned).\nfunction findRepetitionGroup(fiber: ReactFiber): ReactFiber[] | null {\n const parent = fiber.return;\n if (!parent) {\n return null;\n }\n const type = fiber.type;\n const candidates: ReactFiber[] = [];\n let child: ReactFiber | null | undefined = parent.child;\n let scanned = 0;\n while (child && scanned < MAX_SIBLING_SCAN) {\n if (child.type === type) {\n candidates.push(child);\n }\n child = child.sibling;\n scanned += 1;\n }\n\n if (candidates.length < 2) {\n return null;\n }\n\n const sourceKey = getFiberSourceKey(fiber);\n if (!sourceKey) {\n return null;\n }\n const members = candidates.filter((candidate) => {\n return getFiberSourceKey(candidate) === sourceKey;\n });\n return members.length >= 2 ? members : null;\n}\n\nfunction descendChildPath(\n fiber: ReactFiber,\n path: number[],\n): ReactFiber | null {\n let current: ReactFiber | null | undefined = fiber;\n for (const childIndex of path) {\n if (!current) {\n return null;\n }\n let child: ReactFiber | null | undefined = current.child;\n let index = 0;\n while (child && index < childIndex) {\n child = child.sibling;\n index += 1;\n }\n if (!child) {\n return null;\n }\n current = child;\n }\n return current ?? null;\n}\n\nfunction getHostNode(fiber: ReactFiber | null): HTMLElement | null {\n return fiber?.stateNode instanceof HTMLElement ? fiber.stateNode : null;\n}\n\nfunction isMatchingHost(\n fiber: ReactFiber | null,\n type: ReactFiber[\"type\"],\n sourceKey: string | null,\n): boolean {\n if (!fiber || !(fiber.stateNode instanceof HTMLElement)) {\n return false;\n }\n return fiber.type === type && getFiberSourceKey(fiber) === sourceKey;\n}\n\n// Fallback for when the child-index path doesn't land on a matching host (e.g.\n// a repeated unit whose subtree structure differs slightly): DFS the unit's\n// subtree for the first host fiber matching the clicked node's identity.\nfunction findHostInSubtree(\n root: ReactFiber,\n type: ReactFiber[\"type\"],\n sourceKey: string | null,\n): HTMLElement | null {\n const stack: ReactFiber[] = [];\n let child: ReactFiber | null | undefined = root.child;\n while (child) {\n stack.push(child);\n child = child.sibling;\n }\n let scanned = 0;\n while (stack.length > 0 && scanned < MAX_SUBTREE_SCAN) {\n const current = stack.pop();\n scanned += 1;\n if (!current) {\n continue;\n }\n if (isMatchingHost(current, type, sourceKey)) {\n return getHostNode(current);\n }\n let next: ReactFiber | null | undefined = current.child;\n while (next) {\n stack.push(next);\n next = next.sibling;\n }\n }\n return null;\n}\n\n// Fallback current-generation heuristic: a fiber still linked into its\n// parent's child list is *probably* the live generation. Only locally\n// consistent \u2014 a stale parent's child list can still link the stale fiber \u2014\n// so this runs only when the authoritative root check below is unavailable.\nfunction resolveCurrentFiberByParentLinkage(fiber: ReactFiber): ReactFiber {\n const alternate = fiber.alternate;\n if (!alternate) {\n return fiber;\n }\n let child: ReactFiber | null | undefined = fiber.return?.child;\n let scanned = 0;\n while (child && scanned < MAX_SIBLING_SCAN) {\n if (child === fiber) {\n return fiber;\n }\n child = child.sibling;\n scanned += 1;\n }\n return alternate;\n}\n\nfunction getFiberRootCurrent(stateNode: unknown): ReactFiber | null {\n if (\n !stateNode ||\n typeof stateNode !== \"object\" ||\n !(\"current\" in stateNode)\n ) {\n return null;\n }\n const current: unknown = Reflect.get(stateNode, \"current\");\n if (current && typeof current === \"object\" && \"child\" in current) {\n // Legacy cast - structural check above is our fiber discriminator\n // eslint-disable-next-line replo/no-as-cast\n return current as ReactFiber;\n }\n return null;\n}\n\n// React sets a DOM node's fiber pointer once, at node creation, and never\n// re-points it. Under double-buffering the current tree alternates between\n// the two fiber generations on every commit, so after a structure-changing\n// re-render the cached fiber can be the non-current generation \u2014 its\n// parent/sibling linkage then describes a stale tree. Which generation is\n// current can only be answered authoritatively from the root: the HostRoot\n// fiber's `stateNode` is the FiberRoot, whose `current` pointer always\n// references the committed tree (both HostRoot generations share the same\n// FiberRoot object, so it doesn't matter which generation we climbed).\n// Whichever of {fiber, alternate} is reachable from `FiberRoot.current` is\n// the live one. Approach adapted from bippy's `getLatestFiber` (MIT,\n// https://github.com/aidenybai/bippy), with our bounded iterative traversal.\nfunction resolveCurrentFiber(fiber: ReactFiber): ReactFiber {\n const alternate = fiber.alternate;\n if (!alternate) {\n return fiber;\n }\n\n let rootFiber: ReactFiber = fiber;\n let climbed = 0;\n while (rootFiber.return && climbed < MAX_ROOT_CLIMB_DEPTH) {\n rootFiber = rootFiber.return;\n climbed += 1;\n }\n const currentRoot = rootFiber.return\n ? null\n : getFiberRootCurrent(rootFiber.stateNode);\n if (!currentRoot) {\n return resolveCurrentFiberByParentLinkage(fiber);\n }\n\n const stack: ReactFiber[] = [currentRoot];\n let scanned = 0;\n while (stack.length > 0 && scanned < MAX_CURRENT_TREE_SCAN) {\n const node = stack.pop();\n scanned += 1;\n if (!node) {\n continue;\n }\n if (node === fiber || node === alternate) {\n return node;\n }\n if (node.child) {\n stack.push(node.child);\n }\n if (node.sibling) {\n stack.push(node.sibling);\n }\n }\n if (scanned >= MAX_CURRENT_TREE_SCAN) {\n return resolveCurrentFiberByParentLinkage(fiber);\n }\n // Neither generation is reachable from the committed tree: the fiber is\n // detached (unmounted mid-click). Degrade to the cached fiber; downstream\n // returns just the clicked element.\n return fiber;\n}\n\n// Given a clicked element, return every host DOM node in its repetition group,\n// including the element itself. Traverses the fiber tree instead of walking the\n// whole document: climb to the lowest ancestor that forms a repetition group,\n// record the child-index path down to the clicked node, then descend that same\n// path inside each group member. Returns just `[element]` when the element is\n// not repeated.\nexport function getRepetitionHostNodes(element: HTMLElement): HTMLElement[] {\n const cachedFiber = getFiberFromElement(element);\n if (!cachedFiber) {\n return [element];\n }\n const selectedFiber = resolveCurrentFiber(cachedFiber);\n\n const climb: ReactFiber[] = [];\n let cursor: ReactFiber | null | undefined = selectedFiber;\n let depth = 0;\n let unit: ReactFiber | null = null;\n let group: ReactFiber[] | null = null;\n while (cursor && depth < MAX_FIBER_CHAIN_DEPTH) {\n climb.push(cursor);\n const candidate = findRepetitionGroup(cursor);\n if (candidate) {\n unit = cursor;\n group = candidate;\n break;\n }\n cursor = cursor.return;\n depth += 1;\n }\n\n if (!unit || !group) {\n return [element];\n }\n\n const downward = climb.slice(0, climb.indexOf(unit) + 1).reverse();\n // null when a climb step is not linked into its parent's child list (stale\n // generation slipped through) \u2014 every member then resolves via subtree\n // search instead of descending a path recorded against the wrong tree.\n let pathFromUnit: number[] | null = [];\n for (let i = 0; i < downward.length - 1 && pathFromUnit; i += 1) {\n const parentFiber = downward[i];\n const targetFiber = downward[i + 1];\n if (!parentFiber || !targetFiber) {\n break;\n }\n let child: ReactFiber | null | undefined = parentFiber.child;\n let index = 0;\n while (child && child !== targetFiber && child !== targetFiber.alternate) {\n child = child.sibling;\n index += 1;\n }\n if (child) {\n pathFromUnit.push(index);\n } else {\n pathFromUnit = null;\n }\n }\n\n const selectedType = selectedFiber.type;\n const selectedSourceKey = getFiberSourceKey(selectedFiber);\n const nodes: HTMLElement[] = [];\n const seen = new Set<HTMLElement>();\n for (const member of group) {\n const landed = pathFromUnit ? descendChildPath(member, pathFromUnit) : null;\n const node = isMatchingHost(landed, selectedType, selectedSourceKey)\n ? getHostNode(landed)\n : findHostInSubtree(member, selectedType, selectedSourceKey);\n if (node && !seen.has(node)) {\n seen.add(node);\n nodes.push(node);\n }\n }\n\n if (!seen.has(element)) {\n nodes.push(element);\n }\n\n return nodes;\n}\n\nfunction getSerializablePropValue(value: unknown): unknown {\n if (\n value === null ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n if (typeof value === \"string\") {\n return value.length > MAX_SERIALIZED_STRING_LENGTH\n ? `${value.slice(0, MAX_SERIALIZED_STRING_LENGTH)}...`\n : value;\n }\n\n if (Array.isArray(value)) {\n return value.slice(0, 20).map(getSerializablePropValue);\n }\n\n if (typeof value === \"object\") {\n return \"[object]\";\n }\n\n return undefined;\n}\n\nfunction getSerializableProps(\n props: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!props) {\n return undefined;\n }\n\n const serializedProps: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props).slice(\n 0,\n MAX_SERIALIZED_PROP_COUNT,\n )) {\n if (\n key === \"children\" ||\n key === \"ref\" ||\n key.startsWith(\"on\") ||\n typeof value === \"function\" ||\n typeof value === \"symbol\"\n ) {\n continue;\n }\n\n const serializableValue = getSerializablePropValue(value);\n if (serializableValue !== undefined) {\n serializedProps[key] = serializableValue;\n }\n }\n\n return Object.keys(serializedProps).length > 0 ? serializedProps : undefined;\n}\n\nexport function getFiberChain(element: HTMLElement) {\n const rootFiber = getFiberFromElement(element);\n const fiberChain = [];\n const seenKeys = new Set<string>();\n let currentFiber: ReactFiber | null | undefined = rootFiber;\n let depth = 0;\n\n while (currentFiber && depth < MAX_FIBER_CHAIN_DEPTH) {\n const source = getDebugSource(currentFiber);\n if (source) {\n const tagName = getTagName(currentFiber);\n const componentName = getComponentName(currentFiber);\n const key = [\n source.fileName,\n source.lineNumber,\n source.columnNumber ?? \"\",\n tagName ?? \"\",\n componentName ?? \"\",\n ].join(\":\");\n\n if (!seenKeys.has(key)) {\n seenKeys.add(key);\n fiberChain.push({\n sourceLocation: {\n filePath: source.fileName,\n lineNumber: source.lineNumber,\n columnNumber: source.columnNumber,\n componentName,\n },\n tagName,\n componentName,\n props: getSerializableProps(\n currentFiber.memoizedProps ?? currentFiber.pendingProps,\n ),\n });\n }\n }\n\n currentFiber = currentFiber.return;\n depth += 1;\n }\n\n return fiberChain;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// =============================================================================\n// React Fiber / Source Location Utilities\n// =============================================================================\n\nimport { z } from \"zod\";\n\nexport interface DebugSource {\n fileName: string;\n lineNumber: number;\n columnNumber?: number;\n}\n\nexport interface ReactFiber {\n _debugStack?: unknown;\n _debugOwner?: ReactFiber | ReactServerOwner;\n type?:\n | { name?: string; displayName?: string }\n | string\n | ((...args: unknown[]) => unknown)\n | null;\n return?: ReactFiber | null;\n child?: ReactFiber | null;\n sibling?: ReactFiber | null;\n alternate?: ReactFiber | null;\n stateNode?: unknown;\n memoizedProps?: Record<string, unknown>;\n pendingProps?: Record<string, unknown>;\n}\n\ninterface ReactServerOwner {\n name: string;\n debugStack?: unknown;\n owner?: ReactFiber | ReactServerOwner;\n props?: Record<string, unknown>;\n}\n\nconst MAX_FIBER_CHAIN_DEPTH = 80;\nconst MAX_SERIALIZED_PROP_COUNT = 24;\nconst MAX_SERIALIZED_STRING_LENGTH = 500;\nconst MAX_SIBLING_SCAN = 5000;\nconst MAX_SUBTREE_SCAN = 5000;\nconst MAX_ROOT_CLIMB_DEPTH = 1000;\nconst MAX_CURRENT_TREE_SCAN = 50_000;\n\n// Frames produced by React's own JSX runtime \u2014 these come first in\n// `_debugStack.stack` because the `Error` is constructed inside `jsxDEV`. We\n// want the frame *above* them, which is the actual JSX call site.\n//\n// Turbopack rewrites `node_modules/next/dist/compiled/react-server-dom-*` and\n// friends into mangled chunk paths like\n// `_next/static/chunks/<hash>_next_dist_compiled_react-server-dom-turbopack_<hash>._.js`,\n// so we match both the human-readable module paths and the chunk-name forms.\n// Without this, `_debugStack`'s top frame inside React's RSC runtime gets\n// surfaced as the \"host\" source location for every text node on the page \u2014\n// which then symbolicates back to bundled React, not user code.\nconst REACT_INTERNAL_FRAME_PATTERNS = [\n /react.*jsx-dev-runtime/,\n /react.*jsx-runtime/,\n /react-dom\\//,\n /react\\/cjs\\/react\\./,\n /react-server-dom/,\n /react_server_dom/,\n /next[/_.]dist[/_.]compiled/,\n /\\/node_modules\\/(next|react|react-dom)\\//,\n];\n\nfunction isReactInternalFrame(fileName: string): boolean {\n return REACT_INTERNAL_FRAME_PATTERNS.some((pattern) => {\n return pattern.test(fileName);\n });\n}\n\n// React constructs the `_debugStack` Error inside its JSX runtime (`jsxDEV`,\n// `jsx`, `jsxs`), so those frames sit *above* the real JSX call site we want.\n// The file-based check above skips them when their path is recognizable, but\n// Turbopack mangles the client JSX-runtime chunk to an opaque name like\n// `node_modules__pnpm_<hash>._.js` (no \"react\"/\"jsx-dev-runtime\" substring),\n// so the top `jsxDEV` frame slips through and gets surfaced as the element's\n// source \u2014 which then symbolicates back to bundled React, not user code.\n// Matching by function name is stable across Turbopack's chunk hashing.\n// NOTE (Noah, 2026-07-27): Only bites client components; server-component\n// frames carry a recognizable `react-server-dom-*` path.\nconst REACT_INTERNAL_METHOD_PATTERNS = [\n /(?:^|\\.)jsxDEV(?:Impl)?$/,\n /(?:^|\\.)jsxs?$/,\n /(?:^|\\.)fakeJSXCallSite$/,\n];\n\n// React invokes user components inside a sentinel-named function\n// (`react_stack_bottom_frame`, hyphenated in some builds) precisely so tools\n// can tell user frames from React internals: every frame at or below the\n// sentinel is React/scheduler/bootstrap code. Cutting there is robust even\n// when Turbopack mangles those frames' chunk paths beyond what\n// REACT_INTERNAL_FRAME_PATTERNS recognizes. (Sentinel treatment adapted from\n// bippy, MIT, https://github.com/aidenybai/bippy.)\nconst REACT_STACK_BOTTOM_FRAME_PATTERN = /react[-_]stack[-_]bottom[-_]frame/;\n\nfunction isReactInternalMethod(methodName: string | null): boolean {\n if (!methodName) {\n return false;\n }\n return REACT_INTERNAL_METHOD_PATTERNS.some((pattern) => {\n return pattern.test(methodName);\n });\n}\n\nfunction parseDebugStackSource(debugStack: unknown): DebugSource | null {\n let stackText: string | null = null;\n\n if (typeof debugStack === \"string\") {\n stackText = debugStack;\n } else if (\n typeof debugStack === \"object\" &&\n debugStack &&\n \"stack\" in debugStack\n ) {\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n const stack = (debugStack as { stack?: unknown }).stack;\n if (typeof stack === \"string\") {\n stackText = stack;\n }\n }\n\n if (!stackText) {\n return null;\n }\n\n for (const rawLine of stackText.split(\"\\n\")) {\n const line = rawLine.trim();\n if (!line) {\n continue;\n }\n\n if (REACT_STACK_BOTTOM_FRAME_PATTERN.test(line)) {\n // Everything from the sentinel down is React internals \u2014 a frame down\n // there can only be a false positive.\n return null;\n }\n\n // Prefer the framed form `at <method> (<file>:<line>:<col>)` (V8) or\n // `<method>@<file>:<line>:<col>` (JavaScriptCore/SpiderMonkey \u2014 Safari\n // and Firefox editors drive the same in-iframe code) so we can read the\n // function name and skip React's JSX-runtime frames even when Turbopack\n // has mangled their chunk file name beyond recognition.\n const framedMatch =\n line.match(/^at\\s+(.+?)\\s+\\((.*):(\\d+):(\\d+)\\)$/) ??\n // Method names never contain `/`, which keeps `@`-versioned path\n // segments (`.pnpm/react@19.2.4/\u2026`) from being read as a method.\n line.match(/^([^@/]*)@(.+):(\\d+):(\\d+)$/);\n const stackFrameMatch =\n framedMatch ??\n line.match(/^at\\s+(?:.*\\()?(.*):(\\d+):(\\d+)\\)?$/) ??\n line.match(/^(.*):(\\d+):(\\d+)$/);\n\n if (!stackFrameMatch) {\n continue;\n }\n\n const methodName = framedMatch ? framedMatch[1]!.trim() : null;\n const fileOffset = framedMatch ? 2 : 1;\n const fileName = stackFrameMatch[fileOffset]?.trim();\n const lineNumber = Number.parseInt(\n stackFrameMatch[fileOffset + 1] ?? \"\",\n 10,\n );\n const columnNumber = Number.parseInt(\n stackFrameMatch[fileOffset + 2] ?? \"\",\n 10,\n );\n\n if (\n !fileName ||\n !Number.isFinite(lineNumber) ||\n !Number.isFinite(columnNumber)\n ) {\n continue;\n }\n\n if (isReactInternalFrame(fileName) || isReactInternalMethod(methodName)) {\n continue;\n }\n\n return {\n fileName,\n lineNumber,\n columnNumber,\n };\n }\n\n return null;\n}\n\nexport function getFiberFromElement(element: HTMLElement): ReactFiber | null {\n if (!element || typeof element !== \"object\") {\n return null;\n }\n\n const symbolKeys = Object.getOwnPropertySymbols(element);\n const fiberSymbolKey = symbolKeys.find((symbolKey) => {\n return symbolKey.toString().includes(\"reactFiber\");\n });\n if (fiberSymbolKey) {\n return (\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n (element as unknown as Record<symbol, ReactFiber>)[fiberSymbolKey] ?? null\n );\n }\n\n const keys = Object.keys(element);\n const fiberKey = keys.find((key) => key.startsWith(\"__reactFiber$\"));\n if (fiberKey) {\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n return (element as unknown as Record<string, ReactFiber>)[fiberKey] ?? null;\n }\n return null;\n}\n\nexport function getComponentName(\n fiber: ReactFiber | null | undefined,\n): string | undefined {\n if (!fiber?.type) {\n return undefined;\n }\n\n if (typeof fiber.type === \"string\") {\n return undefined;\n }\n\n if (typeof fiber.type === \"function\") {\n return fiber.type.name || undefined;\n }\n\n if (typeof fiber.type === \"object\") {\n return fiber.type.displayName ?? fiber.type.name ?? undefined;\n }\n\n return undefined;\n}\n\n// The per-element source pointer is `fiber._debugStack`, an `Error`\n// constructed inside `jsxDEV` at the JSX call site (dev builds only). We pull\n// the topmost non-React frame out of that stack; it references a compiled\n// SSR/client chunk (e.g. `.next-dev/.../ssr/*.js`).\n// `symbolicateSelectedElement` later resolves those compiled frames to\n// original `.tsx` locations via Next.js's `/__nextjs_original-stack-frames`\n// dev-server endpoint.\nexport function findDebugSource(\n fiber: ReactFiber,\n): { source: DebugSource; componentName?: string } | null {\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n const maxDepth = 50;\n\n while (current && depth < maxDepth) {\n const debugStackSource =\n parseDebugStackSource(current._debugStack) ??\n parseDebugStackSource(\n current._debugOwner && \"_debugStack\" in current._debugOwner\n ? current._debugOwner._debugStack\n : null,\n );\n if (debugStackSource) {\n return {\n source: debugStackSource,\n componentName: getComponentName(current),\n };\n }\n\n current = current.return;\n depth++;\n }\n\n return null;\n}\n\nexport function getSourceLocation(element: HTMLElement) {\n let currentElement: HTMLElement | null = element;\n\n while (currentElement) {\n const fiber = getFiberFromElement(currentElement);\n if (fiber) {\n const debugInfo = findDebugSource(fiber);\n if (debugInfo?.source) {\n return {\n filePath: debugInfo.source.fileName,\n lineNumber: debugInfo.source.lineNumber,\n columnNumber: debugInfo.source.columnNumber,\n componentName: debugInfo.componentName ?? undefined,\n };\n }\n }\n\n currentElement = currentElement.parentElement;\n }\n\n return undefined;\n}\n\nfunction getDebugSource(fiber: ReactFiber): DebugSource | undefined {\n return findDebugSource(fiber)?.source;\n}\n\nfunction getTagName(fiber: ReactFiber): string | undefined {\n return z.string().safeParse(fiber.type).data?.toLowerCase();\n}\n\n// Resolving a fiber's source requires parsing `_debugStack` in React 19, which\n// is expensive. Cache per fiber object. React reuses fiber objects across\n// updates (current/alternate double-buffering), but a fiber's JSX source\n// location is fixed for its lifetime, so the cached key stays valid. Entries\n// are dropped only when the fiber is GC'd (unmount / remount / navigation).\n// Known caveat: a fast-refresh edit that shifts line numbers can leave\n// long-lived fibers keyed against the old revision while newly mounted\n// siblings key against the new one, temporarily splitting a repetition\n// group. Dev-only, and it self-heals on remount.\nconst fiberSourceKeyCache = new WeakMap<ReactFiber, string | null>();\n\nfunction getFiberSourceKey(fiber: ReactFiber): string | null {\n const cached = fiberSourceKeyCache.get(fiber);\n if (cached !== undefined) {\n return cached;\n }\n const source = getDebugSource(fiber);\n const key = source\n ? `${source.fileName}:${source.lineNumber}:${source.columnNumber ?? \"\"}`\n : null;\n fiberSourceKeyCache.set(fiber, key);\n return key;\n}\n\n// A repetition group is >=2 sibling fibers under one parent that share the\n// clicked fiber's element `type` and JSX source location \u2014 i.e. the instances\n// produced by a single `.map()`/loop. Returns null when the fiber is not part\n// of such a group (source parsing is bounded to the direct siblings scanned).\nfunction findRepetitionGroup(fiber: ReactFiber): ReactFiber[] | null {\n const parent = fiber.return;\n if (!parent) {\n return null;\n }\n const type = fiber.type;\n const candidates: ReactFiber[] = [];\n let child: ReactFiber | null | undefined = parent.child;\n let scanned = 0;\n while (child && scanned < MAX_SIBLING_SCAN) {\n if (child.type === type) {\n candidates.push(child);\n }\n child = child.sibling;\n scanned += 1;\n }\n\n if (candidates.length < 2) {\n return null;\n }\n\n const sourceKey = getFiberSourceKey(fiber);\n if (!sourceKey) {\n return null;\n }\n const members = candidates.filter((candidate) => {\n return getFiberSourceKey(candidate) === sourceKey;\n });\n return members.length >= 2 ? members : null;\n}\n\nfunction descendChildPath(\n fiber: ReactFiber,\n path: number[],\n): ReactFiber | null {\n let current: ReactFiber | null | undefined = fiber;\n for (const childIndex of path) {\n if (!current) {\n return null;\n }\n let child: ReactFiber | null | undefined = current.child;\n let index = 0;\n while (child && index < childIndex) {\n child = child.sibling;\n index += 1;\n }\n if (!child) {\n return null;\n }\n current = child;\n }\n return current ?? null;\n}\n\nfunction getHostNode(fiber: ReactFiber | null): HTMLElement | null {\n return fiber?.stateNode instanceof HTMLElement ? fiber.stateNode : null;\n}\n\nfunction isMatchingHost(\n fiber: ReactFiber | null,\n type: ReactFiber[\"type\"],\n sourceKey: string | null,\n): boolean {\n if (!fiber || !(fiber.stateNode instanceof HTMLElement)) {\n return false;\n }\n return fiber.type === type && getFiberSourceKey(fiber) === sourceKey;\n}\n\n// Fallback for when the child-index path doesn't land on a matching host (e.g.\n// a repeated unit whose subtree structure differs slightly): DFS the unit's\n// subtree for the first host fiber matching the clicked node's identity.\nfunction findHostInSubtree(\n root: ReactFiber,\n type: ReactFiber[\"type\"],\n sourceKey: string | null,\n): HTMLElement | null {\n const stack: ReactFiber[] = [];\n let child: ReactFiber | null | undefined = root.child;\n while (child) {\n stack.push(child);\n child = child.sibling;\n }\n let scanned = 0;\n while (stack.length > 0 && scanned < MAX_SUBTREE_SCAN) {\n const current = stack.pop();\n scanned += 1;\n if (!current) {\n continue;\n }\n if (isMatchingHost(current, type, sourceKey)) {\n return getHostNode(current);\n }\n let next: ReactFiber | null | undefined = current.child;\n while (next) {\n stack.push(next);\n next = next.sibling;\n }\n }\n return null;\n}\n\n// Fallback current-generation heuristic: a fiber still linked into its\n// parent's child list is *probably* the live generation. Only locally\n// consistent \u2014 a stale parent's child list can still link the stale fiber \u2014\n// so this runs only when the authoritative root check below is unavailable.\nfunction resolveCurrentFiberByParentLinkage(fiber: ReactFiber): ReactFiber {\n const alternate = fiber.alternate;\n if (!alternate) {\n return fiber;\n }\n let child: ReactFiber | null | undefined = fiber.return?.child;\n let scanned = 0;\n while (child && scanned < MAX_SIBLING_SCAN) {\n if (child === fiber) {\n return fiber;\n }\n child = child.sibling;\n scanned += 1;\n }\n return alternate;\n}\n\nfunction getFiberRootCurrent(stateNode: unknown): ReactFiber | null {\n if (\n !stateNode ||\n typeof stateNode !== \"object\" ||\n !(\"current\" in stateNode)\n ) {\n return null;\n }\n const current: unknown = Reflect.get(stateNode, \"current\");\n if (current && typeof current === \"object\" && \"child\" in current) {\n // Legacy cast - structural check above is our fiber discriminator\n // eslint-disable-next-line replo/no-as-cast\n return current as ReactFiber;\n }\n return null;\n}\n\n// React sets a DOM node's fiber pointer once, at node creation, and never\n// re-points it. Under double-buffering the current tree alternates between\n// the two fiber generations on every commit, so after a structure-changing\n// re-render the cached fiber can be the non-current generation \u2014 its\n// parent/sibling linkage then describes a stale tree. Which generation is\n// current can only be answered authoritatively from the root: the HostRoot\n// fiber's `stateNode` is the FiberRoot, whose `current` pointer always\n// references the committed tree (both HostRoot generations share the same\n// FiberRoot object, so it doesn't matter which generation we climbed).\n// Whichever of {fiber, alternate} is reachable from `FiberRoot.current` is\n// the live one. Approach adapted from bippy's `getLatestFiber` (MIT,\n// https://github.com/aidenybai/bippy), with our bounded iterative traversal.\nfunction resolveCurrentFiber(fiber: ReactFiber): ReactFiber {\n const alternate = fiber.alternate;\n if (!alternate) {\n return fiber;\n }\n\n let rootFiber: ReactFiber = fiber;\n let climbed = 0;\n while (rootFiber.return && climbed < MAX_ROOT_CLIMB_DEPTH) {\n rootFiber = rootFiber.return;\n climbed += 1;\n }\n const currentRoot = rootFiber.return\n ? null\n : getFiberRootCurrent(rootFiber.stateNode);\n if (!currentRoot) {\n return resolveCurrentFiberByParentLinkage(fiber);\n }\n\n const stack: ReactFiber[] = [currentRoot];\n let scanned = 0;\n while (stack.length > 0 && scanned < MAX_CURRENT_TREE_SCAN) {\n const node = stack.pop();\n scanned += 1;\n if (!node) {\n continue;\n }\n if (node === fiber || node === alternate) {\n return node;\n }\n if (node.child) {\n stack.push(node.child);\n }\n if (node.sibling) {\n stack.push(node.sibling);\n }\n }\n if (scanned >= MAX_CURRENT_TREE_SCAN) {\n return resolveCurrentFiberByParentLinkage(fiber);\n }\n // Neither generation is reachable from the committed tree: the fiber is\n // detached (unmounted mid-click). Degrade to the cached fiber; downstream\n // returns just the clicked element.\n return fiber;\n}\n\n// Given a clicked element, return every host DOM node in its repetition group,\n// including the element itself. Traverses the fiber tree instead of walking the\n// whole document: climb to the lowest ancestor that forms a repetition group,\n// record the child-index path down to the clicked node, then descend that same\n// path inside each group member. Returns just `[element]` when the element is\n// not repeated.\nexport function getRepetitionHostNodes(element: HTMLElement): HTMLElement[] {\n const cachedFiber = getFiberFromElement(element);\n if (!cachedFiber) {\n return [element];\n }\n const selectedFiber = resolveCurrentFiber(cachedFiber);\n\n const climb: ReactFiber[] = [];\n let cursor: ReactFiber | null | undefined = selectedFiber;\n let depth = 0;\n let unit: ReactFiber | null = null;\n let group: ReactFiber[] | null = null;\n while (cursor && depth < MAX_FIBER_CHAIN_DEPTH) {\n climb.push(cursor);\n const candidate = findRepetitionGroup(cursor);\n if (candidate) {\n unit = cursor;\n group = candidate;\n break;\n }\n cursor = cursor.return;\n depth += 1;\n }\n\n if (!unit || !group) {\n return [element];\n }\n\n const downward = climb.slice(0, climb.indexOf(unit) + 1).reverse();\n // null when a climb step is not linked into its parent's child list (stale\n // generation slipped through) \u2014 every member then resolves via subtree\n // search instead of descending a path recorded against the wrong tree.\n let pathFromUnit: number[] | null = [];\n for (let i = 0; i < downward.length - 1 && pathFromUnit; i += 1) {\n const parentFiber = downward[i];\n const targetFiber = downward[i + 1];\n if (!parentFiber || !targetFiber) {\n break;\n }\n let child: ReactFiber | null | undefined = parentFiber.child;\n let index = 0;\n while (child && child !== targetFiber && child !== targetFiber.alternate) {\n child = child.sibling;\n index += 1;\n }\n if (child) {\n pathFromUnit.push(index);\n } else {\n pathFromUnit = null;\n }\n }\n\n const selectedType = selectedFiber.type;\n const selectedSourceKey = getFiberSourceKey(selectedFiber);\n const nodes: HTMLElement[] = [];\n const seen = new Set<HTMLElement>();\n for (const member of group) {\n const landed = pathFromUnit ? descendChildPath(member, pathFromUnit) : null;\n const node = isMatchingHost(landed, selectedType, selectedSourceKey)\n ? getHostNode(landed)\n : findHostInSubtree(member, selectedType, selectedSourceKey);\n if (node && !seen.has(node)) {\n seen.add(node);\n nodes.push(node);\n }\n }\n\n if (!seen.has(element)) {\n nodes.push(element);\n }\n\n return nodes;\n}\n\nfunction getSerializablePropValue(value: unknown): unknown {\n if (\n value === null ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n if (typeof value === \"string\") {\n return value.length > MAX_SERIALIZED_STRING_LENGTH\n ? `${value.slice(0, MAX_SERIALIZED_STRING_LENGTH)}...`\n : value;\n }\n\n if (Array.isArray(value)) {\n return value.slice(0, 20).map(getSerializablePropValue);\n }\n\n if (typeof value === \"object\") {\n return \"[object]\";\n }\n\n return undefined;\n}\n\nfunction getSerializableProps(\n props: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!props) {\n return undefined;\n }\n\n const serializedProps: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props).slice(\n 0,\n MAX_SERIALIZED_PROP_COUNT,\n )) {\n if (\n key === \"children\" ||\n key === \"ref\" ||\n key.startsWith(\"on\") ||\n typeof value === \"function\" ||\n typeof value === \"symbol\"\n ) {\n continue;\n }\n\n const serializableValue = getSerializablePropValue(value);\n if (serializableValue !== undefined) {\n serializedProps[key] = serializableValue;\n }\n }\n\n return Object.keys(serializedProps).length > 0 ? serializedProps : undefined;\n}\n\nexport function getFiberChain(element: HTMLElement) {\n const rootFiber = getFiberFromElement(element);\n const fiberChain = [];\n const seenKeys = new Set<string>();\n const seenOwners = new Set<ReactFiber | ReactServerOwner>();\n let currentFiber: ReactFiber | null | undefined = rootFiber;\n let depth = 0;\n\n while (currentFiber && depth < MAX_FIBER_CHAIN_DEPTH) {\n const source = getDebugSource(currentFiber);\n if (source) {\n const tagName = getTagName(currentFiber);\n const componentName = getComponentName(currentFiber);\n const key = [\n source.fileName,\n source.lineNumber,\n source.columnNumber ?? \"\",\n tagName ?? \"\",\n componentName ?? \"\",\n ].join(\":\");\n\n if (!seenKeys.has(key)) {\n seenKeys.add(key);\n fiberChain.push({\n sourceLocation: {\n filePath: source.fileName,\n lineNumber: source.lineNumber,\n columnNumber: source.columnNumber,\n componentName,\n },\n tagName,\n componentName,\n props: getSerializableProps(\n currentFiber.memoizedProps ?? currentFiber.pendingProps,\n ),\n });\n }\n }\n\n // Server components don't have DOM fibers. Their owner records carry\n // the JSX usage stack, which distinguishes separate renders of one component.\n let owner = currentFiber._debugOwner;\n while (\n owner &&\n seenOwners.size < MAX_FIBER_CHAIN_DEPTH &&\n !seenOwners.has(owner)\n ) {\n seenOwners.add(owner);\n if (\"name\" in owner) {\n const ownerSource = parseDebugStackSource(owner.debugStack);\n if (ownerSource) {\n const key = [\n ownerSource.fileName,\n ownerSource.lineNumber,\n ownerSource.columnNumber ?? \"\",\n \"\",\n owner.name,\n ].join(\":\");\n if (!seenKeys.has(key)) {\n seenKeys.add(key);\n fiberChain.push({\n sourceLocation: {\n filePath: ownerSource.fileName,\n lineNumber: ownerSource.lineNumber,\n columnNumber: ownerSource.columnNumber,\n componentName: owner.name,\n },\n tagName: undefined,\n componentName: owner.name,\n props: getSerializableProps(owner.props),\n });\n }\n }\n owner = owner.owner;\n } else {\n owner = owner._debugOwner;\n }\n }\n\n currentFiber = currentFiber.return;\n depth += 1;\n }\n\n return fiberChain;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -38,6 +38,7 @@ function useSelectionInteractions({
38
38
  return;
39
39
  }
40
40
  let dragAnimationFrameId = null;
41
+ const editingPointerIds = /* @__PURE__ */ new Set();
41
42
  let lastClick = null;
42
43
  let dragCandidates = [];
43
44
  const stopDragAnimation = () => {
@@ -131,7 +132,9 @@ function useSelectionInteractions({
131
132
  dragAnimationFrameId = requestAnimationFrame(syncDragRectToViewport);
132
133
  };
133
134
  const handlePointerDown = (event) => {
135
+ editingPointerIds.delete(event.pointerId);
134
136
  if (editingElementRef?.current && event.target instanceof Node && editingElementRef.current.contains(event.target)) {
137
+ editingPointerIds.add(event.pointerId);
135
138
  return;
136
139
  }
137
140
  event.preventDefault();
@@ -230,6 +233,9 @@ function useSelectionInteractions({
230
233
  });
231
234
  };
232
235
  const handlePointerUp = (event) => {
236
+ if (editingPointerIds.delete(event.pointerId)) {
237
+ return;
238
+ }
233
239
  if (editingElementRef?.current && event.target instanceof Node && editingElementRef.current.contains(event.target)) {
234
240
  return;
235
241
  }
@@ -317,10 +323,12 @@ function useSelectionInteractions({
317
323
  event.preventDefault();
318
324
  event.stopPropagation();
319
325
  };
320
- const handlePointerCancel = () => {
326
+ const handlePointerCancel = (event) => {
327
+ editingPointerIds.delete(event.pointerId);
321
328
  resetDragState();
322
329
  };
323
330
  const handleWindowBlur = () => {
331
+ editingPointerIds.clear();
324
332
  resetDragState();
325
333
  };
326
334
  document.addEventListener("pointerdown", handlePointerDown, true);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../select-mode/hooks/useSelectionInteractions.ts"],
4
- "sourcesContent": ["import type { MutableRefObject } from \"react\";\nimport type {\n DisplayMode,\n SelectableData,\n SelectModeClickPosition,\n} from \"schemas/generated/selectMode\";\nimport type { DragCandidate } from \"../interactions/selectionGeometry\";\nimport type { SelectModeInteractionSession } from \"../selectModeSession\";\n\nimport { useEffect } from \"react\";\n\nimport {\n buildElementDescriptor,\n buildSelector,\n getNearestSelectableElement,\n} from \"../descriptor/elementDescriptor\";\nimport { getWebsiteBuilderRpc } from \"../iframeRpcChannel\";\nimport {\n collectDragCandidates,\n getCandidatesInSelection,\n getDocumentScrollOffset,\n getDragPositionFromClient,\n getElementAnchor,\n getPageRectFromViewportRect,\n getViewportRectFromPageRect,\n getViewportSelectionRect,\n} from \"../interactions/selectionGeometry\";\nimport {\n showElementSelectionFrames,\n showSelectionFrames,\n} from \"../selectionFrame\";\nimport { IDLE_SESSION } from \"../selectModeSession\";\nimport { symbolicateSelectedElement } from \"../symbolicate\";\nimport { isTextEditableElement } from \"./useEditModeStateMachine\";\nimport { getRepetitionSiblingElements } from \"./useSiblingResolution\";\n\nconst DOUBLE_CLICK_THRESHOLD_MS = 500;\n\n// React fibers carry only Turbopack chunk paths; resolving them to the\n// user's source file is async and only meaningful for \"react-element\"\n// kinds. Plan selectables already point at the right thing.\nasync function maybeSymbolicate(data: SelectableData): Promise<SelectableData> {\n return data.kind === \"react-element\"\n ? symbolicateSelectedElement(data)\n : data;\n}\n\n/**\n * Owns the iframe-side pointer interactions that drive selection:\n *\n * - On `pointerdown` we open a `drag` session (storing both client + page\n * coords plus the current scroll offset). We don't yet know if this will\n * become a click or an actual drag.\n * - On `pointermove` we update the drag rect and post `DRAG_RECT_UPDATED`\n * to the parent so the live drag rectangle can render. We only flip\n * `hasExceededThreshold` once the rect grows past 6\u00D76 px so that a tiny\n * accidental drag still resolves as a click.\n * - On `pointerup` we either:\n * - resolve as an `ELEMENT_SELECTED` (single click / sub-threshold drag)\n * - resolve as an `AREA_SELECTED` (drag past threshold), filtering the\n * candidates snapshotted at drag start against the final rectangle to\n * enumerate which descendants the user enclosed.\n * - During an active drag a `requestAnimationFrame` loop keeps the rect in\n * sync with the page scroll so the rectangle visually \"sticks\" to the\n * page rather than the viewport.\n *\n * We capture-listen and `preventDefault`/`stopPropagation` clicks so the\n * underlying page can't navigate or trigger handlers while the user is\n * working in selection mode.\n *\n * @author Kevin O'Connell 2026-04-17\n */\nexport function useSelectionInteractions({\n displayMode,\n editingElementRef,\n interactionSessionRef,\n onBeginEditing,\n}: {\n displayMode: DisplayMode;\n editingElementRef?: MutableRefObject<HTMLElement | null>;\n interactionSessionRef: MutableRefObject<SelectModeInteractionSession>;\n onBeginEditing: (args: {\n element: Element;\n descriptorPromise: Promise<SelectableData>;\n }) => void;\n}) {\n // eslint-disable-next-line replo/no-use-effect -- Legacy effect - may or may not be necessary\n useEffect(() => {\n if (displayMode !== \"selection\") {\n return;\n }\n\n let dragAnimationFrameId: number | null = null;\n let lastClick: {\n descriptorPromise: Promise<SelectableData>;\n target: Element;\n time: number;\n } | null = null;\n // Snapshot of the page's meaningful elements + their page rects, taken\n // once when a drag begins so per-move hit-testing avoids a full-DOM scan.\n let dragCandidates: DragCandidate[] = [];\n\n const stopDragAnimation = () => {\n if (dragAnimationFrameId === null) {\n return;\n }\n\n cancelAnimationFrame(dragAnimationFrameId);\n dragAnimationFrameId = null;\n };\n\n // `notifyParentDragCleared` posts a null drag rect so the parent tears\n // down the live drag overlay. The area-commit path suppresses it: the\n // parent maps a null drag rect to `selection = none`, which round-trips\n // back as `setSelectionType(\"none\")` and wipes the in-iframe frames we're\n // about to paint. The follow-up `areaSelected` supersedes the drag overlay\n // on its own, so the null post is pure collateral damage there.\n const resetDragState = ({\n notifyParentDragCleared = true,\n }: { notifyParentDragCleared?: boolean } = {}) => {\n const currentSession = interactionSessionRef.current;\n\n stopDragAnimation();\n\n if (currentSession.type !== \"drag\") {\n dragCandidates = [];\n return;\n }\n\n if (notifyParentDragCleared && currentSession.hasExceededThreshold) {\n getWebsiteBuilderRpc()?.dragRectUpdated({\n dragRect: null,\n selectionRects: [],\n });\n }\n\n dragCandidates = [];\n interactionSessionRef.current = IDLE_SESSION;\n };\n\n const postCurrentDragRect = () => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\") {\n return;\n }\n\n const rect = getViewportSelectionRect({\n dragStart: session.dragStart,\n dragCurrent: session.dragCurrent,\n scrollOffset: session.scrollOffset,\n });\n\n if (\n rect.width <= 6 &&\n rect.height <= 6 &&\n !session.hasExceededThreshold\n ) {\n return;\n }\n\n if (!session.hasExceededThreshold) {\n interactionSessionRef.current = {\n ...session,\n hasExceededThreshold: true,\n };\n }\n\n // Cheap hit-test against the candidates we snapshotted at drag start,\n // projected back to viewport coords so the parent can paint a live\n // highlight on each element the drag will capture. No DOM scan here.\n const selectionPageRect = getPageRectFromViewportRect({\n rect,\n scrollOffset: session.scrollOffset,\n });\n const selectionRects = getCandidatesInSelection({\n candidates: dragCandidates,\n selectionPageRect,\n }).map((candidate) => ({\n id: candidate.id,\n rect: getViewportRectFromPageRect({\n rect: candidate.pageRect,\n scrollOffset: session.scrollOffset,\n }),\n }));\n\n getWebsiteBuilderRpc()?.dragRectUpdated({\n dragRect: rect,\n selectionRects,\n });\n };\n\n const syncDragRectToViewport = () => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\") {\n dragAnimationFrameId = null;\n return;\n }\n\n const nextScrollOffset = getDocumentScrollOffset();\n const nextDragCurrent = getDragPositionFromClient({\n clientX: session.dragCurrent.clientX,\n clientY: session.dragCurrent.clientY,\n scrollOffset: nextScrollOffset,\n });\n\n if (\n nextDragCurrent.pageX !== session.dragCurrent.pageX ||\n nextDragCurrent.pageY !== session.dragCurrent.pageY\n ) {\n interactionSessionRef.current = {\n ...session,\n dragCurrent: nextDragCurrent,\n scrollOffset: nextScrollOffset,\n };\n postCurrentDragRect();\n } else {\n interactionSessionRef.current = {\n ...session,\n scrollOffset: nextScrollOffset,\n };\n }\n\n dragAnimationFrameId = requestAnimationFrame(syncDragRectToViewport);\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n if (\n editingElementRef?.current &&\n event.target instanceof Node &&\n editingElementRef.current.contains(event.target)\n ) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n\n const scrollOffset = getDocumentScrollOffset();\n const dragStart = getDragPositionFromClient({\n clientX: event.clientX,\n clientY: event.clientY,\n scrollOffset,\n });\n interactionSessionRef.current = {\n type: \"drag\",\n dragStart,\n dragCurrent: dragStart,\n scrollOffset,\n hasExceededThreshold: false,\n };\n dragCandidates = collectDragCandidates(scrollOffset);\n\n if (dragAnimationFrameId === null) {\n dragAnimationFrameId = requestAnimationFrame(syncDragRectToViewport);\n }\n };\n\n const handlePointerMove = (event: PointerEvent) => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\") {\n return;\n }\n\n interactionSessionRef.current = {\n ...session,\n dragCurrent: getDragPositionFromClient({\n clientX: event.clientX,\n clientY: event.clientY,\n scrollOffset: getDocumentScrollOffset(),\n }),\n };\n postCurrentDragRect();\n };\n\n const handleViewportChangeDuringDrag = () => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\" || dragAnimationFrameId !== null) {\n return;\n }\n\n dragAnimationFrameId = requestAnimationFrame(syncDragRectToViewport);\n };\n\n const commitElementSelection = ({\n targetElement,\n pointerEvent,\n }: {\n targetElement: Element;\n pointerEvent: PointerEvent;\n }) => {\n const selectionElement = getNearestSelectableElement(targetElement);\n const targetRect = selectionElement.getBoundingClientRect();\n const clickPosition: SelectModeClickPosition = {\n x: pointerEvent.clientX,\n y: pointerEvent.clientY,\n };\n\n // Paint the in-iframe selection frames synchronously for instant\n // feedback \u2014 symbolicate is a network roundtrip and we don't want\n // the visual selection to wait on it.\n const scrollOffset = getDocumentScrollOffset();\n const siblingElements =\n selectionElement instanceof HTMLElement\n ? getRepetitionSiblingElements({ element: selectionElement })\n : [];\n showElementSelectionFrames({\n elements: [selectionElement, ...siblingElements],\n scrollOffset,\n });\n\n const now = pointerEvent.timeStamp;\n const previousClick = lastClick;\n if (\n previousClick &&\n previousClick.target === selectionElement &&\n now - previousClick.time <= DOUBLE_CLICK_THRESHOLD_MS &&\n isTextEditableElement(selectionElement)\n ) {\n lastClick = null;\n onBeginEditing({\n element: selectionElement,\n descriptorPromise: previousClick.descriptorPromise,\n });\n return;\n }\n\n // NOTE (Noah, 2026-07-24): Commit the selection immediately rather than\n // deferring it behind the double-click window. A single click always\n // selects, and a double-click is just \"select + edit\", so there's nothing\n // to suppress \u2014 waiting only added a full DOUBLE_CLICK_THRESHOLD_MS of\n // latency to every click and left `interactionSessionRef` non-element in\n // the gap. Double-click is still detected via the `lastClick` timestamp\n // above; the follow-up click reuses this descriptor to open the editor.\n const data = buildElementDescriptor({\n element: selectionElement,\n clickPosition,\n siblingSelectors: siblingElements.map(buildSelector),\n });\n lastClick = {\n descriptorPromise: Promise.resolve(data),\n target: selectionElement,\n time: now,\n };\n\n if (!selectionElement.isConnected) {\n return;\n }\n interactionSessionRef.current = {\n type: \"element\",\n element: selectionElement,\n siblingElements,\n clickPosition: {\n x: pointerEvent.clientX - targetRect.left,\n y: pointerEvent.clientY - targetRect.top,\n },\n data,\n };\n void maybeSymbolicate(data).then((symbolicated) => {\n getWebsiteBuilderRpc()?.elementSelected({ data: symbolicated });\n });\n };\n\n const handlePointerUp = (event: PointerEvent) => {\n // Clicks inside the element being edited belong to the inline editor, not\n // select mode. Without this guard the double-click detection below re-runs\n // `onBeginEditing` on the same element (e.g. when repositioning the\n // caret), rebuilding the editor over itself and wiping the content.\n // Mirrors the guards in `handlePointerDown` and `handleClick`.\n if (\n editingElementRef?.current &&\n event.target instanceof Node &&\n editingElementRef.current.contains(event.target)\n ) {\n return;\n }\n const snapshot = interactionSessionRef.current;\n const wasDragging =\n snapshot.type === \"drag\" ? snapshot.hasExceededThreshold : false;\n const dragStart = snapshot.type === \"drag\" ? snapshot.dragStart : null;\n const dragCurrent =\n snapshot.type === \"drag\" ? snapshot.dragCurrent : null;\n const scrollOffset =\n snapshot.type === \"drag\"\n ? snapshot.scrollOffset\n : getDocumentScrollOffset();\n // `resetDragState` clears `dragCandidates`, so grab them first \u2014 the\n // final committed set is the same cached candidates the live preview\n // used, so preview and result never disagree.\n const candidates = dragCandidates;\n\n // Suppress the null drag-rect post: if this resolves to an area\n // selection it would otherwise flash the parent to `selection = none`\n // and wipe the frames we paint below. Click/empty-drag paths don't\n // depend on it (a sub-threshold drag never posted a rect to clear).\n resetDragState({ notifyParentDragCleared: false });\n\n if (!dragStart || snapshot.type !== \"drag\") {\n const targetElement = event.target;\n if (!(targetElement instanceof Element)) {\n return;\n }\n\n commitElementSelection({\n targetElement,\n pointerEvent: event,\n });\n return;\n }\n\n const resolvedDragCurrent = dragCurrent ?? dragStart;\n const selectionRect = getViewportSelectionRect({\n dragStart,\n dragCurrent: resolvedDragCurrent,\n scrollOffset,\n });\n\n if (!wasDragging) {\n const targetElement = event.target;\n if (!(targetElement instanceof Element)) {\n return;\n }\n\n commitElementSelection({\n targetElement,\n pointerEvent: event,\n });\n return;\n }\n\n const pageRect = getPageRectFromViewportRect({\n rect: selectionRect,\n scrollOffset,\n });\n\n const selectedCandidates = getCandidatesInSelection({\n candidates,\n selectionPageRect: pageRect,\n });\n const items = selectedCandidates.map((candidate) => {\n return buildElementDescriptor({\n element: candidate.element,\n clickPosition: getElementAnchor({\n element: candidate.element,\n selectionRect,\n }),\n });\n });\n\n interactionSessionRef.current = {\n type: \"area\",\n pageRect,\n items,\n };\n\n // Highlight each captured element so the committed area selection\n // \"sticks\" inside the iframe \u2014 matching how a single click stays\n // outlined \u2014 rather than drawing one faint box over the drag region.\n showSelectionFrames({\n frames: selectedCandidates.map((candidate) => ({\n variant: \"area\" as const,\n pageRect: {\n x: candidate.pageRect.x,\n y: candidate.pageRect.y,\n width: candidate.pageRect.width,\n height: candidate.pageRect.height,\n },\n })),\n });\n\n void Promise.all(items.map(maybeSymbolicate)).then(\n (symbolicatedItems) => {\n getWebsiteBuilderRpc()?.areaSelected({\n rect: selectionRect,\n items: symbolicatedItems,\n });\n },\n );\n };\n\n const handleClick = (event: MouseEvent) => {\n if (\n editingElementRef?.current &&\n event.target instanceof Node &&\n editingElementRef.current.contains(event.target)\n ) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n };\n\n const handlePointerCancel = () => {\n resetDragState();\n };\n\n const handleWindowBlur = () => {\n resetDragState();\n };\n\n document.addEventListener(\"pointerdown\", handlePointerDown, true);\n document.addEventListener(\"pointermove\", handlePointerMove, true);\n document.addEventListener(\"pointerup\", handlePointerUp, true);\n document.addEventListener(\"pointercancel\", handlePointerCancel, true);\n document.addEventListener(\"click\", handleClick, true);\n document.addEventListener(\"scroll\", handleViewportChangeDuringDrag, true);\n window.addEventListener(\"blur\", handleWindowBlur);\n window.addEventListener(\"resize\", handleViewportChangeDuringDrag);\n\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown, true);\n document.removeEventListener(\"pointermove\", handlePointerMove, true);\n document.removeEventListener(\"pointerup\", handlePointerUp, true);\n document.removeEventListener(\"pointercancel\", handlePointerCancel, true);\n document.removeEventListener(\"click\", handleClick, true);\n document.removeEventListener(\n \"scroll\",\n handleViewportChangeDuringDrag,\n true,\n );\n window.removeEventListener(\"blur\", handleWindowBlur);\n window.removeEventListener(\"resize\", handleViewportChangeDuringDrag);\n resetDragState();\n };\n }, [displayMode, editingElementRef, interactionSessionRef, onBeginEditing]);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { MutableRefObject } from \"react\";\nimport type {\n DisplayMode,\n SelectableData,\n SelectModeClickPosition,\n} from \"schemas/generated/selectMode\";\nimport type { DragCandidate } from \"../interactions/selectionGeometry\";\nimport type { SelectModeInteractionSession } from \"../selectModeSession\";\n\nimport { useEffect } from \"react\";\n\nimport {\n buildElementDescriptor,\n buildSelector,\n getNearestSelectableElement,\n} from \"../descriptor/elementDescriptor\";\nimport { getWebsiteBuilderRpc } from \"../iframeRpcChannel\";\nimport {\n collectDragCandidates,\n getCandidatesInSelection,\n getDocumentScrollOffset,\n getDragPositionFromClient,\n getElementAnchor,\n getPageRectFromViewportRect,\n getViewportRectFromPageRect,\n getViewportSelectionRect,\n} from \"../interactions/selectionGeometry\";\nimport {\n showElementSelectionFrames,\n showSelectionFrames,\n} from \"../selectionFrame\";\nimport { IDLE_SESSION } from \"../selectModeSession\";\nimport { symbolicateSelectedElement } from \"../symbolicate\";\nimport { isTextEditableElement } from \"./useEditModeStateMachine\";\nimport { getRepetitionSiblingElements } from \"./useSiblingResolution\";\n\nconst DOUBLE_CLICK_THRESHOLD_MS = 500;\n\n// React fibers carry only Turbopack chunk paths; resolving them to the\n// user's source file is async and only meaningful for \"react-element\"\n// kinds. Plan selectables already point at the right thing.\nasync function maybeSymbolicate(data: SelectableData): Promise<SelectableData> {\n return data.kind === \"react-element\"\n ? symbolicateSelectedElement(data)\n : data;\n}\n\n/**\n * Owns the iframe-side pointer interactions that drive selection:\n *\n * - On `pointerdown` we open a `drag` session (storing both client + page\n * coords plus the current scroll offset). We don't yet know if this will\n * become a click or an actual drag.\n * - On `pointermove` we update the drag rect and post `DRAG_RECT_UPDATED`\n * to the parent so the live drag rectangle can render. We only flip\n * `hasExceededThreshold` once the rect grows past 6\u00D76 px so that a tiny\n * accidental drag still resolves as a click.\n * - On `pointerup` we either:\n * - resolve as an `ELEMENT_SELECTED` (single click / sub-threshold drag)\n * - resolve as an `AREA_SELECTED` (drag past threshold), filtering the\n * candidates snapshotted at drag start against the final rectangle to\n * enumerate which descendants the user enclosed.\n * - During an active drag a `requestAnimationFrame` loop keeps the rect in\n * sync with the page scroll so the rectangle visually \"sticks\" to the\n * page rather than the viewport.\n *\n * We capture-listen and `preventDefault`/`stopPropagation` clicks so the\n * underlying page can't navigate or trigger handlers while the user is\n * working in selection mode.\n *\n * @author Kevin O'Connell 2026-04-17\n */\nexport function useSelectionInteractions({\n displayMode,\n editingElementRef,\n interactionSessionRef,\n onBeginEditing,\n}: {\n displayMode: DisplayMode;\n editingElementRef?: MutableRefObject<HTMLElement | null>;\n interactionSessionRef: MutableRefObject<SelectModeInteractionSession>;\n onBeginEditing: (args: {\n element: Element;\n descriptorPromise: Promise<SelectableData>;\n }) => void;\n}) {\n // eslint-disable-next-line replo/no-use-effect -- Legacy effect - may or may not be necessary\n useEffect(() => {\n if (displayMode !== \"selection\") {\n return;\n }\n\n let dragAnimationFrameId: number | null = null;\n const editingPointerIds = new Set<number>();\n let lastClick: {\n descriptorPromise: Promise<SelectableData>;\n target: Element;\n time: number;\n } | null = null;\n // Snapshot of the page's meaningful elements + their page rects, taken\n // once when a drag begins so per-move hit-testing avoids a full-DOM scan.\n let dragCandidates: DragCandidate[] = [];\n\n const stopDragAnimation = () => {\n if (dragAnimationFrameId === null) {\n return;\n }\n\n cancelAnimationFrame(dragAnimationFrameId);\n dragAnimationFrameId = null;\n };\n\n // `notifyParentDragCleared` posts a null drag rect so the parent tears\n // down the live drag overlay. The area-commit path suppresses it: the\n // parent maps a null drag rect to `selection = none`, which round-trips\n // back as `setSelectionType(\"none\")` and wipes the in-iframe frames we're\n // about to paint. The follow-up `areaSelected` supersedes the drag overlay\n // on its own, so the null post is pure collateral damage there.\n const resetDragState = ({\n notifyParentDragCleared = true,\n }: { notifyParentDragCleared?: boolean } = {}) => {\n const currentSession = interactionSessionRef.current;\n\n stopDragAnimation();\n\n if (currentSession.type !== \"drag\") {\n dragCandidates = [];\n return;\n }\n\n if (notifyParentDragCleared && currentSession.hasExceededThreshold) {\n getWebsiteBuilderRpc()?.dragRectUpdated({\n dragRect: null,\n selectionRects: [],\n });\n }\n\n dragCandidates = [];\n interactionSessionRef.current = IDLE_SESSION;\n };\n\n const postCurrentDragRect = () => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\") {\n return;\n }\n\n const rect = getViewportSelectionRect({\n dragStart: session.dragStart,\n dragCurrent: session.dragCurrent,\n scrollOffset: session.scrollOffset,\n });\n\n if (\n rect.width <= 6 &&\n rect.height <= 6 &&\n !session.hasExceededThreshold\n ) {\n return;\n }\n\n if (!session.hasExceededThreshold) {\n interactionSessionRef.current = {\n ...session,\n hasExceededThreshold: true,\n };\n }\n\n // Cheap hit-test against the candidates we snapshotted at drag start,\n // projected back to viewport coords so the parent can paint a live\n // highlight on each element the drag will capture. No DOM scan here.\n const selectionPageRect = getPageRectFromViewportRect({\n rect,\n scrollOffset: session.scrollOffset,\n });\n const selectionRects = getCandidatesInSelection({\n candidates: dragCandidates,\n selectionPageRect,\n }).map((candidate) => ({\n id: candidate.id,\n rect: getViewportRectFromPageRect({\n rect: candidate.pageRect,\n scrollOffset: session.scrollOffset,\n }),\n }));\n\n getWebsiteBuilderRpc()?.dragRectUpdated({\n dragRect: rect,\n selectionRects,\n });\n };\n\n const syncDragRectToViewport = () => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\") {\n dragAnimationFrameId = null;\n return;\n }\n\n const nextScrollOffset = getDocumentScrollOffset();\n const nextDragCurrent = getDragPositionFromClient({\n clientX: session.dragCurrent.clientX,\n clientY: session.dragCurrent.clientY,\n scrollOffset: nextScrollOffset,\n });\n\n if (\n nextDragCurrent.pageX !== session.dragCurrent.pageX ||\n nextDragCurrent.pageY !== session.dragCurrent.pageY\n ) {\n interactionSessionRef.current = {\n ...session,\n dragCurrent: nextDragCurrent,\n scrollOffset: nextScrollOffset,\n };\n postCurrentDragRect();\n } else {\n interactionSessionRef.current = {\n ...session,\n scrollOffset: nextScrollOffset,\n };\n }\n\n dragAnimationFrameId = requestAnimationFrame(syncDragRectToViewport);\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n editingPointerIds.delete(event.pointerId);\n if (\n editingElementRef?.current &&\n event.target instanceof Node &&\n editingElementRef.current.contains(event.target)\n ) {\n editingPointerIds.add(event.pointerId);\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n\n const scrollOffset = getDocumentScrollOffset();\n const dragStart = getDragPositionFromClient({\n clientX: event.clientX,\n clientY: event.clientY,\n scrollOffset,\n });\n interactionSessionRef.current = {\n type: \"drag\",\n dragStart,\n dragCurrent: dragStart,\n scrollOffset,\n hasExceededThreshold: false,\n };\n dragCandidates = collectDragCandidates(scrollOffset);\n\n if (dragAnimationFrameId === null) {\n dragAnimationFrameId = requestAnimationFrame(syncDragRectToViewport);\n }\n };\n\n const handlePointerMove = (event: PointerEvent) => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\") {\n return;\n }\n\n interactionSessionRef.current = {\n ...session,\n dragCurrent: getDragPositionFromClient({\n clientX: event.clientX,\n clientY: event.clientY,\n scrollOffset: getDocumentScrollOffset(),\n }),\n };\n postCurrentDragRect();\n };\n\n const handleViewportChangeDuringDrag = () => {\n const session = interactionSessionRef.current;\n if (session.type !== \"drag\" || dragAnimationFrameId !== null) {\n return;\n }\n\n dragAnimationFrameId = requestAnimationFrame(syncDragRectToViewport);\n };\n\n const commitElementSelection = ({\n targetElement,\n pointerEvent,\n }: {\n targetElement: Element;\n pointerEvent: PointerEvent;\n }) => {\n const selectionElement = getNearestSelectableElement(targetElement);\n const targetRect = selectionElement.getBoundingClientRect();\n const clickPosition: SelectModeClickPosition = {\n x: pointerEvent.clientX,\n y: pointerEvent.clientY,\n };\n\n // Paint the in-iframe selection frames synchronously for instant\n // feedback \u2014 symbolicate is a network roundtrip and we don't want\n // the visual selection to wait on it.\n const scrollOffset = getDocumentScrollOffset();\n const siblingElements =\n selectionElement instanceof HTMLElement\n ? getRepetitionSiblingElements({ element: selectionElement })\n : [];\n showElementSelectionFrames({\n elements: [selectionElement, ...siblingElements],\n scrollOffset,\n });\n\n const now = pointerEvent.timeStamp;\n const previousClick = lastClick;\n if (\n previousClick &&\n previousClick.target === selectionElement &&\n now - previousClick.time <= DOUBLE_CLICK_THRESHOLD_MS &&\n isTextEditableElement(selectionElement)\n ) {\n lastClick = null;\n onBeginEditing({\n element: selectionElement,\n descriptorPromise: previousClick.descriptorPromise,\n });\n return;\n }\n\n // NOTE (Noah, 2026-07-24): Commit the selection immediately rather than\n // deferring it behind the double-click window. A single click always\n // selects, and a double-click is just \"select + edit\", so there's nothing\n // to suppress \u2014 waiting only added a full DOUBLE_CLICK_THRESHOLD_MS of\n // latency to every click and left `interactionSessionRef` non-element in\n // the gap. Double-click is still detected via the `lastClick` timestamp\n // above; the follow-up click reuses this descriptor to open the editor.\n const data = buildElementDescriptor({\n element: selectionElement,\n clickPosition,\n siblingSelectors: siblingElements.map(buildSelector),\n });\n lastClick = {\n descriptorPromise: Promise.resolve(data),\n target: selectionElement,\n time: now,\n };\n\n if (!selectionElement.isConnected) {\n return;\n }\n interactionSessionRef.current = {\n type: \"element\",\n element: selectionElement,\n siblingElements,\n clickPosition: {\n x: pointerEvent.clientX - targetRect.left,\n y: pointerEvent.clientY - targetRect.top,\n },\n data,\n };\n void maybeSymbolicate(data).then((symbolicated) => {\n getWebsiteBuilderRpc()?.elementSelected({ data: symbolicated });\n });\n };\n\n const handlePointerUp = (event: PointerEvent) => {\n if (editingPointerIds.delete(event.pointerId)) {\n return;\n }\n // Clicks inside the element being edited belong to the inline editor, not\n // select mode. Without this guard the double-click detection below re-runs\n // `onBeginEditing` on the same element (e.g. when repositioning the\n // caret), rebuilding the editor over itself and wiping the content.\n // Mirrors the guards in `handlePointerDown` and `handleClick`.\n if (\n editingElementRef?.current &&\n event.target instanceof Node &&\n editingElementRef.current.contains(event.target)\n ) {\n return;\n }\n const snapshot = interactionSessionRef.current;\n const wasDragging =\n snapshot.type === \"drag\" ? snapshot.hasExceededThreshold : false;\n const dragStart = snapshot.type === \"drag\" ? snapshot.dragStart : null;\n const dragCurrent =\n snapshot.type === \"drag\" ? snapshot.dragCurrent : null;\n const scrollOffset =\n snapshot.type === \"drag\"\n ? snapshot.scrollOffset\n : getDocumentScrollOffset();\n // `resetDragState` clears `dragCandidates`, so grab them first \u2014 the\n // final committed set is the same cached candidates the live preview\n // used, so preview and result never disagree.\n const candidates = dragCandidates;\n\n // Suppress the null drag-rect post: if this resolves to an area\n // selection it would otherwise flash the parent to `selection = none`\n // and wipe the frames we paint below. Click/empty-drag paths don't\n // depend on it (a sub-threshold drag never posted a rect to clear).\n resetDragState({ notifyParentDragCleared: false });\n\n if (!dragStart || snapshot.type !== \"drag\") {\n const targetElement = event.target;\n if (!(targetElement instanceof Element)) {\n return;\n }\n\n commitElementSelection({\n targetElement,\n pointerEvent: event,\n });\n return;\n }\n\n const resolvedDragCurrent = dragCurrent ?? dragStart;\n const selectionRect = getViewportSelectionRect({\n dragStart,\n dragCurrent: resolvedDragCurrent,\n scrollOffset,\n });\n\n if (!wasDragging) {\n const targetElement = event.target;\n if (!(targetElement instanceof Element)) {\n return;\n }\n\n commitElementSelection({\n targetElement,\n pointerEvent: event,\n });\n return;\n }\n\n const pageRect = getPageRectFromViewportRect({\n rect: selectionRect,\n scrollOffset,\n });\n\n const selectedCandidates = getCandidatesInSelection({\n candidates,\n selectionPageRect: pageRect,\n });\n const items = selectedCandidates.map((candidate) => {\n return buildElementDescriptor({\n element: candidate.element,\n clickPosition: getElementAnchor({\n element: candidate.element,\n selectionRect,\n }),\n });\n });\n\n interactionSessionRef.current = {\n type: \"area\",\n pageRect,\n items,\n };\n\n // Highlight each captured element so the committed area selection\n // \"sticks\" inside the iframe \u2014 matching how a single click stays\n // outlined \u2014 rather than drawing one faint box over the drag region.\n showSelectionFrames({\n frames: selectedCandidates.map((candidate) => ({\n variant: \"area\" as const,\n pageRect: {\n x: candidate.pageRect.x,\n y: candidate.pageRect.y,\n width: candidate.pageRect.width,\n height: candidate.pageRect.height,\n },\n })),\n });\n\n void Promise.all(items.map(maybeSymbolicate)).then(\n (symbolicatedItems) => {\n getWebsiteBuilderRpc()?.areaSelected({\n rect: selectionRect,\n items: symbolicatedItems,\n });\n },\n );\n };\n\n const handleClick = (event: MouseEvent) => {\n if (\n editingElementRef?.current &&\n event.target instanceof Node &&\n editingElementRef.current.contains(event.target)\n ) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n };\n\n const handlePointerCancel = (event: PointerEvent) => {\n editingPointerIds.delete(event.pointerId);\n resetDragState();\n };\n\n const handleWindowBlur = () => {\n editingPointerIds.clear();\n resetDragState();\n };\n\n document.addEventListener(\"pointerdown\", handlePointerDown, true);\n document.addEventListener(\"pointermove\", handlePointerMove, true);\n document.addEventListener(\"pointerup\", handlePointerUp, true);\n document.addEventListener(\"pointercancel\", handlePointerCancel, true);\n document.addEventListener(\"click\", handleClick, true);\n document.addEventListener(\"scroll\", handleViewportChangeDuringDrag, true);\n window.addEventListener(\"blur\", handleWindowBlur);\n window.addEventListener(\"resize\", handleViewportChangeDuringDrag);\n\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown, true);\n document.removeEventListener(\"pointermove\", handlePointerMove, true);\n document.removeEventListener(\"pointerup\", handlePointerUp, true);\n document.removeEventListener(\"pointercancel\", handlePointerCancel, true);\n document.removeEventListener(\"click\", handleClick, true);\n document.removeEventListener(\n \"scroll\",\n handleViewportChangeDuringDrag,\n true,\n );\n window.removeEventListener(\"blur\", handleWindowBlur);\n window.removeEventListener(\"resize\", handleViewportChangeDuringDrag);\n resetDragState();\n };\n }, [displayMode, editingElementRef, interactionSessionRef, onBeginEditing]);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }