@designbasekorea/ui 0.2.35 → 0.2.37

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/dist/index.esm.js CHANGED
@@ -5321,17 +5321,18 @@ Chip.displayName = 'Chip';
5321
5321
 
5322
5322
  /* ----------------------- 유틸 ----------------------- */
5323
5323
  const clamp = (n, min, max) => Math.max(min, Math.min(max, n));
5324
+ const normalizeHex = (s) => (s || '').trim().toUpperCase();
5325
+ const isHex = (s) => /^#?[0-9A-Fa-f]{6}$/.test(s || '');
5324
5326
  const hexToRgb = (hex) => {
5325
5327
  const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex.trim());
5326
5328
  if (!m)
5327
5329
  return null;
5328
5330
  return { r: parseInt(m[1], 16), g: parseInt(m[2], 16), b: parseInt(m[3], 16) };
5329
5331
  };
5330
- const rgbToHex = (r, g, b) => {
5331
- const toHex = (n) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, '0');
5332
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
5332
+ const toHex = (r, g, b) => {
5333
+ const h = (x) => clamp(Math.round(x), 0, 255).toString(16).padStart(2, '0');
5334
+ return `#${h(r)}${h(g)}${h(b)}`.toUpperCase();
5333
5335
  };
5334
- /** RGB ↔ HSV (HSV: h[0-360], s[0-100], v[0-100]) */
5335
5336
  const rgbToHsv = (r, g, b) => {
5336
5337
  r /= 255;
5337
5338
  g /= 255;
@@ -5355,7 +5356,7 @@ const rgbToHsv = (r, g, b) => {
5355
5356
  }
5356
5357
  const s = max === 0 ? 0 : d / max;
5357
5358
  const v = max;
5358
- return { h: Math.round(h * 100) / 100, s: Math.round(s * 10000) / 100, v: Math.round(v * 10000) / 100 };
5359
+ return { h, s: s * 100, v: v * 100 };
5359
5360
  };
5360
5361
  const hsvToRgb = (h, s, v) => {
5361
5362
  s /= 100;
@@ -5423,92 +5424,151 @@ const rgbToHsl = (r, g, b) => {
5423
5424
  }
5424
5425
  h *= 60;
5425
5426
  }
5426
- return {
5427
- h: Math.round(h * 100) / 100,
5428
- s: Math.round(s * 10000) / 100,
5429
- l: Math.round(l * 10000) / 100,
5430
- };
5427
+ return { h, s: s * 100, l: l * 100 };
5431
5428
  };
5432
5429
  /* ----------------------- 컴포넌트 ----------------------- */
5433
- const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left', value, defaultValue = '#006FFF', showInput = true, showAlpha = true, showFormatSelector = true, showCopyButton = true, disabled = false, readonly = false, onChange, onApply, onCancel, className, }) => {
5434
- /** 내부 HSV + alpha */
5435
- const [h, setH] = useState(211);
5436
- const [s, setS] = useState(100);
5437
- const [v, setV] = useState(50);
5430
+ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left', value, defaultValue = '#006FFF', showInput = true, showAlpha = true, showFormatSelector = true, showCopyButton = true, showEyedropper = true, disabled = false, readonly = false, onChangeFormat = 'hex', fireOnInit = false, changeDebounceMs = 0, emitDuringDrag = true, onChange, onApply, onCancel, className, }) => {
5431
+ /** 초기 HSV StrictMode에서도 안전하도록 lazy init */
5432
+ const initialHex = (isHex(value) ? normalizeHex(value) : normalizeHex(defaultValue)) || '#006FFF';
5433
+ const initialRgb = hexToRgb(initialHex) || { r: 0, g: 111, b: 255 };
5434
+ const initialHsv = rgbToHsv(initialRgb.r, initialRgb.g, initialRgb.b);
5435
+ const [h, setH] = useState(() => initialHsv.h);
5436
+ const [s, setS] = useState(() => initialHsv.s);
5437
+ const [v, setV] = useState(() => initialHsv.v);
5438
5438
  const [a, setA] = useState(100);
