@redocly/theme
Version:
Shared UI components lib
68 lines (55 loc) • 2.08 kB
text/typescript
import { useEffect, useState, useCallback, useMemo } from 'react';
import type { CodeBlockItems } from '../../components/CodeBlock/CodeBlock';
type CodeBlockTabsProps = {
tabs: CodeBlockItems;
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.items.findIndex((file) => file.name === tabs.value);
return {
currentIndex,
isFirstTab: currentIndex === 0,
isLastTab: currentIndex === tabs.items.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.items[currentIndex - 1].name;
tabs.onChange(prevTab);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentIndex]);
const handleNextTab = useCallback(() => {
if (!isLastTab) {
const nextTab = tabs.items[currentIndex + 1].name;
tabs.onChange(nextTab);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentIndex]);
return { showControls, handlePrevTab, handleNextTab };
}