UNPKG

ngx-ntk-mat-color-picker

Version:

Angular Material Color Picker

739 lines (602 loc) โ€ข 19.4 kB
# 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 ```bash npm install ngx-ntk-mat-color-picker ``` ### Dependencies This library requires the following peer dependencies: ```bash 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 ```typescript import { NgModule } from '@angular/core'; import { NgxMatColorPickerModule } from 'ngx-ntk-mat-color-picker'; @NgModule({ imports: [NgxMatColorPickerModule], }) export class AppModule {} ``` ### Basic Implementation ```html <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 ```typescript 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 ```typescript export type ColorInputFormat = 'rgb' | 'hex' | 'hex6' | 'hex3' | 'hex4' | 'hex8'; ``` ### Color Class ```typescript 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 ```scss // 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 ```typescript 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 ```html <ngx-mat-color-palette [colors]="paletteColors" [selectedColor]="selectedColor" (colorSelected)="onColorSelected($event)"> </ngx-mat-color-palette> ``` ```typescript paletteColors = [ '#ff5722', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#4caf50', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107', '#ff9800', '#ff5722' ]; ``` ### Color Canvas Component ```html <ngx-mat-color-canvas [color]="selectedColor" (colorChange)="onCanvasColorChange($event)"> </ngx-mat-color-canvas> ``` ### Color Collection Component ```html <ngx-mat-color-collection [collections]="colorCollections" (colorSelected)="onCollectionColorSelected($event)"> </ngx-mat-color-collection> ``` ```typescript colorCollections = [ { name: 'Material Colors', colors: ['#f44336', '#e91e63', '#9c27b0', '#673ab7'] }, { name: 'Brand Colors', colors: ['#2196f3', '#4caf50', '#ff9800', '#f44336'] } ]; ``` ### Color Toggle Component ```html <ngx-mat-color-toggle [color]="selectedColor" [disabled]="false" (colorChange)="onToggleColorChange($event)"> </ngx-mat-color-toggle> ``` ## ๐Ÿ”’ Validation & Error Handling ### Color Validation ```typescript // 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 ```typescript @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 ```typescript 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 ```typescript 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 ```typescript // 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 ```typescript // 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 ```typescript @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 ```typescript @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 ```typescript @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: 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Add tests for new functionality 5. 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](https://ntk.ir) ## ๐Ÿ‘จโ€๐Ÿ’ป Author **Alireza Karavi** - GitHub: [@akaravi](https://github.com/akaravi) - Website: [ntk.ir](https://ntk.ir) --- **Note**: This library is part of the NTK CMS Angular Libraries collection. For more information, see the main project README.