Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions .claude/agents/code-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
name: code-reviewer
description: Thorough review of a change against this repo's rules — intent/requirements, correctness, design, security (incl. dependency audit), and test coverage. Reviews flexibly by scope: uncommitted work, the whole branch against its base (default master), a specific commit, or a named branch — always as one combined diff. Use after implementing a change, or to review a branch before merge. Complements the generic /code-review skill, which does not know these project rules.
tools: Read, Grep, Glob, Bash
---

# Code Reviewer

Review a change as one coherent diff and report findings only — do not edit
files. Read enough of the surrounding code to judge it, read the cited rule and
doc files before ruling, and cite `file:line` for every finding.

## Scope — what to review

Orient first: `git status --short` and `git rev-parse --abbrev-ref HEAD`. Then
pick the scope and state which you chose. Always review the **net result as a
single diff, never commit-by-commit** — later commits (fixups, reverts) may
correct earlier ones, and only the final state matters.

* **Explicitly requested** — honour what the invocation asks for: a base branch
(`git diff <branch>...HEAD`), a single commit (`git show <sha>`), or a commit
range (`git diff <from>..<to>`).
* **Uncommitted work present** (`git status --short` non-empty) → review the
working tree against `HEAD` (`git diff HEAD`) plus any untracked files (list
with `git status`, then read them).
* **Clean tree** → review the whole branch against its base (default `master`):
`git diff master...HEAD` (three dots = only what this branch introduced).

Work top-down: first establish what the change is supposed to do, then judge
whether it does so correctly, cleanly, safely, and with tests. The repo-specific
rules in section 6 are the easiest to miss — do not skip them.

## 1. Intent & requirements

* Establish the intent from the task / PR description and any linked issue (a
GitHub issue number appears in parentheses in the commit/PR name, e.g.
`(#261)`). Check the diff against it.
* Is all the planned functionality present, or is something stubbed, `TODO`, or
silently dropped?
* Flag scope creep — unrelated changes riding along
([code.md](../rules/code.md)).

## 2. Correctness & robustness

* **Error handling.** Failures are handled at the right level, not swallowed;
promises are awaited; rejections are handled.
* **Edge cases.** Empty / `null` / `undefined`, zero / one / many, boundary
values, async ordering, and failure paths are handled. Component edge cases:
missing `children`, controlled vs uncontrolled, ref forwarding.
* **Resource hygiene.** `useEffect` subscriptions / listeners / timers are
cleaned up; no retained references or unbounded state growth.

## 3. Design & maintainability

* Clean separation of concerns; the change integrates with the existing patterns
rather than introducing a parallel style — `React.forwardRef` +
`withGlobalProps`, context-aware variants via `useContext`, `classNames()` for
CSS Module classes, `transferProps()` for HTML attribute pass-through, CSS
Modules for styles ([frontend.md](../rules/frontend.md),
[styling.md](../rules/styling.md)).
* Props follow the [API Guidelines](../../src/docs/contribute/api.md) and nesting
follows [Composition](../../src/docs/contribute/composition.md).
* DRY without premature abstraction; sound, reasonably performant code — no heavy
work in render, no needless re-renders.

## 4. Security

* Validate / sanitise external data; no unsafe HTML
(`dangerouslySetInnerHTML`) with untrusted content; no secrets committed.
* **Dependencies.** If `package.json` / `package-lock.json` changed: new
dependencies need explicit approval
([safety-guards.md](../rules/safety-guards.md)); run `npm audit` (in the
devcontainer) and report advisories; sanity-check the lockfile diff for
unexpected or transitive version bumps.

## 5. Tests

* New or changed code is covered — co-located Jest tests in `__tests__/` and/or
Playwright component tests (`.spec.tsx` + `.story.tsx`); obsolete tests for
removed code are deleted. Never leave a component or helper untested
([testing.md](../rules/testing.md)).
* A bug-fix test must fail before the fix and pass after.
* Tests assert behaviour, not implementation details.

## 6. This repo's rules

Easy-to-miss invariants beyond the generic checks above:

