@designbasekorea/ui 0.1.28 → 0.1.29

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
@@ -9628,81 +9628,104 @@ const Skeleton = forwardRef(({ variant = 'text', size = 'm', width, height, anim
9628
9628
  });
9629
9629
  Skeleton.displayName = 'Skeleton';
9630
9630
 
9631
- const SplitView = ({ direction = 'horizontal', mode = 'ratio', initialSplit = 0.5, firstSize = 200, minSize = 100, maxSize, splitterSize = 4, splitterColor, splitterHoverColor, first, second, fullWidth = false, fullHeight = false, className, }) => {
9632
- const [split, setSplit] = useState(initialSplit);
9633
- const [isDragging, setIsDragging] = useState(false);
9631
+ const SplitView = ({ direction = 'horizontal', mode = 'ratio', panels, splitterSize = 4, splitterColor, splitterHoverColor, fullWidth = false, fullHeight = false, className,
9632
+ // Legacy props
9633
+ first, second, initialSplit = 0.5, firstSize = 200, minSize = 100, maxSize, }) => {
9634
+ // Legacy mode: first/second props를 panels로 변환
9635
+ const effectivePanels = panels || [
9636
+ {
9637
+ content: first,
9638
+ size: mode === 'fixed' ? firstSize : initialSplit,
9639
+ minSize,
9640
+ maxSize,
9641
+ resizable: true,
9642
+ },
9643
+ {
9644
+ content: second,
9645
+ resizable: false, // 마지막 패널은 flex로 채움
9646
+ },
9647
+ ];
9648
+ // 각 패널의 현재 크기 상태
9649
+ const [panelSizes, setPanelSizes] = useState(() => effectivePanels.map((panel, index) => {
9650
+ if (panel.size !== undefined)
9651
+ return panel.size;
9652
+ if (mode === 'ratio')
9653
+ return 1 / effectivePanels.length;
9654
+ return 200; // 기본 고정 크기
9655
+ }));
9656
+ const [draggingIndex, setDraggingIndex] = useState(null);
9634
9657
  const containerRef = useRef(null);
9635
- const splitterRef = useRef(null);
9636
- // 분할 비율 또는 고정 크기 계산
9637
- const getSplitValue = useCallback(() => {
9638
- if (mode === 'fixed') {
9639
- return firstSize;
9640
- }
9641
- return Math.max(0, Math.min(1, split)) * 100;
9642
- }, [mode, split, firstSize]);
9643
9658
  // 드래그 시작
9644
- const handleMouseDown = useCallback((e) => {
9659
+ const handleMouseDown = useCallback((index) => (e) => {
9645
9660
  e.preventDefault();
9646
- setIsDragging(true);
9661
+ setDraggingIndex(index);
9647
9662
  document.body.style.cursor = direction === 'horizontal' ? 'col-resize' : 'row-resize';
9648
9663
  document.body.style.userSelect = 'none';
9649
9664
  }, [direction]);
9650
9665
  // 드래그 중
9651
9666
  const handleMouseMove = useCallback((e) => {
9652
- if (!isDragging || !containerRef.current)
9667
+ if (draggingIndex === null || !containerRef.current)
9653
9668
  return;
9654
9669
  const containerRect = containerRef.current.getBoundingClientRect();
9655
- let newSplit;
9670
+ const panel = effectivePanels[draggingIndex];
9671
+ let newSize;
9656
9672
  if (direction === 'horizontal') {
9657
9673
  const containerWidth = containerRect.width;
9658
9674
  const mouseX = e.clientX - containerRect.left;
9675
+ // 이전 패널들의 총 크기 계산
9676
+ let offsetX = 0;
9677
+ for (let i = 0; i < draggingIndex; i++) {
9678
+ const size = panelSizes[i];
9679
+ offsetX += mode === 'fixed' ? size : (size * containerWidth);
9680
+ offsetX += splitterSize; // 분할선 크기 추가
9681
+ }
9682
+ const rawSize = mouseX - offsetX;
9659
9683
  if (mode === 'fixed') {
9660
- // 고정 크기 모드: 픽셀 값으로 설정
9661
- newSplit = Math.max(minSize, Math.min(maxSize || containerWidth - minSize, mouseX));
9662
- setSplit(newSplit);
9684
+ newSize = Math.max(panel.minSize || 0, Math.min(panel.maxSize || containerWidth, rawSize));
9663
9685
  }
9664
9686
  else {
9665
- // 비율 모드: 0-1 값으로 설정
9666
- newSplit = mouseX / containerWidth;
9667
- // 최소/최대 크기 제한
9668
- if (minSize || maxSize) {
9669
- const minSplit = minSize ? minSize / containerWidth : 0;
9670
- const maxSplit = maxSize ? maxSize / containerWidth : 1;
9671
- newSplit = Math.max(minSplit, Math.min(maxSplit, newSplit));
9672
- }
9673
- setSplit(newSplit);
9687
+ newSize = rawSize / containerWidth;
9688
+ const minSplit = panel.minSize ? panel.minSize / containerWidth : 0;
9689
+ const maxSplit = panel.maxSize ? panel.maxSize / containerWidth : 1;
9690
+ newSize = Math.max(minSplit, Math.min(maxSplit, newSize));
9674
9691
  }
9675
9692
  }
9676
9693
  else {
9677
9694
  const containerHeight = containerRect.height;
9678
9695
  const mouseY = e.clientY - containerRect.top;
9696
+ // 이전 패널들의 총 크기 계산
9697
+ let offsetY = 0;
9698
+ for (let i = 0; i < draggingIndex; i++) {
9699
+ const size = panelSizes[i];
9700
+ offsetY += mode === 'fixed' ? size : (size * containerHeight);
9701
+ offsetY += splitterSize; // 분할선 크기 추가
9702
+ }
9703
+ const rawSize = mouseY - offsetY;
9679
9704
  if (mode === 'fixed') {
9680
- // 고정 크기 모드: 픽셀 값으로 설정
9681
- newSplit = Math.max(minSize, Math.min(maxSize || containerHeight - minSize, mouseY));
9682
- setSplit(newSplit);
9705
+ newSize = Math.max(panel.minSize || 0, Math.min(panel.maxSize || containerHeight, rawSize));
9683
9706
  }
9684
9707
  else {
9685
- // 비율 모드: 0-1 값으로 설정
9686
- newSplit = mouseY / containerHeight;
9687
- // 최소/최대 크기 제한
9688
- if (minSize || maxSize) {
9689
- const minSplit = minSize ? minSize / containerHeight : 0;
9690
- const maxSplit = maxSize ? maxSize / containerHeight : 1;
9691
- newSplit = Math.max(minSplit, Math.min(maxSplit, newSplit));
9692
- }
9693
- setSplit(newSplit);
9708
+ newSize = rawSize / containerHeight;
9709
+ const minSplit = panel.minSize ? panel.minSize / containerHeight : 0;
9710
+ const maxSplit = panel.maxSize ? panel.maxSize / containerHeight : 1;
9711
+ newSize = Math.max(minSplit, Math.min(maxSplit, newSize));
9694
9712
  }
9695
9713
  }
9696
- }, [isDragging, direction, mode, minSize, maxSize]);
9714
+ setPanelSizes(prev => {
9715
+ const next = [...prev];
9716
+ next[draggingIndex] = newSize;
9717
+ return next;
9718
+ });
9719
+ }, [draggingIndex, direction, mode, splitterSize, panelSizes, effectivePanels]);
9697
9720
  // 드래그 종료
9698
9721
  const handleMouseUp = useCallback(() => {
9699
- setIsDragging(false);
9722
+ setDraggingIndex(null);
9700
9723
  document.body.style.cursor = '';
9701
9724
  document.body.style.userSelect = '';
9702
9725
  }, []);
9703
9726
  // 이벤트 리스너 등록/해제
9704
9727
  useEffect(() => {
9705
- if (isDragging) {
9728
+ if (draggingIndex !== null) {
9706
9729
  document.addEventListener('mousemove', handleMouseMove);
9707
9730
  document.addEventListener('mouseup', handleMouseUp);
9708
9731
  }
@@ -9710,20 +9733,41 @@ const SplitView = ({ direction = 'horizontal', mode = 'ratio', initialSplit = 0.
9710
9733
  document.removeEventListener('mousemove', handleMouseMove);
9711
9734
  document.removeEventListener('mouseup', handleMouseUp);
9712
9735
  };
9713
- }, [isDragging, handleMouseMove, handleMouseUp]);
9736
+ }, [draggingIndex, handleMouseMove, handleMouseUp]);
9714
9737
  const classes = clsx('designbase-split-view', `designbase-split-view--direction-${direction}`, `designbase-split-view--mode-${mode}`, {
9715
9738
  'designbase-split-view--full-width': fullWidth,
9716
9739
  'designbase-split-view--full-height': fullHeight,
9717
- 'designbase-split-view--dragging': isDragging,
9740
+ 'designbase-split-view--dragging': draggingIndex !== null,
9718
9741
  }, className);
9719
- const splitterClasses = clsx('designbase-split-view__splitter', `designbase-split-view__splitter--direction-${direction}`);
9720
9742
  const style = {
9721
- '--split-value': mode === 'fixed' ? `${getSplitValue()}px` : `${getSplitValue()}%`,
9722
9743
  '--splitter-size': `${splitterSize}px`,
9723
9744
  '--splitter-color': splitterColor,
9724
9745
  '--splitter-hover-color': splitterHoverColor,
9725
9746
  };
9726
- return (jsxs("div", { ref: containerRef, className: classes, style: style, children: [jsx("div", { className: "designbase-split-view__first", children: first }), jsx("div", { ref: splitterRef, className: splitterClasses, onMouseDown: handleMouseDown }), jsx("div", { className: "designbase-split-view__second", children: second })] }));
9747
+ return (jsx("div", { ref: containerRef, className: classes, style: style, children: effectivePanels.map((panel, index) => {
9748
+ const size = panelSizes[index];
9749
+ const isLast = index === effectivePanels.length - 1;
9750
+ const isResizable = panel.resizable !== false && !isLast;
9751
+ const panelStyle = {};
9752
+ if (!isLast) {
9753
+ if (direction === 'horizontal') {
9754
+ panelStyle.width = mode === 'fixed' ? `${size}px` : `${size * 100}%`;
9755
+ panelStyle.flexShrink = 0;
9756
+ }
9757
+ else {
9758
+ panelStyle.height = mode === 'fixed' ? `${size}px` : `${size * 100}%`;
9759
+ panelStyle.flexShrink = 0;
9760
+ }
9761
+ }
9762
+ else {
9763
+ panelStyle.flex = 1;
9764
+ }
9765
+ return (jsxs(React.Fragment, { children: [jsx("div", { className: clsx('designbase-split-view__panel', panel.className), style: panelStyle, children: panel.content }), !isLast && (jsx("div", { className: clsx('designbase-split-view__splitter', `designbase-split-view__splitter--direction-${direction}`, { 'designbase-split-view__splitter--disabled': !isResizable }), onMouseDown: isResizable ? handleMouseDown(index) : undefined, style: {
9766
+ cursor: isResizable
9767
+ ? direction === 'horizontal' ? 'col-resize' : 'row-resize'
9768
+ : 'default',
9769
+ } }))] }, index));
9770
+ }) }));
9727
9771
  };
9728
9772
 
9729
9773
  const Stack = ({ direction = 'vertical', alignment = 'start', justify = 'start', spacing = 'md', fullWidth = false, fullHeight = false, wrap = false, className, children, }) => {