gdp-color-picker 1.0.0 → 1.1.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,22 +1,29 @@
1
-
2
- import React, { useRef, useEffect, useState, useCallback } from 'react';
3
- import { clamp } from './utils/color';
1
+ import React, { useRef, useEffect, useState, useCallback } from "react";
2
+ import { clamp } from "./utils/color";
4
3
 
5
4
  const ColorBoard = ({ hue, saturation, value, onChange }) => {
6
5
  const containerRef = useRef(null);
7
6
  const [isDragging, setIsDragging] = useState(false);
8
7
 
9
- const handleChange = useCallback((e) => {
10
- if (!containerRef.current) return;
11
- const { width, height, left, top } = containerRef.current.getBoundingClientRect();
12
- const x = clamp(e.clientX - left, 0, width);
13
- const y = clamp(e.clientY - top, 0, height);
8
+ const handleChange = useCallback(
9
+ (e) => {
10
+ if (!containerRef.current) return;
11
+ const {
12
+ width,
13
+ height,
14
+ left,
15
+ top,
16
+ } = containerRef.current.getBoundingClientRect();
17
+ const x = clamp(e.clientX - left, 0, width);
18
+ const y = clamp(e.clientY - top, 0, height);
14
19
 
15
- const newSaturation = x / width;
16
- const newValue = 1 - y / height;
20
+ const newSaturation = x / width;
21
+ const newValue = 1 - y / height;
17
22
 
18
- onChange(newSaturation, newValue);
19
- }, [onChange]);
23
+ onChange(newSaturation, newValue);
24
+ },
25
+ [onChange]
26
+ );
20
27
 
21
28
  const handleMouseDown = (e) => {
22
29
  setIsDragging(true);
@@ -35,13 +42,13 @@ const ColorBoard = ({ hue, saturation, value, onChange }) => {
35
42
  };
36
43
 
37
44
  if (isDragging) {
38
- window.addEventListener('mousemove', handleMouseMove);
39
- window.addEventListener('mouseup', handleMouseUp);
45
+ window.addEventListener("mousemove", handleMouseMove);
46
+ window.addEventListener("mouseup", handleMouseUp);
40
47
  }
41
48
 
42
49
  return () => {
43
- window.removeEventListener('mousemove', handleMouseMove);
44
- window.removeEventListener('mouseup', handleMouseUp);
50
+ window.removeEventListener("mousemove", handleMouseMove);
51
+ window.removeEventListener("mouseup", handleMouseUp);
45
52
  };
46
53
  }, [isDragging, handleChange, handleMouseUp]);
47
54
 
@@ -1,36 +1,51 @@
1
- import React, { useState, useEffect, useCallback, useRef } from 'react';
2
- import { rgbToHex, hexToRgb, hsvToRgb, rgbToHsv, rgbToHsl, hslToRgb } from './utils/color';
1
+ import React, { useState, useEffect, useCallback, useRef } from "react";
2
+ import {
3
+ rgbToHex,
4
+ hexToRgb,
5
+ hsvToRgb,
6
+ rgbToHsv,
7
+ rgbToHsl,
8
+ hslToRgb,
9
+ } from "./utils/color";
3
10
 
4
11
  const ColorInput = ({ hue, saturation, value, alpha, onChange }) => {
5
- const [mode, setMode] = useState('HEX');
12
+ const [mode, setMode] = useState("HEX");
6
13
  const [localValue, setLocalValue] = useState({});
7
14
  const [showDropdown, setShowDropdown] = useState(false);
8
15
  const dropdownRef = useRef(null);
9
16
 
10
- // Close dropdown when clicking outside
17
+ // 点击外部关闭下拉菜单
11
18
  useEffect(() => {
12
19
  const handleClickOutside = (event) => {
13
20
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
14
21
  setShowDropdown(false);
15
22
  }
16
23
  };
17
- document.addEventListener('mousedown', handleClickOutside);
24
+ document.addEventListener("mousedown", handleClickOutside);
18
25
  return () => {
19
- document.removeEventListener('mousedown', handleClickOutside);
26
+ document.removeEventListener("mousedown", handleClickOutside);
20
27
  };
21
28
  }, []);
