uilint-react 0.1.48 → 0.1.50

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.
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  useUILintContext,
5
5
  useUILintStore
6
- } from "./chunk-C4QQXZFH.js";
6
+ } from "./chunk-TLHXCIXS.js";
7
7
 
8
8
  // src/components/ui-lint/ElementBadges.tsx
9
9
  import React, { useState, useEffect, useCallback, useMemo } from "react";
@@ -130,12 +130,55 @@ function findNearbyBadges(positions, x, y, threshold) {
130
130
  }
131
131
 
132
132
  // src/components/ui-lint/visibility-utils.ts
133
+ function rectFromLTRB(left, top, right, bottom) {
134
+ const width = Math.max(0, right - left);
135
+ const height = Math.max(0, bottom - top);
136
+ return { left, top, right, bottom, width, height };
137
+ }
138
+ function intersectRects(a, b) {
139
+ const left = Math.max(a.left, b.left);
140
+ const top = Math.max(a.top, b.top);
141
+ const right = Math.min(a.right, b.right);
142
+ const bottom = Math.min(a.bottom, b.bottom);
143
+ if (right <= left || bottom <= top) return null;
144
+ return rectFromLTRB(left, top, right, bottom);
145
+ }
146
+ function isOverflowClipping(style) {
147
+ const vals = [style.overflow, style.overflowX, style.overflowY];
148
+ return vals.some((v) => v && v !== "visible");
149
+ }
150
+ function getElementVisibleRect(element) {
151
+ const el = element;
152
+ const base = el.getBoundingClientRect();
153
+ let visible = rectFromLTRB(
154
+ base.left,
155
+ base.top,
156
+ base.right,
157
+ base.bottom
158
+ );
159
+ const viewport = rectFromLTRB(0, 0, window.innerWidth, window.innerHeight);
160
+ visible = intersectRects(visible, viewport);
161
+ if (!visible) return null;
162
+ let cur = el.parentElement;
163
+ while (cur) {
164
+ const style = window.getComputedStyle(cur);
165
+ if (isOverflowClipping(style)) {
166
+ const r = cur.getBoundingClientRect();
167
+ const clip = rectFromLTRB(r.left, r.top, r.right, r.bottom);
168
+ visible = intersectRects(visible, clip);
169
+ if (!visible) return null;
170
+ }
171
+ cur = cur.parentElement;
172
+ }
173
+ return visible;
174
+ }
133
175
  function isElementCoveredByOverlay(element, badgeX, badgeY) {
134
176
  const elementsAtPoint = document.elementsFromPoint(badgeX, badgeY);
135
177
  for (const el of elementsAtPoint) {
136
178
  if (el.hasAttribute("data-ui-lint")) continue;
137
- if (el === element || element.contains(el)) continue;
138
- if (el.contains(element)) continue;
179
+ if (el === element || element.contains(el) || el.contains(element)) {
180
+ return false;
181
+ }
139
182
  const style = window.getComputedStyle(el);
140
183
  const position = style.position;
141
184
  const zIndex = parseInt(style.zIndex, 10);
@@ -270,14 +313,24 @@ function ElementBadges() {
270
313
  if (!issue) continue;
271
314
  if (!element.element || !document.contains(element.element)) continue;
272
315
  const rect = element.element.getBoundingClientRect();
273
- const x = rect.right - 8;
274
- const y = rect.top - 8;
275
- if (rect.top < -50 || rect.top > window.innerHeight + 50) continue;
276
- if (rect.left < -50 || rect.left > window.innerWidth + 50) continue;
277
- if (isElementCoveredByOverlay(element.element, x, y)) {
316
+ const visible = getElementVisibleRect(element.element);
317
+ if (!visible) continue;
318
+ const desiredX = rect.right - 8;
319
+ const desiredY = rect.top - 8;
320
+ const x = Math.min(desiredX, visible.right - 8);
321
+ const y = Math.max(visible.top + 2, desiredY);
322
+ const testX = visible.left + Math.min(8, visible.width / 2);
323
+ const testY = visible.top + Math.min(8, visible.height / 2);
324
+ if (isElementCoveredByOverlay(element.element, testX, testY)) {
278
325
  continue;
279
326
  }
280
- positions.push({ element, issue, x, y, rect });
327
+ const visibleRect = DOMRect.fromRect({
328
+ x: visible.left,
329
+ y: visible.top,
330
+ width: visible.width,
331
+ height: visible.height
332
+ });
333
+ positions.push({ element, issue, x, y, rect: visibleRect });
281
334
  }
282
335
  setBadgePositions(positions);
283
336
  };
@@ -350,6 +403,9 @@ function ElementBadges() {
350
403
  {
351
404
  "data-ui-lint": true,
352
405
  onMouseDown: handleUILintInteraction,
406
+ onPointerDown: handleUILintInteraction,
407
+ onPointerUp: handleUILintInteraction,
408
+ onTouchStart: handleUILintInteraction,
353
409
  onClick: handleUILintInteraction,
354
410
  onKeyDown: handleUILintInteraction,
355
411
  style: { pointerEvents: "none" },
@@ -432,6 +488,9 @@ function NudgedBadge({
432
488
  },
433
489
  [element, issue, onSelect]
434
490
  );
491
+ const handlePointerDown = useCallback((e) => {
492
+ e.stopPropagation();
493
+ }, []);
435
494
  const hoveredBadge = useMemo(() => {
436
495
  if (hoveredIndex === null) return null;
437
496
  return nearbyBadges[hoveredIndex] ?? null;
@@ -514,6 +573,7 @@ function NudgedBadge({
514
573
  "data-ui-lint": true,
515
574
  onMouseEnter: handleMouseEnter,
516
575
  onMouseLeave: handleMouseLeave,
576
+ onPointerDown: handlePointerDown,
517
577
  onClick: handleClick,
518
578
  children: /* @__PURE__ */ jsx(
519
579
  "div",
@@ -2,9 +2,9 @@
2
2
  "use client";
3
3
  import {
4
4
  InspectionPanel
5
- } from "./chunk-B7DZUX7G.js";
5
+ } from "./chunk-NOYDJR7R.js";
6
6
  import "./chunk-S4IWHBOQ.js";
7
- import "./chunk-C4QQXZFH.js";
7
+ import "./chunk-TLHXCIXS.js";
8
8
  export {
9
9
  InspectionPanel
10
10
  };
@@ -3,8 +3,8 @@
3
3
  import {
4
4
  InspectedElementHighlight,
5
5
  LocatorOverlay
6
- } from "./chunk-VKLP23BP.js";
7
- import "./chunk-C4QQXZFH.js";
6
+ } from "./chunk-TQTSKK5G.js";
7
+ import "./chunk-TLHXCIXS.js";
8
8
  export {
9
9
  InspectedElementHighlight,
10
10
  LocatorOverlay
@@ -2,9 +2,9 @@
2
2
  "use client";
3
3
  import {
4
4
  UILintToolbar
5
- } from "./chunk-FLUATYJF.js";
5
+ } from "./chunk-ZNBNHYJX.js";
6
6
  import "./chunk-S4IWHBOQ.js";
7
- import "./chunk-C4QQXZFH.js";
7
+ import "./chunk-TLHXCIXS.js";
8
8
  export {
9
9
  UILintToolbar
10
10
  };
@@ -7,7 +7,7 @@ import {
7
7
  buildEditorUrl,
8
8
  useUILintContext,
9
9
  useUILintStore
10
- } from "./chunk-C4QQXZFH.js";
10
+ } from "./chunk-TLHXCIXS.js";
11
11
 
12
12
  // src/components/ui-lint/InspectionPanel.tsx
13
13
  import React, {
@@ -362,6 +362,9 @@ function InspectionPanel() {
362
362
  ref: popoverRef,
363
363
  "data-ui-lint": true,
364
364
  onMouseDown: handleUILintInteraction,
365
+ onPointerDown: handleUILintInteraction,
366
+ onPointerUp: handleUILintInteraction,
367
+ onTouchStart: handleUILintInteraction,
365
368
  onClick: handleUILintInteraction,
366
369
  onKeyDown: handleUILintInteraction,
367
370
  style: {
@@ -1063,10 +1063,10 @@ function UILintUI() {
1063
1063
  const [components, setComponents] = useState(null);
1064
1064
  useEffect2(() => {
1065
1065
  Promise.all([
1066
- import("./UILintToolbar-ZBHPX3LA.js"),
1067
- import("./InspectionPanel-PHCAOOL3.js"),
1068
- import("./LocatorOverlay-ZGBYXTXG.js"),
1069
- import("./ElementBadges-TSHIYUHQ.js")
1066
+ import("./UILintToolbar-TXSF3YZF.js"),
1067
+ import("./InspectionPanel-OCCB5KUE.js"),
1068
+ import("./LocatorOverlay-VACYO52F.js"),
1069
+ import("./ElementBadges-ISBIBC3T.js")
1070
1070
  ]).then(([toolbar, panel, locator, badges]) => {
1071
1071
  setComponents({
1072
1072
  Toolbar: toolbar.UILintToolbar,
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  useUILintContext
4
- } from "./chunk-C4QQXZFH.js";
4
+ } from "./chunk-TLHXCIXS.js";
5
5
 
6
6
  // src/components/ui-lint/LocatorOverlay.tsx
7
7
  import { useState, useEffect, useMemo } from "react";
@@ -97,6 +97,10 @@ function InfoTooltip({ rect, source, componentName }) {
97
97
  return /* @__PURE__ */ jsxs(
98
98
  "div",
99
99
  {
100
+ "data-ui-lint": true,
101
+ onPointerDown: (e) => e.stopPropagation(),
102
+ onPointerUp: (e) => e.stopPropagation(),
103
+ onTouchStart: (e) => e.stopPropagation(),
100
104
  style: {
101
105
  ...tooltipStyle,
102
106
  display: "flex",
@@ -9,7 +9,7 @@ import {
9
9
  groupBySourceFile,
10
10
  useUILintContext,
11
11
  useUILintStore
12
- } from "./chunk-C4QQXZFH.js";
12
+ } from "./chunk-TLHXCIXS.js";
13
13
 
14
14
  // src/components/ui-lint/UILintToolbar.tsx
15
15
  import React3, { useState as useState2, useRef as useRef2, useEffect as useEffect3, useCallback as useCallback2 } from "react";
@@ -1101,6 +1101,9 @@ function ScanPanelStack({ show, onClose }) {
1101
1101
  ref: containerRef,
1102
1102
  "data-ui-lint": true,
1103
1103
  onMouseDown: handleUILintInteraction,
1104
+ onPointerDown: handleUILintInteraction,
1105
+ onPointerUp: handleUILintInteraction,
1106
+ onTouchStart: handleUILintInteraction,
1104
1107
  onClick: handleUILintInteraction,
1105
1108
  onKeyDown: handleUILintInteraction,
1106
1109
  style: {
@@ -1672,13 +1675,7 @@ function UILintToolbar() {
1672
1675
  const totalIssues = elementIssues + fileLevelIssues;
1673
1676
  useEffect3(() => {
1674
1677
  const checkForNextOverlay = () => {
1675
- const overlaySelectors = [
1676
- "nextjs-portal",
1677
- "[data-nextjs-dialog]",
1678
- "[data-nextjs-dialog-overlay]",
1679
- "#__next-build-watcher",
1680
- "[data-nextjs-toast]"
1681
- ];
1678
+ const overlaySelectors = ["data-next-badge-root"];
1682
1679
  const hasOverlay = overlaySelectors.some((selector) => {
1683
1680
  const el = document.querySelector(selector);
1684
1681
  if (!el) return false;
@@ -1795,6 +1792,9 @@ function UILintToolbar() {
1795
1792
  {
1796
1793
  "data-ui-lint": true,
1797
1794
  onMouseDown: handleUILintInteraction,
1795
+ onPointerDown: handleUILintInteraction,
1796
+ onPointerUp: handleUILintInteraction,
1797
+ onTouchStart: handleUILintInteraction,
1798
1798
  onClick: handleUILintInteraction,
1799
1799
  onKeyDown: handleUILintInteraction,
1800
1800
  style: {
@@ -1814,6 +1814,12 @@ function UILintToolbar() {
1814
1814
  ref: toolbarRef,
1815
1815
  role: "toolbar",
1816
1816
  "aria-label": "UI Lint toolbar",
1817
+ onMouseDown: handleUILintInteraction,
1818
+ onPointerDown: handleUILintInteraction,
1819
+ onPointerUp: handleUILintInteraction,
1820
+ onTouchStart: handleUILintInteraction,
1821
+ onClick: handleUILintInteraction,
1822
+ onKeyDown: handleUILintInteraction,
1817
1823
  style: { pointerEvents: "auto" },
1818
1824
  children: renderToolbar()
1819
1825
  }
@@ -1823,6 +1829,12 @@ function UILintToolbar() {
1823
1829
  {
1824
1830
  ref: settingsRef,
1825
1831
  className: `uilint-popover ${settingsClosing ? "uilint-popover--closing" : ""}`,
1832
+ onMouseDown: handleUILintInteraction,
1833
+ onPointerDown: handleUILintInteraction,
1834
+ onPointerUp: handleUILintInteraction,
1835
+ onTouchStart: handleUILintInteraction,
1836
+ onClick: handleUILintInteraction,
1837
+ onKeyDown: handleUILintInteraction,
1826
1838
  style: {
1827
1839
  position: "absolute",
1828
1840
  bottom: "100%",
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import {
3
3
  UILintToolbar
4
- } from "./chunk-FLUATYJF.js";
4
+ } from "./chunk-ZNBNHYJX.js";
5
5
  import {
6
6
  InspectionPanel
7
- } from "./chunk-B7DZUX7G.js";
7
+ } from "./chunk-NOYDJR7R.js";
8
8
  import {
9
9
  clearSourceCache,
10
10
  fetchSource,
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-S4IWHBOQ.js";
15
15
  import {
16
16
  LocatorOverlay
17
- } from "./chunk-VKLP23BP.js";
17
+ } from "./chunk-TQTSKK5G.js";
18
18
  import {
19
19
  DATA_UILINT_ID,
20
20
  DEFAULT_SETTINGS,
@@ -30,7 +30,7 @@ import {
30
30
  scanDOMForSources,
31
31
  updateElementRects,
32
32
  useUILintContext
33
- } from "./chunk-C4QQXZFH.js";
33
+ } from "./chunk-TLHXCIXS.js";
34
34
 
35
35
  // src/consistency/snapshot.ts
36
36
  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.48",
3
+ "version": "0.1.50",
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.48",
37
+ "uilint-core": "^0.1.50",
38
38
  "zustand": "^5.0.5"
39
39
  },
40
40
  "peerDependencies": {