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
10 changes: 5 additions & 5 deletions .claude/agents/design-system-expert.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ You are an Angular 22 headless design-system expert for this starter's component
| | `storybook/docs/**` (global foundations/specifications docs) |
| | `scripts/**`, `.github/**` |

**Out-of-scope requests**: refuse and orient — domain components (project prefix, composition of `ui-*`) and core services belong to the main thread per `AGENTS.md`; token additions are proposed as a JSON diff + `npm run tokens:build`, applied only after user approval.
**Out-of-scope requests**: refuse and orient — domain components (project prefix, composition of `ui-*`) and core services belong to the main thread per `AGENTS.md`; token additions are proposed as a JSON diff + `pnpm tokens:build`, applied only after user approval.

## Sources of truth (consult, never duplicate)

Expand Down Expand Up @@ -76,7 +76,7 @@ If the verb matches none of these, or the phrasing is ambiguous (“check that
4. Create/modify the component files, **then** the co-located `.stories.ts` and `.mdx` — both mandatory.
5. Every color/spacing consumed must exist in `src/styles/src/generated/` — grep the variable name to confirm; cover light AND dark (and the 3 brands).
6. Update `components-index.md` (check off / add the component).
7. Verify: `npm run lint` + `npm run build-storybook` (the real AoT typecheck). For visual verification, suggest the `/verify` skill.
7. Verify: `pnpm lint` + `pnpm build-storybook` (the real AoT typecheck). For visual verification, suggest the `/verify` skill.
8. Final summary: files created/modified, lint/build status, propagations (new token needed → proposed JSON diff, consumers impacted via a references search).

### AUDIT mode — gap report, **zero modification**
Expand Down Expand Up @@ -136,14 +136,14 @@ For each component in scope, check:
2. Risky changes (renaming an exported component, changing a public `input()`/`output()` signature, moving between categories): **propose the diff** and ask for confirmation, listing consumers via a references search.
3. Trivial gaps (`*ngIf` → `@if`, `[ngClass]` → `[class]`, decorator → signal, hardcoded value → token, missing `track`): apply directly.
4. **Always** update `.stories.ts` + `.mdx` when the component changes (API, prop, visible behavior) — and `CHANGELOG.md` `[Unreleased]` for user-visible changes.
5. Final verification: `npm run lint` + `npm run build-storybook`.
5. Final verification: `pnpm lint` + `pnpm build-storybook`.

## Guardrails

- **Out of scope**: refuse and orient (domain components, core services, token JSON, Figma).
- **Missing token**: never invent a variable — propose the addition in `src/design-tokens/*.json` + `npm run tokens:build`, ask first.
- **Missing token**: never invent a variable — propose the addition in `src/design-tokens/*.json` + `pnpm tokens:build`, ask first.
- **Doubt about a convention**: cite the source (AGENTS.md section, rule, reference pattern). Otherwise `Grep` the kit (>10 occurrences = de-facto convention; <3 = don't generalize).
- **Verification**: at minimum `npm run lint` + `npm run build-storybook` after any change; report status. Visual doubts → suggest `/verify`.
- **Verification**: at minimum `pnpm lint` + `pnpm build-storybook` after any change; report status. Visual doubts → suggest `/verify`.
- **Never commit** — report the touched files and let the user commit (via `/git-commit`).

## Output format
Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/git-conventions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Git conventions

Full release workflow (SemVer bumps, `npm version`, tags): see `docs/VERSIONING.md`.
Full release workflow (SemVer bumps, `pnpm version`, tags): see `docs/VERSIONING.md`.

## Commit format — Conventional Commits

Expand Down
6 changes: 3 additions & 3 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"Read",
"Glob",
"Grep",
"Bash(npm run lint)",
"Bash(npm run tokens:build)",
"Bash(npm run build-storybook)",
"Bash(pnpm lint)",
"Bash(pnpm tokens:build)",
"Bash(pnpm build-storybook)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)",
Expand Down
8 changes: 4 additions & 4 deletions .claude/skills/generate-ui-component/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Rules:

### `///` comments = the theming doc (mandatory)

The doc's "Theming" table is **generated** from the `.scss` by `npm run docs:config`
The doc's "Theming" table is **generated** from the `.scss` by `pnpm docs:config`
(`scripts/docs.config.mjs` → `storybook/generated/ui-config.json`). So the SCSS comments are
what write the doc: nothing to copy elsewhere.

Expand All @@ -137,7 +137,7 @@ what write the doc: nothing to copy elsewhere.
project rebinds the variable.
- Describe the **role**, not the binding: the "Default (starter)" column and the chain to
`ui-config` are inferred automatically.
- **Every** config variable must have its `///` — `npm run docs:config` counts the missing ones
- **Every** config variable must have its `///` — `pnpm docs:config` counts the missing ones
(they don't appear in the table).
- **Exposed custom properties** (override points) are documented with a `///` where the hook
lives: on its declaration, or on the line reading it with its fallback
Expand Down Expand Up @@ -224,9 +224,9 @@ import { ConfigTable } from '<…>/storybook/blocks/config-table';

## Verification

1. `npx tsc --noEmit -p tsconfig.json` → must pass.
1. `pnpm exec tsc --noEmit -p tsconfig.json` → must pass.
2. Compile the SCSS: `node_modules/.bin/sass --load-path=src/styles --no-source-map --quiet <file.scss>` and check the generated selectors/values.
2bis. `npm run docs:config` → the component must appear, with **0 variables missing a `///`
2bis. `pnpm docs:config` → the component must appear, with **0 variables missing a `///`
comment** (the script prints the count), and every line resolved to a token, a map, a list, or
an accepted literal value.
3. **Live Storybook** (already running on `:6006`, HMR): via the browser tools, open `iframe.html?id=components-ui-{cat}-ui-{name}--<story>&viewMode=story`, measure (getBoundingClientRect, getComputedStyle), test the interaction (click/keyboard), and take a screenshot. Wait for transitions to settle before measuring.
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/qa-component-methodology/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ juste à l'œil :
## 3. Vérifications statiques

```bash
npx eslint <dossier> --max-warnings 0
npx tsc --noEmit -p tsconfig.app.json | grep <composant>
pnpm exec eslint <dossier> --max-warnings 0
pnpm exec tsc --noEmit -p tsconfig.app.json | grep <composant>
```

## 4. Vérification visuelle/interactive dans Storybook
Expand Down
10 changes: 8 additions & 2 deletions .claude/skills/verify/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ Project surface: **Storybook** (no meaningful app page; `ng serve` shows almost
## Recipe that works

```bash
npm run build-storybook # AOT of all stories → storybook-static/
pnpm build-storybook # AOT of all stories → storybook-static/
cd storybook-static && python3 -m http.server 6007 &
```

Drive with Playwright + system Chrome (no browser download):

```js
// npm i playwright in a temporary directory (e.g. /tmp/sb-verify) — not in the repo
// `playwright` is now a repo devDependency,
// so there is no temporary install to do any more: run the script through
// `pnpm exec node <script.mjs>` and import it directly.
import { chromium } from 'playwright';
const browser = await chromium.launch({ channel: 'chrome', headless: true });
```

`channel: 'chrome'` uses the system Chrome, so no browser download is needed. If it
is missing, `pnpm exec playwright install chromium` fetches the bundled one — at the
version the repo pins, which is also the one `@storybook/test-runner` uses.

- URL of a single story: `http://localhost:6007/iframe.html?id=<story-id>`
- Story IDs: `curl -s localhost:6007/index.json` (`entries`), e.g.
`components-ui-forms-ui-input--signal-forms` (title `Components/ui/forms/ui-input` → kebab).
Expand Down
17 changes: 16 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
version: 2

updates:
# npm : cadence hebdomadaire + regroupement par famille technique. Sans ça,
# L'écosystème s'appelle toujours `npm` chez Dependabot : c'est le nom du
# REGISTRE, pas du client. Il lit `pnpm-lock.yaml` (v9) sous cette clé — il n'y
# a pas d'écosystème `pnpm` à basculer
#
# ⚠️ Interaction avec `minimumReleaseAge: 1440` (pnpm-workspace.yaml) : une PR
# qui propose une version publiée depuis moins de 24 h échoue à l'install
# (« no version satisfies minimumReleaseAge »), puis passe d'elle-même à la
# relance suivante. La cadence hebdomadaire ci-dessous rend le cas peu
# fréquent ; pour un correctif de sécurité à prendre tout de suite, passer par
# `minimumReleaseAgeExclude`.
#
# Cadence hebdomadaire + regroupement par famille technique. Sans ça,
# Angular (22.0.x → 22.1.x → ...), Storybook et l'outillage ESLint génèrent
# chacun leur propre PR à chaque bump — sur cette stack (Angular 22,
# Storybook 10, ng-packagr, Style Dictionary), le bruit ferait abandonner
Expand All @@ -22,6 +33,8 @@ updates:
- '@storybook/*'
- '@storybook-community/*'
- 'storybook'
- 'playwright'
- 'axe-playwright'
eslint:
patterns:
- 'eslint*'
Expand All @@ -37,6 +50,8 @@ updates:
- '@storybook/*'
- '@storybook-community/*'
- 'storybook'
- 'playwright'
- 'axe-playwright'
- 'eslint*'
- '@eslint/*'
- 'typescript-eslint'
Expand Down
16 changes: 11 additions & 5 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
name: Build Storybook and demo app
runs-on: ubuntu-latest
steps:
# fetch-depth 0 : `npm run build-storybook` calls `build-info.mjs`, which
# fetch-depth 0 : `pnpm build-storybook` calls `build-info.mjs`, which
# runs `git describe --tags` to find the last published version. A
# shallow checkout (the default) fetches no tags, so the "ahead of
# X.Y.Z" part of the label would silently disappear.
Expand All @@ -42,28 +42,34 @@ jobs:
id: nvmrc
run: echo "NODE_VERSION=$(cat .nvmrc)" >> $GITHUB_OUTPUT

# Avant `setup-node` : c'est la présence de `pnpm` sur le PATH qui permet à
# setup-node de localiser le store à mettre en cache. La version installée
# vient du champ `packageManager` du package.json — un seul endroit à bumper.
- name: Install pnpm
uses: pnpm/action-setup@v6

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }}
cache: 'npm'
cache: 'pnpm'

- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile

- name: Setup Pages
uses: actions/configure-pages@v6

- name: Build Storybook
run: npm run build-storybook
run: pnpm build-storybook

- name: Fix base href for GitHub Pages
run: |
sed -i -e 's|<head>|<head><base href="'"$PAGES_BASE"'">|' storybook-static/index.html
sed -i -e 's|<head>|<head><base href="'"$PAGES_BASE"'">|' storybook-static/iframe.html

- name: Build demo application
run: npm run build -- --configuration production --base-href "$DEMO_BASE"
run: pnpm build --configuration production --base-href "$DEMO_BASE"

- name: Assemble the Pages artifact
run: |
Expand Down
58 changes: 44 additions & 14 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,39 @@ jobs:
id: nvmrc
run: echo "NODE_VERSION=$(cat .nvmrc)" >> $GITHUB_OUTPUT

# Avant `setup-node` : c'est la présence de `pnpm` sur le PATH qui permet à
# setup-node de localiser le store à mettre en cache. La version installée
# vient du champ `packageManager` du package.json — un seul endroit à bumper.
- name: Install pnpm
uses: pnpm/action-setup@v6

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }}
cache: 'npm'
cache: 'pnpm'

