@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.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useRef, useCallback, useEffect, useMemo, useState, useContext, forwardRef, useId, createContext } from 'react';
|
|
2
2
|
import { flushSync, createPortal } from 'react-dom';
|
|
3
|
-
import { CloseIcon, ChevronUpIcon, ChevronDownIcon, SearchIcon, UserIcon,
|
|
3
|
+
import { CloseIcon, ChevronUpIcon, ChevronDownIcon, SearchIcon, UserIcon, ChevronRightIcon, ChevronLeftIcon, ArrowBarLeftIcon, ArrowBarRightIcon, ChevronsUpIcon, InfoFilledIcon, ErrorFilledIcon, WarningFilledIcon, CircleCheckFilledIcon, BulbIcon, CloudCloseIcon, BellActiveIcon, AwardIcon, GalleryIcon, ShareAltIcon, MailIcon, LinkIcon, CopyIcon, MoveIcon, MoreVerticalIcon, StarFilledIcon, StarHalfIcon, StarIcon, SettingsIcon, PauseIcon, PlayIcon, MuteFilledIcon, VolumeUpIcon, ShrinkIcon, ExpandIcon, RefreshIcon, RepeatIcon, VideoIcon, CodeIcon, WriteIcon, ShowIcon, HideIcon, UploadIcon, MinusIcon, PlusIcon, DownloadIcon, HeartIcon, BookmarkIcon, ArrowLeftIcon, ArrowRightIcon, ArrowDownIcon, ArrowUpLeftIcon, ArrowUpRightIcon, ArrowDownLeftIcon, ArrowDownRightIcon } from '@designbasekorea/icons';
|
|
4
4
|
|
|
5
5
|
function getDefaultExportFromCjs (x) {
|
|
6
6
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
@@ -3456,20 +3456,20 @@ const Spinner = ({ type = 'circular', size = 'm', color, speed = 1, label = '로
|
|
|
3456
3456
|
const renderSpinner = () => {
|
|
3457
3457
|
switch (type) {
|
|
3458
3458
|
case 'circular':
|
|
3459
|
-
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" })] }));
|
|
3459
|
+
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" })] }));
|
|
3460
3460
|
case 'dots':
|
|
3461
|
-
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" })] }));
|
|
3461
|
+
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" })] }));
|
|
3462
3462
|
case 'bars':
|
|
3463
|
-
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" })] }));
|
|
3463
|
+
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" })] }));
|
|
3464
3464
|
case 'pulse':
|
|
3465
|
-
return
|
|
3465
|
+
return jsxRuntimeExports.jsx("div", { className: "designbase-spinner__pulse", "aria-hidden": "true" });
|
|
3466
3466
|
case 'ripple':
|
|
3467
|
-
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" })] }));
|
|
3467
|
+
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" })] }));
|
|
3468
3468
|
default:
|
|
3469
3469
|
return null;
|
|
3470
3470
|
}
|
|
3471
3471
|
};
|
|
3472
|
-
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 }))] }));
|
|
3472
|
+
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 }))] }));
|
|
3473
3473
|
};
|
|
3474
3474
|
Spinner.displayName = 'Spinner';
|
|
3475
3475
|
|
|
@@ -3655,7 +3655,7 @@ const Checkbox = forwardRef(({ isSelected, defaultSelected, isIndeterminate = fa
|
|
|
3655
3655
|
});
|
|
3656
3656
|
Checkbox.displayName = 'Checkbox';
|
|
3657
3657
|
|
|
3658
|
-
const Toggle = forwardRef(({ isSelected, defaultSelected, isDisabled = false, isReadOnly = false,
|
|
3658
|
+
const Toggle = forwardRef(({ isSelected, defaultSelected, isDisabled = false, isReadOnly = false, size = 'm', children, className, onChange, ...props }, forwardedRef) => {
|
|
3659
3659
|
const [selected, setSelected] = React.useState(isSelected ?? defaultSelected ?? false);
|
|
3660
3660
|
React.useEffect(() => {
|
|
3661
3661
|
if (isSelected !== undefined) {
|
|
@@ -3673,9 +3673,9 @@ const Toggle = forwardRef(({ isSelected, defaultSelected, isDisabled = false, is
|
|
|
3673
3673
|
'designbase-toggle--selected': selected,
|
|
3674
3674
|
'designbase-toggle--disabled': isDisabled,
|
|
3675
3675
|
'designbase-toggle--readonly': isReadOnly,
|
|
3676
|
-
'designbase-toggle--no-label': !
|
|
3676
|
+
'designbase-toggle--no-label': !children,
|
|
3677
3677
|
}, className);
|
|
3678
|
-
return (jsxRuntimeExports.jsxs("button", { ...props, ref: forwardedRef,
|
|
3678
|
+
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 })] }));
|
|
3679
3679
|
});
|
|
3680
3680
|
Toggle.displayName = 'Toggle';
|
|
3681
3681
|
|
|
@@ -3783,7 +3783,7 @@ const Toast = ({ id, status = 'info', title, description, icon: Icon, duration =
|
|
|
3783
3783
|
const getIconColor = () => {
|
|
3784
3784
|
const colorMap = {
|
|
3785
3785
|
success: 'success',
|
|
3786
|
-
error: '
|
|
3786
|
+
error: 'error',
|
|
3787
3787
|
warning: 'warning',
|
|
3788
3788
|
info: 'info',
|
|
3789
3789
|
};
|
|
@@ -4458,77 +4458,6 @@ const Progressbar = ({ value, max = 100, min = 0, size = 'm', variant = 'default
|
|
|
4458
4458
|
};
|
|
4459
4459
|
Progressbar.displayName = 'Progressbar';
|
|
4460
4460
|
|
|
4461
|
-
const Badge = ({ children, size = 'm', variant = 'primary', style = 'text', count, maxCount = 99, disabled = false, className, ...props }) => {
|
|
4462
|
-
// 숫자 스타일일 때 count 값을 사용
|
|
4463
|
-
const displayContent = style === 'number' && count !== undefined
|
|
4464
|
-
? (count > maxCount ? `${maxCount}+` : count.toString())
|
|
4465
|
-
: children;
|
|
4466
|
-
const classes = clsx('designbase-badge', `designbase-badge--${size}`, `designbase-badge--${variant}`, `designbase-badge--${style}`, {
|
|
4467
|
-
'designbase-badge--disabled': disabled,
|
|
4468
|
-
}, className);
|
|
4469
|
-
return (jsxRuntimeExports.jsx("span", { className: classes, ...props, children: displayContent }));
|
|
4470
|
-
};
|
|
4471
|
-
Badge.displayName = 'Badge';
|
|
4472
|
-
|
|
4473
|
-
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, }) => {
|
|
4474
|
-
const [internalExpanded, setInternalExpanded] = useState(expanded);
|
|
4475
|
-
// expanded prop이 변경될 때 internalExpanded 업데이트
|
|
4476
|
-
useEffect(() => {
|
|
4477
|
-
setInternalExpanded(expanded);
|
|
4478
|
-
}, [expanded]);
|
|
4479
|
-
const handleClick = (e) => {
|
|
4480
|
-
e.preventDefault();
|
|
4481
|
-
if (disabled)
|
|
4482
|
-
return;
|
|
4483
|
-
if (expandable && subItems && subItems.length > 0) {
|
|
4484
|
-
setInternalExpanded(!internalExpanded);
|
|
4485
|
-
}
|
|
4486
|
-
onClick?.({
|
|
4487
|
-
id,
|
|
4488
|
-
label,
|
|
4489
|
-
href,
|
|
4490
|
-
icon: Icon,
|
|
4491
|
-
active,
|
|
4492
|
-
disabled,
|
|
4493
|
-
badge,
|
|
4494
|
-
badgeColor,
|
|
4495
|
-
variant,
|
|
4496
|
-
type,
|
|
4497
|
-
size,
|
|
4498
|
-
subItems,
|
|
4499
|
-
expanded: internalExpanded,
|
|
4500
|
-
expandable,
|
|
4501
|
-
onClick,
|
|
4502
|
-
onChildClick,
|
|
4503
|
-
className,
|
|
4504
|
-
});
|
|
4505
|
-
};
|
|
4506
|
-
const handleChildClick = (child) => {
|
|
4507
|
-
if (child.disabled)
|
|
4508
|
-
return;
|
|
4509
|
-
onChildClick?.(child);
|
|
4510
|
-
};
|
|
4511
|
-
const isExpanded = expandable ? internalExpanded : expanded;
|
|
4512
|
-
const hasChildren = subItems && subItems.length > 0;
|
|
4513
|
-
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}`, {
|
|
4514
|
-
'designbase-menu-item--active': active,
|
|
4515
|
-
'designbase-menu-item--disabled': disabled,
|
|
4516
|
-
'designbase-menu-item--expandable': expandable,
|
|
4517
|
-
'designbase-menu-item--expanded': isExpanded,
|
|
4518
|
-
'designbase-menu-item--with-children': hasChildren,
|
|
4519
|
-
'designbase-menu-item--with-badge': badge,
|
|
4520
|
-
'designbase-menu-item--with-icon': Icon,
|
|
4521
|
-
}, className);
|
|
4522
|
-
const contentClasses = clsx('designbase-menu-item__content', {
|
|
4523
|
-
'designbase-menu-item__content--clickable': onClick || href,
|
|
4524
|
-
});
|
|
4525
|
-
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}`, {
|
|
4526
|
-
'designbase-menu-item__icon--active': active,
|
|
4527
|
-
'designbase-menu-item__icon--disabled': disabled,
|
|
4528
|
-
}), 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(ChevronUpIcon, { size: 16 })) : (jsxRuntimeExports.jsx(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))) }))] }));
|
|
4529
|
-
};
|
|
4530
|
-
MenuItem.displayName = 'MenuItem';
|
|
4531
|
-
|
|
4532
4461
|
const SearchBar = ({ value, defaultValue = '', placeholder = '검색...', size = 'm', variant = 'default', disabled = false, readOnly = false, fullWidth = false, searchIcon: SearchIconComponent = SearchIcon, clearIcon: ClearIconComponent = CloseIcon, onChange, onSearch, onFocus, onBlur, onKeyDown, className, ...props }) => {
|
|
4533
4462
|
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
4534
4463
|
const inputRef = useRef(null);
|
|
@@ -4573,6 +4502,18 @@ const SearchBar = ({ value, defaultValue = '', placeholder = '검색...', size =
|
|
|
4573
4502
|
};
|
|
4574
4503
|
SearchBar.displayName = 'SearchBar';
|
|
4575
4504
|
|
|
4505
|
+
const Badge = ({ children, size = 'm', variant = 'primary', style = 'text', count, maxCount = 99, disabled = false, className, ...props }) => {
|
|
4506
|
+
// 숫자 스타일일 때 count 값을 사용
|
|
4507
|
+
const displayContent = style === 'number' && count !== undefined
|
|
4508
|
+
? (count > maxCount ? `${maxCount}+` : count.toString())
|
|
4509
|
+
: children;
|
|
4510
|
+
const classes = clsx('designbase-badge', `designbase-badge--${size}`, `designbase-badge--${variant}`, `designbase-badge--${style}`, {
|
|
4511
|
+
'designbase-badge--disabled': disabled,
|
|
4512
|
+
}, className);
|
|
4513
|
+
return (jsxRuntimeExports.jsx("span", { className: classes, ...props, children: displayContent }));
|
|
4514
|
+
};
|
|
4515
|
+
Badge.displayName = 'Badge';
|
|
4516
|
+
|
|
4576
4517
|
const Avatar = ({ src, alt, initials, icon, size = 'm', variant = 'circle', status, badge, badgeMaxCount = 99, badgeVariant = 'danger', badgeStyle = 'number', badgeText, onClick, disabled = false, className, ...props }) => {
|
|
4577
4518
|
const [imageError, setImageError] = useState(false);
|
|
4578
4519
|
const [imageLoading, setImageLoading] = useState(true);
|
|
@@ -4705,8 +4646,65 @@ const Navbar = ({ size = 'm', variant = 'default', position = 'static', logo, on
|
|
|
4705
4646
|
const containerClasses = clsx('designbase-navbar__container', {
|
|
4706
4647
|
'designbase-navbar__container--full-width': fullWidth,
|
|
4707
4648
|
});
|
|
4708
|
-
|
|
4709
|
-
|
|
4649
|
+
// 재귀적으로 메뉴 아이템을 렌더링하는 함수
|
|
4650
|
+
const renderMenuItem = (item, depth = 0) => {
|
|
4651
|
+
const hasChildren = item.children && item.children.length > 0;
|
|
4652
|
+
const isFirstLevel = depth === 0;
|
|
4653
|
+
const isSecondLevel = depth === 1;
|
|
4654
|
+
if (isFirstLevel) {
|
|
4655
|
+
// 1depth - 메인 네비게이션
|
|
4656
|
+
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', {
|
|
4657
|
+
'designbase-navbar__nav-link--active': item.active,
|
|
4658
|
+
'designbase-navbar__nav-link--disabled': item.disabled,
|
|
4659
|
+
}), onClick: () => handleItemClick(item), disabled: item.disabled, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label, jsxRuntimeExports.jsx(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', {
|
|
4660
|
+
'designbase-navbar__nav-link--active': item.active,
|
|
4661
|
+
'designbase-navbar__nav-link--disabled': item.disabled,
|
|
4662
|
+
}), onClick: (e) => {
|
|
4663
|
+
if (item.disabled) {
|
|
4664
|
+
e.preventDefault();
|
|
4665
|
+
return;
|
|
4666
|
+
}
|
|
4667
|
+
handleItemClick(item);
|
|
4668
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label] })) }, item.id));
|
|
4669
|
+
}
|
|
4670
|
+
else if (isSecondLevel) {
|
|
4671
|
+
// 2depth - 드롭다운 메뉴
|
|
4672
|
+
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', {
|
|
4673
|
+
'designbase-navbar__dropdown-item--active': item.active,
|
|
4674
|
+
'designbase-navbar__dropdown-item--disabled': item.disabled,
|
|
4675
|
+
}), onClick: (e) => {
|
|
4676
|
+
if (item.disabled) {
|
|
4677
|
+
e.preventDefault();
|
|
4678
|
+
return;
|
|
4679
|
+
}
|
|
4680
|
+
handleItemClick(item);
|
|
4681
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label, jsxRuntimeExports.jsx(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', {
|
|
4682
|
+
'designbase-navbar__dropdown-item--active': item.active,
|
|
4683
|
+
'designbase-navbar__dropdown-item--disabled': item.disabled,
|
|
4684
|
+
}), onClick: (e) => {
|
|
4685
|
+
if (item.disabled) {
|
|
4686
|
+
e.preventDefault();
|
|
4687
|
+
return;
|
|
4688
|
+
}
|
|
4689
|
+
handleItemClick(item);
|
|
4690
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label] })) }, item.id));
|
|
4691
|
+
}
|
|
4692
|
+
else {
|
|
4693
|
+
// 3depth 이상 - 서브메뉴
|
|
4694
|
+
return (jsxRuntimeExports.jsx("li", { children: jsxRuntimeExports.jsxs("a", { href: item.href, className: clsx('designbase-navbar__dropdown-item', {
|
|
4695
|
+
'designbase-navbar__dropdown-item--active': item.active,
|
|
4696
|
+
'designbase-navbar__dropdown-item--disabled': item.disabled,
|
|
4697
|
+
}), onClick: (e) => {
|
|
4698
|
+
if (item.disabled) {
|
|
4699
|
+
e.preventDefault();
|
|
4700
|
+
return;
|
|
4701
|
+
}
|
|
4702
|
+
handleItemClick(item);
|
|
4703
|
+
}, children: [item.icon && React.createElement(item.icon, { size: iconSize, color: 'currentColor' }), item.label] }) }, item.id));
|
|
4704
|
+
}
|
|
4705
|
+
};
|
|
4706
|
+
const renderNavItem = (item) => renderMenuItem(item, 0);
|
|
4707
|
+
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(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', {
|
|
4710
4708
|
'designbase-navbar__user-dropdown-item--disabled': item.disabled,
|
|
4711
4709
|
}), onClick: (e) => {
|
|
4712
4710
|
if (item.disabled) {
|
|
@@ -4744,6 +4742,65 @@ const Navbar = ({ size = 'm', variant = 'default', position = 'static', logo, on
|
|
|
4744
4742
|
};
|
|
4745
4743
|
Navbar.displayName = 'Navbar';
|
|
4746
4744
|
|
|
4745
|
+
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, }) => {
|
|
4746
|
+
const [internalExpanded, setInternalExpanded] = useState(expanded);
|
|
4747
|
+
// expanded prop이 변경될 때 internalExpanded 업데이트
|
|
4748
|
+
useEffect(() => {
|
|
4749
|
+
setInternalExpanded(expanded);
|
|
4750
|
+
}, [expanded]);
|
|
4751
|
+
const handleClick = (e) => {
|
|
4752
|
+
e.preventDefault();
|
|
4753
|
+
if (disabled)
|
|
4754
|
+
return;
|
|
4755
|
+
if (expandable && subItems && subItems.length > 0) {
|
|
4756
|
+
setInternalExpanded(!internalExpanded);
|
|
4757
|
+
}
|
|
4758
|
+
onClick?.({
|
|
4759
|
+
id,
|
|
4760
|
+
label,
|
|
4761
|
+
href,
|
|
4762
|
+
icon: Icon,
|
|
4763
|
+
active,
|
|
4764
|
+
disabled,
|
|
4765
|
+
badge,
|
|
4766
|
+
badgeColor,
|
|
4767
|
+
variant,
|
|
4768
|
+
type,
|
|
4769
|
+
size,
|
|
4770
|
+
subItems,
|
|
4771
|
+
expanded: internalExpanded,
|
|
4772
|
+
expandable,
|
|
4773
|
+
onClick,
|
|
4774
|
+
onChildClick,
|
|
4775
|
+
className,
|
|
4776
|
+
});
|
|
4777
|
+
};
|
|
4778
|
+
const handleChildClick = (child) => {
|
|
4779
|
+
if (child.disabled)
|
|
4780
|
+
return;
|
|
4781
|
+
onChildClick?.(child);
|
|
4782
|
+
};
|
|
4783
|
+
const isExpanded = expandable ? internalExpanded : expanded;
|
|
4784
|
+
const hasChildren = subItems && subItems.length > 0;
|
|
4785
|
+
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}`, {
|
|
4786
|
+
'designbase-menu-item--active': active,
|
|
4787
|
+
'designbase-menu-item--disabled': disabled,
|
|
4788
|
+
'designbase-menu-item--expandable': expandable,
|
|
4789
|
+
'designbase-menu-item--expanded': isExpanded,
|
|
4790
|
+
'designbase-menu-item--with-children': hasChildren,
|
|
4791
|
+
'designbase-menu-item--with-badge': badge,
|
|
4792
|
+
'designbase-menu-item--with-icon': Icon,
|
|
4793
|
+
}, className);
|
|
4794
|
+
const contentClasses = clsx('designbase-menu-item__content', {
|
|
4795
|
+
'designbase-menu-item__content--clickable': onClick || href,
|
|
4796
|
+
});
|
|
4797
|
+
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}`, {
|
|
4798
|
+
'designbase-menu-item__icon--active': active,
|
|
4799
|
+
'designbase-menu-item__icon--disabled': disabled,
|
|
4800
|
+
}), 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(ChevronUpIcon, { size: 16 })) : (jsxRuntimeExports.jsx(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))) }))] }));
|
|
4801
|
+
};
|
|
4802
|
+
MenuItem.displayName = 'MenuItem';
|
|
4803
|
+
|
|
4747
4804
|
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 }) => {
|
|
4748
4805
|
const [expandedItems, setExpandedItems] = useState([]);
|
|
4749
4806
|
const handleToggle = () => {
|
|
@@ -4785,9 +4842,19 @@ const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onL
|
|
|
4785
4842
|
const hasChildren = item.children && item.children.length > 0;
|
|
4786
4843
|
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));
|
|
4787
4844
|
};
|
|
4788
|
-
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,
|
|
4845
|
+
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) => {
|
|
4846
|
+
if (onLogoClick && (e.key === 'Enter' || e.key === ' ')) {
|
|
4847
|
+
e.preventDefault();
|
|
4848
|
+
onLogoClick();
|
|
4849
|
+
}
|
|
4850
|
+
}, 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(ChevronLeftIcon, { className: clsx('designbase-sidebar__toggle-icon', {
|
|
4789
4851
|
'designbase-sidebar__toggle-icon--collapsed': collapsed,
|
|
4790
|
-
}) }) }))] }), 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",
|
|
4852
|
+
}) }) }))] }), 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) => {
|
|
4853
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
4854
|
+
e.preventDefault();
|
|
4855
|
+
onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
|
|
4856
|
+
}
|
|
4857
|
+
}, 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', {
|
|
4791
4858
|
'designbase-sidebar__user-menu-link--disabled': item.disabled,
|
|
4792
4859
|
}), onClick: (e) => {
|
|
4793
4860
|
if (item.disabled) {
|
|
@@ -4795,7 +4862,12 @@ const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onL
|
|
|
4795
4862
|
return;
|
|
4796
4863
|
}
|
|
4797
4864
|
handleUserMenuItemClick(item);
|
|
4798
|
-
}, children: [item.icon && React.createElement(item.icon, { size: 16 }), item.label] }) }, item.id))) }))] })), userProfile && collapsed && (jsxRuntimeExports.jsx("div", { className: "designbase-sidebar__user-collapsed",
|
|
4865
|
+
}, 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) => {
|
|
4866
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
4867
|
+
e.preventDefault();
|
|
4868
|
+
onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
|
|
4869
|
+
}
|
|
4870
|
+
}, 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() })) }))] }) }));
|
|
4799
4871
|
};
|
|
4800
4872
|
Sidebar.displayName = 'Sidebar';
|
|
4801
4873
|
|
|
@@ -5300,14 +5372,22 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5300
5372
|
const [isVisible, setIsVisible] = useState(false);
|
|
5301
5373
|
const [tooltipStyle, setTooltipStyle] = useState({});
|
|
5302
5374
|
const [arrowStyle, setArrowStyle] = useState({});
|
|
5303
|
-
|
|
5375
|
+
// 🔑 DOM 래퍼(ref/이벤트가 항상 붙도록)
|
|
5376
|
+
const triggerWrapperRef = useRef(null);
|
|
5304
5377
|
const tooltipRef = useRef(null);
|
|
5305
|
-
|
|
5378
|
+
// 브라우저 setTimeout은 number 반환
|
|
5379
|
+
const timeoutRef = useRef(null);
|
|
5380
|
+
const clearTimer = () => {
|
|
5381
|
+
if (timeoutRef.current !== null) {
|
|
5382
|
+
window.clearTimeout(timeoutRef.current);
|
|
5383
|
+
timeoutRef.current = null;
|
|
5384
|
+
}
|
|
5385
|
+
};
|
|
5306
5386
|
// 툴팁 위치 계산
|
|
5307
5387
|
const calculatePosition = useCallback(() => {
|
|
5308
|
-
if (!
|
|
5388
|
+
if (!triggerWrapperRef.current || !tooltipRef.current)
|
|
5309
5389
|
return;
|
|
5310
|
-
const triggerRect =
|
|
5390
|
+
const triggerRect = triggerWrapperRef.current.getBoundingClientRect();
|
|
5311
5391
|
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
5312
5392
|
const scrollX = window.pageXOffset || document.documentElement.scrollLeft;
|
|
5313
5393
|
const scrollY = window.pageYOffset || document.documentElement.scrollTop;
|
|
@@ -5320,129 +5400,131 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5320
5400
|
switch (position) {
|
|
5321
5401
|
case 'top':
|
|
5322
5402
|
top = triggerRect.top + scrollY - tooltipRect.height - 8;
|
|
5323
|
-
left = triggerRect.left + scrollX +
|
|
5324
|
-
|
|
5325
|
-
|
|
5403
|
+
left = triggerRect.left + scrollX + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
5404
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5405
|
+
arrowTop = 0;
|
|
5406
|
+
arrowLeft = 0;
|
|
5326
5407
|
break;
|
|
5327
5408
|
case 'top-start':
|
|
5328
5409
|
top = triggerRect.top + scrollY - tooltipRect.height - 8;
|
|
5329
5410
|
left = triggerRect.left + scrollX;
|
|
5330
|
-
|
|
5331
|
-
|
|
5411
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5412
|
+
arrowTop = 0;
|
|
5413
|
+
arrowLeft = 0;
|
|
5332
5414
|
break;
|
|
5333
5415
|
case 'top-end':
|
|
5334
5416
|
top = triggerRect.top + scrollY - tooltipRect.height - 8;
|
|
5335
5417
|
left = triggerRect.right + scrollX - tooltipRect.width;
|
|
5336
|
-
|
|
5337
|
-
|
|
5418
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5419
|
+
arrowTop = 0;
|
|
5420
|
+
arrowLeft = 0;
|
|
5338
5421
|
break;
|
|
5339
5422
|
case 'bottom':
|
|
5340
5423
|
top = triggerRect.bottom + scrollY + 8;
|
|
5341
|
-
left = triggerRect.left + scrollX +
|
|
5342
|
-
|
|
5343
|
-
|
|
5424
|
+
left = triggerRect.left + scrollX + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
5425
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5426
|
+
arrowTop = 0;
|
|
5427
|
+
arrowLeft = 0;
|
|
5344
5428
|
break;
|
|
5345
5429
|
case 'bottom-start':
|
|
5346
5430
|
top = triggerRect.bottom + scrollY + 8;
|
|
5347
5431
|
left = triggerRect.left + scrollX;
|
|
5348
|
-
|
|
5349
|
-
|
|
5432
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5433
|
+
arrowTop = 0;
|
|
5434
|
+
arrowLeft = 0;
|
|
5350
5435
|
break;
|
|
5351
5436
|
case 'bottom-end':
|
|
5352
5437
|
top = triggerRect.bottom + scrollY + 8;
|
|
5353
5438
|
left = triggerRect.right + scrollX - tooltipRect.width;
|
|
5354
|
-
|
|
5355
|
-
|
|
5439
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5440
|
+
arrowTop = 0;
|
|
5441
|
+
arrowLeft = 0;
|
|
5356
5442
|
break;
|
|
5357
5443
|
case 'left':
|
|
5358
|
-
top = triggerRect.top + scrollY +
|
|
5444
|
+
top = triggerRect.top + scrollY + triggerRect.height / 2 - tooltipRect.height / 2;
|
|
5359
5445
|
left = triggerRect.left + scrollX - tooltipRect.width - 8;
|
|
5360
|
-
|
|
5361
|
-
|
|
5446
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5447
|
+
arrowTop = 0;
|
|
5448
|
+
arrowLeft = 0;
|
|
5362
5449
|
break;
|
|
5363
5450
|
case 'left-start':
|
|
5364
5451
|
top = triggerRect.top + scrollY;
|
|
5365
5452
|
left = triggerRect.left + scrollX - tooltipRect.width - 8;
|
|
5366
|
-
|
|
5367
|
-
|
|
5453
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5454
|
+
arrowTop = 0;
|
|
5455
|
+
arrowLeft = 0;
|
|
5368
5456
|
break;
|
|
5369
5457
|
case 'left-end':
|
|
5370
5458
|
top = triggerRect.bottom + scrollY - tooltipRect.height;
|
|
5371
5459
|
left = triggerRect.left + scrollX - tooltipRect.width - 8;
|
|
5372
|
-
|
|
5373
|
-
|
|
5460
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5461
|
+
arrowTop = 0;
|
|
5462
|
+
arrowLeft = 0;
|
|
5374
5463
|
break;
|
|
5375
5464
|
case 'right':
|
|
5376
|
-
top = triggerRect.top + scrollY +
|
|
5465
|
+
top = triggerRect.top + scrollY + triggerRect.height / 2 - tooltipRect.height / 2;
|
|
5377
5466
|
left = triggerRect.right + scrollX + 8;
|
|
5378
|
-
|
|
5379
|
-
|
|
5467
|
+
// CSS에서 화살표는 자동으로 중앙에 위치하므로 스타일 제거
|
|
5468
|
+
arrowTop = 0;
|
|
5469
|
+
arrowLeft = 0;
|
|
5380
5470
|
break;
|
|
5381
5471
|
case 'right-start':
|
|
5382
5472
|
top = triggerRect.top + scrollY;
|
|
5383
5473
|
left = triggerRect.right + scrollX + 8;
|
|
5384
|
-
|
|
5385
|
-
|
|
5474
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5475
|
+
arrowTop = 0;
|
|
5476
|
+
arrowLeft = 0;
|
|
5386
5477
|
break;
|
|
5387
5478
|
case 'right-end':
|
|
5388
5479
|
top = triggerRect.bottom + scrollY - tooltipRect.height;
|
|
5389
5480
|
left = triggerRect.right + scrollX + 8;
|
|
5390
|
-
|
|
5391
|
-
|
|
5481
|
+
// CSS에서 화살표는 자동으로 위치하므로 스타일 제거
|
|
5482
|
+
arrowTop = 0;
|
|
5483
|
+
arrowLeft = 0;
|
|
5392
5484
|
break;
|
|
5393
5485
|
}
|
|
5394
5486
|
// 화면 경계 체크 및 조정
|
|
5395
5487
|
const viewportWidth = window.innerWidth;
|
|
5396
5488
|
const viewportHeight = window.innerHeight;
|
|
5397
|
-
// 수평 경계
|
|
5489
|
+
// 수평 경계
|
|
5398
5490
|
if (left < 8) {
|
|
5399
5491
|
left = 8;
|
|
5400
|
-
if (isHorizontal)
|
|
5492
|
+
if (isHorizontal)
|
|
5401
5493
|
arrowLeft = Math.max(arrowLeft, 4);
|
|
5402
|
-
}
|
|
5403
5494
|
}
|
|
5404
5495
|
else if (left + tooltipRect.width > viewportWidth - 8) {
|
|
5405
5496
|
left = viewportWidth - tooltipRect.width - 8;
|
|
5406
|
-
if (isHorizontal)
|
|
5497
|
+
if (isHorizontal)
|
|
5407
5498
|
arrowLeft = Math.min(arrowLeft, tooltipRect.width - 4);
|
|
5408
|
-
}
|
|
5409
5499
|
}
|
|
5410
|
-
// 수직 경계
|
|
5500
|
+
// 수직 경계
|
|
5411
5501
|
if (top < 8) {
|
|
5412
5502
|
top = 8;
|
|
5413
|
-
if (isVertical)
|
|
5503
|
+
if (isVertical)
|
|
5414
5504
|
arrowTop = Math.max(arrowTop, 4);
|
|
5415
|
-
}
|
|
5416
5505
|
}
|
|
5417
5506
|
else if (top + tooltipRect.height > viewportHeight - 8) {
|
|
5418
5507
|
top = viewportHeight - tooltipRect.height - 8;
|
|
5419
|
-
if (isVertical)
|
|
5508
|
+
if (isVertical)
|
|
5420
5509
|
arrowTop = Math.min(arrowTop, tooltipRect.height - 4);
|
|
5421
|
-
}
|
|
5422
5510
|
}
|
|
5423
5511
|
setTooltipStyle({
|
|
5424
5512
|
position: 'fixed',
|
|
5425
5513
|
top: `${top}px`,
|
|
5426
5514
|
left: `${left}px`,
|
|
5427
5515
|
maxWidth: `${maxWidth}px`,
|
|
5428
|
-
zIndex: 9999
|
|
5429
|
-
});
|
|
5430
|
-
setArrowStyle({
|
|
5431
|
-
position: 'absolute',
|
|
5432
|
-
top: `${arrowTop}px`,
|
|
5433
|
-
left: `${arrowLeft}px`,
|
|
5516
|
+
zIndex: 9999
|
|
5434
5517
|
});
|
|
5518
|
+
// CSS에서 화살표 위치를 자동으로 처리하므로 인라인 스타일 제거
|
|
5519
|
+
setArrowStyle({});
|
|
5435
5520
|
}, [position, maxWidth]);
|
|
5436
5521
|
// 툴팁 표시
|
|
5437
5522
|
const showTooltip = useCallback(() => {
|
|
5438
5523
|
if (disabled || alwaysShow)
|
|
5439
5524
|
return;
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
}
|
|
5443
|
-
timeoutRef.current = setTimeout(() => {
|
|
5525
|
+
clearTimer();
|
|
5526
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
5444
5527
|
setIsVisible(true);
|
|
5445
|
-
// 위치 계산을 위해 다음 프레임에서 실행
|
|
5446
5528
|
requestAnimationFrame(() => {
|
|
5447
5529
|
calculatePosition();
|
|
5448
5530
|
});
|
|
@@ -5452,89 +5534,57 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5452
5534
|
const hideTooltip = useCallback(() => {
|
|
5453
5535
|
if (disabled || alwaysShow)
|
|
5454
5536
|
return;
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
}
|
|
5458
|
-
timeoutRef.current = setTimeout(() => {
|
|
5537
|
+
clearTimer();
|
|
5538
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
5459
5539
|
setIsVisible(false);
|
|
5460
5540
|
}, hideDelay);
|
|
5461
5541
|
}, [disabled, alwaysShow, hideDelay]);
|
|
5462
|
-
//
|
|
5463
|
-
const handleMouseEnter = useCallback(() => {
|
|
5464
|
-
showTooltip();
|
|
5465
|
-
}, [showTooltip]);
|
|
5466
|
-
const handleMouseLeave = useCallback(() => {
|
|
5467
|
-
hideTooltip();
|
|
5468
|
-
}, [hideTooltip]);
|
|
5469
|
-
const handleFocus = useCallback(() => {
|
|
5470
|
-
showTooltip();
|
|
5471
|
-
}, [showTooltip]);
|
|
5472
|
-
const handleBlur = useCallback(() => {
|
|
5473
|
-
hideTooltip();
|
|
5474
|
-
}, [hideTooltip]);
|
|
5475
|
-
// 키보드 이벤트
|
|
5542
|
+
// 키보드 이스케이프
|
|
5476
5543
|
const handleKeyDown = useCallback((e) => {
|
|
5477
|
-
if (e.key === 'Escape')
|
|
5544
|
+
if (e.key === 'Escape')
|
|
5478
5545
|
hideTooltip();
|
|
5479
|
-
}
|
|
5480
5546
|
}, [hideTooltip]);
|
|
5481
|
-
//
|
|
5482
|
-
useEffect(() => {
|
|
5483
|
-
if (isVisible) {
|
|
5484
|
-
const handleResize = () => calculatePosition();
|
|
5485
|
-
const handleScroll = () => calculatePosition();
|
|
5486
|
-
window.addEventListener('resize', handleResize);
|
|
5487
|
-
window.addEventListener('scroll', handleScroll, true);
|
|
5488
|
-
return () => {
|
|
5489
|
-
window.removeEventListener('resize', handleResize);
|
|
5490
|
-
window.removeEventListener('scroll', handleScroll, true);
|
|
5491
|
-
};
|
|
5492
|
-
}
|
|
5493
|
-
}, [isVisible, calculatePosition]);
|
|
5494
|
-
// 컴포넌트 언마운트 시 타이머 정리
|
|
5547
|
+
// 리사이즈/스크롤 중 위치 업데이트
|
|
5495
5548
|
useEffect(() => {
|
|
5549
|
+
if (!isVisible)
|
|
5550
|
+
return;
|
|
5551
|
+
const onResize = () => calculatePosition();
|
|
5552
|
+
const onScroll = () => calculatePosition();
|
|
5553
|
+
window.addEventListener('resize', onResize);
|
|
5554
|
+
window.addEventListener('scroll', onScroll, true);
|
|
5496
5555
|
return () => {
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
}
|
|
5556
|
+
window.removeEventListener('resize', onResize);
|
|
5557
|
+
window.removeEventListener('scroll', onScroll, true);
|
|
5500
5558
|
};
|
|
5501
|
-
}, []);
|
|
5502
|
-
//
|
|
5559
|
+
}, [isVisible, calculatePosition]);
|
|
5560
|
+
// 언마운트 시 타이머 정리
|
|
5561
|
+
useEffect(() => () => clearTimer(), []);
|
|
5562
|
+
// 항상표시 모드
|
|
5503
5563
|
useEffect(() => {
|
|
5504
5564
|
if (alwaysShow && !disabled) {
|
|
5505
5565
|
setIsVisible(true);
|
|
5506
|
-
requestAnimationFrame(() =>
|
|
5507
|
-
calculatePosition();
|
|
5508
|
-
});
|
|
5566
|
+
requestAnimationFrame(() => calculatePosition());
|
|
5509
5567
|
}
|
|
5510
5568
|
else if (!alwaysShow) {
|
|
5511
5569
|
setIsVisible(false);
|
|
5512
5570
|
}
|
|
5513
5571
|
}, [alwaysShow, disabled, calculatePosition]);
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5572
|
+
// content가 동적으로 바뀌어도 위치 갱신
|
|
5573
|
+
useEffect(() => {
|
|
5574
|
+
if (!isVisible)
|
|
5575
|
+
return;
|
|
5576
|
+
const ro = new ResizeObserver(() => calculatePosition());
|
|
5577
|
+
if (tooltipRef.current)
|
|
5578
|
+
ro.observe(tooltipRef.current);
|
|
5579
|
+
return () => ro.disconnect();
|
|
5580
|
+
}, [isVisible, calculatePosition, content]);
|
|
5581
|
+
const classes = clsx('designbase-tooltip', `designbase-tooltip--${size}`, `designbase-tooltip--${variant}`, `designbase-tooltip--${position}`, { 'designbase-tooltip--visible': isVisible, 'designbase-tooltip--disabled': disabled }, className);
|
|
5518
5582
|
const arrowClasses = clsx('designbase-tooltip__arrow', `designbase-tooltip__arrow--${position}`);
|
|
5519
|
-
|
|
5520
|
-
const enhancedChildren = React.cloneElement(children, {
|
|
5521
|
-
ref: triggerRef,
|
|
5522
|
-
onMouseEnter: handleMouseEnter,
|
|
5523
|
-
onMouseLeave: handleMouseLeave,
|
|
5524
|
-
onFocus: handleFocus,
|
|
5525
|
-
onBlur: handleBlur,
|
|
5526
|
-
onKeyDown: handleKeyDown,
|
|
5527
|
-
onMouseDown: (e) => {
|
|
5528
|
-
// 클릭으로 인한 focus 방지 (hover 전용 보장)
|
|
5529
|
-
e.preventDefault();
|
|
5530
|
-
},
|
|
5531
|
-
tabIndex: children.props.tabIndex ?? 0,
|
|
5532
|
-
});
|
|
5533
|
-
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 }))] }))] }));
|
|
5583
|
+
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 })] }))] }));
|
|
5534
5584
|
};
|
|
5535
5585
|
Tooltip.displayName = 'Tooltip';
|
|
5536
5586
|
|
|
5537
|
-
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 }) => {
|
|
5587
|
+
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 }) => {
|
|
5538
5588
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
5539
5589
|
const [popoverStyle, setPopoverStyle] = useState({});
|
|
5540
5590
|
const [arrowStyle, setArrowStyle] = useState({});
|
|
@@ -5747,6 +5797,12 @@ const Popover = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5747
5797
|
closePopover();
|
|
5748
5798
|
}
|
|
5749
5799
|
}, [closeOnEscape, closePopover]);
|
|
5800
|
+
// 닫기 버튼 핸들러
|
|
5801
|
+
const handleCloseClick = useCallback((e) => {
|
|
5802
|
+
e.preventDefault();
|
|
5803
|
+
e.stopPropagation();
|
|
5804
|
+
closePopover();
|
|
5805
|
+
}, [closePopover]);
|
|
5750
5806
|
// 외부 클릭 처리
|
|
5751
5807
|
useEffect(() => {
|
|
5752
5808
|
if (isOpen && closeOnOutsideClick) {
|
|
@@ -5823,7 +5879,7 @@ const Popover = ({ content, children, position = 'top', size = 'm', variant = 'd
|
|
|
5823
5879
|
'aria-expanded': isOpen,
|
|
5824
5880
|
'aria-haspopup': 'dialog',
|
|
5825
5881
|
});
|
|
5826
|
-
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.
|
|
5882
|
+
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 }))] }))] }));
|
|
5827
5883
|
};
|
|
5828
5884
|
Popover.displayName = 'Popover';
|
|
5829
5885
|
|
|
@@ -6909,37 +6965,36 @@ const Reorder = ({ items, variant = 'default', size = 'm', orientation = 'vertic
|
|
|
6909
6965
|
setDraggedIndex(index);
|
|
6910
6966
|
setIsDragging(true);
|
|
6911
6967
|
setDragOverIndex(-1);
|
|
6912
|
-
// 드래그 이미지 설정 -
|
|
6968
|
+
// 드래그 이미지 설정 - 커스텀 드래그 이미지 사용하지 않음
|
|
6969
|
+
// 브라우저 기본 드래그 이미지를 사용하여 자연스러운 드래그 경험 제공
|
|
6970
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
6971
|
+
e.dataTransfer.setData('text/plain', item.id);
|
|
6972
|
+
// 드래그 시작 애니메이션
|
|
6913
6973
|
const dragElement = itemRefs.current.get(item.id);
|
|
6914
6974
|
if (dragElement) {
|
|
6915
|
-
|
|
6916
|
-
const dragImage = dragElement.cloneNode(true);
|
|
6917
|
-
dragImage.style.position = 'absolute';
|
|
6918
|
-
dragImage.style.top = '-1000px';
|
|
6919
|
-
dragImage.style.opacity = '0.9';
|
|
6920
|
-
dragImage.style.transform = 'none'; // 회전 제거
|
|
6921
|
-
dragImage.style.pointerEvents = 'none';
|
|
6922
|
-
dragImage.style.zIndex = '9999';
|
|
6923
|
-
document.body.appendChild(dragImage);
|
|
6924
|
-
e.dataTransfer.setDragImage(dragImage, rect.width / 2, rect.height / 2);
|
|
6925
|
-
// 드래그 이미지 정리
|
|
6926
|
-
setTimeout(() => {
|
|
6927
|
-
if (document.body.contains(dragImage)) {
|
|
6928
|
-
document.body.removeChild(dragImage);
|
|
6929
|
-
}
|
|
6930
|
-
}, 0);
|
|
6975
|
+
dragElement.style.animation = 'dragStart 0.2s ease-out forwards';
|
|
6931
6976
|
}
|
|
6932
|
-
e.dataTransfer.effectAllowed = 'move';
|
|
6933
|
-
e.dataTransfer.setData('text/plain', item.id);
|
|
6934
6977
|
onDragStart?.(item, index);
|
|
6935
6978
|
}, [disabled, onDragStart]);
|
|
6936
|
-
// 드래그 오버 핸들러
|
|
6979
|
+
// 드래그 오버 핸들러 - 드래그 방향에 따른 정확한 디바이더 위치 계산
|
|
6937
6980
|
const handleDragOver = useCallback((e, index) => {
|
|
6938
6981
|
e.preventDefault();
|
|
6939
6982
|
e.dataTransfer.dropEffect = 'move';
|
|
6940
|
-
if (draggedIndex
|
|
6941
|
-
setDragOverIndex(
|
|
6983
|
+
if (draggedIndex === -1 || draggedIndex === index) {
|
|
6984
|
+
setDragOverIndex(-1);
|
|
6985
|
+
return;
|
|
6986
|
+
}
|
|
6987
|
+
// 드래그 방향에 따라 디바이더 위치 결정
|
|
6988
|
+
let dropIndex = index;
|
|
6989
|
+
if (draggedIndex < index) {
|
|
6990
|
+
// 아래로 드래그: 현재 아이템 위에 디바이더 표시
|
|
6991
|
+
dropIndex = index;
|
|
6992
|
+
}
|
|
6993
|
+
else if (draggedIndex > index) {
|
|
6994
|
+
// 위로 드래그: 현재 아이템 위에 디바이더 표시 (index 그대로 사용)
|
|
6995
|
+
dropIndex = index;
|
|
6942
6996
|
}
|
|
6997
|
+
setDragOverIndex(dropIndex);
|
|
6943
6998
|
}, [draggedIndex]);
|
|
6944
6999
|
// 드래그 리브 핸들러
|
|
6945
7000
|
const handleDragLeave = useCallback((e) => {
|
|
@@ -6952,25 +7007,55 @@ const Reorder = ({ items, variant = 'default', size = 'm', orientation = 'vertic
|
|
|
6952
7007
|
setDragOverIndex(-1);
|
|
6953
7008
|
}
|
|
6954
7009
|
}, []);
|
|
6955
|
-
// 드롭 핸들러
|
|
7010
|
+
// 드롭 핸들러 - 드래그 방향에 따른 정확한 드롭 위치 사용
|
|
6956
7011
|
const handleDrop = useCallback((e, dropIndex) => {
|
|
6957
7012
|
e.preventDefault();
|
|
6958
7013
|
if (draggedIndex === -1 || draggedIndex === dropIndex) {
|
|
6959
7014
|
setDragOverIndex(-1);
|
|
6960
7015
|
return;
|
|
6961
7016
|
}
|
|
7017
|
+
// 드래그 방향에 따라 실제 드롭 위치 계산
|
|
7018
|
+
let actualDropIndex = dropIndex;
|
|
7019
|
+
if (draggedIndex < dropIndex) {
|
|
7020
|
+
// 아래로 드래그: 현재 위치에 삽입
|
|
7021
|
+
actualDropIndex = dropIndex;
|
|
7022
|
+
}
|
|
7023
|
+
else if (draggedIndex > dropIndex) {
|
|
7024
|
+
// 위로 드래그: 현재 위치에 삽입 (dropIndex 그대로 사용)
|
|
7025
|
+
actualDropIndex = dropIndex;
|
|
7026
|
+
}
|
|
6962
7027
|
const newItems = [...reorderedItems];
|
|
6963
7028
|
const [draggedItemData] = newItems.splice(draggedIndex, 1);
|
|
6964
|
-
newItems.splice(
|
|
7029
|
+
newItems.splice(actualDropIndex, 0, draggedItemData);
|
|
6965
7030
|
setReorderedItems(newItems);
|
|
6966
7031
|
setDragOverIndex(-1);
|
|
6967
7032
|
setIsDragging(false);
|
|
7033
|
+
// 드롭 완료 애니메이션
|
|
7034
|
+
const dropElement = itemRefs.current.get(draggedItemData.id);
|
|
7035
|
+
if (dropElement) {
|
|
7036
|
+
dropElement.style.animation = 'dropComplete 0.3s ease-out forwards';
|
|
7037
|
+
setTimeout(() => {
|
|
7038
|
+
dropElement.style.animation = '';
|
|
7039
|
+
}, 300);
|
|
7040
|
+
}
|
|
6968
7041
|
onReorder?.(newItems);
|
|
6969
|
-
onDragEnd?.(draggedItemData, draggedIndex,
|
|
7042
|
+
onDragEnd?.(draggedItemData, draggedIndex, actualDropIndex);
|
|
6970
7043
|
}, [reorderedItems, draggedIndex, onReorder, onDragEnd]);
|
|
6971
7044
|
// 드래그 종료 핸들러
|
|
6972
7045
|
const handleDragEnd = useCallback((e) => {
|
|
6973
7046
|
e.preventDefault();
|
|
7047
|
+
// 모든 아이템의 스타일 초기화
|
|
7048
|
+
itemRefs.current.forEach((element) => {
|
|
7049
|
+
if (element) {
|
|
7050
|
+
element.style.animation = '';
|
|
7051
|
+
element.style.transform = '';
|
|
7052
|
+
element.style.opacity = '';
|
|
7053
|
+
element.style.zIndex = '';
|
|
7054
|
+
element.style.boxShadow = '';
|
|
7055
|
+
element.style.border = '';
|
|
7056
|
+
element.style.background = '';
|
|
7057
|
+
}
|
|
7058
|
+
});
|
|
6974
7059
|
setDraggedItem(null);
|
|
6975
7060
|
setDraggedIndex(-1);
|
|
6976
7061
|
setDragOverIndex(-1);
|
|
@@ -7057,11 +7142,21 @@ const Reorder = ({ items, variant = 'default', size = 'm', orientation = 'vertic
|
|
|
7057
7142
|
const isDragged = draggedItem?.id === item.id;
|
|
7058
7143
|
const isDragOver = dragOverIndex === index;
|
|
7059
7144
|
const isDisabled = disabled || item.disabled;
|
|
7145
|
+
// 드래그 방향에 따른 디바이더 클래스 (드롭 위치에만 적용)
|
|
7146
|
+
const isDraggingDown = isDragOver && draggedIndex !== -1 && draggedIndex < index;
|
|
7147
|
+
const isDraggingUp = isDragOver && draggedIndex !== -1 && draggedIndex > index;
|
|
7148
|
+
const isDraggingRight = isDragOver && draggedIndex !== -1 && draggedIndex < index;
|
|
7149
|
+
const isDraggingLeft = isDragOver && draggedIndex !== -1 && draggedIndex > index;
|
|
7060
7150
|
const itemClasses = clsx('designbase-reorder__item', {
|
|
7061
7151
|
'designbase-reorder__item--selected': isSelected,
|
|
7062
7152
|
'designbase-reorder__item--dragged': isDragged,
|
|
7063
7153
|
'designbase-reorder__item--drag-over': isDragOver,
|
|
7064
7154
|
'designbase-reorder__item--disabled': isDisabled,
|
|
7155
|
+
// 드래그 방향에 따른 클래스
|
|
7156
|
+
'designbase-reorder__item--drag-down': isDraggingDown,
|
|
7157
|
+
'designbase-reorder__item--drag-up': isDraggingUp,
|
|
7158
|
+
'designbase-reorder__item--drag-right': isDraggingRight,
|
|
7159
|
+
'designbase-reorder__item--drag-left': isDraggingLeft,
|
|
7065
7160
|
});
|
|
7066
7161
|
return (jsxRuntimeExports.jsxs("div", { ref: (el) => {
|
|
7067
7162
|
if (el) {
|
|
@@ -7714,7 +7809,7 @@ const VideoPlayer = ({ src, poster, title, description, size = 'm', variant = 'd
|
|
|
7714
7809
|
'designbase-video-player--show-controls': showControlsOverlay,
|
|
7715
7810
|
}, className);
|
|
7716
7811
|
const currentSrc = playlist.length > 0 ? playlist[playlistIndex] : src;
|
|
7717
|
-
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(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(PauseIcon, { size: 48 }) : jsxRuntimeExports.jsx(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(PauseIcon, { size: 20 }) : jsxRuntimeExports.jsx(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(MuteFilledIcon, { size: 20 }) : jsxRuntimeExports.jsx(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(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(ChevronRightIcon, { size: 16 }) })] })), enableFullscreen && (jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: toggleFullscreen, children: isFullscreen ? jsxRuntimeExports.jsx(ShrinkIcon, { size: 20 }) : jsxRuntimeExports.jsx(ExpandIcon, { size: 20 }) }))] })] })] })] }))] }));
|
|
7812
|
+
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(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(PauseIcon, { size: 48 }) : jsxRuntimeExports.jsx(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(PauseIcon, { size: 20 }) : jsxRuntimeExports.jsx(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(MuteFilledIcon, { size: 20 }) : jsxRuntimeExports.jsx(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(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(ChevronRightIcon, { size: 16 }) })] })), enableFullscreen && (jsxRuntimeExports.jsx("button", { className: "designbase-video-player__control-button", onClick: toggleFullscreen, children: isFullscreen ? jsxRuntimeExports.jsx(ShrinkIcon, { size: 20 }) : jsxRuntimeExports.jsx(ExpandIcon, { size: 20 }) }))] })] })] })] }))] }));
|
|
7718
7813
|
};
|
|
7719
7814
|
|
|
7720
7815
|
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, }) => {
|
|
@@ -8443,7 +8538,7 @@ const Toolbar = ({ items, size = 'm', variant = 'default', position = 'top', ful
|
|
|
8443
8538
|
return (jsxRuntimeExports.jsxs("div", { className: clsx('designbase-toolbar__item', 'designbase-toolbar__item--dropdown', {
|
|
8444
8539
|
'designbase-toolbar__item--open': openDropdown === item.id,
|
|
8445
8540
|
'designbase-toolbar__item--disabled': item.disabled,
|
|
8446
|
-
}), 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(
|
|
8541
|
+
}), 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(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', {
|
|
8447
8542
|
'designbase-toolbar__dropdown-option--selected': item.selectedValue === option.value,
|
|
8448
8543
|
'designbase-toolbar__dropdown-option--disabled': option.disabled,
|
|
8449
8544
|
}), 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));
|
|
@@ -11801,8 +11896,26 @@ const ResizablePanels = ({ children, initialWidth = '100%', initialHeight = '100
|
|
|
11801
11896
|
return { ...baseStyle, bottom: 0, right: 0 };
|
|
11802
11897
|
}
|
|
11803
11898
|
}, [handlePosition, handleSize, handleColor, direction]);
|
|
11804
|
-
// 기본 리사이즈 핸들 아이콘
|
|
11805
|
-
const
|
|
11899
|
+
// 방향에 따른 기본 리사이즈 핸들 아이콘
|
|
11900
|
+
const getDefaultHandleIcon = () => {
|
|
11901
|
+
const iconSize = Math.max(12, handleSize - 4);
|
|
11902
|
+
switch (handlePosition) {
|
|
11903
|
+
case 'bottom-right':
|
|
11904
|
+
return jsxRuntimeExports.jsx(ArrowDownRightIcon, { size: iconSize });
|
|
11905
|
+
case 'bottom-left':
|
|
11906
|
+
return jsxRuntimeExports.jsx(ArrowDownLeftIcon, { size: iconSize });
|
|
11907
|
+
case 'top-right':
|
|
11908
|
+
return jsxRuntimeExports.jsx(ArrowUpRightIcon, { size: iconSize });
|
|
11909
|
+
case 'top-left':
|
|
11910
|
+
return jsxRuntimeExports.jsx(ArrowUpLeftIcon, { size: iconSize });
|
|
11911
|
+
case 'right':
|
|
11912
|
+
return jsxRuntimeExports.jsx(ArrowRightIcon, { size: iconSize });
|
|
11913
|
+
case 'bottom':
|
|
11914
|
+
return jsxRuntimeExports.jsx(ArrowDownIcon, { size: iconSize });
|
|
11915
|
+
default:
|
|
11916
|
+
return direction === 'both' ? jsxRuntimeExports.jsx(MoveIcon, { size: iconSize }) : jsxRuntimeExports.jsx(ExpandIcon, { size: iconSize });
|
|
11917
|
+
}
|
|
11918
|
+
};
|
|
11806
11919
|
const classes = classNames('designbase-resizable-panels', {
|
|
11807
11920
|
'designbase-resizable-panels--resizing': isResizing,
|
|
11808
11921
|
'designbase-resizable-panels--border': showBorder,
|
|
@@ -11820,7 +11933,7 @@ const ResizablePanels = ({ children, initialWidth = '100%', initialHeight = '100
|
|
|
11820
11933
|
}, onMouseLeave: (e) => {
|
|
11821
11934
|
const target = e.currentTarget;
|
|
11822
11935
|
target.style.backgroundColor = handleColor;
|
|
11823
|
-
}, children: handleIcon ||
|
|
11936
|
+
}, children: handleIcon || getDefaultHandleIcon() })] }));
|
|
11824
11937
|
};
|
|
11825
11938
|
|
|
11826
11939
|
/**
|