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