# @isa/ui/input-controls A comprehensive collection of form input components and directives for Angular applications supporting reactive forms, template-driven forms, and accessibility features. ## Overview The Input Controls library provides a complete suite of reusable form components built on Angular's reactive forms API and Angular CDK. It includes text fields, checkboxes, dropdowns, chips, checklists, listboxes, and inline inputs - all designed to work seamlessly with Angular Forms while maintaining consistent styling and behavior across the ISA application. ## Table of Contents - [Features](#features) - [Quick Start](#quick-start) - [Core Concepts](#core-concepts) - [API Reference](#api-reference) - [Usage Examples](#usage-examples) - [Form Integration](#form-integration) - [Accessibility](#accessibility) - [Testing](#testing) - [Architecture Notes](#architecture-notes) ## Features - **Complete form control suite** - 8 component types covering common input scenarios - **Reactive Forms integration** - ControlValueAccessor implementation for all form controls - **Template-driven forms** - Full ngModel support for two-way binding - **Keyboard navigation** - Arrow keys, Enter, Escape, and Tab support - **Accessibility (a11y)** - ARIA attributes, screen reader support, keyboard navigation - **Customizable appearance** - Multiple size and appearance variants for each control - **Validation support** - Integration with Angular's built-in validators - **CDK integration** - Built on Angular CDK primitives (listbox, a11y, overlay) - **Signal-based inputs** - Modern Angular signals for reactive property management - **Type-safe** - Full TypeScript support with generic type parameters ## Quick Start ### 1. Import Components ```typescript import { Component } from '@angular/core'; import { CheckboxComponent, DropdownButtonComponent, DropdownFilterComponent, DropdownOptionComponent, TextFieldComponent, InputControlDirective, } from '@isa/ui/input-controls'; import { ReactiveFormsModule } from '@angular/forms'; @Component({ selector: 'app-my-form', imports: [ ReactiveFormsModule, CheckboxComponent, DropdownButtonComponent, DropdownFilterComponent, DropdownOptionComponent, TextFieldComponent, InputControlDirective, ], template: '...' }) export class MyFormComponent {} ``` ### 2. Basic Text Field ```html ``` ### 3. Checkbox ```html ``` ### 4. Dropdown ```html Option 1 Option 2 Option 3 ``` ### 5. Dropdown with Filter ```html Germany Austria Switzerland ``` ## Core Concepts ### Component Categories The library provides three main categories of form controls: #### 1. Text Input Controls - **TextFieldComponent** - Standard text input with container, labels, and errors - **TextareaComponent** - Multi-line text input - **InlineInputComponent** - Compact inline text input for space-constrained UIs #### 2. Selection Controls - **CheckboxComponent** - Single checkbox with bullet or checkbox appearance - **ChecklistComponent** - Multiple checkboxes working as a group - **DropdownButtonComponent** - Select dropdown with keyboard navigation - **ChipsComponent** - Single-select chip group - **ListboxDirective** - CDK listbox wrapper for custom list selections #### 3. Supporting Components - **InputControlDirective** - Core directive for input field integration - **TextFieldContainerComponent** - Layout container for text fields - **TextFieldErrorsComponent** - Validation error display - **TextFieldClearComponent** - Clear button for text inputs - **CheckboxLabelDirective** - Label styling for checkboxes - **ChecklistValueDirective** - Value binding for checklist items - **ChipOptionComponent** - Individual chip option - **DropdownOptionComponent** - Individual dropdown option - **DropdownFilterComponent** - Filter input for dropdown options - **ListboxItemDirective** - Individual listbox item ### Control Value Accessor Pattern All form controls implement Angular's `ControlValueAccessor` interface, enabling seamless integration with both reactive and template-driven forms: ```typescript export class DropdownButtonComponent implements ControlValueAccessor { value = model(); disabled = model(false); writeValue(obj: unknown): void { ... } registerOnChange(fn: (value: T) => void): void { ... } registerOnTouched(fn: () => void): void { ... } setDisabledState(isDisabled: boolean): void { ... } } ``` ### Appearance Variants #### Checkbox Appearances ```typescript const CheckboxAppearance = { Bullet: 'bullet', // Round bullet-style selector Checkbox: 'checkbox', // Traditional square checkbox (default) } as const; ``` #### Text Field Sizes ```typescript const TextFieldSize = { Small: 'small', Medium: 'medium', // Default Large: 'large', } as const; ``` ## API Reference ### CheckboxComponent A customizable checkbox component supporting different visual appearances. **Selector:** `ui-checkbox` **Inputs:** - `appearance: CheckboxAppearance` - Visual style ('checkbox' | 'bullet'). Default: 'checkbox' **Usage:** ```html ``` --- ### DropdownButtonComponent A dropdown select component with keyboard navigation and CDK overlay integration. **Selector:** `ui-dropdown` **Inputs:** - `appearance: DropdownAppearance` - Visual style. Default: 'accent-outline' - `label: string` - Dropdown label text - `showSelectedValue: boolean` - Show selected option text. Default: true - `tabIndex: number` - Tab index for keyboard navigation. Default: 0 - `id: string` - Optional element ID - `equals: (a: T | null, b: T | null) => boolean` - Custom equality function for comparing option values. Default: `lodash.isEqual` **Outputs:** - `value: ModelSignal` - Two-way bindable selected value - `disabled: ModelSignal` - Disabled state **Methods:** - `open(): void` - Opens the dropdown overlay - `close(): void` - Closes the dropdown overlay - `select(option, options?): void` - Selects an option programmatically **Keyboard Navigation:** - `Arrow Down/Up` - Navigate through options - `Enter` - Select highlighted option and close - `Escape` - Close dropdown - `Space` - Toggle dropdown open/close (when focused) **Usage:** ```typescript interface Product { id: number; name: string; } products: Product[] = [ { id: 1, name: 'Product A' }, { id: 2, name: 'Product B' } ]; selectedProduct: Product; ``` ```html @for (product of products; track product.id) { {{ product.name }} } ``` **Custom Equality Comparison:** When working with object values, you may need custom comparison logic (e.g., comparing by ID instead of deep equality): ```typescript // Compare products by ID instead of deep equality readonly productEquals = (a: Product | null, b: Product | null) => a?.id === b?.id; ``` ```html @for (product of products; track product.id) { {{ product.name }} } ``` --- ### DropdownFilterComponent A filter input component for use within a DropdownButtonComponent. Renders as a sticky input at the top of the options panel, allowing users to filter options by typing. **Selector:** `ui-dropdown-filter` **Inputs:** - `placeholder: string` - Placeholder text for the filter input. Default: 'Suchen...' **Features:** - Sticky positioning at top of options panel - Auto-focuses when dropdown opens - Clears automatically when dropdown closes - Arrow key navigation works while typing - Enter key selects the highlighted option **Usage:** ```html Germany Austria Switzerland France Italy ``` **Keyboard Navigation (when filter is focused):** - `Arrow Down/Up` - Navigate through options - `Enter` - Select highlighted option and close - `Space` - Types in the input (does not toggle dropdown) - `Escape` - Keeps focus in input --- ### DropdownOptionComponent A selectable option component for use within a DropdownButtonComponent. Implements the CDK Highlightable interface for keyboard navigation support. **Selector:** `ui-dropdown-option` **Inputs:** | Input | Type | Required | Default | Description | |-------|------|----------|---------|-------------| | `value` | `T` | Yes | - | The value associated with this option | | `disabled` | `boolean` | No | `false` | Whether this option is disabled | **Usage:** ```html Option 1 Option 2 Disabled ``` **Features:** - Uses host dropdown's `equals` function for value comparison (defaults to `lodash.isEqual`) - Automatic filtering support when used with `DropdownFilterComponent` - CSS classes applied automatically: `active`, `selected`, `disabled`, `filtered` - ARIA `role="option"` and `aria-selected` attributes for accessibility --- ### ChipsComponent Single-selection chip group with form integration. **Selector:** `ui-chips` **Outputs:** - `value: ModelSignal` - Selected chip value - `disabled: ModelSignal` - Disabled state **Methods:** - `select(value: T, options?): void` - Selects a chip - `toggle(value: T, options?): void` - Toggles chip selection - `isSelected(value: T): boolean` - Checks if value is selected **Usage:** ```typescript type Size = 'S' | 'M' | 'L' | 'XL'; selectedSize: Size = 'M'; ``` ```html Small Medium Large Extra Large ``` --- ### ChecklistComponent Multi-select checkbox group returning an array of selected values. **Selector:** `ui-checklist` **Outputs:** - `value: ModelSignal` - Array of selected values **Usage:** ```typescript selectedFruits: string[] = ['apple', 'banana']; ``` ```html ``` --- ### TextFieldComponent Container component for text input fields with consistent styling. **Selector:** `ui-text-field` **Inputs:** - `size: TextFieldSize` - Field size ('small' | 'medium' | 'large'). Default: 'medium' **Content Projection:** - Requires `InputControlDirective` on child input element **Usage:** ```html ``` --- ### InlineInputComponent Compact inline text input for space-constrained interfaces. **Selector:** `ui-inline-input` **Inputs:** - `size: InlineInputSize` - Field size ('small' | 'medium'). Default: 'medium' **Usage:** ```html ``` --- ### ListboxDirective Wrapper directive for Angular CDK listbox with ISA styling. **Selector:** `[uiListbox]` **Inputs (via CDK):** - `value: any` - Selected value(s) - `compareWith: (o1: any, o2: any) => boolean` - Comparison function - `disabled: boolean` - Disabled state **Outputs (via CDK):** - `valueChange: EventEmitter` - Emits when selection changes **Usage:** ```html
Item 1
Item 2
``` ## Usage Examples ### Reactive Form with Validation ```typescript import { Component, inject } from '@angular/core'; import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { TextFieldComponent, TextFieldContainerComponent, TextFieldErrorsComponent, InputControlDirective, CheckboxComponent, DropdownButtonComponent, DropdownOptionComponent } from '@isa/ui/input-controls'; @Component({ selector: 'app-user-form', imports: [ ReactiveFormsModule, TextFieldComponent, TextFieldContainerComponent, TextFieldErrorsComponent, InputControlDirective, CheckboxComponent, DropdownButtonComponent, DropdownOptionComponent ], template: `
Administrator User
` }) export class UserFormComponent { #fb = inject(FormBuilder); userForm = this.#fb.group({ email: ['', [Validators.required, Validators.email]], role: ['user', Validators.required], acceptTerms: [false, Validators.requiredTrue] }); onSubmit() { if (this.userForm.valid) { console.log('Form submitted:', this.userForm.value); } } } ``` ## Form Integration ### Reactive Forms All components implement `ControlValueAccessor` and work with `FormControl`: ```typescript import { FormControl, Validators } from '@angular/forms'; emailControl = new FormControl('', [Validators.required, Validators.email]); roleControl = new FormControl('user'); agreeControl = new FormControl(false, Validators.requiredTrue); ``` ```html ... ``` ### Template-Driven Forms Use `ngModel` for two-way binding: ```html ... ``` ## Accessibility ### Keyboard Navigation All components support comprehensive keyboard navigation: **Dropdown:** - `Arrow Down/Up` - Navigate through options - `Enter` - Select highlighted option and close - `Escape` - Close dropdown without selection - `Tab` - Move focus to next element **Listbox:** - `Arrow Down/Up` - Navigate items - `Home/End` - Jump to first/last item - `Space/Enter` - Select item **Checkbox/Checklist:** - `Space` - Toggle checkbox state - `Tab` - Move between checkboxes ### ARIA Attributes Components include proper ARIA attributes for screen readers: ```html
``` ## Testing The library uses **Jest** with **Spectator** for testing. ### Running Tests ```bash # Run tests for this library npx nx test ui-input-controls --skip-nx-cache # Run tests with coverage npx nx test ui-input-controls --code-coverage --skip-nx-cache # Run tests in watch mode npx nx test ui-input-controls --watch ``` ### Test Coverage The library includes comprehensive unit tests covering: - **Component rendering** - All visual states and variants - **Form integration** - ControlValueAccessor implementation - **Keyboard navigation** - Arrow keys, Enter, Escape, Tab - **Validation** - Error states and validation display - **Accessibility** - ARIA attributes and screen reader support - **User interactions** - Click, keyboard, focus events ## Architecture Notes ### Design Patterns #### 1. ControlValueAccessor Pattern All form controls implement the CVA interface for seamless Angular Forms integration. **Benefits:** - Works with both reactive and template-driven forms - Automatic validation integration - Consistent API across all controls #### 2. Signal-Based Reactivity Components use Angular signals for reactive state management: ```typescript appearance = input(CheckboxAppearance.Checkbox); appearanceClass = computed(() => this.appearance() === CheckboxAppearance.Bullet ? 'ui-checkbox__bullet' : 'ui-checkbox__checkbox' ); ``` #### 3. CDK Integration Leverages Angular CDK for complex interactions: - **Overlay** - Dropdown positioning (CdkConnectedOverlay) - **A11y** - Keyboard navigation (ActiveDescendantKeyManager) - **Listbox** - Accessible list selection (CdkListbox) ### Performance Considerations 1. **OnPush Change Detection** - All components use OnPush strategy 2. **Signal Reactivity** - Computed signals prevent unnecessary re-renders 3. **KeyManager** - Efficient keyboard navigation without DOM queries ## Dependencies ### Required Libraries - `@angular/core` - Angular framework - `@angular/forms` - Forms module - `@angular/cdk/a11y` - Accessibility utilities - `@angular/cdk/listbox` - Listbox primitive - `@angular/cdk/overlay` - Overlay positioning - `@angular/cdk/collections` - SelectionModel - `@ng-icons/core` - Icon system - `@isa/icons` - ISA icon library - `lodash` - Utility functions (isEqual) ### Path Alias Import from: `@isa/ui/input-controls` ## License Internal ISA Frontend library - not for external distribution.