# `postinstall` chains tokens:build → ui-kit:build → docs:config, so this
# step already proves the 53 entry points compile. A failing package build
# fails the install, before any check below runs.
- name: Install dependencies (builds tokens + package)
run: npm ci
run: pnpm install --frozen-lockfile

# `npm run lint` carries --fix: it repairs instead of reporting, so in CI
# `pnpm lint` carries --fix: it repairs instead of reporting, so in CI
# it would never fail. lint:check is the same target without it.
- name: Lint
run: npm run lint:check
run: pnpm lint:check

- name: Typecheck the demo app
run: npx tsc -p tsconfig.app.json --noEmit
run: pnpm exec tsc -p tsconfig.app.json --noEmit

# FSHSP-93: unit tests on the kit (vitest, via the `test` architect
# target). Covers both the pure-logic specs (mask engine, option
# resolver, date helpers, label formatting) and the TestBed component
# specs (select, autocomplete, input-tags, segment-control, tabs, modal,
# accordion, base CVA).
- name: Unit tests
run: npm run test
run: pnpm test

# `postinstall` has just regenerated everything `docs:config` produces, so
# this step looks redundant. It is not — it enforces two things nothing
Expand All @@ -72,7 +78,7 @@ jobs:
# - The hand-written component lists, via the `components:check` this
# chains — the six places that claim to describe `projects/ui-kit/`.
- name: Check the docs (lists, conventions, quoted counts)
run: npm run docs:config:check
run: pnpm docs:config:check

