react-native-reusables
react-native-reusables copied to clipboard
[ BUG ] Table body is not visible when used under Tabs component
Describe the bug When Table component is rendered under Tabs sections, only table header is visible.
To Reproduce Steps to reproduce the behavior:
- Create a Tab
- Inside TabsContent component, render Table component
Expected behavior Whole table should be visible
Screenshots
Platform (please complete the following information):
- Type: [Simulator, Emulator, Device]
- OS: [iOS, Android]
Additional context Works good on Web
@Shu03 Can you please provide a minimal reproduction repo?
@mrzachnugent https://github.com/Shu03/rn-test
@Shu03 Under the hood, the card, table, and tabs are made with View and Pressable. By converting them toViews, there was still the same problem.
Here is the code that demonstrate how the problem is the same with Views which means its a styling issue and not a react-native-reusables issue:
import { FlashList } from "@shopify/flash-list";
import * as React from "react";
import { Alert, ScrollView, useWindowDimensions, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Button } from "~/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "~/components/ui/table";
import { Text } from "~/components/ui/text";
import { cn } from "~/lib/utils";
const INVOICES = [
{
invoice: "INV001",
paymentStatus: "Paid",
totalAmount: "$250.00",
paymentMethod: "Credit Card",
},
];
const MIN_COLUMN_WIDTHS = [120, 120, 100, 120];
export default function Screen() {
const { width } = useWindowDimensions();
const insets = useSafeAreaInsets();
const columnWidths = React.useMemo(() => {
return MIN_COLUMN_WIDTHS.map((minWidth) => {
const evenWidth = width / MIN_COLUMN_WIDTHS.length;
return evenWidth > minWidth ? evenWidth : minWidth;
});
}, [width]);
return (
<View className="flex-1 justify-center p-6">
<View className="w-full max-w-[400px] mx-auto flex-col gap-1.5">
<View className="flex-row w-full">
<View className="flex-1">
<Text>Account</Text>
</View>
<View className="flex-1">
<Text>Password</Text>
</View>
</View>
<View>
<View>
<View className="gap-4 native:gap-2">
<ScrollView
horizontal
bounces={false}
showsHorizontalScrollIndicator={false}
>
<Table aria-labelledby="invoice-table">
<TableHeader>
<TableRow>
<TableHead
className="px-0.5"
style={{ width: columnWidths[0] }}
>
<Text>Invoice</Text>
</TableHead>
<TableHead style={{ width: columnWidths[1] }}>
<Text>Status</Text>
</TableHead>
<TableHead style={{ width: columnWidths[2] }}>
<Text>Method</Text>
</TableHead>
<TableHead style={{ width: columnWidths[3] }}>
<Text className="text-center md:text-right md:pr-5">
Amount
</Text>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<FlashList
data={INVOICES}
estimatedItemSize={45}
contentContainerStyle={{
paddingBottom: insets.bottom,
}}
showsVerticalScrollIndicator={false}
renderItem={({ item: invoice, index }) => {
return (
<TableRow
key={invoice.invoice}
className={cn(
"active:bg-secondary",
index % 2 && "bg-muted/40 "
)}
>
<TableCell style={{ width: columnWidths[0] }}>
<Text>{invoice.invoice}</Text>
</TableCell>
<TableCell style={{ width: columnWidths[1] }}>
<Text>{invoice.paymentStatus}</Text>
</TableCell>
<TableCell style={{ width: columnWidths[2] }}>
<Text>{invoice.paymentMethod}</Text>
</TableCell>
<TableCell
style={{ width: columnWidths[3] }}
className="items-end "
>
<Button
variant="secondary"
size="sm"
className="shadow-sm shadow-foreground/10 mr-3"
onPress={() => {
Alert.alert(
invoice.totalAmount,
`You pressed the price button on invoice ${invoice.invoice}.`
);
}}
>
<Text>{invoice.totalAmount}</Text>
</Button>
</TableCell>
</TableRow>
);
}}
ListFooterComponent={() => {
return (
<>
<TableFooter>
<TableRow>
<TableCell className="flex-1 justify-center">
<Text className="text-foreground">Total</Text>
</TableCell>
<TableCell className="items-end pr-8">
<Button
size="sm"
variant="ghost"
onPress={() => {
Alert.alert(
"Total Amount",
`You pressed the total amount price button.`
);
}}
>
<Text>$2,500.00</Text>
</Button>
</TableCell>
</TableRow>
</TableFooter>
<View className="items-center py-3 ios:pb-0">
<Text
nativeID="invoice-table"
className="items-center text-sm text-muted-foreground"
>
A list of your recent invoices.
</Text>
</View>
</>
);
}}
/>
</TableBody>
</Table>
</ScrollView>
</View>
</View>
</View>
</View>
</View>
);
}
And here is an example where the table can be seen:
import * as React from "react";
import { Alert, ScrollView, useWindowDimensions, View } from "react-native";
import Animated, {
FadeInUp,
FadeOutDown,
LayoutAnimationConfig,
} from "react-native-reanimated";
import { Info } from "~/lib/icons/Info";
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
import { Button } from "~/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "~/components/ui/card";
import { Progress } from "~/components/ui/progress";
import { Text } from "~/components/ui/text";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "~/components/ui/tooltip";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
import { Label } from "~/components/ui/label";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "~/components/ui/table";
import { cn } from "~/lib/utils";
import { FlashList } from "@shopify/flash-list";
const GITHUB_AVATAR_URI =
"https://i.pinimg.com/originals/ef/a2/8d/efa28d18a04e7fa40ed49eeb0ab660db.jpg";
const INVOICES = [
{
invoice: "INV001",
paymentStatus: "Paid",
totalAmount: "$250.00",
paymentMethod: "Credit Card",
},
];
const MIN_COLUMN_WIDTHS = [120, 120, 100, 120];
export default function Screen() {
const { width } = useWindowDimensions();
const insets = useSafeAreaInsets();
const columnWidths = React.useMemo(() => {
return MIN_COLUMN_WIDTHS.map((minWidth) => {
const evenWidth = width / MIN_COLUMN_WIDTHS.length;
return evenWidth > minWidth ? evenWidth : minWidth;
});
}, [width]);
const [value, setValue] = React.useState("account");
return (
<View className="flex-1 justify-center p-6">
<Tabs
value={value}
onValueChange={setValue}
className="w-full max-w-[400px] mx-auto flex-col gap-1.5 flex-1"
>
<TabsList className="flex-row w-full">
<TabsTrigger value="account" className="flex-1">
<Text>Account</Text>
</TabsTrigger>
<TabsTrigger value="password" className="flex-1">
<Text>Password</Text>
</TabsTrigger>
</TabsList>
<TabsContent value="account" className="flex-1">
<Card className="flex-1">
<CardContent className="gap-4 native:gap-2 flex-1">
<ScrollView
horizontal
bounces={false}
showsHorizontalScrollIndicator={false}
>
<Table aria-labelledby="invoice-table">
<TableHeader>
<TableRow>
<TableHead
className="px-0.5"
style={{ width: columnWidths[0] }}
>
<Text>Invoice</Text>
</TableHead>
<TableHead style={{ width: columnWidths[1] }}>
<Text>Status</Text>
</TableHead>
<TableHead style={{ width: columnWidths[2] }}>
<Text>Method</Text>
</TableHead>
<TableHead style={{ width: columnWidths[3] }}>
<Text className="text-center md:text-right md:pr-5">
Amount
</Text>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<FlashList
data={INVOICES}
estimatedItemSize={45}
contentContainerStyle={{
paddingBottom: insets.bottom,
}}
showsVerticalScrollIndicator={false}
renderItem={({ item: invoice, index }) => {
return (
<TableRow
key={invoice.invoice}
className={cn(
"active:bg-secondary",
index % 2 && "bg-muted/40 "
)}
>
<TableCell style={{ width: columnWidths[0] }}>
<Text>{invoice.invoice}</Text>
</TableCell>
<TableCell style={{ width: columnWidths[1] }}>
<Text>{invoice.paymentStatus}</Text>
</TableCell>
<TableCell style={{ width: columnWidths[2] }}>
<Text>{invoice.paymentMethod}</Text>
</TableCell>
<TableCell
style={{ width: columnWidths[3] }}
className="items-end "
>
<Button
variant="secondary"
size="sm"
className="shadow-sm shadow-foreground/10 mr-3"
onPress={() => {
Alert.alert(
invoice.totalAmount,
`You pressed the price button on invoice ${invoice.invoice}.`
);
}}
>
<Text>{invoice.totalAmount}</Text>
</Button>
</TableCell>
</TableRow>
);
}}
ListFooterComponent={() => {
return (
<>
<TableFooter>
<TableRow>
<TableCell className="flex-1 justify-center">
<Text className="text-foreground">Total</Text>
</TableCell>
<TableCell className="items-end pr-8">
<Button
size="sm"
variant="ghost"
onPress={() => {
Alert.alert(
"Total Amount",
`You pressed the total amount price button.`
);
}}
>
<Text>$2,500.00</Text>
</Button>
</TableCell>
</TableRow>
</TableFooter>
<View className="items-center py-3 ios:pb-0">
<Text
nativeID="invoice-table"
className="items-center text-sm text-muted-foreground"
>
A list of your recent invoices.
</Text>
</View>
</>
);
}}
/>
</TableBody>
</Table>
</ScrollView>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="password">
<Card>
<CardHeader>
<CardTitle>Password</CardTitle>
<CardDescription>
Change your password here. After saving, you'll be logged out.
</CardDescription>
</CardHeader>
<CardContent className="gap-4 native:gap-2">
<View className="gap-1">
<Label nativeID="current">Current password</Label>
</View>
<View className="gap-1">
<Label nativeID="new">New password</Label>
</View>
</CardContent>
<CardFooter>
<Button>
<Text>Save password</Text>
</Button>
</CardFooter>
</Card>
</TabsContent>
</Tabs>
</View>
);
}
If you absolutely want it centered, consider settings heights to your elements (ex: h-14)