inogen/app/components/ui/tabs.tsx

117 lines
2.8 KiB
TypeScript

import React, { createContext, useContext, useState } from "react";
import { cn } from "~/lib/utils";
interface TabsContextType {
value: string;
onValueChange: (value: string) => void;
}
const TabsContext = createContext<TabsContextType | undefined>(undefined);
interface TabsProps {
defaultValue?: string;
value?: string;
onValueChange?: (value: string) => void;
className?: string;
children: React.ReactNode;
}
export function Tabs({
defaultValue,
value,
onValueChange,
className,
children,
}: TabsProps) {
const [internalValue, setInternalValue] = useState(defaultValue || "");
const currentValue = value ?? internalValue;
const handleValueChange = onValueChange ?? setInternalValue;
return (
<TabsContext.Provider
value={{ value: currentValue, onValueChange: handleValueChange }}
>
<div className={cn("w-full", className)}>{children}</div>
</TabsContext.Provider>
);
}
interface TabsListProps {
className?: string;
children: React.ReactNode;
}
export function TabsList({ className, children }: TabsListProps) {
return (
<div
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className,
)}
>
{children}
</div>
);
}
interface TabsTriggerProps {
value: string;
className?: string;
disabled?: boolean;
children: React.ReactNode;
}
export function TabsTrigger({
value,
className,
disabled,
children,
}: TabsTriggerProps) {
const context = useContext(TabsContext);
if (!context) throw new Error("TabsTrigger must be used within Tabs");
const isActive = context.value === value;
return (
<button
type="button"
disabled={disabled}
onClick={() => !disabled && context.onValueChange(value)}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
isActive
? "bg-pr-gray text-foreground shadow-sm"
: "hover:bg-muted/50",
className,
)}
>
{children}
</button>
);
}
interface TabsContentProps {
value: string;
className?: string;
children: React.ReactNode;
}
export function TabsContent({ value, className, children }: TabsContentProps) {
const context = useContext(TabsContext);
if (!context) throw new Error("TabsContent must be used within Tabs");
if (context.value !== value) return null;
return (
<div
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className,
)}
>
{children}
</div>
);
}