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