Files
atomic-design-poc/.claude/skills/ui-component/SKILL.md
T
ehoandClaude Opus 5 d9aef9541f docs: teach overzicht, max-lines and the step contract (RD-33)
CLAUDE.md did not name the overzicht context that RD-03 created, and it did
not name the max-lines budget that RD-02 enforces. An agent that follows it
writes a long page into the wrong context, and meets a red build with no
warning.

CLAUDE.md now names the context, the @overzicht/* alias, the
overzicht -> registratie arrow, the 250-line budget and its glob, and the
step-component contract. layers.mdx gains the same arrow.

atomic-design.mdx credited eslint.config.mjs with the layer rules.
dependency-cruiser enforces them. Each tool is now named for what it does.
The page also gains the layer-folder table and the step contract.

Four paths were pre-monorepo: three example paths in the ui-component skill,
and two citations of libs/shared/src/ui/async, which RD-27 moved to
libs/shared/src/ui/molecules/async.

npm run ci --full passes: 67 and 45 storybook suites, 306 axe tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:14:56 +02:00

56 lines
2.5 KiB
Markdown

---
name: ui-component
description: Add a shared UI building block (atom, molecule, organism) with its Storybook story. Use only after confirming no existing block in shared/ui fits — new blocks are the exception, composition is the default.
---
# UI component (atom / molecule / organism)
First: check `libs/shared/src/ui/` and `libs/shared/src/layout/` — a new page should be
composition of existing blocks. Only add a block when nothing fits.
## Rules
- **Folder = atomic layer**: `libs/shared/src/ui/` atoms → molecules → organisms;
`libs/shared/src/layout/` templates. Each level only uses levels below.
- Standalone component, **English name** (shared = language-agnostic), signal
`input()`s only, `inject()` over constructor DI.
- **Atoms are thin wrappers over CIBG Huisstijl (Bootstrap 5.2) classes** (`btn`,
`form-control`, `card`, …) — you own a small typed `input()` API, the design system
owns the visuals. No CIBG class for it? Hand-roll a small surface from the token
bridge (ADR-0003, e.g. the `alert` atom).
- **Tokens only** — `var(--rhc-*)` / `var(--app-*)`, never hardcoded colors
(`npm run check:tokens` fails the build; escape hatch: `token-ok` marker + reason).
- **No hardcoded Dutch** in shared components — expose copy as `input()`s with
`$localize` defaults; the domain caller supplies the text (see
`libs/shared/src/ui/molecules/async`).
- Components with content-projected slots export a spread constant so callers import
one thing: `export const ASYNC = [AsyncComponent, AsyncLoadedDirective, …] as const;`
## Story (required — this is the component's test)
Co-located `<name>.stories.ts`, title prefixed with the layer:
```ts
const meta: Meta<ButtonComponent> = { title: 'Atoms/Button', component: ButtonComponent };
export const Primary: StoryObj<ButtonComponent> = { args: { variant: 'primary' } };
```
One named export per meaningful state. CI runs axe on every story
(`test-storybook:ci`) — a11y failures break the build. Machines/wizards mount
specific states via the `Seed` message. No heavy component specs; Storybook is the
UI test surface.
## Worked examples
- Atom: `libs/shared/src/ui/atoms/button/` — typed variant API over `btn` classes.
- Molecule: `libs/shared/src/ui/molecules/async/` — slot directives, localizable input
defaults, spread constant.
- Template: `libs/shared/src/layout/wizard-shell/` — the canonical wizard outline.
## Verify
```bash
npm run lint && npm run check:tokens && npm run build
npm run storybook # eyeball the story; CI will run axe
```