{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "floating-label-input",
  "title": "Floating Label Input",
  "description": "An input component with floating label.",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "src/components/ui/floating-label-input.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n// --- HELPER FUNCTIONS & COMPONENTS (Added to fix resolving errors) ---\n\n// 1. `cn` utility function to merge Tailwind classes\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\n// 2. Base `Label` component\nconst Label = React.forwardRef<\n  React.ElementRef<\"label\">,\n  React.ComponentPropsWithoutRef<\"label\">\n>(({ className, ...props }, ref) => (\n  <label\n    ref={ref}\n    className={cn(\n      \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n      className,\n    )}\n    {...props}\n  />\n));\nLabel.displayName = \"Label\";\n\n// 3. User's `Input` component (as provided in the chat history)\nconst inputVariants = cva(\n  \"bg-background file:text-foreground placeholder:text-muted-foreground flex w-full rounded border font-medium file:border-0 file:bg-transparent file:font-medium focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 transition-colors\",\n  {\n    variants: {\n      size: {\n        xl: \"min-h-14 px-4 py-4 text-lg file:text-base\",\n        l: \"min-h-12 px-3 py-3 text-base file:text-sm\",\n        m: \"min-h-10 px-3 py-2 text-sm file:text-sm\",\n        s: \"min-h-8 px-2 py-1.5 text-sm file:text-xs\",\n      },\n      validation: {\n        none: \"border-input focus:border-secondary\",\n        error: \"border-error focus:border-destructive\",\n        success: \"border-green-500 focus:border-green-600\",\n      },\n    },\n    defaultVariants: {\n      size: \"m\",\n      validation: \"none\",\n    },\n  },\n);\nexport interface BaseInputProps\n  extends\n    Omit<React.InputHTMLAttributes<HTMLInputElement>, \"size\">,\n    VariantProps<typeof inputVariants> {\n  validationMsg?: string;\n}\nconst Input = React.forwardRef<HTMLInputElement, BaseInputProps>(\n  (\n    {\n      className,\n      type = \"text\",\n      size = \"m\",\n      validation = \"none\",\n      validationMsg,\n      ...props\n    },\n    ref,\n  ) => {\n    return (\n      <div className=\"w-full\">\n        {\" \"}\n        <input\n          type={type}\n          className={cn(inputVariants({ size, validation }), className)}\n          ref={ref}\n          {...props}\n        />{\" \"}\n        {validationMsg && validation !== \"none\" && (\n          <p\n            className={cn(\"mt-1.5 text-xs font-medium\", {\n              \"text-error\": validation === \"error\",\n              \"text-green-600\": validation === \"success\",\n            })}\n          >\n            {validationMsg}{\" \"}\n          </p>\n        )}{\" \"}\n      </div>\n    );\n  },\n);\nInput.displayName = \"Input\";\n\n// --- FLOATING LABEL IMPLEMENTATION ---\n\n// FloatingInput passes props to the base Input. The placeholder=\" \" is crucial.\nconst FloatingInput = React.forwardRef<\n  HTMLInputElement,\n  React.ComponentPropsWithoutRef<typeof Input>\n>(({ className, ...props }, ref) => {\n  return (\n    <Input placeholder=\" \" className={cn(className)} ref={ref} {...props} />\n  );\n});\nFloatingInput.displayName = \"FloatingInput\";\n\n// Floating label variants using `group` to handle the wrapped <input>\nconst floatingLabelVariants = cva(\n  // Base styles for the un-floated state\n  \"absolute left-2 top-1/2 z-10 origin-[0] -translate-y-1/2 transform cursor-text bg-background px-2 text-muted-foreground duration-300 flex items-center gap-2 whitespace-nowrap pointer-events-none\",\n  {\n    variants: {\n      labelsize: {\n        // Defines the label's text size in its un-floated state\n        xl: \"text-base\",\n        l: \"text-base\",\n        m: \"text-base\",\n        s: \"text-sm\",\n      },\n    },\n    defaultVariants: {\n      labelsize: \"m\",\n    },\n  },\n);\n\n// FloatingLabel component with styles for the floated state triggered by the parent `group`\nconst FloatingLabel = React.forwardRef<\n  React.ElementRef<typeof Label>,\n  React.ComponentPropsWithoutRef<typeof Label> &\n    VariantProps<typeof floatingLabelVariants>\n>(({ className, labelsize, ...props }, ref) => {\n  return (\n    <Label\n      ref={ref}\n      className={cn(\n        floatingLabelVariants({ labelsize }),\n        // Floated state: When the parent `group` is focused OR has a value\n        \"group-focus-within:top-1 group-focus-within:translate-y-1 group-focus-within:scale-95\",\n        'group-data-[value=\"true\"]:top-1 group-data-[value=\"true\"]:translate-y-1 group-data-[value=\"true\"]:scale-95',\n        // Adjust font size for floated state based on initial size\n        {\n          \"group-focus-within:text-0 group-data-[value=true]:text-sm\":\n            labelsize === \"xl\" ||\n            labelsize === \"l\" ||\n            labelsize === \"m\" ||\n            labelsize === \"s\",\n        },\n        className,\n      )}\n      {...props}\n    />\n  );\n});\nFloatingLabel.displayName = \"FloatingLabel\";\n\n// The main component you'll use in your application\ntype FloatingLabelInputProps = React.ComponentPropsWithoutRef<typeof Input> &\n  VariantProps<typeof floatingLabelVariants> & {\n    label?: string;\n    icon?: React.ReactNode;\n    badge?: React.ReactNode;\n  };\n\nconst FloatingLabelInput = React.forwardRef<\n  React.ElementRef<typeof FloatingInput>,\n  FloatingLabelInputProps\n>(\n  (\n    {\n      id,\n      label,\n      icon,\n      badge,\n      labelsize,\n      value: valueProp,\n      defaultValue,\n      onChange,\n      ...props\n    },\n    ref,\n  ) => {\n    const inputId = React.useId() || id;\n    // Check if the input has a value to apply the data attribute\n    const [value, setValue] = React.useState(valueProp ?? defaultValue ?? \"\");\n    React.useEffect(() => {\n      if (valueProp !== undefined) setValue(String(valueProp));\n    }, [valueProp]);\n\n    return (\n      // The `group` class and `data-value` attribute are the keys to the animation\n      <div\n        className=\"relative group\"\n        data-value={\n          typeof value === \"string\" || Array.isArray(value)\n            ? value.length > 0\n            : Boolean(value)\n        }\n      >\n        <FloatingInput\n          ref={ref}\n          id={inputId}\n          value={value}\n          onChange={(e) => {\n            setValue(e.target.value);\n            onChange?.(e); // preserve parent handler\n          }}\n          {...props}\n        />{\" \"}\n        <FloatingLabel htmlFor={inputId} labelsize={labelsize}>\n          <span className=\"flex items-center gap-1 bg-background\">\n            {icon && <span className=\"shrink-0\">{icon}</span>}\n            <span>{label}</span>\n            {badge && (\n              <span className=\"shrink-0 rounded bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground\">\n                {badge}\n              </span>\n            )}\n          </span>\n        </FloatingLabel>\n      </div>\n    );\n  },\n);\nFloatingLabelInput.displayName = \"FloatingLabelInput\";\n\nexport {\n  FloatingInput,\n  FloatingLabel,\n  FloatingLabelInput,\n  floatingLabelVariants,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/floating-label-input.tsx"
    }
  ],
  "type": "registry:ui"
}