Files
ui-essentials/COMPONENT_CREATION_TEMPLATE.md
skyai_dev bf67b7f955 Add comprehensive component library expansion with new UI components
This commit includes multiple new components and improvements to the UI essentials library:

## New Components Added:
- **Accordion**: Expandable/collapsible content panels with full accessibility
- **Alert**: Notification and messaging component with variants and dismiss functionality
- **Popover**: Floating content containers with positioning and trigger options
- **Timeline**: Chronological event display with customizable styling
- **Tree View**: Hierarchical data display with expand/collapse functionality
- **Toast**: Notification component (previously committed, includes style refinements)

## Component Features:
- Full TypeScript implementation with Angular 19+ patterns
- Comprehensive SCSS styling using semantic design tokens exclusively
- Multiple size variants (sm, md, lg) and color variants (primary, success, warning, danger, info)
- Accessibility support with ARIA attributes and keyboard navigation
- Responsive design with mobile-first approach
- Interactive demos showcasing all component features
- Integration with existing design system and routing

## Demo Applications:
- Created comprehensive demo components for each new component
- Interactive examples with live code demonstrations
- Integrated into main demo application routing and navigation

## Documentation:
- Added COMPONENT_CREATION_TEMPLATE.md with detailed guidelines
- Comprehensive component creation patterns and best practices
- Design token usage guidelines and validation rules

## Code Quality:
- Follows established Angular and SCSS conventions
- Uses only verified semantic design tokens
- Maintains consistency with existing component architecture
- Comprehensive error handling and edge case management

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 12:02:38 +10:00

30 KiB

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

// 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]") {
    <ui-[component-name]-demo></ui-[component-name]-demo>
}

// 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

// 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

// 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

@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)

// 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())

// 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)

// 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)

// 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)

// 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)

// 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)

// 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)

// 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)

$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)

$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)

@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:

// 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:

// 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:

// 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

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: `
    <div 
      class="ui-[component-name]"
      [class.ui-[component-name]--{{size}}]="size"
      [class.ui-[component-name]--{{variant}}]="variant"
      [class.ui-[component-name]--disabled]="disabled"
      [class.ui-[component-name]--loading]="loading"
      [attr.aria-disabled]="disabled"
      [attr.aria-busy]="loading"
      [attr.role]="role"
      [tabindex]="disabled ? -1 : tabIndex"
      (click)="handleClick($event)"
      (keydown)="handleKeydown($event)">
      
      @if (loading) {
        <span class="ui-[component-name]__loader" aria-hidden="true"></span>
      }
      
      <ng-content></ng-content>
    </div>
  `,
  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<MouseEvent>();
  
  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

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: `
    <div class="demo-container">
      <h2>[Component Name] Demo</h2>
      
      <!-- Size Variants -->
      <section class="demo-section">
        <h3>Sizes</h3>
        <div class="demo-row">
          @for (size of sizes; track size) {
            <ui-[component-name] [size]="size">
              {{ size }} size
            </ui-[component-name]>
          }
        </div>
      </section>
      
      <!-- Color Variants -->
      <section class="demo-section">
        <h3>Variants</h3>
        <div class="demo-row">
          @for (variant of variants; track variant) {
            <ui-[component-name] [variant]="variant">
              {{ variant }}
            </ui-[component-name]>
          }
        </div>
      </section>
      
      <!-- States -->
      <section class="demo-section">
        <h3>States</h3>
        <div class="demo-row">
          <ui-[component-name] [disabled]="true">Disabled</ui-[component-name]>
          <ui-[component-name] [loading]="true">Loading</ui-[component-name]>
        </div>
      </section>
      
      <!-- Interactive Example -->
      <section class="demo-section">
        <h3>Interactive</h3>
        <ui-[component-name] (clicked)="handleDemoClick($event)">
          Click me
        </ui-[component-name]>
        <p>Clicked: {{ clickCount }} times</p>
      </section>
    </div>
  `,
  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

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.