@replohq/sandbox-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/ClientErrorBoundary.d.ts +10 -0
  2. package/ClientErrorBoundary.js +61 -0
  3. package/ClientErrorBoundary.js.map +7 -0
  4. package/DocumentReadyBeacon.d.ts +1 -0
  5. package/DocumentReadyBeacon.js +9 -0
  6. package/DocumentReadyBeacon.js.map +7 -0
  7. package/LICENSE +11 -0
  8. package/LinkInterceptor.d.ts +1 -0
  9. package/LinkInterceptor.js +128 -0
  10. package/LinkInterceptor.js.map +7 -0
  11. package/NextErrorReporter.d.ts +1 -0
  12. package/NextErrorReporter.js +92 -0
  13. package/NextErrorReporter.js.map +7 -0
  14. package/_vendor/replo-utils/lib/crypto.d.ts +30 -0
  15. package/_vendor/replo-utils/lib/errors.d.ts +83 -0
  16. package/_vendor/replo-utils/lib/fonts.d.ts +49 -0
  17. package/_vendor/replo-utils/lib/fonts.mjs +221 -0
  18. package/_vendor/replo-utils/lib/geometry.d.ts +18 -0
  19. package/_vendor/replo-utils/lib/geometry.mjs +9 -0
  20. package/_vendor/replo-utils/lib/json.d.ts +6 -0
  21. package/_vendor/replo-utils/lib/log.d.ts +11 -0
  22. package/_vendor/replo-utils/lib/misc.d.ts +145 -0
  23. package/_vendor/replo-utils/lib/misc.mjs +2 -0
  24. package/_vendor/replo-utils/lib/object.d.ts +31 -0
  25. package/_vendor/replo-utils/lib/parse.d.ts +15 -0
  26. package/_vendor/replo-utils/lib/posthogReplay.d.ts +43 -0
  27. package/_vendor/replo-utils/lib/posthogReplay.mjs +121 -0
  28. package/_vendor/replo-utils/react/use-iframe-rpc-channel.d.ts +14 -0
  29. package/_vendor/replo-utils/react/use-iframe-rpc-channel.mjs +14 -0
  30. package/_vendor/schemas/designLibrary.d.ts +361 -0
  31. package/_vendor/schemas/designLibrary.mjs +126 -0
  32. package/_vendor/schemas/errors.d.ts +459 -0
  33. package/_vendor/schemas/generated/errors.d.ts +61 -0
  34. package/_vendor/schemas/generated/pageAnnotations.d.ts +48 -0
  35. package/_vendor/schemas/generated/pageAnnotations.mjs +1 -0
  36. package/_vendor/schemas/generated/selectMode.d.ts +119 -0
  37. package/_vendor/schemas/generated/selectMode.mjs +1 -0
  38. package/_vendor/schemas/generated/selectModeIframeRpc.d.ts +100 -0
  39. package/_vendor/schemas/generated/selectModeIframeRpc.mjs +1 -0
  40. package/_vendor/schemas/iframeRpcChannel.d.ts +82 -0
  41. package/_vendor/schemas/iframeRpcChannel.mjs +520 -0
  42. package/_vendor/schemas/pageAnnotations.d.ts +134 -0
  43. package/_vendor/schemas/pageAnnotations.mjs +61 -0
  44. package/_vendor/schemas/savedStyles.d.ts +140 -0
  45. package/_vendor/schemas/selectMode.d.ts +522 -0
  46. package/_vendor/schemas/selectMode.mjs +3 -0
  47. package/_vendor/schemas/selectModeIframeRpc.d.ts +900 -0
  48. package/_vendor/schemas/selectModeIframeRpc.mjs +223 -0
  49. package/annotations/AnnotationLayerMount.d.ts +1 -0
  50. package/annotations/AnnotationLayerMount.js +13 -0
  51. package/annotations/AnnotationLayerMount.js.map +7 -0
  52. package/annotations/annotationController.d.ts +1 -0
  53. package/annotations/annotationController.js +384 -0
  54. package/annotations/annotationController.js.map +7 -0
  55. package/annotations/bridgeGate.d.ts +7 -0
  56. package/annotations/bridgeGate.js +22 -0
  57. package/annotations/bridgeGate.js.map +7 -0
  58. package/chunk-3UFG7XTQ.mjs +205 -0
  59. package/chunk-FNTGY7I5.mjs +68 -0
  60. package/chunk-N5EI2MOZ.mjs +1535 -0
  61. package/design-library-preview/DesignLibraryPreview.d.ts +1 -0
  62. package/design-library-preview/DesignLibraryPreview.js +93 -0
  63. package/design-library-preview/DesignLibraryPreview.js.map +7 -0
  64. package/package.json +41 -0
  65. package/posthog-relay.d.ts +11 -0
  66. package/posthog-relay.js +72 -0
  67. package/posthog-relay.js.map +7 -0
  68. package/sandbox-runtime.d.ts +1 -0
  69. package/sandbox-runtime.js +29 -0
  70. package/sandbox-runtime.js.map +7 -0
  71. package/select-mode/EditorSelection.d.ts +24 -0
  72. package/select-mode/EditorSelection.js +95 -0
  73. package/select-mode/EditorSelection.js.map +7 -0
  74. package/select-mode/annotationFrames.d.ts +33 -0
  75. package/select-mode/annotationFrames.js +119 -0
  76. package/select-mode/annotationFrames.js.map +7 -0
  77. package/select-mode/descriptor/elementDescriptor.d.ts +26 -0
  78. package/select-mode/descriptor/elementDescriptor.js +201 -0
  79. package/select-mode/descriptor/elementDescriptor.js.map +7 -0
  80. package/select-mode/descriptor/styleExtraction.d.ts +3 -0
  81. package/select-mode/descriptor/styleExtraction.js +271 -0
  82. package/select-mode/descriptor/styleExtraction.js.map +7 -0
  83. package/select-mode/displayModeStore.d.ts +10 -0
  84. package/select-mode/displayModeStore.js +47 -0
  85. package/select-mode/displayModeStore.js.map +7 -0
  86. package/select-mode/fast-refresh-relay.d.ts +3 -0
  87. package/select-mode/fast-refresh-relay.js +33 -0
  88. package/select-mode/fast-refresh-relay.js.map +7 -0
  89. package/select-mode/fiber.d.ts +49 -0
  90. package/select-mode/fiber.js +306 -0
  91. package/select-mode/fiber.js.map +7 -0
  92. package/select-mode/hooks/useCrosshairCursor.d.ts +12 -0
  93. package/select-mode/hooks/useCrosshairCursor.js +20 -0
  94. package/select-mode/hooks/useCrosshairCursor.js.map +7 -0
  95. package/select-mode/hooks/useEditModeStateMachine.d.ts +16 -0
  96. package/select-mode/hooks/useEditModeStateMachine.js +235 -0
  97. package/select-mode/hooks/useEditModeStateMachine.js.map +7 -0
  98. package/select-mode/hooks/useOptimisticOverrides.d.ts +17 -0
  99. package/select-mode/hooks/useOptimisticOverrides.js +283 -0
  100. package/select-mode/hooks/useOptimisticOverrides.js.map +7 -0
  101. package/select-mode/hooks/useParentMessaging.d.ts +36 -0
  102. package/select-mode/hooks/useParentMessaging.js +74 -0
  103. package/select-mode/hooks/useParentMessaging.js.map +7 -0
  104. package/select-mode/hooks/useSelectModeController.d.ts +8 -0
  105. package/select-mode/hooks/useSelectModeController.js +46 -0
  106. package/select-mode/hooks/useSelectModeController.js.map +7 -0
  107. package/select-mode/hooks/useSelectionHover.d.ts +22 -0
  108. package/select-mode/hooks/useSelectionHover.js +110 -0
  109. package/select-mode/hooks/useSelectionHover.js.map +7 -0
  110. package/select-mode/hooks/useSelectionInteractions.d.ts +37 -0
  111. package/select-mode/hooks/useSelectionInteractions.js +353 -0
  112. package/select-mode/hooks/useSelectionInteractions.js.map +7 -0
  113. package/select-mode/hooks/useSelectionScrollSync.d.ts +28 -0
  114. package/select-mode/hooks/useSelectionScrollSync.js +70 -0
  115. package/select-mode/hooks/useSelectionScrollSync.js.map +7 -0
  116. package/select-mode/hooks/useSiblingResolution.d.ts +6 -0
  117. package/select-mode/hooks/useSiblingResolution.js +59 -0
  118. package/select-mode/hooks/useSiblingResolution.js.map +7 -0
  119. package/select-mode/iframeRpcChannel.d.ts +356 -0
  120. package/select-mode/iframeRpcChannel.js +92 -0
  121. package/select-mode/iframeRpcChannel.js.map +7 -0
  122. package/select-mode/inlineTextMarks.d.ts +6 -0
  123. package/select-mode/inlineTextMarks.js +25 -0
  124. package/select-mode/inlineTextMarks.js.map +7 -0
  125. package/select-mode/interactions/selectionGeometry.d.ts +105 -0
  126. package/select-mode/interactions/selectionGeometry.js +192 -0
  127. package/select-mode/interactions/selectionGeometry.js.map +7 -0
  128. package/select-mode/selectModeSession.d.ts +21 -0
  129. package/select-mode/selectModeSession.js +7 -0
  130. package/select-mode/selectModeSession.js.map +7 -0
  131. package/select-mode/selectionFrame.d.ts +81 -0
  132. package/select-mode/selectionFrame.js +132 -0
  133. package/select-mode/selectionFrame.js.map +7 -0
  134. package/select-mode/symbolicate.d.ts +2 -0
  135. package/select-mode/symbolicate.js +200 -0
  136. package/select-mode/symbolicate.js.map +7 -0
  137. package/select-mode/tiptapInlineEditor.d.ts +23 -0
  138. package/select-mode/tiptapInlineEditor.js +120 -0
  139. package/select-mode/tiptapInlineEditor.js.map +7 -0
