UI: Refactoring color picker
This commit is contained in:
parent
64264a7834
commit
9d86100a6b
@ -17,21 +17,25 @@
|
|||||||
-->
|
-->
|
||||||
<saturation-component class="saturation-component" [hue]="control.hue" [(color)]="control.value"></saturation-component>
|
<saturation-component class="saturation-component" [hue]="control.hue" [(color)]="control.value"></saturation-component>
|
||||||
|
|
||||||
<div fxFlex fxLayout="row" class="control-component" fxLayoutGap="16px">
|
<div class="control-component">
|
||||||
<indicator-component [colorType]="presentations[selectedPresentation]" [color]="control.value"></indicator-component>
|
<indicator-component class="indicator-component"
|
||||||
<div fxFlex fxLayout="column" fxLayoutAlign="space-between" class="hue-alpha-range">
|
[colorType]="presentations[selectedPresentation]"
|
||||||
<hue-component [(hue)]="control.hue" [(color)]="control.value"></hue-component>
|
[color]="control.value">
|
||||||
<alpha-component *ngIf="control.alphaChannelVisibilityChanges | async" [(color)]="control.value"></alpha-component>
|
</indicator-component>
|
||||||
</div>
|
<div class="hue-alpha-range">
|
||||||
|
<hue-component [(hue)]="control.hue" [(color)]="control.value"></hue-component>
|
||||||
|
<alpha-component [(color)]="control.value"></alpha-component>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div fxFlex fxLayout="row">
|
<div class="color-input-block">
|
||||||
<div fxFlex [ngSwitch]="presentations[selectedPresentation]">
|
<div class="color-input" [ngSwitch]="presentations[selectedPresentation]">
|
||||||
<rgba-input-component *ngSwitchCase="'rgba'" [alpha]="control.alphaChannelVisibilityChanges | async" label [(color)]="control.value" [(hue)]="control.hue"></rgba-input-component>
|
<rgba-input-component *ngSwitchCase="'rgba'" label
|
||||||
<hsla-input-component *ngSwitchCase="'hsla'" [alpha]="control.alphaChannelVisibilityChanges | async" label [(color)]="control.value" [(hue)]="control.hue"></hsla-input-component>
|
[(color)]="control.value" [(hue)]="control.hue"></rgba-input-component>
|
||||||
<hex-input-component *ngSwitchCase="'hex'" label prefix="#" [(color)]="control.value" [(hue)]="control.hue"></hex-input-component>
|
<hsla-input-component *ngSwitchCase="'hsla'" label
|
||||||
</div>
|
[(color)]="control.value" [(hue)]="control.hue"></hsla-input-component>
|
||||||
<div>
|
<hex-input-component *ngSwitchCase="'hex'" label prefix="#" [(color)]="control.value"
|
||||||
<span class="type-btn" (click)="changePresentation()"></span>
|
[(hue)]="control.hue"></hex-input-component>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="type-btn" (click)="changePresentation()"></div>
|
||||||
|
</div>
|
||||||
|
|||||||
@ -17,75 +17,87 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
::ng-deep {
|
.saturation-component {
|
||||||
.saturation-component {
|
height: 100%;
|
||||||
height: 100%;
|
min-height: 200px;
|
||||||
min-height: 200px;
|
max-height: 300px;
|
||||||
max-height: 300px;
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-component {
|
||||||
|
max-height: 48px;
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.indicator-component {
|
||||||
|
height: 48px;
|
||||||
|
width: 48px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin-bottom: 16px;
|
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMUAFg9Gm0AAAAPSURBVAjXY2D4jxXhEgYAfr8P8QhChVEAAAAASUVORK5CYII=') repeat;
|
||||||
div.pointer {
|
|
||||||
border-width: 2px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
indicator-component {
|
|
||||||
svg {
|
|
||||||
vertical-align: -70% !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hue-alpha-range {
|
.hue-alpha-range {
|
||||||
alpha-component, hue-component {
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
> * {
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
border-radius: 9px;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
.pointer {
|
}
|
||||||
height: 18px;
|
}
|
||||||
width: 18px;
|
}
|
||||||
background: none;
|
|
||||||
border: 2px solid #fff;
|
.color-input-block {
|
||||||
}
|
display: flex;
|
||||||
.gradient-color {
|
|
||||||
border-radius: 24px;
|
.color-input {
|
||||||
}
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-btn {
|
||||||
|
height: 26px;
|
||||||
|
width: 20px;
|
||||||
|
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAgCAMAAAAootjDAAAAM1BMVEUAAAAzMzMzMzMzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzMyMjIrKyszMzPF8UZlAAAAEHRSTlMA1fHr4ZxxSRP45sG+sCkGH2+Z6QAAAHJJREFUKM+9kkkSgCAQA0FEVLb5/2tViqgQvNrHviSzKGCt6nDGuNass8i8NsrLiX+bZbrUtDwm7VLYE0zWUtEZ+RvUZpEvN8YhH9QmQRoC8kFpEnVHVP/DJUZVeSAem5fDKxwtms/BR+PT8gN8vwk/0wE1gQzNVYryIwAAAABJRU5ErkJggg==') no-repeat center;
|
||||||
|
background-size: 6px 12px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-component {
|
:host ::ng-deep {
|
||||||
max-height: 48px;
|
.saturation-component {
|
||||||
margin-bottom: 16px;
|
.pointer {
|
||||||
}
|
border-width: 2px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
indicator-component {
|
indicator-component {
|
||||||
height: 48px;
|
svg {
|
||||||
width: 48px;
|
vertical-align: -70% !important;
|
||||||
border-radius: 8px;
|
}
|
||||||
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMUAFg9Gm0AAAAPSURBVAjXY2D4jxXhEgYAfr8P8QhChVEAAAAASUVORK5CYII=') repeat;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.hue-alpha-range {
|
.hue-alpha-range {
|
||||||
hue-component, alpha-component {
|
alpha-component, hue-component {
|
||||||
border-radius: 24px;
|
.pointer {
|
||||||
}
|
height: 18px;
|
||||||
}
|
width: 18px;
|
||||||
|
background: none;
|
||||||
color-presets-component {
|
border: 2px solid #fff;
|
||||||
border-top: 1px solid #d0d0d0;
|
}
|
||||||
}
|
.gradient-color {
|
||||||
|
border-radius: 9px;
|
||||||
.type-btn {
|
}
|
||||||
display: inline-block;
|
}
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAgCAMAAAAootjDAAAAM1BMVEUAAAAzMzMzMzMzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzMyMjIrKyszMzPF8UZlAAAAEHRSTlMA1fHr4ZxxSRP45sG+sCkGH2+Z6QAAAHJJREFUKM+9kkkSgCAQA0FEVLb5/2tViqgQvNrHviSzKGCt6nDGuNass8i8NsrLiX+bZbrUtDwm7VLYE0zWUtEZ+RvUZpEvN8YhH9QmQRoC8kFpEnVHVP/DJUZVeSAem5fDKxwtms/BR+PT8gN8vwk/0wE1gQzNVYryIwAAAABJRU5ErkJggg==') no-repeat center;
|
|
||||||
background-size: 6px 12px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #eee;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import { Component, forwardRef, OnDestroy, OnInit } from '@angular/core';
|
import { Component, forwardRef, OnDestroy } from '@angular/core';
|
||||||
import { Color, ColorPickerControl } from '@iplab/ngx-color-picker';
|
import { Color, ColorPickerControl } from '@iplab/ngx-color-picker';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
@ -41,7 +41,7 @@ export enum ColorType {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ColorPickerComponent implements OnInit, ControlValueAccessor, OnDestroy {
|
export class ColorPickerComponent implements ControlValueAccessor, OnDestroy {
|
||||||
|
|
||||||
selectedPresentation = 0;
|
selectedPresentation = 0;
|
||||||
presentations = [ColorType.hex, ColorType.rgba, ColorType.hsla];
|
presentations = [ColorType.hex, ColorType.rgba, ColorType.hsla];
|
||||||
@ -51,16 +51,17 @@ export class ColorPickerComponent implements OnInit, ControlValueAccessor, OnDes
|
|||||||
|
|
||||||
private subscriptions: Array<Subscription> = [];
|
private subscriptions: Array<Subscription> = [];
|
||||||
|
|
||||||
private propagateChange = null;
|
private propagateChange = (v: any) => {};
|
||||||
|
|
||||||
|
private setValue = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
|
||||||
|
|
||||||
public ngOnInit(): void {
|
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.control.valueChanges.subscribe(value => {
|
this.control.valueChanges.subscribe(() => {
|
||||||
if (this.modelValue) {
|
if (!this.setValue) {
|
||||||
this.updateModel();
|
this.updateModel();
|
||||||
|
} else {
|
||||||
|
this.setValue = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -74,7 +75,8 @@ export class ColorPickerComponent implements OnInit, ControlValueAccessor, OnDes
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeValue(value: string): void {
|
writeValue(value: string): void {
|
||||||
this.control. setValueFrom(value || '#fff');
|
this.setValue = !!value;
|
||||||
|
this.control.setValueFrom(value || '#fff');
|
||||||
this.modelValue = value;
|
this.modelValue = value;
|
||||||
|
|
||||||
if (this.control.initType === ColorType.hexa) {
|
if (this.control.initType === ColorType.hexa) {
|
||||||
|
|||||||
@ -15,8 +15,8 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<form [formGroup]="colorPickerFormGroup" (ngSubmit)="select()">
|
<form [formGroup]="colorPickerFormGroup" (ngSubmit)="select()" style="width: 320px">
|
||||||
<div mat-dialog-content style="padding: 16px; width: 320px; min-width: 100%; max-width: 100%;" fxLayout="row" fxLayoutAlign="center">
|
<div mat-dialog-content style="padding: 16px; display: flex">
|
||||||
<tb-color-picker formControlName="color"></tb-color-picker>
|
<tb-color-picker formControlName="color"></tb-color-picker>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions fxLayout="row">
|
<div mat-dialog-actions fxLayout="row">
|
||||||
|
|||||||
@ -14,19 +14,11 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { ErrorStateMatcher } from '@angular/material/core';
|
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import {
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
FormGroupDirective,
|
|
||||||
NgForm,
|
|
||||||
UntypedFormBuilder,
|
|
||||||
UntypedFormControl,
|
|
||||||
UntypedFormGroup,
|
|
||||||
Validators
|
|
||||||
} from '@angular/forms';
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { DialogComponent } from '@shared/components/dialog.component';
|
import { DialogComponent } from '@shared/components/dialog.component';
|
||||||
|
|
||||||
@ -37,22 +29,18 @@ export interface ColorPickerDialogData {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-color-picker-dialog',
|
selector: 'tb-color-picker-dialog',
|
||||||
templateUrl: './color-picker-dialog.component.html',
|
templateUrl: './color-picker-dialog.component.html',
|
||||||
providers: [{provide: ErrorStateMatcher, useExisting: ColorPickerDialogComponent}],
|
|
||||||
styleUrls: []
|
styleUrls: []
|
||||||
})
|
})
|
||||||
export class ColorPickerDialogComponent extends DialogComponent<ColorPickerDialogComponent, string>
|
export class ColorPickerDialogComponent extends DialogComponent<ColorPickerDialogComponent, string>
|
||||||
implements OnInit, ErrorStateMatcher {
|
implements OnInit {
|
||||||
|
|
||||||
colorPickerFormGroup: UntypedFormGroup;
|
colorPickerFormGroup: FormGroup;
|
||||||
|
|
||||||
submitted = false;
|
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: ColorPickerDialogData,
|
@Inject(MAT_DIALOG_DATA) public data: ColorPickerDialogData,
|
||||||
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
|
|
||||||
public dialogRef: MatDialogRef<ColorPickerDialogComponent, string>,
|
public dialogRef: MatDialogRef<ColorPickerDialogComponent, string>,
|
||||||
public fb: UntypedFormBuilder,) {
|
public fb: FormBuilder) {
|
||||||
super(store, router, dialogRef);
|
super(store, router, dialogRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,18 +50,11 @@ export class ColorPickerDialogComponent extends DialogComponent<ColorPickerDialo
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
|
||||||
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
|
|
||||||
const customErrorState = !!(control && control.invalid && this.submitted);
|
|
||||||
return originalErrorState || customErrorState;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
cancel(): void {
|
||||||
this.dialogRef.close(null);
|
this.dialogRef.close(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
select(): void {
|
select(): void {
|
||||||
this.submitted = true;
|
|
||||||
const color: string = this.colorPickerFormGroup.get('color').value;
|
const color: string = this.colorPickerFormGroup.get('color').value;
|
||||||
this.dialogRef.close(color);
|
this.dialogRef.close(color);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user