Component Conventions

Rules every tip-* design-system component follows. New components should match these exactly so the library stays predictable to compose.

Component shape

Icons

@lucide/angular (v1 — not the deprecated lucide-angular package) has no <lucide-icon name="..."> component; every glyph is its own standalone component. tip-icon (src/app/ui/icon/icon.ts) wraps LucideDynamicIcon (svg[lucideIcon]) so call sites keep passing a plain kebab-case name string ("triangle-alert", "shield-alert"). Icons must be registered via provideLucideIcons(...) in app.config.ts before tip-icon can resolve them by name — adding a new icon means adding it to that registration, not just using the name in a template.

Testing

Vitest via @angular/build:unit-test (npm test from app/frontend/). Every tip-* component ships a co-located <name>.spec.ts covering: default render, each variant/tone, loading state, and output emission on interaction (click/change/keydown). Feature specs additionally cover route-driven state (e.g. order-details.spec.ts asserting the page renders the order resolved from the route param) and async transitions (Orders' skeleton → data → empty-state sequence).

Dependency direction

features/ → ui/ + core/data/. ui/ components are purely presentational (inputs/outputs only — no service injection, no routing). features/ compose ui/ components and read from core/data/ services (OrdersService, DashboardService, AuthService). Never inject a service directly into a ui/* component.