All files / packages/app/components page.native.tsx

0% Statements 0/14
0% Branches 0/4
0% Functions 0/6
0% Lines 0/11

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84                                                                                                                                                                       
import type React from "react";
 
import { NativeTabs } from "expo-router/unstable-native-tabs";
import { useCSSVariable } from "uniwind";
 
import type { IconName } from "~components/icons";
import { IconFamily, glyphMapping } from "~components/icons.native";
import type { FileRouteTypes } from "~web/entry/routeTree.gen";
 
type ShowProps = {
	useShow?: () => boolean;
};
 
export type MenuElement = {
	iconName: IconName;
	text: string;
	pathname: FileRouteTypes["to"];
	useBadgeAmount?: () => number;
} & ShowProps;
 
const useZero = () => 0;
const useTrue = () => true;
 
type Props = {
	elements: (MenuElement & {
		ItemWrapper?: React.FC<React.PropsWithChildren>;
		PageWrapper?: React.FC<React.PropsWithChildren>;
	})[];
};
 
export const Page: React.FC<Props> = ({ elements }) => {
	/* oxlint-disable react-hooks/rules-of-hooks */
	// We're pretty sure amount of these elements is stable, but running hooks inside a callback is not an option
	// And we can't move tabs outside because NativeTabs don't digest wrapped Triggers
	const shows = elements.map(({ useShow = useTrue }) => useShow());
	const badgeAmounts = elements.map(({ useBadgeAmount = useZero }) =>
		useBadgeAmount(),
	);
	/* oxlint-enable react-hooks/rules-of-hooks */
	const foregroundColor = useCSSVariable(`--heroui-foreground`) as string;
	const backgroundColor = useCSSVariable(`--heroui-background`) as string;
	const primaryColor = useCSSVariable(`--heroui-primary`) as string;
	return (
		<NativeTabs
			labelStyle={{
				default: {
					color: foregroundColor,
				},
				selected: {
					color: primaryColor,
				},
			}}
			iconColor={{
				default: foregroundColor,
				selected: primaryColor,
			}}
		>
			{elements.map(({ text, pathname, iconName }, index) => (
				<NativeTabs.Trigger
					key={pathname}
					name={pathname.slice(1)}
					hidden={!shows[index]}
					contentStyle={{ backgroundColor }}
				>
					<NativeTabs.Trigger.Label>{text}</NativeTabs.Trigger.Label>
					<NativeTabs.Trigger.Icon
						src={
							<NativeTabs.Trigger.VectorIcon
								family={IconFamily}
								name={glyphMapping[iconName]}
							/>
						}
					/>
					{badgeAmounts[index] ? (
						<NativeTabs.Trigger.Badge>
							{badgeAmounts[index].toString()}
						</NativeTabs.Trigger.Badge>
					) : null}
				</NativeTabs.Trigger>
			))}
		</NativeTabs>
	);
};