@@ -0,0 +1,26 @@
1
+ import type { SelectableData, SelectModeClickPosition } from "../../_vendor/schemas/generated/selectMode";
2
+ /**
3
+ * Element that should own a click/hover selection: skip TipTap/inline JSX
4
+ * mark wrappers, then prefer an explicit selectable boundary when present.
5
+ */
6
+ export declare function getNearestSelectableElement(element: Element): Element;
7
+ /**
8
+ * Build a CSS selector path from `element` up to the document root. Stops
9
+ * (and short-circuits) at the first ancestor with an `id`. Used so the
10
+ * parent can identify the element later without holding a DOM reference.
11
+ */
12
+ export declare function buildSelector(element: Element): string;
13
+ /**
14
+ * The single entrypoint for converting a DOM `Element` into the serialized
15
+ * `SelectedElement` payload that crosses the iframe<->parent boundary.
16
+ * Centralizes everything the parent (and downstream agent) need to know
17
+ * about a selection: identification, geometry, source location, and a
18
+ * style-inlined HTML snippet.
19
+ *
20
+ * @author Kevin O'Connell 2026-04-17
21
+ */
22
+ export declare function buildElementDescriptor({ element, clickPosition, siblingSelectors, }: {
23
+ element: Element;
24
+ clickPosition: SelectModeClickPosition;
25
+ siblingSelectors?: string[];
26
+ }): SelectableData;
@@ -0,0 +1,201 @@
1
+ import {
2
+ readSelectablePayload,
3
+ SELECT_MODE_SELECTABLE_ATTRIBUTE,
4
+ SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE
5
+ } from "../../_vendor/schemas/selectMode.mjs";
6
+ import { getFiberChain } from "../fiber";
7
+ import { skipInlineTextMarkElements } from "../inlineTextMarks";
8
+ import { getElementBoundingRect } from "../interactions/selectionGeometry";
9
+ import { getDefinedStyles, getInheritedStyles } from "./styleExtraction";
10
+ function getNearestSelectableElement(element) {
11
+ const host = skipInlineTextMarkElements(element);
12
+ return host.closest(`[${SELECT_MODE_SELECTABLE_ATTRIBUTE}]`) ?? host;
13
+ }
14
+ function getSelectableDataFromElement(element) {
15
+ const selectableElement = element.closest(
16
+ `[${SELECT_MODE_SELECTABLE_ATTRIBUTE}]`
17
+ );
18
+ if (!selectableElement) {
19
+ return null;
20
+ }
21
+ const selectablePayload = readSelectablePayload(
22
+ selectableElement.getAttribute(SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE)
23
+ );
24
+ if (!selectablePayload) {
25
+ return null;
26
+ }
27
+ return {
28
+ ...selectablePayload,
29
+ rect: getElementBoundingRect(selectableElement)
30
+ };
31
+ }
32
+ function identifyElement(element) {
33
+ const tagName = element.tagName.toLowerCase();
34
+ if (tagName === "button" || element.getAttribute("role") === "button" || tagName === "input") {
35
+ const trimmedText2 = element.textContent?.trim();
36
+ if (trimmedText2) {
37
+ return `${tagName}: "${trimmedText2.slice(0, 60)}"`;
38
+ }
39
+ const ariaLabel = element.getAttribute("aria-label");
40
+ if (ariaLabel) {
41
+ return `${tagName}: [${ariaLabel}]`;
42
+ }
43
+ if (tagName === "input") {
44
+ const inputType = element.type || "text";
45
+ const placeholder = element.getAttribute("placeholder");
46
+ return placeholder ? `input(${inputType}): "${placeholder}"` : `input(${inputType})`;
47
+ }
48
+ return tagName;
49
+ }
50
+ if (tagName === "a") {
51
+ const trimmedText2 = element.textContent?.trim();
52
+ if (trimmedText2) {
53
+ return `link: "${trimmedText2.slice(0, 60)}"`;
54
+ }
55
+ const href = element.getAttribute("href");
56
+ if (href) {
57
+ return `link: [${href.slice(0, 60)}]`;
58
+ }
59
+ return "link";
60
+ }
61
+ if (tagName === "img") {
62
+ const alt = element.alt;
63
+ if (alt) {
64
+ return `image: "${alt.slice(0, 60)}"`;
65
+ }
66
+ const src = element.src;
67
+ if (src) {
68
+ const filename = src.split("/").pop()?.split("?")[0] ?? src;
69
+ return `image: [${filename.slice(0, 40)}]`;
70
+ }
71
+ return "image";
72
+ }
73
+ if (/^h[1-6]$/.test(tagName)) {
74
+ const trimmedText2 = element.textContent?.trim();
75
+ return trimmedText2 ? `heading(${tagName}): "${trimmedText2.slice(0, 60)}"` : tagName;
76
+ }
77
+ if (["div", "main", "section", "article", "header", "footer", "nav"].includes(
78
+ tagName
79
+ )) {
80
+ const role2 = element.getAttribute("role");
81
+ if (role2) {
82
+ return role2;
83
+ }
84
+ }
85
+ const trimmedText = element.textContent?.trim();
86
+ if (trimmedText && trimmedText.length < 120) {
87
+ const role2 = element.getAttribute("role");
88
+ const label = role2 ?? tagName;
89
+ return `${label}: "${trimmedText.slice(0, 60)}"`;
90
+ }
91
+ const role = element.getAttribute("role");
92
+ if (role) {
93
+ return role;
94
+ }
95
+ const className = element.className;
96
+ if (typeof className === "string" && className) {
97
+ const meaningfulClassName = className.split(/\s+/).find((classToken) => {
98
+ return !classToken.startsWith("_") && !classToken.match(/^[a-z]{1,2}\d/) && classToken.length > 2;
99
+ });
100
+ if (meaningfulClassName) {
101
+ return `${tagName}.${meaningfulClassName}`;
102
+ }
103
+ }
104
+ return tagName;
105
+ }
106
+ function buildSelector(element) {
107
+ const parts = [];
108
+ let currentElement = element;
109
+ while (currentElement && currentElement !== document.documentElement) {
110
+ const tag = currentElement.tagName.toLowerCase();
111
+ const id = currentElement.id;
112
+ if (id) {
113
+ parts.unshift(`#${id}`);
114
+ break;
115
+ }
116
+ const parentElement = currentElement.parentElement;
117
+ if (parentElement) {
118
+ const currentTag = currentElement.tagName;
119
+ const siblings = Array.from(parentElement.children);
120
+ const siblingElementsWithSameTag = siblings.filter((sibling) => {
121
+ return sibling.tagName === currentTag;
122
+ });
123
+ if (siblingElementsWithSameTag.length > 1) {
124
+ const index = siblingElementsWithSameTag.indexOf(currentElement) + 1;
125
+ parts.unshift(`${tag}:nth-of-type(${index})`);
126
+ } else {
127
+ parts.unshift(tag);
128
+ }
129
+ } else {
130
+ parts.unshift(tag);
131
+ }
132
+ currentElement = parentElement;
133
+ }
134
+ return parts.join(" > ");
135
+ }
136
+ function getTextMetrics(element) {
137
+ const text = element.textContent?.trim();
138
+ if (!text) {
139
+ return null;
140
+ }
141
+ const style = window.getComputedStyle(element);
142
+ const parsedLineHeight = Number.parseFloat(style.lineHeight);
143
+ const computedLineHeight = Number.isNaN(parsedLineHeight) ? Number.parseFloat(style.fontSize) * 1.2 : parsedLineHeight;
144
+ try {
145
+ const range = document.createRange();
146
+ range.selectNodeContents(element);
147
+ const lineRects = Array.from(range.getClientRects()).filter((lineRect) => {
148
+ return lineRect.width > 0 && lineRect.height > 0;
149
+ });
150
+ let tightWidth = 0;
151
+ for (const lineRect of lineRects) {
152
+ tightWidth = Math.max(tightWidth, lineRect.width);
153
+ }
154
+ const lineCount = lineRects.length;
155
+ if (lineCount === 0) {
156
+ return null;
157
+ }
158
+ return {
159
+ tightWidth,
160
+ lineCount,
161
+ lineHeight: computedLineHeight
162
+ };
163
+ } catch {
164
+ return null;
165
+ }
166
+ }
167
+ function buildElementDescriptor({
168
+ element,
169
+ clickPosition,
170
+ siblingSelectors = []
171
+ }) {
172
+ const selectableData = getSelectableDataFromElement(element);
173
+ if (selectableData) {
174
+ return selectableData;
175
+ }
176
+ const textMetrics = getTextMetrics(element);
177
+ const fiberChain = element instanceof HTMLElement ? getFiberChain(element) : [];
178
+ const sourceLocation = fiberChain[0]?.sourceLocation;
179
+ return {
180
+ kind: "react-element",
181
+ selector: buildSelector(element),
182
+ tagName: element.tagName.toLowerCase(),
183
+ elementType: identifyElement(element),
184
+ textContent: element.textContent?.trim()?.slice(0, 200) ?? null,
185
+ rect: getElementBoundingRect(element),
186
+ textMetrics,
187
+ outerHTML: element.outerHTML.slice(0, 4e3),
188
+ definedStyles: getDefinedStyles(element),
189
+ inheritedStyles: getInheritedStyles(element),
190
+ clickPosition,
191
+ sourceLocation,
192
+ fiberChain,
193
+ siblingSelectors
194
+ };
195
+ }
196
+ export {
197
+ buildElementDescriptor,
198
+ buildSelector,
199
+ getNearestSelectableElement
200
+ };
201
+ //# sourceMappingURL=elementDescriptor.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../select-mode/descriptor/elementDescriptor.ts"],
4
+ "sourcesContent": ["import type {\n SelectableData,\n SelectModeClickPosition,\n SelectModeTextMetrics,\n} from \"schemas/generated/selectMode\";\n\nimport {\n readSelectablePayload,\n SELECT_MODE_SELECTABLE_ATTRIBUTE,\n SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE,\n} from \"schemas/selectMode\";\n\nimport { getFiberChain } from \"../fiber\";\nimport { skipInlineTextMarkElements } from \"../inlineTextMarks\";\nimport { getElementBoundingRect } from \"../interactions/selectionGeometry\";\nimport { getDefinedStyles, getInheritedStyles } from \"./styleExtraction\";\n\n/**\n * Element that should own a click/hover selection: skip TipTap/inline JSX\n * mark wrappers, then prefer an explicit selectable boundary when present.\n */\nexport function getNearestSelectableElement(element: Element): Element {\n const host = skipInlineTextMarkElements(element);\n return host.closest(`[${SELECT_MODE_SELECTABLE_ATTRIBUTE}]`) ?? host;\n}\n\nfunction getSelectableDataFromElement(element: Element): SelectableData | null {\n const selectableElement = element.closest(\n `[${SELECT_MODE_SELECTABLE_ATTRIBUTE}]`,\n );\n if (!selectableElement) {\n return null;\n }\n\n const selectablePayload = readSelectablePayload(\n selectableElement.getAttribute(SELECT_MODE_SELECTABLE_PAYLOAD_ATTRIBUTE),\n );\n if (!selectablePayload) {\n return null;\n }\n\n return {\n ...selectablePayload,\n rect: getElementBoundingRect(selectableElement),\n };\n}\n\n/**\n * Produce a short human-readable label for an element (used in chat tokens\n * and prompt context). Tag-aware so a `<button>` reads as `button: \"Save\"`\n * rather than just `button` \u2014 that extra detail is what lets the agent\n * resolve \"the save button\" without us having to send a screenshot.\n */\nfunction identifyElement(element: Element): string {\n const tagName = element.tagName.toLowerCase();\n\n if (\n tagName === \"button\" ||\n element.getAttribute(\"role\") === \"button\" ||\n tagName === \"input\"\n ) {\n const trimmedText = element.textContent?.trim();\n if (trimmedText) {\n return `${tagName}: \"${trimmedText.slice(0, 60)}\"`;\n }\n const ariaLabel = element.getAttribute(\"aria-label\");\n if (ariaLabel) {\n return `${tagName}: [${ariaLabel}]`;\n }\n if (tagName === \"input\") {\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n const inputType = (element as HTMLInputElement).type || \"text\";\n const placeholder = element.getAttribute(\"placeholder\");\n return placeholder\n ? `input(${inputType}): \"${placeholder}\"`\n : `input(${inputType})`;\n }\n return tagName;\n }\n\n if (tagName === \"a\") {\n const trimmedText = element.textContent?.trim();\n if (trimmedText) {\n return `link: \"${trimmedText.slice(0, 60)}\"`;\n }\n const href = element.getAttribute(\"href\");\n if (href) {\n return `link: [${href.slice(0, 60)}]`;\n }\n return \"link\";\n }\n\n if (tagName === \"img\") {\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n const alt = (element as HTMLImageElement).alt;\n if (alt) {\n return `image: \"${alt.slice(0, 60)}\"`;\n }\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n const src = (element as HTMLImageElement).src;\n if (src) {\n const filename = src.split(\"/\").pop()?.split(\"?\")[0] ?? src;\n return `image: [${filename.slice(0, 40)}]`;\n }\n return \"image\";\n }\n\n if (/^h[1-6]$/.test(tagName)) {\n const trimmedText = element.textContent?.trim();\n return trimmedText\n ? `heading(${tagName}): \"${trimmedText.slice(0, 60)}\"`\n : tagName;\n }\n\n if (\n [\"div\", \"main\", \"section\", \"article\", \"header\", \"footer\", \"nav\"].includes(\n tagName,\n )\n ) {\n const role = element.getAttribute(\"role\");\n if (role) {\n return role;\n }\n }\n\n const trimmedText = element.textContent?.trim();\n if (trimmedText && trimmedText.length < 120) {\n const role = element.getAttribute(\"role\");\n const label = role ?? tagName;\n return `${label}: \"${trimmedText.slice(0, 60)}\"`;\n }\n\n const role = element.getAttribute(\"role\");\n if (role) {\n return role;\n }\n\n const className = element.className;\n if (typeof className === \"string\" && className) {\n const meaningfulClassName = className.split(/\\s+/).find((classToken) => {\n return (\n !classToken.startsWith(\"_\") &&\n !classToken.match(/^[a-z]{1,2}\\d/) &&\n classToken.length > 2\n );\n });\n if (meaningfulClassName) {\n return `${tagName}.${meaningfulClassName}`;\n }\n }\n\n return tagName;\n}\n\n/**\n * Build a CSS selector path from `element` up to the document root. Stops\n * (and short-circuits) at the first ancestor with an `id`. Used so the\n * parent can identify the element later without holding a DOM reference.\n */\nexport function buildSelector(element: Element): string {\n const parts: string[] = [];\n let currentElement: Element | null = element;\n\n while (currentElement && currentElement !== document.documentElement) {\n const tag = currentElement.tagName.toLowerCase();\n const id = currentElement.id;\n\n if (id) {\n parts.unshift(`#${id}`);\n break;\n }\n\n const parentElement: Element | null = currentElement.parentElement;\n if (parentElement) {\n const currentTag = currentElement.tagName;\n // Legacy cast - may or may not be necessary\n // eslint-disable-next-line replo/no-as-cast\n const siblings = Array.from(parentElement.children) as Element[];\n const siblingElementsWithSameTag = siblings.filter((sibling) => {\n return sibling.tagName === currentTag;\n });\n if (siblingElementsWithSameTag.length > 1) {\n const index = siblingElementsWithSameTag.indexOf(currentElement) + 1;\n parts.unshift(`${tag}:nth-of-type(${index})`);\n } else {\n parts.unshift(tag);\n }\n } else {\n parts.unshift(tag);\n }\n\n currentElement = parentElement;\n }\n\n return parts.join(\" > \");\n}\n\n/**\n * Measures the actual rendered text inside `element` \u2014 the tightest width\n * the text occupies, the line count, and the line height. We return this\n * alongside the element's bounding rect so the parent panel can position\n * itself relative to the *text* (not the element box) for text-heavy\n * elements like headings and paragraphs.\n */\nfunction getTextMetrics(element: Element): SelectModeTextMetrics | null {\n const text = element.textContent?.trim();\n if (!text) {\n return null;\n }\n\n const style = window.getComputedStyle(element);\n const parsedLineHeight = Number.parseFloat(style.lineHeight);\n const computedLineHeight = Number.isNaN(parsedLineHeight)\n ? Number.parseFloat(style.fontSize) * 1.2\n : parsedLineHeight;\n\n try {\n const range = document.createRange();\n range.selectNodeContents(element);\n\n const lineRects = Array.from(range.getClientRects()).filter((lineRect) => {\n return lineRect.width > 0 && lineRect.height > 0;\n });\n\n let tightWidth = 0;\n for (const lineRect of lineRects) {\n tightWidth = Math.max(tightWidth, lineRect.width);\n }\n\n const lineCount = lineRects.length;\n if (lineCount === 0) {\n return null;\n }\n\n return {\n tightWidth,\n lineCount,\n lineHeight: computedLineHeight,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * The single entrypoint for converting a DOM `Element` into the serialized\n * `SelectedElement` payload that crosses the iframe<->parent boundary.\n * Centralizes everything the parent (and downstream agent) need to know\n * about a selection: identification, geometry, source location, and a\n * style-inlined HTML snippet.\n *\n * @author Kevin O'Connell 2026-04-17\n */\nexport function buildElementDescriptor({\n element,\n clickPosition,\n siblingSelectors = [],\n}: {\n element: Element;\n clickPosition: SelectModeClickPosition;\n siblingSelectors?: string[];\n}): SelectableData {\n const selectableData = getSelectableDataFromElement(element);\n if (selectableData) {\n return selectableData;\n }\n\n const textMetrics = getTextMetrics(element);\n const fiberChain =\n element instanceof HTMLElement ? getFiberChain(element) : [];\n const sourceLocation = fiberChain[0]?.sourceLocation;\n\n return {\n kind: \"react-element\",\n selector: buildSelector(element),\n tagName: element.tagName.toLowerCase(),\n elementType: identifyElement(element),\n textContent: element.textContent?.trim()?.slice(0, 200) ?? null,\n rect: getElementBoundingRect(element),\n textMetrics,\n outerHTML: element.outerHTML.slice(0, 4000),\n definedStyles: getDefinedStyles(element),\n inheritedStyles: getInheritedStyles(element),\n clickPosition,\n sourceLocation,\n fiberChain,\n siblingSelectors,\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["trimmedText", "role"]
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { SelectModeDefinedStyle } from "../../_vendor/schemas/generated/selectMode";
2
+ export declare function getDefinedStyles(element: Element): SelectModeDefinedStyle[];
3
+ export declare function getInheritedStyles(element: Element): Record<string, string>;
@@ -0,0 +1,271 @@
1
+ const CONTROL_STYLE_PROPERTIES = [
2
+ "color",
3
+ "background-color",
4
+ "font-family",
5
+ "font-size",
6
+ "font-weight",
7
+ "line-height",
8
+ "letter-spacing",
9
+ "text-align"
10
+ ];
11
+ const CONTROL_STYLE_PROPERTY_SET = new Set(CONTROL_STYLE_PROPERTIES);
12
+ function isControlStyleProperty(propertyName) {
13
+ return CONTROL_STYLE_PROPERTY_SET.has(propertyName);
14
+ }
15
+ function getEscapedClassName(className) {
16
+ return CSS.escape(className);
17
+ }
18
+ function getClassSelectorMatches({
19
+ selectorText,
20
+ classNames
21
+ }) {
22
+ const matches = [];
23
+ const selectorParts = selectorText.split(",").map((selectorPart) => {
24
+ return selectorPart.trim();
25
+ });
26
+ for (const selectorPart of selectorParts) {
27
+ for (const className of classNames) {
28
+ const escapedClassName = getEscapedClassName(className);
29
+ const baseSelector = `.${escapedClassName}`;
30
+ if (selectorPart === baseSelector) {
31
+ matches.push({ className, pseudo: null });
32
+ continue;
33
+ }
34
+ if (!selectorPart.startsWith(`${baseSelector}:`)) {
35
+ continue;
36
+ }
37
+ const pseudo = selectorPart.slice(baseSelector.length);
38
+ const isSimplePseudoSelector = pseudo.startsWith(":") && !/[ >+~#[.]/.test(pseudo) && !pseudo.includes("::");
39
+ if (isSimplePseudoSelector) {
40
+ matches.push({ className, pseudo });
41
+ }
42
+ }
43
+ }
44
+ return matches;
45
+ }
46
+ function getNestedAtRules({
47
+ rule,
48
+ activeAtRules
49
+ }) {
50
+ const nextAtRules = [...activeAtRules];
51
+ if (rule instanceof CSSMediaRule) {
52
+ nextAtRules.push({ type: "@media", text: rule.conditionText });
53
+ } else if (rule instanceof CSSSupportsRule) {
54
+ nextAtRules.push({ type: "@supports", text: rule.conditionText });
55
+ } else if (rule.constructor?.name === "CSSContainerRule" && "conditionText" in rule && typeof rule.conditionText === "string") {
56
+ nextAtRules.push({
57
+ type: "@container",
58
+ text: rule.conditionText
59
+ });
60
+ }
61
+ return nextAtRules;
62
+ }
63
+ function getNestedRuleList(rule) {
64
+ if (typeof CSSGroupingRule !== "undefined" && rule instanceof CSSGroupingRule) {
65
+ return rule.cssRules;
66
+ }
67
+ return null;
68
+ }
69
+ function getStyleVariant({
70
+ atRules,
71
+ pseudo
72
+ }) {
73
+ if (atRules.length === 0 && !pseudo) {
74
+ return null;
75
+ }
76
+ return { atRules, pseudo };
77
+ }
78
+ function getStyleVariantKey(variant) {
79
+ return variant ? JSON.stringify(variant) : "base";
80
+ }
81
+ function getDefinedStyleKey({
82
+ property,
83
+ variant
84
+ }) {
85
+ return `${property}:${getStyleVariantKey(variant)}`;
86
+ }
87
+ function getResolvedClassStyleValue({
88
+ className,
89
+ property,
90
+ raw,
91
+ variant
92
+ }) {
93
+ if (variant) {
94
+ return raw;
95
+ }
96
+ const temporaryElement = document.createElement("div");
97
+ temporaryElement.className = className;
98
+ document.body.append(temporaryElement);
99
+ const resolved = window.getComputedStyle(temporaryElement).getPropertyValue(property);
100
+ temporaryElement.remove();
101
+ return resolved.trim() || raw;
102
+ }
103
+ function setDefinedStyle({
104
+ definedStylesByKey,
105
+ property,
106
+ variant,
107
+ className,
108
+ raw,
109
+ resolved
110
+ }) {
111
+ definedStylesByKey.set(getDefinedStyleKey({ property, variant }), {
112
+ property,
113
+ variant,
114
+ className,
115
+ raw,
116
+ resolved
117
+ });
118
+ }
119
+ function addRuleDefinedStyles({
120
+ rule,
121
+ activeAtRules,
122
+ classNames,
123
+ definedStylesByKey
124
+ }) {
125
+ const selectorMatches = getClassSelectorMatches({
126
+ selectorText: rule.selectorText ?? "",
127
+ classNames
128
+ });
129
+ if (selectorMatches.length === 0) {
130
+ return;
131
+ }
132
+ for (const selectorMatch of selectorMatches) {
133
+ const variant = getStyleVariant({
134
+ atRules: activeAtRules,
135
+ pseudo: selectorMatch.pseudo
136
+ });
137
+ for (let styleIndex = 0; styleIndex < rule.style.length; styleIndex += 1) {
138
+ const property = rule.style.item(styleIndex);
139
+ if (!property || !isControlStyleProperty(property)) {
140
+ continue;
141
+ }
142
+ const raw = rule.style.getPropertyValue(property).trim();
143
+ if (!raw) {
144
+ continue;
145
+ }
146
+ setDefinedStyle({
147
+ definedStylesByKey,
148
+ property,
149
+ variant,
150
+ className: selectorMatch.className,
151
+ raw,
152
+ resolved: getResolvedClassStyleValue({
153
+ className: selectorMatch.className,
154
+ property,
155
+ raw,
156
+ variant
157
+ })
158
+ });
159
+ }
160
+ }
161
+ }
162
+ function addStyleRulesRecursively({
163
+ ruleList,
164
+ activeAtRules,
165
+ classNames,
166
+ definedStylesByKey
167
+ }) {
168
+ for (const rule of Array.from(ruleList)) {
169
+ const nestedRuleList = getNestedRuleList(rule);
170
+ if (nestedRuleList) {
171
+ addStyleRulesRecursively({
172
+ ruleList: nestedRuleList,
173
+ activeAtRules: getNestedAtRules({ rule, activeAtRules }),
174
+ classNames,
175
+ definedStylesByKey
176
+ });
177
+ }
178
+ if (rule instanceof CSSStyleRule) {
179
+ addRuleDefinedStyles({
180
+ rule,
181
+ activeAtRules,
182
+ classNames,
183
+ definedStylesByKey
184
+ });
185
+ }
186
+ }
187
+ }
188
+ function addClassDefinedStyles({
189
+ element,
190
+ definedStylesByKey
191
+ }) {
192
+ const classNames = Array.from(
193
+ new Set([...element.classList].filter(Boolean))
194
+ );
195
+ if (classNames.length === 0) {
196
+ return;
197
+ }
198
+ for (const sheet of Array.from(document.styleSheets)) {
199
+ if (sheet.href) {
200
+ try {
201
+ const sheetUrl = new URL(sheet.href);
202
+ if (sheetUrl.origin !== window.location.origin) {
203
+ continue;
204
+ }
205
+ } catch (error) {
206
+ if (error instanceof TypeError) {
207
+ continue;
208
+ }
209
+ throw error;
210
+ }
211
+ }
212
+ try {
213
+ addStyleRulesRecursively({
214
+ ruleList: sheet.cssRules,
215
+ activeAtRules: [],
216
+ classNames,
217
+ definedStylesByKey
218
+ });
219
+ } catch (error) {
220
+ if (error instanceof DOMException && error.name === "SecurityError") {
221
+ continue;
222
+ }
223
+ throw error;
224
+ }
225
+ }
226
+ }
227
+ function addInlineDefinedStyles({
228
+ element,
229
+ definedStylesByKey
230
+ }) {
231
+ if (!(element instanceof HTMLElement)) {
232
+ return;
233
+ }
234
+ for (let styleIndex = 0; styleIndex < element.style.length; styleIndex += 1) {
235
+ const property = element.style.item(styleIndex);
236
+ if (!property || !isControlStyleProperty(property)) {
237
+ continue;
238
+ }
239
+ const raw = element.style.getPropertyValue(property).trim();
240
+ if (!raw) {
241
+ continue;
242
+ }
243
+ setDefinedStyle({
244
+ definedStylesByKey,
245
+ property,
246
+ variant: null,
247
+ className: null,
248
+ raw,
249
+ resolved: raw
250
+ });
251
+ }
252
+ }
253
+ function getDefinedStyles(element) {
254
+ const definedStylesByKey = /* @__PURE__ */ new Map();
255
+ addClassDefinedStyles({ element, definedStylesByKey });
256
+ addInlineDefinedStyles({ element, definedStylesByKey });
257
+ return Array.from(definedStylesByKey.values());
258
+ }
259
+ function getInheritedStyles(element) {
260
+ const computedStyle = window.getComputedStyle(element);
261
+ const inheritedStyles = {};
262
+ for (const property of CONTROL_STYLE_PROPERTIES) {
263
+ inheritedStyles[property] = computedStyle.getPropertyValue(property);
264
+ }
265
+ return inheritedStyles;
266
+ }
267
+ export {
268
+ getDefinedStyles,
269
+ getInheritedStyles
270
+ };
271
+ //# sourceMappingURL=styleExtraction.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../select-mode/descriptor/styleExtraction.ts"],
4
+ "sourcesContent": ["import type {\n SelectModeDefinedStyle,\n SelectModeStyleAtRule,\n SelectModeStyleVariant,\n} from \"schemas/generated/selectMode\";\n\nconst CONTROL_STYLE_PROPERTIES = [\n \"color\",\n \"background-color\",\n \"font-family\",\n \"font-size\",\n \"font-weight\",\n \"line-height\",\n \"letter-spacing\",\n \"text-align\",\n] as const;\n\ntype ControlStyleProperty = (typeof CONTROL_STYLE_PROPERTIES)[number];\n\nconst CONTROL_STYLE_PROPERTY_SET = new Set<string>(CONTROL_STYLE_PROPERTIES);\n\ntype SelectorMatch = {\n className: string;\n pseudo: string | null;\n};\n\nfunction isControlStyleProperty(\n propertyName: string,\n): propertyName is ControlStyleProperty {\n return CONTROL_STYLE_PROPERTY_SET.has(propertyName);\n}\n\nfunction getEscapedClassName(className: string) {\n return CSS.escape(className);\n}\n\nfunction getClassSelectorMatches({\n selectorText,\n classNames,\n}: {\n selectorText: string;\n classNames: string[];\n}): SelectorMatch[] {\n const matches: SelectorMatch[] = [];\n const selectorParts = selectorText.split(\",\").map((selectorPart) => {\n return selectorPart.trim();\n });\n\n for (const selectorPart of selectorParts) {\n for (const className of classNames) {\n const escapedClassName = getEscapedClassName(className);\n const baseSelector = `.${escapedClassName}`;\n if (selectorPart === baseSelector) {\n matches.push({ className, pseudo: null });\n continue;\n }\n\n if (!selectorPart.startsWith(`${baseSelector}:`)) {\n continue;\n }\n\n const pseudo = selectorPart.slice(baseSelector.length);\n const isSimplePseudoSelector =\n pseudo.startsWith(\":\") &&\n !/[ >+~#[.]/.test(pseudo) &&\n !pseudo.includes(\"::\");\n if (isSimplePseudoSelector) {\n matches.push({ className, pseudo });\n }\n }\n }\n\n return matches;\n}\n\nfunction getNestedAtRules({\n rule,\n activeAtRules,\n}: {\n rule: CSSRule;\n activeAtRules: SelectModeStyleAtRule[];\n}): SelectModeStyleAtRule[] {\n const nextAtRules = [...activeAtRules];\n if (rule instanceof CSSMediaRule) {\n nextAtRules.push({ type: \"@media\", text: rule.conditionText });\n } else if (rule instanceof CSSSupportsRule) {\n nextAtRules.push({ type: \"@supports\", text: rule.conditionText });\n } else if (\n rule.constructor?.name === \"CSSContainerRule\" &&\n \"conditionText\" in rule &&\n typeof rule.conditionText === \"string\"\n ) {\n nextAtRules.push({\n type: \"@container\",\n text: rule.conditionText,\n });\n }\n return nextAtRules;\n}\n\nfunction getNestedRuleList(rule: CSSRule): CSSRuleList | null {\n if (\n typeof CSSGroupingRule !== \"undefined\" &&\n rule instanceof CSSGroupingRule\n ) {\n return rule.cssRules;\n }\n return null;\n}\n\nfunction getStyleVariant({\n atRules,\n pseudo,\n}: {\n atRules: SelectModeStyleAtRule[];\n pseudo: string | null;\n}): SelectModeStyleVariant | null {\n if (atRules.length === 0 && !pseudo) {\n return null;\n }\n return { atRules, pseudo };\n}\n\nfunction getStyleVariantKey(variant: SelectModeStyleVariant | null) {\n return variant ? JSON.stringify(variant) : \"base\";\n}\n\nfunction getDefinedStyleKey({\n property,\n variant,\n}: {\n property: string;\n variant: SelectModeStyleVariant | null;\n}) {\n return `${property}:${getStyleVariantKey(variant)}`;\n}\n\nfunction getResolvedClassStyleValue({\n className,\n property,\n raw,\n variant,\n}: {\n className: string;\n property: string;\n raw: string;\n variant: SelectModeStyleVariant | null;\n}) {\n if (variant) {\n return raw;\n }\n\n const temporaryElement = document.createElement(\"div\");\n temporaryElement.className = className;\n document.body.append(temporaryElement);\n const resolved = window\n .getComputedStyle(temporaryElement)\n .getPropertyValue(property);\n temporaryElement.remove();\n\n return resolved.trim() || raw;\n}\n\nfunction setDefinedStyle({\n definedStylesByKey,\n property,\n variant,\n className,\n raw,\n resolved,\n}: {\n definedStylesByKey: Map<string, SelectModeDefinedStyle>;\n property: string;\n variant: SelectModeStyleVariant | null;\n className: string | null;\n raw: string;\n resolved: string;\n}) {\n definedStylesByKey.set(getDefinedStyleKey({ property, variant }), {\n property,\n variant,\n className,\n raw,\n resolved,\n });\n}\n\nfunction addRuleDefinedStyles({\n rule,\n activeAtRules,\n classNames,\n definedStylesByKey,\n}: {\n rule: CSSStyleRule;\n activeAtRules: SelectModeStyleAtRule[];\n classNames: string[];\n definedStylesByKey: Map<string, SelectModeDefinedStyle>;\n}) {\n const selectorMatches = getClassSelectorMatches({\n selectorText: rule.selectorText ?? \"\",\n classNames,\n });\n if (selectorMatches.length === 0) {\n return;\n }\n\n for (const selectorMatch of selectorMatches) {\n const variant = getStyleVariant({\n atRules: activeAtRules,\n pseudo: selectorMatch.pseudo,\n });\n\n for (let styleIndex = 0; styleIndex < rule.style.length; styleIndex += 1) {\n const property = rule.style.item(styleIndex);\n if (!property || !isControlStyleProperty(property)) {\n continue;\n }\n\n const raw = rule.style.getPropertyValue(property).trim();\n if (!raw) {\n continue;\n }\n\n setDefinedStyle({\n definedStylesByKey,\n property,\n variant,\n className: selectorMatch.className,\n raw,\n resolved: getResolvedClassStyleValue({\n className: selectorMatch.className,\n property,\n raw,\n variant,\n }),\n });\n }\n }\n}\n\nfunction addStyleRulesRecursively({\n ruleList,\n activeAtRules,\n classNames,\n definedStylesByKey,\n}: {\n ruleList: CSSRuleList;\n activeAtRules: SelectModeStyleAtRule[];\n classNames: string[];\n definedStylesByKey: Map<string, SelectModeDefinedStyle>;\n}) {\n for (const rule of Array.from(ruleList)) {\n const nestedRuleList = getNestedRuleList(rule);\n if (nestedRuleList) {\n addStyleRulesRecursively({\n ruleList: nestedRuleList,\n activeAtRules: getNestedAtRules({ rule, activeAtRules }),\n classNames,\n definedStylesByKey,\n });\n }\n\n if (rule instanceof CSSStyleRule) {\n addRuleDefinedStyles({\n rule,\n activeAtRules,\n classNames,\n definedStylesByKey,\n });\n }\n }\n}\n\nfunction addClassDefinedStyles({\n element,\n definedStylesByKey,\n}: {\n element: Element;\n definedStylesByKey: Map<string, SelectModeDefinedStyle>;\n}) {\n const classNames = Array.from(\n new Set([...element.classList].filter(Boolean)),\n );\n if (classNames.length === 0) {\n return;\n }\n\n for (const sheet of Array.from(document.styleSheets)) {\n if (sheet.href) {\n try {\n const sheetUrl = new URL(sheet.href);\n if (sheetUrl.origin !== window.location.origin) {\n continue;\n }\n } catch (error) {\n if (error instanceof TypeError) {\n continue;\n }\n throw error;\n }\n }\n\n try {\n addStyleRulesRecursively({\n ruleList: sheet.cssRules,\n activeAtRules: [],\n classNames,\n definedStylesByKey,\n });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"SecurityError\") {\n continue;\n }\n throw error;\n }\n }\n}\n\nfunction addInlineDefinedStyles({\n element,\n definedStylesByKey,\n}: {\n element: Element;\n definedStylesByKey: Map<string, SelectModeDefinedStyle>;\n}) {\n if (!(element instanceof HTMLElement)) {\n return;\n }\n\n for (let styleIndex = 0; styleIndex < element.style.length; styleIndex += 1) {\n const property = element.style.item(styleIndex);\n if (!property || !isControlStyleProperty(property)) {\n continue;\n }\n const raw = element.style.getPropertyValue(property).trim();\n if (!raw) {\n continue;\n }\n setDefinedStyle({\n definedStylesByKey,\n property,\n variant: null,\n className: null,\n raw,\n resolved: raw,\n });\n }\n}\n\nexport function getDefinedStyles(element: Element): SelectModeDefinedStyle[] {\n const definedStylesByKey = new Map<string, SelectModeDefinedStyle>();\n addClassDefinedStyles({ element, definedStylesByKey });\n addInlineDefinedStyles({ element, definedStylesByKey });\n return Array.from(definedStylesByKey.values());\n}\n\nexport function getInheritedStyles(element: Element): Record<string, string> {\n const computedStyle = window.getComputedStyle(element);\n const inheritedStyles: Record<string, string> = {};\n for (const property of CONTROL_STYLE_PROPERTIES) {\n inheritedStyles[property] = computedStyle.getPropertyValue(property);\n }\n return inheritedStyles;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,10 @@
1
+ import type { DisplayMode } from "../_vendor/schemas/generated/selectMode";
2
+ export declare const displayModeStore: {
3
+ getSnapshot(): DisplayMode;
4
+ getServerSnapshot(): DisplayMode;
5
+ subscribe(listener: () => void): () => void;
6
+ setDisplayMode(nextDisplayMode: DisplayMode): void;
7
+ /** Test-only: reset back to the default so specs don't leak state. */
8
+ reset(): void;
9
+ };
10
+ export declare function useDisplayMode(): DisplayMode;
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { useSyncExternalStore } from "react";
3
+ const listeners = /* @__PURE__ */ new Set();
4
+ let displayMode = "browse";
5
+ const SERVER_SNAPSHOT = "browse";
6
+ function notify() {
7
+ for (const listener of listeners) {
8
+ listener();
9
+ }
10
+ }
11
+ const displayModeStore = {
12
+ getSnapshot() {
13
+ return displayMode;
14
+ },
15
+ getServerSnapshot() {
16
+ return SERVER_SNAPSHOT;
17
+ },
18
+ subscribe(listener) {
19
+ listeners.add(listener);
20
+ return () => {
21
+ listeners.delete(listener);
22
+ };
23
+ },
24
+ setDisplayMode(nextDisplayMode) {
25
+ if (nextDisplayMode === displayMode) {
26
+ return;
27
+ }
28
+ displayMode = nextDisplayMode;
29
+ notify();
30
+ },
31
+ /** Test-only: reset back to the default so specs don't leak state. */
32
+ reset() {
33
+ displayMode = "browse";
34
+ }
35
+ };
36
+ function useDisplayMode() {
37
+ return useSyncExternalStore(
38
+ displayModeStore.subscribe,
39
+ displayModeStore.getSnapshot,
40
+ displayModeStore.getServerSnapshot
41
+ );
42
+ }
43
+ export {
44
+ displayModeStore,
45
+ useDisplayMode
46
+ };
47
+ //# sourceMappingURL=displayModeStore.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../select-mode/displayModeStore.ts"],
4
+ "sourcesContent": ["\"use client\";\n\nimport type { DisplayMode } from \"schemas/generated/selectMode\";\n\nimport { useSyncExternalStore } from \"react\";\n\n/**\n * Framework-agnostic singleton for the preview iframe's select-mode display\n * mode (\"browse\" vs \"selection\"). It lives as a module singleton so that\n * components that don't share a provider ancestor \u2014 `EditorSelection` (which\n * owns the pointer/selection machinery) and `LinkInterceptor` (a sibling under\n * `ReploProvider`) \u2014 can agree on whether the user is currently selecting.\n *\n * `LinkInterceptor` needs this because in agent-preview mode it turns\n * same-origin link clicks into a `replo:navigate` postMessage (SPA-style\n * navigation of the preview). While select mode is active that navigation must\n * stand down so a link click selects the element instead of leaving the page \u2014\n * the two capture-phase click listeners otherwise race, and `stopPropagation`\n * can't suppress a sibling listener on the same node.\n *\n * @author Noah Gilmore 2026-07-23\n */\n\nconst listeners = new Set<() => void>();\nlet displayMode: DisplayMode = \"browse\";\n\n// select-mode DOM behavior is client-only, so the server snapshot is a stable\n// constant and never causes a hydration mismatch.\nconst SERVER_SNAPSHOT: DisplayMode = \"browse\";\n\nfunction notify() {\n for (const listener of listeners) {\n listener();\n }\n}\n\nexport const displayModeStore = {\n getSnapshot(): DisplayMode {\n return displayMode;\n },\n getServerSnapshot(): DisplayMode {\n return SERVER_SNAPSHOT;\n },\n subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n setDisplayMode(nextDisplayMode: DisplayMode) {\n if (nextDisplayMode === displayMode) {\n return;\n }\n displayMode = nextDisplayMode;\n notify();\n },\n /** Test-only: reset back to the default so specs don't leak state. */\n reset() {\n displayMode = \"browse\";\n },\n};\n\nexport function useDisplayMode(): DisplayMode {\n return useSyncExternalStore(\n displayModeStore.subscribe,\n displayModeStore.getSnapshot,\n displayModeStore.getServerSnapshot,\n );\n}\n"],
5
+ "mappings": ";AAIA,SAAS,4BAA4B;AAmBrC,MAAM,YAAY,oBAAI,IAAgB;AACtC,IAAI,cAA2B;AAI/B,MAAM,kBAA+B;AAErC,SAAS,SAAS;AAChB,aAAW,YAAY,WAAW;AAChC,aAAS;AAAA,EACX;AACF;AAEO,MAAM,mBAAmB;AAAA,EAC9B,cAA2B;AACzB,WAAO;AAAA,EACT;AAAA,EACA,oBAAiC;AAC/B,WAAO;AAAA,EACT;AAAA,EACA,UAAU,UAAkC;AAC1C,cAAU,IAAI,QAAQ;AACtB,WAAO,MAAM;AACX,gBAAU,OAAO,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,eAAe,iBAA8B;AAC3C,QAAI,oBAAoB,aAAa;AACnC;AAAA,IACF;AACA,kBAAc;AACd,WAAO;AAAA,EACT;AAAA;AAAA,EAEA,QAAQ;AACN,kBAAc;AAAA,EAChB;AACF;AAEO,SAAS,iBAA8B;AAC5C,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,EACnB;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,3 @@
1
+ export declare function installFastRefreshRelay({ onComplete, }?: {
2
+ onComplete?: () => void;
3
+ }): void;