uilint-react 0.1.34 → 0.1.37

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.
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  useUILintContext
5
- } from "./chunk-MO4NS6EG.js";
5
+ } from "./chunk-DEHJKJNT.js";
6
6
 
7
7
  // src/components/ui-lint/ElementBadges.tsx
8
8
  import React, { useState, useEffect, useCallback, useMemo } from "react";
@@ -167,6 +167,29 @@ function formatElementLabel(element) {
167
167
  return componentName ? `${tag} > ${componentName}` : tag;
168
168
  }
169
169
  var NEARBY_THRESHOLD = 30;
170
+ var WINDOW_EDGE_THRESHOLD = 20;
171
+ var BADGE_SIZE = 18;
172
+ function snapToWindowBounds(x, y) {
173
+ const minX = WINDOW_EDGE_THRESHOLD;
174
+ const maxX = window.innerWidth - BADGE_SIZE - WINDOW_EDGE_THRESHOLD;
175
+ const minY = WINDOW_EDGE_THRESHOLD;
176
+ const maxY = window.innerHeight - BADGE_SIZE - WINDOW_EDGE_THRESHOLD;
177
+ return {
178
+ x: Math.max(minX, Math.min(maxX, x)),
179
+ y: Math.max(minY, Math.min(maxY, y))
180
+ };
181
+ }
182
+ function shouldShowBadge(issue, isAltKeyPressed) {
183
+ if (issue.status === "error") return true;
184
+ if (issue.status === "complete" && issue.issues.length > 0) return true;
185
+ if (issue.status === "complete" && issue.issues.length === 0) {
186
+ return isAltKeyPressed;
187
+ }
188
+ if (issue.status === "scanning" || issue.status === "pending") {
189
+ return isAltKeyPressed;
190
+ }
191
+ return false;
192
+ }
170
193
  function BadgeAnimationStyles() {
171
194
  return /* @__PURE__ */ jsx("style", { children: `
172
195
  @keyframes uilint-badge-spin {
@@ -180,9 +203,33 @@ function ElementBadges() {
180
203
  const [mounted, setMounted] = useState(false);
181
204
  const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
182
205
  const [badgePositions, setBadgePositions] = useState([]);
206
+ const [isAltKeyPressed, setIsAltKeyPressed] = useState(false);
183
207
  useEffect(() => {
184
208
  setMounted(true);
185
209
  }, []);
210
+ useEffect(() => {
211
+ const handleKeyDown = (e) => {
212
+ if (e.altKey) {
213
+ setIsAltKeyPressed(true);
214
+ }
215
+ };
216
+ const handleKeyUp = (e) => {
217
+ if (!e.altKey) {
218
+ setIsAltKeyPressed(false);
219
+ }
220
+ };
221
+ const handleBlur = () => {
222
+ setIsAltKeyPressed(false);
223
+ };
224
+ window.addEventListener("keydown", handleKeyDown);
225
+ window.addEventListener("keyup", handleKeyUp);
226
+ window.addEventListener("blur", handleBlur);
227
+ return () => {
228
+ window.removeEventListener("keydown", handleKeyDown);
229
+ window.removeEventListener("keyup", handleKeyUp);
230
+ window.removeEventListener("blur", handleBlur);
231
+ };
232
+ }, []);
186
233
  useEffect(() => {
187
234
  const handleMouseMove = (e) => {
188
235
  setCursorPos({ x: e.clientX, y: e.clientY });
@@ -236,17 +283,22 @@ function ElementBadges() {
236
283
  () => BadgeLayoutBuilder.create(badgePositions).minDistance(24).repulsion(50).anchorStrength(0.3).iterations(50).compute(),
237
284
  [badgePositions]
238
285
  );
286
+ const visibleBadges = useMemo(() => {
287
+ return nudgedPositions.filter(
288
+ (pos) => shouldShowBadge(pos.issue, isAltKeyPressed)
289
+ );
290
+ }, [nudgedPositions, isAltKeyPressed]);
239
291
  if (!mounted) return null;
240
292
  if (autoScanState.status === "idle") return null;
241
293
  const content = /* @__PURE__ */ jsxs("div", { "data-ui-lint": true, children: [
242
294
  /* @__PURE__ */ jsx(BadgeAnimationStyles, {}),
243
- nudgedPositions.map((nudgedPos) => {
295
+ visibleBadges.map((nudgedPos) => {
244
296
  const distance = Math.hypot(
245
297
  nudgedPos.nudgedX - cursorPos.x,
246
298
  nudgedPos.nudgedY - cursorPos.y
247
299
  );
248
300
  const nearbyBadges = findNearbyBadges(
249
- nudgedPositions,
301
+ visibleBadges,
250
302
  nudgedPos.nudgedX,
251
303
  nudgedPos.nudgedY,
252
304
  NEARBY_THRESHOLD
@@ -278,6 +330,10 @@ function NudgedBadge({
278
330
  const closeTimeoutRef = React.useRef(null);
279
331
  const { element, issue, rect, nudgedX, nudgedY } = position;
280
332
  const hasNearbyBadges = nearbyBadges.length > 1;
333
+ const snappedPosition = useMemo(
334
+ () => snapToWindowBounds(nudgedX, nudgedY),
335
+ [nudgedX, nudgedY]
336
+ );
281
337
  const badgeColor = useMemo(() => {
282
338
  if (issue.status === "error") return STYLES.error;
283
339
  if (issue.status === "scanning") return STYLES.highlight;
@@ -313,14 +369,14 @@ function NudgedBadge({
313
369
  return nearbyBadges[hoveredIndex] ?? null;
314
370
  }, [hoveredIndex, nearbyBadges]);
315
371
  const dropdownStyle = useMemo(() => {
316
- const preferRight = nudgedX < window.innerWidth - 220;
317
- const preferBelow = nudgedY < window.innerHeight - 200;
372
+ const preferRight = snappedPosition.x < window.innerWidth - 220;
373
+ const preferBelow = snappedPosition.y < window.innerHeight - 200;
318
374
  return {
319
375
  position: "fixed",
320
- top: preferBelow ? nudgedY + 12 : void 0,
321
- bottom: preferBelow ? void 0 : window.innerHeight - nudgedY + 12,
322
- left: preferRight ? nudgedX - 8 : void 0,
323
- right: preferRight ? void 0 : window.innerWidth - nudgedX - 8,
376
+ top: preferBelow ? snappedPosition.y + 12 : void 0,
377
+ bottom: preferBelow ? void 0 : window.innerHeight - snappedPosition.y + 12,
378
+ left: preferRight ? snappedPosition.x - 8 : void 0,
379
+ right: preferRight ? void 0 : window.innerWidth - snappedPosition.x - 8,
324
380
  zIndex: 1e5,
325
381
  backgroundColor: STYLES.bg,
326
382
  borderRadius: "8px",
@@ -330,7 +386,7 @@ function NudgedBadge({
330
386
  minWidth: "200px",
331
387
  fontFamily: STYLES.font
332
388
  };
333
- }, [nudgedX, nudgedY]);
389
+ }, [snappedPosition]);
334
390
  const scale = isExpanded ? 1.1 : getScaleFromDistance(distance);
335
391
  const issueCount = issue.status === "complete" ? issue.issues.length : 0;
336
392
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -375,11 +431,11 @@ function NudgedBadge({
375
431
  {
376
432
  style: {
377
433
  position: "fixed",
378
- top: nudgedY - 9,
379
- left: nudgedX - 9,
434
+ top: snappedPosition.y - 0,
435
+ left: snappedPosition.x - 0,
380
436
  zIndex: isExpanded ? 99999 : 99995,
381
437
  cursor: "pointer",
382
- transition: "transform 0.1s ease-out, top 0.15s ease-out, left 0.15s ease-out",
438
+ transition: "transform 0.1s ease-out",
383
439
  transform: `scale(${scale})`,
384
440
  transformOrigin: "center center"
385
441
  },
@@ -2,8 +2,8 @@
2
2
  "use client";
3
3
  import {
4
4
  InspectionPanel
5
- } from "./chunk-JBBUE3Y5.js";
6
- import "./chunk-MO4NS6EG.js";
5
+ } from "./chunk-ITKEGCAZ.js";
6
+ import "./chunk-DEHJKJNT.js";
7
7
  export {
8
8
  InspectionPanel
9
9
  };
@@ -3,8 +3,8 @@
3
3
  import {
4
4
  InspectedElementHighlight,
5
5
  LocatorOverlay
6
- } from "./chunk-Z6PWYQGW.js";
7
- import "./chunk-MO4NS6EG.js";
6
+ } from "./chunk-LZX53CPI.js";
7
+ import "./chunk-DEHJKJNT.js";
8
8
  export {
9
9
  InspectedElementHighlight,
10
10
  LocatorOverlay
@@ -2,8 +2,8 @@
2
2
  "use client";
3
3
  import {
4
4
  UILintToolbar
5
- } from "./chunk-HTNIKCEM.js";
6
- import "./chunk-MO4NS6EG.js";
5
+ } from "./chunk-EYWLUDXI.js";
6
+ import "./chunk-DEHJKJNT.js";
7
7
  export {
8
8
  UILintToolbar
9
9
  };
@@ -1033,10 +1033,10 @@ function UILintUI() {
1033
1033
  const [components, setComponents] = useState(null);
1034
1034
  useEffect(() => {
1035
1035
  Promise.all([
1036
- import("./UILintToolbar-WNV5RS2L.js"),
1037
- import("./InspectionPanel-JNLWBL4D.js"),
1038
- import("./LocatorOverlay-6SAH7LN2.js"),
1039
- import("./ElementBadges-TBAUB3KM.js")
1036
+ import("./UILintToolbar-TM3DVGPO.js"),
1037
+ import("./InspectionPanel-FY7QVWP5.js"),
1038
+ import("./LocatorOverlay-IUZV5OVI.js"),
1039
+ import("./ElementBadges-BASN6P5L.js")
1040
1040
  ]).then(([toolbar, panel, locator, badges]) => {
1041
1041
  setComponents({
1042
1042
  Toolbar: toolbar.UILintToolbar,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  useUILintContext,
4
4
  useUILintStore
5
- } from "./chunk-MO4NS6EG.js";
5
+ } from "./chunk-DEHJKJNT.js";
6
6
 
7
7
  // src/components/ui-lint/UILintToolbar.tsx
8
8
  import { useState, useRef, useEffect } from "react";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  buildEditorUrl,
4
4
  useUILintContext
5
- } from "./chunk-MO4NS6EG.js";
5
+ } from "./chunk-DEHJKJNT.js";
6
6
 
7
7
  // src/components/ui-lint/InspectionPanel.tsx
8
8
  import { useState, useEffect, useCallback, useMemo } from "react";
@@ -666,26 +666,6 @@ function ScanSection({ element }) {
666
666
  }
667
667
  ),
668
668
  showCachedResult && /* @__PURE__ */ jsxs("div", { children: [
669
- /* @__PURE__ */ jsxs(
670
- "div",
671
- {
672
- style: {
673
- display: "flex",
674
- alignItems: "center",
675
- gap: "8px",
676
- marginBottom: "12px",
677
- padding: "8px 12px",
678
- backgroundColor: "rgba(16, 185, 129, 0.1)",
679
- borderRadius: "6px",
680
- fontSize: "11px",
681
- color: STYLES.success
682
- },
683
- children: [
684
- /* @__PURE__ */ jsx(CheckIconSmall, {}),
685
- "Scan complete"
686
- ]
687
- }
688
- ),
689
669
  eslintIssues.length > 0 && /* @__PURE__ */ jsx(ESLintIssuesSection, { issues: eslintIssues }),
690
670
  eslintIssues.length === 0 && /* @__PURE__ */ jsx(
691
671
  "div",
@@ -831,18 +811,6 @@ function ESLintIssuesSection({ issues }) {
831
811
  )
832
812
  ] });
833
813
  }
834
- function CheckIconSmall() {
835
- return /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
836
- "path",
837
- {
838
- d: "M20 6L9 17l-5-5",
839
- stroke: "currentColor",
840
- strokeWidth: "2",
841
- strokeLinecap: "round",
842
- strokeLinejoin: "round"
843
- }
844
- ) });
845
- }
846
814
  function Section({
847
815
  title,
848
816
  children
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  useUILintContext
4
- } from "./chunk-MO4NS6EG.js";
4
+ } from "./chunk-DEHJKJNT.js";
5
5
 
6
6
  // src/components/ui-lint/LocatorOverlay.tsx
7
7
  import { useState, useEffect, useMemo } from "react";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  UILintToolbar
4
- } from "./chunk-HTNIKCEM.js";
4
+ } from "./chunk-EYWLUDXI.js";
5
5
  import {
6
6
  InspectionPanel,
7
7
  clearSourceCache,
@@ -9,10 +9,10 @@ import {
9
9
  fetchSourceWithContext,
10
10
  getCachedSource,
11
11
  prefetchSources
12
- } from "./chunk-JBBUE3Y5.js";
12
+ } from "./chunk-ITKEGCAZ.js";
13
13
  import {
14
14
  LocatorOverlay
15
- } from "./chunk-Z6PWYQGW.js";
15
+ } from "./chunk-LZX53CPI.js";
16
16
  import {
17
17
  DATA_UILINT_ID,
18
18
  DEFAULT_SETTINGS,
@@ -31,7 +31,7 @@ import {
31
31
  scanDOMForSources,
32
32
  updateElementRects,
33
33
  useUILintContext
34
- } from "./chunk-MO4NS6EG.js";
34
+ } from "./chunk-DEHJKJNT.js";
35
35
 
36
36
  // src/consistency/snapshot.ts
37
37
  var DATA_ELEMENTS_ATTR = "data-elements";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uilint-react",
3
- "version": "0.1.34",
3
+ "version": "0.1.37",
4
4
  "description": "React component for AI-powered UI consistency checking",
5
5
  "author": "Peter Suggate",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "node": ">=20.0.0"
35
35
  },
36
36
  "dependencies": {
37
- "uilint-core": "^0.1.34",
37
+ "uilint-core": "^0.1.37",
38
38
  "zustand": "^5.0.5"
39
39
  },
40
40
  "peerDependencies": {