@designbasekorea/ui 0.2.29 → 0.2.30
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 +56 -62
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +56 -62
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +56 -62
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -5353,7 +5353,11 @@
|
|
|
5353
5353
|
gp = 0;
|
|
5354
5354
|
bp = x;
|
|
5355
5355
|
}
|
|
5356
|
-
return {
|
|
5356
|
+
return {
|
|
5357
|
+
r: Math.round((rp + m) * 255),
|
|
5358
|
+
g: Math.round((gp + m) * 255),
|
|
5359
|
+
b: Math.round((bp + m) * 255),
|
|
5360
|
+
};
|
|
5357
5361
|
};
|
|
5358
5362
|
const rgbToHsl = (r, g, b) => {
|
|
5359
5363
|
r /= 255;
|
|
@@ -5378,11 +5382,15 @@
|
|
|
5378
5382
|
}
|
|
5379
5383
|
h *= 60;
|
|
5380
5384
|
}
|
|
5381
|
-
return {
|
|
5385
|
+
return {
|
|
5386
|
+
h: Math.round(h * 100) / 100,
|
|
5387
|
+
s: Math.round(s * 10000) / 100,
|
|
5388
|
+
l: Math.round(l * 10000) / 100,
|
|
5389
|
+
};
|
|
5382
5390
|
};
|
|
5383
5391
|
/* ----------------------- 컴포넌트 ----------------------- */
|
|
5384
5392
|
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, }) => {
|
|
5385
|
-
/** 내부
|
|
5393
|
+
/** 내부 HSV + alpha */
|
|
5386
5394
|
const [h, setH] = React.useState(211);
|
|
5387
5395
|
const [s, setS] = React.useState(100);
|
|
5388
5396
|
const [v, setV] = React.useState(50);
|
|
@@ -5390,15 +5398,13 @@
|
|
|
5390
5398
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
5391
5399
|
const [format, setFormat] = React.useState('hex');
|
|
5392
5400
|
const [isCopied, setIsCopied] = React.useState(false);
|
|
5393
|
-
// 하단 인풋(문자열) — 엔터로만 확정
|
|
5394
5401
|
const [colorInput, setColorInput] = React.useState('');
|
|
5395
5402
|
const [alphaInput, setAlphaInput] = React.useState('100');
|
|
5396
|
-
// 모달용 임시 상태 (취소 시 되돌리기)
|
|
5397
5403
|
const [tempColor, setTempColor] = React.useState('');
|
|
5398
5404
|
const pickerRef = React.useRef(null);
|
|
5399
5405
|
const areaRef = React.useRef(null);
|
|
5400
5406
|
const dragging = React.useRef(false);
|
|
5401
|
-
/**
|
|
5407
|
+
/** 초기값 세팅 */
|
|
5402
5408
|
React.useEffect(() => {
|
|
5403
5409
|
const initial = (value || defaultValue).toUpperCase();
|
|
5404
5410
|
const rgb = hexToRgb(initial);
|
|
@@ -5408,12 +5414,10 @@
|
|
|
5408
5414
|
setS(s);
|
|
5409
5415
|
setV(v);
|
|
5410
5416
|
}
|
|
5411
|
-
// 인풋 초기 표현
|
|
5412
5417
|
setColorInput(initial);
|
|
5413
5418
|
setAlphaInput('100');
|
|
5414
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5415
5419
|
}, []);
|
|
5416
|
-
/**
|
|
5420
|
+
/** 제어형(value) → HSV */
|
|
5417
5421
|
React.useEffect(() => {
|
|
5418
5422
|
if (!value)
|
|
5419
5423
|
return;
|
|
@@ -5425,11 +5429,11 @@
|
|
|
5425
5429
|
setV(v);
|
|
5426
5430
|
}
|
|
5427
5431
|
}, [value]);
|
|
5428
|
-
/**
|
|
5432
|
+
/** RGB/HSL 계산 */
|
|
5429
5433
|
const rgb = React.useMemo(() => hsvToRgb(h, s, v), [h, s, v]);
|
|
5430
5434
|
const hex = React.useMemo(() => rgbToHex(rgb.r, rgb.g, rgb.b), [rgb]);
|
|
5431
5435
|
const hsl = React.useMemo(() => rgbToHsl(rgb.r, rgb.g, rgb.b), [rgb]);
|
|
5432
|
-
/**
|
|
5436
|
+
/** 출력값 formatted */
|
|
5433
5437
|
const formatted = React.useMemo(() => {
|
|
5434
5438
|
const alpha = a / 100;
|
|
5435
5439
|
switch (format) {
|
|
@@ -5441,22 +5445,24 @@
|
|
|
5441
5445
|
default: return hex;
|
|
5442
5446
|
}
|
|
5443
5447
|
}, [format, hex, rgb, hsl, a]);
|
|
5444
|
-
/**
|
|
5448
|
+
/** ✅ 무한 루프 방지: formatted이 부모 value랑 같으면 onChange 호출하지 않음 */
|
|
5445
5449
|
React.useEffect(() => {
|
|
5450
|
+
if (value !== undefined && value.toUpperCase() === formatted.toUpperCase())
|
|
5451
|
+
return;
|
|
5446
5452
|
onChange?.(formatted);
|
|
5447
|
-
|
|
5448
|
-
}, [formatted]);
|
|
5453
|
+
}, [formatted, onChange, value]);
|
|
5449
5454
|
/** 드롭다운 외부 클릭 닫기 */
|
|
5450
5455
|
React.useEffect(() => {
|
|
5451
5456
|
const handler = (e) => {
|
|
5452
|
-
if (pickerRef.current && !pickerRef.current.contains(e.target))
|
|
5457
|
+
if (pickerRef.current && !pickerRef.current.contains(e.target)) {
|
|
5453
5458
|
setIsOpen(false);
|
|
5459
|
+
}
|
|
5454
5460
|
};
|
|
5455
5461
|
if (isOpen && type === 'dropdown')
|
|
5456
5462
|
document.addEventListener('mousedown', handler);
|
|
5457
5463
|
return () => document.removeEventListener('mousedown', handler);
|
|
5458
5464
|
}, [isOpen, type]);
|
|
5459
|
-
/**
|
|
5465
|
+
/** S/V 영역 업데이트 */
|
|
5460
5466
|
const updateFromArea = (clientX, clientY) => {
|
|
5461
5467
|
const el = areaRef.current;
|
|
5462
5468
|
if (!el)
|
|
@@ -5483,12 +5489,11 @@
|
|
|
5483
5489
|
const onAlphaChange = React.useCallback((e) => {
|
|
5484
5490
|
const newAlpha = parseInt(e.target.value, 10);
|
|
5485
5491
|
setA(newAlpha);
|
|
5486
|
-
setAlphaInput(String(newAlpha));
|
|
5492
|
+
setAlphaInput(String(newAlpha));
|
|
5487
5493
|
}, []);
|
|
5488
|
-
/** 컬러
|
|
5494
|
+
/** 컬러 인풋 (엔터 확정) */
|
|
5489
5495
|
const commitColorInput = React.useCallback(() => {
|
|
5490
5496
|
const str = colorInput.trim();
|
|
5491
|
-
// HEX (#RRGGBB)
|
|
5492
5497
|
if (/^#([0-9A-Fa-f]{6})$/.test(str)) {
|
|
5493
5498
|
const rgb = hexToRgb(str);
|
|
5494
5499
|
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
@@ -5498,7 +5503,6 @@
|
|
|
5498
5503
|
setColorInput(str.toUpperCase());
|
|
5499
5504
|
return;
|
|
5500
5505
|
}
|
|
5501
|
-
// rgb(r,g,b)
|
|
5502
5506
|
let m = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(str);
|
|
5503
5507
|
if (m) {
|
|
5504
5508
|
const r = clamp(parseInt(m[1], 10), 0, 255);
|
|
@@ -5511,7 +5515,6 @@
|
|
|
5511
5515
|
setColorInput(`rgb(${r}, ${g}, ${b})`.toUpperCase());
|
|
5512
5516
|
return;
|
|
5513
5517
|
}
|
|
5514
|
-
// rgba(r,g,b,a)
|
|
5515
5518
|
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);
|
|
5516
5519
|
if (m) {
|
|
5517
5520
|
const r = clamp(parseInt(m[1], 10), 0, 255);
|
|
@@ -5527,18 +5530,14 @@
|
|
|
5527
5530
|
setColorInput(`rgba(${r}, ${g}, ${b}, ${alpha})`.toUpperCase());
|
|
5528
5531
|
return;
|
|
5529
5532
|
}
|
|
5530
|
-
// 잘못된 값 → 원복
|
|
5531
5533
|
setColorInput(formatted.toUpperCase());
|
|
5532
5534
|
}, [colorInput, formatted]);
|
|
5533
5535
|
const onColorKeyDown = (e) => {
|
|
5534
5536
|
if (e.key === 'Enter')
|
|
5535
5537
|
commitColorInput();
|
|
5536
5538
|
};
|
|
5537
|
-
const onColorBlur = () =>
|
|
5538
|
-
|
|
5539
|
-
setColorInput(formatted.toUpperCase());
|
|
5540
|
-
};
|
|
5541
|
-
/** 알파 인풋: 엔터로만 확정 (0~100) */
|
|
5539
|
+
const onColorBlur = () => setColorInput(formatted.toUpperCase());
|
|
5540
|
+
/** 알파 인풋 (엔터 확정) */
|
|
5542
5541
|
const commitAlphaInput = React.useCallback(() => {
|
|
5543
5542
|
const n = Number(alphaInput.trim());
|
|
5544
5543
|
if (!Number.isNaN(n) && n >= 0 && n <= 100) {
|
|
@@ -5546,17 +5545,13 @@
|
|
|
5546
5545
|
setAlphaInput(String(Math.round(n)));
|
|
5547
5546
|
return;
|
|
5548
5547
|
}
|
|
5549
|
-
// 잘못된 값 → 원복
|
|
5550
5548
|
setAlphaInput(String(a));
|
|
5551
5549
|
}, [alphaInput, a]);
|
|
5552
5550
|
const onAlphaInputKeyDown = (e) => {
|
|
5553
5551
|
if (e.key === 'Enter')
|
|
5554
5552
|
commitAlphaInput();
|
|
5555
5553
|
};
|
|
5556
|
-
const onAlphaInputBlur = () =>
|
|
5557
|
-
// 엔터로만 반영, 블러 시 원복
|
|
5558
|
-
setAlphaInput(String(a));
|
|
5559
|
-
};
|
|
5554
|
+
const onAlphaInputBlur = () => setAlphaInput(String(a));
|
|
5560
5555
|
/** 복사 */
|
|
5561
5556
|
const onCopy = React.useCallback(async () => {
|
|
5562
5557
|
try {
|
|
@@ -5580,18 +5575,15 @@
|
|
|
5580
5575
|
setS(hsv.s);
|
|
5581
5576
|
setV(hsv.v);
|
|
5582
5577
|
}
|
|
5583
|
-
else {
|
|
5584
|
-
console.log('EyeDropper API is not supported');
|
|
5585
|
-
}
|
|
5586
5578
|
}
|
|
5587
5579
|
catch (e) {
|
|
5588
5580
|
console.error(e);
|
|
5589
5581
|
}
|
|
5590
5582
|
}, []);
|
|
5591
|
-
/**
|
|
5583
|
+
/** modal open(중요: formatted deps 제거) */
|
|
5592
5584
|
const handleModalOpen = React.useCallback(() => {
|
|
5593
5585
|
if (type === 'modal')
|
|
5594
|
-
setTempColor(hex);
|
|
5586
|
+
setTempColor(hex);
|
|
5595
5587
|
setIsOpen(true);
|
|
5596
5588
|
}, [type, hex]);
|
|
5597
5589
|
const handleModalApply = React.useCallback(() => {
|
|
@@ -5604,53 +5596,55 @@
|
|
|
5604
5596
|
if (type === 'modal') {
|
|
5605
5597
|
const rgb = hexToRgb(tempColor);
|
|
5606
5598
|
if (rgb) {
|
|
5607
|
-
const
|
|
5608
|
-
setH(h);
|
|
5609
|
-
setS(s);
|
|
5610
|
-
setV(v);
|
|
5599
|
+
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
5600
|
+
setH(hsv.h);
|
|
5601
|
+
setS(hsv.s);
|
|
5602
|
+
setV(hsv.v);
|
|
5611
5603
|
}
|
|
5612
5604
|
onCancel?.();
|
|
5613
5605
|
setIsOpen(false);
|
|
5614
5606
|
}
|
|
5615
5607
|
}, [type, tempColor, onCancel]);
|
|
5616
|
-
/**
|
|
5608
|
+
/** 스타일 */
|
|
5617
5609
|
const hueTrackStyle = React.useMemo(() => ({
|
|
5618
5610
|
background: `linear-gradient(to right,
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5611
|
+
hsl(0,100%,50%),
|
|
5612
|
+
hsl(60,100%,50%),
|
|
5613
|
+
hsl(120,100%,50%),
|
|
5614
|
+
hsl(180,100%,50%),
|
|
5615
|
+
hsl(240,100%,50%),
|
|
5616
|
+
hsl(300,100%,50%),
|
|
5617
|
+
hsl(360,100%,50%))`,
|
|
5626
5618
|
}), []);
|
|
5627
|
-
// 상단 좌→우: 채도 증가 / 상단→하단: 밝기 감소
|
|
5628
5619
|
const areaBackground = React.useMemo(() => ({
|
|
5629
5620
|
backgroundImage: `
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5621
|
+
linear-gradient(to top, rgba(0,0,0,1), rgba(0,0,0,0)),
|
|
5622
|
+
linear-gradient(to right, #ffffff, hsl(${h}, 100%, 50%))
|
|
5623
|
+
`,
|
|
5633
5624
|
}), [h]);
|
|
5634
|
-
// ✔ 고정 흑백 알파 트랙 (색상 무관)
|
|
5635
5625
|
const alphaTrackStyle = React.useMemo(() => ({
|
|
5636
5626
|
backgroundImage: `
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5627
|
+
linear-gradient(45deg, var(--db-border-base) 25%, transparent 25%),
|
|
5628
|
+
linear-gradient(-45deg, var(--db-border-base) 25%, transparent 25%),
|
|
5629
|
+
linear-gradient(45deg, transparent 75%, var(--db-border-base) 75%),
|
|
5630
|
+
linear-gradient(-45deg, transparent 75%, var(--db-border-base) 75%),
|
|
5631
|
+
linear-gradient(to right, rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0), rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 1))
|
|
5632
|
+
`,
|
|
5643
5633
|
backgroundSize: '8px 8px,8px 8px,8px 8px,8px 8px,100% 100%',
|
|
5644
5634
|
backgroundPosition: '0 0,0 4px,4px -4px,-4px 0,0 0',
|
|
5645
5635
|
backgroundColor: 'var(--db-surface-base)',
|
|
5646
|
-
}), []);
|
|
5636
|
+
}), [rgb]);
|
|
5647
5637
|
const classes = clsx('designbase-color-picker', `designbase-color-picker--${size}`, `designbase-color-picker--${position}`, {
|
|
5648
5638
|
'designbase-color-picker--disabled': disabled,
|
|
5649
5639
|
'designbase-color-picker--readonly': readonly,
|
|
5650
5640
|
'designbase-color-picker--open': isOpen,
|
|
5651
5641
|
'designbase-color-picker--no-input': !showInput,
|
|
5652
5642
|
}, className);
|
|
5653
|
-
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: {
|
|
5643
|
+
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: {
|
|
5644
|
+
backgroundColor: showAlpha
|
|
5645
|
+
? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${a / 100})`
|
|
5646
|
+
: hex
|
|
5647
|
+
} }) }), 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 }) })] }));
|
|
5654
5648
|
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: [
|
|
5655
5649
|
{ label: 'HEX', value: 'hex' },
|
|
5656
5650
|
{ label: 'RGB', value: 'rgb' },
|