AI Skill Report Card
Creating Angular UI Wrappers
Quick Start15 / 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
Workflow13 / 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')
Examples18 / 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
TypeScriptexport 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
Best Practices
- 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>orTemplateReffor flexibility - Always provide NG_VALUE_ACCESSOR for form controls
- Export all components in shared/ui/src/index.ts
Common Pitfalls
- 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