# The opposite case, which the step above CANNOT catch: two of those
# generated files are committed — `component-vars.scss` ships in the
Expand Down Expand Up @@ -100,17 +106,23 @@ jobs:
id: nvmrc
run: echo "NODE_VERSION=$(cat .nvmrc)" >> $GITHUB_OUTPUT

# Avant `setup-node` : c'est la présence de `pnpm` sur le PATH qui permet à
# setup-node de localiser le store à mettre en cache. La version installée
# vient du champ `packageManager` du package.json — un seul endroit à bumper.
- name: Install pnpm
uses: pnpm/action-setup@v6

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }}
cache: 'npm'
cache: 'pnpm'

- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile

- name: Build Storybook
run: npm run build-storybook
run: pnpm build-storybook

# Consumed by the `a11y` job below — avoids rebuilding Storybook twice.
- name: Upload Storybook build
Expand Down Expand Up @@ -139,23 +151,41 @@ jobs:
id: nvmrc
run: echo "NODE_VERSION=$(cat .nvmrc)" >> $GITHUB_OUTPUT

# Avant `setup-node` : c'est la présence de `pnpm` sur le PATH qui permet à
# setup-node de localiser le store à mettre en cache. La version installée
# vient du champ `packageManager` du package.json — un seul endroit à bumper.
- name: Install pnpm
uses: pnpm/action-setup@v6

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }}
cache: 'npm'
cache: 'pnpm'

- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile

- name: Download Storybook build
uses: actions/download-artifact@v8
with:
name: storybook-static
path: storybook-static

# `playwright` est une devDependency DÉCLARÉE, et doit le rester (FSHSP-177).
# Sous npm cette étape était un `npx playwright install` : npx va chercher le
# paquet sur le registre s'il manque, et npm aplatissait de toute façon le
# binaire transitif dans node_modules/.bin. pnpm ne fait ni l'un ni l'autre —
# `pnpm exec` ne lance QUE ce qui est déclaré.
#
# Ne pas « simplifier » en `pnpm dlx playwright` : dlx tire `latest`, donc les
# navigateurs installés ne correspondraient plus au `playwright-core` que
# `@storybook/test-runner` et `axe-playwright` résolvent, et les tests
# échoueraient sur « Executable doesn't exist » — sans bruit, ce job étant
# `continue-on-error`. Pour la même raison, `playwright` est groupé avec
# `storybook` dans dependabot.yml : les trois doivent bouger ensemble.
- name: Install Playwright's Chromium
run: npx playwright install --with-deps chromium
run: pnpm exec playwright install --with-deps chromium

- name: Run accessibility checks (axe-core via test-runner)
run: npm run test-storybook:ci
run: pnpm test-storybook:ci
Loading