@designbasekorea/ui 0.3.1 → 0.3.3

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
@@ -2196,9 +2196,13 @@ const Spinner = ({ type = 'circular', size = 'm', color, speed = 1, label = '로
2196
2196
  };
2197
2197
  Spinner.displayName = 'Spinner';
2198
2198
 
2199
- const GAP$1 = 8; // 트리거와의 간격
2200
- const ARW = 6; // 화살표 반쪽 길이(삼각형 길이)
2201
- const PAD = 8; // 화살표가 박스 안에서 안전하게 보일 최소 여백
2199
+ const GAP$1 = 8; // 트리거와의 간격(박스)
2200
+ const ARW = 6; // border 삼각형 사이즈( SCSS에서 6px)
2201
+ const PAD = 8; // start/end 여백
2202
+ // ✅ 네가 말한 “-10이 되어야 제대로”를 상수로 고정
2203
+ const OUT = -10; // bottom일 때 top, right일 때 left
2204
+ // ✅ top/left는 대칭적으로 “박스에 살짝 겹치게” 만들어 seam 제거
2205
+ const INSET = 2; // (pRect.height - 2), (pRect.width - 2)
2202
2206
  const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'default', delay = 200, hideDelay = 80, alwaysShow = false, disabled = false, maxWidth = 240, showArrow = true, className, ...props }) => {
2203
2207
  const [visible, setVisible] = React.useState(false);
2204
2208
  const [style, setStyle] = React.useState({});
@@ -2217,115 +2221,110 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
2217
2221
  const groupOf = (p) => p.startsWith('top') ? 'top' :
2218
2222
  p.startsWith('bottom') ? 'bottom' :
2219
2223
  p.startsWith('left') ? 'left' : 'right';
2220
- // 위치 계산 (⚠️ 뷰포트 클램핑 후 화살표도 보정)
2221
2224
  const calculatePosition = React.useCallback(() => {
2222
2225
  if (!triggerRef.current || !tooltipRef.current)
2223
2226
  return;
2224
2227
  const tRect = triggerRef.current.getBoundingClientRect();
2225
2228
  const pRect = tooltipRef.current.getBoundingClientRect();
2226
2229
  let top = 0, left = 0;
2227
- // 1차: 이상적(미보정) 화살표 좌표
2228
2230
  let aTop = 0, aLeft = 0;
2229
2231
  switch (position) {
2230
2232
  case 'top':
2231
2233
  top = tRect.top - pRect.height - GAP$1;
2232
2234
  left = tRect.left + tRect.width / 2 - pRect.width / 2;
2233
- aTop = pRect.height;
2235
+ aTop = pRect.height - INSET; // ✅ top은 박스 아래쪽에 살짝 겹침
2234
2236
  aLeft = pRect.width / 2 - ARW;
2235
2237
  break;
2236
2238
  case 'top-start':
2237
2239
  top = tRect.top - pRect.height - GAP$1;
2238
2240
  left = tRect.left;
2239
- aTop = pRect.height;
2241
+ aTop = pRect.height - INSET;
2240
2242
  aLeft = PAD;
2241
2243
  break;
2242
2244
  case 'top-end':
2243
2245
  top = tRect.top - pRect.height - GAP$1;
2244
2246
  left = tRect.right - pRect.width;
2245
- aTop = pRect.height;
2246
- aLeft = pRect.width - PAD;
2247
+ aTop = pRect.height - INSET;
2248
+ aLeft = pRect.width - PAD - ARW;
2247
2249
  break;
2248
2250
  case 'bottom':
2249
2251
  top = tRect.bottom + GAP$1;
2250
2252
  left = tRect.left + tRect.width / 2 - pRect.width / 2;
2251
- aTop = -ARW;
2253
+ aTop = OUT; // ✅ 네 요구: -10
2252
2254
  aLeft = pRect.width / 2 - ARW;
2253
2255
  break;
2254
2256
  case 'bottom-start':
2255
2257
  top = tRect.bottom + GAP$1;
2256
2258
  left = tRect.left;
2257
- aTop = -ARW;
2259
+ aTop = OUT; // ✅ -10
2258
2260
  aLeft = PAD;
2259
2261
  break;
2260
2262
  case 'bottom-end':
2261
2263
  top = tRect.bottom + GAP$1;
2262
2264
  left = tRect.right - pRect.width;
2263
- aTop = -ARW;
2264
- aLeft = pRect.width - PAD;
2265
+ aTop = OUT; // ✅ -10
2266
+ aLeft = pRect.width - PAD - ARW;
2265
2267
  break;
2266
2268
  case 'left':
2267
2269
  top = tRect.top + tRect.height / 2 - pRect.height / 2;
2268
2270
  left = tRect.left - pRect.width - GAP$1;
2269
2271
  aTop = pRect.height / 2 - ARW;
2270
- aLeft = pRect.width;
2272
+ aLeft = pRect.width - INSET; // ✅ left는 박스 오른쪽에 살짝 겹침
2271
2273
  break;
2272
2274
  case 'left-start':
2273
2275
  top = tRect.top;
2274
2276
  left = tRect.left - pRect.width - GAP$1;
2275
2277
  aTop = PAD;
2276
- aLeft = pRect.width;
2278
+ aLeft = pRect.width - INSET;
2277
2279
  break;
2278
2280
  case 'left-end':
2279
2281
  top = tRect.bottom - pRect.height;
2280
2282
  left = tRect.left - pRect.width - GAP$1;
2281
- aTop = pRect.height - PAD;
2282
- aLeft = pRect.width;
2283
+ aTop = pRect.height - PAD - ARW;
2284
+ aLeft = pRect.width - INSET;
2283
2285
  break;
2284
2286
  case 'right':
2285
2287
  top = tRect.top + tRect.height / 2 - pRect.height / 2;
2286
2288
  left = tRect.right + GAP$1;
2287
2289
  aTop = pRect.height / 2 - ARW;
2288
- aLeft = -ARW;
2290
+ aLeft = OUT; // ✅ 네 요구: left:-10
2289
2291
  break;
2290
2292
  case 'right-start':
2291
2293
  top = tRect.top;
2292
2294
  left = tRect.right + GAP$1;
2293
2295
  aTop = PAD;
2294
- aLeft = -ARW;
2296
+ aLeft = OUT; // ✅ -10
2295
2297
  break;
2296
2298
  case 'right-end':
2297
2299
  top = tRect.bottom - pRect.height;
2298
2300
  left = tRect.right + GAP$1;
2299
- aTop = pRect.height - PAD;
2300
- aLeft = -ARW;
2301
+ aTop = pRect.height - PAD - ARW;
2302
+ aLeft = OUT; // ✅ -10
2301
2303
  break;
2302
2304
  }
2303
- // 뷰포트 클램핑
2305
+ // 뷰포트 클램핑(툴팁 박스)
2304
2306
  const vw = window.innerWidth;
2305
2307
  const vh = window.innerHeight;
2306
- if (left < 8)
2307
- left = 8;
2308
- if (left + pRect.width > vw - 8)
2309
- left = vw - pRect.width - 8;
2310
- if (top < 8)
2311
- top = 8;
2312
- if (top + pRect.height > vh - 8)
2313
- top = vh - pRect.height - 8;
2314
- // 🔁 클램핑으로 박스 위치가 바뀌었을 수 있으니, 화살표를 박스 내부에서 다시 보정
2308
+ const EDGE = 8;
2309
+ if (left < EDGE)
2310
+ left = EDGE;
2311
+ if (left + pRect.width > vw - EDGE)
2312
+ left = vw - pRect.width - EDGE;
2313
+ if (top < EDGE)
2314
+ top = EDGE;
2315
+ if (top + pRect.height > vh - EDGE)
2316
+ top = vh - pRect.height - EDGE;
2317
+ // 클램핑으로 박스가 이동했을 때, 화살표가 트리거를 향하도록 보정
2315
2318
  const g = groupOf(position);
2316
2319
  if (g === 'top' || g === 'bottom') {
2317
- // 트리거 중앙 X 를 툴팁 좌표계로 변환
2318
2320
  const triggerCenterX = tRect.left + tRect.width / 2;
2319
- const localX = triggerCenterX - left - ARW; // 화살표 기준점을 고려
2320
- // 8px ~ (width-8px) 범위로 제한
2321
- aLeft = Math.min(pRect.width - PAD, Math.max(PAD, localX));
2322
- // aTop은 이미 위/아래에 고정(-ARW 또는 높이)
2321
+ const localX = triggerCenterX - left - ARW;
2322
+ aLeft = Math.min(pRect.width - PAD - ARW, Math.max(PAD, localX));
2323
2323
  }
2324
2324
  else {
2325
2325
  const triggerCenterY = tRect.top + tRect.height / 2;
2326
2326
  const localY = triggerCenterY - top - ARW;
2327
- aTop = Math.min(pRect.height - PAD, Math.max(PAD, localY));
2328
- // aLeft는 이미 좌/우에 고정(-ARW 또는 너비)
2327
+ aTop = Math.min(pRect.height - PAD - ARW, Math.max(PAD, localY));
2329
2328
  }
2330
2329
  setStyle({
2331
2330
  position: 'fixed',
@@ -2333,17 +2332,15 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
2333
2332
  left,
2334
2333
  maxWidth,
2335
2334
  zIndex: 9999,
2336
- pointerEvents: 'none', // hover 유지
2335
+ pointerEvents: 'none',
2337
2336
  });
2338
2337
  setArrowStyle({ position: 'absolute', top: aTop, left: aLeft });
2339
2338
  setPlacementGroup(g);
2340
2339
  }, [position, maxWidth]);
2341
- // 초기 페인트 전에 위치 확정
2342
2340
  React.useLayoutEffect(() => {
2343
2341
  if (visible || alwaysShow)
2344
2342
  calculatePosition();
2345
2343
  }, [visible, alwaysShow, calculatePosition]);
2346
- // 스크롤/리사이즈/크기변화 추적 (rAF 스로틀)
2347
2344
  React.useEffect(() => {
2348
2345
  if (!(visible || alwaysShow))
2349
2346
  return;
@@ -2374,7 +2371,6 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
2374
2371
  cancelAnimationFrame(rafId.current);
2375
2372
  };
2376
2373
  }, [visible, alwaysShow, calculatePosition]);
