@designbasekorea/ui 0.2.9 → 0.2.12

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.umd.js CHANGED
@@ -10854,8 +10854,11 @@
10854
10854
  const Tabs = ({ items, defaultSelectedId, selectedId, orientation = 'horizontal', size = 'm', fullWidth = false, variant = 'default', className, onTabChange, ...props }) => {
10855
10855
  const [activeTabId, setActiveTabId] = React.useState(selectedId ?? defaultSelectedId ?? items[0]?.id ?? '');
10856
10856
  const [focusedTabId, setFocusedTabId] = React.useState('');
10857
+ const [isDragging, setIsDragging] = React.useState(false);
10857
10858
  const tabListRef = React.useRef(null);
10858
10859
  const tabRefs = React.useRef(new Map());
10860
+ const dragStartRef = React.useRef(null);
10861
+ const clickStartRef = React.useRef(null);
10859
10862
  // 제어 컴포넌트 처리
10860
10863
  React.useEffect(() => {
10861
10864
  if (selectedId !== undefined) {
@@ -10927,18 +10930,126 @@
10927
10930
  }
10928
10931
  }, [items, orientation]);
10929
10932
  const handleTabSelect = React.useCallback((tabId) => {
10933
+ // 드래그 중이면 탭 선택 무시
10934
+ if (isDragging)
10935
+ return;
10930
10936
  const tab = items.find(item => item.id === tabId);
10931
10937
  if (tab && !tab.disabled) {
10932
10938
  setActiveTabId(tabId);
10933
10939
  onTabChange?.(tabId);
10934
10940
  }
10935
- }, [items, onTabChange]);
10941
+ }, [items, onTabChange, isDragging]);
10936
10942
  const handleTabFocus = React.useCallback((tabId) => {
10937
10943
  setFocusedTabId(tabId);
10938
10944
  }, []);
10939
10945
  const handleTabBlur = React.useCallback(() => {
10940
10946
  setFocusedTabId('');
10941
10947
  }, []);
