@replohq/sandbox-runtime 1.20.0 → 1.21.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 +898 -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-NVOBD46N.mjs +541 -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/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,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COMMENTS_OVERLAY_RPC_CHANNEL_ID,
|
|
3
|
+
COMMENTS_OVERLAY_RPC_CHANNEL_VERSION,
|
|
4
|
+
commentsOverlayToHostMethodConfig,
|
|
5
|
+
hostToCommentsOverlayMethodConfig
|
|
6
|
+
} from "../_vendor/schemas/commentsOverlayRpc.mjs";
|
|
7
|
+
import {
|
|
8
|
+
createIframeRpcChannel,
|
|
9
|
+
createIframeRpcRemote
|
|
10
|
+
} from "../_vendor/schemas/iframeRpcChannel.mjs";
|
|
11
|
+
import { symbolicateAnchor } from "./capture";
|
|
12
|
+
import { isAllowedCommentsOverlayOrigin } from "./originGate";
|
|
13
|
+
import { createCommentsOverlay } from "./overlay";
|
|
14
|
+
import { createSymbolicatedSourceLookup } from "./sourceLookup";
|
|
15
|
+
const LOCATION_POLL_MS = 500;
|
|
16
|
+
let stopActiveOverlay = null;
|
|
17
|
+
function startCommentsOverlay({
|
|
18
|
+
symbolicate
|
|
19
|
+
}) {
|
|
20
|
+
if (stopActiveOverlay) {
|
|
21
|
+
return stopActiveOverlay;
|
|
22
|
+
}
|
|
23
|
+
if (typeof window === "undefined" || window.self === window.top) {
|
|
24
|
+
return () => {
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
let hostOrigin = null;
|
|
28
|
+
let isAnnouncing = false;
|
|
29
|
+
let hasAnnouncedToVerifiedHost = false;
|
|
30
|
+
let overlay = null;
|
|
31
|
+
const channel = createIframeRpcChannel({
|
|
32
|
+
subscriberWindow: window,
|
|
33
|
+
channelIdentifier: COMMENTS_OVERLAY_RPC_CHANNEL_ID,
|
|
34
|
+
version: COMMENTS_OVERLAY_RPC_CHANNEL_VERSION,
|
|
35
|
+
getTargetWindow: () => {
|
|
36
|
+
if (!hostOrigin && !isAnnouncing) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
postMessage: (message) => {
|
|
41
|
+
window.parent.postMessage(message, hostOrigin ?? "*");
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
targetOrigin: "*",
|
|
46
|
+
isExpectedMessage: (event) => {
|
|
47
|
+
if (event.source !== window.parent || !isAllowedCommentsOverlayOrigin(event.origin)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
hostOrigin = event.origin;
|
|
51
|
+
return true;
|
|
52
|
+
},
|
|
53
|
+
outgoingMethods: commentsOverlayToHostMethodConfig,
|
|
54
|
+
incomingMethods: hostToCommentsOverlayMethodConfig,
|
|
55
|
+
handlers: {
|
|
56
|
+
setCommentMode: ({ mode }) => {
|
|
57
|
+
announceToVerifiedHost();
|
|
58
|
+
overlay?.setMode(mode);
|
|
59
|
+
},
|
|
60
|
+
setPins: ({ pins }) => {
|
|
61
|
+
announceToVerifiedHost();
|
|
62
|
+
overlay?.setPins(pins);
|
|
63
|
+
},
|
|
64
|
+
focusThread: ({ threadId }) => {
|
|
65
|
+
overlay?.focusThread(threadId);
|
|
66
|
+
},
|
|
67
|
+
clearDraft: () => {
|
|
68
|
+
overlay?.clearDraft();
|
|
69
|
+
},
|
|
70
|
+
setDraftAnchor: ({ anchor }) => {
|
|
71
|
+
overlay?.setDraftAnchor(anchor);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
const host = createIframeRpcRemote(channel);
|
|
76
|
+
function announceToVerifiedHost() {
|
|
77
|
+
if (!hasAnnouncedToVerifiedHost && hostOrigin) {
|
|
78
|
+
hasAnnouncedToVerifiedHost = true;
|
|
79
|
+
host.overlayReady();
|
|
80
|
+
reportLocation({ force: true });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let reportedLocation = null;
|
|
84
|
+
function reportLocation({ force }) {
|
|
85
|
+
if (!hostOrigin) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const url = `${window.location.pathname}${window.location.search}`.slice(
|
|
89
|
+
0,
|
|
90
|
+
2048
|
|
91
|
+
);
|
|
92
|
+
if (!force && url === reportedLocation) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
reportedLocation = url;
|
|
96
|
+
host.locationChanged({ url });
|
|
97
|
+
}
|
|
98
|
+
const handlePopState = () => reportLocation({ force: false });
|
|
99
|
+
window.addEventListener("popstate", handlePopState);
|
|
100
|
+
const locationTimer = window.setInterval(
|
|
101
|
+
() => reportLocation({ force: false }),
|
|
102
|
+
LOCATION_POLL_MS
|
|
103
|
+
);
|
|
104
|
+
overlay = createCommentsOverlay({
|
|
105
|
+
prepareAnchor: (anchor) => symbolicateAnchor(anchor, symbolicate),
|
|
106
|
+
getSource: createSymbolicatedSourceLookup({
|
|
107
|
+
symbolicate,
|
|
108
|
+
onUpdate: () => overlay?.refresh()
|
|
109
|
+
}),
|
|
110
|
+
onAnchorPicked: (input) => host.anchorPicked(input),
|
|
111
|
+
onPinClicked: (input) => host.pinClicked(input),
|
|
112
|
+
onAnchorStatuses: (input) => host.anchorStatuses(input),
|
|
113
|
+
onComposeFromSelection: (input) => host.requestComposeFromSelection(input),
|
|
114
|
+
onPickCancelled: () => host.pickCancelled(),
|
|
115
|
+
onModeShortcut: (input) => host.modeShortcut(input)
|
|
116
|
+
});
|
|
117
|
+
const unsubscribe = channel.subscribe();
|
|
118
|
+
isAnnouncing = true;
|
|
119
|
+
try {
|
|
120
|
+
host.overlayReady();
|
|
121
|
+
} finally {
|
|
122
|
+
isAnnouncing = false;
|
|
123
|
+
}
|
|
124
|
+
stopActiveOverlay = () => {
|
|
125
|
+
window.removeEventListener("popstate", handlePopState);
|
|
126
|
+
window.clearInterval(locationTimer);
|
|
127
|
+
unsubscribe();
|
|
128
|
+
overlay?.destroy();
|
|
129
|
+
overlay = null;
|
|
130
|
+
stopActiveOverlay = null;
|
|
131
|
+
};
|
|
132
|
+
return stopActiveOverlay;
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
startCommentsOverlay
|
|
136
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { CommentAnchorElement } from "../_vendor/schemas/generated/comments";
|
|
2
|
+
export type SourceLocation = {
|
|
3
|
+
filePath: string;
|
|
4
|
+
line?: number;
|
|
5
|
+
col?: number;
|
|
6
|
+
};
|
|
7
|
+
/** Maps compiled locations to original files; returns them unchanged when it can't. */
|
|
8
|
+
export type SourceSymbolicator = (locations: SourceLocation[]) => Promise<SourceLocation[]>;
|
|
9
|
+
export type ElementSource = SourceLocation & {
|
|
10
|
+
componentChain: string[];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Joins an anchor's per-root selector segments for an element inside open
|
|
14
|
+
* shadow roots: the outermost host's selector in the document, then each
|
|
15
|
+
* nested host's (or the element's) selector within the previous shadow root.
|
|
16
|
+
* `>>>` is not valid CSS, so a light-DOM selector never contains it.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SHADOW_SELECTOR_DELIMITER = " >>> ";
|
|
19
|
+
/**
|
|
20
|
+
* The structural `tag:nth-of-type` path from the element up to the nearest
|
|
21
|
+
* ancestor with an id (or the root). Select mode uses it as its selector.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildNthOfTypePath(element: Element): string;
|
|
24
|
+
/**
|
|
25
|
+
* Compiled source of the JSX that rendered `element` (its own `_debugStack`,
|
|
26
|
+
* else its owner component's), plus the owner component names. Null outside
|
|
27
|
+
* React dev builds.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getElementSource(element: Element): ElementSource | null;
|
|
30
|
+
/**
|
|
31
|
+
* Visible text used for similarity tie-breaks; the HTML preview when there is
|
|
32
|
+
* none. Inside a shadow root it includes nested shadow roots' text.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getTextPreview(element: Element): string;
|
|
35
|
+
/** The element an anchor for this click target or selection describes. */
|
|
36
|
+
export declare function getAnchorElement(target: Element | Range): Element | null;
|
|
37
|
+
/**
|
|
38
|
+
* Builds an element anchor (D-13) for a clicked element or a text selection.
|
|
39
|
+
* The selection's quote keeps 80 characters of context on each side within
|
|
40
|
+
* the anchored element; `offset` is `point` as a fraction of its rect.
|
|
41
|
+
*/
|
|
42
|
+
export declare function captureAnchor(target: Element | Range, point: {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
}): CommentAnchorElement;
|
|
46
|
+
/** Anchors exactly `element`; select mode has already chosen it. */
|
|
47
|
+
export declare function captureElementAnchor(element: Element, point: {
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
}): CommentAnchorElement;
|
|
51
|
+
/**
|
|
52
|
+
* Swaps the anchor's compiled source location for the original file and line
|
|
53
|
+
* through `symbolicate` (Next's dev endpoint in the sandbox runtime).
|
|
54
|
+
*/
|
|
55
|
+
export declare function symbolicateAnchor(anchor: CommentAnchorElement, symbolicate: SourceSymbolicator): Promise<CommentAnchorElement>;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { captureQuote } from "./textQuote";
|
|
2
|
+
import { getFiberFromHostInstance, getFiberSource } from "./vendor/bippy";
|
|
3
|
+
import { trackElementAnchor } from "./vendor/elementAnchors";
|
|
4
|
+
import {
|
|
5
|
+
findNearestFiberElement,
|
|
6
|
+
findNearestListItemKey,
|
|
7
|
+
getComponentChain,
|
|
8
|
+
getElementFiber,
|
|
9
|
+
getNearestOwnerFiber,
|
|
10
|
+
normalizeFilePath
|
|
11
|
+
} from "./vendor/fiberElement";
|
|
12
|
+
import { getInlineHTMLPreview } from "./vendor/htmlPreview";
|
|
13
|
+
import {
|
|
14
|
+
buildRelativeNthOfTypePath,
|
|
15
|
+
createNthChildSelector,
|
|
16
|
+
createNearestSemanticSelector,
|
|
17
|
+
createSemanticSelector,
|
|
18
|
+
findUniqueSelector
|
|
19
|
+
} from "./vendor/selector";
|
|
20
|
+
const TEXT_PREVIEW_MAX_CHARS = 200;
|
|
21
|
+
const SHADOW_SELECTOR_DELIMITER = " >>> ";
|
|
22
|
+
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
23
|
+
class AnchorTargetError extends Error {
|
|
24
|
+
constructor() {
|
|
25
|
+
super("captureAnchor: the selection is not inside an element");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isShadowRoot(node) {
|
|
29
|
+
return typeof ShadowRoot !== "undefined" && node instanceof ShadowRoot;
|
|
30
|
+
}
|
|
31
|
+
function getShadowPath(element) {
|
|
32
|
+
const path = [element];
|
|
33
|
+
for (let root = element.getRootNode(); isShadowRoot(root); root = root.host.getRootNode()) {
|
|
34
|
+
path.unshift(root.host);
|
|
35
|
+
}
|
|
36
|
+
return path;
|
|
37
|
+
}
|
|
38
|
+
function isElement(target) {
|
|
39
|
+
return "tagName" in target;
|
|
40
|
+
}
|
|
41
|
+
function buildNthOfTypePath(element) {
|
|
42
|
+
return getShadowPath(element).map(buildRootNthOfTypePath).join(SHADOW_SELECTOR_DELIMITER);
|
|
43
|
+
}
|
|
44
|
+
function buildRootNthOfTypePath(element) {
|
|
45
|
+
const root = isShadowRoot(element.getRootNode()) ? null : element.ownerDocument.documentElement;
|
|
46
|
+
let idAncestor = element;
|
|
47
|
+
while (idAncestor && idAncestor !== root && !idAncestor.id) {
|
|
48
|
+
idAncestor = idAncestor.parentElement;
|
|
49
|
+
}
|
|
50
|
+
const path = buildRelativeNthOfTypePath(idAncestor ?? root, element);
|
|
51
|
+
if (!idAncestor?.id || idAncestor === root) {
|
|
52
|
+
return path;
|
|
53
|
+
}
|
|
54
|
+
const id = `#${CSS.escape(idAncestor.id)}`;
|
|
55
|
+
return path ? `${id} > ${path}` : id;
|
|
56
|
+
}
|
|
57
|
+
function findFiberElementInRoot(element) {
|
|
58
|
+
for (let current = element; current; current = current.parentElement) {
|
|
59
|
+
if (getFiberFromHostInstance(current)) {
|
|
60
|
+
return current;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function climbOutOfSvg(element) {
|
|
66
|
+
let current = element;
|
|
67
|
+
while (current.namespaceURI === SVG_NAMESPACE) {
|
|
68
|
+
const parentNode = current.parentNode;
|
|
69
|
+
const parent = current.parentElement ?? (parentNode && isShadowRoot(parentNode) ? parentNode.host : null);
|
|
70
|
+
if (!parent) {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
current = parent;
|
|
74
|
+
}
|
|
75
|
+
return current;
|
|
76
|
+
}
|
|
77
|
+
function snapToAnchorElement(element) {
|
|
78
|
+
let current = element;
|
|
79
|
+
for (let root = current.getRootNode(); isShadowRoot(root); root = current.getRootNode()) {
|
|
80
|
+
current = climbOutOfSvg(current);
|
|
81
|
+
if (current.getRootNode() !== root) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const fiberElement = findFiberElementInRoot(current);
|
|
85
|
+
if (fiberElement) {
|
|
86
|
+
return fiberElement;
|
|
87
|
+
}
|
|
88
|
+
current = root.host;
|
|
89
|
+
}
|
|
90
|
+
return findNearestFiberElement(current);
|
|
91
|
+
}
|
|
92
|
+
function getElementSource(element) {
|
|
93
|
+
const fiber = getElementFiber(element);
|
|
94
|
+
if (!fiber) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const owner = getNearestOwnerFiber(fiber);
|
|
98
|
+
const source = getFiberSource(fiber) ?? (owner ? getFiberSource(owner) : null);
|
|
99
|
+
if (!source?.fileName) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
filePath: source.fileName,
|
|
104
|
+
line: source.lineNumber,
|
|
105
|
+
col: source.columnNumber,
|
|
106
|
+
componentChain: getComponentChain(fiber)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function collapseWhitespace(text) {
|
|
110
|
+
return text.replace(/\s+/g, " ").trim();
|
|
111
|
+
}
|
|
112
|
+
function getComposedText(node, maxChars) {
|
|
113
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
114
|
+
return (node.textContent ?? "").slice(0, maxChars);
|
|
115
|
+
}
|
|
116
|
+
let text = "";
|
|
117
|
+
const shadowRoot = node instanceof Element ? node.shadowRoot : null;
|
|
118
|
+
for (const child of [
|
|
119
|
+
...shadowRoot ? Array.from(shadowRoot.childNodes) : [],
|
|
120
|
+
...Array.from(node.childNodes)
|
|
121
|
+
]) {
|
|
122
|
+
if (text.length >= maxChars) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
if (child instanceof Element && child.matches("style, script")) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
text += getComposedText(child, maxChars - text.length);
|
|
129
|
+
}
|
|
130
|
+
return text;
|
|
131
|
+
}
|
|
132
|
+
function getTextPreview(element) {
|
|
133
|
+
const maxChars = TEXT_PREVIEW_MAX_CHARS * 10;
|
|
134
|
+
const text = collapseWhitespace(
|
|
135
|
+
isShadowRoot(element.getRootNode()) ? getComposedText(element, maxChars) : (element.textContent ?? "").slice(0, maxChars)
|
|
136
|
+
);
|
|
137
|
+
return (text || getInlineHTMLPreview(element)).slice(
|
|
138
|
+
0,
|
|
139
|
+
TEXT_PREVIEW_MAX_CHARS
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function clampUnit(value) {
|
|
143
|
+
return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 0.5;
|
|
144
|
+
}
|
|
145
|
+
function rangeContainer(range) {
|
|
146
|
+
const node = range.commonAncestorContainer;
|
|
147
|
+
return node instanceof Element ? node : node.parentElement;
|
|
148
|
+
}
|
|
149
|
+
function createAnchorSelectors(element) {
|
|
150
|
+
const path = getShadowPath(element);
|
|
151
|
+
if (path.length === 1) {
|
|
152
|
+
return createRootAnchorSelectors(element);
|
|
153
|
+
}
|
|
154
|
+
const segments = path.map(createRootAnchorSelectors);
|
|
155
|
+
const target = segments.at(-1);
|
|
156
|
+
const semanticSegments = segments.map((segment) => {
|
|
157
|
+
return segment === target ? segment.semanticSelector : segment.semanticSelector ?? segment.selector;
|
|
158
|
+
});
|
|
159
|
+
return {
|
|
160
|
+
semanticSelector: semanticSegments.every(Boolean) ? semanticSegments.join(SHADOW_SELECTOR_DELIMITER) : null,
|
|
161
|
+
selector: segments.map((segment) => segment.selector).join(SHADOW_SELECTOR_DELIMITER)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function createRootAnchorSelectors(element) {
|
|
165
|
+
const ownSemanticSelector = createSemanticSelector(element);
|
|
166
|
+
return {
|
|
167
|
+
semanticSelector: ownSemanticSelector ?? createNearestSemanticSelector(element),
|
|
168
|
+
selector: ownSemanticSelector ?? findUniqueSelector(element) ?? createNthChildSelector(element)
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function getAnchorElement(target) {
|
|
172
|
+
const picked = isElement(target) ? target : rangeContainer(target);
|
|
173
|
+
return picked ? snapToAnchorElement(picked) : null;
|
|
174
|
+
}
|
|
175
|
+
function captureAnchor(target, point) {
|
|
176
|
+
const element = getAnchorElement(target);
|
|
177
|
+
if (!element) {
|
|
178
|
+
throw new AnchorTargetError();
|
|
179
|
+
}
|
|
180
|
+
return buildAnchor({ target, element, point });
|
|
181
|
+
}
|
|
182
|
+
function captureElementAnchor(element, point) {
|
|
183
|
+
return buildAnchor({ target: element, element, point });
|
|
184
|
+
}
|
|
185
|
+
function buildAnchor({
|
|
186
|
+
target,
|
|
187
|
+
element,
|
|
188
|
+
point
|
|
189
|
+
}) {
|
|
190
|
+
trackElementAnchor(element);
|
|
191
|
+
const { semanticSelector, selector } = createAnchorSelectors(element);
|
|
192
|
+
const quote = isElement(target) ? null : captureQuote(target, element);
|
|
193
|
+
const source = getElementSource(element);
|
|
194
|
+
const fiber = getElementFiber(element);
|
|
195
|
+
const listKey = fiber ? findNearestListItemKey(fiber) : null;
|
|
196
|
+
const rect = element.getBoundingClientRect();
|
|
197
|
+
return {
|
|
198
|
+
type: "element",
|
|
199
|
+
...semanticSelector ? { semanticSelector } : {},
|
|
200
|
+
selector,
|
|
201
|
+
nthOfTypePath: buildNthOfTypePath(element),
|
|
202
|
+
...source ? {
|
|
203
|
+
source: {
|
|
204
|
+
filePath: source.filePath,
|
|
205
|
+
componentChain: source.componentChain,
|
|
206
|
+
...source.line === void 0 ? {} : { line: source.line },
|
|
207
|
+
...source.col === void 0 ? {} : { col: source.col }
|
|
208
|
+
}
|
|
209
|
+
} : {},
|
|
210
|
+
...listKey ? { listKey } : {},
|
|
211
|
+
tagName: element.tagName.toLowerCase(),
|
|
212
|
+
textPreview: getTextPreview(element),
|
|
213
|
+
...quote ? { quote } : {},
|
|
214
|
+
offset: {
|
|
215
|
+
x: clampUnit((point.x - rect.left) / rect.width),
|
|
216
|
+
y: clampUnit((point.y - rect.top) / rect.height)
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async function symbolicateAnchor(anchor, symbolicate) {
|
|
221
|
+
const source = anchor.source;
|
|
222
|
+
if (!source) {
|
|
223
|
+
return anchor;
|
|
224
|
+
}
|
|
225
|
+
const [resolved] = await symbolicate([
|
|
226
|
+
{ filePath: source.filePath, line: source.line, col: source.col }
|
|
227
|
+
]);
|
|
228
|
+
if (!resolved) {
|
|
229
|
+
return anchor;
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
...anchor,
|
|
233
|
+
source: {
|
|
234
|
+
filePath: normalizeFilePath(resolved.filePath),
|
|
235
|
+
componentChain: source.componentChain,
|
|
236
|
+
...resolved.line === void 0 ? {} : { line: resolved.line },
|
|
237
|
+
...resolved.col === void 0 ? {} : { col: resolved.col }
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
export {
|
|
242
|
+
SHADOW_SELECTOR_DELIMITER,
|
|
243
|
+
buildNthOfTypePath,
|
|
244
|
+
captureAnchor,
|
|
245
|
+
captureElementAnchor,
|
|
246
|
+
getAnchorElement,
|
|
247
|
+
getElementSource,
|
|
248
|
+
getTextPreview,
|
|
249
|
+
symbolicateAnchor
|
|
250
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isAllowedCommentsOverlayOrigin(origin: string): boolean;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isAllowedEditorOrigin } from "../annotations/bridgeGate";
|
|
2
|
+
const ARTIFACT_CONTENT_ORIGIN_PATTERNS = [
|
|
3
|
+
/^https:\/\/[a-z0-9-]+\.artifacts(?:-staging)?\.replousercontent\.com$/u,
|
|
4
|
+
/^http:\/\/[a-z0-9-]+\.artifacts\.localhost(?::\d+)?$/u
|
|
5
|
+
];
|
|
6
|
+
function isAllowedCommentsOverlayOrigin(origin) {
|
|
7
|
+
return isAllowedEditorOrigin(origin) || ARTIFACT_CONTENT_ORIGIN_PATTERNS.some((pattern) => pattern.test(origin));
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
isAllowedCommentsOverlayOrigin
|
|
11
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { CommentAnchor, CommentAnchorElement } from "../_vendor/schemas/generated/comments";
|
|
2
|
+
import type { CommentOverlayAnchorStatus, CommentOverlayPin, CommentOverlayRect } from "../_vendor/schemas/generated/commentsOverlayRpc";
|
|
3
|
+
import type { DisplayMode } from "../_vendor/schemas/generated/selectMode";
|
|
4
|
+
import type { ElementSource } from "./capture";
|
|
5
|
+
export declare const OVERLAY_Z_INDEX = 2147483645;
|
|
6
|
+
export declare const HIGHLIGHT_BACKGROUND = "rgba(250, 204, 21, 0.28)";
|
|
7
|
+
export declare const BADGE_SIZE_PX = 20;
|
|
8
|
+
export declare const RERESOLVE_DEBOUNCE_MS = 250;
|
|
9
|
+
export type CommentsOverlayCallbacks = {
|
|
10
|
+
onAnchorPicked: (input: {
|
|
11
|
+
anchor: CommentAnchorElement;
|
|
12
|
+
rect: CommentOverlayRect;
|
|
13
|
+
}) => void;
|
|
14
|
+
onPinClicked: (input: {
|
|
15
|
+
threadId: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
onAnchorStatuses: (input: {
|
|
18
|
+
statuses: CommentOverlayAnchorStatus[];
|
|
19
|
+
}) => void;
|
|
20
|
+
onComposeFromSelection: (input: {
|
|
21
|
+
anchor: CommentAnchorElement;
|
|
22
|
+
}) => void;
|
|
23
|
+
onPickCancelled: () => void;
|
|
24
|
+
/** C or Esc pressed in the frame; the host owns the mode. */
|
|
25
|
+
onModeShortcut: (input: {
|
|
26
|
+
mode: "browse" | "comment";
|
|
27
|
+
}) => void;
|
|
28
|
+
};
|
|
29
|
+
type CommentsOverlayOptions = CommentsOverlayCallbacks & {
|
|
30
|
+
/** Async finishing step for a captured anchor, e.g. source symbolication. */
|
|
31
|
+
prepareAnchor: ((anchor: CommentAnchorElement) => Promise<CommentAnchorElement>) | null;
|
|
32
|
+
/** Candidate source lookup for the resolver; null uses the live fiber source. */
|
|
33
|
+
getSource: ((element: Element) => ElementSource | null) | null;
|
|
34
|
+
};
|
|
35
|
+
export type CommentsOverlay = {
|
|
36
|
+
setMode: (mode: DisplayMode) => void;
|
|
37
|
+
setPins: (pins: CommentOverlayPin[]) => void;
|
|
38
|
+
focusThread: (threadId: string) => void;
|
|
39
|
+
clearDraft: () => void;
|
|
40
|
+
setDraftAnchor: (anchor: CommentAnchor | null) => void;
|
|
41
|
+
/** Re-resolves every anchor now, e.g. after symbolication results arrive. */
|
|
42
|
+
refresh: () => void;
|
|
43
|
+
destroy: () => void;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The in-page half of commenting (D-28): resolves anchors, draws highlights
|
|
47
|
+
* and comment markers, outlines and picks elements in comment mode, and offers
|
|
48
|
+
* a "Comment" pill on text selections. It knows thread IDs, anchors and counts
|
|
49
|
+
* only; the host draws every piece of comment content.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createCommentsOverlay(options: CommentsOverlayOptions): CommentsOverlay;
|
|
52
|
+
export {};
|