chore: add missing files

This commit is contained in:
Scott Wilson
2025-12-18 18:25:18 -08:00
parent 857248c32e
commit 68a878e145
4 changed files with 143 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
import { cn } from "../../utils";
function UnstableInput({ className, type, ...props }: React.ComponentProps<"input">) {
return (
<input
type={type}
data-slot="input"
className={cn(
"h-9 w-full min-w-0 rounded-md border border-border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
"selection:bg-foreground selection:text-background",
className
)}
{...props}
/>
);
}
export { UnstableInput };

View File

@@ -0,0 +1 @@
export * from "./Input";

View File

@@ -0,0 +1,121 @@
import { ReactElement } from "react";
import {
ChevronDownIcon,
ChevronFirstIcon,
ChevronLastIcon,
ChevronLeftIcon,
ChevronRightIcon
} from "lucide-react";
import { twMerge } from "tailwind-merge";
import {
UnstableDropdownMenu,
UnstableDropdownMenuCheckboxItem,
UnstableDropdownMenuContent,
UnstableDropdownMenuTrigger
} from "../Dropdown";
import { UnstableIconButton } from "../IconButton";
type UnstablePaginationProps = {
count: number;
page: number;
perPage?: number;
onChangePage: (pageNumber: number) => void;
onChangePerPage: (newRows: number) => void;
className?: string;
perPageList?: number[];
startAdornment?: ReactElement;
};
const UnstablePagination = ({
count,
page = 1,
perPage = 20,
onChangePage,
onChangePerPage,
perPageList = [10, 20, 50, 100],
className,
startAdornment
}: UnstablePaginationProps) => {
const prevPageNumber = Math.max(1, page - 1);
const canGoPrev = page > 1;
const upperLimit = Math.ceil(count / perPage);
const nextPageNumber = Math.min(upperLimit, page + 1);
const canGoNext = page + 1 <= upperLimit;
const canGoFirst = page > 1;
const canGoLast = page < upperLimit;
return (
<div className={twMerge("flex w-full items-center justify-end px-2 pt-2", className)}>
{startAdornment}
<div className={twMerge("mr-4 flex items-center space-x-2", startAdornment && "ml-auto")}>
<div className="text-xs">
{(page - 1) * perPage + 1} - {Math.min((page - 1) * perPage + perPage, count)} of {count}
</div>
<UnstableDropdownMenu>
<UnstableDropdownMenuTrigger asChild>
<UnstableIconButton variant="ghost" size="xs">
<ChevronDownIcon />
</UnstableIconButton>
</UnstableDropdownMenuTrigger>
<UnstableDropdownMenuContent align="end">
{perPageList.map((perPageOption) => (
<UnstableDropdownMenuCheckboxItem
checked={perPageOption === perPage}
key={`pagination-per-page-options-${perPageOption}`}
onClick={() => {
const totalPages = Math.ceil(count / perPageOption);
if (page > totalPages) {
onChangePage(totalPages);
}
onChangePerPage(perPageOption);
}}
>
{perPageOption} rows per page
</UnstableDropdownMenuCheckboxItem>
))}
</UnstableDropdownMenuContent>
</UnstableDropdownMenu>
</div>
<div className="flex items-center space-x-2">
<UnstableIconButton
variant="ghost"
size="xs"
onClick={() => onChangePage(1)}
isDisabled={!canGoFirst}
>
<ChevronFirstIcon />
</UnstableIconButton>
<UnstableIconButton
variant="ghost"
size="xs"
onClick={() => onChangePage(prevPageNumber)}
isDisabled={!canGoPrev}
>
<ChevronLeftIcon />
</UnstableIconButton>
<UnstableIconButton
variant="ghost"
size="xs"
onClick={() => onChangePage(nextPageNumber)}
isDisabled={!canGoNext}
>
<ChevronRightIcon />
</UnstableIconButton>
<UnstableIconButton
variant="ghost"
size="xs"
onClick={() => onChangePage(upperLimit)}
isDisabled={!canGoLast}
>
<ChevronLastIcon />
</UnstableIconButton>
</div>
</div>
);
};
export { UnstablePagination, type UnstablePaginationProps };

View File

@@ -0,0 +1 @@
export * from "./Pagination";