@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.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 (jsxRuntimeExports.jsx("div", { className: "designbase-spinner__pulse" }));
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, isRequired = false, hasLabel = true, size = 'm', children, className, name, value, onChange, ...props }, forwardedRef) => {
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': !hasLabel,
3678
+ 'designbase-toggle--no-label': !children,
3679
3679
  }, className);
3680
- return (jsxRuntimeExports.jsxs("button", { ...props, ref: forwardedRef, name: name, value: value, 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 })] }));
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: 'danger',
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
- const renderNavItem = (item) => (jsxRuntimeExports.jsx("li", { className: "designbase-navbar__nav-item", children: jsxRuntimeExports.jsx(MenuItem, { ...item, type: "inline", style: "dropdown", onClick: () => handleItemClick(item), onChildClick: (child) => handleItemClick(child) }) }, item.id));
4711
- 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("i", { className: "designbase-icon-chevron-down" })] }), 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', {
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, children: logo || jsxRuntimeExports.jsx(Logo, { size: size === 's' ? 's' : size === 'l' ? 'l' : 'm' }) }), collapsible && (jsxRuntimeExports.jsx("button", { className: "designbase-sidebar__toggle", onClick: handleToggle, "aria-label": collapsed ? '사이드바 펼치기' : '사이드바 접기', children: jsxRuntimeExports.jsx("i", { className: clsx('designbase-sidebar__toggle-icon', 'designbase-icon-chevron-left', {
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", 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', {
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", 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() })) }))] }) }));
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
- const triggerRef = React.useRef(null);
5377
+ // 🔑 DOM 래퍼(ref/이벤트가 항상 붙도록)
5378
+ const triggerWrapperRef = React.useRef(null);
5306
5379
  const tooltipRef = React.useRef(null);
5307
- const timeoutRef = React.useRef();
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 (!triggerRef.current || !tooltipRef.current)
5390
+ if (!triggerWrapperRef.current || !tooltipRef.current)
5311
5391
  return;
5312
- const triggerRect = triggerRef.current.getBoundingClientRect();
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 + (triggerRect.width / 2) - (tooltipRect.width / 2);
5326
- arrowTop = tooltipRect.height;
5327
- arrowLeft = tooltipRect.width / 2 - 4;
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
- arrowTop = tooltipRect.height;
5333
- arrowLeft = 12;
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
- arrowTop = tooltipRect.height;
5339
- arrowLeft = tooltipRect.width - 12;
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 + (triggerRect.width / 2) - (tooltipRect.width / 2);
5344
- arrowTop = -4;
5345
- arrowLeft = tooltipRect.width / 2 - 4;
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
- arrowTop = -4;
5351
- arrowLeft = 12;
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
- arrowTop = -4;
5357
- arrowLeft = tooltipRect.width - 12;
5441
+ // CSS에서 화살표는 자동으로 위치하므로 스타일 제거
5442
+ arrowTop = 0;
5443
+ arrowLeft = 0;
5358
5444
  break;
5359
5445
  case 'left':
5360
- top = triggerRect.top + scrollY + (triggerRect.height / 2) - (tooltipRect.height / 2);
5446
+ top = triggerRect.top + scrollY + triggerRect.height / 2 - tooltipRect.height / 2;
5361
5447
  left = triggerRect.left + scrollX - tooltipRect.width - 8;
5362
- arrowTop = tooltipRect.height / 2 - 4;
5363
- arrowLeft = tooltipRect.width;
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
- arrowTop = 12;
5369
- arrowLeft = tooltipRect.width;
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
- arrowTop = tooltipRect.height - 12;
5375
- arrowLeft = tooltipRect.width;
5462
+ // CSS에서 화살표는 자동으로 위치하므로 스타일 제거
5463
+ arrowTop = 0;
5464
+ arrowLeft = 0;
5376
5465
  break;
5377
5466
  case 'right':
5378
- top = triggerRect.top + scrollY + (triggerRect.height / 2) - (tooltipRect.height / 2);
5467
+ top = triggerRect.top + scrollY + triggerRect.height / 2 - tooltipRect.height / 2;
5379
5468
  left = triggerRect.right + scrollX + 8;
5380
- arrowTop = tooltipRect.height / 2 - 4;
5381
- arrowLeft = -4;
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
- arrowTop = 12;
5387
- arrowLeft = -4;
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
- arrowTop = tooltipRect.height - 12;
5393
- arrowLeft = -4;
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
- if (timeoutRef.current) {
5443
- clearTimeout(timeoutRef.current);
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
- if (timeoutRef.current) {
5458
- clearTimeout(timeoutRef.current);
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
- // 이벤트 핸들러 - Tooltip은 항상 hover 기반
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
- if (timeoutRef.current) {
5500
- clearTimeout(timeoutRef.current);
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
- const classes = clsx('designbase-tooltip', `designbase-tooltip--${size}`, `designbase-tooltip--${variant}`, `designbase-tooltip--${position}`, {
5517
- 'designbase-tooltip--visible': isVisible,
5518
- 'designbase-tooltip--disabled': disabled,
5519
- }, className);
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.jsx("div", { className: "designbase-popover__content", children: content }), showArrow && (jsxRuntimeExports.jsx("div", { className: arrowClasses, style: arrowStyle }))] }))] }));
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
- const rect = dragElement.getBoundingClientRect();
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 !== index) {
6943
- setDragOverIndex(index);
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(dropIndex, 0, draggedItemData);
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, dropIndex);
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("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: jsxRuntimeExports.jsx("path", { d: "M3 4.5L6 7.5L9 4.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] }), 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', {
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 defaultHandleIcon = (jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", children: [jsxRuntimeExports.jsx("path", { d: "M12 12H8L10 10L12 12Z" }), jsxRuntimeExports.jsx("path", { d: "M8 8H4L6 6L8 8Z" }), jsxRuntimeExports.jsx("path", { d: "M4 4H0L2 2L4 4Z" })] }));
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 || defaultHandleIcon })] }));
11938
+ }, children: handleIcon || getDefaultHandleIcon() })] }));
11826
11939
  };
11827
11940
 
11828
11941
  /**