@thednp/color-picker 0.0.2-alpha1 → 0.0.2-alpha4

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * ColorPicker v0.0.2alpha1 (http://thednp.github.io/color-picker)
2
+ * ColorPicker v0.0.2alpha4 (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
  */
@@ -843,6 +843,8 @@
843
843
  if (nonColors.includes(color)
844
844
  || ['#', ...COLOR_FORMAT].some((f) => color.includes(f))) return false;
845
845
 
846
+ if (['black', 'white'].includes(color)) return true;
847
+
846
848
  return ['rgb(255, 255, 255)', 'rgb(0, 0, 0)'].every((c) => {
847
849
  setElementStyle(documentHead, { color });
848
850
  const computedColor = getElementStyle(documentHead, 'color');
@@ -869,6 +871,11 @@
869
871
  */
870
872
  function bound01(N, max) {
871
873
  let n = N;
874
+
875
+ if (typeof N === 'number'
876
+ && Math.min(N, 0) === 0 // round values to 6 decimals Math.round(N * (10 ** 6)) / 10 ** 6
877
+ && Math.max(N, 1) === 1) return N;
878
+
872
879
  if (isOnePointZero(N)) n = '100%';
873
880
 
874
881
  const processPercent = isPercentage(n);
@@ -972,15 +979,12 @@
972
979
  /**
973
980
  * Converts an RGB colour value to HSL.
974
981
  *
975
- * @param {number} R Red component [0, 255]
976
- * @param {number} G Green component [0, 255]
977
- * @param {number} B Blue component [0, 255]
982
+ * @param {number} r Red component [0, 1]
983
+ * @param {number} g Green component [0, 1]
984
+ * @param {number} b Blue component [0, 1]
978
985
  * @returns {CP.HSL} {h,s,l} object with [0, 1] ranged values
979
986
  */
980
- function rgbToHsl(R, G, B) {
981
- const r = R / 255;
982
- const g = G / 255;
983
- const b = B / 255;
987
+ function rgbToHsl(r, g, b) {
984
988
  const max = Math.max(r, g, b);
985
989
  const min = Math.min(r, g, b);
986
990
  let h = 0;
@@ -992,17 +996,10 @@
992
996
  } else {
993
997
  const d = max - min;
994
998
  s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
995
- switch (max) {
996
- case r:
997
- h = (g - b) / d + (g < b ? 6 : 0);
998
- break;
999
- case g:
1000
- h = (b - r) / d + 2;
1001
- break;
1002
- case b:
1003
- h = (r - g) / d + 4;
1004
- break;
1005
- }
999
+ if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
1000
+ if (max === g) h = (b - r) / d + 2;
1001
+ if (max === b) h = (r - g) / d + 4;
1002
+
1006
1003
  h /= 6;
1007
1004
  }
1008
1005
  return { h, s, l };
@@ -1031,7 +1028,7 @@
1031
1028
  * @param {number} h Hue Angle [0, 1]
1032
1029
  * @param {number} s Saturation [0, 1]
1033
1030
  * @param {number} l Lightness Angle [0, 1]
1034
- * @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
1031
+ * @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
1035
1032
  */
1036
1033
  function hslToRgb(h, s, l) {
1037
1034
  let r = 0;
@@ -1050,7 +1047,6 @@
1050
1047
  g = hueToRgb(p, q, h);
1051
1048
  b = hueToRgb(p, q, h - 1 / 3);
1052
1049
  }
1053
- [r, g, b] = [r, g, b].map((x) => x * 255);
1054
1050
 
1055
1051
  return { r, g, b };
1056
1052
  }
@@ -1060,16 +1056,12 @@
1060
1056
  * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
1061
1057
  * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
1062
1058
  *
1063
- * @param {number} R Red component [0, 255]
1064
- * @param {number} G Green [0, 255]
1065
- * @param {number} B Blue [0, 255]
1059
+ * @param {number} r Red component [0, 1]
1060
+ * @param {number} g Green [0, 1]
1061
+ * @param {number} b Blue [0, 1]
1066
1062
  * @return {CP.HWB} {h,w,b} object with [0, 1] ranged values
1067
1063
  */
1068
- function rgbToHwb(R, G, B) {
1069
- const r = R / 255;
1070
- const g = G / 255;
1071
- const b = B / 255;
1072
-
1064
+ function rgbToHwb(r, g, b) {
1073
1065
  let f = 0;
1074
1066
  let i = 0;
1075
1067
  const whiteness = Math.min(r, g, b);
@@ -1099,20 +1091,18 @@
1099
1091
  * @param {number} H Hue Angle [0, 1]
1100
1092
  * @param {number} W Whiteness [0, 1]
1101
1093
  * @param {number} B Blackness [0, 1]
1102
- * @return {CP.RGB} {r,g,b} object with [0, 255] ranged values
1094
+ * @return {CP.RGB} {r,g,b} object with [0, 1] ranged values
1103
1095
  *
1104
1096
  * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
1105
1097
  * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
1106
1098
  */
1107
1099
  function hwbToRgb(H, W, B) {
1108
1100
  if (W + B >= 1) {
1109
- const gray = (W / (W + B)) * 255;
1101
+ const gray = W / (W + B);
1110
1102
  return { r: gray, g: gray, b: gray };
1111
1103
  }
1112
1104
  let { r, g, b } = hslToRgb(H, 1, 0.5);
1113
- [r, g, b] = [r, g, b]
1114
- .map((v) => (v / 255) * (1 - W - B) + W)
1115
- .map((v) => v * 255);
1105
+ [r, g, b] = [r, g, b].map((v) => v * (1 - W - B) + W);
1116
1106
 
1117
1107
  return { r, g, b };
1118
1108
  }
@@ -1120,15 +1110,12 @@
1120
1110
  /**
1121
1111
  * Converts an RGB colour value to HSV.
1122
1112
  *
1123
- * @param {number} R Red component [0, 255]
1124
- * @param {number} G Green [0, 255]
1125
- * @param {number} B Blue [0, 255]
1113
+ * @param {number} r Red component [0, 1]
1114
+ * @param {number} g Green [0, 1]
1115
+ * @param {number} b Blue [0, 1]
1126
1116
  * @returns {CP.HSV} {h,s,v} object with [0, 1] ranged values
1127
1117
  */
1128
- function rgbToHsv(R, G, B) {
1129
- const r = R / 255;
1130
- const g = G / 255;
1131
- const b = B / 255;
1118
+ function rgbToHsv(r, g, b) {
1132
1119
  const max = Math.max(r, g, b);
1133
1120
  const min = Math.min(r, g, b);
1134
1121
  let h = 0;
@@ -1138,17 +1125,10 @@
1138
1125
  if (max === min) {
1139
1126
  h = 0; // achromatic
1140
1127
  } else {
1141
- switch (max) {
1142
- case r:
1143
- h = (g - b) / d + (g < b ? 6 : 0);
1144
- break;
1145
- case g:
1146
- h = (b - r) / d + 2;
1147
- break;
1148
- case b:
1149
- h = (r - g) / d + 4;
1150
- break;
1151
- }
1128
+ if (r === max) h = (g - b) / d + (g < b ? 6 : 0);
1129
+ if (g === max) h = (b - r) / d + 2;
1130
+ if (b === max) h = (r - g) / d + 4;
1131
+
1152
1132
  h /= 6;
1153
1133
  }
1154
1134
  return { h, s, v };
@@ -1172,10 +1152,9 @@
1172
1152
  const q = v * (1 - f * s);
1173
1153
  const t = v * (1 - (1 - f) * s);
1174
1154
  const mod = i % 6;
1175
- let r = [v, q, p, p, t, v][mod];
1176
- let g = [t, v, v, q, p, p][mod];
1177
- let b = [p, p, t, v, v, q][mod];
1178
- [r, g, b] = [r, g, b].map((n) => n * 255);
1155
+ const r = [v, q, p, p, t, v][mod];
1156
+ const g = [t, v, v, q, p, p][mod];
1157
+ const b = [p, p, t, v, v, q][mod];
1179
1158
  return { r, g, b };
1180
1159
  }
1181
1160
 
@@ -1243,15 +1222,15 @@
1243
1222
  */
1244
1223
  function stringInputToObject(input) {
1245
1224
  let color = toLowerCase(input.trim());
1225
+
1246
1226
  if (color.length === 0) {
1247
1227
  return {
1248
1228
  r: 0, g: 0, b: 0, a: 1,
1249
1229
  };
1250
1230
  }
1251
- let named = false;
1231
+
1252
1232
  if (isColorName(color)) {
1253
1233
  color = getRGBFromName(color);
1254
- named = true;
1255
1234
  } else if (nonColors.includes(color)) {
1256
1235
  const a = color === 'transparent' ? 0 : 1;
1257
1236
  return {
@@ -1270,24 +1249,28 @@
1270
1249
  r: m1, g: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'rgb',
1271
1250
  };
1272
1251
  }
1252
+
1273
1253
  [, m1, m2, m3, m4] = matchers.hsl.exec(color) || [];
1274
1254
  if (m1 && m2 && m3/* && m4 */) {
1275
1255
  return {
1276
1256
  h: m1, s: m2, l: m3, a: m4 !== undefined ? m4 : 1, format: 'hsl',
1277
1257
  };
1278
1258
  }
1259
+
1279
1260
  [, m1, m2, m3, m4] = matchers.hsv.exec(color) || [];
1280
1261
  if (m1 && m2 && m3/* && m4 */) {
1281
1262
  return {
1282
1263
  h: m1, s: m2, v: m3, a: m4 !== undefined ? m4 : 1, format: 'hsv',
1283
1264
  };
1284
1265
  }
1266
+
1285
1267
  [, m1, m2, m3, m4] = matchers.hwb.exec(color) || [];
1286
1268
  if (m1 && m2 && m3) {
1287
1269
  return {
1288
1270
  h: m1, w: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'hwb',
1289
1271
  };
1290
1272
  }
1273
+
1291
1274
  [, m1, m2, m3, m4] = matchers.hex8.exec(color) || [];
1292
1275
  if (m1 && m2 && m3 && m4) {
1293
1276
  return {
@@ -1295,18 +1278,20 @@
1295
1278
  g: parseIntFromHex(m2),
1296
1279
  b: parseIntFromHex(m3),
1297
1280
  a: convertHexToDecimal(m4),
1298
- format: named ? 'rgb' : 'hex',
1281
+ format: 'hex',
1299
1282
  };
1300
1283
  }
1284
+
1301
1285
  [, m1, m2, m3] = matchers.hex6.exec(color) || [];
1302
1286
  if (m1 && m2 && m3) {
1303
1287
  return {
1304
1288
  r: parseIntFromHex(m1),
1305
1289
  g: parseIntFromHex(m2),
1306
1290
  b: parseIntFromHex(m3),
1307
- format: named ? 'rgb' : 'hex',
1291
+ format: 'hex',
1308
1292
  };
1309
1293
  }
1294
+
1310
1295
  [, m1, m2, m3, m4] = matchers.hex4.exec(color) || [];
1311
1296
  if (m1 && m2 && m3 && m4) {
1312
1297
  return {
@@ -1314,19 +1299,20 @@
1314
1299
  g: parseIntFromHex(m2 + m2),
1315
1300
  b: parseIntFromHex(m3 + m3),
1316
1301
  a: convertHexToDecimal(m4 + m4),
1317
- // format: named ? 'rgb' : 'hex8',
1318
- format: named ? 'rgb' : 'hex',
1302
+ format: 'hex',
1319
1303
  };
1320
1304
  }
1305
+
1321
1306
  [, m1, m2, m3] = matchers.hex3.exec(color) || [];
1322
1307
  if (m1 && m2 && m3) {
1323
1308
  return {
1324
1309
  r: parseIntFromHex(m1 + m1),
1325
1310
  g: parseIntFromHex(m2 + m2),
1326
1311
  b: parseIntFromHex(m3 + m3),
1327
- format: named ? 'rgb' : 'hex',
1312
+ format: 'hex',
1328
1313
  };
1329
1314
  }
1315
+
1330
1316
  return false;
1331
1317
  }
1332
1318
 
@@ -1357,6 +1343,7 @@
1357
1343
  */
1358
1344
  function inputToRGB(input) {
1359
1345
  let rgb = { r: 0, g: 0, b: 0 };
1346
+ /** @type {*} */
1360
1347
  let color = input;
1361
1348
  /** @type {string | number} */
1362
1349
  let a = 1;
@@ -1373,39 +1360,41 @@
1373
1360
  let format = inputFormat && COLOR_FORMAT.includes(inputFormat) ? inputFormat : 'rgb';
1374
1361
 
1375
1362
  if (typeof input === 'string') {
1376
- // @ts-ignore -- this now is converted to object
1377
1363
  color = stringInputToObject(input);
1378
1364
  if (color) ok = true;
1379
1365
  }
1380
1366
  if (typeof color === 'object') {
1381
1367
  if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
1382
1368
  ({ r, g, b } = color);
1383
- // RGB values now are all in [0, 255] range
1384
- [r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255) * 255);
1369
+ // RGB values now are all in [0, 1] range
1370
+ [r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255));
1385
1371
  rgb = { r, g, b };
1386
1372
  ok = true;
1387
- format = 'rgb';
1388
- } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
1373
+ format = color.format || 'rgb';
1374
+ }
1375
+ if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
1389
1376
  ({ h, s, v } = color);
1390
- h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1391
- s = typeof s === 'number' ? s : bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1392
- v = typeof v === 'number' ? v : bound01(v, 100); // brightness can be `5%` or a [0, 1] value
1377
+ h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1378
+ s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1379
+ v = bound01(v, 100); // brightness can be `5%` or a [0, 1] value
1393
1380
  rgb = hsvToRgb(h, s, v);
1394
1381
  ok = true;
1395
1382
  format = 'hsv';
1396
- } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
1383
+ }
1384
+ if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
1397
1385
  ({ h, s, l } = color);
1398
- h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1399
- s = typeof s === 'number' ? s : bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1400
- l = typeof l === 'number' ? l : bound01(l, 100); // lightness can be `5%` or a [0, 1] value
1386
+ h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1387
+ s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1388
+ l = bound01(l, 100); // lightness can be `5%` or a [0, 1] value
1401
1389
  rgb = hslToRgb(h, s, l);
1402
1390
  ok = true;
1403
1391
  format = 'hsl';
1404
- } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
1392
+ }
1393
+ if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
1405
1394
  ({ h, w, b } = color);
1406
- h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1407
- w = typeof w === 'number' ? w : bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
1408
- b = typeof b === 'number' ? b : bound01(b, 100); // blackness can be `5%` or a [0, 1] value
1395
+ h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1396
+ w = bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
1397
+ b = bound01(b, 100); // blackness can be `5%` or a [0, 1] value
1409
1398
  rgb = hwbToRgb(h, w, b);
1410
1399
  ok = true;
1411
1400
  format = 'hwb';
@@ -1422,9 +1411,12 @@
1422
1411
  return {
1423
1412
  ok,
1424
1413
  format,
1425
- r: Math.min(255, Math.max(rgb.r, 0)),
1426
- g: Math.min(255, Math.max(rgb.g, 0)),
1427
- b: Math.min(255, Math.max(rgb.b, 0)),
1414
+ // r: Math.min(255, Math.max(rgb.r, 0)),
1415
+ // g: Math.min(255, Math.max(rgb.g, 0)),
1416
+ // b: Math.min(255, Math.max(rgb.b, 0)),
1417
+ r: rgb.r,
1418
+ g: rgb.g,
1419
+ b: rgb.b,
1428
1420
  a: boundAlpha(a),
1429
1421
  };
1430
1422
  }
@@ -1443,16 +1435,13 @@
1443
1435
  constructor(input, config) {
1444
1436
  let color = input;
1445
1437
  const configFormat = config && COLOR_FORMAT.includes(config)
1446
- ? config : 'rgb';
1438
+ ? config : '';
1447
1439
 
1448
- // If input is already a `Color`, return itself
1440
+ // If input is already a `Color`, clone its values
1449
1441
  if (color instanceof Color) {
1450
1442
  color = inputToRGB(color);
1451
1443
  }
1452
- if (typeof color === 'number') {
1453
- const len = `${color}`.length;
1454
- color = `#${(len === 2 ? '0' : '00')}${color}`;
1455
- }
1444
+
1456
1445
  const {
1457
1446
  r, g, b, a, ok, format,
1458
1447
  } = inputToRGB(color);
@@ -1502,24 +1491,21 @@
1502
1491
  let R = 0;
1503
1492
  let G = 0;
1504
1493
  let B = 0;
1505
- const rp = r / 255;
1506
- const rg = g / 255;
1507
- const rb = b / 255;
1508
1494
 
1509
- if (rp <= 0.03928) {
1510
- R = rp / 12.92;
1495
+ if (r <= 0.03928) {
1496
+ R = r / 12.92;
1511
1497
  } else {
1512
- R = ((rp + 0.055) / 1.055) ** 2.4;
1498
+ R = ((r + 0.055) / 1.055) ** 2.4;
1513
1499
  }
1514
- if (rg <= 0.03928) {
1515
- G = rg / 12.92;
1500
+ if (g <= 0.03928) {
1501
+ G = g / 12.92;
1516
1502
  } else {
1517
- G = ((rg + 0.055) / 1.055) ** 2.4;
1503
+ G = ((g + 0.055) / 1.055) ** 2.4;
1518
1504
  }
1519
- if (rb <= 0.03928) {
1520
- B = rb / 12.92;
1505
+ if (b <= 0.03928) {
1506
+ B = b / 12.92;
1521
1507
  } else {
1522
- B = ((rb + 0.055) / 1.055) ** 2.4;
1508
+ B = ((b + 0.055) / 1.055) ** 2.4;
1523
1509
  }
1524
1510
  return 0.2126 * R + 0.7152 * G + 0.0722 * B;
1525
1511
  }
@@ -1529,7 +1515,7 @@
1529
1515
  * @returns {number} a number in the [0, 255] range
1530
1516
  */
1531
1517
  get brightness() {
1532
- const { r, g, b } = this;
1518
+ const { r, g, b } = this.toRgb();
1533
1519
  return (r * 299 + g * 587 + b * 114) / 1000;
1534
1520
  }
1535
1521
 
@@ -1538,12 +1524,14 @@
1538
1524
  * @returns {CP.RGBA} an {r,g,b,a} object with [0, 255] ranged values
1539
1525
  */
1540
1526
  toRgb() {
1541
- const {
1527
+ let {
1542
1528
  r, g, b, a,
1543
1529
  } = this;
1544
1530
 
1531
+ [r, g, b] = [r, g, b].map((n) => roundPart(n * 255 * 100) / 100);
1532
+ a = roundPart(a * 100) / 100;
1545
1533
  return {
1546
- r, g, b, a: roundPart(a * 100) / 100,
1534
+ r, g, b, a,
1547
1535
  };
1548
1536
  }
1549
1537
 
@@ -1637,7 +1625,7 @@
1637
1625
  toHsv() {
1638
1626
  const {
1639
1627
  r, g, b, a,
1640
- } = this.toRgb();
1628
+ } = this;
1641
1629
  const { h, s, v } = rgbToHsv(r, g, b);
1642
1630
 
1643
1631
  return {
@@ -1652,7 +1640,7 @@
1652
1640
  toHsl() {
1653
1641
  const {
1654
1642
  r, g, b, a,
1655
- } = this.toRgb();
1643
+ } = this;
1656
1644
  const { h, s, l } = rgbToHsl(r, g, b);
1657
1645
 
1658
1646
  return {
@@ -1737,6 +1725,7 @@
1737
1725
  */
1738
1726
  setAlpha(alpha) {
1739
1727
  const self = this;
1728
+ if (typeof alpha !== 'number') return self;
1740
1729
  self.a = boundAlpha(alpha);
1741
1730
  return self;
1742
1731
  }
@@ -1903,26 +1892,23 @@
1903
1892
  } else if (args.length === 2) {
1904
1893
  [hueSteps, lightSteps] = args;
1905
1894
  if ([hueSteps, lightSteps].some((n) => n < 1)) {
1906
- throw TypeError('ColorPalette: when 2 arguments used, both must be larger than 0.');
1895
+ throw TypeError('ColorPalette: both arguments must be higher than 0.');
1907
1896
  }
1908
- } else {
1909
- throw TypeError('ColorPalette requires minimum 2 arguments');
1910
1897
  }
1911
1898
 
1912
- /** @type {Color[]} */
1899
+ /** @type {*} */
1913
1900
  const colors = [];
1914
-
1915
1901
  const hueStep = 360 / hueSteps;
1916
1902
  const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
1917
- const estimatedStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
1903
+ const steps1To13 = [0.25, 0.2, 0.15, 0.11, 0.09, 0.075];
1904
+ const lightSets = [[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]];
1905
+ const closestSet = lightSets.find((set) => set.includes(lightSteps));
1918
1906
 
1919
- let lightStep = 0.25;
1920
- lightStep = [4, 5].includes(lightSteps) ? 0.2 : lightStep;
1921
- lightStep = [6, 7].includes(lightSteps) ? 0.15 : lightStep;
1922
- lightStep = [8, 9].includes(lightSteps) ? 0.11 : lightStep;
1923
- lightStep = [10, 11].includes(lightSteps) ? 0.09 : lightStep;
1924
- lightStep = [12, 13].includes(lightSteps) ? 0.075 : lightStep;
1925
- lightStep = lightSteps > 13 ? estimatedStep : lightStep;
1907
+ // find a lightStep that won't go beyond black and white
1908
+ // something within the [10-90] range of lightness
1909
+ const lightStep = closestSet
1910
+ ? steps1To13[lightSets.indexOf(closestSet)]
1911
+ : (100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100);
1926
1912
 
1927
1913
  // light tints
1928
1914
  for (let i = 1; i < half + 1; i += 1) {
@@ -2437,7 +2423,7 @@
2437
2423
  setAttribute(input, tabIndex, '-1');
2438
2424
  }
2439
2425
 
2440
- var version = "0.0.2alpha1";
2426
+ var version = "0.0.2alpha4";
2441
2427
 
2442
2428
  // @ts-ignore
2443
2429
 
@@ -2480,8 +2466,6 @@
2480
2466
  fn(input, focusinEvent, self.showPicker);
2481
2467
  fn(pickerToggle, mouseclickEvent, self.togglePicker);
2482
2468
 
2483
- fn(input, keydownEvent, self.keyToggle);
2484
-
2485
2469
  if (menuToggle) {
2486
2470
  fn(menuToggle, mouseclickEvent, self.toggleMenu);
2487
2471
  }
@@ -2519,8 +2503,7 @@
2519
2503
  fn(doc, pointerEvents.move, self.pointerMove);
2520
2504
  fn(doc, pointerEvents.up, self.pointerUp);
2521
2505
  fn(parent, focusoutEvent, self.handleFocusOut);
2522
- // @ts-ignore -- this is `Window`
2523
- fn(win, keyupEvent, self.handleDismiss);
2506
+ fn(doc, keyupEvent, self.handleDismiss);
2524
2507
  }
2525
2508
 
2526
2509
  /**
@@ -2604,7 +2587,7 @@
2604
2587
  const input = querySelector(target);
2605
2588
 
2606
2589
  // invalidate
2607
- if (!input) throw new TypeError(`ColorPicker target ${target} cannot be found.`);
2590
+ if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
2608
2591
  self.input = input;
2609
2592
 
2610
2593
  const parent = closest(input, colorPickerParentSelector);
@@ -2651,15 +2634,14 @@
2651
2634
  });
2652
2635
 
2653
2636
  // update and expose component labels
2654
- const tempLabels = ObjectAssign({}, colorPickerLabels);
2655
- const jsonLabels = componentLabels && isValidJSON(componentLabels)
2656
- ? JSON.parse(componentLabels) : componentLabels || {};
2637
+ const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
2638
+ ? JSON.parse(componentLabels) : componentLabels;
2657
2639
 
2658
2640
  /** @type {Record<string, string>} */
2659
- self.componentLabels = ObjectAssign(tempLabels, jsonLabels);
2641
+ self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
2660
2642
 
2661
2643
  /** @type {Color} */
2662
- self.color = new Color('white', format);
2644
+ self.color = new Color(input.value || '#fff', format);
2663
2645
 
2664
2646
  /** @type {CP.ColorFormats} */
2665
2647
  self.format = format;
@@ -2668,7 +2650,7 @@
2668
2650
  if (colorKeywords instanceof Array) {
2669
2651
  self.colorKeywords = colorKeywords;
2670
2652
  } else if (typeof colorKeywords === 'string' && colorKeywords.length) {
2671
- self.colorKeywords = colorKeywords.split(',');
2653
+ self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
2672
2654
  }
2673
2655
 
2674
2656
  // set colour presets
@@ -2697,7 +2679,6 @@
2697
2679
  self.handleFocusOut = self.handleFocusOut.bind(self);
2698
2680
  self.changeHandler = self.changeHandler.bind(self);
2699
2681
  self.handleDismiss = self.handleDismiss.bind(self);
2700
- self.keyToggle = self.keyToggle.bind(self);
2701
2682
  self.handleKnobs = self.handleKnobs.bind(self);
2702
2683
 
2703
2684
  // generate markup
@@ -2789,76 +2770,83 @@
2789
2770
  return inputValue !== '' && new Color(inputValue).isValid;
2790
2771
  }
2791
2772
 
2773
+ /** Returns the colour appearance, usually the closest colour name for the current value. */
2774
+ get appearance() {
2775
+ const {
2776
+ colorLabels, hsl, hsv, format,
2777
+ } = this;
2778
+
2779
+ const hue = roundPart(hsl.h * 360);
2780
+ const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
2781
+ const saturation = roundPart(saturationSource * 100);
2782
+ const lightness = roundPart(hsl.l * 100);
2783
+ const hsvl = hsv.v * 100;
2784
+
2785
+ let colorName;
2786
+
2787
+ // determine color appearance
2788
+ if (lightness === 100 && saturation === 0) {
2789
+ colorName = colorLabels.white;
2790
+ } else if (lightness === 0) {
2791
+ colorName = colorLabels.black;
2792
+ } else if (saturation === 0) {
2793
+ colorName = colorLabels.grey;
2794
+ } else if (hue < 15 || hue >= 345) {
2795
+ colorName = colorLabels.red;
2796
+ } else if (hue >= 15 && hue < 45) {
2797
+ colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
2798
+ } else if (hue >= 45 && hue < 75) {
2799
+ const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
2800
+ const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
2801
+ colorName = isGold ? colorLabels.gold : colorLabels.yellow;
2802
+ colorName = isOlive ? colorLabels.olive : colorName;
2803
+ } else if (hue >= 75 && hue < 155) {
2804
+ colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
2805
+ } else if (hue >= 155 && hue < 175) {
2806
+ colorName = colorLabels.teal;
2807
+ } else if (hue >= 175 && hue < 195) {
2808
+ colorName = colorLabels.cyan;
2809
+ } else if (hue >= 195 && hue < 255) {
2810
+ colorName = colorLabels.blue;
2811
+ } else if (hue >= 255 && hue < 270) {
2812
+ colorName = colorLabels.violet;
2813
+ } else if (hue >= 270 && hue < 295) {
2814
+ colorName = colorLabels.magenta;
2815
+ } else if (hue >= 295 && hue < 345) {
2816
+ colorName = colorLabels.pink;
2817
+ }
2818
+ return colorName;
2819
+ }
2820
+
2792
2821
  /** Updates `ColorPicker` visuals. */
2793
2822
  updateVisuals() {
2794
2823
  const self = this;
2795
2824
  const {
2796
- format, controlPositions, visuals,
2825
+ controlPositions, visuals,
2797
2826
  } = self;
2798
2827
  const [v1, v2, v3] = visuals;
2799
- const { offsetWidth, offsetHeight } = v1;
2800
- const hue = format === 'hsl'
2801
- ? controlPositions.c1x / offsetWidth
2802
- : controlPositions.c2y / offsetHeight;
2803
- // @ts-ignore - `hslToRgb` is assigned to `Color` as static method
2804
- const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
2828
+ const { offsetHeight } = v1;
2829
+ const hue = controlPositions.c2y / offsetHeight;
2830
+ const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
2805
2831
  const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
2806
2832
  const alpha = 1 - controlPositions.c3y / offsetHeight;
2807
2833
  const roundA = roundPart((alpha * 100)) / 100;
2808
2834
 
2809
- if (format !== 'hsl') {
2810
- const fill = new Color({
2811
- h: hue, s: 1, l: 0.5, a: alpha,
2812
- }).toRgbString();
2813
- const hueGradient = `linear-gradient(
2814
- rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
2815
- rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
2816
- rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
2817
- rgb(255,0,0) 100%)`;
2818
- setElementStyle(v1, {
2819
- background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
2820
- linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
2821
- ${whiteGrad}`,
2822
- });
2823
- setElementStyle(v2, { background: hueGradient });
2824
- } else {
2825
- const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
2826
- const fill0 = new Color({
2827
- r: 255, g: 0, b: 0, a: alpha,
2828
- }).saturate(-saturation).toRgbString();
2829
- const fill1 = new Color({
2830
- r: 255, g: 255, b: 0, a: alpha,
2831
- }).saturate(-saturation).toRgbString();
2832
- const fill2 = new Color({
2833
- r: 0, g: 255, b: 0, a: alpha,
2834
- }).saturate(-saturation).toRgbString();
2835
- const fill3 = new Color({
2836
- r: 0, g: 255, b: 255, a: alpha,
2837
- }).saturate(-saturation).toRgbString();
2838
- const fill4 = new Color({
2839
- r: 0, g: 0, b: 255, a: alpha,
2840
- }).saturate(-saturation).toRgbString();
2841
- const fill5 = new Color({
2842
- r: 255, g: 0, b: 255, a: alpha,
2843
- }).saturate(-saturation).toRgbString();
2844
- const fill6 = new Color({
2845
- r: 255, g: 0, b: 0, a: alpha,
2846
- }).saturate(-saturation).toRgbString();
2847
- const fillGradient = `linear-gradient(to right,
2848
- ${fill0} 0%, ${fill1} 16.67%, ${fill2} 33.33%, ${fill3} 50%,
2849
- ${fill4} 66.67%, ${fill5} 83.33%, ${fill6} 100%)`;
2850
- const lightGrad = `linear-gradient(rgba(255,255,255,${roundA}) 0%, rgba(255,255,255,0) 50%),
2851
- linear-gradient(rgba(0,0,0,0) 50%, rgba(0,0,0,${roundA}) 100%)`;
2852
-
2853
- setElementStyle(v1, { background: `${lightGrad},${fillGradient},${whiteGrad}` });
2854
- const {
2855
- r: gr, g: gg, b: gb,
2856
- } = new Color({ r, g, b }).greyscale().toRgb();
2835
+ const fill = new Color({
2836
+ h: hue, s: 1, l: 0.5, a: alpha,
2837
+ }).toRgbString();
2838
+ const hueGradient = `linear-gradient(
2839
+ rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
2840
+ rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
2841
+ rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
2842
+ rgb(255,0,0) 100%)`;
2843
+ setElementStyle(v1, {
2844
+ background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
2845
+ linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
2846
+ ${whiteGrad}`,
2847
+ });
2848
+ setElementStyle(v2, { background: hueGradient });
2857
2849
 
2858
- setElementStyle(v2, {
2859
- background: `linear-gradient(rgb(${r},${g},${b}) 0%, rgb(${gr},${gg},${gb}) 100%)`,
2860
- });
2861
- }
2862
2850
  setElementStyle(v3, {
2863
2851
  background: `linear-gradient(rgba(${r},${g},${b},1) 0%,rgba(${r},${g},${b},0) 100%)`,
2864
2852
  });
@@ -3008,13 +2996,13 @@
3008
2996
  const [v1, v2, v3] = visuals;
3009
2997
  const [c1, c2, c3] = controlKnobs;
3010
2998
  /** @type {HTMLElement} */
3011
- const visual = hasClass(target, 'visual-control')
3012
- ? target : querySelector('.visual-control', target.parentElement);
2999
+ const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
3013
3000
  const visualRect = getBoundingClientRect(visual);
3001
+ const html = getDocumentElement(v1);
3014
3002
  const X = type === 'touchstart' ? touches[0].pageX : pageX;
3015
3003
  const Y = type === 'touchstart' ? touches[0].pageY : pageY;
3016
- const offsetX = X - window.pageXOffset - visualRect.left;
3017
- const offsetY = Y - window.pageYOffset - visualRect.top;
3004
+ const offsetX = X - html.scrollLeft - visualRect.left;
3005
+ const offsetY = Y - html.scrollTop - visualRect.top;
3018
3006
 
3019
3007
  if (target === v1 || target === c1) {
3020
3008
  self.dragElement = visual;
@@ -3074,10 +3062,11 @@
3074
3062
  if (!dragElement) return;
3075
3063
 
3076
3064
  const controlRect = getBoundingClientRect(dragElement);
3077
- const X = type === 'touchmove' ? touches[0].pageX : pageX;
3078
- const Y = type === 'touchmove' ? touches[0].pageY : pageY;
3079
- const offsetX = X - window.pageXOffset - controlRect.left;
3080
- const offsetY = Y - window.pageYOffset - controlRect.top;
3065
+ const win = getDocumentElement(v1);
3066
+ const X = type === touchmoveEvent ? touches[0].pageX : pageX;
3067
+ const Y = type === touchmoveEvent ? touches[0].pageY : pageY;
3068
+ const offsetX = X - win.scrollLeft - controlRect.left;
3069
+ const offsetY = Y - win.scrollTop - controlRect.top;
3081
3070
 
3082
3071
  if (dragElement === v1) {
3083
3072
  self.changeControl1(offsetX, offsetY);
@@ -3104,19 +3093,19 @@
3104
3093
  if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
3105
3094
  e.preventDefault();
3106
3095
 
3107
- const { format, controlKnobs, visuals } = self;
3096
+ const { controlKnobs, visuals } = self;
3108
3097
  const { offsetWidth, offsetHeight } = visuals[0];
3109
3098
  const [c1, c2, c3] = controlKnobs;
3110
3099
  const { activeElement } = getDocument(c1);
3111
3100
  const currentKnob = controlKnobs.find((x) => x === activeElement);
3112
- const yRatio = offsetHeight / (format === 'hsl' ? 100 : 360);
3101
+ const yRatio = offsetHeight / 360;
3113
3102
 
3114
3103
  if (currentKnob) {
3115
3104
  let offsetX = 0;
3116
3105
  let offsetY = 0;
3117
3106
 
3118
3107
  if (target === c1) {
3119
- const xRatio = offsetWidth / (format === 'hsl' ? 360 : 100);
3108
+ const xRatio = offsetWidth / 100;
3120
3109
 
3121
3110
  if ([keyArrowLeft, keyArrowRight].includes(code)) {
3122
3111
  self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
@@ -3166,7 +3155,7 @@
3166
3155
  if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
3167
3156
  if (activeElement === input) {
3168
3157
  if (isNonColorValue) {
3169
- colorSource = 'white';
3158
+ colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
3170
3159
  } else {
3171
3160
  colorSource = currentValue;
3172
3161
  }
@@ -3217,9 +3206,7 @@
3217
3206
  changeControl1(X, Y) {
3218
3207
  const self = this;
3219
3208
  let [offsetX, offsetY] = [0, 0];
3220
- const {
3221
- format, controlPositions, visuals,
3222
- } = self;
3209
+ const { controlPositions, visuals } = self;
3223
3210
  const { offsetHeight, offsetWidth } = visuals[0];
3224
3211
 
3225
3212
  if (X > offsetWidth) offsetX = offsetWidth;
@@ -3228,29 +3215,19 @@
3228
3215
  if (Y > offsetHeight) offsetY = offsetHeight;
3229
3216
  else if (Y >= 0) offsetY = Y;
3230
3217
 
3231
- const hue = format === 'hsl'
3232
- ? offsetX / offsetWidth
3233
- : controlPositions.c2y / offsetHeight;
3218
+ const hue = controlPositions.c2y / offsetHeight;
3234
3219
 
3235
- const saturation = format === 'hsl'
3236
- ? 1 - controlPositions.c2y / offsetHeight
3237
- : offsetX / offsetWidth;
3220
+ const saturation = offsetX / offsetWidth;
3238
3221
 
3239
3222
  const lightness = 1 - offsetY / offsetHeight;
3240
3223
  const alpha = 1 - controlPositions.c3y / offsetHeight;
3241
3224
 
3242
- const colorObject = format === 'hsl'
3243
- ? {
3244
- h: hue, s: saturation, l: lightness, a: alpha,
3245
- }
3246
- : {
3247
- h: hue, s: saturation, v: lightness, a: alpha,
3248
- };
3249
-
3250
3225
  // new color
3251
3226
  const {
3252
3227
  r, g, b, a,
3253
- } = new Color(colorObject);
3228
+ } = new Color({
3229
+ h: hue, s: saturation, v: lightness, a: alpha,
3230
+ });
3254
3231
 
3255
3232
  ObjectAssign(self.color, {
3256
3233
  r, g, b, a,
@@ -3277,7 +3254,7 @@
3277
3254
  changeControl2(Y) {
3278
3255
  const self = this;
3279
3256
  const {
3280
- format, controlPositions, visuals,
3257
+ controlPositions, visuals,
3281
3258
  } = self;
3282
3259
  const { offsetHeight, offsetWidth } = visuals[0];
3283
3260
 
@@ -3286,26 +3263,17 @@
3286
3263
  if (Y > offsetHeight) offsetY = offsetHeight;
3287
3264
  else if (Y >= 0) offsetY = Y;
3288
3265
 
3289
- const hue = format === 'hsl'
3290
- ? controlPositions.c1x / offsetWidth
3291
- : offsetY / offsetHeight;
3292
- const saturation = format === 'hsl'
3293
- ? 1 - offsetY / offsetHeight
3294
- : controlPositions.c1x / offsetWidth;
3266
+ const hue = offsetY / offsetHeight;
3267
+ const saturation = controlPositions.c1x / offsetWidth;
3295
3268
  const lightness = 1 - controlPositions.c1y / offsetHeight;
3296
3269
  const alpha = 1 - controlPositions.c3y / offsetHeight;
3297
- const colorObject = format === 'hsl'
3298
- ? {
3299
- h: hue, s: saturation, l: lightness, a: alpha,
3300
- }
3301
- : {
3302
- h: hue, s: saturation, v: lightness, a: alpha,
3303
- };
3304
3270
 
3305
3271
  // new color
3306
3272
  const {
3307
3273
  r, g, b, a,
3308
- } = new Color(colorObject);
3274
+ } = new Color({
3275
+ h: hue, s: saturation, v: lightness, a: alpha,
3276
+ });
3309
3277
 
3310
3278
  ObjectAssign(self.color, {
3311
3279
  r, g, b, a,
@@ -3392,18 +3360,18 @@
3392
3360
  setControlPositions() {
3393
3361
  const self = this;
3394
3362
  const {
3395
- format, visuals, color, hsl, hsv,
3363
+ visuals, color, hsv,
3396
3364
  } = self;
3397
3365
  const { offsetHeight, offsetWidth } = visuals[0];
3398
3366
  const alpha = color.a;
3399
- const hue = hsl.h;
3367
+ const hue = hsv.h;
3400
3368
 
3401
- const saturation = format !== 'hsl' ? hsv.s : hsl.s;
3402
- const lightness = format !== 'hsl' ? hsv.v : hsl.l;
3369
+ const saturation = hsv.s;
3370
+ const lightness = hsv.v;
3403
3371
 
3404
- self.controlPositions.c1x = format !== 'hsl' ? saturation * offsetWidth : hue * offsetWidth;
3372
+ self.controlPositions.c1x = saturation * offsetWidth;
3405
3373
  self.controlPositions.c1y = (1 - lightness) * offsetHeight;
3406
- self.controlPositions.c2y = format !== 'hsl' ? hue * offsetHeight : (1 - saturation) * offsetHeight;
3374
+ self.controlPositions.c2y = hue * offsetHeight;
3407
3375
  self.controlPositions.c3y = (1 - alpha) * offsetHeight;
3408
3376
  }
3409
3377
 
@@ -3411,78 +3379,40 @@
3411
3379
  updateAppearance() {
3412
3380
  const self = this;
3413
3381
  const {
3414
- componentLabels, colorLabels, color, parent,
3415
- hsl, hsv, hex, format, controlKnobs,
3382
+ componentLabels, color, parent,
3383
+ hsv, hex, format, controlKnobs,
3416
3384
  } = self;
3417
3385
  const {
3418
3386
  appearanceLabel, hexLabel, valueLabel,
3419
3387
  } = componentLabels;
3420
- const { r, g, b } = color.toRgb();
3388
+ let { r, g, b } = color.toRgb();
3421
3389
  const [knob1, knob2, knob3] = controlKnobs;
3422
- const hue = roundPart(hsl.h * 360);
3390
+ const hue = roundPart(hsv.h * 360);
3423
3391
  const alpha = color.a;
3424
- const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
3425
- const saturation = roundPart(saturationSource * 100);
3426
- const lightness = roundPart(hsl.l * 100);
3427
- const hsvl = hsv.v * 100;
3428
- let colorName;
3429
-
3430
- // determine color appearance
3431
- if (lightness === 100 && saturation === 0) {
3432
- colorName = colorLabels.white;
3433
- } else if (lightness === 0) {
3434
- colorName = colorLabels.black;
3435
- } else if (saturation === 0) {
3436
- colorName = colorLabels.grey;
3437
- } else if (hue < 15 || hue >= 345) {
3438
- colorName = colorLabels.red;
3439
- } else if (hue >= 15 && hue < 45) {
3440
- colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
3441
- } else if (hue >= 45 && hue < 75) {
3442
- const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
3443
- const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
3444
- colorName = isGold ? colorLabels.gold : colorLabels.yellow;
3445
- colorName = isOlive ? colorLabels.olive : colorName;
3446
- } else if (hue >= 75 && hue < 155) {
3447
- colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
3448
- } else if (hue >= 155 && hue < 175) {
3449
- colorName = colorLabels.teal;
3450
- } else if (hue >= 175 && hue < 195) {
3451
- colorName = colorLabels.cyan;
3452
- } else if (hue >= 195 && hue < 255) {
3453
- colorName = colorLabels.blue;
3454
- } else if (hue >= 255 && hue < 270) {
3455
- colorName = colorLabels.violet;
3456
- } else if (hue >= 270 && hue < 295) {
3457
- colorName = colorLabels.magenta;
3458
- } else if (hue >= 295 && hue < 345) {
3459
- colorName = colorLabels.pink;
3460
- }
3392
+ const saturation = roundPart(hsv.s * 100);
3393
+ const lightness = roundPart(hsv.v * 100);
3394
+ const colorName = self.appearance;
3461
3395
 
3462
3396
  let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
3463
3397
 
3464
- if (format === 'hsl') {
3465
- colorLabel = `HSL: ${hue}°, ${saturation}%, ${lightness}%`;
3466
- setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3467
- setAttribute(knob1, ariaValueText, `${hue}° & ${lightness}%`);
3468
- setAttribute(knob1, ariaValueNow, `${hue}`);
3469
- setAttribute(knob2, ariaValueText, `${saturation}%`);
3470
- setAttribute(knob2, ariaValueNow, `${saturation}`);
3471
- } else if (format === 'hwb') {
3398
+ if (format === 'hwb') {
3472
3399
  const { hwb } = self;
3473
3400
  const whiteness = roundPart(hwb.w * 100);
3474
3401
  const blackness = roundPart(hwb.b * 100);
3475
3402
  colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
3476
- setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3477
3403
  setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
3478
3404
  setAttribute(knob1, ariaValueNow, `${whiteness}`);
3405
+ setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3479
3406
  setAttribute(knob2, ariaValueText, `${hue}%`);
3480
3407
  setAttribute(knob2, ariaValueNow, `${hue}`);
3481
3408
  } else {
3409
+ [r, g, b] = [r, g, b].map(roundPart);
3410
+ colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
3482
3411
  colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
3483
- setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3412
+
3484
3413
  setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
3485
3414
  setAttribute(knob1, ariaValueNow, `${lightness}`);
3415
+ setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3486
3416
  setAttribute(knob2, ariaValueText, `${hue}°`);
3487
3417
  setAttribute(knob2, ariaValueNow, `${hue}`);
3488
3418
  }
@@ -3577,37 +3507,13 @@
3577
3507
  }
3578
3508
  }
3579
3509
 
3580
- /**
3581
- * The `Space` & `Enter` keys specific event listener.
3582
- * Toggle visibility of the `ColorPicker` / the presets menu, showing one will hide the other.
3583
- * @param {KeyboardEvent} e
3584
- * @this {ColorPicker}
3585
- */
3586
- keyToggle(e) {
3587
- const self = this;
3588
- const { menuToggle } = self;
3589
- const { activeElement } = getDocument(menuToggle);
3590
- const { code } = e;
3591
-
3592
- if ([keyEnter, keySpace].includes(code)) {
3593
- if ((menuToggle && activeElement === menuToggle) || !activeElement) {
3594
- e.preventDefault();
3595
- if (!activeElement) {
3596
- self.togglePicker(e);
3597
- } else {
3598
- self.toggleMenu();
3599
- }
3600
- }
3601
- }
3602
- }
3603
-
3604
3510
  /**
3605
3511
  * Toggle the `ColorPicker` dropdown visibility.
3606
- * @param {Event} e
3512
+ * @param {Event=} e
3607
3513
  * @this {ColorPicker}
3608
3514
  */
3609
3515
  togglePicker(e) {
3610
- e.preventDefault();
3516
+ if (e) e.preventDefault();
3611
3517
  const self = this;
3612
3518
  const { colorPicker } = self;
3613
3519
 
@@ -3628,8 +3534,13 @@
3628
3534
  }
3629
3535
  }
3630
3536
 
3631
- /** Toggles the visibility of the `ColorPicker` presets menu. */
3632
- toggleMenu() {
3537
+ /**
3538
+ * Toggles the visibility of the `ColorPicker` presets menu.
3539
+ * @param {Event=} e
3540
+ * @this {ColorPicker}
3541
+ */
3542
+ toggleMenu(e) {
3543
+ if (e) e.preventDefault();
3633
3544
  const self = this;
3634
3545
  const { colorMenu } = self;
3635
3546
 
@@ -3655,6 +3566,10 @@
3655
3566
  const relatedBtn = openPicker ? pickerToggle : menuToggle;
3656
3567
  const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
3657
3568
 
3569
+ // if (!self.isValid) {
3570
+ self.value = self.color.toString(true);
3571
+ // }
3572
+
3658
3573
  if (openDropdown) {
3659
3574
  removeClass(openDropdown, 'show');
3660
3575
  setAttribute(relatedBtn, ariaExpanded, 'false');
@@ -3668,9 +3583,6 @@
3668
3583
  }, animationDuration);
3669
3584
  }
3670
3585
 
3671
- if (!self.isValid) {
3672
- self.value = self.color.toString();
3673
- }
3674
3586
  if (!focusPrevented) {
3675
3587
  focus(pickerToggle);
3676
3588
  }