2377
- // show/hide
2378
2374
  const show = React.useCallback(() => {
2379
2375
  if (disabled)
2380
2376
  return;
@@ -2388,10 +2384,12 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
2388
2384
  timers.current.t = setTimeout(() => setVisible(false), Math.max(0, hideDelay));
2389
2385
  }, [disabled, hideDelay]);
2390
2386
  React.useEffect(() => () => clearTimer(), []);
2391
- React.useEffect(() => { if (!disabled && alwaysShow)
2392
- setVisible(true);
2393
- else if (!alwaysShow)
2394
- setVisible(false); }, [alwaysShow, disabled]);
2387
+ React.useEffect(() => {
2388
+ if (!disabled && alwaysShow)
2389
+ setVisible(true);
2390
+ else if (!alwaysShow)
2391
+ setVisible(false);
2392
+ }, [alwaysShow, disabled]);
2395
2393
  const onKeyDown = React.useCallback((e) => {
2396
2394
  if (e.key === 'Escape') {
2397
2395
  clearTimer();
@@ -2404,7 +2402,7 @@ const Tooltip = ({ content, children, position = 'top', size = 'm', variant = 'd
2404
2402
  };
2405
2403
  Tooltip.displayName = 'Tooltip';
2406
2404
 
2407
- const Button = React.forwardRef(({ variant = 'primary', size = 'm', radius, fullWidth = false, disabled = false, loading = false, iconOnly = false, startIcon: StartIcon, endIcon: EndIcon, tooltip, tooltipProps, className, children, onPress, type = 'button', ...props }, forwardedRef) => {
2405
+ const Button = React.forwardRef(({ variant = 'primary', size = 'm', radius, fullWidth = false, disabled = false, loading = false, loadingText, iconOnly = false, startIcon: StartIcon, endIcon: EndIcon, tooltip, tooltipProps, className, children, onPress, type = 'button', ...props }, forwardedRef) => {
2408
2406
  const ref = $df56164dff5785e2$export$4338b53315abf666(forwardedRef);
2409
2407
  const { buttonProps } = $701a24aa0da5b062$export$ea18c227d4417cc3({
2410
2408
  ...props,
@@ -2449,7 +2447,13 @@ const Button = React.forwardRef(({ variant = 'primary', size = 'm', radius, full
2449
2447
  };
2450
2448
  const renderContent = () => {
2451
2449
  if (loading) {
2452
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Spinner, { type: "circular", size: size === 's' ? 's' : size === 'l' ? 'l' : 'm', color: getIconColor(), speed: 1, showLabel: false }), !iconOnly && jsxRuntime.jsx("span", { children: "\uB85C\uB529 \uC911..." })] }));
2450
+ // 로딩 표시할 텍스트 결정: loadingText > children > 기본값
2451
+ const displayText = loadingText !== undefined
2452
+ ? loadingText
2453
+ : (!iconOnly && children)
2454
+ ? children
2455
+ : null;
2456
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Spinner, { type: "circular", size: size === 's' ? 's' : size === 'l' ? 'l' : 'm', color: getIconColor(), speed: 1, showLabel: false }), displayText && jsxRuntime.jsx("span", { children: displayText })] }));
2453
2457
  }
2454
2458
  // iconOnly 버튼일 때는 children을 아이콘으로 처리
2455
2459
  if (iconOnly && children && React.isValidElement(children)) {
@@ -4913,23 +4917,7 @@ const Image$1 = ({ src, alt = '', ratio = 'auto', fit = 'cover', loading = 'lazy
4913
4917
  onError?.();
4914
4918
  }
4915
4919
  };
4916
- // aspect ratio 계산
4917
- const getAspectRatioStyle = () => {
4918
- if (ratio === 'auto')
4919
- return {};
4920
- const ratios = {
4921
- '1:1': '100%',
4922
- '16:9': '56.25%',
4923
- '4:3': '75%',
4924
- '3:2': '66.67%',
4925
- '3:4': '133.33%',
4926
- '2:1': '50%',
4927
- 'auto': 'auto',
4928
- };
4929
- return {
4930
- paddingBottom: ratios[ratio],
4931
- };
4932
- };
4920
+ // aspect ratio CSS 클래스로 처리되므로 인라인 스타일 불필요
4933
4921
  // 둥근 모서리 클래스 계산
4934
4922
  const getRoundedClass = () => {
4935
4923
  if (rounded === true)
@@ -4956,7 +4944,6 @@ const Image$1 = ({ src, alt = '', ratio = 'auto', fit = 'cover', loading = 'lazy
4956
4944
  height: fullHeight ? '100%' : height,
4957
4945
  maxWidth,
4958
4946
  maxHeight,
4959
- ...getAspectRatioStyle(),
4960
4947
  };
4961
4948
  const getRatioClass = () => {
4962
4949
  if (ratio === 'auto')
@@ -6313,7 +6300,7 @@ const ContextMenu = ({ items, open, x, y, onClose, className, }) => {
6313
6300
  }
6314
6301
  const hasSubMenu = item.subItems && item.subItems.length > 0;
6315
6302
  const isSubMenuOpen = activeSubMenu === item.id;
6316
- return (jsxRuntime.jsxs("div", { className: "designbase-context-menu__item-wrapper", children: [jsxRuntime.jsx(MenuItem, { id: item.id, label: item.label || '', icon: item.icon, onClick: () => handleItemClick(item), disabled: item.disabled, variant: item.variant, className: item.className }), hasSubMenu && (jsxRuntime.jsx("div", { ref: (el) => (subMenuRefs.current[item.id] = el), className: clsx('designbase-context-menu__submenu', {
6303
+ return (jsxRuntime.jsxs("div", { className: "designbase-context-menu__item-wrapper", children: [jsxRuntime.jsx(MenuItem, { id: item.id, label: item.label || '', icon: item.icon, onClick: () => handleItemClick(item), disabled: item.disabled, variant: item.variant, className: item.className }), hasSubMenu && (jsxRuntime.jsx("div", { ref: (el) => { subMenuRefs.current[item.id] = el; }, className: clsx('designbase-context-menu__submenu', {
6317
6304
  'designbase-context-menu__submenu--open': isSubMenuOpen,
6318
6305
  }), onMouseEnter: () => setActiveSubMenu(item.id), onMouseLeave: handleSubMenuClose, children: item.subItems.map((subItem, subIndex) => renderMenuItem(subItem, subIndex)) }))] }, item.id));
6319
6306
  }, [activeSubMenu, handleItemClick, handleSubMenuOpen, handleSubMenuClose]);
@@ -8838,7 +8825,7 @@ const Masonry = ({ images, columns = 3, spacing = 'm', ratio = 'auto', fit = 'co
8838
8825
  'designbase-masonry--infinite-scroll': infiniteScroll,
8839
8826
  }, className);
8840
8827
  const distributedImages = distributeImages();
8841
- const renderImage = (image, index, columnIndex) => (jsxRuntime.jsxs("div", { ref: (el) => (imageRefs.current[index] = el), className: clsx('designbase-masonry__item', {
8828
+ const renderImage = (image, index, columnIndex) => (jsxRuntime.jsxs("div", { ref: (el) => { imageRefs.current[index] = el; }, className: clsx('designbase-masonry__item', {
8842
8829
  'designbase-masonry__item--visible': visibleImages.includes(index),
8843
8830
  }), style: {
8844
8831
  animationDelay: `${index * animationDelay}ms`,
@@ -9551,15 +9538,16 @@ hideDelay = 80, alwaysShow = false, disabled = false, maxWidth = 300, showArrow
9551
9538
  const classes = clsx('designbase-popover', `designbase-popover--${size}`, `designbase-popover--${variant}`, `designbase-popover--${position}`, { 'designbase-popover--visible': isOpen, 'designbase-popover--disabled': disabled }, className);
9552
9539
  const arrowClasses = clsx('designbase-popover__arrow', `designbase-popover__arrow--${position}`);
9553
9540
  // 자식에 트리거 이벤트 주입
9541
+ const childProps = children.props;
9554
9542
  const enhancedChildren = React.cloneElement(children, {
9555
9543
  ref: triggerRef,
9556
- onClick: (e) => { children.props.onClick?.(e); handleClick(e); },
9557
- onMouseEnter: (e) => { children.props.onMouseEnter?.(e); handleMouseEnter(); },
9558
- onMouseLeave: (e) => { children.props.onMouseLeave?.(e); handleMouseLeave(); },
9559
- onFocus: (e) => { children.props.onFocus?.(e); handleFocus(); },
9560
- onBlur: (e) => { children.props.onBlur?.(e); handleBlur(); },
9561
- onKeyDown: (e) => { children.props.onKeyDown?.(e); handleKeyDown(e); },
9562
- tabIndex: children.props.tabIndex ?? 0,
9544
+ onClick: (e) => { childProps.onClick?.(e); handleClick(e); },
9545
+ onMouseEnter: (e) => { childProps.onMouseEnter?.(e); handleMouseEnter(); },
9546
+ onMouseLeave: (e) => { childProps.onMouseLeave?.(e); handleMouseLeave(); },
9547
+ onFocus: (e) => { childProps.onFocus?.(e); handleFocus(); },
9548
+ onBlur: (e) => { childProps.onBlur?.(e); handleBlur(); },
9549
+ onKeyDown: (e) => { childProps.onKeyDown?.(e); handleKeyDown(e); },
9550
+ tabIndex: childProps.tabIndex ?? 0,
9563
9551
  'aria-expanded': isOpen,
9564
9552
  'aria-haspopup': 'dialog',
9565
9553
  });
@@ -9610,16 +9598,20 @@ const ProgressStep = ({ items, size = 'm', layout = 'vertical', currentStep = 0,
9610
9598
  const status = getStepStatus(index, item.status);
9611
9599
  const isLast = index === items.length - 1;
9612
9600
  const isClickable = clickable && !disabled && !item.disabled;
9601
+ // 연결선의 상태 결정: 현재 단계가 완료되었으면 completed로 표시
9602
+ const prevStatus = index > 0 ? getStepStatus(index - 1, items[index - 1].status) : 'pending';
9603
+ const connectorStatus = prevStatus === 'completed' ? 'completed' : status;
9613
9604
  const stepClasses = clsx('designbase-progress-step__item', `designbase-progress-step__item--${status}`, {
9614
9605
  'designbase-progress-step__item--clickable': isClickable,
9615
9606
  'designbase-progress-step__item--disabled': item.disabled,
9616
9607
  });
9617
- return (jsxRuntime.jsxs("div", { className: stepClasses, children: [jsxRuntime.jsxs("div", { className: "designbase-progress-step__indicator-container", children: [jsxRuntime.jsx("div", { className: "designbase-progress-step__indicator", onClick: () => handleStepClick(item, index), tabIndex: isClickable ? 0 : -1, role: isClickable ? 'button' : undefined, "aria-label": `${item.title} 단계로 이동`, onKeyDown: (e) => {
9608
+ const connectorClasses = clsx('designbase-progress-step__connector', `designbase-progress-step__connector--${connectorStatus}`);
9609
+ return (jsxRuntime.jsxs("div", { className: stepClasses, children: [jsxRuntime.jsxs("div", { className: "designbase-progress-step__indicator-container", children: [jsxRuntime.jsxs("div", { className: "designbase-progress-step__indicator", onClick: () => handleStepClick(item, index), tabIndex: isClickable ? 0 : -1, role: isClickable ? 'button' : undefined, "aria-label": `${item.title} 단계로 이동`, onKeyDown: (e) => {
9618
9610
  if (e.key === 'Enter' || e.key === ' ') {
9619
9611
  e.preventDefault();
9620
9612
  handleStepClick(item, index);
9621
9613
  }
9622
- }, children: item.icon ? (jsxRuntime.jsx("div", { className: "designbase-progress-step__icon", children: item.icon })) : (jsxRuntime.jsx("span", { className: "designbase-progress-step__number", children: index + 1 })) }), !isLast && (jsxRuntime.jsx("div", { className: "designbase-progress-step__connector" }))] }), jsxRuntime.jsxs("div", { className: "designbase-progress-step__content", children: [jsxRuntime.jsxs("div", { className: "designbase-progress-step__header", children: [jsxRuntime.jsx("h3", { className: "designbase-progress-step__title", children: item.title }), item.timestamp && (jsxRuntime.jsx("span", { className: "designbase-progress-step__timestamp", children: item.timestamp }))] }), item.description && (jsxRuntime.jsx("p", { className: "designbase-progress-step__description", children: item.description }))] })] }, item.id));
9614
+ }, children: [status === 'active' && (jsxRuntime.jsx("div", { className: "designbase-progress-step__pulse" })), item.icon ? (jsxRuntime.jsx("div", { className: "designbase-progress-step__icon", children: item.icon })) : (jsxRuntime.jsx("span", { className: "designbase-progress-step__number", children: index + 1 }))] }), !isLast && (jsxRuntime.jsx("div", { className: connectorClasses }))] }), jsxRuntime.jsxs("div", { className: "designbase-progress-step__content", children: [jsxRuntime.jsxs("div", { className: "designbase-progress-step__header", children: [jsxRuntime.jsx("h3", { className: "designbase-progress-step__title", children: item.title }), item.timestamp && (jsxRuntime.jsx("span", { className: "designbase-progress-step__timestamp", children: item.timestamp }))] }), item.description && (jsxRuntime.jsx("p", { className: "designbase-progress-step__description", children: item.description }))] })] }, item.id));
9623
9615
  }) }));
9624
9616
  };
9625
9617
 
@@ -11379,7 +11371,7 @@ const Tabs = ({ items, defaultSelectedId, selectedId, orientation = 'horizontal'
11379
11371
  };
11380
11372
  Tabs.displayName = 'Tabs';
11381
11373
 
11382
- const Timeline = ({ items, position = 'alternate', variant = 'default', size = 'm', color = 'primary', clickable = false, fullWidth = false, disabled = false, className, style, onItemClick, }) => {
11374
+ const Timeline = ({ items, type = 'alternate', variant = 'default', size = 'm', color = 'primary', clickable = false, fullWidth = false, disabled = false, className, style, onItemClick, }) => {
11383
11375
  const handleItemClick = (item, index) => {
11384
11376
  if (disabled || item.disabled || !clickable)
11385
11377
  return;
@@ -11387,20 +11379,13 @@ const Timeline = ({ items, position = 'alternate', variant = 'default', size = '
11387
11379
  onItemClick?.(item, index);
11388
11380
  };
11389
11381
  const getItemPosition = (index) => {
11390
- switch (position) {
11391
- case 'left':
11392
- return 'left';
11393
- case 'right':
11394
- return 'right';
11395
- case 'alternate':
11396
- return index % 2 === 0 ? 'left' : 'right';
11397
- case 'reverse-alternate':
11398
- return index % 2 === 0 ? 'right' : 'left';
11399
- default:
11400
- return 'left';
11382
+ if (type === 'left') {
11383
+ return 'left';
11401
11384
  }
11385
+ // alternate 타입: 짝수는 왼쪽, 홀수는 오른쪽
11386
+ return index % 2 === 0 ? 'left' : 'right';
11402
11387
  };
11403
- const classes = clsx('designbase-timeline', `designbase-timeline--${position}`, `designbase-timeline--${variant}`, `designbase-timeline--${size}`, {
11388
+ const classes = clsx('designbase-timeline', `designbase-timeline--${type}`, `designbase-timeline--${variant}`, `designbase-timeline--${size}`, {
11404
11389
  'designbase-timeline--clickable': clickable,
11405
11390
  'designbase-timeline--full-width': fullWidth,
11406
11391
  'designbase-timeline--disabled': disabled,
@@ -11415,30 +11400,29 @@ const Timeline = ({ items, position = 'alternate', variant = 'default', size = '
11415
11400
  'designbase-timeline__item--disabled': item.disabled,
11416
11401
  });
11417
11402
  const contentClasses = clsx('designbase-timeline__content', `designbase-timeline__content--${itemPosition}`);
11418
- const separatorClasses = clsx('designbase-timeline__separator', `designbase-timeline__separator--${itemPosition}`);
11419
11403
  const dotClasses = clsx('designbase-timeline__dot', `designbase-timeline__dot--${itemColor}`, `designbase-timeline__dot--${variant}`, {
11420
11404
  'designbase-timeline__dot--clickable': isClickable,
11421
11405
  });
11422
- return (jsxRuntime.jsxs("div", { className: itemClasses, children: [jsxRuntime.jsx("div", { className: contentClasses, children: jsxRuntime.jsxs("div", { className: "designbase-timeline__content-inner", onClick: () => handleItemClick(item, index), tabIndex: isClickable ? 0 : -1, role: isClickable ? 'button' : undefined, "aria-label": `${item.title} 타임라인 아이템`, onKeyDown: (e) => {
11423
- if (e.key === 'Enter' || e.key === ' ') {
11424
- e.preventDefault();
11425
- handleItemClick(item, index);
11426
- }
11427
- }, children: [item.timestamp && (jsxRuntime.jsx("div", { className: "designbase-timeline__timestamp", children: item.timestamp })), jsxRuntime.jsx("h3", { className: "designbase-timeline__title", children: item.title }), item.description && (jsxRuntime.jsx("p", { className: "designbase-timeline__description", children: item.description }))] }) }), jsxRuntime.jsxs("div", { className: separatorClasses, children: [jsxRuntime.jsx("div", { className: dotClasses, onClick: () => handleItemClick(item, index), tabIndex: isClickable ? 0 : -1, role: isClickable ? 'button' : undefined, "aria-label": `${item.title} 타임라인 점`, onKeyDown: (e) => {
11406
+ return (jsxRuntime.jsxs("div", { className: itemClasses, children: [jsxRuntime.jsxs("div", { className: "designbase-timeline__indicator-container", children: [jsxRuntime.jsx("div", { className: dotClasses, onClick: () => handleItemClick(item, index), tabIndex: isClickable ? 0 : -1, role: isClickable ? 'button' : undefined, "aria-label": `${item.title} 타임라인 점`, onKeyDown: (e) => {
11428
11407
  if (e.key === 'Enter' || e.key === ' ') {
11429
11408
  e.preventDefault();
11430
11409
  handleItemClick(item, index);
11431
11410
  }
11432
- }, children: item.icon ? (jsxRuntime.jsx("div", { className: "designbase-timeline__icon", children: item.icon })) : (jsxRuntime.jsx("div", { className: "designbase-timeline__dot-inner" })) }), !isLast && (jsxRuntime.jsx("div", { className: "designbase-timeline__connector" }))] })] }, item.id));
11411
+ }, children: item.icon ? (jsxRuntime.jsx("div", { className: "designbase-timeline__icon", children: item.icon })) : (jsxRuntime.jsx("span", { className: "designbase-timeline__number", children: index + 1 })) }), !isLast && (jsxRuntime.jsx("div", { className: "designbase-timeline__connector" }))] }), jsxRuntime.jsx("div", { className: contentClasses, children: jsxRuntime.jsxs("div", { className: "designbase-timeline__content-inner", onClick: () => handleItemClick(item, index), tabIndex: isClickable ? 0 : -1, role: isClickable ? 'button' : undefined, "aria-label": `${item.title} 타임라인 아이템`, onKeyDown: (e) => {
11412
+ if (e.key === 'Enter' || e.key === ' ') {
11413
+ e.preventDefault();
11414
+ handleItemClick(item, index);
11415
+ }
11416
+ }, children: [item.timestamp && (jsxRuntime.jsx("div", { className: "designbase-timeline__timestamp", children: item.timestamp })), jsxRuntime.jsx("h3", { className: "designbase-timeline__title", children: item.title }), item.description && (jsxRuntime.jsx("p", { className: "designbase-timeline__description", children: item.description }))] }) })] }, item.id));
11433
11417
  }) }) }));
11434
11418
  };
11435
11419
 
11436
- const Toast = ({ id, status = 'info', title, description, icon: Icon, duration = 5000, showProgress = false, showCloseButton = true, position = 'top-right', onClose, className, }) => {
11420
+ const Toast = ({ id, status = 'info', title, description, icon: Icon, duration = 5000, showProgress = false, showCloseButton = true, onClose, className, }) => {
11437
11421
  const [isVisible, setIsVisible] = React.useState(false);
11438
11422
  const [progress, setProgress] = React.useState(100);
11439
11423
  const progressRef = React.useRef(null);
11440
- const timeoutRef = React.useRef();
11441
- const progressIntervalRef = React.useRef();
11424
+ const timeoutRef = React.useRef(undefined);
11425
+ const progressIntervalRef = React.useRef(undefined);
11442
11426
  // 토스트 표시 애니메이션
11443
11427
  React.useEffect(() => {
11444
11428
  const timer = setTimeout(() => setIsVisible(true), 50);
@@ -11484,7 +11468,7 @@ const Toast = ({ id, status = 'info', title, description, icon: Icon, duration =
11484
11468
  clearInterval(progressIntervalRef.current);
11485
11469
  handleClose();
11486
11470
  };
11487
- const classes = clsx('designbase-toast', `designbase-toast--${status}`, `designbase-toast--${position}`, {
11471
+ const classes = clsx('designbase-toast', `designbase-toast--${status}`, {
11488
11472
  'designbase-toast--visible': isVisible,
11489
11473
  'designbase-toast--with-icon': Icon,
11490
11474
  'designbase-toast--with-description': description,
@@ -11546,7 +11530,7 @@ const useToast = () => {
11546
11530
  }
11547
11531
  return context;
11548
11532
  };
11549
- const ToastProvider = ({ children }) => {
11533
+ const ToastProvider = ({ children, position = 'top-right' }) => {
11550
11534
  const [toasts, setToasts] = React.useState([]);
11551
11535
  const addToast = React.useCallback((toast) => {
11552
11536
  const id = `toast-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
@@ -11563,7 +11547,7 @@ const ToastProvider = ({ children }) => {
11563
11547
  const removeToast = React.useCallback((id) => {
11564
11548
  setToasts(prev => prev.filter(toast => toast.id !== id));
11565
11549
  }, []);
11566
- return (jsxRuntime.jsxs(ToastContext.Provider, { value: { addToast, removeToast }, children: [children, jsxRuntime.jsx(ToastContainer, { toasts: toasts, onRemoveToast: removeToast })] }));
11550
+ return (jsxRuntime.jsxs(ToastContext.Provider, { value: { addToast, removeToast }, children: [children, jsxRuntime.jsx(ToastContainer, { toasts: toasts, position: position, onRemoveToast: removeToast })] }));
11567
11551
  };
11568
11552
 
11569
11553
  const Toggle = React.forwardRef(({ isSelected, defaultSelected, isDisabled = false, isReadOnly = false, size = 'm', children, className, onChange, ...props }, forwardedRef) => {