@devaccel-labs/app-comments-toolbar 0.0.0-stage → 1.0.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/README.md +19 -2
- package/dist/chunks/chunk-CSKXLF33.js +153 -0
- package/dist/chunks/chunk-HUM5FQII.js +160 -0
- package/dist/chunks/render-page-76MLIT6M.js +1421 -0
- package/dist/chunks/runtime-JX75TKER.js +9267 -0
- package/dist/chunks/screenshot-66ARTBGR.js +12 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +91 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +87 -0
- package/dist/types/compiler/annotate.d.ts +10 -0
- package/dist/types/compiler/enabled.d.ts +14 -0
- package/dist/types/compiler/index.d.ts +2 -0
- package/dist/types/core/index.d.ts +2 -0
- package/dist/types/core/resolve.d.ts +29 -0
- package/dist/types/core/types.d.ts +65 -0
- package/dist/types/react.d.ts +2 -0
- package/dist/types/runtime/attachments.d.ts +73 -0
- package/dist/types/runtime/capture-ui.d.ts +35 -0
- package/dist/types/runtime/capture.d.ts +30 -0
- package/dist/types/runtime/client.d.ts +220 -0
- package/dist/types/runtime/dashboard.d.ts +28 -0
- package/dist/types/runtime/details.d.ts +43 -0
- package/dist/types/runtime/dock.d.ts +38 -0
- package/dist/types/runtime/edits.d.ts +20 -0
- package/dist/types/runtime/format.d.ts +15 -0
- package/dist/types/runtime/freshness.d.ts +18 -0
- package/dist/types/runtime/handoff.d.ts +15 -0
- package/dist/types/runtime/icons.d.ts +40 -0
- package/dist/types/runtime/idle.d.ts +6 -0
- package/dist/types/runtime/index.d.ts +2 -0
- package/dist/types/runtime/loader.d.ts +14 -0
- package/dist/types/runtime/members.d.ts +11 -0
- package/dist/types/runtime/mentions.d.ts +17 -0
- package/dist/types/runtime/placement.d.ts +43 -0
- package/dist/types/runtime/record.d.ts +33 -0
- package/dist/types/runtime/redact.d.ts +10 -0
- package/dist/types/runtime/related.d.ts +11 -0
- package/dist/types/runtime/render-page.d.ts +1 -0
- package/dist/types/runtime/replay.d.ts +42 -0
- package/dist/types/runtime/runtime-version.d.ts +7 -0
- package/dist/types/runtime/runtime.d.ts +8 -0
- package/dist/types/runtime/screenshot.d.ts +12 -0
- package/dist/types/runtime/session.d.ts +25 -0
- package/dist/types/runtime/styles.d.ts +5 -0
- package/dist/types/runtime/sync.d.ts +25 -0
- package/dist/types/runtime/toolbar.d.ts +22 -0
- package/dist/types/server/index.d.ts +14 -0
- package/dist/types/server.d.ts +2 -0
- package/dist/types/vite/plugin.d.ts +20 -0
- package/dist/types/vite.d.ts +1 -0
- package/dist/vite.d.ts +1 -0
- package/dist/vite.js +173 -0
- package/package.json +52 -4
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types/react.js";
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
captureHandoff,
|
|
3
|
+
runtimeVersion,
|
|
4
|
+
sessionFor,
|
|
5
|
+
whenIdle
|
|
6
|
+
} from "./chunks/chunk-CSKXLF33.js";
|
|
7
|
+
|
|
8
|
+
// src/runtime/loader.tsx
|
|
9
|
+
import { useEffect, useRef } from "react";
|
|
10
|
+
var IDLE_TIMEOUT_MS = 3e3;
|
|
11
|
+
captureHandoff();
|
|
12
|
+
var bundled = () => import("./chunks/runtime-JX75TKER.js");
|
|
13
|
+
async function loadRuntime(apiUrl, source) {
|
|
14
|
+
if (source === "bundled") return bundled();
|
|
15
|
+
const url = `${apiUrl.replace(/\/+$/, "")}/v1/toolbar/${runtimeVersion}.js`;
|
|
16
|
+
try {
|
|
17
|
+
const remote = await import(
|
|
18
|
+
/* @vite-ignore */
|
|
19
|
+
/* webpackIgnore: true */
|
|
20
|
+
url
|
|
21
|
+
);
|
|
22
|
+
if (typeof remote.mount === "function") return remote;
|
|
23
|
+
throw new Error(`${url} has no mount export`);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.warn(
|
|
26
|
+
"[comment-service] Could not load the latest toolbar, using the copy bundled with the package.",
|
|
27
|
+
error
|
|
28
|
+
);
|
|
29
|
+
return bundled();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function CommentToolbar({
|
|
33
|
+
source = "latest",
|
|
34
|
+
sessionPath = "/api/comment-service/session",
|
|
35
|
+
pollMs,
|
|
36
|
+
position,
|
|
37
|
+
theme,
|
|
38
|
+
navigate
|
|
39
|
+
}) {
|
|
40
|
+
const handle = useRef(null);
|
|
41
|
+
const navigateRef = useRef(navigate);
|
|
42
|
+
navigateRef.current = navigate;
|
|
43
|
+
const hasNavigate = Boolean(navigate);
|
|
44
|
+
const props = useRef({});
|
|
45
|
+
props.current = {
|
|
46
|
+
sessionPath,
|
|
47
|
+
pollMs,
|
|
48
|
+
position,
|
|
49
|
+
theme,
|
|
50
|
+
navigate: hasNavigate ? (href) => navigateRef.current?.(href) : void 0,
|
|
51
|
+
getSession: sessionFor(sessionPath)
|
|
52
|
+
};
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
let cancelled = false;
|
|
55
|
+
let mounted = null;
|
|
56
|
+
let container = null;
|
|
57
|
+
const start = async () => {
|
|
58
|
+
const session = await sessionFor(sessionPath)().catch(() => null);
|
|
59
|
+
if (!session || cancelled) return;
|
|
60
|
+
const runtime = await loadRuntime(session.apiUrl, source);
|
|
61
|
+
if (cancelled) return;
|
|
62
|
+
container = document.createElement("div");
|
|
63
|
+
container.setAttribute("data-cs-runtime", source);
|
|
64
|
+
container.style.display = "contents";
|
|
65
|
+
document.body.append(container);
|
|
66
|
+
mounted = runtime.mount(container, props.current);
|
|
67
|
+
handle.current = mounted;
|
|
68
|
+
};
|
|
69
|
+
const cancelIdle = whenIdle(() => {
|
|
70
|
+
start().catch(
|
|
71
|
+
(error) => console.warn("[comment-service] The toolbar could not start.", error)
|
|
72
|
+
);
|
|
73
|
+
}, IDLE_TIMEOUT_MS);
|
|
74
|
+
return () => {
|
|
75
|
+
cancelled = true;
|
|
76
|
+
cancelIdle();
|
|
77
|
+
handle.current = null;
|
|
78
|
+
queueMicrotask(() => {
|
|
79
|
+
mounted?.unmount();
|
|
80
|
+
container?.remove();
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
}, [sessionPath, source]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
handle.current?.update(props.current);
|
|
86
|
+
}, [pollMs, position, theme, hasNavigate]);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
CommentToolbar
|
|
91
|
+
};
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types/server.js";
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/server/index.ts
|
|
2
|
+
function readCommentServiceConfig(env = process.env) {
|
|
3
|
+
const url = env.COMMENT_SERVICE_URL?.replace(/\/$/, "");
|
|
4
|
+
const project = env.COMMENT_SERVICE_PROJECT;
|
|
5
|
+
const environment = env.COMMENT_SERVICE_ENVIRONMENT;
|
|
6
|
+
const secret = env.COMMENT_SERVICE_SECRET;
|
|
7
|
+
if (!url || !project || !environment || !secret) return null;
|
|
8
|
+
const linked = (env.COMMENT_SERVICE_LINKED ?? "").split(/[\s,]+/).filter(Boolean);
|
|
9
|
+
return { url, project, environment, secret, linked };
|
|
10
|
+
}
|
|
11
|
+
function declaredOrigin(request) {
|
|
12
|
+
const value = request.headers.get("origin") ?? request.headers.get("x-comment-service-origin");
|
|
13
|
+
if (!value) return null;
|
|
14
|
+
try {
|
|
15
|
+
const origin = new URL(value).origin;
|
|
16
|
+
return origin === "null" ? null : origin;
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function requestOrigin(request) {
|
|
22
|
+
const declared = declaredOrigin(request);
|
|
23
|
+
if (declared) return declared;
|
|
24
|
+
const url = new URL(request.url);
|
|
25
|
+
const host = request.headers.get("x-forwarded-host") ?? request.headers.get("host");
|
|
26
|
+
if (!host || host.includes("/")) return url.origin;
|
|
27
|
+
const proto = (request.headers.get("x-forwarded-proto") ?? url.protocol.replace(":", "")).split(",")[0].trim();
|
|
28
|
+
return `${proto}://${host}`;
|
|
29
|
+
}
|
|
30
|
+
async function handleSessionRequest(request, config = readCommentServiceConfig()) {
|
|
31
|
+
const headers = { "cache-control": "no-store" };
|
|
32
|
+
if (!config) return Response.json({ enabled: false }, { headers });
|
|
33
|
+
const origin = requestOrigin(request);
|
|
34
|
+
let response;
|
|
35
|
+
try {
|
|
36
|
+
response = await fetch(`${config.url}/v1/host/session`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: {
|
|
39
|
+
authorization: `Bearer ${config.secret}`,
|
|
40
|
+
"content-type": "application/json"
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({
|
|
43
|
+
project: config.project,
|
|
44
|
+
environment: config.environment,
|
|
45
|
+
origin,
|
|
46
|
+
linked: config.linked ?? []
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
} catch {
|
|
50
|
+
return Response.json(
|
|
51
|
+
{ enabled: false, error: "Comment service is unreachable." },
|
|
52
|
+
{ status: 502, headers }
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const payload2 = await response.json().catch(() => null);
|
|
57
|
+
return Response.json(
|
|
58
|
+
{
|
|
59
|
+
enabled: false,
|
|
60
|
+
error: payload2?.error?.message ?? "Comment service rejected this environment.",
|
|
61
|
+
origin,
|
|
62
|
+
status: response.status
|
|
63
|
+
},
|
|
64
|
+
{ status: 502, headers }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const payload = await response.json();
|
|
68
|
+
if (payload.unknownLinked?.length) {
|
|
69
|
+
console.warn(
|
|
70
|
+
`[comment-service] COMMENT_SERVICE_LINKED: no environment named ${payload.unknownLinked.join(", ")} in project ${config.project}.`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return Response.json(
|
|
74
|
+
{
|
|
75
|
+
enabled: true,
|
|
76
|
+
apiUrl: config.url,
|
|
77
|
+
project: config.project,
|
|
78
|
+
environment: config.environment,
|
|
79
|
+
hostToken: payload.token
|
|
80
|
+
},
|
|
81
|
+
{ headers }
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
handleSessionRequest,
|
|
86
|
+
readCommentServiceConfig
|
|
87
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function toProjectPath(filename: string, root: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* Stamp the root node of each component of each component with a stable file + component name.
|
|
4
|
+
* Line numbers are intentionally not included: moving the component in the file
|
|
5
|
+
* or on the page must not change the stamp. A root that is itself a component
|
|
6
|
+
* (`<DropdownMenu>`, `<Menu.Root>`) gets the stamp as a prop: it reaches the DOM when
|
|
7
|
+
* the component spreads its props, and the toolbar reads it from React's tree when
|
|
8
|
+
* the component renders into a portal.
|
|
9
|
+
*/
|
|
10
|
+
export declare function annotateSource(code: string, filename: string, root: string): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** A host app that serves the toolbar sets this, in its env files, its Wrangler `vars`, or the build's environment. */
|
|
2
|
+
export declare const CONFIG_KEY = "COMMENT_SERVICE_URL";
|
|
3
|
+
/**
|
|
4
|
+
* Whether to stamp components. An explicit option or COMMENT_SERVICE_ENABLED wins; otherwise the dev server always
|
|
5
|
+
* stamps, and a build stamps only when it can see comment-service configuration.
|
|
6
|
+
*/
|
|
7
|
+
export declare function stampingEnabled({ option, flag, command, configured, }: {
|
|
8
|
+
option: boolean | undefined;
|
|
9
|
+
flag: string | undefined;
|
|
10
|
+
command: "build" | "serve";
|
|
11
|
+
configured: () => boolean;
|
|
12
|
+
}): boolean;
|
|
13
|
+
/** Comment-service configuration a build can see: its environment, Vite env files for the mode, or Wrangler config. */
|
|
14
|
+
export declare function buildConfigured(root: string, mode: string, env?: Record<string, string | undefined>): boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Anchor, Candidate, Resolution } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Drop elements that contain another match, so a wrapping div doesn't steal the button.
|
|
4
|
+
*
|
|
5
|
+
* Sorted by path, an element's descendants ("0/1/…") come directly after it: "/" sorts before every digit, so
|
|
6
|
+
* nothing else can sit between "0/1" and "0/1/4". One pass over the sorted list finds every ancestor, instead of
|
|
7
|
+
* comparing every pair; a page section with thousands of elements used to take seconds here.
|
|
8
|
+
*/
|
|
9
|
+
export declare function dropAncestors(candidates: Candidate[]): Candidate[];
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a stored anchor against the elements currently on the route.
|
|
12
|
+
*
|
|
13
|
+
* Order is deliberate:
|
|
14
|
+
* 1. An explicit id (`data-cs-anchor`, `data-testid`, stable `id`) wins.
|
|
15
|
+
* 2. Otherwise the match is component file + component name + role + label.
|
|
16
|
+
* 3. Sibling index and pixel position are ignored, so inserting, reordering,
|
|
17
|
+
* or moving the element (including out of a sheet) does not retarget the comment.
|
|
18
|
+
* 4. A tie is ambiguous. We do not fall back to "the first one" or the old index.
|
|
19
|
+
* 5. A unique component whose label changed is "drifted": still shown, marked uncertain.
|
|
20
|
+
* 6. A match that exists but is inside a closed dialog is "hidden", not deleted.
|
|
21
|
+
* 7. No match is "unavailable". The thread stays in the inbox.
|
|
22
|
+
*
|
|
23
|
+
* `candidates` may be a targeted subset of the page, as long as it holds every element with one of the anchor's
|
|
24
|
+
* explicit ids and every element owned by a component of the anchor's name. The drift check looks at everything
|
|
25
|
+
* inside the component's root, so such callers pass `inside` to supply those candidates on demand.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveAnchor(anchor: Anchor, candidates: Candidate[], inside?: (root: Candidate) => Candidate[]): Resolution;
|
|
28
|
+
export declare function describeAnchor(anchor: Anchor): string;
|
|
29
|
+
export declare function validateAnchor(input: unknown): Anchor | null;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** Stable identity for a commented element. Pixel and DOM-index position are not part of the match. */
|
|
2
|
+
export type Anchor = {
|
|
3
|
+
v: 1;
|
|
4
|
+
/** Pathname only, no query or hash. */
|
|
5
|
+
route: string;
|
|
6
|
+
/**
|
|
7
|
+
* Dialog or sheet the element lived in when the comment was written.
|
|
8
|
+
* Used to explain a hidden thread. Not required to match after the element moves out of the overlay.
|
|
9
|
+
*/
|
|
10
|
+
overlay: {
|
|
11
|
+
role: string;
|
|
12
|
+
name: string;
|
|
13
|
+
} | null;
|
|
14
|
+
/** Opt-in stable ids: data-cs-anchor, data-testid, or a human id. Highest priority. */
|
|
15
|
+
explicit: Array<{
|
|
16
|
+
attr: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}>;
|
|
19
|
+
/** React component that owns the element. File path is relative and has no line number. */
|
|
20
|
+
component: {
|
|
21
|
+
name: string;
|
|
22
|
+
file: string | null;
|
|
23
|
+
} | null;
|
|
24
|
+
/** Component names from the tree, outer to inner. Diagnostic. */
|
|
25
|
+
stack: string[];
|
|
26
|
+
role: string | null;
|
|
27
|
+
accName: string | null;
|
|
28
|
+
text: string | null;
|
|
29
|
+
tag: string;
|
|
30
|
+
/** Sibling path inside the component. Stored for agents, never used to choose a match. */
|
|
31
|
+
intra: string | null;
|
|
32
|
+
};
|
|
33
|
+
export type Candidate = {
|
|
34
|
+
key: string;
|
|
35
|
+
route: string;
|
|
36
|
+
visible: boolean;
|
|
37
|
+
/** Index path from the document body. Used only to tell ancestors from descendants. */
|
|
38
|
+
path: string;
|
|
39
|
+
componentRoot: boolean;
|
|
40
|
+
overlay: {
|
|
41
|
+
role: string;
|
|
42
|
+
name: string;
|
|
43
|
+
} | null;
|
|
44
|
+
explicit: Array<{
|
|
45
|
+
attr: string;
|
|
46
|
+
value: string;
|
|
47
|
+
}>;
|
|
48
|
+
component: {
|
|
49
|
+
name: string;
|
|
50
|
+
file: string | null;
|
|
51
|
+
} | null;
|
|
52
|
+
stack: string[];
|
|
53
|
+
role: string | null;
|
|
54
|
+
accName: string | null;
|
|
55
|
+
text: string | null;
|
|
56
|
+
tag: string;
|
|
57
|
+
intra: string | null;
|
|
58
|
+
};
|
|
59
|
+
export type ResolutionStatus = "pinned" | "drifted" | "hidden" | "ambiguous" | "unavailable";
|
|
60
|
+
export type Resolution = {
|
|
61
|
+
status: ResolutionStatus;
|
|
62
|
+
key: string | null;
|
|
63
|
+
score: number;
|
|
64
|
+
reason: string;
|
|
65
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type ClipboardEvent } from "react";
|
|
2
|
+
import { type Attachment, type Capture } from "./client.js";
|
|
3
|
+
import type { Session } from "./session.js";
|
|
4
|
+
export type Pending = {
|
|
5
|
+
key: string;
|
|
6
|
+
name: string;
|
|
7
|
+
size: number;
|
|
8
|
+
contentType: string;
|
|
9
|
+
preview: string | null;
|
|
10
|
+
status: "uploading" | "ready" | "failed";
|
|
11
|
+
id?: string;
|
|
12
|
+
error?: string;
|
|
13
|
+
capture?: Capture;
|
|
14
|
+
};
|
|
15
|
+
export declare function formatSize(bytes: number): string;
|
|
16
|
+
/** Files attached to one draft. Each upload starts immediately so posting doesn't wait on the network. */
|
|
17
|
+
export declare function useAttachments(session: Session | null, memberToken: string | null, onError: (message: string) => void, environment?: string): {
|
|
18
|
+
items: Pending[];
|
|
19
|
+
add: (files: Array<{
|
|
20
|
+
blob: Blob;
|
|
21
|
+
name: string;
|
|
22
|
+
capture?: Capture;
|
|
23
|
+
}>) => void;
|
|
24
|
+
remove: (key: string) => void;
|
|
25
|
+
reset: () => void;
|
|
26
|
+
ids: string[];
|
|
27
|
+
uploading: boolean;
|
|
28
|
+
};
|
|
29
|
+
export declare function filesFromClipboard(event: ClipboardEvent): {
|
|
30
|
+
blob: Blob;
|
|
31
|
+
name: string;
|
|
32
|
+
}[];
|
|
33
|
+
export type PreviewFile = {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
contentType: string;
|
|
37
|
+
url: string;
|
|
38
|
+
capture?: Capture;
|
|
39
|
+
};
|
|
40
|
+
/** Images, videos, and replays waiting in a draft, in tray order, for the preview beside the composer. */
|
|
41
|
+
export declare function pendingPreviews(items: Pending[]): PreviewFile[];
|
|
42
|
+
export declare function AttachmentTray({ items, activeKey, onPreview, onRemove, }: {
|
|
43
|
+
items: Pending[];
|
|
44
|
+
activeKey?: string | null;
|
|
45
|
+
onPreview?: (item: Pending) => void;
|
|
46
|
+
onRemove: (key: string) => void;
|
|
47
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
48
|
+
export declare function AttachButtons({ onFiles, onSnapshot, onRecord, onReplay, capturing, }: {
|
|
49
|
+
onFiles: (files: Array<{
|
|
50
|
+
blob: Blob;
|
|
51
|
+
name: string;
|
|
52
|
+
}>) => void;
|
|
53
|
+
onSnapshot: () => void;
|
|
54
|
+
onRecord: () => void;
|
|
55
|
+
onReplay: (() => void) | null;
|
|
56
|
+
capturing: boolean;
|
|
57
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
58
|
+
/** Images, videos, and replays in the order a thread shows them, so preview arrows follow the thread. */
|
|
59
|
+
export declare function visualAttachments(messages: Array<{
|
|
60
|
+
attachments?: Attachment[];
|
|
61
|
+
}> | undefined): Attachment[];
|
|
62
|
+
export declare function MessageAttachments({ attachments, activeId, onPreview, }: {
|
|
63
|
+
attachments?: Attachment[];
|
|
64
|
+
activeId?: string | null;
|
|
65
|
+
onPreview: (file: Attachment) => void;
|
|
66
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
67
|
+
/** The image, video, or replay open beside a thread. Arrows walk the thread's other previewable files. */
|
|
68
|
+
export declare function MediaPane({ files, fileId, onSelect, onClose, }: {
|
|
69
|
+
files: PreviewFile[];
|
|
70
|
+
fileId: string;
|
|
71
|
+
onSelect: (fileId: string) => void;
|
|
72
|
+
onClose: () => void;
|
|
73
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Capture } from "./client.js";
|
|
2
|
+
type AddFiles = (files: Array<{
|
|
3
|
+
blob: Blob;
|
|
4
|
+
name: string;
|
|
5
|
+
capture?: Capture;
|
|
6
|
+
}>) => void;
|
|
7
|
+
/** Records the current tab, then asks before the file is attached. Nothing is uploaded here. */
|
|
8
|
+
export declare function useTabRecording(onError: (message: string) => void): {
|
|
9
|
+
phase: "idle" | "recording" | "review";
|
|
10
|
+
elapsed: number;
|
|
11
|
+
review: {
|
|
12
|
+
url: string;
|
|
13
|
+
blob: Blob;
|
|
14
|
+
} | null;
|
|
15
|
+
tooBig: boolean;
|
|
16
|
+
begin: (add: AddFiles) => Promise<void>;
|
|
17
|
+
stop: () => void | undefined;
|
|
18
|
+
cancel: () => void;
|
|
19
|
+
keep: () => void;
|
|
20
|
+
again: () => void;
|
|
21
|
+
};
|
|
22
|
+
export declare function RecordChrome({ phase, elapsed, review, tooBig, onStop, onCancel, onKeep, onAgain, }: {
|
|
23
|
+
phase: "recording" | "review";
|
|
24
|
+
elapsed: number;
|
|
25
|
+
review: {
|
|
26
|
+
url: string;
|
|
27
|
+
blob: Blob;
|
|
28
|
+
} | null;
|
|
29
|
+
tooBig: boolean;
|
|
30
|
+
onStop: () => void;
|
|
31
|
+
onCancel: () => void;
|
|
32
|
+
onKeep: () => void;
|
|
33
|
+
onAgain: () => void;
|
|
34
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Anchor, Candidate, Resolution } from "../core/index.js";
|
|
2
|
+
type Owned = {
|
|
3
|
+
component: {
|
|
4
|
+
name: string;
|
|
5
|
+
file: string | null;
|
|
6
|
+
} | null;
|
|
7
|
+
stack: string[];
|
|
8
|
+
componentRoot: boolean;
|
|
9
|
+
owner: Element | null;
|
|
10
|
+
};
|
|
11
|
+
/** Each field is computed when first read, so a resolve only pays for what the match looks at. */
|
|
12
|
+
export declare function candidateFromElement(element: Element, route: string, key: string, owned?: Owned, pathOf?: (element: Element) => string): Candidate;
|
|
13
|
+
export declare function captureAnchor(element: Element, route?: string): Anchor;
|
|
14
|
+
export type Resolved = {
|
|
15
|
+
resolution: Resolution;
|
|
16
|
+
element: Element | null;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Resolves anchors against the page as it is now, building candidates only for the elements that can decide the
|
|
20
|
+
* result: those carrying one of the anchor's explicit ids, those owned by a component of the anchor's name, and,
|
|
21
|
+
* when the label changed, those inside that component's root. Never walks the whole page for a stamped anchor.
|
|
22
|
+
* Reuse one resolver for anchors resolved together; make a new one once the page may have changed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createResolver(route?: string): {
|
|
25
|
+
resolve(anchor: Anchor): Resolved;
|
|
26
|
+
};
|
|
27
|
+
export declare function resolveInDocument(anchor: Anchor, route?: string): Resolved;
|
|
28
|
+
export declare function elementAt(x: number, y: number): Element | null;
|
|
29
|
+
export declare function describeElement(element: Element): string;
|
|
30
|
+
export {};
|