Ctrl K
ComunidadGuías…

src/components/dives/dive-unit-number-field.tsx

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"use client";

import {
  Control,
  ControllerRenderProps,
  FieldValues,
  Path,
} from "react-hook-form";
import type { LucideIcon } from "lucide-react";
import { EntryUnitLabelRow } from "@/components/entry-unit-toggle";
import { UnitNumberInput } from "@/components/unit-number-input";
import {
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { useEntryUnits } from "@/hooks/useEntryUnits";
import { unitLabel, type EntryDimension } from "@/lib/units";

interface UnitNumberItemProps {
  /** The label without its unit, which follows the dimension's entry units. */
  label: string;
  dimension: EntryDimension;
  /** Inside the box, on its left. Absent on a tank's pressures, which carry none. */
  icon?: LucideIcon;
  min?: number;
  max?: number;
  placeholderValue?: number;
  emptyValue?: null | "";
}

export interface DiveUnitNumberFieldProps<
  TFieldValues extends FieldValues,
> extends UnitNumberItemProps {
  control: Control<TFieldValues>;
  name: Path<TFieldValues>;
}

// One of the dive form's measured numbers: a label carrying its unit and the toggle
// that flips it, the box, and the field's message. Every box of one dimension shares
// the toggle's setting - flipping Maximum depth flips Average depth too - since all
// of them read the one setting `useEntryUnits` keeps per dimension.
export function DiveUnitNumberField<TFieldValues extends FieldValues>({
  control,
  name,
  ...item
}: DiveUnitNumberFieldProps<TFieldValues>) {
  return (
    <FormField
      control={control}
      name={name}
      render={({ field }) => <DiveUnitNumberItem field={field} {...item} />}
    />
  );
}

/** The field's body, for a host that already holds the `FormField` - see the weight. */
export function DiveUnitNumberItem<TFieldValues extends FieldValues>({
  field,
  label,
  dimension,
  icon: Icon,
  ...input
}: UnitNumberItemProps & {
  field: ControllerRenderProps<TFieldValues, Path<TFieldValues>>;
}) {
  const { entryUnits, toggleEntryUnits } = useEntryUnits();
  const units = entryUnits(dimension);
  const box = (
    <FormControl
      render={
        <UnitNumberInput
          dimension={dimension}
          units={units}
          className={Icon && "pl-9"}
          {...input}
          {...field}
        />
      }
    />
  );

  return (
    <FormItem>
      <EntryUnitLabelRow
        dimension={dimension}
        entryUnits={units}
        onToggle={() => toggleEntryUnits(dimension)}
      >
        <FormLabel>
          {label} ({unitLabel(dimension, units)})
        </FormLabel>
      </EntryUnitLabelRow>
      {Icon ? (
        <div className="relative">
          <Icon className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2" />
          {box}
        </div>
      ) : (
        box
      )}
      <FormMessage />
    </FormItem>
  );
}