10948
+ // 드래그 스크롤 핸들러들
10949
+ const handleMouseDown = React.useCallback((e) => {
10950
+ if (orientation !== 'horizontal' || !tabListRef.current)
10951
+ return;
10952
+ // 클릭 시작 위치와 시간 기록
10953
+ clickStartRef.current = {
10954
+ x: e.pageX,
10955
+ y: e.pageY,
10956
+ time: Date.now()
10957
+ };
10958
+ dragStartRef.current = {
10959
+ x: e.pageX - tabListRef.current.offsetLeft,
10960
+ scrollLeft: tabListRef.current.scrollLeft
10961
+ };
10962
+ }, [orientation]);
10963
+ const handleMouseMove = React.useCallback((e) => {
10964
+ if (!dragStartRef.current || !tabListRef.current)
10965
+ return;
10966
+ // 아직 드래그가 시작되지 않았다면 드래그 시작 여부 판단
10967
+ if (!isDragging && clickStartRef.current) {
10968
+ const deltaX = Math.abs(e.pageX - clickStartRef.current.x);
10969
+ const deltaY = Math.abs(e.pageY - clickStartRef.current.y);
10970
+ const deltaTime = Date.now() - clickStartRef.current.time;
10971
+ // 5px 이상 이동하거나 200ms 이상 지났으면 드래그 시작
10972
+ if (deltaX > 5 || deltaY > 5 || deltaTime > 200) {
10973
+ setIsDragging(true);
10974
+ }
10975
+ }
10976
+ if (!isDragging || !dragStartRef.current)
10977
+ return;
10978
+ e.preventDefault();
10979
+ const x = e.pageX - tabListRef.current.offsetLeft;
10980
+ const walk = (x - dragStartRef.current.x) * 2; // 스크롤 속도 조절
10981
+ tabListRef.current.scrollLeft = dragStartRef.current.scrollLeft - walk;
10982
+ }, [isDragging]);
10983
+ const handleMouseUp = React.useCallback(() => {
10984
+ setIsDragging(false);
10985
+ dragStartRef.current = null;
10986
+ clickStartRef.current = null;
10987
+ }, []);
10988
+ const handleMouseLeave = React.useCallback(() => {
10989
+ setIsDragging(false);
10990
+ dragStartRef.current = null;
10991
+ clickStartRef.current = null;
10992
+ }, []);
10993
+ // 터치 이벤트 핸들러들
10994
+ const handleTouchStart = React.useCallback((e) => {
10995
+ if (orientation !== 'horizontal' || !tabListRef.current)
10996
+ return;
10997
+ const touch = e.touches[0];
10998
+ // 클릭 시작 위치와 시간 기록
10999
+ clickStartRef.current = {
11000
+ x: touch.pageX,
11001
+ y: touch.pageY,
11002
+ time: Date.now()
11003
+ };
11004
+ dragStartRef.current = {
11005
+ x: touch.pageX - tabListRef.current.offsetLeft,
11006
+ scrollLeft: tabListRef.current.scrollLeft
11007
+ };
11008
+ }, [orientation]);
11009
+ const handleTouchMove = React.useCallback((e) => {
11010
+ if (!dragStartRef.current || !tabListRef.current)
11011
+ return;
11012
+ // 아직 드래그가 시작되지 않았다면 드래그 시작 여부 판단
11013
+ if (!isDragging && clickStartRef.current) {
11014
+ const touch = e.touches[0];
11015
+ const deltaX = Math.abs(touch.pageX - clickStartRef.current.x);
11016
+ const deltaY = Math.abs(touch.pageY - clickStartRef.current.y);
11017
+ const deltaTime = Date.now() - clickStartRef.current.time;
11018
+ // 5px 이상 이동하거나 200ms 이상 지났으면 드래그 시작
11019
+ if (deltaX > 5 || deltaY > 5 || deltaTime > 200) {
11020
+ setIsDragging(true);
11021
+ }
11022
+ }
11023
+ if (!isDragging || !dragStartRef.current)
11024
+ return;
11025
+ e.preventDefault();
11026
+ const touch = e.touches[0];
11027
+ const x = touch.pageX - tabListRef.current.offsetLeft;
11028
+ const walk = (x - dragStartRef.current.x) * 2; // 스크롤 속도 조절
11029
+ tabListRef.current.scrollLeft = dragStartRef.current.scrollLeft - walk;
11030
+ }, [isDragging]);
11031
+ const handleTouchEnd = React.useCallback(() => {
11032
+ setIsDragging(false);
11033
+ dragStartRef.current = null;
11034
+ clickStartRef.current = null;
11035
+ }, []);
11036
+ // 드래그 이벤트 리스너 등록/해제
11037
+ React.useEffect(() => {
11038
+ if (isDragging) {
11039
+ document.addEventListener('mousemove', handleMouseMove);
11040
+ document.addEventListener('mouseup', handleMouseUp);
11041
+ document.addEventListener('mouseleave', handleMouseLeave);
11042
+ document.addEventListener('touchmove', handleTouchMove, { passive: false });
11043
+ document.addEventListener('touchend', handleTouchEnd);
11044
+ }
11045
+ return () => {
11046
+ document.removeEventListener('mousemove', handleMouseMove);
11047
+ document.removeEventListener('mouseup', handleMouseUp);
11048
+ document.removeEventListener('mouseleave', handleMouseLeave);
11049
+ document.removeEventListener('touchmove', handleTouchMove);
11050
+ document.removeEventListener('touchend', handleTouchEnd);
11051
+ };
11052
+ }, [isDragging, handleMouseMove, handleMouseUp, handleMouseLeave, handleTouchMove, handleTouchEnd]);
10942
11053
  const activeTab = items.find(item => item.id === activeTabId);
10943
11054
  items.findIndex(item => item.id === activeTabId);
10944
11055
  const classes = clsx('designbase-tabs', `designbase-tabs--${orientation}`, `designbase-tabs--${size}`, `designbase-tabs--${variant}`, {
@@ -10946,8 +11057,9 @@
10946
11057
  }, className);
10947
11058
  const tabListClasses = clsx('designbase-tabs__list', `designbase-tabs__list--${orientation}`, {
10948
11059
  'designbase-tabs__list--full-width': fullWidth,
11060
+ 'designbase-tabs__list--dragging': isDragging,
10949
11061
  });
10950
- return (jsxRuntime.jsxs("div", { className: classes, ...props, children: [jsxRuntime.jsx("div", { ref: tabListRef, className: tabListClasses, role: "tablist", "aria-orientation": orientation, "aria-label": "\uD0ED \uBAA9\uB85D", children: items.map((item, index) => {
11062
+ return (jsxRuntime.jsxs("div", { className: classes, ...props, children: [jsxRuntime.jsx("div", { ref: tabListRef, className: tabListClasses, role: "tablist", "aria-orientation": orientation, "aria-label": "\uD0ED \uBAA9\uB85D", onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, children: items.map((item, index) => {
10951
11063
  const isSelected = item.id === activeTabId;
10952
11064
  const isFocused = item.id === focusedTabId;
10953
11065
  const isDisabled = item.disabled;