@wangs-ui/create-react-app 1.0.35 → 1.0.36
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/dist/bin.js +69 -13
- package/package.json +7 -4
- package/template/README.md +114 -0
- package/template/package.json +4 -4
- package/template/agents/skills/form-management/SKILL.md +0 -95
- package/template/agents/skills/i18n-standardization/SKILL.md +0 -104
- package/template/agents/skills/wangs-ui-components/SKILL.md +0 -84
package/dist/bin.js
CHANGED
|
@@ -1122,18 +1122,73 @@ function copyProjectTemplate(options) {
|
|
|
1122
1122
|
}
|
|
1123
1123
|
}
|
|
1124
1124
|
//#endregion
|
|
1125
|
-
//#region
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1125
|
+
//#region ../skills/dist/src-C22mKmnQ.js
|
|
1126
|
+
var __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
1127
|
+
function getSkillsDir() {
|
|
1128
|
+
const candidates = [
|
|
1129
|
+
path.resolve(__dirname$1, "skills"),
|
|
1130
|
+
path.resolve(__dirname$1, "../skills"),
|
|
1131
|
+
path.resolve(__dirname$1, "../../skills")
|
|
1132
|
+
];
|
|
1133
|
+
for (const c of candidates) if (fs.existsSync(c)) return c;
|
|
1134
|
+
return path.resolve(__dirname$1, "skills");
|
|
1135
|
+
}
|
|
1136
|
+
function loadAllSkills() {
|
|
1137
|
+
const skillsDir = getSkillsDir();
|
|
1138
|
+
if (!fs.existsSync(skillsDir)) return [];
|
|
1139
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
1140
|
+
const skills = [];
|
|
1141
|
+
for (const entry of entries) if (entry.isDirectory()) {
|
|
1142
|
+
const skillMdPath = path.join(skillsDir, entry.name, "SKILL.md");
|
|
1143
|
+
if (fs.existsSync(skillMdPath)) {
|
|
1144
|
+
const content = fs.readFileSync(skillMdPath, "utf-8");
|
|
1145
|
+
const { name: entryName } = entry;
|
|
1146
|
+
let name = entryName;
|
|
1147
|
+
let description = "Wangs UI consumer skill";
|
|
1148
|
+
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
1149
|
+
if (frontmatterMatch) {
|
|
1150
|
+
const fm = frontmatterMatch[1];
|
|
1151
|
+
const nameMatch = fm.match(/^name:\s*(.+)$/m);
|
|
1152
|
+
const descMatch = fm.match(/^description:\s*(.+)$/m);
|
|
1153
|
+
if (nameMatch) name = nameMatch[1].trim();
|
|
1154
|
+
if (descMatch) description = descMatch[1].trim();
|
|
1155
|
+
}
|
|
1156
|
+
skills.push({
|
|
1157
|
+
id: entry.name,
|
|
1158
|
+
name,
|
|
1159
|
+
description,
|
|
1160
|
+
content
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return skills;
|
|
1165
|
+
}
|
|
1166
|
+
function getAgentSkillDirs(baseDir = process.cwd()) {
|
|
1167
|
+
const dirs = [];
|
|
1168
|
+
const candidates = [
|
|
1169
|
+
path.join(baseDir, ".agents", "skills"),
|
|
1170
|
+
path.join(baseDir, ".claude", "skills"),
|
|
1171
|
+
path.join(baseDir, ".opencode", "skills"),
|
|
1172
|
+
path.join(baseDir, ".kilo", "skills")
|
|
1173
|
+
];
|
|
1174
|
+
for (const c of candidates) if (fs.existsSync(c) || fs.existsSync(path.dirname(c))) dirs.push(c);
|
|
1175
|
+
if (dirs.length === 0) dirs.push(path.join(baseDir, ".agents", "skills"));
|
|
1176
|
+
return dirs;
|
|
1177
|
+
}
|
|
1178
|
+
function installSkill(skill, baseDir = process.cwd()) {
|
|
1179
|
+
const targetDirs = getAgentSkillDirs(baseDir);
|
|
1180
|
+
const writtenPaths = [];
|
|
1181
|
+
for (const baseSkillDir of targetDirs) {
|
|
1182
|
+
const destDir = path.join(baseSkillDir, skill.id);
|
|
1183
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
1184
|
+
const destFile = path.join(destDir, "SKILL.md");
|
|
1185
|
+
fs.writeFileSync(destFile, skill.content, "utf-8");
|
|
1186
|
+
writtenPaths.push(destFile);
|
|
1135
1187
|
}
|
|
1188
|
+
return writtenPaths;
|
|
1136
1189
|
}
|
|
1190
|
+
//#endregion
|
|
1191
|
+
//#region src/utils/mcpInstaller.ts
|
|
1137
1192
|
function setupAgentConfigurations(options) {
|
|
1138
1193
|
const { targetDir, templateDir, agents } = options;
|
|
1139
1194
|
const configuredAgents = [];
|
|
@@ -1173,13 +1228,14 @@ function setupAgentConfigurations(options) {
|
|
|
1173
1228
|
}
|
|
1174
1229
|
if (agents.includes("antigravity")) {
|
|
1175
1230
|
const agentsMcpSrc = path.join(agentsTemplateDir, "agents.mcp.json");
|
|
1176
|
-
const skillsSrc = path.join(agentsTemplateDir, "skills");
|
|
1177
1231
|
const dotAgents = path.join(targetDir, ".agents");
|
|
1178
1232
|
fs.mkdirSync(dotAgents, { recursive: true });
|
|
1179
1233
|
if (fs.existsSync(agentsMcpSrc)) fs.copyFileSync(agentsMcpSrc, path.join(dotAgents, "mcp_config.json"));
|
|
1180
|
-
|
|
1181
|
-
configuredAgents.push("Antigravity IDE & CLI (.agents/mcp_config.json, .agents/skills)");
|
|
1234
|
+
configuredAgents.push("Antigravity IDE & CLI (.agents/mcp_config.json)");
|
|
1182
1235
|
}
|
|
1236
|
+
const allSkills = loadAllSkills();
|
|
1237
|
+
for (const skill of allSkills) installSkill(skill, targetDir);
|
|
1238
|
+
if (allSkills.length > 0) configuredAgents.push(`Wangs UI Consumer Skills (${allSkills.map((s) => s.id).join(", ")})`);
|
|
1183
1239
|
return configuredAgents;
|
|
1184
1240
|
}
|
|
1185
1241
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wangs-ui/create-react-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.36",
|
|
4
4
|
"description": "Scaffold a modern React app with Wangs UI, Vite 8, Oxlint, Oxfmt, and AI Agent MCP integration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antigravity",
|
|
@@ -41,16 +41,19 @@
|
|
|
41
41
|
"template/_gitignore",
|
|
42
42
|
"template/_npmrc",
|
|
43
43
|
"template/src",
|
|
44
|
-
"template/agents"
|
|
44
|
+
"template/agents",
|
|
45
|
+
"template/README.md"
|
|
45
46
|
],
|
|
46
47
|
"type": "module",
|
|
47
48
|
"publishConfig": {
|
|
48
49
|
"access": "public",
|
|
49
50
|
"registry": "https://registry.npmjs.org/"
|
|
50
51
|
},
|
|
51
|
-
"
|
|
52
|
-
"@clack/prompts": "^1.7.0"
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@clack/prompts": "^1.7.0",
|
|
54
|
+
"@wangs-ui/skills": "1.0.36"
|
|
53
55
|
},
|
|
56
|
+
"devDependencies": {},
|
|
54
57
|
"scripts": {
|
|
55
58
|
"build": "vite build",
|
|
56
59
|
"check:publint": "publint",
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Wangs UI React Application
|
|
2
|
+
|
|
3
|
+
A modern enterprise React application built with **Wangs UI Design System**, Vite 8, Tailwind CSS v4, Oxlint, and pre-configured AI Agent MCP workflows.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Getting Started
|
|
8
|
+
|
|
9
|
+
### 1. Install Dependencies
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Available Scripts
|
|
16
|
+
|
|
17
|
+
| Command | Description |
|
|
18
|
+
| :------------- | :------------------------------------------ |
|
|
19
|
+
| `pnpm dev` | Start the local development server with HMR |
|
|
20
|
+
| `pnpm build` | Build optimized production bundle |
|
|
21
|
+
| `pnpm preview` | Preview production build locally |
|
|
22
|
+
| `pnpm lint` | Lint codebase with fast Oxlint |
|
|
23
|
+
| `pnpm fmt` | Format codebase with Oxfmt |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🎨 Working with Wangs UI
|
|
28
|
+
|
|
29
|
+
### 1. Modular Subpath Imports
|
|
30
|
+
|
|
31
|
+
Always import primitive components and icons via their subpaths to ensure optimal tree-shaking:
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// Primitives
|
|
35
|
+
import Button from '@wangs-ui/react-core/primitive/button';
|
|
36
|
+
import Card from '@wangs-ui/react-core/primitive/card';
|
|
37
|
+
import InputText from '@wangs-ui/react-core/primitive/inputtext';
|
|
38
|
+
import DataTable, { Column } from '@wangs-ui/react-core/primitive/datatable';
|
|
39
|
+
|
|
40
|
+
// Icons
|
|
41
|
+
import { SearchLine, AddLine, DeleteBin6Line } from '@wangs-ui/react-icons';
|
|
42
|
+
|
|
43
|
+
// Form & Internationalization
|
|
44
|
+
import { Form, Field } from '@wangs-ui/react-core';
|
|
45
|
+
import { useFormControl } from '@wangs-ui/form';
|
|
46
|
+
import { useI18n } from '@wangs-ui/react-i18n';
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Strict Primitive Rule
|
|
50
|
+
|
|
51
|
+
Never write unstyled raw HTML elements (`<button>`, `<input>`, `<table>`, `<dialog>`). Always use the corresponding Wangs UI primitive component.
|
|
52
|
+
|
|
53
|
+
### 3. Internationalization (`useI18n`)
|
|
54
|
+
|
|
55
|
+
Never hardcode user-facing text strings in JSX. Always wrap UI labels, button text, table headers, and error messages in `t()`:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
const { t } = useI18n();
|
|
59
|
+
|
|
60
|
+
return <Button label={t('Save Changes')} severity="primary" />;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🤖 AI Agent & MCP Integration
|
|
66
|
+
|
|
67
|
+
This project comes pre-configured with **`@wangs-ui/mcp`** for leading AI agents:
|
|
68
|
+
|
|
69
|
+
- **Antigravity IDE & CLI**: `.agents/mcp_config.json`
|
|
70
|
+
- **Claude Code**: `.mcp.json` & `CLAUDE.md`
|
|
71
|
+
- **OpenCode**: `opencode.json` & `.opencode/mcp.json`
|
|
72
|
+
- **Kilo**: `.kilo/mcp.json` & `.vscode/mcp.json`
|
|
73
|
+
|
|
74
|
+
The MCP server provides live access to:
|
|
75
|
+
|
|
76
|
+
1. **Component Documentation & Types**: `get-documentation({ id: "button" })`
|
|
77
|
+
2. **Component Stories & Variants**: `get-documentation-for-story({ id: "button", storyName: "Primary" })`
|
|
78
|
+
3. **Knowledge Graph Queries**: `query_graph({ query: "DataTable" })`
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 📦 Managing AI Agent Skills (`@wangs-ui/skills`)
|
|
83
|
+
|
|
84
|
+
Skills provide high-level workflows and recipes for AI agents (form management, data grids, modal dialogs, i18n formatting). You can install, update, or remove skills independently using the CLI:
|
|
85
|
+
|
|
86
|
+
### List Available Skills
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npx @wangs-ui/skills list
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Install Specific Skills
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Interactive selection
|
|
96
|
+
npx @wangs-ui/skills add
|
|
97
|
+
|
|
98
|
+
# Direct install
|
|
99
|
+
npx @wangs-ui/skills add create-form data-table dialog-modal
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Update Installed Skills
|
|
103
|
+
|
|
104
|
+
To update all skills in your project to the latest definitions:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npx @wangs-ui/skills update
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Remove a Skill
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npx @wangs-ui/skills remove create-form
|
|
114
|
+
```
|
package/template/package.json
CHANGED
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"format:check": "oxfmt --check"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@wangs-ui/react-core": "^1.0.
|
|
17
|
-
"@wangs-ui/react-i18n": "^1.0.
|
|
18
|
-
"@wangs-ui/react-icons": "^1.0.
|
|
19
|
-
"@wangs-ui/react-presets": "^1.0.
|
|
16
|
+
"@wangs-ui/react-core": "^1.0.36",
|
|
17
|
+
"@wangs-ui/react-i18n": "^1.0.36",
|
|
18
|
+
"@wangs-ui/react-icons": "^1.0.36",
|
|
19
|
+
"@wangs-ui/react-presets": "^1.0.36",
|
|
20
20
|
"clsx": "^2.1.1",
|
|
21
21
|
"react": "^19.2.7",
|
|
22
22
|
"react-dom": "^19.2.7",
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: form-management
|
|
3
|
-
description: Guidelines and best practices for creating, validating, and submitting forms using Wangs UI Form and Field components.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Form Management & Validation Guidelines
|
|
7
|
-
|
|
8
|
-
This skill defines the standards for form implementation with `@wangs-ui/form`, `useFormControl`, and `@wangs-ui/react-core` `Form` / `Field` components.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## 1. Core Architecture
|
|
13
|
-
|
|
14
|
-
Wangs UI provides strongly typed form controllers:
|
|
15
|
-
|
|
16
|
-
- `useFormControl({ type: 'json' })`: For standard JSON payload forms.
|
|
17
|
-
- `useFormControl({ type: 'formdata' })`: For multipart forms (file uploads).
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 2. Standard Form Pattern
|
|
22
|
-
|
|
23
|
-
```tsx
|
|
24
|
-
import React, { useState } from 'react';
|
|
25
|
-
import { Button, Card, Form, Field, InputText, InputPassword } from '@wangs-ui/react-core';
|
|
26
|
-
import { useFormControl } from '@wangs-ui/form';
|
|
27
|
-
import { useI18n } from '@wangs-ui/react-i18n';
|
|
28
|
-
|
|
29
|
-
interface LoginFormValues {
|
|
30
|
-
email: string;
|
|
31
|
-
password: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export default function LoginForm(): React.ReactElement {
|
|
35
|
-
const { t } = useI18n();
|
|
36
|
-
const formControl = useFormControl<LoginFormValues>({ type: 'json' });
|
|
37
|
-
const [loading, setLoading] = useState(false);
|
|
38
|
-
|
|
39
|
-
const handleSubmit = async (values: LoginFormValues) => {
|
|
40
|
-
setLoading(true);
|
|
41
|
-
try {
|
|
42
|
-
console.log('Submitted values:', values);
|
|
43
|
-
} finally {
|
|
44
|
-
setLoading(false);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<Card className="w-full max-w-md p-6">
|
|
50
|
-
<Form control={formControl} onSubmit={handleSubmit} className="flex flex-col gap-4">
|
|
51
|
-
<h2 className="heading-2">{t('Sign In')}</h2>
|
|
52
|
-
|
|
53
|
-
<Field<string>
|
|
54
|
-
name="email"
|
|
55
|
-
label={t('Email Address')}
|
|
56
|
-
required
|
|
57
|
-
rules={{
|
|
58
|
-
pattern: {
|
|
59
|
-
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
60
|
-
message: t('Invalid email address'),
|
|
61
|
-
},
|
|
62
|
-
}}
|
|
63
|
-
>
|
|
64
|
-
{(field) => (
|
|
65
|
-
<InputText {...field} placeholder={t('Enter your email')} value={field.value || ''} />
|
|
66
|
-
)}
|
|
67
|
-
</Field>
|
|
68
|
-
|
|
69
|
-
<Field<string> name="password" label={t('Password')} required>
|
|
70
|
-
{(field) => (
|
|
71
|
-
<InputPassword
|
|
72
|
-
{...field}
|
|
73
|
-
placeholder={t('Enter your password')}
|
|
74
|
-
value={field.value || ''}
|
|
75
|
-
/>
|
|
76
|
-
)}
|
|
77
|
-
</Field>
|
|
78
|
-
|
|
79
|
-
<Button type="submit" label={t('Submit')} severity="primary" loading={loading} />
|
|
80
|
-
</Form>
|
|
81
|
-
</Card>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## 3. Mandatory Rules
|
|
89
|
-
|
|
90
|
-
1. **Always Use `<Form>` and `<Field>`**:
|
|
91
|
-
Never use raw HTML `<form>` or uncontrolled `<input>`.
|
|
92
|
-
2. **Translate Labels and Error Messages**:
|
|
93
|
-
Always wrap `label`, `placeholder`, and validation `message` in `t()`.
|
|
94
|
-
3. **Strongly Typed Models**:
|
|
95
|
-
Define a TypeScript interface for form values and pass it to `useFormControl<Model>()`.
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: i18n-standardization
|
|
3
|
-
description: Guidelines and rules for implementing and using the JIT i18n translation functions (t) and locale formatters in this Wangs UI project.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: JIT i18n Implementation & Usage Guidelines
|
|
7
|
-
|
|
8
|
-
This skill defines the coding standards, rules, and best practices for writing translation strings and formatting dates/numbers using the JIT i18n system.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## 1. Core Principles
|
|
13
|
-
|
|
14
|
-
The localization system uses a **Just-In-Time (JIT)** workflow. All user-facing English strings act directly as keys. The `t()` function resolves these keys against local memory, the network cache, or triggers a real-time background backend AI translation without blocking UI rendering.
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 2. Mandatory Rules
|
|
19
|
-
|
|
20
|
-
### A. Translate at Consumer Level for `ReactNode` Props
|
|
21
|
-
|
|
22
|
-
All user-facing text props in Wangs UI components (`label`, `placeholder`, `emptyMessage`, `header`, `tooltip`, etc.) are typed as `ReactNode`. Components render them as-is and **do NOT call `t()` internally**. Translation MUST be called at the consumer level:
|
|
23
|
-
|
|
24
|
-
```tsx
|
|
25
|
-
// DO
|
|
26
|
-
const { t } = useI18n();
|
|
27
|
-
|
|
28
|
-
<Button label={t('Save Changes')} />
|
|
29
|
-
<Select placeholder={t('Select category...')} />
|
|
30
|
-
<DataTable emptyMessage={t('No data available')} />
|
|
31
|
-
|
|
32
|
-
// DO NOT: pass raw English strings without t()
|
|
33
|
-
<Button label="Save Changes" />
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### B. Named Variable Interpolation (Enforced)
|
|
37
|
-
|
|
38
|
-
Always use descriptive named variables (`{count}`, `{userName}`, `{fileName}`) passed via an object argument. This provides necessary semantic context for AI translation engines:
|
|
39
|
-
|
|
40
|
-
```tsx
|
|
41
|
-
// DO
|
|
42
|
-
t('Upload {count} files to {folderName}', { count: 5, folderName: 'Documents' });
|
|
43
|
-
|
|
44
|
-
// DO NOT: use positional indices for multi-variable strings
|
|
45
|
-
t('Upload {0} files to {1}', 5, 'Documents');
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### C. ICU Pluralization & Zero-State (`=0`)
|
|
49
|
-
|
|
50
|
-
Write ICU conditional plural/select structures directly inside the text keys. Always include `=0` branches to handle zero values within ICU syntax instead of creating separate JavaScript `if` or ternary branches:
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
// DO
|
|
54
|
-
t('{count, plural, =0 {No files uploaded} one {Uploaded 1 file} other {Uploaded {count} files}}', {
|
|
55
|
-
count,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// DO NOT: write manual JS conditionals for pluralization
|
|
59
|
-
count === 0 ? t('No files') : t('{count} files', { count });
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### D. Formatting Dates, Numbers & Currencies
|
|
63
|
-
|
|
64
|
-
Always format dates, numbers, currencies, and relative time using `useLocaleFormatter()` **before** passing them into `t()`:
|
|
65
|
-
|
|
66
|
-
```tsx
|
|
67
|
-
import { useI18n, useLocaleFormatter } from '@wangs-ui/react-i18n';
|
|
68
|
-
|
|
69
|
-
const { t } = useI18n();
|
|
70
|
-
const { formatDate, formatRelativeTime, formatCurrency, formatNumber } = useLocaleFormatter();
|
|
71
|
-
|
|
72
|
-
// Date formatting
|
|
73
|
-
const dateLabel = t('Created on {date}', {
|
|
74
|
-
date: formatDate(new Date(), 'dd MMMM yyyy'),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Relative time formatting
|
|
78
|
-
const timeLabel = t('Updated {time}', {
|
|
79
|
-
time: formatRelativeTime(updatedAt),
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Currency formatting
|
|
83
|
-
const priceText = formatCurrency(150000, 'IDR');
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## 3. Strict Prohibitions (MUST NOT)
|
|
89
|
-
|
|
90
|
-
1. **NO Dynamic String Concatenation**:
|
|
91
|
-
Never use string concatenation or template literals inside `t()`:
|
|
92
|
-
```tsx
|
|
93
|
-
// FORBIDDEN
|
|
94
|
-
t('Hello ' + user.name);
|
|
95
|
-
t(`Upload to ${folder}`);
|
|
96
|
-
```
|
|
97
|
-
2. **NO Hardcoded Strings in JSX**:
|
|
98
|
-
Never render raw text nodes without `t()`:
|
|
99
|
-
```tsx
|
|
100
|
-
// FORBIDDEN
|
|
101
|
-
<h1>Dashboard Overview</h1>
|
|
102
|
-
```
|
|
103
|
-
3. **NO Static Translation JSON Files**:
|
|
104
|
-
Never create static `.json` dictionaries (e.g. `id.json`, `en.json`). Localization is completely dynamic via JIT translation.
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: wangs-ui-components
|
|
3
|
-
description: Guidelines and rules for using and composing Wangs UI Design System components and icons in this React application.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Wangs UI Component Usage & Design System Standards
|
|
7
|
-
|
|
8
|
-
This skill defines the rules for building user interfaces with `@wangs-ui/react-core`, `@wangs-ui/react-icons`, and `@wangs-ui/react-presets`.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## 1. Subpath Import Style (Mandatory)
|
|
13
|
-
|
|
14
|
-
Components and providers are exported via clean, modular subpaths:
|
|
15
|
-
|
|
16
|
-
```tsx
|
|
17
|
-
// Provider / Contexts
|
|
18
|
-
import { WangsUiProvider } from '@wangs-ui/react-core/api';
|
|
19
|
-
|
|
20
|
-
// Primitive Components
|
|
21
|
-
import Button from '@wangs-ui/react-core/primitive/button';
|
|
22
|
-
import Card from '@wangs-ui/react-core/primitive/card';
|
|
23
|
-
import InputText from '@wangs-ui/react-core/primitive/inputtext';
|
|
24
|
-
import Select from '@wangs-ui/react-core/primitive/select';
|
|
25
|
-
import Dialog from '@wangs-ui/react-core/primitive/dialog';
|
|
26
|
-
import Modal from '@wangs-ui/react-core/primitive/modal';
|
|
27
|
-
import DataTable from '@wangs-ui/react-core/primitive/datatable';
|
|
28
|
-
|
|
29
|
-
// Icons
|
|
30
|
-
import { AddLine, SearchLine, DeleteBin6Line } from '@wangs-ui/react-icons';
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## 2. Primitive Component Rule (Strictly Enforced)
|
|
36
|
-
|
|
37
|
-
Never use unstyled raw HTML controls when a corresponding Wangs UI primitive component exists:
|
|
38
|
-
|
|
39
|
-
| Raw HTML Control (Forbidden) | Wangs UI Component (Mandatory) | Subpath Import |
|
|
40
|
-
| :--------------------------- | :----------------------------- | :--------------------------------------------- |
|
|
41
|
-
| `<button>` | `Button` | `@wangs-ui/react-core/primitive/button` |
|
|
42
|
-
| `<input type="text">` | `InputText` | `@wangs-ui/react-core/primitive/inputtext` |
|
|
43
|
-
| `<input type="number">` | `InputNumber` | `@wangs-ui/react-core/primitive/inputnumber` |
|
|
44
|
-
| `<input type="password">` | `InputPassword` | `@wangs-ui/react-core/primitive/inputpassword` |
|
|
45
|
-
| `<input type="checkbox">` | `Checkbox` | `@wangs-ui/react-core/primitive/checkbox` |
|
|
46
|
-
| `<select>` / dropdown | `Select` / `Dropdown` | `@wangs-ui/react-core/primitive/select` |
|
|
47
|
-
| `<dialog>` / modal | `Dialog` / `Modal` | `@wangs-ui/react-core/primitive/dialog` |
|
|
48
|
-
| `<table>` | `DataTable` | `@wangs-ui/react-core/primitive/datatable` |
|
|
49
|
-
| Container box | `Card` | `@wangs-ui/react-core/primitive/card` |
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## 3. Typography & Spacing Scale
|
|
54
|
-
|
|
55
|
-
### Typography (Typeface: Manrope)
|
|
56
|
-
|
|
57
|
-
Use semantic heading classes rather than arbitrary text size utilities:
|
|
58
|
-
|
|
59
|
-
- `.heading-1` (22px, 600 weight) — Page title
|
|
60
|
-
- `.heading-2` (18px, 600 weight) — Section title
|
|
61
|
-
- `.heading-3` (16px, 500 weight) — Card / Container header
|
|
62
|
-
- `.heading-4` (14px, 500 weight) — Sub-headers / Field labels
|
|
63
|
-
- `.heading-5` (12px, 600 weight) — Small titles
|
|
64
|
-
- `.p` (12px, 500 weight) — Body text
|
|
65
|
-
|
|
66
|
-
### Color Tokens
|
|
67
|
-
|
|
68
|
-
- Primary: `bg-primary-500`, `text-primary-500`, `border-primary-500`
|
|
69
|
-
- Secondary / Text: `text-secondary-900` (main text), `text-secondary-500` (muted/caption), `border-secondary-200`
|
|
70
|
-
- Semantic: `success-500`, `danger-500`, `warning-500`, `info-500`
|
|
71
|
-
|
|
72
|
-
### Spacing Tokens (4px Grid)
|
|
73
|
-
|
|
74
|
-
- `gap-xs` (4px), `gap-s` (6px), `gap-md` (8px), `gap-m` (12px), `gap-l` (16px), `gap-xl` (20px), `gap-xxl` (24px)
|
|
75
|
-
- `p-xs`, `p-s`, `p-md`, `p-m`, `p-l`, `p-xl`, `p-xxl`
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## 4. MCP Component Inspection
|
|
80
|
-
|
|
81
|
-
When creating new views or composing complex components:
|
|
82
|
-
|
|
83
|
-
- Use the `@wangs-ui/mcp` server tools (`get-documentation`, `list-all-documentation`) to inspect component props, types, and story examples.
|
|
84
|
-
- Do NOT guess prop names or event handlers.
|