@bornova/colorpicker 1.0.0 → 1.0.1

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,4 +1,4 @@
1
- /* @bornova/colorpicker v1.0.0 */
1
+ /* @bornova/colorpicker v1.0.1 */
2
2
  const settings = {
3
3
  el: "[data-colorpicker]",
4
4
  parent: "body",
@@ -36,7 +36,16 @@ const settings = {
36
36
  }
37
37
  };
38
38
 
39
- const ctx = document.createElement("canvas").getContext("2d");
39
+ let ctx;
40
+
41
+ function getCtx() {
42
+ if (!ctx && typeof document !== "undefined") {
43
+ try {
44
+ ctx = document.createElement("canvas").getContext("2d");
45
+ } catch {}
46
+ }
47
+ return ctx;
48
+ }
40
49
 
41
50
  function HSVAtoRGBA(hsva) {
42
51
  const saturation = hsva.s / 100;
@@ -105,25 +114,70 @@ function RGBAtoHSVA(rgba) {
105
114
 
106
115
  function strToRGBA(str) {
107
116
  const regex = /^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i;
117
+ const canvasCtx = getCtx();
108
118
  let match, rgba;
109
- ctx.fillStyle = "#000";
110
- ctx.fillStyle = str;
111
- match = regex.exec(ctx.fillStyle);
112
- if (match) {
113
- rgba = {
114
- r: Number(match[3]),
115
- g: Number(match[4]),
116
- b: Number(match[5]),
117
- a: Number(match[6])
118
- };
119
+ if (canvasCtx) {
120
+ canvasCtx.fillStyle = "#000";
121
+ canvasCtx.fillStyle = str;
122
+ match = regex.exec(canvasCtx.fillStyle);
123
+ if (match) {
124
+ rgba = {
125
+ r: Number(match[3]),
126
+ g: Number(match[4]),
127
+ b: Number(match[5]),
128
+ a: match[6] === "" ? 1 : Number(match[6])
129
+ };
130
+ } else {
131
+ match = canvasCtx.fillStyle.replace("#", "").match(/.{2}/g).map(h => parseInt(h, 16));
132
+ rgba = {
133
+ r: match[0],
134
+ g: match[1],
135
+ b: match[2],
136
+ a: match[3] !== undefined ? Number((match[3] / 255).toFixed(2)) : 1
137
+ };
138
+ }
119
139
  } else {
120
- match = ctx.fillStyle.replace("#", "").match(/.{2}/g).map(h => parseInt(h, 16));
121
- rgba = {
122
- r: match[0],
123
- g: match[1],
124
- b: match[2],
125
- a: 1
126
- };
140
+ match = regex.exec(str);
141
+ if (match) {
142
+ rgba = {
143
+ r: Number(match[3]),
144
+ g: Number(match[4]),
145
+ b: Number(match[5]),
146
+ a: match[6] === "" ? 1 : Number(match[6])
147
+ };
148
+ } else {
149
+ const hex = str.replace("#", "");
150
+ if (hex.length === 3 || hex.length === 4) {
151
+ const r = parseInt(hex[0] + hex[0], 16);
152
+ const g = parseInt(hex[1] + hex[1], 16);
153
+ const b = parseInt(hex[2] + hex[2], 16);
154
+ const a = hex.length === 4 ? Number((parseInt(hex[3] + hex[3], 16) / 255).toFixed(2)) : 1;
155
+ rgba = {
156
+ r: r,
157
+ g: g,
158
+ b: b,
159
+ a: a
160
+ };
161
+ } else if (hex.length === 6 || hex.length === 8) {
162
+ const r = parseInt(hex.slice(0, 2), 16);
163
+ const g = parseInt(hex.slice(2, 4), 16);
164
+ const b = parseInt(hex.slice(4, 6), 16);
165
+ const a = hex.length === 8 ? Number((parseInt(hex.slice(6, 8), 16) / 255).toFixed(2)) : 1;
166
+ rgba = {
167
+ r: r,
168
+ g: g,
169
+ b: b,
170
+ a: a
171
+ };
172
+ } else {
173
+ rgba = {
174
+ r: 0,
175
+ g: 0,
176
+ b: 0,
177
+ a: 1
178
+ };
179
+ }
180
+ }
127
181
  }
128
182
  return rgba;
129
183
  }
@@ -134,7 +188,7 @@ function RGBAToHex(rgba) {
134
188
  const B = rgba.b.toString(16).padStart(2, "0");
135
189
  let A = "";
136
190
  if (settings.alpha && (rgba.a < 1 || settings.forceAlpha)) {
137
- A = (rgba.a * 255 | 0).toString(16).padStart(2, "0");
191
+ A = Math.round(rgba.a * 255).toString(16).padStart(2, "0");
138
192
  }
139
193
  return "#" + R + G + B + A;
140
194
  }
@@ -399,11 +453,17 @@ function attachVirtualInstance(element) {
399
453
  if (element.matches(selector)) {
400
454
  currentInstanceId = selector;
401
455
  defaultInstance = {};
402
- unsupportedOptions.forEach(option => delete options[option]);
403
- for (const option of Object.keys(options)) {
456
+ const clonedOptions = {
457
+ ...options
458
+ };
459
+ unsupportedOptions.forEach(option => delete clonedOptions[option]);
460
+ for (const option of Object.keys(clonedOptions)) {
404
461
  defaultInstance[option] = Array.isArray(settings[option]) ? [ ...settings[option] ] : settings[option];
462
+ if (option === "clearButton") {
463
+ defaultInstance["clearLabel"] = settings.clearLabel;
464
+ }
405
465
  }
406
- configure(options);
466
+ configure(clonedOptions);
407
467
  break;
408
468
  }
409
469
  }
@@ -446,13 +506,22 @@ function openPicker(event) {
446
506
  colorValue.focus({
447
507
  preventScroll: true
448
508
  });
449
- colorValue.setSelectionRange(currentEl.selectionStart, currentEl.selectionEnd);
509
+ let selectionStart = 0;
510
+ let selectionEnd = 0;
511
+ try {
512
+ selectionStart = currentEl.selectionStart;
513
+ selectionEnd = currentEl.selectionEnd;
514
+ } catch {}
515
+ colorValue.setSelectionRange(selectionStart, selectionEnd);
450
516
  }
451
517
  if (settings.selectInput) {
452
518
  colorValue.select();
453
519
  }
454
520
  if (keyboardNav || settings.swatchesOnly) {
455
- getFocusableElements().shift().focus();
521
+ const firstFocusable = getFocusableElements().shift();
522
+ if (firstFocusable) {
523
+ firstFocusable.focus();
524
+ }
456
525
  }
457
526
  currentEl.dispatchEvent(new Event("open", {
458
527
  bubbles: false
@@ -564,6 +633,14 @@ function closePicker(revert) {
564
633
  bubbles: true
565
634
  }));
566
635
  }
636
+ } else {
637
+ const value = colorValue.value;
638
+ if (value === "") {
639
+ pickColor("");
640
+ } else {
641
+ setColorFromStr(value);
642
+ pickColor(colorValue.value);
643
+ }
567
644
  }
568
645
  setTimeout(() => {
569
646
  if (oldColor !== prevEl.value) {
@@ -825,13 +902,17 @@ function init() {
825
902
  }
826
903
  if (key === "Tab" && target.matches(".clr-picker *")) {
827
904
  const focusables = getFocusableElements();
828
- const firstFocusable = focusables.shift();
829
- const lastFocusable = focusables.pop();
830
- if (shiftKey && target === firstFocusable) {
831
- lastFocusable.focus();
832
- event.preventDefault();
833
- } else if (!shiftKey && target === lastFocusable) {
834
- firstFocusable.focus();
905
+ if (focusables.length > 1) {
906
+ const firstFocusable = focusables[0];
907
+ const lastFocusable = focusables[focusables.length - 1];
908
+ if (shiftKey && target === firstFocusable) {
909
+ lastFocusable.focus();
910
+ event.preventDefault();
911
+ } else if (!shiftKey && target === lastFocusable) {
912
+ firstFocusable.focus();
913
+ event.preventDefault();
914
+ }
915
+ } else if (focusables.length === 1) {
835
916
  event.preventDefault();
836
917
  }
837
918
  }
package/package.json CHANGED
@@ -1,51 +1,51 @@
1
- {
2
- "name": "@bornova/colorpicker",
3
- "version": "1.0.0",
4
- "description": "A lightweight and elegant JavaScript color picker written in vanilla JavaScript. Zero dependencies.",
5
- "keywords": [
6
- "color",
7
- "picker",
8
- "javascript"
9
- ],
10
- "homepage": "https://github.com/bornova/ColorPicker#readme",
11
- "bugs": {
12
- "url": "https://github.com/bornova/ColorPicker/issues"
13
- },
14
- "repository": {
15
- "type": "git",
16
- "url": "git+https://github.com/bornova/ColorPicker.git"
17
- },
18
- "license": "MIT",
19
- "type": "module",
20
- "exports": {
21
- ".": {
22
- "types": "./dist/types/index.d.ts",
23
- "import": "./dist/esm/colorpicker.js"
24
- }
25
- },
26
- "jsdelivr": "./dist/browser/colorpicker.min.js",
27
- "unpkg": "./dist/browser/colorpicker.min.js",
28
- "types": "./dist/types/index.d.ts",
29
- "files": [
30
- "dist"
31
- ],
32
- "scripts": {
33
- "prebuild": "npm run lint && npm run prettier",
34
- "build": "rollup -c && npm run types",
35
- "format": "npm run prettier:fix && npm run lint:fix",
36
- "lint": "eslint .",
37
- "lint:fix": "eslint --fix .",
38
- "prettier": "prettier --check .",
39
- "prettier:fix": "prettier --write .",
40
- "types": "tsc"
41
- },
42
- "devDependencies": {
43
- "@eslint/js": "^10.0.1",
44
- "@rollup/plugin-terser": "^1.0.0",
45
- "eslint": "^10.4.0",
46
- "globals": "^17.6.0",
47
- "prettier": "^3.8.3",
48
- "rollup": "^4.60.4",
49
- "typescript": "^6.0.3"
50
- }
51
- }
1
+ {
2
+ "name": "@bornova/colorpicker",
3
+ "version": "1.0.1",
4
+ "description": "A lightweight and elegant JavaScript color picker written in vanilla JavaScript. Zero dependencies.",
5
+ "keywords": [
6
+ "color",
7
+ "picker",
8
+ "javascript"
9
+ ],
10
+ "homepage": "https://github.com/bornova/ColorPicker#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/bornova/ColorPicker/issues"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/bornova/ColorPicker.git"
17
+ },
18
+ "license": "MIT",
19
+ "type": "module",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/types/index.d.ts",
23
+ "import": "./dist/esm/colorpicker.js"
24
+ }
25
+ },
26
+ "jsdelivr": "./dist/browser/colorpicker.min.js",
27
+ "unpkg": "./dist/browser/colorpicker.min.js",
28
+ "types": "./dist/types/index.d.ts",
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "scripts": {
33
+ "prebuild": "npm run lint && npm run prettier",
34
+ "build": "rollup -c && npm run types",
35
+ "format": "npm run prettier:fix && npm run lint:fix",
36
+ "lint": "eslint .",
37
+ "lint:fix": "eslint --fix .",
38
+ "prettier": "prettier --check .",
39
+ "prettier:fix": "prettier --write .",
40
+ "types": "tsc"
41
+ },
42
+ "devDependencies": {
43
+ "@eslint/js": "^10.0.1",
44
+ "@rollup/plugin-terser": "^1.0.0",
45
+ "eslint": "^10.4.0",
46
+ "globals": "^17.6.0",
47
+ "prettier": "^3.8.3",
48
+ "rollup": "^4.60.4",
49
+ "typescript": "^6.0.3"
50
+ }
51
+ }