claude-toolkit 0.16.0 → 0.17.0

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 (68) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +54 -13
  3. package/bin/cli.ts +75 -19
  4. package/package.json +6 -7
  5. package/src/generator.ts +64 -26
  6. package/src/refresh-hint.ts +95 -0
  7. package/bin/postinstall.mjs +0 -69
  8. package/docs/README.md +0 -59
  9. package/docs/agents/code-reviewer.md +0 -76
  10. package/docs/agents/github-workflow.md +0 -98
  11. package/docs/best-practices/capacitor/README.md +0 -64
  12. package/docs/best-practices/capacitor/capacitor-8.md +0 -60
  13. package/docs/best-practices/capacitor/capgo-setup.md +0 -151
  14. package/docs/best-practices/capacitor/channels-and-rollouts.md +0 -101
  15. package/docs/best-practices/capacitor/live-updates-ota.md +0 -75
  16. package/docs/best-practices/capacitor/security-encryption.md +0 -68
  17. package/docs/best-practices/solidjs/README.md +0 -43
  18. package/docs/best-practices/solidjs/anti-patterns.md +0 -166
  19. package/docs/best-practices/solidjs/component-patterns.md +0 -131
  20. package/docs/best-practices/solidjs/context-and-global-state.md +0 -131
  21. package/docs/best-practices/solidjs/control-flow.md +0 -124
  22. package/docs/best-practices/solidjs/data-fetching.md +0 -205
  23. package/docs/best-practices/solidjs/effects-and-lifecycle.md +0 -113
  24. package/docs/best-practices/solidjs/performance.md +0 -100
  25. package/docs/best-practices/solidjs/props-patterns.md +0 -100
  26. package/docs/best-practices/solidjs/reactivity-model.md +0 -104
  27. package/docs/best-practices/solidjs/signals-and-state.md +0 -78
  28. package/docs/best-practices/solidjs/stores-and-nested-state.md +0 -111
  29. package/docs/best-practices/solidjs/typescript-integration.md +0 -186
  30. package/docs/best-practices/testing/README.md +0 -84
  31. package/docs/best-practices/testing/playwright-e2e.md +0 -649
  32. package/docs/best-practices/testing/storybook-interaction.md +0 -455
  33. package/docs/best-practices/testing/vitest-unit.md +0 -451
  34. package/docs/best-practices/typescript/README.md +0 -45
  35. package/docs/best-practices/typescript/any-and-unknown.md +0 -73
  36. package/docs/best-practices/typescript/deriving-vs-decoupling.md +0 -83
  37. package/docs/best-practices/typescript/discriminated-unions.md +0 -75
  38. package/docs/best-practices/typescript/enums-alternatives.md +0 -72
  39. package/docs/best-practices/typescript/essential-patterns.md +0 -119
  40. package/docs/best-practices/typescript/generics-patterns.md +0 -105
  41. package/docs/best-practices/typescript/micro-opinions.md +0 -87
  42. package/docs/best-practices/typescript/runtime-validation.md +0 -62
  43. package/docs/best-practices/typescript/satisfies-operator.md +0 -100
  44. package/docs/best-practices/typescript/tsconfig-cheat-sheet.md +0 -160
  45. package/docs/best-practices/typescript/type-organization.md +0 -64
  46. package/docs/best-practices/typescript/type-vs-interface.md +0 -80
  47. package/docs/commands/code-quality.md +0 -36
  48. package/docs/commands/onboard.md +0 -63
  49. package/docs/commands/pr-review.md +0 -91
  50. package/docs/commands/pr-summary.md +0 -50
  51. package/docs/commands/proto-check.md +0 -59
  52. package/docs/commands/ticket.md +0 -56
  53. package/docs/skills/code-style.md +0 -26
  54. package/docs/skills/systematic-debugging.md +0 -70
  55. package/docs/skills/testing-patterns.md +0 -140
  56. package/docs/skills/typescript-conventions.md +0 -283
  57. package/docs/skills/verification-before-completion.md +0 -103
  58. package/docs/stacks/capacitor-ota.md +0 -145
  59. package/docs/stacks/cloudflare-d1-kv.md +0 -144
  60. package/docs/stacks/esnext-idioms.md +0 -25
  61. package/docs/stacks/i18n-typesafe.md +0 -141
  62. package/docs/stacks/playwright-patterns.md +0 -179
  63. package/docs/stacks/protobuf-contracts.md +0 -85
  64. package/docs/stacks/rust-wasm-patterns.md +0 -106
  65. package/docs/stacks/solidjs-patterns.md +0 -110
  66. package/docs/stacks/storybook-patterns.md +0 -177
  67. package/docs/stacks/vanilla-extract-patterns.md +0 -115
  68. package/docs/stacks/vite-vitest-patterns.md +0 -485
