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
2 changes: 1 addition & 1 deletion .claude/skills/contributing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
160 changes: 160 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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/<Category>/<ComponentName>"` (e.g. `Buttons`, `Form`, `Navigation`). Top-level groups `Content`, `Layout`, and `Base` skip the `Components` segment — `"TEDI-Ready/Content/<ComponentName>"`, 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: `<tedi-my-component [formControl]="control" />`
})
class TestHostComponent {
control = new FormControl<ValueType>(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.
161 changes: 1 addition & 160 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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/<Category>/<ComponentName>"` (e.g. `Buttons`, `Form`, `Navigation`). Top-level groups `Content`, `Layout`, and `Base` skip the `Components` segment — `"TEDI-Ready/Content/<ComponentName>"`, 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: `<tedi-my-component [formControl]="control" />`
})
class TestHostComponent {
control = new FormControl<ValueType>(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
Loading