UNPKG

@vipstorage/material-color-picker

Version:
807 lines (795 loc) 76.2 kB
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\">#&nbsp;</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\">#&nbsp;</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') {