5439
5439
  const [isOpen, setIsOpen] = useState(false);
5440
5440
  const [format, setFormat] = useState('hex');
5441
5441
  const [isCopied, setIsCopied] = useState(false);
5442
- const [colorInput, setColorInput] = useState('');
5442
+ const [colorInput, setColorInput] = useState(() => initialHex);
5443
5443
  const [alphaInput, setAlphaInput] = useState('100');
5444
5444
  const [tempColor, setTempColor] = useState('');
5445
5445
  const pickerRef = useRef(null);
5446
5446
  const areaRef = useRef(null);
5447
+ /** 드래그 상태/자체 발사 억제 */
5447
5448
  const dragging = useRef(false);
5448
- /** 초기값 세팅 */
5449
- useEffect(() => {
5450
- const initial = (value || defaultValue).toUpperCase();
5451
- const rgb = hexToRgb(initial);
5452
- if (rgb) {
5453
- const { h, s, v } = rgbToHsv(rgb.r, rgb.g, rgb.b);
5454
- setH(h);
5455
- setS(s);
5456
- setV(v);
5457
- }
5458
- setColorInput(initial);
5459
- setAlphaInput('100');
5460
- }, []);
5461
- /** 제어형(value) → HSV */
5449
+ const didMountRef = useRef(false);
5450
+ const lastEmittedHexRef = useRef(initialHex);
5451
+ const suppressNextValueSyncRef = useRef(false);
5452
+ const emitErrorCountRef = useRef(0);
5453
+ const emitBlockedUntilRef = useRef(0);
5454
+ const debounceTimerRef = useRef(null);
5455
+ /** 외부 value 변화 → 내부 HSV 반영(자기 발사 직후는 무시 가능) */
5462
5456
  useEffect(() => {
5463
- if (!value)
5457
+ if (value == null)
5458
+ return;
5459
+ const norm = normalizeHex(value);
5460
+ if (!isHex(norm))
5461
+ return;
5462
+ // 자기 자신이 방금 보낸 값이면 동기화 스킵(미세 진동 방지)
5463
+ if (suppressNextValueSyncRef.current && norm === lastEmittedHexRef.current) {
5464
+ suppressNextValueSyncRef.current = false;
5464
5465
  return;
5465
- const rgb = hexToRgb(value);
5466
- if (rgb) {
5467
- const { h, s, v } = rgbToHsv(rgb.r, rgb.g, rgb.b);
5468
- setH(h);
5469
- setS(s);
5470
- setV(v);
5471
5466
  }
5467
+ const rgb = hexToRgb(norm);
5468
+ if (!rgb)
5469
+ return;
5470
+ const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
5471
+ setH(hsv.h);
5472
+ setS(hsv.s);
5473
+ setV(hsv.v);
5474
+ setColorInput(norm);
5472
5475
  }, [value]);
5473
- /** RGB/HSL 계산 */
5476
+ /** 파생값 */
5474
5477
  const rgb = useMemo(() => hsvToRgb(h, s, v), [h, s, v]);
5475
- const hex = useMemo(() => rgbToHex(rgb.r, rgb.g, rgb.b), [rgb]);
5478
+ const hex = useMemo(() => toHex(rgb.r, rgb.g, rgb.b), [rgb]);
5476
5479
  const hsl = useMemo(() => rgbToHsl(rgb.r, rgb.g, rgb.b), [rgb]);
5477
- /** 출력값 formatted */
5478
- const formatted = useMemo(() => {
5480
+ /** 표시 문자열(UI 포맷) */
5481
+ const uiFormatted = useMemo(() => {
5479
5482
  const alpha = a / 100;
5480
5483
  switch (format) {
5481
5484
  case 'hex': return hex;
5482
5485
  case 'rgb': return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
5483
5486
  case 'rgba': return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha.toFixed(2)})`;
5484
- case 'hsl': return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
5485
- case 'hsla': return `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${alpha.toFixed(2)})`;
5487
+ case 'hsl': return `hsl(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%)`;
5488
+ case 'hsla': return `hsla(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%, ${alpha.toFixed(2)})`;
5486
5489
  default: return hex;
5487
5490
  }
5488
5491
  }, [format, hex, rgb, hsl, a]);
5489
- /** 무한 루프 방지: formatted이 부모 value랑 같으면 onChange 호출하지 않음 */
5492
+ /** 바깥으로 내보낼 문자열 */
5493
+ const outward = useMemo(() => (onChangeFormat === 'hex' ? hex : uiFormatted), [hex, uiFormatted, onChangeFormat]);
5494
+ /** colorInput(표시 전용) 동기화 — 순수 표시만, 포커스 중이면 건드리지 않는 게 안전하지만 간단히 비교 후 반영 */
5490
5495
  useEffect(() => {
5491
- if (value !== undefined && value.toUpperCase() === formatted.toUpperCase())
5492
- return;
5493
- onChange?.(formatted);
5496
+ const next = format === 'hex' ? normalizeHex(uiFormatted) : uiFormatted;
5497
+ if (colorInput !== next)
5498
+ setColorInput(next);
5494
5499
  // eslint-disable-next-line react-hooks/exhaustive-deps
5495
- }, [formatted]); // onChange와 value를 의존성에서 제거
5496
- /** formatted 변경시 colorInput 동기화 */
5497
- useEffect(() => {
5498
- setColorInput(formatted.toUpperCase());
5499
- }, [formatted]);
5500
+ }, [uiFormatted, format]);
5500
5501
  /** 드롭다운 외부 클릭 닫기 */
5501
5502
  useEffect(() => {
5502
5503
  const handler = (e) => {
5503
- if (pickerRef.current && !pickerRef.current.contains(e.target)) {
5504
+ if (pickerRef.current && !pickerRef.current.contains(e.target))
5504
5505
  setIsOpen(false);
5505
- }
5506
5506
  };
5507
5507
  if (isOpen && type === 'dropdown')
5508
5508
  document.addEventListener('mousedown', handler);
5509
5509
  return () => document.removeEventListener('mousedown', handler);
5510
5510
  }, [isOpen, type]);
5511
- /** S/V 영역 업데이트 */
5511
+ /** ===== onChange 발사 컨트롤러 ===== */
5512
+ const actuallyEmit = useCallback(() => {
5513
+ if (!onChange)
5514
+ return;
5515
+ const now = Date.now();
5516
+ if (emitBlockedUntilRef.current > now)
5517
+ return;
5518
+ const currentHex = normalizeHex(hex);
5519
+ const parentHex = isHex(value) ? normalizeHex(value) : null;
5520
+ // 부모값과 동치면 발사 금지
5521
+ if (parentHex && parentHex === currentHex)
5522
+ return;
5523
+ // 직전 발사와 동일하면 발사 금지
5524
+ if (lastEmittedHexRef.current === currentHex)
5525
+ return;
5526
+ try {
5527
+ lastEmittedHexRef.current = currentHex;
5528
+ suppressNextValueSyncRef.current = true; // 다음 value 동기화 스킵(왕복 진동 방지)
5529
+ onChange(onChangeFormat === 'hex' ? currentHex : outward);
5530
+ emitErrorCountRef.current = 0;
5531
+ }
5532
+ catch {
5533
+ emitErrorCountRef.current += 1;
5534
+ if (emitErrorCountRef.current >= 20) {
5535
+ emitBlockedUntilRef.current = Date.now() + 3000;
5536
+ console.warn('[ColorPicker] onChange errors too frequent; temporarily muted.');
5537
+ }
5538
+ }
5539
+ }, [hex, outward, onChange, onChangeFormat, value]);
5540
+ /** 변경 감지 → 발사(드래그 중 정책 + 디바운스 반영) */
5541
+ useEffect(() => {
5542
+ // 첫 렌더
5543
+ if (!didMountRef.current) {
5544
+ didMountRef.current = true;
5545
+ if (!fireOnInit)
5546
+ return;
5547
+ }
5548
+ // 드래그 중이면 정책 적용
5549
+ if (dragging.current && !emitDuringDrag) {
5550
+ // 드래그 끝에서 발사하므로 지금은 무시
5551
+ return;
5552
+ }
5553
+ if (!onChange)
5554
+ return;
5555
+ if (changeDebounceMs > 0) {
5556
+ if (debounceTimerRef.current)
5557
+ window.clearTimeout(debounceTimerRef.current);
5558
+ debounceTimerRef.current = window.setTimeout(() => {
5559
+ actuallyEmit();
5560
+ }, changeDebounceMs);
5561
+ return () => {
5562
+ if (debounceTimerRef.current)
5563
+ window.clearTimeout(debounceTimerRef.current);
5564
+ };
5565
+ }
5566
+ else {
5567
+ actuallyEmit();
5568
+ }
5569
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5570
+ }, [hex, a, format]); // h/s/v → hex로 수렴됨. a/format도 외부로 나갈 수 있으니 포함.
5571
+ /** ===== SV 영역 ===== */
5512
5572
  const updateFromArea = (clientX, clientY) => {
5513
5573
  const el = areaRef.current;
5514
5574
  if (!el)
@@ -5516,28 +5576,71 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5516
5576
  const rect = el.getBoundingClientRect();
5517
5577
  const x = clamp(clientX - rect.left, 0, rect.width);
5518
5578
  const y = clamp(clientY - rect.top, 0, rect.height);
5519
- const newS = Math.round((x / rect.width) * 100);
5520
- const newV = Math.round(100 - (y / rect.height) * 100);
5579
+ const newS = (x / rect.width) * 100;
5580
+ const newV = 100 - (y / rect.height) * 100;
5581
+ // 소수점 그대로 보관 → 색 떨림 감소
5521
5582
  setS(newS);
5522
5583
  setV(newV);
5523
5584
  };
5524
- const onAreaMouseDown = (e) => { dragging.current = true; updateFromArea(e.clientX, e.clientY); };
5525
- const onAreaMouseMove = (e) => { if (dragging.current)
5526
- updateFromArea(e.clientX, e.clientY); };
5527
- const onAreaMouseUp = () => { dragging.current = false; };
5528
- const onAreaLeave = () => { dragging.current = false; };
5529
- const onAreaTouchStart = (e) => { dragging.current = true; const t = e.touches[0]; updateFromArea(t.clientX, t.clientY); };
5530
- const onAreaTouchMove = (e) => { if (!dragging.current)
5531
- return; const t = e.touches[0]; updateFromArea(t.clientX, t.clientY); };
5532
- const onAreaTouchEnd = () => { dragging.current = false; };
5585
+ const onAreaMouseDown = (e) => {
5586
+ if (disabled || readonly)
5587
+ return;
5588
+ dragging.current = true;
5589
+ updateFromArea(e.clientX, e.clientY);
5590
+ };
5591
+ const onAreaMouseMove = (e) => {
5592
+ if (!dragging.current || disabled || readonly)
5593
+ return;
5594
+ updateFromArea(e.clientX, e.clientY);
5595
+ };
5596
+ const finishDrag = () => {
5597
+ if (!dragging.current)
5598
+ return;
5599
+ dragging.current = false;
5600
+ // 드래그 종료 시 한 번만 발사
5601
+ if (!emitDuringDrag) {
5602
+ if (changeDebounceMs > 0) {
5603
+ if (debounceTimerRef.current)
5604
+ window.clearTimeout(debounceTimerRef.current);
5605
+ debounceTimerRef.current = window.setTimeout(() => {
5606
+ actuallyEmit();
5607
+ }, changeDebounceMs);
5608
+ }
5609
+ else {
5610
+ actuallyEmit();
5611
+ }
5612
+ }
5613
+ };
5614
+ const onAreaMouseUp = finishDrag;
5615
+ const onAreaLeave = finishDrag;
5616
+ const onAreaTouchStart = (e) => {
5617
+ if (disabled || readonly)
5618
+ return;
5619
+ dragging.current = true;
5620
+ const t = e.touches[0];
5621
+ updateFromArea(t.clientX, t.clientY);
5622
+ };
5623
+ const onAreaTouchMove = (e) => {
5624
+ if (!dragging.current || disabled || readonly)
5625
+ return;
5626
+ const t = e.touches[0];
5627
+ updateFromArea(t.clientX, t.clientY);
5628
+ };
5629
+ const onAreaTouchEnd = finishDrag;
5533
5630
  /** 슬라이더 */
5534
- const onHueChange = useCallback((e) => setH(parseInt(e.target.value, 10)), []);
5631
+ const onHueChange = useCallback((e) => {
5632
+ if (disabled || readonly)
5633
+ return;
5634
+ setH(parseFloat(e.target.value));
5635
+ }, [disabled, readonly]);
5535
5636
  const onAlphaChange = useCallback((e) => {
5637
+ if (disabled || readonly)
5638
+ return;
5536
5639
  const newAlpha = parseInt(e.target.value, 10);
5537
5640
  setA(newAlpha);
5538
5641
  setAlphaInput(String(newAlpha));
5539
- }, []);
5540
- /** 컬러 인풋 (엔터 확정) */
5642
+ }, [disabled, readonly]);
5643
+ /** 입력 확정 */
5541
5644
  const commitColorInput = useCallback(() => {
5542
5645
  const str = colorInput.trim();
5543
5646
  if (/^#([0-9A-Fa-f]{6})$/.test(str)) {
@@ -5546,7 +5649,7 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5546
5649
  setH(hsv.h);
5547
5650
  setS(hsv.s);
5548
5651
  setV(hsv.v);
5549
- setColorInput(str.toUpperCase());
5652
+ setColorInput(normalizeHex(str));
5550
5653
  return;
5551
5654
  }
5552
5655
  let m = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(str);
@@ -5558,7 +5661,7 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5558
5661
  setH(hsv.h);
5559
5662
  setS(hsv.s);
5560
5663
  setV(hsv.v);
5561
- setColorInput(`rgb(${r}, ${g}, ${b})`.toUpperCase());
5664
+ setColorInput(`rgb(${r}, ${g}, ${b})`);
5562
5665
  return;
5563
5666
  }
5564
5667
  m = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0?\.\d+)\s*\)$/i.exec(str);
@@ -5573,42 +5676,49 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5573
5676
  setV(hsv.v);
5574
5677
  setA(Math.round(alpha * 100));
5575
5678
  setAlphaInput(String(Math.round(alpha * 100)));
5576
- setColorInput(`rgba(${r}, ${g}, ${b}, ${alpha})`.toUpperCase());
5577
- return;
5578
- }
5579
- setColorInput(formatted.toUpperCase());
5580
- }, [colorInput, formatted]);
5581
- const onColorKeyDown = (e) => {
5582
- if (e.key === 'Enter')
5583
- commitColorInput();
5584
- };
5585
- const onColorBlur = () => setColorInput(formatted.toUpperCase());
5586
- /** 알파 인풋 (엔터 확정) */
5679
+ setColorInput(`rgba(${r}, ${g}, ${b}, ${alpha})`);
5680
+ return;
5681
+ }
5682
+ // 인식 실패 → 표시값으로 원복
5683
+ const next = format === 'hex' ? normalizeHex(uiFormatted) : uiFormatted;
5684
+ if (colorInput !== next)
5685
+ setColorInput(next);
5686
+ }, [colorInput, uiFormatted, format]);
5687
+ const onColorKeyDown = (e) => { if (e.key === 'Enter')
5688
+ commitColorInput(); };
5689
+ const onColorBlur = () => {
5690
+ const next = format === 'hex' ? normalizeHex(uiFormatted) : uiFormatted;
5691
+ if (colorInput !== next)
5692
+ setColorInput(next);
5693
+ };
5694
+ /** 알파 입력 확정 */
5587
5695
  const commitAlphaInput = useCallback(() => {
5588
5696
  const n = Number(alphaInput.trim());
5589
5697
  if (!Number.isNaN(n) && n >= 0 && n <= 100) {
5590
- setA(Math.round(n));
5591
- setAlphaInput(String(Math.round(n)));
5698
+ const rounded = Math.round(n);
5699
+ if (a !== rounded)
5700
+ setA(rounded);
5701
+ if (alphaInput !== String(rounded))
5702
+ setAlphaInput(String(rounded));
5592
5703
  return;
5593
5704
  }
5594
5705
  setAlphaInput(String(a));
5595
5706
  }, [alphaInput, a]);
5596
- const onAlphaInputKeyDown = (e) => {
5597
- if (e.key === 'Enter')
5598
- commitAlphaInput();
5599
- };
5600
- const onAlphaInputBlur = () => setAlphaInput(String(a));
5707
+ const onAlphaInputKeyDown = (e) => { if (e.key === 'Enter')
5708
+ commitAlphaInput(); };
5709
+ const onAlphaInputBlur = () => { if (alphaInput !== String(a))
5710
+ setAlphaInput(String(a)); };
5601
5711
  /** 복사 */
5602
5712
  const onCopy = useCallback(async () => {
5603
5713
  try {
5604
- await navigator.clipboard.writeText(formatted);
5714
+ await navigator.clipboard.writeText(uiFormatted);
5605
5715
  setIsCopied(true);
5606
5716
  setTimeout(() => setIsCopied(false), 1600);
5607
5717
  }
5608
5718
  catch (e) {
5609
5719
  console.error(e);
5610
5720
  }
5611
- }, [formatted]);
5721
+ }, [uiFormatted]);
5612
5722
  /** EyeDropper */
5613
5723
  const onEyedrop = useCallback(async () => {
5614
5724
  try {
@@ -5626,7 +5736,8 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5626
5736
  console.error(e);
5627
5737
  }
5628
5738
  }, []);
5629
- /** modal open(중요: formatted deps 제거) */
5739
+ const isEyedropperAvailable = typeof window !== 'undefined' && 'EyeDropper' in window;
5740
+ /** 모달 */
5630
5741
  const handleModalOpen = useCallback(() => {
5631
5742
  if (type === 'modal')
5632
5743
  setTempColor(hex);
@@ -5634,10 +5745,11 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5634
5745
  }, [type, hex]);
5635
5746
  const handleModalApply = useCallback(() => {
5636
5747
  if (type === 'modal') {
5637
- onApply?.(formatted);
5748
+ const out = onChangeFormat === 'hex' ? hex : uiFormatted;
5749
+ onApply?.(out);
5638
5750
  setIsOpen(false);
5639
5751
  }
5640
- }, [type, formatted, onApply]);
5752
+ }, [type, hex, uiFormatted, onApply, onChangeFormat]);
5641
5753
  const handleModalCancel = useCallback(() => {
5642
5754
  if (type === 'modal') {
5643
5755
  const rgb = hexToRgb(tempColor);
@@ -5654,28 +5766,28 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5654
5766
  /** 스타일 */
5655
5767
  const hueTrackStyle = useMemo(() => ({
5656
5768
  background: `linear-gradient(to right,
5657
- hsl(0,100%,50%),
5658
- hsl(60,100%,50%),
5659
- hsl(120,100%,50%),
5660
- hsl(180,100%,50%),
5661
- hsl(240,100%,50%),
5662
- hsl(300,100%,50%),
5663
- hsl(360,100%,50%))`,
5769
+ hsl(0,100%,50%),
5770
+ hsl(60,100%,50%),
5771
+ hsl(120,100%,50%),
5772
+ hsl(180,100%,50%),
5773
+ hsl(240,100%,50%),
5774
+ hsl(300,100%,50%),
5775
+ hsl(360,100%,50%))`,
5664
5776
  }), []);
