@ehfuse/mui-virtual-data-table 1.0.3 → 1.0.4

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
@@ -457,6 +457,7 @@ showScrollbar = true, }, ref) => {
457
457
  const [dragStart, setDragStart] = react.useState({ y: 0, scrollTop: 0 });
458
458
  const [thumbHeight, setThumbHeight] = react.useState(0);
459
459
  const [thumbTop, setThumbTop] = react.useState(0);
460
+ const [hasScrollableContent, setHasScrollableContent] = react.useState(false);
460
461
  // 드래그 스크롤 상태
461
462
  const [isDragScrolling, setIsDragScrolling] = react.useState(false);
462
463
  const [dragScrollStart, setDragScrollStart] = react.useState({
@@ -593,9 +594,33 @@ showScrollbar = true, }, ref) => {
593
594
  return containerRef.current;
594
595
  }
595
596
  // children 요소에서 스크롤 가능한 요소 찾기
597
+ // 중첩된 OverlayScrollbar의 영역은 제외 (다른 OverlayScrollbar의 container는 스킵)
596
598
  const childScrollableElements = containerRef.current.querySelectorAll('[data-virtuoso-scroller], [style*="overflow"], .virtuoso-scroller, [style*="overflow: auto"], [style*="overflow:auto"]');
597
599
  for (const child of childScrollableElements) {
598
600
  const element = child;
601
+ // 이 요소가 다른 OverlayScrollbar의 container인지 확인
602
+ // (자신의 containerRef는 아니어야 하고, overlay-scrollbar-container 클래스를 가진 경우)
603
+ if (element !== containerRef.current &&
604
+ element.classList.contains("overlay-scrollbar-container")) {
605
+ // 중첩된 OverlayScrollbar의 container이므로 스킵
606
+ continue;
607
+ }
608
+ // 이 요소의 부모 중에 다른 OverlayScrollbar container가 있는지 확인
609
+ let parent = element.parentElement;
610
+ let isNestedInAnotherScrollbar = false;
611
+ while (parent && parent !== containerRef.current) {
612
+ if (parent.classList.contains("overlay-scrollbar-container") &&
613
+ parent !== containerRef.current) {
614
+ // 다른 OverlayScrollbar 내부의 요소이므로 스킵
615
+ isNestedInAnotherScrollbar = true;
616
+ break;
617
+ }
618
+ parent = parent.parentElement;
619
+ }
620
+ if (isNestedInAnotherScrollbar) {
621
+ continue;
622
+ }
623
+ // 스크롤 가능한 요소인지 확인
599
624
  if (element.scrollHeight > element.clientHeight + 2) {
600
625
  cachedScrollContainerRef.current = element;
601
626
  return element;
@@ -628,15 +653,18 @@ showScrollbar = true, }, ref) => {
628
653
  }, [clearHideTimer, finalAutoHideConfig.enabled]);
629
654
  // 스크롤바 위치 및 크기 업데이트
630
655
  const updateScrollbar = react.useCallback(() => {
631
- if (!scrollbarRef.current)
632
- return;
633
656
  const scrollableElement = findScrollableElement();
634
657
  if (!scrollableElement) {
635
658
  // 스크롤 불가능하면 숨김
636
659
  setScrollbarVisible(false);
660
+ setHasScrollableContent(false);
637
661
  clearHideTimer();
638
662
  return;
639
663
  }
664
+ // 스크롤 가능한 콘텐츠가 있음을 표시
665
+ setHasScrollableContent(true);
666
+ if (!scrollbarRef.current)
667
+ return;
640
668
  // 자동 숨김이 비활성화되어 있으면 스크롤바를 항상 표시
641
669
  if (!finalAutoHideConfig.enabled) {
642
670
  setScrollbarVisible(true);
@@ -894,10 +922,25 @@ showScrollbar = true, }, ref) => {
894
922
  const container = containerRef.current;
895
923
  if (container && !scrollableElement) {
896
924
  elementsToWatch.push(container);
897
- // children 요소들의 스크롤도 감지
925
+ // children 요소들의 스크롤도 감지 (중첩된 OverlayScrollbar 제외)
898
926
  const childScrollableElements = container.querySelectorAll('[data-virtuoso-scroller], [style*="overflow"], .virtuoso-scroller, [style*="overflow: auto"], [style*="overflow:auto"]');
899
927
  childScrollableElements.forEach((child) => {
900
- elementsToWatch.push(child);
928
+ const element = child;
929
+ // 다른 OverlayScrollbar의 container는 제외
930
+ if (element !== container &&
931
+ element.classList.contains("overlay-scrollbar-container")) {
932
+ return;
933
+ }
934
+ // 부모 중에 다른 OverlayScrollbar container가 있으면 제외
935
+ let parent = element.parentElement;
936
+ while (parent && parent !== container) {
937
+ if (parent.classList.contains("overlay-scrollbar-container") &&
938
+ parent !== container) {
939
+ return; // 중첩된 OverlayScrollbar 내부이므로 제외
940
+ }
941
+ parent = parent.parentElement;
942
+ }
943
+ elementsToWatch.push(element);
901
944
  });
902
945
  }
903
946
  // 모든 요소에 이벤트 리스너 등록
@@ -1037,16 +1080,13 @@ showScrollbar = true, }, ref) => {
1037
1080
  }, [updateScrollbar]);
