defmodule Toast do @moduledoc """ Server-rendered toast notifications for Phoenix LiveView. This module provides the main API for sending toast notifications that are managed server-side using LiveView streams. """ defstruct [ :id, :type, :message, :title, :description, :duration, :action, :icon, :close_button, :position, :important ] @type t :: %__MODULE__{ id: String.t(), type: :info | :success | :error | :warning | :loading | :default, message: String.t(), title: String.t() | nil, description: String.t() | nil, duration: integer() | nil, action: map() | nil, icon: String.t() | nil, close_button: boolean(), position: atom() | nil, important: boolean() } @doc """ Sends a toast notification to the LiveComponent. ## Examples LiveToast.send_toast(:info, "Operation completed!") LiveToast.send_toast(:error, "Something went wrong", title: "Error", duration: 10_000) """ def send_toast(type, message, opts \\ []) do toast = build_toast(type, message, opts) Phoenix.LiveView.send_update(self(), Toast.LiveComponent, id: "toast-group", toast: toast ) end @doc """ Sends a toast notification and updates the flash. Used for toasts that should persist across live navigation. """ def put_toast(socket, type, message, opts \\ []) do toast = build_toast(type, message, opts) Phoenix.LiveView.send_update(self(), Toast.LiveComponent, id: "toast-group", toast: toast, flash_key: type, flash_value: message ) Phoenix.LiveView.put_flash(socket, type, message) end @doc """ Updates an existing toast by ID. ## Examples Toast.update_toast("toast-123", message: "Updated message", type: :success) Toast.update_toast("toast-123", title: "New Title", duration: 10_000) """ def update_toast(toast_id, updates) do Phoenix.LiveView.send_update(self(), Toast.LiveComponent, id: "toast-group", update_toast: %{id: toast_id, updates: updates} ) end @doc """ Clears a specific toast by ID. """ def clear_toast(id) do Phoenix.LiveView.send_update(self(), Toast.LiveComponent, id: "toast-group", clear: id ) end @doc """ Clears all toasts. """ def clear_all_toasts() do Phoenix.LiveView.send_update(self(), Toast.LiveComponent, id: "toast-group", clear_all: true ) end defp build_toast(type, message, opts) do %__MODULE__{ id: opts[:id] || generate_id(), type: type, message: message, title: opts[:title], description: opts[:description], duration: opts[:duration] || 6000, action: opts[:action], icon: opts[:icon], close_button: Keyword.get(opts, :close_button, true), position: opts[:position], important: Keyword.get(opts, :important, false) } end defp generate_id do "toast-#{:crypto.strong_rand_bytes(8) |> Base.encode16(case: :lower)}" end end