import { Component, useEffect, useRef, type ElementType, type ErrorInfo, type ReactNode } from "react";
export function Badge({ count, tone = "default" }: { count: number; tone?: "default" | "warn" | "danger" }) {
if (count <= 0) return null;
const toneClass = tone === "danger" ? "bg-[color:var(--danger)] text-white" : tone === "warn" ? "bg-[color:var(--warn)] text-white" : "bg-[color:var(--muted)] text-white";
return (
{count > 99 ? "99+" : count}
);
}
export function SectionButton({
active,
label,
icon: Icon,
onClick,
badge,
badgeTone,
collapsed = false,
}: {
active: boolean;
label: string;
icon: ElementType;
onClick: () => void;
badge?: number;
badgeTone?: "default" | "warn" | "danger";
collapsed?: boolean;
}) {
if (collapsed) {
return (
);
}
return (
);
}
export function Panel({
title,
eyebrow,
children,
action,
className = "",
tone = "plain",
}: {
title: string;
eyebrow?: string;
children: ReactNode;
action?: ReactNode;
className?: string;
tone?: "plain" | "surface";
}) {
return (
{eyebrow ?
{eyebrow}
: null}
{title}
{action}
{children}
);
}
export function Modal({
open,
title,
onClose,
children,
width = "640px",
}: {
open: boolean;
title: string;
onClose: () => void;
children: ReactNode;
width?: string;
}) {
const trapRef = useFocusTrap(open);
useEffect(() => {
if (!open) return;
function onKey(event: KeyboardEvent) {
if (event.key === "Escape") onClose();
}
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [open, onClose]);
if (!open) return null;
return (
e.stopPropagation()}
>
{children}
);
}
export function Field({ label, children }: { label: string; children: ReactNode }) {
return (
);
}
export function Input({
value,
onChange,
placeholder,
type = "text",
readOnly = false,
disabled = false,
label,
id,
ariaLabel,
}: {
value: string;
onChange: (value: string) => void;
placeholder?: string;
type?: string;
readOnly?: boolean;
disabled?: boolean;
label?: string;
id?: string;
ariaLabel?: string;
}) {
const input = (
onChange(event.target.value)}
/>
);
if (label) {
return (
);
}
return input;
}
export function TextArea({
value,
onChange,
placeholder,
rows = 4,
label,
}: {
value: string;
onChange: (value: string) => void;
placeholder?: string;
rows?: number;
label?: string;
}) {
const textarea = (