{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "field",
  "title": "Field",
  "description": "Gives any control a label, description, error and required mark, and wires the ids and aria attributes so nobody has to remember them.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils",
    "https://miseui.junsu4621.workers.dev/r/motion.json",
    "https://miseui.junsu4621.workers.dev/r/label.json"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/field.tsx",
      "content": "import type * as React from \"react\"\nimport { isValidElement, useId, useMemo } from \"react\"\nimport { motion } from \"motion/react\"\nimport { Label } from \"@/registry/miseui/ui/label\"\nimport {\n  FieldContext,\n  FieldControl,\n  FieldError,\n  joinIds,\n  renderControl,\n  useFieldShake,\n  type FieldControlWiring,\n  type FieldEffect,\n  type FieldVariant,\n} from \"@/registry/miseui/ui/field-parts\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\n/**\n * Resting state only: the label starts floated, so anything that is not an empty input (a select, a switch,\n * an input with a value) simply shows a small label. The selector targets the frame around label and control.\n */\nconst FLOATING_LABEL_CLASS = cn(\n  \"pointer-events-none absolute top-2 left-3 z-10 origin-top-left scale-[0.85] font-normal text-muted-foreground\",\n  \"transition-[translate,scale] duration-(--duration-fast) ease-(--ease-mise) motion-reduce:transition-none\",\n  \"[[data-slot=field-control]:has(:placeholder-shown):not(:focus-within)>&]:translate-y-[9px]\",\n  \"[[data-slot=field-control]:has(:placeholder-shown):not(:focus-within)>&]:scale-100\",\n)\n\n/** Only the text dims: a disabled control already dims itself, and dimming both would fade it twice. */\nconst DISABLED_TEXT_CLASS =\n  \"data-[disabled=true]:[&_[data-slot=field-description]]:opacity-50 data-[disabled=true]:[&_[data-slot=label]]:opacity-50\"\n\ntype FieldProps = Omit<React.ComponentProps<\"div\">, \"children\"> & {\n  label: React.ReactNode\n  /** Stays visible next to any error, so the guidance is not lost at the moment it is needed. */\n  description?: React.ReactNode\n  /** Makes the control invalid and shows the text. */\n  error?: React.ReactNode\n  required?: boolean\n  disabled?: boolean\n  /** `stacked` top to bottom, `inline` label left, `floating` label inside the input, `card` bordered settings row. */\n  variant?: FieldVariant\n  /** `shake-error` shakes the control when an error arrives; `materialize` grows the error in. */\n  effect?: FieldEffect\n  /** One control, wired through cloneElement. Use `FieldControl` when it sits inside a wrapper. */\n  children: React.ReactNode\n}\n\nfunction controlIdOf(children: React.ReactNode, fallback: string) {\n  if (!isValidElement<{ id?: string }>(children)) return fallback\n  return children.props.id ?? fallback\n}\n\nfunction useFieldWiring({ children, description, error, required, disabled }: FieldProps) {\n  const generatedId = useId()\n  const controlId = controlIdOf(children, `${generatedId}-control`)\n  const labelId = `${generatedId}-label`\n  const descriptionId = `${generatedId}-description`\n  const errorId = `${generatedId}-error`\n  const hasDescription = Boolean(description)\n  const hasError = Boolean(error)\n  const wiring = useMemo<FieldControlWiring>(\n    () => ({\n      id: controlId,\n      \"aria-labelledby\": labelId,\n      \"aria-describedby\": joinIds(hasDescription ? descriptionId : null, hasError ? errorId : null),\n      \"aria-invalid\": hasError ? true : undefined,\n      \"aria-required\": required ? true : undefined,\n      disabled: disabled ? true : undefined,\n    }),\n    [controlId, labelId, hasDescription, descriptionId, hasError, errorId, required, disabled],\n  )\n  return { wiring, descriptionId, errorId }\n}\n\ninterface FieldParts {\n  labelNode: React.ReactNode\n  descriptionNode: React.ReactNode\n  controlNode: React.ReactNode\n  errorNode: React.ReactNode\n}\n\n/** The four arrangements, because the same four parts mean different things in each. */\nfunction FieldLayout({ variant, labelNode, descriptionNode, controlNode, errorNode }: FieldParts & { variant: FieldVariant }) {\n  if (variant === \"inline\") {\n    return (\n      <div data-slot=\"field-grid\" className=\"grid gap-2 @sm:grid-cols-[minmax(0,10rem)_minmax(0,1fr)] @sm:gap-4\">\n        <div data-slot=\"field-label-column\" className=\"@sm:pt-2\">\n          {labelNode}\n        </div>\n        <div className=\"grid min-w-0 gap-2\">\n          {controlNode}\n          {descriptionNode}\n          {errorNode}\n        </div>\n      </div>\n    )\n  }\n  if (variant === \"card\") {\n    return (\n      <div className=\"grid gap-2 rounded-lg border p-4 shadow-xs\">\n        <div className=\"flex flex-wrap items-center justify-between gap-x-4 gap-y-2\">\n          <div data-slot=\"field-label-column\" className=\"grid min-w-0 flex-1 basis-40 gap-1\">\n            {labelNode}\n            {descriptionNode}\n          </div>\n          {controlNode}\n        </div>\n        {errorNode}\n      </div>\n    )\n  }\n  return (\n    <div className=\"grid min-w-0 gap-2\">\n      {variant === \"stacked\" ? labelNode : null}\n      {controlNode}\n      {descriptionNode}\n      {errorNode}\n    </div>\n  )\n}\n\nfunction FieldLabel({ wiring, floating, required, children }: { wiring: FieldControlWiring; floating: boolean; required: boolean; children: React.ReactNode }) {\n  return (\n    <Label\n      id={wiring[\"aria-labelledby\"]}\n      htmlFor={wiring.id}\n      className={floating ? FLOATING_LABEL_CLASS : \"leading-5\"}\n    >\n      <span className=\"min-w-0\">{children}</span>\n      {required ? (\n        <span data-slot=\"field-required\" aria-hidden=\"true\" className=\"-ml-1 text-destructive\">\n          *\n        </span>\n      ) : null}\n    </Label>\n  )\n}\n\nfunction Field(fieldProps: FieldProps) {\n  const { label, description, error, required = false, disabled = false, variant = \"stacked\", effect, className, children, ...props } = fieldProps\n  const { wiring, descriptionId, errorId } = useFieldWiring(fieldProps)\n  const floating = variant === \"floating\"\n  const scope = useFieldShake(error, effect === \"shake-error\")\n  const labelNode = (\n    <FieldLabel wiring={wiring} floating={floating} required={required}>\n      {label}\n    </FieldLabel>\n  )\n  const descriptionNode = description ? (\n    <p id={descriptionId} data-slot=\"field-description\" className=\"text-[13px] leading-5 text-muted-foreground\">\n      {description}\n    </p>\n  ) : null\n  const controlNode = (\n    <motion.div ref={scope} data-slot=\"field-control\" className={cn(\"relative min-w-0\", variant === \"card\" && \"shrink-0\")}>\n      {renderControl(children, wiring, floating)}\n      {floating ? labelNode : null}\n    </motion.div>\n  )\n  const errorNode = <FieldError id={errorId} error={error} materialize={effect === \"materialize\"} />\n  return (\n    <FieldContext.Provider value={wiring}>\n      <div\n        data-slot=\"field\"\n        data-variant={variant}\n        data-effect={effect}\n        data-disabled={disabled ? \"true\" : undefined}\n        // Container query, not media query: a field in a narrow sidebar must stack even on a wide screen.\n        className={cn(\"@container w-full min-w-0\", DISABLED_TEXT_CLASS, className)}\n        {...props}\n      >\n        <FieldLayout variant={variant} {...{ labelNode, descriptionNode, controlNode, errorNode }} />\n      </div>\n    </FieldContext.Provider>\n  )\n}\n\nexport { Field, FieldControl, type FieldProps, type FieldVariant, type FieldEffect }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/miseui/ui/field-parts.tsx",
      "content": "import type * as React from \"react\"\nimport { cloneElement, createContext, isValidElement, useContext, useEffect } from \"react\"\nimport { AnimatePresence, motion, useAnimate, useReducedMotion } from \"motion/react\"\nimport { SPRING_DEFAULT } from \"@/registry/miseui/lib/motion\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\ntype FieldVariant = \"stacked\" | \"inline\" | \"floating\" | \"card\"\ntype FieldEffect = \"shake-error\" | \"materialize\"\n\ninterface FieldControlWiring {\n  id: string\n  \"aria-labelledby\": string\n  \"aria-describedby\"?: string\n  \"aria-invalid\"?: true\n  \"aria-required\"?: true\n  disabled?: true\n}\n\nconst FieldContext = createContext<FieldControlWiring | null>(null)\n\nconst SHAKE_X_PX = [0, -6, 6, -4, 4, 0]\nconst SHAKE_SECONDS = 0.32\n/** Room for the small floated label above the typed text. */\nconst FLOATING_CONTROL_CLASS =\n  \"h-12 pt-5 pb-1 placeholder:text-transparent focus-visible:placeholder:text-muted-foreground\"\n\ntype AnyProps = Record<string, unknown>\n\nfunction joinIds(...ids: readonly unknown[]) {\n  const joined = ids.filter(Boolean).join(\" \")\n  return joined || undefined\n}\n\n/** The child's own values win or merge, so a control that was already wired keeps working. */\nfunction wireControl(child: React.ReactElement<AnyProps>, wiring: FieldControlWiring, floating: boolean) {\n  const { props } = child\n  const floatingProps = floating\n    ? {\n        className: cn(props.className as string | undefined, FLOATING_CONTROL_CLASS),\n        // :placeholder-shown is how the label senses an empty field; it needs a placeholder to exist at all.\n        placeholder: props.placeholder ?? \" \",\n      }\n    : {}\n  return cloneElement(child, {\n    ...wiring,\n    ...floatingProps,\n    id: props.id ?? wiring.id,\n    \"aria-describedby\": joinIds(props[\"aria-describedby\"], wiring[\"aria-describedby\"]),\n    \"aria-invalid\": props[\"aria-invalid\"] ?? wiring[\"aria-invalid\"],\n    \"aria-required\": props[\"aria-required\"] ?? wiring[\"aria-required\"],\n    disabled: props.disabled ?? wiring.disabled,\n  })\n}\n\nfunction renderControl(children: React.ReactNode, wiring: FieldControlWiring, floating: boolean) {\n  if (!isValidElement<AnyProps>(children)) return children\n  return wireControl(children, wiring, floating)\n}\n\n/** For a control nested inside a root that swallows props, such as `SelectTrigger` inside `Select`. */\nfunction FieldControl({ children }: { children: React.ReactElement<AnyProps> }) {\n  const wiring = useContext(FieldContext)\n  return wiring ? wireControl(children, wiring, false) : children\n}\n\nfunction useFieldShake(error: React.ReactNode, enabled: boolean) {\n  const reduceMotion = useReducedMotion() ?? false\n  const [scope, animate] = useAnimate<HTMLDivElement>()\n  useEffect(() => {\n    if (!enabled || !error || reduceMotion || !scope.current) return\n    animate(scope.current, { x: SHAKE_X_PX }, { duration: SHAKE_SECONDS, ease: \"easeOut\" })\n  }, [error, enabled, reduceMotion, animate, scope])\n  return scope\n}\n\nconst ERROR_CLASS = \"text-[13px] leading-5 text-destructive\"\n\ninterface FieldErrorProps {\n  id: string\n  error: React.ReactNode\n  materialize: boolean\n}\n\nfunction MaterializingError({ id, error }: Pick<FieldErrorProps, \"id\" | \"error\">) {\n  const reduceMotion = useReducedMotion() ?? false\n  return (\n    <AnimatePresence initial={false}>\n      {error ? (\n        <motion.p\n          key=\"error\"\n          id={id}\n          data-slot=\"field-error\"\n          data-materialize={reduceMotion ? \"false\" : \"true\"}\n          className={cn(ERROR_CLASS, \"overflow-hidden\")}\n          initial={reduceMotion ? false : { height: 0, opacity: 0, filter: \"blur(4px)\" }}\n          animate={reduceMotion ? undefined : { height: \"auto\", opacity: 1, filter: \"blur(0px)\" }}\n          exit={reduceMotion ? undefined : { height: 0, opacity: 0, filter: \"blur(4px)\" }}\n          transition={SPRING_DEFAULT}\n        >\n          {error}\n        </motion.p>\n      ) : null}\n    </AnimatePresence>\n  )\n}\n\n/** The live region is always mounted: a region that appears with its own text is often not announced. */\nfunction FieldError({ id, error, materialize }: FieldErrorProps) {\n  return (\n    <div data-slot=\"field-live\" aria-live=\"polite\">\n      {materialize ? (\n        <MaterializingError id={id} error={error} />\n      ) : error ? (\n        <p id={id} data-slot=\"field-error\" className={ERROR_CLASS}>\n          {error}\n        </p>\n      ) : null}\n    </div>\n  )\n}\n\nexport {\n  FieldContext,\n  FieldControl,\n  FieldError,\n  joinIds,\n  renderControl,\n  useFieldShake,\n  type FieldControlWiring,\n  type FieldEffect,\n  type FieldVariant,\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}