* **Lint gate** ([CLAUDE.md](../../CLAUDE.md#commands)): `npm run lint` =
eslint + markdownlint + stylelint. It is not auto-run — remind the author to
run `npm run lint`, `npm run test:jest`, and `npm run test:playwright-ct:all`.
Comment thread
bedrich-schindler marked this conversation as resolved.
* **Component layout** ([frontend.md](../rules/frontend.md)): every component
folder has the `.jsx` + `index.js` barrel + `*.module.scss` + `_settings`/
`_theme`/`_tools` SCSS partials + `README.md` + `__tests__/`. PropTypes, not
TypeScript, in source.
* **CSS Modules class naming** ([styling.md](../rules/styling.md)): `root`,
`isRootXxx`, `hasRootXxx`, `isRootInXxx`, `isRootLayoutXxx`.
* **Docs** ([docs.md](../rules/docs.md)): component docs live in the component's
`README.md`; new doc pages are wired into `mkdocs.yml`.
* **Git hygiene** ([git.md](../rules/git.md)): no push or remote change without
approval; commit/PR subjects imperative English with backticked symbols and a
trailing `(#issue)` when one exists; **no `Co-Authored-By`**. PR names land in
the changelog.

## Output format

Group findings by severity. For each:
`severity | file:line | rule/doc cited | what is wrong | concrete fix`.

```text
## Blocking
- [requirements] src/components/Foo/Foo.jsx:42 — acceptance criterion not implemented.
- [tests] src/helpers/bar/bar.js:10 (testing.md) — new helper `bar` has no test.

## Non-blocking / nits
- [design] src/components/Foo/Foo.jsx:7 (frontend.md) — ref not forwarded to root element.

## Reminders
- Run `npm run lint`, `npm run test:jest`, and `npm run test:playwright-ct:all` before committing.
```

End with a one-line verdict: APPROVE / APPROVE WITH NITS / REQUEST CHANGES.
22 changes: 22 additions & 0 deletions .claude/rules/code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Code

* Modify files only within defined scope, do not make changes that affect
unrelated parts of the codebase, e.g. do not change unrelated comments,
imports, code or documentation.
* Keep changes minimal and focused.
* Follow the project formatting and style sources:
[.editorconfig](../../.editorconfig) (general),
[.markdownlint.jsonc](../../.markdownlint.jsonc) (Markdown),
[.eslintrc](../../.eslintrc) / [.eslintrc-ts](../../.eslintrc-ts)
(JavaScript/TypeScript), [stylelint.config.js](../../stylelint.config.js)
(SCSS).
* Only fix linting/formatting issues in files you created or modified for the
current task. Do not fix pre-existing issues outside that scope.
* Keep comments simple and use terminology and language matching repository
standards.
* Revert unrelated changes. If they are worth keeping, ask the user whether to
track them separately — either as a GitHub issue (propose a title and
description first, and confirm before creating it) or, for small changes, on a
separate branch without an issue.
Comment thread
bedrich-schindler marked this conversation as resolved.
* Do not use one character long variable names or shortened names unless it is a
common abbreviation.
35 changes: 35 additions & 0 deletions .claude/rules/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
paths:
- "src/docs/**"
- "src/components/**/README.md"
- "src/helpers/**/README.md"
- "README.md"
---

# Documentation

## Commands

* Run `npm run markdownlint` after changes (add `-- --fix` to autofix).
* Run `mkdocs build` and `mkdocs serve` to build and serve the documentation
* To verify a rendered component or the docs previews in a real browser
(navigate, click, screenshot, inspect the running docs site), drive host
Chrome through the `chrome-host` MCP. See
[AI Integration](../../src/docs/contribute/ai-integration.md).

See [Commands](../../CLAUDE.md#commands).

## Conventions

* Documentation is built with [Material for MkDocs][mkdocs-material] and
[Docoff][docoff] (live, runnable component previews). Component docs live in
each component's `README.md`; guides and foundations live under `src/docs/`.
* New pages must be wired into the navigation in [mkdocs.yml](../../mkdocs.yml).
* Use relative links between docs.

## Reference

* [General Guidelines › Documenting](../../src/docs/contribute/general-guidelines.md#documenting)

[mkdocs-material]: https://squidfunk.github.io/mkdocs-material/
[docoff]: https://github.com/react-ui-org/docoff
72 changes: 72 additions & 0 deletions .claude/rules/frontend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
paths:
- "src/**/*.js"
- "src/**/*.jsx"
---

# Frontend (React component library)

## Commands

* If dependencies change, run `npm ci`.
* Run `npm run eslint` after changes (add `-- --fix` to autofix).
* To verify a rendered component or the docs previews in a real browser
(navigate, click, screenshot, inspect the running docs site), drive host
Chrome through the `chrome-host` MCP. See
[AI Integration](../../src/docs/contribute/ai-integration.md).

## Stack

React UI is a themeable React component library, distributed as a UMD bundle
(with separate CSS) and as ESM (consumers run their own SASS pipeline).
Components are plain JavaScript / JSX (Babel, no TypeScript in the source) for
React 18, validated with `prop-types`. TypeScript appears only in tests and type
checks.

## Component structure

Each component lives in `src/components/<ComponentName>/` and follows this
layout:

```text
Button/
Button.jsx # Component implementation (React.forwardRef + withGlobalProps)
Button.module.scss # CSS Modules styles
index.js # Re-exports default (withGlobalProps-wrapped) as named export
_settings.scss # Component-level SCSS variables
_theme.scss # CSS custom properties (design tokens)
_tools.scss # SCSS mixins
README.md # Docoff/MkDocs documentation with live previews
helpers/ # Component-specific helper functions
__tests__/
Button.spec.tsx # Playwright visual + functional tests
Button.story.tsx # Story components used as test fixtures
_propTests/ # Reusable prop test generators (arrays of test cases)
```

## Implementation pattern

Components are `.jsx` files (not `.tsx`) using PropTypes. They:

1. Use `React.forwardRef` to forward refs to the root HTML element.
2. Are wrapped with `withGlobalProps(Component, 'ComponentName')` for global prop
injection; the wrapped version is the default export.
3. Use `useContext` to detect layout/group contexts (`FormLayoutContext`,
`ButtonGroupContext`, `InputGroupContext`) and apply CSS class variants
accordingly.
4. Use the `classNames()` helper to conditionally combine CSS Module class names.
5. Use `transferProps()` to pass through non-React HTML attributes to the root
element.

Honour the [API Guidelines](../../src/docs/contribute/api.md) and
[Composition](../../src/docs/contribute/composition.md) when shaping props and
nesting.

## Styling

Component styles use SCSS with CSS Modules — see the [styling rule](styling.md).

## Tests

Components are covered by Jest unit tests and table-driven Playwright component
tests — see the [testing rule](testing.md).
13 changes: 13 additions & 0 deletions .claude/rules/git.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Git

## Skills

Use `/commit` to commit changes.

## Conventions

Full rules are in [General Guidelines › Git Workflow](../../src/docs/contribute/general-guidelines.md#git-workflow).

## Reference

* [General Guidelines › Git Workflow](../../src/docs/contribute/general-guidelines.md#git-workflow)
9 changes: 9 additions & 0 deletions .claude/rules/safety-guards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Safety guards

* Never modify files listed in [.gitignore](../../.gitignore) unless approved
in a skill
* Never modify any files outside the project root
* Never run shell commands that can alter system state or access sensitive data
when run on the host system
* Never modify the git remote (e.g. `git push`) without explicit human approval
* Never introduce new dependencies without explicit human approval
32 changes: 32 additions & 0 deletions .claude/rules/styling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
paths:
- "src/**/*.scss"
- "src/**/*.css"
---

# Styling

## Commands

Run `npm run stylelint` after changes (add `-- --fix` to autofix).

## Styling

Styles use SCSS with CSS Modules (`.module.scss`) with camelCase class names. A
component's styles live next to it as `Foo.module.scss` and are imported as a
module.

Class naming convention:

* `root` for the root element.
* Modifiers follow `isRootXxx` (state), `hasRootXxx` (has feature),
`isRootInXxx` (context), `isRootLayoutXxx` (layout variant).

`src/styles/` contains the global theming system: settings (variables), tools
(mixins), and a large set of CSS custom properties for theming. Component SCSS
files `@use` their own `_settings`, `_theme`, `_tools` partials plus the shared
styles from `src/styles/`. Theme tokens are exposed as CSS custom properties.

## Reference

* [CSS Guidelines](../../src/docs/contribute/css.md)
59 changes: 59 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
paths:
- "**/*.spec.tsx"
- "**/*.story.tsx"
- "**/__tests__/**"
- "tests/**"
---

# Testing

## Commands

* Run all Jest unit tests with `npm run test:jest` (TS + JS). For a single file:
`npm run test:jest:ts -- <file>` or `npm run test:jest:js -- <file>`.
* Run all Playwright component tests with `npm run test:playwright-ct:all`; for
one component, `npm run test:playwright-ct:all -- -- src/components/Button`.
* Update Playwright snapshots with `npm run test:playwright-ct:all-with-update`.
* Serve the report with `npm run test:playwright-ct:show-report`.

## Testing

Create/update tests for added or changed components and helpers, and remove
obsolete tests when functionality is removed. Never leave a component or helper
without tests. When fixing a bug, add a test that fails before the fix and
passes after it.

### Organization

Jest unit/component tests are co-located in a component's `__tests__/` folder.

### Playwright component tests

`.spec.tsx` specs use a table-driven pattern:

* Import arrays of test cases from `_propTests/` directories and from shared
`tests/playwright/propTests/`.
* Each test case is `{ name, props, onBeforeTest?, onBeforeSnapshot? }`; custom
field tests add `customFieldLayoutProps`, `customFieldProps`, etc.
* `mixPropTests([...arrays])` generates the cartesian product of multiple prop
arrays.
* `propTests` from `tests/playwright/` provides standard reusable test sets
(e.g. `layoutPropTest`, `sizePropTest`, `disabledPropTest`).
* Snapshot images are stored alongside the spec file in
`<ComponentName>.spec.tsx-snapshots/`.

**Story components** (`.story.tsx`) wrap the real component in a minimal fixture
(sometimes inside a context provider) and are imported only by `.spec.tsx`
files. Naming convention: `<ComponentName>ForTest`, `<ComponentName>ForRefTest`,
`<ComponentName>ForFormLayoutTests` — the FormLayout story component is always
last.

**Test describe structure:** `test.describe('ComponentName')` →
`test.describe('base')` (if present) → `visual` / `non-visual` /
`functionality`; the `formLayout` describe is always the last block at the same
level as `base`.

## Reference

* [Testing Guidelines](../../src/docs/contribute/testing-guidelines.md)
Loading
Loading