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.
- package/README.md +87 -28
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.mjs +1 -1
- package/dist/index.modern.mjs.map +1 -1
- package/dist/index.module.js +1 -1
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/package.json +2 -4
- package/src/lib/ColorBoard.js +23 -16
- package/src/lib/ColorInput.js +167 -77
- package/src/lib/Sliders.js +19 -22
- package/src/lib/index.css +302 -47
- package/src/lib/index.js +375 -50
- package/src/lib/utils/color.js +88 -93
package/src/lib/index.js
CHANGED
|
@@ -1,85 +1,197 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
2
|
+
import ReactDOM from "react-dom";
|
|
3
|
+
import ColorBoard from "./ColorBoard";
|
|
4
|
+
import { HueSlider, AlphaSlider } from "./Sliders";
|
|
5
|
+
import ColorInput from "./ColorInput";
|
|
6
|
+
import {
|
|
7
|
+
hsvToRgb,
|
|
8
|
+
rgbToHex,
|
|
9
|
+
parseColor,
|
|
10
|
+
hexToRgb,
|
|
11
|
+
rgbToHsv,
|
|
12
|
+
} from "./utils/color";
|
|
13
|
+
import "./index.css";
|
|
1
14
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
const DEFAULT_PRESETS = [
|
|
16
|
+
"#E0B5AE",
|
|
17
|
+
"#B2BBDE",
|
|
18
|
+
"#F2DDB3",
|
|
19
|
+
"#E0E5C5",
|
|
20
|
+
"#BBD0C3",
|
|
21
|
+
"#B5D1E3",
|
|
22
|
+
"#FFFFFF",
|
|
23
|
+
"#D25536",
|
|
24
|
+
"#EFA154",
|
|
25
|
+
"#F7DA7E",
|
|
26
|
+
"#5FA67F",
|
|
27
|
+
"#A2829D",
|
|
28
|
+
"#D390A2",
|
|
29
|
+
"#000000",
|
|
30
|
+
"#0099A4",
|
|
31
|
+
"#EABA00",
|
|
32
|
+
"#C9462C",
|
|
33
|
+
"#3171AC",
|
|
34
|
+
"#783780",
|
|
35
|
+
"#1E80EA",
|
|
36
|
+
"#2AAC3B",
|
|
37
|
+
"#B63455",
|
|
38
|
+
"#81532F",
|
|
39
|
+
"#AA9A5C",
|
|
40
|
+
"#828281",
|
|
41
|
+
"#055753",
|
|
42
|
+
"#8F262B",
|
|
43
|
+
"#F0D8D0",
|
|
44
|
+
];
|
|
8
45
|
|
|
9
|
-
const ColorPicker = ({
|
|
10
|
-
|
|
46
|
+
const ColorPicker = ({
|
|
47
|
+
value,
|
|
48
|
+
defaultValue,
|
|
49
|
+
onChange,
|
|
50
|
+
showLabel = true,
|
|
51
|
+
label = "Color",
|
|
52
|
+
showArrow = true,
|
|
53
|
+
showInput = true,
|
|
54
|
+
showColorBoard = true,
|
|
55
|
+
presets: customPresets,
|
|
56
|
+
}) => {
|
|
11
57
|
const [isOpen, setIsOpen] = useState(false);
|
|
12
|
-
|
|
13
|
-
|
|
58
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
59
|
+
const [recentColors, setRecentColors] = useState([]);
|
|
60
|
+
const presets = customPresets || DEFAULT_PRESETS;
|
|
61
|
+
|
|
14
62
|
const [color, setColor] = useState(() => {
|
|
15
|
-
const initColor = value || defaultValue ||
|
|
63
|
+
const initColor = value || defaultValue || "#1677ff";
|
|
16
64
|
return parseColor(initColor);
|
|
17
65
|
});
|
|
18
66
|
|
|
67
|
+
const [inputValue, setInputValue] = useState(() => {
|
|
68
|
+
const rgb = hsvToRgb(color.h, color.s, color.v);
|
|
69
|
+
return rgbToHex(rgb.r, rgb.g, rgb.b).toUpperCase();
|
|
70
|
+
});
|
|
71
|
+
|
|
19
72
|
const containerRef = useRef(null);
|
|
73
|
+
const triggerRef = useRef(null);
|
|
74
|
+
const [panelStyle, setPanelStyle] = useState({});
|
|
20
75
|
|
|
21
|
-
// Sync with prop value if controlled
|
|
22
76
|
useEffect(() => {
|
|
23
77
|
if (value !== undefined) {
|
|
24
|
-
|
|
78
|
+
const newColor = parseColor(value);
|
|
79
|
+
setColor(newColor);
|
|
80
|
+
const rgb = hsvToRgb(newColor.h, newColor.s, newColor.v);
|
|
81
|
+
setInputValue(rgbToHex(rgb.r, rgb.g, rgb.b).toUpperCase());
|
|
25
82
|
}
|
|
26
83
|
}, [value]);
|
|
27
84
|
|
|
28
85
|
const handleChange = (newColor) => {
|
|
29
86
|
const nextColor = { ...color, ...newColor };
|
|
30
87
|
setColor(nextColor);
|
|
31
|
-
|
|
88
|
+
|
|
89
|
+
const rgb = hsvToRgb(nextColor.h, nextColor.s, nextColor.v);
|
|
90
|
+
const hex = rgbToHex(rgb.r, rgb.g, rgb.b).toUpperCase();
|
|
91
|
+
setInputValue(hex);
|
|
92
|
+
|
|
32
93
|
if (onChange) {
|
|
33
|
-
const rgb = hsvToRgb(nextColor.h, nextColor.s, nextColor.v);
|
|
34
|
-
const hex = rgbToHex(rgb.r, rgb.g, rgb.b);
|
|
35
|
-
// Return a rich object or just hex string?
|
|
36
|
-
// AntD returns an object, but simple string is often easier.
|
|
37
|
-
// Let's return the hex string and the object as second arg just in case.
|
|
38
94
|
onChange(hex, { ...rgb, a: nextColor.a });
|
|
39
95
|
}
|
|
40
96
|
};
|
|
41
97
|
|
|
42
|
-
|
|
98
|
+
const handleInputChange = (e) => {
|
|
99
|
+
const val = e.target.value;
|
|
100
|
+
setInputValue(val);
|
|
101
|
+
|
|
102
|
+
if (/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i.test(val)) {
|
|
103
|
+
const rgb = hexToRgb(val);
|
|
104
|
+
if (rgb) {
|
|
105
|
+
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
106
|
+
handleChange({ ...hsv, a: color.a });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (
|
|
113
|
+
!isOpen ||
|
|
114
|
+
!triggerRef.current ||
|
|
115
|
+
typeof window === "undefined" ||
|
|
116
|
+
typeof document === "undefined"
|
|
117
|
+
) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
122
|
+
const top = triggerRect.bottom + 4 + window.scrollY;
|
|
123
|
+
const left = triggerRect.left + window.scrollX;
|
|
124
|
+
|
|
125
|
+
setPanelStyle({
|
|
126
|
+
position: "absolute",
|
|
127
|
+
top,
|
|
128
|
+
left,
|
|
129
|
+
zIndex: 9999,
|
|
130
|
+
});
|
|
131
|
+
}, [isOpen]);
|
|
132
|
+
|
|
133
|
+
const handleEyeDropper = async () => {
|
|
134
|
+
if (!window.EyeDropper) {
|
|
135
|
+
alert("当前浏览器不支持屏幕取色功能");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const eyeDropper = new window.EyeDropper();
|
|
141
|
+
const result = await eyeDropper.open();
|
|
142
|
+
const { sRGBHex } = result;
|
|
143
|
+
const rgb = hexToRgb(sRGBHex);
|
|
144
|
+
if (rgb) {
|
|
145
|
+
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
146
|
+
handleChange({ ...hsv, a: 1 });
|
|
147
|
+
}
|
|
148
|
+
} catch (e) {
|
|
149
|
+
// 用户取消取色或发生错误
|
|
150
|
+
console.log("EyeDropper failed or canceled:", e);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
43
154
|
useEffect(() => {
|
|
44
155
|
const handleClickOutside = (event) => {
|
|
45
|
-
if (
|
|
156
|
+
if (
|
|
157
|
+
containerRef.current &&
|
|
158
|
+
!containerRef.current.contains(event.target)
|
|
159
|
+
) {
|
|
46
160
|
setIsOpen(false);
|
|
47
161
|
}
|
|
48
162
|
};
|
|
49
163
|
|
|
50
164
|
if (isOpen) {
|
|
51
|
-
document.addEventListener(
|
|
165
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
166
|
+
} else {
|
|
167
|
+
const rgb = hsvToRgb(color.h, color.s, color.v);
|
|
168
|
+
const currentHex = rgbToHex(rgb.r, rgb.g, rgb.b).toUpperCase();
|
|
169
|
+
setRecentColors((prev) => {
|
|
170
|
+
if (prev.includes(currentHex)) return prev;
|
|
171
|
+
return [currentHex, ...prev].slice(0, 10);
|
|
172
|
+
});
|
|
52
173
|
}
|
|
53
|
-
|
|
174
|
+
|
|
54
175
|
return () => {
|
|
55
|
-
document.removeEventListener(
|
|
176
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
56
177
|
};
|
|
57
|
-
}, [isOpen]);
|
|
178
|
+
}, [isOpen, color]);
|
|
58
179
|
|
|
59
180
|
const rgb = hsvToRgb(color.h, color.s, color.v);
|
|
60
181
|
const displayColor = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${color.a})`;
|
|
182
|
+
const initialLimit = 14;
|
|
183
|
+
const visiblePresets = isExpanded ? presets : presets.slice(0, initialLimit);
|
|
184
|
+
const showExpand = presets.length > initialLimit;
|
|
61
185
|
|
|
62
|
-
|
|
63
|
-
<div className="color-picker-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/>
|
|
72
|
-
</div>
|
|
73
|
-
|
|
74
|
-
{isOpen && (
|
|
75
|
-
<div
|
|
76
|
-
className="color-picker-panel"
|
|
77
|
-
style={{
|
|
78
|
-
position: 'absolute',
|
|
79
|
-
top: '100%',
|
|
80
|
-
left: 0,
|
|
81
|
-
zIndex: 1000,
|
|
82
|
-
marginTop: 4
|
|
186
|
+
const panel = isOpen ? (
|
|
187
|
+
<div className="color-picker-panel" style={panelStyle}>
|
|
188
|
+
{showColorBoard && (
|
|
189
|
+
<div
|
|
190
|
+
className="color-picker-board-wrapper"
|
|
191
|
+
style={{
|
|
192
|
+
marginTop: "10px",
|
|
193
|
+
paddingTop: "10px",
|
|
194
|
+
borderTop: "1px solid #eee",
|
|
83
195
|
}}
|
|
84
196
|
>
|
|
85
197
|
<ColorBoard
|
|
@@ -88,10 +200,7 @@ const ColorPicker = ({ value, defaultValue, onChange }) => {
|
|
|
88
200
|
value={color.v}
|
|
89
201
|
onChange={(s, v) => handleChange({ s, v })}
|
|
90
202
|
/>
|
|
91
|
-
<HueSlider
|
|
92
|
-
hue={color.h}
|
|
93
|
-
onChange={(h) => handleChange({ h })}
|
|
94
|
-
/>
|
|
203
|
+
<HueSlider hue={color.h} onChange={(h) => handleChange({ h })} />
|
|
95
204
|
<AlphaSlider
|
|
96
205
|
alpha={color.a}
|
|
97
206
|
color={rgb}
|
|
@@ -106,6 +215,222 @@ const ColorPicker = ({ value, defaultValue, onChange }) => {
|
|
|
106
215
|
/>
|
|
107
216
|
</div>
|
|
108
217
|
)}
|
|
218
|
+
<div className="color-picker-presets">
|
|
219
|
+
<div className="palette-section-title" style={{ marginTop: 8 }}>
|
|
220
|
+
<span>Recommended</span>
|
|
221
|
+
<span
|
|
222
|
+
className="color-picker-icon-right"
|
|
223
|
+
onClick={handleEyeDropper}
|
|
224
|
+
title="屏幕取色"
|
|
225
|
+
>
|
|
226
|
+
<svg
|
|
227
|
+
width="16"
|
|
228
|
+
height="16"
|
|
229
|
+
viewBox="0 0 16 16"
|
|
230
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
231
|
+
>
|
|
232
|
+
<defs>
|
|
233
|
+
<rect id="path-1" x="0" y="0" width="16" height="16" />
|
|
234
|
+
</defs>
|
|
235
|
+
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
236
|
+
<g transform="translate(-920.000000, -594.000000)">
|
|
237
|
+
<g transform="translate(720.000000, 418.000000)">
|
|
238
|
+
<g transform="translate(200.000000, 176.000000)">
|
|
239
|
+
<mask id="mask-2" fill="white">
|
|
240
|
+
<use xlinkHref="#path-1" />
|
|
241
|
+
</mask>
|
|
242
|
+
<g />
|
|
243
|
+
<g
|
|
244
|
+
mask="url(#mask-2)"
|
|
245
|
+
fill="#000000"
|
|
246
|
+
fillOpacity="0.85"
|
|
247
|
+
fillRule="nonzero"
|
|
248
|
+
>
|
|
249
|
+
<g transform="translate(8.106532, 8.106532) rotate(-315.000000) translate(-8.106532, -8.106532) translate(-0.266667, -0.266667)">
|
|
250
|
+
<path d="M5.67238576,2.96585378 L6.99478644,4.28811977 L7.03978941,4.24867364 C7.66833128,3.72977631 8.60030981,3.76436946 9.18839345,4.3524531 L9.94264069,5.10670034 C10.1509203,5.31497996 10.1509203,5.65266795 9.94264069,5.86094757 L9.18778644,6.61411977 L13.7138769,11.1406782 C14.4428555,11.8696569 14.4428555,13.0515648 13.7138769,13.7805435 C12.9848982,14.5095222 11.8029902,14.5095222 11.0740115,13.7805435 L6.54778644,9.25411977 L5.7942809,10.0093074 C5.58600128,10.217587 5.24831329,10.217587 5.04003367,10.0093074 L4.28578644,9.25506012 C3.66094757,8.63022125 3.66094757,7.61715729 4.28578644,6.99231842 L4.35178644,6.92511977 L3.03252045,5.6057191 C2.30354177,4.87674042 2.30354177,3.69483246 3.03252045,2.96585378 C3.76149912,2.2368751 4.94340708,2.2368751 5.67238576,2.96585378 Z M8.43414622,7.36944204 L7.86778644,7.93411977 L7.30277537,8.50081289 L11.8282588,13.0262963 C12.1295204,13.3275579 12.6112769,13.3383172 12.925431,13.0585743 L12.9596296,13.0262963 C13.2720491,12.7138769 13.2720491,12.2073449 12.9596296,11.8949254 L8.43414622,7.36944204 Z M7.70907857,5.07958956 L7.67989899,5.10670034 L5.04003367,7.74656565 C4.83175405,7.95484528 4.83175405,8.29253326 5.04003367,8.50081289 L5.41715729,8.8779365 L8.81126984,5.48382395 L8.43414622,5.10670034 C8.23533385,4.90788797 7.91861014,4.89885105 7.70907857,5.07958956 Z M3.82096628,3.68782298 L3.78676768,3.72010101 C3.47434825,4.03252045 3.47434825,4.53905243 3.78676768,4.85147186 L5.10670034,6.17140452 L6.23807119,5.04003367 L4.91813853,3.72010101 C4.61687693,3.41883942 4.13512038,3.40808007 3.82096628,3.68782298 Z" transform="translate(8.373199, 8.373199) rotate(-315.000000) translate(-8.373199, -8.373199)" />
|
|
251
|
+
</g>
|
|
252
|
+
</g>
|
|
253
|
+
</g>
|
|
254
|
+
</g>
|
|
255
|
+
</g>
|
|
256
|
+
</g>
|
|
257
|
+
</svg>
|
|
258
|
+
</span>
|
|
259
|
+
</div>
|
|
260
|
+
<div className={`presets-grid modern`}>
|
|
261
|
+
{presets.map((preset, idx) => (
|
|
262
|
+
<div
|
|
263
|
+
key={idx}
|
|
264
|
+
className="preset-item preset-item-inner"
|
|
265
|
+
style={{ backgroundColor: preset }}
|
|
266
|
+
onClick={() => {
|
|
267
|
+
const rgbValue = hexToRgb(preset);
|
|
268
|
+
if (rgbValue) {
|
|
269
|
+
const hsv = rgbToHsv(rgbValue.r, rgbValue.g, rgbValue.b);
|
|
270
|
+
handleChange({ ...hsv, a: 1 });
|
|
271
|
+
}
|
|
272
|
+
}}
|
|
273
|
+
title={preset}
|
|
274
|
+
/>
|
|
275
|
+
))}
|
|
276
|
+
</div>
|
|
277
|
+
{/* {showExpand && (
|
|
278
|
+
<div
|
|
279
|
+
className="presets-collapse"
|
|
280
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
|
281
|
+
>
|
|
282
|
+
{isExpanded ? "Less" : "More"}
|
|
283
|
+
<span className={`collapse-arrow ${isExpanded ? "expanded" : ""}`}>
|
|
284
|
+
▼
|
|
285
|
+
</span>
|
|
286
|
+
</div>
|
|
287
|
+
)} */}
|
|
288
|
+
|
|
289
|
+
{recentColors.length > 0 && (
|
|
290
|
+
<>
|
|
291
|
+
<div className="palette-section-title">Recent</div>
|
|
292
|
+
<div className="presets-grid recent">
|
|
293
|
+
{recentColors.map((recentColor, idx) => (
|
|
294
|
+
<div
|
|
295
|
+
key={idx}
|
|
296
|
+
className="preset-item"
|
|
297
|
+
style={{ backgroundColor: recentColor }}
|
|
298
|
+
onClick={() => {
|
|
299
|
+
const rgbValue = hexToRgb(recentColor);
|
|
300
|
+
if (rgbValue) {
|
|
301
|
+
const hsv = rgbToHsv(
|
|
302
|
+
rgbValue.r,
|
|
303
|
+
rgbValue.g,
|
|
304
|
+
rgbValue.b
|
|
305
|
+
);
|
|
306
|
+
handleChange({ ...hsv, a: 1 });
|
|
307
|
+
}
|
|
308
|
+
}}
|
|
309
|
+
title={recentColor}
|
|
310
|
+
/>
|
|
311
|
+
))}
|
|
312
|
+
</div>
|
|
313
|
+
</>
|
|
314
|
+
)}
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
) : null;
|
|
318
|
+
|
|
319
|
+
return (
|
|
320
|
+
<div className="color-picker-container" ref={containerRef}>
|
|
321
|
+
<div className="color-picker-main-row">
|
|
322
|
+
<div className="color-picker-tooltip-trigger">
|
|
323
|
+
{showLabel && <span className="color-picker-label">{label}</span>}
|
|
324
|
+
|
|
325
|
+
<div
|
|
326
|
+
className={`color-picker-trigger ${isOpen ? "is-open" : ""}`}
|
|
327
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
328
|
+
ref={triggerRef}
|
|
329
|
+
>
|
|
330
|
+
<div
|
|
331
|
+
className="color-block"
|
|
332
|
+
style={{ backgroundColor: displayColor }}
|
|
333
|
+
/>
|
|
334
|
+
{showArrow && (
|
|
335
|
+
<span className={`color-picker-arrow ${isOpen ? "open" : ""}`}>
|
|
336
|
+
<svg
|
|
337
|
+
width="16"
|
|
338
|
+
height="16"
|
|
339
|
+
viewBox="0 0 16 16"
|
|
340
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
341
|
+
>
|
|
342
|
+
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
343
|
+
<g
|
|
344
|
+
transform="translate(-1348.000000, -88.000000)"
|
|
345
|
+
fillRule="nonzero"
|
|
346
|
+
>
|
|
347
|
+
<g transform="translate(0.000000, 60.000000)">
|
|
348
|
+
<g transform="translate(584.000000, 20.000000)">
|
|
349
|
+
<g transform="translate(728.000000, 4.000000)">
|
|
350
|
+
<g transform="translate(44.000000, 12.000000) rotate(-360.000000) translate(-44.000000, -12.000000) translate(36.000000, 4.000000)">
|
|
351
|
+
<rect
|
|
352
|
+
fill="#000000"
|
|
353
|
+
opacity="0"
|
|
354
|
+
x="0"
|
|
355
|
+
y="0"
|
|
356
|
+
width="16"
|
|
357
|
+
height="16"
|
|
358
|
+
/>
|
|
359
|
+
<path
|
|
360
|
+
d="M13.0750341,5.34788541 C12.9440655,5.21691678 12.7257845,5.21691678 12.5948158,5.34788541 L8.01091405,9.93178717 L3.40518417,5.34788541 C3.27421555,5.21691678 3.05593452,5.21691678 2.92496589,5.34788541 C2.79399727,5.47885403 2.79399727,5.69713506 2.92496589,5.82810369 L7.77080491,10.6521146 C7.90177353,10.7830832 8.12005456,10.7830832 8.25102319,10.6521146 L13.0750341,5.82810369 C13.2060027,5.69713506 13.2060027,5.47885403 13.0750341,5.34788541 Z"
|
|
361
|
+
stroke="#FFFFFF"
|
|
362
|
+
/>
|
|
363
|
+
</g>
|
|
364
|
+
</g>
|
|
365
|
+
</g>
|
|
366
|
+
</g>
|
|
367
|
+
</g>
|
|
368
|
+
</g>
|
|
369
|
+
</svg>
|
|
370
|
+
</span>
|
|
371
|
+
)}
|
|
372
|
+
<span className="tooltip-text">Color Picker</span>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
{showInput && (
|
|
377
|
+
<div className="color-picker-input-wrapper">
|
|
378
|
+
<input
|
|
379
|
+
type="text"
|
|
380
|
+
value={inputValue}
|
|
381
|
+
onChange={handleInputChange}
|
|
382
|
+
placeholder="Please input color"
|
|
383
|
+
/>
|
|
384
|
+
{inputValue && (
|
|
385
|
+
<span
|
|
386
|
+
className="input-clear-icon"
|
|
387
|
+
onClick={() => setInputValue("")}
|
|
388
|
+
>
|
|
389
|
+
<img
|
|
390
|
+
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAA8klEQVQ4T51SwVHDQAzcdQOETugAqISkg/Cw9CRf2Q+gAkwlJB1QimnAYnRz57m55AG5l2+9K632RFw44zg+ALiPX+5+FJFTS2MNmNme5AuATUOcARxE5L3gq9DMJpJPlxxU2CQiu7gnYe70mq19tgXcfcXc/VlV34pwJnkTBFXdDsOwBfCRO+1EZKoczSJyywjC3b8qO4mYxai+SyGQfKSZHXIg9XhJHEDTPXHC7vXCq63mVP8cjrv/qOrm7DkAxGyRan1qLM3/rwUoz7UuQCkdixCrFW9atwt7JPcl6TNhIUdgy7Lcxb3ruu++74/tKv4CNXed5xhXezYAAAAASUVORK5CYII="
|
|
391
|
+
alt=""
|
|
392
|
+
width="12"
|
|
393
|
+
height="12"
|
|
394
|
+
/>
|
|
395
|
+
</span>
|
|
396
|
+
)}
|
|
397
|
+
</div>
|
|
398
|
+
)}
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
{typeof document !== "undefined" &&
|
|
402
|
+
ReactDOM.createPortal(panel, document.body)}
|
|
403
|
+
|
|
404
|
+
<div>
|
|
405
|
+
<div className={`presets-grid modern`}>
|
|
406
|
+
{visiblePresets.map((preset, idx) => (
|
|
407
|
+
<div
|
|
408
|
+
key={idx}
|
|
409
|
+
className="preset-item"
|
|
410
|
+
style={{ backgroundColor: preset }}
|
|
411
|
+
onClick={() => {
|
|
412
|
+
const rgb = hexToRgb(preset);
|
|
413
|
+
if (rgb) {
|
|
414
|
+
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
415
|
+
handleChange({ ...hsv, a: 1 });
|
|
416
|
+
}
|
|
417
|
+
}}
|
|
418
|
+
title={preset}
|
|
419
|
+
/>
|
|
420
|
+
))}
|
|
421
|
+
</div>
|
|
422
|
+
{showExpand && (
|
|
423
|
+
<div
|
|
424
|
+
className="presets-collapse"
|
|
425
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
|
426
|
+
>
|
|
427
|
+
{isExpanded ? "Less" : "More"}
|
|
428
|
+
<span className={`collapse-arrow ${isExpanded ? "expanded" : ""}`}>
|
|
429
|
+
▼
|
|
430
|
+
</span>
|
|
431
|
+
</div>
|
|
432
|
+
)}
|
|
433
|
+
</div>
|
|
109
434
|
</div>
|
|
110
435
|
);
|
|
111
436
|
};
|