@designbasekorea/ui 0.1.4 → 0.1.7
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.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.css.map +1 -1
- package/dist/index.esm.js +346 -233
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +345 -232
- package/dist/index.js.map +1 -1
- package/dist/index.umd.css +1 -1
- package/dist/index.umd.css.map +1 -1
- package/dist/index.umd.js +345 -232
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -3458,20 +3458,20 @@ const Spinner = ({ type = 'circular', size = 'm', color, speed = 1, label = '로
|
|
|
3458
3458
|
const renderSpinner = () => {
|
|
3459
3459
|
switch (type) {
|
|
3460
3460
|
case 'circular':
|
|
3461
|
-
return (jsxRuntimeExports.jsxs("svg", { className: "designbase-spinner__circular", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntimeExports.jsx("circle", { className: "designbase-spinner__circular-track", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2", fill: "none" }), jsxRuntimeExports.jsx("circle", { className: "designbase-spinner__circular-indicator", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2", fill: "none", strokeLinecap: "round" })] }));
|
|
3461
|
+
return (jsxRuntimeExports.jsxs("svg", { className: "designbase-spinner__circular", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [jsxRuntimeExports.jsx("circle", { className: "designbase-spinner__circular-track", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2", fill: "none" }), jsxRuntimeExports.jsx("circle", { className: "designbase-spinner__circular-indicator", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2", fill: "none", strokeLinecap: "round" })] }));
|
|
3462
3462
|
case 'dots':
|
|
3463
|
-
return (jsxRuntimeExports.jsxs("div", { className: "designbase-spinner__dots", children: [jsxRuntimeExports.jsx("div", { className: "designbase-spinner__dot" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__dot" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__dot" })] }));
|
|
3463
|
+
return (jsxRuntimeExports.jsxs("div", { className: "designbase-spinner__dots", "aria-hidden": "true", children: [jsxRuntimeExports.jsx("div", { className: "designbase-spinner__dot" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__dot" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__dot" })] }));
|
|
3464
3464
|
case 'bars':
|
|
3465
|
-
return (jsxRuntimeExports.jsxs("div", { className: "designbase-spinner__bars", children: [jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" })] }));
|
|
3465
|
+
return (jsxRuntimeExports.jsxs("div", { className: "designbase-spinner__bars", "aria-hidden": "true", children: [jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__bar" })] }));
|
|
3466
3466
|
case 'pulse':
|
|
3467
|
-
return
|
|
3467
|
+
return jsxRuntimeExports.jsx("div", { className: "designbase-spinner__pulse", "aria-hidden": "true" });
|
|
3468
3468
|
case 'ripple':
|
|
3469
|
-
return (jsxRuntimeExports.jsxs("div", { className: "designbase-spinner__ripple", children: [jsxRuntimeExports.jsx("div", { className: "designbase-spinner__ripple-circle" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__ripple-circle" })] }));
|
|
3469
|
+
return (jsxRuntimeExports.jsxs("div", { className: "designbase-spinner__ripple", "aria-hidden": "true", children: [jsxRuntimeExports.jsx("div", { className: "designbase-spinner__ripple-circle" }), jsxRuntimeExports.jsx("div", { className: "designbase-spinner__ripple-circle" })] }));
|
|
3470
3470
|
default:
|
|
3471
3471
|
return null;
|
|
3472
3472
|
}
|
|
3473
3473
|
};
|
|
3474
|
-
return (jsxRuntimeExports.jsxs("div", { className: classes, style: style, role: "status", "aria-label": showLabel ? label : undefined, ...props, children: [renderSpinner(), showLabel && label && (jsxRuntimeExports.jsx("span", { className: "designbase-spinner__label", "aria-hidden": "true", children: label }))] }));
|
|
3474
|
+
return (jsxRuntimeExports.jsxs("div", { className: classes, style: style, role: "status", "aria-live": "polite", "aria-busy": "true", "aria-label": showLabel ? label : undefined, ...props, children: [renderSpinner(), showLabel && label && (jsxRuntimeExports.jsx("span", { className: "designbase-spinner__label", "aria-hidden": "true", children: label }))] }));
|
|
3475
3475
|
};
|
|
3476
3476
|
Spinner.displayName = 'Spinner';
|
|
3477
3477
|
|
|
@@ -3657,7 +3657,7 @@ const Checkbox = React.forwardRef(({ isSelected, defaultSelected, isIndeterminat
|
|
|
3657
3657
|
});
|
|
3658
3658
|
Checkbox.displayName = 'Checkbox';
|
|
3659
3659
|
|
|
3660
|
-
const Toggle = React.forwardRef(({ isSelected, defaultSelected, isDisabled = false, isReadOnly = false,
|
|
3660
|
+
const Toggle = React.forwardRef(({ isSelected, defaultSelected, isDisabled = false, isReadOnly = false, size = 'm', children, className, onChange, ...props }, forwardedRef) => {
|
|
3661
3661
|
const [selected, setSelected] = React.useState(isSelected ?? defaultSelected ?? false);
|
|
3662
3662
|
React.useEffect(() => {
|
|
3663
3663
|
if (isSelected !== undefined) {
|
|
@@ -3675,9 +3675,9 @@ const Toggle = React.forwardRef(({ isSelected, defaultSelected, isDisabled = fal
|
|
|
3675
3675
|
'designbase-toggle--selected': selected,
|
|
3676
3676
|
'designbase-toggle--disabled': isDisabled,
|
|
3677
3677
|
'designbase-toggle--readonly': isReadOnly,
|
|
3678
|
-
'designbase-toggle--no-label': !
|
|
3678
|
+
'designbase-toggle--no-label': !children,
|
|
3679
3679
|
}, className);
|
|
3680
|
-
return (jsxRuntimeExports.jsxs("button", { ...props, ref: forwardedRef,
|
|
3680
|
+
return (jsxRuntimeExports.jsxs("button", { ...props, ref: forwardedRef, className: classes, onClick: handleClick, disabled: isDisabled, type: "button", children: [jsxRuntimeExports.jsx("div", { className: "designbase-toggle__track", children: jsxRuntimeExports.jsx("div", { className: "designbase-toggle__thumb" }) }), children && jsxRuntimeExports.jsx("span", { className: "designbase-toggle__label", children: children })] }));
|
|
3681
3681
|
});
|
|
3682
3682
|
Toggle.displayName = 'Toggle';
|
|
3683
3683
|
|
|
@@ -3785,7 +3785,7 @@ const Toast = ({ id, status = 'info', title, description, icon: Icon, duration =
|
|
|
3785
3785
|
const getIconColor = () => {
|
|
3786
3786
|
const colorMap = {
|
|
3787
3787
|
success: 'success',
|
|
3788
|
-
error: '
|
|
3788
|
+
error: 'error',
|
|
3789
3789
|
warning: 'warning',
|
|
3790
3790
|
info: 'info',
|
|
3791
3791
|
};
|
|
@@ -4460,77 +4460,6 @@ const Progressbar = ({ value, max = 100, min = 0, size = 'm', variant = 'default
|
|
|
4460
4460
|
};
|
|
4461
4461
|
Progressbar.displayName = 'Progressbar';
|
|
4462
4462
|
|
|
4463
|
-
const Badge = ({ children, size = 'm', variant = 'primary', style = 'text', count, maxCount = 99, disabled = false, className, ...props }) => {
|
|
4464
|
-
// 숫자 스타일일 때 count 값을 사용
|
|
4465
|
-
const displayContent = style === 'number' && count !== undefined
|
|
4466
|
-
? (count > maxCount ? `${maxCount}+` : count.toString())
|
|
4467
|
-
: children;
|
|
4468
|
-
const classes = clsx('designbase-badge', `designbase-badge--${size}`, `designbase-badge--${variant}`, `designbase-badge--${style}`, {
|
|
4469
|
-
'designbase-badge--disabled': disabled,
|
|
4470
|
-
}, className);
|
|
4471
|
-
return (jsxRuntimeExports.jsx("span", { className: classes, ...props, children: displayContent }));
|
|
4472
|
-
};
|
|
4473
|
-
Badge.displayName = 'Badge';
|
|
4474
|
-
|
|
4475
|
-
const MenuItem = ({ id, label, href, icon: Icon, active = false, disabled = false, badge, badgeColor = 'primary', variant = 'default', type = 'inline', size = 'm', style = 'dropdown', subItems, expanded = false, expandable = false, depth = 0, onClick, onChildClick, className, }) => {
|
|
4476
|
-
const [internalExpanded, setInternalExpanded] = React.useState(expanded);
|
|
4477
|
-
// expanded prop이 변경될 때 internalExpanded 업데이트
|
|
4478
|
-
React.useEffect(() => {
|
|
4479
|
-
setInternalExpanded(expanded);
|
|
4480
|
-
}, [expanded]);
|
|
4481
|
-
const handleClick = (e) => {
|
|
4482
|
-
e.preventDefault();
|
|
4483
|
-
if (disabled)
|
|
4484
|
-
return;
|
|
4485
|
-
if (expandable && subItems && subItems.length > 0) {
|
|
4486
|
-
setInternalExpanded(!internalExpanded);
|
|
4487
|
-
}
|
|
4488
|
-
onClick?.({
|
|
4489
|
-
id,
|
|
4490
|
-
label,
|
|
4491
|
-
href,
|
|
4492
|
-
icon: Icon,
|
|
4493
|
-
active,
|
|
4494
|
-
disabled,
|
|
4495
|
-
badge,
|
|
4496
|
-
badgeColor,
|
|
4497
|
-
variant,
|
|
4498
|
-
type,
|
|
4499
|
-
size,
|
|
4500
|
-
subItems,
|
|
4501
|
-
expanded: internalExpanded,
|
|
4502
|
-
expandable,
|
|
4503
|
-
onClick,
|
|
4504
|
-
onChildClick,
|
|
4505
|
-
className,
|
|
4506
|
-
});
|
|
4507
|
-
};
|
|
4508
|
-
const handleChildClick = (child) => {
|
|
4509
|
-
if (child.disabled)
|
|
4510
|
-
return;
|
|
4511
|
-
onChildClick?.(child);
|
|
4512
|
-
};
|
|
4513
|
-
const isExpanded = expandable ? internalExpanded : expanded;
|
|
4514
|
-
const hasChildren = subItems && subItems.length > 0;
|
|
4515
|
-
const classes = clsx('designbase-menu-item', `designbase-menu-item--${type}`, `designbase-menu-item--${size}`, `designbase-menu-item--${variant}`, `designbase-menu-item--${style}`, `designbase-menu-item--depth-${depth}`, {
|
|
4516
|
-
'designbase-menu-item--active': active,
|
|
4517
|
-
'designbase-menu-item--disabled': disabled,
|
|
4518
|
-
'designbase-menu-item--expandable': expandable,
|
|
4519
|
-
'designbase-menu-item--expanded': isExpanded,
|
|
4520
|
-
'designbase-menu-item--with-children': hasChildren,
|
|
4521
|
-
'designbase-menu-item--with-badge': badge,
|
|
4522
|
-
'designbase-menu-item--with-icon': Icon,
|
|
4523
|
-
}, className);
|
|
4524
|
-
const contentClasses = clsx('designbase-menu-item__content', {
|
|
4525
|
-
'designbase-menu-item__content--clickable': onClick || href,
|
|
4526
|
-
});
|
|
4527
|
-
return (jsxRuntimeExports.jsxs("div", { className: classes, children: [jsxRuntimeExports.jsxs("div", { className: contentClasses, onClick: handleClick, children: [Icon && (jsxRuntimeExports.jsx("div", { className: clsx('designbase-menu-item__icon', `designbase-menu-item__icon--${variant}`, {
|
|
4528
|
-
'designbase-menu-item__icon--active': active,
|
|
4529
|
-
'designbase-menu-item__icon--disabled': disabled,
|
|
4530
|
-
}), children: jsxRuntimeExports.jsx(Icon, { size: size === 's' ? 16 : size === 'l' ? 24 : 20 }) })), jsxRuntimeExports.jsx("span", { className: "designbase-menu-item__label", children: label }), badge && (jsxRuntimeExports.jsx(Badge, { count: typeof badge === 'string' ? parseInt(badge) : badge, variant: badgeColor === 'neutral' ? 'secondary' : badgeColor, size: "s", style: "number" })), hasChildren && (jsxRuntimeExports.jsx("div", { className: "designbase-menu-item__expand-icon", children: isExpanded ? (jsxRuntimeExports.jsx(icons.ChevronUpIcon, { size: 16 })) : (jsxRuntimeExports.jsx(icons.ChevronDownIcon, { size: 16 })) }))] }), hasChildren && isExpanded && (jsxRuntimeExports.jsx("div", { className: clsx('designbase-menu-item__children', `designbase-menu-item__children--${style}`), children: subItems.map((child) => (jsxRuntimeExports.jsx(MenuItem, { id: child.id, label: child.label, href: child.href, icon: child.icon, active: child.active, disabled: child.disabled, badge: child.badge, badgeColor: child.badgeColor, variant: child.variant, type: child.type, size: size, style: child.style || style, subItems: child.subItems, depth: depth + 1, onClick: () => handleChildClick(child), onChildClick: onChildClick }, child.id))) }))] }));
|
|
4531
|
-
};
|
|
4532
|
-
MenuItem.displayName = 'MenuItem';
|
|
4533
|
-
|
|
4534
4463
|
const SearchBar = ({ value, defaultValue = '', placeholder = '검색...', size = 'm', variant = 'default', disabled = false, readOnly = false, fullWidth = false, searchIcon: SearchIconComponent = icons.SearchIcon, clearIcon: ClearIconComponent = icons.CloseIcon, onChange, onSearch, onFocus, onBlur, onKeyDown, className, ...props }) => {
|
|
4535
4464
|
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
4536
4465
|
const inputRef = React.useRef(null);
|
|
@@ -4575,6 +4504,18 @@ const SearchBar = ({ value, defaultValue = '', placeholder = '검색...', size =
|
|
|
4575
4504
|
};
|
|
4576
4505
|
SearchBar.displayName = 'SearchBar';
|
|
4577
4506
|
|
|
4507
|
+
const Badge = ({ children, size = 'm', variant = 'primary', style = 'text', count, maxCount = 99, disabled = false, className, ...props }) => {
|
|
4508
|
+
// 숫자 스타일일 때 count 값을 사용
|
|
4509
|
+
const displayContent = style === 'number' && count !== undefined
|
|
4510
|
+
? (count > maxCount ? `${maxCount}+` : count.toString())
|
|
4511
|
+
: children;
|
|
4512
|
+
const classes = clsx('designbase-badge', `designbase-badge--${size}`, `designbase-badge--${variant}`, `designbase-badge--${style}`, {
|
|
4513
|
+
'designbase-badge--disabled': disabled,
|
|
4514
|
+
}, className);
|
|
4515
|
+
return (jsxRuntimeExports.jsx("span", { className: classes, ...props, children: displayContent }));
|
|
4516
|
+
};
|
|
4517
|
+
Badge.displayName = 'Badge';
|
|
4518
|
+
|
|
4578
4519
|
const Avatar = ({ src, alt, initials, icon, size = 'm', variant = 'circle', status, badge, badgeMaxCount = 99, badgeVariant = 'danger', badgeStyle = 'number', badgeText, onClick, disabled = false, className, ...props }) => {
|
|
4579
4520
|
const [imageError, setImageError] = React.useState(false);
|
|
4580
4521
|
const [imageLoading, setImageLoading] = React.useState(true);
|
|
@@ -4707,8 +4648,65 @@ const Navbar = ({ size = 'm', variant = 'default', position = 'static', logo, on
|
|
|
4707
4648
|
const containerClasses = clsx('designbase-navbar__container', {
|
|
4708
4649
|
'designbase-navbar__container--full-width': fullWidth,
|
|
4709
4650
|
});
|
|
4710
|
-
|
|
4711
|
-
|
|
4651
|
+
// 재귀적으로 메뉴 아이템을 렌더링하는 함수
|
|
4652
|
+
const renderMenuItem = (item, depth = 0) => {
|
|
4653
|
+
const hasChildren = item.children && item.children.length > 0;
|
|
4654
|
+
const isFirstLevel = depth === 0;
|
|
4655
|
+
const isSecondLevel = depth === 1;
|
|
4656
|
+
if (isFirstLevel) {
|
|
4657
|
+
// 1depth - 메인 네비게이션
|
|
4658
|
+
return (jsxRuntimeExports.jsx("li", { className: "designbase-navbar__nav-item", children: hasChildren ? (jsxRuntimeExports.jsxs("div", { className: "designbase-navbar__dropdown", children: [jsxRuntimeExports.jsxs("button", { className: clsx('designbase-navbar__nav-link', 'designbase-navbar__nav-link--has-children', {
|
|
4659
|
+
'designbase-navbar__nav-link--active': item.active,
|
|
4660
|
+
'designbase-navbar__nav-link--disabled': item.disabled,
|
|
4661
|
+
}), onClick: () => handleItemClick(item), disabled: item.disabled, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label, jsxRuntimeExports.jsx(icons.ChevronDownIcon, { size: 12, className: "designbase-navbar__chevron" })] }), jsxRuntimeExports.jsx("ul", { className: "designbase-navbar__dropdown-menu", children: item.children.map((child) => renderMenuItem(child, 1)) })] })) : (jsxRuntimeExports.jsxs("a", { href: item.href, className: clsx('designbase-navbar__nav-link', {
|
|
4662
|
+
'designbase-navbar__nav-link--active': item.active,
|
|
4663
|
+
'designbase-navbar__nav-link--disabled': item.disabled,
|
|
4664
|
+
}), onClick: (e) => {
|
|
4665
|
+
if (item.disabled) {
|
|
4666
|
+
e.preventDefault();
|
|
4667
|
+
return;
|
|
4668
|
+
}
|
|
4669
|
+
handleItemClick(item);
|
|
4670
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label] })) }, item.id));
|
|
4671
|
+
}
|
|
4672
|
+
else if (isSecondLevel) {
|
|
4673
|
+
// 2depth - 드롭다운 메뉴
|
|
4674
|
+
return (jsxRuntimeExports.jsx("li", { children: hasChildren ? (jsxRuntimeExports.jsxs("div", { className: "designbase-navbar__dropdown-item designbase-navbar__dropdown-item--has-children", children: [jsxRuntimeExports.jsxs("a", { href: item.href, className: clsx('designbase-navbar__dropdown-item', {
|
|
4675
|
+
'designbase-navbar__dropdown-item--active': item.active,
|
|
4676
|
+
'designbase-navbar__dropdown-item--disabled': item.disabled,
|
|
4677
|
+
}), onClick: (e) => {
|
|
4678
|
+
if (item.disabled) {
|
|
4679
|
+
e.preventDefault();
|
|
4680
|
+
return;
|
|
4681
|
+
}
|
|
4682
|
+
handleItemClick(item);
|
|
4683
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label, jsxRuntimeExports.jsx(icons.ChevronRightIcon, { size: 12, className: "designbase-navbar__chevron" })] }), jsxRuntimeExports.jsx("ul", { className: "designbase-navbar__submenu", children: item.children.map((child) => renderMenuItem(child, 2)) })] })) : (jsxRuntimeExports.jsxs("a", { href: item.href, className: clsx('designbase-navbar__dropdown-item', {
|
|
4684
|
+
'designbase-navbar__dropdown-item--active': item.active,
|
|
4685
|
+
'designbase-navbar__dropdown-item--disabled': item.disabled,
|
|
4686
|
+
}), onClick: (e) => {
|
|
4687
|
+
if (item.disabled) {
|
|
4688
|
+
e.preventDefault();
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4691
|
+
handleItemClick(item);
|
|
4692
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label] })) }, item.id));
|
|
4693
|
+
}
|
|
4694
|
+
else {
|
|
4695
|
+
// 3depth 이상 - 서브메뉴
|
|
4696
|
+
return (jsxRuntimeExports.jsx("li", { children: jsxRuntimeExports.jsxs("a", { href: item.href, className: clsx('designbase-navbar__dropdown-item', {
|
|
4697
|
+
'designbase-navbar__dropdown-item--active': item.active,
|
|
4698
|
+
'designbase-navbar__dropdown-item--disabled': item.disabled,
|
|
4699
|
+
}), onClick: (e) => {
|
|
4700
|
+
if (item.disabled) {
|
|
4701
|
+
e.preventDefault();
|
|
4702
|
+
return;
|
|
4703
|
+
}
|
|
4704
|
+
handleItemClick(item);
|
|
4705
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label] }) }, item.id));
|
|
4706
|
+
}
|
|
4707
|
+
};
|
|
4708
|
+
const renderNavItem = (item) => renderMenuItem(item, 0);
|
|
4709
|
+
return (jsxRuntimeExports.jsxs("nav", { className: classes, role: "navigation", "aria-label": "\uBA54\uC778 \uB124\uBE44\uAC8C\uC774\uC158", ...props, children: [jsxRuntimeExports.jsxs("div", { className: containerClasses, children: [jsxRuntimeExports.jsx("div", { className: "designbase-navbar__brand", children: jsxRuntimeExports.jsx("div", { className: "designbase-navbar__logo", onClick: onLogoClick, role: onLogoClick ? 'button' : undefined, tabIndex: onLogoClick ? 0 : undefined, children: logo || jsxRuntimeExports.jsx(Logo, { size: size === 's' ? 's' : size === 'l' ? 'l' : 'm' }) }) }), jsxRuntimeExports.jsx("div", { className: "designbase-navbar__nav", children: jsxRuntimeExports.jsx("ul", { className: "designbase-navbar__nav-list", children: items.map(renderNavItem) }) }), showSearch && (jsxRuntimeExports.jsx("div", { className: "designbase-navbar__search", children: jsxRuntimeExports.jsx(SearchBar, { placeholder: searchPlaceholder, value: searchQuery, onChange: setSearchQuery, onSearch: onSearch, size: size === 's' ? 's' : size === 'l' ? 'l' : 'm', variant: "outlined" }) })), jsxRuntimeExports.jsx("div", { className: "designbase-navbar__user-menu", children: isAuthenticated && userProfile ? (jsxRuntimeExports.jsxs("div", { className: "designbase-navbar__user-dropdown", children: [jsxRuntimeExports.jsxs("button", { className: "designbase-navbar__user-toggle", onClick: handleUserMenuToggle, "aria-expanded": isUserMenuOpen, children: [jsxRuntimeExports.jsx(Avatar, { src: userProfile.avatar, alt: userProfile.name, initials: userProfile.name, size: size === 's' ? 's' : size === 'l' ? 'l' : 'm', badge: userProfile.badge, badgeVariant: userProfile.badgeVariant, badgeStyle: userProfile.badgeStyle, badgeText: userProfile.badgeText }), jsxRuntimeExports.jsx("span", { className: "designbase-navbar__user-name", children: userProfile.name }), jsxRuntimeExports.jsx(icons.ChevronDownIcon, { size: 12 })] }), isUserMenuOpen && (jsxRuntimeExports.jsxs("ul", { className: "designbase-navbar__user-dropdown-menu", children: [userProfile.email && (jsxRuntimeExports.jsx("li", { className: "designbase-navbar__user-info", children: jsxRuntimeExports.jsx("span", { className: "designbase-navbar__user-email", children: userProfile.email }) })), userMenuItems.map((item) => (jsxRuntimeExports.jsx("li", { children: jsxRuntimeExports.jsxs("a", { href: item.href, className: clsx('designbase-navbar__user-dropdown-item', {
|
|
4712
4710
|
'designbase-navbar__user-dropdown-item--disabled': item.disabled,
|
|
4713
4711
|
}), onClick: (e) => {
|
|
4714
4712
|
if (item.disabled) {
|
|
@@ -4746,6 +4744,65 @@ const Navbar = ({ size = 'm', variant = 'default', position = 'static', logo, on
|
|
|
4746
4744
|
};
|
|
4747
4745
|
Navbar.displayName = 'Navbar';
|
|
4748
4746
|
|
|
4747
|
+
const MenuItem = ({ id, label, href, icon: Icon, active = false, disabled = false, badge, badgeColor = 'primary', variant = 'default', type = 'inline', size = 'm', style = 'dropdown', subItems, expanded = false, expandable = false, depth = 0, onClick, onChildClick, className, }) => {
|
|
4748
|
+
const [internalExpanded, setInternalExpanded] = React.useState(expanded);
|
|
4749
|
+
// expanded prop이 변경될 때 internalExpanded 업데이트
|
|
4750
|
+
React.useEffect(() => {
|
|
4751
|
+
setInternalExpanded(expanded);
|
|
4752
|
+
}, [expanded]);
|
|
4753
|
+
const handleClick = (e) => {
|
|
4754
|
+
e.preventDefault();
|
|
4755
|
+
if (disabled)
|
|
4756
|
+
return;
|
|
4757
|
+
if (expandable && subItems && subItems.length > 0) {
|
|
4758
|
+
setInternalExpanded(!internalExpanded);
|
|
4759
|
+
}
|
|
4760
|
+
onClick?.({
|
|
4761
|
+
id,
|
|
4762
|
+
label,
|
|
4763
|
+
href,
|
|
4764
|
+
icon: Icon,
|
|
4765
|
+
active,
|
|
4766
|
+
disabled,
|
|
4767
|
+
badge,
|
|
4768
|
+
badgeColor,
|
|
4769
|
+
variant,
|
|
4770
|
+
type,
|
|
4771
|
+
size,
|
|
4772
|
+
subItems,
|
|
4773
|
+
expanded: internalExpanded,
|
|
4774
|
+
expandable,
|
|
4775
|
+
onClick,
|
|
4776
|
+
onChildClick,
|
|
4777
|
+
className,
|
|
4778
|
+
});
|
|
4779
|
+
};
|
|
4780
|
+
const handleChildClick = (child) => {
|
|
4781
|
+
if (child.disabled)
|
|
4782
|
+
return;
|
|
4783
|
+
onChildClick?.(child);
|
|
4784
|
+
};
|
|
4785
|
+
const isExpanded = expandable ? internalExpanded : expanded;
|
|
4786
|
+
const hasChildren = subItems && subItems.length > 0;
|
|
4787
|
+
const classes = clsx('designbase-menu-item', `designbase-menu-item--${type}`, `designbase-menu-item--${size}`, `designbase-menu-item--${variant}`, `designbase-menu-item--${style}`, `designbase-menu-item--depth-${depth}`, {
|
|
4788
|
+
'designbase-menu-item--active': active,
|
|
4789
|
+
'designbase-menu-item--disabled': disabled,
|
|
4790
|
+
'designbase-menu-item--expandable': expandable,
|
|
4791
|
+
'designbase-menu-item--expanded': isExpanded,
|
|
4792
|
+
'designbase-menu-item--with-children': hasChildren,
|
|
4793
|
+
'designbase-menu-item--with-badge': badge,
|
|
4794
|
+
'designbase-menu-item--with-icon': Icon,
|
|
4795
|
+
}, className);
|
|
4796
|
+
const contentClasses = clsx('designbase-menu-item__content', {
|
|
4797
|
+
'designbase-menu-item__content--clickable': onClick || href,
|
|
4798
|
+
});
|
|
4799
|
+
return (jsxRuntimeExports.jsxs("div", { className: classes, children: [jsxRuntimeExports.jsxs("div", { className: contentClasses, onClick: handleClick, children: [Icon && (jsxRuntimeExports.jsx("div", { className: clsx('designbase-menu-item__icon', `designbase-menu-item__icon--${variant}`, {
|
|
4800
|
+
'designbase-menu-item__icon--active': active,
|
|
4801
|
+
'designbase-menu-item__icon--disabled': disabled,
|
|
4802
|
+
}), children: jsxRuntimeExports.jsx(Icon, { size: size === 's' ? 16 : size === 'l' ? 24 : 20 }) })), jsxRuntimeExports.jsx("span", { className: "designbase-menu-item__label", children: label }), badge && (jsxRuntimeExports.jsx(Badge, { count: typeof badge === 'string' ? parseInt(badge) : badge, variant: badgeColor === 'neutral' ? 'secondary' : badgeColor, size: "s", style: "number" })), hasChildren && (jsxRuntimeExports.jsx("div", { className: "designbase-menu-item__expand-icon", children: isExpanded ? (jsxRuntimeExports.jsx(icons.ChevronUpIcon, { size: 16 })) : (jsxRuntimeExports.jsx(icons.ChevronDownIcon, { size: 16 })) }))] }), hasChildren && isExpanded && (jsxRuntimeExports.jsx("div", { className: clsx('designbase-menu-item__children', `designbase-menu-item__children--${style}`), children: subItems.map((child) => (jsxRuntimeExports.jsx(MenuItem, { id: child.id, label: child.label, href: child.href, icon: child.icon, active: child.active, disabled: child.disabled, badge: child.badge, badgeColor: child.badgeColor, variant: child.variant, type: child.type, size: size, style: child.style || style, subItems: child.subItems, depth: depth + 1, onClick: () => handleChildClick(child), onChildClick: onChildClick }, child.id))) }))] }));
|
|
4803
|
+
};
|
|
4804
|
+
MenuItem.displayName = 'MenuItem';
|
|
4805
|
+
|
|
4749
4806
|
const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onLogoClick, items = [], onItemClick, userProfile, userMenuItems = [], onUserMenuItemClick, collapsed = false, onToggle, collapsible = true, fixed = false, fullHeight = false, shadow = false, className, ...props }) => {
|
|
4750
4807
|
const [expandedItems, setExpandedItems] = React.useState([]);
|
|
4751
4808
|
const handleToggle = () => {
|
|
@@ -4787,9 +4844,19 @@ const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onL
|
|
|
4787
4844
|
const hasChildren = item.children && item.children.length > 0;
|
|
4788
4845
|
return (jsxRuntimeExports.jsx("li", { className: "designbase-sidebar__item", children: jsxRuntimeExports.jsx(MenuItem, { ...item, type: "block", style: "accordion", depth: level, expanded: isExpanded, expandable: hasChildren, onClick: () => handleItemClick(item), onChildClick: (child) => handleItemClick(child) }) }, item.id));
|
|
4789
4846
|
};
|
|
4790
|
-
return (jsxRuntimeExports.jsx("aside", { className: classes, role: "complementary", "aria-label": "\uC0AC\uC774\uB4DC\uBC14 \uB124\uBE44\uAC8C\uC774\uC158", ...props, children: jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__container", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__header", children: [jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__logo", onClick: onLogoClick, role: onLogoClick ? 'button' : undefined, tabIndex: onLogoClick ? 0 : undefined,
|
|
4847
|
+
return (jsxRuntimeExports.jsx("aside", { className: classes, role: "complementary", "aria-label": "\uC0AC\uC774\uB4DC\uBC14 \uB124\uBE44\uAC8C\uC774\uC158", ...props, children: jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__container", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__header", children: [jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__logo", onClick: onLogoClick, role: onLogoClick ? 'button' : undefined, tabIndex: onLogoClick ? 0 : undefined, onKeyDown: (e) => {
|
|
4848
|
+
if (onLogoClick && (e.key === 'Enter' || e.key === ' ')) {
|
|
4849
|
+
e.preventDefault();
|
|
4850
|
+
onLogoClick();
|
|
4851
|
+
}
|
|
4852
|
+
}, children: logo || jsxRuntimeExports.jsx(Logo, { size: size === 's' ? 's' : size === 'l' ? 'l' : 'm' }) }), collapsible && (jsxRuntimeExports.jsx(Button, { variant: "ghost", size: "s", iconOnly: true, className: "designbase-sidebar__toggle", onPress: handleToggle, "aria-label": collapsed ? '사이드바 펼치기' : '사이드바 접기', children: jsxRuntimeExports.jsx(icons.ChevronLeftIcon, { className: clsx('designbase-sidebar__toggle-icon', {
|
|
4791
4853
|
'designbase-sidebar__toggle-icon--collapsed': collapsed,
|
|
4792
|
-
}) }) }))] }), jsxRuntimeExports.jsx("nav", { className: "designbase-sidebar__nav", children: jsxRuntimeExports.jsx("ul", { className: "designbase-sidebar__nav-list", children: items.map((item) => renderSidebarItem(item)) }) }), userProfile && !collapsed && (jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__user", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__user-info",
|
|
4854
|
+
}) }) }))] }), jsxRuntimeExports.jsx("nav", { className: "designbase-sidebar__nav", children: jsxRuntimeExports.jsx("ul", { className: "designbase-sidebar__nav-list", children: items.map((item) => renderSidebarItem(item)) }) }), userProfile && !collapsed && (jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__user", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__user-info", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
4855
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
4856
|
+
e.preventDefault();
|
|
4857
|
+
onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
|
|
4858
|
+
}
|
|
4859
|
+
}, style: { cursor: 'pointer' }, children: [userProfile.avatar ? (jsxRuntimeExports.jsx("img", { src: userProfile.avatar, alt: userProfile.name, className: "designbase-sidebar__user-avatar" })) : (jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-avatar-placeholder", children: userProfile.name.charAt(0).toUpperCase() })), jsxRuntimeExports.jsxs("div", { className: "designbase-sidebar__user-details", children: [jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-name", children: userProfile.name }), userProfile.email && (jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-email", children: userProfile.email })), userProfile.role && (jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-role", children: userProfile.role }))] })] }), userMenuItems.length > 0 && (jsxRuntimeExports.jsx("ul", { className: "designbase-sidebar__user-menu", children: userMenuItems.map((item) => (jsxRuntimeExports.jsx("li", { children: jsxRuntimeExports.jsxs("a", { href: item.href, className: clsx('designbase-sidebar__user-menu-link', {
|
|
4793
4860
|
'designbase-sidebar__user-menu-link--disabled': item.disabled,
|
|
4794
4861
|
}), onClick: (e) => {
|
|
4795
4862
|
if (item.disabled) {
|
|
@@ -4797,7 +4864,12 @@ const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onL
|
|
|
4797
4864
|
return;
|
|
4798
4865
|
}
|
|
4799
4866
|
handleUserMenuItemClick(item);
|
|
4800
|
-
}, children: [item.icon && React.createElement(item.icon, { size: 16 }), item.label] }) }, item.id))) }))] })), userProfile && collapsed && (jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-collapsed",
|
|
4867
|
+
}, children: [item.icon && React.createElement(item.icon, { size: 16 }), item.label] }) }, item.id))) }))] })), userProfile && collapsed && (jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-collapsed", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
4868
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
4869
|
+
e.preventDefault();
|
|
4870
|
+
onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
|
|
4871
|
+
}
|
|
4872
|
+
}, style: { cursor: 'pointer' }, children: userProfile.avatar ? (jsxRuntimeExports.jsx("img", { src: userProfile.avatar, alt: userProfile.name, className: "designbase-sidebar__user-avatar-collapsed" })) : (jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-avatar-placeholder-collapsed", children: userProfile.name.charAt(0).toUpperCase() })) }))] }) }));
|
|
4801
4873
|
};
|
|
4802
4874
|
Sidebar.displayName = 'Sidebar';
|
|
4803
4875
|
|
|
@@ -5302,14 +5374,22 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5302
5374
|
const [isVisible, setIsVisible] = React.useState(false);
|
|
5303
5375
|
const [tooltipStyle, setTooltipStyle] = React.useState({});
|
|
5304
5376
|
const [arrowStyle, setArrowStyle] = React.useState({});
|
|
5305
|
-
|
|
5377
|
+
// 🔑 DOM 래퍼(ref/이벤트가 항상 붙도록)
|
|
5378
|
+
const triggerWrapperRef = React.useRef(null);
|
|
5306
5379
|
const tooltipRef = React.useRef(null);
|
|
5307
|
-
|
|
5380
|
+
// 브라우저 setTimeout은 number 반환
|
|
5381
|
+
const timeoutRef = React.useRef(null);
|
|
5382
|
+
const clearTimer = () => {
|
|
5383
|
+
if (timeoutRef.current !== null) {
|
|
5384
|
+
window.clearTimeout(timeoutRef.current);
|
|
5385
|
+
timeoutRef.current = null;
|
|
5386
|
+
}
|
|
5387
|
+
};
|
|
5308
5388
|
// 툴팁 위치 계산
|
|
5309
5389
|
const calculatePosition = React.useCallback(() => {
|
|
5310
|
-
if (!
|
|
5390
|
+
if (!triggerWrapperRef.current || !tooltipRef.current)
|
|
5311
5391
|
return;
|
|
5312
|
-
const triggerRect =
|
|
5392
|
+
const triggerRect = triggerWrapperRef.current.getBoundingClientRect();
|
|
5313
5393
|
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
5314
5394
|
const scrollX = window.pageXOffset || document.documentElement.scrollLeft;
|
|
5315
5395
|
const scrollY = window.pageYOffset || document.documentElement.scrollTop;
|
|
@@ -5322,129 +5402,131 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5322
5402
|
switch (position) {
|
|
5323
5403
|
case 'top':
|
|
5324
5404
|
top = triggerRect.top + scrollY - tooltipRect.height - 8;
|
|
5325
|
-
left = triggerRect.left + scrollX +
|
|
5326
|
-
|
|
5327
|
-
|
|
5405
|
+
left = triggerRect.left + scrollX + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
5406
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5407
|
+
arrowTop = 0;
|
|
5408
|
+
arrowLeft = 0;
|
|
5328
5409
|
break;
|
|
5329
5410
|
case 'top-start':
|
|
5330
5411
|
top = triggerRect.top + scrollY - tooltipRect.height - 8;
|
|
5331
5412
|
left = triggerRect.left + scrollX;
|
|
5332
|
-
|
|
5333
|
-
|
|
5413
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5414
|
+
arrowTop = 0;
|
|
5415
|
+
arrowLeft = 0;
|
|
5334
5416
|
break;
|
|
5335
5417
|
case 'top-end':
|
|
5336
5418
|
top = triggerRect.top + scrollY - tooltipRect.height - 8;
|
|
5337
5419
|
left = triggerRect.right + scrollX - tooltipRect.width;
|
|
5338
|
-
|
|
5339
|
-
|
|
5420
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5421
|
+
arrowTop = 0;
|
|
5422
|
+
arrowLeft = 0;
|
|
5340
5423
|
break;
|
|
5341
5424
|
case 'bottom':
|
|
5342
5425
|
top = triggerRect.bottom + scrollY + 8;
|
|
5343
|
-
left = triggerRect.left + scrollX +
|
|
5344
|
-
|
|
5345
|
-
|
|
5426
|
+
left = triggerRect.left + scrollX + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
5427
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5428
|
+
arrowTop = 0;
|
|
5429
|
+
arrowLeft = 0;
|
|
5346
5430
|
break;
|
|
5347
5431
|
case 'bottom-start':
|
|
5348
5432
|
top = triggerRect.bottom + scrollY + 8;
|
|
5349
5433
|
left = triggerRect.left + scrollX;
|
|
5350
|
-
|
|
5351
|
-
|
|
5434
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5435
|
+
arrowTop = 0;
|
|
5436
|
+
arrowLeft = 0;
|
|
5352
5437
|
break;
|
|
5353
5438
|
case 'bottom-end':
|
|
5354
5439
|
top = triggerRect.bottom + scrollY + 8;
|
|
5355
5440
|
left = triggerRect.right + scrollX - tooltipRect.width;
|
|
5356
|
-
|
|
5357
|
-
|
|
5441
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5442
|
+
arrowTop = 0;
|
|
5443
|
+
arrowLeft = 0;
|
|
5358
5444
|
break;
|
|
5359
5445
|
case 'left':
|
|
5360
|
-
top = triggerRect.top + scrollY +
|
|
5446
|
+
top = triggerRect.top + scrollY + triggerRect.height / 2 - tooltipRect.height / 2;
|
|
5361
5447
|
left = triggerRect.left + scrollX - tooltipRect.width - 8;
|
|
5362
|
-
|
|
5363
|
-
|
|
5448
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5449
|
+
arrowTop = 0;
|
|
5450
|
+
arrowLeft = 0;
|
|
5364
5451
|
break;
|
|
5365
5452
|
case 'left-start':
|
|
5366
5453
|
top = triggerRect.top + scrollY;
|
|
5367
5454
|
left = triggerRect.left + scrollX - tooltipRect.width - 8;
|
|
5368
|
-
|
|
5369
|
-
|
|
5455
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5456
|
+
arrowTop = 0;
|
|
5457
|
+
arrowLeft = 0;
|
|
5370
5458
|
break;
|
|
5371
5459
|
case 'left-end':
|
|
5372
5460
|
top = triggerRect.bottom + scrollY - tooltipRect.height;
|
|
5373
5461
|
left = triggerRect.left + scrollX - tooltipRect.width - 8;
|
|
5374
|
-
|
|
5375
|
-
|
|
5462
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5463
|
+
arrowTop = 0;
|
|
5464
|
+
arrowLeft = 0;
|
|
5376
5465
|
break;
|
|
5377
5466
|
case 'right':
|
|
5378
|
-
top = triggerRect.top + scrollY +
|
|
5467
|
+
top = triggerRect.top + scrollY + triggerRect.height / 2 - tooltipRect.height / 2;
|
|
5379
5468
|
left = triggerRect.right + scrollX + 8;
|
|
5380
|
-
|
|
5381
|
-
|
|
5469
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5470
|
+
arrowTop = 0;
|
|
5471
|
+
arrowLeft = 0;
|
|
5382
5472
|
break;
|
|
5383
5473
|
case 'right-start':
|
|
5384
5474
|
top = triggerRect.top + scrollY;
|
|
5385
5475
|
left = triggerRect.right + scrollX + 8;
|
|
5386
|
-
|
|
5387
|
-
|
|
5476
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5477
|
+
arrowTop = 0;
|
|
5478
|
+
arrowLeft = 0;
|
|
5388
5479
|
break;
|
|
5389
5480
|
case 'right-end':
|
|
5390
5481
|
top = triggerRect.bottom + scrollY - tooltipRect.height;
|
|
5391
5482
|
left = triggerRect.right + scrollX + 8;
|
|
5392
|
-
|
|
5393
|
-
|
|
5483
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5484
|
+
arrowTop = 0;
|
|
5485
|
+
arrowLeft = 0;
|
|
5394
5486
|
break;
|
|
5395
5487
|
}
|
|
5396
5488
|
// 화면 경계 체크 및 조정
|
|
5397
5489
|
const viewportWidth = window.innerWidth;
|
|
5398
5490
|
const viewportHeight = window.innerHeight;
|
|
5399
|
-
// 수평 경계
|
|
5491
|
+
// 수평 경계
|
|
5400
5492
|
if (left < 8) {
|
|
5401
5493
|
left = 8;
|
|
5402
|
-
if (isHorizontal)
|
|
5494
|
+
if (isHorizontal)
|
|
5403
5495
|
arrowLeft = Math.max(arrowLeft, 4);
|
|
5404
|
-
}
|
|
5405
5496
|
}
|
|
5406
5497
|
else if (left + tooltipRect.width > viewportWidth - 8) {
|
|
5407
5498
|
left = viewportWidth - tooltipRect.width - 8;
|
|
5408
|
-
if (isHorizontal)
|
|
5499
|
+
if (isHorizontal)
|
|
5409
5500
|
arrowLeft = Math.min(arrowLeft, tooltipRect.width - 4);
|
|
5410
|
-
}
|
|
5411
5501
|
}
|
|
5412
|
-
// 수직 경계
|
|
5502
|
+
// 수직 경계
|
|
5413
5503
|
if (top < 8) {
|
|
5414
5504
|
top = 8;
|
|
5415
|
-
if (isVertical)
|
|
5505
|
+
if (isVertical)
|
|
5416
5506
|
arrowTop = Math.max(arrowTop, 4);
|
|
5417
|
-
}
|
|
5418
5507
|
}
|
|
5419
5508
|
else if (top + tooltipRect.height > viewportHeight - 8) {
|
|
5420
5509
|
top = viewportHeight - tooltipRect.height - 8;
|
|
5421
|
-
if (isVertical)
|
|
5510
|
+
if (isVertical)
|
|
5422
5511
|
arrowTop = Math.min(arrowTop, tooltipRect.height - 4);
|
|
5423
|
-
}
|
|
5424
5512
|
}
|
|
5425
5513
|
setTooltipStyle({
|
|
5426
5514
|
position: 'fixed',
|
|
5427
5515
|
top: `${top}px`,
|
|
5428
5516
|
left: `${left}px`,
|
|
5429
5517
|
maxWidth: `${maxWidth}px`,
|
|
5430
|
-
zIndex: 9999
|
|
5431
|
-
});
|
|
5432
|
-
setArrowStyle({
|
|
5433
|
-
position: 'absolute',
|
|
5434
|
-
top: `${arrowTop}px`,
|
|
5435
|
-
left: `${arrowLeft}px`,
|
|
5518
|
+
zIndex: 9999
|
|
5436
5519
|
});
|
|
5520
|
+
// CSS에서 화살표 위치를 자동으로 처리하므로 인라인 스타일 제거
|
|
5521
|
+
setArrowStyle({});
|
|
5437
5522
|
}, [position, maxWidth]);
|
|
5438
5523
|
// 툴팁 표시
|
|
5439
5524
|
const showTooltip = React.useCallback(() => {
|
|
5440
5525
|
if (disabled || alwaysShow)
|
|
5441
5526
|
return;
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
}
|
|
5445
|
-
timeoutRef.current = setTimeout(() => {
|
|
5527
|
+
clearTimer();
|
|
5528
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
5446
5529
|
setIsVisible(true);
|
|
5447
|
-
// 위치 계산을 위해 다음 프레임에서 실행
|
|
5448
5530
|
requestAnimationFrame(() => {
|
|
5449
5531
|
calculatePosition();
|
|
5450
5532
|
});
|
|
@@ -5454,89 +5536,57 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5454
5536
|
const hideTooltip = React.useCallback(() => {
|
|
5455
5537
|
if (disabled || alwaysShow)
|
|
5456
5538
|
return;
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
}
|
|
5460
|
-
timeoutRef.current = setTimeout(() => {
|
|
5539
|
+
clearTimer();
|
|
5540
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
5461
5541
|
setIsVisible(false);
|
|
5462
5542
|
}, hideDelay);
|
|
5463
5543
|
}, [disabled, alwaysShow, hideDelay]);
|
|
5464
|
-
//
|
|
5465
|
-
const handleMouseEnter = React.useCallback(() => {
|
|
5466
|
-
showTooltip();
|
|
5467
|
-
}, [showTooltip]);
|
|
5468
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
5469
|
-
hideTooltip();
|
|
5470
|
-
}, [hideTooltip]);
|
|
5471
|
-
const handleFocus = React.useCallback(() => {
|
|
5472
|
-
showTooltip();
|
|
5473
|
-
}, [showTooltip]);
|
|
5474
|
-
const handleBlur = React.useCallback(() => {
|
|
5475
|
-
hideTooltip();
|
|
5476
|
-
}, [hideTooltip]);
|
|
5477
|
-
// 키보드 이벤트
|
|
5544
|
+
// 키보드 이스케이프
|
|
5478
5545
|
const handleKeyDown = React.useCallback((e) => {
|
|
5479
|
-
if (e.key === 'Escape')
|
|
5546
|
+
if (e.key === 'Escape')
|
|
5480
5547
|
hideTooltip();
|
|
5481
|
-
}
|
|
5482
5548
|
}, [hideTooltip]);
|
|
5483
|
-
//
|
|
5484
|
-
React.useEffect(() => {
|
|
5485
|
-
if (isVisible) {
|
|
5486
|
-
const handleResize = () => calculatePosition();
|
|
5487
|
-
const handleScroll = () => calculatePosition();
|
|
5488
|
-
window.addEventListener('resize', handleResize);
|
|
5489
|
-
window.addEventListener('scroll', handleScroll, true);
|
|
5490
|
-
return () => {
|
|
5491
|
-
window.removeEventListener('resize', handleResize);
|
|
5492
|
-
window.removeEventListener('scroll', handleScroll, true);
|
|
5493
|
-
};
|
|
5494
|
-
}
|
|
5495
|
-
}, [isVisible, calculatePosition]);
|
|
5496
|
-
// 컴포넌트 언마운트 시 타이머 정리
|
|
5549
|
+
// 리사이즈/스크롤 중 위치 업데이트
|
|
5497
5550
|
React.useEffect(() => {
|
|
5551
|
+
if (!isVisible)
|
|
5552
|
+
return;
|
|
5553
|
+
const onResize = () => calculatePosition();
|
|
5554
|
+
const onScroll = () => calculatePosition();
|
|
5555
|
+
window.addEventListener('resize', onResize);
|
|
5556
|
+
window.addEventListener('scroll', onScroll, true);
|
|
5498
5557
|
return () => {
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
}
|
|
5558
|
+
window.removeEventListener('resize', onResize);
|
|
5559
|
+
window.removeEventListener('scroll', onScroll, true);
|
|
5502
5560
|
};
|
|
5503
|
-
}, []);
|
|
5504
|
-
//
|
|
5561
|
+
}, [isVisible, calculatePosition]);
|
|
5562
|
+
// 언마운트 시 타이머 정리
|
|
5563
|
+
React.useEffect(() => () => clearTimer(), []);
|
|
5564
|
+
// 항상표시 모드
|
|
5505
5565
|
React.useEffect(() => {
|
|
5506
5566
|
if (alwaysShow && !disabled) {
|
|
5507
5567
|
setIsVisible(true);
|
|
5508
|
-
requestAnimationFrame(() =>
|
|
5509
|
-
calculatePosition();
|
|
5510
|
-
});
|
|
5568
|
+
requestAnimationFrame(() => calculatePosition());
|
|
5511
5569
|
}
|
|
5512
5570
|
else if (!alwaysShow) {
|
|
5513
5571
|
setIsVisible(false);
|
|
5514
5572
|
}
|
|
5515
5573
|
}, [alwaysShow, disabled, calculatePosition]);
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5574
|
+
// content가 동적으로 바뀌어도 위치 갱신
|
|
5575
|
+
React.useEffect(() => {
|
|
5576
|
+
if (!isVisible)
|
|
5577
|
+
return;
|
|
5578
|
+
const ro = new ResizeObserver(() => calculatePosition());
|
|
5579
|
+
if (tooltipRef.current)
|
|
5580
|
+
ro.observe(tooltipRef.current);
|
|
5581
|
+
return () => ro.disconnect();
|
|
5582
|
+
}, [isVisible, calculatePosition, content]);
|
|
5583
|
+
const classes = clsx('designbase-tooltip', `designbase-tooltip--${size}`, `designbase-tooltip--${variant}`, `designbase-tooltip--${position}`, { 'designbase-tooltip--visible': isVisible, 'designbase-tooltip--disabled': disabled }, className);
|
|
5520
5584
|
const arrowClasses = clsx('designbase-tooltip__arrow', `designbase-tooltip__arrow--${position}`);
|
|
5521
|
-
|
|
5522
|
-
const enhancedChildren = React.cloneElement(children, {
|
|
5523
|
-
ref: triggerRef,
|
|
5524
|
-
onMouseEnter: handleMouseEnter,
|
|
5525
|
-
onMouseLeave: handleMouseLeave,
|
|
5526
|
-
onFocus: handleFocus,
|
|
5527
|
-
onBlur: handleBlur,
|
|
5528
|
-
onKeyDown: handleKeyDown,
|
|
5529
|
-
onMouseDown: (e) => {
|
|
5530
|
-
// 클릭으로 인한 focus 방지 (hover 전용 보장)
|
|
5531
|
-
e.preventDefault();
|
|
5532
|
-
},
|
|
5533
|
-
tabIndex: children.props.tabIndex ?? 0,
|
|
5534
|
-
});
|
|
5535
|
-
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [enhancedChildren, isVisible && (jsxRuntimeExports.jsxs("div", { ref: tooltipRef, className: classes, style: tooltipStyle, role: "tooltip", "aria-hidden": !isVisible, ...props, children: [jsxRuntimeExports.jsx("div", { className: "designbase-tooltip__content", children: content }), showArrow && (jsxRuntimeExports.jsx("div", { className: arrowClasses, style: arrowStyle }))] }))] }));
|
|
5585
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("span", { ref: triggerWrapperRef, className: "designbase-tooltip__trigger", onMouseEnter: showTooltip, onMouseLeave: hideTooltip, onFocus: showTooltip, onBlur: hideTooltip, onKeyDown: handleKeyDown, tabIndex: 0, "aria-describedby": isVisible ? 'designbase-tooltip' : undefined, children: children }), isVisible && (jsxRuntimeExports.jsxs("div", { ref: tooltipRef, className: classes, style: tooltipStyle, role: "tooltip", id: "designbase-tooltip", "aria-hidden": !isVisible, ...props, children: [jsxRuntimeExports.jsx("div", { className: "designbase-tooltip__content", children: content }), showArrow && jsxRuntimeExports.jsx("div", { className: arrowClasses, style: arrowStyle })] }))] }));
|
|
5536
5586
|
};
|
|
5537
5587
|
Tooltip.displayName = 'Tooltip';
|
|
5538
5588
|
|
|
5539
|
-
const Popover = ({ content, children, position = 'top', size = 'm', variant = 'default', trigger = 'click', delay = 200, hideDelay = 0, alwaysShow = false, disabled = false, maxWidth = 300, showArrow = true, closeOnOutsideClick = true, closeOnEscape = true, open: controlledOpen, onOpenChange, className, ...props }) => {
|
|
5589
|
+
const Popover = ({ content, children, position = 'top', size = 'm', variant = 'default', trigger = 'click', delay = 200, hideDelay = 0, alwaysShow = false, disabled = false, maxWidth = 300, showArrow = true, closeOnOutsideClick = true, closeOnEscape = true, open: controlledOpen, onOpenChange, showCloseButton = true, className, ...props }) => {
|
|
5540
5590
|
const [internalOpen, setInternalOpen] = React.useState(false);
|
|
5541
5591
|
const [popoverStyle, setPopoverStyle] = React.useState({});
|
|
5542
5592
|
const [arrowStyle, setArrowStyle] = React.useState({});
|
|
@@ -5749,6 +5799,12 @@ const Popover = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5749
5799
|
closePopover();
|
|
5750
5800
|
}
|
|
5751
5801
|
}, [closeOnEscape, closePopover]);
|
|
5802
|
+
// 닫기 버튼 핸들러
|
|
5803
|
+
const handleCloseClick = React.useCallback((e) => {
|
|
5804
|
+
e.preventDefault();
|
|
5805
|
+
e.stopPropagation();
|
|
5806
|
+
closePopover();
|
|
5807
|
+
}, [closePopover]);
|
|
5752
5808
|
// 외부 클릭 처리
|
|
5753
5809
|
React.useEffect(() => {
|
|
5754
5810
|
if (isOpen && closeOnOutsideClick) {
|
|
@@ -5825,7 +5881,7 @@ const Popover = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5825
5881
|
'aria-expanded': isOpen,
|
|
5826
5882
|
'aria-haspopup': 'dialog',
|
|
5827
5883
|
});
|
|
5828
|
-
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [enhancedChildren, isOpen && (jsxRuntimeExports.jsxs("div", { ref: popoverRef, className: classes, style: popoverStyle, role: "dialog", "aria-modal": "false", ...props, children: [jsxRuntimeExports.
|
|
5884
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [enhancedChildren, isOpen && (jsxRuntimeExports.jsxs("div", { ref: popoverRef, className: classes, style: popoverStyle, role: "dialog", "aria-modal": "false", ...props, children: [jsxRuntimeExports.jsxs("div", { className: "designbase-popover__content", children: [showCloseButton && (jsxRuntimeExports.jsx("button", { className: "designbase-popover__close-button", onClick: handleCloseClick, "aria-label": "\uD31D\uC624\uBC84 \uB2EB\uAE30", type: "button" })), content] }), showArrow && (jsxRuntimeExports.jsx("div", { className: arrowClasses, style: arrowStyle }))] }))] }));
|
|
5829
5885
|
};
|
|
5830
5886
|
Popover.displayName = 'Popover';
|
|
5831
5887
|
|
|
@@ -6911,37 +6967,36 @@ const Reorder = ({ items, variant = 'default', size = 'm', orientation = 'vertic
|
|
|
6911
6967
|
setDraggedIndex(index);
|
|
6912
6968
|
setIsDragging(true);
|
|
6913
6969
|
setDragOverIndex(-1);
|
|
6914
|
-
// 드래그 이미지 설정 -
|
|
6970
|
+
// 드래그 이미지 설정 - 커스텀 드래그 이미지 사용하지 않음
|
|
6971
|
+
// 브라우저 기본 드래그 이미지를 사용하여 자연스러운 드래그 경험 제공
|
|
6972
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
6973
|
+
e.dataTransfer.setData('text/plain', item.id);
|
|
6974
|
+
// 드래그 시작 애니메이션
|
|
6915
6975
|
const dragElement = itemRefs.current.get(item.id);
|
|
6916
6976
|
if (dragElement) {
|
|
6917
|
-
|
|
6918
|
-
const dragImage = dragElement.cloneNode(true);
|
|
6919
|
-
dragImage.style.position = 'absolute';
|
|
6920
|
-
dragImage.style.top = '-1000px';
|
|
6921
|
-
dragImage.style.opacity = '0.9';
|
|
6922
|
-
dragImage.style.transform = 'none'; // 회전 제거
|
|
6923
|
-
dragImage.style.pointerEvents = 'none';
|
|
6924
|
-
dragImage.style.zIndex = '9999';
|
|
6925
|
-
document.body.appendChild(dragImage);
|
|
6926
|
-
e.dataTransfer.setDragImage(dragImage, rect.width / 2, rect.height / 2);
|
|
6927
|
-
// 드래그 이미지 정리
|
|
6928
|
-
setTimeout(() => {
|
|
6929
|
-
if (document.body.contains(dragImage)) {
|
|
6930
|
-
document.body.removeChild(dragImage);
|
|
6931
|
-
}
|
|
6932
|
-
}, 0);
|
|
6977
|
+
dragElement.style.animation = 'dragStart 0.2s ease-out forwards';
|
|
6933
6978
|
}
|
|
6934
|
-
e.dataTransfer.effectAllowed = 'move';
|
|
6935
|
-
e.dataTransfer.setData('text/plain', item.id);
|
|
6936
6979
|
onDragStart?.(item, index);
|
|
6937
6980
|
}, [disabled, onDragStart]);
|
|
6938
|
-
// 드래그 오버 핸들러
|
|
6981
|
+
// 드래그 오버 핸들러 - 드래그 방향에 따른 정확한 디바이더 위치 계산
|
|
6939
6982
|
const handleDragOver = React.useCallback((e, index) => {
|
|
6940
6983
|
e.preventDefault();
|
|
6941
6984
|
e.dataTransfer.dropEffect = 'move';
|
|
6942
|
-
if (draggedIndex
|
|
6943
|
-
setDragOverIndex(
|
|
6985
|
+
if (draggedIndex === -1 || draggedIndex === index) {
|
|
6986
|
+
setDragOverIndex(-1);
|
|
6987
|
+
return;
|
|
6988
|
+
}
|
|
6989
|
+
// 드래그 방향에 따라 디바이더 위치 결정
|
|
6990
|
+
let dropIndex = index;
|
|
6991
|
+
if (draggedIndex < index) {
|
|
6992
|
+
// 아래로 드래그: 현재 아이템 위에 디바이더 표시
|
|
6993
|
+
dropIndex = index;
|
|
6994
|
+
}
|
|
6995
|
+
else if (draggedIndex > index) {
|
|
6996
|
+
// 위로 드래그: 현재 아이템 위에 디바이더 표시 (index 그대로 사용)
|
|
6997
|
+
dropIndex = index;
|
|
6944
6998
|
}
|
|
6999
|
+
setDragOverIndex(dropIndex);
|
|
6945
7000
|
}, [draggedIndex]);
|
|
6946
7001
|
// 드래그 리브 핸들러
|
|
6947
7002
|
const handleDragLeave = React.useCallback((e) => {
|
|
@@ -6954,25 +7009,55 @@ const Reorder = ({ items, variant = 'default', size = 'm', orientation = 'vertic
|
|
|
6954
7009
|
setDragOverIndex(-1);
|
|
6955
7010
|
}
|
|
6956
7011
|
}, []);
|
|
6957
|
-
// 드롭 핸들러
|
|
7012
|
+
// 드롭 핸들러 - 드래그 방향에 따른 정확한 드롭 위치 사용
|
|
6958
7013
|
const handleDrop = React.useCallback((e, dropIndex) => {
|
|
6959
7014
|
e.preventDefault();
|
|
6960
7015
|
if (draggedIndex === -1 || draggedIndex === dropIndex) {
|
|
6961
7016
|
setDragOverIndex(-1);
|
|
6962
7017
|
return;
|
|
6963
7018
|
}
|
|
7019
|
+
// 드래그 방향에 따라 실제 드롭 위치 계산
|
|
7020
|
+
let actualDropIndex = dropIndex;
|
|
7021
|
+
if (draggedIndex < dropIndex) {
|
|
7022
|
+
// 아래로 드래그: 현재 위치에 삽입
|
|
7023
|
+
actualDropIndex = dropIndex;
|
|
7024
|
+
}
|
|
7025
|
+
else if (draggedIndex > dropIndex) {
|
|
7026
|
+
// 위로 드래그: 현재 위치에 삽입 (dropIndex 그대로 사용)
|
|
7027
|
+
actualDropIndex = dropIndex;
|
|
7028
|
+
}
|
|
6964
7029
|
const newItems = [...reorderedItems];
|
|
6965
7030
|
const [draggedItemData] = newItems.splice(draggedIndex, 1);
|
|
6966
|
-
newItems.splice(
|
|
7031
|
+
newItems.splice(actualDropIndex, 0, draggedItemData);
|
|
6967
7032
|
setReorderedItems(newItems);
|
|
6968
7033
|
setDragOverIndex(-1);
|
|
6969
7034
|
setIsDragging(false);
|
|
7035
|
+
// 드롭 완료 애니메이션
|
|
7036
|
+
const dropElement = itemRefs.current.get(draggedItemData.id);
|
|
7037
|
+
if (dropElement) {
|
|
7038
|
+
dropElement.style.animation = 'dropComplete 0.3s ease-out forwards';
|
|
7039
|
+
setTimeout(() => {
|
|
7040
|
+
dropElement.style.animation = '';
|
|
7041
|
+
}, 300);
|
|
7042
|
+
}
|
|
6970
7043
|
onReorder?.(newItems);
|
|
6971
|
-
onDragEnd?.(draggedItemData, draggedIndex,
|
|
7044
|
+
onDragEnd?.(draggedItemData, draggedIndex, actualDropIndex);
|
|
6972
7045
|
}, [reorderedItems, draggedIndex, onReorder, onDragEnd]);
|
|
6973
7046
|
// 드래그 종료 핸들러
|
|
6974
7047
|
const handleDragEnd = React.useCallback((e) => {
|
|
6975
7048
|
e.preventDefault();
|
|
7049
|
+
// 모든 아이템의 스타일 초기화
|
|
7050
|
+
itemRefs.current.forEach((element) => {
|
|
7051
|
+
if (element) {
|
|
7052
|
+
element.style.animation = '';
|
|
7053
|
+
element.style.transform = '';
|
|
7054
|
+
element.style.opacity = '';
|
|
7055
|
+
element.style.zIndex = '';
|
|
7056
|
+
element.style.boxShadow = '';
|
|
7057
|
+
element.style.border = '';
|
|
7058
|
+
element.style.background = '';
|
|
7059
|
+
}
|
|
7060
|
+
});
|
|
6976
7061
|
setDraggedItem(null);
|
|
6977
7062
|
setDraggedIndex(-1);
|
|
6978
7063
|
setDragOverIndex(-1);
|
|
@@ -7059,11 +7144,21 @@ const Reorder = ({ items, variant = 'default', size = 'm', orientation = 'vertic
|
|
|
7059
7144
|
const isDragged = draggedItem?.id === item.id;
|
|
7060
7145
|
const isDragOver = dragOverIndex === index;
|
|
7061
7146
|
const isDisabled = disabled || item.disabled;
|
|
7147
|
+
// 드래그 방향에 따른 디바이더 클래스 (드롭 위치에만 적용)
|
|
7148
|
+
const isDraggingDown = isDragOver && draggedIndex !== -1 && draggedIndex < index;
|
|
7149
|
+
const isDraggingUp = isDragOver && draggedIndex !== -1 && draggedIndex > index;
|
|
7150
|
+
const isDraggingRight = isDragOver && draggedIndex !== -1 && draggedIndex < index;
|
|
7151
|
+
const isDraggingLeft = isDragOver && draggedIndex !== -1 && draggedIndex > index;
|
|
7062
7152
|
const itemClasses = clsx('designbase-reorder__item', {
|
|
7063
7153
|
'designbase-reorder__item--selected': isSelected,
|
|
7064
7154
|
'designbase-reorder__item--dragged': isDragged,
|
|
7065
7155
|
'designbase-reorder__item--drag-over': isDragOver,
|
|
7066
7156
|
'designbase-reorder__item--disabled': isDisabled,
|
|
7157
|
+
// 드래그 방향에 따른 클래스
|
|
7158
|
+
'designbase-reorder__item--drag-down': isDraggingDown,
|
|
7159
|
+
'designbase-reorder__item--drag-up': isDraggingUp,
|
|
7160
|
+
'designbase-reorder__item--drag-right': isDraggingRight,
|
|
7161
|
+
'designbase-reorder__item--drag-left': isDraggingLeft,
|
|
7067
7162
|
});
|
|
7068
7163
|
return (jsxRuntimeExports.jsxs("div", { ref: (el) => {
|
|
7069
7164
|
if (el) {
|
|
@@ -7716,7 +7811,7 @@ const VideoPlayer = ({ src, poster, title, description, size = 'm', variant = 'd
|
|
|
7716
7811
|
'designbase-video-player--show-controls': showControlsOverlay,
|
|
7717
7812
|
}, className);
|
|
7718
7813
|
const currentSrc = playlist.length > 0 ? playlist[playlistIndex] : src;
|
|
7719
|
-
return (jsxRuntimeExports.jsxs("div", { ref: containerRef, className: classes, onMouseEnter: () => setShowControlsOverlay(true), onMouseLeave: () => setShowControlsOverlay(false), children: [jsxRuntimeExports.jsxs("video", { ref: videoRef, src: currentSrc, poster: poster, autoPlay: autoPlay, loop: loop, muted: muted, playsInline: true, className: "designbase-video-player__video", children: [subtitles.map((subtitle, index) => (jsxRuntimeExports.jsx("track", { kind: "subtitles", src: subtitle.src, srcLang: subtitle.lang, label: subtitle.label, default: subtitle.label === currentSubtitle }, index))), "\uBE44\uB514\uC624\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBE0C\uB77C\uC6B0\uC800\uC785\uB2C8\uB2E4."] }), isLoading && (jsxRuntimeExports.jsx("div", { className: "designbase-video-player__loading", children: jsxRuntimeExports.jsx("div", { className: "designbase-video-player__spinner" }) })), error && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__error", children: [jsxRuntimeExports.jsx("p", { children: error }), jsxRuntimeExports.jsx("button", { onClick: () => window.location.reload(), children: "\uB2E4\uC2DC \uC2DC\uB3C4" })] })), showControls && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__overlay", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__top-controls", children: [title && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__title", children: [jsxRuntimeExports.jsx("h3", { children: title }), description && jsxRuntimeExports.jsx("p", { children: description })] })), showSettings && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__settings", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__settings-button", onClick: () => setShowSettingsMenu(!showSettingsMenu), children: jsxRuntimeExports.jsx(icons.SettingsIcon, { size: 20 }) }), showSettingsMenu && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__settings-menu", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__setting-group", children: [jsxRuntimeExports.jsx("label", { children: "\uC7AC\uC0DD \uC18D\uB3C4" }), jsxRuntimeExports.jsx("select", { value: playbackRate, onChange: (e) => handlePlaybackRateChange(parseFloat(e.target.value)), children: playbackRates.map(rate => (jsxRuntimeExports.jsxs("option", { value: rate, children: [rate, "x"] }, rate))) })] }), qualities.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__setting-group", children: [jsxRuntimeExports.jsx("label", { children: "\uD488\uC9C8" }), jsxRuntimeExports.jsx("select", { value: currentQuality, onChange: (e) => handleQualityChange(e.target.value), children: qualities.map(quality => (jsxRuntimeExports.jsx("option", { value: quality.value, children: quality.label }, quality.value))) })] })), subtitles.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__setting-group", children: [jsxRuntimeExports.jsx("label", { children: "\uC790\uB9C9" }), jsxRuntimeExports.jsxs("select", { value: currentSubtitle, onChange: (e) => handleSubtitleChange(e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: "\uC790\uB9C9 \uC5C6\uC74C" }), subtitles.map(subtitle => (jsxRuntimeExports.jsx("option", { value: subtitle.label, children: subtitle.label }, subtitle.label)))] })] }))] }))] }))] }), jsxRuntimeExports.jsx("div", { className: "designbase-video-player__center-controls", children: jsxRuntimeExports.jsx("button", { className: "designbase-video-player__play-button", onClick: togglePlay, children: isPlaying ? jsxRuntimeExports.jsx(icons.PauseIcon, { size: 48 }) : jsxRuntimeExports.jsx(icons.PlayIcon, { size: 48 }) }) }), jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__bottom-controls", children: [showProgress && (jsxRuntimeExports.jsxs("div", { ref: progressRef, className: "designbase-video-player__progress", onClick: handleProgressChange, children: [jsxRuntimeExports.jsx("div", { className: "designbase-video-player__progress-bar", style: { width: `${progressPercentage}%` } }), jsxRuntimeExports.jsx("div", { className: "designbase-video-player__progress-handle", style: { left: `${progressPercentage}%` } })] })), jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__controls", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__left-controls", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: togglePlay, children: isPlaying ? jsxRuntimeExports.jsx(icons.PauseIcon, { size: 20 }) : jsxRuntimeExports.jsx(icons.PlayIcon, { size: 20 }) }), showVolume && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__volume", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: toggleMute, onMouseEnter: () => setShowVolumeSlider(true), onMouseLeave: () => setShowVolumeSlider(false), children: isMuted || volume === 0 ? jsxRuntimeExports.jsx(icons.MuteFilledIcon, { size: 20 }) : jsxRuntimeExports.jsx(icons.VolumeUpIcon, { size: 20 }) }), showVolumeSlider && (jsxRuntimeExports.jsx("div", { ref: volumeRef, className: "designbase-video-player__volume-slider", children: jsxRuntimeExports.jsx("input", { type: "range", min: "0", max: "1", step: "0.1", value: volume, onChange: handleVolumeSliderChange }) }))] })), showTime && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__time", children: [jsxRuntimeExports.jsx("span", { children: formatTime(currentTime) }), jsxRuntimeExports.jsx("span", { children: "/" }), jsxRuntimeExports.jsx("span", { children: formatTime(duration) })] }))] }), jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__right-controls", children: [playlist.length > 1 && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__playlist-controls", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", disabled: playlistIndex === 0, onClick: () => handlePlaylistChange(playlistIndex - 1), children: jsxRuntimeExports.jsx(icons.ChevronLeftIcon, { size: 16 }) }), jsxRuntimeExports.jsxs("span", { children: [playlistIndex + 1, " / ", playlist.length] }), jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", disabled: playlistIndex === playlist.length - 1, onClick: () => handlePlaylistChange(playlistIndex + 1), children: jsxRuntimeExports.jsx(icons.ChevronRightIcon, { size: 16 }) })] })), enableFullscreen && (jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: toggleFullscreen, children: isFullscreen ? jsxRuntimeExports.jsx(icons.ShrinkIcon, { size: 20 }) : jsxRuntimeExports.jsx(icons.ExpandIcon, { size: 20 }) }))] })] })] })] }))] }));
|
|
7814
|
+
return (jsxRuntimeExports.jsxs("div", { ref: containerRef, className: classes, onMouseEnter: () => setShowControlsOverlay(true), onMouseLeave: () => setShowControlsOverlay(false), children: [jsxRuntimeExports.jsxs("video", { ref: videoRef, src: currentSrc, poster: poster, autoPlay: autoPlay, loop: loop, muted: muted, playsInline: true, className: "designbase-video-player__video", children: [subtitles.map((subtitle, index) => (jsxRuntimeExports.jsx("track", { kind: "subtitles", src: subtitle.src, srcLang: subtitle.lang, label: subtitle.label, default: subtitle.label === currentSubtitle }, index))), "\uBE44\uB514\uC624\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBE0C\uB77C\uC6B0\uC800\uC785\uB2C8\uB2E4."] }), isLoading && (jsxRuntimeExports.jsx("div", { className: "designbase-video-player__loading", children: jsxRuntimeExports.jsx("div", { className: "designbase-video-player__spinner" }) })), error && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__error", children: [jsxRuntimeExports.jsx("p", { children: error }), jsxRuntimeExports.jsx("button", { onClick: () => window.location.reload(), children: "\uB2E4\uC2DC \uC2DC\uB3C4" })] })), showControls && (jsxRuntimeExports.jsx("div", { className: "designbase-video-player__dim-overlay" })), showControls && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__overlay", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__top-controls", children: [title && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__title", children: [jsxRuntimeExports.jsx("h3", { children: title }), description && jsxRuntimeExports.jsx("p", { children: description })] })), showSettings && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__settings", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__settings-button", onClick: () => setShowSettingsMenu(!showSettingsMenu), children: jsxRuntimeExports.jsx(icons.SettingsIcon, { size: 20 }) }), showSettingsMenu && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__settings-menu", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__setting-group", children: [jsxRuntimeExports.jsx("label", { children: "\uC7AC\uC0DD \uC18D\uB3C4" }), jsxRuntimeExports.jsx("select", { value: playbackRate, onChange: (e) => handlePlaybackRateChange(parseFloat(e.target.value)), children: playbackRates.map(rate => (jsxRuntimeExports.jsxs("option", { value: rate, children: [rate, "x"] }, rate))) })] }), qualities.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__setting-group", children: [jsxRuntimeExports.jsx("label", { children: "\uD488\uC9C8" }), jsxRuntimeExports.jsx("select", { value: currentQuality, onChange: (e) => handleQualityChange(e.target.value), children: qualities.map(quality => (jsxRuntimeExports.jsx("option", { value: quality.value, children: quality.label }, quality.value))) })] })), subtitles.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__setting-group", children: [jsxRuntimeExports.jsx("label", { children: "\uC790\uB9C9" }), jsxRuntimeExports.jsxs("select", { value: currentSubtitle, onChange: (e) => handleSubtitleChange(e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: "\uC790\uB9C9 \uC5C6\uC74C" }), subtitles.map(subtitle => (jsxRuntimeExports.jsx("option", { value: subtitle.label, children: subtitle.label }, subtitle.label)))] })] }))] }))] }))] }), jsxRuntimeExports.jsx("div", { className: "designbase-video-player__center-controls", children: jsxRuntimeExports.jsx("button", { className: "designbase-video-player__play-button", onClick: togglePlay, children: isPlaying ? jsxRuntimeExports.jsx(icons.PauseIcon, { size: 48 }) : jsxRuntimeExports.jsx(icons.PlayIcon, { size: 48 }) }) }), jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__bottom-controls", children: [showProgress && (jsxRuntimeExports.jsxs("div", { ref: progressRef, className: "designbase-video-player__progress", onClick: handleProgressChange, children: [jsxRuntimeExports.jsx("div", { className: "designbase-video-player__progress-bar", style: { width: `${progressPercentage}%` } }), jsxRuntimeExports.jsx("div", { className: "designbase-video-player__progress-handle", style: { left: `${progressPercentage}%` } })] })), jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__controls", children: [jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__left-controls", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: togglePlay, children: isPlaying ? jsxRuntimeExports.jsx(icons.PauseIcon, { size: 20 }) : jsxRuntimeExports.jsx(icons.PlayIcon, { size: 20 }) }), showVolume && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__volume", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: toggleMute, onMouseEnter: () => setShowVolumeSlider(true), onMouseLeave: () => setShowVolumeSlider(false), children: isMuted || volume === 0 ? jsxRuntimeExports.jsx(icons.MuteFilledIcon, { size: 20 }) : jsxRuntimeExports.jsx(icons.VolumeUpIcon, { size: 20 }) }), showVolumeSlider && (jsxRuntimeExports.jsx("div", { ref: volumeRef, className: "designbase-video-player__volume-slider", children: jsxRuntimeExports.jsx("input", { type: "range", min: "0", max: "1", step: "0.1", value: volume, onChange: handleVolumeSliderChange }) }))] })), showTime && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__time", children: [jsxRuntimeExports.jsx("span", { children: formatTime(currentTime) }), jsxRuntimeExports.jsx("span", { children: "/" }), jsxRuntimeExports.jsx("span", { children: formatTime(duration) })] }))] }), jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__right-controls", children: [playlist.length > 1 && (jsxRuntimeExports.jsxs("div", { className: "designbase-video-player__playlist-controls", children: [jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", disabled: playlistIndex === 0, onClick: () => handlePlaylistChange(playlistIndex - 1), children: jsxRuntimeExports.jsx(icons.ChevronLeftIcon, { size: 16 }) }), jsxRuntimeExports.jsxs("span", { children: [playlistIndex + 1, " / ", playlist.length] }), jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", disabled: playlistIndex === playlist.length - 1, onClick: () => handlePlaylistChange(playlistIndex + 1), children: jsxRuntimeExports.jsx(icons.ChevronRightIcon, { size: 16 }) })] })), enableFullscreen && (jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: toggleFullscreen, children: isFullscreen ? jsxRuntimeExports.jsx(icons.ShrinkIcon, { size: 20 }) : jsxRuntimeExports.jsx(icons.ExpandIcon, { size: 20 }) }))] })] })] })] }))] }));
|
|
7720
7815
|
};
|
|
7721
7816
|
|
|
7722
7817
|
const AudioPlayer = ({ src, title, artist, album, albumArt, size = 'm', variant = 'default', theme = 'auto', autoPlay = false, loop = false, muted = false, showControls = true, enableKeyboard = true, showProgress = true, showTime = true, showVolume = true, showSettings = false, playlist = [], currentIndex = 0, autoPause = true, playbackRates = [0.5, 0.75, 1, 1.25, 1.5, 2], defaultPlaybackRate = 1, repeatMode = 'none', shuffle = false, onPlay, onPause, onEnded, onTimeUpdate, onVolumeChange, onPlaylistChange, onPlaybackRateChange, onRepeatModeChange, onShuffleChange, onError, className, }) => {
|
|
@@ -8445,7 +8540,7 @@ const Toolbar = ({ items, size = 'm', variant = 'default', position = 'top', ful
|
|
|
8445
8540
|
return (jsxRuntimeExports.jsxs("div", { className: clsx('designbase-toolbar__item', 'designbase-toolbar__item--dropdown', {
|
|
8446
8541
|
'designbase-toolbar__item--open': openDropdown === item.id,
|
|
8447
8542
|
'designbase-toolbar__item--disabled': item.disabled,
|
|
8448
|
-
}), children: [jsxRuntimeExports.jsxs("button", { className: "designbase-toolbar__dropdown-trigger", onClick: () => handleItemClick(item), disabled: item.disabled, title: item.tooltip, children: [item.icon && (jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__item-icon", children: item.icon })), item.label && (jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__item-label", children: item.label })), jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__dropdown-arrow", children: jsxRuntimeExports.jsx(
|
|
8543
|
+
}), children: [jsxRuntimeExports.jsxs("button", { className: "designbase-toolbar__dropdown-trigger", onClick: () => handleItemClick(item), disabled: item.disabled, title: item.tooltip, children: [item.icon && (jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__item-icon", children: item.icon })), item.label && (jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__item-label", children: item.label })), jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__dropdown-arrow", children: jsxRuntimeExports.jsx(icons.ChevronDownIcon, { size: 12 }) })] }), openDropdown === item.id && item.options && (jsxRuntimeExports.jsx("div", { className: "designbase-toolbar__dropdown-menu", children: item.options.map((option) => (jsxRuntimeExports.jsxs("button", { className: clsx('designbase-toolbar__dropdown-option', {
|
|
8449
8544
|
'designbase-toolbar__dropdown-option--selected': item.selectedValue === option.value,
|
|
8450
8545
|
'designbase-toolbar__dropdown-option--disabled': option.disabled,
|
|
8451
8546
|
}), onClick: () => handleOptionClick(item, option.value), disabled: option.disabled, children: [option.icon && (jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__dropdown-option-icon", children: option.icon })), jsxRuntimeExports.jsx("span", { className: "designbase-toolbar__dropdown-option-label", children: option.label })] }, option.value))) }))] }, item.id));
|
|
@@ -11803,8 +11898,26 @@ const ResizablePanels = ({ children, initialWidth = '100%', initialHeight = '100
|
|
|
11803
11898
|
return { ...baseStyle, bottom: 0, right: 0 };
|
|
11804
11899
|
}
|
|
11805
11900
|
}, [handlePosition, handleSize, handleColor, direction]);
|
|
11806
|
-
// 기본 리사이즈 핸들 아이콘
|
|
11807
|
-
const
|
|
11901
|
+
// 방향에 따른 기본 리사이즈 핸들 아이콘
|
|
11902
|
+
const getDefaultHandleIcon = () => {
|
|
11903
|
+
const iconSize = Math.max(12, handleSize - 4);
|
|
11904
|
+
switch (handlePosition) {
|
|
11905
|
+
case 'bottom-right':
|
|
11906
|
+
return jsxRuntimeExports.jsx(icons.ArrowDownRightIcon, { size: iconSize });
|
|
11907
|
+
case 'bottom-left':
|
|
11908
|
+
return jsxRuntimeExports.jsx(icons.ArrowDownLeftIcon, { size: iconSize });
|
|
11909
|
+
case 'top-right':
|
|
11910
|
+
return jsxRuntimeExports.jsx(icons.ArrowUpRightIcon, { size: iconSize });
|
|
11911
|
+
case 'top-left':
|
|
11912
|
+
return jsxRuntimeExports.jsx(icons.ArrowUpLeftIcon, { size: iconSize });
|
|
11913
|
+
case 'right':
|
|
11914
|
+
return jsxRuntimeExports.jsx(icons.ArrowRightIcon, { size: iconSize });
|
|
11915
|
+
case 'bottom':
|
|
11916
|
+
return jsxRuntimeExports.jsx(icons.ArrowDownIcon, { size: iconSize });
|
|
11917
|
+
default:
|
|
11918
|
+
return direction === 'both' ? jsxRuntimeExports.jsx(icons.MoveIcon, { size: iconSize }) : jsxRuntimeExports.jsx(icons.ExpandIcon, { size: iconSize });
|
|
11919
|
+
}
|
|
11920
|
+
};
|
|
11808
11921
|
const classes = classNames('designbase-resizable-panels', {
|
|
11809
11922
|
'designbase-resizable-panels--resizing': isResizing,
|
|
11810
11923
|
'designbase-resizable-panels--border': showBorder,
|
|
@@ -11822,7 +11935,7 @@ const ResizablePanels = ({ children, initialWidth = '100%', initialHeight = '100
|
|
|
11822
11935
|
}, onMouseLeave: (e) => {
|
|
11823
11936
|
const target = e.currentTarget;
|
|
11824
11937
|
target.style.backgroundColor = handleColor;
|
|
11825
|
-
}, children: handleIcon ||
|
|
11938
|
+
}, children: handleIcon || getDefaultHandleIcon() })] }));
|
|
11826
11939
|
};
|
|
11827
11940
|
|
|
11828
11941
|
/**
|