66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
import { useLayoutEffect, useRef, useState } from "react";
|
|
import styles from "./index.module.css";
|
|
|
|
type TabItems = {
|
|
tabName: string;
|
|
[key: string]: any;
|
|
}[]
|
|
|
|
export default function BottomTabs({ tabItems, activeIndex, setActiveIndex }: { tabItems: TabItems, activeIndex: number, setActiveIndex: (index: number) => void }) {
|
|
const tabsRef = useRef<HTMLDivElement>(null);
|
|
const tabItemRefs = useRef<(HTMLDivElement | null)[]>([]);
|
|
const [tabIndicator, setTabIndicator] = useState({ x: 0, width: 0 });
|
|
|
|
useLayoutEffect(() => {
|
|
if (!tabItems?.length) return;
|
|
const root = tabsRef.current;
|
|
if (!root) return;
|
|
|
|
const updateIndicator = () => {
|
|
const tab = tabItemRefs.current[activeIndex];
|
|
if (!tab) return;
|
|
const rootRect = root.getBoundingClientRect();
|
|
const tabRect = tab.getBoundingClientRect();
|
|
setTabIndicator({
|
|
x: tabRect.left - rootRect.left,
|
|
width: tabRect.width,
|
|
});
|
|
};
|
|
|
|
updateIndicator();
|
|
const ro = new ResizeObserver(updateIndicator);
|
|
ro.observe(root);
|
|
window.addEventListener("resize", updateIndicator);
|
|
return () => {
|
|
ro.disconnect();
|
|
window.removeEventListener("resize", updateIndicator);
|
|
};
|
|
}, [activeIndex, tabItems]);
|
|
|
|
return (
|
|
<div ref={tabsRef} className={styles.bottomTabsSectionTabsWrap}>
|
|
<div
|
|
className={styles.bottomTabsSectionTabIndicator}
|
|
style={{
|
|
transform: `translateX(${tabIndicator.x}px)`,
|
|
width: tabIndicator.width,
|
|
opacity: tabIndicator.width > 0 ? 1 : 0,
|
|
}}
|
|
/>
|
|
<div className={styles.bottomTabsSectionContentTabs}>
|
|
{tabItems.map((item, i) => (
|
|
<div
|
|
key={i}
|
|
ref={(el) => {
|
|
tabItemRefs.current[i] = el;
|
|
}}
|
|
className={styles.bottomTabsSectionContentTab}
|
|
onClick={() => setActiveIndex(i)}
|
|
>
|
|
<span>{item.tabName}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
} |