uilint-react 0.2.8 → 0.2.10
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 +35 -31
- package/dist/DevTool.d.ts +3 -3
- package/dist/DevTool.d.ts.map +1 -1
- package/dist/components/ui-lint/ElementBadges.d.ts.map +1 -1
- package/dist/components/ui-lint/InspectionPanel.d.ts.map +1 -1
- package/dist/components/ui-lint/LocatorOverlay.d.ts.map +1 -1
- package/dist/components/ui-lint/ScanResultsPopover.d.ts.map +1 -1
- package/dist/components/ui-lint/UILintUI.d.ts +5 -0
- package/dist/components/ui-lint/UILintUI.d.ts.map +1 -0
- package/dist/components/ui-lint/hooks/index.d.ts +4 -0
- package/dist/components/ui-lint/hooks/index.d.ts.map +1 -0
- package/dist/components/ui-lint/hooks/useAutoScans.d.ts +5 -0
- package/dist/components/ui-lint/hooks/useAutoScans.d.ts.map +1 -0
- package/dist/components/ui-lint/hooks/useDevToolEventHandlers.d.ts +5 -0
- package/dist/components/ui-lint/hooks/useDevToolEventHandlers.d.ts.map +1 -0
- package/dist/components/ui-lint/hooks/useNavigationDetection.d.ts +6 -0
- package/dist/components/ui-lint/hooks/useNavigationDetection.d.ts.map +1 -0
- package/dist/components/ui-lint/index.d.ts +1 -2
- package/dist/components/ui-lint/index.d.ts.map +1 -1
- package/dist/components/ui-lint/store.d.ts +18 -6
- package/dist/components/ui-lint/store.d.ts.map +1 -1
- package/dist/components/ui-lint/toolbar/icons.d.ts +4 -0
- package/dist/components/ui-lint/toolbar/icons.d.ts.map +1 -1
- package/dist/components/ui-lint/toolbar/index.d.ts.map +1 -1
- package/dist/components/ui-lint/toolbar/tabs/ConfigureTab.d.ts.map +1 -1
- package/dist/components/ui-lint/toolbar/tabs/ESLintTab.d.ts.map +1 -1
- package/dist/components/ui-lint/toolbar/tabs/VisionTab.d.ts.map +1 -1
- package/dist/components/ui-lint/types.d.ts +80 -35
- package/dist/components/ui-lint/types.d.ts.map +1 -1
- package/dist/devtools-types.d.ts +31 -0
- package/dist/devtools.js +93 -93
- package/dist/devtools.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12953 -42
- package/dist/index.js.map +1 -1
- package/dist/scanner/vision-capture.d.ts +1 -1
- package/dist/scanner/vision-capture.d.ts.map +1 -1
- package/dist/{vision-capture-EIrYA_XF.js → vision-capture-l4ZJB8M8.js} +89 -76
- package/dist/vision-capture-l4ZJB8M8.js.map +1 -0
- package/package.json +5 -4
- package/dist/ElementBadges-H5_y7fLt.js +0 -672
- package/dist/ElementBadges-H5_y7fLt.js.map +0 -1
- package/dist/VisionIssueBadge-Bw_1zmLh.js +0 -154
- package/dist/VisionIssueBadge-Bw_1zmLh.js.map +0 -1
- package/dist/components/ui-lint/UILintProvider.d.ts +0 -11
- package/dist/components/ui-lint/UILintProvider.d.ts.map +0 -1
- package/dist/index-Cu1-cGo1.js +0 -12839
- package/dist/index-Cu1-cGo1.js.map +0 -1
- package/dist/vision-capture-EIrYA_XF.js.map +0 -1
|
@@ -71,7 +71,7 @@ export interface VisionAnalysisResult {
|
|
|
71
71
|
* with deduplication for repeated elements (e.g., list items).
|
|
72
72
|
*
|
|
73
73
|
* @param container - Container element to scan (default: document.body)
|
|
74
|
-
* @param region - Optional region to filter elements (only include elements within this region)
|
|
74
|
+
* @param region - Optional region to filter elements (only include elements within this region, in viewport coordinates)
|
|
75
75
|
*/
|
|
76
76
|
export declare function collectElementManifest(container?: Element, region?: {
|
|
77
77
|
x: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vision-capture.d.ts","sourceRoot":"","sources":["../../src/scanner/vision-capture.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,QAAQ,EACJ,SAAS,GACT,WAAW,GACX,OAAO,GACP,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,kBAAkB,GAElB,OAAO,CAAC;IACZ,qBAAqB;IACrB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB;IACvB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,sCAAsC;IACtC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0KD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,GAAE,OAAuB,EAClC,MAAM,CAAC,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/D,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"vision-capture.d.ts","sourceRoot":"","sources":["../../src/scanner/vision-capture.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,QAAQ,EACJ,SAAS,GACT,WAAW,GACX,OAAO,GACP,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,kBAAkB,GAElB,OAAO,CAAC;IACZ,qBAAqB;IACrB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB;IACvB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,sCAAsC;IACtC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0KD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,GAAE,OAAuB,EAClC,MAAM,CAAC,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/D,eAAe,EAAE,CAgGnB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,EAAE,EACrB,QAAQ,EAAE,eAAe,EAAE,GAC1B,WAAW,EAAE,CA0Bf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAqCzD;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE;IACpD,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqDlB;AAyDD;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAKxC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE;IAClD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;;;;;;;EASA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const E = /* @__PURE__ */ new Set([
|
|
2
2
|
"SCRIPT",
|
|
3
3
|
"STYLE",
|
|
4
4
|
"SVG",
|
|
@@ -12,9 +12,9 @@ const d = /* @__PURE__ */ new Set([
|
|
|
12
12
|
"NOSCRIPT",
|
|
13
13
|
"TEMPLATE",
|
|
14
14
|
"SLOT"
|
|
15
|
-
]),
|
|
16
|
-
function
|
|
17
|
-
const t =
|
|
15
|
+
]), y = 3, g = 100;
|
|
16
|
+
function b(e) {
|
|
17
|
+
const t = e.tagName.toUpperCase(), r = e.getAttribute("role");
|
|
18
18
|
if (r) return r;
|
|
19
19
|
switch (t) {
|
|
20
20
|
case "BUTTON":
|
|
@@ -29,8 +29,8 @@ function w(n) {
|
|
|
29
29
|
case "H6":
|
|
30
30
|
return "heading";
|
|
31
31
|
case "INPUT": {
|
|
32
|
-
const
|
|
33
|
-
return
|
|
32
|
+
const n = e.type;
|
|
33
|
+
return n === "submit" || n === "button" ? "button" : n === "checkbox" ? "checkbox" : n === "radio" ? "radio" : "textbox";
|
|
34
34
|
}
|
|
35
35
|
case "TEXTAREA":
|
|
36
36
|
return "textbox";
|
|
@@ -65,85 +65,93 @@ function w(n) {
|
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
function
|
|
69
|
-
const t =
|
|
68
|
+
function S(e) {
|
|
69
|
+
const t = e.innerText?.trim();
|
|
70
70
|
if (t)
|
|
71
|
-
return t.length >
|
|
72
|
-
const r =
|
|
71
|
+
return t.length > g ? t.slice(0, g) + "…" : t;
|
|
72
|
+
const r = e.getAttribute("aria-label");
|
|
73
73
|
if (r) return r;
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
-
const o =
|
|
74
|
+
const n = e.getAttribute("title");
|
|
75
|
+
if (n) return n;
|
|
76
|
+
const o = e.getAttribute("placeholder");
|
|
77
77
|
if (o) return o;
|
|
78
|
-
const i =
|
|
78
|
+
const i = e.getAttribute("alt");
|
|
79
79
|
return i || "";
|
|
80
80
|
}
|
|
81
|
-
function
|
|
82
|
-
const t =
|
|
81
|
+
function T(e) {
|
|
82
|
+
const t = e, r = window.getComputedStyle(t);
|
|
83
83
|
if (r.display === "none" || r.visibility === "hidden" || r.opacity === "0") return !1;
|
|
84
|
-
const
|
|
85
|
-
return !(
|
|
84
|
+
const n = e.getBoundingClientRect();
|
|
85
|
+
return !(n.width === 0 && n.height === 0 || n.bottom < -100 || n.top > window.innerHeight + 100 || n.right < -100 || n.left > window.innerWidth + 100);
|
|
86
86
|
}
|
|
87
|
-
function
|
|
88
|
-
const r =
|
|
89
|
-
return !(
|
|
87
|
+
function x(e, t) {
|
|
88
|
+
const r = e.left + e.width, n = e.top + e.height, o = t.x + t.width, i = t.y + t.height;
|
|
89
|
+
return !(e.left > o || r < t.x || e.top > i || n < t.y);
|
|
90
90
|
}
|
|
91
|
-
function
|
|
92
|
-
const r = [],
|
|
93
|
-
for (const
|
|
94
|
-
if (
|
|
95
|
-
const
|
|
96
|
-
if (t && !
|
|
97
|
-
const s =
|
|
91
|
+
function A(e = document.body, t) {
|
|
92
|
+
const r = [], n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), i = window.scrollX || window.pageXOffset || 0, l = window.scrollY || window.pageYOffset || 0, f = e.querySelectorAll("[data-loc]");
|
|
93
|
+
for (const c of f) {
|
|
94
|
+
if (c.closest("[data-ui-lint]") || E.has(c.tagName) || !T(c)) continue;
|
|
95
|
+
const a = c.getBoundingClientRect();
|
|
96
|
+
if (t && !x(a, t)) continue;
|
|
97
|
+
const s = c.getAttribute("data-loc");
|
|
98
98
|
if (!s) continue;
|
|
99
|
-
const
|
|
100
|
-
|
|
99
|
+
const h = n.get(s) || 0;
|
|
100
|
+
n.set(s, h + 1);
|
|
101
101
|
let u = o.get(s);
|
|
102
|
-
if (u || (u = [], o.set(s, u)), u.length >=
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
if (u || (u = [], o.set(s, u)), u.length >= y) continue;
|
|
103
|
+
const w = S(c), m = c.getAttribute("data-ui-lint-id") || `loc:${s}#${h}`;
|
|
104
|
+
let d;
|
|
105
|
+
t ? d = {
|
|
106
|
+
x: a.x - t.x,
|
|
107
|
+
y: a.y - t.y,
|
|
108
|
+
width: a.width,
|
|
109
|
+
height: a.height
|
|
110
|
+
} : d = {
|
|
111
|
+
x: a.x + i,
|
|
112
|
+
y: a.y + l,
|
|
113
|
+
width: a.width,
|
|
114
|
+
height: a.height
|
|
115
|
+
};
|
|
116
|
+
const p = {
|
|
117
|
+
id: m,
|
|
118
|
+
text: w,
|
|
106
119
|
dataLoc: s,
|
|
107
|
-
rect:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
width: c.width,
|
|
111
|
-
height: c.height
|
|
112
|
-
},
|
|
113
|
-
tagName: a.tagName.toLowerCase(),
|
|
114
|
-
role: w(a)
|
|
120
|
+
rect: d,
|
|
121
|
+
tagName: c.tagName.toLowerCase(),
|
|
122
|
+
role: b(c)
|
|
115
123
|
};
|
|
116
|
-
u.push(
|
|
124
|
+
u.push(p);
|
|
117
125
|
}
|
|
118
|
-
for (const [
|
|
119
|
-
const s =
|
|
120
|
-
|
|
121
|
-
u === 0 && s >
|
|
126
|
+
for (const [c, a] of o) {
|
|
127
|
+
const s = n.get(c) || a.length;
|
|
128
|
+
a.forEach((h, u) => {
|
|
129
|
+
u === 0 && s > a.length && (h.instanceCount = s), r.push(h);
|
|
122
130
|
});
|
|
123
131
|
}
|
|
124
132
|
return r;
|
|
125
133
|
}
|
|
126
|
-
async function
|
|
127
|
-
const
|
|
128
|
-
if (!
|
|
134
|
+
async function C() {
|
|
135
|
+
const e = await import("./index-L3Zm-CoX.js").catch(() => null);
|
|
136
|
+
if (!e)
|
|
129
137
|
throw new Error(
|
|
130
138
|
"Screenshot capture unavailable: `html-to-image` failed to load (check the uilint-react bundle/deps)"
|
|
131
139
|
);
|
|
132
140
|
try {
|
|
133
|
-
return await
|
|
141
|
+
return await e.toPng(document.body, {
|
|
134
142
|
// Keep file size down for WS transport
|
|
135
143
|
pixelRatio: 1,
|
|
136
144
|
cacheBust: !0,
|
|
137
145
|
filter: (r) => !(r instanceof Element && r.closest("[data-ui-lint]"))
|
|
138
146
|
});
|
|
139
147
|
} catch (t) {
|
|
140
|
-
const
|
|
148
|
+
const n = (t instanceof Error ? t : new Error(String(t))).message || "Unknown error", o = /tainted|cross[- ]origin|CORS|security/i.test(n) ? " Hint: this is often caused by cross-origin images/fonts; try removing external images or ensuring they allow CORS." : "";
|
|
141
149
|
throw new Error(
|
|
142
|
-
`Screenshot capture failed (html-to-image): ${
|
|
150
|
+
`Screenshot capture failed (html-to-image): ${n}.${o}`
|
|
143
151
|
);
|
|
144
152
|
}
|
|
145
153
|
}
|
|
146
|
-
async function
|
|
154
|
+
async function L(e) {
|
|
147
155
|
const t = await import("./index-L3Zm-CoX.js").catch(() => null);
|
|
148
156
|
if (!t)
|
|
149
157
|
throw new Error(
|
|
@@ -153,9 +161,14 @@ async function x(n) {
|
|
|
153
161
|
const r = await t.toPng(document.body, {
|
|
154
162
|
pixelRatio: 1,
|
|
155
163
|
cacheBust: !0,
|
|
156
|
-
filter: (
|
|
157
|
-
})
|
|
158
|
-
|
|
164
|
+
filter: (l) => !(l instanceof Element && l.closest("[data-ui-lint]"))
|
|
165
|
+
}), n = window.scrollX || window.pageXOffset || 0, o = window.scrollY || window.pageYOffset || 0, i = {
|
|
166
|
+
x: e.x + n,
|
|
167
|
+
y: e.y + o,
|
|
168
|
+
width: e.width,
|
|
169
|
+
height: e.height
|
|
170
|
+
};
|
|
171
|
+
return await R(r, i);
|
|
159
172
|
} catch (r) {
|
|
160
173
|
const o = (r instanceof Error ? r : new Error(String(r))).message || "Unknown error", i = /tainted|cross[- ]origin|CORS|security/i.test(o) ? " Hint: this is often caused by cross-origin images/fonts; try removing external images or ensuring they allow CORS." : "";
|
|
161
174
|
throw new Error(
|
|
@@ -163,19 +176,19 @@ async function x(n) {
|
|
|
163
176
|
);
|
|
164
177
|
}
|
|
165
178
|
}
|
|
166
|
-
async function
|
|
167
|
-
return new Promise((r,
|
|
179
|
+
async function R(e, t) {
|
|
180
|
+
return new Promise((r, n) => {
|
|
168
181
|
const o = new Image();
|
|
169
182
|
o.onload = () => {
|
|
170
183
|
try {
|
|
171
184
|
const i = document.createElement("canvas");
|
|
172
185
|
i.width = t.width, i.height = t.height;
|
|
173
|
-
const
|
|
174
|
-
if (!
|
|
175
|
-
|
|
186
|
+
const l = i.getContext("2d");
|
|
187
|
+
if (!l) {
|
|
188
|
+
n(new Error("Failed to get canvas context"));
|
|
176
189
|
return;
|
|
177
190
|
}
|
|
178
|
-
|
|
191
|
+
l.drawImage(
|
|
179
192
|
o,
|
|
180
193
|
t.x,
|
|
181
194
|
t.y,
|
|
@@ -186,31 +199,31 @@ async function y(n, t) {
|
|
|
186
199
|
t.width,
|
|
187
200
|
t.height
|
|
188
201
|
);
|
|
189
|
-
const
|
|
190
|
-
r(
|
|
202
|
+
const f = i.toDataURL("image/png");
|
|
203
|
+
r(f);
|
|
191
204
|
} catch (i) {
|
|
192
|
-
|
|
205
|
+
n(
|
|
193
206
|
new Error(
|
|
194
207
|
`Failed to crop image: ${i instanceof Error ? i.message : String(i)}`
|
|
195
208
|
)
|
|
196
209
|
);
|
|
197
210
|
}
|
|
198
211
|
}, o.onerror = () => {
|
|
199
|
-
|
|
200
|
-
}, o.src =
|
|
212
|
+
n(new Error("Failed to load image for cropping"));
|
|
213
|
+
}, o.src = e;
|
|
201
214
|
});
|
|
202
215
|
}
|
|
203
|
-
function
|
|
216
|
+
function I() {
|
|
204
217
|
return window.location.pathname.replace(/\/+$/, "") || "/";
|
|
205
218
|
}
|
|
206
|
-
function
|
|
219
|
+
function O() {
|
|
207
220
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
208
221
|
}
|
|
209
222
|
export {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
223
|
+
C as captureScreenshot,
|
|
224
|
+
L as captureScreenshotRegion,
|
|
225
|
+
A as collectElementManifest,
|
|
226
|
+
O as generateTimestamp,
|
|
227
|
+
I as getCurrentRoute
|
|
215
228
|
};
|
|
216
|
-
//# sourceMappingURL=vision-capture-
|
|
229
|
+
//# sourceMappingURL=vision-capture-l4ZJB8M8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vision-capture-l4ZJB8M8.js","sources":["../src/scanner/vision-capture.ts"],"sourcesContent":["/**\n * Vision Capture Module\n *\n * Provides screenshot capture and element manifest building for vision-based analysis.\n * Uses html-to-image for DOM-to-image capture.\n */\n\n/**\n * Element manifest entry for vision analysis\n */\nexport interface ElementManifest {\n /** Unique ID (data-ui-lint-id if present, otherwise generated) */\n id: string;\n /** Visible text content (truncated to 100 chars) */\n text: string;\n /** data-loc value: \"path:line:column\" */\n dataLoc: string;\n /** Bounding rectangle */\n rect: { x: number; y: number; width: number; height: number };\n /** HTML tag name */\n tagName: string;\n /** Inferred semantic role (button, heading, link, etc.) */\n role?: string;\n /** Total instances with same dataLoc (if deduplicated) */\n instanceCount?: number;\n}\n\n/**\n * Vision analysis issue from the LLM\n */\nexport interface VisionIssue {\n /** Text of the element this issue refers to */\n elementText: string;\n /** Issue description */\n message: string;\n /** Issue category */\n category:\n | \"spacing\"\n | \"alignment\"\n | \"color\"\n | \"typography\"\n | \"layout\"\n | \"contrast\"\n | \"visual-hierarchy\"\n // backward/defensive (older payloads or custom models)\n | \"other\";\n /** Severity level */\n severity: \"error\" | \"warning\" | \"info\";\n /** Matched dataLoc from manifest (filled in after text matching) */\n dataLoc?: string;\n /** Matched element ID (filled in after text matching) */\n elementId?: string;\n}\n\n/**\n * Vision analysis result\n */\nexport interface VisionAnalysisResult {\n /** Route/path that was analyzed */\n route: string;\n /** Timestamp of capture */\n timestamp: number;\n /** Screenshot as base64 data URL */\n screenshotDataUrl?: string;\n /** Element manifest */\n manifest: ElementManifest[];\n /** Issues found by vision analysis */\n issues: VisionIssue[];\n /** Analysis duration in ms */\n analysisTime: number;\n /** Error message if analysis failed */\n error?: string;\n}\n\n/**\n * Tags to skip when collecting manifest\n */\nconst SKIP_TAGS = new Set([\n \"SCRIPT\",\n \"STYLE\",\n \"SVG\",\n \"PATH\",\n \"CIRCLE\",\n \"RECT\",\n \"LINE\",\n \"POLYGON\",\n \"POLYLINE\",\n \"ELLIPSE\",\n \"NOSCRIPT\",\n \"TEMPLATE\",\n \"SLOT\",\n]);\n\n/**\n * Max instances per dataLoc to include in manifest (for deduplication)\n */\nconst MAX_INSTANCES_PER_DATALOC = 3;\n\n/**\n * Max text length for element text\n */\nconst MAX_TEXT_LENGTH = 100;\n\n/**\n * Infer semantic role from element\n */\nfunction inferRole(element: Element): string | undefined {\n const tagName = element.tagName.toUpperCase();\n\n // Check explicit role attribute\n const explicitRole = element.getAttribute(\"role\");\n if (explicitRole) return explicitRole;\n\n // Infer from tag name\n switch (tagName) {\n case \"BUTTON\":\n return \"button\";\n case \"A\":\n return \"link\";\n case \"H1\":\n case \"H2\":\n case \"H3\":\n case \"H4\":\n case \"H5\":\n case \"H6\":\n return \"heading\";\n case \"INPUT\": {\n const type = (element as HTMLInputElement).type;\n if (type === \"submit\" || type === \"button\") return \"button\";\n if (type === \"checkbox\") return \"checkbox\";\n if (type === \"radio\") return \"radio\";\n return \"textbox\";\n }\n case \"TEXTAREA\":\n return \"textbox\";\n case \"SELECT\":\n return \"combobox\";\n case \"IMG\":\n return \"img\";\n case \"NAV\":\n return \"navigation\";\n case \"MAIN\":\n return \"main\";\n case \"HEADER\":\n return \"banner\";\n case \"FOOTER\":\n return \"contentinfo\";\n case \"ASIDE\":\n return \"complementary\";\n case \"ARTICLE\":\n return \"article\";\n case \"SECTION\":\n return \"region\";\n case \"FORM\":\n return \"form\";\n case \"TABLE\":\n return \"table\";\n case \"UL\":\n case \"OL\":\n return \"list\";\n case \"LI\":\n return \"listitem\";\n default:\n return undefined;\n }\n}\n\n/**\n * Get visible text content from element\n */\nfunction getVisibleText(element: Element): string {\n // Try innerText first (respects visibility)\n const innerText = (element as HTMLElement).innerText?.trim();\n if (innerText) {\n return innerText.length > MAX_TEXT_LENGTH\n ? innerText.slice(0, MAX_TEXT_LENGTH) + \"…\"\n : innerText;\n }\n\n // Fallback to aria-label\n const ariaLabel = element.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel;\n\n // Fallback to title\n const title = element.getAttribute(\"title\");\n if (title) return title;\n\n // Fallback to placeholder for inputs\n const placeholder = element.getAttribute(\"placeholder\");\n if (placeholder) return placeholder;\n\n // Fallback to alt for images\n const alt = element.getAttribute(\"alt\");\n if (alt) return alt;\n\n return \"\";\n}\n\n/**\n * Check if element is visible\n */\nfunction isElementVisible(element: Element): boolean {\n const htmlEl = element as HTMLElement;\n\n // Check computed style\n const style = window.getComputedStyle(htmlEl);\n if (style.display === \"none\") return false;\n if (style.visibility === \"hidden\") return false;\n if (style.opacity === \"0\") return false;\n\n // Check dimensions\n const rect = element.getBoundingClientRect();\n if (rect.width === 0 && rect.height === 0) return false;\n\n // Check if in viewport (with some margin)\n if (rect.bottom < -100 || rect.top > window.innerHeight + 100) return false;\n if (rect.right < -100 || rect.left > window.innerWidth + 100) return false;\n\n return true;\n}\n\n/**\n * Check if element rect intersects with a region\n */\nfunction rectIntersectsRegion(\n rect: DOMRect,\n region: { x: number; y: number; width: number; height: number }\n): boolean {\n const rectRight = rect.left + rect.width;\n const rectBottom = rect.top + rect.height;\n const regionRight = region.x + region.width;\n const regionBottom = region.y + region.height;\n\n // Check if rectangles overlap\n return !(\n rect.left > regionRight ||\n rectRight < region.x ||\n rect.top > regionBottom ||\n rectBottom < region.y\n );\n}\n\n/**\n * Collect element manifest from DOM\n *\n * Scans all elements with data-loc attributes and builds a manifest\n * with deduplication for repeated elements (e.g., list items).\n *\n * @param container - Container element to scan (default: document.body)\n * @param region - Optional region to filter elements (only include elements within this region, in viewport coordinates)\n */\nexport function collectElementManifest(\n container: Element = document.body,\n region?: { x: number; y: number; width: number; height: number }\n): ElementManifest[] {\n const manifest: ElementManifest[] = [];\n const dataLocCounts = new Map<string, number>();\n const dataLocInstances = new Map<string, ElementManifest[]>();\n\n // Get scroll offset for converting viewport coords to document coords\n const scrollX = window.scrollX || window.pageXOffset || 0;\n const scrollY = window.scrollY || window.pageYOffset || 0;\n\n // Find all elements with data-loc\n const elements = container.querySelectorAll(\"[data-loc]\");\n\n for (const element of elements) {\n // Skip UILint's own elements\n if (element.closest(\"[data-ui-lint]\")) continue;\n\n // Skip certain tag types\n if (SKIP_TAGS.has(element.tagName)) continue;\n\n // Skip hidden elements\n if (!isElementVisible(element)) continue;\n\n // Skip elements outside the region (if region is specified)\n // Region is in viewport coordinates, same as getBoundingClientRect\n const rect = element.getBoundingClientRect();\n if (region && !rectIntersectsRegion(rect, region)) continue;\n\n const dataLoc = element.getAttribute(\"data-loc\");\n if (!dataLoc) continue;\n\n // Track instance count\n const currentCount = dataLocCounts.get(dataLoc) || 0;\n dataLocCounts.set(dataLoc, currentCount + 1);\n\n // Get or create instances array for this dataLoc\n let instances = dataLocInstances.get(dataLoc);\n if (!instances) {\n instances = [];\n dataLocInstances.set(dataLoc, instances);\n }\n\n // Only collect up to MAX_INSTANCES_PER_DATALOC\n if (instances.length >= MAX_INSTANCES_PER_DATALOC) continue;\n\n const text = getVisibleText(element);\n const id =\n element.getAttribute(\"data-ui-lint-id\") ||\n `loc:${dataLoc}#${currentCount}`;\n\n // For region captures, store coordinates relative to the region origin\n // For full page captures, store document coordinates (viewport + scroll)\n let entryRect: { x: number; y: number; width: number; height: number };\n if (region) {\n // Relative to the region's top-left corner\n entryRect = {\n x: rect.x - region.x,\n y: rect.y - region.y,\n width: rect.width,\n height: rect.height,\n };\n } else {\n // Document coordinates for full page\n entryRect = {\n x: rect.x + scrollX,\n y: rect.y + scrollY,\n width: rect.width,\n height: rect.height,\n };\n }\n\n const entry: ElementManifest = {\n id,\n text,\n dataLoc,\n rect: entryRect,\n tagName: element.tagName.toLowerCase(),\n role: inferRole(element),\n };\n\n instances.push(entry);\n }\n\n // Build final manifest with instance counts\n for (const [dataLoc, instances] of dataLocInstances) {\n const totalCount = dataLocCounts.get(dataLoc) || instances.length;\n\n instances.forEach((entry, index) => {\n // Add instance count to first entry if there are more than shown\n if (index === 0 && totalCount > instances.length) {\n entry.instanceCount = totalCount;\n }\n manifest.push(entry);\n });\n }\n\n return manifest;\n}\n\n/**\n * Match vision issues to manifest entries by element text\n *\n * The LLM returns issues with elementText; we need to map back to dataLoc\n */\nexport function matchIssuesToManifest(\n issues: VisionIssue[],\n manifest: ElementManifest[]\n): VisionIssue[] {\n return issues.map((issue) => {\n // Try exact match first\n let match = manifest.find(\n (m) => m.text.toLowerCase() === issue.elementText.toLowerCase()\n );\n\n // Try partial match (text starts with or contains)\n if (!match) {\n match = manifest.find(\n (m) =>\n m.text.toLowerCase().includes(issue.elementText.toLowerCase()) ||\n issue.elementText.toLowerCase().includes(m.text.toLowerCase())\n );\n }\n\n if (match) {\n return {\n ...issue,\n dataLoc: match.dataLoc,\n elementId: match.id,\n };\n }\n\n return issue;\n });\n}\n\n/**\n * Capture screenshot of the current page\n *\n * Uses html-to-image library for DOM-to-image capture.\n * Falls back to canvas if html-to-image is not available.\n */\nexport async function captureScreenshot(): Promise<string> {\n // Try to use html-to-image if available\n const htmlToImage = await import(\"html-to-image\").catch(() => null);\n\n if (!htmlToImage) {\n throw new Error(\n \"Screenshot capture unavailable: `html-to-image` failed to load (check the uilint-react bundle/deps)\"\n );\n }\n\n try {\n const dataUrl = await htmlToImage.toPng(document.body, {\n // Keep file size down for WS transport\n pixelRatio: 1,\n cacheBust: true,\n filter: (node) => {\n // Skip UILint overlay elements\n if (node instanceof Element && node.closest(\"[data-ui-lint]\")) {\n return false;\n }\n return true;\n },\n });\n return dataUrl;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n const msg = err.message || \"Unknown error\";\n\n // Common failure modes: cross-origin images/fonts taint the canvas.\n const hint = /tainted|cross[- ]origin|CORS|security/i.test(msg)\n ? \" Hint: this is often caused by cross-origin images/fonts; try removing external images or ensuring they allow CORS.\"\n : \"\";\n\n throw new Error(\n `Screenshot capture failed (html-to-image): ${msg}.${hint}`\n );\n }\n}\n\n/**\n * Capture screenshot of a specific region of the page\n *\n * @param region - The region to capture (in viewport coordinates)\n */\nexport async function captureScreenshotRegion(region: {\n x: number;\n y: number;\n width: number;\n height: number;\n}): Promise<string> {\n // Try to use html-to-image if available\n const htmlToImage = await import(\"html-to-image\").catch(() => null);\n\n if (!htmlToImage) {\n throw new Error(\n \"Screenshot capture unavailable: `html-to-image` failed to load (check the uilint-react bundle/deps)\"\n );\n }\n\n try {\n // Capture the full page first, then crop to the region\n // This is more reliable than trying to capture a specific element\n const dataUrl = await htmlToImage.toPng(document.body, {\n pixelRatio: 1,\n cacheBust: true,\n filter: (node) => {\n // Skip UILint overlay elements\n if (node instanceof Element && node.closest(\"[data-ui-lint]\")) {\n return false;\n }\n return true;\n },\n });\n\n // The region coordinates are viewport-relative (from mouse events),\n // but html-to-image captures the full document including scrolled content.\n // We need to add the scroll offset to get the correct position in the full document.\n const scrollX = window.scrollX || window.pageXOffset || 0;\n const scrollY = window.scrollY || window.pageYOffset || 0;\n\n const documentRegion = {\n x: region.x + scrollX,\n y: region.y + scrollY,\n width: region.width,\n height: region.height,\n };\n\n // Crop the image to the selected region using canvas\n return await cropImageToRegion(dataUrl, documentRegion);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n const msg = err.message || \"Unknown error\";\n\n // Common failure modes: cross-origin images/fonts taint the canvas.\n const hint = /tainted|cross[- ]origin|CORS|security/i.test(msg)\n ? \" Hint: this is often caused by cross-origin images/fonts; try removing external images or ensuring they allow CORS.\"\n : \"\";\n\n throw new Error(\n `Screenshot capture failed (html-to-image): ${msg}.${hint}`\n );\n }\n}\n\n/**\n * Crop an image data URL to a specific region\n */\nasync function cropImageToRegion(\n dataUrl: string,\n region: { x: number; y: number; width: number; height: number }\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n try {\n // Create a canvas for cropping\n const canvas = document.createElement(\"canvas\");\n canvas.width = region.width;\n canvas.height = region.height;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Failed to get canvas context\"));\n return;\n }\n\n // Draw the cropped region\n ctx.drawImage(\n img,\n region.x,\n region.y,\n region.width,\n region.height,\n 0,\n 0,\n region.width,\n region.height\n );\n\n // Convert to data URL\n const croppedDataUrl = canvas.toDataURL(\"image/png\");\n resolve(croppedDataUrl);\n } catch (error) {\n reject(\n new Error(\n `Failed to crop image: ${\n error instanceof Error ? error.message : String(error)\n }`\n )\n );\n }\n };\n img.onerror = () => {\n reject(new Error(\"Failed to load image for cropping\"));\n };\n img.src = dataUrl;\n });\n}\n\n/**\n * Get current route from URL\n */\nexport function getCurrentRoute(): string {\n const path = window.location.pathname;\n // Normalize: remove trailing slashes, handle index\n const normalized = path.replace(/\\/+$/, \"\") || \"/\";\n return normalized;\n}\n\n/**\n * Generate filename-safe timestamp\n */\nexport function generateTimestamp(): string {\n return new Date().toISOString().replace(/[:.]/g, \"-\");\n}\n\n/**\n * Build vision analysis request payload\n */\nexport function buildVisionAnalysisPayload(options: {\n screenshotDataUrl?: string;\n manifest: ElementManifest[];\n route: string;\n /** Screenshot filename saved under `.uilint/screenshots` (e.g. uilint-...png) */\n screenshotFile?: string;\n}) {\n return {\n type: \"vision:analyze\" as const,\n route: options.route,\n timestamp: Date.now(),\n screenshot: options.screenshotDataUrl,\n screenshotFile: options.screenshotFile,\n manifest: options.manifest,\n };\n}\n"],"names":["SKIP_TAGS","MAX_INSTANCES_PER_DATALOC","MAX_TEXT_LENGTH","inferRole","element","tagName","explicitRole","type","getVisibleText","innerText","ariaLabel","title","placeholder","alt","isElementVisible","htmlEl","style","rect","rectIntersectsRegion","region","rectRight","rectBottom","regionRight","regionBottom","collectElementManifest","container","manifest","dataLocCounts","dataLocInstances","scrollX","scrollY","elements","dataLoc","currentCount","instances","text","id","entryRect","entry","totalCount","index","captureScreenshot","htmlToImage","node","error","msg","hint","captureScreenshotRegion","dataUrl","documentRegion","cropImageToRegion","resolve","reject","img","canvas","ctx","croppedDataUrl","getCurrentRoute","generateTimestamp"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uilint-react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"description": "React component for AI-powered UI consistency checking",
|
|
5
5
|
"author": "Peter Suggate",
|
|
6
6
|
"repository": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"import": "./dist/node.js"
|
|
27
27
|
},
|
|
28
28
|
"./devtools": {
|
|
29
|
+
"types": "./dist/devtools-types.d.ts",
|
|
29
30
|
"import": "./dist/devtools.js"
|
|
30
31
|
}
|
|
31
32
|
},
|
|
@@ -46,8 +47,8 @@
|
|
|
46
47
|
"react-use-measure": "^2.1.7",
|
|
47
48
|
"tw-animate-css": "^1.4.0",
|
|
48
49
|
"zustand": "^5.0.10",
|
|
49
|
-
"uilint-core": "0.2.
|
|
50
|
-
"uilint-eslint": "0.2.
|
|
50
|
+
"uilint-core": "0.2.10",
|
|
51
|
+
"uilint-eslint": "0.2.10"
|
|
51
52
|
},
|
|
52
53
|
"peerDependencies": {
|
|
53
54
|
"react": "^19.0.0",
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
"access": "public"
|
|
93
94
|
},
|
|
94
95
|
"scripts": {
|
|
95
|
-
"build": "vite build && vite build -c vite.devtools.config.ts",
|
|
96
|
+
"build": "vite build && vite build -c vite.devtools.config.ts && cp src/devtools-types.d.ts dist/",
|
|
96
97
|
"dev": "vite build --watch",
|
|
97
98
|
"test": "vitest run",
|
|
98
99
|
"test:watch": "vitest --watch",
|