AI Skill Report Card

Creating Angular UI Wrappers

A-82·Mar 29, 2026·Source: Web
15 / 15
TypeScript
// lib-button.ts import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; @Component({ selector: 'lib-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: ` <button class="lib-button lib-button--{{variant}} lib-button--{{size}}" [disabled]="disabled" (click)="onClick.emit($event)"> <ng-content></ng-content> </button> `, styleUrls: ['./lib-button.css'] }) export class Button { @Input() variant: 'primary' | 'secondary' = 'primary'; @Input() size: 'sm' | 'md' | 'lg' = 'md'; @Input() disabled = false; @Output() onClick = new EventEmitter<Event>(); }
Recommendation
Remove redundant phrases like 'Don't create abstract base classes - keep components self-contained' which over-explains basic Angular knowledge
13 / 15

Progress:

  • Create component files: {name}.ts, {name}.html, {name}.css, {name}.spec.ts, {name}.stories.ts
  • Define selector as lib-{name} (kebab-case)
  • Set standalone: true and OnPush strategy
  • Add typed inputs with defaults
  • Implement template with new control flow (@if, @for)
  • Style with design tokens (var(--cds-*))
  • Add to shared/ui/src/index.ts exports
  • Create Storybook stories with tags: ['autodocs']
Recommendation
Condense the Common Pitfalls section - some items are too obvious (like 'Don't forget to add to index.ts')
18 / 20

Example 1: Basic Input Wrapper

TypeScript
@Component({ selector: 'lib-input', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Input), multi: true } ] }) export class Input implements ControlValueAccessor { @Input() placeholder = ''; @Input() label = ''; readonly value = model<string>(''); }

Example 2: PrimeNG Wrapper

TypeScript
// lib-prime-dialog.css /* ============================================ PRIMENG OVERRIDE - CLEANUP ============================================ */ :host ::ng-deep .p-dialog { border-radius: var(--cds-radius-lg); background: var(--cds-color-bg-main); } :host ::ng-deep .p-dialog-header { padding: var(--cds-spacing-4); border-bottom: 1px solid var(--cds-color-border-subtle); }

Example 3: Storybook Story

TypeScript
export default { title: 'Components/Button', component: Button, tags: ['autodocs'], argTypes: { variant: { control: 'select', options: ['primary', 'secondary'], description: 'Button visual style' } } }; export const Default = { args: { variant: 'primary', size: 'md' } };
Recommendation
Add a concrete input/output example showing before/after transformation of a raw PrimeNG component
  • Use design tokens exclusively: var(--cds-spacing-4), var(--cds-color-bg-main)
  • Implement signal-based inputs for Angular v17+: readonly label = input.required<string>()
  • Use BEM-like CSS with lib- prefix: .lib-button--primary, .lib-input__wrapper
  • Content projection via <ng-content> or TemplateRef for flexibility
  • Always provide NG_VALUE_ACCESSOR for form controls
  • Export all components in shared/ui/src/index.ts
  • Don't create abstract base classes - keep components self-contained
  • Don't use old structural directives (*ngIf, *ngFor) - use @if, @for
  • Don't forget OnPush change detection strategy
  • Don't style without design tokens - always use CSS custom properties
  • Don't skip the cleanup comment block for PrimeNG overrides
  • Don't forget to add components to the main index.ts export file
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
15/15
Workflow
13/15
Examples
18/20
Completeness
18/20
Format
15/15
Conciseness
13/15