import React, { ComponentType } from 'react'; import { StyleSheet, TouchableOpacity, View, StyleProp, ViewStyle } from 'react-native'; import { useTheme } from './ThemeContext'; const emptyStyle = {}; const noop = () => undefined; export type TabProps = { readonly children?: React.ReactNode; readonly title?: React.ReactElement; }; export const Tab: ComponentType = () => null; export type TabBarProps = { readonly children?: React.ReactNode; readonly contentStyle?: StyleProp; readonly onSelect?: (tabIdx: number) => void; readonly selectedIndex?: number; readonly tabStyle?: StyleProp; readonly wrapperStyle?: StyleProp; }; const TabBar: ComponentType = ({ selectedIndex = 0, onSelect = noop, children, wrapperStyle = emptyStyle, tabStyle = emptyStyle, contentStyle = emptyStyle, }: TabBarProps) => { const theme = useTheme(); const tabs = React.Children.toArray(children); const [contents, setContents] = React.useState(new Array(tabs.length).fill(null)); const titles = tabs .map(tab => { if (React.isValidElement(tab)) { return tab.props.title; } return null; }) .map((title, index) => ( { if (onSelect !== undefined) { onSelect(index); } }} style={StyleSheet.flatten([ theme.tabBar.tab, index === selectedIndex ? theme.tabBar.selectedTab : emptyStyle, tabStyle, ])} > {title} )); React.useEffect(() => { const selectedContent = tabs.map(tab => { if (React.isValidElement(tab)) { return tab.props.children; } return null; })[selectedIndex]; setContents([ ...contents.slice(0, selectedIndex), selectedContent, ...contents.slice(selectedIndex + 1, contents.length), ]); }, [selectedIndex]); return ( {titles} {contents.map((content, index) => ( {content} ))} ); }; const CompoundTabBar = TabBar as typeof TabBar & { Tab: typeof Tab; }; CompoundTabBar.Tab = Tab; export default CompoundTabBar;