Skip to content
Source
Sign inSign up

elementContext.ts

82 lines2.3 KB

1import type {
2 PickedElementPayload,
3 PickedElementStackFrame,
4 PreviewAnnotationPayload,
5} from "@t3tools/contracts";
6​
7const ELEMENT_CONTEXT_HTML_PREVIEW_LIMIT = 4000;
8const ELEMENT_CONTEXT_STYLES_LIMIT = 4000;
9​
10export interface ElementContextSelection {
11 pageUrl: string;
12 pageTitle: string | null;
13 tagName: string;
14 selector: string | null;
15 htmlPreview: string;
16 componentName: string | null;
17 source: PickedElementStackFrame | null;
18 styles: string;
20​
21function truncateString(value: string, limit: number): string {
22 if (value.length <= limit) return value;
23 return `${value.slice(0, Math.max(0, limit - 1))}…`;
25​
26function normalizeText(value: string): string {
27 return value.replace(/\r\n/g, "\n").replace(/^\n+|\n+$/g, "");
29​
30/** Clamps string fields to keep large outerHTML payloads within localStorage limits. */
31export function normalizeElementContextSelection(
32 raw: PickedElementPayload,
33): ElementContextSelection | null {
34 const pageUrl = raw.pageUrl.trim();
35 const tagName = raw.tagName.trim().toLowerCase();
36 if (pageUrl.length === 0 || tagName.length === 0) {
37 return null;
38 }
39 const stackFrame = raw.source ?? raw.stack[0] ?? null;
40 return {
41 pageUrl,
42 pageTitle: raw.pageTitle?.trim() ?? null,
43 tagName,
44 selector: raw.selector?.trim() || null,
45 htmlPreview: truncateString(normalizeText(raw.htmlPreview), ELEMENT_CONTEXT_HTML_PREVIEW_LIMIT),
46 componentName: raw.componentName?.trim() || null,
47 source: stackFrame
48 ? {
49 functionName: stackFrame.functionName?.trim() || null,
50 fileName: stackFrame.fileName?.trim() || null,
51 lineNumber: stackFrame.lineNumber ?? null,
52 columnNumber: stackFrame.columnNumber ?? null,
53 }
54 : null,
55 styles: truncateString(normalizeText(raw.styles), ELEMENT_CONTEXT_STYLES_LIMIT),
56 };
58​
59export function elementContextToPreviewAnnotation(
60 element: ElementContextSelection,
61 id: string,
62 pickedAt: string,
63): PreviewAnnotationPayload {
64 return {
65 id,
66 pageUrl: element.pageUrl,
67 pageTitle: element.pageTitle,
68 comment: "",
69 elements: [
70 {
71 id,
72 element: { ...element, stack: [], pickedAt },
73 rect: { x: 0, y: 0, width: 0, height: 0 },
74 },
75 ],
76 regions: [],
77 strokes: [],
78 styleChanges: [],
79 screenshot: null,
80 createdAt: pickedAt,
81 };