@libs-ui/components-breadcrumb
v0.2.357-11
Published
> Component hiển thị tiến trình nhiều bước (step indicator / breadcrumb) cho các quy trình làm việc trong Angular.
Readme
@libs-ui/components-breadcrumb
Component hiển thị tiến trình nhiều bước (step indicator / breadcrumb) cho các quy trình làm việc trong Angular.
Giới thiệu
@libs-ui/components-breadcrumb cung cấp hai component: LibsUiComponentsBreadcrumbComponent dùng cho breadcrumb bước đơn giản dạng số thứ tự, và LibsUiComponentsBreadcrumbMultiStepComponent dùng cho breadcrumb dạng tab liền khối (pill-style) hỗ trợ dropdown tại từng bước. Cả hai đều hỗ trợ điều khiển programmatic qua FunctionsControl, tích hợp i18n, và sử dụng Angular Signals với ChangeDetectionStrategy.OnPush.
Tính năng
- ✅ Hiển thị các bước với số thứ tự, tiêu đề và trạng thái (đang chọn, đã hoàn thành, vô hiệu hóa)
- ✅ Three alignment modes:
center(mặc định),left,right - ✅ Tùy chỉnh độ rộng dải ngăn cách giữa các bước
- ✅ Two-way binding cho
completedIndexvàstepsqua Angular Signalsmodel() - ✅ Điều khiển programmatic qua
IBreadCrumbFunctionControlEvent(set selected, complete, disable, reset) - ✅ Sub-component
MultiStepvới kiểu hiển thị pill liền khối, hỗ trợ dropdown tại từng bước - ✅ Tích hợp
@ngx-translate/corecho tiêu đề đa ngôn ngữ - ✅ Standalone component,
ChangeDetectionStrategy.OnPush, Angular Signals - ✅ Hỗ trợ accessibility: keyboard navigation (
Enter,Space)
Khi nào sử dụng
- Khi cần hiển thị tiến trình của quy trình nhiều bước (wizard, multi-step form, checkout flow)
- Khi muốn cho người dùng biết đang ở bước nào và còn bao nhiêu bước còn lại
- Khi cần điều khiển breadcrumb từ bên ngoài (tự động chuyển bước, đánh dấu hoàn thành) qua API
- Khi có quy trình phức tạp với từng bước có thể chọn giá trị từ dropdown (
MultiStep)
Cài đặt
npm install @libs-ui/components-breadcrumbImport
// Component breadcrumb bước đơn giản
import { LibsUiComponentsBreadcrumbComponent } from '@libs-ui/components-breadcrumb';
// Component breadcrumb dạng pill/tab liền khối có dropdown
import { LibsUiComponentsBreadcrumbMultiStepComponent } from '@libs-ui/components-breadcrumb';
// Interfaces & Types
import {
ITabBreadCrumb,
ITabBreadCrumbSelected,
ITabBreadCrumbMultiStep,
ITabBreadCrumbMultiStepSelected,
IBreadCrumbFunctionControlEvent,
IConfigClassMultiStep,
TYPE_MODE_BREADCRUMB,
TYPE_MULTI_STEP,
} from '@libs-ui/components-breadcrumb';
@Component({
standalone: true,
imports: [LibsUiComponentsBreadcrumbComponent],
// ...
})
export class YourComponent {}Ví dụ sử dụng
1. Breadcrumb cơ bản
// your.component.ts
import { Component } from '@angular/core';
import { ITabBreadCrumb, LibsUiComponentsBreadcrumbComponent } from '@libs-ui/components-breadcrumb';
@Component({
selector: 'app-example',
standalone: true,
imports: [LibsUiComponentsBreadcrumbComponent],
templateUrl: './example.component.html',
})
export class ExampleComponent {
readonly steps: ITabBreadCrumb[] = [
{ number: 1, title: 'Thông tin cơ bản' },
{ number: 2, title: 'Cấu hình dịch vụ' },
{ number: 3, title: 'Xác nhận & Hoàn tất' },
];
}<!-- your.component.html -->
<libs_ui-components-breadcrumb [steps]="steps" />2. Breadcrumb với chế độ căn lề và độ rộng tùy chỉnh
// your.component.ts
import { Component } from '@angular/core';
import { ITabBreadCrumb, LibsUiComponentsBreadcrumbComponent } from '@libs-ui/components-breadcrumb';
@Component({
selector: 'app-example',
standalone: true,
imports: [LibsUiComponentsBreadcrumbComponent],
templateUrl: './example.component.html',
})
export class ExampleComponent {
readonly steps: ITabBreadCrumb[] = [
{ number: 1, title: 'Khởi tạo' },
{ number: 2, title: 'Thiết lập' },
{ number: 3, title: 'Hoàn thành' },
];
}<!-- Căn trái, dải ngăn cách 40px -->
<libs_ui-components-breadcrumb
[steps]="steps"
mode="left"
[width]="40"
/>
<!-- Căn phải, dải ngăn cách 20px -->
<libs_ui-components-breadcrumb
[steps]="steps"
mode="right"
[width]="20"
/>3. Breadcrumb với điều khiển programmatic qua FunctionsControl
// your.component.ts
import { Component, signal } from '@angular/core';
import {
IBreadCrumbFunctionControlEvent,
ITabBreadCrumb,
ITabBreadCrumbSelected,
LibsUiComponentsBreadcrumbComponent,
} from '@libs-ui/components-breadcrumb';
@Component({
selector: 'app-example',
standalone: true,
imports: [LibsUiComponentsBreadcrumbComponent],
templateUrl: './example.component.html',
})
export class ExampleComponent {
readonly steps: ITabBreadCrumb[] = [
{ number: 1, title: 'Nhập thông tin' },
{ number: 2, title: 'Xác minh' },
{ number: 3, title: 'Hoàn tất' },
];
readonly completedSteps = signal<number[]>([]);
private breadcrumbControl: IBreadCrumbFunctionControlEvent | undefined;
handlerFunctionControl(event: IBreadCrumbFunctionControlEvent): void {
this.breadcrumbControl = event;
}
handlerStepSelected(event: ITabBreadCrumbSelected): void {
this.breadcrumbControl?.setSelectedStep(event.index);
}
async goToNextStep(): Promise<void> {
const currentIndex = await this.breadcrumbControl?.getSelectedIndex() ?? 0;
await this.breadcrumbControl?.setCompletedStep(true, currentIndex);
await this.breadcrumbControl?.setSelectedStep(currentIndex + 1);
}
async resetAll(): Promise<void> {
await this.breadcrumbControl?.resetCompleteIndex(true);
await this.breadcrumbControl?.setSelectedStep(0);
}
}<libs_ui-components-breadcrumb
[steps]="steps"
[(completedIndex)]="completedSteps"
(outFunctionControl)="handlerFunctionControl($event)"
(outStepSelected)="handlerStepSelected($event)"
/>
<div class="flex gap-3 mt-4">
<button (click)="goToNextStep()">Bước tiếp theo</button>
<button (click)="resetAll()">Reset tất cả</button>
</div>4. MultiStep breadcrumb dạng pill
// your.component.ts
import { Component } from '@angular/core';
import {
ITabBreadCrumbMultiStep,
ITabBreadCrumbMultiStepSelected,
LibsUiComponentsBreadcrumbMultiStepComponent,
} from '@libs-ui/components-breadcrumb';
@Component({
selector: 'app-example',
standalone: true,
imports: [LibsUiComponentsBreadcrumbMultiStepComponent],
templateUrl: './example.component.html',
})
export class ExampleComponent {
readonly multiSteps: ITabBreadCrumbMultiStep[] = [
{ number: 1, title: 'Đề xuất', status: 'completed', type: 'text' },
{ number: 2, title: 'Phê duyệt', status: 'selected', type: 'text' },
{ number: 3, title: 'Thực hiện', status: 'normal', type: 'text' },
{ number: 4, title: 'Kết thúc', status: 'disabled', type: 'text' },
];
handlerMultiStepSelect(event: ITabBreadCrumbMultiStepSelected<ITabBreadCrumbMultiStep>): void {
console.log('Selected step:', event.index, 'Type:', event.type);
}
}<libs_ui-components-breadcrumb-multi_step
[stepsMulti]="multiSteps"
(outMultiStepSelect)="handlerMultiStepSelect($event)"
/>5. Bước có trạng thái disable và class tùy chỉnh
// your.component.ts
import { Component } from '@angular/core';
import { ITabBreadCrumb, LibsUiComponentsBreadcrumbComponent } from '@libs-ui/components-breadcrumb';
@Component({
selector: 'app-example',
standalone: true,
imports: [LibsUiComponentsBreadcrumbComponent],
templateUrl: './example.component.html',
})
export class ExampleComponent {
readonly steps: ITabBreadCrumb[] = [
{ number: 1, title: 'Khởi tạo' },
{ number: 2, title: 'Xem xét', disable: true },
{ number: 3, title: 'Phê duyệt', classInclude: 'w-[200px]' },
];
}<libs_ui-components-breadcrumb
[steps]="steps"
[backgroundWhite]="true"
classInclude="px-4 py-2"
/>@Input() — LibsUiComponentsBreadcrumbComponent
| Input | Type | Default | Mô tả | Ví dụ |
|---|---|---|---|---|
| [backgroundWhite] | boolean | undefined | Áp dụng nền trắng (#ffffff) cho container | [backgroundWhite]="true" |
| [classInclude] | string | undefined | Class CSS bổ sung cho container bao ngoài | classInclude="px-4 py-2" |
| [(completedIndex)] | Array<number> | [] | Two-way binding — danh sách index các bước đã hoàn thành (hiển thị icon check) | [(completedIndex)]="completedSteps" |
| [mode] | 'center' \| 'left' \| 'right' | 'center' | Canh lề của các bước trong container | mode="left" |
| [(steps)] | Array<ITabBreadCrumb> | undefined | Two-way binding — danh sách cấu hình các bước | [(steps)]="steps" |
| [width] | number | 24 | Độ rộng (px) của dải ngăn cách ngang giữa các bước | [width]="40" |
@Output() — LibsUiComponentsBreadcrumbComponent
| Output | Type | Mô tả | Handler TS | Binding HTML |
|---|---|---|---|---|
| (outFunctionControl) | IBreadCrumbFunctionControlEvent | Emit object chứa các hàm điều khiển component, phát ngay trong ngOnInit. Phải capture để gọi API programmatic. | handlerFunctionControl(event: IBreadCrumbFunctionControlEvent): void { this.control = event; } | (outFunctionControl)="handlerFunctionControl($event)" |
| (outStepSelected) | ITabBreadCrumbSelected | Emit khi người dùng click vào một bước (không phát nếu bước bị disable) | handlerStepSelected(event: ITabBreadCrumbSelected): void { this.control?.setSelectedStep(event.index); } | (outStepSelected)="handlerStepSelected($event)" |
@Input() — LibsUiComponentsBreadcrumbMultiStepComponent
Kế thừa toàn bộ Input của LibsUiComponentsBreadcrumbComponent, cộng thêm:
| Input | Type | Default | Mô tả | Ví dụ |
|---|---|---|---|---|
| [configClassMultiStep] | IConfigClassMultiStep | undefined | Cấu hình class và kích thước cho từng bước pill | [configClassMultiStep]="{ maxWidth: 160, width: 120 }" |
| [elementRef] | HTMLElement | undefined | Tham chiếu đến container HTMLElement để hỗ trợ auto-scroll đến bước đang chọn | [elementRef]="containerEl" |
| [popoverCustomConfig] | IPopoverCustomConfig | ConfigPopupDropdown() | Cấu hình popover tùy chỉnh cho dropdown tại mỗi bước | [popoverCustomConfig]="myPopoverConfig" |
| [stepsMulti] | Array<ITabBreadCrumbMultiStep> | — (required) | Danh sách cấu hình đầy đủ các bước multi-step | [stepsMulti]="multiSteps" |
@Output() — LibsUiComponentsBreadcrumbMultiStepComponent
Kế thừa toàn bộ Output của LibsUiComponentsBreadcrumbComponent, cộng thêm:
| Output | Type | Mô tả | Handler TS | Binding HTML |
|---|---|---|---|---|
| (outMultiStepSelect) | ITabBreadCrumbMultiStepSelected<any> | Emit khi người dùng chọn bước (text click hoặc chọn item từ dropdown). Kèm callBack để ẩn/hiện keys trong dropdown. | handlerMultiStepSelect(event: ITabBreadCrumbMultiStepSelected<MyStep>): void { this.onSelectStep(event); } | (outMultiStepSelect)="handlerMultiStepSelect($event)" |
FunctionsControl API — IBreadCrumbFunctionControlEvent
Capture object từ (outFunctionControl) để gọi các phương thức điều khiển:
| Method | Signature | Mô tả |
|---|---|---|
| getCompleteIndex | () => Promise<Array<number>> | Lấy danh sách index các bước đang được đánh dấu hoàn thành |
| getSelectedIndex | () => Promise<number> | Lấy index của bước đang được chọn |
| resetCompleteIndex | (resetAll: boolean, index?: number) => Promise<void> | Reset trạng thái hoàn thành — resetAll=true xóa tất cả, resetAll=false + index xóa 1 bước cụ thể |
| setCompletedStep | (complete: boolean, index: number) => Promise<void> | Đánh dấu hoặc bỏ đánh dấu hoàn thành cho bước tại index |
| setSelectedStep | (index: number) => Promise<void> | Thiết lập bước đang được chọn (highlight active) |
| setStepDisable | (steps: Array<number>) => Promise<void> | Thiết lập danh sách các bước bị vô hiệu hóa (không thể click) |
Types & Interfaces
import {
ITabBreadCrumb,
ITabBreadCrumbSelected,
ITabBreadCrumbMultiStep,
ITabBreadCrumbMultiStepSelected,
IBreadCrumbFunctionControlEvent,
IConfigClassMultiStep,
TYPE_MODE_BREADCRUMB,
TYPE_MULTI_STEP,
} from '@libs-ui/components-breadcrumb';
/** Cấu hình một bước trong breadcrumb đơn giản */
export interface ITabBreadCrumb {
number: number; // Số hiển thị trong vòng tròn bước
title: string; // Tiêu đề bước (hỗ trợ i18n key)
valid?: boolean; // Trạng thái hợp lệ
disable?: boolean; // Vô hiệu hóa click trên bước này
classInclude?: string; // Class CSS bổ sung riêng cho bước này (mặc định: 'w-full')
config?: IPopover; // Cấu hình popover tooltip
}
/** Dữ liệu emit khi chọn bước */
export interface ITabBreadCrumbSelected {
index: number; // Index (0-based) của bước được chọn
}
/** Cấu hình một bước trong MultiStep breadcrumb */
export interface ITabBreadCrumbMultiStep extends ITabBreadCrumb {
status: TYPE_MULTI_STEP; // Trạng thái hiển thị của bước
type: 'text' | 'dropdown'; // Kiểu tương tác: text click hoặc dropdown
listHasButtonUnSelectOption?: boolean; // Hiện nút bỏ chọn trong dropdown
listConfigItem?: IListConfigItem; // Cấu hình danh sách dropdown
popover?: IPopover; // Cấu hình tooltip cho tiêu đề
listKeysHidden?: Array<string>; // Danh sách keys ẩn trong dropdown
}
/** Dữ liệu emit khi chọn bước trong MultiStep */
export interface ITabBreadCrumbMultiStepSelected<T> {
type: 'text' | 'dropdown'; // Kiểu tương tác đã xảy ra
index: number; // Index (0-based) của bước được chọn
step?: T; // Item được chọn từ dropdown (nếu type='dropdown')
callBack?: (step: T) => void; // Callback để cập nhật keys ẩn trong dropdown
}
/** Object điều khiển breadcrumb từ bên ngoài (emit qua outFunctionControl) */
export interface IBreadCrumbFunctionControlEvent {
setSelectedStep: (index: number) => Promise<void>;
setCompletedStep: (complete: boolean, index: number) => Promise<void>;
setStepDisable: (steps: Array<number>) => Promise<void>;
getCompleteIndex: () => Promise<Array<number>>;
getSelectedIndex: () => Promise<number>;
resetCompleteIndex: (resetAll: boolean, index?: number) => Promise<void>;
}
/** Cấu hình class/kích thước cho MultiStep pill */
export interface IConfigClassMultiStep {
classTitleInclude?: string; // Class CSS bổ sung cho phần tiêu đề trong pill
classInclude?: string; // Class CSS bổ sung cho container pill
maxWidth?: number; // Chiều rộng tối đa (px) của pill
width?: number; // Chiều rộng cố định (px) của pill
}
/** Chế độ căn lề breadcrumb */
export type TYPE_MODE_BREADCRUMB = 'center' | 'left' | 'right';
/**
* Trạng thái hiển thị của bước trong MultiStep:
* - 'completed': đã hoàn thành (màu xanh lá)
* - 'selected': đang được chọn (màu brand chính)
* - 'failed': thất bại (màu đỏ)
* - 'disabled': vô hiệu hóa (màu xám, không click được)
* - 'normal': bình thường chưa thực hiện
*/
export type TYPE_MULTI_STEP = 'completed' | 'selected' | 'failed' | 'disabled' | 'normal';Lưu ý quan trọng
⚠️ FunctionsControl emit trong ngOnInit: (outFunctionControl) phát ngay khi component khởi tạo (ngOnInit). Phải khai báo handler và lưu object vào biến class để sử dụng sau — không nhận được nếu đăng ký quá muộn.
⚠️ stepsMulti là required trong MultiStep: LibsUiComponentsBreadcrumbMultiStepComponent yêu cầu bắt buộc [stepsMulti]. Thiếu prop này sẽ văng lỗi TypeScript tại compile time.
⚠️ Bước disable không phát sự kiện: Bước có disable: true (với ITabBreadCrumb) hoặc status: 'disabled' (với ITabBreadCrumbMultiStep) sẽ không trigger outStepSelected hay outMultiStepSelect.
⚠️ completedIndex dùng model() — Two-way binding: [(completedIndex)] là Angular Signal model(), không phải @Input/@Output truyền thống. Có thể bind hai chiều hoặc chỉ bind một chiều [completedIndex].
⚠️ Auto-scroll trong MultiStep: Truyền [elementRef] (tham chiếu đến container có overflow-x: auto) để component tự động cuộn đến bước đang được chọn khi mount.
Sub-components
LibsUiComponentsBreadcrumbMultiStepComponent
Component con kế thừa từ LibsUiComponentsBreadcrumbComponent, cung cấp kiểu hiển thị breadcrumb dạng pill/tab liền khối thường dùng trong các màn hình phức tạp với nhiều trạng thái (completed, selected, failed, disabled, normal). Mỗi bước có thể là text click hoặc dropdown để chọn sub-item.
import { LibsUiComponentsBreadcrumbMultiStepComponent } from '@libs-ui/components-breadcrumb';<!-- Selector: libs_ui-components-breadcrumb-multi_step -->
<libs_ui-components-breadcrumb-multi_step
[stepsMulti]="steps"
mode="left"
(outMultiStepSelect)="handlerMultiStepSelect($event)"
/>