diff --git a/.claude/skills/contributing/SKILL.md b/.claude/skills/contributing/SKILL.md index c915656ad..60f72eca6 100644 --- a/.claude/skills/contributing/SKILL.md +++ b/.claude/skills/contributing/SKILL.md @@ -14,7 +14,7 @@ You are a senior Angular and TypeScript engineer specializing in accessible UI c ## Before Any Code -1. Read `CLAUDE.md` at the project root for commands, architecture, and conventions. +1. Read `AGENTS.md` at the project root for commands, architecture, and conventions. 2. Read [best-practices](references/best-practices.md) for coding patterns. 3. If creating or modifying a component, check if TEDI React (`../react/src/tedi/components/`) has an equivalent — use as behavioral reference. 4. Check TEDI Core (`../core/src/`) for available design tokens, mixins, and shared styles. diff --git a/.coderabbit.yaml b/.coderabbit.yaml index f5b31c60b..157489db0 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -24,7 +24,7 @@ reviews: - path: "**" instructions: | Read and enforce the project conventions from these files: - - `CLAUDE.md` — project overview, architecture, component patterns, styling rules, testing setup, and "Do NOT" list. + - `AGENTS.md` — project overview, architecture, component patterns, styling rules, testing setup, and "Do NOT" list. - `.claude/skills/contributing/references/best-practices.md` — detailed coding patterns for components, SCSS, testing, stories, and barrel exports. Key things to NOT flag as issues: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..f6b5d4464 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,160 @@ +# AGENTS.md + +Guidance for AI coding agents working in this repository. + +## Project Overview + +TEDI Design System Angular component library (`@tedi-design-system/angular`). Angular 19 standalone component library published via ng-packagr, with Storybook for documentation. + +## Commands + +```bash +npm start # Start Storybook dev server (port 6006) +npm test # Run all tests (Jest) +npm run test:watch # Run tests in watch mode +npx jest path/to/file # Run a single test file +npm run lint # Stylelint (SCSS) + ESLint (TS/HTML) with --fix +npm run build # Build library to dist/ +``` + +## Architecture + +### Directory Layout + +- `src/tedi/components/` — All UI components, organized by category (form, buttons, overlay, etc.) +- `src/tedi/directives/` — Attribute/structural directives +- `src/tedi/services/` — Services (translation, theme, breakpoint, toast) +- `src/tedi/utils/` — Utility functions (date, cookies, elements) +- `src/tedi/tokens/` — Injection tokens (theme, translation) +- `src/tedi/providers/` — Angular providers +- `src/community/` — Community-contributed components (separate entry point, NOT a reference for TEDI patterns) + +> The library lives under `src/` (`src/tedi`, `src/community`), with `src/package.json` + `src/ng-package.json` as the ng-packagr primary entry point. The root `package.json` is the workspace/tooling manifest. This mirrors the React repo's `src/` layout — see issue #166. + +### Component File Convention + +Each component folder contains: +```text +component-name.component.ts # Component class +component-name.component.html # Template +component-name.component.scss # Styles +component-name.component.spec.ts # Tests +component-name.stories.ts # Storybook stories +index.ts # Barrel export +``` + +### Component Patterns + +All components are: +- **Standalone** (`standalone: true`) +- **OnPush** change detection +- **ViewEncapsulation.None** (styles not encapsulated) +- Using **Angular signals** (`input()`, `model()`, `signal()`, `computed()`) +- Selector prefix: `tedi-` (e.g., `tedi-button`, `tedi-date-picker`) + +Form controls implement `ControlValueAccessor` with `NG_VALUE_ACCESSOR` provider for reactive forms integration. + +### Export Chain + +`src/public-api.ts` → `src/tedi/index.ts` → category `index.ts` → component `index.ts` + +Path aliases: +- `@tedi-design-system/angular/tedi` → `./src/tedi/index.ts` +- `@tedi-design-system/angular/community` → `./src/community/index.ts` + +## Styling + +- BEM with `tedi-` prefix: `.tedi-component`, `.tedi-component__element`, `.tedi-component--modifier` +- Sub-components that are their own Angular components are **separate BEM blocks** with a shared prefix: `tedi-modal-header`, `tedi-modal-footer` (not `tedi-modal__header`). Use `__` elements only for simple DOM nodes inside a single component's template (e.g., `tedi-modal-header__head`). +- Stylelint enforces the `tedi-` prefix pattern on all class selectors +- Design tokens come from `@tedi-design-system/core` +- Max nesting depth: 4 +- **Target CSS classes, not Angular element selectors** — add classes to component hosts and style those. Only style element selectors directly for third-party components where you can't control the host (e.g., `cdk-dialog-container`). + +## Testing + +- Jest with `jest-preset-angular`, jsdom environment +- Coverage thresholds: 80% on branches/functions/lines/statements +- Test inputs via `fixture.componentRef.setInput('propName', value)` +- Mock `TediTranslationService` in tests that use translated components +- For form controls, use a test host component with `ReactiveFormsModule` and `FormControl` + +## Storybook + +- Stories at `src/tedi/**/*.stories.ts` +- Title format: `"TEDI-Ready/Components//"` (e.g. `Buttons`, `Form`, `Navigation`). Top-level groups `Content`, `Layout`, and `Base` skip the `Components` segment — `"TEDI-Ready/Content/"`, etc. Check sibling stories in the same folder to confirm the prefix. +- Uses `moduleMetadata` decorator for imports +- Status parameters: `partiallyTediReady`, `existsInTediReady`, `devComponent`, etc. +- Compodoc integration enabled for auto-generated docs + +## Commits + +- Conventional commits enforced by commitlint +- Must reference an issue (e.g., `feat(date-picker): add feature #258`) +- Subject minimum 10 characters +- Pre-commit hook runs lint-staged (stylelint + prettier) + +## Related Repositories + +- **TEDI React** (`../react/`) — React implementation of the same design system. Useful as behavioral reference. +- **TEDI Core** (`../core/`) — Shared design tokens, SCSS variables, fonts, and icons. + +> **Note:** These sibling repositories are available in local development only. They are NOT present in CI/CD environments — do not rely on `../react/` or `../core/` paths in build scripts, tests, or imports that run in CI. + +## Branches + +- `main` — production releases +- `rc` — pre-releases (base branch for PRs) + +## Do NOT + +- Use `@Input()`, `@Output()`, or `@ViewChild()` decorators — use `input()`, `model()`, `output()`, `viewChild()` signal APIs +- Use `ViewEncapsulation.Emulated` or `ShadowDom` — always `ViewEncapsulation.None` +- Hardcode color values — always use design tokens from `@tedi-design-system/core` +- Use fallback values in CSS `var()` functions — write `var(--token-name)`, not `var(--token-name, fallback)` +- Use Angular encapsulation for style scoping — use BEM naming with `tedi-` prefix instead +- Forget `multi: true` in `NG_VALUE_ACCESSOR` providers +- Forget `forwardRef()` when a component references itself in its own providers +- Add event listeners without removing them in `ngOnDestroy` — use arrow function properties for correct reference +- Use regular methods for event handlers that need cleanup — use `handleX = (e: Event) => {}` property syntax +- Forget to provide `TediTranslationService` mock and `TEDI_TRANSLATION_DEFAULT_TOKEN` in tests +- Use `fakeAsync`/`tick` without cleaning up in `afterEach` +- Use `src/community/` components as reference for coding patterns or style — they are community-contributed and not always reviewed +- Forget to add `.parent__button:hover .tedi-icon { color: inherit; }` (and similar for selected/active states) in components that contain icons and change text color on state — without this, the icon's color modifier class wins over the parent's color. Use `color="inherit"` for component-owned icons; for projected icons, the CSS override ensures the consumer's color applies in default state but inherits on hover/selected +- Style Angular element selectors directly (e.g., `tedi-modal-header { ... }`) — add a CSS class to the host and style the class instead. Exception: third-party elements you can't add classes to (e.g., `cdk-dialog-container`) + +## Common Test Setup + +Tests that use translated components need: +```typescript +class TranslationMock { + translate(key: string) { return key; } + track(key: string) { return () => key; } +} + +// In TestBed providers: +{ provide: TediTranslationService, useClass: TranslationMock }, +{ provide: TEDI_TRANSLATION_DEFAULT_TOKEN, useValue: 'et' }, +``` + +Form control tests need a host component: +```typescript +@Component({ + standalone: true, + imports: [MyComponent, ReactiveFormsModule], + template: `` +}) +class TestHostComponent { + control = new FormControl(defaultValue); +} +``` + +## For Code Review Agents (CodeRabbit, etc.) + +Read `.claude/skills/contributing/references/best-practices.md` for the full set of coding patterns and rules to enforce during review. + +Key things to **not** flag: +- `ViewEncapsulation.None` — intentional, not a security concern. +- Missing CSS `var()` fallback values — intentionally omitted. +- CdkListbox private API access (`_setNextFocusToSelectedOption`, `_handleKeydown`) in the select component — intentional workarounds, no public CDK alternative exists. +- `parameters.status: { type: ["breakpointSupport"] }` on a story — this is a valid, registered status badge (see `.storybook/preview.tsx` and `best-practices.md`). Keep it on components with breakpoint-dependent behavior or inputs that accept breakpoint values. Do not suggest removing it. diff --git a/CLAUDE.md b/CLAUDE.md index a4a34f3ec..43c994c2d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,160 +1 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -TEDI Design System Angular component library (`@tedi-design-system/angular`). Angular 19 standalone component library published via ng-packagr, with Storybook for documentation. - -## Commands - -```bash -npm start # Start Storybook dev server (port 6006) -npm test # Run all tests (Jest) -npm run test:watch # Run tests in watch mode -npx jest path/to/file # Run a single test file -npm run lint # Stylelint (SCSS) + ESLint (TS/HTML) with --fix -npm run build # Build library to dist/ -``` - -## Architecture - -### Directory Layout - -- `src/tedi/components/` — All UI components, organized by category (form, buttons, overlay, etc.) -- `src/tedi/directives/` — Attribute/structural directives -- `src/tedi/services/` — Services (translation, theme, breakpoint, toast) -- `src/tedi/utils/` — Utility functions (date, cookies, elements) -- `src/tedi/tokens/` — Injection tokens (theme, translation) -- `src/tedi/providers/` — Angular providers -- `src/community/` — Community-contributed components (separate entry point, NOT a reference for TEDI patterns) - -> The library lives under `src/` (`src/tedi`, `src/community`), with `src/package.json` + `src/ng-package.json` as the ng-packagr primary entry point. The root `package.json` is the workspace/tooling manifest. This mirrors the React repo's `src/` layout — see issue #166. - -### Component File Convention - -Each component folder contains: -```text -component-name.component.ts # Component class -component-name.component.html # Template -component-name.component.scss # Styles -component-name.component.spec.ts # Tests -component-name.stories.ts # Storybook stories -index.ts # Barrel export -``` - -### Component Patterns - -All components are: -- **Standalone** (`standalone: true`) -- **OnPush** change detection -- **ViewEncapsulation.None** (styles not encapsulated) -- Using **Angular signals** (`input()`, `model()`, `signal()`, `computed()`) -- Selector prefix: `tedi-` (e.g., `tedi-button`, `tedi-date-picker`) - -Form controls implement `ControlValueAccessor` with `NG_VALUE_ACCESSOR` provider for reactive forms integration. - -### Export Chain - -`src/public-api.ts` → `src/tedi/index.ts` → category `index.ts` → component `index.ts` - -Path aliases: -- `@tedi-design-system/angular/tedi` → `./src/tedi/index.ts` -- `@tedi-design-system/angular/community` → `./src/community/index.ts` - -## Styling - -- BEM with `tedi-` prefix: `.tedi-component`, `.tedi-component__element`, `.tedi-component--modifier` -- Sub-components that are their own Angular components are **separate BEM blocks** with a shared prefix: `tedi-modal-header`, `tedi-modal-footer` (not `tedi-modal__header`). Use `__` elements only for simple DOM nodes inside a single component's template (e.g., `tedi-modal-header__head`). -- Stylelint enforces the `tedi-` prefix pattern on all class selectors -- Design tokens come from `@tedi-design-system/core` -- Max nesting depth: 4 -- **Target CSS classes, not Angular element selectors** — add classes to component hosts and style those. Only style element selectors directly for third-party components where you can't control the host (e.g., `cdk-dialog-container`). - -## Testing - -- Jest with `jest-preset-angular`, jsdom environment -- Coverage thresholds: 80% on branches/functions/lines/statements -- Test inputs via `fixture.componentRef.setInput('propName', value)` -- Mock `TediTranslationService` in tests that use translated components -- For form controls, use a test host component with `ReactiveFormsModule` and `FormControl` - -## Storybook - -- Stories at `src/tedi/**/*.stories.ts` -- Title format: `"TEDI-Ready/Components//"` (e.g. `Buttons`, `Form`, `Navigation`). Top-level groups `Content`, `Layout`, and `Base` skip the `Components` segment — `"TEDI-Ready/Content/"`, etc. Check sibling stories in the same folder to confirm the prefix. -- Uses `moduleMetadata` decorator for imports -- Status parameters: `partiallyTediReady`, `existsInTediReady`, `devComponent`, etc. -- Compodoc integration enabled for auto-generated docs - -## Commits - -- Conventional commits enforced by commitlint -- Must reference an issue (e.g., `feat(date-picker): add feature #258`) -- Subject minimum 10 characters -- Pre-commit hook runs lint-staged (stylelint + prettier) - -## Related Repositories - -- **TEDI React** (`../react/`) — React implementation of the same design system. Useful as behavioral reference. -- **TEDI Core** (`../core/`) — Shared design tokens, SCSS variables, fonts, and icons. - -> **Note:** These sibling repositories are available in local development only. They are NOT present in CI/CD environments — do not rely on `../react/` or `../core/` paths in build scripts, tests, or imports that run in CI. - -## Branches - -- `main` — production releases -- `rc` — pre-releases (base branch for PRs) - -## Do NOT - -- Use `@Input()`, `@Output()`, or `@ViewChild()` decorators — use `input()`, `model()`, `output()`, `viewChild()` signal APIs -- Use `ViewEncapsulation.Emulated` or `ShadowDom` — always `ViewEncapsulation.None` -- Hardcode color values — always use design tokens from `@tedi-design-system/core` -- Use fallback values in CSS `var()` functions — write `var(--token-name)`, not `var(--token-name, fallback)` -- Use Angular encapsulation for style scoping — use BEM naming with `tedi-` prefix instead -- Forget `multi: true` in `NG_VALUE_ACCESSOR` providers -- Forget `forwardRef()` when a component references itself in its own providers -- Add event listeners without removing them in `ngOnDestroy` — use arrow function properties for correct reference -- Use regular methods for event handlers that need cleanup — use `handleX = (e: Event) => {}` property syntax -- Forget to provide `TediTranslationService` mock and `TEDI_TRANSLATION_DEFAULT_TOKEN` in tests -- Use `fakeAsync`/`tick` without cleaning up in `afterEach` -- Use `src/community/` components as reference for coding patterns or style — they are community-contributed and not always reviewed -- Forget to add `.parent__button:hover .tedi-icon { color: inherit; }` (and similar for selected/active states) in components that contain icons and change text color on state — without this, the icon's color modifier class wins over the parent's color. Use `color="inherit"` for component-owned icons; for projected icons, the CSS override ensures the consumer's color applies in default state but inherits on hover/selected -- Style Angular element selectors directly (e.g., `tedi-modal-header { ... }`) — add a CSS class to the host and style the class instead. Exception: third-party elements you can't add classes to (e.g., `cdk-dialog-container`) - -## Common Test Setup - -Tests that use translated components need: -```typescript -class TranslationMock { - translate(key: string) { return key; } - track(key: string) { return () => key; } -} - -// In TestBed providers: -{ provide: TediTranslationService, useClass: TranslationMock }, -{ provide: TEDI_TRANSLATION_DEFAULT_TOKEN, useValue: 'et' }, -``` - -Form control tests need a host component: -```typescript -@Component({ - standalone: true, - imports: [MyComponent, ReactiveFormsModule], - template: `` -}) -class TestHostComponent { - control = new FormControl(defaultValue); -} -``` - -## For Code Review Agents (CodeRabbit, etc.) - -Read `.claude/skills/contributing/references/best-practices.md` for the full set of coding patterns and rules to enforce during review. - -Key things to **not** flag: -- `ViewEncapsulation.None` — intentional, not a security concern. -- Missing CSS `var()` fallback values — intentionally omitted. -- CdkListbox private API access (`_setNextFocusToSelectedOption`, `_handleKeydown`) in the select component — intentional workarounds, no public CDK alternative exists. -- `parameters.status: { type: ["breakpointSupport"] }` on a story — this is a valid, registered status badge (see `.storybook/preview.tsx` and `best-practices.md`). Keep it on components with breakpoint-dependent behavior or inputs that accept breakpoint values. Do not suggest removing it. +@AGENTS.md