@@ -1,85 +0,0 @@
1
- # Protobuf Contracts
2
-
3
- > Protocol Buffer definitions and code generation for frontend/backend contracts.
4
-
5
- **Type:** Stack Skill (requires `protobuf` stack)
6
- **Source:** [`stacks/protobuf/skills/ct-protobuf-contracts/SKILL.md`](../stacks/protobuf/skills/ct-protobuf-contracts/SKILL.md)
7
- **Directory Mappings:** `proto/`
8
- **File Extensions:** `.proto`
9
-
10
- ## Overview
11
-
12
- Protocol Buffers (proto3) define the API contract between frontend and backend. Protobuf provides compact binary serialization, type safety across languages, and backward-compatible schema evolution.
13
-
14
- ## Proto3 Conventions
15
-
16
- - Use **PascalCase** for message names, **snake_case** for field names
17
- - Fields 1-15 use 1 byte (reserve for frequent fields), 16-2047 use 2 bytes
18
- - **Never reuse** a field number after removing a field
19
- - When removing fields, reserve the number AND name
20
- - Enums must always start with `UNSPECIFIED = 0`
21
-
22
- ## Message Patterns
23
-
24
- ### Request/Response Pairs
25
- ```protobuf
26
- message GetUserRequest { string user_id = 1; }
27
- message GetUserResponse { UserProfile user = 1; }
28
- ```
29
-
30
- ### Lists with Pagination
31
- ```protobuf
32
- message ListEventsRequest {
33
- int32 page_size = 1;
34
- string page_token = 2;
35
- }
36
- message ListEventsResponse {
37
- repeated Event events = 1;
38
- string next_page_token = 2;
39
- int32 total_count = 3;
40
- }
41
- ```
42
-
43
- ### Service Definitions
44
- ```protobuf
45
- service UserService {
46
- rpc GetUser(GetUserRequest) returns (GetUserResponse);
47
- rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
48
- rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
49
- }
50
- ```
51
-
52
- ## Code Generation
53
-
54
- | Target | Tool | Command |
55
- |---|---|---|
56
- | Frontend (TypeScript) | protoc-gen-ts | `buf generate --template buf.gen.ts.yaml` |
57
- | Backend (Rust) | prost-build | Via `build.rs` with `prost_build::Config` |
58
-
59
- ## Buf CLI Commands
60
-
61
- | Command | Purpose |
62
- |---|---|
63
- | `buf lint` | Lint proto files |
64
- | `buf format -w` | Format in place |
65
- | `buf breaking --against .git#branch=main` | Check for breaking changes |
66
- | `buf generate` | Run code generation |
67
-
68
- ## Versioning Rules
69
-
70
- 1. **Never remove or renumber fields** -- use `reserved` instead
71
- 2. **Never change a field type** -- add a new field with the correct type
72
- 3. **Enum values are forever** -- 0 must always be UNSPECIFIED
73
- 4. **Adding fields is safe** -- new fields get default values in old clients
74
- 5. **Run `buf breaking` before merging** -- catch breaking changes in CI
75
-
76
- ## Anti-patterns
77
-
78
- | Anti-pattern | Why it's wrong |
79
- |---|---|
80
- | **Reusing field numbers** | Causes data corruption. Always reserve removed field numbers. |
81
- | **Overly nested messages** | Deep nesting hurts readability and evolution. Flatten where practical. |
82
- | **Missing UNSPECIFIED enum** | Proto3 requires 0 as default. Without UNSPECIFIED, 0 maps to a real value. |
83
- | **Using proto2 syntax** | Always use proto3 for new projects. |
84
- | **Skipping buf lint** | Inconsistent naming compounds over time. |
85
- | **Large messages** | Protobuf is not designed for multi-MB payloads. Use streaming or chunking. |
@@ -1,106 +0,0 @@
1
- # Rust WASM Patterns
2
-
3
- > Rust WASM patterns for Cloudflare Workers with worker-rs.
4
-
5
- **Type:** Stack Skill (requires `rust-wasm` stack)
6
- **Source:** [`stacks/rust-wasm/skills/ct-rust-wasm-patterns/SKILL.md`](../stacks/rust-wasm/skills/ct-rust-wasm-patterns/SKILL.md)
7
- **Directory Mappings:** `worker/`, `worker/src/`
8
- **File Extensions:** `.rs`, `.toml`
9
-
10
- ## Overview
11
-
12
- Cloudflare Workers can run Rust compiled to WebAssembly via the `worker` crate (worker-rs). The target is `wasm32-unknown-unknown`. Workers handle HTTP requests at the edge with low latency.
13
-
14
- ## Project Structure
15
-
16
- ```
17
- worker/
18
- Cargo.toml
19
- src/
20
- lib.rs # Entry point with main router
21
- routes/
22
- models/
23
- error.rs # Custom error types
24
- wrangler.toml # Cloudflare config
25
- ```
26
-
27
- ## Key Patterns
28
-
29
- ### Request Routing
30
-
31
- ```rust
32
- #[event(fetch)]
33
- async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
34
- Router::new()
35
- .get_async("/api/users/:id", get_user)
36
- .post_async("/api/users", create_user)
37
- .run(req, env)
38
- .await
39
- }
40
- ```
41
-
42
- ### Handler Pattern
43
-
44
- ```rust
45
- async fn get_user(req: Request, ctx: RouteContext<()>) -> Result<Response> {
46
- let id = ctx.param("id")
47
- .ok_or_else(|| Error::RustError("Missing id parameter".into()))?;
48
- let db = ctx.env.d1("DB")?;
49
- // ...
50
- }
51
- ```
52
-
53
- ### Error Handling
54
-
55
- Define a custom `AppError` enum that converts to `worker::Error`:
56
-
57
- ```rust
58
- pub enum AppError {
59
- NotFound(String),
60
- BadRequest(String),
61
- Internal(String),
62
- Unauthorized,
63
- }
64
-
65
- impl From<AppError> for WorkerError { ... }
66
- ```
67
-
68
- ### Env Bindings
69
-
70
- Access Cloudflare services through the `Env` object:
71
-
72
- | Binding | Access |
73
- |---|---|
74
- | D1 Database | `env.d1("DB")?` |
75
- | KV Namespace | `env.kv("MY_KV")?` |
76
- | R2 Bucket | `env.bucket("MY_BUCKET")?` |
77
- | Secrets | `env.secret("API_KEY")?.to_string()` |
78
- | Variables | `env.var("CONFIG_VAR")?.to_string()` |
79
-
80
- ### Serde for JSON
81
-
82
- Use `#[derive(Serialize, Deserialize)]` for request/response types. Parse request bodies with `req.json().await?` and respond with `Response::from_json(&data)`.
83
-
84
- ## Cargo.toml Essentials
85
-
86
- ```toml
87
- [lib]
88
- crate-type = ["cdylib"]
89
-
90
- [dependencies]
91
- worker = "0.5"
92
- serde = { version = "1", features = ["derive"] }
93
- serde_json = "1"
94
- console_error_panic_hook = "0.1"
95
- ```
96
-
97
- ## Anti-patterns
98
-
99
- | Anti-pattern | Why it's wrong |
100
- |---|---|
101
- | **Panics in production** | Always use `Result`. `unwrap()` and `expect()` crash the worker. |
102
- | **Blocking operations** | WASM is single-threaded. All I/O must be `async`. |
103
- | **Large binary sizes** | Keep dependencies minimal. Target under 1MB compressed. |
104
- | **Ignoring memory limits** | Workers have 128MB memory. Stream large files, don't buffer. |
105
- | **Raw SQL string concatenation** | Always use prepared statements with `bind()`. |
106
- | **Missing CORS headers** | Workers serving APIs must handle OPTIONS preflight requests. |
@@ -1,110 +0,0 @@
1
- # SolidJS Patterns
2
-
3
- > SolidJS reactivity, signals, effects, and component patterns.
4
-
5
- **Type:** Stack Skill (requires `solidjs` stack)
6
- **Source:** [`stacks/solidjs/skills/ct-solidjs-patterns/SKILL.md`](../stacks/solidjs/skills/ct-solidjs-patterns/SKILL.md)
7
- **Directory Mappings:** `src/components/`, `src/hooks/`, `src/pages/`
8
- **File Extensions:** `.tsx`, `.jsx`
9
-
10
- ## Overview
11
-
12
- SolidJS uses **fine-grained reactivity** with no virtual DOM. Components run once; only the reactive expressions inside them re-execute when dependencies change. This is fundamentally different from React.
13
-
14
- ## Core Primitives
15
-
16
- ### createSignal
17
- ```tsx
18
- const [count, setCount] = createSignal(0);
19
- // Read: count() -- always call as function
20
- // Write: setCount(1) or setCount(prev => prev + 1)
21
- ```
22
-
23
- ### createEffect
24
- Runs side effects when tracked dependencies change. Automatically tracks any signal read inside it.
25
- ```tsx
26
- createEffect(() => {
27
- console.log("Count changed:", count());
28
- });
29
- ```
30
-
31
- ### createMemo
32
- Derived computation that caches its result. Only recalculates when dependencies change.
33
- ```tsx
34
- const doubled = createMemo(() => count() * 2);
35
- ```
36
-
37
- ### createResource
38
- Async data fetching tied to a signal source. Returns a resource with loading/error states.
39
- ```tsx
40
- const [data] = createResource(userId, fetchUser);
41
- // data(), data.loading, data.error
42
- ```
43
-
44
- ## Component Patterns
45
-
46
- | Component | Purpose | Example |
47
- |---|---|---|
48
- | `<Show>` | Conditional rendering | `<Show when={isLoggedIn()} fallback={<Login />}>` |
49
- | `<For>` | List rendering (keyed by reference) | `<For each={items()}>{(item) => ...}</For>` |
50
- | `<Switch>/<Match>` | Multi-branch conditional | `<Match when={state() === "loading"}>` |
51
- | `<ErrorBoundary>` | Error catching | `<ErrorBoundary fallback={(err) => ...}>` |
52
- | `<Suspense>` | Async loading states | `<Suspense fallback={<Loading />}>` |
53
-
54
- ## Props Handling
55
-
56
- **CRITICAL: Never destructure props.** Destructuring breaks reactivity.
57
-
58
- ```tsx
59
- // WRONG -- kills reactivity
60
- const MyComponent = ({ name, count }) => { ... };
61
-
62
- // CORRECT -- preserves reactivity
63
- const MyComponent = (props) => {
64
- return <div>{props.name}: {props.count}</div>;
65
- };
66
- ```
67
-
68
- - Use `mergeProps` for defaults: `const merged = mergeProps({ color: "blue" }, props)`
69
- - Use `splitProps` to separate prop groups: `const [local, others] = splitProps(props, ["class", "style"])`
70
-
71
- ## Store Patterns
72
-
73
- `createStore` provides deep reactivity for complex nested state with path-based updates:
74
-
75
- ```tsx
76
- const [state, setState] = createStore({
77
- user: { name: "Alice", settings: { theme: "dark" } }
78
- });
79
-
80
- // Granular updates
81
- setState("user", "settings", "theme", "light");
82
- ```
83
-
84
- ## Anti-patterns
85
-
86
- | Anti-pattern | Why it's wrong |
87
- |---|---|
88
- | **Destructuring props** | Breaks reactivity. Always use `props.x`. |
89
- | **Unnecessary createEffect** | If you just need a derived value, use `createMemo`. |
90
- | **Treating it like React** | Components do NOT re-run. Only reactive expressions update. |
91
- | **Array index as key in For** | `<For>` is keyed by reference automatically. |
92
- | **Reading signals outside reactive context** | Captures the value once at component top level. |
93
- | **Forgetting to call signals** | `count` is a getter function, `count()` is the value. |
94
-
95
- ## Best Practices Reference
96
-
97
- For deeper guidance on SolidJS patterns (sourced from official docs and Ryan Carniato):
98
-
99
- | Topic | Guide |
100
- |---|---|
101
- | How fine-grained reactivity works internally | [Reactivity Model](../best-practices/solidjs/reactivity-model.md) |
102
- | Signal vs memo, derived values, when to use what | [Signals & State](../best-practices/solidjs/signals-and-state.md) |
103
- | `produce`, `reconcile`, path syntax for nested state | [Stores & Nested State](../best-practices/solidjs/stores-and-nested-state.md) |
104
- | `mergeProps`, `splitProps`, `children` helper | [Props Patterns](../best-practices/solidjs/props-patterns.md) |
105
- | When NOT to use effects, `onMount`, `onCleanup` | [Effects & Lifecycle](../best-practices/solidjs/effects-and-lifecycle.md) |
106
- | `Show`, `For`, `Switch`/`Match`, `Suspense` details | [Control Flow](../best-practices/solidjs/control-flow.md) |
107
- | `createResource`, `createAsync`, optimistic updates | [Data Fetching](../best-practices/solidjs/data-fetching.md) |
108
- | Full catalog of common SolidJS mistakes | [Anti-Patterns](../best-practices/solidjs/anti-patterns.md) |
109
-
110
- See the full collection: [SolidJS Best Practices](../best-practices/solidjs/README.md)
@@ -1,177 +0,0 @@
1
- # Storybook Patterns
2
-
3
- > Storybook interaction testing, CSF 3 stories, play functions, a11y, and visual regression for SolidJS components.
4
-
5
- **Type:** Stack Skill (requires `storybook` stack)
6
- **Source:** [`stacks/storybook/skills/ct-storybook-patterns/SKILL.md`](../../stacks/storybook/skills/ct-storybook-patterns/SKILL.md)
7
- **Directory Mappings:** `.storybook/`, `src/**/*.stories.tsx`
8
- **File Extensions:** `.stories.tsx`, `.stories.ts`
9
-
10
- ## Overview
11
-
12
- Storybook is the middle layer of the testing pyramid: component interaction testing, visual regression, and accessibility auditing in a real browser.
13
-
14
- ## SolidJS Integration
15
-
16
- Uses community packages: `storybook-solidjs` (renderer) + `storybook-solidjs-vite` (builder).
17
-
18
- **Critical:** Always use `createJSXDecorator` for JSX decorators. Standard decorators cause duplicate DOM elements with SolidJS.
19
-
20
- ```tsx
21
- import { createJSXDecorator } from "storybook-solidjs";
22
-
23
- const ThemeDecorator = createJSXDecorator((Story) => (
24
- <ThemeProvider><Story /></ThemeProvider>
25
- ));
26
- ```
27
-
28
- ## CSF 3 Stories
29
-
30
- Use CSF 3 (not CSF Factories -- React-only as of Storybook 10.3).
31
-
32
- ```tsx
33
- import type { Meta, StoryObj } from "storybook-solidjs";
34
-
35
- const meta = {
36
- title: "Components/Button",
37
- component: Button,
38
- tags: ["autodocs"],
39
- } satisfies Meta<typeof Button>;
40
-
41
- export default meta;
42
- type Story = StoryObj<typeof meta>;
43
-
44
- export const Primary: Story = {
45
- args: { variant: "primary", children: "Click me" },
46
- };
47
- ```
48
-
49
- ### Coverage Checklist
50
-
51
- Every component needs stories for: all visual states (default, hover, focus, active, disabled, loading, error, empty), viewport sizes where layout differs, theme variants, edge cases (long text, missing data).
52
-
53
- ## Interaction Testing
54
-
55
- Import everything from `@storybook/test` (instrumented versions). Never import from `@testing-library/dom` directly.
56
-
57
- ```tsx
58
- import { expect, fn, userEvent, within } from "@storybook/test";
59
-
60
- export const SubmitForm: Story = {
61
- args: { onSubmit: fn() },
62
- play: async ({ canvasElement, args, step }) => {
63
- const canvas = within(canvasElement);
64
- await step("Fill form", async () => {
65
- await userEvent.type(canvas.getByLabelText("Email"), "user@example.com");
66
- });
67
- await step("Submit", async () => {
68
- await userEvent.click(canvas.getByRole("button", { name: "Sign in" }));
69
- });
70
- await expect(args.onSubmit).toHaveBeenCalledOnce();
71
- },
72
- };
73
- ```
74
-
75
- **Key rules:**
76
- 1. Always `await` expect calls (enables Interactions panel logging).
77
- 2. Use `step()` to organize complex interactions.
78
- 3. Use `fn()` for spying (auto-restored between stories).
79
-
80
- ## Running in CI (Vitest Addon)
81
-
82
- Use `@storybook/addon-vitest` (replaces old test-runner). No running Storybook instance needed.
83
-
84
- Required dependencies: `@storybook/addon-vitest`, `@vitest/browser`, `@vitest/browser-playwright`, `@vitest/coverage-v8`.
85
-
86
- Add as an inline project in your main Vite config using `test.projects`:
87
-
88
- ```typescript
89
- // vite.config.ts
90
- import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
91
- import { playwright } from "@vitest/browser-playwright";
92
-
93
- export default defineConfig({
94
- plugins: [/* ...app plugins */],
95
- test: {
96
- projects: [
97
- {
98
- extends: true,
99
- test: { name: "unit", environment: "jsdom", setupFiles: ["./tests/setup.ts"] },
100
- },
101
- {
102
- extends: true,
103
- plugins: [storybookTest({ configDir: ".storybook" })],
104
- test: {
105
- name: "storybook",
106
- browser: { enabled: true, headless: true, provider: playwright(), instances: [{ browser: "chromium" }] },
107
- setupFiles: [".storybook/vitest.setup.ts"],
108
- },
109
- },
110
- ],
111
- },
112
- });
113
- ```
114
-
115
- ## Accessibility
116
-
117
- Built on axe-core. Set globally in `.storybook/preview.ts`:
118
-
119
- ```typescript
120
- export default {
121
- parameters: { a11y: { test: "error" } }, // "error" | "todo" | "off"
122
- tags: ["a11y-test"],
123
- };
124
- ```
125
-
126
- ## MSW for API Components
127
-
128
- ```typescript
129
- // .storybook/preview.ts
130
- import { initialize, mswLoader } from "msw-storybook-addon";
131
- initialize();
132
- export default { loaders: [mswLoader] };
133
- ```
134
-
135
- Per-story handlers via `parameters.msw.handlers`. Keep success handlers in shared `mocks/handlers.ts`, override with error/edge-case at story level.
136
-
137
- ## Module Mocking (Storybook 10)
138
-
139
- `sb.mock` for internal module replacement. Register in `.storybook/preview.ts` only:
140
-
141
- ```typescript
142
- import { sb } from "@storybook/test";
143
- sb.mock("../src/api/client", () => ({ fetchUser: async () => ({ name: "Mock" }) }));
144
- ```
145
-
146
- MSW for network-level; `sb.mock` for internal modules.
147
-
148
- ## Portable Stories
149
-
150
- Reuse stories in Vitest with `composeStories`:
151
-
152
- ```tsx
153
- import { composeStories } from "storybook-solidjs";
154
- import * as stories from "./Button.stories";
155
- const { Primary } = composeStories(stories);
156
-
157
- test("renders primary", () => {
158
- const { getByRole } = render(() => <Primary />);
159
- expect(getByRole("button")).toBeInTheDocument();
160
- });
161
- ```
162
-
163
- ## Anti-Patterns
164
-
165
- 1. **Destructuring SolidJS props in stories** -- Pass props via `args`; use `createJSXDecorator` for decorators.
166
- 2. **Importing from `@testing-library/dom`** -- Use `@storybook/test` for instrumented versions.
167
- 3. **Not awaiting `expect()` in play functions** -- Always `await expect(...)`.
168
- 4. **Skipping error/edge-case stories** -- Always include loading, error, empty, boundary states.
169
- 5. **Using `@storybook/test-runner`** -- Use `@storybook/addon-vitest` instead.
170
- 6. **Registering `sb.mock` in story files** -- Register in `.storybook/preview.ts` only.
171
-
172
- ## See Also
173
-
174
- - [ct-testing-patterns](../skills/testing-patterns.md) -- Framework-agnostic TDD practices
175
- - [Storybook Interaction Best Practices](../best-practices/testing/storybook-interaction.md) -- SolidJS-specific Storybook patterns
176
- - [ct-vite-vitest-patterns](vite-vitest-patterns.md) -- Unit testing layer
177
- - [ct-playwright-patterns](playwright-patterns.md) -- E2E testing layer
@@ -1,115 +0,0 @@
1
- # Vanilla Extract Patterns
2
-
3
- > Type-safe CSS with vanilla-extract, sprinkles, and recipes.
4
-
5
- **Type:** Stack Skill (requires `vanilla-extract` stack)
6
- **Source:** [`stacks/vanilla-extract/skills/ct-vanilla-extract-patterns/SKILL.md`](../stacks/vanilla-extract/skills/ct-vanilla-extract-patterns/SKILL.md)
7
- **Directory Mappings:** `src/styles/`, `src/theme/`
8
- **File Extensions:** `.css.ts`
9
-
10
- ## Overview
11
-
12
- vanilla-extract provides zero-runtime, type-safe CSS written in TypeScript. All styles are authored in `*.css.ts` files and extracted to static CSS at build time.
13
-
14
- **Important:** All vanilla-extract files MUST use the `*.css.ts` extension. The build plugin only processes these files.
15
-
16
- ## Core API
17
-
18
- ### style() -- Single Class Styles
19
-
20
- Creates a single scoped class name with type-checked CSS properties.
21
-
22
- ```ts
23
- import { style } from '@vanilla-extract/css';
24
-
25
- export const button = style({
26
- padding: '8px 16px',
27
- borderRadius: '4px',
28
- ':hover': { opacity: 0.9 },
29
- });
30
- ```
31
-
32
- Compose styles by passing an array:
33
-
34
- ```ts
35
- export const primaryButton = style([button, { background: 'blue', color: 'white' }]);
36
- ```
37
-
38
- ### styleVariants() -- Variant Maps
39
-
40
- Creates a map of related style variants from a single definition.
41
-
42
- ```ts
43
- export const colorVariant = styleVariants({
44
- primary: { background: 'blue', color: 'white' },
45
- secondary: { background: 'gray', color: 'black' },
46
- danger: { background: 'red', color: 'white' },
47
- });
48
- ```
49
-
50
- ### recipe() -- Component Variants
51
-
52
- Creates multi-variant styles with `defaultVariants` and compound variants. Requires `@vanilla-extract/recipes`.
53
-
54
- ```ts
55
- export const buttonRecipe = recipe({
56
- base: { padding: '8px 16px', borderRadius: '4px' },
57
- variants: {
58
- color: {
59
- primary: { background: 'blue', color: 'white' },
60
- secondary: { background: 'gray', color: 'black' },
61
- },
62
- size: {
63
- small: { fontSize: '12px' },
64
- medium: { fontSize: '14px' },
65
- large: { fontSize: '16px' },
66
- },
67
- },
68
- defaultVariants: { color: 'primary', size: 'medium' },
69
- });
70
- ```
71
-
72
- ### globalStyle() -- Use Sparingly
73
-
74
- For CSS resets, body defaults, or third-party element overrides only.
75
-
76
- ## Theming
77
-
78
- ### Contract-first theming (recommended)
79
-
80
- ```ts
81
- import { createThemeContract, createTheme } from '@vanilla-extract/css';
82
-
83
- export const vars = createThemeContract({
84
- color: { brand: null, text: null, background: null },
85
- space: { small: null, medium: null, large: null },
86
- });
87
-
88
- export const lightTheme = createTheme(vars, {
89
- color: { brand: '#0066ff', text: '#1a1a1a', background: '#ffffff' },
90
- space: { small: '4px', medium: '8px', large: '16px' },
91
- });
92
- ```
93
-
94
- Use `vars` for type-safe token references: `style({ color: vars.color.brand })`
95
-
96
- ### Sprinkles -- Atomic Utility Classes
97
-
98
- Requires `@vanilla-extract/sprinkles`. Creates constrained atomic CSS classes with responsive conditions.
99
-
100
- ## Anti-patterns
101
-
102
- | Anti-pattern | Why it's wrong |
103
- | ----------------------------- | ---------------------------------------------------------------- |
104
- | **Inline styles** | Defeats the purpose. Use `style()` or `sprinkles()`. |
105
- | **Runtime CSS** | vanilla-extract is build-time only. |
106
- | **Overusing globalStyle** | Prefer scoped `style()`. Global styles create implicit coupling. |
107
- | **Non-`.css.ts` files** | Style definitions in `.ts` files will not be processed. |
108
- | **String-based theme values** | Use the `vars` object for type-safe references. |
109
-
110
- ## Best Practices Reference
111
-
112
- | Topic | Guide |
113
- | ----------------------------------------- | ---------------------------------------------------------------------------- |
114
- | `type` vs `interface` for theme contracts | [Type vs Interface](../best-practices/typescript/type-vs-interface.md) |
115
- | `satisfies` for config validation | [The satisfies Operator](../best-practices/typescript/satisfies-operator.md) |