@libs-ui/components-buttons-select-color
v0.2.357-11
Published
> Button tích hợp color picker dạng popover, hỗ trợ chế độ apply ngay hoặc apply sau khi xác nhận.
Readme
@libs-ui/components-buttons-select-color
Button tích hợp color picker dạng popover, hỗ trợ chế độ apply ngay hoặc apply sau khi xác nhận.
Giới thiệu
LibsUiComponentsButtonsSelectColorComponent là standalone Angular component hiển thị một button mở popover chứa color picker. Component hỗ trợ hai chế độ: applyNow = true để emit màu ngay khi chọn, hoặc applyNow = false để hiển thị nút Cancel / Apply trước khi xác nhận. Màu có thể được emit dưới dạng chuỗi đơn (outColorChange) hoặc object chứa tất cả định dạng (outColorChangeMultipleType).
Tính năng
- ✅ Hai chế độ: Apply ngay (
applyNow = true) hoặc Apply sau qua nút xác nhận (applyNow = false) - ✅ Emit màu dưới nhiều định dạng: HEX, RGB, RGBA, HSL, HSLA, Alpha
- ✅ Tùy chỉnh button trigger qua
IButton(label, icon, type, disabled...) - ✅ Hỗ trợ external content — dùng bất kỳ element nào làm trigger thay cho button mặc định
- ✅ Tùy chỉnh color picker options (màu khởi tạo, hiển thị formats, alpha slider...)
- ✅ Điều hướng popover 4 chiều:
top,bottom,left,right - ✅ Two-way binding cho
zIndextránh xung đột với modal/dialog khác - ✅ Tự động cleanup popover khi component bị destroy
- ✅ OnPush Change Detection + Angular Signals
Khi nào sử dụng
- Cho phép user chọn màu trong các tính năng theme customization, color settings
- Tích hợp color picker vào toolbar, design tool, form nhập màu sắc
- Khi cần preview màu trước khi confirm (
applyNow = false) - Khi cần hiển thị một color swatch làm trigger thay cho button thông thường (
externalContent = true)
Cài đặt
npm install @libs-ui/components-buttons-select-colorImport
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
import { IOutputColorChangeMultipleType, IPickerCustomOptions } from '@libs-ui/components-color-picker';
import { IButton } from '@libs-ui/components-buttons-button';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsSelectColorComponent],
})
export class MyComponent {}Ví dụ sử dụng
1. Apply ngay khi chọn màu
<!-- template.html -->
<libs_ui-components-buttons-select_color
[button]="{ label: 'Select Color', type: 'button-primary' }"
[applyNow]="true"
(outColorChange)="handlerColorChange($event)"
/>
<div [style.background-color]="selectedColor()" class="w-24 h-8 rounded mt-4">
{{ selectedColor() }}
</div>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsSelectColorComponent],
})
export class MyComponent {
protected selectedColor = signal<string>('#3b82f6');
protected handlerColorChange(event: string): void {
event.stopPropagation?.();
this.selectedColor.set(event);
}
}2. Chọn trước, bấm Apply sau + nhận nhiều định dạng màu
<!-- template.html -->
<libs_ui-components-buttons-select_color
[button]="{ label: 'Choose Color', type: 'button-secondary' }"
[applyNow]="false"
(outColorChange)="handlerColorChange($event)"
(outColorChangeMultipleType)="handlerColorChangeMultipleType($event)"
/>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
import { IOutputColorChangeMultipleType } from '@libs-ui/components-color-picker';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsSelectColorComponent],
})
export class MyComponent {
protected selectedColor = signal<string>('#10b981');
protected colorFormats = signal<IOutputColorChangeMultipleType | null>(null);
protected handlerColorChange(event: string): void {
this.selectedColor.set(event);
}
protected handlerColorChangeMultipleType(event: IOutputColorChangeMultipleType): void {
this.colorFormats.set(event);
// event.hex → '#10b981'
// event.rgb → 'rgb(16, 185, 129)'
// event.rgba → 'rgba(16, 185, 129, 1)'
// event.hsl → 'hsl(160, 84%, 39%)'
// event.hsla → 'hsla(160, 84%, 39%, 1)'
// event.alpha → 1
}
}3. Tùy chỉnh color picker options
<!-- template.html -->
<libs_ui-components-buttons-select_color
[button]="{ label: 'Pick Color', type: 'button-secondary', classIconLeft: 'libs-ui-icon-editor-color-background' }"
[customOptions]="customOptions"
[applyNow]="true"
(outColorChange)="handlerColorChange($event)"
/>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
import { IPickerCustomOptions } from '@libs-ui/components-color-picker';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsSelectColorComponent],
})
export class MyComponent {
protected selectedColor = signal<string>('#ff5733');
protected readonly customOptions: IPickerCustomOptions = {
color: '#ff5733',
showAlpha: true,
showHex: true,
showRgb: true,
showHsl: true,
format: 'hex',
};
protected handlerColorChange(event: string): void {
this.selectedColor.set(event);
}
}4. External content — dùng color swatch làm trigger
<!-- template.html -->
<libs_ui-components-buttons-select_color
[externalContent]="true"
[applyNow]="true"
(outColorChange)="handlerColorChange($event)">
<div class="libs-ui-buttons-select-color">
<div
class="w-12 h-12 rounded-lg border-2 border-gray-300 cursor-pointer shadow-sm hover:shadow-md transition-shadow"
[style.background-color]="selectedColor()">
</div>
</div>
</libs_ui-components-buttons-select_color>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsSelectColorComponent],
})
export class MyComponent {
protected selectedColor = signal<string>('#8b5cf6');
protected handlerColorChange(event: string): void {
this.selectedColor.set(event);
}
}5. Icon only button với hướng popover tùy chỉnh
<!-- template.html -->
<libs_ui-components-buttons-select_color
[button]="{ classIconLeft: 'libs-ui-icon-editor-color-background', iconOnlyType: true }"
[direction]="'top'"
[applyNow]="true"
(outColorChange)="handlerColorChange($event)"
/>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsSelectColorComponent],
})
export class MyComponent {
protected selectedColor = signal<string>('#3b82f6');
protected handlerColorChange(event: string): void {
this.selectedColor.set(event);
}
}6. Two-way binding zIndex tránh xung đột với modal
<!-- template.html -->
<libs_ui-components-buttons-select_color
[button]="{ label: 'Select Color' }"
[(zIndex)]="popoverZIndex"
[applyNow]="true"
(outColorChange)="handlerColorChange($event)"
/>// component.ts
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsSelectColorComponent } from '@libs-ui/components-buttons-select-color';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsSelectColorComponent],
})
export class MyComponent {
protected selectedColor = signal<string>('#3b82f6');
protected popoverZIndex = 2000;
protected handlerColorChange(event: string): void {
this.selectedColor.set(event);
}
}@Input()
| Input | Type | Default | Mô tả | Ví dụ |
|---|---|---|---|---|
| [applyNow] | boolean | false | true: emit màu ngay khi chọn, không cần xác nhận. false: hiển thị nút Cancel / Apply, emit khi bấm Apply | [applyNow]="true" |
| [button] | IButton | undefined | Cấu hình cho button trigger (label, type, icon, disabled...). Bị bỏ qua khi externalContent = true | [button]="{ label: 'Pick', type: 'button-primary' }" |
| [customOptions] | IPickerCustomOptions | undefined | Tùy chỉnh color picker: màu khởi tạo, hiện/ẩn formats (hex, rgb, hsl), alpha slider, kích thước thanh slider | [customOptions]="{ color: '#ff0000', showAlpha: true, format: 'hex' }" |
| [direction] | TYPE_POPOVER_DIRECTION | 'bottom' | Hướng mở popover so với trigger button | [direction]="'top'" |
| [externalContent] | boolean | false | true: dùng content projection (class libs-ui-buttons-select-color) thay cho button mặc định | [externalContent]="true" |
| [(zIndex)] | number | 1200 | Z-index của popover, hỗ trợ two-way binding | [(zIndex)]="myZIndex" |
@Output()
| Output | Type | Mô tả | Handler TS | Binding HTML |
|---|---|---|---|---|
| (outColorChange) | string | Emit màu đã chọn dưới dạng chuỗi, format theo customOptions.format (mặc định: hex). Khi applyNow = false chỉ emit khi bấm Apply | handlerColorChange(event: string): void { this.selectedColor.set(event); } | (outColorChange)="handlerColorChange($event)" |
| (outColorChangeMultipleType) | IOutputColorChangeMultipleType | Emit object chứa tất cả định dạng màu (hex, rgb, rgba, hsl, hsla, alpha) cùng lúc. Khi applyNow = false chỉ emit khi bấm Apply | handlerColorChangeMultipleType(event: IOutputColorChangeMultipleType): void { this.colorFormats.set(event); } | (outColorChangeMultipleType)="handlerColorChangeMultipleType($event)" |
Types & Interfaces
import { IOutputColorChangeMultipleType, IPickerCustomOptions } from '@libs-ui/components-color-picker';
import { IButton } from '@libs-ui/components-buttons-button';
import { TYPE_POPOVER_DIRECTION } from '@libs-ui/components-popover';IPickerCustomOptions
export interface IPickerCustomOptions {
/** Kích thước saturation/lightness bar [width, height] */
slBarSize?: Array<number>;
/** Kích thước hue bar [width, height] */
hueBarSize?: Array<number>;
/** Kích thước alpha bar [width, height] */
alphaBarSize?: Array<number>;
/** Hiển thị HSL input — default: true */
showHsl?: boolean;
/** Hiển thị RGB input — default: true */
showRgb?: boolean;
/** Hiển thị HEX input — default: true */
showHex?: boolean;
/** Hiển thị Alpha slider — default: false */
showAlpha?: boolean;
/** Màu khởi tạo: HEX string hoặc RGB array */
color?: string | Array<number>;
/** Format chuỗi màu emit qua outColorChange */
format?: 'rgb' | 'rgba' | 'hsl' | 'hsla' | 'hex' | 'color';
}IOutputColorChangeMultipleType
export interface IOutputColorChangeMultipleType {
/** Màu dạng RGBA: "rgba(255, 0, 0, 1)" */
rgba: string;
/** Màu dạng RGB: "rgb(255, 0, 0)" */
rgb: string;
/** Màu dạng HEX: "#ff0000" */
hex: string;
/** Màu dạng HSL: "hsl(0, 100%, 50%)" */
hsl: string;
/** Màu dạng HSLA: "hsla(0, 100%, 50%, 1)" */
hsla: string;
/** Giá trị alpha trong khoảng 0–1 */
alpha: number;
}TYPE_POPOVER_DIRECTION
export type TYPE_POPOVER_DIRECTION = 'top' | 'bottom' | 'left' | 'right';IButton (các thuộc tính thường dùng)
export interface IButton {
/** Nhãn hiển thị trên button */
label?: string;
/** Kiểu button: 'button-primary' | 'button-secondary' | 'button-third' | ... */
type?: TYPE_BUTTON;
/** Class icon bên trái */
classIconLeft?: string;
/** Class icon bên phải */
classIconRight?: string;
/** Hiển thị dạng icon only (không label) */
iconOnlyType?: boolean;
/** Vô hiệu hóa button */
disable?: boolean;
/** Class thêm vào button */
classInclude?: string;
}Lưu ý quan trọng
⚠️ External content selector bắt buộc: Khi dùng [externalContent]="true", wrapper div của content projection PHẢI có class libs-ui-buttons-select-color. Thiếu class này popover sẽ không mở.
<!-- ĐÚNG -->
<libs_ui-components-buttons-select_color [externalContent]="true" [applyNow]="true">
<div class="libs-ui-buttons-select-color">
<div class="w-10 h-10 rounded cursor-pointer" [style.background-color]="selectedColor()"></div>
</div>
</libs_ui-components-buttons-select_color>
<!-- SAI — thiếu class libs-ui-buttons-select-color -->
<libs_ui-components-buttons-select_color [externalContent]="true" [applyNow]="true">
<div>
<div class="w-10 h-10 rounded cursor-pointer"></div>
</div>
</libs_ui-components-buttons-select_color>⚠️ Hành vi emit khi applyNow = false: Khi applyNow = false, component giữ màu đã chọn trong state nội bộ và chỉ emit outColorChange + outColorChangeMultipleType khi user bấm nút "Apply". Bấm "Cancel" đóng popover mà không emit. Bấm "Apply" cũng tự đóng popover sau khi emit.
⚠️ Format chuỗi từ outColorChange: Output outColorChange emit chuỗi theo customOptions.format. Nếu không thiết lập customOptions.format, format mặc định phụ thuộc vào color picker. Để nhận màu theo tất cả định dạng cùng lúc, dùng outColorChangeMultipleType.
⚠️ Z-index khi dùng trong modal/dialog: Default z-index là 1200. Khi component nằm bên trong modal hoặc dialog có z-index cao hơn, cần tăng [(zIndex)] lên tương ứng để popover hiển thị đúng trên cùng.
⚠️ Cleanup tự động: Component tự gọi removePopoverOverlay() trong ngOnDestroy. Không cần cleanup thủ công ở component cha.
