@wangs-ui/skills 1.3.0-alpha.2 → 1.3.0-alpha.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.
Files changed (80) hide show
  1. package/README.md +15 -11
  2. package/dist/bin.js +20 -15
  3. package/dist/index.js +2 -2
  4. package/dist/rules/wangs-ui/default-props-precedence.md +13 -0
  5. package/dist/rules/wangs-ui/forms-destructuring-lock.md +18 -0
  6. package/dist/rules/wangs-ui/no-raw-html.md +28 -0
  7. package/dist/rules/wangs-ui/no-redundant-wrappers.md +55 -0
  8. package/dist/rules/wangs-ui/react19-checklist-and-reference.md +37 -0
  9. package/dist/rules/wangs-ui/react19-compiler-render-patterns.md +12 -0
  10. package/dist/rules/wangs-ui/react19-naming-conventions.md +15 -0
  11. package/dist/rules/wangs-ui/react19-no-manual-memoization.md +27 -0
  12. package/dist/rules/wangs-ui/react19-primitives-typing.md +84 -0
  13. package/dist/rules/wangs-ui/react19-props-typing.md +24 -0
  14. package/dist/rules/wangs-ui/react19-purity-and-immutability.md +40 -0
  15. package/dist/rules/wangs-ui/react19-tooling-and-opt-out.md +77 -0
  16. package/dist/rules/wangs-ui/theme-variable-override-breaks-engine.md +19 -0
  17. package/dist/rules/wangs-ui/typescript-assertions-last-resort.md +12 -0
  18. package/dist/rules/wangs-ui/typescript-checklist-and-reference.md +33 -0
  19. package/dist/rules/wangs-ui/typescript-discriminated-unions.md +39 -0
  20. package/dist/rules/wangs-ui/typescript-explicit-return-types.md +21 -0
  21. package/dist/rules/wangs-ui/typescript-interface-vs-type.md +39 -0
  22. package/dist/rules/wangs-ui/typescript-literal-unions-vs-enums.md +21 -0
  23. package/dist/rules/wangs-ui/typescript-naming-conventions.md +23 -0
  24. package/dist/rules/wangs-ui/typescript-narrowing-over-casting.md +43 -0
  25. package/dist/rules/wangs-ui/typescript-readonly-by-default.md +23 -0
  26. package/dist/rules/wangs-ui/typescript-tsconfig-strictness.md +30 -0
  27. package/dist/rules/wangs-ui/typescript-zero-any.md +36 -0
  28. package/dist/skills/wangs-ui/craft-theme/SKILL.md +63 -0
  29. package/dist/skills/{create-form → wangs-ui/create-form}/SKILL.md +27 -16
  30. package/{skills → dist/skills/wangs-ui}/data-table/SKILL.md +24 -15
  31. package/{skills → dist/skills/wangs-ui}/dialog-modal/SKILL.md +18 -9
  32. package/{skills → dist/skills/wangs-ui}/i18n-usage/SKILL.md +19 -11
  33. package/dist/skills/wangs-ui/layout-navigation/SKILL.md +156 -0
  34. package/dist/skills/wangs-ui/responsive-design/SKILL.md +107 -0
  35. package/dist/skills/wangs-ui/universal-layout/SKILL.md +80 -0
  36. package/dist/skills/wangs-ui/wangs-ui-components/SKILL.md +104 -0
  37. package/dist/src-BFwMaU8I.js +663 -0
  38. package/package.json +3 -2
  39. package/rules/wangs-ui/default-props-precedence.md +13 -0
  40. package/rules/wangs-ui/forms-destructuring-lock.md +18 -0
  41. package/rules/wangs-ui/no-raw-html.md +28 -0
  42. package/rules/wangs-ui/no-redundant-wrappers.md +55 -0
  43. package/rules/wangs-ui/react19-checklist-and-reference.md +37 -0
  44. package/rules/wangs-ui/react19-compiler-render-patterns.md +12 -0
  45. package/rules/wangs-ui/react19-naming-conventions.md +15 -0
  46. package/rules/wangs-ui/react19-no-manual-memoization.md +27 -0
  47. package/rules/wangs-ui/react19-primitives-typing.md +84 -0
  48. package/rules/wangs-ui/react19-props-typing.md +24 -0
  49. package/rules/wangs-ui/react19-purity-and-immutability.md +40 -0
  50. package/rules/wangs-ui/react19-tooling-and-opt-out.md +77 -0
  51. package/rules/wangs-ui/theme-variable-override-breaks-engine.md +19 -0
  52. package/rules/wangs-ui/typescript-assertions-last-resort.md +12 -0
  53. package/rules/wangs-ui/typescript-checklist-and-reference.md +33 -0
  54. package/rules/wangs-ui/typescript-discriminated-unions.md +39 -0
  55. package/rules/wangs-ui/typescript-explicit-return-types.md +21 -0
  56. package/rules/wangs-ui/typescript-interface-vs-type.md +39 -0
  57. package/rules/wangs-ui/typescript-literal-unions-vs-enums.md +21 -0
  58. package/rules/wangs-ui/typescript-naming-conventions.md +23 -0
  59. package/rules/wangs-ui/typescript-narrowing-over-casting.md +43 -0
  60. package/rules/wangs-ui/typescript-readonly-by-default.md +23 -0
  61. package/rules/wangs-ui/typescript-tsconfig-strictness.md +30 -0
  62. package/rules/wangs-ui/typescript-zero-any.md +36 -0
  63. package/skills/wangs-ui/craft-theme/SKILL.md +63 -0
  64. package/skills/{create-form → wangs-ui/create-form}/SKILL.md +27 -16
  65. package/{dist/skills → skills/wangs-ui}/data-table/SKILL.md +24 -15
  66. package/{dist/skills → skills/wangs-ui}/dialog-modal/SKILL.md +18 -9
  67. package/{dist/skills → skills/wangs-ui}/i18n-usage/SKILL.md +19 -11
  68. package/skills/wangs-ui/layout-navigation/SKILL.md +156 -0
  69. package/skills/wangs-ui/responsive-design/SKILL.md +107 -0
  70. package/skills/wangs-ui/universal-layout/SKILL.md +80 -0
  71. package/skills/wangs-ui/wangs-ui-components/SKILL.md +104 -0
  72. package/dist/skills/layout-navigation/SKILL.md +0 -62
  73. package/dist/skills/react19-compiler-typescript/SKILL.md +0 -388
  74. package/dist/skills/typescript-strict-typing/SKILL.md +0 -317
  75. package/dist/skills/wangs-ui-components/SKILL.md +0 -108
  76. package/dist/src-DDi-O7tk.js +0 -246
  77. package/skills/layout-navigation/SKILL.md +0 -62
  78. package/skills/react19-compiler-typescript/SKILL.md +0 -388
  79. package/skills/typescript-strict-typing/SKILL.md +0 -317
  80. package/skills/wangs-ui-components/SKILL.md +0 -108
