@thednp/color-picker 0.0.1 → 0.0.2-alpha1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ // Color v0.0.2alpha1 | thednp © 2022 | MIT-License
2
+ !function(t,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(t="undefined"!=typeof globalThis?globalThis:t||self).Color=r()}(this,(function(){"use strict";const{head:t}=document;function r(t,r){const e=getComputedStyle(t);return r in e?e[r]:""}const e=(t,r)=>Object.assign(t,r),n=(t,r)=>{e(t.style,r)},o=["transparent","currentColor","inherit","revert","initial"];function s(t){const r=Math.floor(t);return t-r<.5?r:Math.round(t)}const a=["rgb","hex","hsl","hsv","hwb"],i="[-\\+]?\\d*\\.?\\d+(?:deg|rad|grad|turn)?",h="(?:[-\\+]?\\d*\\.\\d+%?)|(?:[-\\+]?\\d+%?)",u=`(?:${h})|(?:${i})`,c="(?:[,|\\s]+)",b=`(?:[\\s|\\(\\s|\\s\\(\\s]+)?(${u})${c}(${h})${c}(${h})(?:[,|\\/\\s]*)?(${h})?(?:[\\s|\\)\\s]+)?`,g={CSS_UNIT:new RegExp(u),hwb:new RegExp("hwb"+b),rgb:new RegExp("rgb(?:a)?"+b),hsl:new RegExp("hsl(?:a)?"+b),hsv:new RegExp("hsv(?:a)?"+b),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/};function l(t){return(""+t).includes(".")&&1===parseFloat(t)}function f(t){return(""+t).includes("%")}function m(e){return!o.includes(e)&&!["#",...a].some(t=>e.includes(t))&&["rgb(255, 255, 255)","rgb(0, 0, 0)"].every(o=>{n(t,{color:e});const s=r(t,"color");return n(t,{color:""}),s!==o})}function p(t){return Boolean(g.CSS_UNIT.exec(String(t)))}function d(t,r){let e=t;l(t)&&(e="100%");const n=f(e);return e=360===r?parseFloat(e):Math.min(r,Math.max(0,parseFloat(e))),n&&(e=e*r/100),Math.abs(e-r)<1e-6?1:(e=360===r?(e<0?e%r+r:e%r)/r:e%r/r,e)}function x(t){let r=parseFloat(""+t);return(Number.isNaN(r)||r<0||r>1)&&(r=1),r}function S(t){return Math.min(1,Math.max(0,t))}function $(e){n(t,{color:e});const o=r(t,"color");return n(t,{color:""}),o}function A(t){return s(255*t).toString(16)}function w(t){return H(t)/255}function H(t){return parseInt(t,16)}function y(t){return 1===t.length?"0"+t:String(t)}function v(t,r,e){const n=t/255,o=r/255,s=e/255,a=Math.max(n,o,s),i=Math.min(n,o,s);let h=0,u=0;const c=(a+i)/2;if(a===i)u=0,h=0;else{const t=a-i;switch(u=c>.5?t/(2-a-i):t/(a+i),a){case n:h=(o-s)/t+(o<s?6:0);break;case o:h=(s-n)/t+2;break;case s:h=(n-o)/t+4}h/=6}return{h:h,s:u,l:c}}function R(t,r,e){let n=e;return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*n*(r-t):n<.5?r:n<2/3?t+(r-t)*(2/3-n)*6:t}function M(t,r,e){let n=0,o=0,s=0;if(0===r)o=e,s=e,n=e;else{const a=e<.5?e*(1+r):e+r-e*r,i=2*e-a;n=R(i,a,t+1/3),o=R(i,a,t),s=R(i,a,t-1/3)}return[n,o,s]=[n,o,s].map(t=>255*t),{r:n,g:o,b:s}}function F(t,r,e){const n=t/255,o=r/255,s=e/255;let a=0,i=0;const h=Math.min(n,o,s),u=Math.max(n,o,s),c=1-u;if(u===h)return{h:0,w:h,b:c};n===h?(a=o-s,i=3):(a=o===h?s-n:n-o,i=o===h?5:1);const b=(i-a/(u-h))/6;return{h:1===b?0:b,w:h,b:c}}function T(t,r,e){if(r+e>=1){const t=r/(r+e)*255;return{r:t,g:t,b:t}}let{r:n,g:o,b:s}=M(t,1,.5);return[n,o,s]=[n,o,s].map(t=>t/255*(1-r-e)+r).map(t=>255*t),{r:n,g:o,b:s}}function C(t,r,e){const n=t/255,o=r/255,s=e/255,a=Math.max(n,o,s),i=Math.min(n,o,s);let h=0;const u=a,c=a-i,b=0===a?0:c/a;if(a===i)h=0;else{switch(a){case n:h=(o-s)/c+(o<s?6:0);break;case o:h=(s-n)/c+2;break;case s:h=(n-o)/c+4}h/=6}return{h:h,s:b,v:u}}function E(t,r,e){const n=6*t,o=r,s=e,a=Math.floor(n),i=n-a,h=s*(1-o),u=s*(1-i*o),c=s*(1-(1-i)*o),b=a%6;let g=[s,u,h,h,c,s][b],l=[c,s,s,u,h,h][b],f=[h,h,c,s,s,u][b];return[g,l,f]=[g,l,f].map(t=>255*t),{r:g,g:l,b:f}}function N(t,r,e,n){const o=[y(s(t).toString(16)),y(s(r).toString(16)),y(s(e).toString(16))];return n&&o[0].charAt(0)===o[0].charAt(1)&&o[1].charAt(0)===o[1].charAt(1)&&o[2].charAt(0)===o[2].charAt(1)?o[0].charAt(0)+o[1].charAt(0)+o[2].charAt(0):o.join("")}function k(t,r,e,n,o){const a=[y(s(t).toString(16)),y(s(r).toString(16)),y(s(e).toString(16)),y(A(n))];return o&&a[0].charAt(0)===a[0].charAt(1)&&a[1].charAt(0)===a[1].charAt(1)&&a[2].charAt(0)===a[2].charAt(1)&&a[3].charAt(0)===a[3].charAt(1)?a[0].charAt(0)+a[1].charAt(0)+a[2].charAt(0)+a[3].charAt(0):a.join("")}function I(t){let r=t.trim().toLowerCase();if(0===r.length)return{r:0,g:0,b:0,a:1};let e=!1;if(m(r))r=$(r),e=!0;else if(o.includes(r)){return{r:0,g:0,b:0,a:"transparent"===r?0:1,format:"rgb",ok:!0}}let[,n,s,a,i]=g.rgb.exec(r)||[];return n&&s&&a?{r:n,g:s,b:a,a:void 0!==i?i:1,format:"rgb"}:([,n,s,a,i]=g.hsl.exec(r)||[],n&&s&&a?{h:n,s:s,l:a,a:void 0!==i?i:1,format:"hsl"}:([,n,s,a,i]=g.hsv.exec(r)||[],n&&s&&a?{h:n,s:s,v:a,a:void 0!==i?i:1,format:"hsv"}:([,n,s,a,i]=g.hwb.exec(r)||[],n&&s&&a?{h:n,w:s,b:a,a:void 0!==i?i:1,format:"hwb"}:([,n,s,a,i]=g.hex8.exec(r)||[],n&&s&&a&&i?{r:H(n),g:H(s),b:H(a),a:w(i),format:e?"rgb":"hex"}:([,n,s,a]=g.hex6.exec(r)||[],n&&s&&a?{r:H(n),g:H(s),b:H(a),format:e?"rgb":"hex"}:([,n,s,a,i]=g.hex4.exec(r)||[],n&&s&&a&&i?{r:H(n+n),g:H(s+s),b:H(a+a),a:w(i+i),format:e?"rgb":"hex"}:([,n,s,a]=g.hex3.exec(r)||[],!!(n&&s&&a)&&{r:H(n+n),g:H(s+s),b:H(a+a),format:e?"rgb":"hex"})))))))}function j(t){let r={r:0,g:0,b:0},e=t,n=1,o=null,s=null,i=null,h=null,u=null,c=null,b=null,g=null,l=!1;const m="object"==typeof e&&e.format;let S=m&&a.includes(m)?m:"rgb";return"string"==typeof t&&(e=I(t),e&&(l=!0)),"object"==typeof e&&(p(e.r)&&p(e.g)&&p(e.b)?(({r:b,g:g,b:u}=e),[b,g,u]=[b,g,u].map(t=>255*d(t,f(t)?100:255)),r={r:b,g:g,b:u},l=!0,S="rgb"):p(e.h)&&p(e.s)&&p(e.v)?(({h:c,s:o,v:s}=e),c="number"==typeof c?c:d(c,360),o="number"==typeof o?o:d(o,100),s="number"==typeof s?s:d(s,100),r=E(c,o,s),l=!0,S="hsv"):p(e.h)&&p(e.s)&&p(e.l)?(({h:c,s:o,l:i}=e),c="number"==typeof c?c:d(c,360),o="number"==typeof o?o:d(o,100),i="number"==typeof i?i:d(i,100),r=M(c,o,i),l=!0,S="hsl"):p(e.h)&&p(e.w)&&p(e.b)&&(({h:c,w:h,b:u}=e),c="number"==typeof c?c:d(c,360),h="number"==typeof h?h:d(h,100),u="number"==typeof u?u:d(u,100),r=T(c,h,u),l=!0,S="hwb"),p(e.a)&&(n=e.a,n=f(""+n)||parseFloat(n)>1?d(n,100):n)),void 0===e&&(l=!0),{ok:l,format:S,r:Math.min(255,Math.max(r.r,0)),g:Math.min(255,Math.max(r.g,0)),b:Math.min(255,Math.max(r.b,0)),a:x(n)}}class _{constructor(t,r){let e=t;const n=r&&a.includes(r)?r:"rgb";if(e instanceof _&&(e=j(e)),"number"==typeof e){e=`#${2===(""+e).length?"0":"00"}${e}`}const{r:o,g:s,b:i,a:h,ok:u,format:c}=j(e);this.originalInput=t,this.r=o,this.g=s,this.b=i,this.a=h,this.ok=u,this.format=n||c}get isValid(){return this.ok}get isDark(){return this.brightness<120}get luminance(){const{r:t,g:r,b:e}=this;let n=0,o=0,s=0;const a=t/255,i=r/255,h=e/255;return n=a<=.03928?a/12.92:((a+.055)/1.055)**2.4,o=i<=.03928?i/12.92:((i+.055)/1.055)**2.4,s=h<=.03928?h/12.92:((h+.055)/1.055)**2.4,.2126*n+.7152*o+.0722*s}get brightness(){const{r:t,g:r,b:e}=this;return(299*t+587*r+114*e)/1e3}toRgb(){const{r:t,g:r,b:e,a:n}=this;return{r:t,g:r,b:e,a:s(100*n)/100}}toRgbString(){const{r:t,g:r,b:e,a:n}=this.toRgb(),[o,a,i]=[t,r,e].map(s);return 1===n?`rgb(${o}, ${a}, ${i})`:`rgba(${o}, ${a}, ${i}, ${n})`}toRgbCSS4String(){const{r:t,g:r,b:e,a:n}=this.toRgb(),[o,a,i]=[t,r,e].map(s);return`rgb(${o} ${a} ${i}${1===n?"":` / ${s(100*n)}%`})`}toHex(t){const{r:r,g:e,b:n,a:o}=this.toRgb();return 1===o?N(r,e,n,t):k(r,e,n,o,t)}toHexString(t){return"#"+this.toHex(t)}toHex8(t){const{r:r,g:e,b:n,a:o}=this.toRgb();return k(r,e,n,o,t)}toHex8String(t){return"#"+this.toHex8(t)}toHsv(){const{r:t,g:r,b:e,a:n}=this.toRgb(),{h:o,s:s,v:a}=C(t,r,e);return{h:o,s:s,v:a,a:n}}toHsl(){const{r:t,g:r,b:e,a:n}=this.toRgb(),{h:o,s:s,l:a}=v(t,r,e);return{h:o,s:s,l:a,a:n}}toHslString(){let{h:t,s:r,l:e,a:n}=this.toHsl();return t=s(360*t),r=s(100*r),e=s(100*e),n=s(100*n)/100,1===n?`hsl(${t}, ${r}%, ${e}%)`:`hsla(${t}, ${r}%, ${e}%, ${n})`}toHslCSS4String(){let{h:t,s:r,l:e,a:n}=this.toHsl();t=s(360*t),r=s(100*r),e=s(100*e),n=s(100*n);return`hsl(${t}deg ${r}% ${e}%${n<100?` / ${s(n)}%`:""})`}toHwb(){const{r:t,g:r,b:e,a:n}=this,{h:o,w:s,b:a}=F(t,r,e);return{h:o,w:s,b:a,a:n}}toHwbString(){let{h:t,w:r,b:e,a:n}=this.toHwb();t=s(360*t),r=s(100*r),e=s(100*e),n=s(100*n);return`hwb(${t}deg ${r}% ${e}%${n<100?` / ${s(n)}%`:""})`}setAlpha(t){return this.a=x(t),this}saturate(t){if("number"!=typeof t)return this;const{h:r,s:n,l:o}=this.toHsl(),{r:s,g:a,b:i}=M(r,S(n+t/100),o);return e(this,{r:s,g:a,b:i}),this}desaturate(t){return"number"==typeof t?this.saturate(-t):this}greyscale(){return this.saturate(-100)}lighten(t){if("number"!=typeof t)return this;const{h:r,s:n,l:o}=this.toHsl(),{r:s,g:a,b:i}=M(r,n,S(o+t/100));return e(this,{r:s,g:a,b:i}),this}darken(t){return"number"==typeof t?this.lighten(-t):this}spin(t){if("number"!=typeof t)return this;const{h:r,s:n,l:o}=this.toHsl(),{r:s,g:a,b:i}=M(S((360*r+t)%360/360),n,o);return e(this,{r:s,g:a,b:i}),this}clone(){return new _(this)}toString(t){const{format:r}=this;return"hex"===r?this.toHexString(t):"hsl"===r?this.toHslString():"hwb"===r?this.toHwbString():this.toRgbString()}}return e(_,{ANGLES:"deg|rad|grad|turn",CSS_ANGLE:i,CSS_INTEGER:"[-\\+]?\\d+%?",CSS_NUMBER:"[-\\+]?\\d*\\.\\d+%?",CSS_UNIT:h,CSS_UNIT2:u,PERMISSIVE_MATCH:b,matchers:g,isOnePointZero:l,isPercentage:f,isValidCSSUnit:p,isColorName:m,pad2:y,clamp01:S,bound01:d,boundAlpha:x,getRGBFromName:$,convertHexToDecimal:w,convertDecimalToHex:A,rgbToHsl:v,rgbToHex:N,rgbToHsv:C,rgbToHwb:F,rgbaToHex:k,hslToRgb:M,hsvToRgb:E,hueToRgb:R,hwbToRgb:T,parseIntFromHex:H,stringInputToObject:I,inputToRGB:j,roundPart:s,getElementStyle:r,setElementStyle:n,ObjectAssign:e}),_}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thednp/color-picker",
3
- "version": "0.0.1",
3
+ "version": "0.0.2alpha1",
4
4
  "description": "Modern Color Picker Web Component",
5
5
  "main": "dist/js/color-picker.min.js",
6
6
  "module": "dist/js/color-picker.esm.js",
@@ -18,7 +18,9 @@
18
18
  "registry": "https://registry.npmjs.org/"
19
19
  },
20
20
  "scripts": {
21
- "test": "echo \"Error: no test specified\" && exit 1",
21
+ "instrument": "npx nyc instrument --all --compact=false src/js cypress/instrumented",
22
+ "test": "npm run instrument && npx cypress run",
23
+ "coverage:report": "npx nyc report --exclude=src/js/util --reporter=lcov --reporter=text --report-dir=cypress/coverage",
22
24
  "fix:js": "eslint src/ --config .eslintrc --fix",
23
25
  "lint:js": "eslint src/ --config .eslintrc",
24
26
  "fix:css": "stylelint --config .stylelintrc.json -s --fix scss \"src/scss/*.scss\"",
@@ -31,6 +33,14 @@
31
33
  "build-ce-min": "rollup --environment FORMAT:umd,MIN:true,NAME:ColorPickerElement,INPUTFILE:src/js/color-picker-element.js,OUTPUTFILE:dist/js/color-picker-element.min.js -c",
32
34
  "build-ce-esm": "rollup --environment FORMAT:esm,MIN:false,NAME:ColorPickerElement,INPUTFILE:src/js/color-picker-element.js,OUTPUTFILE:dist/js/color-picker-element-esm.js -c",
33
35
  "build-ce-esm-min": "rollup --environment FORMAT:esm,MIN:true,NAME:ColorPickerElement,INPUTFILE:src/js/color-picker-element.js,OUTPUTFILE:dist/js/color-picker-element-esm.min.js -c",
36
+ "build-cl": "rollup --environment FORMAT:umd,MIN:false,NAME:Color,INPUTFILE:src/js/color.js,OUTPUTFILE:dist/js/color.js -c",
37
+ "build-cl-min": "rollup --environment FORMAT:umd,MIN:true,NAME:Color,INPUTFILE:src/js/color.js,OUTPUTFILE:dist/js/color.min.js -c",
38
+ "build-cl-esm": "rollup --environment FORMAT:esm,MIN:false,NAME:Color,INPUTFILE:src/js/color.js,OUTPUTFILE:dist/js/color-esm.js -c",
39
+ "build-cl-esm-min": "rollup --environment FORMAT:esm,MIN:true,NAME:Color,INPUTFILE:src/js/color.js,OUTPUTFILE:dist/js/color-esm.min.js -c",
40
+ "build-cpl": "rollup --environment FORMAT:umd,MIN:false,NAME:ColorPalette,INPUTFILE:src/js/color-palette.js,OUTPUTFILE:dist/js/color-palette.js -c",
41
+ "build-cpl-min": "rollup --environment FORMAT:umd,MIN:true,NAME:ColorPalette,INPUTFILE:src/js/color-palette.js,OUTPUTFILE:dist/js/color-palette.min.js -c",
42
+ "build-cpl-esm": "rollup --environment FORMAT:esm,MIN:false,NAME:ColorPalette,INPUTFILE:src/js/color-palette.js,OUTPUTFILE:dist/js/color-palette-esm.js -c",
43
+ "build-cpl-esm-min": "rollup --environment FORMAT:esm,MIN:true,NAME:ColorPalette,INPUTFILE:src/js/color-palette.js,OUTPUTFILE:dist/js/color-palette-esm.min.js -c",
34
44
  "build-minjs": "rollup --environment FORMAT:umd,MIN:true -c",
35
45
  "build-esm": "rollup --environment FORMAT:esm,MIN:false -c",
36
46
  "build-esmjs": "rollup --environment FORMAT:esm,MIN:true -c",
@@ -68,15 +78,21 @@
68
78
  "shorter-js": "^0.3.4"
69
79
  },
70
80
  "devDependencies": {
81
+ "@bahmutov/cypress-esbuild-preprocessor": "^2.1.3",
82
+ "@cypress/code-coverage": "^3.9.12",
71
83
  "@rollup/plugin-buble": "^0.21.3",
84
+ "@rollup/plugin-commonjs": "^21.0.3",
72
85
  "@rollup/plugin-json": "^4.1.0",
73
86
  "@rollup/plugin-node-resolve": "^7.1.3",
87
+ "babel-plugin-istanbul": "^6.1.1",
88
+ "cypress": "^9.5.3",
89
+ "esbuild": "^0.14.30",
74
90
  "eslint": "^7.22.0",
75
91
  "eslint-config-airbnb-base": "^14.2.1",
76
92
  "eslint-plugin-import": "^2.22.1",
77
93
  "eslint-plugin-vue": "^7.7.0",
78
94
  "npm-run-all": "^4.1.5",
79
- "rollup": "^1.32.1",
95
+ "rollup": "^2.70.1",
80
96
  "rollup-plugin-terser": "^5.3.1",
81
97
  "sass": "^1.39.0",
82
98
  "stylelint": "^13.12.0",
@@ -1,3 +1,5 @@
1
+ import ObjectAssign from 'shorter-js/src/misc/ObjectAssign';
2
+
1
3
  import roundPart from './util/roundPart';
2
4
  import Color from './color';
3
5
 
@@ -6,7 +8,7 @@ import Color from './color';
6
8
  * Returns a color palette with a given set of parameters.
7
9
  * @example
8
10
  * new ColorPalette(0, 12, 10);
9
- * // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: array }
11
+ * // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: Array<Color> }
10
12
  */
11
13
  export default class ColorPalette {
12
14
  /**
@@ -26,11 +28,14 @@ export default class ColorPalette {
26
28
  [hue, hueSteps, lightSteps] = args;
27
29
  } else if (args.length === 2) {
28
30
  [hueSteps, lightSteps] = args;
31
+ if ([hueSteps, lightSteps].some((n) => n < 1)) {
32
+ throw TypeError('ColorPalette: when 2 arguments used, both must be larger than 0.');
33
+ }
29
34
  } else {
30
35
  throw TypeError('ColorPalette requires minimum 2 arguments');
31
36
  }
32
37
 
33
- /** @type {string[]} */
38
+ /** @type {Color[]} */
34
39
  const colors = [];
35
40
 
36
41
  const hueStep = 360 / hueSteps;
@@ -59,7 +64,7 @@ export default class ColorPalette {
59
64
  for (let i = 0; i < hueSteps; i += 1) {
60
65
  const currentHue = ((hue + i * hueStep) % 360) / 360;
61
66
  lightnessArray.forEach((l) => {
62
- colors.push(new Color({ h: currentHue, s: 1, l }).toHexString());
67
+ colors.push(new Color({ h: currentHue, s: 1, l }));
63
68
  });
64
69
  }
65
70
 
@@ -69,3 +74,5 @@ export default class ColorPalette {
69
74
  this.colors = colors;
70
75
  }
71
76
  }
77
+
78
+ ObjectAssign(ColorPalette, { Color });
@@ -7,7 +7,7 @@ import getAttribute from 'shorter-js/src/attr/getAttribute';
7
7
  import Color from './color';
8
8
  import ColorPicker, { getColorPickerInstance } from './color-picker';
9
9
  import ColorPalette from './color-palette';
10
- import Version from './version';
10
+ import Version from './util/version';
11
11
 
12
12
  let CPID = 0;
13
13
 
@@ -1,14 +1,10 @@
1
1
  import { addListener, removeListener } from 'event-listener.js';
2
2
 
3
3
  import ariaDescription from 'shorter-js/src/strings/ariaDescription';
4
- // import ariaLabel from 'shorter-js/src/strings/ariaLabel';
5
4
  import ariaSelected from 'shorter-js/src/strings/ariaSelected';
6
5
  import ariaExpanded from 'shorter-js/src/strings/ariaExpanded';
7
6
  import ariaValueText from 'shorter-js/src/strings/ariaValueText';
8
7
  import ariaValueNow from 'shorter-js/src/strings/ariaValueNow';
9
- import ariaHasPopup from 'shorter-js/src/strings/ariaHasPopup';
10
- import ariaHidden from 'shorter-js/src/strings/ariaHidden';
11
- import ariaLabelledBy from 'shorter-js/src/strings/ariaLabelledBy';
12
8
  import keyArrowDown from 'shorter-js/src/strings/keyArrowDown';
13
9
  import keyArrowUp from 'shorter-js/src/strings/keyArrowUp';
14
10
  import keyArrowLeft from 'shorter-js/src/strings/keyArrowLeft';
@@ -31,7 +27,7 @@ import keyupEvent from 'shorter-js/src/strings/keyupEvent';
31
27
  import resizeEvent from 'shorter-js/src/strings/resizeEvent';
32
28
  import focusoutEvent from 'shorter-js/src/strings/focusoutEvent';
33
29
 
34
- import isMobile from 'shorter-js/src/boolean/isMobile';
30
+ // import isMobile from 'shorter-js/src/boolean/isMobile';
35
31
  import getDocument from 'shorter-js/src/get/getDocument';
36
32
  import getDocumentElement from 'shorter-js/src/get/getDocumentElement';
37
33
  import getWindow from 'shorter-js/src/get/getWindow';
@@ -42,8 +38,6 @@ import getElementTransitionDuration from 'shorter-js/src/get/getElementTransitio
42
38
  import querySelector from 'shorter-js/src/selectors/querySelector';
43
39
  import closest from 'shorter-js/src/selectors/closest';
44
40
  import getElementsByClassName from 'shorter-js/src/selectors/getElementsByClassName';
45
- import createElement from 'shorter-js/src/misc/createElement';
46
- import createElementNS from 'shorter-js/src/misc/createElementNS';
47
41
  import dispatchEvent from 'shorter-js/src/misc/dispatchEvent';
48
42
  import ObjectAssign from 'shorter-js/src/misc/ObjectAssign';
49
43
  import Data, { getInstance } from 'shorter-js/src/misc/data';
@@ -60,19 +54,16 @@ import removeAttribute from 'shorter-js/src/attr/removeAttribute';
60
54
 
61
55
  // ColorPicker Util
62
56
  // ================
57
+ import Color from './color';
58
+ import ColorPalette from './color-palette';
63
59
  import colorPickerLabels from './util/colorPickerLabels';
64
60
  import colorNames from './util/colorNames';
65
61
  import nonColors from './util/nonColors';
66
- import getColorForm from './util/getColorForm';
67
- import getColorControls from './util/getColorControls';
68
- import getColorMenu from './util/getColorMenu';
69
- import vHidden from './util/vHidden';
70
62
  import tabIndex from './util/tabindex';
71
63
  import isValidJSON from './util/isValidJSON';
72
64
  import roundPart from './util/roundPart';
73
- import Color from './color';
74
- import ColorPalette from './color-palette';
75
- import Version from './version';
65
+ import setMarkup from './util/setMarkup';
66
+ import Version from './util/version';
76
67
 
77
68
  // ColorPicker GC
78
69
  // ==============
@@ -99,110 +90,6 @@ const initColorPicker = (element) => new ColorPicker(element);
99
90
  // ColorPicker Private Methods
100
91
  // ===========================
101
92
 
102
- /**
103
- * Generate HTML markup and update instance properties.
104
- * @param {ColorPicker} self
105
- */
106
- function initCallback(self) {
107
- const {
108
- input, parent, format, id, componentLabels, colorKeywords, colorPresets,
109
- } = self;
110
- const colorValue = getAttribute(input, 'value') || '#fff';
111
-
112
- const {
113
- toggleLabel, pickerLabel, formatLabel, hexLabel,
114
- } = componentLabels;
115
-
116
- // update color
117
- const color = nonColors.includes(colorValue) ? '#fff' : colorValue;
118
- self.color = new Color(color, format);
119
-
120
- // set initial controls dimensions
121
- // make the controls smaller on mobile
122
- const dropClass = isMobile ? ' mobile' : '';
123
- const formatString = format === 'hex' ? hexLabel : format.toUpperCase();
124
-
125
- const pickerBtn = createElement({
126
- id: `picker-btn-${id}`,
127
- tagName: 'button',
128
- className: 'picker-toggle btn-appearance',
129
- });
130
- setAttribute(pickerBtn, ariaExpanded, 'false');
131
- setAttribute(pickerBtn, ariaHasPopup, 'true');
132
- pickerBtn.append(createElement({
133
- tagName: 'span',
134
- className: vHidden,
135
- innerText: `${pickerLabel}. ${formatLabel}: ${formatString}`,
136
- }));
137
-
138
- const pickerDropdown = createElement({
139
- tagName: 'div',
140
- className: `color-dropdown picker${dropClass}`,
141
- });
142
- setAttribute(pickerDropdown, ariaLabelledBy, `picker-btn-${id}`);
143
- setAttribute(pickerDropdown, 'role', 'group');
144
-
145
- const colorControls = getColorControls(self);
146
- const colorForm = getColorForm(self);
147
-
148
- pickerDropdown.append(colorControls, colorForm);
149
- input.before(pickerBtn);
150
- parent.append(pickerDropdown);
151
-
152
- // set colour key menu template
153
- if (colorKeywords || colorPresets) {
154
- const presetsDropdown = createElement({
155
- tagName: 'div',
156
- className: `color-dropdown scrollable menu${dropClass}`,
157
- });
158
-
159
- // color presets
160
- if ((colorPresets instanceof Array && colorPresets.length)
161
- || (colorPresets instanceof ColorPalette && colorPresets.colors)) {
162
- const presetsMenu = getColorMenu(self, colorPresets, 'color-options');
163
- presetsDropdown.append(presetsMenu);
164
- }
165
-
166
- // explicit defaults [reset, initial, inherit, transparent, currentColor]
167
- if (colorKeywords && colorKeywords.length) {
168
- const keywordsMenu = getColorMenu(self, colorKeywords, 'color-defaults');
169
- presetsDropdown.append(keywordsMenu);
170
- }
171
-
172
- const presetsBtn = createElement({
173
- tagName: 'button',
174
- className: 'menu-toggle btn-appearance',
175
- });
176
- setAttribute(presetsBtn, tabIndex, '-1');
177
- setAttribute(presetsBtn, ariaExpanded, 'false');
178
- setAttribute(presetsBtn, ariaHasPopup, 'true');
179
-
180
- const xmlns = encodeURI('http://www.w3.org/2000/svg');
181
- const presetsIcon = createElementNS(xmlns, { tagName: 'svg' });
182
- setAttribute(presetsIcon, 'xmlns', xmlns);
183
- setAttribute(presetsIcon, 'viewBox', '0 0 512 512');
184
- setAttribute(presetsIcon, ariaHidden, 'true');
185
-
186
- const path = createElementNS(xmlns, { tagName: 'path' });
187
- setAttribute(path, 'd', 'M98,158l157,156L411,158l27,27L255,368L71,185L98,158z');
188
- setAttribute(path, 'fill', '#fff');
189
- presetsIcon.append(path);
190
- presetsBtn.append(createElement({
191
- tagName: 'span',
192
- className: vHidden,
193
- innerText: `${toggleLabel}`,
194
- }), presetsIcon);
195
-
196
- parent.append(presetsBtn, presetsDropdown);
197
- }
198
-
199
- // solve non-colors after settings save
200
- if (colorKeywords && nonColors.includes(colorValue)) {
201
- self.value = colorValue;
202
- }
203
- setAttribute(input, tabIndex, '-1');
204
- }
205
-
206
93
  /**
207
94
  * Add / remove `ColorPicker` main event listeners.
208
95
  * @param {ColorPicker} self
@@ -436,7 +323,7 @@ export default class ColorPicker {
436
323
  self.handleKnobs = self.handleKnobs.bind(self);
437
324
 
438
325
  // generate markup
439
- initCallback(self);
326
+ setMarkup(self);
440
327
 
441
328
  const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
442
329
  // set main elements
@@ -632,7 +519,7 @@ export default class ColorPicker {
632
519
  const self = this;
633
520
  const { activeElement } = getDocument(self.input);
634
521
 
635
- if ((isMobile && self.dragElement)
522
+ if ((e.type === touchmoveEvent && self.dragElement)
636
523
  || (activeElement && self.controlKnobs.includes(activeElement))) {
637
524
  e.stopPropagation();
638
525
  e.preventDefault();
package/src/js/color.js CHANGED
@@ -1,13 +1,14 @@
1
- import getDocumentHead from 'shorter-js/src/get/getDocumentHead';
1
+ import documentHead from 'shorter-js/src/blocks/documentHead';
2
2
  import getElementStyle from 'shorter-js/src/get/getElementStyle';
3
3
  import setElementStyle from 'shorter-js/src/misc/setElementStyle';
4
4
  import ObjectAssign from 'shorter-js/src/misc/ObjectAssign';
5
+ import toLowerCase from 'shorter-js/src/misc/toLowerCase';
5
6
 
6
7
  import nonColors from './util/nonColors';
7
8
  import roundPart from './util/roundPart';
8
9
 
9
10
  // Color supported formats
10
- const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsb', 'hwb'];
11
+ const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsv', 'hwb'];
11
12
 
12
13
  // Hue angles
13
14
  const ANGLES = 'deg|rad|grad|turn';
@@ -29,10 +30,17 @@ const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`;
29
30
  // Add angles to the mix
30
31
  const CSS_UNIT2 = `(?:${CSS_UNIT})|(?:${CSS_ANGLE})`;
31
32
 
33
+ // Start & end
34
+ const START_MATCH = '(?:[\\s|\\(\\s|\\s\\(\\s]+)?';
35
+ const END_MATCH = '(?:[\\s|\\)\\s]+)?';
36
+ // Components separation
37
+ const SEP = '(?:[,|\\s]+)';
38
+ const SEP2 = '(?:[,|\\/\\s]*)?';
39
+
32
40
  // Actual matching.
33
41
  // Parentheses and commas are optional, but not required.
34
42
  // Whitespace can take the place of commas or opening paren
35
- const PERMISSIVE_MATCH = `[\\s|\\(]+(${CSS_UNIT2})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s|\\/\\s]*(${CSS_UNIT})?\\s*\\)?`;
43
+ const PERMISSIVE_MATCH = `${START_MATCH}(${CSS_UNIT2})${SEP}(${CSS_UNIT})${SEP}(${CSS_UNIT})${SEP2}(${CSS_UNIT})?${END_MATCH}`;
36
44
 
37
45
  const matchers = {
38
46
  CSS_UNIT: new RegExp(CSS_UNIT2),
@@ -65,23 +73,22 @@ function isPercentage(n) {
65
73
  return `${n}`.includes('%');
66
74
  }
67
75
 
68
- /**
69
- * Check to see if string passed in is an angle
70
- * @param {string} n testing string
71
- * @returns {boolean} the query result
72
- */
73
- function isAngle(n) {
74
- return ANGLES.split('|').some((a) => `${n}`.includes(a));
75
- }
76
-
77
76
  /**
78
77
  * Check to see if string passed is a web safe colour.
78
+ * @see https://stackoverflow.com/a/16994164
79
79
  * @param {string} color a colour name, EG: *red*
80
80
  * @returns {boolean} the query result
81
81
  */
82
82
  function isColorName(color) {
83
- return !['#', ...COLOR_FORMAT].some((s) => color.includes(s))
84
- && !/[0-9]/.test(color);
83
+ if (nonColors.includes(color)
84
+ || ['#', ...COLOR_FORMAT].some((f) => color.includes(f))) return false;
85
+
86
+ return ['rgb(255, 255, 255)', 'rgb(0, 0, 0)'].every((c) => {
87
+ setElementStyle(documentHead, { color });
88
+ const computedColor = getElementStyle(documentHead, 'color');
89
+ setElementStyle(documentHead, { color: '' });
90
+ return computedColor !== c;
91
+ });
85
92
  }
86
93
 
87
94
  /**
@@ -102,15 +109,15 @@ function isValidCSSUnit(color) {
102
109
  */
103
110
  function bound01(N, max) {
104
111
  let n = N;
105
- if (isOnePointZero(n)) n = '100%';
106
-
107
- n = max === 360 ? n : Math.min(max, Math.max(0, parseFloat(n)));
112
+ if (isOnePointZero(N)) n = '100%';
108
113
 
109
- // Handle hue angles
110
- if (isAngle(N)) n = N.replace(new RegExp(ANGLES), '');
114
+ const processPercent = isPercentage(n);
115
+ n = max === 360
116
+ ? parseFloat(n)
117
+ : Math.min(max, Math.max(0, parseFloat(n)));
111
118
 
112
119
  // Automatically convert percentage into number
113
- if (isPercentage(n)) n = parseInt(String(n * max), 10) / 100;
120
+ if (processPercent) n = (n * max) / 100;
114
121
 
115
122
  // Handle floating point rounding errors
116
123
  if (Math.abs(n - max) < 0.000001) {
@@ -121,11 +128,11 @@ function bound01(N, max) {
121
128
  // If n is a hue given in degrees,
122
129
  // wrap around out-of-range values into [0, 360] range
123
130
  // then convert into [0, 1].
124
- n = (n < 0 ? (n % max) + max : n % max) / parseFloat(String(max));
131
+ n = (n < 0 ? (n % max) + max : n % max) / max;
125
132
  } else {
126
133
  // If n not a hue given in degrees
127
134
  // Convert into [0, 1] range if it isn't already.
128
- n = (n % max) / parseFloat(String(max));
135
+ n = (n % max) / max;
129
136
  }
130
137
  return n;
131
138
  }
@@ -160,7 +167,6 @@ function clamp01(v) {
160
167
  * @returns {string}
161
168
  */
162
169
  function getRGBFromName(name) {
163
- const documentHead = getDocumentHead();
164
170
  setElementStyle(documentHead, { color: name });
165
171
  const colorName = getElementStyle(documentHead, 'color');
166
172
  setElementStyle(documentHead, { color: '' });
@@ -260,6 +266,36 @@ function hueToRgb(p, q, t) {
260
266
  return p;
261
267
  }
262
268
 
269
+ /**
270
+ * Converts an HSL colour value to RGB.
271
+ *
272
+ * @param {number} h Hue Angle [0, 1]
273
+ * @param {number} s Saturation [0, 1]
274
+ * @param {number} l Lightness Angle [0, 1]
275
+ * @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
276
+ */
277
+ function hslToRgb(h, s, l) {
278
+ let r = 0;
279
+ let g = 0;
280
+ let b = 0;
281
+
282
+ if (s === 0) {
283
+ // achromatic
284
+ g = l;
285
+ b = l;
286
+ r = l;
287
+ } else {
288
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
289
+ const p = 2 * l - q;
290
+ r = hueToRgb(p, q, h + 1 / 3);
291
+ g = hueToRgb(p, q, h);
292
+ b = hueToRgb(p, q, h - 1 / 3);
293
+ }
294
+ [r, g, b] = [r, g, b].map((x) => x * 255);
295
+
296
+ return { r, g, b };
297
+ }
298
+
263
299
  /**
264
300
  * Returns an HWB colour object from an RGB colour object.
265
301
  * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
@@ -322,36 +358,6 @@ function hwbToRgb(H, W, B) {
322
358
  return { r, g, b };
323
359
  }
324
360
 
325
- /**
326
- * Converts an HSL colour value to RGB.
327
- *
328
- * @param {number} h Hue Angle [0, 1]
329
- * @param {number} s Saturation [0, 1]
330
- * @param {number} l Lightness Angle [0, 1]
331
- * @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
332
- */
333
- function hslToRgb(h, s, l) {
334
- let r = 0;
335
- let g = 0;
336
- let b = 0;
337
-
338
- if (s === 0) {
339
- // achromatic
340
- g = l;
341
- b = l;
342
- r = l;
343
- } else {
344
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
345
- const p = 2 * l - q;
346
- r = hueToRgb(p, q, h + 1 / 3);
347
- g = hueToRgb(p, q, h);
348
- b = hueToRgb(p, q, h - 1 / 3);
349
- }
350
- [r, g, b] = [r, g, b].map((x) => x * 255);
351
-
352
- return { r, g, b };
353
- }
354
-
355
361
  /**
356
362
  * Converts an RGB colour value to HSV.
357
363
  *
@@ -408,10 +414,11 @@ function hsvToRgb(H, S, V) {
408
414
  const q = v * (1 - f * s);
409
415
  const t = v * (1 - (1 - f) * s);
410
416
  const mod = i % 6;
411
- const r = [v, q, p, p, t, v][mod];
412
- const g = [t, v, v, q, p, p][mod];
413
- const b = [p, p, t, v, v, q][mod];
414
- return { r: r * 255, g: g * 255, b: b * 255 };
417
+ let r = [v, q, p, p, t, v][mod];
418
+ let g = [t, v, v, q, p, p][mod];
419
+ let b = [p, p, t, v, v, q][mod];
420
+ [r, g, b] = [r, g, b].map((n) => n * 255);
421
+ return { r, g, b };
415
422
  }
416
423
 
417
424
  /**
@@ -435,7 +442,7 @@ function rgbToHex(r, g, b, allow3Char) {
435
442
  // Return a 3 character hex if possible
436
443
  if (allow3Char && hex[0].charAt(0) === hex[0].charAt(1)
437
444
  && hex[1].charAt(0) === hex[1].charAt(1)
438
- && hex[2].charAt(0) === hex[2].charAt(1)) {
445
+ && hex[2].charAt(0) === hex[2].charAt(1)) {
439
446
  return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
440
447
  }
441
448
 
@@ -463,39 +470,24 @@ function rgbaToHex(r, g, b, a, allow4Char) {
463
470
  // Return a 4 character hex if possible
464
471
  if (allow4Char && hex[0].charAt(0) === hex[0].charAt(1)
465
472
  && hex[1].charAt(0) === hex[1].charAt(1)
466
- && hex[2].charAt(0) === hex[2].charAt(1)
467
- && hex[3].charAt(0) === hex[3].charAt(1)) {
473
+ && hex[2].charAt(0) === hex[2].charAt(1)
474
+ && hex[3].charAt(0) === hex[3].charAt(1)) {
468
475
  return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
469
476
  }
470
477
  return hex.join('');
471
478
  }
472
479
 
473
- /**
474
- * Returns a colour object corresponding to a given number.
475
- * @param {number} color input number
476
- * @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
477
- */
478
- function numberInputToObject(color) {
479
- /* eslint-disable no-bitwise */
480
- return {
481
- r: color >> 16,
482
- g: (color & 0xff00) >> 8,
483
- b: color & 0xff,
484
- };
485
- /* eslint-enable no-bitwise */
486
- }
487
-
488
480
  /**
489
481
  * Permissive string parsing. Take in a number of formats, and output an object
490
482
  * based on detected format. Returns {r,g,b} or {h,s,l} or {h,s,v}
491
483
  * @param {string} input colour value in any format
492
- * @returns {Record<string, (number | string)> | false} an object matching the RegExp
484
+ * @returns {Record<string, (number | string | boolean)> | false} an object matching the RegExp
493
485
  */
494
486
  function stringInputToObject(input) {
495
- let color = input.trim().toLowerCase();
487
+ let color = toLowerCase(input.trim());
496
488
  if (color.length === 0) {
497
489
  return {
498
- r: 0, g: 0, b: 0, a: 0,
490
+ r: 0, g: 0, b: 0, a: 1,
499
491
  };
500
492
  }
501
493
  let named = false;
@@ -503,11 +495,9 @@ function stringInputToObject(input) {
503
495
  color = getRGBFromName(color);
504
496
  named = true;
505
497
  } else if (nonColors.includes(color)) {
506
- const isTransparent = color === 'transparent';
507
- const rgb = isTransparent ? 0 : 255;
508
- const a = isTransparent ? 0 : 1;
498
+ const a = color === 'transparent' ? 0 : 1;
509
499
  return {
510
- r: rgb, g: rgb, b: rgb, a, format: 'rgb',
500
+ r: 0, g: 0, b: 0, a, format: 'rgb', ok: true,
511
501
  };
512
502
  }
513
503
 
@@ -547,7 +537,6 @@ function stringInputToObject(input) {
547
537
  g: parseIntFromHex(m2),
548
538
  b: parseIntFromHex(m3),
549
539
  a: convertHexToDecimal(m4),
550
- // format: named ? 'rgb' : 'hex8',
551
540
  format: named ? 'rgb' : 'hex',
552
541
  };
553
542
  }
@@ -611,6 +600,7 @@ function stringInputToObject(input) {
611
600
  function inputToRGB(input) {
612
601
  let rgb = { r: 0, g: 0, b: 0 };
613
602
  let color = input;
603
+ /** @type {string | number} */
614
604
  let a = 1;
615
605
  let s = null;
616
606
  let v = null;
@@ -621,7 +611,8 @@ function inputToRGB(input) {
621
611
  let r = null;
622
612
  let g = null;
623
613
  let ok = false;
624
- let format = 'hex';
614
+ const inputFormat = typeof color === 'object' && color.format;
615
+ let format = inputFormat && COLOR_FORMAT.includes(inputFormat) ? inputFormat : 'rgb';
625
616
 
626
617
  if (typeof input === 'string') {
627
618
  // @ts-ignore -- this now is converted to object
@@ -662,14 +653,17 @@ function inputToRGB(input) {
662
653
  format = 'hwb';
663
654
  }
664
655
  if (isValidCSSUnit(color.a)) {
665
- a = color.a;
666
- a = isPercentage(`${a}`) ? bound01(a, 100) : a;
656
+ a = color.a; // @ts-ignore -- `parseFloat` works with numbers too
657
+ a = isPercentage(`${a}`) || parseFloat(a) > 1 ? bound01(a, 100) : a;
667
658
  }
668
659
  }
660
+ if (typeof color === 'undefined') {
661
+ ok = true;
662
+ }
669
663
 
670
664
  return {
671
- ok, // @ts-ignore
672
- format: color.format || format,
665
+ ok,
666
+ format,
673
667
  r: Math.min(255, Math.max(rgb.r, 0)),
674
668
  g: Math.min(255, Math.max(rgb.g, 0)),
675
669
  b: Math.min(255, Math.max(rgb.b, 0)),
@@ -698,7 +692,8 @@ export default class Color {
698
692
  color = inputToRGB(color);
699
693
  }
700
694
  if (typeof color === 'number') {
701
- color = numberInputToObject(color);
695
+ const len = `${color}`.length;
696
+ color = `#${(len === 2 ? '0' : '00')}${color}`;
702
697
  }
703
698
  const {
704
699
  r, g, b, a, ok, format,
@@ -708,7 +703,7 @@ export default class Color {
708
703
  const self = this;
709
704
 
710
705
  /** @type {CP.ColorInput} */
711
- self.originalInput = color;
706
+ self.originalInput = input;
712
707
  /** @type {number} */
713
708
  self.r = r;
714
709
  /** @type {number} */
@@ -1098,6 +1093,7 @@ ObjectAssign(Color, {
1098
1093
  isOnePointZero,
1099
1094
  isPercentage,
1100
1095
  isValidCSSUnit,
1096
+ isColorName,
1101
1097
  pad2,
1102
1098
  clamp01,
1103
1099
  bound01,
@@ -1115,9 +1111,10 @@ ObjectAssign(Color, {
1115
1111
  hueToRgb,
1116
1112
  hwbToRgb,
1117
1113
  parseIntFromHex,
1118
- numberInputToObject,
1119
1114
  stringInputToObject,
1120
1115
  inputToRGB,
1121
1116
  roundPart,
1117
+ getElementStyle,
1118
+ setElementStyle,
1122
1119
  ObjectAssign,
1123
1120
  });