mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
- 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
787 lines
19 KiB
Markdown
787 lines
19 KiB
Markdown
# @isa/ui/menu
|
|
|
|
A lightweight Angular component library providing accessible menu components built on Angular CDK Menu. Part of the ISA Design System.
|
|
|
|
## Overview
|
|
|
|
The Menu component library delivers reusable, accessible menu components that wrap Angular CDK Menu directives with ISA-specific styling and conventions. It provides a simple API for creating dropdown menus, context menus, and other menu-based UI patterns.
|
|
|
|
### Key Features
|
|
|
|
- **Angular CDK Integration**: Built on `@angular/cdk/menu` for robust accessibility and keyboard navigation
|
|
- **Host Directives Pattern**: Leverages Angular host directives for clean, declarative API
|
|
- **Minimal Overhead**: Thin wrapper around CDK with ISA styling hooks
|
|
- **CSS-Based Styling**: Uses Tailwind and ISA design tokens via CSS classes
|
|
- **Keyboard Navigation**: Full keyboard support (Arrow keys, Enter, Escape) via CDK
|
|
- **ARIA Compliance**: Automatic ARIA attributes for screen readers
|
|
- **Standalone Components**: Modern Angular standalone architecture
|
|
|
|
## Installation
|
|
|
|
This library is part of the ISA monorepo and uses path aliases for imports:
|
|
|
|
```typescript
|
|
import { UiMenu, MenuComponent, MenuItemDirective } from '@isa/ui/menu';
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Basic Usage
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
|
|
@Component({
|
|
selector: 'app-example',
|
|
standalone: true,
|
|
imports: [UiMenu],
|
|
template: `
|
|
<ui-menu>
|
|
<button uiMenuItem>Action 1</button>
|
|
<button uiMenuItem>Action 2</button>
|
|
<button uiMenuItem>Action 3</button>
|
|
</ui-menu>
|
|
`
|
|
})
|
|
export class ExampleComponent {}
|
|
```
|
|
|
|
### Dropdown Menu Example
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
import { CdkMenuTrigger } from '@angular/cdk/menu';
|
|
|
|
@Component({
|
|
selector: 'app-dropdown-example',
|
|
standalone: true,
|
|
imports: [UiMenu, CdkMenuTrigger],
|
|
template: `
|
|
<button [cdkMenuTriggerFor]="menu">Open Menu</button>
|
|
|
|
<ng-template #menu>
|
|
<ui-menu>
|
|
<button uiMenuItem (click)="onEdit()">Edit</button>
|
|
<button uiMenuItem (click)="onDelete()">Delete</button>
|
|
<button uiMenuItem (click)="onShare()">Share</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
`
|
|
})
|
|
export class DropdownExampleComponent {
|
|
onEdit() { console.log('Edit clicked'); }
|
|
onDelete() { console.log('Delete clicked'); }
|
|
onShare() { console.log('Share clicked'); }
|
|
}
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### MenuComponent
|
|
|
|
**Selector**: `ui-menu`
|
|
|
|
A container component for menu items that provides accessibility and keyboard navigation.
|
|
|
|
#### Host Directives
|
|
|
|
- **CdkMenu**: Provides core menu functionality, keyboard navigation, and ARIA attributes
|
|
|
|
#### Host Properties
|
|
|
|
- **CSS Class**: `.ui-menu` - Applied to the host element for styling
|
|
|
|
#### Template
|
|
|
|
- Simple content projection: `<ng-content></ng-content>`
|
|
|
|
####Configuration
|
|
|
|
- **Change Detection**: Default (inherited from Angular)
|
|
- **View Encapsulation**: Default
|
|
- **Standalone**: `false` (import via `UiMenu` array)
|
|
|
|
### MenuItemDirective
|
|
|
|
**Selector**: `[uiMenuItem]`
|
|
|
|
A directive that marks elements as menu items, adding appropriate styling and behavior.
|
|
|
|
#### Host Directives
|
|
|
|
- **CdkMenuItem**: Provides menu item functionality, click handling, and ARIA attributes
|
|
|
|
#### Host Properties
|
|
|
|
- **CSS Class**: `.ui-menu-item` - Applied to the host element for styling
|
|
|
|
#### Configuration
|
|
|
|
- **Standalone**: `false` (import via `UiMenu` array)
|
|
|
|
### UiMenu Import Array
|
|
|
|
Convenience import for both menu components:
|
|
|
|
```typescript
|
|
export const UiMenu = [MenuComponent, MenuItemDirective];
|
|
```
|
|
|
|
**Usage**:
|
|
```typescript
|
|
imports: [UiMenu] // Imports both MenuComponent and MenuItemDirective
|
|
```
|
|
|
|
## Usage Examples
|
|
|
|
### Example 1: Simple Menu List
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
|
|
@Component({
|
|
selector: 'app-simple-menu',
|
|
standalone: true,
|
|
imports: [UiMenu],
|
|
template: `
|
|
<ui-menu>
|
|
<button uiMenuItem>Home</button>
|
|
<button uiMenuItem>About</button>
|
|
<button uiMenuItem>Contact</button>
|
|
</ui-menu>
|
|
`
|
|
})
|
|
export class SimpleMenuComponent {}
|
|
```
|
|
|
|
### Example 2: Context Menu with Icons
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
import { CdkContextMenuTrigger } from '@angular/cdk/menu';
|
|
import { NgIconComponent } from '@ng-icons/core';
|
|
|
|
@Component({
|
|
selector: 'app-context-menu',
|
|
standalone: true,
|
|
imports: [UiMenu, CdkContextMenuTrigger, NgIconComponent],
|
|
template: `
|
|
<div [cdkContextMenuTriggerFor]="contextMenu" class="context-area">
|
|
Right-click here
|
|
</div>
|
|
|
|
<ng-template #contextMenu>
|
|
<ui-menu>
|
|
<button uiMenuItem>
|
|
<ng-icon name="isaActionCopy"></ng-icon>
|
|
Copy
|
|
</button>
|
|
<button uiMenuItem>
|
|
<ng-icon name="isaActionPaste"></ng-icon>
|
|
Paste
|
|
</button>
|
|
<button uiMenuItem>
|
|
<ng-icon name="isaActionDelete"></ng-icon>
|
|
Delete
|
|
</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
`
|
|
})
|
|
export class ContextMenuComponent {}
|
|
```
|
|
|
|
### Example 3: Nested Menus (Submenus)
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
import { CdkMenuTrigger } from '@angular/cdk/menu';
|
|
|
|
@Component({
|
|
selector: 'app-nested-menu',
|
|
standalone: true,
|
|
imports: [UiMenu, CdkMenuTrigger],
|
|
template: `
|
|
<button [cdkMenuTriggerFor]="mainMenu">File</button>
|
|
|
|
<ng-template #mainMenu>
|
|
<ui-menu>
|
|
<button uiMenuItem>New File</button>
|
|
<button uiMenuItem [cdkMenuTriggerFor]="openMenu">Open</button>
|
|
<button uiMenuItem>Save</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
|
|
<ng-template #openMenu>
|
|
<ui-menu>
|
|
<button uiMenuItem>Recent Files</button>
|
|
<button uiMenuItem>Browse...</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
`
|
|
})
|
|
export class NestedMenuComponent {}
|
|
```
|
|
|
|
### Example 4: Menu with Disabled Items
|
|
|
|
```typescript
|
|
import { Component, signal } from '@angular/core';
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
import { CdkMenuTrigger } from '@angular/cdk/menu';
|
|
|
|
@Component({
|
|
selector: 'app-disabled-menu',
|
|
standalone: true,
|
|
imports: [UiMenu, CdkMenuTrigger],
|
|
template: `
|
|
<button [cdkMenuTriggerFor]="menu">Actions</button>
|
|
|
|
<ng-template #menu>
|
|
<ui-menu>
|
|
<button uiMenuItem [disabled]="false">Edit</button>
|
|
<button uiMenuItem [disabled]="!canDelete()">Delete</button>
|
|
<button uiMenuItem [disabled]="false">Share</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
`
|
|
})
|
|
export class DisabledMenuComponent {
|
|
canDelete = signal(false); // Dynamic disabled state
|
|
}
|
|
```
|
|
|
|
### Example 5: Menu with Click Handlers
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
import { CdkMenuTrigger } from '@angular/cdk/menu';
|
|
import { Router } from '@angular/router';
|
|
|
|
@Component({
|
|
selector: 'app-navigation-menu',
|
|
standalone: true,
|
|
imports: [UiMenu, CdkMenuTrigger],
|
|
template: `
|
|
<button [cdkMenuTriggerFor]="menu">Navigate</button>
|
|
|
|
<ng-template #menu>
|
|
<ui-menu>
|
|
<button uiMenuItem (click)="navigateTo('/dashboard')">Dashboard</button>
|
|
<button uiMenuItem (click)="navigateTo('/reports')">Reports</button>
|
|
<button uiMenuItem (click)="navigateTo('/settings')">Settings</button>
|
|
<button uiMenuItem (click)="logout()">Logout</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
`
|
|
})
|
|
export class NavigationMenuComponent {
|
|
constructor(private router: Router) {}
|
|
|
|
navigateTo(path: string): void {
|
|
this.router.navigate([path]);
|
|
}
|
|
|
|
logout(): void {
|
|
// Logout logic
|
|
}
|
|
}
|
|
```
|
|
|
|
## Architecture Notes
|
|
|
|
### Component Structure
|
|
|
|
```
|
|
MenuComponent
|
|
├── Host Element (<ui-menu>)
|
|
│ ├── Host Directive: CdkMenu
|
|
│ │ ├── Keyboard Navigation (Arrow keys, Enter, Escape)
|
|
│ │ ├── ARIA Attributes (role="menu")
|
|
│ │ └── Focus Management
|
|
│ ├── CSS Class: .ui-menu
|
|
│ └── <ng-content> (Projects menu items)
|
|
|
|
MenuItemDirective
|
|
├── Host Element ([uiMenuItem])
|
|
│ ├── Host Directive: CdkMenuItem
|
|
│ │ ├── Click Handling
|
|
│ │ ├── ARIA Attributes (role="menuitem")
|
|
│ │ └── Keyboard Interaction
|
|
│ └── CSS Class: .ui-menu-item
|
|
```
|
|
|
|
### Host Directives Pattern
|
|
|
|
**Why Host Directives?**
|
|
|
|
This library uses Angular's **host directives** feature introduced in Angular 15 to:
|
|
|
|
1. **Reuse CDK Logic**: Leverage `@angular/cdk/menu` without re-implementing functionality
|
|
2. **Clean API**: Hide CDK complexity while exposing ISA-specific styling
|
|
3. **Maintainability**: CDK updates automatically benefit this library
|
|
4. **Type Safety**: Full TypeScript support for all CDK features
|
|
|
|
**How It Works**:
|
|
|
|
```typescript
|
|
@Component({
|
|
selector: 'ui-menu',
|
|
template: '<ng-content></ng-content>',
|
|
host: { class: 'ui-menu' },
|
|
hostDirectives: [CdkMenu], // Applies CdkMenu to this component's host
|
|
})
|
|
export class MenuComponent {}
|
|
```
|
|
|
|
When you use `<ui-menu>`, it automatically:
|
|
- Applies all `CdkMenu` behaviors (keyboard nav, ARIA, etc.)
|
|
- Adds `.ui-menu` CSS class for styling
|
|
- Projects child content (menu items)
|
|
|
|
### CDK Menu Features
|
|
|
|
**Automatic Features** (via CdkMenu):
|
|
|
|
- **Keyboard Navigation**:
|
|
- `↓` / `↑`: Navigate menu items
|
|
- `Enter` / `Space`: Activate item
|
|
- `Escape`: Close menu
|
|
- `Tab`: Move focus out of menu
|
|
|
|
- **ARIA Attributes**:
|
|
- `role="menu"` on menu container
|
|
- `role="menuitem"` on menu items
|
|
- `aria-disabled` on disabled items
|
|
- `aria-haspopup` for submenus
|
|
|
|
- **Focus Management**:
|
|
- Auto-focus first item on open
|
|
- Circular focus wrapping
|
|
- Focus restoration on close
|
|
|
|
### Styling Architecture
|
|
|
|
**CSS Class Hooks**:
|
|
|
|
```scss
|
|
// Applied by MenuComponent
|
|
.ui-menu {
|
|
// Container styles (padding, background, border, shadow)
|
|
}
|
|
|
|
// Applied by MenuItemDirective
|
|
.ui-menu-item {
|
|
// Item styles (padding, hover, focus, active states)
|
|
}
|
|
|
|
// Disabled state (via CDK)
|
|
.ui-menu-item[disabled] {
|
|
// Disabled styles (opacity, cursor, pointer-events)
|
|
}
|
|
```
|
|
|
|
**Tailwind Integration**:
|
|
|
|
The library provides CSS class hooks that can be styled via:
|
|
- Global SCSS files
|
|
- Tailwind `@apply` directives
|
|
- Custom Tailwind plugins (ISA menu plugin)
|
|
|
|
**Example Tailwind Configuration**:
|
|
|
|
```css
|
|
/* styles.scss */
|
|
.ui-menu {
|
|
@apply bg-white shadow-lg rounded-md py-1;
|
|
}
|
|
|
|
.ui-menu-item {
|
|
@apply px-4 py-2 hover:bg-gray-100 cursor-pointer;
|
|
}
|
|
|
|
.ui-menu-item[disabled] {
|
|
@apply opacity-50 cursor-not-allowed;
|
|
}
|
|
```
|
|
|
|
### Integration with Angular CDK
|
|
|
|
**Required CDK Directives** (imported separately):
|
|
|
|
```typescript
|
|
import { CdkMenuTrigger } from '@angular/cdk/menu'; // For dropdown triggers
|
|
import { CdkContextMenuTrigger } from '@angular/cdk/menu'; // For context menus
|
|
```
|
|
|
|
**CDK Menu Trigger**:
|
|
|
|
```typescript
|
|
<button [cdkMenuTriggerFor]="menuTemplate">Open Menu</button>
|
|
<ng-template #menuTemplate>
|
|
<ui-menu>...</ui-menu>
|
|
</ng-template>
|
|
```
|
|
|
|
**CDK Context Menu Trigger**:
|
|
|
|
```typescript
|
|
<div [cdkContextMenuTriggerFor]="contextMenuTemplate">Right-click me</div>
|
|
<ng-template #contextMenuTemplate>
|
|
<ui-menu>...</ui-menu>
|
|
</ng-template>
|
|
```
|
|
|
|
### Performance Characteristics
|
|
|
|
**Optimization Strategies**:
|
|
- **Lightweight Components**: Minimal overhead over CDK base
|
|
- **No Template**: MenuComponent uses empty template (content projection only)
|
|
- **No Change Detection**: Default strategy (components are simple wrappers)
|
|
- **CDK Optimizations**: Inherits CDK's efficient event handling and focus management
|
|
|
|
**Bundle Impact**:
|
|
- **Component Size**: ~2KB (both components combined)
|
|
- **CDK Dependency**: ~15KB (shared with other CDK features)
|
|
- **Total Overhead**: Minimal, mostly CDK dependency
|
|
|
|
## Dependencies
|
|
|
|
### Angular Dependencies
|
|
|
|
| Package | Version | Purpose |
|
|
|---------|---------|---------|
|
|
| `@angular/core` | 20.1.2 | Component framework and dependency injection |
|
|
| `@angular/cdk/menu` | 20.1.2 | CDK Menu directives for accessibility and keyboard nav |
|
|
|
|
### Internal Dependencies
|
|
|
|
None - this library has no dependencies on other `@isa/*` libraries.
|
|
|
|
### Peer Dependencies
|
|
|
|
```json
|
|
{
|
|
"peerDependencies": {
|
|
"@angular/core": "^20.0.0",
|
|
"@angular/cdk": "^20.0.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Test Configuration
|
|
|
|
**Framework**: Jest
|
|
|
|
**Configuration**: `jest.config.ts` (extends workspace defaults)
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# Run tests with fresh results
|
|
npx nx test ui-menu --skip-nx-cache
|
|
|
|
# Run tests in watch mode
|
|
npx nx test ui-menu --watch
|
|
|
|
# Run tests with coverage
|
|
npx nx test ui-menu --code-coverage --skip-nx-cache
|
|
```
|
|
|
|
### Testing Recommendations
|
|
|
|
#### Unit Test Coverage
|
|
|
|
**Test menu rendering**:
|
|
```typescript
|
|
import { TestBed } from '@angular/core/testing';
|
|
import { MenuComponent, MenuItemDirective } from '@isa/ui/menu';
|
|
|
|
describe('MenuComponent', () => {
|
|
it('should render menu with items', () => {
|
|
const fixture = TestBed.createComponent(MenuComponent);
|
|
fixture.detectChanges();
|
|
|
|
const menuElement = fixture.nativeElement;
|
|
expect(menuElement.classList.contains('ui-menu')).toBe(true);
|
|
});
|
|
});
|
|
```
|
|
|
|
**Test menu item directive**:
|
|
```typescript
|
|
describe('MenuItemDirective', () => {
|
|
it('should apply ui-menu-item class', () => {
|
|
// Create test component with directive
|
|
const fixture = TestBed.createComponent(TestHostComponent);
|
|
fixture.detectChanges();
|
|
|
|
const menuItem = fixture.nativeElement.querySelector('[uiMenuItem]');
|
|
expect(menuItem.classList.contains('ui-menu-item')).toBe(true);
|
|
});
|
|
});
|
|
```
|
|
|
|
**Test keyboard navigation** (via CDK):
|
|
```typescript
|
|
it('should navigate menu items with keyboard', () => {
|
|
const fixture = TestBed.createComponent(MenuComponent);
|
|
fixture.detectChanges();
|
|
|
|
const menuElement = fixture.nativeElement;
|
|
|
|
// Simulate down arrow
|
|
menuElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
|
|
|
|
// Verify focus moved
|
|
expect(document.activeElement).toBe(firstMenuItem);
|
|
});
|
|
```
|
|
|
|
#### Integration Test Scenarios
|
|
|
|
**Test with CDK trigger**:
|
|
```typescript
|
|
import { CdkMenuTrigger } from '@angular/cdk/menu';
|
|
|
|
@Component({
|
|
template: `
|
|
<button [cdkMenuTriggerFor]="menu" #trigger="cdkMenuTrigger">Open</button>
|
|
<ng-template #menu>
|
|
<ui-menu>
|
|
<button uiMenuItem>Item 1</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
`
|
|
})
|
|
class TestHostComponent {}
|
|
|
|
it('should open menu on trigger click', () => {
|
|
const fixture = TestBed.createComponent(TestHostComponent);
|
|
fixture.detectChanges();
|
|
|
|
const triggerButton = fixture.nativeElement.querySelector('button');
|
|
triggerButton.click();
|
|
fixture.detectChanges();
|
|
|
|
// Verify menu is open
|
|
const menu = document.querySelector('ui-menu');
|
|
expect(menu).toBeTruthy();
|
|
});
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Use CDK Triggers for Dropdown Menus
|
|
|
|
```typescript
|
|
// ✅ GOOD: Use CdkMenuTrigger for dropdowns
|
|
<button [cdkMenuTriggerFor]="menu">Open Menu</button>
|
|
<ng-template #menu>
|
|
<ui-menu>...</ui-menu>
|
|
</ng-template>
|
|
|
|
// ❌ BAD: Manual show/hide logic
|
|
<button (click)="showMenu = true">Open Menu</button>
|
|
<ui-menu *ngIf="showMenu">...</ui-menu>
|
|
```
|
|
|
|
### 2. Always Use MenuItemDirective on Interactive Elements
|
|
|
|
```typescript
|
|
// ✅ GOOD: Apply directive to buttons
|
|
<ui-menu>
|
|
<button uiMenuItem>Action</button>
|
|
</ui-menu>
|
|
|
|
// ❌ BAD: Non-interactive elements
|
|
<ui-menu>
|
|
<div uiMenuItem>Action</div> // Won't receive keyboard events properly
|
|
</ui-menu>
|
|
```
|
|
|
|
### 3. Leverage CDK Features
|
|
|
|
```typescript
|
|
// ✅ GOOD: Use CDK for submenus
|
|
<button uiMenuItem [cdkMenuTriggerFor]="submenu">More</button>
|
|
<ng-template #submenu>
|
|
<ui-menu>...</ui-menu>
|
|
</ng-template>
|
|
|
|
// ❌ BAD: Manual submenu implementation
|
|
<button uiMenuItem (click)="toggleSubmenu()">More</button>
|
|
<ui-menu *ngIf="submenuOpen">...</ui-menu>
|
|
```
|
|
|
|
### 4. Provide ARIA Labels for Icon-Only Items
|
|
|
|
```typescript
|
|
// ✅ GOOD: Accessible icon-only menu item
|
|
<button uiMenuItem aria-label="Delete">
|
|
<ng-icon name="isaActionDelete"></ng-icon>
|
|
</button>
|
|
|
|
// ❌ BAD: No accessible label
|
|
<button uiMenuItem>
|
|
<ng-icon name="isaActionDelete"></ng-icon>
|
|
</button>
|
|
```
|
|
|
|
### 5. Use Semantic HTML
|
|
|
|
```typescript
|
|
// ✅ GOOD: Use buttons for actions
|
|
<ui-menu>
|
|
<button uiMenuItem>Edit</button>
|
|
<button uiMenuItem>Delete</button>
|
|
</ui-menu>
|
|
|
|
// ❌ BAD: Use divs/spans
|
|
<ui-menu>
|
|
<div uiMenuItem>Edit</div>
|
|
<span uiMenuItem>Delete</span>
|
|
</ui-menu>
|
|
```
|
|
|
|
### 6. Handle Menu Item Clicks Properly
|
|
|
|
```typescript
|
|
// ✅ GOOD: Use click handlers on menu items
|
|
<button uiMenuItem (click)="handleAction()">Action</button>
|
|
|
|
// ❌ BAD: Wrap in extra divs with click handlers
|
|
<div (click)="handleAction()">
|
|
<button uiMenuItem>Action</button>
|
|
</div>
|
|
```
|
|
|
|
## Common Pitfalls
|
|
|
|
### 1. Forgetting CDK Imports
|
|
|
|
```typescript
|
|
// ❌ ERROR: Missing CdkMenuTrigger import
|
|
imports: [UiMenu]
|
|
|
|
// ✅ CORRECT: Import CDK directives separately
|
|
imports: [UiMenu, CdkMenuTrigger]
|
|
```
|
|
|
|
### 2. Using Menu Without Template
|
|
|
|
```typescript
|
|
// ❌ ERROR: Menu needs ng-template with trigger
|
|
<ui-menu>
|
|
<button uiMenuItem>Item</button>
|
|
</ui-menu>
|
|
|
|
// ✅ CORRECT: Use with CDK trigger and template
|
|
<button [cdkMenuTriggerFor]="menu">Open</button>
|
|
<ng-template #menu>
|
|
<ui-menu>
|
|
<button uiMenuItem>Item</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
```
|
|
|
|
### 3. Incorrect Selector Usage
|
|
|
|
```typescript
|
|
// ❌ ERROR: Wrong directive name
|
|
<button menuItem>Action</button>
|
|
|
|
// ✅ CORRECT: Use uiMenuItem
|
|
<button uiMenuItem>Action</button>
|
|
```
|
|
|
|
## Migration Guide
|
|
|
|
### From Custom Menu to @isa/ui/menu
|
|
|
|
**Before**:
|
|
```typescript
|
|
@Component({
|
|
template: `
|
|
<div class="custom-menu">
|
|
<div class="menu-item" (click)="action1()">Action 1</div>
|
|
<div class="menu-item" (click)="action2()">Action 2</div>
|
|
</div>
|
|
`
|
|
})
|
|
```
|
|
|
|
**After**:
|
|
```typescript
|
|
import { UiMenu } from '@isa/ui/menu';
|
|
import { CdkMenuTrigger } from '@angular/cdk/menu';
|
|
|
|
@Component({
|
|
standalone: true,
|
|
imports: [UiMenu, CdkMenuTrigger],
|
|
template: `
|
|
<button [cdkMenuTriggerFor]="menu">Open Menu</button>
|
|
<ng-template #menu>
|
|
<ui-menu>
|
|
<button uiMenuItem (click)="action1()">Action 1</button>
|
|
<button uiMenuItem (click)="action2()">Action 2</button>
|
|
</ui-menu>
|
|
</ng-template>
|
|
`
|
|
})
|
|
```
|
|
|
|
**Benefits**:
|
|
- Automatic keyboard navigation
|
|
- ARIA compliance
|
|
- Focus management
|
|
- Consistent styling
|
|
- Less custom code
|
|
|
|
## Related Documentation
|
|
|
|
- **Angular CDK Menu**: [Official CDK Menu Documentation](https://material.angular.io/cdk/menu/overview)
|
|
- **Host Directives**: Angular guide on host directives
|
|
- **@isa/ui/buttons**: Button components often used with menus
|
|
- **ISA Design System**: Menu styling guidelines
|
|
|
|
## Support and Contributing
|
|
|
|
For questions, issues, or contributions related to the Menu components:
|
|
|
|
1. Review Angular CDK Menu documentation for advanced features
|
|
2. Check ISA Design System for styling standards
|
|
3. Consult Tailwind configuration for menu styling utilities
|
|
4. Follow Angular standalone component best practices
|
|
|
|
## Changelog
|
|
|
|
### Current Version
|
|
|
|
**Features**:
|
|
- Standalone-ready component and directive
|
|
- Angular CDK Menu integration via host directives
|
|
- Minimal API surface (component + directive)
|
|
- Full keyboard navigation and ARIA support
|
|
- Tailwind/ISA design system styling hooks
|
|
|
|
**Testing**:
|
|
- Jest configuration
|
|
- Unit tests for component and directive
|
|
|
|
---
|
|
|
|
**Package**: `@isa/ui/menu`
|
|
**Path Alias**: `@isa/ui/menu`
|
|
**Entry Point**: `libs/ui/menu/src/index.ts`
|
|
**Selectors**: `ui-menu`, `[uiMenuItem]`
|
|
**Type**: Angular Component Library (CDK Wrapper)
|