# Avatar Upload (https://v2.s3.dimah.dev/docs/react/ui/components/avatar-upload)

`AvatarUpload` shows a stored image and replaces it. A click opens the file
picker, and an image dropped on it uploads too. It shows the new image while
it uploads, with a progress ring.

## Preview [#preview]

<DemoPreview name="avatar-upload-demo.tsx">
  <AvatarUploadDemo />
</DemoPreview>

## Install [#install]

Complete [UI Setup](https://v2.s3.dimah.dev/docs/react/ui) first: the stylesheet and one
`<Toaster />`. Then add this component:

<Tabs items={["npm package", "shadcn registry"]}>

<Tab value="npm package">

```tsx
import { AvatarUpload } from "@dimah-s3/ui";
```

</Tab>

<Tab value="shadcn registry">

```npm
npx shadcn@latest add @dimah-s3/avatar-upload
```

</Tab>

</Tabs>

---

## Usage [#usage]

```tsx
"use client";

import { useUpload } from "@dimah-s3/react";
import { AvatarUpload, UploadToasts } from "@dimah-s3/ui";

export function ProfilePhoto({
  avatarKey,
  saveAvatar,
}: {
  avatarKey: string | null;
  saveAvatar: (key: string) => void;
}) {
  const upload = useUpload({ route: "avatar", accept: ["image/*"] });

  return (
    <>
      <AvatarUpload
        upload={upload}
        route="avatar"
        objectKey={avatarKey}
        label="Change profile photo"
        onChange={(result) => saveAvatar(result.key)}
      />
      <UploadToasts upload={upload} />
    </>
  );
}
```

`onChange` runs once for each image that uploads. Store `result.key` and
pass it back as `objectKey`. Images that uploaded before the avatar mounted
are not reported.

## Examples [#examples]

### Sizes and shapes [#sizes-and-shapes]

`size` sets the width and height in pixels. `shape="square"` rounds the
corners instead of the whole image, for logos and covers.

<DemoPreview name="avatar-upload-shapes-demo.tsx">
  <AvatarUploadShapesDemo />
</DemoPreview>

## What it shows [#what-it-shows]

- While an image uploads, and after it succeeds, the picked file's preview.
- Otherwise `objectKey`, signed through `route` with
  [`ObjectImage`](https://v2.s3.dimah.dev/docs/react/ui/components/object-image).
- Without a key, or when the image cannot load, a placeholder icon.

`route` is the route that signs the GET for `objectKey`. It is usually the
same route the hook uploads to. `size` sets the width and height in pixels,
and `shape` is `circle` (the default) or `square`.
The button is disabled while the hook is (`useUpload({ disabled: true })`).

## Accessibility [#accessibility]

`label` is required: it is the button's accessible name. A polite live region
announces the upload: "Preparing…", "Uploading…", "Upload complete", the
error, or the reason a file was rejected.

## Without a provider [#without-a-provider]

`AvatarUpload` signs the image URL with the API from `<S3Provider>`. Without
a provider, pass the same `api` to the hook and to the component:

```tsx
const upload = useUpload({ api, route: "avatar" });

<AvatarUpload
  api={api}
  upload={upload}
  route="avatar"
  objectKey={avatarKey}
  label="Change profile photo"
/>;
```

---

## Props [#props]

```ts
import type { AvatarUploadProps } from "@dimah-s3/ui";
```

<AutoTypeTable
  path="packages/ui/src/components/dimah-s3/upload/avatar-upload.tsx"
  name="AvatarUploadProps"
/>