5665
5777
  const areaBackground = useMemo(() => ({
5666
5778
  backgroundImage: `
5667
- linear-gradient(to top, rgba(0,0,0,1), rgba(0,0,0,0)),
5668
- linear-gradient(to right, #ffffff, hsl(${h}, 100%, 50%))
5669
- `,
5779
+ linear-gradient(to top, rgba(0,0,0,1), rgba(0,0,0,0)),
5780
+ linear-gradient(to right, #ffffff, hsl(${h}, 100%, 50%))
5781
+ `,
5670
5782
  }), [h]);
5671
5783
  const alphaTrackStyle = useMemo(() => ({
5672
5784
  backgroundImage: `
5673
- linear-gradient(45deg, var(--db-border-base) 25%, transparent 25%),
5674
- linear-gradient(-45deg, var(--db-border-base) 25%, transparent 25%),
5675
- linear-gradient(45deg, transparent 75%, var(--db-border-base) 75%),
5676
- linear-gradient(-45deg, transparent 75%, var(--db-border-base) 75%),
5677
- linear-gradient(to right, rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0), rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 1))
5678
- `,
5785
+ linear-gradient(45deg, var(--db-border-base) 25%, transparent 25%),
5786
+ linear-gradient(-45deg, var(--db-border-base) 25%, transparent 25%),
5787
+ linear-gradient(45deg, transparent 75%, var(--db-border-base) 75%),
5788
+ linear-gradient(-45deg, transparent 75%, var(--db-border-base) 75%),
5789
+ linear-gradient(to right, rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0), rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 1))
5790
+ `,
5679
5791
  backgroundSize: '8px 8px,8px 8px,8px 8px,8px 8px,100% 100%',
5680
5792
  backgroundPosition: '0 0,0 4px,4px -4px,-4px 0,0 0',
5681
5793
  backgroundColor: 'var(--db-surface-base)',
@@ -5687,11 +5799,9 @@ const ColorPicker = ({ size = 'm', type = 'dropdown', position = 'bottom-left',
5687
5799
  'designbase-color-picker--no-input': !showInput,
5688
5800
  }, className);
5689
5801
  const Trigger = (jsxs("div", { className: "designbase-color-picker__trigger", onClick: () => !disabled && !readonly && (type === 'modal' ? handleModalOpen() : setIsOpen(v => !v)), children: [jsx("div", { className: "designbase-color-picker__color-display", children: jsx("div", { className: "designbase-color-picker__color-box", style: {
5690
- backgroundColor: showAlpha
5691
- ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${a / 100})`
5692
- : hex
5802
+ backgroundColor: showAlpha ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${a / 100})` : hex
5693
5803
  } }) }), showInput && (jsx("input", { type: "text", value: colorInput, onChange: (e) => setColorInput(e.target.value), onKeyDown: onColorKeyDown, onBlur: onColorBlur, onClick: (e) => e.stopPropagation(), disabled: disabled, readOnly: readonly, className: "designbase-color-picker__input", placeholder: "#000000" })), showInput && showCopyButton && (jsx("button", { type: "button", className: "designbase-color-picker__copy-button-inline", onClick: (e) => { e.stopPropagation(); onCopy(); }, disabled: disabled, "aria-label": "Copy color value", children: isCopied ? jsx(DoneIcon$1, { size: 14 }) : jsx(CopyIcon, { size: 14 }) })), jsx("button", { type: "button", className: "designbase-color-picker__toggle", disabled: disabled, "aria-label": "Toggle color picker", children: jsx(ChevronDownIcon, { size: 16 }) })] }));
5694
- const Selector = (jsxs("div", { className: "designbase-color-picker__selector", children: [jsx("div", { className: "designbase-color-picker__color-area", children: jsx("div", { ref: areaRef, className: "designbase-color-picker__color-field", style: areaBackground, onMouseDown: onAreaMouseDown, onMouseMove: onAreaMouseMove, onMouseUp: onAreaMouseUp, onMouseLeave: onAreaLeave, onTouchStart: onAreaTouchStart, onTouchMove: onAreaTouchMove, onTouchEnd: onAreaTouchEnd, children: jsx("div", { className: "designbase-color-picker__color-pointer", style: { left: `${s}%`, top: `${100 - v}%`, backgroundColor: `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})` } }) }) }), jsxs("div", { className: "designbase-color-picker__controls", children: [jsx(Button, { variant: "tertiary", size: "m", iconOnly: true, onClick: onEyedrop, "aria-label": "Eyedropper tool", children: jsx(EyedropperIcon, {}) }), jsxs("div", { className: "designbase-color-picker__slider-container", children: [jsx("div", { className: "designbase-color-picker__hue-slider", children: jsx("input", { type: "range", min: 0, max: 360, value: h, onChange: onHueChange, className: "designbase-color-picker__slider designbase-color-picker__slider--hue", style: hueTrackStyle }) }), showAlpha && (jsx("div", { className: "designbase-color-picker__alpha-slider", children: jsx("input", { type: "range", min: 0, max: 100, value: a, onChange: onAlphaChange, className: "designbase-color-picker__slider designbase-color-picker__slider--alpha", style: alphaTrackStyle }) }))] })] }), jsxs("div", { className: "designbase-color-picker__value-display", children: [showFormatSelector && (jsx(Select, { value: format, onChange: (v) => setFormat(v), showClearButton: false, options: [
5804
+ const Selector = (jsxs("div", { className: "designbase-color-picker__selector", children: [jsx("div", { className: "designbase-color-picker__color-area", children: jsx("div", { ref: areaRef, className: "designbase-color-picker__color-field", style: areaBackground, onMouseDown: onAreaMouseDown, onMouseMove: onAreaMouseMove, onMouseUp: onAreaMouseUp, onMouseLeave: onAreaLeave, onTouchStart: onAreaTouchStart, onTouchMove: onAreaTouchMove, onTouchEnd: onAreaTouchEnd, children: jsx("div", { className: "designbase-color-picker__color-pointer", style: { left: `${s}%`, top: `${100 - v}%`, backgroundColor: `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})` } }) }) }), jsxs("div", { className: "designbase-color-picker__controls", children: [showEyedropper && isEyedropperAvailable && (jsx(Button, { variant: "tertiary", size: "m", iconOnly: true, onClick: onEyedrop, "aria-label": "Eyedropper tool", children: jsx(EyedropperIcon, {}) })), jsxs("div", { className: "designbase-color-picker__slider-container", children: [jsx("div", { className: "designbase-color-picker__hue-slider", children: jsx("input", { type: "range", min: 0, max: 360, value: h, onChange: onHueChange, className: "designbase-color-picker__slider designbase-color-picker__slider--hue", style: hueTrackStyle }) }), showAlpha && (jsx("div", { className: "designbase-color-picker__alpha-slider", children: jsx("input", { type: "range", min: 0, max: 100, value: a, onChange: onAlphaChange, className: "designbase-color-picker__slider designbase-color-picker__slider--alpha", style: alphaTrackStyle }) }))] })] }), jsxs("div", { className: "designbase-color-picker__value-display", children: [showFormatSelector && (jsx(Select, { value: format, onChange: (v) => setFormat(v), showClearButton: false, options: [
5695
5805
  { label: 'HEX', value: 'hex' },
5696
5806
  { label: 'RGB', value: 'rgb' },
5697
5807
  { label: 'RGBA', value: 'rgba' },