{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"c-time-picker-12","type":"registry:block","title":"Form field with validation","description":"Native form field with a required check, an error, reset and the submitted value.","dependencies":[],"registryDependencies":["button","field","@reui/time-picker"],"files":[{"path":"c-time-picker-12.tsx","type":"registry:block","content":"\"use client\"\n\nimport { useId, useState } from \"react\"\nimport { TimePicker } from \"@/components/reui/time-picker\"\n\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n} from \"@/components/ui/field\"\n\nexport function Pattern() {\n  const id = useId()\n  const [invalid, setInvalid] = useState(false)\n  const [booked, setBooked] = useState<string | null>(null)\n\n  return (\n    /* `noValidate`: the Field draws the error, not the browser bubble. */\n    <form\n      noValidate\n      className=\"mx-auto w-full max-w-sm\"\n      onSubmit={(event) => {\n        event.preventDefault()\n        /* The picker submits `HH:mm` under its `name`, or \"\" while empty. */\n        const time = String(\n          new FormData(event.currentTarget).get(\"deliveryTime\") ?? \"\"\n        )\n        setInvalid(!time)\n        setBooked(time || null)\n      }}\n      onReset={() => {\n        /* The picker returns to its default (empty) on the same reset. */\n        setInvalid(false)\n        setBooked(null)\n      }}\n    >\n      <FieldGroup>\n        <Field data-invalid={invalid || undefined}>\n          <FieldLabel id={`${id}-label`} htmlFor={id}>\n            Delivery time\n          </FieldLabel>\n          <TimePicker\n            id={id}\n            name=\"deliveryTime\"\n            required\n            /* Sets aria-invalid on the trigger; the Field colors the label. */\n            invalid={invalid}\n            minuteStep={30}\n            min=\"08:00\"\n            max=\"20:00\"\n            aria-labelledby={`${id}-label`}\n            aria-describedby={`${id}-hint`}\n            onValueChange={(next) => {\n              /* A pick clears the error; emptying the field waits for Submit. */\n              if (next) setInvalid(false)\n            }}\n          />\n          {/* One id for both, so aria-describedby follows whichever is shown. */}\n          {invalid ? (\n            <FieldError id={`${id}-hint`}>\n              Choose a delivery time to continue.\n            </FieldError>\n          ) : (\n            <FieldDescription id={`${id}-hint`}>\n              30-minute slots between 08:00 and 20:00.\n            </FieldDescription>\n          )}\n        </Field>\n        <div className=\"flex items-center gap-2\">\n          <Button type=\"submit\">Submit</Button>\n          <Button type=\"reset\" variant=\"outline\">\n            Reset\n          </Button>\n          <p\n            role=\"status\"\n            className=\"text-muted-foreground ms-auto min-w-0 truncate text-sm\"\n          >\n            {booked && `Delivery booked for ${booked}`}\n          </p>\n        </div>\n      </FieldGroup>\n    </form>\n  )\n}","target":"components/examples/c-time-picker-12.tsx"}],"meta":{"order":12,"label":"Form Validation"}}