@vipstorage/material-color-picker
Version:
Angular Material Color Picker
807 lines (795 loc) • 76.2 kB
JavaScript
import { ComponentPortal, PortalModule } from '@angular/cdk/portal';
import * as i1$1 from '@angular/common';
import { DOCUMENT, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, Directive, Output, Input, Component, HostListener, ViewEncapsulation, Injectable, InjectionToken, ChangeDetectionStrategy, ViewChild, Optional, Inject, forwardRef, ContentChild, NgModule } from '@angular/core';
import * as i4 from '@angular/forms';
import { Validators, FormControl, FormGroup, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as i2$1 from '@angular/material/button';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import * as i2$2 from '@angular/material/dialog';
import { MatDialogModule } from '@angular/material/dialog';
import * as i3$1 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import * as i1 from '@angular/material/input';
import { MAT_INPUT_VALUE_ACCESSOR, MatInputModule } from '@angular/material/input';
import { MatRadioModule } from '@angular/material/radio';
import { Subject, merge, Subscription, of } from 'rxjs';
import { takeUntil, debounceTime, distinctUntilChanged, take, filter } from 'rxjs/operators';
import * as i2 from '@angular/material/form-field';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ESCAPE, UP_ARROW, DOWN_ARROW } from '@angular/cdk/keycodes';
import * as i3 from '@angular/cdk/overlay';
import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
import { mixinColor } from '@angular/material/core';
import { matDatepickerAnimations } from '@angular/material/datepicker';
import * as i5 from '@angular/cdk/bidi';
const trimLeft = /^\s+/;
const trimRight = /\s+$/;
const tinyCounter = 0;
const mathRound = Math.round;
const mathMin = Math.min;
const mathMax = Math.max;
const mathRandom = Math.random;
const NUMERIC_REGEX = /[^0-9]/g;
const MAX_RGB = 255;
const MIN_RGB = 0;
/** List basic colors */
const BASIC_COLORS = ["#ffffff", "#ffff00", "#ff00ff", "#ff0000",
"#c0c0c0", "#808080", "#808000", "#800080",
"#800000", "#00ffff", "#00ff00", "#008080",
"#008000", "#0000ff", "#000080", "#000000"
];
/**
* Get color at position
* @param ctx
* @param x
* @param y
*/
function getColorAtPosition(ctx, x, y) {
const imageData = ctx.getImageData(x, y, 1, 1).data;
return { r: imageData[0], g: imageData[1], b: imageData[2] };
}
// `rgbaToHex`
// Converts an RGBA color plus alpha transparency to hex
// Assumes r, g, b are contained in the set [0, 255] and
// a in [0, 1]. Returns a 4 or 8 character rgba hex
function rgbaToHex(r, g, b, a, allow4Char) {
var hex = [
pad2(mathRound(r).toString(16)),
pad2(mathRound(g).toString(16)),
pad2(mathRound(b).toString(16)),
pad2(convertDecimalToHex(a))
];
// Return a 4 character hex if possible
if (allow4Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1) && hex[3].charAt(0) == hex[3].charAt(1)) {
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
}
return hex.join("");
}
// Force a hex value to have 2 characters
function pad2(c) {
return c.length == 1 ? '0' + c : '' + c;
}
// Converts a decimal to a hex value
function convertDecimalToHex(d) {
return Math.round(parseFloat(d) * 255).toString(16);
}
// Converts a hex value to a decimal
function convertHexToDecimal(h) {
return (parseIntFromHex(h) / 255);
}
// Parse a base-16 hex value into a base-10 integer
function parseIntFromHex(val) {
return parseInt(val, 16);
}
// `rgbToHex`
// Converts an RGB color to hex
// Assumes r, g, and b are contained in the set [0, 255]
// Returns a 3 or 6 character hex
function rgbToHex(r, g, b, allow3Char) {
var hex = [
pad2(mathRound(r).toString(16)),
pad2(mathRound(g).toString(16)),
pad2(mathRound(b).toString(16))
];
// Return a 3 character hex if possible
if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
}
return hex.join("");
}
// Actual matching.
// Parentheses and commas are optional, but not required.
// Whitespace can take the place of commas or opening parent
const CSS_INTEGER = "[-\\+]?\\d+%?";
const CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
const CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
const PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
const PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
const matchers = {
CSS_UNIT: new RegExp(CSS_UNIT),
rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
};
// `stringInputToObject`
// Permissive string parsing. Take in a number of formats, and output an object
// based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
function stringInputToObject(color) {
color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();
// Try to match string input using regular expressions.
// Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
// Just return an object and let the conversion functions handle that.
// This way the result will be the same whether the tinycolor is initialized with string or object.
let match;
let obj;
if ((match = matchers.rgb.exec(color))) {
return { r: match[1], g: match[2], b: match[3], a: 1 };
}
if ((match = matchers.rgba.exec(color))) {
return { r: match[1], g: match[2], b: match[3], a: match[4] };
}
if ((match = matchers.hex8.exec(color))) {
return {
r: parseIntFromHex(match[1]),
g: parseIntFromHex(match[2]),
b: parseIntFromHex(match[3]),
a: convertHexToDecimal(match[4]),
};
}
if ((match = matchers.hex6.exec(color))) {
return {
r: parseIntFromHex(match[1]),
g: parseIntFromHex(match[2]),
b: parseIntFromHex(match[3]),
a: 1
};
}
if ((match = matchers.hex4.exec(color))) {
return {
r: parseIntFromHex(match[1] + '' + match[1]),
g: parseIntFromHex(match[2] + '' + match[2]),
b: parseIntFromHex(match[3] + '' + match[3]),
a: convertHexToDecimal(match[4] + '' + match[4]),
};
}
if ((match = matchers.hex3.exec(color))) {
return {
r: parseIntFromHex(match[1] + '' + match[1]),
g: parseIntFromHex(match[2] + '' + match[2]),
b: parseIntFromHex(match[3] + '' + match[3]),
a: 1
};
}
return null;
}
function createMissingDateImplError(provider) {
return Error(`NgxMatColorPicker: No provider found for ${provider}. You must define MAT_COLOR_FORMATS in your module`);
}
class Color {
constructor(_r, _g, _b, _a) {
this.r = _r > MAX_RGB ? MAX_RGB : _r;
this.g = _g > MAX_RGB ? MAX_RGB : _g;
this.b = _b > MAX_RGB ? MAX_RGB : _b;
if (_a != null) {
this.a = _a > 1 ? 1 : _a;
}
else {
this.a = 1;
}
this.roundA = Math.round(this.a);
this.hex = rgbToHex(this.r, this.g, this.b);
this.rgba = this.toRgba();
}
toHex(allow3Char) {
return rgbToHex(this.r, this.g, this.b, allow3Char);
}
toRgba() {
return `rgba(${this.r},${this.g},${this.b},${this.a})`;
}
toHexString(allow3Char) {
return '#' + this.toHex(allow3Char);
}
toRgbString() {
return (this.a === 1) ?
"rgb(" + Math.round(this.r) + ", " + Math.round(this.g) + ", " + Math.round(this.b) + ")" :
"rgba(" + Math.round(this.r) + ", " + Math.round(this.g) + ", " + Math.round(this.b) + ", " + this.roundA + ")";
}
toHex8(allow4Char) {
return rgbaToHex(this.r, this.g, this.b, this.a, allow4Char);
}
toHex8String(allow4Char) {
return '#' + this.toHex8(allow4Char);
}
toString(format) {
let formatSet = !!format;
let formattedString;
let hasAlpha = this.a < 1 && this.a >= 0;
let needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6"
|| format === "hex3" || format === "hex4" || format === "hex8");
if (needsAlphaFormat) {
return this.toRgbString();
}
if (format === "rgb") {
formattedString = this.toRgbString();
}
if (format === "hex" || format === "hex6") {
formattedString = this.toHexString();
}
if (format === "hex3") {
formattedString = this.toHexString(true);
}
if (format === "hex4") {
formattedString = this.toHex8String(true);
}
if (format === "hex8") {
formattedString = this.toHex8String();
}
return formattedString || this.toHexString();
}
}
class NgxMatBaseColorCanvas {
constructor(zone, elementId) {
this.zone = zone;
this.colorChanged = new EventEmitter();
this.x = 0;
this.y = 0;
this.drag = false;
this._destroyed = new Subject();
this.elementId = elementId;
}
ngOnDestroy() {
this._destroyed.next();
this._destroyed.complete();
}
ngAfterViewInit() {
this.canvas = document.getElementById(this.elementId);
this.ctx = this.canvas.getContext('2d');
this.width = this.canvas.width;
this.height = this.canvas.height;
this.draw();
}
draw() {
this.ctx.clearRect(0, 0, this.width, this.height);
this.ctx.rect(0, 0, this.width, this.height);
this.fillGradient();
if (this.y != 0) {
this.redrawIndicator(this.x, this.y);
}
}
onMousedown(e) {
this.drag = true;
this.changeColor(e);
this.zone.runOutsideAngular(() => {
this.canvas.addEventListener('mousemove', this.onMousemove.bind(this));
});
}
onMousemove(e) {
if (this.drag) {
this.zone.run(() => {
this.changeColor(e);
});
}
}
onMouseup(e) {
this.drag = false;
this.canvas.removeEventListener('mousemove', this.onMousemove);
}
emitChange(color) {
this.colorChanged.emit(color);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatBaseColorCanvas, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: NgxMatBaseColorCanvas, inputs: { color: "color", theme: "theme" }, outputs: { colorChanged: "colorChanged" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatBaseColorCanvas, decorators: [{
type: Directive,
args: [{}]
}], ctorParameters: () => [{ type: i0.NgZone }, { type: undefined }], propDecorators: { colorChanged: [{
type: Output
}], color: [{
type: Input
}], theme: [{
type: Input
}] } });
class NgxMatColorSliderComponent extends NgxMatBaseColorCanvas {
constructor(zone) {
super(zone, 'color-strip');
this.zone = zone;
}
ngOnInit() {
}
ngAfterViewInit() {
super.ngAfterViewInit();
}
fillGradient() {
const grd = this.ctx.createLinearGradient(0, 0, 0, this.height);
grd.addColorStop(0, 'rgba(255, 0, 0, 1)');
grd.addColorStop(0.17, 'rgba(255, 255, 0, 1)');
grd.addColorStop(0.34, 'rgba(0, 255, 0, 1)');
grd.addColorStop(0.51, 'rgba(0, 255, 255, 1)');
grd.addColorStop(0.68, 'rgba(0, 0, 255, 1)');
grd.addColorStop(0.85, 'rgba(255, 0, 255, 1)');
grd.addColorStop(1, 'rgba(255, 0, 0, 1)');
this.ctx.fillStyle = grd;
this.ctx.fill();
}
redrawIndicator(x, y) {
this.ctx.beginPath();
this.ctx.strokeStyle = 'white';
this.ctx.lineWidth = 2;
this.ctx.arc(7.5, y, 7.5, 0, 2 * Math.PI, false);
this.ctx.stroke();
this.ctx.closePath();
}
changeColor(e) {
this.x = e.offsetX;
this.y = e.offsetY;
this.draw();
const { r, g, b } = getColorAtPosition(this.ctx, e.offsetX, e.offsetY);
this.emitChange(new Color(r, g, b));
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorSliderComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.9", type: NgxMatColorSliderComponent, selector: "ngx-mat-color-slider", usesInheritance: true, ngImport: i0, template: "<canvas id=\"color-strip\" class=\"zone-strip\" (mousedown)=\"onMousedown($event)\" (mouseup)=\"onMouseup($event)\"\n width=\"15\" height=\"234\"></canvas>", styles: [""] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorSliderComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-color-slider', template: "<canvas id=\"color-strip\" class=\"zone-strip\" (mousedown)=\"onMousedown($event)\" (mouseup)=\"onMouseup($event)\"\n width=\"15\" height=\"234\"></canvas>" }]
}], ctorParameters: () => [{ type: i0.NgZone }] });
class NumericColorInputDirective {
constructor() { }
onInput($event) {
this._formatInput($event.target);
}
/**
* Format input
* @param input
*/
_formatInput(input) {
let val = Number(input.value.replace(NUMERIC_REGEX, ''));
val = isNaN(val) ? 0 : val;
input.value = val;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NumericColorInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.9", type: NumericColorInputDirective, selector: "[ngxMatNumericColorInput]", host: { listeners: { "input": "onInput($event)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NumericColorInputDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngxMatNumericColorInput]'
}]
}], ctorParameters: () => [], propDecorators: { onInput: [{
type: HostListener,
args: ['input', ['$event']]
}] } });
const RADIUS_NOB = 5;
class NgxMatColorCanvasComponent extends NgxMatBaseColorCanvas {
get rCtrl() {
return this.formGroup.get('r');
}
get gCtrl() {
return this.formGroup.get('g');
}
get bCtrl() {
return this.formGroup.get('b');
}
get aCtrl() {
return this.formGroup.get('a');
}
get hexCtrl() {
return this.formGroup.get('hex');
}
constructor(zone) {
super(zone, 'color-block');
this.zone = zone;
this._resetBaseColor = true;
this.formGroup = new FormGroup({
r: new FormControl(null, [Validators.required]),
g: new FormControl(null, [Validators.required]),
b: new FormControl(null, [Validators.required]),
a: new FormControl(null, [Validators.required]),
hex: new FormControl(null, [Validators.required, Validators.pattern(matchers.hex6)]),
});
}
ngOnInit() {
const rgbaCtrl$ = merge(this.rCtrl.valueChanges, this.gCtrl.valueChanges, this.bCtrl.valueChanges, this.aCtrl.valueChanges);
rgbaCtrl$.pipe(takeUntil(this._destroyed), debounceTime(400))
.subscribe(_ => {
const color = new Color(Number(this.rCtrl.value), Number(this.gCtrl.value), Number(this.bCtrl.value), Number(this.aCtrl.value));
this.emitChange(color);
});
const hexCtrl$ = this.hexCtrl.valueChanges;
hexCtrl$.pipe(takeUntil(this._destroyed), debounceTime(400), distinctUntilChanged())
.subscribe(hex => {
const obj = stringInputToObject(hex);
if (obj != null) {
const color = new Color(obj.r, obj.g, obj.b, obj.a);
this.emitChange(color);
}
});
}
ngOnChanges(changes) {
if (changes.color && changes.color.currentValue) {
this.updateForm(changes.color.currentValue);
if (this._resetBaseColor) {
this._baseColor = changes.color.currentValue;
}
this._resetBaseColor = true;
if (!changes.color.firstChange) {
this.draw();
}
}
}
updateForm(val) {
const config = { emitEvent: false };
this.rCtrl.setValue(val.r, config);
this.gCtrl.setValue(val.g, config);
this.bCtrl.setValue(val.b, config);
this.aCtrl.setValue(val.a, config);
this.hexCtrl.setValue(val.hex, config);
}
redrawIndicator(x, y) {
this.ctx.beginPath();
this.ctx.strokeStyle = 'white';
this.ctx.arc(x, y, RADIUS_NOB, 0, 2 * Math.PI, false);
this.ctx.stroke();
this.ctx.closePath();
}
fillGradient() {
this.ctx.fillStyle = this._baseColor ? this._baseColor.rgba : 'rgba(255,255,255,1)';
this.ctx.fillRect(0, 0, this.width, this.height);
const grdWhite = this.ctx.createLinearGradient(0, 0, this.width, 0);
grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
this.ctx.fillStyle = grdWhite;
this.ctx.fillRect(0, 0, this.width, this.height);
const grdBlack = this.ctx.createLinearGradient(0, 0, 0, this.height);
grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
this.ctx.fillStyle = grdBlack;
this.ctx.fillRect(0, 0, this.width, this.height);
}
onSliderColorChanged(c) {
this._baseColor = c;
this.color = c;
this.fillGradient();
this.emitChange(c);
}
changeColor(e) {
this.x = e.offsetX;
this.y = e.offsetY;
this._resetBaseColor = false;
this.draw();
const { r, g, b } = getColorAtPosition(this.ctx, e.offsetX, e.offsetY);
this.emitChange(new Color(r, g, b));
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorCanvasComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.9", type: NgxMatColorCanvasComponent, selector: "ngx-mat-color-canvas", host: { classAttribute: "ngx-mat-color-canvas" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"formGroup\">\n <div class=\"color-canvas-row\">\n <div class=\"zone-canvas\">\n <canvas id=\"color-block\" class=\"zone-block\" (mousedown)=\"onMousedown($event)\" (mouseup)=\"onMouseup($event)\"\n width=\"200\" height=\"235\"></canvas>\n <ngx-mat-color-slider (colorChanged)=\"onSliderColorChanged($event)\"></ngx-mat-color-slider>\n </div>\n\n <div class=\"zone-inputs\">\n <mat-form-field [color]=\"theme\">\n <mat-label>R</mat-label>\n <input matInput formControlName=\"r\" ngxMatNumericColorInput autocomplete=\"off\">\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>G</mat-label>\n <input matInput formControlName=\"g\" ngxMatNumericColorInput autocomplete=\"off\">\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>B</mat-label>\n <input matInput formControlName=\"b\" ngxMatNumericColorInput autocomplete=\"off\">\n </mat-form-field>\n </div>\n </div>\n\n <div class=\"color-canvas-row\">\n <button mat-mini-fab [style.background-color]=\"color?.rgba || 'transparent'\" class=\"preview\"></button>\n <mat-form-field [color]=\"theme\">\n <mat-label>HEX6</mat-label>\n <mat-label matPrefix class=\"symbol\"># </mat-label>\n <input matInput formControlName=\"hex\" autocomplete=\"off\">\n </mat-form-field>\n <mat-form-field class=\"input-opacity\" [color]=\"theme\">\n <mat-label>A</mat-label>\n <input matInput formControlName=\"a\" type=\"number\" min=\"0\" max=\"1\" step=\"0.1\" autocomplete=\"off\">\n </mat-form-field>\n </div>\n</form>", styles: [".ngx-mat-color-canvas .color-canvas-row{display:flex}.ngx-mat-color-canvas .color-canvas-row:first-of-type{height:235px;margin-bottom:12px}.ngx-mat-color-canvas .color-canvas-row:first-of-type .card{height:180px}.ngx-mat-color-canvas .color-canvas-row canvas:hover{cursor:crosshair}.ngx-mat-color-canvas .color-canvas-row .zone{display:flex}.ngx-mat-color-canvas .color-canvas-row .zone-canvas{height:235px}.ngx-mat-color-canvas .color-canvas-row .zone-canvas .zone-block{border:1px solid rgba(0,0,0,.12)}.ngx-mat-color-canvas .color-canvas-row .zone-strip{flex-basis:auto;margin-left:10px}.ngx-mat-color-canvas .color-canvas-row .zone-inputs{display:flex;width:60px;height:235px;flex-direction:column;margin-left:16px;margin-top:12px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2){display:flex}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .preview{min-width:40px;min-height:40px;height:40px;width:40px;margin-top:12px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field{margin-left:16px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:first-of-type{width:170px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:first-of-type .symbol{font-weight:700;color:#0000008a}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:last-of-type{width:60px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:last-of-type .mat-mdc-text-field-wrapper{padding:0 8px}.ngx-mat-color-canvas .mat-mdc-form-field-label{font-weight:700}.ngx-mat-color-canvas .mat-mdc-form-field .mdc-text-field--filled:not(.mdc-text-field--disabled){background-color:transparent}\n"], dependencies: [{ kind: "directive", type: i1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab]", exportAs: ["matButton"] }, { kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i4.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: NgxMatColorSliderComponent, selector: "ngx-mat-color-slider" }, { kind: "directive", type: NumericColorInputDirective, selector: "[ngxMatNumericColorInput]" }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorCanvasComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-color-canvas', encapsulation: ViewEncapsulation.None, host: {
'class': 'ngx-mat-color-canvas'
}, template: "<form [formGroup]=\"formGroup\">\n <div class=\"color-canvas-row\">\n <div class=\"zone-canvas\">\n <canvas id=\"color-block\" class=\"zone-block\" (mousedown)=\"onMousedown($event)\" (mouseup)=\"onMouseup($event)\"\n width=\"200\" height=\"235\"></canvas>\n <ngx-mat-color-slider (colorChanged)=\"onSliderColorChanged($event)\"></ngx-mat-color-slider>\n </div>\n\n <div class=\"zone-inputs\">\n <mat-form-field [color]=\"theme\">\n <mat-label>R</mat-label>\n <input matInput formControlName=\"r\" ngxMatNumericColorInput autocomplete=\"off\">\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>G</mat-label>\n <input matInput formControlName=\"g\" ngxMatNumericColorInput autocomplete=\"off\">\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>B</mat-label>\n <input matInput formControlName=\"b\" ngxMatNumericColorInput autocomplete=\"off\">\n </mat-form-field>\n </div>\n </div>\n\n <div class=\"color-canvas-row\">\n <button mat-mini-fab [style.background-color]=\"color?.rgba || 'transparent'\" class=\"preview\"></button>\n <mat-form-field [color]=\"theme\">\n <mat-label>HEX6</mat-label>\n <mat-label matPrefix class=\"symbol\"># </mat-label>\n <input matInput formControlName=\"hex\" autocomplete=\"off\">\n </mat-form-field>\n <mat-form-field class=\"input-opacity\" [color]=\"theme\">\n <mat-label>A</mat-label>\n <input matInput formControlName=\"a\" type=\"number\" min=\"0\" max=\"1\" step=\"0.1\" autocomplete=\"off\">\n </mat-form-field>\n </div>\n</form>", styles: [".ngx-mat-color-canvas .color-canvas-row{display:flex}.ngx-mat-color-canvas .color-canvas-row:first-of-type{height:235px;margin-bottom:12px}.ngx-mat-color-canvas .color-canvas-row:first-of-type .card{height:180px}.ngx-mat-color-canvas .color-canvas-row canvas:hover{cursor:crosshair}.ngx-mat-color-canvas .color-canvas-row .zone{display:flex}.ngx-mat-color-canvas .color-canvas-row .zone-canvas{height:235px}.ngx-mat-color-canvas .color-canvas-row .zone-canvas .zone-block{border:1px solid rgba(0,0,0,.12)}.ngx-mat-color-canvas .color-canvas-row .zone-strip{flex-basis:auto;margin-left:10px}.ngx-mat-color-canvas .color-canvas-row .zone-inputs{display:flex;width:60px;height:235px;flex-direction:column;margin-left:16px;margin-top:12px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2){display:flex}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .preview{min-width:40px;min-height:40px;height:40px;width:40px;margin-top:12px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field{margin-left:16px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:first-of-type{width:170px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:first-of-type .symbol{font-weight:700;color:#0000008a}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:last-of-type{width:60px}.ngx-mat-color-canvas .color-canvas-row:nth-of-type(2) .mat-mdc-form-field:last-of-type .mat-mdc-text-field-wrapper{padding:0 8px}.ngx-mat-color-canvas .mat-mdc-form-field-label{font-weight:700}.ngx-mat-color-canvas .mat-mdc-form-field .mdc-text-field--filled:not(.mdc-text-field--disabled){background-color:transparent}\n"] }]
}], ctorParameters: () => [{ type: i0.NgZone }] });
class NgxMatColorCollectionComponent {
set color(c) {
if (c) {
this.selectedColor = c.toHexString();
}
}
constructor() {
this.colorChanged = new EventEmitter();
this.colors1 = BASIC_COLORS.slice(0, 8);
this.colors2 = BASIC_COLORS.slice(8, 16);
}
ngOnInit() {
}
select(hex) {
this.selectedColor = hex;
const { r, g, b, a } = stringInputToObject(hex);
this.colorChanged.emit(new Color(r, g, b, a));
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorCollectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.9", type: NgxMatColorCollectionComponent, selector: "ngx-mat-color-collection", inputs: { color: "color" }, outputs: { colorChanged: "colorChanged" }, host: { classAttribute: "ngx-mat-color-collection" }, ngImport: i0, template: "<div class=\"color-collection-row\">\n <button *ngFor=\"let c of colors1\" mat-mini-fab [style.background-color]=\"c\" class=\"btn-color\"\n (click)=\"select(c)\" [ngClass]=\"{'active': selectedColor === c}\" [disableRipple]=\"true\">\n </button>\n</div>\n<div class=\"color-collection-row\">\n <button *ngFor=\"let c of colors2\" mat-mini-fab [style.background-color]=\"c\" class=\"btn-color\"\n (click)=\"select(c)\" [ngClass]=\"{'active': selectedColor === c}\" [disableRipple]=\"true\">\n </button>\n</div>", styles: [".ngx-mat-color-collection .btn-color{height:20px;width:20px;margin-right:11px;box-shadow:none;opacity:.3;will-change:opacity;transition:opacity .3s linear}.ngx-mat-color-collection .btn-color.active{box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f;opacity:1}.ngx-mat-color-collection .btn-color .mat-mdc-button-touch-target{display:none!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab]", exportAs: ["matButton"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorCollectionComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-color-collection', encapsulation: ViewEncapsulation.None, host: {
'class': 'ngx-mat-color-collection'
}, template: "<div class=\"color-collection-row\">\n <button *ngFor=\"let c of colors1\" mat-mini-fab [style.background-color]=\"c\" class=\"btn-color\"\n (click)=\"select(c)\" [ngClass]=\"{'active': selectedColor === c}\" [disableRipple]=\"true\">\n </button>\n</div>\n<div class=\"color-collection-row\">\n <button *ngFor=\"let c of colors2\" mat-mini-fab [style.background-color]=\"c\" class=\"btn-color\"\n (click)=\"select(c)\" [ngClass]=\"{'active': selectedColor === c}\" [disableRipple]=\"true\">\n </button>\n</div>", styles: [".ngx-mat-color-collection .btn-color{height:20px;width:20px;margin-right:11px;box-shadow:none;opacity:.3;will-change:opacity;transition:opacity .3s linear}.ngx-mat-color-collection .btn-color.active{box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024,0 1px 18px #0000001f;opacity:1}.ngx-mat-color-collection .btn-color .mat-mdc-button-touch-target{display:none!important}\n"] }]
}], ctorParameters: () => [], propDecorators: { colorChanged: [{
type: Output
}], color: [{
type: Input
}] } });
class NgxMatColorPaletteComponent {
constructor() {
this.colorChanged = new EventEmitter();
}
ngOnInit() {
}
handleColorChanged(color) {
this.colorChanged.emit(color);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorPaletteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.9", type: NgxMatColorPaletteComponent, selector: "ngx-mat-color-palette", inputs: { color: "color", theme: "theme" }, outputs: { colorChanged: "colorChanged" }, host: { classAttribute: "ngx-mat-color-palette" }, ngImport: i0, template: "<ngx-mat-color-canvas (colorChanged)=\"handleColorChanged($event)\" [color]=\"color\"\n [theme]=\"theme\"></ngx-mat-color-canvas>\n\n<ngx-mat-color-collection (colorChanged)=\"handleColorChanged($event)\" [color]=\"color\">\n</ngx-mat-color-collection>", styles: [".ngx-mat-color-palette .actions{margin-top:10px;display:flex}.ngx-mat-color-palette .actions .left{display:flex;flex-direction:column;margin-right:15px}.ngx-mat-color-palette .actions .left .preview{flex:2 1 auto;margin-bottom:10px}.ngx-mat-color-palette .actions .right{display:flex;width:60px;flex-direction:column}\n"], dependencies: [{ kind: "component", type: NgxMatColorCanvasComponent, selector: "ngx-mat-color-canvas" }, { kind: "component", type: NgxMatColorCollectionComponent, selector: "ngx-mat-color-collection", inputs: ["color"], outputs: ["colorChanged"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorPaletteComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-color-palette', encapsulation: ViewEncapsulation.None, host: {
'class': 'ngx-mat-color-palette'
}, template: "<ngx-mat-color-canvas (colorChanged)=\"handleColorChanged($event)\" [color]=\"color\"\n [theme]=\"theme\"></ngx-mat-color-canvas>\n\n<ngx-mat-color-collection (colorChanged)=\"handleColorChanged($event)\" [color]=\"color\">\n</ngx-mat-color-collection>", styles: [".ngx-mat-color-palette .actions{margin-top:10px;display:flex}.ngx-mat-color-palette .actions .left{display:flex;flex-direction:column;margin-right:15px}.ngx-mat-color-palette .actions .left .preview{flex:2 1 auto;margin-bottom:10px}.ngx-mat-color-palette .actions .right{display:flex;width:60px;flex-direction:column}\n"] }]
}], ctorParameters: () => [], propDecorators: { colorChanged: [{
type: Output
}], color: [{
type: Input
}], theme: [{
type: Input
}] } });
class ColorAdapter {
constructor() { }
sameColor(a, b) {
if (a == null && b == null)
return true;
if (a != null && b != null)
return a.rgba === b.rgba;
return false;
}
format(c, format) {
return c.toString(format);
}
parse(value) {
const obj = stringInputToObject(value);
if (obj) {
return new Color(obj.r, obj.g, obj.b, obj.a);
}
return null;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ColorAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ColorAdapter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: ColorAdapter, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
const NGX_MAT_COLOR_FORMATS = {
display: {
colorInput: 'hex'
}
};
const MAT_COLOR_FORMATS = new InjectionToken('mat-color-formats');
/** Injection token that determines the scroll handling while the calendar is open. */
const NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY = new InjectionToken('ngx-mat-colorpicker-scroll-strategy');
function NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY_FACTORY(overlay) {
return () => overlay.scrollStrategies.reposition();
}
const NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY_FACTORY_PROVIDER = {
provide: NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY,
deps: [Overlay],
useFactory: NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY_FACTORY,
};
const _MatColorpickerContentBase = mixinColor(class {
constructor(_elementRef) {
this._elementRef = _elementRef;
}
});
class NgxMatColorPickerContentComponent extends _MatColorpickerContentBase {
constructor(elementRef) {
super(elementRef);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorPickerContentComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.9", type: NgxMatColorPickerContentComponent, selector: "ngx-mat-color-picker-content", inputs: { color: "color" }, host: { properties: { "@transformPanel": "\"enter\"", "class.ngx-mat-colorpicker-content-touch": "picker.touchUi" }, classAttribute: "ngx-mat-colorpicker-content" }, viewQueries: [{ propertyName: "_palette", first: true, predicate: NgxMatColorPaletteComponent, descendants: true }], exportAs: ["ngxMatColorPickerContent"], usesInheritance: true, ngImport: i0, template: "<ngx-mat-color-palette (colorChanged)=\"picker.select($event)\" \n[color]=\"picker._selected\"\n[theme]=\"color\"></ngx-mat-color-palette>", styles: [".ngx-mat-colorpicker-content{display:block;border-radius:4px;box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f;background-color:#fff;color:#000000de;padding:16px}.ngx-mat-colorpicker-content .ngx-mat-color-palette{width:296px;height:354px}.ngx-mat-colorpicker-content-touch{display:block;max-height:80vh;overflow:auto}.ngx-mat-colorpicker-content-touch .ngx-mat-color-palette{min-width:250px;min-height:312px;max-width:750px;max-height:788px}@media all and (orientation: landscape){.mat-colorpicker-content-touch .ngx-mat-color-palette{width:64vh;height:80vh}}@media all and (orientation: portrait){.mat-colorpicker-content-touch .ngx-mat-color-palette{width:80vw;height:100vw}}\n"], dependencies: [{ kind: "component", type: NgxMatColorPaletteComponent, selector: "ngx-mat-color-palette", inputs: ["color", "theme"], outputs: ["colorChanged"] }], animations: [
matDatepickerAnimations.transformPanel,
matDatepickerAnimations.fadeInCalendar,
], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: NgxMatColorPickerContentComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-color-picker-content', host: {
'class': 'ngx-mat-colorpicker-content',
'[@transformPanel]': '"enter"',
'[class.ngx-mat-colorpicker-content-touch]': 'picker.touchUi',
}, animations: [
matDatepickerAnimations.transformPanel,
matDatepickerAnimations.fadeInCalendar,
], exportAs: 'ngxMatColorPickerContent', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, inputs: ['color'], template: "<ngx-mat-color-palette (colorChanged)=\"picker.select($event)\" \n[color]=\"picker._selected\"\n[theme]=\"color\"></ngx-mat-color-palette>", styles: [".ngx-mat-colorpicker-content{display:block;border-radius:4px;box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f;background-color:#fff;color:#000000de;padding:16px}.ngx-mat-colorpicker-content .ngx-mat-color-palette{width:296px;height:354px}.ngx-mat-colorpicker-content-touch{display:block;max-height:80vh;overflow:auto}.ngx-mat-colorpicker-content-touch .ngx-mat-color-palette{min-width:250px;min-height:312px;max-width:750px;max-height:788px}@media all and (orientation: landscape){.mat-colorpicker-content-touch .ngx-mat-color-palette{width:64vh;height:80vh}}@media all and (orientation: portrait){.mat-colorpicker-content-touch .ngx-mat-color-palette{width:80vw;height:100vw}}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { _palette: [{
type: ViewChild,
args: [NgxMatColorPaletteComponent]
}] } });
class NgxMatColorPickerComponent {
get disabled() {
return this._disabled === undefined && this._pickerInput ?
this._pickerInput.disabled : !!this._disabled;
}
set disabled(value) {
const newValue = coerceBooleanProperty(value);
if (newValue !== this._disabled) {
this._disabled = newValue;
this._disabledChange.next(newValue);
}
}
get touchUi() { return this._touchUi; }
set touchUi(value) {
this._touchUi = coerceBooleanProperty(value);
}
/** Whether the calendar is open. */
get opened() { return this._opened; }
set opened(value) { value ? this.open() : this.close(); }
/** Default Color palette to use on the datepicker's calendar. */
get defaultColor() {
return this._defaultColor;
}
set defaultColor(value) {
this._defaultColor = value;
}
/** Color palette to use on the datepicker's calendar. */
get color() {
return this._color ||
(this._pickerInput ? this._pickerInput.getThemePalette() : undefined);
}
set color(value) {
this._color = value;
}
/** The currently selected date. */
get _selected() { return this._validSelected; }
set _selected(value) { this._validSelected = value; }
constructor(_dialog, _overlay, _zone, _adapter, _dir, scrollStrategy, _document, _viewContainerRef) {
this._dialog = _dialog;
this._overlay = _overlay;
this._zone = _zone;
this._adapter = _adapter;
this._dir = _dir;
this._document = _document;
this._viewContainerRef = _viewContainerRef;
/** Emits when the datepicker has been opened. */
this.openedStream = new EventEmitter();
/** Emits when the datepicker has been closed. */
this.closedStream = new EventEmitter();
this._touchUi = false;
this._opened = false;
this._defaultColor = 'primary';
this._validSelected = null;
/** Emits when the datepicker is disabled. */
this._disabledChange = new Subject();
/** The element that was focused before the datepicker was opened. */
this._focusedElementBeforeOpen = null;
/** Subscription to value changes in the associated input element. */
this._inputSubscription = Subscription.EMPTY;
/** Emits new selected date when selected date changes. */
this._selectedChanged = new Subject();
this._scrollStrategy = scrollStrategy;
}
ngOnInit() {
}
ngOnDestroy() {
this.close();
this._inputSubscription.unsubscribe();
this._disabledChange.complete();
if (this._popupRef) {
this._popupRef.dispose();
this._popupComponentRef = null;
}
}
/** Selects the given date */
select(nextVal) {
let oldValue = this._selected;
this._selected = nextVal;
if (!this._adapter.sameColor(oldValue, this._selected)) {
this._selectedChanged.next(nextVal);
}
}
/**
* Register an input with this datepicker.
* @param input The datepicker input to register with this datepicker.
*/
registerInput(input) {
if (this._pickerInput) {
throw Error('A ColorPicker can only be associated with a single input.');
}
this._pickerInput = input;
this._inputSubscription =
this._pickerInput._valueChange.subscribe((value) => this._selected = value);
}
open() {
if (this._opened || this.disabled) {
return;
}
if (!this._pickerInput) {
throw Error('Attempted to open an ColorPicker with no associated input.');
}
if (this._document) {
this._focusedElementBeforeOpen = this._document.activeElement;
}
this.touchUi ? this._openAsDialog() : this._openAsPopup();
this._opened = true;
this.openedStream.emit();
}
/** Open the calendar as a dialog. */
_openAsDialog() {
if (this._dialogRef) {
this._dialogRef.close();
}
this._dialogRef = this._dialog.open(NgxMatColorPickerContentComponent, {
direction: this._dir ? this._dir.value : 'ltr',
viewContainerRef: this._viewContainerRef,
panelClass: 'ngx-mat-colorpicker-dialog',
});
this._dialogRef.afterClosed().subscribe(() => this.close());
this._dialogRef.componentInstance.picker = this;
this._setColor();
}
/** Open the calendar as a popup. */
_openAsPopup() {
if (!this._portal) {
this._portal = new ComponentPortal(NgxMatColorPickerContentComponent, this._viewContainerRef);
}
if (!this._popupRef) {
this._createPopup();
}
if (!this._popupRef.hasAttached()) {
this._popupComponentRef = this._popupRef.attach(this._portal);
this._popupComponentRef.instance.picker = this;
this._setColor();
// Update the position once the calendar has rendered.
this._zone.onStable.asObservable().pipe(take(1)).subscribe(() => {
this._popupRef.updatePosition();
});
}
}
/** Create the popup. */
_createPopup() {
const overlayConfig = new OverlayConfig({
positionStrategy: this._createPopupPositionStrategy(),
hasBackdrop: true,
backdropClass: 'mat-overlay-transparent-backdrop',
direction: this._dir,
scrollStrategy: this._scrollStrategy(),
panelClass: 'mat-colorpicker-popup',
});
this._popupRef = this._overlay.create(overlayConfig);
this._popupRef.overlayElement.setAttribute('role', 'dialog');
merge(this._popupRef.backdropClick(), this._popupRef.detachments(), this._popupRef.keydownEvents().pipe(filter(event => {
// Closing on alt + up is only valid when there's an input associated with the datepicker.
return event.keyCode === ESCAPE ||
(this._pickerInput && event.altKey && event.keyCode === UP_ARROW);
}))).subscribe(event => {
if (event) {
event.preventDefault();
}
this.close();
});
}
close() {
if (!this._opened) {
return;
}
if (this._popupRef && this._popupRef.hasAttached()) {
this._popupRef.detach();
}
if (this._dialogRef) {
this._dialogRef.close();
this._dialogRef = null;
}
if (this._portal && this._portal.isAttached) {
this._portal.detach();
}
const completeClose = () => {
// The `_opened` could've been reset already if
// we got two events in quick succession.
if (this._opened) {
this._opened = false;
this.closedStream.emit();
this._focusedElementBeforeOpen = null;
}
};
if (this._focusedElementBeforeOpen &&
typeof this._focusedElementBeforeOpen.focus === 'function') {