@replohq/sandbox-runtime 1.20.0 → 1.22.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.
- package/_vendor/schemas/comments.d.ts +906 -0
- package/_vendor/schemas/commentsOverlayRpc.d.ts +348 -0
- package/_vendor/schemas/commentsOverlayRpc.mjs +92 -0
- package/_vendor/schemas/generated/comments.d.ts +237 -0
- package/_vendor/schemas/generated/commentsOverlayRpc.d.ts +18 -0
- package/_vendor/schemas/generated/selectMode.d.ts +3 -1
- package/_vendor/schemas/selectMode.d.ts +113 -0
- package/_vendor/schemas/selectMode.mjs +1 -1
- package/_vendor/schemas/selectModeIframeRpc.d.ts +226 -0
- package/_vendor/schemas/selectModeIframeRpc.mjs +1 -1
- package/buildMetadata.js +3 -3
- package/chunk-CGRTGQO5.mjs +544 -0
- package/comments-overlay/CommentsOverlayMount.d.ts +1 -0
- package/comments-overlay/CommentsOverlayMount.js +44 -0
- package/comments-overlay/LICENSE-THIRD-PARTY.md +45 -0
- package/comments-overlay/bridge.d.ts +11 -0
- package/comments-overlay/bridge.js +136 -0
- package/comments-overlay/capture.d.ts +55 -0
- package/comments-overlay/capture.js +250 -0
- package/comments-overlay/originGate.d.ts +1 -0
- package/comments-overlay/originGate.js +11 -0
- package/comments-overlay/overlay.d.ts +52 -0
- package/comments-overlay/overlay.js +781 -0
- package/comments-overlay/resolve.d.ts +27 -0
- package/comments-overlay/resolve.js +201 -0
- package/comments-overlay/sourceLookup.d.ts +11 -0
- package/comments-overlay/sourceLookup.js +63 -0
- package/comments-overlay/textQuote.d.ts +17 -0
- package/comments-overlay/textQuote.js +87 -0
- package/comments-overlay/vendor/bippy.d.ts +53 -0
- package/comments-overlay/vendor/bippy.js +402 -0
- package/comments-overlay/vendor/elementAnchors.d.ts +9 -0
- package/comments-overlay/vendor/elementAnchors.js +144 -0
- package/comments-overlay/vendor/fiberElement.d.ts +21 -0
- package/comments-overlay/vendor/fiberElement.js +251 -0
- package/comments-overlay/vendor/htmlPreview.d.ts +13 -0
- package/comments-overlay/vendor/htmlPreview.js +179 -0
- package/comments-overlay/vendor/selector.d.ts +38 -0
- package/comments-overlay/vendor/selector.js +372 -0
- package/next/config.js +37 -1
- package/package.json +4 -4
- package/sandbox-runtime.js +2 -0
- package/select-mode/descriptor/elementDescriptor.d.ts +4 -3
- package/select-mode/descriptor/elementDescriptor.js +20 -30
- package/select-mode/iframeRpcChannel.d.ts +84 -0
- package/select-mode/symbolicate.js +25 -7
- package/chunk-QTGDSYSU.mjs +0 -249
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025 Aiden Bai
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
* https://github.com/aidenybai/react-grab
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
getDisplayName,
|
|
8
|
+
getFiberFromHostInstance,
|
|
9
|
+
getLatestFiber,
|
|
10
|
+
isCompositeFiber,
|
|
11
|
+
isFiber,
|
|
12
|
+
normalizeFileName
|
|
13
|
+
} from "./bippy";
|
|
14
|
+
const MAX_OWNER_DEPTH = 80;
|
|
15
|
+
const MAX_COMPONENT_CHAIN_LENGTH = 10;
|
|
16
|
+
const LIST_ITEM_KEY_MAX_LENGTH_CHARS = 120;
|
|
17
|
+
function isShadowRoot(node) {
|
|
18
|
+
return typeof ShadowRoot !== "undefined" && node instanceof ShadowRoot;
|
|
19
|
+
}
|
|
20
|
+
function findNearestFiberElement(element) {
|
|
21
|
+
let current = element;
|
|
22
|
+
while (current?.ownerDocument === element.ownerDocument) {
|
|
23
|
+
if (getFiberFromHostInstance(current)) {
|
|
24
|
+
return current;
|
|
25
|
+
}
|
|
26
|
+
if (current.parentElement) {
|
|
27
|
+
current = current.parentElement;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const rootNode = current.getRootNode();
|
|
31
|
+
current = isShadowRoot(rootNode) ? rootNode.host : null;
|
|
32
|
+
}
|
|
33
|
+
return element;
|
|
34
|
+
}
|
|
35
|
+
function getElementFiber(element) {
|
|
36
|
+
const fiber = getFiberFromHostInstance(element);
|
|
37
|
+
return fiber ? getLatestFiber(fiber) : null;
|
|
38
|
+
}
|
|
39
|
+
function hasKeyedSibling(fiber) {
|
|
40
|
+
let sibling = fiber.return?.child ?? null;
|
|
41
|
+
while (sibling) {
|
|
42
|
+
if (sibling !== fiber && sibling.key !== null) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
sibling = sibling.sibling;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
function findNearestListItemKey(startingFiber) {
|
|
50
|
+
let fiber = startingFiber;
|
|
51
|
+
let componentBoundariesCrossed = 0;
|
|
52
|
+
while (fiber) {
|
|
53
|
+
if (fiber.key !== null && hasKeyedSibling(fiber)) {
|
|
54
|
+
return String(fiber.key).slice(0, LIST_ITEM_KEY_MAX_LENGTH_CHARS);
|
|
55
|
+
}
|
|
56
|
+
if (isCompositeFiber(fiber)) {
|
|
57
|
+
componentBoundariesCrossed += 1;
|
|
58
|
+
if (componentBoundariesCrossed === 2) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
fiber = fiber.return;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const NON_COMPONENT_PREFIXES = [
|
|
67
|
+
"_",
|
|
68
|
+
"$",
|
|
69
|
+
"motion.",
|
|
70
|
+
"styled.",
|
|
71
|
+
"chakra.",
|
|
72
|
+
"ark.",
|
|
73
|
+
"Primitive.",
|
|
74
|
+
"Slot."
|
|
75
|
+
];
|
|
76
|
+
const NEXT_INTERNAL_COMPONENT_NAMES = /* @__PURE__ */ new Set([
|
|
77
|
+
"AppRouter",
|
|
78
|
+
"AppRouterAnnouncer",
|
|
79
|
+
"AppDevOverlay",
|
|
80
|
+
"AppDevOverlayErrorBoundary",
|
|
81
|
+
"ClientPageRoot",
|
|
82
|
+
"ClientSegmentRoot",
|
|
83
|
+
"DevRootHTTPAccessFallbackBoundary",
|
|
84
|
+
"ErrorBoundary",
|
|
85
|
+
"ErrorBoundaryHandler",
|
|
86
|
+
"GracefulDegradeBoundary",
|
|
87
|
+
"HTTPAccessErrorFallback",
|
|
88
|
+
"HTTPAccessFallbackBoundary",
|
|
89
|
+
"HTTPAccessFallbackErrorBoundary",
|
|
90
|
+
"HandleRedirect",
|
|
91
|
+
"Head",
|
|
92
|
+
"HistoryUpdater",
|
|
93
|
+
"HotReload",
|
|
94
|
+
"InnerLayoutRouter",
|
|
95
|
+
"InnerScrollAndFocusHandler",
|
|
96
|
+
"InnerScrollAndFocusHandlerOld",
|
|
97
|
+
"InnerScrollAndMaybeFocusHandler",
|
|
98
|
+
"InnerScrollHandlerNew",
|
|
99
|
+
"LinkComponent",
|
|
100
|
+
"LoadableComponent",
|
|
101
|
+
"LoadingBoundary",
|
|
102
|
+
"LoadingBoundaryProvider",
|
|
103
|
+
"NotAllowedRootHTTPFallbackError",
|
|
104
|
+
"OfflineProvider",
|
|
105
|
+
"OuterLayoutRouter",
|
|
106
|
+
"RedirectBoundary",
|
|
107
|
+
"RedirectErrorBoundary",
|
|
108
|
+
"RenderFromTemplateContext",
|
|
109
|
+
"RenderValidationBoundaryAtThisLevel",
|
|
110
|
+
"ReplaySsrOnlyErrors",
|
|
111
|
+
"RootErrorBoundary",
|
|
112
|
+
"RootLevelDevOverlayElement",
|
|
113
|
+
"Router",
|
|
114
|
+
"ScrollAndFocusHandler",
|
|
115
|
+
"ScrollAndMaybeFocusHandler",
|
|
116
|
+
"SegmentBoundaryTrigger",
|
|
117
|
+
"SegmentBoundaryTriggerNode",
|
|
118
|
+
"SegmentStateProvider",
|
|
119
|
+
"SegmentTrieNode",
|
|
120
|
+
"SegmentViewNode",
|
|
121
|
+
"SegmentViewStateNode",
|
|
122
|
+
"ServerRoot",
|
|
123
|
+
"body",
|
|
124
|
+
"html"
|
|
125
|
+
]);
|
|
126
|
+
const PLACEHOLDER_COMPONENT_NAMES = /* @__PURE__ */ new Set([
|
|
127
|
+
"<anonymous>",
|
|
128
|
+
"<unknown>",
|
|
129
|
+
"Anonymous",
|
|
130
|
+
"Unknown"
|
|
131
|
+
]);
|
|
132
|
+
const REACT_INTERNAL_COMPONENT_NAMES = /* @__PURE__ */ new Set([
|
|
133
|
+
"Suspense",
|
|
134
|
+
"Fragment",
|
|
135
|
+
"StrictMode",
|
|
136
|
+
"Profiler",
|
|
137
|
+
"SuspenseList"
|
|
138
|
+
]);
|
|
139
|
+
const LIBRARY_INTERNAL_COMPONENT_NAMES = /* @__PURE__ */ new Set([
|
|
140
|
+
"MotionDOMComponent",
|
|
141
|
+
"Slot",
|
|
142
|
+
"SlotClone"
|
|
143
|
+
]);
|
|
144
|
+
const LIBRARY_INTERNAL_COMPONENT_SUFFIXES = [
|
|
145
|
+
".Consumer",
|
|
146
|
+
".Context",
|
|
147
|
+
".Provider",
|
|
148
|
+
".Slot",
|
|
149
|
+
".SlotClone",
|
|
150
|
+
".Slottable",
|
|
151
|
+
"ProviderProvider"
|
|
152
|
+
];
|
|
153
|
+
function isInternalComponentName(name, isNextProject) {
|
|
154
|
+
return PLACEHOLDER_COMPONENT_NAMES.has(name) || isNextProject && NEXT_INTERNAL_COMPONENT_NAMES.has(name) || REACT_INTERNAL_COMPONENT_NAMES.has(name) || LIBRARY_INTERNAL_COMPONENT_NAMES.has(name) || LIBRARY_INTERNAL_COMPONENT_SUFFIXES.some((suffix) => {
|
|
155
|
+
return name.endsWith(suffix);
|
|
156
|
+
}) || NON_COMPONENT_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
157
|
+
}
|
|
158
|
+
function isUsefulComponentName(name, isNextProject) {
|
|
159
|
+
return name.length > 1 && name[0] === name[0]?.toUpperCase() && !isInternalComponentName(name, isNextProject);
|
|
160
|
+
}
|
|
161
|
+
let cachedIsNextProject;
|
|
162
|
+
function hasNextAssetScript(allowCrossOrigin) {
|
|
163
|
+
const documentUrl = new URL(document.baseURI);
|
|
164
|
+
return Array.from(document.scripts).some((script) => {
|
|
165
|
+
if (!script.src) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const scriptUrl = new URL(script.src, documentUrl);
|
|
170
|
+
return (allowCrossOrigin || scriptUrl.origin === documentUrl.origin) && scriptUrl.pathname.includes("/_next/static/");
|
|
171
|
+
} catch {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
function isNextProjectRuntime() {
|
|
177
|
+
cachedIsNextProject ??= typeof document !== "undefined" && Boolean(
|
|
178
|
+
document.getElementById("__NEXT_DATA__") || document.querySelector("nextjs-portal") || hasNextAssetScript(false) || Array.from(document.scripts).some((script) => {
|
|
179
|
+
return script.textContent?.includes("self.__next_f.push");
|
|
180
|
+
}) && hasNextAssetScript(true)
|
|
181
|
+
);
|
|
182
|
+
return cachedIsNextProject;
|
|
183
|
+
}
|
|
184
|
+
const BUNDLER_LAYER_PREFIX_REGEX = /^(?:\.\/)?\/?\([a-z][a-z0-9-]*\)\//;
|
|
185
|
+
function normalizeFilePath(fileName) {
|
|
186
|
+
const normalized = normalizeFileName(fileName).replace(
|
|
187
|
+
BUNDLER_LAYER_PREFIX_REGEX,
|
|
188
|
+
""
|
|
189
|
+
);
|
|
190
|
+
return normalized.startsWith("./") ? normalized.slice(2) : normalized;
|
|
191
|
+
}
|
|
192
|
+
function getOwnerName(owner) {
|
|
193
|
+
if (isFiber(owner)) {
|
|
194
|
+
return isCompositeFiber(owner) ? getDisplayName(owner.type) : null;
|
|
195
|
+
}
|
|
196
|
+
return owner.name || null;
|
|
197
|
+
}
|
|
198
|
+
function getNextOwner(owner) {
|
|
199
|
+
return (isFiber(owner) ? owner._debugOwner : owner.owner) ?? null;
|
|
200
|
+
}
|
|
201
|
+
function getComponentChain(fiber) {
|
|
202
|
+
const isNextProject = isNextProjectRuntime();
|
|
203
|
+
const names = [];
|
|
204
|
+
const push = (name) => {
|
|
205
|
+
if (name && isUsefulComponentName(name, isNextProject) && names.at(-1) !== name) {
|
|
206
|
+
names.push(name);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
const seen = /* @__PURE__ */ new Set();
|
|
210
|
+
let owner = fiber._debugOwner ?? null;
|
|
211
|
+
for (let depth = 0; owner && depth < MAX_OWNER_DEPTH && names.length < MAX_COMPONENT_CHAIN_LENGTH; depth++) {
|
|
212
|
+
if (seen.has(owner)) {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
seen.add(owner);
|
|
216
|
+
push(getOwnerName(owner));
|
|
217
|
+
owner = getNextOwner(owner);
|
|
218
|
+
}
|
|
219
|
+
if (names.length > 0) {
|
|
220
|
+
return names;
|
|
221
|
+
}
|
|
222
|
+
let ancestor = fiber.return;
|
|
223
|
+
for (let depth = 0; ancestor && depth < MAX_OWNER_DEPTH && names.length < MAX_COMPONENT_CHAIN_LENGTH; depth++) {
|
|
224
|
+
if (isCompositeFiber(ancestor)) {
|
|
225
|
+
push(getDisplayName(ancestor.type));
|
|
226
|
+
}
|
|
227
|
+
ancestor = ancestor.return;
|
|
228
|
+
}
|
|
229
|
+
return names;
|
|
230
|
+
}
|
|
231
|
+
function getNearestOwnerFiber(fiber) {
|
|
232
|
+
const owner = fiber._debugOwner;
|
|
233
|
+
if (owner && isFiber(owner)) {
|
|
234
|
+
return owner;
|
|
235
|
+
}
|
|
236
|
+
let ancestor = fiber.return;
|
|
237
|
+
while (ancestor && !isCompositeFiber(ancestor)) {
|
|
238
|
+
ancestor = ancestor.return;
|
|
239
|
+
}
|
|
240
|
+
return ancestor;
|
|
241
|
+
}
|
|
242
|
+
export {
|
|
243
|
+
findNearestFiberElement,
|
|
244
|
+
findNearestListItemKey,
|
|
245
|
+
getComponentChain,
|
|
246
|
+
getElementFiber,
|
|
247
|
+
getNearestOwnerFiber,
|
|
248
|
+
isNextProjectRuntime,
|
|
249
|
+
isUsefulComponentName,
|
|
250
|
+
normalizeFilePath
|
|
251
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025 Aiden Bai
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
* https://github.com/aidenybai/react-grab
|
|
5
|
+
*/
|
|
6
|
+
export declare const PREVIEW_TEXT_MAX_LENGTH = 100;
|
|
7
|
+
/**
|
|
8
|
+
* Visible text for a preview: direct text for most tags, descendant text for
|
|
9
|
+
* text-wrapping tags (buttons, links, labels, code).
|
|
10
|
+
*/
|
|
11
|
+
export declare function getPreviewTextContent(element: Element): string;
|
|
12
|
+
/** One-line HTML preview: at most 8 prioritized attributes and 100 characters of text. */
|
|
13
|
+
export declare function getInlineHTMLPreview(element: Element): string;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025 Aiden Bai
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
* https://github.com/aidenybai/react-grab
|
|
5
|
+
*/
|
|
6
|
+
const PREVIEW_TEXT_MAX_LENGTH = 100;
|
|
7
|
+
const PREVIEW_ATTR_VALUE_MAX_LENGTH = 15;
|
|
8
|
+
const PREVIEW_IDENTIFYING_ATTR_VALUE_MAX_LENGTH_CHARS = 120;
|
|
9
|
+
const PREVIEW_ATTRIBUTE_MAX_COUNT = 8;
|
|
10
|
+
const PREVIEW_PRIORITY_ATTRS = [
|
|
11
|
+
"id",
|
|
12
|
+
"class",
|
|
13
|
+
"aria-label",
|
|
14
|
+
"data-testid",
|
|
15
|
+
"role",
|
|
16
|
+
"name",
|
|
17
|
+
"title"
|
|
18
|
+
];
|
|
19
|
+
const PREVIEW_IDENTIFYING_ATTRS = /* @__PURE__ */ new Set([
|
|
20
|
+
"id",
|
|
21
|
+
"data-testid",
|
|
22
|
+
"aria-label",
|
|
23
|
+
"href",
|
|
24
|
+
"src",
|
|
25
|
+
"alt",
|
|
26
|
+
"type",
|
|
27
|
+
"name",
|
|
28
|
+
"placeholder",
|
|
29
|
+
"role",
|
|
30
|
+
"for",
|
|
31
|
+
"action",
|
|
32
|
+
"method",
|
|
33
|
+
"title",
|
|
34
|
+
"disabled",
|
|
35
|
+
"checked",
|
|
36
|
+
"readonly",
|
|
37
|
+
"required",
|
|
38
|
+
"selected",
|
|
39
|
+
"open"
|
|
40
|
+
]);
|
|
41
|
+
const PREVIEW_DESCENDANT_TEXT_TAGS = /* @__PURE__ */ new Set([
|
|
42
|
+
"a",
|
|
43
|
+
"button",
|
|
44
|
+
"code",
|
|
45
|
+
"label",
|
|
46
|
+
"option",
|
|
47
|
+
"pre",
|
|
48
|
+
"summary",
|
|
49
|
+
"text"
|
|
50
|
+
]);
|
|
51
|
+
const PREVIEW_SKIPPED_TEXT_TAGS = /* @__PURE__ */ new Set([
|
|
52
|
+
"script",
|
|
53
|
+
"style",
|
|
54
|
+
"template",
|
|
55
|
+
"noscript"
|
|
56
|
+
]);
|
|
57
|
+
const TRUNCATION_SUFFIX = "...";
|
|
58
|
+
function escapeHtmlText(text) {
|
|
59
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
60
|
+
}
|
|
61
|
+
function escapeHtmlAttribute(value) {
|
|
62
|
+
return escapeHtmlText(value).replace(/"/g, """).replace(/\r/g, " ").replace(/\n/g, " ").replace(/\t/g, "	");
|
|
63
|
+
}
|
|
64
|
+
function truncateEscapedHtml(escapedHtml, maxLength) {
|
|
65
|
+
if (escapedHtml.length <= maxLength) {
|
|
66
|
+
return escapedHtml;
|
|
67
|
+
}
|
|
68
|
+
const truncated = escapedHtml.slice(
|
|
69
|
+
0,
|
|
70
|
+
Math.max(0, maxLength - TRUNCATION_SUFFIX.length)
|
|
71
|
+
);
|
|
72
|
+
const lastEntityStart = truncated.lastIndexOf("&");
|
|
73
|
+
const complete = lastEntityStart > truncated.lastIndexOf(";") ? truncated.slice(0, lastEntityStart) : truncated;
|
|
74
|
+
return `${complete}${TRUNCATION_SUFFIX}`.slice(0, maxLength);
|
|
75
|
+
}
|
|
76
|
+
function collapseText(text) {
|
|
77
|
+
return text.replace(/\s+/g, " ").trim();
|
|
78
|
+
}
|
|
79
|
+
function shouldSkipElementText(element) {
|
|
80
|
+
return element.getAttribute("aria-hidden") === "true" || element.hasAttribute("hidden") || PREVIEW_SKIPPED_TEXT_TAGS.has(element.tagName.toLowerCase());
|
|
81
|
+
}
|
|
82
|
+
function getDirectTextContent(element) {
|
|
83
|
+
const parts = [];
|
|
84
|
+
for (const node of Array.from(element.childNodes)) {
|
|
85
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
86
|
+
const text = collapseText(node.textContent ?? "");
|
|
87
|
+
if (text) {
|
|
88
|
+
parts.push(text);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return parts.join(" ");
|
|
93
|
+
}
|
|
94
|
+
function collectDescendantText(node, parts, budget) {
|
|
95
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
96
|
+
const text = collapseText(node.textContent ?? "");
|
|
97
|
+
if (!text) {
|
|
98
|
+
return budget;
|
|
99
|
+
}
|
|
100
|
+
parts.push(text);
|
|
101
|
+
return budget - text.length;
|
|
102
|
+
}
|
|
103
|
+
if (!(node instanceof Element) || shouldSkipElementText(node)) {
|
|
104
|
+
return budget;
|
|
105
|
+
}
|
|
106
|
+
let remaining = budget;
|
|
107
|
+
for (const child of Array.from(node.childNodes)) {
|
|
108
|
+
remaining = collectDescendantText(child, parts, remaining);
|
|
109
|
+
if (remaining <= 0) {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return remaining;
|
|
114
|
+
}
|
|
115
|
+
function getPreviewTextContent(element) {
|
|
116
|
+
if (shouldSkipElementText(element)) {
|
|
117
|
+
return "";
|
|
118
|
+
}
|
|
119
|
+
const tagName = element.tagName.toLowerCase();
|
|
120
|
+
const directText = getDirectTextContent(element);
|
|
121
|
+
if (!PREVIEW_DESCENDANT_TEXT_TAGS.has(tagName)) {
|
|
122
|
+
return directText;
|
|
123
|
+
}
|
|
124
|
+
if (directText && element.children.length === 0) {
|
|
125
|
+
return directText;
|
|
126
|
+
}
|
|
127
|
+
const parts = [];
|
|
128
|
+
collectDescendantText(element, parts, PREVIEW_TEXT_MAX_LENGTH);
|
|
129
|
+
return parts.join(" ");
|
|
130
|
+
}
|
|
131
|
+
function formatAttribute(name, value, maxLength) {
|
|
132
|
+
return `${name}="${truncateEscapedHtml(escapeHtmlAttribute(value), maxLength)}"`;
|
|
133
|
+
}
|
|
134
|
+
function formatAttrsForPreview(element) {
|
|
135
|
+
const priorityParts = [];
|
|
136
|
+
for (const name of PREVIEW_PRIORITY_ATTRS) {
|
|
137
|
+
const value = element.getAttribute(name);
|
|
138
|
+
if (value) {
|
|
139
|
+
priorityParts.push(
|
|
140
|
+
` ${formatAttribute(
|
|
141
|
+
name,
|
|
142
|
+
value,
|
|
143
|
+
name === "class" ? PREVIEW_ATTR_VALUE_MAX_LENGTH : PREVIEW_IDENTIFYING_ATTR_VALUE_MAX_LENGTH_CHARS
|
|
144
|
+
)}`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const identifyingParts = [];
|
|
149
|
+
const remainingParts = [];
|
|
150
|
+
for (const { name, value } of Array.from(element.attributes)) {
|
|
151
|
+
if (PREVIEW_PRIORITY_ATTRS.includes(name) || name === "style" || name.startsWith("data-replo-comments")) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (PREVIEW_IDENTIFYING_ATTRS.has(name)) {
|
|
155
|
+
identifyingParts.push(
|
|
156
|
+
value ? ` ${formatAttribute(name, value, PREVIEW_IDENTIFYING_ATTR_VALUE_MAX_LENGTH_CHARS)}` : ` ${name}`
|
|
157
|
+
);
|
|
158
|
+
} else if (value) {
|
|
159
|
+
remainingParts.push(
|
|
160
|
+
` ${formatAttribute(name, value, PREVIEW_ATTR_VALUE_MAX_LENGTH)}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return [...priorityParts, ...identifyingParts, ...remainingParts].slice(0, PREVIEW_ATTRIBUTE_MAX_COUNT).join("");
|
|
165
|
+
}
|
|
166
|
+
function getInlineHTMLPreview(element) {
|
|
167
|
+
const tagName = element.tagName.toLowerCase();
|
|
168
|
+
const text = truncateEscapedHtml(
|
|
169
|
+
escapeHtmlText(getPreviewTextContent(element)),
|
|
170
|
+
PREVIEW_TEXT_MAX_LENGTH
|
|
171
|
+
);
|
|
172
|
+
const attrs = formatAttrsForPreview(element);
|
|
173
|
+
return text ? `<${tagName}${attrs}>${text}</${tagName}>` : `<${tagName}${attrs} />`;
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
PREVIEW_TEXT_MAX_LENGTH,
|
|
177
|
+
getInlineHTMLPreview,
|
|
178
|
+
getPreviewTextContent
|
|
179
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025 Aiden Bai
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
* https://github.com/aidenybai/react-grab
|
|
5
|
+
*/
|
|
6
|
+
export declare const FINDER_TIMEOUT_MS = 200;
|
|
7
|
+
/** Rejects ids that frameworks generate per render (useId, Radix, MUI, …). */
|
|
8
|
+
export declare function isStableElementId(elementId: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* The fast semantic pass: a stable `#id`, then the preferred attributes
|
|
11
|
+
* (`data-testid`, `aria-label`, `href`, interactive `role`, …), each verified
|
|
12
|
+
* unique in the document. Null when nothing semantic identifies the element.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSemanticSelector(element: Element): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Climbs from `element` to the nearest identifiable ancestor (a stable id,
|
|
17
|
+
* a preferred attribute, an interactive role or a form control) that
|
|
18
|
+
* `isCandidateAccepted` takes, stopping before overly broad containers.
|
|
19
|
+
*/
|
|
20
|
+
export declare function findSelectorTarget(element: Element, isCandidateAccepted?: (candidate: Element) => boolean): Element;
|
|
21
|
+
/** Climbs to `ancestor`, or to the top of the element's root when it is null. */
|
|
22
|
+
export declare function buildRelativeNthOfTypePath(ancestor: Element | null, element: Element): string;
|
|
23
|
+
/**
|
|
24
|
+
* React Grab's nearest-semantic pass: the element's own semantic selector, or
|
|
25
|
+
* the nearest identifiable ancestor's followed by the structural path down to
|
|
26
|
+
* the element. Unlike React Grab, the result always selects the element itself
|
|
27
|
+
* (verified unique), so it can serve as an anchor signal.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createNearestSemanticSelector(element: Element): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Finder-style search: the cheapest unique combination of id / word-like
|
|
32
|
+
* class / accepted attribute / tag / nth-of-type / nth-child segments over the
|
|
33
|
+
* element's ancestors, within a time budget. Null when nothing unique turns up
|
|
34
|
+
* in time.
|
|
35
|
+
*/
|
|
36
|
+
export declare function findUniqueSelector(target: Element, timeoutMs?: number): string | null;
|
|
37
|
+
/** Last resort: an nth-child chain from the element to an id or the body. */
|
|
38
|
+
export declare function createNthChildSelector(element: Element): string;
|