Seed: healthcare template (18 files)
This commit is contained in:
@@ -0,0 +1,72 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
const SelectContext = React.createContext<{
|
||||||
|
value: string; setValue: (v: string) => void;
|
||||||
|
open: boolean; setOpen: (o: boolean) => void;
|
||||||
|
labels: React.MutableRefObject<Record<string, React.ReactNode>>;
|
||||||
|
}>({ value: "", setValue: () => {}, open: false, setOpen: () => {}, labels: { current: {} } as any });
|
||||||
|
|
||||||
|
export function Select({ defaultValue = "", value: controlled, onValueChange, children }: { defaultValue?: string; value?: string; onValueChange?: (v: string) => void; children?: React.ReactNode }) {
|
||||||
|
const [internal, setInternal] = React.useState(defaultValue);
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const labels = React.useRef<Record<string, React.ReactNode>>({});
|
||||||
|
const value = controlled ?? internal;
|
||||||
|
const setValue = (v: string) => { setInternal(v); onValueChange?.(v); setOpen(false); };
|
||||||
|
return (
|
||||||
|
<SelectContext.Provider value={{ value, setValue, open, setOpen, labels }}>
|
||||||
|
<div className="relative inline-block w-full">{children}</div>
|
||||||
|
</SelectContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectTrigger({ className, children, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) {
|
||||||
|
const ctx = React.useContext(SelectContext);
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => ctx.setOpen(!ctx.open)}
|
||||||
|
className={cn("flex h-10 w-full items-center justify-between rounded-md border border-slate-300 bg-white px-3 py-2 text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<span className="ml-2 opacity-50">⌄</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectValue({ placeholder }: { placeholder?: string }) {
|
||||||
|
const ctx = React.useContext(SelectContext);
|
||||||
|
return <span>{ctx.value ? (ctx.labels.current[ctx.value] ?? ctx.value) : (placeholder || "Select...")}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectContent({ className, children, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
||||||
|
const ctx = React.useContext(SelectContext);
|
||||||
|
if (!ctx.open) return null;
|
||||||
|
return (
|
||||||
|
<div className={cn("absolute z-50 mt-1 w-full rounded-md border border-slate-200 bg-white py-1 shadow-lg", className)} {...props}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectItem({ value, className, children, ...props }: React.HTMLAttributes<HTMLDivElement> & { value: string }) {
|
||||||
|
const ctx = React.useContext(SelectContext);
|
||||||
|
ctx.labels.current[value] = children;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => ctx.setValue(value)}
|
||||||
|
className={cn("cursor-pointer px-3 py-2 text-sm hover:bg-slate-100", ctx.value === value && "bg-slate-50 font-medium", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectGroup({ children }: { children?: React.ReactNode }) { return <div>{children}</div>; }
|
||||||
|
export function SelectLabel({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
||||||
|
return <div className={cn("px-3 py-1.5 text-xs font-semibold text-slate-500", className)} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Select;
|
||||||
Reference in New Issue
Block a user