@@ -0,0 +1,33 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when doing a final TypeScript review pass on a file."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Review Checklist & Quick Reference
8
+
9
+ ## Review Checklist
10
+
11
+ Before considering TypeScript code "done," verify:
12
+
13
+ - [ ] No `any` anywhere (including implicit `any` from missing annotations)
14
+ - [ ] External/uncertain data enters as `unknown` and is narrowed before use
15
+ - [ ] Variant state is a discriminated union, not optional fields + booleans
16
+ - [ ] `interface` used for object/entity shapes; `type` used for unions/aliases/intersections
17
+ - [ ] No stray `I` prefixes on interfaces
18
+ - [ ] Naming follows casing conventions consistently
19
+ - [ ] `as` / `!` are rare, justified, and can't be replaced by a guard or null check
20
+ - [ ] Exported functions/methods have explicit return types
21
+ - [ ] Switch statements over unions have an exhaustiveness (`never`) check
22
+ - [ ] `tsconfig.json` includes the strictness baseline
23
+
24
+ ## Quick Reference
25
+
26
+ | Situation | Use |
27
+ | ---------------------------------------------- | ------------------------------------------------------------- |
28
+ | External/uncertain data | `unknown` + narrowing |
29
+ | "This value is definitely one of these shapes" | Discriminated union (`type`) |
30
+ | Object with identity, may be extended | `interface` |
31
+ | Union, intersection, tuple, mapped type | `type` |
32
+ | Need to prove a type through logic | Type guard / narrowing |
33
+ | Tempted to write `any` | Stop — use `unknown`, a generic, or a local interface instead |
@@ -0,0 +1,39 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when modeling a variant or multi-shape state in TypeScript."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Discriminated Unions for Variant State
8
+
9
+ Whenever a value can be one of several distinct "shapes" (loading/success/error states, event types, API response variants), model it as a **discriminated union** with a literal tag field — never as a loose object with optional fields or boolean flags.
10
+
11
+ ```ts
12
+ // ❌ Bad — booleans can contradict each other; unclear which fields are valid together
13
+ interface FetchState {
14
+ isLoading: boolean;
15
+ isError: boolean;
16
+ data?: User;
17
+ error?: string;
18
+ }
19
+
20
+ // ✅ Good — only one shape is possible at a time, and the compiler enforces it
21
+ type FetchState =
22
+ | { status: 'idle' }
23
+ | { status: 'loading' }
24
+ | { status: 'success'; data: User }
25
+ | { status: 'error'; error: string };
26
+
27
+ function render(state: FetchState) {
28
+ switch (state.status) {
29
+ case 'success':
30
+ return state.data.name; // `data` is guaranteed to exist here
31
+ case 'error':
32
+ return state.error; // `error` is guaranteed to exist here
33
+ default:
34
+ return null;
35
+ }
36
+ }
37
+ ```
38
+
39
+ Use a consistent tag field name across a codebase (`kind`, `type`, or `status` — pick one and stick with it) so narrowing patterns stay predictable.
@@ -0,0 +1,21 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when writing or reviewing an exported function, class method, or public API surface in TypeScript."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Explicit Return Types on Exported Functions
8
+
9
+ Inference is fine for local, private helpers, but exported functions, class methods, and anything forming a public API should declare an explicit return type. This prevents an internal implementation change from silently widening/narrowing the public contract.
10
+
11
+ ```ts
12
+ // ❌ Return type is inferred and can silently drift
13
+ export function getActiveUsers(users: User[]) {
14
+ return users.filter((u) => u.active);
15
+ }
16
+
17
+ // ✅ Explicit, intentional contract
18
+ export function getActiveUsers(users: User[]): User[] {
19
+ return users.filter((u) => u.active);
20
+ }
21
+ ```
@@ -0,0 +1,39 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when deciding between `interface` and `type` for a new TypeScript declaration."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — `interface` vs `type`
8
+
9
+ Both can describe object shapes, but they signal different intent. Default rule:
10
+
11
+ | Use `interface` for... | Use `type` for... |
12
+ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
13
+ | Object / entity shapes (a `User`, a `Product`, a component's `Props`) | Unions (`"a" \| "b"`) and discriminated unions |
14
+ | Public API contracts meant to be `implements`-ed by classes | Intersections (`A & B`) |
15
+ | Shapes that consumers may want to **extend/augment** (declaration merging) | Tuples (`[string, number]`) |
16
+ | | Function types / callback signatures |
17
+ | | Mapped, conditional, or utility-derived types (`Partial<T>`, `Pick<T, K>`) |
18
+ | | Aliasing a primitive or another type for readability |
19
+
20
+ ```ts
21
+ // ✅ interface — an entity with identity, extendable
22
+ interface User {
23
+ id: string;
24
+ email: string;
25
+ role: UserRole;
26
+ }
27
+
28
+ interface AdminUser extends User {
29
+ permissions: Permission[];
30
+ }
31
+
32
+ // ✅ type — union, alias, derived shape
33
+ type UserRole = 'admin' | 'editor' | 'viewer';
34
+ type UserId = User['id'];
35
+ type PartialUser = Partial<User>;
36
+ type Callback<T> = (value: T) => void;
37
+ ```
38
+
39
+ Don't mix conventions arbitrarily within one file — if a shape is a plain data object that will never need a union/intersection, `interface` is the default; the moment it needs to express "one of several shapes," reach for `type`.
@@ -0,0 +1,21 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when modeling a fixed set of string or numeric variants in TypeScript."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Prefer Literal Unions Over Numeric Enums
8
+
9
+ String literal unions are simpler, tree-shake better, and produce clearer error messages than TypeScript `enum`. Reserve `enum` (or `as const` object maps) for cases that need reverse lookup or genuinely benefit from a namespaced runtime value.
10
+
11
+ ```ts
12
+ // ✅ Preferred
13
+ type OrderStatus = 'pending' | 'shipped' | 'delivered' | 'cancelled';
14
+
15
+ // Acceptable when a namespaced runtime object is actually needed
16
+ const OrderStatus = {
17
+ Pending: 'pending',
18
+ Shipped: 'shipped',
19
+ } as const;
20
+ type OrderStatus = (typeof OrderStatus)[keyof typeof OrderStatus];
21
+ ```
@@ -0,0 +1,23 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when naming a TypeScript type, variable, or constant."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Naming Conventions
8
+
9
+ | Kind | Convention | Example |
10
+ | ---------------------------------------------------------- | ------------------------------------------- | ----------------------------------- |
11
+ | Types, interfaces, classes, enums | `PascalCase` | `UserProfile`, `OrderStatus` |
12
+ | Interfaces | `PascalCase`, **no `I` prefix** | `User`, not `IUser` |
13
+ | Type aliases | `PascalCase` | `type ApiResponse<T> = ...` |
14
+ | Variables, functions, methods, properties | `camelCase` | `getUserById`, `isValid` |
15
+ | Booleans | `camelCase` with `is/has/should/can` prefix | `isLoading`, `hasPermission` |
16
+ | True constants (module-level, never reassigned, primitive) | `UPPER_SNAKE_CASE` | `MAX_RETRIES`, `DEFAULT_TIMEOUT_MS` |
17
+ | Enum members | `PascalCase` | `enum Status { Active, Archived }` |
18
+ | Generic type parameters (simple, single-purpose) | Single uppercase letter | `T`, `K`, `V`, `E` for errors |
19
+ | Generic type parameters (multiple / non-obvious) | Descriptive, prefixed with `T` | `TInput`, `TOutput`, `TContext` |
20
+ | Discriminated union tag field | Consistent across the codebase | `kind`, `type`, or `status` |
21
+ | Files with a single exported entity | Match the entity name | `UserProfile.ts`, `useAuth.ts` |
22
+
23
+ Naming should describe **intent**, not implementation — `fetchUser` not `getUserFromApiEndpoint`; `retryCount` not `numRetries2`.
@@ -0,0 +1,43 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when narrowing an `unknown` or union-typed value in TypeScript."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — `unknown` + Narrowing, Not Casting
8
+
9
+ Prefer proving a type through control flow over asserting it with `as`.
10
+
11
+ ## Narrowing techniques, in order of preference:
12
+
13
+ 1. **`typeof`** — primitives (`string`, `number`, `boolean`, `undefined`, `function`)
14
+ 2. **`instanceof`** — class instances, `Error`, `Date`, custom classes
15
+ 3. **`in`** — checking a property exists before accessing it on a union/unknown
16
+ 4. **User-defined type guards** — `function isUser(x: unknown): x is User`
17
+ 5. **Discriminated union tag checks** — `switch (value.kind) { ... }`
18
+ 6. **Exhaustiveness checks** — a `never`-typed default branch so adding a new variant is a compile error until every switch/if-chain handles it
19
+
20
+ ```ts
21
+ // ✅ Type guard
22
+ function isUser(value: unknown): value is User {
23
+ return typeof value === 'object' && value !== null && 'id' in value && 'email' in value;
24
+ }
25
+
26
+ // ✅ Exhaustiveness check
27
+ function assertNever(x: never): never {
28
+ throw new Error(`Unhandled case: ${JSON.stringify(x)}`);
29
+ }
30
+
31
+ function area(shape: Shape): number {
32
+ switch (shape.kind) {
33
+ case 'circle':
34
+ return Math.PI * shape.radius ** 2;
35
+ case 'square':
36
+ return shape.side ** 2;
37
+ default:
38
+ return assertNever(shape); // compile error if a variant is missed
39
+ }
40
+ }
41
+ ```
42
+
43
+ Type assertions (`as X`) and the non-null assertion (`!`) bypass this entirely — treat them as a last resort, not a shortcut.
@@ -0,0 +1,23 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when declaring a TypeScript collection or object shape."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Readonly by Default
8
+
9
+ Prefer immutable shapes unless mutation is intentional and localized.
10
+
11
+ ```ts
12
+ interface Point {
13
+ readonly x: number;
14
+ readonly y: number;
15
+ }
16
+
17
+ function config(values: readonly string[]) {
18
+ /* ... */
19
+ }
20
+
21
+ const ROLES = ['admin', 'editor', 'viewer'] as const;
22
+ type UserRole = (typeof ROLES)[number];
23
+ ```
@@ -0,0 +1,30 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when configuring or reviewing tsconfig.json compiler strictness options."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Baseline `tsconfig.json` Strictness
8
+
9
+ Treat these as the non-negotiable floor for any project this rule touches:
10
+
11
+ ```json
12
+ {
13
+ "compilerOptions": {
14
+ "strict": true,
15
+ "noImplicitAny": true,
16
+ "strictNullChecks": true,
17
+ "strictFunctionTypes": true,
18
+ "strictPropertyInitialization": true,
19
+ "noUncheckedIndexedAccess": true,
20
+ "exactOptionalPropertyTypes": true,
21
+ "noImplicitOverride": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUnusedLocals": true,
24
+ "noUnusedParameters": true,
25
+ "forceConsistentCasingInFileNames": true
26
+ }
27
+ }
28
+ ```
29
+
30
+ `strict: true` alone enables the core group (`noImplicitAny`, `strictNullChecks`, etc.), but `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` are commonly missed and close real gaps (array/object index access returning `T` instead of `T | undefined`; optional properties silently accepting `undefined` as an explicit value).
@@ -0,0 +1,36 @@
1
+ ---
2
+ trigger: model_decision
3
+ description: "Apply when writing or reviewing any TypeScript type annotation."
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Rule: TypeScript — Never Use `any`
8
+
9
+ `any` is not "unknown type," it's "type checking off." It's contagious — once a value is `any`, everything it touches becomes unchecked too.
10
+
11
+ - Never write `any` for parameters, return types, variables, or generics.
12
+ - Use `unknown` for genuinely unknown external data (API responses, `JSON.parse`, catch clauses, third-party callbacks) and narrow it before use.
13
+ - Use generics (`<T>`) when a function needs to work across types but preserve the relationship between input and output.
14
+ - If a library ships untyped, write a minimal local type/interface for the surface area you actually use instead of reaching for `any`.
15
+
16
+ ```ts
17
+ // ❌ Bad
18
+ function parseConfig(json: any) {
19
+ return json.settings.theme; // no safety, no autocomplete, silent runtime crash
20
+ }
21
+
22
+ // ✅ Good
23
+ function parseConfig(json: unknown): string {
24
+ if (
25
+ typeof json === 'object' &&
26
+ json !== null &&
27
+ 'settings' in json &&
28
+ typeof (json as { settings: unknown }).settings === 'object'
29
+ ) {
30
+ // still narrow further or validate with a schema library (zod, valibot, etc.)
31
+ }
32
+ throw new Error('Invalid config shape');
33
+ }
34
+ ```
35
+
36
+ The only acceptable `any` is a well-justified, isolated, and commented one (e.g. interfacing with a genuinely untyped legacy module) — never a default.
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: craft-theme
3
+ description: Generate a brand-color theme (13-shade tonal palette + semantic tokens) for a Wangs UI app via the `wangs-ui-generate-palette` CLI — never hand-write hex shade ramps.
4
+ metadata:
5
+ owner: wangs-ui
6
+ ---
7
+ # Skill: Craft Theme
8
+
9
+ Use this skill whenever the user asks to create, customize, or rebrand the color theme of an app built on `@wangs-ui/react-core` / `@wangs-ui/foundation` — "make the app's theme orange", "use our brand color #ff6b35", "add a new palette called sunset", etc.
10
+
11
+ ## The rule this skill exists to enforce
12
+
13
+ **Never hand-write a 13-shade tonal ramp, and never hand-pick which shade pairs with which as a text/foreground color.** Wangs UI's own design system shipped with exactly that mistake for a while: hand-tuned palette files drifted from what the perceptual (OKLCH) generator would produce, which caused white text to render at 2.54:1 contrast on one brand's primary color — invisible-adjacent, and only caught by a dedicated audit. The generator and the contrast math it's paired with exist specifically so this class of bug can't happen again. Always reach for the CLI below instead of writing hex values yourself.
14
+
15
+ ## 1. Generate the palette
16
+
17
+ ```bash
18
+ pnpm exec wangs-ui-generate-palette --name=<id> --primary=<#hex> [options] --out=<path>
19
+ ```
20
+
21
+ - `--name` (required): identifier for the palette, e.g. `sunset`. Used for the exported const name (`sunsetPalette`) and, unless `--out` is given, the output filename (`sunset.ts`).
22
+ - `--primary` (required): the brand/key hex color, e.g. `#ff6b35`.
23
+ - Optional per-family overrides — omit any of these to let the generator harmoniously auto-derive it from `--primary` (secondary: boosted-lightness variant of primary's hue; tertiary: +60° hue rotation; general: near-neutral variant of primary's hue) or fall back to the generator's calibrated defaults (success/danger/warning/info):
24
+ `--secondary=#hex --tertiary=#hex --general=#hex --success=#hex --danger=#hex --warning=#hex --info=#hex`
25
+ - `--out=<path>` (optional): where to write the file. Defaults to `./<name>.ts` in the current working directory — always pass an explicit `--out` pointing into the consumer app's own theme directory (e.g. `src/theme/sunset.ts`), don't rely on the default.
26
+
27
+ If `@wangs-ui/foundation` isn't already a dependency of the project you're working in, install it first (`pnpm add @wangs-ui/foundation` or the project's equivalent) — the CLI ships as its `bin`.
28
+
29
+ **The written file is chmod'd read-only (0o444) and headed with an AUTO-GENERATED / DO NOT EDIT BY HAND comment.** If a color needs to change, re-run the command (it clears the read-only bit, rewrites, and re-locks it) — never hand-edit a shade in the output, and never `chmod` it writable to bypass this. Note the read-only bit is a local filesystem attribute only; it is not preserved by git across clones, so it is a deterrent for the person/agent working in this checkout right now, not a hard guarantee for every future contributor.
30
+
31
+ ## 2. Wire it into the app
32
+
33
+ The generated file exports a plain `Palette` object — pass it directly to `WangsUiProvider`'s `theme.palette` (or `theme.defaultPalette` for uncontrolled mode):
34
+
35
+ ```tsx
36
+ import { WangsUiProvider } from '@wangs-ui/react-core/api';
37
+ import preset from '@wangs-ui/react-presets/fixedasset'; // or whichever preset the app uses
38
+ import { sunsetPalette } from './theme/sunset';
39
+
40
+ const App = () => (
41
+ <WangsUiProvider configOptions={{ preset }} theme={{ palette: sunsetPalette, mode: 'light' }}>
42
+ <YourApp />
43
+ </WangsUiProvider>
44
+ );
45
+ ```
46
+
47
+ `theme.palette` also accepts a built-in palette name (`'blue' | 'emerald' | 'crimson' | 'carbon' | 'gold'`) or a raw hex string — a generated `Palette` object is the right choice once you have brand-specific secondary/tertiary/status colors to preserve, not just a single key color.
48
+
49
+ ## 3. Regenerating / evolving an existing custom palette
50
+
51
+ To change a color, re-run the same command with a new hex for the family that changed — **always pass every family you want to keep**, not just the one changing, since each run is a full regeneration from the anchors you give it:
52
+
53
+ ```bash
54
+ pnpm exec wangs-ui-generate-palette --name=sunset --primary=#ff6b35 --tertiary=#2a9d8f --out=src/theme/sunset.ts
55
+ ```
56
+
57
+ ## 4. If you're extending Wangs UI itself (contributing a new official palette)
58
+
59
+ This is a different, rarer case than theming a consumer app — only relevant if you're working inside the `wangs-ui-react` monorepo itself and adding a 6th built-in palette alongside blue/emerald/crimson/carbon/gold:
60
+
61
+ 1. Run the generator with `--out` pointing at `packages/foundation/theme/tokens/palettes/<name>.ts`.
62
+ 2. Register it: add `'<name>'` to the `PaletteName` union and `paletteLoaders` map in `packages/foundation/theme/context/ThemeContext.tsx`, and re-export it from `packages/foundation/theme/tokens/palettes/index.ts`.
63
+ 3. Run the contrast regression suite before considering it done: `pnpm exec vitest run --config packages/foundation/vitest.config.ts` — it checks every semantic token pairing (including the new palette) against WCAG AA across both light and dark mode. See `packages/foundation/theme/tokens/COLOR_TOKEN_CONTRACT.md` for the full rule set this is checked against.
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: create-form
3
3
  description: Form architecture, validation workflows, strongly-typed forms (useForm, useDialogForm, useWatchField), initialValues/reset lifecycle, and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.
4
+ metadata:
5
+ owner: wangs-ui
4
6
  ---
5
-
6
7
  # Skill: Form Architecture & Validation Workflows
7
8
 
8
9
  Use this skill when building forms, data entry panels, modal forms, settings pages, or multipart forms in Wangs UI applications.
@@ -13,28 +14,36 @@ Use this skill when building forms, data entry panels, modal forms, settings pag
13
14
 
14
15
  Do **NOT** hardcode or guess prop names, component options, preset variations, or Storybook patterns in this document. Always retrieve component definitions, active props, and live Storybook implementations directly via MCP:
15
16
 
16
- ### Component & Form Documentation Protocol:
17
+ ### Component & Form API Protocol:
18
+
19
+ ```json
20
+ get_component_api({ "component": "form" })
21
+ get_component_api({ "component": "field" })
22
+ get_component_api({ "component": "dialogform" })
23
+ get_component_api({ "component": "input" })
24
+ get_component_api({ "component": "numberinput" })
25
+ get_component_api({ "component": "select" })
26
+ get_component_api({ "component": "multiselect" })
27
+ get_component_api({ "component": "datepicker" })
28
+ get_component_api({ "component": "fileupload" })
29
+ ```
30
+
31
+ ### Curated Form Documentation:
17
32
 
18
33
  ```json
19
- get-documentation({ "id": "form" })
20
- get-documentation({ "id": "field" })
21
- get-documentation({ "id": "dialogform" })
22
- get-documentation({ "id": "input" })
23
- get-documentation({ "id": "numberinput" })
24
- get-documentation({ "id": "select" })
25
- get-documentation({ "id": "multiselect" })
26
- get-documentation({ "id": "datepicker" })
27
- get-documentation({ "id": "fileupload" })
34
+ get_documentation({ "id": "form" })
35
+ get_documentation({ "id": "dialogform" })
36
+ get_documentation({ "id": "field" })
28
37
  ```
29
38
 
30
39
  ### Live Storybook & Interactive Behavior Protocol:
31
40
 
32
41
  ```json
33
- get-documentation-for-story({ "id": "form", "storyName": "Default" })
34
- get-documentation-for-story({ "id": "form", "storyName": "AsyncInitialValues" })
35
- get-documentation-for-story({ "id": "form", "storyName": "ConditionalFields" })
36
- get-documentation-for-story({ "id": "form", "storyName": "CascadingOptions" })
37
- get-documentation-for-story({ "id": "dialogform", "storyName": "Default" })
42
+ get_component_examples({ "component": "form", "variant": "Default" })
43
+ get_component_examples({ "component": "form", "variant": "AsyncInitialValues" })
44
+ get_component_examples({ "component": "form", "variant": "ConditionalFields" })
45
+ get_component_examples({ "component": "form", "variant": "CascadingOptions" })
46
+ get_component_examples({ "component": "dialogform", "variant": "Default" })
38
47
  ```
39
48
 
40
49
  ### Knowledge Graph & Symbol Usages:
@@ -74,6 +83,8 @@ query_graph({ "query": "useWatchField" })
74
83
  - **Children Render Callback**: `Field` yields `{ fieldProps, fieldState }`.
75
84
  - **`fieldProps`**: Pass directly to primitive inputs (`<Input {...fieldProps} />`). Contains `name`, `value`, `ref`, `onChange`.
76
85
  - **`fieldState`**: Provides `invalid`, `error`, `isDirty`, `isPending`. Pass `invalid={fieldState.invalid}` to primitive components for accessibility and validation styling.
86
+ - **⚠️ Mandatory Destructuring (Never `(field) => ...`)**: `<Field>`'s callback render prop must destructure as `{({ fieldProps, fieldState })}`. Passing a single parameter instead (`{(field) => ...}`) produces `undefined` `value`/`onChange` and permanently locks the input.
87
+ - **Pass `fieldProps.onChange` directly**: `<Field>` is generic and `fieldProps.onChange` is already typed to the field's value type. Do not wrap it in unnecessary `e?.target?.value` extractions.
77
88
 
78
89
  ---
79
90
 
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: data-table
3
3
  description: Architecture, workflows, and MCP discovery protocol for building DataTables with sorting, pagination, filtering, selection, and export.
4
+ metadata:
5
+ owner: wangs-ui
4
6
  ---
5
-
6
7
  # Skill: DataTable Architecture & Integration Workflows
7
8
 
8
9
  Use this skill when implementing data grids, server-paginated tables, filterable listing views, or batch management interfaces with `@wangs-ui/react-core`.
@@ -13,24 +14,31 @@ Use this skill when implementing data grids, server-paginated tables, filterable
13
14
 
14
15
  Do **NOT** guess table prop names or hardcode table structures. Query the MCP server dynamically to inspect exact TypeScript signatures, live story implementations, and companion controls:
15
16
 
16
- ### Inspect Component Contracts:
17
+ ### Inspect Component Contracts (`component` parameter):
18
+
19
+ ```json
20
+ get_component_api({ "component": "datatable" })
21
+ get_component_api({ "component": "exportbutton" })
22
+ get_component_api({ "component": "filtercontainer" })
23
+ get_component_api({ "component": "bulkactionbutton" })
24
+ ```
25
+
26
+ ### Read Curated Documentation:
17
27
 
18
28
  ```json
19
- get-documentation({ "id": "datatable" })
20
- get-documentation({ "id": "exportbutton" })
21
- get-documentation({ "id": "filtercontainer" })
22
- get-documentation({ "id": "bulkactionbutton" })
29
+ get_documentation({ "id": "datatable" })
30
+ get_documentation({ "id": "exportbutton" })
23
31
  ```
24
32
 
25
33
  ### Inspect Live Story Implementations:
26
34
 
27
35
  ```json
28
- get-documentation-for-story({ "id": "datatable", "storyName": "Basic" })
29
- get-documentation-for-story({ "id": "datatable", "storyName": "ServerPagination" })
30
- get-documentation-for-story({ "id": "datatable", "storyName": "Sortable" })
31
- get-documentation-for-story({ "id": "datatable", "storyName": "MultipleSelection" })
32
- get-documentation-for-story({ "id": "datatable", "storyName": "CustomColumn" })
33
- get-documentation-for-story({ "id": "exportbutton", "storyName": "WithTable" })
36
+ get_component_examples({ "component": "datatable", "variant": "Basic" })
37
+ get_component_examples({ "component": "datatable", "variant": "CursorPagination" })
38
+ get_component_examples({ "component": "datatable", "variant": "Sortable" })
39
+ get_component_examples({ "component": "datatable", "variant": "MultipleSelection" })
40
+ get_component_examples({ "component": "datatable", "variant": "CustomColumn" })
41
+ get_component_examples({ "component": "exportbutton", "variant": "WithTable" })
34
42
  ```
35
43
 
36
44
  ### Inspect Knowledge Graph & Usages:
@@ -47,7 +55,7 @@ query_graph({ "query": "useDataTableFetch" })
47
55
  The Wangs UI `DataTable` is built on a modular, headless-first architecture:
48
56
 
49
57
  1. **Declarative Column Definitions (`TableColumn<T>[]`)**:
50
- Columns are configured as typed array objects, not as JSX children. Check `get-documentation({ "id": "datatable" })` for column field types.
58
+ Columns are configured as typed array objects, not as JSX children. Check `get_component_api({ "component": "datatable" })` for column field types.
51
59
  2. **Table Instance Hook (`useDataTable`)**:
52
60
  Coordinates table state (sorting, pagination, selection, column ordering, pinning, visibility).
53
61
  3. **Data Fetching Hook (`useDataTableFetch`)**:
@@ -62,7 +70,8 @@ The Wangs UI `DataTable` is built on a modular, headless-first architecture:
62
70
 
63
71
  ## 3. Mandatory Implementation Rules
64
72
 
65
- 1. **Query MCP for Current Code Patterns**: Always run `get-documentation-for-story` for `datatable` before drafting code.
73
+ 1. **Query MCP for Current Code Patterns**: Always run `get_component_examples` for `datatable` before drafting code.
66
74
  2. **Strict Subpath Imports**: Import via `@wangs-ui/react-core/primitive/datatable` and companion primitive paths.
67
75
  3. **Always Translate Visible Copy**: All column header labels, empty state messages, and action button labels must be wrapped in `t('...')` from `@wangs-ui/react-i18n`.
68
- 4. **Stable Row Identity**: Always configure a unique key identifier for stable selection and row identity.
76
+ 4. **Stable Row Identity**: Always configure a unique key identifier (`dataKey` / `rowId`) for stable selection and row identity.
77
+ 5. **Zero Redundant Table Wrappers**: Never wrap `<DataTable />` in an isolated `<div>` or `<Box>` solely to set width or margin. Wangs UI DataTable manages its own container scroll and layout dimensions out of the box.
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: dialog-modal
3
3
  description: Patterns, overlay selection criteria, and MCP discovery protocol for Dialog, Modal, and DialogForm components in Wangs UI.
4
+ metadata:
5
+ owner: wangs-ui
4
6
  ---
5
-
6
7
  # Skill: Dialog, Modal & Overlay Workflows
7
8
 
8
9
  Use this skill when building interactive modals, create/edit dialog forms, destructive action confirmations, or slide-in overlay panels.
@@ -13,21 +14,29 @@ Use this skill when building interactive modals, create/edit dialog forms, destr
13
14
 
14
15
  Do **NOT** guess overlay props, event names, or footer slots. Query the MCP server dynamically to inspect exact contracts and live story implementations:
15
16
 
16
- ### Inspect Overlay Contracts:
17
+ ### Inspect Overlay Contracts (`component` parameter):
18
+
19
+ ```json
20
+ get_component_api({ "component": "dialog" })
21
+ get_component_api({ "component": "dialogform" })
22
+ get_component_api({ "component": "modal" })
23
+ get_component_api({ "component": "toast" })
24
+ ```
25
+
26
+ ### Read Curated Overlay Documentation:
17
27
 
18
28
  ```json
19
- get-documentation({ "id": "dialog" })
20
- get-documentation({ "id": "dialogform" })
21
- get-documentation({ "id": "modal" })
22
- get-documentation({ "id": "toast" })
29
+ get_documentation({ "id": "dialog" })
30
+ get_documentation({ "id": "dialogform" })
31
+ get_documentation({ "id": "modal" })
23
32
  ```
24
33
 
25
34
  ### Inspect Live Story Implementations:
26
35
 
27
36
  ```json
28
- get-documentation-for-story({ "id": "dialog", "storyName": "Confirmation" })
29
- get-documentation-for-story({ "id": "dialogform", "storyName": "Default" })
30
- get-documentation-for-story({ "id": "modal", "storyName": "Default" })
37
+ get_component_examples({ "component": "dialog", "variant": "RichHeaderFooter" })
38
+ get_component_examples({ "component": "dialogform", "variant": "Default" })
39
+ get_component_examples({ "component": "modal", "variant": "Default" })
31
40
  ```
32
41
 
33
42
  ### Inspect Knowledge Graph & Usages:
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: i18n-usage
3
3
  description: Comprehensive guidelines for application internationalization, JIT translations (t), ICU formatting, and locale-aware formatting with @wangs-ui/react-i18n.
4
+ metadata:
5
+ owner: wangs-ui
4
6
  ---
5
-
6
7
  # Skill: Application Internationalization & Formatting Protocol
7
8
 
8
9
  Use this skill when implementing multi-language interfaces, translating user-facing text, formatting dates, times, currencies, or numbers in React applications built with Wangs UI and `@wangs-ui/react-i18n`.
@@ -13,22 +14,29 @@ Use this skill when implementing multi-language interfaces, translating user-fac
13
14
 
14
15
  Do **NOT** guess component localization contracts, language switcher variants, or datepicker props. Query the MCP server dynamically to inspect exact props and live story implementations:
15
16
 
16
- ### Inspect Localized Component Contracts:
17
+ ### Inspect Localized Component Contracts (`component` parameter):
18
+
19
+ ```json
20
+ get_component_api({ "component": "languageswitcher" })
21
+ get_component_api({ "component": "currencyinput" })
22
+ get_component_api({ "component": "datepicker" })
23
+ get_component_api({ "component": "select" })
24
+ get_component_api({ "component": "datatable" })
25
+ ```
26
+
27
+ ### Read Curated Localization Documentation:
17
28
 
18
29
  ```json
19
- get-documentation({ "id": "languageswitcher" })
20
- get-documentation({ "id": "currencyinput" })
21
- get-documentation({ "id": "datepicker" })
22
- get-documentation({ "id": "select" })
23
- get-documentation({ "id": "datatable" })
30
+ get_documentation({ "id": "languageswitcher" })
31
+ get_documentation({ "id": "currencyinput" })
24
32
  ```
25
33
 
26
34
  ### Inspect Live Story Implementations:
27
35
 
28
36
  ```json
29
- get-documentation-for-story({ "id": "languageswitcher", "storyName": "Basic" })
30
- get-documentation-for-story({ "id": "currencyinput", "storyName": "Basic" })
31
- get-documentation-for-story({ "id": "datepicker", "storyName": "Default" })
37
+ get_component_examples({ "component": "languageswitcher", "variant": "Default" })
38
+ get_component_examples({ "component": "currencyinput", "variant": "Default" })
39
+ get_component_examples({ "component": "datepicker", "variant": "Default" })
32
40
  ```
33
41
 
34
42
  ---
@@ -132,7 +140,7 @@ selectedCount === 0
132
140
  Use standard supported HTML tags (`<a>`, `<b>`, `<i>`, `<u>`, `<s>`, `<br/>`, `<sub>`, `<sup>`, `<code>`, `<mark>`) for inline styling. Tags are automatically parsed into React elements without custom regex or string manipulation:
133
141
 
134
142
  ```tsx
135
- import Link from '@wangs-ui/foundation/theme/Link';
143
+ import { Link } from '@wangs-ui/foundation/theme';
136
144
 
137
145
  t('You have selected <b>{count} items</b>. Click <a>here</a> to review.', {
138
146
  count: selectedCount,