blob: c8b4aba5352f8a7fe5a475547a639020572f491f [file]
/**
* Tailwind catalyst component
*/
'use client';
import { clsx } from 'clsx';
import type React from 'react';
import { createContext, useContext, useState } from 'react';
import { Link } from './link';
const TableContext = createContext<{
bleed: boolean;
dense: number; // 0 is not dense, 1 is dense, 2 is very dense
grid: boolean;
striped: boolean;
}>({
bleed: false,
dense: 0,
grid: false,
striped: false
});
export function Table({
bleed = false,
dense = 0,
grid = false,
striped = false,
className,
children,
...props
}: {
bleed?: boolean;
dense?: number;
grid?: boolean;
striped?: boolean;
} & React.ComponentPropsWithoutRef<'div'>) {
return (
<TableContext.Provider
value={{ bleed, dense, grid, striped } as React.ContextType<typeof TableContext>}>
<div className="flow-root">
<div
{...props}
className={clsx(className, '-mx-[--gutter] overflow-x-auto whitespace-nowrap')}>
<div
className={clsx('inline-block min-w-full align-middle', !bleed && 'sm:px-[--gutter]')}>
<table className="min-w-full text-left text-sm/6">{children}</table>
</div>
</div>
</div>
</TableContext.Provider>
);
}
export function TableHead({ className, ...props }: React.ComponentPropsWithoutRef<'thead'>) {
return <thead className={clsx(className, 'text-zinc-500 dark:text-zinc-400')} {...props} />;
}
export function TableBody(props: React.ComponentPropsWithoutRef<'tbody'>) {
return <tbody {...props} />;
}
const TableRowContext = createContext<{ href?: string; target?: string; title?: string }>({
href: undefined,
target: undefined,
title: undefined
});
export function TableRow({
href,
target,
title,
className,
children,
...props
}: { href?: string; target?: string; title?: string } & React.ComponentPropsWithoutRef<'tr'>) {
const { striped } = useContext(TableContext);
return (
<TableRowContext.Provider
value={{ href, target, title } as React.ContextType<typeof TableRowContext>}>
<tr
{...props}
className={clsx(
className,
href &&
'has-[[data-row-link][data-focus]]:outline has-[[data-row-link][data-focus]]:outline-2 has-[[data-row-link][data-focus]]:-outline-offset-2 has-[[data-row-link][data-focus]]:outline-blue-500 dark:focus-within:bg-white/[2.5%]',
striped && 'even:bg-zinc-950/[2.5%] dark:even:bg-white/[2.5%]',
href && striped && 'hover:bg-zinc-950/5 dark:hover:bg-white/5',
href && !striped && 'hover:bg-zinc-950/[2.5%] dark:hover:bg-white/[2.5%]'
)}>
{children}
</tr>
</TableRowContext.Provider>
);
}
export function TableHeader({ className, ...props }: React.ComponentPropsWithoutRef<'th'>) {
const { bleed, grid } = useContext(TableContext);
return (
<th
{...props}
className={clsx(
className,
'border-b border-b-zinc-950/10 px-4 py-2 font-medium first:pl-[var(--gutter,theme(spacing.2))] last:pr-[var(--gutter,theme(spacing.2))] dark:border-b-white/10',
grid && 'border-l border-l-zinc-950/5 first:border-l-0 dark:border-l-white/5',
!bleed && 'sm:first:pl-2 sm:last:pr-2'
)}
/>
);
}
export function TableCell({ className, children, ...props }: React.ComponentPropsWithoutRef<'td'>) {
const { bleed, dense, grid, striped } = useContext(TableContext);
const { href, target, title } = useContext(TableRowContext);
const [cellRef, setCellRef] = useState<HTMLElement | null>(null);
return (
<td
ref={href ? setCellRef : undefined}
{...props}
className={clsx(
className,
'relative px-4 first:pl-[var(--gutter,theme(spacing.2))] last:pr-[var(--gutter,theme(spacing.2))]',
!striped && 'border-b border-zinc-950/5 dark:border-white/5',
grid && 'border-l border-l-zinc-950/5 first:border-l-0 dark:border-l-white/5',
dense == 0 ? 'py-4' : dense == 1 ? 'py-2.5' : 'py-0.2', //'py-2.5' : 'py-4',
!bleed && 'sm:first:pl-2 sm:last:pr-2'
)}>
{href && (
<Link
data-row-link
href={href}
target={target}
aria-label={title}
tabIndex={cellRef?.previousElementSibling === null ? 0 : -1}
className="absolute inset-0 focus:outline-none"
/>
)}
{children}
</td>
);
}