- 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
14 KiB
@isa/ui/bullet-list
A lightweight bullet list component system for Angular applications supporting customizable icons and hierarchical content presentation.
Overview
The Bullet List library provides a pair of components (ui-bullet-list and ui-bullet-list-item) that work together to create visually consistent bullet-point lists with icon support. The system uses Angular's host-based component injection to propagate icon configuration from parent to children, enabling both uniform and customized list appearances.
Table of Contents
- Features
- Quick Start
- Component API
- Usage Examples
- Styling and Customization
- Architecture Notes
- Testing
- Dependencies
Features
- Parent-child icon inheritance - Default icon flows from list to items
- Per-item icon override - Individual items can specify custom icons
- Angular signals integration - Reactive icon computation with
computed() - Standalone components - Modern Angular architecture with explicit imports
- Icon library integration - Uses
@ng-icons/corewith ISA icon set - OnPush change detection - Optimized performance
- Host-based injection - Seamless parent-child communication
- Content projection - Flexible content rendering via
<ng-content>
Quick Start
1. Import Components
import { Component } from '@angular/core';
import { BulletListComponent, BulletListItemComponent } from '@isa/ui/bullet-list';
@Component({
selector: 'app-feature-list',
imports: [BulletListComponent, BulletListItemComponent],
template: `...`
})
export class FeatureListComponent {}
2. Basic Usage
<ui-bullet-list>
<ui-bullet-list-item>First feature</ui-bullet-list-item>
<ui-bullet-list-item>Second feature</ui-bullet-list-item>
<ui-bullet-list-item>Third feature</ui-bullet-list-item>
</ui-bullet-list>
3. Custom Icons
<!-- Custom icon for entire list -->
<ui-bullet-list [icon]="'isaActionCheck'">
<ui-bullet-list-item>Completed task</ui-bullet-list-item>
<ui-bullet-list-item>Another completed task</ui-bullet-list-item>
</ui-bullet-list>
<!-- Mixed icons - per-item override -->
<ui-bullet-list>
<ui-bullet-list-item [icon]="'isaActionCheck'">Done</ui-bullet-list-item>
<ui-bullet-list-item [icon]="'isaActionClock'">In progress</ui-bullet-list-item>
<ui-bullet-list-item>Default icon</ui-bullet-list-item>
</ui-bullet-list>
Component API
BulletListComponent
Container component for bullet list items.
Selector
'ui-bullet-list'
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
icon |
string |
'isaActionChevronRight' |
Default icon name for all child items |
Host Bindings
class:'ui-bullet-list'- Base CSS class for styling
Template
Content projection only - wraps child items:
<ng-content></ng-content>
Providers
Automatically provides isaActionChevronRight icon to the icon registry.
BulletListItemComponent
Individual item within a bullet list.
Selector
'ui-bullet-list-item'
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
icon |
string | undefined |
undefined |
Custom icon override (uses parent icon if undefined) |
Computed Properties
| Property | Type | Description |
|---|---|---|
iconName() |
string | undefined |
Computed icon name - resolves to item icon or falls back to parent icon |
Host Bindings
class:'ui-bullet-list-item'- Base CSS class for styling
Template
<ng-icon [name]="iconName()" size="1.5rem"></ng-icon>
<ng-content></ng-content>
Usage Examples
Basic Feature List
import { Component } from '@angular/core';
import { BulletListComponent, BulletListItemComponent } from '@isa/ui/bullet-list';
@Component({
selector: 'app-product-features',
imports: [BulletListComponent, BulletListItemComponent],
template: `
<h2>Product Features</h2>
<ui-bullet-list>
<ui-bullet-list-item>Fast performance</ui-bullet-list-item>
<ui-bullet-list-item>Easy to use</ui-bullet-list-item>
<ui-bullet-list-item>Highly customizable</ui-bullet-list-item>
</ui-bullet-list>
`
})
export class ProductFeaturesComponent {}
Custom List Icon
@Component({
selector: 'app-task-list',
imports: [BulletListComponent, BulletListItemComponent],
template: `
<h2>Completed Tasks</h2>
<ui-bullet-list [icon]="'isaActionCheck'">
<ui-bullet-list-item>Project setup complete</ui-bullet-list-item>
<ui-bullet-list-item>Tests passing</ui-bullet-list-item>
<ui-bullet-list-item>Documentation updated</ui-bullet-list-item>
</ui-bullet-list>
`
})
export class TaskListComponent {}
Mixed Icons with Status Indicators
@Component({
selector: 'app-status-list',
imports: [BulletListComponent, BulletListItemComponent],
template: `
<h2>Task Status</h2>
<ui-bullet-list>
<ui-bullet-list-item [icon]="'isaActionCheck'">
Authentication implemented
</ui-bullet-list-item>
<ui-bullet-list-item [icon]="'isaActionClock'">
API integration in progress
</ui-bullet-list-item>
<ui-bullet-list-item [icon]="'isaActionWarning'">
Performance testing pending
</ui-bullet-list-item>
</ui-bullet-list>
`
})
export class StatusListComponent {}
Dynamic Icon Selection
import { Component, signal } from '@angular/core';
import { BulletListComponent, BulletListItemComponent } from '@isa/ui/bullet-list';
@Component({
selector: 'app-dynamic-list',
imports: [BulletListComponent, BulletListItemComponent],
template: `
<ui-bullet-list [icon]="currentIcon()">
<ui-bullet-list-item>Item 1</ui-bullet-list-item>
<ui-bullet-list-item>Item 2</ui-bullet-list-item>
<ui-bullet-list-item>Item 3</ui-bullet-list-item>
</ui-bullet-list>
<button (click)="changeIcon()">Toggle Icon</button>
`
})
export class DynamicListComponent {
currentIcon = signal('isaActionChevronRight');
changeIcon() {
const newIcon = this.currentIcon() === 'isaActionChevronRight'
? 'isaActionCheck'
: 'isaActionChevronRight';
this.currentIcon.set(newIcon);
}
}
Nested Content with Rich HTML
@Component({
selector: 'app-rich-list',
imports: [BulletListComponent, BulletListItemComponent],
template: `
<ui-bullet-list>
<ui-bullet-list-item>
<strong>Bold heading:</strong> Regular text description
</ui-bullet-list-item>
<ui-bullet-list-item>
<a href="/docs">Link to documentation</a>
</ui-bullet-list-item>
<ui-bullet-list-item>
<span class="highlight">Highlighted content</span> with normal text
</ui-bullet-list-item>
</ui-bullet-list>
`
})
export class RichListComponent {}
Conditional Items with Control Flow
import { Component, signal } from '@angular/core';
import { BulletListComponent, BulletListItemComponent } from '@isa/ui/bullet-list';
@Component({
selector: 'app-conditional-list',
imports: [BulletListComponent, BulletListItemComponent],
template: `
<ui-bullet-list>
<ui-bullet-list-item>Always visible</ui-bullet-list-item>
@if (showAdditional()) {
<ui-bullet-list-item>Conditional item 1</ui-bullet-list-item>
<ui-bullet-list-item>Conditional item 2</ui-bullet-list-item>
}
@for (item of dynamicItems(); track item.id) {
<ui-bullet-list-item [icon]="item.icon">
{{ item.text }}
</ui-bullet-list-item>
}
</ui-bullet-list>
`
})
export class ConditionalListComponent {
showAdditional = signal(true);
dynamicItems = signal([
{ id: 1, text: 'Dynamic 1', icon: 'isaActionCheck' },
{ id: 2, text: 'Dynamic 2', icon: 'isaActionClock' }
]);
}
Styling and Customization
CSS Classes
The components expose the following CSS classes for styling:
/* List container */
.ui-bullet-list {
/* Add spacing, layout, etc. */
}
/* Individual list items */
.ui-bullet-list-item {
/* Style item layout */
}
/* Icon within items (via ng-icon) */
.ui-bullet-list-item ng-icon {
/* Customize icon appearance */
}
Example Styling
// Custom spacing and layout
.ui-bullet-list {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.ui-bullet-list-item {
display: flex;
align-items: flex-start;
gap: 0.5rem;
ng-icon {
flex-shrink: 0;
margin-top: 0.125rem; // Align with text
color: var(--isa-accent-500);
}
}
// Status-specific styling
.ui-bullet-list-item {
&.success ng-icon {
color: var(--isa-success-500);
}
&.warning ng-icon {
color: var(--isa-warning-500);
}
&.error ng-icon {
color: var(--isa-error-500);
}
}
Icon Size Customization
The default icon size is 1.5rem. To customize globally:
.ui-bullet-list-item ng-icon {
font-size: 1.25rem; // Smaller icons
width: 1.25rem;
height: 1.25rem;
}
Architecture Notes
Parent-Child Communication Pattern
The library uses Angular's dependency injection with the host flag to enable seamless communication:
// In BulletListItemComponent
#bulletList = inject(BulletListComponent, { optional: true, host: true });
This pattern:
- Only injects the direct parent
BulletListComponent - Returns
nullif no parent exists (viaoptional: true) - Enables icon inheritance without prop drilling
Icon Resolution Logic
iconName = computed(() => {
return this.icon() ?? this.#bulletList?.icon();
});
Resolution order:
- Use item's own
iconinput if provided - Fall back to parent list's
iconinput - Fall back to default
'isaActionChevronRight'
Change Detection Strategy
Both components use OnPush change detection for optimal performance:
- Changes only trigger when inputs change
- Computed signals automatically track dependencies
- No manual change detection needed
Standalone Architecture
Components are fully standalone with explicit imports:
imports: [NgIcon] // BulletListItemComponent
imports: [] // BulletListComponent (no dependencies)
Testing
The library uses Vitest with Angular Testing Utilities for testing.
Running Tests
# Run tests for this library
npx nx test ui-bullet-list --skip-nx-cache
# Run tests with coverage
npx nx test ui-bullet-list --code-coverage --skip-nx-cache
# Run tests in watch mode
npx nx test ui-bullet-list --watch
Test Coverage
The library includes comprehensive tests covering:
- Component rendering - Verifies components render correctly
- Icon inheritance - Tests parent-to-child icon propagation
- Icon override - Tests per-item icon customization
- Content projection - Validates ng-content rendering
- Host injection - Tests optional host injection behavior
- Signal reactivity - Tests computed signal updates
Example Test
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { describe, it, expect, beforeEach } from 'vitest';
import { BulletListComponent, BulletListItemComponent } from '@isa/ui/bullet-list';
describe('BulletListItemComponent', () => {
let component: BulletListItemComponent;
let fixture: ComponentFixture<BulletListItemComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [BulletListItemComponent, BulletListComponent]
});
fixture = TestBed.createComponent(BulletListItemComponent);
component = fixture.componentInstance;
});
it('should use parent icon when no icon provided', () => {
// Arrange: Create parent list with custom icon
const parentFixture = TestBed.createComponent(BulletListComponent);
parentFixture.componentInstance.icon.set('isaActionCheck');
// Act: Create child item
const childFixture = TestBed.createComponent(BulletListItemComponent);
// Assert: Child should inherit parent icon
expect(childFixture.componentInstance.iconName()).toBe('isaActionCheck');
});
it('should override parent icon when icon input provided', () => {
// Arrange & Act
component.icon.set('isaActionWarning');
fixture.detectChanges();
// Assert
expect(component.iconName()).toBe('isaActionWarning');
});
});
Dependencies
Required Libraries
@angular/core- Angular framework (v20.1.2)@ng-icons/core- Icon component library@isa/icons- ISA icon set (providesisaActionChevronRight)
Path Alias
Import from: @isa/ui/bullet-list
Peer Dependencies
The components require the icon library to be properly configured at the application level. Ensure @ng-icons/core is installed and configured.
Best Practices
- Consistent Icon Usage - Use the same icon set throughout your application for visual consistency
- Semantic Icons - Choose icons that match the context (check marks for completed items, chevrons for navigation)
- Accessibility - Ensure icon meanings are clear from surrounding text
- Performance - The OnPush strategy means you can safely use these components in large lists
- Content Structure - Keep list items concise; use nested HTML for complex content
- Icon Registration - Only icons used in the list need to be registered (parent component handles default)
License
Internal ISA Frontend library - not for external distribution.