@lucasvu/scope-ui 0.0.2 → 0.0.3
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/AI_SETUP.md +101 -0
- package/README.md +11 -2
- package/bin/scope-ui-init.mjs +147 -0
- package/package.json +8 -2
package/AI_SETUP.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# AI Setup
|
|
2
|
+
|
|
3
|
+
Mục tiêu của file này là để AI của project dùng `@lucasvu/scope-ui` đúng cách, không import lung tung, không hardcode màu sai chỗ và không chọn nhầm component.
|
|
4
|
+
|
|
5
|
+
Nếu project consumer đã cài package, cách nhanh nhất là chạy:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx scope-ui-init
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
CLI này sẽ tạo `AGENTS.md` và `src/styles/ui-theme.css` theo đúng convention bên dưới.
|
|
12
|
+
|
|
13
|
+
## 1. Import style đúng thứ tự
|
|
14
|
+
|
|
15
|
+
Import package CSS trước, rồi mới import file override theme của project.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import '@lucasvu/scope-ui/styles.css'
|
|
19
|
+
import './styles/ui-theme.css'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`ui-theme.css` nên là nơi duy nhất override màu, surface, border, shadow và gradient của thư viện.
|
|
23
|
+
|
|
24
|
+
## 2. Tạo file theme của project
|
|
25
|
+
|
|
26
|
+
Đặt file tại `src/styles/ui-theme.css`.
|
|
27
|
+
|
|
28
|
+
```css
|
|
29
|
+
:root {
|
|
30
|
+
--tw-primary: 12 88% 56%;
|
|
31
|
+
--tw-accent: 24 95% 52%;
|
|
32
|
+
--primary-grad-from: 24 95% 52%;
|
|
33
|
+
--primary-grad-to: 12 88% 56%;
|
|
34
|
+
--surface: rgba(255, 248, 240, 0.92);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.dark {
|
|
38
|
+
--tw-primary: 18 100% 62%;
|
|
39
|
+
--tw-accent: 35 100% 58%;
|
|
40
|
+
--surface: rgba(24, 24, 27, 0.82);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Không nên override màu trực tiếp trong từng component nếu chỉ đang đổi theme.
|
|
45
|
+
|
|
46
|
+
## 3. Rule cho AI của project
|
|
47
|
+
|
|
48
|
+
Copy phần này vào system prompt, repo instructions, `AGENTS.md`, Cursor rules, hoặc bất kỳ chỗ nào project đang dùng để ép AI theo convention:
|
|
49
|
+
|
|
50
|
+
```md
|
|
51
|
+
Use `@lucasvu/scope-ui` as the default UI library.
|
|
52
|
+
|
|
53
|
+
Always:
|
|
54
|
+
- import `@lucasvu/scope-ui/styles.css` once at the app entry
|
|
55
|
+
- import the project theme override file after the package stylesheet
|
|
56
|
+
- use root exports from `@lucasvu/scope-ui`
|
|
57
|
+
- read `uiAiManifest` to choose the right component by intent
|
|
58
|
+
- read `uiThemeContract` before changing colors, surfaces, borders, or shadows
|
|
59
|
+
|
|
60
|
+
Do not:
|
|
61
|
+
- import from `MainFe` unless the task explicitly targets a legacy screen
|
|
62
|
+
- hardcode brand colors inside page components when a theme token already exists
|
|
63
|
+
- create duplicate Button/Input/Select wrappers unless a project-specific behavior is required
|
|
64
|
+
|
|
65
|
+
Component choice:
|
|
66
|
+
- `Input` for short text
|
|
67
|
+
- `Textarea` for multiline text
|
|
68
|
+
- `Select` for small fixed options
|
|
69
|
+
- `SearchableSelect` for larger local option sets
|
|
70
|
+
- `Combobox` for type-and-pick
|
|
71
|
+
- `AsyncCombobox` for remote search
|
|
72
|
+
- `MultiSelect` for multi-pick
|
|
73
|
+
- `Field` only for custom controls or grouped content
|
|
74
|
+
- `DataTable` for tabular records
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 4. Runtime contract cho AI/codegen
|
|
78
|
+
|
|
79
|
+
Trong code, AI có thể đọc trực tiếp:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { uiAiManifest, uiThemeContract, uiProjectAiRules } from '@lucasvu/scope-ui'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- `uiAiManifest`: chọn component theo intent
|
|
86
|
+
- `uiThemeContract`: biết override token nào và override ở đâu
|
|
87
|
+
- `uiProjectAiRules`: rule ngắn gọn để inject vào agent của project
|
|
88
|
+
|
|
89
|
+
## 5. Chỗ override theme
|
|
90
|
+
|
|
91
|
+
Nếu project có app shell:
|
|
92
|
+
|
|
93
|
+
- import `@lucasvu/scope-ui/styles.css` ở app entry
|
|
94
|
+
- import `src/styles/ui-theme.css` ngay sau đó
|
|
95
|
+
- toggle dark mode bằng class `.dark` trên `html` hoặc `body`, hoặc dùng `[data-ui-theme='dark']`
|
|
96
|
+
|
|
97
|
+
Nếu project có nhiều brand/theme:
|
|
98
|
+
|
|
99
|
+
- giữ `:root` là theme mặc định
|
|
100
|
+
- tạo selector như `[data-ui-theme='brand-a']`, `[data-ui-theme='brand-b']`
|
|
101
|
+
- chỉ override token trong file theme, không fork component
|
package/README.md
CHANGED
|
@@ -43,7 +43,15 @@ npm install @lucasvu/scope-ui
|
|
|
43
43
|
import '@lucasvu/scope-ui/styles.css'
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
3)
|
|
46
|
+
3) Nếu muốn bootstrap rule/theme cho AI trong project consumer:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx scope-ui-init
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Lệnh này sẽ tạo `AGENTS.md` và `src/styles/ui-theme.css` trong repo hiện tại. Dùng `--force` nếu muốn overwrite file đã tồn tại.
|
|
53
|
+
|
|
54
|
+
4) Dùng component:
|
|
47
55
|
|
|
48
56
|
```tsx
|
|
49
57
|
import {
|
|
@@ -120,6 +128,7 @@ Nếu muốn AI render UI đúng và ổn định theo thư viện này, đừng
|
|
|
120
128
|
|
|
121
129
|
- Import CSS global một lần: `@lucasvu/scope-ui/styles.css`
|
|
122
130
|
- Import file theme override của project ngay sau package CSS, ví dụ `./styles/ui-theme.css`
|
|
131
|
+
- Chạy `npx scope-ui-init` ở project consumer để tạo `AGENTS.md` và `src/styles/ui-theme.css`
|
|
123
132
|
- Chỉ dùng các component canonical ở root package; tránh `MainFe` nếu không phải legacy screen
|
|
124
133
|
- Cho agent đọc `uiAiManifest` để biết component nào dùng cho intent nào, props quan trọng là gì, và khi nào không nên dùng
|
|
125
134
|
- Cho agent đọc `uiThemeContract` để biết màu/token phải override ở đâu
|
|
@@ -132,7 +141,7 @@ import { uiAiManifest, uiProjectAiRules, uiThemeContract } from '@lucasvu/scope-
|
|
|
132
141
|
|
|
133
142
|
`uiThemeContract` mô tả token màu, surface, border, shadow, gradient và selector theme (`:root`, `.dark`, `[data-ui-theme='*']`) để AI không hardcode màu sai chỗ.
|
|
134
143
|
|
|
135
|
-
`AI_SETUP.md`
|
|
144
|
+
`AI_SETUP.md` và CLI `scope-ui-init` giúp bootstrap rule/theme cho repo consumer mà không cần copy tay.
|
|
136
145
|
|
|
137
146
|
## Theme Override
|
|
138
147
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { dirname, resolve } from 'node:path'
|
|
5
|
+
import process from 'node:process'
|
|
6
|
+
|
|
7
|
+
const PACKAGE_NAME = '@lucasvu/scope-ui'
|
|
8
|
+
|
|
9
|
+
function parseArgs(argv) {
|
|
10
|
+
const args = {
|
|
11
|
+
force: false,
|
|
12
|
+
agentsFile: 'AGENTS.md',
|
|
13
|
+
themeFile: 'src/styles/ui-theme.css',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
17
|
+
const arg = argv[index]
|
|
18
|
+
if (arg === '--force') {
|
|
19
|
+
args.force = true
|
|
20
|
+
continue
|
|
21
|
+
}
|
|
22
|
+
if (arg === '--agents-file') {
|
|
23
|
+
args.agentsFile = argv[index + 1] ?? args.agentsFile
|
|
24
|
+
index += 1
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
27
|
+
if (arg === '--theme-file') {
|
|
28
|
+
args.themeFile = argv[index + 1] ?? args.themeFile
|
|
29
|
+
index += 1
|
|
30
|
+
continue
|
|
31
|
+
}
|
|
32
|
+
if (arg === '--help' || arg === '-h') {
|
|
33
|
+
printHelp()
|
|
34
|
+
process.exit(0)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return args
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function printHelp() {
|
|
42
|
+
console.log(`scope-ui-init
|
|
43
|
+
|
|
44
|
+
Create bootstrap files for using ${PACKAGE_NAME} with AI/codegen.
|
|
45
|
+
|
|
46
|
+
Usage:
|
|
47
|
+
npx scope-ui-init
|
|
48
|
+
npx scope-ui-init --force
|
|
49
|
+
npx scope-ui-init --agents-file AGENTS.md --theme-file src/styles/ui-theme.css
|
|
50
|
+
|
|
51
|
+
Options:
|
|
52
|
+
--force overwrite existing files
|
|
53
|
+
--agents-file target path for the generated AGENTS.md file
|
|
54
|
+
--theme-file target path for the generated theme override file
|
|
55
|
+
--help, -h show this help
|
|
56
|
+
`)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function createAgentsTemplate({ themeFile }) {
|
|
60
|
+
return `# Agent Rules
|
|
61
|
+
|
|
62
|
+
This repo uses \`${PACKAGE_NAME}\` as the default UI library.
|
|
63
|
+
|
|
64
|
+
Primary references:
|
|
65
|
+
- \`node_modules/${PACKAGE_NAME}/README.md\`
|
|
66
|
+
- \`node_modules/${PACKAGE_NAME}/AI_SETUP.md\`
|
|
67
|
+
- \`${themeFile}\`
|
|
68
|
+
|
|
69
|
+
Always:
|
|
70
|
+
- import \`${PACKAGE_NAME}/styles.css\` once at the app entry
|
|
71
|
+
- import the project theme override file after the package stylesheet
|
|
72
|
+
- use root exports from \`${PACKAGE_NAME}\`
|
|
73
|
+
- read \`uiAiManifest\` before choosing components
|
|
74
|
+
- read \`uiThemeContract\` before changing colors, surfaces, borders, or shadows
|
|
75
|
+
- keep UI token-driven and theme-driven
|
|
76
|
+
|
|
77
|
+
Do not:
|
|
78
|
+
- import from \`MainFe\` unless the task explicitly targets a legacy screen
|
|
79
|
+
- hardcode brand colors inside page components when a theme token already exists
|
|
80
|
+
- create duplicate Button/Input/Select wrappers unless a project-specific behavior is required
|
|
81
|
+
|
|
82
|
+
Component choice:
|
|
83
|
+
- \`Input\` for short text
|
|
84
|
+
- \`Textarea\` for multiline text
|
|
85
|
+
- \`Select\` for small fixed options
|
|
86
|
+
- \`SearchableSelect\` for larger local option sets
|
|
87
|
+
- \`Combobox\` for type-and-pick
|
|
88
|
+
- \`AsyncCombobox\` for remote search
|
|
89
|
+
- \`MultiSelect\` for multi-pick
|
|
90
|
+
- \`Field\` only for custom controls or grouped content
|
|
91
|
+
- \`DataTable\` for tabular records
|
|
92
|
+
`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function createThemeTemplate() {
|
|
96
|
+
return `:root {
|
|
97
|
+
/* Override only the tokens you need for the project brand. */
|
|
98
|
+
/* --tw-primary: 221.2 83.2% 53.3%; */
|
|
99
|
+
/* --tw-accent: 199 89% 48%; */
|
|
100
|
+
/* --primary-grad-from: 199 89% 48%; */
|
|
101
|
+
/* --primary-grad-to: 221.2 83.2% 53.3%; */
|
|
102
|
+
/* --surface: rgba(255, 255, 255, 0.92); */
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.dark {
|
|
106
|
+
/* --tw-primary: 217.2 91.2% 59.8%; */
|
|
107
|
+
/* --tw-accent: 199 89% 48%; */
|
|
108
|
+
/* --surface: rgba(15, 23, 42, 0.78); */
|
|
109
|
+
}
|
|
110
|
+
`
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function writeFile(targetPath, content, force) {
|
|
114
|
+
const absolutePath = resolve(process.cwd(), targetPath)
|
|
115
|
+
const alreadyExists = existsSync(absolutePath)
|
|
116
|
+
|
|
117
|
+
if (alreadyExists && !force) {
|
|
118
|
+
return { path: targetPath, status: 'skipped' }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
mkdirSync(dirname(absolutePath), { recursive: true })
|
|
122
|
+
writeFileSync(absolutePath, content, 'utf8')
|
|
123
|
+
return { path: targetPath, status: alreadyExists ? 'overwritten' : 'created' }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const options = parseArgs(process.argv.slice(2))
|
|
127
|
+
|
|
128
|
+
const agentsResult = writeFile(
|
|
129
|
+
options.agentsFile,
|
|
130
|
+
createAgentsTemplate({ themeFile: options.themeFile }),
|
|
131
|
+
options.force,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
const themeResult = writeFile(
|
|
135
|
+
options.themeFile,
|
|
136
|
+
createThemeTemplate(),
|
|
137
|
+
options.force,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
console.log(`Initialized ${PACKAGE_NAME}`)
|
|
141
|
+
console.log(`- ${agentsResult.path}: ${agentsResult.status}`)
|
|
142
|
+
console.log(`- ${themeResult.path}: ${themeResult.status}`)
|
|
143
|
+
console.log('')
|
|
144
|
+
console.log('Next steps:')
|
|
145
|
+
console.log(`1. Import \`${PACKAGE_NAME}/styles.css\` once at your app entry.`)
|
|
146
|
+
console.log(`2. Import \`${options.themeFile}\` right after the package stylesheet.`)
|
|
147
|
+
console.log(`3. Let your agent read \`${options.agentsFile}\` before generating UI.`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucasvu/scope-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -14,13 +14,19 @@
|
|
|
14
14
|
"./styles.css": "./dist/styles.css",
|
|
15
15
|
"./package.json": "./package.json"
|
|
16
16
|
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"scope-ui-init": "./bin/scope-ui-init.mjs"
|
|
19
|
+
},
|
|
17
20
|
"files": [
|
|
18
|
-
"dist"
|
|
21
|
+
"dist",
|
|
22
|
+
"bin",
|
|
23
|
+
"AI_SETUP.md"
|
|
19
24
|
],
|
|
20
25
|
"scripts": {
|
|
21
26
|
"build": "npm run build:js && npm run build:css",
|
|
22
27
|
"build:js": "tsup",
|
|
23
28
|
"build:css": "tailwindcss -c ./tailwind.config.js -i ./src/styles.css -o ./dist/styles.css --minify",
|
|
29
|
+
"init-ai": "node ./bin/scope-ui-init.mjs",
|
|
24
30
|
"prepublishOnly": "npm run build"
|
|
25
31
|
},
|
|
26
32
|
"publishConfig": {
|