Skip to content

Commit 2aeb3b5

Browse files
authored
chore: migrate components (p.2), add claude rules, add skills to easily create/migrate components (#370)
1 parent 2da7a82 commit 2aeb3b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2370
-28
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
name: migrate-component
3+
description: Migrate a component from observe/frontend to weka-ui-components v2
4+
argument-hint: "<ComponentName>"
5+
disable-model-invocation: true
6+
---
7+
8+
Migrate a component from observe/frontend to weka-ui-components v2: $ARGUMENTS
9+
10+
## Instructions
11+
12+
Migrate the specified component from `observe/frontend/src/components/` into `lib/v2/components/` following the migration plan in the observe/frontend repo (`COMPONENT_MIGRATION_PLAN.md`).
13+
14+
### Steps
15+
16+
1. **Read the source component** in the observe/frontend repo at `../gohome/observe/frontend/src/components/<ComponentName>/` (relative to the workspace root). Understand its props, dependencies, styles, and behavior.
17+
18+
2. **Design the v2 version** using the `ts-react-linter-driven-development:component-designing` skill. Plan any API improvements, type changes, or simplifications.
19+
20+
3. **Create the v2 component folder** at `lib/v2/components/<ComponentName>/` with ALL required files:
21+
- `<ComponentName>.tsx` — migrated component with CSS Modules, relative imports
22+
- `<componentName>.module.scss` — styles converted to CSS Modules (camelCase filename)
23+
- `<ComponentName>.test.tsx` — tests ported to Vitest + React Testing Library
24+
- `<ComponentName>.stories.tsx` — Storybook stories (Default + key state variants)
25+
- `index.ts` — barrel export
26+
27+
4. **Apply code transformations:**
28+
- Convert all string union types to const object + `keyof typeof` pattern
29+
- Replace path alias imports with relative imports
30+
- Replace `@use '../../styles' as *` with CSS variables from `lib/v2/styles/`
31+
- Move shared helpers to `lib/v2/utils/` if used by multiple components
32+
- Export both const objects and derived types
33+
34+
5. **Register the component** in `lib/v2/components/index.ts` — add component, type, and const exports.
35+
36+
6. **Run the full workflow** using `ts-react-linter-driven-development:linter-driven-development` skill.
37+
38+
7. **Validate** by running:
39+
```bash
40+
yarn typecheck
41+
yarn lintcheck
42+
yarn test:run
43+
```
44+
45+
8. **Build dist** so consumer projects can use the new component:
46+
```bash
47+
yarn build
48+
```
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
name: new-v2-component
3+
description: Scaffold a new v2 component with all required files (tsx, scss, test, stories, index)
4+
argument-hint: "<ComponentName>"
5+
disable-model-invocation: true
6+
---
7+
8+
Create a new v2 component: $ARGUMENTS
9+
10+
## Instructions
11+
12+
Create a complete v2 component scaffold in `lib/v2/components/` following the project conventions from CLAUDE.md.
13+
14+
### Steps
15+
16+
1. **Design the component** using the `ts-react-linter-driven-development:component-designing` skill to plan the API, props interface, and type design.
17+
18+
2. **Create the component folder** at `lib/v2/components/<ComponentName>/` with ALL required files:
19+
- `<ComponentName>.tsx` — component implementation
20+
- `<componentName>.module.scss` — CSS Modules styles (camelCase filename)
21+
- `<ComponentName>.test.tsx` — Vitest tests with React Testing Library
22+
- `<ComponentName>.stories.tsx` — Storybook stories (Default + key state variants)
23+
- `index.ts` — barrel export
24+
25+
3. **Follow code conventions:**
26+
- All string union types must use the const object + `keyof typeof` pattern (e.g., `BUTTON_VARIANTS` + `ButtonVariant`)
27+
- Export both const objects and derived types
28+
- Use CSS variables from `lib/v2/styles/` for theming
29+
- Use shared utilities from `lib/v2/utils/consts.ts` (e.g., `EMPTY_STRING`, `NOOP`)
30+
- Use relative imports (no path aliases)
31+
32+
4. **Register the component** in `lib/v2/components/index.ts`:
33+
- Add component export
34+
- Add type exports
35+
- Add const object exports (if any)
36+
37+
5. **Run the full workflow** using `ts-react-linter-driven-development:linter-driven-development` skill to ensure linting, tests, and type checking all pass.
38+
39+
6. **Validate** by running:
40+
```bash
41+
yarn typecheck
42+
yarn lintcheck
43+
yarn test:run
44+
```

CLAUDE.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# weka-ui-components
2+
3+
Shared React/TypeScript component library for Weka products. Published as `@weka/weka-ui-components` on GitHub Packages.
4+
5+
## Quick Commands
6+
7+
```bash
8+
yarn test:run # Run all tests (Vitest)
9+
yarn test # Run tests in watch mode
10+
yarn typecheck # TypeScript type checking
11+
yarn lintcheck # ESLint check
12+
yarn lint # ESLint with auto-fix
13+
yarn format # Prettier formatting
14+
yarn build # Build dist (Vite)
15+
yarn storybook # Start Storybook on port 6006
16+
```
17+
18+
## Project Structure
19+
20+
```
21+
lib/
22+
├── v2/ # v2 components (new, CSS Modules-based)
23+
│ ├── components/ # React components
24+
│ ├── hooks/ # Custom hooks
25+
│ ├── icons/ # SVG icon components
26+
│ ├── styles/ # CSS variables, themes (_colors.scss, _theme.scss)
27+
│ ├── types/ # Shared TypeScript types
28+
│ ├── utils/ # Shared utilities and constants
29+
│ └── index.ts # v2 barrel export
30+
├── ... # Legacy v1 components
31+
└── main.ts # Main entry point
32+
dist/ # Built output (types + JS)
33+
plugins/ # ESLint, Prettier, TypeScript shared configs
34+
```
35+
36+
## v2 Component Structure
37+
38+
Every v2 component must include all of these files:
39+
40+
```
41+
lib/v2/components/ComponentName/
42+
├── ComponentName.tsx # Component implementation
43+
├── componentName.module.scss # CSS Modules (camelCase filename)
44+
├── ComponentName.test.tsx # Vitest tests
45+
├── ComponentName.stories.tsx # Storybook stories
46+
└── index.ts # Barrel export
47+
```
48+
49+
## Code Guidelines
50+
51+
### String Union Types -> Const Objects
52+
53+
All string union types must use the **const object + `keyof typeof`** pattern. Never define plain `type Foo = 'a' | 'b'` unions.
54+
55+
```typescript
56+
// Good: Single source of truth
57+
export const BUTTON_VARIANTS = {
58+
PRIMARY: 'primary',
59+
SECONDARY: 'secondary'
60+
} as const
61+
62+
export type ButtonVariant =
63+
(typeof BUTTON_VARIANTS)[keyof typeof BUTTON_VARIANTS]
64+
65+
// Use the const everywhere — no raw strings
66+
variant = BUTTON_VARIANTS.PRIMARY
67+
if (variant === BUTTON_VARIANTS.SECONDARY) { ... }
68+
69+
// Bad: Duplicating values
70+
type ButtonVariant = 'primary' | 'secondary'
71+
```
72+
73+
**Naming conventions:**
74+
- Const object: UPPER_SNAKE_CASE, plural (e.g., `BUTTON_VARIANTS`, `FLEX_DIRECTIONS`, `PROTOCOL_TAG_SIZES`)
75+
- Derived type: PascalCase, singular (e.g., `ButtonVariant`, `FlexDirection`, `ProtocolTagSize`)
76+
- Export both the const object and the derived type from the component and barrel index
77+
78+
### No Repeated String Literals
79+
80+
When using a string literal, always:
81+
1. **Check if a constant already exists** in `lib/v2/utils/consts.ts` or in the relevant component's const objects
82+
2. **Create a new constant** if the string is used more than once and no constant exists yet
83+
84+
This applies to all strings — DOM event names (`DOM_EVENTS.KEYDOWN`), keyboard keys (`KEYBOARD_KEYS.ESCAPE`), status values, labels, etc. The only exceptions are standard JSX/HTML attributes that are inherently self-documenting (e.g., `fill='none'`, `xmlns`, `type='text/css'`).
85+
86+
### Constants and Derived Types
87+
88+
- Define string literal constants as objects with `as const` assertion
89+
- Derive types from constants using `keyof typeof` pattern instead of manually defining union types
90+
- Place shared constants in `lib/v2/utils/consts.ts`
91+
- When adding a new constant that is related to existing constants, define it in the same file where related constants live
92+
93+
### DRY Principle (Don't Repeat Yourself)
94+
95+
- Avoid code duplication — extract common logic into reusable functions or hooks
96+
- Use configuration objects instead of repetitive switch statements or conditionals
97+
- Before writing a new helper function, check if a similar one already exists in `lib/v2/utils/` or sibling components
98+
- If a function is used by 2+ components, it should live in a shared location (`lib/v2/utils/` or `lib/v2/hooks/`)
99+
100+
### TypeScript Types
101+
102+
- Don't create a new type if an equivalent type already exists (check `lib/v2/types/` first)
103+
- Use utility types (`Omit`, `Pick`, `Partial`, etc.) instead of duplicating types with minor differences
104+
- Import types from their source packages when available (e.g., `import type SimpleBarCore from 'simplebar-core'`)
105+
106+
### Type Guards
107+
108+
- Use existing type guard functions instead of inline type checks
109+
- Check shared utils before writing inline type guards — a reusable one may already exist
110+
111+
### Comments
112+
113+
- Avoid inline comments that explain what code does — code should be self-explanatory through descriptive names
114+
- Keep JSDoc comments on custom hooks and non-obvious constants — they provide IDE tooltips
115+
- Remove comments that merely restate what the code already says
116+
117+
### Control Flow
118+
119+
- Avoid empty `else` blocks
120+
- Use early returns instead of else blocks when possible
121+
122+
### Testing Guidelines
123+
124+
- Every component must have a `.test.tsx` file — tests are not optional
125+
- Tests should be self-explanatory — avoid comments that explain what a function or method does
126+
- Test names should clearly describe the expected behavior
127+
- Use descriptive variable names in tests instead of relying on comments
128+
- Structure tests with clear arrange/act/assert patterns
129+
- Use React Testing Library — test user behavior, not implementation details
130+
131+
### Storybook Guidelines
132+
133+
- Every component must have a `.stories.tsx` file
134+
- Include multiple story variants: Default + key states (e.g., disabled, error, loading)
135+
- New icons must be added to `lib/v2/icons/Icons.stories.tsx` (consolidated gallery pattern)
136+
137+
## Development Workflow
138+
139+
When creating, migrating, or significantly modifying a v2 component, use the `ts-react-linter-driven-development` skills:
140+
141+
- **`component-designing`** — when planning new component APIs, props interfaces, and type design
142+
- **`linter-driven-development`** — as the main workflow orchestrator (design -> test -> lint -> refactor -> review -> commit)
143+
- **`testing`** — for test structure, patterns, and strategy decisions
144+
- **`refactoring`** — when ESLint flags complexity issues or code needs simplification
145+
- **`pre-commit-review`** — after linting and tests pass, to validate design quality
146+
- **`documentation`** — for Storybook stories, JSDoc comments, and feature guides
147+
148+
## v2 Styles System
149+
150+
Components use CSS Modules with a CSS variable-based theme system:
151+
152+
- **Color variables:** Defined in `lib/v2/styles/_colors.scss`
153+
- **Theme mixins:** Light/dark themes in `lib/v2/styles/_theme.scss`
154+
- **Semantic variables:** `--text-primary`, `--bg-primary`, `--gray-300-700`, etc.
155+
- **Theme switching:** Via `data-theme="light"` / `data-theme="dark"` attributes
156+
157+
When migrating a component that uses CSS variables not yet defined:
158+
1. Add the SCSS variable to `_colors.scss` if it's a new color
159+
2. Add the CSS variable to both `v2-light-theme` and `v2-dark-theme` mixins in `_theme.scss`
160+
161+
## Build and Publish
162+
163+
After adding new v2 components:
164+
1. Export from `lib/v2/components/index.ts` (both component and const objects)
165+
2. Run `yarn build` to regenerate `dist/` including `.d.ts` type declarations
166+
3. Consumer projects resolve types from `dist/v2/index.d.ts`, not from `lib/` source
167+
168+
## Versioning
169+
170+
- `release:patch` — bug fixes
171+
- `release:minor` — new components or features
172+
- `release:major` — breaking changes
173+
- `release:beta` — pre-release versions
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type { Meta, StoryObj } from '@storybook/react'
2+
3+
import { NOOP } from '../../utils/consts'
4+
5+
import { Button } from './Button'
6+
7+
const meta: Meta<typeof Button> = {
8+
title: 'v2/Button',
9+
component: Button,
10+
tags: ['autodocs'],
11+
argTypes: {
12+
variant: {
13+
control: 'radio',
14+
options: ['primary', 'secondary']
15+
},
16+
disabled: { control: 'boolean' },
17+
isRounded: { control: 'boolean' }
18+
}
19+
}
20+
21+
export default meta
22+
type Story = StoryObj<typeof Button>
23+
24+
export const Primary: Story = {
25+
args: {
26+
children: 'Primary Button',
27+
variant: 'primary',
28+
onClick: NOOP
29+
}
30+
}
31+
32+
export const Secondary: Story = {
33+
args: {
34+
children: 'Secondary Button',
35+
variant: 'secondary',
36+
onClick: NOOP
37+
}
38+
}
39+
40+
export const Disabled: Story = {
41+
args: {
42+
children: 'Disabled Button',
43+
disabled: true,
44+
onClick: NOOP
45+
}
46+
}
47+
48+
export const Rounded: Story = {
49+
args: {
50+
children: 'Rounded',
51+
isRounded: true,
52+
onClick: NOOP
53+
}
54+
}

0 commit comments

Comments
 (0)