import { Component, OnInit, Input, Output, EventEmitter, ChangeDetectorRef, SimpleChanges, ViewChild, ElementRef, Renderer2, Inject, AfterViewInit, OnChanges, OnDestroy, forwardRef } from '@angular/core'; import { Color, ColorString } from './helpers/color.class'; import { ColorPickerControl, ColorType } from './helpers/control.class'; import { getValueByType } from './helpers/helper.functions'; import { DOCUMENT } from '@angular/common'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; const FARRIS_ColorPicker_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ColorPickerComponent), multi: true }; @Component({ selector: 'farrisui-color-picker, color-picker', templateUrl: './color-picker.component.html', styleUrls: [`./color-picker.component.scss`], providers: [FARRIS_ColorPicker_VALUE_ACCESSOR] }) export class ColorPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy, ControlValueAccessor { @Input() color: string; @Input() disabled = false; @Input() size: string; @Input() set showAlpha(v: boolean) { this._showAlpha = !v; } get showAlpha() { if (this.colorFormat && this.colorFormat.indexOf('a') > 0) { return true; } else if ( this.control.initType && this.control.initType.indexOf('a') > 0 ) { return true; } return this._showAlpha; } @Input() set colorFormat(v: ColorType) { this._colorFormat = v; } get colorFormat() { if (!this._colorFormat) { if (this.control.initType) { return this.control.initType; } } return this._colorFormat; } @Input() presets: Array = []; /** * @deprecated */ @Input() selectOnly: boolean; @Input() editable = false; @Input() control: ColorPickerControl; @Output() public change: EventEmitter = new EventEmitter(false); @Output() public activeChange: EventEmitter = new EventEmitter(false); @ViewChild('trigger') public trigger: ElementRef; @ViewChild('pickerPanel') public pickerPanel: ElementRef; public isShowPanel = false; private _showAlpha = false; private _colorFormat: ColorType; private _preColor: string; set preColor(v: string) { this._color = v; this._preColor = v; this.renderer.setStyle( this.trigger.nativeElement, 'background', this._preColor ); } get preColor() { return this._preColor; } set _color(v: string) { if (this.control) { this.control.setValueFrom(v); } } get _color() { if (this.colorFormat) { return getValueByType( new Color(this.color), ColorType[this.colorFormat] ); } else { return this.color; } } onModelChange = (val) => {}; onTouched = (val) => {}; constructor( private readonly cdr: ChangeDetectorRef, private renderer: Renderer2, protected readonly elementRef: ElementRef, @Inject(DOCUMENT) document ) { document.addEventListener('click', e => { this.isShowPanel = false; }); } ngOnInit(): void { if (!this.control) { this.control = new ColorPickerControl(); } if (this.color) { this.control.setValueFrom(this.color); } if (!this.control.hasPresets()) { this.control.setColorPresets(this.presets); } this.control.valueChanges.subscribe(value => { this.cdr.markForCheck(); this.color = getValueByType(value, ColorType[this.colorFormat]); this.activeChange.emit( getValueByType(value, ColorType[this.colorFormat]) ); }); // console.log(ColorType[this.colorFormat]); this.preColor = getValueByType( new Color(this.color), ColorType[this.colorFormat] ); } ngAfterViewInit(): void { document.body.insertBefore(this.pickerPanel.nativeElement, null); } public ngOnDestroy(): void { this.control.unsubscribe(); this.cdr.detach(); } public ngOnChanges(changes: SimpleChanges): void { if ( this.color && this.control && getValueByType(this.control.value, this.control.initType) !== this.color ) { this.control.setValueFrom(this.color); } if (changes.colorFormat && !changes.colorFormat.isFirstChange()) { this.preColor = getValueByType( new Color(this.color), this.colorFormat); this.onModelChange(this.preColor); } } onBlur($event) { this.onModelChange(this.preColor); } public clear(): void { this.color = ''; this.renderer.setStyle(this.trigger.nativeElement, 'background', ''); } public commit(): void { this.renderer.setStyle( this.trigger.nativeElement, 'background', this.color ); this.preColor = this.color; this.onModelChange(this.preColor); this.isShowPanel = false; } public toggleShowPanel(e): void { e.stopPropagation(); if (this.disabled) { return; } this.isShowPanel = !this.isShowPanel; const { top: elTop, left: elLeft, height: elHeight } = this.elementRef.nativeElement.getBoundingClientRect(); const { height: panelHeight, width: panelWidth } = this.pickerPanel.nativeElement.getBoundingClientRect(); if (elTop + panelHeight + 30 > window.innerHeight) { this.renderer.setStyle( this.pickerPanel.nativeElement, 'top', `${elTop - panelHeight - 5}px` ); } else { this.renderer.setStyle( this.pickerPanel.nativeElement, 'top', `${elTop + elHeight + 5}px` ); } this.renderer.setStyle( this.pickerPanel.nativeElement, 'left', `${elLeft}px` ); } writeValue(val: any): void { if (val === undefined || val === null) { val = ''; } this.color = val; this.preColor = getValueByType( new Color(this.color), ColorType[this.colorFormat] ); } registerOnChange(fn: any): void { this.onModelChange = fn; } registerOnTouched(fn: any): void { this.onTouched = fn; } setDisabledState?(isDisabled: boolean): void { this.disabled = isDisabled; } }