ngx-ntk-mat-color-picker
v20.26.2
Published
Angular Material Color Picker
Downloads
100
Maintainers
Readme
NGX NTK Material Color Picker
ngx-ntk-mat-color-picker - Advanced Angular Material color picker component with multiple color formats, palette support, and customizable interface
📋 Overview
The NGX NTK Material Color Picker is a powerful Angular Material-based color picker component that provides a comprehensive color selection interface. It supports multiple color formats (RGB, HEX, RGBA), includes a color palette, canvas picker, and collection of predefined colors. Perfect for applications requiring advanced color selection capabilities with Material Design aesthetics.
🚀 Installation
npm install ngx-ntk-mat-color-pickerDependencies
This library requires the following peer dependencies:
npm install @angular/material @angular/forms @angular/cdk📦 Features
Core Features
- Multiple Color Formats - RGB, HEX, HEX3, HEX4, HEX6, HEX8, RGBA
- Color Palette - Visual color palette for quick selection
- Color Canvas - Interactive canvas for precise color picking
- Color Collection - Predefined color collections
- Color Toggle - Toggle component for color selection
- Material Design - Native Angular Material integration
- Responsive Design - Mobile-friendly interface
- Accessibility - ARIA support and keyboard navigation
Advanced Features
- Custom Color Formats - Extensible color format support
- Color Validation - Built-in color validation
- Color Conversion - Automatic format conversion
- Overlay Positioning - Configurable popup positioning
- Scroll Strategy - Customizable scroll behavior
- Touch UI Support - Touch-friendly interface
- Theme Integration - Material theme compatibility
🔧 Usage
Basic Setup
import { NgModule } from '@angular/core';
import { NgxMatColorPickerModule } from 'ngx-ntk-mat-color-picker';
@NgModule({
imports: [NgxMatColorPickerModule],
})
export class AppModule {}Basic Implementation
<mat-form-field>
<mat-label>Choose a color</mat-label>
<input matInput [ngxMatColorPicker]="picker" placeholder="Select color">
<mat-icon matSuffix [ngxMatColorpickerToggleIcon]="picker"></mat-icon>
<ngx-mat-color-picker #picker></ngx-mat-color-picker>
</mat-form-field>Advanced Configuration
import { Component } from '@angular/core';
import { Color, ColorInputFormat } from 'ngx-ntk-mat-color-picker';
@Component({
selector: 'app-color-selector',
template: `
<mat-form-field>
<mat-label>Advanced Color Picker</mat-label>
<input
matInput
[ngxMatColorPicker]="picker"
[value]="selectedColor"
[format]="'hex'"
[disabled]="false"
[touchUi]="false"
placeholder="Choose a color"
(colorChange)="onColorChange($event)">
<mat-icon matSuffix [ngxMatColorpickerToggleIcon]="picker"></mat-icon>
<ngx-mat-color-picker
#picker
[format]="'hex'"
[touchUi]="false"
[disabled]="false"
(colorChange)="onColorChange($event)"
(opened)="onPickerOpened()"
(closed)="onPickerClosed()">
</ngx-mat-color-picker>
</mat-form-field>
`
})
export class ColorSelectorComponent {
selectedColor: string = '#ff5722';
onColorChange(color: Color): void {
console.log('Color changed:', color.toString('hex'));
this.selectedColor = color.toString('hex');
}
onPickerOpened(): void {
console.log('Color picker opened');
}
onPickerClosed(): void {
console.log('Color picker closed');
}
}📚 API Reference
Input Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| format | ColorInputFormat | 'hex' | Color format for input/output |
| touchUi | boolean | false | Enable touch-friendly interface |
| disabled | boolean | false | Disable color picker |
| value | string | - | Initial color value |
| placeholder | string | - | Input placeholder text |
Output Events
| Event | Type | Description |
|-------|------|-------------|
| colorChange | EventEmitter | Color change event |
| opened | EventEmitter | Picker opened event |
| closed | EventEmitter | Picker closed event |
ColorInputFormat Types
export type ColorInputFormat = 'rgb' | 'hex' | 'hex6' | 'hex3' | 'hex4' | 'hex8';Color Class
export class Color {
r: number; // Red component (0-255)
g: number; // Green component (0-255)
b: number; // Blue component (0-255)
a: number; // Alpha component (0-1)
roundA: number; // Rounded alpha value
hex: string; // HEX representation
rgba: string; // RGBA representation
// Methods
toHex(allow3Char?: boolean): string;
toRgba(): string;
toHexString(allow3Char?: boolean): string;
toRgbString(): string;
toHex8(allow4Char: boolean): string;
toHex8String(allow4Char?: boolean): string;
toString(format: ColorInputFormat): string;
}🎨 Customization
Custom Styling
// Custom color picker styles
.ngx-mat-color-picker {
.mat-form-field {
width: 100%;
}
.color-picker-toggle {
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: scale(1.1);
}
}
.color-picker-content {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
overflow: hidden;
.color-palette {
padding: 16px;
border-bottom: 1px solid #e0e0e0;
.color-item {
width: 32px;
height: 32px;
border-radius: 50%;
margin: 4px;
cursor: pointer;
border: 2px solid transparent;
transition: all 0.2s ease;
&:hover {
transform: scale(1.1);
border-color: #333;
}
&.selected {
border-color: #2196f3;
box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.3);
}
}
}
.color-canvas {
padding: 16px;
.canvas-container {
position: relative;
width: 100%;
height: 200px;
border-radius: 8px;
overflow: hidden;
cursor: crosshair;
}
.color-slider {
margin-top: 16px;
height: 20px;
border-radius: 10px;
background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
cursor: pointer;
}
}
.color-inputs {
padding: 16px;
background-color: #f5f5f5;
.input-group {
display: flex;
gap: 8px;
margin-bottom: 8px;
.mat-form-field {
flex: 1;
}
.color-preview {
width: 40px;
height: 40px;
border-radius: 4px;
border: 1px solid #ddd;
}
}
}
}
}Custom Color Formats
import { ColorAdapter } from 'ngx-ntk-mat-color-picker';
// Custom color adapter
export class CustomColorAdapter extends ColorAdapter {
parse(value: string): Color | null {
// Custom parsing logic
if (value.startsWith('custom:')) {
const colorValue = value.replace('custom:', '');
// Parse custom format
return this.parseCustomFormat(colorValue);
}
return super.parse(value);
}
format(color: Color): string {
// Custom formatting logic
return `custom:${color.r},${color.g},${color.b},${color.a}`;
}
private parseCustomFormat(value: string): Color {
const [r, g, b, a] = value.split(',').map(Number);
return new Color(r, g, b, a);
}
}🌈 Color Components
Color Palette Component
<ngx-mat-color-palette
[colors]="paletteColors"
[selectedColor]="selectedColor"
(colorSelected)="onColorSelected($event)">
</ngx-mat-color-palette>paletteColors = [
'#ff5722', '#e91e63', '#9c27b0', '#673ab7',
'#3f51b5', '#2196f3', '#03a9f4', '#00bcd4',
'#009688', '#4caf50', '#8bc34a', '#cddc39',
'#ffeb3b', '#ffc107', '#ff9800', '#ff5722'
];Color Canvas Component
<ngx-mat-color-canvas
[color]="selectedColor"
(colorChange)="onCanvasColorChange($event)">
</ngx-mat-color-canvas>Color Collection Component
<ngx-mat-color-collection
[collections]="colorCollections"
(colorSelected)="onCollectionColorSelected($event)">
</ngx-mat-color-collection>colorCollections = [
{
name: 'Material Colors',
colors: ['#f44336', '#e91e63', '#9c27b0', '#673ab7']
},
{
name: 'Brand Colors',
colors: ['#2196f3', '#4caf50', '#ff9800', '#f44336']
}
];Color Toggle Component
<ngx-mat-color-toggle
[color]="selectedColor"
[disabled]="false"
(colorChange)="onToggleColorChange($event)">
</ngx-mat-color-toggle>🔒 Validation & Error Handling
Color Validation
// Custom color validation
validateColor(color: string): boolean {
const colorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
return colorRegex.test(color);
}
// Color range validation
validateColorRange(color: Color): boolean {
return color.r >= 0 && color.r <= 255 &&
color.g >= 0 && color.g <= 255 &&
color.b >= 0 && color.b <= 255 &&
color.a >= 0 && color.a <= 1;
}Error Handling
@Component({
template: `
<mat-form-field>
<input
matInput
[ngxMatColorPicker]="picker"
[value]="colorValue"
(colorChange)="onColorChange($event)"
(error)="onColorError($event)">
<ngx-mat-color-picker #picker></ngx-mat-color-picker>
<mat-error *ngIf="colorError">{{ colorError }}</mat-error>
</mat-form-field>
`
})
export class ColorPickerWithValidation {
colorValue: string = '#ff5722';
colorError: string = '';
onColorChange(color: Color): void {
if (this.validateColor(color.toString('hex'))) {
this.colorValue = color.toString('hex');
this.colorError = '';
} else {
this.colorError = 'Invalid color format';
}
}
onColorError(error: any): void {
console.error('Color picker error:', error);
this.colorError = 'Color picker error occurred';
}
}🧪 Testing
Unit Tests
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NgxMatColorPickerModule } from 'ngx-ntk-mat-color-picker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
describe('ColorPickerComponent', () => {
let component: ColorPickerComponent;
let fixture: ComponentFixture<ColorPickerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
NgxMatColorPickerModule,
MatFormFieldModule,
MatInputModule,
NoopAnimationsModule
],
declarations: [ColorPickerComponent]
}).compileComponents();
fixture = TestBed.createComponent(ColorPickerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should emit color change event', () => {
const mockColor = new Color(255, 87, 34, 1);
spyOn(component.colorChange, 'emit');
component.onColorChange(mockColor);
expect(component.colorChange.emit).toHaveBeenCalledWith(mockColor);
});
it('should format color correctly', () => {
const color = new Color(255, 87, 34, 1);
expect(color.toString('hex')).toBe('#ff5722');
expect(color.toString('rgb')).toBe('rgb(255, 87, 34)');
expect(color.toString('rgba')).toBe('rgba(255, 87, 34, 1)');
});
});Integration Tests
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NgxMatColorPickerModule } from 'ngx-ntk-mat-color-picker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
describe('ColorPicker Integration', () => {
let fixture: ComponentFixture<ColorPickerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
NgxMatColorPickerModule,
MatFormFieldModule,
MatInputModule,
NoopAnimationsModule
],
declarations: [ColorPickerComponent]
}).compileComponents();
fixture = TestBed.createComponent(ColorPickerComponent);
});
it('should display color picker input', () => {
fixture.detectChanges();
const input = fixture.nativeElement.querySelector('input');
expect(input).toBeTruthy();
});
it('should open color picker on toggle click', () => {
fixture.detectChanges();
const toggle = fixture.nativeElement.querySelector('.mat-icon');
toggle.click();
fixture.detectChanges();
const pickerContent = fixture.nativeElement.querySelector('.ngx-mat-colorpicker-content');
expect(pickerContent).toBeTruthy();
});
it('should update input value when color is selected', () => {
fixture.componentInstance.selectedColor = '#ff5722';
fixture.detectChanges();
const input = fixture.nativeElement.querySelector('input');
expect(input.value).toBe('#ff5722');
});
});⚡ Performance
Optimization Tips
// Use OnPush change detection for better performance
@Component({
selector: 'app-color-picker',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ColorPickerComponent {
// Implement trackBy function for ngFor
trackByColor(index: number, color: string): string {
return color;
}
// Debounce color change events
private colorChangeSubject = new Subject<Color>();
ngOnInit(): void {
this.colorChangeSubject.pipe(
debounceTime(300),
distinctUntilChanged((prev, curr) => prev.toString() === curr.toString())
).subscribe(color => {
this.handleColorChange(color);
});
}
onColorChange(color: Color): void {
this.colorChangeSubject.next(color);
}
}Memory Management
// Proper cleanup
ngOnDestroy(): void {
this.colorChangeSubject.complete();
this.destroy$.next();
this.destroy$.complete();
}
// Lazy load color picker content
loadColorPickerContent(): void {
if (!this.pickerContentLoaded) {
this.loadPickerContentAsync().subscribe(() => {
this.pickerContentLoaded = true;
});
}
}📝 Examples
Basic Color Picker
@Component({
selector: 'app-basic-color-picker',
template: `
<mat-form-field>
<mat-label>Choose a color</mat-label>
<input matInput [ngxMatColorPicker]="picker" placeholder="Select color">
<mat-icon matSuffix [ngxMatColorpickerToggleIcon]="picker"></mat-icon>
<ngx-mat-color-picker #picker></ngx-mat-color-picker>
</mat-form-field>
`
})
export class BasicColorPickerComponent {
selectedColor: string = '#ff5722';
}Advanced Color Picker with Custom Format
@Component({
selector: 'app-advanced-color-picker',
template: `
<mat-form-field>
<mat-label>Advanced Color Picker</mat-label>
<input
matInput
[ngxMatColorPicker]="picker"
[value]="selectedColor"
[format]="'rgba'"
placeholder="Choose a color with alpha"
(colorChange)="onColorChange($event)">
<mat-icon matSuffix [ngxMatColorpickerToggleIcon]="picker"></mat-icon>
<ngx-mat-color-picker
#picker
[format]="'rgba'"
[touchUi]="false"
(colorChange)="onColorChange($event)">
</ngx-mat-color-picker>
</mat-form-field>
<div class="color-preview" [style.background-color]="selectedColor">
Selected Color: {{ selectedColor }}
</div>
`,
styles: [`
.color-preview {
width: 100px;
height: 100px;
border-radius: 8px;
border: 2px solid #ddd;
display: flex;
align-items: center;
justify-content: center;
color: white;
text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
font-size: 12px;
text-align: center;
margin-top: 16px;
}
`]
})
export class AdvancedColorPickerComponent {
selectedColor: string = 'rgba(255, 87, 34, 1)';
onColorChange(color: Color): void {
this.selectedColor = color.toString('rgba');
console.log('Color changed to:', this.selectedColor);
}
}Color Picker with Validation
@Component({
selector: 'app-validated-color-picker',
template: `
<mat-form-field>
<mat-label>Validated Color Picker</mat-label>
<input
matInput
[ngxMatColorPicker]="picker"
[value]="selectedColor"
[formControl]="colorControl"
placeholder="Choose a valid color">
<mat-icon matSuffix [ngxMatColorpickerToggleIcon]="picker"></mat-icon>
<ngx-mat-color-picker #picker></ngx-mat-color-picker>
<mat-error *ngIf="colorControl.hasError('invalidColor')">
Please select a valid color
</mat-error>
</mat-form-field>
`
})
export class ValidatedColorPickerComponent {
selectedColor: string = '#ff5722';
colorControl = new FormControl('', [this.colorValidator()]);
colorValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const color = control.value;
if (!color) return null;
const isValid = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);
return isValid ? null : { invalidColor: true };
};
}
}🔄 Version History
v20.25.3
- Initial release with core functionality
- Multiple color format support
- Material Design integration
- Color palette and canvas components
- Touch UI support
- Accessibility features
v20.25.2
- Bug fixes and performance improvements
- Enhanced color validation
- Improved accessibility features
- Better mobile responsiveness
🤝 Contributing
We welcome contributions! Please see our contributing guidelines:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
📄 License
This project is licensed under the ISC License.
🆘 Support
For support and questions:
- Create an issue on GitHub
- Contact: ntk.ir
👨💻 Author
Alireza Karavi
Note: This library is part of the NTK CMS Angular Libraries collection. For more information, see the main project README.
