gdp-color-picker 1.1.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/src/lib/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import React, { useState, useRef, useEffect } from "react";
2
+ import ReactDOM from "react-dom";
2
3
  import ColorBoard from "./ColorBoard";
3
4
  import { HueSlider, AlphaSlider } from "./Sliders";
4
5
  import ColorInput from "./ColorInput";
@@ -108,18 +109,25 @@ const ColorPicker = ({
108
109
  };
109
110
 
110
111
  useEffect(() => {
111
- if (isOpen && containerRef.current && triggerRef.current) {
112
- const triggerRect = triggerRef.current.getBoundingClientRect();
113
- const containerRect = containerRef.current.getBoundingClientRect();
114
- const left = triggerRect.left - containerRect.left;
115
- const top = triggerRect.bottom - containerRect.top + 4;
116
- setPanelStyle({
117
- position: "absolute",
118
- top,
119
- left,
120
- zIndex: 1000,
121
- });
112
+ if (
113
+ !isOpen ||
114
+ !triggerRef.current ||
115
+ typeof window === "undefined" ||
116
+ typeof document === "undefined"
117
+ ) {
118
+ return;
122
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
+ });
123
131
  }, [isOpen]);
124
132
 
125
133
  const handleEyeDropper = async () => {
@@ -171,10 +179,143 @@ const ColorPicker = ({
171
179
 
172
180
  const rgb = hsvToRgb(color.h, color.s, color.v);
173
181
  const displayColor = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${color.a})`;
174
- const initialLimit = 28;
182
+ const initialLimit = 14;
175
183
  const visiblePresets = isExpanded ? presets : presets.slice(0, initialLimit);
176
184
  const showExpand = presets.length > initialLimit;
177
185
 
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",
195
+ }}
196
+ >
197
+ <ColorBoard
198
+ hue={color.h}
199
+ saturation={color.s}
200
+ value={color.v}
201
+ onChange={(s, v) => handleChange({ s, v })}
202
+ />
203
+ <HueSlider hue={color.h} onChange={(h) => handleChange({ h })} />
204
+ <AlphaSlider
205
+ alpha={color.a}
206
+ color={rgb}
207
+ onChange={(a) => handleChange({ a })}
208
+ />
209
+ <ColorInput
210
+ hue={color.h}
211
+ saturation={color.s}
212
+ value={color.v}
213
+ alpha={color.a}
214
+ onChange={(newHsv) => handleChange(newHsv)}
215
+ />
216
+ </div>
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
+
178
319
  return (
179
320
  <div className="color-picker-container" ref={containerRef}>
180
321
  <div className="color-picker-main-row">
@@ -193,12 +334,38 @@ const ColorPicker = ({
193
334
  {showArrow && (
194
335
  <span className={`color-picker-arrow ${isOpen ? "open" : ""}`}>
195
336
  <svg
196
- viewBox="0 0 1024 1024"
197
- width="12"
198
- height="12"
199
- fill="currentColor"
337
+ width="16"
338
+ height="16"
339
+ viewBox="0 0 16 16"
340
+ xmlns="http://www.w3.org/2000/svg"
200
341
  >
201
- <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" />
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>
202
369
  </svg>
203
370
  </span>
204
371
  )}
@@ -219,122 +386,21 @@ const ColorPicker = ({
219
386
  className="input-clear-icon"
220
387
  onClick={() => setInputValue("")}
221
388
  >
222
- ×
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
+ />
223
395
  </span>
224
396
  )}
225
397
  </div>
226
398
  )}
227
399
  </div>
228
400
 
229
- {isOpen && (
230
- <div
231
- className="color-picker-panel"
232
- style={panelStyle}
233
- >
234
- {showColorBoard && (
235
- <div
236
- className="color-picker-board-wrapper"
237
- style={{
238
- marginTop: "10px",
239
- paddingTop: "10px",
240
- borderTop: "1px solid #eee",
241
- }}
242
- >
243
- <ColorBoard
244
- hue={color.h}
245
- saturation={color.s}
246
- value={color.v}
247
- onChange={(s, v) => handleChange({ s, v })}
248
- />
249
- <HueSlider hue={color.h} onChange={(h) => handleChange({ h })} />
250
- <AlphaSlider
251
- alpha={color.a}
252
- color={rgb}
253
- onChange={(a) => handleChange({ a })}
254
- />
255
- <ColorInput
256
- hue={color.h}
257
- saturation={color.s}
258
- value={color.v}
259
- alpha={color.a}
260
- onChange={(newHsv) => handleChange(newHsv)}
261
- />
262
- </div>
263
- )}
264
- <div className="color-picker-presets">
265
- <div className="palette-section-title" style={{ marginTop: 8 }}>
266
- <span>Recommended</span>
267
- <span
268
- className="color-picker-icon-right"
269
- onClick={handleEyeDropper}
270
- title="屏幕取色"
271
- >
272
- <svg
273
- viewBox="0 0 1024 1024"
274
- width="12"
275
- height="12"
276
- fill="currentColor"
277
- >
278
- <path d="M512 192C320 192 170.7 320 96 512c74.7 192 224 320 416 320s341.3-128 416-320C853.3 320 704 192 512 192zm0 512c-105.9 0-192-86.1-192-192s86.1-192 192-192 192 86.1 192 192-86.1 192-192 192zm0-320a128 128 0 100 256 128 128 0 000-256z" />
279
- </svg>
280
- </span>
281
- </div>
282
- <div className={`presets-grid modern`}>
283
- {visiblePresets.map((preset, idx) => (
284
- <div
285
- key={idx}
286
- className="preset-item"
287
- style={{ backgroundColor: preset }}
288
- onClick={() => {
289
- const rgb = hexToRgb(preset);
290
- if (rgb) {
291
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
292
- handleChange({ ...hsv, a: 1 });
293
- }
294
- }}
295
- title={preset}
296
- />
297
- ))}
298
- </div>
299
- {showExpand && (
300
- <div
301
- className="presets-collapse"
302
- onClick={() => setIsExpanded(!isExpanded)}
303
- >
304
- {isExpanded ? "Less" : "More"}
305
- <span
306
- className={`collapse-arrow ${isExpanded ? "expanded" : ""}`}
307
- >
308
-
309
- </span>
310
- </div>
311
- )}
401
+ {typeof document !== "undefined" &&
402
+ ReactDOM.createPortal(panel, document.body)}
312
403
 
313
- {recentColors.length > 0 && (
314
- <>
315
- <div className="palette-section-title">Recent</div>
316
- <div className="presets-grid recent">
317
- {recentColors.map((color, idx) => (
318
- <div
319
- key={idx}
320
- className="preset-item"
321
- style={{ backgroundColor: color }}
322
- onClick={() => {
323
- const rgb = hexToRgb(color);
324
- if (rgb) {
325
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
326
- handleChange({ ...hsv, a: 1 });
327
- }
328
- }}
329
- title={color}
330
- />
331
- ))}
332
- </div>
333
- </>
334
- )}
335
- </div>
336
- </div>
337
- )}
338
404
  <div>
339
405
  <div className={`presets-grid modern`}>
340
406
  {visiblePresets.map((preset, idx) => (