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