From 0f1048cb3c0e86af4df532f79af9ad60500289ba Mon Sep 17 00:00:00 2001 From: Sercan Yemen Date: Thu, 26 Jul 2018 14:10:35 +0300 Subject: [PATCH] (FuseMaterialColorPicker) Greatly simplified the color picker, added reactive forms support and improved its design, closes #79 --- .../material-color-picker.component.html | 49 ++- .../material-color-picker.component.scss | 41 +-- .../material-color-picker.component.ts | 305 +++++++++--------- .../material-color-picker.module.ts | 4 +- .../material-color-picker.theme.scss | 14 + 5 files changed, 196 insertions(+), 217 deletions(-) create mode 100644 src/@fuse/components/material-color-picker/material-color-picker.theme.scss diff --git a/src/@fuse/components/material-color-picker/material-color-picker.component.html b/src/@fuse/components/material-color-picker/material-color-picker.component.html index 16b28439..1d901438 100644 --- a/src/@fuse/components/material-color-picker/material-color-picker.component.html +++ b/src/@fuse/components/material-color-picker/material-color-picker.component.html @@ -1,20 +1,20 @@ - + -
@@ -23,45 +23,40 @@ - Select Color + Select a Color
-
-
- - {{color.key}} - + [ngClass]="color.key" + [class.selected]="selectedPalette === color.key" + (click)="selectPalette($event, color.key)">
-
+
-
- - {{hue}} - - check +
diff --git a/src/@fuse/components/material-color-picker/material-color-picker.component.scss b/src/@fuse/components/material-color-picker/material-color-picker.component.scss index 9a4647bb..eccb22b1 100644 --- a/src/@fuse/components/material-color-picker/material-color-picker.component.scss +++ b/src/@fuse/components/material-color-picker/material-color-picker.component.scss @@ -1,5 +1,5 @@ .fuse-material-color-picker-menu { - width: 208px; + width: 245px; .mat-menu-content { padding: 0; @@ -7,44 +7,29 @@ .views { display: flex; flex-direction: column; - position: relative; - overflow: hidden; - min-height: 258px; - height: 308px; - background-color: #F7F7F7; + min-height: 165px; .view { - position: absolute; - width: 208px; - height: 100%; - bottom: 0; - left: 0; - right: 0; - top: 0; + overflow: hidden; .colors { - position: relative; - padding: 4px; + padding: 1px 0 0 0; + margin-left: -1px; .color { - position: relative; - width: 46px; - height: 46px; - margin: 2px; + width: 40px; + height: 40px; + margin: 0 0 1px 1px; border-radius: 0; cursor: pointer; + transition: border-radius .4s cubic-bezier(.25, .8, .25, 1); - .label { - padding: 2px; - font-size: 10px; + &:hover { + border-radius: 20%; } - mat-icon { - position: absolute; - top: 2px; - right: 2px; - font-size: 16px; - opacity: 0.7; + &.selected { + border-radius: 50% !important; } } } diff --git a/src/@fuse/components/material-color-picker/material-color-picker.component.ts b/src/@fuse/components/material-color-picker/material-color-picker.component.ts index f914fa4e..3448ed5c 100644 --- a/src/@fuse/components/material-color-picker/material-color-picker.component.ts +++ b/src/@fuse/components/material-color-picker/material-color-picker.component.ts @@ -1,55 +1,40 @@ -import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation } from '@angular/core'; +import { Component, EventEmitter, forwardRef, Input, Output, ViewEncapsulation } from '@angular/core'; import { fuseAnimations } from '@fuse/animations'; import { MatColors } from '@fuse/mat-colors'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; + +export const FUSE_MATERIAL_COLOR_PICKER_VALUE_ACCESSOR: any = { + provide : NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FuseMaterialColorPickerComponent), + multi : true +}; @Component({ selector : 'fuse-material-color-picker', templateUrl : './material-color-picker.component.html', styleUrls : ['./material-color-picker.component.scss'], animations : fuseAnimations, - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, + providers : [FUSE_MATERIAL_COLOR_PICKER_VALUE_ACCESSOR] }) -export class FuseMaterialColorPickerComponent implements OnChanges +export class FuseMaterialColorPickerComponent implements ControlValueAccessor { colors: any; hues: string[]; - selectedColor: any; view: string; - - @Input() + selectedColor: any; selectedPalette: string; - - @Input() selectedHue: string; - @Input() - selectedFg: string; - - @Input() - value: any; - + // Color changed @Output() - onValueChange: EventEmitter; - - @Output() - selectedPaletteChange: EventEmitter; - - @Output() - selectedHueChange: EventEmitter; - - @Output() - selectedClassChange: EventEmitter; - - @Output() - selectedBgChange: EventEmitter; - - @Output() - selectedFgChange: EventEmitter; + colorChanged: EventEmitter; // Private - _selectedClass: string; - _selectedBg: string; + private _color: string; + private _modelChange: (value: any) => void; + private _modelTouched: (value: any) => void; /** * Constructor @@ -57,23 +42,18 @@ export class FuseMaterialColorPickerComponent implements OnChanges constructor() { // Set the defaults + this.colorChanged = new EventEmitter(); this.colors = MatColors.all; this.hues = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']; - this.selectedFg = ''; - this.selectedHue = ''; - this.selectedPalette = ''; + this.selectedHue = '500'; this.view = 'palettes'; - this.onValueChange = new EventEmitter(); - this.selectedPaletteChange = new EventEmitter(); - this.selectedHueChange = new EventEmitter(); - this.selectedClassChange = new EventEmitter(); - this.selectedBgChange = new EventEmitter(); - this.selectedFgChange = new EventEmitter(); - // Set the private defaults - this._selectedClass = ''; - this._selectedBg = ''; + this._color = ''; + this._modelChange = () => { + }; + this._modelTouched = () => { + }; } // ----------------------------------------------------------------------------------------------------- @@ -86,88 +66,76 @@ export class FuseMaterialColorPickerComponent implements OnChanges * @param value */ @Input() - set selectedClass(value) + set color(value) { - if ( value && value !== '' && this._selectedClass !== value ) + if ( !value || value === '' || this._color === value ) { - const color = value.split('-'); - if ( color.length >= 5 ) - { - this.selectedPalette = color[1] + '-' + color[2]; - this.selectedHue = color[3]; - } - else - { - this.selectedPalette = color[1]; - this.selectedHue = color[2]; - } - } - this._selectedClass = value; - } - - get selectedClass(): string - { - return this._selectedClass; - } - - /** - * Selected bg - * - * @param value - */ - @Input() - set selectedBg(value) - { - if ( value && value !== '' && this._selectedBg !== value ) - { - for ( const palette in this.colors ) - { - if ( !this.colors.hasOwnProperty(palette) ) - { - continue; - } - - for ( const hue of this.hues ) - { - if ( this.colors[palette][hue] === value ) - { - this.selectedPalette = palette; - this.selectedHue = hue; - break; - } - } - } - } - this._selectedBg = value; - } - - get selectedBg(): string - { - return this._selectedBg; - } - - // ----------------------------------------------------------------------------------------------------- - // @ Lifecycle hooks - // ----------------------------------------------------------------------------------------------------- - - /** - * On changes - * - * @param changes - */ - ngOnChanges(changes: any): void - { - if ( changes.selectedBg && changes.selectedBg.currentValue === '' || - changes.selectedClass && changes.selectedClass.currentValue === '' || - changes.selectedPalette && changes.selectedPalette.currentValue === '' ) - { - this.removeColor(); return; } - if ( changes.selectedPalette || changes.selectedHue || changes.selectedClass || changes.selectedBg ) + + // Split the color value (red-400, blue-500, fuse-navy-700 etc.) + const colorParts = value.split('-'); + + // Take the very last part as the selected hue value + this.selectedHue = colorParts[colorParts.length - 1]; + + // Remove the last part + colorParts.pop(); + + // Rejoin the remaining parts as the selected palette name + this.selectedPalette = colorParts.join('-'); + + // Store the color value + this._color = value; + } + + get color(): string + { + return this._color; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Control Value Accessor implementation + // ----------------------------------------------------------------------------------------------------- + + /** + * Register on change function + * + * @param fn + */ + registerOnChange(fn: any): void + { + this._modelChange = fn; + } + + /** + * Register on touched function + * + * @param fn + */ + registerOnTouched(fn: any): void + { + this._modelTouched = fn; + } + + /** + * Write value to the view from model + * + * @param color + */ + writeValue(color: any): void + { + // Return if null + if ( !color ) { - this.updateSelectedColor(); + return; } + + // Set the color + this.color = color; + + // Update the selected color + this.updateSelectedColor(); } // ----------------------------------------------------------------------------------------------------- @@ -177,35 +145,61 @@ export class FuseMaterialColorPickerComponent implements OnChanges /** * Select palette * + * @param event * @param palette */ - selectPalette(palette): void + selectPalette(event, palette): void { - this.selectedPalette = palette; - this.updateSelectedColor(); + // Stop propagation + event.stopPropagation(); + + // Go to 'hues' view this.view = 'hues'; + + // Update the selected palette + this.selectedPalette = palette; + + // Update the selected color + this.updateSelectedColor(); } /** * Select hue * + * @param event * @param hue */ - selectHue(hue): void + selectHue(event, hue): void { + // Stop propagation + event.stopPropagation(); + + // Update the selected huse this.selectedHue = hue; + + // Update the selected color this.updateSelectedColor(); } /** * Remove color + * + * @param event */ - removeColor(): void + removeColor(event): void { + // Stop propagation + event.stopPropagation(); + + // Return to the 'palettes' view + this.view = 'palettes'; + + // Clear the selected palette and hue this.selectedPalette = ''; this.selectedHue = ''; + + // Update the selected color this.updateSelectedColor(); - this.view = 'palettes'; } /** @@ -213,49 +207,40 @@ export class FuseMaterialColorPickerComponent implements OnChanges */ updateSelectedColor(): void { - setTimeout(() => { + if ( this.selectedColor && this.selectedColor.palette === this.selectedPalette && this.selectedColor.hue === this.selectedHue ) + { + return; + } - if ( this.selectedColor && this.selectedPalette === this.selectedColor.palette && this.selectedHue === this.selectedColor.hue ) - { - return; - } + // Set the selected color object + this.selectedColor = { + palette: this.selectedPalette, + hue : this.selectedHue, + class : this.selectedPalette + '-' + this.selectedHue, + bg : this.selectedPalette === '' ? '' : MatColors.getColor(this.selectedPalette)[this.selectedHue], + fg : this.selectedPalette === '' ? '' : MatColors.getColor(this.selectedPalette).contrast[this.selectedHue] + }; - if ( this.selectedPalette !== '' && this.selectedHue !== '' ) - { - this.selectedBg = MatColors.getColor(this.selectedPalette)[this.selectedHue]; - this.selectedFg = MatColors.getColor(this.selectedPalette).contrast[this.selectedHue]; - this.selectedClass = 'mat-' + this.selectedPalette + '-' + this.selectedHue + '-bg'; - } - else - { - this.selectedBg = ''; - this.selectedFg = ''; - } + // Emit the color changed event + this.colorChanged.emit(this.selectedColor); - this.selectedColor = { - palette: this.selectedPalette, - hue : this.selectedHue, - class : this.selectedClass, - bg : this.selectedBg, - fg : this.selectedFg - }; + // Mark the model as touched + this._modelTouched(this.selectedColor.class); - this.selectedPaletteChange.emit(this.selectedPalette); - this.selectedHueChange.emit(this.selectedHue); - this.selectedClassChange.emit(this.selectedClass); - this.selectedBgChange.emit(this.selectedBg); - this.selectedFgChange.emit(this.selectedFg); - - this.value = this.selectedColor; - this.onValueChange.emit(this.selectedColor); - }); + // Update the model + this._modelChange(this.selectedColor.class); } /** - * Go back to palette selection + * Go to palettes view + * + * @param event */ - backToPaletteSelection(): void + goToPalettesView(event): void { + // Stop propagation + event.stopPropagation(); + this.view = 'palettes'; } diff --git a/src/@fuse/components/material-color-picker/material-color-picker.module.ts b/src/@fuse/components/material-color-picker/material-color-picker.module.ts index 6562e678..41881bd0 100644 --- a/src/@fuse/components/material-color-picker/material-color-picker.module.ts +++ b/src/@fuse/components/material-color-picker/material-color-picker.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; -import { MatButtonModule, MatIconModule, MatMenuModule, MatRippleModule } from '@angular/material'; +import { MatButtonModule, MatIconModule, MatMenuModule, MatTooltipModule } from '@angular/material'; import { FusePipesModule } from '@fuse/pipes/pipes.module'; @@ -19,7 +19,7 @@ import { FuseMaterialColorPickerComponent } from '@fuse/components/material-colo MatButtonModule, MatIconModule, MatMenuModule, - MatRippleModule, + MatTooltipModule, FusePipesModule ], diff --git a/src/@fuse/components/material-color-picker/material-color-picker.theme.scss b/src/@fuse/components/material-color-picker/material-color-picker.theme.scss new file mode 100644 index 00000000..de2f98eb --- /dev/null +++ b/src/@fuse/components/material-color-picker/material-color-picker.theme.scss @@ -0,0 +1,14 @@ +@mixin fuse-material-color-picker-theme($theme) { + + $background: map_get($theme, background); + + .fuse-material-color-picker-menu { + + .mat-menu-content { + + .views { + background: #303030; + } + } + } +} \ No newline at end of file