uilint-react 0.1.19 → 0.1.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uilint-react",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
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.19"
37
+ "uilint-core": "^0.1.21"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "react": "^19.0.0",
@@ -1,9 +0,0 @@
1
- "use client";
2
- "use client";
3
- import {
4
- LocatorOverlay
5
- } from "./chunk-KUFV22FO.js";
6
- import "./chunk-7WYVWDRU.js";
7
- export {
8
- LocatorOverlay
9
- };
@@ -1,9 +0,0 @@
1
- "use client";
2
- "use client";
3
- import {
4
- SourceOverlays
5
- } from "./chunk-MEP7WO7U.js";
6
- import "./chunk-7WYVWDRU.js";
7
- export {
8
- SourceOverlays
9
- };
@@ -1,210 +0,0 @@
1
- "use client";
2
- import {
3
- buildEditorUrl,
4
- useUILintContext
5
- } from "./chunk-7WYVWDRU.js";
6
-
7
- // src/components/ui-lint/SourceOverlays.tsx
8
- import { useState, useEffect, useMemo, useCallback } from "react";
9
- import { createPortal } from "react-dom";
10
- import { jsx, jsxs } from "react/jsx-runtime";
11
- var STYLES = {
12
- font: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
13
- fontMono: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace',
14
- shadow: "0 2px 8px rgba(0, 0, 0, 0.3)"
15
- };
16
- function getLabelPositionStyles(position) {
17
- switch (position) {
18
- case "top-left":
19
- return { top: "-1px", left: "-1px" };
20
- case "top-right":
21
- return { top: "-1px", right: "-1px" };
22
- case "bottom-left":
23
- return { bottom: "-1px", left: "-1px" };
24
- case "bottom-right":
25
- return { bottom: "-1px", right: "-1px" };
26
- }
27
- }
28
- function SourceOverlays() {
29
- const {
30
- sourceFiles,
31
- scannedElements,
32
- settings,
33
- selectedElement,
34
- setSelectedElement,
35
- hoveredElement,
36
- setHoveredElement,
37
- mode
38
- } = useUILintContext();
39
- const [mounted, setMounted] = useState(false);
40
- useEffect(() => {
41
- setMounted(true);
42
- }, []);
43
- const elementToFile = useMemo(() => {
44
- const map = /* @__PURE__ */ new Map();
45
- for (const file of sourceFiles) {
46
- for (const element of file.elements) {
47
- map.set(element.id, file);
48
- }
49
- }
50
- return map;
51
- }, [sourceFiles]);
52
- const handleElementClick = useCallback(
53
- (element) => {
54
- if (mode === "inspect") {
55
- setSelectedElement(
56
- selectedElement?.id === element.id ? null : element
57
- );
58
- }
59
- },
60
- [mode, selectedElement, setSelectedElement]
61
- );
62
- const handleLabelClick = useCallback(
63
- (element, e) => {
64
- e.stopPropagation();
65
- if (element.source) {
66
- const url = buildEditorUrl(element.source, "cursor");
67
- window.open(url, "_blank");
68
- }
69
- },
70
- []
71
- );
72
- if (!mounted) return null;
73
- const content = /* @__PURE__ */ jsxs("div", { "data-ui-lint": true, style: { pointerEvents: "none" }, children: [
74
- /* @__PURE__ */ jsx("style", { children: `
75
- @keyframes uilint-overlay-fade-in {
76
- from { opacity: 0; }
77
- to { opacity: 1; }
78
- }
79
- ` }),
80
- scannedElements.map((element) => {
81
- const file = elementToFile.get(element.id);
82
- if (!file) return null;
83
- const isSelected = selectedElement?.id === element.id;
84
- const isHovered = hoveredElement?.id === element.id;
85
- return /* @__PURE__ */ jsx(
86
- ElementOverlay,
87
- {
88
- element,
89
- file,
90
- settings,
91
- isSelected,
92
- isHovered,
93
- onHover: () => setHoveredElement(element),
94
- onLeave: () => setHoveredElement(null),
95
- onClick: () => handleElementClick(element),
96
- onLabelClick: (e) => handleLabelClick(element, e),
97
- showClickable: mode === "inspect"
98
- },
99
- element.id
100
- );
101
- })
102
- ] });
103
- return createPortal(content, document.body);
104
- }
105
- function ElementOverlay({
106
- element,
107
- file,
108
- settings,
109
- isSelected,
110
- isHovered,
111
- onHover,
112
- onLeave,
113
- onClick,
114
- onLabelClick,
115
- showClickable
116
- }) {
117
- const { rect } = element;
118
- if (rect.width < 20 || rect.height < 20) return null;
119
- if (rect.bottom < 0 || rect.top > window.innerHeight || rect.right < 0 || rect.left > window.innerWidth) {
120
- return null;
121
- }
122
- const borderWidth = isSelected ? 3 : isHovered ? 2 : 1.5;
123
- return /* @__PURE__ */ jsx(
124
- "div",
125
- {
126
- style: {
127
- position: "fixed",
128
- top: rect.top,
129
- left: rect.left,
130
- width: rect.width,
131
- height: rect.height,
132
- border: `${borderWidth}px solid ${file.color}`,
133
- borderRadius: "2px",
134
- pointerEvents: showClickable ? "auto" : "none",
135
- cursor: showClickable ? "pointer" : "default",
136
- zIndex: isSelected ? 99998 : isHovered ? 99997 : 99996,
137
- animation: "uilint-overlay-fade-in 0.15s ease-out",
138
- transition: "border-width 0.15s"
139
- },
140
- onMouseEnter: onHover,
141
- onMouseLeave: onLeave,
142
- onClick,
143
- children: settings.showLabels && /* @__PURE__ */ jsx(
144
- FileLabel,
145
- {
146
- file,
147
- element,
148
- position: settings.labelPosition,
149
- isHovered,
150
- isSelected,
151
- onClick: onLabelClick
152
- }
153
- )
154
- }
155
- );
156
- }
157
- function FileLabel({
158
- file,
159
- element,
160
- position,
161
- isHovered,
162
- isSelected,
163
- onClick
164
- }) {
165
- const [showFullPath, setShowFullPath] = useState(false);
166
- const positionStyles = getLabelPositionStyles(position);
167
- const displayName = file.displayName.length > 20 ? file.displayName.slice(0, 17) + "..." : file.displayName;
168
- return /* @__PURE__ */ jsxs(
169
- "div",
170
- {
171
- style: {
172
- position: "absolute",
173
- ...positionStyles,
174
- display: "flex",
175
- alignItems: "center",
176
- gap: "4px",
177
- padding: "2px 6px",
178
- borderRadius: "3px",
179
- backgroundColor: file.color,
180
- color: "#FFFFFF",
181
- fontSize: "10px",
182
- fontWeight: 600,
183
- fontFamily: STYLES.fontMono,
184
- whiteSpace: "nowrap",
185
- pointerEvents: "auto",
186
- cursor: "pointer",
187
- boxShadow: STYLES.shadow,
188
- transition: "transform 0.1s, padding 0.1s",
189
- transform: isHovered || isSelected ? "scale(1.05)" : "scale(1)",
190
- zIndex: 99999
191
- },
192
- onMouseEnter: () => setShowFullPath(true),
193
- onMouseLeave: () => setShowFullPath(false),
194
- onClick,
195
- title: `${file.path}:${element.source?.lineNumber || "?"}
196
- Click to open in editor`,
197
- children: [
198
- /* @__PURE__ */ jsx("span", { children: displayName }),
199
- element.source?.lineNumber && /* @__PURE__ */ jsxs("span", { style: { opacity: 0.8, fontSize: "9px" }, children: [
200
- ":",
201
- element.source.lineNumber
202
- ] })
203
- ]
204
- }
205
- );
206
- }
207
-
208
- export {
209
- SourceOverlays
210
- };