uilint-react 0.1.6 → 0.1.8
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 +210 -0
- package/package.json +14 -3
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# uilint-react
|
|
2
|
+
|
|
3
|
+
React component for AI-powered UI consistency checking in running applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`uilint-react` provides React components and utilities for analyzing UI consistency at runtime and in tests. It includes a visual overlay for development and a JSDOM adapter for testing.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install uilint-react uilint-core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage in a Running App
|
|
16
|
+
|
|
17
|
+
Wrap your app with the `<UILint>` component to get a visual overlay:
|
|
18
|
+
|
|
19
|
+
### Next.js Setup
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
// app/layout.tsx
|
|
23
|
+
import { UILint } from "uilint-react";
|
|
24
|
+
|
|
25
|
+
export default function RootLayout({ children }) {
|
|
26
|
+
return (
|
|
27
|
+
<html>
|
|
28
|
+
<body>
|
|
29
|
+
<UILint
|
|
30
|
+
enabled={process.env.NODE_ENV !== "production"}
|
|
31
|
+
position="bottom-left"
|
|
32
|
+
autoScan={false}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</UILint>
|
|
36
|
+
</body>
|
|
37
|
+
</html>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Props
|
|
43
|
+
|
|
44
|
+
| Prop | Type | Default | Description |
|
|
45
|
+
| ------------- | -------------------------------------------------------------- | ----------------------- | ------------------------------- |
|
|
46
|
+
| `enabled` | `boolean` | `true` | Enable/disable UILint |
|
|
47
|
+
| `position` | `'bottom-left' \| 'bottom-right' \| 'top-left' \| 'top-right'` | `'bottom-left'` | Overlay position |
|
|
48
|
+
| `autoScan` | `boolean` | `false` | Automatically scan on page load |
|
|
49
|
+
| `apiEndpoint` | `string` | `'/api/uilint/analyze'` | Custom API endpoint |
|
|
50
|
+
|
|
51
|
+
### API Routes
|
|
52
|
+
|
|
53
|
+
You'll need to add API routes for the React component:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
// app/api/uilint/analyze/route.ts
|
|
57
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
58
|
+
import { OllamaClient } from "uilint-core";
|
|
59
|
+
|
|
60
|
+
export async function POST(request: NextRequest) {
|
|
61
|
+
const { styleSummary, styleGuide, generateGuide, model } =
|
|
62
|
+
await request.json();
|
|
63
|
+
const client = new OllamaClient({ model: model || "qwen2.5-coder:7b" });
|
|
64
|
+
|
|
65
|
+
if (generateGuide) {
|
|
66
|
+
const styleGuideContent = await client.generateStyleGuide(styleSummary);
|
|
67
|
+
return NextResponse.json({ styleGuide: styleGuideContent });
|
|
68
|
+
} else {
|
|
69
|
+
const result = await client.analyzeStyles(styleSummary, styleGuide);
|
|
70
|
+
return NextResponse.json({ issues: result.issues });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// app/api/uilint/styleguide/route.ts
|
|
77
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
78
|
+
import {
|
|
79
|
+
readStyleGuideFromProject,
|
|
80
|
+
writeStyleGuide,
|
|
81
|
+
styleGuideExists,
|
|
82
|
+
getDefaultStyleGuidePath,
|
|
83
|
+
} from "uilint-core/node";
|
|
84
|
+
|
|
85
|
+
export async function GET() {
|
|
86
|
+
const projectPath = process.cwd();
|
|
87
|
+
if (!styleGuideExists(projectPath)) {
|
|
88
|
+
return NextResponse.json({ exists: false, content: null });
|
|
89
|
+
}
|
|
90
|
+
const content = await readStyleGuideFromProject(projectPath);
|
|
91
|
+
return NextResponse.json({ exists: true, content });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function POST(request: NextRequest) {
|
|
95
|
+
const { content } = await request.json();
|
|
96
|
+
const projectPath = process.cwd();
|
|
97
|
+
const stylePath = getDefaultStyleGuidePath(projectPath);
|
|
98
|
+
await writeStyleGuide(stylePath, content);
|
|
99
|
+
return NextResponse.json({ success: true });
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Usage in Tests
|
|
104
|
+
|
|
105
|
+
UILint can run in Vitest/Jest tests with JSDOM:
|
|
106
|
+
|
|
107
|
+
### Basic Test
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { render, screen } from "@testing-library/react";
|
|
111
|
+
import { UILint } from "uilint-react";
|
|
112
|
+
import { MyComponent } from "./MyComponent";
|
|
113
|
+
|
|
114
|
+
test("MyComponent has consistent styles", async () => {
|
|
115
|
+
render(
|
|
116
|
+
<UILint enabled={true}>
|
|
117
|
+
<MyComponent />
|
|
118
|
+
</UILint>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(screen.getByRole("button")).toBeInTheDocument();
|
|
122
|
+
|
|
123
|
+
// UILint automatically outputs warnings to console:
|
|
124
|
+
// ⚠️ [UILint] Button uses #3B82F6 but style guide specifies #2563EB
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Direct JSDOM Adapter
|
|
129
|
+
|
|
130
|
+
For more control, use the `JSDOMAdapter`:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { JSDOMAdapter, runUILintInTest } from "uilint-react";
|
|
134
|
+
import { render } from "@testing-library/react";
|
|
135
|
+
|
|
136
|
+
test("detect style inconsistencies", async () => {
|
|
137
|
+
render(<MyComponent />);
|
|
138
|
+
|
|
139
|
+
// Run UILint and get issues
|
|
140
|
+
const issues = await runUILintInTest(document.body);
|
|
141
|
+
|
|
142
|
+
// Assert on specific issues
|
|
143
|
+
expect(issues).toHaveLength(0); // Fail if any issues found
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("custom adapter usage", async () => {
|
|
147
|
+
render(<MyComponent />);
|
|
148
|
+
|
|
149
|
+
const adapter = new JSDOMAdapter(".uilint/styleguide.md");
|
|
150
|
+
await adapter.loadStyleGuide();
|
|
151
|
+
|
|
152
|
+
const result = await adapter.analyze(document.body);
|
|
153
|
+
adapter.outputWarnings(result.issues);
|
|
154
|
+
|
|
155
|
+
expect(result.issues.filter((i) => i.type === "color")).toHaveLength(0);
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## API
|
|
160
|
+
|
|
161
|
+
### UILint Component
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
interface UILintProps {
|
|
165
|
+
enabled?: boolean;
|
|
166
|
+
position?: "bottom-left" | "bottom-right" | "top-left" | "top-right";
|
|
167
|
+
autoScan?: boolean;
|
|
168
|
+
apiEndpoint?: string;
|
|
169
|
+
children: React.ReactNode;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function UILint(props: UILintProps): JSX.Element;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### JSDOM Adapter
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
class JSDOMAdapter {
|
|
179
|
+
constructor(styleGuidePath?: string);
|
|
180
|
+
|
|
181
|
+
loadStyleGuide(): Promise<void>;
|
|
182
|
+
analyze(element: Element): Promise<{ issues: Issue[] }>;
|
|
183
|
+
outputWarnings(issues: Issue[]): void;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function runUILintInTest(element: Element): Promise<Issue[]>;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Prerequisites
|
|
190
|
+
|
|
191
|
+
For LLM-powered features, you need [Ollama](https://ollama.ai) installed locally:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Install Ollama, then pull the default model
|
|
195
|
+
ollama pull qwen2.5-coder:7b
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Related Packages
|
|
199
|
+
|
|
200
|
+
- [`uilint-core`](https://www.npmjs.com/package/uilint-core) - Core library
|
|
201
|
+
- [`uilint-cli`](https://www.npmjs.com/package/uilint-cli) - Command-line interface
|
|
202
|
+
- [`uilint-mcp`](https://www.npmjs.com/package/uilint-mcp) - MCP server
|
|
203
|
+
|
|
204
|
+
## Documentation
|
|
205
|
+
|
|
206
|
+
For full documentation, visit the [UILint GitHub repository](https://github.com/peter-suggate/uilint).
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uilint-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "React component for AI-powered UI consistency checking",
|
|
5
|
+
"author": "Peter Suggate",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/peter-suggate/uilint.git",
|
|
9
|
+
"directory": "packages/uilint-react"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/peter-suggate/uilint#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/peter-suggate/uilint/issues"
|
|
14
|
+
},
|
|
5
15
|
"type": "module",
|
|
6
16
|
"main": "./dist/index.js",
|
|
7
17
|
"module": "./dist/index.js",
|
|
@@ -17,13 +27,14 @@
|
|
|
17
27
|
}
|
|
18
28
|
},
|
|
19
29
|
"files": [
|
|
20
|
-
"dist"
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md"
|
|
21
32
|
],
|
|
22
33
|
"engines": {
|
|
23
34
|
"node": ">=20.0.0"
|
|
24
35
|
},
|
|
25
36
|
"dependencies": {
|
|
26
|
-
"uilint-core": "^0.1.
|
|
37
|
+
"uilint-core": "^0.1.8"
|
|
27
38
|
},
|
|
28
39
|
"peerDependencies": {
|
|
29
40
|
"react": "^19.0.0",
|