@redocly/theme
Version:
Shared UI components lib
68 lines (55 loc) • 2.1 kB
text/typescript
import { useEffect, useState, useCallback, useMemo } from 'react';
import type { FileTabs } from '@redocly/theme/components/CodeBlock/CodeBlock';
type CodeBlockTabsProps = {
tabs: FileTabs;
containerRef: React.RefObject<HTMLDivElement | null>;
tabRefs: React.RefObject<HTMLButtonElement[]>;
};
export function useCodeBlockTabsControls({ tabs, containerRef, tabRefs }: CodeBlockTabsProps) {
const [showControls, setShowControls] = useState(false);
const tabsWidth = useMemo(
() =>
tabRefs?.current?.reduce((acc, tabRef) => {
return tabRef ? acc + tabRef.offsetWidth : acc;
}, 0) || 0,
// eslint-disable-next-line react-hooks/exhaustive-deps
[tabRefs?.current?.length],
);
const { currentIndex, isFirstTab, isLastTab } = useMemo(() => {
const currentIndex = tabs.files.findIndex((file) => file.name === tabs.activeTabName);
return {
currentIndex,
isFirstTab: currentIndex === 0,
isLastTab: currentIndex === tabs.files.length - 1,
};
}, [tabs]);
useEffect(() => {
if (containerRef.current) {
const container = containerRef.current;
const resizeObserver = new ResizeObserver((entries) => {
const containerWidth = entries[0].contentRect.width;
setShowControls(tabsWidth > containerWidth);
});
resizeObserver.observe(container);
return () => {
resizeObserver.unobserve(container as HTMLDivElement);
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [containerRef.current]);
const handlePrevTab = useCallback(() => {
if (!isFirstTab) {
const prevTab = tabs.files[currentIndex - 1].name;
tabs.handleTabSwitch(prevTab);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentIndex]);
const handleNextTab = useCallback(() => {
if (!isLastTab) {
const nextTab = tabs.files[currentIndex + 1].name;
tabs.handleTabSwitch(nextTab);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentIndex]);
return { showControls, handlePrevTab, handleNextTab };
}