1038
1081
  // 컴포넌트 초기화 완료 표시 (hover 이벤트 활성화용)
1039
1082
  react.useLayoutEffect(() => {
1040
- const timer = setTimeout(() => {
1041
- setIsInitialized(true);
1042
- // 초기화 후 스크롤바 업데이트 (썸 높이 정확하게 계산)
1043
- updateScrollbar();
1044
- // 자동 숨김이 비활성화되어 있으면 스크롤바를 항상 표시
1045
- if (!finalAutoHideConfig.enabled && isScrollable()) {
1046
- setScrollbarVisible(true);
1047
- }
1048
- }, 0);
1049
- return () => clearTimeout(timer);
1083
+ setIsInitialized(true);
1084
+ // 초기화 직후 스크롤바 업데이트 (썸 높이 정확하게 계산)
1085
+ updateScrollbar();
1086
+ // 자동 숨김이 비활성화되어 있으면 스크롤바를 항상 표시
1087
+ if (!finalAutoHideConfig.enabled && isScrollable()) {
1088
+ setScrollbarVisible(true);
1089
+ }
1050
1090
  }, [isScrollable, updateScrollbar, finalAutoHideConfig.enabled]);
1051
1091
  // Resize observer로 크기 변경 감지
1052
1092
  react.useEffect(() => {
@@ -1148,7 +1188,7 @@ showScrollbar = true, }, ref) => {
1148
1188
  minHeight: 0, // flex shrink 허용
1149
1189
  display: "flex", // flex 컨테이너로 설정
1150
1190
  flexDirection: "column", // 세로 방향 정렬
1151
- }, children: children }) }), showScrollbar && (jsxRuntime.jsxs("div", { ref: scrollbarRef, className: "overlay-scrollbar-track", onMouseEnter: () => {
1191
+ }, children: children }) }), showScrollbar && hasScrollableContent && (jsxRuntime.jsxs("div", { ref: scrollbarRef, className: "overlay-scrollbar-track", onMouseEnter: () => {
1152
1192
  clearHideTimer();
1153
1193
  setScrollbarVisible(true);
1154
1194
  }, onMouseLeave: () => {
@@ -1211,7 +1251,7 @@ showScrollbar = true, }, ref) => {
1211
1251
  borderRadius: `${finalThumbConfig.radius}px`,
1212
1252
  cursor: "pointer",
1213
1253
  transition: "background-color 0.2s ease-in-out, opacity 0.2s ease-in-out",
1214
- } })] })), showScrollbar && showArrows && (jsxRuntime.jsx("div", { className: "overlay-scrollbar-up-arrow", onClick: handleUpArrowClick, onMouseEnter: () => setHoveredArrow("up"), onMouseLeave: () => setHoveredArrow(null), style: {
1254
+ } })] })), showScrollbar && hasScrollableContent && showArrows && (jsxRuntime.jsx("div", { className: "overlay-scrollbar-up-arrow", onClick: handleUpArrowClick, onMouseEnter: () => setHoveredArrow("up"), onMouseLeave: () => setHoveredArrow(null), style: {
1215
1255
  position: "absolute",
1216
1256
  top: `${finalTrackConfig.margin}px`,
1217
1257
  right: finalTrackConfig.alignment === "right"
@@ -1237,7 +1277,7 @@ showScrollbar = true, }, ref) => {
1237
1277
  : finalArrowsConfig.opacity
1238
1278
  : 0,
1239
1279
  transition: "opacity 0.2s ease-in-out, color 0.15s ease-in-out",
1240
- }, children: "\u25B2" })), showScrollbar && showArrows && (jsxRuntime.jsx("div", { className: "overlay-scrollbar-down-arrow", onClick: handleDownArrowClick, onMouseEnter: () => setHoveredArrow("down"), onMouseLeave: () => setHoveredArrow(null), style: {
1280
+ }, children: "\u25B2" })), showScrollbar && hasScrollableContent && showArrows && (jsxRuntime.jsx("div", { className: "overlay-scrollbar-down-arrow", onClick: handleDownArrowClick, onMouseEnter: () => setHoveredArrow("down"), onMouseLeave: () => setHoveredArrow(null), style: {
1241
1281
  position: "absolute",
1242
1282
  bottom: `${finalTrackConfig.margin}px`,
1243
1283
  right: finalTrackConfig.alignment === "right"