@thednp/color-picker 0.0.1-alpha2 → 0.0.1-alpha3
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +31 -15
- package/dist/css/color-picker.css +37 -15
- package/dist/css/color-picker.min.css +2 -2
- package/dist/css/color-picker.rtl.css +37 -15
- package/dist/css/color-picker.rtl.min.css +2 -2
- package/dist/js/color-picker-element-esm.js +164 -135
- package/dist/js/color-picker-element-esm.min.js +2 -2
- package/dist/js/color-picker-element.js +164 -135
- package/dist/js/color-picker-element.min.js +2 -2
- package/dist/js/color-picker-esm.js +159 -133
- package/dist/js/color-picker-esm.min.js +2 -2
- package/dist/js/color-picker.js +159 -133
- package/dist/js/color-picker.min.js +2 -2
- package/package.json +1 -1
- package/src/js/color-palette.js +18 -9
- package/src/js/color-picker-element.js +7 -3
- package/src/js/color-picker.js +59 -48
- package/src/js/color.js +33 -34
- package/src/js/util/getColorControls.js +3 -3
- package/src/js/util/getColorForm.js +0 -1
- package/src/js/util/getColorMenu.js +21 -28
- package/src/js/util/roundPart.js +9 -0
- package/src/js/util/setCSSProperties.js +12 -0
- package/src/js/util/tabindex.js +3 -0
- package/src/scss/color-picker.scss +35 -12
- package/types/cp.d.ts +1 -3
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* ColorPickerElement v0.0.
|
2
|
+
* ColorPickerElement v0.0.1alpha3 (http://thednp.github.io/color-picker)
|
3
3
|
* Copyright 2022 © thednp
|
4
4
|
* Licensed under MIT (https://github.com/thednp/color-picker/blob/master/LICENSE)
|
5
5
|
*/
|
@@ -110,19 +110,36 @@ function getElementStyle(element, property) {
|
|
110
110
|
return property in computedStyle ? computedStyle[property] : '';
|
111
111
|
}
|
112
112
|
|
113
|
+
/**
|
114
|
+
* Shortcut for `Object.keys()` static method.
|
115
|
+
* @param {Record<string, any>} obj a target object
|
116
|
+
* @returns {string[]}
|
117
|
+
*/
|
118
|
+
const ObjectKeys = (obj) => Object.keys(obj);
|
119
|
+
|
113
120
|
/**
|
114
121
|
* Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
|
115
122
|
* @param {HTMLElement | Element} element target element
|
116
123
|
* @param {Partial<CSSStyleDeclaration>} styles attribute value
|
117
124
|
*/
|
118
125
|
// @ts-ignore
|
119
|
-
const setElementStyle = (element, styles) =>
|
126
|
+
const setElementStyle = (element, styles) => ObjectAssign(element.style, styles);
|
120
127
|
|
121
128
|
/**
|
122
129
|
* A list of explicit default non-color values.
|
123
130
|
*/
|
124
131
|
const nonColors = ['transparent', 'currentColor', 'inherit', 'revert', 'initial'];
|
125
132
|
|
133
|
+
/**
|
134
|
+
* Round colour components, for all formats except HEX.
|
135
|
+
* @param {number} v one of the colour components
|
136
|
+
* @returns {number} the rounded number
|
137
|
+
*/
|
138
|
+
function roundPart(v) {
|
139
|
+
const floor = Math.floor(v);
|
140
|
+
return v - floor < 0.5 ? floor : Math.round(v);
|
141
|
+
}
|
142
|
+
|
126
143
|
// Color supported formats
|
127
144
|
const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsb', 'hwb'];
|
128
145
|
|
@@ -290,7 +307,7 @@ function getRGBFromName(name) {
|
|
290
307
|
* @returns {string} - the hexadecimal value
|
291
308
|
*/
|
292
309
|
function convertDecimalToHex(d) {
|
293
|
-
return
|
310
|
+
return roundPart(d * 255).toString(16);
|
294
311
|
}
|
295
312
|
|
296
313
|
/**
|
@@ -542,9 +559,9 @@ function hsvToRgb(H, S, V) {
|
|
542
559
|
*/
|
543
560
|
function rgbToHex(r, g, b, allow3Char) {
|
544
561
|
const hex = [
|
545
|
-
pad2(
|
546
|
-
pad2(
|
547
|
-
pad2(
|
562
|
+
pad2(roundPart(r).toString(16)),
|
563
|
+
pad2(roundPart(g).toString(16)),
|
564
|
+
pad2(roundPart(b).toString(16)),
|
548
565
|
];
|
549
566
|
|
550
567
|
// Return a 3 character hex if possible
|
@@ -569,9 +586,9 @@ function rgbToHex(r, g, b, allow3Char) {
|
|
569
586
|
*/
|
570
587
|
function rgbaToHex(r, g, b, a, allow4Char) {
|
571
588
|
const hex = [
|
572
|
-
pad2(
|
573
|
-
pad2(
|
574
|
-
pad2(
|
589
|
+
pad2(roundPart(r).toString(16)),
|
590
|
+
pad2(roundPart(g).toString(16)),
|
591
|
+
pad2(roundPart(b).toString(16)),
|
575
592
|
pad2(convertDecimalToHex(a)),
|
576
593
|
];
|
577
594
|
|
@@ -733,6 +750,8 @@ function inputToRGB(input) {
|
|
733
750
|
let w = null;
|
734
751
|
let b = null;
|
735
752
|
let h = null;
|
753
|
+
let r = null;
|
754
|
+
let g = null;
|
736
755
|
let ok = false;
|
737
756
|
let format = 'hex';
|
738
757
|
|
@@ -743,7 +762,10 @@ function inputToRGB(input) {
|
|
743
762
|
}
|
744
763
|
if (typeof color === 'object') {
|
745
764
|
if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
|
746
|
-
|
765
|
+
({ r, g, b } = color);
|
766
|
+
[r, g, b] = [...[r, g, b]]
|
767
|
+
.map((n) => bound01(n, isPercentage(n) ? 100 : 255) * 255).map(roundPart);
|
768
|
+
rgb = { r, g, b }; // RGB values now are all in [0, 255] range
|
747
769
|
ok = true;
|
748
770
|
format = 'rgb';
|
749
771
|
} else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
|
@@ -831,14 +853,6 @@ class Color {
|
|
831
853
|
self.ok = ok;
|
832
854
|
/** @type {CP.ColorFormats} */
|
833
855
|
self.format = configFormat || format;
|
834
|
-
|
835
|
-
// Don't let the range of [0,255] come back in [0,1].
|
836
|
-
// Potentially lose a little bit of precision here, but will fix issues where
|
837
|
-
// .5 gets interpreted as half of the total, instead of half of 1
|
838
|
-
// If it was supposed to be 128, this was already taken care of by `inputToRgb`
|
839
|
-
if (r < 1) self.r = Math.round(r);
|
840
|
-
if (g < 1) self.g = Math.round(g);
|
841
|
-
if (b < 1) self.b = Math.round(b);
|
842
856
|
}
|
843
857
|
|
844
858
|
/**
|
@@ -854,7 +868,7 @@ class Color {
|
|
854
868
|
* @returns {boolean} the query result
|
855
869
|
*/
|
856
870
|
get isDark() {
|
857
|
-
return this.brightness <
|
871
|
+
return this.brightness < 120;
|
858
872
|
}
|
859
873
|
|
860
874
|
/**
|
@@ -906,13 +920,13 @@ class Color {
|
|
906
920
|
const {
|
907
921
|
r, g, b, a,
|
908
922
|
} = this;
|
909
|
-
const [R, G, B] = [r, g, b].map((x) =>
|
923
|
+
const [R, G, B] = [r, g, b].map((x) => roundPart(x));
|
910
924
|
|
911
925
|
return {
|
912
926
|
r: R,
|
913
927
|
g: G,
|
914
928
|
b: B,
|
915
|
-
a:
|
929
|
+
a: roundPart(a * 100) / 100,
|
916
930
|
};
|
917
931
|
}
|
918
932
|
|
@@ -942,7 +956,7 @@ class Color {
|
|
942
956
|
const {
|
943
957
|
r, g, b, a,
|
944
958
|
} = this.toRgb();
|
945
|
-
const A = a === 1 ? '' : ` / ${
|
959
|
+
const A = a === 1 ? '' : ` / ${roundPart(a * 100)}%`;
|
946
960
|
|
947
961
|
return `rgb(${r} ${g} ${b}${A})`;
|
948
962
|
}
|
@@ -1037,10 +1051,10 @@ class Color {
|
|
1037
1051
|
let {
|
1038
1052
|
h, s, l, a,
|
1039
1053
|
} = this.toHsl();
|
1040
|
-
h =
|
1041
|
-
s =
|
1042
|
-
l =
|
1043
|
-
a =
|
1054
|
+
h = roundPart(h * 360);
|
1055
|
+
s = roundPart(s * 100);
|
1056
|
+
l = roundPart(l * 100);
|
1057
|
+
a = roundPart(a * 100) / 100;
|
1044
1058
|
|
1045
1059
|
return a === 1
|
1046
1060
|
? `hsl(${h}, ${s}%, ${l}%)`
|
@@ -1057,11 +1071,11 @@ class Color {
|
|
1057
1071
|
let {
|
1058
1072
|
h, s, l, a,
|
1059
1073
|
} = this.toHsl();
|
1060
|
-
h =
|
1061
|
-
s =
|
1062
|
-
l =
|
1063
|
-
a =
|
1064
|
-
const A = a < 100 ? ` / ${
|
1074
|
+
h = roundPart(h * 360);
|
1075
|
+
s = roundPart(s * 100);
|
1076
|
+
l = roundPart(l * 100);
|
1077
|
+
a = roundPart(a * 100);
|
1078
|
+
const A = a < 100 ? ` / ${roundPart(a)}%` : '';
|
1065
1079
|
|
1066
1080
|
return `hsl(${h}deg ${s}% ${l}%${A})`;
|
1067
1081
|
}
|
@@ -1088,11 +1102,11 @@ class Color {
|
|
1088
1102
|
let {
|
1089
1103
|
h, w, b, a,
|
1090
1104
|
} = this.toHwb();
|
1091
|
-
h =
|
1092
|
-
w =
|
1093
|
-
b =
|
1094
|
-
a =
|
1095
|
-
const A = a < 100 ? ` / ${
|
1105
|
+
h = roundPart(h * 360);
|
1106
|
+
w = roundPart(w * 100);
|
1107
|
+
b = roundPart(b * 100);
|
1108
|
+
a = roundPart(a * 100);
|
1109
|
+
const A = a < 100 ? ` / ${roundPart(a)}%` : '';
|
1096
1110
|
|
1097
1111
|
return `hwb(${h}deg ${w}% ${b}%${A})`;
|
1098
1112
|
}
|
@@ -1238,6 +1252,7 @@ ObjectAssign(Color, {
|
|
1238
1252
|
numberInputToObject,
|
1239
1253
|
stringInputToObject,
|
1240
1254
|
inputToRGB,
|
1255
|
+
roundPart,
|
1241
1256
|
ObjectAssign,
|
1242
1257
|
});
|
1243
1258
|
|
@@ -1866,13 +1881,6 @@ function normalizeValue(value) {
|
|
1866
1881
|
return value;
|
1867
1882
|
}
|
1868
1883
|
|
1869
|
-
/**
|
1870
|
-
* Shortcut for `Object.keys()` static method.
|
1871
|
-
* @param {Record<string, any>} obj a target object
|
1872
|
-
* @returns {string[]}
|
1873
|
-
*/
|
1874
|
-
const ObjectKeys = (obj) => Object.keys(obj);
|
1875
|
-
|
1876
1884
|
/**
|
1877
1885
|
* Shortcut for `String.toLowerCase()`.
|
1878
1886
|
*
|
@@ -2075,7 +2083,6 @@ function getColorForm(self) {
|
|
2075
2083
|
max,
|
2076
2084
|
step,
|
2077
2085
|
});
|
2078
|
-
// }
|
2079
2086
|
colorForm.append(cInputLabel, cInput);
|
2080
2087
|
});
|
2081
2088
|
return colorForm;
|
@@ -2099,6 +2106,8 @@ const ariaValueMin = 'aria-valuemin';
|
|
2099
2106
|
*/
|
2100
2107
|
const ariaValueMax = 'aria-valuemax';
|
2101
2108
|
|
2109
|
+
const tabIndex = 'tabindex';
|
2110
|
+
|
2102
2111
|
/**
|
2103
2112
|
* Returns all color controls for `ColorPicker`.
|
2104
2113
|
*
|
@@ -2164,10 +2173,8 @@ function getColorControls(self) {
|
|
2164
2173
|
const {
|
2165
2174
|
i, c, l, min, max,
|
2166
2175
|
} = template;
|
2167
|
-
// const hidden = i === 2 && format === 'hwb' ? ' v-hidden' : '';
|
2168
2176
|
const control = createElement({
|
2169
2177
|
tagName: 'div',
|
2170
|
-
// className: `color-control${hidden}`,
|
2171
2178
|
className: 'color-control',
|
2172
2179
|
});
|
2173
2180
|
setAttribute(control, 'role', 'presentation');
|
@@ -2187,7 +2194,7 @@ function getColorControls(self) {
|
|
2187
2194
|
|
2188
2195
|
setAttribute(knob, ariaLabel, l);
|
2189
2196
|
setAttribute(knob, 'role', 'slider');
|
2190
|
-
setAttribute(knob,
|
2197
|
+
setAttribute(knob, tabIndex, '0');
|
2191
2198
|
setAttribute(knob, ariaValueMin, `${min}`);
|
2192
2199
|
setAttribute(knob, ariaValueMax, `${max}`);
|
2193
2200
|
control.append(knob);
|
@@ -2197,6 +2204,17 @@ function getColorControls(self) {
|
|
2197
2204
|
return colorControls;
|
2198
2205
|
}
|
2199
2206
|
|
2207
|
+
/**
|
2208
|
+
* Helps setting CSS variables to the color-menu.
|
2209
|
+
* @param {HTMLElement} element
|
2210
|
+
* @param {Record<string,any>} props
|
2211
|
+
*/
|
2212
|
+
function setCSSProperties(element, props) {
|
2213
|
+
ObjectKeys(props).forEach((prop) => {
|
2214
|
+
element.style.setProperty(prop, props[prop]);
|
2215
|
+
});
|
2216
|
+
}
|
2217
|
+
|
2200
2218
|
/**
|
2201
2219
|
* @class
|
2202
2220
|
* Returns a color palette with a given set of parameters.
|
@@ -2209,8 +2227,8 @@ class ColorPalette {
|
|
2209
2227
|
* The `hue` parameter is optional, which would be set to 0.
|
2210
2228
|
* @param {number[]} args represeinting hue, hueSteps, lightSteps
|
2211
2229
|
* * `args.hue` the starting Hue [0, 360]
|
2212
|
-
* * `args.hueSteps` Hue Steps Count [5,
|
2213
|
-
* * `args.lightSteps` Lightness Steps Count [
|
2230
|
+
* * `args.hueSteps` Hue Steps Count [5, 24]
|
2231
|
+
* * `args.lightSteps` Lightness Steps Count [5, 12]
|
2214
2232
|
*/
|
2215
2233
|
constructor(...args) {
|
2216
2234
|
let hue = 0;
|
@@ -2223,24 +2241,32 @@ class ColorPalette {
|
|
2223
2241
|
} else if (args.length === 2) {
|
2224
2242
|
[hueSteps, lightSteps] = args;
|
2225
2243
|
} else {
|
2226
|
-
throw TypeError('
|
2244
|
+
throw TypeError('ColorPalette requires minimum 2 arguments');
|
2227
2245
|
}
|
2228
2246
|
|
2229
2247
|
/** @type {string[]} */
|
2230
2248
|
const colors = [];
|
2231
2249
|
|
2232
2250
|
const hueStep = 360 / hueSteps;
|
2233
|
-
const
|
2234
|
-
const
|
2251
|
+
const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
|
2252
|
+
const estimatedStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
|
2253
|
+
|
2254
|
+
let lightStep = 0.25;
|
2255
|
+
lightStep = [4, 5].includes(lightSteps) ? 0.2 : lightStep;
|
2256
|
+
lightStep = [6, 7].includes(lightSteps) ? 0.15 : lightStep;
|
2257
|
+
lightStep = [8, 9].includes(lightSteps) ? 0.11 : lightStep;
|
2258
|
+
lightStep = [10, 11].includes(lightSteps) ? 0.09 : lightStep;
|
2259
|
+
lightStep = [12, 13].includes(lightSteps) ? 0.075 : lightStep;
|
2260
|
+
lightStep = lightSteps > 13 ? estimatedStep : lightStep;
|
2235
2261
|
|
2236
2262
|
// light tints
|
2237
|
-
for (let i =
|
2238
|
-
lightnessArray = [...lightnessArray, (0.5 + lightStep * (i
|
2263
|
+
for (let i = 1; i < half + 1; i += 1) {
|
2264
|
+
lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
|
2239
2265
|
}
|
2240
2266
|
|
2241
2267
|
// dark tints
|
2242
|
-
for (let i =
|
2243
|
-
lightnessArray = [(0.5 - lightStep * (i
|
2268
|
+
for (let i = 1; i < lightSteps - half; i += 1) {
|
2269
|
+
lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
|
2244
2270
|
}
|
2245
2271
|
|
2246
2272
|
// feed `colors` Array
|
@@ -2275,45 +2301,38 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2275
2301
|
colorsArray = colorsArray instanceof Array ? colorsArray : [];
|
2276
2302
|
const colorsCount = colorsArray.length;
|
2277
2303
|
const { lightSteps } = isPalette ? colorsSource : { lightSteps: null };
|
2278
|
-
|
2279
|
-
|| Math.max(...[5, 6, 7, 8, 9, 10].filter((x) => colorsCount > (x * 2) && !(colorsCount % x)));
|
2280
|
-
fit = Number.isFinite(fit) ? fit : 5;
|
2304
|
+
const fit = lightSteps || [9, 10].find((x) => colorsCount > x * 2 && !(colorsCount % x)) || 5;
|
2281
2305
|
const isMultiLine = isOptionsMenu && colorsCount > fit;
|
2282
|
-
let rowCountHover =
|
2283
|
-
rowCountHover = isMultiLine && colorsCount
|
2284
|
-
rowCountHover = colorsCount >=
|
2285
|
-
rowCountHover = colorsCount >=
|
2286
|
-
|
2287
|
-
const
|
2288
|
-
const isScrollable = isMultiLine && colorsCount > rowCountHover * fit;
|
2306
|
+
let rowCountHover = 2;
|
2307
|
+
rowCountHover = isMultiLine && colorsCount >= fit * 2 ? 3 : rowCountHover;
|
2308
|
+
rowCountHover = colorsCount >= fit * 3 ? 4 : rowCountHover;
|
2309
|
+
rowCountHover = colorsCount >= fit * 4 ? 5 : rowCountHover;
|
2310
|
+
const rowCount = rowCountHover - (colorsCount < fit * 3 ? 1 : 2);
|
2311
|
+
const isScrollable = isMultiLine && colorsCount > rowCount * fit;
|
2289
2312
|
let finalClass = menuClass;
|
2290
2313
|
finalClass += isScrollable ? ' scrollable' : '';
|
2291
2314
|
finalClass += isMultiLine ? ' multiline' : '';
|
2292
2315
|
const gap = isMultiLine ? '1px' : '0.25rem';
|
2293
2316
|
let optionSize = isMultiLine ? 1.75 : 2;
|
2294
|
-
optionSize =
|
2317
|
+
optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
|
2295
2318
|
const menuHeight = `${(rowCount || 1) * optionSize}rem`;
|
2296
2319
|
const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
|
2297
|
-
const gridTemplateColumns = `repeat(${fit}, ${optionSize}rem)`;
|
2298
|
-
const gridTemplateRows = `repeat(auto-fill, ${optionSize}rem)`;
|
2299
2320
|
|
2300
2321
|
const menu = createElement({
|
2301
2322
|
tagName: 'ul',
|
2302
2323
|
className: finalClass,
|
2303
2324
|
});
|
2304
2325
|
setAttribute(menu, 'role', 'listbox');
|
2305
|
-
setAttribute(menu, ariaLabel,
|
2306
|
-
|
2307
|
-
if (
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2314
|
-
|
2315
|
-
};
|
2316
|
-
setElementStyle(menu, menuStyle);
|
2326
|
+
setAttribute(menu, ariaLabel, menuLabel);
|
2327
|
+
|
2328
|
+
if (isScrollable) { // @ts-ignore
|
2329
|
+
setCSSProperties(menu, {
|
2330
|
+
'--grid-item-size': `${optionSize}rem`,
|
2331
|
+
'--grid-fit': fit,
|
2332
|
+
'--grid-gap': gap,
|
2333
|
+
'--grid-height': menuHeight,
|
2334
|
+
'--grid-hover-height': menuHeightHover,
|
2335
|
+
});
|
2317
2336
|
}
|
2318
2337
|
|
2319
2338
|
colorsArray.forEach((x) => {
|
@@ -2328,15 +2347,13 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2328
2347
|
innerText: `${label || x}`,
|
2329
2348
|
});
|
2330
2349
|
|
2331
|
-
setAttribute(option,
|
2350
|
+
setAttribute(option, tabIndex, '0');
|
2332
2351
|
setAttribute(option, 'data-value', `${value}`);
|
2333
2352
|
setAttribute(option, 'role', 'option');
|
2334
2353
|
setAttribute(option, ariaSelected, isActive ? 'true' : 'false');
|
2335
2354
|
|
2336
2355
|
if (isOptionsMenu) {
|
2337
|
-
setElementStyle(option, {
|
2338
|
-
width: `${optionSize}rem`, height: `${optionSize}rem`, backgroundColor: x,
|
2339
|
-
});
|
2356
|
+
setElementStyle(option, { backgroundColor: x });
|
2340
2357
|
}
|
2341
2358
|
|
2342
2359
|
menu.append(option);
|
@@ -2358,7 +2375,7 @@ function isValidJSON(str) {
|
|
2358
2375
|
return true;
|
2359
2376
|
}
|
2360
2377
|
|
2361
|
-
var version = "0.0.
|
2378
|
+
var version = "0.0.1alpha3";
|
2362
2379
|
|
2363
2380
|
// @ts-ignore
|
2364
2381
|
|
@@ -2373,8 +2390,8 @@ const colorPickerDefaults = {
|
|
2373
2390
|
componentLabels: colorPickerLabels,
|
2374
2391
|
colorLabels: colorNames,
|
2375
2392
|
format: 'rgb',
|
2376
|
-
colorPresets:
|
2377
|
-
colorKeywords:
|
2393
|
+
colorPresets: false,
|
2394
|
+
colorKeywords: false,
|
2378
2395
|
};
|
2379
2396
|
|
2380
2397
|
// ColorPicker Static Methods
|
@@ -2463,7 +2480,7 @@ function initCallback(self) {
|
|
2463
2480
|
tagName: 'button',
|
2464
2481
|
className: 'menu-toggle btn-appearance',
|
2465
2482
|
});
|
2466
|
-
setAttribute(presetsBtn,
|
2483
|
+
setAttribute(presetsBtn, tabIndex, '-1');
|
2467
2484
|
setAttribute(presetsBtn, ariaExpanded, 'false');
|
2468
2485
|
setAttribute(presetsBtn, ariaHasPopup, 'true');
|
2469
2486
|
|
@@ -2490,7 +2507,7 @@ function initCallback(self) {
|
|
2490
2507
|
if (colorKeywords && nonColors.includes(colorValue)) {
|
2491
2508
|
self.value = colorValue;
|
2492
2509
|
}
|
2493
|
-
setAttribute(input,
|
2510
|
+
setAttribute(input, tabIndex, '-1');
|
2494
2511
|
}
|
2495
2512
|
|
2496
2513
|
/**
|
@@ -2591,8 +2608,19 @@ function showDropdown(self, dropdown) {
|
|
2591
2608
|
addClass(dropdown, 'bottom');
|
2592
2609
|
reflow(dropdown);
|
2593
2610
|
addClass(dropdown, 'show');
|
2611
|
+
|
2594
2612
|
if (isPicker) self.update();
|
2595
|
-
|
2613
|
+
|
2614
|
+
if (!self.isOpen) {
|
2615
|
+
toggleEventsOnShown(self, true);
|
2616
|
+
self.updateDropdownPosition();
|
2617
|
+
self.isOpen = true;
|
2618
|
+
setAttribute(self.input, tabIndex, '0');
|
2619
|
+
if (menuToggle) {
|
2620
|
+
setAttribute(menuToggle, tabIndex, '0');
|
2621
|
+
}
|
2622
|
+
}
|
2623
|
+
|
2596
2624
|
setAttribute(nextBtn, ariaExpanded, 'true');
|
2597
2625
|
if (activeBtn) {
|
2598
2626
|
setAttribute(activeBtn, ariaExpanded, 'false');
|
@@ -2762,7 +2790,7 @@ class ColorPicker {
|
|
2762
2790
|
set value(v) { this.input.value = v; }
|
2763
2791
|
|
2764
2792
|
/** Check if the colour presets include any non-colour. */
|
2765
|
-
get
|
2793
|
+
get hasNonColor() {
|
2766
2794
|
return this.colorKeywords instanceof Array
|
2767
2795
|
&& this.colorKeywords.some((x) => nonColors.includes(x));
|
2768
2796
|
}
|
@@ -2818,7 +2846,7 @@ class ColorPicker {
|
|
2818
2846
|
const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
|
2819
2847
|
const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
|
2820
2848
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
2821
|
-
const roundA =
|
2849
|
+
const roundA = roundPart((alpha * 100)) / 100;
|
2822
2850
|
|
2823
2851
|
if (format !== 'hsl') {
|
2824
2852
|
const fill = new Color({
|
@@ -2836,7 +2864,7 @@ class ColorPicker {
|
|
2836
2864
|
});
|
2837
2865
|
setElementStyle(v2, { background: hueGradient });
|
2838
2866
|
} else {
|
2839
|
-
const saturation =
|
2867
|
+
const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
|
2840
2868
|
const fill0 = new Color({
|
2841
2869
|
r: 255, g: 0, b: 0, a: alpha,
|
2842
2870
|
}).saturate(-saturation).toRgbString();
|
@@ -2991,12 +3019,12 @@ class ColorPicker {
|
|
2991
3019
|
|
2992
3020
|
self.update();
|
2993
3021
|
|
2994
|
-
if (currentActive) {
|
2995
|
-
removeClass(currentActive, 'active');
|
2996
|
-
removeAttribute(currentActive, ariaSelected);
|
2997
|
-
}
|
2998
|
-
|
2999
3022
|
if (currentActive !== target) {
|
3023
|
+
if (currentActive) {
|
3024
|
+
removeClass(currentActive, 'active');
|
3025
|
+
removeAttribute(currentActive, ariaSelected);
|
3026
|
+
}
|
3027
|
+
|
3000
3028
|
addClass(target, 'active');
|
3001
3029
|
setAttribute(target, ariaSelected, 'true');
|
3002
3030
|
|
@@ -3163,7 +3191,7 @@ class ColorPicker {
|
|
3163
3191
|
const [v1, v2, v3, v4] = format === 'rgb'
|
3164
3192
|
? inputs.map((i) => parseFloat(i.value) / (i === i4 ? 100 : 1))
|
3165
3193
|
: inputs.map((i) => parseFloat(i.value) / (i !== i1 ? 100 : 360));
|
3166
|
-
const isNonColorValue = self.
|
3194
|
+
const isNonColorValue = self.hasNonColor && nonColors.includes(currentValue);
|
3167
3195
|
const alpha = i4 ? v4 : (1 - controlPositions.c3y / offsetHeight);
|
3168
3196
|
|
3169
3197
|
if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
|
@@ -3422,11 +3450,11 @@ class ColorPicker {
|
|
3422
3450
|
} = componentLabels;
|
3423
3451
|
const { r, g, b } = color.toRgb();
|
3424
3452
|
const [knob1, knob2, knob3] = controlKnobs;
|
3425
|
-
const hue =
|
3453
|
+
const hue = roundPart(hsl.h * 360);
|
3426
3454
|
const alpha = color.a;
|
3427
3455
|
const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
|
3428
|
-
const saturation =
|
3429
|
-
const lightness =
|
3456
|
+
const saturation = roundPart(saturationSource * 100);
|
3457
|
+
const lightness = roundPart(hsl.l * 100);
|
3430
3458
|
const hsvl = hsv.v * 100;
|
3431
3459
|
let colorName;
|
3432
3460
|
|
@@ -3473,8 +3501,8 @@ class ColorPicker {
|
|
3473
3501
|
setAttribute(knob2, ariaValueNow, `${saturation}`);
|
3474
3502
|
} else if (format === 'hwb') {
|
3475
3503
|
const { hwb } = self;
|
3476
|
-
const whiteness =
|
3477
|
-
const blackness =
|
3504
|
+
const whiteness = roundPart(hwb.w * 100);
|
3505
|
+
const blackness = roundPart(hwb.b * 100);
|
3478
3506
|
colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
|
3479
3507
|
setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3480
3508
|
setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
|
@@ -3490,7 +3518,7 @@ class ColorPicker {
|
|
3490
3518
|
setAttribute(knob2, ariaValueNow, `${hue}`);
|
3491
3519
|
}
|
3492
3520
|
|
3493
|
-
const alphaValue =
|
3521
|
+
const alphaValue = roundPart(alpha * 100);
|
3494
3522
|
setAttribute(knob3, ariaValueText, `${alphaValue}%`);
|
3495
3523
|
setAttribute(knob3, ariaValueNow, `${alphaValue}`);
|
3496
3524
|
|
@@ -3513,10 +3541,14 @@ class ColorPicker {
|
|
3513
3541
|
/** Updates the control knobs actual positions. */
|
3514
3542
|
updateControls() {
|
3515
3543
|
const { controlKnobs, controlPositions } = this;
|
3544
|
+
const {
|
3545
|
+
c1x, c1y, c2y, c3y,
|
3546
|
+
} = controlPositions;
|
3516
3547
|
const [control1, control2, control3] = controlKnobs;
|
3517
|
-
|
3518
|
-
setElementStyle(
|
3519
|
-
setElementStyle(
|
3548
|
+
|
3549
|
+
setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
|
3550
|
+
setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
|
3551
|
+
setElementStyle(control3, { transform: `translate3d(0,${c3y - 4}px,0)` });
|
3520
3552
|
}
|
3521
3553
|
|
3522
3554
|
/**
|
@@ -3529,16 +3561,16 @@ class ColorPicker {
|
|
3529
3561
|
value: oldColor, format, inputs, color, hsl,
|
3530
3562
|
} = self;
|
3531
3563
|
const [i1, i2, i3, i4] = inputs;
|
3532
|
-
const alpha =
|
3533
|
-
const hue =
|
3564
|
+
const alpha = roundPart(color.a * 100);
|
3565
|
+
const hue = roundPart(hsl.h * 360);
|
3534
3566
|
let newColor;
|
3535
3567
|
|
3536
3568
|
if (format === 'hex') {
|
3537
3569
|
newColor = self.color.toHexString(true);
|
3538
3570
|
i1.value = self.hex;
|
3539
3571
|
} else if (format === 'hsl') {
|
3540
|
-
const lightness =
|
3541
|
-
const saturation =
|
3572
|
+
const lightness = roundPart(hsl.l * 100);
|
3573
|
+
const saturation = roundPart(hsl.s * 100);
|
3542
3574
|
newColor = self.color.toHslString();
|
3543
3575
|
i1.value = `${hue}`;
|
3544
3576
|
i2.value = `${saturation}`;
|
@@ -3546,8 +3578,8 @@ class ColorPicker {
|
|
3546
3578
|
i4.value = `${alpha}`;
|
3547
3579
|
} else if (format === 'hwb') {
|
3548
3580
|
const { w, b } = self.hwb;
|
3549
|
-
const whiteness =
|
3550
|
-
const blackness =
|
3581
|
+
const whiteness = roundPart(w * 100);
|
3582
|
+
const blackness = roundPart(b * 100);
|
3551
3583
|
|
3552
3584
|
newColor = self.color.toHwbString();
|
3553
3585
|
i1.value = `${hue}`;
|
@@ -3619,7 +3651,7 @@ class ColorPicker {
|
|
3619
3651
|
const self = this;
|
3620
3652
|
const { colorPicker } = self;
|
3621
3653
|
|
3622
|
-
if (!hasClass(colorPicker,
|
3654
|
+
if (!['top', 'bottom'].some((c) => hasClass(colorPicker, c))) {
|
3623
3655
|
showDropdown(self, colorPicker);
|
3624
3656
|
}
|
3625
3657
|
}
|
@@ -3636,21 +3668,6 @@ class ColorPicker {
|
|
3636
3668
|
}
|
3637
3669
|
}
|
3638
3670
|
|
3639
|
-
/** Shows the `ColorPicker` dropdown or the presets menu. */
|
3640
|
-
show() {
|
3641
|
-
const self = this;
|
3642
|
-
const { menuToggle } = self;
|
3643
|
-
if (!self.isOpen) {
|
3644
|
-
toggleEventsOnShown(self, true);
|
3645
|
-
self.updateDropdownPosition();
|
3646
|
-
self.isOpen = true;
|
3647
|
-
setAttribute(self.input, 'tabindex', '0');
|
3648
|
-
if (menuToggle) {
|
3649
|
-
setAttribute(menuToggle, 'tabindex', '0');
|
3650
|
-
}
|
3651
|
-
}
|
3652
|
-
}
|
3653
|
-
|
3654
3671
|
/**
|
3655
3672
|
* Hides the currently open `ColorPicker` dropdown.
|
3656
3673
|
* @param {boolean=} focusPrevented
|
@@ -3685,9 +3702,9 @@ class ColorPicker {
|
|
3685
3702
|
if (!focusPrevented) {
|
3686
3703
|
focus(pickerToggle);
|
3687
3704
|
}
|
3688
|
-
setAttribute(input,
|
3705
|
+
setAttribute(input, tabIndex, '-1');
|
3689
3706
|
if (menuToggle) {
|
3690
|
-
setAttribute(menuToggle,
|
3707
|
+
setAttribute(menuToggle, tabIndex, '-1');
|
3691
3708
|
}
|
3692
3709
|
}
|
3693
3710
|
}
|
@@ -3701,7 +3718,10 @@ class ColorPicker {
|
|
3701
3718
|
[...parent.children].forEach((el) => {
|
3702
3719
|
if (el !== input) el.remove();
|
3703
3720
|
});
|
3721
|
+
|
3722
|
+
removeAttribute(input, tabIndex);
|
3704
3723
|
setElementStyle(input, { backgroundColor: '' });
|
3724
|
+
|
3705
3725
|
['txt-light', 'txt-dark'].forEach((c) => removeClass(parent, c));
|
3706
3726
|
Data.remove(input, colorPickerString);
|
3707
3727
|
}
|
@@ -3709,10 +3729,16 @@ class ColorPicker {
|
|
3709
3729
|
|
3710
3730
|
ObjectAssign(ColorPicker, {
|
3711
3731
|
Color,
|
3732
|
+
ColorPalette,
|
3712
3733
|
Version,
|
3713
3734
|
getInstance: getColorPickerInstance,
|
3714
3735
|
init: initColorPicker,
|
3715
3736
|
selector: colorPickerSelector,
|
3737
|
+
// utils important for render
|
3738
|
+
roundPart,
|
3739
|
+
setElementStyle,
|
3740
|
+
setAttribute,
|
3741
|
+
getBoundingClientRect,
|
3716
3742
|
});
|
3717
3743
|
|
3718
3744
|
let CPID = 0;
|
@@ -3720,8 +3746,9 @@ let CPID = 0;
|
|
3720
3746
|
/**
|
3721
3747
|
* `ColorPickerElement` Web Component.
|
3722
3748
|
* @example
|
3723
|
-
* <
|
3724
|
-
*
|
3749
|
+
* <label for="UNIQUE_ID">Label</label>
|
3750
|
+
* <color-picker data-format="hex" data-value="#075">
|
3751
|
+
* <input id="UNIQUE_ID" type="text" class="color-preview btn-appearance">
|
3725
3752
|
* </color-picker>
|
3726
3753
|
*/
|
3727
3754
|
class ColorPickerElement extends HTMLElement {
|
@@ -3802,6 +3829,8 @@ class ColorPickerElement extends HTMLElement {
|
|
3802
3829
|
ObjectAssign(ColorPickerElement, {
|
3803
3830
|
Color,
|
3804
3831
|
ColorPicker,
|
3832
|
+
ColorPalette,
|
3833
|
+
getInstance: getColorPickerInstance,
|
3805
3834
|
Version,
|
3806
3835
|
});
|
3807
3836
|
|