{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-dialog14",
  "title": "Alert dialog",
  "description": "Alert dialog built with shadcn/ui.",
  "files": [
    {
      "path": "contents/components/alert-dialog/14/index.tsx",
      "content": "\"use client\";\n\nimport { CheckIcon, ImagePlusIcon, XIcon } from \"lucide-react\";\nimport { useId } from \"react\";\n\nimport { useCharacterLimit } from \"@/hooks/use-character-limit\";\nimport { useFileUpload } from \"@/hooks/use-file-upload\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Textarea } from \"@/components/ui/textarea\";\n\nconst initialBgImage = [\n  {\n    id: \"profile-bg-123456789\",\n    name: \"profile-bg.jpg\",\n    size: 1528737,\n    type: \"image/jpeg\",\n    url: \"https://images.unsplash.com/photo-1557683316-973673baf926?w=800\",\n  },\n];\n\nconst initialAvatarImage = [\n  {\n    id: \"avatar-123456789\",\n    name: \"avatar-72-01.jpg\",\n    size: 1528737,\n    type: \"image/jpeg\",\n    url: \"https://i.pravatar.cc/150?img=14\",\n  },\n];\n\nexport default function Component() {\n  const id = useId();\n\n  const maxLength = 180;\n  const {\n    value,\n    characterCount,\n    handleChange,\n    maxLength: limit,\n  } = useCharacterLimit({\n    initialValue:\n      \"Hey, I am Margaret, a web developer who loves turning ideas into amazing websites!\",\n    maxLength,\n  });\n\n  return (\n    <Dialog>\n      <DialogTrigger asChild>\n        <Button variant=\"outline\">Edit profile</Button>\n      </DialogTrigger>\n      <DialogContent className=\"flex flex-col gap-0 overflow-y-visible p-0 sm:max-w-lg [&>button:last-child]:top-3.5\">\n        <DialogHeader className=\"contents space-y-0 text-left\">\n          <DialogTitle className=\"border-b px-6 py-4 font-normal\">\n            Edit profile\n          </DialogTitle>\n        </DialogHeader>\n        <DialogDescription className=\"sr-only\">\n          Make changes to your profile here. You can change your photo and set a\n          username.\n        </DialogDescription>\n        <div className=\"overflow-y-auto\">\n          <ProfileBg />\n          <Avatar />\n          <div className=\"px-6 pt-4 pb-6\">\n            <form className=\"space-y-4\">\n              <div className=\"flex flex-col gap-4 sm:flex-row\">\n                <div className=\"flex-1 space-y-2\">\n                  <Label htmlFor={`${id}-first-name`}>First name</Label>\n                  <Input\n                    defaultValue=\"Margaret\"\n                    id={`${id}-first-name`}\n                    placeholder=\"Matt\"\n                    required\n                    type=\"text\"\n                  />\n                </div>\n                <div className=\"flex-1 space-y-2\">\n                  <Label htmlFor={`${id}-last-name`}>Last name</Label>\n                  <Input\n                    defaultValue=\"Villard\"\n                    id={`${id}-last-name`}\n                    placeholder=\"Welsh\"\n                    required\n                    type=\"text\"\n                  />\n                </div>\n              </div>\n              <div className=\"*:not-first:mt-2\">\n                <Label htmlFor={`${id}-username`}>Username</Label>\n                <div className=\"relative\">\n                  <Input\n                    className=\"peer pe-9\"\n                    defaultValue=\"margaret-villard-69\"\n                    id={`${id}-username`}\n                    placeholder=\"Username\"\n                    required\n                    type=\"text\"\n                  />\n                  <div className=\"text-muted-foreground/80 pointer-events-none absolute inset-y-0 end-0 flex items-center justify-center pe-3 peer-disabled:opacity-50\">\n                    <CheckIcon\n                      aria-hidden=\"true\"\n                      className=\"text-emerald-500\"\n                      size={16}\n                    />\n                  </div>\n                </div>\n              </div>\n              <div className=\"*:not-first:mt-2\">\n                <Label htmlFor={`${id}-website`}>Website</Label>\n                <div className=\"flex rounded-md shadow-xs\">\n                  <span className=\"border-input bg-background text-muted-foreground -z-10 inline-flex items-center rounded-s-md border px-3 text-sm\">\n                    https://\n                  </span>\n                  <Input\n                    className=\"-ms-px rounded-s-none shadow-none\"\n                    defaultValue=\"www.margaret.com\"\n                    id={`${id}-website`}\n                    placeholder=\"yourwebsite.com\"\n                    type=\"text\"\n                  />\n                </div>\n              </div>\n              <div className=\"*:not-first:mt-2\">\n                <Label htmlFor={`${id}-bio`}>Biography</Label>\n                <Textarea\n                  aria-describedby={`${id}-description`}\n                  defaultValue={value}\n                  id={`${id}-bio`}\n                  maxLength={maxLength}\n                  onChange={handleChange}\n                  placeholder=\"Write a few sentences about yourself\"\n                />\n                <p\n                  aria-live=\"polite\"\n                  className=\"text-muted-foreground mt-2 text-right text-xs\"\n                  id={`${id}-description`}\n                  role=\"status\"\n                >\n                  <span className=\"tabular-nums\">{limit - characterCount}</span>{\" \"}\n                  characters left\n                </p>\n              </div>\n            </form>\n          </div>\n        </div>\n        <DialogFooter className=\"border-t px-6 py-4\">\n          <DialogClose asChild>\n            <Button type=\"button\" variant=\"outline\">\n              Cancel\n            </Button>\n          </DialogClose>\n          <DialogClose asChild>\n            <Button type=\"button\">Save changes</Button>\n          </DialogClose>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  );\n}\n\nfunction ProfileBg() {\n  const [{ files }, { removeFile, openFileDialog, getInputProps }] =\n    useFileUpload({\n      accept: \"image/*\",\n      initialFiles: initialBgImage,\n    });\n\n  const currentImage = files[0]?.preview || null;\n\n  return (\n    <div className=\"h-32\">\n      <div className=\"bg-muted relative flex size-full items-center justify-center overflow-hidden\">\n        {currentImage && (\n          <img\n            alt={\n              files[0]?.preview\n                ? \"Upload preview\"\n                : \"Default profile background\"\n            }\n            className=\"size-full object-cover\"\n            height={96}\n            src={currentImage}\n            width={512}\n          />\n        )}\n        <div className=\"absolute inset-0 flex items-center justify-center gap-2\">\n          <button\n            aria-label={currentImage ? \"Change image\" : \"Upload image\"}\n            className=\"focus-visible:border-ring focus-visible:ring-ring/50 z-50 flex size-10 cursor-pointer items-center justify-center rounded-full bg-black/60 text-white transition-[color,box-shadow] outline-none hover:bg-black/80 focus-visible:ring-[3px]\"\n            onClick={openFileDialog}\n            type=\"button\"\n          >\n            <ImagePlusIcon aria-hidden=\"true\" size={16} />\n          </button>\n          {currentImage && (\n            <button\n              aria-label=\"Remove image\"\n              className=\"focus-visible:border-ring focus-visible:ring-ring/50 z-50 flex size-10 cursor-pointer items-center justify-center rounded-full bg-black/60 text-white transition-[color,box-shadow] outline-none hover:bg-black/80 focus-visible:ring-[3px]\"\n              onClick={() => removeFile(files[0]?.id)}\n              type=\"button\"\n            >\n              <XIcon aria-hidden=\"true\" size={16} />\n            </button>\n          )}\n        </div>\n      </div>\n      <input\n        {...getInputProps()}\n        aria-label=\"Upload image file\"\n        className=\"sr-only\"\n      />\n    </div>\n  );\n}\n\nfunction Avatar() {\n  const [{ files }, { openFileDialog, getInputProps }] = useFileUpload({\n    accept: \"image/*\",\n    initialFiles: initialAvatarImage,\n  });\n\n  const currentImage = files[0]?.preview || null;\n\n  return (\n    <div className=\"-mt-10 px-6\">\n      <div className=\"border-background bg-muted relative flex size-20 items-center justify-center overflow-hidden rounded-full border-4 shadow-xs shadow-black/10\">\n        {currentImage && (\n          <img\n            alt=\"Profile\"\n            className=\"size-full object-cover\"\n            height={80}\n            src={currentImage}\n            width={80}\n          />\n        )}\n        <button\n          aria-label=\"Change profile picture\"\n          className=\"focus-visible:border-ring focus-visible:ring-ring/50 absolute flex size-8 cursor-pointer items-center justify-center rounded-full bg-black/60 text-white transition-[color,box-shadow] outline-none hover:bg-black/80 focus-visible:ring-[3px]\"\n          onClick={openFileDialog}\n          type=\"button\"\n        >\n          <ImagePlusIcon aria-hidden=\"true\" size={16} />\n        </button>\n        <input\n          {...getInputProps()}\n          aria-label=\"Upload profile picture\"\n          className=\"sr-only\"\n        />\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/alert-dialog14.tsx"
    }
  ],
  "type": "registry:component"
}