@thednp/color-picker 0.0.1 → 0.0.2-alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  });