|
| 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 |
0 commit comments