- Add new reward-order-confirmation feature library with components and store - Implement checkout completion orchestrator service for order finalization - Migrate checkout/oms/crm models to Zod schemas for better type safety - Add order creation facade and display order schemas - Update shopping cart facade with order completion flow - Add comprehensive tests for shopping cart facade - Update routing to include order confirmation page
@isa/ui/item-rows
A collection of reusable row components for displaying structured data with consistent layouts across Angular applications.
Overview
The Item Rows UI library provides three specialized row components for presenting structured information in a consistent, accessible format. These components enable standardized display of product items, client information, and key-value data pairs throughout the ISA application. Each component uses content projection and directive-based composition for maximum flexibility while maintaining design system consistency.
Table of Contents
- Features
- Quick Start
- Core Concepts
- API Reference
- Usage Examples
- Styling and Customization
- Testing
- Architecture Notes
Features
- Three row components - ItemRowComponent, ItemRowDataComponent, and ClientRowComponent
- Directive-based composition - Flexible data organization with semantic directives
- Content projection - Full control over row content via ng-content
- Convenience imports - Pre-bundled directive arrays for easy imports
- OnPush change detection - Optimized rendering performance
- ViewEncapsulation.None - Global styling integration with design system
- BEM-like CSS naming - Predictable class structure for styling
- Standalone architecture - Modern Angular components with explicit imports
- Type-safe directives - Directive selectors support both attribute and element syntax
- SCSS integration - Component-scoped styles with BEM conventions
Quick Start
1. Basic Item Row
import { Component } from '@angular/core';
import { ItemRowComponent } from '@isa/ui/item-rows';
@Component({
selector: 'app-product-list-item',
template: `
<ui-item-row>
<h3>Product Name</h3>
<p>Product description and details</p>
</ui-item-row>
`,
imports: [ItemRowComponent]
})
export class ProductListItemComponent {}
2. Item Row with Data Pairs
import { Component } from '@angular/core';
import { ItemRowDataImports } from '@isa/ui/item-rows';
@Component({
selector: 'app-product-details',
template: `
<ui-item-row-data>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Price:</span>
<span uiItemRowDataValue>$29.99</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Stock:</span>
<span uiItemRowDataValue>In Stock</span>
</div>
</ui-item-row-data>
`,
imports: [ItemRowDataImports]
})
export class ProductDetailsComponent {}
3. Client Row
import { Component } from '@angular/core';
import { ClientRowImports } from '@isa/ui/item-rows';
@Component({
selector: 'app-customer-card',
template: `
<ui-client-row>
<div uiClientRowContent>
<h4>Customer Name</h4>
<p>customer@example.com</p>
</div>
</ui-client-row>
`,
imports: [ClientRowImports]
})
export class CustomerCardComponent {}
Core Concepts
Component Types
The library provides three distinct row components, each optimized for specific use cases:
1. ItemRowComponent
- Purpose: General-purpose row container for any item content
- Use Cases: Product listings, order items, search results, general lists
- Structure: Simple container with no internal layout structure
- CSS Class:
ui-item-row - Selectors:
<ui-item-row>or[ui-item-row]
2. ItemRowDataComponent with Directives
- Purpose: Key-value data presentation with label/value pairs
- Use Cases: Product specifications, order details, metadata display
- Structure: Hierarchical with row/label/value organization
- CSS Classes:
ui-item-row-data(container)ui-item-row-data-row(individual row)ui-item-row-data-label(left-side label)ui-item-row-data-value(right-side value)
- Directives:
ItemRowDataComponent- Main containerItemRowDataRowDirective- Individual data rowItemRowDataLabelDirective- Label elementItemRowDataValueDirective- Value element
3. ClientRowComponent
- Purpose: Customer/client information display
- Use Cases: Customer lists, client cards, user profiles
- Structure: Specialized layout for client-specific content
- CSS Classes:
ui-client-row(container)ui-client-row-content(content wrapper)
- Directives:
ClientRowComponent- Main containerClientRowContentDirective- Content wrapper
Directive-Based Composition
The library uses directives to create semantic, reusable layout patterns:
// Attribute syntax (preferred)
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Label</span>
<span uiItemRowDataValue>Value</span>
</div>
// Element syntax (alternative)
<ui-item-row-data-row>
<ui-item-row-data-label>Label</ui-item-row-data-label>
<ui-item-row-data-value>Value</ui-item-row-data-value>
</ui-item-row-data-row>
Benefits of directive composition:
- Semantic HTML - Clear intent in templates
- Flexible markup - Use with any HTML element
- Type safety - Directive selectors enforce correct usage
- Consistent styling - Predictable CSS classes
Convenience Import Arrays
The library provides pre-bundled directive arrays for simplified imports:
// ItemRowDataImports - All data row components and directives
export const ItemRowDataImports = [
ItemRowDataComponent,
ItemRowDataLabelDirective,
ItemRowDataValueDirective,
ItemRowDataRowDirective,
];
// ClientRowImports - Client row component and content directive
export const ClientRowImports = [
ClientRowComponent,
ClientRowContentDirective
];
Usage:
@Component({
// Import entire directive family at once
imports: [ItemRowDataImports]
})
API Reference
ItemRowComponent
Basic row container for general item display.
Selector
<ui-item-row>Content</ui-item-row>
<!-- OR -->
<div ui-item-row>Content</div>
Properties
- No inputs - Pure container component
- Host class:
ui-item-row - Change Detection: OnPush
- Encapsulation: None
Template
<ng-content></ng-content>
Example
<ui-item-row>
<div class="product-header">
<h3>Product Title</h3>
<span class="price">$99.99</span>
</div>
<p class="description">Product description text</p>
</ui-item-row>
ItemRowDataComponent
Container for key-value data pairs with semantic directives.
Selector
<ui-item-row-data>Content</ui-item-row-data>
Properties
- No inputs - Container with directive-based children
- Host class:
ui-item-row-data - Change Detection: OnPush
- Encapsulation: None
Template
<ng-content></ng-content>
Example
<ui-item-row-data>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>SKU:</span>
<span uiItemRowDataValue>ABC-12345</span>
</div>
</ui-item-row-data>
ItemRowDataRowDirective
Marks an element as a data row within ItemRowDataComponent.
Selectors
<div uiItemRowDataRow>Content</div>
<!-- OR -->
<ui-item-row-data-row>Content</ui-item-row-data-row>
Properties
- No inputs - Structural directive
- Host class:
ui-item-row-data-row
Example
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Weight:</span>
<span uiItemRowDataValue>2.5 kg</span>
</div>
ItemRowDataLabelDirective
Marks an element as a label (left side) in a data row.
Selectors
<span uiItemRowDataLabel>Label Text</span>
<!-- OR -->
<ui-item-row-data-label>Label Text</ui-item-row-data-label>
Properties
- No inputs - Structural directive
- Host class:
ui-item-row-data-label
Example
<span uiItemRowDataLabel>Category:</span>
ItemRowDataValueDirective
Marks an element as a value (right side) in a data row.
Selectors
<span uiItemRowDataValue>Value Text</span>
<!-- OR -->
<ui-item-row-data-value>Value Text</ui-item-row-data-value>
Properties
- No inputs - Structural directive
- Host class:
ui-item-row-data-value
Example
<span uiItemRowDataValue>Electronics</span>
ClientRowComponent
Specialized row component for client/customer information.
Selector
<ui-client-row>Content</ui-client-row>
Properties
- No inputs - Container component
- Host class:
ui-client-row - Change Detection: OnPush
- Encapsulation: None
- Standalone: true
Template
<ng-content></ng-content>
Example
<ui-client-row>
<div uiClientRowContent>
<h4>John Doe</h4>
<p>john.doe@example.com</p>
</div>
</ui-client-row>
ClientRowContentDirective
Marks an element as content within ClientRowComponent.
Selectors
<div uiClientRowContent>Content</div>
<!-- OR -->
<ui-client-row-content>Content</ui-client-row-content>
Properties
- No inputs - Structural directive
- Host class:
ui-client-row-content
Example
<div uiClientRowContent>
<div class="client-info">
<span class="client-name">Jane Smith</span>
<span class="client-id">#12345</span>
</div>
</div>
Convenience Import Arrays
ItemRowDataImports
Bundle of all data row components and directives.
export const ItemRowDataImports = [
ItemRowDataComponent,
ItemRowDataLabelDirective,
ItemRowDataValueDirective,
ItemRowDataRowDirective,
];
Usage:
@Component({
imports: [ItemRowDataImports]
})
ClientRowImports
Bundle of client row component and directive.
export const ClientRowImports = [
ClientRowComponent,
ClientRowContentDirective
];
Usage:
@Component({
imports: [ClientRowImports]
})
Usage Examples
Product Information Display
import { Component, input } from '@angular/core';
import { ItemRowComponent, ItemRowDataImports } from '@isa/ui/item-rows';
interface Product {
id: number;
name: string;
sku: string;
price: number;
stock: number;
category: string;
}
@Component({
selector: 'app-product-info',
template: `
<ui-item-row>
<h3>{{ product().name }}</h3>
<ui-item-row-data>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>SKU:</span>
<span uiItemRowDataValue>{{ product().sku }}</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Price:</span>
<span uiItemRowDataValue>\${{ product().price }}</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Stock:</span>
<span uiItemRowDataValue>{{ product().stock }} units</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Category:</span>
<span uiItemRowDataValue>{{ product().category }}</span>
</div>
</ui-item-row-data>
</ui-item-row>
`,
imports: [ItemRowComponent, ItemRowDataImports]
})
export class ProductInfoComponent {
product = input.required<Product>();
}
Order Details List
import { Component, input } from '@angular/core';
import { ItemRowDataImports } from '@isa/ui/item-rows';
import { DatePipe, CurrencyPipe } from '@angular/common';
interface Order {
orderNumber: string;
date: Date;
status: string;
total: number;
shippingMethod: string;
}
@Component({
selector: 'app-order-details',
template: `
<ui-item-row-data>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Order Number:</span>
<strong uiItemRowDataValue>{{ order().orderNumber }}</strong>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Order Date:</span>
<span uiItemRowDataValue>{{ order().date | date:'short' }}</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Status:</span>
<span uiItemRowDataValue class="status-{{ order().status }}">
{{ order().status }}
</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Total:</span>
<span uiItemRowDataValue>{{ order().total | currency }}</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Shipping:</span>
<span uiItemRowDataValue>{{ order().shippingMethod }}</span>
</div>
</ui-item-row-data>
`,
imports: [ItemRowDataImports, DatePipe, CurrencyPipe]
})
export class OrderDetailsComponent {
order = input.required<Order>();
}
Customer List with Client Rows
import { Component, signal } from '@angular/core';
import { ClientRowImports } from '@isa/ui/item-rows';
interface Customer {
id: number;
name: string;
email: string;
phone: string;
company: string;
}
@Component({
selector: 'app-customer-list',
template: `
<div class="customer-list">
@for (customer of customers(); track customer.id) {
<ui-client-row>
<div uiClientRowContent class="customer-card">
<div class="customer-header">
<h4>{{ customer.name }}</h4>
<span class="customer-id">#{{ customer.id }}</span>
</div>
<div class="customer-details">
<p>{{ customer.email }}</p>
<p>{{ customer.phone }}</p>
<p class="company">{{ customer.company }}</p>
</div>
</div>
</ui-client-row>
}
</div>
`,
imports: [ClientRowImports],
styles: [`
.customer-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.customer-card {
padding: 1rem;
}
.customer-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.company {
color: var(--isa-text-secondary);
font-size: 0.875rem;
}
`]
})
export class CustomerListComponent {
customers = signal<Customer[]>([
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
phone: '+1 555-0100',
company: 'Acme Corp'
},
// ... more customers
]);
}
Mixed Content with Conditional Rendering
import { Component, input, computed } from '@angular/core';
import { ItemRowComponent, ItemRowDataImports } from '@isa/ui/item-rows';
interface ProductWithVariants {
name: string;
basePrice: number;
hasVariants: boolean;
variants?: Array<{ name: string; price: number }>;
specifications: Record<string, string>;
}
@Component({
selector: 'app-product-variant-info',
template: `
<ui-item-row>
<h3>{{ product().name }}</h3>
@if (product().hasVariants) {
<div class="variants">
@for (variant of product().variants; track variant.name) {
<span class="variant-chip">
{{ variant.name }} - \${{ variant.price }}
</span>
}
</div>
}
<ui-item-row-data>
@for (spec of specificationEntries(); track spec.key) {
<div uiItemRowDataRow>
<span uiItemRowDataLabel>{{ spec.key }}:</span>
<span uiItemRowDataValue>{{ spec.value }}</span>
</div>
}
</ui-item-row-data>
</ui-item-row>
`,
imports: [ItemRowComponent, ItemRowDataImports]
})
export class ProductVariantInfoComponent {
product = input.required<ProductWithVariants>();
specificationEntries = computed(() =>
Object.entries(this.product().specifications).map(([key, value]) => ({
key,
value
}))
);
}
Nested Row Structures
import { Component } from '@angular/core';
import { ItemRowComponent, ItemRowDataImports } from '@isa/ui/item-rows';
@Component({
selector: 'app-order-item-detail',
template: `
<ui-item-row class="order-item">
<!-- Product header -->
<div class="item-header">
<h4>Wireless Headphones</h4>
<span class="quantity">Qty: 2</span>
</div>
<!-- Primary product details -->
<ui-item-row-data class="primary-details">
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Unit Price:</span>
<span uiItemRowDataValue>$79.99</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Subtotal:</span>
<span uiItemRowDataValue>$159.98</span>
</div>
</ui-item-row-data>
<!-- Shipping information -->
<ui-item-row-data class="shipping-details">
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Estimated Delivery:</span>
<span uiItemRowDataValue>Dec 25, 2025</span>
</div>
<div uiItemRowDataRow>
<span uiItemRowDataLabel>Shipping Method:</span>
<span uiItemRowDataValue>Standard (3-5 days)</span>
</div>
</ui-item-row-data>
</ui-item-row>
`,
imports: [ItemRowComponent, ItemRowDataImports]
})
export class OrderItemDetailComponent {}
Dynamic Data Rows
import { Component, input, computed } from '@angular/core';
import { ItemRowDataImports } from '@isa/ui/item-rows';
@Component({
selector: 'app-dynamic-metadata',
template: `
<ui-item-row-data>
@for (field of metadataFields(); track field.key) {
<div uiItemRowDataRow>
<span uiItemRowDataLabel>{{ field.label }}:</span>
<span
uiItemRowDataValue
[class]="field.highlightClass">
{{ field.value }}
</span>
</div>
}
</ui-item-row-data>
`,
imports: [ItemRowDataImports]
})
export class DynamicMetadataComponent {
metadata = input.required<Record<string, any>>();
metadataFields = computed(() => {
const data = this.metadata();
return Object.entries(data).map(([key, value]) => ({
key,
label: this.formatLabel(key),
value: this.formatValue(value),
highlightClass: this.getHighlightClass(key, value)
}));
});
private formatLabel(key: string): string {
return key
.replace(/([A-Z])/g, ' $1')
.replace(/^./, str => str.toUpperCase());
}
private formatValue(value: any): string {
if (typeof value === 'boolean') return value ? 'Yes' : 'No';
if (value === null || value === undefined) return 'N/A';
return String(value);
}
private getHighlightClass(key: string, value: any): string {
if (key === 'status') {
return value === 'active' ? 'text-success' : 'text-muted';
}
return '';
}
}
Styling and Customization
CSS Class Structure
The components generate predictable BEM-like class structures:
/* ItemRowComponent */
.ui-item-row {
/* Base item row styles */
display: block;
padding: 1rem;
border-bottom: 1px solid var(--isa-border-color);
}
/* ItemRowDataComponent */
.ui-item-row-data {
/* Container for data rows */
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.ui-item-row-data-row {
/* Individual data row */
display: grid;
grid-template-columns: minmax(120px, 1fr) 2fr;
gap: 1rem;
align-items: start;
}
.ui-item-row-data-label {
/* Label (left column) */
font-weight: 500;
color: var(--isa-text-secondary);
text-align: left;
}
.ui-item-row-data-value {
/* Value (right column) */
color: var(--isa-text-primary);
text-align: left;
}
/* ClientRowComponent */
.ui-client-row {
/* Client row container */
display: block;
background-color: var(--isa-surface);
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.ui-client-row-content {
/* Client row content wrapper */
padding: 1.5rem;
}
Custom Styling Examples
// Custom product row styling
.product-listing {
ui-item-row {
background-color: white;
border-radius: 4px;
margin-bottom: 1rem;
transition: box-shadow 0.2s;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
}
.ui-item-row-data {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid var(--isa-border-color);
}
.ui-item-row-data-label {
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.ui-item-row-data-value {
font-weight: 600;
}
}
// Custom client row styling
.customer-directory {
ui-client-row {
margin-bottom: 1rem;
border: 1px solid var(--isa-border-light);
&:hover {
border-color: var(--isa-brand-primary);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
.ui-client-row-content {
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
align-items: center;
}
}
Responsive Layouts
/* Mobile-first responsive data rows */
.ui-item-row-data-row {
/* Stack on mobile */
display: flex;
flex-direction: column;
gap: 0.25rem;
}
@media (min-width: 640px) {
.ui-item-row-data-row {
/* Side-by-side on tablet and up */
flex-direction: row;
justify-content: space-between;
}
}
@media (min-width: 1024px) {
.ui-item-row-data-row {
/* Grid layout on desktop */
display: grid;
grid-template-columns: minmax(150px, 1fr) 3fr;
}
}
Tailwind CSS Integration
<!-- Using Tailwind classes with item rows -->
<ui-item-row class="p-4 mb-4 bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow">
<ui-item-row-data class="space-y-2">
<div uiItemRowDataRow class="grid grid-cols-2 gap-4">
<span uiItemRowDataLabel class="text-sm font-medium text-gray-600">
Label
</span>
<span uiItemRowDataValue class="text-base text-gray-900">
Value
</span>
</div>
</ui-item-row-data>
</ui-item-row>
Testing
The library uses Jest for testing (legacy setup - migration to Vitest pending).
Running Tests
# Run tests for this library
npx nx test ui-item-rows --skip-nx-cache
# Run tests with coverage
npx nx test ui-item-rows --code-coverage --skip-nx-cache
# Run tests in watch mode
npx nx test ui-item-rows --watch
Test Structure
The library should include tests covering:
- Component rendering - Verify components render correctly
- Content projection - Test ng-content works as expected
- Directive application - Verify CSS classes are applied correctly
- Host bindings - Test host class bindings
- Nested structures - Test complex nesting scenarios
Example Test
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { describe, it, expect, beforeEach } from '@jest/globals';
import {
ItemRowDataComponent,
ItemRowDataRowDirective,
ItemRowDataLabelDirective,
ItemRowDataValueDirective
} from './item-row-data.component';
describe('ItemRowDataComponent', () => {
let component: ItemRowDataComponent;
let fixture: ComponentFixture<ItemRowDataComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
ItemRowDataComponent,
ItemRowDataRowDirective,
ItemRowDataLabelDirective,
ItemRowDataValueDirective
]
});
fixture = TestBed.createComponent(ItemRowDataComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should have ui-item-row-data class', () => {
const element = fixture.nativeElement as HTMLElement;
expect(element.classList.contains('ui-item-row-data')).toBe(true);
});
it('should project content', () => {
const compiled = fixture.nativeElement as HTMLElement;
const testContent = '<div>Test Content</div>';
compiled.innerHTML = testContent;
fixture.detectChanges();
expect(compiled.innerHTML).toContain('Test Content');
});
});
Architecture Notes
Current Architecture
The library follows a directive-based composition pattern:
ItemRowComponent (Simple Container)
├── No inputs, pure content projection
└── CSS: ui-item-row
ItemRowDataComponent (Data Container)
├── No inputs, container for data rows
├── CSS: ui-item-row-data
└── Works with directives:
├── ItemRowDataRowDirective (row wrapper)
├── ItemRowDataLabelDirective (label/key)
└── ItemRowDataValueDirective (value)
ClientRowComponent (Client Container)
├── No inputs, specialized for clients
├── CSS: ui-client-row
└── Works with directive:
└── ClientRowContentDirective (content wrapper)
Design Decisions
1. Directive-Based Composition
Decision: Use directives instead of child components for layout structure Rationale:
- Flexibility to use any HTML element (div, span, p, etc.)
- Semantic selectors (
uiItemRowDataLabelvs generic component) - Lighter weight than full components
- Easier to apply to existing markup
Impact: More flexible templates with clear semantic meaning
2. Dual Selector Support
Decision: Support both attribute and element selectors Rationale:
[uiItemRowDataRow]- Attribute syntax for flexible element types<ui-item-row-data-row>- Element syntax for clarity- Developers can choose based on preference and context
- Consistent with Angular best practices
Impact: Better developer experience with choice of syntax
3. Convenience Import Arrays
Decision: Export pre-bundled directive arrays Rationale:
- Reduces boilerplate in component imports
- Ensures all related directives are imported together
- Clear API - import array, not individual directives
- Prevents missing directive errors
Impact: Simpler, more maintainable component declarations
4. No Component Inputs
Decision: Components have no @Input properties Rationale:
- Pure structural components focused on layout
- Content and styling controlled via projection and CSS
- Simpler API with fewer configuration options
- Promotes composition over configuration
Impact: Simpler components, styling handled via CSS
5. ViewEncapsulation.None
Decision: Use ViewEncapsulation.None for global CSS classes Rationale:
- Consistent with ISA design system approach
- BEM-like naming prevents conflicts
- Easier theming and customization
- Works well with Tailwind utility classes
Impact: Flexible styling with global CSS classes
Migration Considerations
Testing Framework Migration (Pending)
Current State: Uses Jest Target: Migrate to Vitest + Angular Testing Utilities Reason: Aligns with ISA codebase standards (13 libraries already migrated) Priority: Low - works well with Jest currently
Migration steps when ready:
- Update project.json to use @nx/vite:test
- Add vite.config.mts
- Convert tests to use Vitest imports
- Update test setup files
Performance Considerations
- OnPush change detection - Minimal overhead for structural components
- No reactive inputs - No signal overhead
- Simple templates - Just ng-content projection
- Directive overhead - Minimal, just CSS class application
- No JavaScript logic - Pure presentational components
Future Enhancements
Potential improvements identified:
- Icon Support - Add optional icon directives for labels
- Accordion Behavior - Collapsible row variants
- Selection Support - Checkbox/radio integration
- Loading States - Skeleton variants for data rows
- Empty States - Placeholder content when no data
- Accessibility - ARIA attributes for screen readers
- Animation Support - Entry/exit animations for rows
Dependencies
Required Libraries
@angular/core- Angular framework (20.1.2)@angular/common- CommonModule (implicitly used)
Optional Libraries
None - pure presentation components with no external dependencies.
Path Alias
Import from: @isa/ui/item-rows
License
Internal ISA Frontend library - not for external distribution.