# `PhiaUi.Components.ImageUpload`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/inputs/image_upload.ex#L1)

Image upload component for PhiaUI.

Provides `image_upload/1` — a styled wrapper over Phoenix LiveView's native
file upload system (`live_file_input`). Renders a click-to-upload drop zone,
live image previews via `live_img_preview/1`, per-entry progress bars,
per-entry error messages, and entry removal buttons.

This component uses **zero custom JavaScript** — all upload behaviour is
handled by Phoenix LiveView's built-in upload machinery. No JS hook is needed.

## When to use

Use `image_upload/1` for any image attachment field in a form:

- Profile / avatar upload
- Product image gallery
- Article cover image
- Document attachment (with accept: ~w(.pdf .docx .xlsx))
- Receipt / invoice photo capture

## Requirements

The parent LiveView must configure the upload with `allow_upload/3` in `mount/3`:

    def mount(_params, _session, socket) do
      {:ok,
       socket
       |> allow_upload(:avatar,
         accept: ~w(.jpg .jpeg .png .webp .gif),
         max_entries: 1,
         max_file_size: 5_242_880  # 5 MB
       )}
    end

Then pass `@uploads.avatar` as the `:upload` attribute.

## Basic example

    <.form for={@form} phx-submit="save_profile" phx-change="validate">
      <.image_upload
        upload={@uploads.avatar}
        label="Drag & drop or click to upload a profile photo"
      />
      <.button type="submit">Save</.button>
    </.form>

## Multiple files example

    def mount(_params, _session, socket) do
      {:ok,
       socket
       |> allow_upload(:product_images,
         accept: ~w(.jpg .jpeg .png .webp),
         max_entries: 6,
         max_file_size: 10_000_000
       )}
    end

    <.image_upload
      upload={@uploads.product_images}
      label="Upload up to 6 product images"
    />

## Handling entry cancellation

Add this event handler to support the entry removal (×) button:

    def handle_event("cancel_upload", %{"ref" => ref}, socket) do
      {:noreply, cancel_upload(socket, :avatar, ref)}
    end

The upload name (`:avatar`) must match the atom used in `allow_upload/3`.

## Consuming uploads after form submission

After a successful `phx-submit`, consume entries with `consume_uploaded_entries/3`:

    def handle_event("save_profile", _params, socket) do
      urls =
        consume_uploaded_entries(socket, :avatar, fn %{path: tmp_path}, _entry ->
          dest = Path.join([:code.priv_dir(:my_app), "static", "uploads",
                            Path.basename(tmp_path) <> ".jpg"])
          File.cp!(tmp_path, dest)
          {:ok, "/uploads/" <> Path.basename(dest)}
        end)

      {:noreply, assign(socket, profile_image_url: List.first(urls))}
    end

## Error messages

The component maps Phoenix LiveView upload error atoms to English strings:

| Atom              | Message                       |
|-------------------|-------------------------------|
| `:too_large`      | "File too large"              |
| `:not_accepted`   | "Unsupported file format"     |
| `:too_many_files` | "File limit reached"          |
| other             | "Upload error"                |

# `image_upload`

Renders an image upload zone integrated with Phoenix LiveView's upload system.

Renders:
1. A click-to-upload drop zone (a `<label>` wrapping `live_file_input/1`)
2. A list of accepted entries — each with a thumbnail preview, filename,
   progress bar, and a remove button
3. Per-entry error messages for validation failures

The drop zone is hidden from the visible file input (`sr-only`) so the
entire styled `<label>` area acts as the upload trigger. This approach
requires no custom JS — it is standard HTML form behaviour.

## Attributes

* `upload` (`:any`) (required) - A `Phoenix.LiveView.UploadConfig` struct returned by `@uploads.field_name`.
  Provides entry list, progress, errors, and the file input reference.

* `label` (`:string`) - Instructional text displayed inside the drop zone. Defaults to `"Click or drag & drop to upload"`.
* `class` (`:string`) - Additional CSS classes for the outer wrapper div. Defaults to `nil`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