22
29
 
23
- const getRgb = useCallback(() => hsvToRgb(hue, saturation, value), [hue, saturation, value]);
30
+ const getRgb = useCallback(() => hsvToRgb(hue, saturation, value), [
31
+ hue,
32
+ saturation,
33
+ value,
34
+ ]);
24
35
 
25
36
  useEffect(() => {
26
37
  const rgb = getRgb();
27
- if (mode === 'HEX') {
38
+ if (mode === "HEX") {
28
39
  setLocalValue({ hex: rgbToHex(rgb.r, rgb.g, rgb.b) });
29
- } else if (mode === 'RGB') {
40
+ } else if (mode === "RGB") {
30
41
  setLocalValue({ r: rgb.r, g: rgb.g, b: rgb.b });
31
- } else if (mode === 'HSL') {
42
+ } else if (mode === "HSL") {
32
43
  const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
33
- setLocalValue({ h: Math.round(hsl.h), s: Math.round(hsl.s * 100), l: Math.round(hsl.l * 100) });
44
+ setLocalValue({
45
+ h: Math.round(hsl.h),
46
+ s: Math.round(hsl.s * 100),
47
+ l: Math.round(hsl.l * 100),
48
+ });
34
49
  }
35
50
  }, [hue, saturation, value, mode, getRgb]);
36
51
 
@@ -53,85 +68,160 @@ const ColorInput = ({ hue, saturation, value, alpha, onChange }) => {
53
68
  const g = parseInt(newValue.g, 10);
54
69
  const b = parseInt(newValue.b, 10);
55
70
  if (!isNaN(r) && !isNaN(g) && !isNaN(b)) {
56
- const hsv = rgbToHsv(Math.min(255, Math.max(0, r)), Math.min(255, Math.max(0, g)), Math.min(255, Math.max(0, b)));
57
- onChange({ ...hsv, a: alpha });
71
+ const hsv = rgbToHsv(
72
+ Math.min(255, Math.max(0, r)),
73
+ Math.min(255, Math.max(0, g)),
74
+ Math.min(255, Math.max(0, b))
75
+ );
76
+ onChange({ ...hsv, a: alpha });
58
77
  }
59
78
  };
60
79
 
61
80
  const handleHslChange = (key, val) => {
62
- const newValue = { ...localValue, [key]: val };
63
- setLocalValue(newValue);
64
- const h = parseInt(newValue.h, 10);
65
- const s = parseInt(newValue.s, 10);
66
- const l = parseInt(newValue.l, 10);
67
- if (!isNaN(h) && !isNaN(s) && !isNaN(l)) {
68
- const rgb = hslToRgb(Math.min(360, Math.max(0, h)), Math.min(100, Math.max(0, s)) / 100, Math.min(100, Math.max(0, l)) / 100);
69
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
70
- onChange({ ...hsv, a: alpha });
71
- }
72
- };
73
-
74
- const openEyeDropper = async () => {
75
- if (!window.EyeDropper) return;
76
- const eyeDropper = new window.EyeDropper();
77
- try {
78
- const result = await eyeDropper.open();
79
- const rgb = hexToRgb(result.sRGBHex);
80
- if (rgb) {
81
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
82
- onChange({ ...hsv, a: alpha });
83
- }
84
- } catch (e) {
85
- // User canceled
81
+ const newValue = { ...localValue, [key]: val };
82
+ setLocalValue(newValue);
83
+ const h = parseInt(newValue.h, 10);
84
+ const s = parseInt(newValue.s, 10);
85
+ const l = parseInt(newValue.l, 10);
86
+ if (!isNaN(h) && !isNaN(s) && !isNaN(l)) {
87
+ const rgb = hslToRgb(
88
+ Math.min(360, Math.max(0, h)),
89
+ Math.min(100, Math.max(0, s)) / 100,
90
+ Math.min(100, Math.max(0, l)) / 100
91
+ );
92
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
93
+ onChange({ ...hsv, a: alpha });
86
94
  }
87
95
  };
88
96
 
89
97
  return (
90
98
  <div className="color-input-container">
91
- <div className="color-input-row">
92
- <div className="mode-selector" ref={dropdownRef} onClick={() => setShowDropdown(!showDropdown)}>
93
- <span>{mode}</span>
94
- <span className="arrow" style={{ fontSize: '10px', marginLeft: '4px', transform: showDropdown ? 'rotate(180deg)' : 'rotate(0deg)', display: 'inline-block', transition: 'transform 0.2s' }}>▼</span>
95
- {showDropdown && (
96
- <div className="mode-dropdown">
97
- <div className="mode-option" onClick={(e) => { e.stopPropagation(); setMode('HEX'); setShowDropdown(false); }}>HEX</div>
98
- <div className="mode-option" onClick={(e) => { e.stopPropagation(); setMode('RGB'); setShowDropdown(false); }}>RGB</div>
99
- <div className="mode-option" onClick={(e) => { e.stopPropagation(); setMode('HSL'); setShowDropdown(false); }}>HSL</div>
100
- </div>
101
- )}
102
- </div>
103
-
104
- {window.EyeDropper && (
105
- <div className="eyedropper-icon" onClick={openEyeDropper} title="Pick Color">
106
- <svg viewBox="0 0 24 24" width="16" height="16">
107
- <path fill="currentColor" d="M17.5,1.5c-0.8,0-1.5,0.3-2.1,0.9l-8,8c-0.6,0.6-0.9,1.3-0.9,2.1v2.5l-4,4l1.5,1.5l4-4h2.5c0.8,0,1.5-0.3,2.1-0.9l8-8c0.6-0.6,0.9-1.3,0.9-2.1s-0.3-1.5-0.9-2.1S18.3,1.5,17.5,1.5z M17.5,10l-8-8l8,8z M6.5,12.5v2.5h-2.5L2,17l2,2l2-2v-2.5h2.5l8-8L10,5L6.5,8.5V12.5z"/>
108
- <path d="M19.3 8.9L15.1 4.7 17.5 2.3c.4-.4 1-.4 1.4 0l2.7 2.7c.4.4.4 1 0 1.4L19.3 8.9zM13.7 6.1L4 15.8V20h4.2l9.7-9.7-4.2-4.2z" fill="currentColor"/>
109
- </svg>
110
- </div>
111
- )}
99
+ <div
100
+ className="mode-selector"
101
+ ref={dropdownRef}
102
+ onClick={() => setShowDropdown(!showDropdown)}
103
+ >
104
+ <span>{mode.charAt(0) + mode.slice(1).toLowerCase()}</span>
105
+ <span
106
+ className="arrow"
107
+ style={{
108
+ fontSize: "10px",
109
+ marginLeft: "4px",
110
+ transform: showDropdown ? "rotate(180deg)" : "rotate(0deg)",
111
+ display: "inline-block",
112
+ transition: "transform 0.2s",
113
+ color: "#8c8c8c",
114
+ }}
115
+ >
116
+ <svg
117
+ viewBox="0 0 1024 1024"
118
+ width="10"
119
+ height="10"
120
+ fill="currentColor"
121
+ >
122
+ <path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3 0.1-12.7-6.4-12.7z" />
123
+ </svg>
124
+ </span>
125
+ {showDropdown && (
126
+ <div className="mode-dropdown">
127
+ <div
128
+ className="mode-option"
129
+ onClick={(e) => {
130
+ e.stopPropagation();
131
+ setMode("HEX");
132
+ setShowDropdown(false);
133
+ }}
134
+ >
135
+ Hex
136
+ </div>
137
+ <div
138
+ className="mode-option"
139
+ onClick={(e) => {
140
+ e.stopPropagation();
141
+ setMode("RGB");
142
+ setShowDropdown(false);
143
+ }}
144
+ >
145
+ RGB
146
+ </div>
147
+ <div
148
+ className="mode-option"
149
+ onClick={(e) => {
150
+ e.stopPropagation();
151
+ setMode("HSL");
152
+ setShowDropdown(false);
153
+ }}
154
+ >
155
+ HSL
156
+ </div>
157
+ </div>
158
+ )}
112
159
  </div>
113
160
 
114
161
  <div className="color-input-fields">
115
- {mode === 'HEX' && (
116
- <input className="color-input" value={localValue.hex || ''} onChange={handleHexChange} />
117
- )}
118
- {mode === 'RGB' && (
119
- <>
120
- <input className="color-input" type="number" placeholder="R" value={localValue.r !== undefined ? localValue.r : ''} onChange={(e) => handleRgbChange('r', e.target.value)} />
121
- <input className="color-input" type="number" placeholder="G" value={localValue.g !== undefined ? localValue.g : ''} onChange={(e) => handleRgbChange('g', e.target.value)} />
122
- <input className="color-input" type="number" placeholder="B" value={localValue.b !== undefined ? localValue.b : ''} onChange={(e) => handleRgbChange('b', e.target.value)} />
123
- </>
124
- )}
125
- {mode === 'HSL' && (
126
- <>
127
- <input className="color-input" type="number" placeholder="H" value={localValue.h !== undefined ? localValue.h : ''} onChange={(e) => handleHslChange('h', e.target.value)} />
128
- <input className="color-input" type="number" placeholder="S" value={localValue.s !== undefined ? localValue.s : ''} onChange={(e) => handleHslChange('s', e.target.value)} />
129
- <input className="color-input" type="number" placeholder="L" value={localValue.l !== undefined ? localValue.l : ''} onChange={(e) => handleHslChange('l', e.target.value)} />
130
- </>
131
- )}
132
- <div className="color-input alpha-display">
133
- {Math.round(alpha * 100)}%
162
+ {mode === "HEX" && (
163
+ <div className="hex-input-wrapper">
164
+ <span className="hex-prefix">#</span>
165
+ <input
166
+ className="color-input hex"
167
+ value={localValue.hex ? localValue.hex.replace("#", "") : ""}
168
+ onChange={handleHexChange}
169
+ />
134
170
  </div>
171
+ )}
172
+ {mode === "RGB" && (
173
+ <>
174
+ <input
175
+ className="color-input"
176
+ type="number"
177
+ placeholder="R"
178
+ value={localValue.r !== undefined ? localValue.r : ""}
179
+ onChange={(e) => handleRgbChange("r", e.target.value)}
180
+ />
181
+ <input
182
+ className="color-input"
183
+ type="number"
184
+ placeholder="G"
185
+ value={localValue.g !== undefined ? localValue.g : ""}
186
+ onChange={(e) => handleRgbChange("g", e.target.value)}
187
+ />
188
+ <input
189
+ className="color-input"
190
+ type="number"
191
+ placeholder="B"
192
+ value={localValue.b !== undefined ? localValue.b : ""}
193
+ onChange={(e) => handleRgbChange("b", e.target.value)}
194
+ />
195
+ </>
196
+ )}
197
+ {mode === "HSL" && (
198
+ <>
199
+ <input
200
+ className="color-input"
201
+ type="number"
202
+ placeholder="H"
203
+ value={localValue.h !== undefined ? localValue.h : ""}
204
+ onChange={(e) => handleHslChange("h", e.target.value)}
205
+ />
206
+ <input
207
+ className="color-input"
208
+ type="number"
209
+ placeholder="S"
210
+ value={localValue.s !== undefined ? localValue.s : ""}
211
+ onChange={(e) => handleHslChange("s", e.target.value)}
212
+ />
213
+ <input
214
+ className="color-input"
215
+ type="number"
216
+ placeholder="L"
217
+ value={localValue.l !== undefined ? localValue.l : ""}
218
+ onChange={(e) => handleHslChange("l", e.target.value)}
219
+ />
220
+ </>
221
+ )}
222
+ <div className="color-input alpha-display">
223
+ {Math.round(alpha * 100)}%
224
+ </div>
135
225
  </div>
136
226
  </div>
137
227
  );
@@ -1,18 +1,20 @@
1
-
2
- import React, { useRef, useState, useEffect, useCallback } from 'react';
3
- import { clamp } from './utils/color';
1
+ import React, { useRef, useState, useEffect, useCallback } from "react";
2
+ import { clamp } from "./utils/color";
4
3
 
5
4
  const Slider = ({ value, max, onChange, className, style, children }) => {
6
5
  const containerRef = useRef(null);
7
6
  const [isDragging, setIsDragging] = useState(false);
8
7
 
9
- const handleChange = useCallback((e) => {
10
- if (!containerRef.current) return;
11
- const { width, left } = containerRef.current.getBoundingClientRect();
12
- const x = clamp(e.clientX - left, 0, width);
13
- const newValue = (x / width) * max;
14
- onChange(newValue);
15
- }, [max, onChange]);
8
+ const handleChange = useCallback(
9
+ (e) => {
10
+ if (!containerRef.current) return;
11
+ const { width, left } = containerRef.current.getBoundingClientRect();
12
+ const x = clamp(e.clientX - left, 0, width);
13
+ const newValue = (x / width) * max;
14
+ onChange(newValue);
15
+ },
16
+ [max, onChange]
17
+ );
16
18
 
17
19
  const handleMouseDown = (e) => {
18
20
  setIsDragging(true);
@@ -31,20 +33,20 @@ const Slider = ({ value, max, onChange, className, style, children }) => {
31
33
  };
32
34
 
33
35
  if (isDragging) {
34
- window.addEventListener('mousemove', handleMouseMove);
35
- window.addEventListener('mouseup', handleMouseUp);
36
+ window.addEventListener("mousemove", handleMouseMove);
37
+ window.addEventListener("mouseup", handleMouseUp);
36
38
  }
37
39
 
38
40
  return () => {
39
- window.removeEventListener('mousemove', handleMouseMove);
40
- window.removeEventListener('mouseup', handleMouseUp);
41
+ window.removeEventListener("mousemove", handleMouseMove);
42
+ window.removeEventListener("mouseup", handleMouseUp);
41
43
  };
42
44
  }, [isDragging, handleChange, handleMouseUp]);
43
45
 
44
46
  return (
45
47
  <div
46
48
  ref={containerRef}
47
- className={`color-slider ${className || ''}`}
49
+ className={`color-slider ${className || ""}`}
48
50
  style={style}
49
51
  onMouseDown={handleMouseDown}
50
52
  >
@@ -61,12 +63,7 @@ const Slider = ({ value, max, onChange, className, style, children }) => {
61
63
 
62
64
  export const HueSlider = ({ hue, onChange }) => {
63
65
  return (
64
- <Slider
65
- value={hue}
66
- max={360}
67
- onChange={onChange}
68
- className="hue-slider"
69
- />
66
+ <Slider value={hue} max={360} onChange={onChange} className="hue-slider" />
70
67
  );
71
68
  };
72
69
 
@@ -79,7 +76,7 @@ export const AlphaSlider = ({ alpha, color, onChange }) => {
79
76
  onChange={onChange}
80
77
  className="alpha-slider-bg"
81
78
  style={{
82
- background: `linear-gradient(to right, rgba(${r},${g},${b},0) 0%, rgba(${r},${g},${b},1) 100%)`
79
+ background: `linear-gradient(to right, rgba(${r},${g},${b},0) 0%, rgba(${r},${g},${b},1) 100%)`,
83
80
  }}
84
81
  />
85
82
  );