# Component Creation Template
## ⚠️ CRITICAL RESTRICTIONS ⚠️
### DO NOT MODIFY EXISTING COMPONENTS
- **NEVER** alter Angular or SCSS code of already built components
- **NEVER** change existing component files unless explicitly instructed
- **ONLY** create NEW components as specified in the task
- **ONLY** update integration files (routes, menu, public API) to add references to new components
- If asked to modify an existing component, REQUEST CLARIFICATION before proceeding
- Existing components are PRODUCTION CODE and must remain untouched
### Protected Files and Directories
The following should NEVER be modified without explicit permission:
- Any existing component files in `@projects/ui-essentials/src/lib/components/`
- Any existing demo files in `@projects/demo-ui-essentials/src/app/demos/`
- Only ADD new entries to:
- `demos.routes.ts` (add new cases, don't modify existing)
- `dashboard.component.ts` (add new menu items, don't modify existing)
- `public-api.ts` (add new exports, don't modify existing)
---
## Component Creation Task Template
### 1. Component Selection
- Alert/Notification
### 2. Pre-Development Checklist
- [ ] Check if similar component exists in codebase
- [ ] Review existing components in same category for patterns
- [ ] Identify required design tokens from semantic layer
- [ ] Plan component API (inputs, outputs, content projection)
- [ ] **CONFIRM: This is a NEW component, not a modification of an existing one**
### 3. Implementation Steps
#### Step 1: Create Component Structure
**Location:** `@projects/ui-essentials/src/lib/components/[category]/[component-name]/`
Create these NEW files (do not overwrite existing):
- `[component-name].component.ts`
- `[component-name].component.scss`
- `index.ts` (barrel export)
#### Step 2: SCSS Implementation
Follow the **Design Token Guidelines** below to create component styles.
#### Step 3: Angular Component Implementation
Follow the **Angular Component Guidelines** below.
#### Step 4: Create Demo Component
**Location:** `@projects/demo-ui-essentials/src/app/demos/[component-name]-demo/`
- Create NEW demo component showing all variants, sizes, and states
- Include interactive examples and code snippets
- Follow existing demo patterns
#### Step 5: Integration Updates (ADDITIVE ONLY)
##### A. Update Routes (ADD ONLY - DO NOT MODIFY EXISTING)
**File:** `@projects/demo-ui-essentials/src/app/demos/demos.routes.ts`
```typescript
// Add import - DO NOT MODIFY EXISTING IMPORTS
import { [ComponentName]DemoComponent } from './[component-name]-demo/[component-name]-demo.component';
// Add to template switch case - DO NOT MODIFY EXISTING CASES
@case ("[component-name]") {
}
// Add to imports array - DO NOT REMOVE OR MODIFY EXISTING ENTRIES
imports: [...existing, [ComponentName]DemoComponent]
```
##### B. Update Dashboard Menu (ADD ONLY - DO NOT MODIFY EXISTING)
**File:** `@projects/demo-ui-essentials/src/app/features/dashboard/dashboard.component.ts`
```typescript
// Import appropriate FontAwesome icon - DO NOT MODIFY EXISTING IMPORTS
import { faIconName } from '@fortawesome/free-solid-svg-icons';
// Add in ngOnInit() - DO NOT MODIFY EXISTING MENU ITEMS
this.addMenuItem("[component-id]", "[Component Label]", this.faIconName);
```
##### C. Update Public API (ADD ONLY - DO NOT MODIFY EXISTING)
**File:** `@projects/ui-essentials/src/public-api.ts`
```typescript
// Add export in appropriate section - DO NOT MODIFY EXISTING EXPORTS
export * from './lib/components/[category]/[component-name]';
```
### ⚠️ INTEGRATION WARNING ⚠️
When updating integration files:
- **ONLY ADD** new entries
- **NEVER DELETE** existing entries
- **NEVER MODIFY** existing entries
- **PRESERVE** all existing formatting and structure
- **TEST** that existing components still work after changes
---
## Design Token Guidelines ⚠️ CRITICAL: ONLY USE EXISTING TOKENS ⚠️
### MANDATORY: Import and Use Semantic Tokens
```scss
@use '@projects/shared-ui/src/styles/semantic' as *;
```
### 🚨 TOKEN VALIDATION RULES 🚨
- ❌ **NEVER** invent or guess token names
- ❌ **NEVER** use tokens not listed below
- ❌ **NEVER** hardcode values (px, rem, #hex colors, etc.)
- ✅ **ALWAYS** use semantic tokens for ALL values
- ✅ **ALWAYS** check this reference before using any token
- ✅ **ASK FOR GUIDANCE** if needed token doesn't exist
### Available Token Categories (VERIFIED ACTUAL TOKENS):
## 1. **COLORS** (Single Values - Use Directly)
```scss
// Text Colors
$semantic-color-text-primary // Primary text
$semantic-color-text-secondary // Secondary text
$semantic-color-text-tertiary // Tertiary text
$semantic-color-text-disabled // Disabled text
$semantic-color-text-inverse // Inverse text
// Surface Colors
$semantic-color-surface-primary // Primary surface
$semantic-color-surface-secondary // Secondary surface
$semantic-color-surface-elevated // Elevated surface
$semantic-color-surface // Base surface
$semantic-color-surface-container // Container surface
// Border Colors
$semantic-color-border-primary // Primary border
$semantic-color-border-secondary // Secondary border
$semantic-color-border-subtle // Subtle border
$semantic-color-border-focus // Focus border
$semantic-color-border-error // Error border
// Brand Colors
$semantic-color-primary // Primary brand
$semantic-color-secondary // Secondary brand
$semantic-color-on-primary // Text on primary
$semantic-color-on-secondary // Text on secondary
// Feedback Colors
$semantic-color-success // Success state
$semantic-color-warning // Warning state
$semantic-color-danger // Danger/error state
$semantic-color-info // Info state
$semantic-color-on-success // Text on success
$semantic-color-on-warning // Text on warning
$semantic-color-on-danger // Text on danger
$semantic-color-on-info // Text on info
// Focus and Interactive
$semantic-color-focus // Focus indicator
$semantic-color-interactive-primary // Interactive primary
$semantic-color-backdrop // Backdrop/overlay
```
## 2. **TYPOGRAPHY** (Maps and Single Values)
### Typography Maps (Use with map-get())
```scss
// Headings (Maps - Extract individual properties)
$semantic-typography-heading-h1 // h1 heading map
$semantic-typography-heading-h2 // h2 heading map
$semantic-typography-heading-h3 // h3 heading map
$semantic-typography-heading-h4 // h4 heading map
$semantic-typography-heading-h5 // h5 heading map
// Body Text (Maps)
$semantic-typography-body-large // Large body text map
$semantic-typography-body-medium // Medium body text map
$semantic-typography-body-small // Small body text map
// UI Components (Maps)
$semantic-typography-button-large // Large button text map
$semantic-typography-button-medium // Medium button text map
$semantic-typography-button-small // Small button text map
$semantic-typography-label // Form label map
$semantic-typography-input // Input text map
$semantic-typography-caption // Caption text map
// Usage Example for Maps:
font-family: map-get($semantic-typography-body-medium, font-family);
font-size: map-get($semantic-typography-body-medium, font-size);
font-weight: map-get($semantic-typography-body-medium, font-weight);
line-height: map-get($semantic-typography-body-medium, line-height);
```
### Typography Single Values (Use Directly)
```scss
// Font Weights
$semantic-typography-font-weight-normal
$semantic-typography-font-weight-medium
$semantic-typography-font-weight-semibold
$semantic-typography-font-weight-bold
// Font Sizes
$semantic-typography-font-size-xs
$semantic-typography-font-size-sm
$semantic-typography-font-size-md
$semantic-typography-font-size-lg
$semantic-typography-font-size-xl
$semantic-typography-font-size-2xl
$semantic-typography-font-size-3xl
// Line Heights
$semantic-typography-line-height-tight
$semantic-typography-line-height-normal
$semantic-typography-line-height-relaxed
// Font Families
$semantic-typography-font-family-sans
$semantic-typography-font-family-serif
$semantic-typography-font-family-mono
```
## 3. **SPACING** (Single Values - Use Directly)
```scss
// Component Spacing
$semantic-spacing-component-xs // Extra small component spacing
$semantic-spacing-component-sm // Small component spacing
$semantic-spacing-component-md // Medium component spacing
$semantic-spacing-component-lg // Large component spacing
$semantic-spacing-component-xl // Extra large component spacing
// Layout Spacing
$semantic-spacing-layout-section-xs // Extra small section spacing
$semantic-spacing-layout-section-sm // Small section spacing
$semantic-spacing-layout-section-md // Medium section spacing
$semantic-spacing-layout-section-lg // Large section spacing
$semantic-spacing-layout-section-xl // Extra large section spacing
// Content Spacing
$semantic-spacing-content-paragraph // Paragraph spacing
$semantic-spacing-content-heading // Heading spacing
$semantic-spacing-content-list-item // List item spacing
$semantic-spacing-content-line-tight // Tight line spacing
// Interactive Spacing
$semantic-spacing-interactive-button-padding-x // Button horizontal padding
$semantic-spacing-interactive-button-padding-y // Button vertical padding
$semantic-spacing-interactive-input-padding-x // Input horizontal padding
$semantic-spacing-interactive-input-padding-y // Input vertical padding
// Grid and Stack Spacing
$semantic-spacing-grid-gap-sm // Small grid gap
$semantic-spacing-grid-gap-md // Medium grid gap
$semantic-spacing-grid-gap-lg // Large grid gap
$semantic-spacing-stack-sm // Small stack spacing
$semantic-spacing-stack-md // Medium stack spacing
$semantic-spacing-stack-lg // Large stack spacing
// Form Spacing
$semantic-spacing-form-field-gap // Form field gap
$semantic-spacing-form-group-gap // Form group gap
```
## 4. **BORDERS** (Single Values - Use Directly)
```scss
// Border Widths
$semantic-border-width-1 // 1px border
$semantic-border-width-2 // 2px border
$semantic-border-card-width // Standard card border width
// Border Radius
$semantic-border-radius-sm // Small radius
$semantic-border-radius-md // Medium radius
$semantic-border-radius-lg // Large radius
$semantic-border-radius-xl // Extra large radius
$semantic-border-radius-full // Full/circle radius
// Component Borders
$semantic-border-button-radius // Button border radius
$semantic-border-input-radius // Input border radius
$semantic-border-card-radius // Card border radius
```
## 5. **SHADOWS** (Single Values - Use Directly)
```scss
// Elevation Shadows
$semantic-shadow-elevation-0 // No shadow
$semantic-shadow-elevation-1 // Level 1 elevation
$semantic-shadow-elevation-2 // Level 2 elevation
$semantic-shadow-elevation-3 // Level 3 elevation
$semantic-shadow-elevation-4 // Level 4 elevation
$semantic-shadow-elevation-5 // Level 5 elevation
// Component Shadows
$semantic-shadow-card-rest // Card default shadow
$semantic-shadow-card-hover // Card hover shadow
$semantic-shadow-button-rest // Button default shadow
$semantic-shadow-button-hover // Button hover shadow
$semantic-shadow-dropdown // Dropdown shadow
$semantic-shadow-modal // Modal shadow
```
## 6. **MOTION** (Single Values and Maps)
### Motion Single Values (Use Directly)
```scss
// Duration
$semantic-motion-duration-fast // Fast duration
$semantic-motion-duration-normal // Normal duration
$semantic-motion-duration-slow // Slow duration
// Easing
$semantic-motion-easing-ease // Standard easing
$semantic-motion-easing-ease-in-out // Ease in-out
$semantic-motion-easing-spring // Spring easing
```
## 7. **SIZING** (Single Values - Use Directly)
```scss
// Button Heights
$semantic-sizing-button-height-sm // Small button height
$semantic-sizing-button-height-md // Medium button height
$semantic-sizing-button-height-lg // Large button height
// Input Heights
$semantic-sizing-input-height-sm // Small input height
$semantic-sizing-input-height-md // Medium input height
$semantic-sizing-input-height-lg // Large input height
// Icon Sizes
$semantic-sizing-icon-inline // Inline icon size
$semantic-sizing-icon-button // Button icon size
$semantic-sizing-icon-navigation // Navigation icon size
// Touch Targets
$semantic-sizing-touch-minimum // Minimum touch target
$semantic-sizing-touch-target // Standard touch target
```
## 8. **Z-INDEX** (Single Values - Use Directly)
```scss
$semantic-z-index-dropdown // Dropdown layer
$semantic-z-index-modal // Modal layer
$semantic-z-index-tooltip // Tooltip layer
$semantic-z-index-overlay // Overlay layer
```
## 9. **OPACITY** (Single Values - Use Directly)
```scss
$semantic-opacity-disabled // Disabled opacity
$semantic-opacity-hover // Hover opacity
$semantic-opacity-backdrop // Backdrop opacity
$semantic-opacity-subtle // Subtle opacity
```
### Strict Rules:
- ❌ **NEVER** hardcode values (px, rem, #hex colors, etc.)
- ❌ **NEVER** use base tokens directly (from `/base/` directory)
- ❌ **NEVER** use magic numbers
- ✅ **ALWAYS** use semantic tokens for ALL values
- ✅ **ALWAYS** follow BEM naming convention for classes
- ✅ **ALWAYS** use SCSS nesting appropriately (max 3 levels)
- ✅ **ALWAYS** include responsive breakpoints using `$semantic-breakpoint-*` tokens
- ✅ **ALWAYS** maintain consistency with existing components
### Component SCSS Template (CORRECTED)
```scss
@use '@projects/shared-ui/src/styles/semantic' as *;
.ui-[component-name] {
// Core Structure
display: flex;
position: relative;
// Layout & Spacing - ONLY USE ACTUAL TOKENS
padding: $semantic-spacing-component-md;
margin: $semantic-spacing-layout-section-sm;
// Visual Design - ONLY USE ACTUAL TOKENS
background: $semantic-color-surface-primary;
border: $semantic-border-card-width solid $semantic-color-border-primary;
border-radius: $semantic-border-card-radius;
box-shadow: $semantic-shadow-elevation-1;
// Typography - USE MAP-GET FOR MAPS, SINGLE VALUES DIRECTLY
font-family: map-get($semantic-typography-body-medium, font-family);
font-size: map-get($semantic-typography-body-medium, font-size);
font-weight: map-get($semantic-typography-body-medium, font-weight);
line-height: map-get($semantic-typography-body-medium, line-height);
color: $semantic-color-text-primary;
// Transitions - ONLY USE ACTUAL TOKENS
transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease;
// Sizing Variants - ONLY USE ACTUAL TOKENS
&--sm {
min-height: $semantic-sizing-button-height-sm;
padding: $semantic-spacing-component-xs;
font-family: map-get($semantic-typography-body-small, font-family);
font-size: map-get($semantic-typography-body-small, font-size);
font-weight: map-get($semantic-typography-body-small, font-weight);
line-height: map-get($semantic-typography-body-small, line-height);
}
&--md {
min-height: $semantic-sizing-button-height-md;
padding: $semantic-spacing-component-sm;
// Typography already set above for medium
}
&--lg {
min-height: $semantic-sizing-button-height-lg;
padding: $semantic-spacing-component-lg;
font-family: map-get($semantic-typography-body-large, font-family);
font-size: map-get($semantic-typography-body-large, font-size);
font-weight: map-get($semantic-typography-body-large, font-weight);
line-height: map-get($semantic-typography-body-large, line-height);
}
// Color Variants - ONLY USE ACTUAL TOKENS
&--primary {
background: $semantic-color-primary;
color: $semantic-color-on-primary;
border-color: $semantic-color-primary;
}
&--secondary {
background: $semantic-color-secondary;
color: $semantic-color-on-secondary;
border-color: $semantic-color-secondary;
}
&--success {
background: $semantic-color-success;
color: $semantic-color-on-success;
border-color: $semantic-color-success;
}
&--danger {
background: $semantic-color-danger;
color: $semantic-color-on-danger;
border-color: $semantic-color-danger;
}
// State Variants - ONLY USE ACTUAL TOKENS
&--disabled {
opacity: $semantic-opacity-disabled;
cursor: not-allowed;
pointer-events: none;
}
// BEM Element - ONLY USE ACTUAL TOKENS
&__element {
padding: $semantic-spacing-content-line-tight;
color: $semantic-color-text-secondary;
// Element modifier
&--active {
color: $semantic-color-text-primary;
font-weight: $semantic-typography-font-weight-semibold;
}
}
// Interactive States - ONLY USE ACTUAL TOKENS
&:not(.ui-[component-name]--disabled) {
&:hover {
box-shadow: $semantic-shadow-card-hover;
}
&:focus-visible {
outline: 2px solid $semantic-color-focus;
outline-offset: 2px;
}
&:active {
box-shadow: $semantic-shadow-card-rest;
}
}
// Responsive Design - USE ACTUAL BREAKPOINT TOKENS
@media (max-width: $semantic-breakpoint-md - 1) {
padding: $semantic-spacing-component-sm;
}
@media (max-width: $semantic-breakpoint-sm - 1) {
padding: $semantic-spacing-component-xs;
font-family: map-get($semantic-typography-body-small, font-family);
font-size: map-get($semantic-typography-body-small, font-size);
font-weight: map-get($semantic-typography-body-small, font-weight);
line-height: map-get($semantic-typography-body-small, line-height);
}
}
```
### 🚨 CRITICAL TOKEN VALIDATION 🚨
#### ❌ COMMON MISTAKES TO AVOID:
```scss
// WRONG - These tokens DON'T EXIST:
font-size: $semantic-typography-heading-h3; // This is a MAP, not a single value!
padding: $semantic-spacing-layout-xs; // DOESN'T EXIST
box-shadow: $semantic-shadow-card-featured; // DOESN'T EXIST
border-radius: $semantic-border-radius-xs; // DOESN'T EXIST
transition: $semantic-motion-duration-medium; // DOESN'T EXIST
background: $semantic-color-background-primary; // DOESN'T EXIST
// WRONG - Hardcoded values:
padding: 16px; // Use $semantic-spacing-component-md
color: #333333; // Use $semantic-color-text-primary
border-radius: 8px; // Use $semantic-border-radius-md
```
#### ✅ CORRECT USAGE:
```scss
// RIGHT - Use map-get for typography maps:
font-size: map-get($semantic-typography-heading-h3, font-size);
font-weight: map-get($semantic-typography-heading-h3, font-weight);
// RIGHT - Use single value tokens directly:
padding: $semantic-spacing-component-md;
color: $semantic-color-text-primary;
border-radius: $semantic-border-card-radius;
box-shadow: $semantic-shadow-elevation-2;
```
### ⚠️ MAP USAGE WARNING ⚠️
These tokens are **MAPS** and require `map-get()`:
- `$semantic-typography-heading-*` (h1, h2, h3, h4, h5)
- `$semantic-typography-body-*` (large, medium, small)
- `$semantic-typography-button-*` (large, medium, small)
- `$semantic-typography-label`
- `$semantic-typography-input`
- `$semantic-typography-caption`
**Always extract individual properties:**
```scss
// CORRECT MAP USAGE:
font-family: map-get($semantic-typography-body-medium, font-family);
font-size: map-get($semantic-typography-body-medium, font-size);
font-weight: map-get($semantic-typography-body-medium, font-weight);
line-height: map-get($semantic-typography-body-medium, line-height);
```
### Expected Deliverables:
1. **SCSS file** properly structured with ONLY existing semantic tokens
2. **BEM methodology** consistently applied throughout
3. **Responsive design** using actual breakpoint tokens
4. **Interactive states** (hover, focus, active) defined with real tokens
5. **Zero hardcoded values** - everything uses verified design tokens
6. **Proper map usage** for typography tokens
7. **Comments** explaining major sections if complex
### Quality Checklist:
- [ ] All colors use actual `$semantic-color-*` tokens
- [ ] All spacing uses actual `$semantic-spacing-*` tokens
- [ ] All typography uses proper map-get() for maps or single tokens
- [ ] All shadows use actual `$semantic-shadow-*` tokens
- [ ] All borders use actual `$semantic-border-*` tokens
- [ ] All motion uses actual `$semantic-motion-*` tokens
- [ ] **No hardcoded values anywhere**
- [ ] **No invented token names**
- [ ] BEM naming convention followed
- [ ] Responsive breakpoints implemented with actual tokens
- [ ] File saved in correct directory
---
## Angular Component Guidelines (Enhanced)
### Angular 19+ Development Standards:
#### TEMPLATES:
- Use inline templates in @Component decorator
- Use new control flow syntax: @if, @for, @switch (NOT *ngIf, *ngFor)
- Use @defer for lazy loading where appropriate
- Put stylesheets in a separate scss file to the component
#### STYLING:
- Import design tokens: @use '@projects/shared-ui/src/styles/semantic' as *;
- **CRITICAL:** Ensure correct semantic tokens are used. Do not invent new ones.
- **If a semantic variable is required but doesn't exist, ASK FOR INSTRUCTION**
- NO hardcoded values - use only design tokens for colors, spacing, typography, breakpoints
- Follow BEM naming convention for class names
- Use SCSS nesting judiciously (max 3 levels)
- Prefer mixins and functions from the design system
#### TYPESCRIPT:
- Use standalone components (no NgModules)
- Prefer signals over observables for state management
- Use inject() function over constructor injection
- Strong typing everywhere - avoid 'any'
- Use readonly where applicable
- Implement OnPush change detection by default
#### STRUCTURE:
- Feature-based folder structure
- Barrel exports for clean imports
- Smart/presentational component pattern
- Services should be provided in root unless scoped needed
### Component Template
```typescript
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
type ComponentSize = 'sm' | 'md' | 'lg';
type ComponentVariant = 'primary' | 'secondary' | 'success' | 'danger';
@Component({
selector: 'ui-[component-name]',
standalone: true,
imports: [CommonModule],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
template: `
@if (loading) {
}
`,
styleUrl: './[component-name].component.scss'
})
export class [ComponentName]Component {
@Input() size: ComponentSize = 'md';
@Input() variant: ComponentVariant = 'primary';
@Input() disabled = false;
@Input() loading = false;
@Input() role = '[appropriate-aria-role]';
@Input() tabIndex = 0;
@Output() clicked = new EventEmitter();
handleClick(event: MouseEvent): void {
if (!this.disabled && !this.loading) {
this.clicked.emit(event);
}
}
handleKeydown(event: KeyboardEvent): void {
// Implement keyboard navigation
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.handleClick(event as any);
}
}
}
```
### Demo Component Template
```typescript
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { [ComponentName]Component } from '../[component-name].component';
@Component({
selector: 'ui-[component-name]-demo',
standalone: true,
imports: [CommonModule, [ComponentName]Component],
template: `
[Component Name] Demo
Sizes
@for (size of sizes; track size) {
{{ size }} size
}
Variants
@for (variant of variants; track variant) {
{{ variant }}
}
Interactive
Click me
Clicked: {{ clickCount }} times
`,
styleUrl: './[component-name]-demo.component.scss'
})
export class [ComponentName]DemoComponent {
sizes = ['sm', 'md', 'lg'] as const;
variants = ['primary', 'secondary', 'success', 'danger'] as const;
clickCount = 0;
handleDemoClick(event: MouseEvent): void {
this.clickCount++;
console.log('Component clicked', event);
}
}
```
### Component Requirements
- **Design Tokens**: Use ONLY verified semantic tokens throughout
- **Variants**: Include common UI system variants (colors, styles)
- **Sizes**: sm, md, lg sizing options
- **States**: hover, focus, active, disabled
- **Accessibility**: ARIA support, keyboard navigation
---
## Testing Requirements
### Unit Test Template
```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { [ComponentName]Component } from './[component-name].component';
describe('[ComponentName]Component', () => {
let component: [ComponentName]Component;
let fixture: ComponentFixture<[ComponentName]Component>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [[ComponentName]Component]
}).compileComponents();
fixture = TestBed.createComponent([ComponentName]Component);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should apply size classes correctly', () => {
component.size = 'lg';
fixture.detectChanges();
const element = fixture.nativeElement.querySelector('.ui-[component-name]');
expect(element).toHaveClass('ui-[component-name]--lg');
});
it('should handle disabled state', () => {
component.disabled = true;
fixture.detectChanges();
const element = fixture.nativeElement.querySelector('.ui-[component-name]');
expect(element).toHaveClass('ui-[component-name]--disabled');
expect(element.getAttribute('aria-disabled')).toBe('true');
});
it('should emit click events when not disabled', () => {
spyOn(component.clicked, 'emit');
const element = fixture.nativeElement.querySelector('.ui-[component-name]');
element.click();
expect(component.clicked.emit).toHaveBeenCalled();
});
it('should not emit click events when disabled', () => {
component.disabled = true;
spyOn(component.clicked, 'emit');
const element = fixture.nativeElement.querySelector('.ui-[component-name]');
element.click();
expect(component.clicked.emit).not.toHaveBeenCalled();
});
it('should support keyboard navigation', () => {
spyOn(component, 'handleClick');
const element = fixture.nativeElement.querySelector('.ui-[component-name]');
const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
element.dispatchEvent(enterEvent);
expect(component.handleClick).toHaveBeenCalled();
});
});
```
---
## Component Quality Checklist
### ⚠️ PRE-FLIGHT CHECK ⚠️
- [ ] **CONFIRMED: Creating NEW component, not modifying existing**
- [ ] **VERIFIED: No existing component files will be altered**
- [ ] **CHECKED: Only adding to integration files, not modifying**
### Functionality
- [ ] All size variants work correctly (sm, md, lg)
- [ ] All color variants apply properly
- [ ] Disabled state prevents interaction
- [ ] Loading state shows indicator
- [ ] Events emit correctly
- [ ] Content projection works
### Styling ⚠️ CRITICAL VALIDATION ⚠️
- [ ] **Uses ONLY verified existing semantic tokens**
- [ ] **NO HARDCODED VALUES** (px, rem, hex colors)
- [ ] **NO INVENTED TOKEN NAMES**
- [ ] Responsive on all breakpoints
- [ ] Follows BEM naming convention
- [ ] Proper state transitions
- [ ] Map tokens used with map-get()
### Accessibility
- [ ] Proper ARIA attributes
- [ ] Keyboard navigable
- [ ] Focus indicators visible
- [ ] Screen reader friendly
- [ ] Meets WCAG 2.1 AA standards
- [ ] Color contrast sufficient
### Code Quality
- [ ] TypeScript strictly typed
- [ ] OnPush change detection
- [ ] Standalone component
- [ ] Proper imports/exports
- [ ] Demo shows all features
- [ ] Unit tests pass
### Integration
- [ ] Added to public API (additive only)
- [ ] Demo route configured (additive only)
- [ ] Menu item added to dashboard (additive only)
- [ ] Build passes without errors
- [ ] Follows project conventions
- [ ] **Existing components still work**
---
## 🚨 FINAL TOKEN VALIDATION 🚨
### Before Implementation:
1. **VERIFY** every token used exists in the reference above
2. **ASK FOR HELP** if you need a token that doesn't exist
3. **TEST** build process to catch any invalid tokens
4. **NEVER GUESS** or invent token names
### If you need a token that doesn't exist:
- **STOP** implementation
- **ASK** "This component needs [specific token type] but I don't see one available. Should I [alternative approach] or do you have guidance?"
- **WAIT** for direction rather than inventing tokens
This template provides a comprehensive guide for creating consistent, high-quality NEW components that integrate seamlessly with the existing design system without affecting any existing code, **and most importantly, without using non-existent tokens that would cause build failures**.