134 lines
4.6 KiB
Markdown
134 lines
4.6 KiB
Markdown
# Contributing
|
|
|
|
This repo treats components as source-owned product infrastructure, not generated vendor
|
|
artifacts. Changes should preserve the existing token system, component contract, and docs
|
|
discipline instead of introducing parallel patterns.
|
|
|
|
## Before you start
|
|
|
|
Read the current contract and docs baseline first:
|
|
|
|
- `roadmap.md`
|
|
- `packages/ui/src/lib/contracts.ts`
|
|
- `apps/docs/src/component-authoring.stories.tsx`
|
|
|
|
Then inspect the closest existing component before adding a new one.
|
|
|
|
## Default workflow
|
|
|
|
1. Confirm the component or change fits the current system layers.
|
|
2. Reuse the existing contract helpers, slot names, state naming, and variant conventions.
|
|
3. Add or update Storybook stories so behavior is reviewable.
|
|
4. Add or update tests before treating the component as done.
|
|
5. Run the relevant validation commands locally.
|
|
|
|
## Authoring rules
|
|
|
|
These are the baseline rules for public components in `packages/ui`:
|
|
|
|
- Expose `className` on every styled public component.
|
|
- Forward `ref` on every focusable or measurable public component.
|
|
- Use `asChild` only when the root is intentionally polymorphic.
|
|
- Prefer controlled and uncontrolled APIs together when the component manages user state.
|
|
- Represent boolean UI states with empty-string `data-*` attributes.
|
|
- Represent finite machine states with stable `data-state="..."` values.
|
|
- Name stylable internal parts with `data-slot`.
|
|
- Keep `variant` semantic and `size` meaningful; do not add one-off booleans that fragment the API.
|
|
|
|
## Styling and token rules
|
|
|
|
- Consume tokens and motion recipes instead of hardcoded brand values.
|
|
- Prefer semantic roles such as `primary`, `muted`, `destructive`, `surface`, and `card`.
|
|
- Keep shared layout, focus, and interaction primitives in the CVA base string.
|
|
- Avoid `transition-all`.
|
|
- Prefer animating `transform` and `opacity`.
|
|
- Use `data-state` driven animation where possible.
|
|
|
|
## Theme and reduced motion expectations
|
|
|
|
Every meaningful UI change should be reviewed under:
|
|
|
|
- the default theme
|
|
- alternate themes when contrast or surface depth could shift
|
|
- reduced motion
|
|
|
|
Practical expectations:
|
|
|
|
- The component should remain usable when motion is reduced.
|
|
- Motion should communicate state or hierarchy, not hide missing feedback.
|
|
- Theme differences should come from tokens, not conditional component styling forks.
|
|
|
|
## Storybook expectations
|
|
|
|
Storybook is not just a gallery. It is the review surface for API, anatomy, and behavior.
|
|
|
|
Minimum story recipe:
|
|
|
|
- `Playground`: one opinionated default example
|
|
- `States`: only when the component has meaningful state comparisons
|
|
- `Anatomy`: document stable slots and public `data-*` hooks
|
|
- `Accessibility` or `Motion`: choose whichever behavior is easiest to misunderstand
|
|
|
|
Writing rules:
|
|
|
|
- Use `docs.description.component` to explain when to choose the component.
|
|
- Use real product language instead of filler copy.
|
|
- Keep examples narrow and intentional.
|
|
- If a story exists only to explain slots, accessibility, or motion, say that directly.
|
|
|
|
## Testing and QA expectations
|
|
|
|
Component work is not done until the behavior is covered at the right level.
|
|
|
|
Use the following baseline:
|
|
|
|
- Unit and interaction tests in `packages/ui/src/components/*.test.tsx`
|
|
- Storybook interaction coverage where a representative `play` flow adds signal
|
|
- Playwright smoke coverage for high-value cross-component flows
|
|
|
|
Common things to cover:
|
|
|
|
- trigger and close behavior
|
|
- keyboard behavior
|
|
- controlled and uncontrolled state
|
|
- slot and `data-*` attributes that consumers rely on
|
|
- invalid, disabled, loading, or required state where relevant
|
|
- reduced motion behavior when the component has meaningful animation
|
|
|
|
## Validation commands
|
|
|
|
Run the narrowest useful set while working, then the broader set before opening a PR.
|
|
|
|
Core checks:
|
|
|
|
```bash
|
|
pnpm lint
|
|
pnpm typecheck
|
|
pnpm test
|
|
```
|
|
|
|
Docs and smoke checks:
|
|
|
|
```bash
|
|
pnpm dev:docs
|
|
pnpm build:docs
|
|
pnpm test:e2e:smoke
|
|
```
|
|
|
|
## Practical repo guidance
|
|
|
|
- Keep shared integration points small. If you only need a new component, avoid unrelated changes.
|
|
- Treat `packages/ui/src/index.ts` as a shared export surface and change it deliberately.
|
|
- Prefer adding a sibling pattern over mutating an existing component unless the API itself is wrong.
|
|
- If a change needs a new dependency, justify it against the repo's current stack and complexity budget.
|
|
|
|
## Definition of done
|
|
|
|
A component or pattern change is ready when:
|
|
|
|
- the implementation uses tokens and follows the current contract
|
|
- the docs explain when to use it and how it is structured
|
|
- tests cover the important behavior
|
|
- accessibility and reduced motion were considered explicitly
|
|
- the repo's standard validation commands pass
|