UNPKG

@ngxmc/color-picker

Version:
816 lines (806 loc) 74.5 kB
import * as i0 from '@angular/core'; import { output, input, signal, Input, Directive, Component, ViewEncapsulation, Injectable, InjectionToken, viewChild, ChangeDetectionStrategy, EventEmitter, DOCUMENT, HostBinding, Output, Optional, Inject, forwardRef, effect, untracked, HostListener } from '@angular/core'; import * as i3 from '@angular/forms'; import { FormGroup, FormControl, Validators, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; import * as i1 from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field'; import * as i2 from '@angular/material/input'; import { MatInputModule, MAT_INPUT_VALUE_ACCESSOR } from '@angular/material/input'; import { Subject, merge, Subscription, of } from 'rxjs'; import { takeUntil, debounceTime, distinctUntilChanged, take, filter } from 'rxjs/operators'; import { NgClass } from '@angular/common'; import * as i1$1 from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ESCAPE, UP_ARROW, DOWN_ARROW } from '@angular/cdk/keycodes'; import * as i2$1 from '@angular/cdk/overlay'; import { Overlay, OverlayConfig } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; import { matDatepickerAnimations } from '@angular/material/datepicker'; import * as i1$2 from '@angular/material/dialog'; import * as i4 from '@angular/cdk/bidi'; import * as i2$2 from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon'; 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 { set setColor(color) { this.color.set(color); } constructor(zone, elementId) { this.zone = zone; this.colorChanged = output(); this.theme = input(); this.color = signal(null); 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: "20.0.0", ngImport: i0, type: NgxMatBaseColorCanvas, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.0", type: NgxMatBaseColorCanvas, isStandalone: true, inputs: { theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, setColor: { classPropertyName: "setColor", publicName: "color", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { colorChanged: "colorChanged" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: NgxMatBaseColorCanvas, decorators: [{ type: Directive }], ctorParameters: () => [{ type: i0.NgZone }, { type: undefined }], propDecorators: { setColor: [{ type: Input, args: [{ alias: 'color', }] }] } }); class NgxMatColorSliderComponent extends NgxMatBaseColorCanvas { constructor(zone) { super(zone, 'color-strip'); this.zone = zone; } 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: "20.0.0", ngImport: i0, type: NgxMatColorSliderComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.0", type: NgxMatColorSliderComponent, isStandalone: true, selector: "ngx-mat-color-slider", usesInheritance: true, ngImport: i0, template: "<canvas\n id=\"color-strip\"\n class=\"zone-strip\"\n (mousedown)=\"onMousedown($event)\"\n (mouseup)=\"onMouseup($event)\"\n width=\"15\"\n height=\"234\"\n></canvas>\n", styles: [""] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: NgxMatColorSliderComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-mat-color-slider', template: "<canvas\n id=\"color-strip\"\n class=\"zone-strip\"\n (mousedown)=\"onMousedown($event)\"\n (mouseup)=\"onMouseup($event)\"\n width=\"15\"\n height=\"234\"\n></canvas>\n" }] }], ctorParameters: () => [{ type: i0.NgZone }] }); 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.set(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: "20.0.0", ngImport: i0, type: NgxMatColorCanvasComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.0", type: NgxMatColorCanvasComponent, isStandalone: true, 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\n id=\"color-block\"\n class=\"zone-block\"\n (mousedown)=\"onMousedown($event)\"\n (mouseup)=\"onMouseup($event)\"\n width=\"200\"\n height=\"235\"\n ></canvas>\n <ngx-mat-color-slider (colorChanged)=\"onSliderColorChanged($event)\" />\n </div>\n\n <div class=\"zone-inputs\">\n <mat-form-field [color]=\"theme\">\n <mat-label>R</mat-label>\n <input\n matInput\n formControlName=\"r\"\n ngxMatNumericColorInput\n autocomplete=\"off\"\n />\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>G</mat-label>\n <input\n matInput\n formControlName=\"g\"\n ngxMatNumericColorInput\n autocomplete=\"off\"\n />\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>B</mat-label>\n <input\n matInput\n formControlName=\"b\"\n ngxMatNumericColorInput\n autocomplete=\"off\"\n />\n </mat-form-field>\n </div>\n </div>\n\n <div class=\"color-canvas-row\">\n <button\n mat-mini-fab\n [style.background-color]=\"color()?.rgba || 'transparent'\"\n class=\"preview\"\n ></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\n matInput\n formControlName=\"a\"\n type=\"number\"\n min=\"0\"\n max=\"1\"\n step=\"0.1\"\n autocomplete=\"off\"\n />\n </mat-form-field>\n </div>\n</form>\n", 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: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i1.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: NgxMatColorSliderComponent, selector: "ngx-mat-color-slider" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.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: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: NgxMatColorCanvasComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-mat-color-canvas', encapsulation: ViewEncapsulation.None, host: { class: 'ngx-mat-color-canvas', }, imports: [MatFormFieldModule, MatInputModule, NgxMatColorSliderComponent, ReactiveFormsModule], template: "<form [formGroup]=\"formGroup\">\n <div class=\"color-canvas-row\">\n <div class=\"zone-canvas\">\n <canvas\n id=\"color-block\"\n class=\"zone-block\"\n (mousedown)=\"onMousedown($event)\"\n (mouseup)=\"onMouseup($event)\"\n width=\"200\"\n height=\"235\"\n ></canvas>\n <ngx-mat-color-slider (colorChanged)=\"onSliderColorChanged($event)\" />\n </div>\n\n <div class=\"zone-inputs\">\n <mat-form-field [color]=\"theme\">\n <mat-label>R</mat-label>\n <input\n matInput\n formControlName=\"r\"\n ngxMatNumericColorInput\n autocomplete=\"off\"\n />\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>G</mat-label>\n <input\n matInput\n formControlName=\"g\"\n ngxMatNumericColorInput\n autocomplete=\"off\"\n />\n </mat-form-field>\n\n <mat-form-field [color]=\"theme\">\n <mat-label>B</mat-label>\n <input\n matInput\n formControlName=\"b\"\n ngxMatNumericColorInput\n autocomplete=\"off\"\n />\n </mat-form-field>\n </div>\n </div>\n\n <div class=\"color-canvas-row\">\n <button\n mat-mini-fab\n [style.background-color]=\"color()?.rgba || 'transparent'\"\n class=\"preview\"\n ></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\n matInput\n formControlName=\"a\"\n type=\"number\"\n min=\"0\"\n max=\"1\"\n step=\"0.1\"\n autocomplete=\"off\"\n />\n </mat-form-field>\n </div>\n</form>\n", 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 { constructor() { this.colorChanged = output(); this.selectedColor = signal(''); this.colors1 = BASIC_COLORS.slice(0, 8); this.colors2 = BASIC_COLORS.slice(8, 16); } set color(c) { if (c) { this.selectedColor.set(c.toHexString()); } } select(hex) { this.selectedColor.set(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: "20.0.0", ngImport: i0, type: NgxMatColorCollectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: NgxMatColorCollectionComponent, isStandalone: true, 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 @for (c of colors1; track c) {\n <button\n mat-mini-fab\n [style.background-color]=\"c\"\n class=\"btn-color\"\n (click)=\"select(c)\"\n [ngClass]=\"{ active: selectedColor() === c }\"\n [disableRipple]=\"true\"></button>\n }\n</div>\n<div class=\"color-collection-row\">\n @for (c of colors2; track c) {\n <button\n mat-mini-fab\n [style.background-color]=\"c\"\n class=\"btn-color\"\n (click)=\"select(c)\"\n [ngClass]=\"{ active: selectedColor() === c }\"\n [disableRipple]=\"true\"></button>\n }\n</div>\n", 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: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: NgxMatColorCollectionComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-mat-color-collection', encapsulation: ViewEncapsulation.None, host: { class: 'ngx-mat-color-collection', }, imports: [MatButtonModule, NgClass], template: "<div class=\"color-collection-row\">\n @for (c of colors1; track c) {\n <button\n mat-mini-fab\n [style.background-color]=\"c\"\n class=\"btn-color\"\n (click)=\"select(c)\"\n [ngClass]=\"{ active: selectedColor() === c }\"\n [disableRipple]=\"true\"></button>\n }\n</div>\n<div class=\"color-collection-row\">\n @for (c of colors2; track c) {\n <button\n mat-mini-fab\n [style.background-color]=\"c\"\n class=\"btn-color\"\n (click)=\"select(c)\"\n [ngClass]=\"{ active: selectedColor() === c }\"\n [disableRipple]=\"true\"></button>\n }\n</div>\n", 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"] }] }], propDecorators: { color: [{ type: Input }] } }); class NgxMatColorPaletteComponent { constructor() { this.colorChanged = output(); this.color = input(); this.theme = input(); } handleColorChanged(color) { this.colorChanged.emit(color); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: NgxMatColorPaletteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.0", type: NgxMatColorPaletteComponent, isStandalone: true, selector: "ngx-mat-color-palette", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { colorChanged: "colorChanged" }, host: { classAttribute: "ngx-mat-color-palette" }, ngImport: i0, template: "<ngx-mat-color-canvas\n (colorChanged)=\"handleColorChanged($event)\"\n [color]=\"color()\"\n [theme]=\"theme()\"\n/>\n\n<ngx-mat-color-collection\n (colorChanged)=\"handleColorChanged($event)\"\n [color]=\"color()\"\n/>\n", 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: NgxMatColorCollectionComponent, selector: "ngx-mat-color-collection", inputs: ["color"], outputs: ["colorChanged"] }, { kind: "component", type: NgxMatColorCanvasComponent, selector: "ngx-mat-color-canvas" }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: NgxMatColorPaletteComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-mat-color-palette', encapsulation: ViewEncapsulation.None, host: { class: 'ngx-mat-color-palette', }, imports: [NgxMatColorCollectionComponent, NgxMatColorCanvasComponent], template: "<ngx-mat-color-canvas\n (colorChanged)=\"handleColorChanged($event)\"\n [color]=\"color()\"\n [theme]=\"theme()\"\n/>\n\n<ngx-mat-color-collection\n (colorChanged)=\"handleColorChanged($event)\"\n [color]=\"color()\"\n/>\n", 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"] }] }] }); class ColorAdapter { 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: "20.0.0", ngImport: i0, type: ColorAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ColorAdapter }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ColorAdapter, decorators: [{ type: Injectable }] }); 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, }; class NgxMatColorPickerContentComponent { constructor() { /** Reference to the internal calendar component. */ this._palette = viewChild(NgxMatColorPaletteComponent); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: NgxMatColorPickerContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.0", type: NgxMatColorPickerContentComponent, isStandalone: true, 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, isSignal: true }], exportAs: ["ngxMatColorPickerContent"], ngImport: i0, template: "<ngx-mat-color-palette\n (colorChanged)=\"picker.select($event)\"\n [color]=\"picker._selected\"\n [theme]=\"color\"></ngx-mat-color-palette>\n", 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: "20.0.0", 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'], imports: [NgxMatColorPaletteComponent], template: "<ngx-mat-color-palette\n (colorChanged)=\"picker.select($event)\"\n [color]=\"picker._selected\"\n [theme]=\"color\"></ngx-mat-color-palette>\n", 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: () => [] }); 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; } get isPrimary() { return this.color === 'primary'; } get isAccent() { return this.color === 'accent'; } get isWarn() { return this.color === 'warn'; } /** 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 EventEmitter(); /** 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; } 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') { // Because IE moves focus asynchronously, we can't count on it being restored before we've // marked the datepicker as closed. If the event fires out of sequence and the element that // we're refocusing opens the datepicker on focus, t