├── .gitignore ├── LICENSE ├── _config.yml ├── bower.json ├── examples ├── app │ ├── app.component.ts │ ├── app.module.ts │ ├── demo.html │ └── main.ts ├── index.html ├── package.json ├── systemjs.config.js ├── tsconfig.json └── typings.json ├── examples_webpack ├── config │ ├── helpers.js │ ├── karma-test-shim.js │ ├── karma.conf.js │ ├── webpack.common.js │ ├── webpack.dev.js │ ├── webpack.prod.js │ └── webpack.test.js ├── karma.config.js ├── package.json ├── public │ ├── css │ │ └── styles.css │ └── images │ │ └── angular.png ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ └── vendor.ts ├── tsconfig.json ├── typings.json └── webpack.config.js ├── gulpfile.js ├── index.d.ts ├── index.html ├── index.js ├── index.js.map ├── index.ts ├── lib ├── classes.d.ts ├── classes.js ├── classes.js.map ├── classes.ts ├── color-picker.directive.d.ts ├── color-picker.directive.js ├── color-picker.directive.js.map ├── color-picker.directive.ts ├── color-picker.module.d.ts ├── color-picker.module.js ├── color-picker.module.js.map ├── color-picker.module.ts ├── color-picker.service.d.ts ├── color-picker.service.js ├── color-picker.service.js.map ├── color-picker.service.ts ├── index.d.ts ├── index.js ├── index.js.map └── index.ts ├── package.json ├── readme.md ├── src ├── classes.ts ├── color-picker.directive.ts ├── color-picker.module.ts ├── color-picker.service.ts ├── index.ts └── templates │ └── default │ ├── color-picker.html │ └── color-picker.scss ├── tsconfig.json └── typings.json /.gitignore: -------------------------------------------------------------------------------- 1 | examples/app/*.js 2 | examples/app/*.js.map 3 | examples/app/*.d.ts 4 | 5 | examples/node_modules/* 6 | examples/typings/* 7 | examples/npm-debug.log 8 | 9 | examples_webpack/node_modules/* 10 | examples_webpack/dist/* 11 | examples_webpack/typings/* 12 | 13 | node_modules/* 14 | typings/* 15 | npm-debug.log 16 | 17 | nbproject/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2016 Alberto Pujante 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | gems: 2 | - jekyll-redirect-from -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-color-picker", 3 | "version": "1.2.1", 4 | "authors": [ 5 | "Alberto Pujante " 6 | ], 7 | "description": "Color Picker Directive for Angular 2 with no dependencies required", 8 | "main": [ 9 | "lib/color-picker.directive.ts" 10 | ], 11 | "ignore": [ 12 | "node_modules" 13 | ], 14 | "licence": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {ColorPickerDirective, ColorPickerService, Rgba} from 'angular2-color-picker'; 3 | 4 | export class Cmyk { 5 | constructor(public c: number, public m: number, public y: number, public k: number) { } 6 | } 7 | 8 | @Component({ 9 | selector: 'my-app', 10 | templateUrl: 'app/demo.html' 11 | }) 12 | 13 | export class AppComponent { 14 | 15 | constructor(private cpService: ColorPickerService) { 16 | this.arrayColors['color'] = '#2883e9'; 17 | this.arrayColors['color2'] = '#e920e9'; 18 | this.arrayColors['color3'] = 'rgb(255,245,0)'; 19 | this.arrayColors['color4'] = 'rgb(236,64,64)'; 20 | this.arrayColors['color5'] = 'rgba(45,208,45,1)'; 21 | } 22 | 23 | private color: string = '#2889e9'; 24 | private color2: string = "hsla(300,82%,52%)"; 25 | private color3: string = "#fff500"; 26 | private color4: string = "rgb(236,64,64)"; 27 | private color5: string = "rgba(45,208,45,1)"; 28 | private color6: string = "#1973c0"; 29 | private color7: string = "#f200bd"; 30 | private color8: string = "#a8ff00"; 31 | private color9: string = "#278ce2"; 32 | private color10: string = "#0a6211"; 33 | private color11: string = "#f2ff00"; 34 | private color12: string = "#f200bd"; 35 | private color13: string = "#1973c0"; 36 | private color14: string = "#a8ff00"; 37 | private color15: string = "#a51ad6a3"; 38 | 39 | private arrayColors: any = {}; 40 | private selectedColor: string = 'color'; 41 | 42 | private toggle: boolean; 43 | private toggle2: boolean; 44 | private lastColor = '#ff0'; 45 | private cmyk: Cmyk = new Cmyk(0, 0, 0, 0); 46 | 47 | onChangeColor(color: string): Cmyk { 48 | return this.rgbaToCmyk(this.cpService.hsvaToRgba(this.cpService.stringToHsva(color))); 49 | } 50 | 51 | rgbaToCmyk(rgba: Rgba): Cmyk { 52 | let cmyk: Cmyk = new Cmyk(0, 0, 0, 0), k: number; 53 | k = 1 - Math.max(rgba.r, rgba.g, rgba.b); 54 | if (k == 1) return new Cmyk(0, 0, 0, 1); 55 | cmyk.c = (1 - rgba.r - k) / (1 - k); 56 | cmyk.m = (1 - rgba.g - k) / (1 - k); 57 | cmyk.y = (1 - rgba.b - k) / (1 - k); 58 | cmyk.k = k; 59 | return cmyk; 60 | } 61 | 62 | onChangeColorHex8(color: string): string { 63 | return this.cpService.outputFormat(this.cpService.stringToHsva(color, true), 'rgba', true); 64 | } 65 | } -------------------------------------------------------------------------------- /examples/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {BrowserModule} from '@angular/platform-browser'; 3 | import {ColorPickerModule} from 'angular2-color-picker'; 4 | 5 | import {AppComponent} from './app.component'; 6 | 7 | @NgModule({ 8 | bootstrap: [AppComponent], 9 | declarations: [AppComponent], 10 | imports: [BrowserModule, ColorPickerModule] 11 | }) 12 | export class AppModule { } -------------------------------------------------------------------------------- /examples/app/demo.html: -------------------------------------------------------------------------------- 1 |
2 |

Angular2 Color Picker Directive

3 |

A Color Picker Directive for Angular 2 with no dependencies.

4 |

by Alberto Pujante

5 | View on Github 6 | 7 |
8 |
9 |
10 | 11 |
12 |
13 |

Usage:

14 |
 15 | <input [(colorPicker)]="color" 
 16 |        [style.background]="color"/>
 17 |             
18 |

Or:

19 |
 20 | <input [colorPicker]="color" 
 21 |         (colorPickerChange)="color=$event"
 22 |         [style.background]="color"/>
 23 |             
24 |
25 |
26 | 27 |
28 |
29 |
30 | 33 |
34 |
35 |

Show the color in the input field:

36 |
 37 | <input [(colorPicker)]="color" 
 38 |        [style.background]="color" 
 39 |        [value]="color"/>
 40 |             
41 |
42 |
43 | 44 |
45 |
46 |
47 |

51 | 55 |
56 |
57 |

Output format:

58 |
 59 | <input [(colorPicker)]="color" 
 60 |        [style.background]="color" 
 61 |        [value]="color"
 62 |        [cpOutputFormat]="'rgba'"/>
 63 |             
64 |
65 |
66 | 67 |
68 |
69 |
70 | 74 |
75 |
76 |

Changing dialog position:

77 |
 78 | <input [(colorPicker)]="color" 
 79 |        [style.background]="color" 
 80 |        [value]="color"
 81 |        [cpPosition]="'bottom'"/>
 82 |             
83 |
84 |
85 | 86 |
87 |
88 |
89 | Change me! 94 |
95 |
96 |

You can introduce a offset of the color picker relative to the html element:

97 |
 98 | <span [(colorPicker)]="color" 
 99 |       [cpPosition]="'bottom'"
100 |       [style.color]="color"
101 |       [cpPositionOffset]="'50%'"
102 |       [cpPositionRelativeToArrow]="true">Change me!</span>
103 |             
104 |
105 |
106 | 107 |
108 |
109 |
110 | 114 |
115 |
116 |

Show cancel button:

117 |
118 | <input [(colorPicker)]="color" 
119 |        [style.background]="color" 
120 |        [value]="color"
121 |        [cpCancelButton]="true"/>
122 |             
123 |
124 |
125 | 126 |
127 |
128 |
129 | 134 |
135 |
136 |

Change cancel button class, in this example we are using a bootstrap button:

137 |
138 | <input [(colorPicker)]="color" 
139 |        [style.background]="color" 
140 |        [value]="color"
141 |        [cpCancelButton]="true"
142 |        [cpCancelButtonClass]= "'btn btn-primary btn-xs'"/>
143 |             
144 |
145 |
146 | 147 |
148 |
149 |
150 | 156 |
157 |
158 |

Show OK button:

159 |
160 | <input [(colorPicker)]="color" 
161 |        [style.background]="color" 
162 |        [value]="color"
163 |        [cpOKButton]="true"
164 |        [cpSaveClickOutside]="false"
165 |        [cpOKButtonClass]= "'btn btn-primary btn-xs'"/>
166 |             
167 |
168 |
169 | 170 |
171 |
172 |
173 | 174 | 177 | 178 |
179 | 180 |
181 |
182 | C 183 |
184 |
185 | M 186 |
187 |
188 |
189 | 190 |
191 |
192 | Y 193 |
194 |
195 | K 196 |
197 |
198 |
199 | 200 |
201 |
202 |

Change event color:

203 |
204 | <input [colorPicker]="color" 
205 |        (colorPickerChange)="cmyk=onChangeColor($event);color=$event"
206 |        [style.background]="color"/>
207 | 
208 | <span [style.font-size.px]="100*cmyk.c"/>C</span/>
209 | <span [style.font-size.px]="100*cmyk.m"/>M</span/>
210 | <span [style.font-size.px]="100*cmyk.y"/>Y</span/>
211 | <span [style.font-size.px]="100*cmyk.k"/>K</span/>
212 |             
213 |
214 |
215 | 216 |
217 |
218 |
219 | 222 |
223 |
224 |

With preset colors:

225 |
226 | <input [(colorPicker)]="color" 
227 |        [style.background]="color"
228 |        [cpPresetColors]="['#fff', '#000', '#2889e9', '#e920e9', '#fff500', 'rgb(236,64,64)']"/>
229 |             
230 |
231 |
232 | 233 |
234 |
235 |
236 | 240 |
241 | 243 |

244 |
Toggle status: {{toggle2}}
245 |
246 |
247 |

Use cpToggle with cpIgnoredElements:

248 |
249 | <input #ignoredInput [(colorPicker)]="color"
250 |        [(cpToggle)]="toggle"
251 |        [style.background]="color"
252 |        [cpIgnoredElements]="[ignoredButton, ignoredInput]"/>
253 | 
254 | <button (click)="toggle=!toggle;lastColor=color"  
255 |          #ignoredButton></button>    
256 |             
257 |
258 |
259 | 260 |
261 |
262 |
263 | 267 |
268 | 273 |
274 | 280 |
281 |
282 |

Change alpha channel behaviour:

283 |
284 | <input [(colorPicker)]="color" 
285 |        [style.background]="color" 
286 |        [cpAlphaChannel]="'disabled'"
287 |        [value]="color"/>
288 | 
289 | <input [(colorPicker)]="color" 
290 |        [style.background]="color" 
291 |        [cpAlphaChannel]="'hex8'"
292 |        [cpOutputFormat]="'rgba'"
293 |        [value]="color"/>
294 | 
295 | <input [colorPicker]="color" 
296 |        (colorPickerChange)="rgbaText=onChangeColorHex8($event);color=$event"
297 |        [style.background]="rgbaText" 
298 |        [cpAlphaChannel]="'hex8'"    
299 |        [value]="color"/>
300 |             
301 |
302 |
303 | 304 |
305 |
306 | 307 |
308 | 314 | 315 |
316 | 317 |
318 | 319 |
322 | 323 |
326 | 327 |
330 | 331 |
334 | 335 |
338 | 339 |
340 | 341 |
342 |

Show the dialog permanently:

343 |
344 | <span [(colorPicker)]="arrayColors[selectedColor]"     
345 |       [cpType]="'fixed'"
346 |       [style.background]="arrayColors[selectedColor]"
347 |       [cpToggle]="true"></span>
348 | 
349 | <div [style.background]="arrayColors['color']"
350 |      (click)="selectedColor='color'"></div>
351 | 
352 | <div [style.background]="arrayColors['color2']"
353 |      (click)="selectedColor='color2'"></div>
354 | 
355 | ...
356 |             
357 |
358 |
359 | 360 |
361 |
362 |
363 |
364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 377 | 378 | 379 | 380 | 383 | 384 | 385 | 386 | 390 | 391 | 392 | 393 | 397 | 398 | 399 | 400 | 404 | 405 | 406 | 407 | 411 | 412 | 413 | 414 | 418 | 419 | 420 | 421 | 425 | 426 | 427 | 428 | 431 | 432 | 433 | 434 | 437 | 438 | 439 | 440 | 444 | 445 | 446 | 447 | 450 | 451 | 452 | 453 | 456 | 457 | 458 | 459 | 463 | 464 | 465 | 466 | 470 | 471 | 472 | 473 | 477 | 478 | 479 | 480 | 484 | 485 | 486 | 487 | 491 | 492 | 493 | 494 | 499 | 500 | 501 | 502 | 508 | 509 | 510 |
OptionsValues (default values in bold)
cpOutputFormat 375 | 'hex', 'rgba', 'hsla' 376 |
cpPosition 381 | 'right', 'left', 'top', 'bottom' 382 |
cpPositionOffset 387 | '0%'
388 | Dialog offset (percent) relative to the element that contains the directive. 389 |
cpPositionRelativeToArrow 394 | false, true
395 | Dialog position is calculated relative to the dialog (false) or relative to the dialog arrow (true). 396 |
cpWidth 401 | '230px'
402 | Use this option to set color picker dialog width (pixels). 403 |
cpHeight 408 | 'auto'
409 | Use this option to force color picker dialog height (pixels). 410 |
cpSaveClickOutside 415 | true, false
416 | If true the initial color is restored when user clicks outside. 417 |
cpOKButton 422 | false, true
423 | Shows the Ok button. Saves the selected color. 424 |
cpOKButtonText 429 | 'OK' 430 |
cpOKButtonClass 435 | Class to customize the OK button. 436 |
cpCancelButton 441 | false, true
442 | Shows the Cancel button. Cancel the selected color. 443 |
cpCancelButtonText 448 | 'Cancel' 449 |
cpCancelButtonClass 454 | Class to customize the Cancel button. 455 |
cpFallbackColor 460 | '#fff'
461 | Is used when the color is not well-formed or not defined. 462 |
cpPresetLabel 467 | 'Preset colors'
468 | Label for preset colors if any provided used. 469 |
cpPresetColors 474 | []
475 | Array of preset colors to show in the color picker dialog. 476 |
cpToggle 481 | false, true
482 | Input/ouput to open/close the color picker. 483 |
cpIgnoredElements 488 | []
489 | Array of HTML elements that will be ignored by the color picker when they are clicked. 490 |
cpDialogDisplay 495 | 'popup', 'inline'
496 | popup: dialog is showed when user clicks in the directive.
497 | inline: dialog is showed permanently. You can show/hide the dialog with cpToggle. 498 |
cpAlphaChannel 503 | 'hex6', 'hex8', 'disabled'
504 | hex6: alpha channel is not allowed in hexadecimal values.
505 | hex8: alpha channel is allowed in hexadecimal values.
506 | disabled: alpha channel disabled.
507 |
511 |
512 |
513 |
514 | 515 |
516 | 517 |
-------------------------------------------------------------------------------- /examples/app/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { AppModule } from './app.module'; 3 | platformBrowserDynamic().bootstrapModule(AppModule); -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angular 2 Color Picker (Demo Page) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 83 | 84 | 85 | 86 | Loading... 87 | 88 | 89 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-color-picker-example", 3 | "version": "1.3.1", 4 | "description": "Example for Angular2 Color Picker", 5 | "scripts": { 6 | "start": "npm run lite", 7 | "lite": "lite-server" 8 | }, 9 | "license": "MIT", 10 | "dependencies": { 11 | "@angular/common": "~2.4.0", 12 | "@angular/compiler": "~2.4.0", 13 | "@angular/core": "~2.4.0", 14 | "@angular/forms": "~2.4.0", 15 | "@angular/http": "~2.4.0", 16 | "@angular/platform-browser": "~2.4.0", 17 | "@angular/platform-browser-dynamic": "~2.4.0", 18 | "@angular/router": "~3.4.0", 19 | "@angular/upgrade": "~2.4.0", 20 | "angular-in-memory-web-api": "~0.2.4", 21 | "core-js": "^2.4.1", 22 | "rxjs": "5.0.1", 23 | "zone.js": "^0.7.4" 24 | }, 25 | "devDependencies": { 26 | "concurrently": "^3.0.0", 27 | "lite-server": "^2.2.2" 28 | } 29 | } -------------------------------------------------------------------------------- /examples/systemjs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * System configuration for Angular 2 samples 3 | * Adjust as necessary for your application needs. 4 | */ 5 | (function (global) { 6 | System.config({ 7 | transpiler: 'ts', 8 | typescriptOptions: { 9 | tsconfig: true 10 | }, 11 | meta: { 12 | 'typescript': { 13 | "exports": "ts" 14 | } 15 | }, 16 | paths: { 17 | // paths serve as alias 18 | //'npm:': 'node_modules/' 19 | 'npm:': 'https://unpkg.com/' 20 | }, 21 | // map tells the System loader where to look for things 22 | map: { 23 | // our app is within the app folder 24 | app: 'app', 25 | // angular bundles 26 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 27 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 28 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 29 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 30 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 31 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 32 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 33 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 34 | // other libraries 35 | 'rxjs': 'npm:rxjs', 36 | 'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api', 37 | 'angular2-color-picker': 'node_modules/angular2-color-picker', 38 | 'ts': 'npm:plugin-typescript@4.0.10/lib/plugin.js', 39 | 'typescript': 'npm:typescript@2.0.2/lib/typescript.js' 40 | }, 41 | // packages tells the System loader how to load when no filename and/or no extension 42 | packages: { 43 | app: { 44 | main: './main.ts', 45 | defaultExtension: 'ts' 46 | }, 47 | rxjs: { 48 | defaultExtension: 'js' 49 | }, 50 | 'angular2-in-memory-web-api': { 51 | main: './index.js', 52 | defaultExtension: 'js' 53 | }, 54 | 'angular2-color-picker': {main: 'index.ts', defaultExtension: 'ts'} 55 | } 56 | }); 57 | })(this); 58 | 59 | -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160725163759", 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", 5 | "node": "registry:dt/node#6.0.0+20160909174046" 6 | } 7 | } -------------------------------------------------------------------------------- /examples_webpack/config/helpers.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var _root = path.resolve(__dirname, '..'); 3 | function root(args) { 4 | args = Array.prototype.slice.call(arguments, 0); 5 | return path.join.apply(path, [_root].concat(args)); 6 | } 7 | exports.root = root; -------------------------------------------------------------------------------- /examples_webpack/config/karma-test-shim.js: -------------------------------------------------------------------------------- 1 | Error.stackTraceLimit = Infinity; 2 | 3 | require('core-js/es6'); 4 | require('core-js/es7/reflect'); 5 | 6 | require('zone.js/dist/zone'); 7 | require('zone.js/dist/long-stack-trace-zone'); 8 | require('zone.js/dist/proxy'); 9 | require('zone.js/dist/sync-test'); 10 | require('zone.js/dist/jasmine-patch'); 11 | require('zone.js/dist/async-test'); 12 | require('zone.js/dist/fake-async-test'); 13 | 14 | var appContext = require.context('../src', true, /\.spec\.ts/); 15 | 16 | appContext.keys().forEach(appContext); 17 | 18 | var testing = require('@angular/core/testing'); 19 | var browser = require('@angular/platform-browser-dynamic/testing'); 20 | 21 | testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting()); 22 | -------------------------------------------------------------------------------- /examples_webpack/config/karma.conf.js: -------------------------------------------------------------------------------- 1 | var webpackConfig = require('./webpack.test'); 2 | 3 | module.exports = function (config) { 4 | var _config = { 5 | basePath: '', 6 | frameworks: ['jasmine'], 7 | files: [ 8 | {pattern: './config/karma-test-shim.js', watched: false} 9 | ], 10 | preprocessors: { 11 | './config/karma-test-shim.js': ['webpack', 'sourcemap'] 12 | }, 13 | webpack: webpackConfig, 14 | webpackMiddleware: { 15 | stats: 'errors-only' 16 | }, 17 | webpackServer: { 18 | noInfo: true 19 | }, 20 | reporters: ['progress'], 21 | port: 9876, 22 | colors: true, 23 | logLevel: config.LOG_INFO, 24 | autoWatch: false, 25 | browsers: ['PhantomJS'], 26 | singleRun: true 27 | }; 28 | 29 | config.set(_config); 30 | }; 31 | -------------------------------------------------------------------------------- /examples_webpack/config/webpack.common.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 4 | var helpers = require('./helpers'); 5 | 6 | module.exports = { 7 | entry: { 8 | 'polyfills': './src/polyfills.ts', 9 | 'vendor': './src/vendor.ts', 10 | 'app': './src/main.ts' 11 | }, 12 | resolve: { 13 | extensions: ['.ts', '.js'] 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.ts$/, 19 | loaders: ['awesome-typescript-loader', 'angular2-template-loader'] 20 | }, 21 | { 22 | test: /\.html$/, 23 | loader: 'html-loader' 24 | }, 25 | { 26 | test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, 27 | loader: 'file-loader?name=assets/[name].[hash].[ext]' 28 | }, 29 | { 30 | test: /\.css$/, 31 | exclude: helpers.root('src', 'app'), 32 | loader: ExtractTextPlugin.extract({fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap'}) 33 | }, 34 | { 35 | test: /\.css$/, 36 | include: helpers.root('src', 'app'), 37 | loader: 'raw-loader' 38 | } 39 | ] 40 | }, 41 | plugins: [ 42 | // Workaround for angular/angular#11580 43 | new webpack.ContextReplacementPlugin( 44 | // The (\\|\/) piece accounts for path separators in *nix and Windows 45 | /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, 46 | helpers.root('./src'), // location of your src 47 | {} // a map of your routes 48 | ), 49 | new webpack.optimize.CommonsChunkPlugin({ 50 | name: ['app', 'vendor', 'polyfills'] 51 | }), 52 | new HtmlWebpackPlugin({ 53 | template: 'src/index.html' 54 | }) 55 | ] 56 | }; 57 | -------------------------------------------------------------------------------- /examples_webpack/config/webpack.dev.js: -------------------------------------------------------------------------------- 1 | var webpackMerge = require('webpack-merge'); 2 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | var commonConfig = require('./webpack.common.js'); 4 | var helpers = require('./helpers'); 5 | 6 | module.exports = webpackMerge(commonConfig, { 7 | devtool: 'cheap-module-eval-source-map', 8 | output: { 9 | path: helpers.root('dist'), 10 | publicPath: 'http://localhost:8080/', 11 | filename: '[name].js', 12 | chunkFilename: '[id].chunk.js' 13 | }, 14 | plugins: [ 15 | new ExtractTextPlugin('[name].css') 16 | ], 17 | devServer: { 18 | historyApiFallback: true, 19 | stats: 'minimal' 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /examples_webpack/config/webpack.prod.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var webpackMerge = require('webpack-merge'); 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 4 | var commonConfig = require('./webpack.common.js'); 5 | var helpers = require('./helpers'); 6 | 7 | const ENV = process.env.NODE_ENV = process.env.ENV = 'production'; 8 | 9 | module.exports = webpackMerge(commonConfig, { 10 | devtool: 'source-map', 11 | output: { 12 | path: helpers.root('dist'), 13 | publicPath: '/', 14 | filename: '[name].[hash].js', 15 | chunkFilename: '[id].[hash].chunk.js' 16 | }, 17 | plugins: [ 18 | new webpack.NoEmitOnErrorsPlugin(), 19 | new webpack.optimize.UglifyJsPlugin({// https://github.com/angular/angular/issues/10618 20 | mangle: { 21 | keep_fnames: true 22 | } 23 | }), 24 | new ExtractTextPlugin('[name].[hash].css'), 25 | new webpack.DefinePlugin({ 26 | 'process.env': { 27 | 'ENV': JSON.stringify(ENV) 28 | } 29 | }), 30 | new webpack.LoaderOptionsPlugin({ 31 | htmlLoader: { 32 | minimize: false // workaround for ng2 33 | } 34 | }) 35 | ] 36 | }); 37 | -------------------------------------------------------------------------------- /examples_webpack/config/webpack.test.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var helpers = require('./helpers'); 3 | 4 | module.exports = { 5 | devtool: 'inline-source-map', 6 | resolve: { 7 | extensions: ['.ts', '.js'] 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.ts$/, 13 | loaders: ['awesome-typescript-loader', 'angular2-template-loader'] 14 | }, 15 | { 16 | test: /\.html$/, 17 | loader: 'html-loader' 18 | 19 | }, 20 | { 21 | test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, 22 | loader: 'null-loader' 23 | }, 24 | { 25 | test: /\.css$/, 26 | exclude: helpers.root('src', 'app'), 27 | loader: 'null-loader' 28 | }, 29 | { 30 | test: /\.css$/, 31 | include: helpers.root('src', 'app'), 32 | loader: 'raw-loader' 33 | } 34 | ] 35 | }, 36 | plugins: [ 37 | new webpack.ContextReplacementPlugin( 38 | // The (\\|\/) piece accounts for path separators in *nix and Windows 39 | /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, 40 | helpers.root('./src'), // location of your src 41 | {} // a map of your routes 42 | ) 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /examples_webpack/karma.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/karma.conf.js'); -------------------------------------------------------------------------------- /examples_webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-color-picker-example", 3 | "version": "1.3.1", 4 | "description": "Example for Angular2 Color Picker", 5 | "scripts": { 6 | "start": "webpack-dev-server --inline --progress --port 8080", 7 | "test": "karma start", 8 | "build": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "@angular/common": "~2.4.0", 13 | "@angular/compiler": "~2.4.0", 14 | "@angular/core": "~2.4.0", 15 | "@angular/forms": "~2.4.0", 16 | "@angular/http": "~2.4.0", 17 | "@angular/platform-browser": "~2.4.0", 18 | "@angular/platform-browser-dynamic": "~2.4.0", 19 | "@angular/router": "~3.4.0", 20 | "core-js": "^2.4.1", 21 | "rxjs": "5.0.1", 22 | "zone.js": "^0.7.4" 23 | }, 24 | "devDependencies": { 25 | "@types/node": "^6.0.45", 26 | "@types/jasmine": "^2.5.35", 27 | "angular2-template-loader": "^0.6.0", 28 | "awesome-typescript-loader": "^3.0.0-beta.18", 29 | "css-loader": "^0.26.1", 30 | "extract-text-webpack-plugin": "2.0.0-beta.5", 31 | "file-loader": "^0.9.0", 32 | "html-loader": "^0.4.3", 33 | "html-webpack-plugin": "^2.16.1", 34 | "jasmine-core": "^2.4.1", 35 | "karma": "^1.2.0", 36 | "karma-jasmine": "^1.0.2", 37 | "karma-phantomjs-launcher": "^1.0.2", 38 | "karma-sourcemap-loader": "^0.3.7", 39 | "karma-webpack": "^2.0.1", 40 | "null-loader": "^0.1.1", 41 | "phantomjs-prebuilt": "^2.1.7", 42 | "raw-loader": "^0.5.1", 43 | "rimraf": "^2.5.2", 44 | "style-loader": "^0.13.1", 45 | "typescript": "~2.0.10", 46 | "webpack": "2.2.0", 47 | "webpack-dev-server": "2.2.0-rc.0", 48 | "webpack-merge": "^2.4.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples_webpack/public/css/styles.css: -------------------------------------------------------------------------------- 1 | .col-md-5 > input{ 2 | margin-bottom: 10px; 3 | width: 182px; 4 | } -------------------------------------------------------------------------------- /examples_webpack/public/images/angular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alberplz/angular2-color-picker/1c29ca1c49afbe832826899a9c04d1c061d170e3/examples_webpack/public/images/angular.png -------------------------------------------------------------------------------- /examples_webpack/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | #changeme{ 2 | font-size:30px; 3 | font-weight: bolder; 4 | cursor: pointer; 5 | } 6 | .cmyk{ 7 | margin-left: 11px; 8 | } 9 | .cmyk div{ 10 | height: 72px; 11 | width: 72px; 12 | line-height: 72px; 13 | text-align: center; 14 | float:left; 15 | } 16 | .cmyk span{ 17 | font-weight: bolder; 18 | text-shadow: 1px 1px 2px #bbb; 19 | } 20 | 21 | #color-comparator button{ 22 | height: 26px; 23 | width: 26px; 24 | display: block; 25 | float:left; 26 | border:none; 27 | margin:0; 28 | padding:0; 29 | border: 2px solid #888; 30 | } 31 | 32 | #color-comparator > input{ 33 | height: 26px; 34 | width: 182px; 35 | display: block; 36 | float:left; 37 | border:none; 38 | margin:0; 39 | padding:0; 40 | } 41 | 42 | .array-colors-element{ 43 | width: 100px; 44 | height: 25px; 45 | margin-bottom: 15px; 46 | } 47 | -------------------------------------------------------------------------------- /examples_webpack/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Angular2 Color Picker Directive

3 |

A Color Picker Directive for Angular 2 with no dependencies.

4 |

by Alberto Pujante

5 | View on Github 6 | 7 |
8 |
9 |
10 | 11 |
12 |
13 |

Usage:

14 |
 15 | <input [(colorPicker)]="color" 
 16 |        [style.background]="color"/>
 17 |             
18 |

Or:

19 |
 20 | <input [colorPicker]="color" 
 21 |         (colorPickerChange)="color=$event"
 22 |         [style.background]="color"/>
 23 |             
24 |
25 |
26 | 27 |
28 |
29 |
30 | 33 |
34 |
35 |

Show the color in the input field:

36 |
 37 | <input [(colorPicker)]="color" 
 38 |        [style.background]="color" 
 39 |        [value]="color"/>
 40 |             
41 |
42 |
43 | 44 |
45 |
46 |
47 |

51 | 55 |
56 |
57 |

Output format:

58 |
 59 | <input [(colorPicker)]="color" 
 60 |        [style.background]="color" 
 61 |        [value]="color"
 62 |        [cpOutputFormat]="'rgba'"/>
 63 |             
64 |
65 |
66 | 67 |
68 |
69 |
70 | 74 |
75 |
76 |

Changing dialog position:

77 |
 78 | <input [(colorPicker)]="color" 
 79 |        [style.background]="color" 
 80 |        [value]="color"
 81 |        [cpPosition]="'bottom'"/>
 82 |             
83 |
84 |
85 | 86 |
87 |
88 |
89 | Change me! 94 |
95 |
96 |

You can introduce a offset of the color picker relative to the html element:

97 |
 98 | <span [(colorPicker)]="color" 
 99 |       [cpPosition]="'bottom'"
100 |       [style.color]="color"
101 |       [cpPositionOffset]="'50%'"
102 |       [cpPositionRelativeToArrow]="true">Change me!</span>
103 |             
104 |
105 |
106 | 107 |
108 |
109 |
110 | 114 |
115 |
116 |

Show cancel button:

117 |
118 | <input [(colorPicker)]="color" 
119 |        [style.background]="color" 
120 |        [value]="color"
121 |        [cpCancelButton]="true"/>
122 |             
123 |
124 |
125 | 126 |
127 |
128 |
129 | 134 |
135 |
136 |

Change cancel button class, in this example we are using a bootstrap button:

137 |
138 | <input [(colorPicker)]="color" 
139 |        [style.background]="color" 
140 |        [value]="color"
141 |        [cpCancelButton]="true"
142 |        [cpCancelButtonClass]= "'btn btn-primary btn-xs'"/>
143 |             
144 |
145 |
146 | 147 |
148 |
149 |
150 | 156 |
157 |
158 |

Show OK button:

159 |
160 | <input [(colorPicker)]="color" 
161 |        [style.background]="color" 
162 |        [value]="color"
163 |        [cpOKButton]="true"
164 |        [cpSaveClickOutside]="false"
165 |        [cpOKButtonClass]= "'btn btn-primary btn-xs'"/>
166 |             
167 |
168 |
169 | 170 |
171 |
172 |
173 | 174 | 177 | 178 |
179 | 180 |
181 |
182 | C 183 |
184 |
185 | M 186 |
187 |
188 |
189 | 190 |
191 |
192 | Y 193 |
194 |
195 | K 196 |
197 |
198 |
199 | 200 |
201 |
202 |

Change event color:

203 |
204 | <input [colorPicker]="color" 
205 |        (colorPickerChange)="cmyk=onChangeColor($event);color=$event"
206 |        [style.background]="color"/>
207 | 
208 | <span [style.font-size.px]="100*cmyk.c"/>C</span/>
209 | <span [style.font-size.px]="100*cmyk.m"/>M</span/>
210 | <span [style.font-size.px]="100*cmyk.y"/>Y</span/>
211 | <span [style.font-size.px]="100*cmyk.k"/>K</span/>
212 |             
213 |
214 |
215 | 216 |
217 |
218 |
219 | 222 |
223 |
224 |

With preset colors:

225 |
226 | <input [(colorPicker)]="color" 
227 |        [style.background]="color"
228 |        [cpPresetColors]="['#fff', '#000', '#2889e9', '#e920e9', '#fff500', 'rgb(236,64,64)']"/>
229 |             
230 |
231 |
232 | 233 |
234 |
235 |
236 | 240 |
241 | 243 |

244 |
Toggle status: {{toggle2}}
245 |
246 |
247 |

Use cpToggle with cpIgnoredElements:

248 |
249 | <input #ignoredInput [(colorPicker)]="color"
250 |        [(cpToggle)]="toggle"
251 |        [style.background]="color"
252 |        [cpIgnoredElements]="[ignoredButton, ignoredInput]"/>
253 | 
254 | <button (click)="toggle=!toggle;lastColor=color"  
255 |          #ignoredButton></button>    
256 |             
257 |
258 |
259 | 260 |
261 |
262 |
263 | 267 |
268 | 273 |
274 | 280 |
281 |
282 |

Change alpha channel behaviour:

283 |
284 | <input [(colorPicker)]="color" 
285 |        [style.background]="color" 
286 |        [cpAlphaChannel]="'disabled'"
287 |        [value]="color"/>
288 | 
289 | <input [(colorPicker)]="color" 
290 |        [style.background]="color" 
291 |        [cpAlphaChannel]="'hex8'"
292 |        [cpOutputFormat]="'rgba'"
293 |        [value]="color"/>
294 | 
295 | <input [colorPicker]="color" 
296 |        (colorPickerChange)="rgbaText=onChangeColorHex8($event);color=$event"
297 |        [style.background]="rgbaText" 
298 |        [cpAlphaChannel]="'hex8'"    
299 |        [value]="color"/>
300 |             
301 |
302 |
303 | 304 |
305 |
306 | 307 |
308 | 314 | 315 |
316 | 317 |
318 | 319 |
322 | 323 |
326 | 327 |
330 | 331 |
334 | 335 |
338 | 339 |
340 | 341 |
342 |

Show the dialog permanently:

343 |
344 | <span [(colorPicker)]="arrayColors[selectedColor]"     
345 |       [cpType]="'fixed'"
346 |       [style.background]="arrayColors[selectedColor]"
347 |       [cpToggle]="true"></span>
348 | 
349 | <div [style.background]="arrayColors['color']"
350 |      (click)="selectedColor='color'"></div>
351 | 
352 | <div [style.background]="arrayColors['color2']"
353 |      (click)="selectedColor='color2'"></div>
354 | 
355 | ...
356 |             
357 |
358 |
359 | 360 |
361 |
362 |
363 |
364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 377 | 378 | 379 | 380 | 383 | 384 | 385 | 386 | 390 | 391 | 392 | 393 | 397 | 398 | 399 | 400 | 404 | 405 | 406 | 407 | 411 | 412 | 413 | 414 | 418 | 419 | 420 | 421 | 425 | 426 | 427 | 428 | 431 | 432 | 433 | 434 | 437 | 438 | 439 | 440 | 444 | 445 | 446 | 447 | 450 | 451 | 452 | 453 | 456 | 457 | 458 | 459 | 463 | 464 | 465 | 466 | 470 | 471 | 472 | 473 | 477 | 478 | 479 | 480 | 484 | 485 | 486 | 487 | 491 | 492 | 493 | 494 | 499 | 500 | 501 | 502 | 508 | 509 | 510 |
OptionsValues (default values in bold)
cpOutputFormat 375 | 'hex', 'rgba', 'hsla' 376 |
cpPosition 381 | 'right', 'left', 'top', 'bottom' 382 |
cpPositionOffset 387 | '0%'
388 | Dialog offset (percent) relative to the element that contains the directive. 389 |
cpPositionRelativeToArrow 394 | false, true
395 | Dialog position is calculated relative to the dialog (false) or relative to the dialog arrow (true). 396 |
cpWidth 401 | '230px'
402 | Use this option to set color picker dialog width (pixels). 403 |
cpHeight 408 | 'auto'
409 | Use this option to force color picker dialog height (pixels). 410 |
cpSaveClickOutside 415 | true, false
416 | If true the initial color is restored when user clicks outside. 417 |
cpOKButton 422 | false, true
423 | Shows the Ok button. Saves the selected color. 424 |
cpOKButtonText 429 | 'OK' 430 |
cpOKButtonClass 435 | Class to customize the OK button. 436 |
cpCancelButton 441 | false, true
442 | Shows the Cancel button. Cancel the selected color. 443 |
cpCancelButtonText 448 | 'Cancel' 449 |
cpCancelButtonClass 454 | Class to customize the Cancel button. 455 |
cpFallbackColor 460 | '#fff'
461 | Is used when the color is not well-formed or not defined. 462 |
cpPresetLabel 467 | 'Preset colors'
468 | Label for preset colors if any provided used. 469 |
cpPresetColors 474 | []
475 | Array of preset colors to show in the color picker dialog. 476 |
cpToggle 481 | false, true
482 | Input/ouput to open/close the color picker. 483 |
cpIgnoredElements 488 | []
489 | Array of HTML elements that will be ignored by the color picker when they are clicked. 490 |
cpDialogDisplay 495 | 'popup', 'inline'
496 | popup: dialog is showed when user clicks in the directive.
497 | inline: dialog is showed permanently. You can show/hide the dialog with cpToggle. 498 |
cpAlphaChannel 503 | 'hex6', 'hex8', 'disabled'
504 | hex6: alpha channel is not allowed in hexadecimal values.
505 | hex8: alpha channel is allowed in hexadecimal values.
506 | disabled: alpha channel disabled.
507 |
511 |
512 |
513 |
514 | 515 |
516 | 517 |
-------------------------------------------------------------------------------- /examples_webpack/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('App', () => { 4 | beforeEach(() => { 5 | TestBed.configureTestingModule({ declarations: [AppComponent] }); 6 | }); 7 | it('should work', () => { 8 | let fixture = TestBed.createComponent(AppComponent); 9 | expect(fixture.componentInstance instanceof AppComponent).toBe(true, 'should create AppComponent'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /examples_webpack/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import '../../public/css/styles.css'; 3 | import {ColorPickerService, Rgba} from 'angular2-color-picker/lib'; 4 | 5 | export class Cmyk { 6 | constructor(public c: number, public m: number, public y: number, public k: number) { } 7 | } 8 | 9 | @Component({ 10 | selector: 'my-app', 11 | templateUrl: './app.component.html', 12 | styleUrls: ['./app.component.css'] 13 | }) 14 | export class AppComponent { 15 | 16 | constructor(private cpService: ColorPickerService) { 17 | this.arrayColors['color'] = '#2883e9'; 18 | this.arrayColors['color2'] = '#e920e9'; 19 | this.arrayColors['color3'] = 'rgb(255,245,0)'; 20 | this.arrayColors['color4'] = 'rgb(236,64,64)'; 21 | this.arrayColors['color5'] = 'rgba(45,208,45,1)'; 22 | } 23 | 24 | private color: string = '#2889e9'; 25 | private color2: string = "hsla(300,82%,52%)"; 26 | private color3: string = "#fff500"; 27 | private color4: string = "rgb(236,64,64)"; 28 | private color5: string = "rgba(45,208,45,1)"; 29 | private color6: string = "#1973c0"; 30 | private color7: string = "#f200bd"; 31 | private color8: string = "#a8ff00"; 32 | private color9: string = "#278ce2"; 33 | private color10: string = "#0a6211"; 34 | private color11: string = "#f2ff00"; 35 | private color12: string = "#f200bd"; 36 | private color13: string = "#1973c0"; 37 | private color14: string = "#a8ff00"; 38 | private color15: string = "#a51ad6a3"; 39 | 40 | private arrayColors: any = {}; 41 | private selectedColor: string = 'color'; 42 | 43 | private toggle: boolean; 44 | private toggle2: boolean; 45 | private lastColor = '#ff0'; 46 | private cmyk: Cmyk = new Cmyk(0, 0, 0, 0); 47 | 48 | onChangeColor(color: string): Cmyk { 49 | return this.rgbaToCmyk(this.cpService.hsvaToRgba(this.cpService.stringToHsva(color))); 50 | } 51 | 52 | rgbaToCmyk(rgba: Rgba): Cmyk { 53 | let cmyk: Cmyk = new Cmyk(0, 0, 0, 0), k: number; 54 | k = 1 - Math.max(rgba.r, rgba.g, rgba.b); 55 | if (k == 1) return new Cmyk(0, 0, 0, 1); 56 | cmyk.c = (1 - rgba.r - k) / (1 - k); 57 | cmyk.m = (1 - rgba.g - k) / (1 - k); 58 | cmyk.y = (1 - rgba.b - k) / (1 - k); 59 | cmyk.k = k; 60 | return cmyk; 61 | } 62 | 63 | onChangeColorHex8(color: string): string { 64 | return this.cpService.outputFormat(this.cpService.stringToHsva(color, true), 'rgba', true); 65 | } 66 | } -------------------------------------------------------------------------------- /examples_webpack/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { AppComponent } from './app.component'; 4 | import {ColorPickerModule, ColorPickerService} from 'angular2-color-picker/lib'; 5 | 6 | @NgModule({ 7 | imports: [ 8 | BrowserModule, 9 | ColorPickerModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | providers: [ColorPickerService], 15 | bootstrap: [AppComponent] 16 | }) 17 | export class AppModule { } 18 | -------------------------------------------------------------------------------- /examples_webpack/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular With Webpack 6 | 7 | 8 | 9 | 10 | 11 | Loading... 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples_webpack/src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { AppModule } from './app/app.module'; 4 | if (process.env.ENV === 'production') { 5 | enableProdMode(); 6 | } 7 | platformBrowserDynamic().bootstrapModule(AppModule); 8 | -------------------------------------------------------------------------------- /examples_webpack/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es6'; 2 | import 'core-js/es7/reflect'; 3 | require('zone.js/dist/zone'); 4 | 5 | if (process.env.ENV === 'production') { 6 | // Production 7 | } else { 8 | // Development and test 9 | Error['stackTraceLimit'] = Infinity; 10 | require('zone.js/dist/long-stack-trace-zone'); 11 | } 12 | -------------------------------------------------------------------------------- /examples_webpack/src/vendor.ts: -------------------------------------------------------------------------------- 1 | // Angular 2 | import '@angular/platform-browser'; 3 | import '@angular/platform-browser-dynamic'; 4 | import '@angular/core'; 5 | import '@angular/common'; 6 | import '@angular/http'; 7 | import '@angular/router'; 8 | 9 | // RxJS 10 | import 'rxjs'; 11 | 12 | // Other vendors for example jQuery, Lodash or Bootstrap 13 | // You can import js, ts, css, sass, ... 14 | 15 | import 'angular2-color-picker/lib'; -------------------------------------------------------------------------------- /examples_webpack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "lib": ["es2015", "dom"], 10 | "noImplicitAny": true, 11 | "suppressImplicitAnyIndexErrors": true 12 | } 13 | } -------------------------------------------------------------------------------- /examples_webpack/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160725163759", 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", 5 | "node": "registry:dt/node#6.0.0+20160909174046" 6 | } 7 | } -------------------------------------------------------------------------------- /examples_webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/webpack.dev.js'); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var del = require('del'); 3 | var tsc = require('gulp-typescript'); 4 | var gulpTypings = require("gulp-typings"); 5 | var sourcemaps = require('gulp-sourcemaps'); 6 | var tscConfig = require('./tsconfig.json'); 7 | var sass = require('gulp-sass'); 8 | var uglify = require('gulp-uglify'); 9 | var inlineNg2Template = require('gulp-inline-ng2-template'); 10 | var runSequence = require('run-sequence'); 11 | 12 | gulp.task('clean', function () { 13 | return del.sync('lib/**/*'); 14 | }); 15 | 16 | gulp.task("typings", function () { 17 | return gulp.src("./typings.json").pipe(gulpTypings()); 18 | }); 19 | 20 | gulp.task('sass', function () { 21 | return gulp.src('src/**/*.scss') 22 | .pipe(sass({outputStyle: 'compressed'})) 23 | .pipe(gulp.dest('src')); 24 | }); 25 | 26 | gulp.task('createts', function () { 27 | return gulp.src(['src/**/*.ts']) 28 | .pipe(inlineNg2Template({base: '/src'})) 29 | .pipe(gulp.dest('lib')); 30 | }); 31 | 32 | gulp.task('compile:lib', function () { 33 | var r = gulp.src(['typings/index.d.ts', 'lib/**/*.ts']) 34 | .pipe(sourcemaps.init()) 35 | .pipe(tsc(tscConfig.compilerOptions)); 36 | 37 | r.dts.pipe(gulp.dest('lib')); 38 | r.js.pipe(uglify()).pipe(gulp.dest('lib')); 39 | 40 | return r.pipe(sourcemaps.write('.')) 41 | .pipe(gulp.dest('lib')); 42 | }); 43 | 44 | gulp.task('compile:index', function () { 45 | var r = gulp.src(['typings/index.d.ts', 'index.ts']) 46 | .pipe(sourcemaps.init()) 47 | .pipe(tsc(tscConfig.compilerOptions)); 48 | 49 | r.dts.pipe(gulp.dest('.')); 50 | r.js.pipe(gulp.dest('.')); 51 | 52 | return r.pipe(sourcemaps.write('.')) 53 | .pipe(gulp.dest('.')); 54 | }); 55 | 56 | gulp.task('clean:postcompile', function () { 57 | return del.sync('src/templates/default/color-picker.css'); 58 | }); 59 | 60 | gulp.task('default', function (callback) { 61 | runSequence('clean', 'typings', 'sass', 'createts', 'compile:lib', 'compile:index', 'clean:postcompile', callback); 62 | }); 63 | 64 | //copy the library to example/node_modules/angular2-color-picker and examples_webpack/node_modules/angular2-color-picker 65 | gulp.task('copylib', function (callback) { 66 | runSequence('clean:examples', 'copy:lib', 'copy:index', callback); 67 | }); 68 | 69 | gulp.task('copy:lib', function () { 70 | return gulp.src(['lib/**/*']) 71 | .pipe(gulp.dest('examples_webpack/node_modules/angular2-color-picker/lib')) 72 | .pipe(gulp.dest('examples/node_modules/angular2-color-picker/lib')); 73 | }); 74 | 75 | gulp.task('copy:index', function () { 76 | return gulp.src(['index.*']) 77 | .pipe(gulp.dest('examples/node_modules/angular2-color-picker')) 78 | .pipe(gulp.dest('examples/node_modules/angular2-color-picker')); 79 | }); 80 | 81 | gulp.task('clean:examples', function () { 82 | return del.sync('examples_webpack/node_modules/angular2-color-picker/**/*', 'examples/node_modules/angular2-color-picker/**/*'); 83 | }); -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/index'; 2 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | redirect_to: "http://alberplz.github.io/angular2-color-picker/examples/index.html" 3 | --- -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function __export(m) { 3 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; 4 | } 5 | __export(require("./lib/index")); 6 | 7 | //# sourceMappingURL=index.js.map 8 | -------------------------------------------------------------------------------- /index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["index.ts"],"names":[],"mappings":";;;;AAAA,iCAA4B","file":"index.js","sourcesContent":["export * from './lib/index';"]} -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/index'; -------------------------------------------------------------------------------- /lib/classes.d.ts: -------------------------------------------------------------------------------- 1 | export declare class Hsva { 2 | h: number; 3 | s: number; 4 | v: number; 5 | a: number; 6 | constructor(h: number, s: number, v: number, a: number); 7 | } 8 | export declare class Hsla { 9 | h: number; 10 | s: number; 11 | l: number; 12 | a: number; 13 | constructor(h: number, s: number, l: number, a: number); 14 | } 15 | export declare class Rgba { 16 | r: number; 17 | g: number; 18 | b: number; 19 | a: number; 20 | constructor(r: number, g: number, b: number, a: number); 21 | } 22 | export declare class SliderPosition { 23 | h: number; 24 | s: number; 25 | v: number; 26 | a: number; 27 | constructor(h: number, s: number, v: number, a: number); 28 | } 29 | export declare class SliderDimension { 30 | h: number; 31 | s: number; 32 | v: number; 33 | a: number; 34 | constructor(h: number, s: number, v: number, a: number); 35 | } 36 | -------------------------------------------------------------------------------- /lib/classes.js: -------------------------------------------------------------------------------- 1 | "use strict";var Hsva=function(){function i(i,t,s,n){this.h=i,this.s=t,this.v=s,this.a=n}return i}();exports.Hsva=Hsva;var Hsla=function(){function i(i,t,s,n){this.h=i,this.s=t,this.l=s,this.a=n}return i}();exports.Hsla=Hsla;var Rgba=function(){function i(i,t,s,n){this.r=i,this.g=t,this.b=s,this.a=n}return i}();exports.Rgba=Rgba;var SliderPosition=function(){function i(i,t,s,n){this.h=i,this.s=t,this.v=s,this.a=n}return i}();exports.SliderPosition=SliderPosition;var SliderDimension=function(){function i(i,t,s,n){this.h=i,this.s=t,this.v=s,this.a=n}return i}();exports.SliderDimension=SliderDimension; -------------------------------------------------------------------------------- /lib/classes.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["classes.ts"],"names":[],"mappings":";AAAA;IACI,cAAmB,CAAS,EAAS,CAAS,EAAS,CAAS,EAAS,CAAS;QAA/D,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;IAAI,CAAC;IAC3F,WAAC;AAAD,CAFA,AAEC,IAAA;AAFY,oBAAI;AAGjB;IACI,cAAmB,CAAS,EAAS,CAAS,EAAS,CAAS,EAAS,CAAS;QAA/D,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;IAAI,CAAC;IAC3F,WAAC;AAAD,CAFA,AAEC,IAAA;AAFY,oBAAI;AAGjB;IACI,cAAmB,CAAS,EAAS,CAAS,EAAS,CAAS,EAAS,CAAS;QAA/D,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;IAAI,CAAC;IAC3F,WAAC;AAAD,CAFA,AAEC,IAAA;AAFY,oBAAI;AAGjB;IACI,wBAAmB,CAAS,EAAS,CAAS,EAAS,CAAS,EAAS,CAAS;QAA/D,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;IAAI,CAAC;IAC3F,qBAAC;AAAD,CAFA,AAEC,IAAA;AAFY,wCAAc;AAG3B;IACI,yBAAmB,CAAS,EAAS,CAAS,EAAS,CAAS,EAAS,CAAS;QAA/D,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;QAAS,MAAC,GAAD,CAAC,CAAQ;IAAI,CAAC;IAC3F,sBAAC;AAAD,CAFA,AAEC,IAAA;AAFY,0CAAe","file":"classes.js","sourcesContent":["export class Hsva {\n constructor(public h: number, public s: number, public v: number, public a: number) { }\n}\nexport class Hsla {\n constructor(public h: number, public s: number, public l: number, public a: number) { }\n}\nexport class Rgba {\n constructor(public r: number, public g: number, public b: number, public a: number) { }\n}\nexport class SliderPosition {\n constructor(public h: number, public s: number, public v: number, public a: number) { }\n}\nexport class SliderDimension {\n constructor(public h: number, public s: number, public v: number, public a: number) { }\n}"]} -------------------------------------------------------------------------------- /lib/classes.ts: -------------------------------------------------------------------------------- 1 | export class Hsva { 2 | constructor(public h: number, public s: number, public v: number, public a: number) { } 3 | } 4 | export class Hsla { 5 | constructor(public h: number, public s: number, public l: number, public a: number) { } 6 | } 7 | export class Rgba { 8 | constructor(public r: number, public g: number, public b: number, public a: number) { } 9 | } 10 | export class SliderPosition { 11 | constructor(public h: number, public s: number, public v: number, public a: number) { } 12 | } 13 | export class SliderDimension { 14 | constructor(public h: number, public s: number, public v: number, public a: number) { } 15 | } -------------------------------------------------------------------------------- /lib/color-picker.directive.d.ts: -------------------------------------------------------------------------------- 1 | import { OnChanges, ViewContainerRef, ElementRef, EventEmitter, OnInit } from '@angular/core'; 2 | import { ColorPickerService } from './color-picker.service'; 3 | import { Compiler } from '@angular/core'; 4 | export declare class ColorPickerDirective implements OnInit, OnChanges { 5 | private compiler; 6 | private vcRef; 7 | private el; 8 | private service; 9 | colorPicker: string; 10 | colorPickerChange: EventEmitter; 11 | cpToggle: boolean; 12 | cpToggleChange: EventEmitter; 13 | cpPosition: string; 14 | cpPositionOffset: string; 15 | cpPositionRelativeToArrow: boolean; 16 | cpOutputFormat: string; 17 | cpPresetLabel: string; 18 | cpPresetColors: Array; 19 | cpCancelButton: boolean; 20 | cpCancelButtonClass: string; 21 | cpCancelButtonText: string; 22 | cpOKButton: boolean; 23 | cpOKButtonClass: string; 24 | cpOKButtonText: string; 25 | cpFallbackColor: string; 26 | cpHeight: string; 27 | cpWidth: string; 28 | cpIgnoredElements: any; 29 | cpDialogDisplay: string; 30 | cpSaveClickOutside: boolean; 31 | cpAlphaChannel: string; 32 | private dialog; 33 | private created; 34 | private ignoreChanges; 35 | constructor(compiler: Compiler, vcRef: ViewContainerRef, el: ElementRef, service: ColorPickerService); 36 | ngOnChanges(changes: any): void; 37 | ngOnInit(): void; 38 | onClick(): void; 39 | openDialog(): void; 40 | colorChanged(value: string, ignore?: boolean): void; 41 | changeInput(value: string): void; 42 | toggle(value: boolean): void; 43 | } 44 | export declare class TextDirective { 45 | newValue: EventEmitter; 46 | text: any; 47 | rg: number; 48 | changeInput(value: string): void; 49 | } 50 | export declare class SliderDirective { 51 | private el; 52 | newValue: EventEmitter; 53 | slider: string; 54 | rgX: number; 55 | rgY: number; 56 | private listenerMove; 57 | private listenerStop; 58 | constructor(el: ElementRef); 59 | setCursor(event: any): void; 60 | move(event: any): void; 61 | start(event: any): void; 62 | stop(): void; 63 | getX(event: any): number; 64 | getY(event: any): number; 65 | } 66 | export declare class DialogComponent implements OnInit { 67 | private el; 68 | private service; 69 | private hsva; 70 | private rgbaText; 71 | private hslaText; 72 | private hexText; 73 | private outputColor; 74 | private selectedColor; 75 | private alphaSliderColor; 76 | private hueSliderColor; 77 | private slider; 78 | private sliderDimMax; 79 | private format; 80 | private show; 81 | private top; 82 | private left; 83 | private position; 84 | private directiveInstance; 85 | private initialColor; 86 | private directiveElementRef; 87 | private listenerMouseDown; 88 | private listenerResize; 89 | private cpPosition; 90 | private cpPositionOffset; 91 | private cpOutputFormat; 92 | private cpPresetLabel; 93 | private cpPresetColors; 94 | private cpCancelButton; 95 | private cpCancelButtonClass; 96 | private cpCancelButtonText; 97 | private cpOKButton; 98 | private cpOKButtonClass; 99 | private cpOKButtonText; 100 | private cpHeight; 101 | private cpWidth; 102 | private cpIgnoredElements; 103 | private cpDialogDisplay; 104 | private cpSaveClickOutside; 105 | private cpAlphaChannel; 106 | private dialogArrowSize; 107 | private dialogArrowOffset; 108 | private arrowTop; 109 | hueSlider: any; 110 | alphaSlider: any; 111 | dialogElement: any; 112 | constructor(el: ElementRef, service: ColorPickerService); 113 | setDialog(instance: any, elementRef: ElementRef, color: any, cpPosition: string, cpPositionOffset: string, cpPositionRelativeToArrow: boolean, cpOutputFormat: string, cpPresetLabel: string, cpPresetColors: Array, cpCancelButton: boolean, cpCancelButtonClass: string, cpCancelButtonText: string, cpOKButton: boolean, cpOKButtonClass: string, cpOKButtonText: string, cpHeight: string, cpWidth: string, cpIgnoredElements: any, cpDialogDisplay: string, cpSaveClickOutside: boolean, cpAlphaChannel: string): void; 114 | ngOnInit(): void; 115 | setInitialColor(color: any): void; 116 | openDialog(color: any, emit?: boolean): void; 117 | cancelColor(): void; 118 | oKColor(): void; 119 | setColorFromString(value: string, emit?: boolean): void; 120 | onMouseDown(event: any): void; 121 | openColorPicker(): void; 122 | closeColorPicker(): void; 123 | onResize(): void; 124 | setDialogPosition(): void; 125 | setSaturation(val: { 126 | v: number; 127 | rg: number; 128 | }): void; 129 | setLightness(val: { 130 | v: number; 131 | rg: number; 132 | }): void; 133 | setHue(val: { 134 | v: number; 135 | rg: number; 136 | }): void; 137 | setAlpha(val: { 138 | v: number; 139 | rg: number; 140 | }): void; 141 | setR(val: { 142 | v: number; 143 | rg: number; 144 | }): void; 145 | setG(val: { 146 | v: number; 147 | rg: number; 148 | }): void; 149 | setB(val: { 150 | v: number; 151 | rg: number; 152 | }): void; 153 | setSaturationAndBrightness(val: { 154 | s: number; 155 | v: number; 156 | rgX: number; 157 | rgY: number; 158 | }): void; 159 | formatPolicy(): number; 160 | update(emit?: boolean): void; 161 | isDescendant(parent: any, child: any): boolean; 162 | createBox(element: any, offset: boolean): any; 163 | } 164 | -------------------------------------------------------------------------------- /lib/color-picker.module.d.ts: -------------------------------------------------------------------------------- 1 | export declare class ColorPickerModule { 2 | } 3 | -------------------------------------------------------------------------------- /lib/color-picker.module.js: -------------------------------------------------------------------------------- 1 | "use strict";var __decorate=this&&this.__decorate||function(e,r,o,c){var i,t=arguments.length,l=t<3?r:null===c?c=Object.getOwnPropertyDescriptor(r,o):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,r,o,c);else for(var _=e.length-1;_>=0;_--)(i=e[_])&&(l=(t<3?i(l):t>3?i(r,o,l):i(r,o))||l);return t>3&&l&&Object.defineProperty(r,o,l),l},core_1=require("@angular/core"),common_1=require("@angular/common"),color_picker_service_1=require("./color-picker.service"),color_picker_directive_1=require("./color-picker.directive"),ColorPickerModule=function(){function e(){}return e}();ColorPickerModule=__decorate([core_1.NgModule({imports:[common_1.CommonModule],providers:[color_picker_service_1.ColorPickerService],declarations:[color_picker_directive_1.ColorPickerDirective],exports:[color_picker_directive_1.ColorPickerDirective]})],ColorPickerModule),exports.ColorPickerModule=ColorPickerModule; -------------------------------------------------------------------------------- /lib/color-picker.module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["color-picker.module.ts"],"names":[],"mappings":";;;;;;;AAAA,sCAAuC;AACvC,0CAA6C;AAE7C,+DAA0D;AAC1D,mEAA8D;AAQ9D,IAAa,iBAAiB;IAA9B;IAAgC,CAAC;IAAD,wBAAC;AAAD,CAAhC,AAAiC,IAAA;AAApB,iBAAiB;IAN7B,eAAQ,CAAC;QACN,OAAO,EAAE,CAAC,qBAAY,CAAC;QACvB,SAAS,EAAE,CAAC,yCAAkB,CAAC;QAC/B,YAAY,EAAE,CAAC,6CAAoB,CAAC;QACpC,OAAO,EAAE,CAAC,6CAAoB,CAAC;KAClC,CAAC;GACW,iBAAiB,CAAG;AAApB,8CAAiB","file":"color-picker.module.js","sourcesContent":["import {NgModule} from '@angular/core';\nimport {CommonModule} from '@angular/common';\n\nimport {ColorPickerService} from './color-picker.service';\nimport {ColorPickerDirective} from './color-picker.directive';\n\n@NgModule({\n imports: [CommonModule],\n providers: [ColorPickerService],\n declarations: [ColorPickerDirective],\n exports: [ColorPickerDirective]\n})\nexport class ColorPickerModule {}\n"]} -------------------------------------------------------------------------------- /lib/color-picker.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | 4 | import {ColorPickerService} from './color-picker.service'; 5 | import {ColorPickerDirective} from './color-picker.directive'; 6 | 7 | @NgModule({ 8 | imports: [CommonModule], 9 | providers: [ColorPickerService], 10 | declarations: [ColorPickerDirective], 11 | exports: [ColorPickerDirective] 12 | }) 13 | export class ColorPickerModule {} 14 | -------------------------------------------------------------------------------- /lib/color-picker.service.d.ts: -------------------------------------------------------------------------------- 1 | import { Rgba, Hsla, Hsva } from './classes'; 2 | export declare class ColorPickerService { 3 | constructor(); 4 | hsla2hsva(hsla: Hsla): Hsva; 5 | hsva2hsla(hsva: Hsva): Hsla; 6 | rgbaToHsva(rgba: Rgba): Hsva; 7 | hsvaToRgba(hsva: Hsva): Rgba; 8 | stringToHsva(colorString?: string, hex8?: boolean): Hsva; 9 | outputFormat(hsva: Hsva, outputFormat: string, allowHex8: boolean): string; 10 | hexText(rgba: Rgba, allowHex8: boolean): string; 11 | denormalizeRGBA(rgba: Rgba): Rgba; 12 | } 13 | -------------------------------------------------------------------------------- /lib/color-picker.service.js: -------------------------------------------------------------------------------- 1 | "use strict";var __decorate=this&&this.__decorate||function(a,e,s,r){var t,n=arguments.length,o=n<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,s):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(a,e,s,r);else for(var i=a.length-1;i>=0;i--)(t=a[i])&&(o=(n<3?t(o):n>3?t(e,s,o):t(e,s))||o);return n>3&&o&&Object.defineProperty(e,s,o),o},__metadata=this&&this.__metadata||function(a,e){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,e)},core_1=require("@angular/core"),classes_1=require("./classes"),ColorPickerService=function(){function a(){}return a.prototype.hsla2hsva=function(a){var e=Math.min(a.h,1),s=Math.min(a.s,1),r=Math.min(a.l,1),t=Math.min(a.a,1);if(0===r)return new classes_1.Hsva(e,0,0,t);var n=r+s*(1-Math.abs(2*r-1))/2;return new classes_1.Hsva(e,2*(n-r)/n,n,t)},a.prototype.hsva2hsla=function(a){var e=a.h,s=a.s,r=a.v,t=a.a;if(0===r)return new classes_1.Hsla(e,0,0,t);if(0===s&&1===r)return new classes_1.Hsla(e,1,1,t);var n=r*(2-s)/2;return new classes_1.Hsla(e,r*s/(1-Math.abs(2*n-1)),n,t)},a.prototype.rgbaToHsva=function(a){var e,s,r=Math.min(a.r,1),t=Math.min(a.g,1),n=Math.min(a.b,1),o=Math.min(a.a,1),i=Math.max(r,t,n),c=Math.min(r,t,n),h=i,l=i-c;if(s=0===i?0:l/i,i===c)e=0;else{switch(i){case r:e=(t-n)/l+(t 3 | This is a Color Picker Directive/Component for Angular 2. 4 | 5 | # Demo page 6 | http://alberplz.github.io/angular2-color-picker/examples/index.html 7 | 8 | # Installation 9 | ```bash 10 | npm i --save angular2-color-picker 11 | ``` 12 | 13 | # Usage 14 | * Use it in your HTML elements, for example: 15 | ```html 16 | 17 | ``` 18 | * Or: 19 | ```html 20 | 21 | ``` 22 | 23 | * Add ColorPickerModule in your app.module.ts: 24 | ```javascript 25 | import {ColorPickerModule} from 'angular2-color-picker'; 26 | 27 | @NgModule({ 28 | ... 29 | imports: [ColorPickerModule] 30 | }) 31 | 32 | ``` 33 | * Set color the variable. You can use ColorPickerService in your component if you want extra functions. 34 | ```javascript 35 | import {Component} from '@angular/core'; 36 | import {ColorPickerService} from 'angular2-color-picker'; 37 | 38 | @Component({ 39 | selector: 'my-app', 40 | templateUrl: 'app/demo.html' 41 | }) 42 | 43 | export class AppComponent { 44 | private color: string = "#127bdc"; 45 | constructor(private cpService: ColorPickerService) { 46 | } 47 | } 48 | ``` 49 | * Configure system.config.js 50 | ```javascript 51 | var map = { 52 | ... 53 | 'angular2-color-picker': 'node_modules/angular2-color-picker' 54 | }; 55 | var packages = { 56 | ... 57 | 'angular2-color-picker': {main:'index.js', defaultExtension: 'js'} 58 | }; 59 | ``` 60 | #Build 61 | ```bash 62 | git clone https://github.com/Alberplz/angular2-color-picker.git 63 | npm install 64 | cd agular2-color-picker 65 | npm run build 66 | gulp copylib 67 | ``` 68 | 69 | #Options 70 | Default option is the first item. 71 | ```html 72 | [cpOutputFormat]="'hex', 'rgba', 'hsla'" 73 | [cpPosition]="'right', 'left', 'top', 'bottom'" 74 | [cpPositionOffset]="'0%'" 75 | [cpPositionRelativeToArrow]="false, true" 76 | [cpWidth]="'230px'" 77 | [cpHeight]="'auto'" 78 | [cpSaveClickOutside]="true, false" 79 | [cpOKButton]="false, true" 80 | [cpOKButtonClass]="''" 81 | [cpOKButtonText]="'OK'" 82 | [cpCancelButton]="false, true" 83 | [cpCancelButtonClass]="''" 84 | [cpCancelButtonText]="'Cancel'" 85 | [cpFallbackColor]="'#fff'" 86 | [cpPresetLabel]="'Preset colors'" 87 | [cpPresetColors]="[]", e.g: "['#fff', '#000']" 88 | [cpToggle] = "false, true" 89 | [cpIgnoredElements]="[]" 90 | [cpDialogDisplay]="'popup,' 'inline'" 91 | [cpAlphaChannel]="'hex6', 'hex8', 'disabled'" 92 | ``` 93 | 94 | #Extra content 95 | If you want to change precalculated images for color picker sliders, you can find a little script in this project: 96 | https://github.com/Alberplz/angular-colorpicker-directive 97 | 98 | #Tested in: 99 | * Chrome 100 | * Firefox 101 | * Microsoft Edge 102 | * Opera 103 | * Safari 104 | * Internet Explorer 105 | 106 | #For previous version of Angular: 107 | https://github.com/Alberplz/angular-colorpicker-directive -------------------------------------------------------------------------------- /src/classes.ts: -------------------------------------------------------------------------------- 1 | export class Hsva { 2 | constructor(public h: number, public s: number, public v: number, public a: number) { } 3 | } 4 | export class Hsla { 5 | constructor(public h: number, public s: number, public l: number, public a: number) { } 6 | } 7 | export class Rgba { 8 | constructor(public r: number, public g: number, public b: number, public a: number) { } 9 | } 10 | export class SliderPosition { 11 | constructor(public h: number, public s: number, public v: number, public a: number) { } 12 | } 13 | export class SliderDimension { 14 | constructor(public h: number, public s: number, public v: number, public a: number) { } 15 | } -------------------------------------------------------------------------------- /src/color-picker.directive.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnChanges, Directive, Input, Output, ViewContainerRef, ElementRef, EventEmitter, OnInit, ViewChild} from '@angular/core'; 2 | import {ColorPickerService} from './color-picker.service'; 3 | import {Rgba, Hsla, Hsva, SliderPosition, SliderDimension} from './classes'; 4 | import {NgModule, Compiler, ReflectiveInjector} from '@angular/core'; 5 | import { BrowserModule } from '@angular/platform-browser'; 6 | 7 | @Directive({ 8 | selector: '[colorPicker]', 9 | host: { 10 | '(input)': 'changeInput($event.target.value)', 11 | '(click)': 'onClick()' 12 | } 13 | }) 14 | export class ColorPickerDirective implements OnInit, OnChanges { 15 | @Input('colorPicker') colorPicker: string; 16 | @Output('colorPickerChange') colorPickerChange = new EventEmitter(true); 17 | @Input('cpToggle') cpToggle: boolean; 18 | @Output('cpToggleChange') cpToggleChange = new EventEmitter(true); 19 | @Input('cpPosition') cpPosition: string = 'right'; 20 | @Input('cpPositionOffset') cpPositionOffset: string = '0%'; 21 | @Input('cpPositionRelativeToArrow') cpPositionRelativeToArrow: boolean = false; 22 | @Input('cpOutputFormat') cpOutputFormat: string = 'hex'; 23 | @Input('cpPresetLabel') cpPresetLabel: string = 'Preset colors'; 24 | @Input('cpPresetColors') cpPresetColors: Array; 25 | @Input('cpCancelButton') cpCancelButton: boolean = false; 26 | @Input('cpCancelButtonClass') cpCancelButtonClass: string = 'cp-cancel-button-class'; 27 | @Input('cpCancelButtonText') cpCancelButtonText: string = 'Cancel'; 28 | @Input('cpOKButton') cpOKButton: boolean = false; 29 | @Input('cpOKButtonClass') cpOKButtonClass: string = 'cp-ok-button-class'; 30 | @Input('cpOKButtonText') cpOKButtonText: string = 'OK'; 31 | @Input('cpFallbackColor') cpFallbackColor: string = '#fff'; 32 | @Input('cpHeight') cpHeight: string = 'auto'; 33 | @Input('cpWidth') cpWidth: string = '230px'; 34 | @Input('cpIgnoredElements') cpIgnoredElements: any = []; 35 | @Input('cpDialogDisplay') cpDialogDisplay: string = 'popup'; 36 | @Input('cpSaveClickOutside') cpSaveClickOutside: boolean = true; 37 | @Input('cpAlphaChannel') cpAlphaChannel: string = 'hex6'; 38 | 39 | private dialog: any; 40 | private created: boolean; 41 | private ignoreChanges: boolean = false; 42 | 43 | constructor(private compiler: Compiler, private vcRef: ViewContainerRef, private el: ElementRef, private service: ColorPickerService) { 44 | this.created = false; 45 | } 46 | 47 | ngOnChanges(changes: any): void { 48 | if (changes.cpToggle) { 49 | if (changes.cpToggle.currentValue) this.openDialog(); 50 | if (!changes.cpToggle.currentValue && this.dialog) this.dialog.closeColorPicker(); 51 | } 52 | if (changes.colorPicker) { 53 | if (this.dialog && !this.ignoreChanges) { 54 | if (this.cpDialogDisplay === 'inline') { 55 | this.dialog.setInitialColor(changes.colorPicker.currentValue); 56 | } 57 | this.dialog.setColorFromString(changes.colorPicker.currentValue, false); 58 | 59 | } 60 | this.ignoreChanges = false; 61 | } 62 | } 63 | 64 | ngOnInit() { 65 | let hsva = this.service.stringToHsva(this.colorPicker); 66 | if (hsva === null) hsva = this.service.stringToHsva(this.colorPicker, true); 67 | if (hsva == null) { 68 | hsva = this.service.stringToHsva(this.cpFallbackColor); 69 | } 70 | this.colorPickerChange.emit(this.service.outputFormat(hsva, this.cpOutputFormat, this.cpAlphaChannel === 'hex8')); 71 | } 72 | 73 | onClick() { 74 | if (this.cpIgnoredElements.filter((item: any) => item === this.el.nativeElement).length === 0) { 75 | this.openDialog(); 76 | } 77 | } 78 | 79 | openDialog() { 80 | if (!this.created) { 81 | this.created = true; 82 | this.compiler.compileModuleAndAllComponentsAsync(DynamicCpModule) 83 | .then(factory => { 84 | const compFactory = factory.componentFactories.find(x => x.componentType === DialogComponent); 85 | const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector); 86 | const cmpRef = this.vcRef.createComponent(compFactory, 0, injector, []); 87 | cmpRef.instance.setDialog(this, this.el, this.colorPicker, this.cpPosition, this.cpPositionOffset, 88 | this.cpPositionRelativeToArrow, this.cpOutputFormat, this.cpPresetLabel, this.cpPresetColors, 89 | this.cpCancelButton, this.cpCancelButtonClass, this.cpCancelButtonText, 90 | this.cpOKButton, this.cpOKButtonClass, this.cpOKButtonText, this.cpHeight, this.cpWidth, 91 | this.cpIgnoredElements, this.cpDialogDisplay, this.cpSaveClickOutside, this.cpAlphaChannel); 92 | this.dialog = cmpRef.instance; 93 | }); 94 | } else if (this.dialog) { 95 | this.dialog.openDialog(this.colorPicker); 96 | } 97 | } 98 | 99 | colorChanged(value: string, ignore: boolean = true) { 100 | this.ignoreChanges = ignore; 101 | this.colorPickerChange.emit(value) 102 | } 103 | 104 | changeInput(value: string) { 105 | this.dialog.setColorFromString(value, true); 106 | } 107 | 108 | toggle(value: boolean) { 109 | this.cpToggleChange.emit(value); 110 | } 111 | } 112 | 113 | 114 | @Directive({ 115 | selector: '[text]', 116 | host: { 117 | '(input)': 'changeInput($event.target.value)' 118 | } 119 | }) 120 | export class TextDirective { 121 | @Output('newValue') newValue = new EventEmitter(); 122 | @Input('text') text: any; 123 | @Input('rg') rg: number; 124 | 125 | changeInput(value: string) { 126 | if (this.rg === undefined) { 127 | this.newValue.emit(value); 128 | } else { 129 | let numeric = parseFloat(value) 130 | if (!isNaN(numeric) && numeric >= 0 && numeric <= this.rg) { 131 | this.newValue.emit({ v: numeric, rg: this.rg }); 132 | } 133 | } 134 | } 135 | } 136 | 137 | @Directive({ 138 | selector: '[slider]', 139 | host: { 140 | '(mousedown)': 'start($event)', 141 | '(touchstart)': 'start($event)' 142 | } 143 | }) 144 | export class SliderDirective { 145 | @Output('newValue') newValue = new EventEmitter(); 146 | @Input('slider') slider: string; 147 | @Input('rgX') rgX: number; 148 | @Input('rgY') rgY: number; 149 | private listenerMove: any; 150 | private listenerStop: any; 151 | 152 | constructor(private el: ElementRef) { 153 | this.listenerMove = (event: any) => { this.move(event) }; 154 | this.listenerStop = () => { this.stop() }; 155 | } 156 | 157 | setCursor(event: any) { 158 | let height = this.el.nativeElement.offsetHeight; 159 | let width = this.el.nativeElement.offsetWidth; 160 | let x = Math.max(0, Math.min(this.getX(event), width)); 161 | let y = Math.max(0, Math.min(this.getY(event), height)); 162 | 163 | if (this.rgX !== undefined && this.rgY !== undefined) { 164 | this.newValue.emit({ s: x / width, v: (1 - y / height), rgX: this.rgX, rgY: this.rgY }); 165 | } else if (this.rgX === undefined && this.rgY !== undefined) {//ready to use vertical sliders 166 | this.newValue.emit({ v: y / height, rg: this.rgY }); 167 | } else { 168 | this.newValue.emit({ v: x / width, rg: this.rgX }); 169 | } 170 | } 171 | 172 | move(event: any) { 173 | event.preventDefault(); 174 | this.setCursor(event); 175 | } 176 | 177 | start(event: any) { 178 | this.setCursor(event); 179 | document.addEventListener('mousemove', this.listenerMove); 180 | document.addEventListener('touchmove', this.listenerMove); 181 | document.addEventListener('mouseup', this.listenerStop); 182 | document.addEventListener('touchend', this.listenerStop); 183 | } 184 | 185 | stop() { 186 | document.removeEventListener('mousemove', this.listenerMove); 187 | document.removeEventListener('touchmove', this.listenerMove); 188 | document.removeEventListener('mouseup', this.listenerStop); 189 | document.removeEventListener('touchend', this.listenerStop); 190 | } 191 | 192 | getX(event: any): number { 193 | return (event.pageX !== undefined ? event.pageX : event.touches[0].pageX) - this.el.nativeElement.getBoundingClientRect().left - window.pageXOffset; 194 | } 195 | getY(event: any): number { 196 | return (event.pageY !== undefined ? event.pageY : event.touches[0].pageY) - this.el.nativeElement.getBoundingClientRect().top - window.pageYOffset; 197 | } 198 | } 199 | 200 | @Component({ 201 | selector: 'color-picker', 202 | templateUrl: './templates/default/color-picker.html', 203 | styleUrls: ['./templates/default/color-picker.css'] 204 | }) 205 | 206 | export class DialogComponent implements OnInit { 207 | private hsva: Hsva; 208 | private rgbaText: Rgba; 209 | private hslaText: Hsla; 210 | private hexText: string; 211 | private outputColor: string; 212 | private selectedColor: string; 213 | private alphaSliderColor: string; 214 | private hueSliderColor: string; 215 | private slider: SliderPosition; 216 | private sliderDimMax: SliderDimension; 217 | private format: number; 218 | private show: boolean; 219 | private top: number; 220 | private left: number; 221 | private position: string; 222 | private directiveInstance: any; 223 | private initialColor: string; 224 | private directiveElementRef: ElementRef; 225 | 226 | private listenerMouseDown: any; 227 | private listenerResize: any; 228 | 229 | private cpPosition: string; 230 | private cpPositionOffset: number; 231 | private cpOutputFormat: string; 232 | private cpPresetLabel: string; 233 | private cpPresetColors: Array; 234 | private cpCancelButton: boolean; 235 | private cpCancelButtonClass: string; 236 | private cpCancelButtonText: string; 237 | private cpOKButton: boolean; 238 | private cpOKButtonClass: string; 239 | private cpOKButtonText: string; 240 | private cpHeight: number; 241 | private cpWidth: number; 242 | private cpIgnoredElements: any; 243 | private cpDialogDisplay: string; 244 | private cpSaveClickOutside: boolean; 245 | private cpAlphaChannel: string; 246 | 247 | private dialogArrowSize: number = 10; 248 | private dialogArrowOffset: number = 15; 249 | private arrowTop: number; 250 | 251 | @ViewChild('hueSlider') hueSlider: any; 252 | @ViewChild('alphaSlider') alphaSlider: any; 253 | 254 | @ViewChild('dialogPopup') dialogElement: any; 255 | 256 | constructor(private el: ElementRef, private service: ColorPickerService) { } 257 | 258 | setDialog(instance: any, elementRef: ElementRef, color: any, cpPosition: string, cpPositionOffset: string, 259 | cpPositionRelativeToArrow: boolean, cpOutputFormat: string, cpPresetLabel: string, cpPresetColors: Array, 260 | cpCancelButton: boolean, cpCancelButtonClass: string, cpCancelButtonText: string, 261 | cpOKButton: boolean, cpOKButtonClass: string, cpOKButtonText: string, 262 | cpHeight: string, cpWidth: string, 263 | cpIgnoredElements: any, cpDialogDisplay: string, cpSaveClickOutside: boolean, cpAlphaChannel: string) { 264 | this.directiveInstance = instance; 265 | this.initialColor = color; 266 | this.directiveElementRef = elementRef; 267 | this.cpPosition = cpPosition; 268 | this.cpPositionOffset = parseInt(cpPositionOffset); 269 | if (!cpPositionRelativeToArrow) { 270 | this.dialogArrowOffset = 0; 271 | } 272 | this.cpOutputFormat = cpOutputFormat; 273 | this.cpPresetLabel = cpPresetLabel; 274 | this.cpPresetColors = cpPresetColors; 275 | this.cpCancelButton = cpCancelButton; 276 | this.cpCancelButtonClass = cpCancelButtonClass; 277 | this.cpCancelButtonText = cpCancelButtonText; 278 | this.cpOKButton = cpOKButton; 279 | this.cpOKButtonClass = cpOKButtonClass; 280 | this.cpOKButtonText = cpOKButtonText; 281 | this.cpHeight = parseInt(cpHeight); 282 | this.cpWidth = parseInt(cpWidth); 283 | this.cpIgnoredElements = cpIgnoredElements; 284 | this.cpDialogDisplay = cpDialogDisplay; 285 | if (this.cpDialogDisplay === 'inline') { 286 | this.dialogArrowOffset = 0; 287 | this.dialogArrowSize = 0; 288 | } 289 | this.cpSaveClickOutside = cpSaveClickOutside; 290 | this.cpAlphaChannel = cpAlphaChannel; 291 | } 292 | 293 | ngOnInit() { 294 | let alphaWidth = this.alphaSlider.nativeElement.offsetWidth; 295 | let hueWidth = this.hueSlider.nativeElement.offsetWidth; 296 | this.sliderDimMax = new SliderDimension(hueWidth, this.cpWidth, 130, alphaWidth); 297 | this.slider = new SliderPosition(0, 0, 0, 0); 298 | if (this.cpOutputFormat === 'rgba') { 299 | this.format = 1; 300 | } else if (this.cpOutputFormat === 'hsla') { 301 | this.format = 2; 302 | } else { 303 | this.format = 0; 304 | } 305 | this.listenerMouseDown = (event: any) => { this.onMouseDown(event) }; 306 | this.listenerResize = () => { this.onResize() }; 307 | this.openDialog(this.initialColor, false); 308 | } 309 | 310 | setInitialColor(color: any) { 311 | this.initialColor = color; 312 | } 313 | 314 | openDialog(color: any, emit: boolean = true) { 315 | this.setInitialColor(color); 316 | this.setColorFromString(color, emit); 317 | this.openColorPicker(); 318 | } 319 | 320 | cancelColor() { 321 | this.setColorFromString(this.initialColor, true); 322 | if (this.cpDialogDisplay === 'popup') { 323 | this.directiveInstance.colorChanged(this.initialColor, true); 324 | this.closeColorPicker(); 325 | } 326 | } 327 | 328 | oKColor() { 329 | if (this.cpDialogDisplay === 'popup') { 330 | this.closeColorPicker(); 331 | } 332 | } 333 | 334 | setColorFromString(value: string, emit: boolean = true) { 335 | let hsva: Hsva; 336 | if (this.cpAlphaChannel === 'hex8') { 337 | hsva = this.service.stringToHsva(value, true); 338 | if (!hsva && !this.hsva) { 339 | hsva = this.service.stringToHsva(value, false); 340 | } 341 | } else { 342 | hsva = this.service.stringToHsva(value, false); 343 | } 344 | if (hsva) { 345 | this.hsva = hsva; 346 | this.update(emit); 347 | } 348 | } 349 | 350 | onMouseDown(event: any) { 351 | if ((!this.isDescendant(this.el.nativeElement, event.target) 352 | && event.target != this.directiveElementRef.nativeElement && 353 | this.cpIgnoredElements.filter((item: any) => item === event.target).length === 0) && this.cpDialogDisplay === 'popup') { 354 | if (!this.cpSaveClickOutside) { 355 | this.setColorFromString(this.initialColor, false); 356 | this.directiveInstance.colorChanged(this.initialColor) 357 | } 358 | this.closeColorPicker(); 359 | } 360 | } 361 | 362 | openColorPicker() { 363 | if (!this.show) { 364 | this.setDialogPosition(); 365 | this.show = true; 366 | this.directiveInstance.toggle(true); 367 | document.addEventListener('mousedown', this.listenerMouseDown); 368 | window.addEventListener('resize', this.listenerResize); 369 | } 370 | } 371 | 372 | closeColorPicker() { 373 | if (this.show) { 374 | this.show = false; 375 | this.directiveInstance.toggle(false); 376 | document.removeEventListener('mousedown', this.listenerMouseDown); 377 | window.removeEventListener('resize', this.listenerResize); 378 | } 379 | } 380 | 381 | onResize() { 382 | if (this.position === 'fixed') { 383 | this.setDialogPosition(); 384 | } 385 | } 386 | 387 | setDialogPosition() { 388 | let dialogHeight = this.dialogElement.nativeElement.offsetHeight; 389 | let node = this.directiveElementRef.nativeElement, position = 'static'; 390 | let parentNode: any = null; 391 | while (node !== null && node.tagName !== 'HTML') { 392 | position = window.getComputedStyle(node).getPropertyValue("position"); 393 | if (position !== 'static' && parentNode === null) { 394 | parentNode = node; 395 | } 396 | if (position === 'fixed') { 397 | break; 398 | } 399 | node = node.parentNode; 400 | } 401 | if (position !== 'fixed') { 402 | var boxDirective = this.createBox(this.directiveElementRef.nativeElement, true); 403 | if (parentNode === null) { parentNode = node } 404 | var boxParent = this.createBox(parentNode, true); 405 | this.top = boxDirective.top - boxParent.top; 406 | this.left = boxDirective.left - boxParent.left; 407 | } else { 408 | var boxDirective = this.createBox(this.directiveElementRef.nativeElement, false); 409 | this.top = boxDirective.top; 410 | this.left = boxDirective.left; 411 | this.position = 'fixed'; 412 | } 413 | if (this.cpPosition === 'left') { 414 | this.top += boxDirective.height * this.cpPositionOffset / 100 - this.dialogArrowOffset; 415 | this.left -= this.cpWidth + this.dialogArrowSize - 2; 416 | } else if (this.cpPosition === 'top') { 417 | this.top -= dialogHeight + this.dialogArrowSize; 418 | this.left += this.cpPositionOffset / 100 * boxDirective.width - this.dialogArrowOffset; 419 | this.arrowTop = dialogHeight - 1; 420 | } else if (this.cpPosition === 'bottom') { 421 | this.top += boxDirective.height + this.dialogArrowSize; 422 | this.left += this.cpPositionOffset / 100 * boxDirective.width - this.dialogArrowOffset; 423 | } else { 424 | this.top += boxDirective.height * this.cpPositionOffset / 100 - this.dialogArrowOffset; 425 | this.left += boxDirective.width + this.dialogArrowSize; 426 | } 427 | } 428 | 429 | setSaturation(val: { v: number, rg: number }) { 430 | let hsla = this.service.hsva2hsla(this.hsva); 431 | hsla.s = val.v / val.rg; 432 | this.hsva = this.service.hsla2hsva(hsla); 433 | this.update(); 434 | } 435 | 436 | setLightness(val: { v: number, rg: number }) { 437 | let hsla = this.service.hsva2hsla(this.hsva); 438 | hsla.l = val.v / val.rg; 439 | this.hsva = this.service.hsla2hsva(hsla); 440 | this.update(); 441 | } 442 | 443 | setHue(val: { v: number, rg: number }) { 444 | this.hsva.h = val.v / val.rg; 445 | this.update(); 446 | } 447 | 448 | setAlpha(val: { v: number, rg: number }) { 449 | this.hsva.a = val.v / val.rg; 450 | this.update(); 451 | } 452 | 453 | setR(val: { v: number, rg: number }) { 454 | let rgba = this.service.hsvaToRgba(this.hsva); 455 | rgba.r = val.v / val.rg; 456 | this.hsva = this.service.rgbaToHsva(rgba); 457 | this.update(); 458 | } 459 | setG(val: { v: number, rg: number }) { 460 | let rgba = this.service.hsvaToRgba(this.hsva); 461 | rgba.g = val.v / val.rg; 462 | this.hsva = this.service.rgbaToHsva(rgba); 463 | this.update(); 464 | } 465 | setB(val: { v: number, rg: number }) { 466 | let rgba = this.service.hsvaToRgba(this.hsva); 467 | rgba.b = val.v / val.rg; 468 | this.hsva = this.service.rgbaToHsva(rgba); 469 | this.update(); 470 | } 471 | 472 | setSaturationAndBrightness(val: { s: number, v: number, rgX: number, rgY: number }) { 473 | this.hsva.s = val.s / val.rgX; 474 | this.hsva.v = val.v / val.rgY; 475 | this.update(); 476 | } 477 | 478 | formatPolicy(): number { 479 | this.format = (this.format + 1) % 3; 480 | if (this.format === 0 && this.hsva.a < 1 && this.cpAlphaChannel === 'hex6') { 481 | this.format++; 482 | } 483 | return this.format; 484 | } 485 | 486 | update(emit: boolean = true) { 487 | let hsla = this.service.hsva2hsla(this.hsva); 488 | let rgba = this.service.denormalizeRGBA(this.service.hsvaToRgba(this.hsva)); 489 | let hueRgba = this.service.denormalizeRGBA(this.service.hsvaToRgba(new Hsva(this.hsva.h, 1, 1, 1))); 490 | 491 | this.hslaText = new Hsla(Math.round((hsla.h) * 360), Math.round(hsla.s * 100), Math.round(hsla.l * 100), Math.round(hsla.a * 100) / 100); 492 | this.rgbaText = new Rgba(rgba.r, rgba.g, rgba.b, Math.round(rgba.a * 100) / 100); 493 | this.hexText = this.service.hexText(rgba, this.cpAlphaChannel === 'hex8'); 494 | 495 | this.alphaSliderColor = 'rgb(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ')'; 496 | this.hueSliderColor = 'rgb(' + hueRgba.r + ',' + hueRgba.g + ',' + hueRgba.b + ')'; 497 | 498 | if (this.format === 0 && this.hsva.a < 1 && this.cpAlphaChannel === 'hex6') { 499 | this.format++; 500 | } 501 | 502 | let lastOutput = this.outputColor; 503 | this.outputColor = this.service.outputFormat(this.hsva, this.cpOutputFormat, this.cpAlphaChannel === 'hex8'); 504 | this.selectedColor = this.service.outputFormat(this.hsva, 'rgba', false); 505 | 506 | this.slider = new SliderPosition((this.hsva.h) * this.sliderDimMax.h - 8, this.hsva.s * this.sliderDimMax.s - 8, 507 | (1 - this.hsva.v) * this.sliderDimMax.v - 8, this.hsva.a * this.sliderDimMax.a - 8) 508 | 509 | if (emit && lastOutput !== this.outputColor) { 510 | this.directiveInstance.colorChanged(this.outputColor); 511 | } 512 | } 513 | 514 | isDescendant(parent: any, child: any): boolean { 515 | let node: any = child.parentNode; 516 | while (node !== null) { 517 | if (node === parent) { 518 | return true; 519 | } 520 | node = node.parentNode; 521 | } 522 | return false; 523 | } 524 | 525 | createBox(element: any, offset: boolean): any { 526 | return { 527 | top: element.getBoundingClientRect().top + (offset ? window.pageYOffset : 0), 528 | left: element.getBoundingClientRect().left + (offset ? window.pageXOffset : 0), 529 | width: element.offsetWidth, 530 | height: element.offsetHeight 531 | }; 532 | } 533 | } 534 | 535 | @NgModule({ 536 | imports: [BrowserModule], 537 | declarations: [DialogComponent, TextDirective, SliderDirective] 538 | }) 539 | class DynamicCpModule { }; -------------------------------------------------------------------------------- /src/color-picker.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | 4 | import {ColorPickerService} from './color-picker.service'; 5 | import {ColorPickerDirective} from './color-picker.directive'; 6 | 7 | @NgModule({ 8 | imports: [CommonModule], 9 | providers: [ColorPickerService], 10 | declarations: [ColorPickerDirective], 11 | exports: [ColorPickerDirective] 12 | }) 13 | export class ColorPickerModule {} 14 | -------------------------------------------------------------------------------- /src/color-picker.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Rgba, Hsla, Hsva} from './classes'; 3 | 4 | @Injectable() 5 | export class ColorPickerService { 6 | constructor() { } 7 | 8 | hsla2hsva(hsla: Hsla): Hsva { 9 | let h = Math.min(hsla.h, 1), s = Math.min(hsla.s, 1), l = Math.min(hsla.l, 1), a = Math.min(hsla.a, 1); 10 | if (l === 0) { 11 | return new Hsva(h, 0, 0, a); 12 | } else { 13 | let v = l + s * (1 - Math.abs(2 * l - 1)) / 2; 14 | return new Hsva(h, 2 * (v - l) / v, v, a); 15 | } 16 | } 17 | 18 | hsva2hsla(hsva: Hsva): Hsla { 19 | let h = hsva.h, s = hsva.s, v = hsva.v, a = hsva.a; 20 | if (v === 0) { 21 | return new Hsla(h, 0, 0, a) 22 | } else if (s === 0 && v === 1) { 23 | return new Hsla(h, 1, 1, a) 24 | } else { 25 | let l = v * (2 - s) / 2; 26 | return new Hsla(h, v * s / (1 - Math.abs(2 * l - 1)), l, a) 27 | } 28 | } 29 | 30 | rgbaToHsva(rgba: Rgba): Hsva { 31 | let r = Math.min(rgba.r, 1), g = Math.min(rgba.g, 1), b = Math.min(rgba.b, 1), a = Math.min(rgba.a, 1); 32 | let max = Math.max(r, g, b), min = Math.min(r, g, b); 33 | let h: number, s: number, v: number = max; 34 | 35 | let d = max - min; 36 | s = max === 0 ? 0 : d / max; 37 | 38 | if (max === min) { 39 | h = 0; 40 | } else { 41 | switch (max) { 42 | case r: 43 | h = (g - b) / d + (g < b ? 6 : 0); 44 | break; 45 | case g: 46 | h = (b - r) / d + 2; 47 | break; 48 | case b: 49 | h = (r - g) / d + 4; 50 | break; 51 | } 52 | h /= 6; 53 | } 54 | 55 | return new Hsva(h, s, v, a) 56 | } 57 | 58 | hsvaToRgba(hsva: Hsva): Rgba { 59 | let h = hsva.h, s = hsva.s, v = hsva.v, a = hsva.a; 60 | let r: number, g: number, b: number; 61 | 62 | let i = Math.floor(h * 6); 63 | let f = h * 6 - i; 64 | let p = v * (1 - s); 65 | let q = v * (1 - f * s); 66 | let t = v * (1 - (1 - f) * s); 67 | 68 | switch (i % 6) { 69 | case 0: 70 | r = v, g = t, b = p; 71 | break; 72 | case 1: 73 | r = q, g = v, b = p; 74 | break; 75 | case 2: 76 | r = p, g = v, b = t; 77 | break; 78 | case 3: 79 | r = p, g = q, b = v; 80 | break; 81 | case 4: 82 | r = t, g = p, b = v; 83 | break; 84 | case 5: 85 | r = v, g = p, b = q; 86 | break; 87 | } 88 | 89 | return new Rgba(r, g, b, a) 90 | } 91 | 92 | stringToHsva(colorString: string = '', hex8: boolean = false): Hsva { 93 | let stringParsers = [ 94 | { 95 | re: /(rgb)a?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*%?,\s*(\d{1,3})\s*%?(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 96 | parse: function(execResult: any) { 97 | return new Rgba(parseInt(execResult[2]) / 255, 98 | parseInt(execResult[3]) / 255, 99 | parseInt(execResult[4]) / 255, 100 | isNaN(parseFloat(execResult[5])) ? 1 : parseFloat(execResult[5])); 101 | } 102 | }, 103 | { 104 | re: /(hsl)a?\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 105 | parse: function(execResult: any) { 106 | return new Hsla(parseInt(execResult[2]) / 360, 107 | parseInt(execResult[3]) / 100, 108 | parseInt(execResult[4]) / 100, 109 | isNaN(parseFloat(execResult[5])) ? 1 : parseFloat(execResult[5])); 110 | } 111 | } 112 | ]; 113 | if (hex8) { 114 | stringParsers.push({ 115 | re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/, 116 | parse: function(execResult: any) { 117 | return new Rgba(parseInt(execResult[1], 16) / 255, 118 | parseInt(execResult[2], 16) / 255, 119 | parseInt(execResult[3], 16) / 255, 120 | parseInt(execResult[4], 16) / 255); 121 | } 122 | }); 123 | } else { 124 | stringParsers.push({ 125 | re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/, 126 | parse: function(execResult: any) { 127 | return new Rgba(parseInt(execResult[1], 16) / 255, 128 | parseInt(execResult[2], 16) / 255, 129 | parseInt(execResult[3], 16) / 255, 130 | 1); 131 | } 132 | }, 133 | { 134 | re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/, 135 | parse: function(execResult: any) { 136 | return new Rgba(parseInt(execResult[1] + execResult[1], 16) / 255, 137 | parseInt(execResult[2] + execResult[2], 16) / 255, 138 | parseInt(execResult[3] + execResult[3], 16) / 255, 139 | 1); 140 | } 141 | }); 142 | } 143 | 144 | 145 | colorString = colorString.toLowerCase(); 146 | let hsva: Hsva = null; 147 | for (let key in stringParsers) { 148 | if (stringParsers.hasOwnProperty(key)) { 149 | let parser = stringParsers[key]; 150 | let match = parser.re.exec(colorString), color: any = match && parser.parse(match); 151 | if (color) { 152 | if (color instanceof Rgba) { 153 | hsva = this.rgbaToHsva(color); 154 | } else if (color instanceof Hsla) { 155 | hsva = this.hsla2hsva(color); 156 | } 157 | return hsva; 158 | } 159 | } 160 | } 161 | return hsva; 162 | } 163 | 164 | outputFormat(hsva: Hsva, outputFormat: string, allowHex8: boolean): string { 165 | if (hsva.a < 1) { 166 | switch (outputFormat) { 167 | case 'hsla': 168 | let hsla = this.hsva2hsla(hsva); 169 | let hslaText = new Hsla(Math.round((hsla.h) * 360), Math.round(hsla.s * 100), Math.round(hsla.l * 100), Math.round(hsla.a * 100) / 100); 170 | return 'hsla(' + hslaText.h + ',' + hslaText.s + '%,' + hslaText.l + '%,' + hslaText.a + ')'; 171 | default: 172 | if (allowHex8 && outputFormat === 'hex') 173 | return this.hexText(this.denormalizeRGBA(this.hsvaToRgba(hsva)), allowHex8); 174 | let rgba = this.denormalizeRGBA(this.hsvaToRgba(hsva)); 175 | return 'rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + Math.round(rgba.a * 100) / 100 + ')'; 176 | } 177 | } else { 178 | switch (outputFormat) { 179 | case 'hsla': 180 | let hsla = this.hsva2hsla(hsva); 181 | let hslaText = new Hsla(Math.round((hsla.h) * 360), Math.round(hsla.s * 100), Math.round(hsla.l * 100), Math.round(hsla.a * 100) / 100); 182 | return 'hsl(' + hslaText.h + ',' + hslaText.s + '%,' + hslaText.l + '%)'; 183 | case 'rgba': 184 | let rgba = this.denormalizeRGBA(this.hsvaToRgba(hsva)); 185 | return 'rgb(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ')'; 186 | default: 187 | return this.hexText(this.denormalizeRGBA(this.hsvaToRgba(hsva)), allowHex8); 188 | } 189 | } 190 | } 191 | 192 | hexText(rgba: Rgba, allowHex8: boolean): string { 193 | let hexText = '#' + ((1 << 24) | (rgba.r << 16) | (rgba.g << 8) | rgba.b).toString(16).substr(1); 194 | if (hexText[1] === hexText[2] && hexText[3] === hexText[4] && hexText[5] === hexText[6] && rgba.a === 1 && !allowHex8) { 195 | hexText = '#' + hexText[1] + hexText[3] + hexText[5]; 196 | } 197 | if (allowHex8) { 198 | hexText += ((1 << 8) | Math.round(rgba.a * 255)).toString(16).substr(1); 199 | } 200 | return hexText; 201 | } 202 | 203 | denormalizeRGBA(rgba: Rgba): Rgba { 204 | return new Rgba(Math.round(rgba.r * 255), Math.round(rgba.g * 255), Math.round(rgba.b * 255), rgba.a); 205 | } 206 | 207 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './classes'; 2 | export * from './color-picker.directive'; 3 | export * from './color-picker.module'; 4 | export * from './color-picker.service'; 5 | -------------------------------------------------------------------------------- /src/templates/default/color-picker.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 |
32 |
33 |
H
S
L
A
34 |
35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | 43 |
44 |
45 |
R
G
B
A
46 |
47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 |
Hex
55 |
56 |
57 | 58 |
59 | 60 |
61 |
62 | 63 |
{{cpPresetLabel}}
64 | 65 |
66 |
67 | 68 |
69 | 70 | 71 |
72 | 73 |
74 | -------------------------------------------------------------------------------- /src/templates/default/color-picker.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Styles for Color Picker 3 | * 4 | * Alberto Pujante 5 | * 6 | * @licence: http://opensource.org/licenses/MIT 7 | */ 8 | .color-picker *{ 9 | -webkit-box-sizing: border-box; 10 | -moz-box-sizing: border-box; 11 | box-sizing: border-box; 12 | margin:0; 13 | font-size:11px; 14 | } 15 | 16 | @mixin boder-radius($radius){ 17 | -moz-border-radius: $radius; 18 | -webkit-border-radius: $radius; 19 | border-radius: $radius; 20 | -khtml-border-radius: $radius; 21 | } 22 | 23 | .color-picker{ 24 | cursor: default; 25 | width: 230px; 26 | height: auto; 27 | border:#777 solid 1px; 28 | left:30px; 29 | top:250px; 30 | position:absolute; 31 | z-index:1000; 32 | background-color: #fff; 33 | 34 | -webkit-touch-callout: none; 35 | -webkit-user-select: none; 36 | -khtml-user-select: none; 37 | -moz-user-select: none; 38 | -ms-user-select: none; 39 | user-select: none; 40 | 41 | i{ 42 | cursor:default; 43 | position:relative; 44 | } 45 | 46 | input{ 47 | text-align: center; 48 | font-size: 13px; 49 | height: 26px; 50 | &:invalid{ 51 | box-shadow: none; 52 | } 53 | &:-moz-submit-invalid{ 54 | box-shadow: none; 55 | } 56 | &:-moz-ui-invalid{ 57 | box-shadow: none; 58 | } 59 | 60 | &::-webkit-inner-spin-button, 61 | &::-webkit-outer-spin-button{ 62 | -webkit-appearance: none; 63 | margin: 0; 64 | } 65 | -moz-appearance: textfield; 66 | } 67 | 68 | .button-area{ 69 | padding: 0 16px 16px 16px; 70 | text-align: right; 71 | } 72 | 73 | //.cp-cancel-button-class, cp-ok-button-class{ 74 | //text-align: center; 75 | //text-transform: uppercase; 76 | //} 77 | 78 | .preset-area { 79 | padding: 4px 15px; 80 | 81 | .preset-label { 82 | width: 100%; 83 | padding: 4px; 84 | font-size:11px; 85 | text-align: left; 86 | color: #555; 87 | } 88 | 89 | .preset-color { 90 | cursor: pointer; 91 | display: inline-block; 92 | width: 18px; 93 | height: 18px; 94 | margin: 4px 6px 8px 6px; 95 | @include boder-radius(25%); 96 | border: #a9a9a9 solid 1px; 97 | } 98 | } 99 | 100 | .arrow{ 101 | height: 0; 102 | width: 0; 103 | border-style: solid; 104 | position:absolute; 105 | z-index: 999999; 106 | } 107 | 108 | .arrow-right{ 109 | border-width: 5px 10px; 110 | border-color: rgba(0,0,0,0) #777 rgba(0,0,0,0) rgba(0,0,0,0); 111 | top: 10px; 112 | left:-20px; 113 | } 114 | 115 | .arrow-left{ 116 | border-width: 5px 10px; 117 | border-color: rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) #777; 118 | top: 10px; 119 | left:231px; 120 | } 121 | 122 | .arrow-bottom{ 123 | border-width: 10px 5px; 124 | border-color: rgba(0,0,0,0) rgba(0,0,0,0) #777 rgba(0,0,0,0); 125 | top: -20px; 126 | left:10px; 127 | } 128 | 129 | .arrow-top{ 130 | border-width: 10px 5px; 131 | border-color: #777 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0); 132 | //top: 289px; 133 | left:10px; 134 | } 135 | 136 | div.cursor-sv{ 137 | cursor:default; 138 | position:relative; 139 | @include boder-radius(50%); 140 | width: 15px; 141 | height: 15px; 142 | border: #ddd solid 1px; 143 | } 144 | 145 | div.cursor{ 146 | cursor:default; 147 | position:relative; 148 | @include boder-radius(50%); 149 | width: 16px; 150 | height: 16px; 151 | border: #222 solid 2px; 152 | } 153 | 154 | .saturation-lightness{ 155 | cursor: pointer; 156 | width: 100%; 157 | height: 130px; 158 | border:none; 159 | background-size: 100% 100%; 160 | background-image: url('data:image/png;base64,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'); 161 | } 162 | 163 | .box{ 164 | display: flex; 165 | padding: 4px 8px; 166 | 167 | .left{ 168 | position: relative; 169 | padding: 16px 8px; 170 | } 171 | .right{ 172 | flex: 1 1 auto; 173 | padding: 12px 8px; 174 | } 175 | } 176 | 177 | .hue{ 178 | cursor: pointer; 179 | width: 100%; 180 | height: 16px; 181 | border:none; 182 | margin-bottom: 16px; 183 | background-size: 100% 100%; 184 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwkUFWbCCAAAAFxJREFUaN7t0kEKg0AQAME2x83/n2qu5qCgD1iDhCoYdpnbQC9bbY1qVO/jvc6k3ad91s7/7F1/csgPrujuQ17BDYSFsBAWwgJhISyEBcJCWAgLhIWwEBYIi2f7Ar/1TCgFH2X9AAAAAElFTkSuQmCC'); 185 | } 186 | .alpha{ 187 | cursor: pointer; 188 | width: 100%; 189 | height: 16px; 190 | border:none; 191 | background-size: 100% 100%; 192 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwYQlZMa3gAAAWVJREFUaN7tmEGO6jAQRCsOArHgBpyAJYGjcGocxAm4A2IHpmoWE0eBH+ezmFlNvU06shJ3W6VEelWMUQAIIF9f6qZpimsA1LYtS2uF51/u27YVAFZVRUkEoGHdPV/sIcbIEIIkUdI/9Xa7neyv61+SWFUVAVCSct00TWn2fv6u3+Ecfd3tXzy/0+nEUu+SPjo/kqzrmiQpScN6v98XewfA8/lMkiLJ2WxGSUopcT6fM6U0NX9/frfbjev1WtfrlZfLhYfDQQHG/AIOlnGwjINlHCxjHCzjYJm/TJWdCwquJXseFFzGwDNNeiKMOJTO8xQdDQaeB29+K9efeLaBo9J7vdvtJj1RjFFjfiv7qv95tjx/7leSQgh93e1ffMeIp6O+YQjho/N791t1XVOSSI7N//K+4/GoxWLBx+PB5/Op5XLJ+/3OlJJWqxU3m83ovv5iGf8KjYNlHCxjHCzjYBkHy5gf5gusvQU7U37jTAAAAABJRU5ErkJggg=='); 193 | } 194 | 195 | .selected-color{ 196 | width: 40px; 197 | height: 40px; 198 | top: 16px; 199 | left: 8px; 200 | position:absolute; 201 | @include boder-radius(50%); 202 | } 203 | 204 | .selected-color-background{ 205 | width: 40px; 206 | height: 40px; 207 | @include boder-radius(50%); 208 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAh0lEQVRYR+2W0QlAMQgD60zdfwOdqa8TmI/wQMr5K0I5bZLIzLOa2nt37VVVbd+dDx5obgCC3KBLwJ2ff4PnVidkf+ucIhw80HQaCLo3DMH3CRK3iFsmAWVl6hPNDwt8EvNE5q+YuEXcMgkonVM6SdyCoEvAnZ8v1Hjx817MilmxSUB5rdLJDycZgUAZUch/AAAAAElFTkSuQmCC'); 209 | } 210 | 211 | .type-policy{ 212 | position: absolute; 213 | top: 215px; 214 | right: 12px; 215 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAgCAYAAAAffCjxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAACewAAAnsB01CO3AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIASURBVEiJ7ZY9axRRFIafsxMStrLQJpAgpBFhi+C9w1YSo00I6RZ/g9vZpBf/QOr4GyRgkSKNSrAadsZqQGwCkuAWyRZJsySwvhZ7N/vhzrgbLH3Ld8597jlzz50zJokyxXH8DqDVar0qi6v8BbItqSGpEcfxdlmsFWXkvX8AfAVWg3UKPEnT9GKujMzsAFgZsVaCN1VTQd77XUnrgE1kv+6935268WRpzrnHZvYRWC7YvC3pRZZl3wozqtVqiyH9IgjAspkd1Gq1xUJQtVrdB9ZKIAOthdg/Qc65LUk7wNIMoCVJO865rYFhkqjX6/d7vV4GPJwBMqofURS5JEk6FYBer/eeYb/Mo9WwFnPOvQbeAvfuAAK4BN4sAJtAG/gJIElmNuiJyba3EGNmZiPeZuEVmVell/Y/6N+CzDn3AXhEOOo7Hv/3BeAz8IzQkMPnJbuPx1wC+yYJ7/0nYIP5S/0FHKdp+rwCEEXRS/rf5Hl1Gtb2M0iSpCOpCZzPATmX1EySpHMLAsiy7MjMDoHrGSDXZnaYZdnRwBh7J91utwmczAA6CbG3GgPleX4jqUH/a1CktqRGnuc3hSCAMB32gKspkCtgb3KCQMmkjeP4WNJThrNNZval1WptTIsv7JtQ4tmIdRa8qSoEpWl6YWZNoAN0zKxZNPehpLSBZv2t+Q0CJ9lLnARQLAAAAABJRU5ErkJggg=='); 216 | background-repeat: no-repeat; 217 | background-position: center; 218 | background-size: 8px 16px; 219 | -moz-background-size: 8px 16px; 220 | -webkit-background-size: 8px 16px; 221 | -o-background-size: 8px 16px; 222 | width:16px; 223 | height:24px; 224 | } 225 | 226 | .hsla-text, .rgba-text{ 227 | width: 100%; 228 | font-size:11px; 229 | padding: 4px 8px; 230 | 231 | .box{ 232 | padding: 0 24px 8px 8px; 233 | input{ 234 | min-width: 0; 235 | flex: 1; 236 | margin: 0; 237 | float:left; 238 | margin-right:8px; 239 | border: #a9a9a9 solid 1px; 240 | padding: 1px; 241 | 242 | &:last-child{ 243 | margin-right: 0; 244 | } 245 | } 246 | div{ 247 | flex: 1 1 auto; 248 | text-align: center; 249 | color: #555; 250 | margin-right:8px; 251 | 252 | &:last-child{ 253 | margin-right: 0; 254 | } 255 | } 256 | } 257 | } 258 | 259 | .hex-text{ 260 | width: 100%; 261 | font-size: 11px; 262 | padding: 4px 8px; 263 | 264 | .box{ 265 | padding: 0 24px 8px 8px; 266 | input{ 267 | flex: 1 1 auto; 268 | border: #a9a9a9 solid 1px; 269 | padding: 1px; 270 | } 271 | div{ 272 | flex: 1 1 auto; 273 | text-align: center; 274 | color: #555; 275 | float:left; 276 | clear: left; 277 | } 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": false, 11 | "declaration": true 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | "examples", 16 | "examples_webpack" 17 | ] 18 | } -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160725163759", 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", 5 | "node": "registry:dt/node#6.0.0+20160909174046" 6 | } 7 | } --------------------------------------------------------------------------------