@replohq/sandbox-runtime 1.7.1 → 1.7.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.
Files changed (123) hide show
  1. package/ClientErrorBoundary.d.ts +1 -1
  2. package/ClientErrorBoundary.js +0 -5
  3. package/DocumentReadyBeacon.js +0 -1
  4. package/LinkInterceptor.js +0 -1
  5. package/NavigationReceiver.js +0 -1
  6. package/NextErrorReporter.js +0 -1
  7. package/README.md +48 -0
  8. package/_vendor/replo-utils/lib/crypto.d.ts +2 -8
  9. package/_vendor/replo-utils/lib/fonts.d.ts +8 -0
  10. package/_vendor/replo-utils/lib/fonts.mjs +12 -14
  11. package/_vendor/replo-utils/lib/geometry.mjs +0 -1
  12. package/_vendor/replo-utils/lib/math.d.ts +0 -4
  13. package/_vendor/replo-utils/lib/math.mjs +0 -1
  14. package/_vendor/replo-utils/lib/posthogReplay.mjs +0 -1
  15. package/_vendor/replo-utils/react/use-iframe-rpc-channel.mjs +0 -1
  16. package/_vendor/replo-utils/react/use-viewport-snapshot-responder.mjs +9 -25
  17. package/_vendor/schemas/componentPreview.mjs +0 -4
  18. package/_vendor/schemas/designLibrary.mjs +0 -2
  19. package/_vendor/schemas/errors.d.ts +0 -3
  20. package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +1 -1
  21. package/_vendor/schemas/iframeRpcChannel.d.ts +1 -1
  22. package/_vendor/schemas/iframeRpcChannel.mjs +0 -22
  23. package/_vendor/schemas/pageAnnotations.mjs +0 -3
  24. package/_vendor/schemas/selectMode.d.ts +0 -4
  25. package/_vendor/schemas/selectModeIframeRpc.d.ts +4 -4
  26. package/_vendor/schemas/selectModeIframeRpc.mjs +2 -12
  27. package/annotations/AnnotationLayerMount.js +0 -1
  28. package/annotations/annotationController.js +0 -3
  29. package/annotations/bridgeGate.js +0 -4
  30. package/buildMetadata.js +3 -3
  31. package/chunk-3YA3QXUQ.mjs +1 -4
  32. package/chunk-FLYEIRFK.mjs +0 -1
  33. package/chunk-G3S6ZNPF.mjs +0 -7
  34. package/chunk-JUKCUPQ6.mjs +5 -129
  35. package/chunk-SGKQ5HGT.mjs +0 -1
  36. package/chunk-TESFJQID.mjs +0 -1
  37. package/chunk-UOBGRB5I.mjs +0 -5
  38. package/design-library-preview/DesignLibraryPreview.js +0 -1
  39. package/next/component-preview-client.js +0 -1
  40. package/next/component-preview-href.js +0 -1
  41. package/next/component-preview-props.js +0 -1
  42. package/next/component-preview.js +0 -1
  43. package/next/config.js +0 -1
  44. package/package.json +4 -4
  45. package/posthog-relay.js +0 -5
  46. package/sandbox-runtime.js +0 -1
  47. package/select-mode/EditorSelection.d.ts +0 -2
  48. package/select-mode/EditorSelection.js +0 -1
  49. package/select-mode/annotationFrames.js +0 -1
  50. package/select-mode/descriptor/elementDescriptor.d.ts +0 -2
  51. package/select-mode/descriptor/elementDescriptor.js +0 -1
  52. package/select-mode/descriptor/styleExtraction.js +0 -1
  53. package/select-mode/displayModeStore.js +0 -2
  54. package/select-mode/fast-refresh-relay.js +0 -1
  55. package/select-mode/fiber.js +1 -5
  56. package/select-mode/hooks/useCrosshairCursor.d.ts +0 -2
  57. package/select-mode/hooks/useCrosshairCursor.js +0 -1
  58. package/select-mode/hooks/useEditModeStateMachine.js +0 -1
  59. package/select-mode/hooks/useOptimisticOverrides.js +0 -1
  60. package/select-mode/hooks/useParentMessaging.d.ts +0 -2
  61. package/select-mode/hooks/useParentMessaging.js +0 -1
  62. package/select-mode/hooks/useSelectModeController.js +0 -1
  63. package/select-mode/hooks/useSelectionHover.d.ts +0 -2
  64. package/select-mode/hooks/useSelectionHover.js +0 -1
  65. package/select-mode/hooks/useSelectionInteractions.d.ts +0 -2
  66. package/select-mode/hooks/useSelectionInteractions.js +0 -1
  67. package/select-mode/hooks/useSelectionScrollSync.d.ts +0 -2
  68. package/select-mode/hooks/useSelectionScrollSync.js +0 -1
  69. package/select-mode/hooks/useSiblingResolution.js +0 -1
  70. package/select-mode/iframeRpcChannel.d.ts +2 -2
  71. package/select-mode/iframeRpcChannel.js +0 -1
  72. package/select-mode/inlineTextMarks.js +0 -1
  73. package/select-mode/interactions/selectionGeometry.d.ts +0 -20
  74. package/select-mode/interactions/selectionGeometry.js +0 -1
  75. package/select-mode/optimisticOverrideDom.js +0 -1
  76. package/select-mode/selectModeSession.js +0 -1
  77. package/select-mode/selectionFrame.d.ts +0 -7
  78. package/select-mode/selectionFrame.js +0 -1
  79. package/select-mode/selectionPublish.js +0 -1
  80. package/select-mode/symbolicate.js +0 -1
  81. package/select-mode/tiptapInlineEditor.js +0 -5
  82. package/ClientErrorBoundary.js.map +0 -7
  83. package/DocumentReadyBeacon.js.map +0 -7
  84. package/LinkInterceptor.js.map +0 -7
  85. package/NavigationReceiver.js.map +0 -7
  86. package/NextErrorReporter.js.map +0 -7
  87. package/annotations/AnnotationLayerMount.js.map +0 -7
  88. package/annotations/annotationController.js.map +0 -7
  89. package/annotations/bridgeGate.js.map +0 -7
  90. package/buildMetadata.js.map +0 -7
  91. package/design-library-preview/DesignLibraryPreview.js.map +0 -7
  92. package/next/component-preview-client.js.map +0 -7
  93. package/next/component-preview-href.js.map +0 -7
  94. package/next/component-preview-props.js.map +0 -7
  95. package/next/component-preview.js.map +0 -7
  96. package/next/config.js.map +0 -7
  97. package/posthog-relay.js.map +0 -7
  98. package/sandbox-runtime.js.map +0 -7
  99. package/select-mode/EditorSelection.js.map +0 -7
  100. package/select-mode/annotationFrames.js.map +0 -7
  101. package/select-mode/descriptor/elementDescriptor.js.map +0 -7
  102. package/select-mode/descriptor/styleExtraction.js.map +0 -7
  103. package/select-mode/displayModeStore.js.map +0 -7
  104. package/select-mode/fast-refresh-relay.js.map +0 -7
  105. package/select-mode/fiber.js.map +0 -7
  106. package/select-mode/hooks/useCrosshairCursor.js.map +0 -7
  107. package/select-mode/hooks/useEditModeStateMachine.js.map +0 -7
  108. package/select-mode/hooks/useOptimisticOverrides.js.map +0 -7
  109. package/select-mode/hooks/useParentMessaging.js.map +0 -7
  110. package/select-mode/hooks/useSelectModeController.js.map +0 -7
  111. package/select-mode/hooks/useSelectionHover.js.map +0 -7
  112. package/select-mode/hooks/useSelectionInteractions.js.map +0 -7
  113. package/select-mode/hooks/useSelectionScrollSync.js.map +0 -7
  114. package/select-mode/hooks/useSiblingResolution.js.map +0 -7
  115. package/select-mode/iframeRpcChannel.js.map +0 -7
  116. package/select-mode/inlineTextMarks.js.map +0 -7
  117. package/select-mode/interactions/selectionGeometry.js.map +0 -7
  118. package/select-mode/optimisticOverrideDom.js.map +0 -7
  119. package/select-mode/selectModeSession.js.map +0 -7
  120. package/select-mode/selectionFrame.js.map +0 -7
  121. package/select-mode/selectionPublish.js.map +0 -7
  122. package/select-mode/symbolicate.js.map +0 -7
  123. package/select-mode/tiptapInlineEditor.js.map +0 -7
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/hooks/useOptimisticOverrides.ts"],
4
- "sourcesContent": ["import type { SelectModeOptimisticUpdatePayload } from \"schemas/generated/selectMode\";\n\nimport { useCallback } from \"react\";\n\nimport { buildSelector } from \"../descriptor/elementDescriptor\";\nimport {\n SELECT_MODE_OVERRIDE_ATTRIBUTE,\n SELECT_MODE_OVERRIDE_STYLE_ATTRIBUTE,\n} from \"../optimisticOverrideDom\";\nimport { getRepetitionSiblingSelectors } from \"./useSiblingResolution\";\n\ntype OverrideTarget = {\n element: HTMLElement;\n originalState: OriginalPayloadState;\n selector: string;\n};\n\ntype OriginalPayloadState =\n | {\n kind: \"attributes\";\n values: { name: string; value: string | null }[];\n }\n | { kind: \"content\"; innerHTML: string }\n | { kind: \"css\" };\n\ntype IframeOverride = {\n editId: string;\n payload: SelectModeOptimisticUpdatePayload;\n registrationTimeout: number;\n sessionId: string | null;\n state: \"live\" | \"fired\";\n targets: OverrideTarget[];\n token: string;\n};\n\nconst OVERRIDE_REGISTRATION_TIMEOUT_MS = 15_000;\nconst SESSION_OUTCOME_RETENTION_MS = 60_000;\nconst OVERRIDE_REGISTRY_KEY = \"reploSelectOverrideRegistryV2\";\nconst SESSION_OUTCOME_REGISTRY_KEY = \"reploSelectOverrideSessionOutcomesV2\";\n\ntype SessionOutcome = \"persisted\" | \"failed\";\n\nfunction getOverrideList(): IframeOverride[] {\n const existing: unknown = Reflect.get(window, OVERRIDE_REGISTRY_KEY);\n if (Array.isArray(existing)) {\n return existing;\n }\n const overrides: IframeOverride[] = [];\n Reflect.set(window, OVERRIDE_REGISTRY_KEY, overrides);\n return overrides;\n}\n\nfunction setOverrideList(overrides: IframeOverride[]) {\n Reflect.set(window, OVERRIDE_REGISTRY_KEY, overrides);\n}\n\nfunction getSessionOutcomes(): Map<string, SessionOutcome> {\n const existing: unknown = Reflect.get(window, SESSION_OUTCOME_REGISTRY_KEY);\n if (existing instanceof Map) {\n return existing;\n }\n const outcomes = new Map<string, SessionOutcome>();\n Reflect.set(window, SESSION_OUTCOME_REGISTRY_KEY, outcomes);\n return outcomes;\n}\n\nfunction getElementsForTargetMode({\n element,\n targetMode,\n}: {\n element: HTMLElement;\n targetMode: \"primary\" | \"group\";\n}) {\n if (targetMode === \"primary\") {\n return [element];\n }\n\n return [\n element,\n ...getRepetitionSiblingSelectors({ element })\n .map((selector) => document.querySelector(selector))\n .filter((candidate): candidate is HTMLElement => {\n return candidate instanceof HTMLElement;\n }),\n ];\n}\n\nfunction isImageSourcePayload({\n element,\n payload,\n}: {\n element: HTMLElement;\n payload: SelectModeOptimisticUpdatePayload;\n}) {\n return (\n payload.kind === \"attribute\" &&\n payload.name.toLowerCase() === \"src\" &&\n element instanceof HTMLImageElement\n );\n}\n\nfunction getOriginalState({\n element,\n payload,\n}: {\n element: HTMLElement;\n payload: SelectModeOptimisticUpdatePayload;\n}): OriginalPayloadState {\n if (payload.kind === \"attribute\") {\n const names = isImageSourcePayload({ element, payload })\n ? [payload.name, \"srcset\"]\n : [payload.name];\n return {\n kind: \"attributes\",\n values: names.map((name) => ({\n name,\n value: element.getAttribute(name),\n })),\n };\n }\n if (payload.kind === \"content\") {\n return { kind: \"content\", innerHTML: element.innerHTML };\n }\n return { kind: \"css\" };\n}\n\nfunction getStyleElement(token: string) {\n return document.querySelector<HTMLStyleElement>(\n `style[${SELECT_MODE_OVERRIDE_STYLE_ATTRIBUTE}=\"${token}\"]`,\n );\n}\n\nfunction addToken(element: HTMLElement, token: string) {\n const tokens = new Set(\n (element.getAttribute(SELECT_MODE_OVERRIDE_ATTRIBUTE) ?? \"\")\n .split(/\\s+/)\n .filter(Boolean),\n );\n tokens.add(token);\n element.setAttribute(SELECT_MODE_OVERRIDE_ATTRIBUTE, [...tokens].join(\" \"));\n}\n\nfunction removeToken(element: HTMLElement, token: string) {\n const tokens = (element.getAttribute(SELECT_MODE_OVERRIDE_ATTRIBUTE) ?? \"\")\n .split(/\\s+/)\n .filter((candidate) => candidate && candidate !== token);\n if (tokens.length === 0) {\n element.removeAttribute(SELECT_MODE_OVERRIDE_ATTRIBUTE);\n return;\n }\n element.setAttribute(SELECT_MODE_OVERRIDE_ATTRIBUTE, tokens.join(\" \"));\n}\n\nfunction applyPayload({\n element,\n payload,\n token,\n}: {\n element: HTMLElement;\n payload: SelectModeOptimisticUpdatePayload;\n token: string;\n}) {\n if (payload.kind === \"css\") {\n addToken(element, token);\n return;\n }\n if (payload.kind === \"attribute\") {\n if (isImageSourcePayload({ element, payload })) {\n element.removeAttribute(\"srcset\");\n }\n element.setAttribute(payload.name, payload.value);\n return;\n }\n element.innerHTML = payload.innerHTML;\n}\n\nfunction restoreOriginalState({\n element,\n originalState,\n}: {\n element: HTMLElement;\n originalState: OriginalPayloadState;\n}) {\n if (originalState.kind === \"attributes\") {\n for (const { name, value } of originalState.values) {\n if (value === null) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value);\n }\n }\n return;\n }\n if (originalState.kind === \"content\") {\n element.innerHTML = originalState.innerHTML;\n }\n}\n\nfunction installCssRule(override: IframeOverride) {\n if (override.payload.kind !== \"css\") {\n return;\n }\n const style = document.createElement(\"style\");\n style.dataset.reploSelectOverride = override.token;\n style.textContent = `[${SELECT_MODE_OVERRIDE_ATTRIBUTE}~=\"${override.token}\"] { ${override.payload.property}: ${override.payload.value ?? \"revert\"} !important; }`;\n document.head.append(style);\n}\n\nfunction resolveTarget(target: OverrideTarget) {\n if (target.element.isConnected) {\n return target.element;\n }\n const replacement = document.querySelector(target.selector);\n return replacement instanceof HTMLElement ? replacement : null;\n}\n\nfunction reapplyOverride({\n override,\n skipElement,\n}: {\n override: IframeOverride;\n skipElement: HTMLElement | null;\n}) {\n for (const target of override.targets) {\n const element = resolveTarget(target);\n if (!element || (skipElement && element.contains(skipElement))) {\n continue;\n }\n if (element !== target.element) {\n target.element = element;\n target.originalState = getOriginalState({\n element,\n payload: override.payload,\n });\n }\n applyPayload({ element, payload: override.payload, token: override.token });\n }\n}\n\nfunction removeOverride({\n editId,\n outcome,\n}: {\n editId: string;\n outcome: SessionOutcome;\n}) {\n const override = getOverrideList().find(\n (candidate) => candidate.editId === editId,\n );\n if (!override) {\n return;\n }\n\n clearTimeout(override.registrationTimeout);\n getStyleElement(override.token)?.remove();\n for (const target of override.targets) {\n const element = resolveTarget(target);\n if (!element) {\n continue;\n }\n removeToken(element, override.token);\n if (outcome === \"failed\") {\n restoreOriginalState({\n element,\n originalState: target.originalState,\n });\n }\n }\n setOverrideList(\n getOverrideList().filter((candidate) => candidate.editId !== editId),\n );\n\n if (outcome === \"failed\") {\n for (const remainingOverride of getOverrideList()) {\n reapplyOverride({ override: remainingOverride, skipElement: null });\n }\n }\n}\n\nexport function useOptimisticOverrides() {\n const applyOptimisticUpdate = useCallback(\n ({\n editId,\n payload,\n targetSelector,\n targetMode,\n }: {\n editId: string;\n payload: SelectModeOptimisticUpdatePayload;\n targetSelector: string;\n targetMode: \"primary\" | \"group\";\n }) => {\n const targetElement = document.querySelector(targetSelector);\n if (!(targetElement instanceof HTMLElement)) {\n return;\n }\n\n removeOverride({ editId, outcome: \"failed\" });\n const elements = getElementsForTargetMode({\n element: targetElement,\n targetMode,\n });\n const token = `override-${editId}`;\n const override: IframeOverride = {\n editId,\n payload,\n registrationTimeout: window.setTimeout(() => {\n removeOverride({ editId, outcome: \"failed\" });\n }, OVERRIDE_REGISTRATION_TIMEOUT_MS),\n sessionId: null,\n state: \"live\",\n targets: elements.map((element) => ({\n element,\n originalState: getOriginalState({ element, payload }),\n selector: buildSelector(element),\n })),\n token,\n };\n getOverrideList().push(override);\n installCssRule(override);\n reapplyOverride({ override, skipElement: null });\n },\n [],\n );\n\n const reapplyOverrides = useCallback(\n ({ skipElement }: { skipElement: HTMLElement | null }) => {\n for (const override of getOverrideList()) {\n reapplyOverride({ override, skipElement });\n }\n },\n [],\n );\n\n const markCommitted = useCallback((editId: string, sessionId: string) => {\n const override = getOverrideList().find((candidate) => {\n return candidate.editId === editId;\n });\n if (!override) {\n return;\n }\n clearTimeout(override.registrationTimeout);\n override.sessionId = sessionId;\n override.state = \"fired\";\n const outcome = getSessionOutcomes().get(sessionId);\n if (outcome) {\n removeOverride({ editId, outcome });\n }\n }, []);\n\n const resolveSessionOverrides = useCallback(\n (sessionId: string, outcome: SessionOutcome) => {\n getSessionOutcomes().set(sessionId, outcome);\n window.setTimeout(() => {\n getSessionOutcomes().delete(sessionId);\n }, SESSION_OUTCOME_RETENTION_MS);\n const editIds = getOverrideList()\n .filter((override) => override.sessionId === sessionId)\n .map((override) => override.editId);\n for (const editId of editIds) {\n removeOverride({ editId, outcome });\n }\n },\n [],\n );\n\n const revertOverride = useCallback((editId: string) => {\n removeOverride({ editId, outcome: \"failed\" });\n }, []);\n\n return {\n applyOptimisticUpdate,\n markCommitted,\n reapplyOverrides,\n resolveSessionOverrides,\n revertOverride,\n };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/hooks/useParentMessaging.ts"],
4
- "sourcesContent": ["import type {\n DisplayMode,\n SelectModeFormatCommand,\n SelectModeOptimisticUpdatePayload,\n SelectModeSelectionType,\n} from \"schemas/generated/selectMode\";\n\nimport { useEffect, useMemo } from \"react\";\n\nimport { useIframeRpcChannel } from \"replo-utils/react/use-iframe-rpc-channel\";\nimport { iframeRuntimeBuildMetadataSchema } from \"schemas/selectModeIframeRpc\";\nimport { z } from \"zod\";\n\nimport { BUILD_METADATA } from \"../../buildMetadata\";\nimport {\n getSelectModeIframeRpcChannel,\n getWebsiteBuilderRpc,\n setSelectModeParentHandlers,\n} from \"../iframeRpcChannel\";\n\nconst SDK_BUILD_METADATA_SPECIFIER = \"@replohq/sdk/lib/buildMetadata\";\n\nconst sdkBuildMetadataModuleSchema = z.object({\n BUILD_METADATA: iframeRuntimeBuildMetadataSchema,\n});\n\nasync function announceSdkBuildMetadata() {\n try {\n const sdkBuildMetadata = sdkBuildMetadataModuleSchema.safeParse(\n await import(SDK_BUILD_METADATA_SPECIFIER),\n );\n if (sdkBuildMetadata.success) {\n getWebsiteBuilderRpc()?.iframeReady(sdkBuildMetadata.data.BUILD_METADATA);\n }\n } catch {\n // Sites that haven't installed @replohq/sdk still handshake with sandbox-runtime alone.\n }\n}\n\n/**\n * Inbound side of the iframe<->parent selectMode bridge.\n *\n * Listens for Website Builder \u2192 canopy methods and applies them locally:\n * - `setDisplayMode`: switch the iframe between `browse` and `selection`.\n * - `setSelectionType`: declarative push of the parent's current\n * selection type. The interesting transition is `* \u2192 \"none\"`, which\n * tears down any in-iframe selection frame / in-progress drag \u2014 agent-ui\n * drives it from `agentUiState.selectionType` so panel dismiss / submit\n * flow through the same path as exiting selection mode entirely. The\n * regression test in `EditorSelection.spec.tsx` covers the case where\n * losing this used to lock the iframe out of further selections.\n *\n * Also fires `iframeReady` on mount so the parent knows it's safe to push\n * the initial `setDisplayMode` \u2014 without this handshake the parent would\n * race the iframe's mount and the first message could be lost.\n *\n * @author Kevin O'Connell 2026-04-17\n */\nexport function useParentMessaging({\n applyOptimisticUpdate,\n markCommitted,\n resolveSessionOverrides,\n onEnterEditMode,\n onExitEditMode,\n onFormatCommand,\n revertOverride,\n setDisplayMode,\n setSelectionType,\n}: {\n applyOptimisticUpdate?: (input: {\n editId: string;\n payload: SelectModeOptimisticUpdatePayload;\n targetSelector: string;\n targetMode: \"primary\" | \"group\";\n }) => void;\n markCommitted?: (editId: string, sessionId: string) => void;\n resolveSessionOverrides?: (\n sessionId: string,\n outcome: \"persisted\" | \"failed\",\n ) => void;\n onEnterEditMode?: () => void;\n onExitEditMode?: () => void;\n onFormatCommand?: (command: SelectModeFormatCommand) => void;\n revertOverride?: (editId: string) => void;\n setDisplayMode: (displayMode: DisplayMode) => void;\n setSelectionType: (input: {\n selectionType: SelectModeSelectionType;\n selectors?: string[];\n }) => void;\n}) {\n useIframeRpcChannel(useMemo(() => getSelectModeIframeRpcChannel(), []));\n\n // eslint-disable-next-line replo/no-use-effect -- Legacy effect - may or may not be necessary\n useEffect(() => {\n setSelectModeParentHandlers({\n setDisplayMode: ({ displayMode }) => {\n setDisplayMode(displayMode);\n },\n setSelectionType: (input) => {\n setSelectionType(input);\n },\n applyOptimisticUpdate: (message) => {\n applyOptimisticUpdate?.({\n editId: message.editId,\n payload: message.payload,\n targetSelector: message.targetSelector,\n targetMode: message.targetMode,\n });\n },\n markCommitted: ({ editId, sessionId }) => {\n markCommitted?.(editId, sessionId);\n },\n resolveSessionOverrides: ({ sessionId, outcome }) => {\n resolveSessionOverrides?.(sessionId, outcome);\n },\n revertOverride: ({ editId }) => {\n revertOverride?.(editId);\n },\n enterEditMode: () => {\n onEnterEditMode?.();\n },\n exitEditMode: () => {\n onExitEditMode?.();\n },\n formatCommand: ({ command }) => {\n onFormatCommand?.(command);\n },\n });\n const rpc = getWebsiteBuilderRpc();\n rpc?.iframeReady(BUILD_METADATA);\n void announceSdkBuildMetadata();\n\n return () => {\n setSelectModeParentHandlers(null);\n };\n }, [\n applyOptimisticUpdate,\n markCommitted,\n resolveSessionOverrides,\n onEnterEditMode,\n onExitEditMode,\n onFormatCommand,\n revertOverride,\n setDisplayMode,\n setSelectionType,\n ]);\n}\n"],
5
- "mappings": "AAOA,SAAS,WAAW,eAAe;AAEnC,SAAS,2BAA2B;AACpC,SAAS,wCAAwC;AACjD,SAAS,SAAS;AAElB,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,+BAA+B;AAErC,MAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,gBAAgB;AAClB,CAAC;AAED,eAAe,2BAA2B;AACxC,MAAI;AACF,UAAM,mBAAmB,6BAA6B;AAAA,MACpD,MAAM,OAAO;AAAA,IACf;AACA,QAAI,iBAAiB,SAAS;AAC5B,2BAAqB,GAAG,YAAY,iBAAiB,KAAK,cAAc;AAAA,IAC1E;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAqBO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAqBG;AACD,sBAAoB,QAAQ,MAAM,8BAA8B,GAAG,CAAC,CAAC,CAAC;AAGtE,YAAU,MAAM;AACd,gCAA4B;AAAA,MAC1B,gBAAgB,CAAC,EAAE,YAAY,MAAM;AACnC,uBAAe,WAAW;AAAA,MAC5B;AAAA,MACA,kBAAkB,CAAC,UAAU;AAC3B,yBAAiB,KAAK;AAAA,MACxB;AAAA,MACA,uBAAuB,CAAC,YAAY;AAClC,gCAAwB;AAAA,UACtB,QAAQ,QAAQ;AAAA,UAChB,SAAS,QAAQ;AAAA,UACjB,gBAAgB,QAAQ;AAAA,UACxB,YAAY,QAAQ;AAAA,QACtB,CAAC;AAAA,MACH;AAAA,MACA,eAAe,CAAC,EAAE,QAAQ,UAAU,MAAM;AACxC,wBAAgB,QAAQ,SAAS;AAAA,MACnC;AAAA,MACA,yBAAyB,CAAC,EAAE,WAAW,QAAQ,MAAM;AACnD,kCAA0B,WAAW,OAAO;AAAA,MAC9C;AAAA,MACA,gBAAgB,CAAC,EAAE,OAAO,MAAM;AAC9B,yBAAiB,MAAM;AAAA,MACzB;AAAA,MACA,eAAe,MAAM;AACnB,0BAAkB;AAAA,MACpB;AAAA,MACA,cAAc,MAAM;AAClB,yBAAiB;AAAA,MACnB;AAAA,MACA,eAAe,CAAC,EAAE,QAAQ,MAAM;AAC9B,0BAAkB,OAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AACD,UAAM,MAAM,qBAAqB;AACjC,SAAK,YAAY,cAAc;AAC/B,SAAK,yBAAyB;AAE9B,WAAO,MAAM;AACX,kCAA4B,IAAI;AAAA,IAClC;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/hooks/useSelectModeController.ts"],
4
- "sourcesContent": ["import type {\n DisplayMode,\n SelectModeSelectionType,\n} from \"schemas/generated/selectMode\";\nimport type { SelectModeInteractionSession } from \"../selectModeSession\";\n\nimport { useCallback, useRef } from \"react\";\n\nimport { displayModeStore, useDisplayMode } from \"../displayModeStore\";\nimport { getWebsiteBuilderRpc } from \"../iframeRpcChannel\";\nimport { getDocumentScrollOffset } from \"../interactions/selectionGeometry\";\nimport { hideSelectionFrame, showAreaSelectionFrames } from \"../selectionFrame\";\nimport { IDLE_SESSION } from \"../selectModeSession\";\nimport { resetHoverRectDedup } from \"./useSelectionHover\";\n\n/**\n * Tear down any in-progress drag/selection. Re-used by both the\n * display-mode flip-out path (defensive: belt-and-braces with the\n * parent's `setSelectionType(\"none\")` push) and by the explicit\n * `setSelectionType(\"none\")` path below.\n */\nfunction resetInteractionSession({\n interactionSessionRef,\n}: {\n interactionSessionRef: React.MutableRefObject<SelectModeInteractionSession>;\n}) {\n const currentSession = interactionSessionRef.current;\n if (currentSession.type === \"drag\" && currentSession.hasExceededThreshold) {\n getWebsiteBuilderRpc()?.dragRectUpdated({\n dragRect: null,\n selectionRects: [],\n });\n }\n hideSelectionFrame();\n // The parent wiped its hover overlay as part of this clear; the hover\n // hook's rect dedup must forget its last post or an identical rect would\n // never re-render the overlay.\n resetHoverRectDedup();\n interactionSessionRef.current = IDLE_SESSION;\n}\n\nexport function useSelectModeController() {\n // Display mode lives in a module singleton so the sibling `LinkInterceptor`\n // can read it (and stand down during selection) without a shared provider.\n const displayMode = useDisplayMode();\n const interactionSessionRef =\n useRef<SelectModeInteractionSession>(IDLE_SESSION);\n\n // The parent is authoritative for \"is there a current selection?\". Canopy\n // originates selections via pointer events, posts them up, agent-ui\n // mirrors `selection.type` into `agentUiState`, and the result is pushed\n // back down here. When the parent says `none` (panel dismissed / submit /\n // exit selection mode) we tear down the in-iframe frame; the matching\n // commit-side paths are in `useSelectionInteractions`.\n const setSelectionType = useCallback(\n ({\n selectionType,\n selectors,\n }: {\n selectionType: SelectModeSelectionType;\n selectors?: string[];\n }) => {\n if (selectionType === \"none\") {\n resetInteractionSession({ interactionSessionRef });\n return;\n }\n const session = interactionSessionRef.current;\n if (selectionType !== \"area\" || !selectors || session.type !== \"area\") {\n return;\n }\n // The editor can remove a single member (the tag's X) without a\n // pointer event ever reaching the iframe, so trim the session to the\n // members the parent still holds.\n const retainedSelectors = new Set(selectors);\n const items = session.items.filter((item) => {\n return (\n item.data.kind !== \"react-element\" ||\n retainedSelectors.has(item.data.selector)\n );\n });\n if (items.length === session.items.length) {\n return;\n }\n if (items.length === 0) {\n resetInteractionSession({ interactionSessionRef });\n return;\n }\n interactionSessionRef.current = { ...session, items };\n showAreaSelectionFrames({\n elements: items.map((item) => item.element),\n scrollOffset: getDocumentScrollOffset(),\n });\n },\n [],\n );\n\n const setDisplayMode = useCallback((nextDisplayMode: DisplayMode) => {\n if (\n displayModeStore.getSnapshot() === \"selection\" &&\n nextDisplayMode !== \"selection\"\n ) {\n resetInteractionSession({ interactionSessionRef });\n }\n\n displayModeStore.setDisplayMode(nextDisplayMode);\n }, []);\n\n return {\n displayMode,\n interactionSessionRef,\n setDisplayMode,\n setSelectionType,\n };\n}\n"],
5
- "mappings": "AAMA,SAAS,aAAa,cAAc;AAEpC,SAAS,kBAAkB,sBAAsB;AACjD,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AACxC,SAAS,oBAAoB,+BAA+B;AAC5D,SAAS,oBAAoB;AAC7B,SAAS,2BAA2B;AAQpC,SAAS,wBAAwB;AAAA,EAC/B;AACF,GAEG;AACD,QAAM,iBAAiB,sBAAsB;AAC7C,MAAI,eAAe,SAAS,UAAU,eAAe,sBAAsB;AACzE,yBAAqB,GAAG,gBAAgB;AAAA,MACtC,UAAU;AAAA,MACV,gBAAgB,CAAC;AAAA,IACnB,CAAC;AAAA,EACH;AACA,qBAAmB;AAInB,sBAAoB;AACpB,wBAAsB,UAAU;AAClC;AAEO,SAAS,0BAA0B;AAGxC,QAAM,cAAc,eAAe;AACnC,QAAM,wBACJ,OAAqC,YAAY;AAQnD,QAAM,mBAAmB;AAAA,IACvB,CAAC;AAAA,MACC;AAAA,MACA;AAAA,IACF,MAGM;AACJ,UAAI,kBAAkB,QAAQ;AAC5B,gCAAwB,EAAE,sBAAsB,CAAC;AACjD;AAAA,MACF;AACA,YAAM,UAAU,sBAAsB;AACtC,UAAI,kBAAkB,UAAU,CAAC,aAAa,QAAQ,SAAS,QAAQ;AACrE;AAAA,MACF;AAIA,YAAM,oBAAoB,IAAI,IAAI,SAAS;AAC3C,YAAM,QAAQ,QAAQ,MAAM,OAAO,CAAC,SAAS;AAC3C,eACE,KAAK,KAAK,SAAS,mBACnB,kBAAkB,IAAI,KAAK,KAAK,QAAQ;AAAA,MAE5C,CAAC;AACD,UAAI,MAAM,WAAW,QAAQ,MAAM,QAAQ;AACzC;AAAA,MACF;AACA,UAAI,MAAM,WAAW,GAAG;AACtB,gCAAwB,EAAE,sBAAsB,CAAC;AACjD;AAAA,MACF;AACA,4BAAsB,UAAU,EAAE,GAAG,SAAS,MAAM;AACpD,8BAAwB;AAAA,QACtB,UAAU,MAAM,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,QAC1C,cAAc,wBAAwB;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,iBAAiB,YAAY,CAAC,oBAAiC;AACnE,QACE,iBAAiB,YAAY,MAAM,eACnC,oBAAoB,aACpB;AACA,8BAAwB,EAAE,sBAAsB,CAAC;AAAA,IACnD;AAEA,qBAAiB,eAAe,eAAe;AAAA,EACjD,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/hooks/useSelectionHover.ts"],
4
- "sourcesContent": ["import type { MutableRefObject } from \"react\";\nimport type {\n DisplayMode,\n SelectModeBoundingRect,\n} from \"schemas/generated/selectMode\";\nimport type { SelectModeInteractionSession } from \"../selectModeSession\";\n\nimport { useEffect } from \"react\";\n\nimport { getNearestSelectableElement } from \"../descriptor/elementDescriptor\";\nimport { getWebsiteBuilderRpc } from \"../iframeRpcChannel\";\nimport { getElementBoundingRect } from \"../interactions/selectionGeometry\";\n\n// The parent clears its hover overlay without a round-trip when a selection\n// is dismissed (Escape, prompt submit). The rect-dedup cache below must\n// forget its last posted rect at that moment, or hovering the same element\n// again would produce an \"unchanged\" rect that never re-posts and the\n// overlay would stay missing. `resetInteractionSession` calls this on the\n// parent-authoritative clear path.\nlet activeHoverDedupReset: (() => void) | null = null;\n\nexport function resetHoverRectDedup() {\n activeHoverDedupReset?.();\n}\n\n/**\n * Tracks whichever element is under the user's pointer while in `selection`\n * mode and reports its bounding rect to the parent so the parent can render\n * the hover overlay.\n *\n * Two behaviors worth knowing about:\n * - During an active drag we suppress hover updates; the drag overlay is\n * the only highlight we want visible.\n * - Unchanged rectangles do not cross the iframe bridge. Viewport updates\n * are coalesced because scroll and wheel can fire in the same frame.\n *\n * @author Noah Gilmore 2026-07-26\n */\nexport function useSelectionHover({\n displayMode,\n interactionSessionRef,\n}: {\n displayMode: DisplayMode;\n interactionSessionRef: MutableRefObject<SelectModeInteractionSession>;\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 hoverSyncAnimationFrameId: number | null = null;\n let lastPointerClientPosition: { x: number; y: number } | null = null;\n let lastPostedRect: SelectModeBoundingRect | null | undefined;\n activeHoverDedupReset = () => {\n lastPostedRect = undefined;\n };\n\n // NOTE (Kevin O'Connell, 2026-04-20): `null` is the deliberate \"no element\n // under pointer / pointer left viewport\" signal \u2014 it produces a\n // clear-hover notification to the parent, not an error.\n const postHoveredElement = (element: Element | null) => {\n const rect = element ? getElementBoundingRect(element) : null;\n const isUnchanged =\n lastPostedRect !== undefined &&\n (rect === lastPostedRect ||\n (rect !== null &&\n lastPostedRect !== null &&\n rect.x === lastPostedRect.x &&\n rect.y === lastPostedRect.y &&\n rect.width === lastPostedRect.width &&\n rect.height === lastPostedRect.height));\n if (isUnchanged) {\n return;\n }\n lastPostedRect = rect;\n // The hover overlay only needs the element rect \u2014 serializing the full\n // styled outerHTML on every pointer move would be wasteful and never\n // consumed by the parent.\n getWebsiteBuilderRpc()?.hoverElement({ rect });\n };\n\n const syncCurrentHover = (\n pointerClientPosition = lastPointerClientPosition,\n ) => {\n let hoveredElement: Element | null = null;\n\n if (pointerClientPosition) {\n const isPointerWithinViewport =\n pointerClientPosition.x >= 0 &&\n pointerClientPosition.y >= 0 &&\n pointerClientPosition.x <= window.innerWidth &&\n pointerClientPosition.y <= window.innerHeight;\n\n if (isPointerWithinViewport) {\n hoveredElement = document.elementFromPoint(\n pointerClientPosition.x,\n pointerClientPosition.y,\n );\n }\n }\n\n if (!hoveredElement) {\n const hoveredElementStack = document.querySelectorAll(\":hover\");\n hoveredElement =\n hoveredElementStack[hoveredElementStack.length - 1] ?? null;\n }\n\n postHoveredElement(\n hoveredElement ? getNearestSelectableElement(hoveredElement) : null,\n );\n };\n\n const scheduleHoverSync = () => {\n if (\n interactionSessionRef.current.type === \"drag\" ||\n hoverSyncAnimationFrameId !== null\n ) {\n return;\n }\n\n hoverSyncAnimationFrameId = requestAnimationFrame(() => {\n hoverSyncAnimationFrameId = null;\n syncCurrentHover();\n });\n };\n\n const handlePointerMove = (event: PointerEvent) => {\n lastPointerClientPosition = {\n x: event.clientX,\n y: event.clientY,\n };\n\n if (interactionSessionRef.current.type === \"drag\") {\n return;\n }\n\n syncCurrentHover(lastPointerClientPosition);\n };\n\n // Catches the \"cursor is already inside the iframe when select mode\n // toggles on\" case \u2014 pointermove only fires on motion, so a stationary\n // cursor would otherwise wait forever for the first hover sync.\n const handlePointerOver = (event: PointerEvent) => {\n lastPointerClientPosition = {\n x: event.clientX,\n y: event.clientY,\n };\n\n if (interactionSessionRef.current.type === \"drag\") {\n return;\n }\n\n syncCurrentHover(lastPointerClientPosition);\n };\n\n const handlePointerOut = (event: PointerEvent) => {\n if (interactionSessionRef.current.type === \"drag\") {\n return;\n }\n\n const nextRelatedTarget = event.relatedTarget;\n if (\n nextRelatedTarget instanceof Node &&\n document.contains(nextRelatedTarget)\n ) {\n return;\n }\n\n lastPointerClientPosition = null;\n if (hoverSyncAnimationFrameId !== null) {\n cancelAnimationFrame(hoverSyncAnimationFrameId);\n hoverSyncAnimationFrameId = null;\n }\n postHoveredElement(null);\n };\n\n const handleViewportChange = () => {\n scheduleHoverSync();\n };\n\n syncCurrentHover();\n document.addEventListener(\"pointermove\", handlePointerMove, true);\n document.addEventListener(\"pointerover\", handlePointerOver, true);\n document.addEventListener(\"pointerout\", handlePointerOut, true);\n document.addEventListener(\"scroll\", handleViewportChange, true);\n document.addEventListener(\"wheel\", handleViewportChange, {\n capture: true,\n passive: true,\n });\n window.addEventListener(\"resize\", handleViewportChange);\n\n return () => {\n activeHoverDedupReset = null;\n if (hoverSyncAnimationFrameId !== null) {\n cancelAnimationFrame(hoverSyncAnimationFrameId);\n }\n document.removeEventListener(\"pointermove\", handlePointerMove, true);\n document.removeEventListener(\"pointerover\", handlePointerOver, true);\n document.removeEventListener(\"pointerout\", handlePointerOut, true);\n document.removeEventListener(\"scroll\", handleViewportChange, true);\n document.removeEventListener(\"wheel\", handleViewportChange, {\n capture: true,\n });\n window.removeEventListener(\"resize\", handleViewportChange);\n };\n }, [displayMode, interactionSessionRef]);\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/hooks/useSelectionInteractions.ts"],
4
- "sourcesContent": ["import type { MutableRefObject } from \"react\";\nimport type {\n DisplayMode,\n SelectableData,\n SelectModeBoundingRect,\n} from \"schemas/generated/selectMode\";\nimport type { DragCandidate } from \"../interactions/selectionGeometry\";\nimport type {\n SelectModeAreaItem,\n SelectModeInteractionSession,\n} 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 getPointRect,\n getSelectionAfterAdditiveClick,\n getViewportRectFromPageRect,\n getViewportSelectionRect,\n isAdditiveSelectionClick,\n unionElementPageRects,\n} from \"../interactions/selectionGeometry\";\nimport {\n hideSelectionFrame,\n showAreaSelectionFrames,\n showElementSelectionFrames,\n} from \"../selectionFrame\";\nimport { isSelectionStillCurrent } from \"../selectionPublish\";\nimport {\n getConnectedSelectedElement,\n IDLE_SESSION,\n} from \"../selectModeSession\";\nimport { symbolicateSelectedElement } from \"../symbolicate\";\nimport { isTextEditableElement } from \"./useEditModeStateMachine\";\nimport { getRepetitionSiblingElements } from \"./useSiblingResolution\";\n\nconst DOUBLE_CLICK_THRESHOLD_MS = 500;\n\nfunction getSelectedElementsFromSession(\n session: SelectModeInteractionSession,\n): Element[] {\n if (session.type === \"element\") {\n const liveElement = getConnectedSelectedElement(session);\n return liveElement ? [liveElement] : [];\n }\n if (session.type === \"area\") {\n return session.items.flatMap((item) => {\n const liveElement = getConnectedSelectedElement(item);\n return liveElement ? [liveElement] : [];\n });\n }\n return [];\n}\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 // Pointerdown always opens a drag session, so stash the committed\n // selection here. A sub-threshold Shift/Command click reads it back.\n let committedSelectionAtPointerDown: Element[] = [];\n\n const clearCommittedSelection = ({\n rect,\n }: {\n rect: SelectModeBoundingRect;\n }) => {\n hideSelectionFrame();\n interactionSessionRef.current = IDLE_SESSION;\n getWebsiteBuilderRpc()?.areaSelected({ rect, items: [] });\n };\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 (event.button !== 0) {\n return;\n }\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 committedSelectionAtPointerDown = getSelectedElementsFromSession(\n interactionSessionRef.current,\n );\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 commitAreaSelection = ({\n selectedElements,\n pageRect,\n anchorRect,\n scrollOffset,\n }: {\n selectedElements: Element[];\n pageRect: SelectModeBoundingRect;\n // Viewport rect each member's click anchor is clamped toward: the drag\n // rect for drag-select, the pointer for a modifier click.\n anchorRect: SelectModeBoundingRect;\n scrollOffset: ReturnType<typeof getDocumentScrollOffset>;\n }) => {\n const items: SelectModeAreaItem[] = selectedElements.map((element) => ({\n element,\n data: buildElementDescriptor({\n element,\n clickPosition: getElementAnchor({\n element,\n selectionRect: anchorRect,\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 showAreaSelectionFrames({ elements: selectedElements, scrollOffset });\n\n const rect = getViewportRectFromPageRect({\n rect: pageRect,\n scrollOffset,\n });\n void Promise.all(items.map((item) => maybeSymbolicate(item.data))).then(\n (symbolicatedItems) => {\n if (\n !isSelectionStillCurrent({\n session: interactionSessionRef.current,\n selection: { type: \"area\", pageRect },\n })\n ) {\n return;\n }\n getWebsiteBuilderRpc()?.areaSelected({\n rect,\n items: symbolicatedItems,\n });\n },\n );\n };\n\n const commitElementSelection = ({\n selectionElement,\n pointerEvent,\n }: {\n selectionElement: Element;\n pointerEvent: PointerEvent;\n }) => {\n const targetRect = selectionElement.getBoundingClientRect();\n // A modifier click can commit an element the pointer is not over\n // (deselecting down to one), so clamp the anchor into its bounds.\n const clickPosition = getElementAnchor({\n element: selectionElement,\n selectionRect: getPointRect({\n x: pointerEvent.clientX,\n y: pointerEvent.clientY,\n }),\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: clickPosition.x - targetRect.left,\n y: clickPosition.y - targetRect.top,\n },\n data,\n };\n void maybeSymbolicate(data).then((symbolicated) => {\n if (\n !isSelectionStillCurrent({\n session: interactionSessionRef.current,\n selection: { type: \"element\", element: selectionElement },\n })\n ) {\n return;\n }\n getWebsiteBuilderRpc()?.elementSelected({ data: symbolicated });\n });\n };\n\n const commitClickSelection = ({\n targetElement,\n pointerEvent,\n candidates,\n }: {\n targetElement: Element;\n pointerEvent: PointerEvent;\n candidates: DragCandidate[];\n }) => {\n const selectionElement = getNearestSelectableElement(targetElement);\n if (!isAdditiveSelectionClick(pointerEvent)) {\n commitElementSelection({ selectionElement, pointerEvent });\n return;\n }\n\n // A modifier click is never the second half of a double-click.\n lastClick = null;\n const pointerRect = getPointRect({\n x: pointerEvent.clientX,\n y: pointerEvent.clientY,\n });\n const nextElements = getSelectionAfterAdditiveClick({\n candidates,\n currentSelectedElements: committedSelectionAtPointerDown,\n targetElement: selectionElement,\n });\n const [firstElement] = nextElements;\n if (!firstElement) {\n clearCommittedSelection({ rect: pointerRect });\n return;\n }\n if (nextElements.length === 1) {\n commitElementSelection({\n selectionElement: firstElement,\n pointerEvent,\n });\n // The survivor was not clicked, so it must not arm double-click.\n lastClick = null;\n return;\n }\n const scrollOffset = getDocumentScrollOffset();\n const pageRect = unionElementPageRects({\n elements: nextElements,\n scrollOffset,\n });\n if (!pageRect) {\n return;\n }\n commitAreaSelection({\n selectedElements: nextElements,\n pageRect,\n anchorRect: pointerRect,\n scrollOffset,\n });\n };\n\n const handlePointerUp = (event: PointerEvent) => {\n if (event.button !== 0) {\n return;\n }\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 commitClickSelection({\n targetElement,\n pointerEvent: event,\n candidates,\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 commitClickSelection({\n targetElement,\n pointerEvent: event,\n candidates,\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 commitAreaSelection({\n selectedElements: selectedCandidates.map(\n (candidate) => candidate.element,\n ),\n pageRect,\n anchorRect: selectionRect,\n scrollOffset,\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
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/hooks/useSelectionScrollSync.ts"],
4
- "sourcesContent": ["import type { MutableRefObject } from \"react\";\nimport type { DisplayMode } from \"schemas/generated/selectMode\";\nimport type { SelectModeInteractionSession } from \"../selectModeSession\";\n\nimport { useEffect } from \"react\";\n\nimport { getWebsiteBuilderRpc } from \"../iframeRpcChannel\";\nimport {\n getDocumentScrollOffset,\n getElementBoundingRect,\n getViewportRectFromPageRect,\n} from \"../interactions/selectionGeometry\";\nimport { showElementSelectionFrames } from \"../selectionFrame\";\n\n/**\n * After a selection (element or area) has been resolved, the parent's\n * highlight overlay is positioned in viewport coordinates. When the user\n * scrolls the iframe document the highlight would otherwise lag behind the\n * underlying element. This hook re-sends an updated rect on every scroll\n * (rAF-coalesced) so the parent overlay tracks the element/area through\n * scrolls without us having to mirror scroll state into the parent.\n *\n * - For an `element` session we send only `{ boundingRect, clickPosition }`\n * \u2014 the rest of the descriptor (selector, outerHTML, computed styles,\n * text metrics, source location) was captured at selection-commit time\n * and doesn't change while the user is just scrolling. Rebuilding the\n * full descriptor here would call `serializeStyledElement` recursively.\n * The in-iframe frames only remeasure the selected repetition group.\n * - For an `area` session we keep the original *page* rect (which doesn't\n * move) and convert it to viewport coordinates using the latest scroll\n * offset before sending.\n *\n * @author Noah Gilmore 2026-07-26\n */\nexport function useSelectionScrollSync({\n displayMode,\n interactionSessionRef,\n}: {\n displayMode: DisplayMode;\n interactionSessionRef: MutableRefObject<SelectModeInteractionSession>;\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 animationFrameId: number | null = null;\n\n const handleScroll = () => {\n if (animationFrameId !== null) {\n return;\n }\n\n animationFrameId = requestAnimationFrame(() => {\n animationFrameId = null;\n\n const session = interactionSessionRef.current;\n if (session.type === \"element\") {\n const boundingRect = getElementBoundingRect(session.element);\n const sessionClickPosition = session.clickPosition;\n const clickPosition = {\n x:\n sessionClickPosition !== null\n ? boundingRect.left + sessionClickPosition.x\n : boundingRect.right,\n y:\n sessionClickPosition !== null\n ? boundingRect.top + sessionClickPosition.y\n : boundingRect.bottom,\n };\n // Page coordinates of the in-iframe frame are stable across\n // pure scroll, but layout shifts during scroll (sticky\n // headers expanding, lazy images settling, etc.) can move the\n // selected element. Re-applying every rAF tick keeps the\n // frame glued; same-value style writes are cheap and don't\n // repaint.\n const scrollOffset = getDocumentScrollOffset();\n showElementSelectionFrames({\n elements: [session.element, ...session.siblingElements],\n scrollOffset,\n });\n getWebsiteBuilderRpc()?.selectedElementRectUpdate({\n rect: boundingRect,\n clickPosition,\n });\n return;\n }\n\n if (session.type === \"area\") {\n getWebsiteBuilderRpc()?.selectedAreaRectUpdate({\n rect: getViewportRectFromPageRect({\n rect: session.pageRect,\n scrollOffset: getDocumentScrollOffset(),\n }),\n });\n }\n });\n };\n\n document.addEventListener(\"scroll\", handleScroll, true);\n return () => {\n document.removeEventListener(\"scroll\", handleScroll, true);\n if (animationFrameId !== null) {\n cancelAnimationFrame(animationFrameId);\n }\n };\n }, [displayMode, interactionSessionRef]);\n}\n"],
5
- "mappings": "AAIA,SAAS,iBAAiB;AAE1B,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kCAAkC;AAsBpC,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA;AACF,GAGG;AAED,YAAU,MAAM;AACd,QAAI,gBAAgB,aAAa;AAC/B;AAAA,IACF;AAEA,QAAI,mBAAkC;AAEtC,UAAM,eAAe,MAAM;AACzB,UAAI,qBAAqB,MAAM;AAC7B;AAAA,MACF;AAEA,yBAAmB,sBAAsB,MAAM;AAC7C,2BAAmB;AAEnB,cAAM,UAAU,sBAAsB;AACtC,YAAI,QAAQ,SAAS,WAAW;AAC9B,gBAAM,eAAe,uBAAuB,QAAQ,OAAO;AAC3D,gBAAM,uBAAuB,QAAQ;AACrC,gBAAM,gBAAgB;AAAA,YACpB,GACE,yBAAyB,OACrB,aAAa,OAAO,qBAAqB,IACzC,aAAa;AAAA,YACnB,GACE,yBAAyB,OACrB,aAAa,MAAM,qBAAqB,IACxC,aAAa;AAAA,UACrB;AAOA,gBAAM,eAAe,wBAAwB;AAC7C,qCAA2B;AAAA,YACzB,UAAU,CAAC,QAAQ,SAAS,GAAG,QAAQ,eAAe;AAAA,YACtD;AAAA,UACF,CAAC;AACD,+BAAqB,GAAG,0BAA0B;AAAA,YAChD,MAAM;AAAA,YACN;AAAA,UACF,CAAC;AACD;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS,QAAQ;AAC3B,+BAAqB,GAAG,uBAAuB;AAAA,YAC7C,MAAM,4BAA4B;AAAA,cAChC,MAAM,QAAQ;AAAA,cACd,cAAc,wBAAwB;AAAA,YACxC,CAAC;AAAA,UACH,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAEA,aAAS,iBAAiB,UAAU,cAAc,IAAI;AACtD,WAAO,MAAM;AACX,eAAS,oBAAoB,UAAU,cAAc,IAAI;AACzD,UAAI,qBAAqB,MAAM;AAC7B,6BAAqB,gBAAgB;AAAA,MACvC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,aAAa,qBAAqB,CAAC;AACzC;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/hooks/useSiblingResolution.ts"],
4
- "sourcesContent": ["import { buildSelector } from \"../descriptor/elementDescriptor\";\nimport { getRepetitionHostNodes } from \"../fiber\";\n\nexport function getRepetitionSiblingElements({\n element,\n}: {\n element: Element;\n}): HTMLElement[] {\n if (!(element instanceof HTMLElement)) {\n return [];\n }\n\n // Hidden members \u2014 a timed-out Suspense sibling's offscreen subtree, a\n // conditionally `display: none`d item \u2014 would get zero-size selection\n // frames and dead selectors, so only visible members count as siblings.\n return getRepetitionHostNodes(element).filter((node) => {\n return node !== element && (node.checkVisibility?.() ?? true);\n });\n}\n\nexport function getRepetitionSiblingSelectors({\n element,\n}: {\n element: Element;\n}): string[] {\n return getRepetitionSiblingElements({ element }).map(buildSelector);\n}\n"],
5
- "mappings": "AAAA,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AAEhC,SAAS,6BAA6B;AAAA,EAC3C;AACF,GAEkB;AAChB,MAAI,EAAE,mBAAmB,cAAc;AACrC,WAAO,CAAC;AAAA,EACV;AAKA,SAAO,uBAAuB,OAAO,EAAE,OAAO,CAAC,SAAS;AACtD,WAAO,SAAS,YAAY,KAAK,kBAAkB,KAAK;AAAA,EAC1D,CAAC;AACH;AAEO,SAAS,8BAA8B;AAAA,EAC5C;AACF,GAEa;AACX,SAAO,6BAA6B,EAAE,QAAQ,CAAC,EAAE,IAAI,aAAa;AACpE;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../select-mode/iframeRpcChannel.ts"],
4
- "sourcesContent": ["import type { SelectedElement } from \"schemas/generated/selectMode\";\nimport type {\n IframeRpcChannelInputHandlers,\n IframeRpcChannelRemote,\n} from \"schemas/iframeRpcChannel\";\n\nimport {\n createIframeRpcChannel,\n createIframeRpcRemote,\n} from \"schemas/iframeRpcChannel\";\nimport {\n canopyToWebsiteBuilderMethodConfig,\n SELECT_MODE_IFRAME_RPC_CHANNEL_ID,\n SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION,\n websiteBuilderToCanopyMethodConfig,\n} from \"schemas/selectModeIframeRpc\";\n\nimport { symbolicateSelectedElement } from \"./symbolicate\";\n\nexport type WebsiteBuilderRpcRemote = IframeRpcChannelRemote<\n typeof canopyToWebsiteBuilderMethodConfig\n>;\n\ntype SelectModeParentMessagingHandlers = Omit<\n IframeRpcChannelInputHandlers<typeof websiteBuilderToCanopyMethodConfig>,\n \"symbolicateSelectedElement\" | \"navigateToRoute\"\n>;\n\n// Module-level handler pointers; `useParentMessaging` sets these on mount\n// and nulls them on unmount. Inbound void methods are dropped until then.\n// `symbolicateSelectedElement` is wired permanently on the channel.\nlet messagingHandlers: SelectModeParentMessagingHandlers | null = null;\n\n// Set by `NavigationReceiver` while a router is mounted; unhandled commands are dropped.\nlet navigateToRouteHandler: ((input: { pathname: string }) => void) | null =\n null;\n\nexport function setNavigateToRouteHandler(\n handler: ((input: { pathname: string }) => void) | null,\n) {\n navigateToRouteHandler = handler;\n}\n\nfunction createSelectModeIframeRpcChannel() {\n return createIframeRpcChannel({\n subscriberWindow: window,\n channelIdentifier: SELECT_MODE_IFRAME_RPC_CHANNEL_ID,\n version: SELECT_MODE_IFRAME_RPC_CHANNEL_VERSION,\n getTargetWindow: () => (window.parent === window ? null : window.parent),\n targetOrigin: \"*\",\n isExpectedMessage: (event) => event.source === window.parent,\n outgoingMethods: canopyToWebsiteBuilderMethodConfig,\n incomingMethods: websiteBuilderToCanopyMethodConfig,\n handlers: {\n setDisplayMode: (input) => {\n messagingHandlers?.setDisplayMode(input);\n },\n setSelectionType: (input) => {\n messagingHandlers?.setSelectionType(input);\n },\n applyOptimisticUpdate: (input) => {\n messagingHandlers?.applyOptimisticUpdate(input);\n },\n markCommitted: (input) => {\n messagingHandlers?.markCommitted(input);\n },\n resolveSessionOverrides: (input) => {\n messagingHandlers?.resolveSessionOverrides(input);\n },\n revertOverride: (input) => {\n messagingHandlers?.revertOverride(input);\n },\n enterEditMode: (input) => {\n messagingHandlers?.enterEditMode(input);\n },\n exitEditMode: (input) => {\n messagingHandlers?.exitEditMode(input);\n },\n formatCommand: (input) => {\n messagingHandlers?.formatCommand(input);\n },\n symbolicateSelectedElement: (element) => {\n return symbolicateSelectedElement(element);\n },\n navigateToRoute: (input) => {\n navigateToRouteHandler?.(input);\n },\n },\n });\n}\n\nlet channel: ReturnType<typeof createSelectModeIframeRpcChannel> | null = null;\nlet websiteBuilderRpc: WebsiteBuilderRpcRemote | null = null;\n\nexport function getSelectModeIframeRpcChannel() {\n if (typeof window === \"undefined\") {\n return null;\n }\n channel ??= createSelectModeIframeRpcChannel();\n return channel;\n}\n\nexport function setSelectModeParentHandlers(\n nextHandlers: SelectModeParentMessagingHandlers | null,\n) {\n messagingHandlers = nextHandlers;\n}\n\nexport function getWebsiteBuilderRpc(): WebsiteBuilderRpcRemote | null {\n const currentChannel = getSelectModeIframeRpcChannel();\n if (!currentChannel) {\n return null;\n }\n websiteBuilderRpc ??= createIframeRpcRemote(currentChannel);\n return websiteBuilderRpc;\n}\n\nexport function requestInlineTextEdit(input: {\n editId: string;\n element: SelectedElement;\n}) {\n const remote = getWebsiteBuilderRpc();\n if (!remote) {\n return Promise.reject(\n new Error(\"Website Builder iframe RPC is unavailable\"),\n );\n }\n return remote.requestInlineTextEdit(input);\n}\n"],
5
- "mappings": "AAMA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,kCAAkC;AAc3C,IAAI,oBAA8D;AAGlE,IAAI,yBACF;AAEK,SAAS,0BACd,SACA;AACA,2BAAyB;AAC3B;AAEA,SAAS,mCAAmC;AAC1C,SAAO,uBAAuB;AAAA,IAC5B,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,SAAS;AAAA,IACT,iBAAiB,MAAO,OAAO,WAAW,SAAS,OAAO,OAAO;AAAA,IACjE,cAAc;AAAA,IACd,mBAAmB,CAAC,UAAU,MAAM,WAAW,OAAO;AAAA,IACtD,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,UAAU;AAAA,MACR,gBAAgB,CAAC,UAAU;AACzB,2BAAmB,eAAe,KAAK;AAAA,MACzC;AAAA,MACA,kBAAkB,CAAC,UAAU;AAC3B,2BAAmB,iBAAiB,KAAK;AAAA,MAC3C;AAAA,MACA,uBAAuB,CAAC,UAAU;AAChC,2BAAmB,sBAAsB,KAAK;AAAA,MAChD;AAAA,MACA,eAAe,CAAC,UAAU;AACxB,2BAAmB,cAAc,KAAK;AAAA,MACxC;AAAA,MACA,yBAAyB,CAAC,UAAU;AAClC,2BAAmB,wBAAwB,KAAK;AAAA,MAClD;AAAA,MACA,gBAAgB,CAAC,UAAU;AACzB,2BAAmB,eAAe,KAAK;AAAA,MACzC;AAAA,MACA,eAAe,CAAC,UAAU;AACxB,2BAAmB,cAAc,KAAK;AAAA,MACxC;AAAA,MACA,cAAc,CAAC,UAAU;AACvB,2BAAmB,aAAa,KAAK;AAAA,MACvC;AAAA,MACA,eAAe,CAAC,UAAU;AACxB,2BAAmB,cAAc,KAAK;AAAA,MACxC;AAAA,MACA,4BAA4B,CAAC,YAAY;AACvC,eAAO,2BAA2B,OAAO;AAAA,MAC3C;AAAA,MACA,iBAAiB,CAAC,UAAU;AAC1B,iCAAyB,KAAK;AAAA,MAChC;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,IAAI,UAAsE;AAC1E,IAAI,oBAAoD;AAEjD,SAAS,gCAAgC;AAC9C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AACA,cAAY,iCAAiC;AAC7C,SAAO;AACT;AAEO,SAAS,4BACd,cACA;AACA,sBAAoB;AACtB;AAEO,SAAS,uBAAuD;AACrE,QAAM,iBAAiB,8BAA8B;AACrD,MAAI,CAAC,gBAAgB;AACnB,WAAO;AAAA,EACT;AACA,wBAAsB,sBAAsB,cAAc;AAC1D,SAAO;AACT;AAEO,SAAS,sBAAsB,OAGnC;AACD,QAAM,SAAS,qBAAqB;AACpC,MAAI,CAAC,QAAQ;AACX,WAAO,QAAQ;AAAA,MACb,IAAI,MAAM,2CAA2C;AAAA,IACvD;AAAA,EACF;AACA,SAAO,OAAO,sBAAsB,KAAK;AAC3C;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../select-mode/inlineTextMarks.ts"],
4
- "sourcesContent": ["// NOTE (Noah, 2026-07-23): TipTap / inline JSX marks are not independently\n// selectable \u2014 clicking bold/italic text should select the host block, not\n// the <strong>/<em> wrapper. Keep in sync with tiptapInlineEditor marks.\nconst INLINE_TEXT_MARK_TAGS = new Set([\n \"b\",\n \"strong\",\n \"em\",\n \"i\",\n \"s\",\n \"strike\",\n \"u\",\n \"mark\",\n]);\n\nexport function isInlineTextMarkElement(element: Element): boolean {\n return INLINE_TEXT_MARK_TAGS.has(element.tagName.toLowerCase());\n}\n\n/**\n * Walk up past nested inline text marks so selection targets the host\n * element (e.g. `<p>hello <em>world</em></p>` \u2192 the `<p>`).\n */\nexport function skipInlineTextMarkElements(element: Element): Element {\n let current = element;\n while (\n isInlineTextMarkElement(current) &&\n current.parentElement &&\n current.parentElement !== document.documentElement &&\n current.parentElement !== document.body\n ) {\n current = current.parentElement;\n }\n return current;\n}\n"],
5
- "mappings": "AAGA,MAAM,wBAAwB,oBAAI,IAAI;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,wBAAwB,SAA2B;AACjE,SAAO,sBAAsB,IAAI,QAAQ,QAAQ,YAAY,CAAC;AAChE;AAMO,SAAS,2BAA2B,SAA2B;AACpE,MAAI,UAAU;AACd,SACE,wBAAwB,OAAO,KAC/B,QAAQ,iBACR,QAAQ,kBAAkB,SAAS,mBACnC,QAAQ,kBAAkB,SAAS,MACnC;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../select-mode/interactions/selectionGeometry.ts"],
4
- "sourcesContent": ["import type {\n SelectModeBoundingRect,\n SelectModeClickPosition,\n} from \"schemas/generated/selectMode\";\n\nimport { isIntersecting, isRectEnclosing } from \"replo-utils/lib/geometry\";\nimport { v4 as uuidv4 } from \"uuid\";\n\nimport { isInlineTextMarkElement } from \"../inlineTextMarks\";\n\nexport type DragPosition = {\n clientX: number;\n clientY: number;\n pageX: number;\n pageY: number;\n};\n\nexport type ScrollOffset = {\n left: number;\n top: number;\n};\n\nexport type SelectedAreaState = {\n pageRect: SelectModeBoundingRect;\n};\n\n// NOTE (Noah, 2026-04-21): A small fudge factor so elements\n// that visually appear to touch the selection rect (but whose bounding\n// box is a pixel or two off due to borders/sub-pixel rendering) still get\n// included.\nconst SELECTION_TOLERANCE_PX = 4;\n\nfunction normalizeSelectionRect({\n startX,\n startY,\n endX,\n endY,\n}: {\n startX: number;\n startY: number;\n endX: number;\n endY: number;\n}): SelectModeBoundingRect {\n const left = Math.min(startX, endX);\n const right = Math.max(startX, endX);\n const top = Math.min(startY, endY);\n const bottom = Math.max(startY, endY);\n\n return {\n x: left,\n y: top,\n width: right - left,\n height: bottom - top,\n top,\n right,\n bottom,\n left,\n };\n}\n\n/**\n * @author Kevin O'Connell 2026-04-17\n */\nexport function getDragPositionFromClient({\n clientX,\n clientY,\n scrollOffset,\n}: {\n clientX: number;\n clientY: number;\n scrollOffset: ScrollOffset;\n}): DragPosition {\n return {\n clientX,\n clientY,\n pageX: clientX + scrollOffset.left,\n pageY: clientY + scrollOffset.top,\n };\n}\n\n/**\n * @author Kevin O'Connell 2026-04-17\n */\nexport function getDocumentScrollOffset(): ScrollOffset {\n const scrollingElement = document.scrollingElement;\n return {\n left: scrollingElement?.scrollLeft ?? window.scrollX,\n top: scrollingElement?.scrollTop ?? window.scrollY,\n };\n}\n\n/**\n * @author Kevin O'Connell 2026-04-17\n */\nexport function getViewportSelectionRect({\n dragStart,\n dragCurrent,\n scrollOffset,\n}: {\n dragStart: DragPosition;\n dragCurrent: DragPosition;\n scrollOffset: ScrollOffset;\n}): SelectModeBoundingRect {\n return normalizeSelectionRect({\n startX: dragStart.pageX - scrollOffset.left,\n startY: dragStart.pageY - scrollOffset.top,\n endX: dragCurrent.pageX - scrollOffset.left,\n endY: dragCurrent.pageY - scrollOffset.top,\n });\n}\n\n/**\n * @author Kevin O'Connell 2026-04-17\n */\nexport function getPageRectFromViewportRect({\n rect,\n scrollOffset,\n}: {\n rect: SelectModeBoundingRect;\n scrollOffset: ScrollOffset;\n}): SelectModeBoundingRect {\n return {\n x: rect.x + scrollOffset.left,\n y: rect.y + scrollOffset.top,\n width: rect.width,\n height: rect.height,\n left: rect.left + scrollOffset.left,\n top: rect.top + scrollOffset.top,\n right: rect.right + scrollOffset.left,\n bottom: rect.bottom + scrollOffset.top,\n };\n}\n\n/**\n * @author Kevin O'Connell 2026-04-17\n */\nexport function getViewportRectFromPageRect({\n rect,\n scrollOffset,\n}: {\n rect: SelectModeBoundingRect;\n scrollOffset: ScrollOffset;\n}): SelectModeBoundingRect {\n return {\n x: rect.x - scrollOffset.left,\n y: rect.y - scrollOffset.top,\n width: rect.width,\n height: rect.height,\n left: rect.left - scrollOffset.left,\n top: rect.top - scrollOffset.top,\n right: rect.right - scrollOffset.left,\n bottom: rect.bottom - scrollOffset.top,\n };\n}\n\nfunction isMeaningfulElement(\n element: Element,\n elementRect: SelectModeBoundingRect,\n): boolean {\n const tagName = element.tagName.toLowerCase();\n if ([\"html\", \"body\", \"script\", \"style\", \"meta\", \"link\"].includes(tagName)) {\n return false;\n }\n\n if (isInlineTextMarkElement(element)) {\n return false;\n }\n\n if (elementRect.width < 4 || elementRect.height < 4) {\n return false;\n }\n\n return true;\n}\n\n/**\n * A drag captures an element when their boxes overlap (within\n * `tolerancePx`) \u2014 but NOT when the drag sits entirely inside the\n * element. The latter case is the user dragging *within* a large\n * container (a section, `<main>`, `<body>`) to lasso its children; the\n * container itself isn't a thing they're trying to select, so we drop it.\n */\nexport function doesRectIntersectSelection({\n elementRect,\n selectionRect,\n tolerancePx,\n}: {\n elementRect: SelectModeBoundingRect;\n selectionRect: SelectModeBoundingRect;\n tolerancePx: number;\n}) {\n return (\n isIntersecting(elementRect, selectionRect, { tolerance: tolerancePx }) &&\n !isRectEnclosing(elementRect, selectionRect)\n );\n}\n\n// A meaningful element plus its page-coordinate rect and a stable id,\n// snapshotted once when a drag begins. Page coordinates are scroll-\n// invariant, so per-move hit-testing never needs to re-measure.\nexport type DragCandidate = {\n id: string;\n element: Element;\n pageRect: SelectModeBoundingRect;\n};\n\n/**\n * Snapshots every meaningful element and its page rect when a drag begins.\n * Each candidate gets a stable id so the parent overlay can key its\n * live highlights without remounting them as the drag moves.\n */\nexport function collectDragCandidates(\n scrollOffset: ScrollOffset,\n): DragCandidate[] {\n const candidates: DragCandidate[] = [];\n for (const element of Array.from(document.querySelectorAll(\"*\"))) {\n const viewportRect = getElementBoundingRect(element);\n if (!isMeaningfulElement(element, viewportRect)) {\n continue;\n }\n candidates.push({\n id: uuidv4(),\n element,\n pageRect: getPageRectFromViewportRect({\n rect: viewportRect,\n scrollOffset,\n }),\n });\n }\n return candidates;\n}\n\n/**\n * Drop a child whose parent is also selected and every one of that\n * parent's *candidate* children is selected: the parent already represents\n * the whole group, so the children are redundant. Returns only the\n * candidates that survive the collapse.\n *\n * Only children that are themselves drag candidates count toward \"fully\n * covered\". A parent's DOM children can include decorative / non-selectable\n * elements (and `.children` excludes text nodes); those can never be\n * selected, so counting them would wedge the check permanently false and\n * the collapse would never fire.\n *\n * Membership is read once up front, so the collapse cascades up the tree\n * in a single pass \u2014 a parent kept this round is itself dropped when *its*\n * parent is likewise fully covered, leaving only the topmost ancestor of\n * any fully-enclosed subtree.\n */\nfunction collapseFullyCoveredChildren({\n candidates,\n selected,\n}: {\n candidates: DragCandidate[];\n selected: DragCandidate[];\n}): DragCandidate[] {\n const candidateElements = new Set(\n candidates.map((candidate) => candidate.element),\n );\n const selectedElements = new Set(\n selected.map((candidate) => candidate.element),\n );\n return selected.filter((candidate) => {\n const parent = candidate.element.parentElement;\n if (!parent || !selectedElements.has(parent)) {\n return true;\n }\n const everyCandidateChildSelected = Array.from(parent.children)\n .filter((child) => candidateElements.has(child))\n .every((child) => selectedElements.has(child));\n return !everyCandidateChildSelected;\n });\n}\n\n/**\n * Cheap per-move hit-test against the pre-collected candidates: keep the\n * ones whose page rect overlaps the selection (excluding any that wholly\n * enclose it), then collapse any fully-covered parent/children group down\n * to just the parent (see `collapseFullyCoveredChildren`). Does no DOM\n * queries or re-measures of geometry \u2014 the only DOM reads are cheap\n * parent/child structural lookups.\n *\n * Because the collapse depends on which siblings are currently captured,\n * elements legitimately move in and out of the result as the drag grows or\n * shrinks: a child drops out the moment the drag swallows its last sibling\n * (the parent takes over), and reappears if the drag retreats.\n */\nexport function getCandidatesInSelection({\n candidates,\n selectionPageRect,\n}: {\n candidates: DragCandidate[];\n selectionPageRect: SelectModeBoundingRect;\n}): DragCandidate[] {\n const intersecting = candidates.filter((candidate) => {\n return doesRectIntersectSelection({\n elementRect: candidate.pageRect,\n selectionRect: selectionPageRect,\n tolerancePx: SELECTION_TOLERANCE_PX,\n });\n });\n\n return collapseFullyCoveredChildren({ candidates, selected: intersecting });\n}\n\n/**\n * Shift / Command / Ctrl click toggles the clicked element in the current\n * selection (theme-builder canvas rules): a click inside an already-selected\n * ancestor is ignored, selecting a parent drops its selected descendants,\n * and once every candidate child of a candidate parent is selected the\n * parent replaces them \u2014 the same collapse drag-select applies.\n */\nexport function getSelectionAfterAdditiveClick({\n candidates,\n currentSelectedElements,\n targetElement,\n}: {\n candidates: DragCandidate[];\n currentSelectedElements: Element[];\n targetElement: Element;\n}): Element[] {\n if (currentSelectedElements.includes(targetElement)) {\n return currentSelectedElements.filter(\n (element) => element !== targetElement,\n );\n }\n if (\n currentSelectedElements.some((element) => element.contains(targetElement))\n ) {\n return currentSelectedElements;\n }\n\n const selected = new Set(\n currentSelectedElements.filter(\n (element) => !targetElement.contains(element),\n ),\n );\n selected.add(targetElement);\n\n const candidateElements = new Set(\n candidates.map((candidate) => candidate.element),\n );\n let parent = targetElement.parentElement;\n while (parent && candidateElements.has(parent)) {\n const candidateChildren = Array.from(parent.children).filter((child) => {\n return candidateElements.has(child);\n });\n if (\n candidateChildren.length === 0 ||\n !candidateChildren.every((child) => selected.has(child))\n ) {\n break;\n }\n for (const child of candidateChildren) {\n selected.delete(child);\n }\n selected.add(parent);\n parent = parent.parentElement;\n }\n return [...selected];\n}\n\nexport function isAdditiveSelectionClick(event: {\n shiftKey: boolean;\n metaKey: boolean;\n ctrlKey: boolean;\n}): boolean {\n return event.shiftKey || event.metaKey || event.ctrlKey;\n}\n\nexport function getPointRect({\n x,\n y,\n}: {\n x: number;\n y: number;\n}): SelectModeBoundingRect {\n return { x, y, width: 0, height: 0, top: y, right: x, bottom: y, left: x };\n}\n\nexport function unionElementPageRects({\n elements,\n scrollOffset,\n}: {\n elements: Element[];\n scrollOffset: ScrollOffset;\n}): SelectModeBoundingRect | null {\n const rects = elements.map((element) => {\n return getPageRectFromViewportRect({\n rect: getElementBoundingRect(element),\n scrollOffset,\n });\n });\n const firstRect = rects[0];\n if (!firstRect) {\n return null;\n }\n return rects.slice(1).reduce((union, rect) => {\n const left = Math.min(union.left, rect.left);\n const top = Math.min(union.top, rect.top);\n const right = Math.max(union.right, rect.right);\n const bottom = Math.max(union.bottom, rect.bottom);\n return {\n x: left,\n y: top,\n width: right - left,\n height: bottom - top,\n left,\n top,\n right,\n bottom,\n };\n }, firstRect);\n}\n\n/**\n * Picks a \"click position\" for an element that fell inside an area\n * selection. We use the corner of the element nearest the top-left of the\n * selection rect, clamped to the element's own bounds. This anchor is what\n * lets the selected-element overlay continue to track the element when the\n * user scrolls (`useSelectionScrollSync` re-projects relative to it).\n *\n * @author Kevin O'Connell 2026-04-17\n */\nexport function getElementAnchor({\n element,\n selectionRect,\n}: {\n element: Element;\n selectionRect: SelectModeBoundingRect;\n}): SelectModeClickPosition {\n const rect = element.getBoundingClientRect();\n\n return {\n x: Math.min(Math.max(selectionRect.left, rect.left), rect.right),\n y: Math.min(Math.max(selectionRect.top, rect.top), rect.bottom),\n };\n}\n\n/**\n * @author Kevin O'Connell 2026-04-17\n */\nexport function getElementBoundingRect(\n element: Element,\n): SelectModeBoundingRect {\n const rect = element.getBoundingClientRect();\n\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../select-mode/optimisticOverrideDom.ts"],
4
- "sourcesContent": ["export const SELECT_MODE_OVERRIDE_ATTRIBUTE = \"data-replo-select-overrides\";\nexport const SELECT_MODE_OVERRIDE_STYLE_ATTRIBUTE =\n \"data-replo-select-override\";\n"],
5
- "mappings": "AAAO,MAAM,iCAAiC;AACvC,MAAM,uCACX;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 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 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
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 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\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
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../select-mode/selectionPublish.ts"],
4
- "sourcesContent": ["import type { SelectModeBoundingRect } from \"schemas/generated/selectMode\";\nimport type { SelectModeInteractionSession } from \"./selectModeSession\";\n\nimport { exhaustiveSwitch } from \"replo-utils/lib/misc\";\n\n// Selection publishes wait on a network symbolicate, so a slower earlier\n// request can resolve after the user has moved on. Publish only if the\n// session still names the same selection the request was for. Switching\n// away and back to the original selection should accept that original\n// request \u2014 the selected thing matching is what matters, not request order.\ntype SelectionPublishTarget =\n | { type: \"element\"; element: Element }\n | { type: \"area\"; pageRect: SelectModeBoundingRect };\n\nexport function isSelectionStillCurrent({\n session,\n selection,\n}: {\n session: SelectModeInteractionSession;\n selection: SelectionPublishTarget;\n}): boolean {\n return exhaustiveSwitch(selection)({\n element: ({ element }) => {\n return session.type === \"element\" && session.element === element;\n },\n area: ({ pageRect }) => {\n return (\n session.type === \"area\" && isSamePageRect(session.pageRect, pageRect)\n );\n },\n });\n}\n\nfunction isSamePageRect(\n left: SelectModeBoundingRect,\n right: SelectModeBoundingRect,\n): boolean {\n return (\n left.x === right.x &&\n left.y === right.y &&\n left.width === right.width &&\n left.height === right.height\n );\n}\n"],
5
- "mappings": "AAGA,SAAS,wBAAwB;AAW1B,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AACF,GAGY;AACV,SAAO,iBAAiB,SAAS,EAAE;AAAA,IACjC,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,aAAO,QAAQ,SAAS,aAAa,QAAQ,YAAY;AAAA,IAC3D;AAAA,IACA,MAAM,CAAC,EAAE,SAAS,MAAM;AACtB,aACE,QAAQ,SAAS,UAAU,eAAe,QAAQ,UAAU,QAAQ;AAAA,IAExE;AAAA,EACF,CAAC;AACH;AAEA,SAAS,eACP,MACA,OACS;AACT,SACE,KAAK,MAAM,MAAM,KACjB,KAAK,MAAM,MAAM,KACjB,KAAK,UAAU,MAAM,SACrB,KAAK,WAAW,MAAM;AAE1B;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../select-mode/symbolicate.ts"],
4
- "sourcesContent": ["import type {\n SelectedElement,\n SelectModeFiberChainEntry,\n SelectModeSourceLocation,\n} from \"schemas/generated/selectMode\";\n\nimport { isNullish } from \"replo-utils/lib/misc\";\n\n/**\n * Runtime source-attribution for React 19 + Next.js Turbopack.\n *\n * React 19 removed `fiber._debugSource`; the only per-element source pointer\n * left is `fiber._debugStack`, whose `.stack` references compiled SSR/client\n * chunks. We POST those compiled frames to Next.js's dev-only\n * `/__nextjs_original-stack-frames` endpoint, which symbolicates them through\n * Turbopack's in-memory source maps \u2014 the same mechanism the Next error\n * overlay uses (see `next/dist/server/dev/middleware-turbopack.js`).\n */\n\ntype NextStackFrame = {\n file: string | null;\n methodName: string | null;\n arguments: string[];\n // Next.js's `/__nextjs_original-stack-frames` reads these as `line1`/`column1`\n // (1-based) in the request body \u2014 same field names it uses in the response.\n // Sending `lineNumber`/`column` is silently dropped on the server side.\n line1: number | null;\n column1: number | null;\n};\n\ntype ResolvedFrame = {\n file: string | null;\n line1?: number | null;\n column1?: number | null;\n methodName?: string | null;\n ignored?: boolean;\n arguments?: string[];\n};\n\ntype OriginalStackFrameResponse = {\n originalStackFrame: ResolvedFrame | null;\n originalCodeFrame: string | null;\n};\n\ntype SettledResponseEntry =\n | { status: \"fulfilled\"; value: OriginalStackFrameResponse }\n | { status: \"rejected\"; reason: string };\n\nconst SYMBOLICATE_ENDPOINT = \"/__nextjs_original-stack-frames\";\n\nfunction isLikelyCompiledLocation(\n location: SelectModeSourceLocation | undefined,\n): boolean {\n if (!location) {\n return false;\n }\n const filePath = location.filePath;\n return (\n filePath.includes(\".next\") ||\n filePath.includes(\"/chunks/\") ||\n filePath.includes(\"webpack-internal:\") ||\n filePath.includes(\"turbopack:\") ||\n filePath.endsWith(\".js\") ||\n filePath.startsWith(\"about:\")\n );\n}\n\n// A resolved source that lives in a dependency or framework internal is never\n// the user's own code. The canonical case is Next's `<Image>`, whose rendered\n// `<img>` symbolicates to\n// `.../node_modules/next/src/client/image-component.tsx` \u2014 useless as an edit\n// target. We skip these and keep walking the ownership chain toward the user's\n// call site. See (Noah, 2026-07-09, REPL-29098).\nfunction isDependencyOrInternalPath(filePath: string): boolean {\n return (\n filePath.includes(\"node_modules\") ||\n filePath.includes(\"/dist/compiled/\") ||\n filePath.startsWith(\"about:\")\n );\n}\n\n// React 19 fibers for server-rendered (RSC) elements carry a `_debugStack`\n// whose top frame points at an SSR chunk (e.g. `about://React/Server/file://\n// .../.next-dev/.../server/chunks/ssr/*.js`). The endpoint resolves those\n// against the server bundler context; client chunks go through the client\n// bundler context. Mis-routing returns the compiled chunk unchanged.\nfunction isServerChunk(filePath: string): boolean {\n return (\n filePath.startsWith(\"about://React/Server\") ||\n filePath.includes(\"/server/chunks/\") ||\n filePath.includes(\".next-dev/dev/server/\") ||\n filePath.includes(\".next/server/\")\n );\n}\n\n// Matches the `/_next/static/...` tail of a browser chunk URL's pathname.\n// Capture group 1 is the `/static/...` segment that lives under the dist dir\n// on disk. Mirrors `regexNextStatic` in\n// `next/dist/server/lib/parse-stack.js`.\nconst NEXT_STATIC_PATH_PATTERN = /\\/_next(\\/static\\/.+)/;\n\n// Absolute path to the dev dist dir (e.g.\n// `/workspace/dev/website/.next-dev/dev`). Next.js define-injects this into\n// dev client bundles (see the `__NEXT_DIST_DIR` define in\n// `next/dist/build/define-env.ts`); because the sandbox runtime is transpiled into the\n// host Next app, the replacement reaches this reference too. Outside a Next\n// dev client build the value is absent, so we bail and leave the URL as-is.\nfunction getNextDistDir(): string | null {\n try {\n const distDir = process.env.__NEXT_DIST_DIR;\n return typeof distDir === \"string\" && distDir.length > 0 ? distDir : null;\n } catch {\n return null;\n }\n}\n\n// Turbopack's `/__nextjs_original-stack-frames` backend only resolves source\n// maps for `file://` (or bare filesystem) paths \u2014 it rejects browser chunk\n// URLs (`https://host/_next/static/chunks/X.js`) with \"Unknown url scheme\",\n// which is why client-component frames never symbolicated in the sandbox\n// (everything is served over https) even though it worked for RSC frames that\n// already carry filesystem paths. Rewrite the URL to the on-disk dist path the\n// same way Next's own server-side stack parser does, so the endpoint can map\n// it back to the user's `.tsx`.\nfunction rewriteBrowserChunkUrlToDistPath(filePath: string): string {\n if (!/^https?:\\/\\//.test(filePath)) {\n return filePath;\n }\n const distDir = getNextDistDir();\n if (!distDir) {\n return filePath;\n }\n let url: URL;\n try {\n url = new URL(filePath);\n } catch {\n return filePath;\n }\n const staticPathMatch = NEXT_STATIC_PATH_PATTERN.exec(url.pathname);\n if (!staticPathMatch?.[1]) {\n return filePath;\n }\n const normalizedDistDir = distDir.replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n return `file://${normalizedDistDir}${staticPathMatch[1]}${url.search}`;\n}\n\n// React 19's `_debugStack.stack` for RSC components wraps the SSR chunk URL\n// in an `about://React/Server/` prefix and appends a `?<digits>` cache-buster\n// (e.g. `about://React/Server/file:///.../[root-of-the-server]__abc._.js?21`).\n// Turbopack's source-map lookup matches against the bare chunk URL; with\n// either decoration in place it returns the compiled chunk unchanged. Client\n// components instead carry a plain browser chunk URL, which Turbopack rejects\n// outright unless rewritten to its on-disk `file://` path.\nfunction normalizeFilePathForSymbolicator(filePath: string): string {\n let normalized = filePath;\n if (normalized.startsWith(\"about://React/Server/\")) {\n normalized = normalized.slice(\"about://React/Server/\".length);\n }\n normalized = normalized.replace(/\\?\\d+$/, \"\");\n return rewriteBrowserChunkUrlToDistPath(normalized);\n}\n\nfunction toNextStackFrame(location: SelectModeSourceLocation): NextStackFrame {\n return {\n file: normalizeFilePathForSymbolicator(location.filePath),\n methodName: location.componentName ?? null,\n arguments: [],\n line1: location.lineNumber,\n column1: location.columnNumber ?? null,\n };\n}\n\nfunction extractResolvedFrame(\n entry: SettledResponseEntry | null,\n): ResolvedFrame | null {\n if (!entry || entry.status !== \"fulfilled\") {\n return null;\n }\n return entry.value?.originalStackFrame ?? null;\n}\n\nasync function postFrames({\n frames,\n isServer,\n}: {\n frames: NextStackFrame[];\n isServer: boolean;\n}): Promise<(SettledResponseEntry | null)[]> {\n if (frames.length === 0) {\n return [];\n }\n try {\n const response = await fetch(SYMBOLICATE_ENDPOINT, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n frames,\n isServer,\n isEdgeServer: false,\n isAppDirectory: true,\n }),\n });\n if (!response.ok) {\n console.log(\"[selectMode] symbolicate: endpoint returned non-OK status\", {\n status: response.status,\n isServer,\n });\n return frames.map(() => null);\n }\n const parsed: unknown = await response.json();\n if (Array.isArray(parsed)) {\n // Promise.allSettled-shaped entries; see\n // node_modules/next/dist/server/dev/middleware-turbopack.js.\n // Legacy cast - the runtime shape isn't exported as a type.\n // eslint-disable-next-line replo/no-as-cast\n return parsed as (SettledResponseEntry | null)[];\n }\n return frames.map(() => null);\n } catch (error) {\n console.log(\"[selectMode] symbolicate: fetch failed\", {\n isServer,\n error,\n });\n return frames.map(() => null);\n }\n}\n\nasync function symbolicateFrames(\n frames: NextStackFrame[],\n): Promise<(SettledResponseEntry | null)[]> {\n const serverIndices: number[] = [];\n const clientIndices: number[] = [];\n for (const [index, frame] of frames.entries()) {\n if (frame.file && isServerChunk(frame.file)) {\n serverIndices.push(index);\n } else {\n clientIndices.push(index);\n }\n }\n\n const [serverResults, clientResults] = await Promise.all([\n postFrames({\n frames: serverIndices.map((index) => frames[index]!),\n isServer: true,\n }),\n postFrames({\n frames: clientIndices.map((index) => frames[index]!),\n isServer: false,\n }),\n ]);\n\n const merged: (SettledResponseEntry | null)[] = frames.map(() => null);\n for (const [position, index] of serverIndices.entries()) {\n merged[index] = serverResults[position] ?? null;\n }\n for (const [position, index] of clientIndices.entries()) {\n merged[index] = clientResults[position] ?? null;\n }\n return merged;\n}\n\nfunction applyResolved({\n original,\n frame,\n}: {\n original: SelectModeSourceLocation;\n frame: ResolvedFrame | null;\n}): SelectModeSourceLocation {\n if (!frame || !frame.file || isNullish(frame.line1)) {\n return original;\n }\n return {\n filePath: frame.file,\n lineNumber: frame.line1,\n columnNumber: frame.column1 ?? undefined,\n componentName: original.componentName,\n };\n}\n\n// The innermost chain entry that is a usable edit target: already-symbolicated\n// (still-compiled frames failed to resolve and are useless) and outside\n// dependency/framework code. See (Noah, 2026-07-09, REPL-29098).\nfunction findUserSourceLocation(\n fiberChain: SelectModeFiberChainEntry[],\n): SelectModeSourceLocation | undefined {\n return fiberChain.find((entry) => {\n return (\n !isLikelyCompiledLocation(entry.sourceLocation) &&\n !isDependencyOrInternalPath(entry.sourceLocation.filePath)\n );\n })?.sourceLocation;\n}\n\nexport async function symbolicateSelectedElement(\n selectedElement: SelectedElement,\n): Promise<SelectedElement> {\n const targets: {\n location: SelectModeSourceLocation;\n apply: (next: SelectModeSourceLocation) => void;\n }[] = [];\n\n const fiberChain: SelectModeFiberChainEntry[] =\n selectedElement.fiberChain.map((entry) => ({ ...entry }));\n for (const entry of fiberChain) {\n if (isLikelyCompiledLocation(entry.sourceLocation)) {\n targets.push({\n location: entry.sourceLocation,\n apply: (next) => {\n entry.sourceLocation = next;\n },\n });\n }\n }\n\n let sourceLocation = selectedElement.sourceLocation;\n // With a chain present `sourceLocation` is re-derived from it below, so\n // targeting it here would just duplicate the chain head's round trip.\n if (\n fiberChain.length === 0 &&\n sourceLocation &&\n isLikelyCompiledLocation(sourceLocation)\n ) {\n const captured = sourceLocation;\n targets.push({\n location: captured,\n apply: (next) => {\n sourceLocation = next;\n },\n });\n }\n\n if (targets.length === 0) {\n return selectedElement;\n }\n\n const resolved = await symbolicateFrames(\n targets.map((target) => toNextStackFrame(target.location)),\n );\n\n for (const [index, target] of targets.entries()) {\n const frame = extractResolvedFrame(resolved[index] ?? null);\n target.apply(applyResolved({ original: target.location, frame }));\n }\n\n if (fiberChain.length > 0) {\n // Fall back to the chain head so we never regress to attributing nothing.\n sourceLocation =\n findUserSourceLocation(fiberChain) ?? fiberChain[0]!.sourceLocation;\n }\n\n return {\n ...selectedElement,\n sourceLocation,\n fiberChain,\n };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../select-mode/tiptapInlineEditor.ts"],
4
- "sourcesContent": ["import type { JSONContent } from \"@tiptap/core\";\nimport type { SelectModeFormatCommand } from \"schemas/generated/selectMode\";\n\nimport { Editor, Mark } from \"@tiptap/core\";\nimport Bold from \"@tiptap/extension-bold\";\nimport Document from \"@tiptap/extension-document\";\nimport Italic from \"@tiptap/extension-italic\";\nimport Strike from \"@tiptap/extension-strike\";\nimport Text from \"@tiptap/extension-text\";\nimport Underline from \"@tiptap/extension-underline\";\n\nconst InlineDocument = Document.extend({\n content: \"inline*\",\n});\n\nconst InlineLink = Mark.create({\n name: \"link\",\n inclusive: false,\n addAttributes() {\n return {\n class: { default: null },\n href: { default: null },\n rel: { default: null },\n target: { default: null },\n };\n },\n parseHTML() {\n return [{ tag: \"a[href]\" }];\n },\n renderHTML({ HTMLAttributes }) {\n return [\"a\", HTMLAttributes, 0];\n },\n});\n\nexport type InlineTiptapEditor = {\n focus: () => void;\n focusAndSelectAll: () => void;\n destroy: () => void;\n getHTML: () => string;\n getJSON: () => JSONContent;\n runFormatCommand: (command: SelectModeFormatCommand) => void;\n};\n\nexport function createInlineTiptapEditor({\n element,\n content,\n onCommit,\n onEscape,\n onBlur,\n onSelectionUpdate,\n}: {\n element: HTMLElement;\n content: string;\n onCommit: () => void;\n onEscape: () => void;\n onBlur: () => void;\n onSelectionUpdate: (activeMarks: {\n bold: boolean;\n italic: boolean;\n underline: boolean;\n strike: boolean;\n }) => void;\n}): InlineTiptapEditor {\n const originalAttributes = Array.from(\n element.attributes,\n ({ name, value }) => ({\n name,\n value,\n }),\n );\n // ProseMirror *appends* its contenteditable to the mount node rather than\n // replacing it, so the element's original text node would survive as a\n // sibling and render a duplicate copy. The editor's initial content comes\n // from the `content` option below (not the element's DOM), and the caller\n // keeps the original HTML for revert, so emptying the node here is safe.\n element.replaceChildren();\n const mount = {\n mount: element,\n } as unknown as Element; /* eslint-disable-line replo/no-as-cast -- NOTE (Noah Gilmore, 2026-07-16): ProseMirror accepts this documented direct-mount shape at runtime, but Tiptap v2's Editor option incorrectly narrows it to Element. */\n const editor = new Editor({\n element: mount,\n content,\n extensions: [\n InlineDocument,\n Text,\n Bold,\n Italic,\n Underline,\n Strike,\n InlineLink,\n ],\n editorProps: {\n // Drop the browser's default focus ring on the contenteditable \u2014 the\n // select-mode selection frame already indicates the edit target.\n attributes: {\n \"data-select-mode-inline-editor\": \"\",\n style: \"outline: none;\",\n },\n handleKeyDown: (_view, event) => {\n // Commit on Shift-Enter or Cmd/Ctrl-Enter; a bare Enter inserts a line\n // break as usual.\n if (\n event.key === \"Enter\" &&\n (event.shiftKey || event.metaKey || event.ctrlKey)\n ) {\n event.preventDefault();\n onCommit();\n return true;\n }\n if (event.key === \"Escape\") {\n event.preventDefault();\n onEscape();\n return true;\n }\n return false;\n },\n },\n onSelectionUpdate: ({ editor: activeEditor }) => {\n onSelectionUpdate({\n bold: activeEditor.isActive(\"bold\"),\n italic: activeEditor.isActive(\"italic\"),\n underline: activeEditor.isActive(\"underline\"),\n strike: activeEditor.isActive(\"strike\"),\n });\n },\n onBlur: () => {\n onBlur();\n },\n });\n\n return {\n focus: () => editor.commands.focus(),\n // Focus the editor with the full text block selected so the user can type\n // to replace it immediately (or arrow/click to drop the selection).\n focusAndSelectAll: () => editor.chain().focus().selectAll().run(),\n destroy: () => {\n editor.destroy();\n for (const attribute of Array.from(element.attributes)) {\n element.removeAttribute(attribute.name);\n }\n for (const { name, value } of originalAttributes) {\n element.setAttribute(name, value);\n }\n },\n getHTML: () => editor.getHTML(),\n getJSON: () => editor.getJSON(),\n runFormatCommand: (command) => {\n const commandRunners: Record<SelectModeFormatCommand, () => void> = {\n toggleBold: () => editor.chain().focus().toggleBold().run(),\n toggleItalic: () => editor.chain().focus().toggleItalic().run(),\n toggleUnderline: () => editor.chain().focus().toggleUnderline().run(),\n toggleStrike: () => editor.chain().focus().toggleStrike().run(),\n };\n commandRunners[command]();\n },\n };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }