@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
  */
@@ -837,6 +837,8 @@ function isColorName(color) {
837
837
  if (nonColors.includes(color)
838
838
  || ['#', ...COLOR_FORMAT].some((f) => color.includes(f))) return false;
839
839
 
840
+ if (['black', 'white'].includes(color)) return true;
841
+
840
842
  return ['rgb(255, 255, 255)', 'rgb(0, 0, 0)'].every((c) => {
841
843
  setElementStyle(documentHead, { color });
842
844
  const computedColor = getElementStyle(documentHead, 'color');
@@ -863,6 +865,11 @@ function isValidCSSUnit(color) {
863
865
  */
864
866
  function bound01(N, max) {
865
867
  let n = N;
868
+
869
+ if (typeof N === 'number'
870
+ && Math.min(N, 0) === 0 // round values to 6 decimals Math.round(N * (10 ** 6)) / 10 ** 6
871
+ && Math.max(N, 1) === 1) return N;
872
+
866
873
  if (isOnePointZero(N)) n = '100%';
867
874
 
868
875
  const processPercent = isPercentage(n);
@@ -966,15 +973,12 @@ function pad2(c) {
966
973
  /**
967
974
  * Converts an RGB colour value to HSL.
968
975
  *
969
- * @param {number} R Red component [0, 255]
970
- * @param {number} G Green component [0, 255]
971
- * @param {number} B Blue component [0, 255]
976
+ * @param {number} r Red component [0, 1]
977
+ * @param {number} g Green component [0, 1]
978
+ * @param {number} b Blue component [0, 1]
972
979
  * @returns {CP.HSL} {h,s,l} object with [0, 1] ranged values
973
980
  */
974
- function rgbToHsl(R, G, B) {
975
- const r = R / 255;
976
- const g = G / 255;
977
- const b = B / 255;
981
+ function rgbToHsl(r, g, b) {
978
982
  const max = Math.max(r, g, b);
979
983
  const min = Math.min(r, g, b);
980
984
  let h = 0;
@@ -986,17 +990,10 @@ function rgbToHsl(R, G, B) {
986
990
  } else {
987
991
  const d = max - min;
988
992
  s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
989
- switch (max) {
990
- case r:
991
- h = (g - b) / d + (g < b ? 6 : 0);
992
- break;
993
- case g:
994
- h = (b - r) / d + 2;
995
- break;
996
- case b:
997
- h = (r - g) / d + 4;
998
- break;
999
- }
993
+ if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
994
+ if (max === g) h = (b - r) / d + 2;
995
+ if (max === b) h = (r - g) / d + 4;
996
+
1000
997
  h /= 6;
1001
998
  }
1002
999
  return { h, s, l };
@@ -1025,7 +1022,7 @@ function hueToRgb(p, q, t) {
1025
1022
  * @param {number} h Hue Angle [0, 1]
1026
1023
  * @param {number} s Saturation [0, 1]
1027
1024
  * @param {number} l Lightness Angle [0, 1]
1028
- * @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
1025
+ * @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
1029
1026
  */
1030
1027
  function hslToRgb(h, s, l) {
1031
1028
  let r = 0;
@@ -1044,7 +1041,6 @@ function hslToRgb(h, s, l) {
1044
1041
  g = hueToRgb(p, q, h);
1045
1042
  b = hueToRgb(p, q, h - 1 / 3);
1046
1043
  }
1047
- [r, g, b] = [r, g, b].map((x) => x * 255);
1048
1044
 
1049
1045
  return { r, g, b };
1050
1046
  }
@@ -1054,16 +1050,12 @@ function hslToRgb(h, s, l) {
1054
1050
  * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
1055
1051
  * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
1056
1052
  *
1057
- * @param {number} R Red component [0, 255]
1058
- * @param {number} G Green [0, 255]
1059
- * @param {number} B Blue [0, 255]
1053
+ * @param {number} r Red component [0, 1]
1054
+ * @param {number} g Green [0, 1]
1055
+ * @param {number} b Blue [0, 1]
1060
1056
  * @return {CP.HWB} {h,w,b} object with [0, 1] ranged values
1061
1057
  */
1062
- function rgbToHwb(R, G, B) {
1063
- const r = R / 255;
1064
- const g = G / 255;
1065
- const b = B / 255;
1066
-
1058
+ function rgbToHwb(r, g, b) {
1067
1059
  let f = 0;
1068
1060
  let i = 0;
1069
1061
  const whiteness = Math.min(r, g, b);
@@ -1093,20 +1085,18 @@ function rgbToHwb(R, G, B) {
1093
1085
  * @param {number} H Hue Angle [0, 1]
1094
1086
  * @param {number} W Whiteness [0, 1]
1095
1087
  * @param {number} B Blackness [0, 1]
1096
- * @return {CP.RGB} {r,g,b} object with [0, 255] ranged values
1088
+ * @return {CP.RGB} {r,g,b} object with [0, 1] ranged values
1097
1089
  *
1098
1090
  * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
1099
1091
  * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
1100
1092
  */
1101
1093
  function hwbToRgb(H, W, B) {
1102
1094
  if (W + B >= 1) {
1103
- const gray = (W / (W + B)) * 255;
1095
+ const gray = W / (W + B);
1104
1096
  return { r: gray, g: gray, b: gray };
1105
1097
  }
1106
1098
  let { r, g, b } = hslToRgb(H, 1, 0.5);
1107
- [r, g, b] = [r, g, b]
1108
- .map((v) => (v / 255) * (1 - W - B) + W)
1109
- .map((v) => v * 255);
1099
+ [r, g, b] = [r, g, b].map((v) => v * (1 - W - B) + W);
1110
1100
 
1111
1101
  return { r, g, b };
1112
1102
  }
@@ -1114,15 +1104,12 @@ function hwbToRgb(H, W, B) {
1114
1104
  /**
1115
1105
  * Converts an RGB colour value to HSV.
1116
1106
  *
1117
- * @param {number} R Red component [0, 255]
1118
- * @param {number} G Green [0, 255]
1119
- * @param {number} B Blue [0, 255]
1107
+ * @param {number} r Red component [0, 1]
1108
+ * @param {number} g Green [0, 1]
1109
+ * @param {number} b Blue [0, 1]
1120
1110
  * @returns {CP.HSV} {h,s,v} object with [0, 1] ranged values
1121
1111
  */
1122
- function rgbToHsv(R, G, B) {
1123
- const r = R / 255;
1124
- const g = G / 255;
1125
- const b = B / 255;
1112
+ function rgbToHsv(r, g, b) {
1126
1113
  const max = Math.max(r, g, b);
1127
1114
  const min = Math.min(r, g, b);
1128
1115
  let h = 0;
@@ -1132,17 +1119,10 @@ function rgbToHsv(R, G, B) {
1132
1119
  if (max === min) {
1133
1120
  h = 0; // achromatic
1134
1121
  } else {
1135
- switch (max) {
1136
- case r:
1137
- h = (g - b) / d + (g < b ? 6 : 0);
1138
- break;
1139
- case g:
1140
- h = (b - r) / d + 2;
1141
- break;
1142
- case b:
1143
- h = (r - g) / d + 4;
1144
- break;
1145
- }
1122
+ if (r === max) h = (g - b) / d + (g < b ? 6 : 0);
1123
+ if (g === max) h = (b - r) / d + 2;
1124
+ if (b === max) h = (r - g) / d + 4;
1125
+
1146
1126
  h /= 6;
1147
1127
  }
1148
1128
  return { h, s, v };
@@ -1166,10 +1146,9 @@ function hsvToRgb(H, S, V) {
1166
1146
  const q = v * (1 - f * s);
1167
1147
  const t = v * (1 - (1 - f) * s);
1168
1148
  const mod = i % 6;
1169
- let r = [v, q, p, p, t, v][mod];
1170
- let g = [t, v, v, q, p, p][mod];
1171
- let b = [p, p, t, v, v, q][mod];
1172
- [r, g, b] = [r, g, b].map((n) => n * 255);
1149
+ const r = [v, q, p, p, t, v][mod];
1150
+ const g = [t, v, v, q, p, p][mod];
1151
+ const b = [p, p, t, v, v, q][mod];
1173
1152
  return { r, g, b };
1174
1153
  }
1175
1154
 
@@ -1237,15 +1216,15 @@ function rgbaToHex(r, g, b, a, allow4Char) {
1237
1216
  */
1238
1217
  function stringInputToObject(input) {
1239
1218
  let color = toLowerCase(input.trim());
1219
+
1240
1220
  if (color.length === 0) {
1241
1221
  return {
1242
1222
  r: 0, g: 0, b: 0, a: 1,
1243
1223
  };
1244
1224
  }
1245
- let named = false;
1225
+
1246
1226
  if (isColorName(color)) {
1247
1227
  color = getRGBFromName(color);
1248
- named = true;
1249
1228
  } else if (nonColors.includes(color)) {
1250
1229
  const a = color === 'transparent' ? 0 : 1;
1251
1230
  return {
@@ -1264,24 +1243,28 @@ function stringInputToObject(input) {
1264
1243
  r: m1, g: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'rgb',
1265
1244
  };
1266
1245
  }
1246
+
1267
1247
  [, m1, m2, m3, m4] = matchers.hsl.exec(color) || [];
1268
1248
  if (m1 && m2 && m3/* && m4 */) {
1269
1249
  return {
1270
1250
  h: m1, s: m2, l: m3, a: m4 !== undefined ? m4 : 1, format: 'hsl',
1271
1251
  };
1272
1252
  }
1253
+
1273
1254
  [, m1, m2, m3, m4] = matchers.hsv.exec(color) || [];
1274
1255
  if (m1 && m2 && m3/* && m4 */) {
1275
1256
  return {
1276
1257
  h: m1, s: m2, v: m3, a: m4 !== undefined ? m4 : 1, format: 'hsv',
1277
1258
  };
1278
1259
  }
1260
+
1279
1261
  [, m1, m2, m3, m4] = matchers.hwb.exec(color) || [];
1280
1262
  if (m1 && m2 && m3) {
1281
1263
  return {
1282
1264
  h: m1, w: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'hwb',
1283
1265
  };
1284
1266
  }
1267
+
1285
1268
  [, m1, m2, m3, m4] = matchers.hex8.exec(color) || [];
1286
1269
  if (m1 && m2 && m3 && m4) {
1287
1270
  return {
@@ -1289,18 +1272,20 @@ function stringInputToObject(input) {
1289
1272
  g: parseIntFromHex(m2),
1290
1273
  b: parseIntFromHex(m3),
1291
1274
  a: convertHexToDecimal(m4),
1292
- format: named ? 'rgb' : 'hex',
1275
+ format: 'hex',
1293
1276
  };
1294
1277
  }
1278
+
1295
1279
  [, m1, m2, m3] = matchers.hex6.exec(color) || [];
1296
1280
  if (m1 && m2 && m3) {
1297
1281
  return {
1298
1282
  r: parseIntFromHex(m1),
1299
1283
  g: parseIntFromHex(m2),
1300
1284
  b: parseIntFromHex(m3),
1301
- format: named ? 'rgb' : 'hex',
1285
+ format: 'hex',
1302
1286
  };
1303
1287
  }
1288
+
1304
1289
  [, m1, m2, m3, m4] = matchers.hex4.exec(color) || [];
1305
1290
  if (m1 && m2 && m3 && m4) {
1306
1291
  return {
@@ -1308,19 +1293,20 @@ function stringInputToObject(input) {
1308
1293
  g: parseIntFromHex(m2 + m2),
1309
1294
  b: parseIntFromHex(m3 + m3),
1310
1295
  a: convertHexToDecimal(m4 + m4),
1311
- // format: named ? 'rgb' : 'hex8',
1312
- format: named ? 'rgb' : 'hex',
1296
+ format: 'hex',
1313
1297
  };
1314
1298
  }
1299
+
1315
1300
  [, m1, m2, m3] = matchers.hex3.exec(color) || [];
1316
1301
  if (m1 && m2 && m3) {
1317
1302
  return {
1318
1303
  r: parseIntFromHex(m1 + m1),
1319
1304
  g: parseIntFromHex(m2 + m2),
1320
1305
  b: parseIntFromHex(m3 + m3),
1321
- format: named ? 'rgb' : 'hex',
1306
+ format: 'hex',
1322
1307
  };
1323
1308
  }
1309
+
1324
1310
  return false;
1325
1311
  }
1326
1312
 
@@ -1351,6 +1337,7 @@ function stringInputToObject(input) {
1351
1337
  */
1352
1338
  function inputToRGB(input) {
1353
1339
  let rgb = { r: 0, g: 0, b: 0 };
1340
+ /** @type {*} */
1354
1341
  let color = input;
1355
1342
  /** @type {string | number} */
1356
1343
  let a = 1;
@@ -1367,39 +1354,41 @@ function inputToRGB(input) {
1367
1354
  let format = inputFormat && COLOR_FORMAT.includes(inputFormat) ? inputFormat : 'rgb';
1368
1355
 
1369
1356
  if (typeof input === 'string') {
1370
- // @ts-ignore -- this now is converted to object
1371
1357
  color = stringInputToObject(input);
1372
1358
  if (color) ok = true;
1373
1359
  }
1374
1360
  if (typeof color === 'object') {
1375
1361
  if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
1376
1362
  ({ r, g, b } = color);
1377
- // RGB values now are all in [0, 255] range
1378
- [r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255) * 255);
1363
+ // RGB values now are all in [0, 1] range
1364
+ [r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255));
1379
1365
  rgb = { r, g, b };
1380
1366
  ok = true;
1381
- format = 'rgb';
1382
- } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
1367
+ format = color.format || 'rgb';
1368
+ }
1369
+ if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
1383
1370
  ({ h, s, v } = color);
1384
- h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1385
- s = typeof s === 'number' ? s : bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1386
- v = typeof v === 'number' ? v : bound01(v, 100); // brightness can be `5%` or a [0, 1] value
1371
+ h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1372
+ s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1373
+ v = bound01(v, 100); // brightness can be `5%` or a [0, 1] value
1387
1374
  rgb = hsvToRgb(h, s, v);
1388
1375
  ok = true;
1389
1376
  format = 'hsv';
1390
- } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
1377
+ }
1378
+ if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
1391
1379
  ({ h, s, l } = color);
1392
- h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1393
- s = typeof s === 'number' ? s : bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1394
- l = typeof l === 'number' ? l : bound01(l, 100); // lightness can be `5%` or a [0, 1] value
1380
+ h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1381
+ s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1382
+ l = bound01(l, 100); // lightness can be `5%` or a [0, 1] value
1395
1383
  rgb = hslToRgb(h, s, l);
1396
1384
  ok = true;
1397
1385
  format = 'hsl';
1398
- } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
1386
+ }
1387
+ if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
1399
1388
  ({ h, w, b } = color);
1400
- h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1401
- w = typeof w === 'number' ? w : bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
1402
- b = typeof b === 'number' ? b : bound01(b, 100); // blackness can be `5%` or a [0, 1] value
1389
+ h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1390
+ w = bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
1391
+ b = bound01(b, 100); // blackness can be `5%` or a [0, 1] value
1403
1392
  rgb = hwbToRgb(h, w, b);
1404
1393
  ok = true;
1405
1394
  format = 'hwb';
@@ -1416,9 +1405,12 @@ function inputToRGB(input) {
1416
1405
  return {
1417
1406
  ok,
1418
1407
  format,
1419
- r: Math.min(255, Math.max(rgb.r, 0)),
1420
- g: Math.min(255, Math.max(rgb.g, 0)),
1421
- b: Math.min(255, Math.max(rgb.b, 0)),
1408
+ // r: Math.min(255, Math.max(rgb.r, 0)),
1409
+ // g: Math.min(255, Math.max(rgb.g, 0)),
1410
+ // b: Math.min(255, Math.max(rgb.b, 0)),
1411
+ r: rgb.r,
1412
+ g: rgb.g,
1413
+ b: rgb.b,
1422
1414
  a: boundAlpha(a),
1423
1415
  };
1424
1416
  }
@@ -1437,16 +1429,13 @@ class Color {
1437
1429
  constructor(input, config) {
1438
1430
  let color = input;
1439
1431
  const configFormat = config && COLOR_FORMAT.includes(config)
1440
- ? config : 'rgb';
1432
+ ? config : '';
1441
1433
 
1442
- // If input is already a `Color`, return itself
1434
+ // If input is already a `Color`, clone its values
1443
1435
  if (color instanceof Color) {
1444
1436
  color = inputToRGB(color);
1445
1437
  }
1446
- if (typeof color === 'number') {
1447
- const len = `${color}`.length;
1448
- color = `#${(len === 2 ? '0' : '00')}${color}`;
1449
- }
1438
+
1450
1439
  const {
1451
1440
  r, g, b, a, ok, format,
1452
1441
  } = inputToRGB(color);
@@ -1496,24 +1485,21 @@ class Color {
1496
1485
  let R = 0;
1497
1486
  let G = 0;
1498
1487
  let B = 0;
1499
- const rp = r / 255;
1500
- const rg = g / 255;
1501
- const rb = b / 255;
1502
1488
 
1503
- if (rp <= 0.03928) {
1504
- R = rp / 12.92;
1489
+ if (r <= 0.03928) {
1490
+ R = r / 12.92;
1505
1491
  } else {
1506
- R = ((rp + 0.055) / 1.055) ** 2.4;
1492
+ R = ((r + 0.055) / 1.055) ** 2.4;
1507
1493
  }
1508
- if (rg <= 0.03928) {
1509
- G = rg / 12.92;
1494
+ if (g <= 0.03928) {
1495
+ G = g / 12.92;
1510
1496
  } else {
1511
- G = ((rg + 0.055) / 1.055) ** 2.4;
1497
+ G = ((g + 0.055) / 1.055) ** 2.4;
1512
1498
  }
1513
- if (rb <= 0.03928) {
1514
- B = rb / 12.92;
1499
+ if (b <= 0.03928) {
1500
+ B = b / 12.92;
1515
1501
  } else {
1516
- B = ((rb + 0.055) / 1.055) ** 2.4;
1502
+ B = ((b + 0.055) / 1.055) ** 2.4;
1517
1503
  }
1518
1504
  return 0.2126 * R + 0.7152 * G + 0.0722 * B;
1519
1505
  }
@@ -1523,7 +1509,7 @@ class Color {
1523
1509
  * @returns {number} a number in the [0, 255] range
1524
1510
  */
1525
1511
  get brightness() {
1526
- const { r, g, b } = this;
1512
+ const { r, g, b } = this.toRgb();
1527
1513
  return (r * 299 + g * 587 + b * 114) / 1000;
1528
1514
  }
1529
1515
 
@@ -1532,12 +1518,14 @@ class Color {
1532
1518
  * @returns {CP.RGBA} an {r,g,b,a} object with [0, 255] ranged values
1533
1519
  */
1534
1520
  toRgb() {
1535
- const {
1521
+ let {
1536
1522
  r, g, b, a,
1537
1523
  } = this;
1538
1524
 
1525
+ [r, g, b] = [r, g, b].map((n) => roundPart(n * 255 * 100) / 100);
1526
+ a = roundPart(a * 100) / 100;
1539
1527
  return {
1540
- r, g, b, a: roundPart(a * 100) / 100,
1528
+ r, g, b, a,
1541
1529
  };
1542
1530
  }
1543
1531
 
@@ -1631,7 +1619,7 @@ class Color {
1631
1619
  toHsv() {
1632
1620
  const {
1633
1621
  r, g, b, a,
1634
- } = this.toRgb();
1622
+ } = this;
1635
1623
  const { h, s, v } = rgbToHsv(r, g, b);
1636
1624
 
1637
1625
  return {
@@ -1646,7 +1634,7 @@ class Color {
1646
1634
  toHsl() {
1647
1635
  const {
1648
1636
  r, g, b, a,
1649
- } = this.toRgb();
1637
+ } = this;
1650
1638
  const { h, s, l } = rgbToHsl(r, g, b);
1651
1639
 
1652
1640
  return {
@@ -1731,6 +1719,7 @@ class Color {
1731
1719
  */
1732
1720
  setAlpha(alpha) {
1733
1721
  const self = this;
1722
+ if (typeof alpha !== 'number') return self;
1734
1723
  self.a = boundAlpha(alpha);
1735
1724
  return self;
1736
1725
  }
@@ -1897,26 +1886,23 @@ class ColorPalette {
1897
1886
  } else if (args.length === 2) {
1898
1887
  [hueSteps, lightSteps] = args;
1899
1888
  if ([hueSteps, lightSteps].some((n) => n < 1)) {
1900
- throw TypeError('ColorPalette: when 2 arguments used, both must be larger than 0.');
1889
+ throw TypeError('ColorPalette: both arguments must be higher than 0.');
1901
1890
  }
1902
- } else {
1903
- throw TypeError('ColorPalette requires minimum 2 arguments');
1904
1891
  }
1905
1892
 
1906
- /** @type {Color[]} */
1893
+ /** @type {*} */
1907
1894
  const colors = [];
1908
-
1909
1895
  const hueStep = 360 / hueSteps;
1910
1896
  const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
1911
- const estimatedStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
1897
+ const steps1To13 = [0.25, 0.2, 0.15, 0.11, 0.09, 0.075];
1898
+ const lightSets = [[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]];
1899
+ const closestSet = lightSets.find((set) => set.includes(lightSteps));
1912
1900
 
1913
- let lightStep = 0.25;
1914
- lightStep = [4, 5].includes(lightSteps) ? 0.2 : lightStep;
1915
- lightStep = [6, 7].includes(lightSteps) ? 0.15 : lightStep;
1916
- lightStep = [8, 9].includes(lightSteps) ? 0.11 : lightStep;
1917
- lightStep = [10, 11].includes(lightSteps) ? 0.09 : lightStep;
1918
- lightStep = [12, 13].includes(lightSteps) ? 0.075 : lightStep;
1919
- lightStep = lightSteps > 13 ? estimatedStep : lightStep;
1901
+ // find a lightStep that won't go beyond black and white
1902
+ // something within the [10-90] range of lightness
1903
+ const lightStep = closestSet
1904
+ ? steps1To13[lightSets.indexOf(closestSet)]
1905
+ : (100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100);
1920
1906
 
1921
1907
  // light tints
1922
1908
  for (let i = 1; i < half + 1; i += 1) {
@@ -2431,7 +2417,7 @@ function setMarkup(self) {
2431
2417
  setAttribute(input, tabIndex, '-1');
2432
2418
  }
2433
2419
 
2434
- var version = "0.0.2alpha1";
2420
+ var version = "0.0.2alpha4";
2435
2421
 
2436
2422
  // @ts-ignore
2437
2423
 
@@ -2474,8 +2460,6 @@ function toggleEvents(self, action) {
2474
2460
  fn(input, focusinEvent, self.showPicker);
2475
2461
  fn(pickerToggle, mouseclickEvent, self.togglePicker);
2476
2462
 
2477
- fn(input, keydownEvent, self.keyToggle);
2478
-
2479
2463
  if (menuToggle) {
2480
2464
  fn(menuToggle, mouseclickEvent, self.toggleMenu);
2481
2465
  }
@@ -2513,8 +2497,7 @@ function toggleEventsOnShown(self, action) {
2513
2497
  fn(doc, pointerEvents.move, self.pointerMove);
2514
2498
  fn(doc, pointerEvents.up, self.pointerUp);
2515
2499
  fn(parent, focusoutEvent, self.handleFocusOut);
2516
- // @ts-ignore -- this is `Window`
2517
- fn(win, keyupEvent, self.handleDismiss);
2500
+ fn(doc, keyupEvent, self.handleDismiss);
2518
2501
  }
2519
2502
 
2520
2503
  /**
@@ -2598,7 +2581,7 @@ class ColorPicker {
2598
2581
  const input = querySelector(target);
2599
2582
 
2600
2583
  // invalidate
2601
- if (!input) throw new TypeError(`ColorPicker target ${target} cannot be found.`);
2584
+ if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
2602
2585
  self.input = input;
2603
2586
 
2604
2587
  const parent = closest(input, colorPickerParentSelector);
@@ -2645,15 +2628,14 @@ class ColorPicker {
2645
2628
  });
2646
2629
 
2647
2630
  // update and expose component labels
2648
- const tempLabels = ObjectAssign({}, colorPickerLabels);
2649
- const jsonLabels = componentLabels && isValidJSON(componentLabels)
2650
- ? JSON.parse(componentLabels) : componentLabels || {};
2631
+ const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
2632
+ ? JSON.parse(componentLabels) : componentLabels;
2651
2633
 
2652
2634
  /** @type {Record<string, string>} */
2653
- self.componentLabels = ObjectAssign(tempLabels, jsonLabels);
2635
+ self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
2654
2636
 
2655
2637
  /** @type {Color} */
2656
- self.color = new Color('white', format);
2638
+ self.color = new Color(input.value || '#fff', format);
2657
2639
 
2658
2640
  /** @type {CP.ColorFormats} */
2659
2641
  self.format = format;
@@ -2662,7 +2644,7 @@ class ColorPicker {
2662
2644
  if (colorKeywords instanceof Array) {
2663
2645
  self.colorKeywords = colorKeywords;
2664
2646
  } else if (typeof colorKeywords === 'string' && colorKeywords.length) {
2665
- self.colorKeywords = colorKeywords.split(',');
2647
+ self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
2666
2648
  }
2667
2649
 
2668
2650
  // set colour presets
@@ -2691,7 +2673,6 @@ class ColorPicker {
2691
2673
  self.handleFocusOut = self.handleFocusOut.bind(self);
2692
2674
  self.changeHandler = self.changeHandler.bind(self);
2693
2675
  self.handleDismiss = self.handleDismiss.bind(self);
2694
- self.keyToggle = self.keyToggle.bind(self);
2695
2676
  self.handleKnobs = self.handleKnobs.bind(self);
2696
2677
 
2697
2678
  // generate markup
@@ -2783,76 +2764,83 @@ class ColorPicker {
2783
2764
  return inputValue !== '' && new Color(inputValue).isValid;
2784
2765
  }
2785
2766
 
2767
+ /** Returns the colour appearance, usually the closest colour name for the current value. */
2768
+ get appearance() {
2769
+ const {
2770
+ colorLabels, hsl, hsv, format,
2771
+ } = this;
2772
+
2773
+ const hue = roundPart(hsl.h * 360);
2774
+ const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
2775
+ const saturation = roundPart(saturationSource * 100);
2776
+ const lightness = roundPart(hsl.l * 100);
2777
+ const hsvl = hsv.v * 100;
2778
+
2779
+ let colorName;
2780
+
2781
+ // determine color appearance
2782
+ if (lightness === 100 && saturation === 0) {
2783
+ colorName = colorLabels.white;
2784
+ } else if (lightness === 0) {
2785
+ colorName = colorLabels.black;
2786
+ } else if (saturation === 0) {
2787
+ colorName = colorLabels.grey;
2788
+ } else if (hue < 15 || hue >= 345) {
2789
+ colorName = colorLabels.red;
2790
+ } else if (hue >= 15 && hue < 45) {
2791
+ colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
2792
+ } else if (hue >= 45 && hue < 75) {
2793
+ const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
2794
+ const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
2795
+ colorName = isGold ? colorLabels.gold : colorLabels.yellow;
2796
+ colorName = isOlive ? colorLabels.olive : colorName;
2797
+ } else if (hue >= 75 && hue < 155) {
2798
+ colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
2799
+ } else if (hue >= 155 && hue < 175) {
2800
+ colorName = colorLabels.teal;
2801
+ } else if (hue >= 175 && hue < 195) {
2802
+ colorName = colorLabels.cyan;
2803
+ } else if (hue >= 195 && hue < 255) {
2804
+ colorName = colorLabels.blue;
2805
+ } else if (hue >= 255 && hue < 270) {
2806
+ colorName = colorLabels.violet;
2807
+ } else if (hue >= 270 && hue < 295) {
2808
+ colorName = colorLabels.magenta;
2809
+ } else if (hue >= 295 && hue < 345) {
2810
+ colorName = colorLabels.pink;
2811
+ }
2812
+ return colorName;
2813
+ }
2814
+
2786
2815
  /** Updates `ColorPicker` visuals. */
2787
2816
  updateVisuals() {
2788
2817
  const self = this;
2789
2818
  const {
2790
- format, controlPositions, visuals,
2819
+ controlPositions, visuals,
2791
2820
  } = self;
2792
2821
  const [v1, v2, v3] = visuals;
2793
- const { offsetWidth, offsetHeight } = v1;
2794
- const hue = format === 'hsl'
2795
- ? controlPositions.c1x / offsetWidth
2796
- : controlPositions.c2y / offsetHeight;
2797
- // @ts-ignore - `hslToRgb` is assigned to `Color` as static method
2798
- const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
2822
+ const { offsetHeight } = v1;
2823
+ const hue = controlPositions.c2y / offsetHeight;
2824
+ const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
2799
2825
  const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
2800
2826
  const alpha = 1 - controlPositions.c3y / offsetHeight;
2801
2827
  const roundA = roundPart((alpha * 100)) / 100;
2802
2828
 
2803
- if (format !== 'hsl') {
2804
- const fill = new Color({
2805
- h: hue, s: 1, l: 0.5, a: alpha,
2806
- }).toRgbString();
2807
- const hueGradient = `linear-gradient(
2808
- rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
2809
- rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
2810
- rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
2811
- rgb(255,0,0) 100%)`;
2812
- setElementStyle(v1, {
2813
- background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
2814
- linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
2815
- ${whiteGrad}`,
2816
- });
2817
- setElementStyle(v2, { background: hueGradient });
2818
- } else {
2819
- const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
2820
- const fill0 = new Color({
2821
- r: 255, g: 0, b: 0, a: alpha,
2822
- }).saturate(-saturation).toRgbString();
2823
- const fill1 = new Color({
2824
- r: 255, g: 255, b: 0, a: alpha,
2825
- }).saturate(-saturation).toRgbString();
2826
- const fill2 = new Color({
2827
- r: 0, g: 255, b: 0, a: alpha,
2828
- }).saturate(-saturation).toRgbString();
2829
- const fill3 = new Color({
2830
- r: 0, g: 255, b: 255, a: alpha,
2831
- }).saturate(-saturation).toRgbString();
2832
- const fill4 = new Color({
2833
- r: 0, g: 0, b: 255, a: alpha,
2834
- }).saturate(-saturation).toRgbString();
2835
- const fill5 = new Color({
2836
- r: 255, g: 0, b: 255, a: alpha,
2837
- }).saturate(-saturation).toRgbString();
2838
- const fill6 = new Color({
2839
- r: 255, g: 0, b: 0, a: alpha,
2840
- }).saturate(-saturation).toRgbString();
2841
- const fillGradient = `linear-gradient(to right,
2842
- ${fill0} 0%, ${fill1} 16.67%, ${fill2} 33.33%, ${fill3} 50%,
2843
- ${fill4} 66.67%, ${fill5} 83.33%, ${fill6} 100%)`;
2844
- const lightGrad = `linear-gradient(rgba(255,255,255,${roundA}) 0%, rgba(255,255,255,0) 50%),
2845
- linear-gradient(rgba(0,0,0,0) 50%, rgba(0,0,0,${roundA}) 100%)`;
2846
-
2847
- setElementStyle(v1, { background: `${lightGrad},${fillGradient},${whiteGrad}` });
2848
- const {
2849
- r: gr, g: gg, b: gb,
2850
- } = new Color({ r, g, b }).greyscale().toRgb();
2829
+ const fill = new Color({
2830
+ h: hue, s: 1, l: 0.5, a: alpha,
2831
+ }).toRgbString();
2832
+ const hueGradient = `linear-gradient(
2833
+ rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
2834
+ rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
2835
+ rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
2836
+ rgb(255,0,0) 100%)`;
2837
+ setElementStyle(v1, {
2838
+ background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
2839
+ linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
2840
+ ${whiteGrad}`,
2841
+ });
2842
+ setElementStyle(v2, { background: hueGradient });
2851
2843
 
2852
- setElementStyle(v2, {
2853
- background: `linear-gradient(rgb(${r},${g},${b}) 0%, rgb(${gr},${gg},${gb}) 100%)`,
2854
- });
2855
- }
2856
2844
  setElementStyle(v3, {
2857
2845
  background: `linear-gradient(rgba(${r},${g},${b},1) 0%,rgba(${r},${g},${b},0) 100%)`,
2858
2846
  });
@@ -3002,13 +2990,13 @@ class ColorPicker {
3002
2990
  const [v1, v2, v3] = visuals;
3003
2991
  const [c1, c2, c3] = controlKnobs;
3004
2992
  /** @type {HTMLElement} */
3005
- const visual = hasClass(target, 'visual-control')
3006
- ? target : querySelector('.visual-control', target.parentElement);
2993
+ const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
3007
2994
  const visualRect = getBoundingClientRect(visual);
2995
+ const html = getDocumentElement(v1);
3008
2996
  const X = type === 'touchstart' ? touches[0].pageX : pageX;
3009
2997
  const Y = type === 'touchstart' ? touches[0].pageY : pageY;
3010
- const offsetX = X - window.pageXOffset - visualRect.left;
3011
- const offsetY = Y - window.pageYOffset - visualRect.top;
2998
+ const offsetX = X - html.scrollLeft - visualRect.left;
2999
+ const offsetY = Y - html.scrollTop - visualRect.top;
3012
3000
 
3013
3001
  if (target === v1 || target === c1) {
3014
3002
  self.dragElement = visual;
@@ -3068,10 +3056,11 @@ class ColorPicker {
3068
3056
  if (!dragElement) return;
3069
3057
 
3070
3058
  const controlRect = getBoundingClientRect(dragElement);
3071
- const X = type === 'touchmove' ? touches[0].pageX : pageX;
3072
- const Y = type === 'touchmove' ? touches[0].pageY : pageY;
3073
- const offsetX = X - window.pageXOffset - controlRect.left;
3074
- const offsetY = Y - window.pageYOffset - controlRect.top;
3059
+ const win = getDocumentElement(v1);
3060
+ const X = type === touchmoveEvent ? touches[0].pageX : pageX;
3061
+ const Y = type === touchmoveEvent ? touches[0].pageY : pageY;
3062
+ const offsetX = X - win.scrollLeft - controlRect.left;
3063
+ const offsetY = Y - win.scrollTop - controlRect.top;
3075
3064
 
3076
3065
  if (dragElement === v1) {
3077
3066
  self.changeControl1(offsetX, offsetY);
@@ -3098,19 +3087,19 @@ class ColorPicker {
3098
3087
  if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
3099
3088
  e.preventDefault();
3100
3089
 
3101
- const { format, controlKnobs, visuals } = self;
3090
+ const { controlKnobs, visuals } = self;
3102
3091
  const { offsetWidth, offsetHeight } = visuals[0];
3103
3092
  const [c1, c2, c3] = controlKnobs;
3104
3093
  const { activeElement } = getDocument(c1);
3105
3094
  const currentKnob = controlKnobs.find((x) => x === activeElement);
3106
- const yRatio = offsetHeight / (format === 'hsl' ? 100 : 360);
3095
+ const yRatio = offsetHeight / 360;
3107
3096
 
3108
3097
  if (currentKnob) {
3109
3098
  let offsetX = 0;
3110
3099
  let offsetY = 0;
3111
3100
 
3112
3101
  if (target === c1) {
3113
- const xRatio = offsetWidth / (format === 'hsl' ? 360 : 100);
3102
+ const xRatio = offsetWidth / 100;
3114
3103
 
3115
3104
  if ([keyArrowLeft, keyArrowRight].includes(code)) {
3116
3105
  self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
@@ -3160,7 +3149,7 @@ class ColorPicker {
3160
3149
  if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
3161
3150
  if (activeElement === input) {
3162
3151
  if (isNonColorValue) {
3163
- colorSource = 'white';
3152
+ colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
3164
3153
  } else {
3165
3154
  colorSource = currentValue;
3166
3155
  }
@@ -3211,9 +3200,7 @@ class ColorPicker {
3211
3200
  changeControl1(X, Y) {
3212
3201
  const self = this;
3213
3202
  let [offsetX, offsetY] = [0, 0];
3214
- const {
3215
- format, controlPositions, visuals,
3216
- } = self;
3203
+ const { controlPositions, visuals } = self;
3217
3204
  const { offsetHeight, offsetWidth } = visuals[0];
3218
3205
 
3219
3206
  if (X > offsetWidth) offsetX = offsetWidth;
@@ -3222,29 +3209,19 @@ class ColorPicker {
3222
3209
  if (Y > offsetHeight) offsetY = offsetHeight;
3223
3210
  else if (Y >= 0) offsetY = Y;
3224
3211
 
3225
- const hue = format === 'hsl'
3226
- ? offsetX / offsetWidth
3227
- : controlPositions.c2y / offsetHeight;
3212
+ const hue = controlPositions.c2y / offsetHeight;
3228
3213
 
3229
- const saturation = format === 'hsl'
3230
- ? 1 - controlPositions.c2y / offsetHeight
3231
- : offsetX / offsetWidth;
3214
+ const saturation = offsetX / offsetWidth;
3232
3215
 
3233
3216
  const lightness = 1 - offsetY / offsetHeight;
3234
3217
  const alpha = 1 - controlPositions.c3y / offsetHeight;
3235
3218
 
3236
- const colorObject = format === 'hsl'
3237
- ? {
3238
- h: hue, s: saturation, l: lightness, a: alpha,
3239
- }
3240
- : {
3241
- h: hue, s: saturation, v: lightness, a: alpha,
3242
- };
3243
-
3244
3219
  // new color
3245
3220
  const {
3246
3221
  r, g, b, a,
3247
- } = new Color(colorObject);
3222
+ } = new Color({
3223
+ h: hue, s: saturation, v: lightness, a: alpha,
3224
+ });
3248
3225
 
3249
3226
  ObjectAssign(self.color, {
3250
3227
  r, g, b, a,
@@ -3271,7 +3248,7 @@ class ColorPicker {
3271
3248
  changeControl2(Y) {
3272
3249
  const self = this;
3273
3250
  const {
3274
- format, controlPositions, visuals,
3251
+ controlPositions, visuals,
3275
3252
  } = self;
3276
3253
  const { offsetHeight, offsetWidth } = visuals[0];
3277
3254
 
@@ -3280,26 +3257,17 @@ class ColorPicker {
3280
3257
  if (Y > offsetHeight) offsetY = offsetHeight;
3281
3258
  else if (Y >= 0) offsetY = Y;
3282
3259
 
3283
- const hue = format === 'hsl'
3284
- ? controlPositions.c1x / offsetWidth
3285
- : offsetY / offsetHeight;
3286
- const saturation = format === 'hsl'
3287
- ? 1 - offsetY / offsetHeight
3288
- : controlPositions.c1x / offsetWidth;
3260
+ const hue = offsetY / offsetHeight;
3261
+ const saturation = controlPositions.c1x / offsetWidth;
3289
3262
  const lightness = 1 - controlPositions.c1y / offsetHeight;
3290
3263
  const alpha = 1 - controlPositions.c3y / offsetHeight;
3291
- const colorObject = format === 'hsl'
3292
- ? {
3293
- h: hue, s: saturation, l: lightness, a: alpha,
3294
- }
3295
- : {
3296
- h: hue, s: saturation, v: lightness, a: alpha,
3297
- };
3298
3264
 
3299
3265
  // new color
3300
3266
  const {
3301
3267
  r, g, b, a,
3302
- } = new Color(colorObject);
3268
+ } = new Color({
3269
+ h: hue, s: saturation, v: lightness, a: alpha,
3270
+ });
3303
3271
 
3304
3272
  ObjectAssign(self.color, {
3305
3273
  r, g, b, a,
@@ -3386,18 +3354,18 @@ class ColorPicker {
3386
3354
  setControlPositions() {
3387
3355
  const self = this;
3388
3356
  const {
3389
- format, visuals, color, hsl, hsv,
3357
+ visuals, color, hsv,
3390
3358
  } = self;
3391
3359
  const { offsetHeight, offsetWidth } = visuals[0];
3392
3360
  const alpha = color.a;
3393
- const hue = hsl.h;
3361
+ const hue = hsv.h;
3394
3362
 
3395
- const saturation = format !== 'hsl' ? hsv.s : hsl.s;
3396
- const lightness = format !== 'hsl' ? hsv.v : hsl.l;
3363
+ const saturation = hsv.s;
3364
+ const lightness = hsv.v;
3397
3365
 
3398
- self.controlPositions.c1x = format !== 'hsl' ? saturation * offsetWidth : hue * offsetWidth;
3366
+ self.controlPositions.c1x = saturation * offsetWidth;
3399
3367
  self.controlPositions.c1y = (1 - lightness) * offsetHeight;
3400
- self.controlPositions.c2y = format !== 'hsl' ? hue * offsetHeight : (1 - saturation) * offsetHeight;
3368
+ self.controlPositions.c2y = hue * offsetHeight;
3401
3369
  self.controlPositions.c3y = (1 - alpha) * offsetHeight;
3402
3370
  }
3403
3371
 
@@ -3405,78 +3373,40 @@ class ColorPicker {
3405
3373
  updateAppearance() {
3406
3374
  const self = this;
3407
3375
  const {
3408
- componentLabels, colorLabels, color, parent,
3409
- hsl, hsv, hex, format, controlKnobs,
3376
+ componentLabels, color, parent,
3377
+ hsv, hex, format, controlKnobs,
3410
3378
  } = self;
3411
3379
  const {
3412
3380
  appearanceLabel, hexLabel, valueLabel,
3413
3381
  } = componentLabels;
3414
- const { r, g, b } = color.toRgb();
3382
+ let { r, g, b } = color.toRgb();
3415
3383
  const [knob1, knob2, knob3] = controlKnobs;
3416
- const hue = roundPart(hsl.h * 360);
3384
+ const hue = roundPart(hsv.h * 360);
3417
3385
  const alpha = color.a;
3418
- const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
3419
- const saturation = roundPart(saturationSource * 100);
3420
- const lightness = roundPart(hsl.l * 100);
3421
- const hsvl = hsv.v * 100;
3422
- let colorName;
3423
-
3424
- // determine color appearance
3425
- if (lightness === 100 && saturation === 0) {
3426
- colorName = colorLabels.white;
3427
- } else if (lightness === 0) {
3428
- colorName = colorLabels.black;
3429
- } else if (saturation === 0) {
3430
- colorName = colorLabels.grey;
3431
- } else if (hue < 15 || hue >= 345) {
3432
- colorName = colorLabels.red;
3433
- } else if (hue >= 15 && hue < 45) {
3434
- colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
3435
- } else if (hue >= 45 && hue < 75) {
3436
- const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
3437
- const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
3438
- colorName = isGold ? colorLabels.gold : colorLabels.yellow;
3439
- colorName = isOlive ? colorLabels.olive : colorName;
3440
- } else if (hue >= 75 && hue < 155) {
3441
- colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
3442
- } else if (hue >= 155 && hue < 175) {
3443
- colorName = colorLabels.teal;
3444
- } else if (hue >= 175 && hue < 195) {
3445
- colorName = colorLabels.cyan;
3446
- } else if (hue >= 195 && hue < 255) {
3447
- colorName = colorLabels.blue;
3448
- } else if (hue >= 255 && hue < 270) {
3449
- colorName = colorLabels.violet;
3450
- } else if (hue >= 270 && hue < 295) {
3451
- colorName = colorLabels.magenta;
3452
- } else if (hue >= 295 && hue < 345) {
3453
- colorName = colorLabels.pink;
3454
- }
3386
+ const saturation = roundPart(hsv.s * 100);
3387
+ const lightness = roundPart(hsv.v * 100);
3388
+ const colorName = self.appearance;
3455
3389
 
3456
3390
  let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
3457
3391
 
3458
- if (format === 'hsl') {
3459
- colorLabel = `HSL: ${hue}°, ${saturation}%, ${lightness}%`;
3460
- setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3461
- setAttribute(knob1, ariaValueText, `${hue}° & ${lightness}%`);
3462
- setAttribute(knob1, ariaValueNow, `${hue}`);
3463
- setAttribute(knob2, ariaValueText, `${saturation}%`);
3464
- setAttribute(knob2, ariaValueNow, `${saturation}`);
3465
- } else if (format === 'hwb') {
3392
+ if (format === 'hwb') {
3466
3393
  const { hwb } = self;
3467
3394
  const whiteness = roundPart(hwb.w * 100);
3468
3395
  const blackness = roundPart(hwb.b * 100);
3469
3396
  colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
3470
- setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3471
3397
  setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
3472
3398
  setAttribute(knob1, ariaValueNow, `${whiteness}`);
3399
+ setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3473
3400
  setAttribute(knob2, ariaValueText, `${hue}%`);
3474
3401
  setAttribute(knob2, ariaValueNow, `${hue}`);
3475
3402
  } else {
3403
+ [r, g, b] = [r, g, b].map(roundPart);
3404
+ colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
3476
3405
  colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
3477
- setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3406
+
3478
3407
  setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
3479
3408
  setAttribute(knob1, ariaValueNow, `${lightness}`);
3409
+ setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3480
3410
  setAttribute(knob2, ariaValueText, `${hue}°`);
3481
3411
  setAttribute(knob2, ariaValueNow, `${hue}`);
3482
3412
  }
@@ -3571,37 +3501,13 @@ class ColorPicker {
3571
3501
  }
3572
3502
  }
3573
3503
 
3574
- /**
3575
- * The `Space` & `Enter` keys specific event listener.
3576
- * Toggle visibility of the `ColorPicker` / the presets menu, showing one will hide the other.
3577
- * @param {KeyboardEvent} e
3578
- * @this {ColorPicker}
3579
- */
3580
- keyToggle(e) {
3581
- const self = this;
3582
- const { menuToggle } = self;
3583
- const { activeElement } = getDocument(menuToggle);
3584
- const { code } = e;
3585
-
3586
- if ([keyEnter, keySpace].includes(code)) {
3587
- if ((menuToggle && activeElement === menuToggle) || !activeElement) {
3588
- e.preventDefault();
3589
- if (!activeElement) {
3590
- self.togglePicker(e);
3591
- } else {
3592
- self.toggleMenu();
3593
- }
3594
- }
3595
- }
3596
- }
3597
-
3598
3504
  /**
3599
3505
  * Toggle the `ColorPicker` dropdown visibility.
3600
- * @param {Event} e
3506
+ * @param {Event=} e
3601
3507
  * @this {ColorPicker}
3602
3508
  */
3603
3509
  togglePicker(e) {
3604
- e.preventDefault();
3510
+ if (e) e.preventDefault();
3605
3511
  const self = this;
3606
3512
  const { colorPicker } = self;
3607
3513
 
@@ -3622,8 +3528,13 @@ class ColorPicker {
3622
3528
  }
3623
3529
  }
3624
3530
 
3625
- /** Toggles the visibility of the `ColorPicker` presets menu. */
3626
- toggleMenu() {
3531
+ /**
3532
+ * Toggles the visibility of the `ColorPicker` presets menu.
3533
+ * @param {Event=} e
3534
+ * @this {ColorPicker}
3535
+ */
3536
+ toggleMenu(e) {
3537
+ if (e) e.preventDefault();
3627
3538
  const self = this;
3628
3539
  const { colorMenu } = self;
3629
3540
 
@@ -3649,6 +3560,10 @@ class ColorPicker {
3649
3560
  const relatedBtn = openPicker ? pickerToggle : menuToggle;
3650
3561
  const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
3651
3562
 
3563
+ // if (!self.isValid) {
3564
+ self.value = self.color.toString(true);
3565
+ // }
3566
+
3652
3567
  if (openDropdown) {
3653
3568
  removeClass(openDropdown, 'show');
3654
3569
  setAttribute(relatedBtn, ariaExpanded, 'false');
@@ -3662,9 +3577,6 @@ class ColorPicker {
3662
3577
  }, animationDuration);
3663
3578
  }
3664
3579
 
3665
- if (!self.isValid) {
3666
- self.value = self.color.toString();
3667
- }
3668
3580
  if (!focusPrevented) {
3669
3581
  focus(pickerToggle);
3670
3582
  }