@libs-ui/components-process-bar-standard
v0.2.357-4
Published
> Component hiển thị thanh tiến trình (progress bar) dạng stack hoặc separate với hỗ trợ Angular Signals.
Downloads
3,018
Readme
@libs-ui/components-process-bar-standard
Component hiển thị thanh tiến trình (progress bar) dạng stack hoặc separate với hỗ trợ Angular Signals.
Giới thiệu
LibsUiComponentsProcessBarStandardComponent là standalone Angular component hiển thị thanh tiến trình đa bước. Component hỗ trợ 2 chế độ: stack (các bước ghép liền nhau thành 1 thanh) và separate (mỗi bước là 1 thanh riêng). Toàn bộ state quản lý qua Angular Signals với kiến trúc Nested Signal — mỗi step là một WritableSignal độc lập, cho phép cập nhật realtime mà không re-render toàn bộ.
Tính năng
- ✅ Chế độ Stack — các bước nối liền nhau trên 1 thanh, tỷ lệ tính tự động theo
totalValue - ✅ Chế độ Separate — mỗi bước hiển thị thành 1 thanh riêng biệt kèm label và phần trăm
- ✅ Hiển thị phần trăm tùy chọn cho từng bước hoặc toàn bộ config
- ✅ Label tùy chỉnh ngay trong thanh (stack và separate)
- ✅ Custom class, màu sắc, bo góc, chiều cao, chiều rộng linh hoạt
- ✅ Nested Signals — cập nhật từng step riêng lẻ mà không trigger re-render toàn bộ
- ✅ Global default config qua injection token
PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT - ✅
OnPushChange Detection + Standalone Component
Khi nào sử dụng
- Hiển thị tiến trình của một quy trình đa bước (upload, xử lý, phê duyệt)
- Dashboard widget so sánh các chỉ số (doanh thu, mục tiêu, trạng thái)
- Hiển thị tỷ lệ phân bổ dữ liệu (ví dụ: phân bổ ngân sách, nguồn lực)
- Realtime progress với dữ liệu thay đổi thường xuyên nhờ Nested Signals
Cài đặt
npm install @libs-ui/components-process-bar-standardImport
import { LibsUiComponentsProcessBarStandardComponent } from '@libs-ui/components-process-bar-standard';
@Component({
standalone: true,
imports: [LibsUiComponentsProcessBarStandardComponent],
// ...
})
export class MyComponent {}Ví dụ sử dụng
Ví dụ 1 — Stack cơ bản (3 bước)
import { signal } from '@angular/core';
import {
LibsUiComponentsProcessBarStandardComponent,
IProcessBarStandardInterface,
IProcessBarStandardStepInterface,
} from '@libs-ui/components-process-bar-standard';
@Component({
standalone: true,
imports: [LibsUiComponentsProcessBarStandardComponent],
template: `
<libs_ui-components-process_bar-standard [config]="configStack()" />
`,
})
export class MyComponent {
private readonly stepProcessing = signal<IProcessBarStandardStepInterface>({
value: 30,
color: '#EF4444',
label: 'Processing',
});
private readonly stepDone = signal<IProcessBarStandardStepInterface>({
value: 50,
color: '#3B82F6',
label: 'Done',
});
private readonly stepPending = signal<IProcessBarStandardStepInterface>({
value: 20,
color: '#10B981',
});
readonly configStack = signal<IProcessBarStandardInterface>({
width: '100%',
height: '24px',
radius: 12,
totalValue: 100,
mode: 'stack',
steps: signal([this.stepProcessing, this.stepDone, this.stepPending]),
});
}<libs_ui-components-process_bar-standard [config]="configStack()" />Ví dụ 2 — Separate mode với hiển thị phần trăm
import { signal } from '@angular/core';
import {
LibsUiComponentsProcessBarStandardComponent,
IProcessBarStandardInterface,
IProcessBarStandardStepInterface,
} from '@libs-ui/components-process-bar-standard';
@Component({
standalone: true,
imports: [LibsUiComponentsProcessBarStandardComponent],
template: `
<libs_ui-components-process_bar-standard [config]="configSeparate()" />
`,
})
export class MyComponent {
private readonly stepProgress = signal<IProcessBarStandardStepInterface>({
value: 75,
color: '#8B5CF6',
label: 'Tiến độ',
showPercent: true,
});
private readonly stepPending = signal<IProcessBarStandardStepInterface>({
value: 45,
color: '#F59E0B',
label: 'Đang chờ',
showPercent: true,
});
readonly configSeparate = signal<IProcessBarStandardInterface>({
width: '100%',
height: '16px',
backgroundColor: 'transparent',
radius: 8,
totalValue: 100,
mode: 'separate',
steps: signal([this.stepProgress, this.stepPending]),
});
}<libs_ui-components-process_bar-standard [config]="configSeparate()" />Ví dụ 3 — Cập nhật realtime bằng Nested Signals
import { signal, computed } from '@angular/core';
import {
LibsUiComponentsProcessBarStandardComponent,
IProcessBarStandardInterface,
IProcessBarStandardStepInterface,
} from '@libs-ui/components-process-bar-standard';
@Component({
standalone: true,
imports: [LibsUiComponentsProcessBarStandardComponent],
template: `
<button (click)="handlerIncrement($event)">Tăng tiến độ</button>
<libs_ui-components-process_bar-standard [config]="configRealtime()" />
`,
})
export class MyComponent {
private readonly currentValue = signal(40);
private readonly stepMain = signal<IProcessBarStandardStepInterface>({
value: 40,
color: '#EC4899',
label: 'Đang xử lý',
});
readonly configRealtime = computed<IProcessBarStandardInterface>(() => ({
width: '100%',
height: '20px',
radius: 10,
totalValue: 100,
mode: 'stack',
steps: signal([this.stepMain]),
}));
protected handlerIncrement(event: Event): void {
event.stopPropagation();
const next = Math.min(this.currentValue() + 10, 100);
this.currentValue.set(next);
this.stepMain.update((step) => ({ ...step, value: next }));
}
}<button (click)="handlerIncrement($event)">Tăng tiến độ</button>
<libs_ui-components-process_bar-standard [config]="configRealtime()" />Ví dụ 4 — Global default config qua Injection Token
import { ApplicationConfig } from '@angular/core';
import { PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT } from '@libs-ui/utils';
import { IProcessBarStandardConfigDefaultInterface } from '@libs-ui/components-process-bar-standard';
export const appConfig: ApplicationConfig = {
providers: [
{
provide: PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT,
useValue: {
height: '16px',
backgroundColor: '#F1F5F9',
radius: 8,
} satisfies IProcessBarStandardConfigDefaultInterface,
},
],
};Sau khi cấu hình global, mọi instance của component sẽ tự động áp dụng giá trị mặc định trên nếu không truyền tường minh qua [config].
@Input()
| Input | Type | Default | Mô tả | Ví dụ |
|---|---|---|---|---|
| [config] | IProcessBarStandardInterface | Bắt buộc | Object cấu hình toàn bộ thanh tiến trình gồm kích thước, màu sắc, chế độ và danh sách bước | [config]="configStack()" |
IProcessBarStandardInterface
Cấu trúc object truyền vào [config]:
| Thuộc tính | Type | Bắt buộc | Default | Mô tả | Ví dụ |
|---|---|---|---|---|---|
| totalValue | number | Bắt buộc | — | Giá trị tổng dùng để tính phần trăm cho từng bước | totalValue: 100 |
| steps | WritableSignal<Array<WritableSignal<IProcessBarStandardStepInterface>>> | Bắt buộc | — | Danh sách các bước, mỗi bước là một WritableSignal | steps: signal([stepA, stepB]) |
| mode | 'stack' \| 'separate' | Không | 'stack' | Chế độ hiển thị: stack = ghép liền, separate = tách rời | mode: 'separate' |
| width | string | Không | '100%' | Chiều rộng của thanh | width: '300px' |
| height | string | Không | '12px' | Chiều cao của thanh | height: '20px' |
| backgroundColor | string | Không | '#F8F9FA' | Màu nền của container thanh | backgroundColor: '#E5E7EB' |
| radius | number | Không | 20 | Độ bo góc tính bằng px | radius: 8 |
| classInclude | string | Không | '' | CSS class bổ sung cho element wrapper | classInclude: 'mt-4' |
| showPercent | boolean | Không | false | Hiển thị phần trăm (áp dụng cho tất cả bước trong chế độ separate, có thể override ở từng bước) | showPercent: true |
| percentClass | string | Không | '' | CSS class cho phần text phần trăm (áp dụng cho tất cả bước, có thể override ở từng bước) | percentClass: 'text-blue-600' |
IProcessBarStandardStepInterface
Cấu trúc object mô tả từng bước trong steps:
| Thuộc tính | Type | Bắt buộc | Default | Mô tả | Ví dụ |
|---|---|---|---|---|---|
| value | number | Bắt buộc | — | Giá trị của bước, được chia cho totalValue để tính % | value: 40 |
| color | string | Bắt buộc | — | Màu nền của bước (hex, rgb, tên màu CSS) | color: '#3B82F6' |
| label | string | Không | undefined | Văn bản hiển thị bên trong thanh bước | label: 'Hoàn thành' |
| classLabel | string | Không | '' | CSS class bổ sung cho element label | classLabel: 'text-white' |
| classInclude | string | Không | '' | CSS class bổ sung cho element thanh của bước (chỉ chế độ separate) | classInclude: 'rounded-full' |
| showPercent | boolean | Không | undefined | Override hiển thị phần trăm riêng cho bước này (chỉ chế độ separate) | showPercent: true |
| percentClass | string | Không | '' | Override CSS class cho text phần trăm riêng cho bước này | percentClass: 'libs-ui-font-h5r' |
IProcessBarStandardConfigDefaultInterface
Interface dùng khi cung cấp global default qua PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT:
| Thuộc tính | Type | Mô tả |
|---|---|---|
| width | string | Chiều rộng mặc định toàn cục |
| height | string | Chiều cao mặc định toàn cục |
| backgroundColor | string | Màu nền mặc định toàn cục |
| radius | number | Bo góc mặc định toàn cục (px) |
Types & Interfaces
import {
IProcessBarStandardInterface,
IProcessBarStandardStepInterface,
IProcessBarStandardConfigDefaultInterface,
} from '@libs-ui/components-process-bar-standard';Định nghĩa đầy đủ:
import { WritableSignal } from '@angular/core';
export interface IProcessBarStandardConfigDefaultInterface {
width?: string;
height?: string;
backgroundColor?: string;
radius?: number;
}
export interface IProcessBarStandardInterface {
width?: string;
height?: string;
backgroundColor?: string;
radius?: number;
totalValue: number;
mode?: 'stack' | 'separate' | 'steps';
classInclude?: string;
showPercent?: boolean;
percentClass?: string;
steps: WritableSignal<Array<WritableSignal<IProcessBarStandardStepInterface>>>;
}
export interface IProcessBarStandardStepInterface {
classInclude?: string;
label?: string;
classLabel?: string;
value: number;
color: string;
showPercent?: boolean;
percentClass?: string;
}Lưu ý quan trọng
⚠️ Nested Signals bắt buộc: Property steps yêu cầu cấu trúc WritableSignal<Array<WritableSignal<IProcessBarStandardStepInterface>>>. Mỗi step phải là một WritableSignal riêng — không được truyền plain object hay array thông thường.
⚠️ Cập nhật realtime đúng cách: Để cập nhật giá trị một bước mà không trigger re-render toàn bộ, hãy gọi .update() trực tiếp trên signal của step đó (this.stepA.update(s => ({ ...s, value: 60 }))). Không tạo lại signal mới hay thay thế toàn bộ mảng.
⚠️ Mode steps chưa implement: Thuộc tính mode có giá trị 'steps' trong type nhưng chưa được render trong template. Chỉ sử dụng 'stack' hoặc 'separate'.
⚠️ showPercent chỉ hoạt động ở chế độ separate: Trong chế độ stack, thuộc tính showPercent (cả ở config lẫn từng step) không có hiệu lực vì cấu trúc layout không hỗ trợ.
⚠️ Global default token: Nếu inject PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT, các giá trị trong token sẽ là fallback khi thuộc tính tương ứng trong [config] không được truyền. Thứ tự ưu tiên: config.xxx > tokenDefault.xxx > hardcoded default.
Demo
npx nx serve core-uiTruy cập: http://localhost:4500/components/process-bar/standard
