237 lines · 6.3 KB
import { forwardRef, useId } from "react";
import { inputVariants } from "@cloudflare/kumo/components/input";
import { Label } from "@cloudflare/kumo/components/label";
import { Select as KumoSelect } from "@cloudflare/kumo/components/select";
import { cn } from "~/utils/cn";

const CONTROL = cn(inputVariants({ focusIndicator: true }), "w-full disabled:opacity-60");
const ERROR_CONTROL = cn(inputVariants({ variant: "error", focusIndicator: true }), "w-full disabled:opacity-60");

function controlClass(error: string | null | undefined, className?: string): string {
  return cn(error ? ERROR_CONTROL : CONTROL, className);
}

type FieldShellProps = {
  label: string;
  hint?: string;
  error?: string | null;
  id: string;
  children: React.ReactNode;
};

function FieldShell({ label, hint, error, id, children }: FieldShellProps) {
  return (
    <div className="flex flex-col gap-1.5">
      <Label htmlFor={id}>{label}</Label>
      {children}
      {hint && !error && (
        <p id={`${id}-hint`} className="text-sm text-kumo-subtle">
          {hint}
        </p>
      )}
      {error && <FieldError id={`${id}-error`}>{error}</FieldError>}
    </div>
  );
}

function describedBy(id: string, hint?: string, error?: string | null): string | undefined {
  if (error) return `${id}-error`;
  if (hint) return `${id}-hint`;
  return undefined;