UNPKG

@vipstorage/material-color-picker

Version:
1 lines 102 kB
{"version":3,"file":"vipstorage-material-color-picker.mjs","sources":["../../../../projects/color-picker/src/lib/helpers/color-helpers.ts","../../../../projects/color-picker/src/lib/models/color.model.ts","../../../../projects/color-picker/src/lib/components/color-canvas/base-color-canvas.ts","../../../../projects/color-picker/src/lib/components/color-canvas/color-slider/color-slider.component.ts","../../../../projects/color-picker/src/lib/components/color-canvas/color-slider/color-slider.component.html","../../../../projects/color-picker/src/lib/directives/numeric-color-input.directive.ts","../../../../projects/color-picker/src/lib/components/color-canvas/color-canvas.component.ts","../../../../projects/color-picker/src/lib/components/color-canvas/color-canvas.component.html","../../../../projects/color-picker/src/lib/components/color-collection/color-collection.component.ts","../../../../projects/color-picker/src/lib/components/color-collection/color-collection.component.html","../../../../projects/color-picker/src/lib/components/color-palette/color-palette.component.ts","../../../../projects/color-picker/src/lib/components/color-palette/color-palette.component.html","../../../../projects/color-picker/src/lib/services/color-adapter.ts","../../../../projects/color-picker/src/lib/services/color-formats.ts","../../../../projects/color-picker/src/lib/components/color-picker/color-picker.component.ts","../../../../projects/color-picker/src/lib/components/color-picker/color-picker-content.component.html","../../../../projects/color-picker/src/lib/components/color-picker/color-input.component.ts","../../../../projects/color-picker/src/lib/components/color-toggle/color-toggle.component.ts","../../../../projects/color-picker/src/lib/components/color-toggle/color-toggle.component.html","../../../../projects/color-picker/src/lib/color-picker.module.ts","../../../../projects/color-picker/src/public-api.ts","../../../../projects/color-picker/src/vipstorage-material-color-picker.ts"],"sourcesContent":["\nconst trimLeft = /^\\s+/;\nconst trimRight = /\\s+$/;\nconst tinyCounter = 0;\nconst mathRound = Math.round;\nconst mathMin = Math.min;\nconst mathMax = Math.max;\nconst mathRandom = Math.random;\n\nexport const NUMERIC_REGEX = /[^0-9]/g;\nexport const MAX_RGB = 255;\nexport const MIN_RGB = 0;\n\n\n/** List basic colors */\nexport const BASIC_COLORS = [\"#ffffff\", \"#ffff00\", \"#ff00ff\", \"#ff0000\",\n \"#c0c0c0\", \"#808080\", \"#808000\", \"#800080\",\n \"#800000\", \"#00ffff\", \"#00ff00\", \"#008080\",\n \"#008000\", \"#0000ff\", \"#000080\", \"#000000\"\n];\n\n/**\n * Get color at position\n * @param ctx \n * @param x \n * @param y \n */\nexport function getColorAtPosition(ctx: CanvasRenderingContext2D, x: number, y: number): { r: number, g: number, b: number } {\n const imageData: Uint8ClampedArray = ctx.getImageData(x, y, 1, 1).data;\n return { r: imageData[0], g: imageData[1], b: imageData[2] };\n}\n\n// `rgbaToHex`\n// Converts an RGBA color plus alpha transparency to hex\n// Assumes r, g, b are contained in the set [0, 255] and\n// a in [0, 1]. Returns a 4 or 8 character rgba hex\nexport function rgbaToHex(r: number, g: number, b: number, a: number, allow4Char?: boolean): string {\n var hex = [\n pad2(mathRound(r).toString(16)),\n pad2(mathRound(g).toString(16)),\n pad2(mathRound(b).toString(16)),\n pad2(convertDecimalToHex(a))\n ];\n\n // Return a 4 character hex if possible\n 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)) {\n return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);\n }\n\n return hex.join(\"\");\n}\n\n// Force a hex value to have 2 characters\nexport function pad2(c): string {\n return c.length == 1 ? '0' + c : '' + c;\n}\n\n// Converts a decimal to a hex value\nexport function convertDecimalToHex(d) {\n return Math.round(parseFloat(d) * 255).toString(16);\n}\n\n// Converts a hex value to a decimal\nfunction convertHexToDecimal(h) {\n return (parseIntFromHex(h) / 255);\n}\n\n// Parse a base-16 hex value into a base-10 integer\nfunction parseIntFromHex(val) {\n return parseInt(val, 16);\n}\n\n// `rgbToHex`\n// Converts an RGB color to hex\n// Assumes r, g, and b are contained in the set [0, 255]\n// Returns a 3 or 6 character hex\nexport function rgbToHex(r: number, g: number, b: number, allow3Char?: boolean) {\n\n var hex = [\n pad2(mathRound(r).toString(16)),\n pad2(mathRound(g).toString(16)),\n pad2(mathRound(b).toString(16))\n ];\n\n // Return a 3 character hex if possible\n 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)) {\n return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);\n }\n\n return hex.join(\"\");\n}\n\n// Actual matching.\n// Parentheses and commas are optional, but not required.\n// Whitespace can take the place of commas or opening parent\nconst CSS_INTEGER = \"[-\\\\+]?\\\\d+%?\";\nconst CSS_NUMBER = \"[-\\\\+]?\\\\d*\\\\.\\\\d+%?\";\nconst CSS_UNIT = \"(?:\" + CSS_NUMBER + \")|(?:\" + CSS_INTEGER + \")\";\nconst PERMISSIVE_MATCH3 = \"[\\\\s|\\\\(]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")\\\\s*\\\\)?\";\nconst PERMISSIVE_MATCH4 = \"[\\\\s|\\\\(]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")\\\\s*\\\\)?\";\n\nexport const matchers = {\n CSS_UNIT: new RegExp(CSS_UNIT),\n rgb: new RegExp(\"rgb\" + PERMISSIVE_MATCH3),\n rgba: new RegExp(\"rgba\" + PERMISSIVE_MATCH4),\n hsl: new RegExp(\"hsl\" + PERMISSIVE_MATCH3),\n hsla: new RegExp(\"hsla\" + PERMISSIVE_MATCH4),\n hsv: new RegExp(\"hsv\" + PERMISSIVE_MATCH3),\n hsva: new RegExp(\"hsva\" + PERMISSIVE_MATCH4),\n hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,\n hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,\n hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,\n hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/\n};\n\n// `stringInputToObject`\n// Permissive string parsing. Take in a number of formats, and output an object\n// based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`\nexport function stringInputToObject(color: string): { r: number, g: number, b: number, a: number } {\n\n color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();\n\n // Try to match string input using regular expressions.\n // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]\n // Just return an object and let the conversion functions handle that.\n // This way the result will be the same whether the tinycolor is initialized with string or object.\n let match;\n let obj;\n if ((match = matchers.rgb.exec(color))) {\n return { r: match[1], g: match[2], b: match[3], a: 1 };\n }\n if ((match = matchers.rgba.exec(color))) {\n return { r: match[1], g: match[2], b: match[3], a: match[4] };\n }\n\n if ((match = matchers.hex8.exec(color))) {\n return {\n r: parseIntFromHex(match[1]),\n g: parseIntFromHex(match[2]),\n b: parseIntFromHex(match[3]),\n a: convertHexToDecimal(match[4]),\n };\n }\n if ((match = matchers.hex6.exec(color))) {\n return {\n r: parseIntFromHex(match[1]),\n g: parseIntFromHex(match[2]),\n b: parseIntFromHex(match[3]),\n a: 1\n };\n }\n if ((match = matchers.hex4.exec(color))) {\n return {\n r: parseIntFromHex(match[1] + '' + match[1]),\n g: parseIntFromHex(match[2] + '' + match[2]),\n b: parseIntFromHex(match[3] + '' + match[3]),\n a: convertHexToDecimal(match[4] + '' + match[4]),\n };\n }\n if ((match = matchers.hex3.exec(color))) {\n return {\n r: parseIntFromHex(match[1] + '' + match[1]),\n g: parseIntFromHex(match[2] + '' + match[2]),\n b: parseIntFromHex(match[3] + '' + match[3]),\n a: 1\n };\n }\n\n return null;\n}\n\nexport function createMissingDateImplError(provider: string) {\n return Error(\n `NgxMatColorPicker: No provider found for ${provider}. You must define MAT_COLOR_FORMATS in your module`);\n}","import { MAX_RGB, rgbaToHex, rgbToHex } from '../helpers';\nimport { ColorInputFormat } from './color-input-format';\n\nexport class Color {\n\n public r: number;\n public g: number;\n public b: number;\n public a: number;\n public roundA: number;\n\n public hex: string;\n public rgba: string;\n\n constructor(_r: number, _g: number, _b: number, _a?: number) {\n this.r = _r > MAX_RGB ? MAX_RGB : _r;\n this.g = _g > MAX_RGB ? MAX_RGB : _g;\n this.b = _b > MAX_RGB ? MAX_RGB : _b;\n if (_a != null) {\n this.a = _a > 1 ? 1 : _a;\n } else {\n this.a = 1;\n }\n this.roundA = Math.round(this.a);\n this.hex = rgbToHex(this.r, this.g, this.b);\n this.rgba = this.toRgba();\n }\n\n public toHex(allow3Char?: boolean, ): string {\n return rgbToHex(this.r, this.g, this.b, allow3Char);\n }\n\n public toRgba(): string {\n return `rgba(${this.r},${this.g},${this.b},${this.a})`;\n }\n\n public toHexString(allow3Char?: boolean): string {\n return '#' + this.toHex(allow3Char);\n }\n\n public toRgbString(): string {\n return (this.a === 1) ?\n \"rgb(\" + Math.round(this.r) + \", \" + Math.round(this.g) + \", \" + Math.round(this.b) + \")\" :\n \"rgba(\" + Math.round(this.r) + \", \" + Math.round(this.g) + \", \" + Math.round(this.b) + \", \" + this.roundA + \")\";\n }\n\n public toHex8(allow4Char): string {\n return rgbaToHex(this.r, this.g, this.b, this.a, allow4Char);\n }\n\n public toHex8String(allow4Char?: boolean): string {\n return '#' + this.toHex8(allow4Char);\n }\n\n public toString(format: ColorInputFormat): string {\n let formatSet = !!format;\n\n let formattedString;\n let hasAlpha = this.a < 1 && this.a >= 0;\n let needsAlphaFormat = !formatSet && hasAlpha && (format === \"hex\" || format === \"hex6\"\n || format === \"hex3\" || format === \"hex4\" || format === \"hex8\");\n\n if (needsAlphaFormat) {\n return this.toRgbString();\n }\n if (format === \"rgb\") {\n formattedString = this.toRgbString();\n }\n if (format === \"hex\" || format === \"hex6\") {\n formattedString = this.toHexString();\n }\n if (format === \"hex3\") {\n formattedString = this.toHexString(true);\n }\n if (format === \"hex4\") {\n formattedString = this.toHex8String(true);\n }\n if (format === \"hex8\") {\n formattedString = this.toHex8String();\n }\n\n return formattedString || this.toHexString();\n }\n\n}","import { AfterViewInit, Directive, EventEmitter, Input, NgZone, OnDestroy, Output } from '@angular/core';\nimport { ThemePalette } from '@angular/material/core';\nimport { Subject } from 'rxjs';\nimport { Color } from '../../models';\n\n@Directive({\n\n})\nexport abstract class NgxMatBaseColorCanvas implements OnDestroy, AfterViewInit {\n\n\t@Output() colorChanged: EventEmitter<Color> = new EventEmitter<Color>();\n\t@Input() color: Color;\n\t@Input() theme: ThemePalette;\n\n\tcanvas: HTMLCanvasElement;\n\n\telementId: string;\n\n\tctx: CanvasRenderingContext2D;\n\twidth: number;\n\theight: number;\n\n\tx: number = 0;\n\ty: number = 0;\n\n\tdrag = false;\n\n\tprotected _destroyed: Subject<void> = new Subject<void>();\n\n\tconstructor(protected zone: NgZone, elementId: string) {\n\t\tthis.elementId = elementId;\n\t}\n\n\tngOnDestroy(): void {\n\t\tthis._destroyed.next();\n\t\tthis._destroyed.complete();\n\t}\n\n\tngAfterViewInit(): void {\n\t\tthis.canvas = <HTMLCanvasElement>document.getElementById(this.elementId);\n\t\tthis.ctx = this.canvas.getContext('2d');\n\t\tthis.width = this.canvas.width;\n\t\tthis.height = this.canvas.height;\n\t\tthis.draw();\n\t}\n\n\tprotected draw() {\n\t\tthis.ctx.clearRect(0, 0, this.width, this.height);\n\t\tthis.ctx.rect(0, 0, this.width, this.height);\n\t\tthis.fillGradient();\n\t\tif (this.y != 0) {\n\t\t\tthis.redrawIndicator(this.x, this.y);\n\t\t}\n\t}\n\n\n\tpublic onMousedown(e: MouseEvent) {\n\t\tthis.drag = true;\n\t\tthis.changeColor(e);\n\n\t\tthis.zone.runOutsideAngular(() => {\n\t\t\tthis.canvas.addEventListener('mousemove', this.onMousemove.bind(this));\n\t\t})\n\t}\n\n\tpublic onMousemove(e: MouseEvent) {\n\t\tif (this.drag) {\n\t\t\tthis.zone.run(() => {\n\t\t\t\tthis.changeColor(e);\n\t\t\t})\n\t\t}\n\t}\n\n\tpublic onMouseup(e: MouseEvent) {\n\t\tthis.drag = false;\n\t\tthis.canvas.removeEventListener('mousemove', this.onMousemove);\n\t}\n\n\tpublic emitChange(color: Color) {\n\t\tthis.colorChanged.emit(color);\n\t}\n\n\tabstract changeColor(e: MouseEvent): void;\n\tabstract fillGradient(): void;\n\tabstract redrawIndicator(x: number, y: number): void;\n\n}\n","import { Component, OnInit, Output, EventEmitter, NgZone } from '@angular/core';\nimport { Color } from '../../../models';\nimport { getColorAtPosition } from '../../../helpers';\nimport { NgxMatBaseColorCanvas } from '../base-color-canvas';\n\n@Component({\n selector: 'ngx-mat-color-slider',\n templateUrl: './color-slider.component.html',\n styleUrls: ['./color-slider.component.scss']\n})\nexport class NgxMatColorSliderComponent extends NgxMatBaseColorCanvas implements OnInit {\n\n constructor(protected zone: NgZone) {\n super(zone,'color-strip');\n }\n\n ngOnInit() {\n\n }\n\n ngAfterViewInit(): void {\n super.ngAfterViewInit();\n }\n\n public fillGradient() {\n const grd = this.ctx.createLinearGradient(0, 0, 0, this.height);\n grd.addColorStop(0, 'rgba(255, 0, 0, 1)');\n grd.addColorStop(0.17, 'rgba(255, 255, 0, 1)');\n grd.addColorStop(0.34, 'rgba(0, 255, 0, 1)');\n grd.addColorStop(0.51, 'rgba(0, 255, 255, 1)');\n grd.addColorStop(0.68, 'rgba(0, 0, 255, 1)');\n grd.addColorStop(0.85, 'rgba(255, 0, 255, 1)');\n grd.addColorStop(1, 'rgba(255, 0, 0, 1)');\n\n this.ctx.fillStyle = grd;\n this.ctx.fill();\n }\n\n public redrawIndicator(x: number, y: number) {\n this.ctx.beginPath();\n this.ctx.strokeStyle = 'white';\n this.ctx.lineWidth = 2;\n this.ctx.arc(7.5, y, 7.5, 0, 2 * Math.PI, false);\n this.ctx.stroke();\n this.ctx.closePath();\n }\n\n public changeColor(e: MouseEvent) {\n this.x = e.offsetX;\n this.y = e.offsetY;\n this.draw();\n const { r, g, b } = getColorAtPosition(this.ctx, e.offsetX, e.offsetY);\n this.emitChange(new Color(r, g, b));\n }\n\n\n}\n","<canvas id=\"color-strip\" class=\"zone-strip\" (mousedown)=\"onMousedown($event)\" (mouseup)=\"onMouseup($event)\"\n width=\"15\" height=\"234\"></canvas>","import { Directive, HostListener } from '@angular/core';\nimport { NUMERIC_REGEX } from '../helpers';\n\n@Directive({\n selector: '[ngxMatNumericColorInput]'\n})\nexport class NumericColorInputDirective {\n\n constructor() { }\n\n @HostListener('input', ['$event'])\n onInput($event: any) {\n this._formatInput($event.target);\n }\n\n /**\n* Format input\n* @param input \n*/\n private _formatInput(input: any) {\n let val = Number(input.value.replace(NUMERIC_REGEX, ''));\n val = isNaN(val) ? 0 : val;\n input.value = val;\n }\n\n}\n","import { AfterViewInit, Component, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';\nimport { merge } from 'rxjs';\nimport { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';\nimport { getColorAtPosition, matchers, stringInputToObject } from '../../helpers';\nimport { Color } from '../../models';\nimport { NgxMatBaseColorCanvas } from './base-color-canvas';\n\nconst RADIUS_NOB = 5;\n\n@Component({\n selector: 'ngx-mat-color-canvas',\n templateUrl: './color-canvas.component.html',\n styleUrls: ['./color-canvas.component.scss'],\n encapsulation: ViewEncapsulation.None,\n host: {\n 'class': 'ngx-mat-color-canvas'\n }\n})\nexport class NgxMatColorCanvasComponent extends NgxMatBaseColorCanvas\n implements OnInit, AfterViewInit, OnChanges, OnDestroy {\n\n private _baseColor: Color;\n\n get rCtrl(): AbstractControl {\n return this.formGroup.get('r');\n }\n\n get gCtrl(): AbstractControl {\n return this.formGroup.get('g');\n }\n\n get bCtrl(): AbstractControl {\n return this.formGroup.get('b');\n }\n\n get aCtrl(): AbstractControl {\n return this.formGroup.get('a');\n }\n\n get hexCtrl(): AbstractControl {\n return this.formGroup.get('hex');\n }\n\n _resetBaseColor = true;\n\n formGroup: FormGroup;\n\n rgba: string;\n\n constructor(protected zone: NgZone) {\n super(zone, 'color-block');\n this.formGroup = new FormGroup({\n r: new FormControl(null, [Validators.required]),\n g: new FormControl(null, [Validators.required]),\n b: new FormControl(null, [Validators.required]),\n a: new FormControl(null, [Validators.required]),\n hex: new FormControl(null, [Validators.required, Validators.pattern(matchers.hex6)]),\n });\n }\n\n ngOnInit() {\n\n const rgbaCtrl$ = merge(this.rCtrl.valueChanges, this.gCtrl.valueChanges,\n this.bCtrl.valueChanges, this.aCtrl.valueChanges);\n rgbaCtrl$.pipe(takeUntil(this._destroyed), debounceTime(400))\n .subscribe(_ => {\n const color = new Color(Number(this.rCtrl.value),\n Number(this.gCtrl.value), Number(this.bCtrl.value), Number(this.aCtrl.value));\n this.emitChange(color);\n });\n\n const hexCtrl$ = this.hexCtrl.valueChanges;\n hexCtrl$.pipe(takeUntil(this._destroyed), debounceTime(400), distinctUntilChanged())\n .subscribe(hex => {\n const obj = stringInputToObject(hex);\n if (obj != null) {\n const color = new Color(obj.r, obj.g, obj.b, obj.a);\n this.emitChange(color);\n }\n })\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.color && changes.color.currentValue) {\n this.updateForm(changes.color.currentValue);\n if (this._resetBaseColor) {\n this._baseColor = changes.color.currentValue;\n }\n\n this._resetBaseColor = true;\n\n if (!changes.color.firstChange) {\n this.draw();\n }\n }\n }\n\n private updateForm(val: Color): void {\n const config = { emitEvent: false };\n this.rCtrl.setValue(val.r, config);\n this.gCtrl.setValue(val.g, config);\n this.bCtrl.setValue(val.b, config);\n this.aCtrl.setValue(val.a, config);\n this.hexCtrl.setValue(val.hex, config);\n }\n\n public redrawIndicator(x: number, y: number) {\n this.ctx.beginPath();\n this.ctx.strokeStyle = 'white';\n this.ctx.arc(x, y, RADIUS_NOB, 0, 2 * Math.PI, false);\n this.ctx.stroke();\n this.ctx.closePath();\n }\n\n public fillGradient() {\n this.ctx.fillStyle = this._baseColor ? this._baseColor.rgba : 'rgba(255,255,255,1)';\n this.ctx.fillRect(0, 0, this.width, this.height);\n\n const grdWhite = this.ctx.createLinearGradient(0, 0, this.width, 0);\n grdWhite.addColorStop(0, 'rgba(255,255,255,1)');\n grdWhite.addColorStop(1, 'rgba(255,255,255,0)');\n this.ctx.fillStyle = grdWhite;\n this.ctx.fillRect(0, 0, this.width, this.height);\n\n const grdBlack = this.ctx.createLinearGradient(0, 0, 0, this.height);\n grdBlack.addColorStop(0, 'rgba(0,0,0,0)');\n grdBlack.addColorStop(1, 'rgba(0,0,0,1)');\n this.ctx.fillStyle = grdBlack;\n this.ctx.fillRect(0, 0, this.width, this.height);\n }\n\n public onSliderColorChanged(c: Color) {\n this._baseColor = c;\n this.color = c;\n this.fillGradient();\n this.emitChange(c);\n }\n\n public changeColor(e: MouseEvent): void {\n this.x = e.offsetX;\n this.y = e.offsetY;\n this._resetBaseColor = false;\n this.draw();\n const { r, g, b } = getColorAtPosition(this.ctx, e.offsetX, e.offsetY);\n this.emitChange(new Color(r, g, b));\n }\n\n}\n","<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>","import { Component, EventEmitter, OnInit, Output, ViewEncapsulation, Input } from '@angular/core';\nimport { Color } from '../../models';\nimport { BASIC_COLORS, stringInputToObject } from '../../helpers';\n\n@Component({\n selector: 'ngx-mat-color-collection',\n templateUrl: './color-collection.component.html',\n styleUrls: ['./color-collection.component.scss'],\n encapsulation: ViewEncapsulation.None,\n host: {\n 'class': 'ngx-mat-color-collection'\n }\n})\nexport class NgxMatColorCollectionComponent implements OnInit {\n\n @Output() colorChanged: EventEmitter<Color> = new EventEmitter<Color>();\n\n @Input()\n set color(c: Color) {\n if (c) {\n this.selectedColor = c.toHexString();\n }\n }\n\n selectedColor: string;\n\n colors1: string[] = BASIC_COLORS.slice(0, 8);\n colors2: string[] = BASIC_COLORS.slice(8, 16);\n\n constructor() { }\n\n ngOnInit() {\n }\n\n select(hex: string) {\n this.selectedColor = hex;\n const { r, g, b, a } = stringInputToObject(hex);\n this.colorChanged.emit(new Color(r, g, b, a));\n }\n\n}\n","<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>","import { Component, OnInit, ViewEncapsulation, Output, EventEmitter, Input } from '@angular/core';\nimport { Color } from '../../models';\nimport { ThemePalette } from '@angular/material/core';\n\n@Component({\n selector: 'ngx-mat-color-palette',\n templateUrl: 'color-palette.component.html',\n styleUrls: ['color-palette.component.scss'],\n encapsulation: ViewEncapsulation.None,\n host: {\n 'class': 'ngx-mat-color-palette'\n }\n})\nexport class NgxMatColorPaletteComponent implements OnInit {\n\n @Output() colorChanged: EventEmitter<Color> = new EventEmitter<Color>();\n\n @Input() color: Color;\n @Input() theme: ThemePalette;\n\n constructor() { }\n\n ngOnInit() {\n }\n\n public handleColorChanged(color: Color) {\n this.colorChanged.emit(color);\n }\n\n}\n","<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>","import { Injectable } from '@angular/core';\nimport { stringInputToObject } from '../helpers';\nimport { Color, ColorInputFormat } from '../models';\n\n@Injectable()\nexport class ColorAdapter {\n\n constructor() { }\n\n sameColor(a: Color, b: Color) {\n if (a == null && b == null) return true;\n if (a != null && b != null) return a.rgba === b.rgba;\n return false;\n }\n\n format(c: Color, format: ColorInputFormat): string {\n return c.toString(format);\n }\n\n parse(value: string): Color | null {\n const obj = stringInputToObject(value);\n if (obj) {\n return new Color(obj.r, obj.g, obj.b, obj.a);\n }\n return null;\n }\n\n}\n","import { InjectionToken } from '@angular/core';\nimport { ColorInputFormat } from '../models';\n\nexport type MatColorFormats = {\n display: {\n colorInput: ColorInputFormat;\n }\n}\n\nexport const NGX_MAT_COLOR_FORMATS: MatColorFormats = {\n display: {\n colorInput: 'hex'\n }\n}\n\nexport const MAT_COLOR_FORMATS = new InjectionToken<MatColorFormats>('mat-color-formats');\n","import { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ESCAPE, UP_ARROW } from '@angular/cdk/keycodes';\nimport { Overlay, OverlayConfig, OverlayRef, PositionStrategy, ScrollStrategy } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { DOCUMENT } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, ComponentRef, ElementRef, EventEmitter, Inject, InjectionToken, Input, NgZone, OnDestroy, OnInit, Optional, Output, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';\nimport { CanColor, ThemePalette, mixinColor } from '@angular/material/core';\nimport { matDatepickerAnimations } from '@angular/material/datepicker';\nimport { MatDialog, MatDialogRef } from '@angular/material/dialog';\nimport { Subject, Subscription, merge } from 'rxjs';\nimport { filter, take } from 'rxjs/operators';\nimport { Color } from '../../models';\nimport { ColorAdapter } from '../../services';\nimport { NgxMatColorPaletteComponent } from '../color-palette/color-palette.component';\nimport { NgxMatColorPickerInput } from './color-input.component';\n\n/** Injection token that determines the scroll handling while the calendar is open. */\nexport const NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY =\n new InjectionToken<() => ScrollStrategy>('ngx-mat-colorpicker-scroll-strategy');\n\n\nexport function NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy {\n return () => overlay.scrollStrategies.reposition();\n}\n\n\nexport const NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY_FACTORY_PROVIDER = {\n provide: NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY,\n deps: [Overlay],\n useFactory: NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY_FACTORY,\n};\n\nconst _MatColorpickerContentBase = mixinColor(\n class {\n constructor(public _elementRef: ElementRef) { }\n },\n);\n\n\n@Component({\n selector: 'ngx-mat-color-picker-content',\n templateUrl: './color-picker-content.component.html',\n styleUrls: ['color-picker-content.component.scss'],\n host: {\n 'class': 'ngx-mat-colorpicker-content',\n '[@transformPanel]': '\"enter\"',\n '[class.ngx-mat-colorpicker-content-touch]': 'picker.touchUi',\n },\n animations: [\n matDatepickerAnimations.transformPanel,\n matDatepickerAnimations.fadeInCalendar,\n ],\n exportAs: 'ngxMatColorPickerContent',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n inputs: ['color']\n})\nexport class NgxMatColorPickerContentComponent extends _MatColorpickerContentBase\n implements CanColor {\n\n /** Reference to the internal calendar component. */\n @ViewChild(NgxMatColorPaletteComponent) _palette: NgxMatColorPaletteComponent;\n\n picker: NgxMatColorPickerComponent;\n _isAbove: boolean;\n\n constructor(elementRef: ElementRef) {\n super(elementRef);\n }\n\n}\n\n@Component({\n selector: 'ngx-mat-color-picker',\n template: '',\n exportAs: 'ngxMatColorPicker',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class NgxMatColorPickerComponent implements OnInit, OnDestroy, CanColor {\n\n private _scrollStrategy: () => ScrollStrategy;\n\n /** Emits when the datepicker has been opened. */\n @Output('opened') openedStream: EventEmitter<void> = new EventEmitter<void>();\n\n /** Emits when the datepicker has been closed. */\n @Output('closed') closedStream: EventEmitter<void> = new EventEmitter<void>();\n\n @Input() get disabled() {\n return this._disabled === undefined && this._pickerInput ?\n this._pickerInput.disabled : !!this._disabled;\n }\n set disabled(value: boolean) {\n const newValue = coerceBooleanProperty(value);\n\n if (newValue !== this._disabled) {\n this._disabled = newValue;\n this._disabledChange.next(newValue);\n }\n }\n private _disabled: boolean;\n\n @Input()\n get touchUi(): boolean { return this._touchUi; }\n set touchUi(value: boolean) {\n this._touchUi = coerceBooleanProperty(value);\n }\n private _touchUi = false;\n\n /** Whether the calendar is open. */\n @Input()\n get opened(): boolean { return this._opened; }\n set opened(value: boolean) { value ? this.open() : this.close(); }\n private _opened = false;\n\n /** Default Color palette to use on the datepicker's calendar. */\n @Input()\n get defaultColor(): ThemePalette {\n return this._defaultColor;\n }\n set defaultColor(value: ThemePalette) {\n this._defaultColor = value;\n }\n _defaultColor: ThemePalette = 'primary';\n\n /** Color palette to use on the datepicker's calendar. */\n @Input()\n get color(): ThemePalette {\n return this._color ||\n (this._pickerInput ? this._pickerInput.getThemePalette() : undefined);\n }\n set color(value: ThemePalette) {\n this._color = value;\n }\n _color: ThemePalette;\n\n\n /** The currently selected date. */\n get _selected(): Color { return this._validSelected; }\n set _selected(value: Color) { this._validSelected = value; }\n private _validSelected: Color = null;\n\n\n _pickerInput: NgxMatColorPickerInput;\n /** A reference to the overlay when the picker is opened as a popup. */\n _popupRef: OverlayRef;\n\n /** A reference to the dialog when the picker is opened as a dialog. */\n private _dialogRef: MatDialogRef<NgxMatColorPickerContentComponent> | null;\n /** Reference to the component instantiated in popup mode. */\n private _popupComponentRef: ComponentRef<NgxMatColorPickerContentComponent> | null;\n /** A portal containing the content for this picker. */\n private _portal: ComponentPortal<NgxMatColorPickerContentComponent>;\n\n /** Emits when the datepicker is disabled. */\n readonly _disabledChange = new Subject<boolean>();\n\n /** The element that was focused before the datepicker was opened. */\n private _focusedElementBeforeOpen: HTMLElement | null = null;\n\n /** Subscription to value changes in the associated input element. */\n private _inputSubscription = Subscription.EMPTY;\n\n /** Emits new selected date when selected date changes. */\n readonly _selectedChanged = new Subject<Color>();\n\n constructor(private _dialog: MatDialog,\n private _overlay: Overlay,\n private _zone: NgZone,\n private _adapter: ColorAdapter,\n @Optional() private _dir: Directionality,\n @Inject(NGX_MAT_COLOR_PICKER_SCROLL_STRATEGY) scrollStrategy: any,\n @Optional() @Inject(DOCUMENT) private _document: any,\n private _viewContainerRef: ViewContainerRef) {\n this._scrollStrategy = scrollStrategy;\n }\n\n ngOnInit() {\n }\n\n ngOnDestroy() {\n this.close();\n this._inputSubscription.unsubscribe();\n this._disabledChange.complete();\n\n if (this._popupRef) {\n this._popupRef.dispose();\n this._popupComponentRef = null;\n }\n }\n\n\n /** Selects the given date */\n select(nextVal: Color): void {\n let oldValue = this._selected;\n this._selected = nextVal;\n if (!this._adapter.sameColor(oldValue, this._selected)) {\n this._selectedChanged.next(nextVal);\n }\n }\n\n\n /**\n * Register an input with this datepicker.\n * @param input The datepicker input to register with this datepicker.\n */\n registerInput(input: NgxMatColorPickerInput): void {\n if (this._pickerInput) {\n throw Error('A ColorPicker can only be associated with a single input.');\n }\n this._pickerInput = input;\n this._inputSubscription =\n this._pickerInput._valueChange.subscribe((value: Color) => this._selected = value);\n }\n\n public open(): void {\n if (this._opened || this.disabled) {\n return;\n }\n if (!this._pickerInput) {\n throw Error('Attempted to open an ColorPicker with no associated input.');\n }\n\n if (this._document) {\n this._focusedElementBeforeOpen = this._document.activeElement;\n }\n\n this.touchUi ? this._openAsDialog() : this._openAsPopup();\n this._opened = true;\n this.openedStream.emit();\n }\n\n /** Open the calendar as a dialog. */\n private _openAsDialog(): void {\n\n if (this._dialogRef) {\n this._dialogRef.close();\n }\n\n this._dialogRef = this._dialog.open<NgxMatColorPickerContentComponent>(NgxMatColorPickerContentComponent, {\n direction: this._dir ? this._dir.value : 'ltr',\n viewContainerRef: this._viewContainerRef,\n panelClass: 'ngx-mat-colorpicker-dialog',\n });\n\n this._dialogRef.afterClosed().subscribe(() => this.close());\n this._dialogRef.componentInstance.picker = this;\n this._setColor();\n }\n\n /** Open the calendar as a popup. */\n private _openAsPopup(): void {\n\n if (!this._portal) {\n this._portal = new ComponentPortal<NgxMatColorPickerContentComponent>(NgxMatColorPickerContentComponent,\n this._viewContainerRef);\n }\n\n if (!this._popupRef) {\n this._createPopup();\n }\n\n if (!this._popupRef.hasAttached()) {\n this._popupComponentRef = this._popupRef.attach(this._portal);\n this._popupComponentRef.instance.picker = this;\n this._setColor();\n\n // Update the position once the calendar has rendered.\n this._zone.onStable.asObservable().pipe(take(1)).subscribe(() => {\n this._popupRef.updatePosition();\n });\n }\n }\n\n /** Create the popup. */\n private _createPopup(): void {\n const overlayConfig = new OverlayConfig({\n positionStrategy: this._createPopupPositionStrategy(),\n hasBackdrop: true,\n backdropClass: 'mat-overlay-transparent-backdrop',\n direction: this._dir,\n scrollStrategy: this._scrollStrategy(),\n panelClass: 'mat-colorpicker-popup',\n });\n\n this._popupRef = this._overlay.create(overlayConfig);\n this._popupRef.overlayElement.setAttribute('role', 'dialog');\n\n merge(\n this._popupRef.backdropClick(),\n this._popupRef.detachments(),\n this._popupRef.keydownEvents().pipe(filter(event => {\n // Closing on alt + up is only valid when there's an input associated with the datepicker.\n return event.keyCode === ESCAPE ||\n (this._pickerInput && event.altKey && event.keyCode === UP_ARROW);\n }))\n ).subscribe(event => {\n if (event) {\n event.preventDefault();\n }\n\n this.close();\n });\n }\n\n\n close(): void {\n if (!this._opened) {\n return;\n }\n if (this._popupRef && this._popupRef.hasAttached()) {\n this._popupRef.detach();\n }\n if (this._dialogRef) {\n this._dialogRef.close();\n this._dialogRef = null;\n }\n if (this._portal && this._portal.isAttached) {\n this._portal.detach();\n }\n\n const completeClose = () => {\n // The `_opened` could've been reset already if\n // we got two events in quick succession.\n if (this._opened) {\n this._opened = false;\n this.closedStream.emit();\n this._focusedElementBeforeOpen = null;\n }\n };\n\n if (this._focusedElementBeforeOpen &&\n typeof this._focusedElementBeforeOpen.focus === 'function') {\n // Because IE moves focus asynchronously, we can't count on it being restored before we've\n // marked the datepicker as closed. If the event fires out of sequence and the element that\n // we're refocusing opens the datepicker on focus, the user could be stuck with not being\n // able to close the calendar at all. We work around it by making the logic, that marks\n // the datepicker as closed, async as well.\n this._focusedElementBeforeOpen.focus();\n setTimeout(completeClose);\n } else {\n completeClose();\n }\n }\n\n /** Passes the current theme color along to the calendar overlay. */\n private _setColor(): void {\n const color = this.color;\n if (this._popupComponentRef) {\n this._popupComponentRef.instance.color = color;\n }\n if (this._dialogRef) {\n this._dialogRef.componentInstance.color = color;\n }\n }\n\n /** Create the popup PositionStrategy. */\n private _createPopupPositionStrategy(): PositionStrategy {\n return this._overlay.position()\n .flexibleConnectedTo(this._pickerInput.getConnectedOverlayOrigin())\n .withTransformOriginOn('.ngx-mat-colorpicker-content')\n .withFlexibleDimensions(false)\n .withViewportMargin(8)\n .withLockedPosition()\n .withPositions([\n {\n originX: 'start',\n originY: 'bottom',\n overlayX: 'start',\n overlayY: 'top'\n },\n {\n originX: 'start',\n originY: 'top',\n overlayX: 'start',\n overlayY: 'bottom'\n },\n {\n originX: 'end',\n originY: 'bottom',\n overlayX: 'end',\n overlayY: 'top'\n },\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'bottom'\n }\n ]);\n }\n\n\n}\n","<ngx-mat-color-palette (colorChanged)=\"picker.select($event)\" \n[color]=\"picker._selected\"\n[theme]=\"color\"></ngx-mat-color-palette>","import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { DOWN_ARROW } from '@angular/cdk/keycodes';\nimport { Directive, ElementRef, EventEmitter, forwardRef, Inject, Input, OnDestroy, OnInit, Optional, Output } from '@angular/core';\nimport { AbstractControl, ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator, ValidatorFn, Validators } from '@angular/forms';\nimport { ThemePalette } from '@angular/material/core';\nimport { MatFormField } from '@angular/material/form-field';\nimport { MAT_INPUT_VALUE_ACCESSOR } from '@angular/material/input';\nimport { Subscription } from 'rxjs';\nimport { createMissingDateImplError } from '../../helpers';\nimport { Color } from '../../models';\nimport { ColorAdapter, MAT_COLOR_FORMATS, MatColorFormats } from '../../services';\nimport { NgxMatColorPickerComponent } from './color-picker.component';\n\nexport class NgxMatColorPickerInputEvent {\n /** The new value for the target colorpicker input. */\n value: Color | null;\n\n constructor(\n /** Reference to the colorpicker input component that emitted the event. */\n public target: NgxMatColorPickerInput,\n /** Reference to the native input element associated with the colorpicker input. */\n public targetElement: HTMLElement) {\n this.value = this.target.value;\n }\n}\n\n\nexport const MAT_COLORPICKER_VALUE_ACCESSOR: any = {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NgxMatColorPickerInput),\n multi: true\n};\n\n\nexport const MAT_COLORPICKER_VALIDATORS: any = {\n provide: NG_VALIDATORS,\n useExisting: forwardRef(() => NgxMatColorPickerInput),\n multi: true\n};\n\n@Directive({\n selector: 'input[ngxMatColorPicker]',\n providers: [\n MAT_COLORPICKER_VALUE_ACCESSOR,\n MAT_COLORPICKER_VALIDATORS,\n { provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: NgxMatColorPickerInput },\n ],\n host: {\n '[attr.aria-haspopup]': '_picker ? \"dialog\" : null',\n '[attr.aria-owns]': '(_picker?.opened && _picker.id) || null',\n '[disabled]': 'disabled',\n '(input)': '_onInput($event.target.value)',\n '(change)': '_onChange()',\n '(blur)': '_onBlur()',\n '(keydown)': '_onKeydown($event)',\n },\n exportAs: 'ngxMatColorPickerInput',\n})\nexport class NgxMatColorPickerInput implements ControlValueAccessor, OnInit, OnDestroy, Validator {\n\n @Input()\n set ngxMatColorPicker(value: NgxMatColorPickerComponent) {\n if (!value) {\n return;\n }\n\n this._picker = value;\n this._picker.registerInput(this);\n this._pickerSubscription.unsubscribe();\n\n this._pickerSubscription = this._picker._selectedChanged.subscribe((selected: Color) => {\n this.value = selected;\n this._cvaOnChange(selected);\n this._onTouched();\n this.colorInput.emit(new NgxMatColorPickerInputEvent(this, this._elementRef.nativeElement));\n this.colorChange.emit(new NgxMatColorPickerInputEvent(this, this._elementRef.nativeElement));\n });\n }\n _picker: NgxMatColorPickerComponent;\n\n /** Whether the colorpicker-input is disabled. */\n @Input()\n get disabled(): boolean { return !!this._disabled; }\n set disabled(value: boolean) {\n const newValue = coerceBooleanProperty(value);\n const element = this._elementRef.nativeElement;\n\n if (this._disabled !== newValue) {\n this._disabled = newValue;\n this._disabledChange.emit(newValue);\n }\n\n // We need to null check the `blur` method, because it's undefined during SSR.\n if (newValue && element.blur) {\n // Normally, native input elements automatically blur if they turn disabled. This behavior\n // is problematic, because it would mean that it triggers another change detection cycle,\n // which then causes a changed after checked error if the input element was focused before.\n element.blur();\n }\n }\n private _disabled: boolean;\n\n /** The value of the input. */\n @Input()\n get value(): Color | null { return this._value; }\n set value(value: Color | null) {\n const oldValue = this.value;\n this._value = value;\n this._formatValue(value);\n\n if (!this._adapter.sameColor(oldValue, value)) {\n this._valueChange.emit(value);\n }\n\n }\n private _value: Color | null;\n\n /** Emits when a `change` event is fired on this `<input>`. */\n @Output() readonly colorChange: EventEmitter<NgxMatColorPickerInputEvent> =\n new EventEmitter<NgxMatColorPickerInputEvent>();\n\n /** Emits when an `input` event is fired on this `<input>`. */\n @Output() readonly colorInput: EventEmitter<NgxMatColorPickerInputEvent> =\n new EventEmitter<NgxMatColorPickerInputEvent>();\n\n /** Emits when the disabled state has changed */\n _disabledChange = new EventEmitter<boolean>();\n\n /** Emits when the value changes (either due to user input or programmatic change). */\n _valueChange = new EventEmitter<Color>();\n\n _onTouched = () => { };\n\n private _cvaOnChange: (value: any) => void = () => { };\n\n private _validatorOnChange = () => { };\n\n private _pickerSubscription = Subscription.EMPTY;\n\n /** The combined form control validator for this input. */\n private _validator: ValidatorFn | null =\n Validators.compose([]);\n\n /** Whether the last value set on the input was valid. */\n private _lastValueValid = false;\n\n constructor(private _elementRef: ElementRef<HTMLInputElement>,\n @Optional() private _formField: MatFormField,\n @Optional() @Inject(MAT_COLOR_FORMATS) private _colorFormats: MatColorFormats,\n private _adapter: ColorAdapter) {\n if (!this._colorFormats) {\n throw createMissingDateImplError('MAT_COLOR_FORMATS');\n }\n }\n\n /** Returns the palette used by the input's form field, if any. */\n public getThemePalette(): ThemePalette {\n return this._formField ? this._formField.color : undefined;\n }\n\n\n registerOnValidatorChange(fn: () => void): void {\n this._validatorOnChange = fn;\n }\n\n\n validate(c: AbstractControl): ValidationErrors | null {\n return this._validator ? this._validator(c) : null;\n }\n\n /**\n * @deprecated\n * @breaking-change 8.0.0 Use `getConnectedOverlayOrigin` instead\n */\n getPopupConnectionElementRef(): ElementRef {\n return this.getConnectedOverlayOrigin();\n }\n\n /**\n * Gets the element that the colorpicker popup should be connected to.\n * @return The element to connect the popup to.\n */\n getConnectedOverlayOrigin(): ElementRef {\n return this._formField ? this._formField.getConnectedOverlayOrigin() : this._elementRef;\n }\n\n\n ngOnInit() {\n }\n\n ngOnDestroy(): void {\n this._pickerSubscription.unsubscribe();\n this._valueChange.complete();\n this._disabledChange.complete();\n }\n\n // Implemented as part of ControlValueAccessor.\n writeValue(value: Color): void {\n this.value = value;\n }\n\n // Implemented as part of ControlValueAccessor.\n registerOnChange(fn: (value: any) => void): void {\n this._cvaOnChange = fn;\n }\n\n // Implemented as part of ControlValueAccessor.\n registerOnTouched(fn: () => void): void {\n this._onTouched = fn;\n }\n\n // Implemented as part of ControlValueAccessor.\n setDisabledState(isDisabled: boolean): void {\n this.disabled = isDisabled;\n }\n\n _onChange() {\n this.colorChange.emit(new NgxMatColorPickerInputEvent(this, this._elementRef.nativeElement));\n }\n\n _onKeydown(event: KeyboardEvent) {\n const isAltDownArrow = event.altKey && event.keyCode === DOWN_ARROW;\n\n if (this._picker && isAltDownArrow && !this._elementRef.nativeElement.readOnly) {\n this._picker.open();\n event.preventDefault();\n }\n }\n\n /** Handles blur events on the input. */\n _onBlur() {\n // Reformat the input only if we have a valid value.\n if (this.value) {\n this._formatValue(this.value);\n }\n\n this._onTouched();\n }\n\n /** Formats a value and sets it on the input element. */\n private _formatValue(value: Color | null) {\n this._elementRef.nativeElement.value = value ? this._adapter.format(value, this._colorFormats.display.colorInput) : '';\n }\n\n _onInput(value: string) {\n const lastValueWasValid = this._lastValueValid;\n const nextValue = this._adapter.parse(value);\n\n if (!this._adapter.sameColor(nextValue, this._value)) {\n this._value = nextValue;\n this._cvaOnChange(nextValue);\n this._valueChange.emit(nextValue);\n this.colorInput.emit(new NgxMatColorPickerInputEvent(this, this._elementRef.nativeElement));\n } else if (lastValueWasValid !== this._lastValueValid) {\n this._validatorOnChange();\n }\n }\n\n}\n\n\n","import {\n AfterContentInit, ChangeDetectorRef, Component, ContentChild, Directive, Input, OnChanges, OnDestroy,\n OnInit, SimpleChanges, ViewChild, ViewEncapsulation\n} from '@angular/core';\nimport { MatButton } from '@angular/material/button';\nimport { Subscription, merge, of } from 'rxjs';\nimport { NgxMatColorPickerComponent } from '../color-picker/color-picker.component';\n\n@Directive({\n selector: '[ngxMatColorpickerToggleIcon]',\n})\nexport class NgxMatColorpickerToggleIcon { }\n\n@Component({\n selector: 'ngx-mat-color-toggle',\n templateUrl: './color-toggle.component.html',\n styleUrls: ['./color-toggle.component.scss'],\n host: {\n 'class': 'ngx-mat-color-toggle',\n // Always set the tabindex to -1 so that it doesn't overlap with any custom tabindex the\n // consumer may have provided, while still being able to receive focus.\n '[attr.tabindex]': '-1',\n '[class.ngx-mat-color-toggle-active]': 'picker && picker.opened',\n '[class.mat-accent]': 'picker && picker.color === \"accent\"',\n '[class.mat-warn]': 'picker && picker.color === \"warn\"',\n '(focus)': '_button.focus()',\n },\n exportAs: 'ngxMatColorPickerToggle',\n encapsulation: ViewEncapsulation.None\n})\nexport class NgxMatColorToggleComponent implements OnInit, AfterContentInit, OnChanges, OnDestroy {\n\n private _stateChanges = Subscription.EMPTY;\n\n @Input('for') picker: NgxMatColorPickerComponent;\n @Input() tabIndex: number;\n\n @Input() get disabled(): boolean {\n if (this._disabled == null && this.picker) {\n return this.picker.disabled;\n }\n }\n set disabled(value: boolean) {\n this._disabled = value;\n }\n private _disabled: boolean;\n\n /** Whether ripples on the toggle should be disabled. */\n @Input() disableRipple: boolean;\n\n /** Custom icon set by the consumer. */\n @ContentChild(NgxMatColorpickerToggleIcon) _customIcon: NgxMatColorpickerToggleIcon;\n\n @ViewChild('button') _button: MatButton;