diff --git a/README.md b/README.md index 22bb8a6..0549aac 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,25 @@ msgstr "Aguanta mientras volvemos a la normalidad" component-specific presentation or behavior without adding library-level options. LiveToast does not interpret metadata. +### Default custom toast component + +Pass `toast_component_fn` to `LiveToast.toast_group` when all programmatic toasts in that host should use the same +custom component. A `component:` passed to an individual `send_toast/3` call takes precedence. This host default does +not change Phoenix flash or connection-notice rendering. + +```heex + +``` + +```elixir +LiveToast.send_toast(:info, "The message was sent.", title: "Sent") +``` + ### Custom component metadata Custom component functions receive `metadata` alongside the standard toast assigns such as `kind`, `title`, `body`, diff --git a/demo/lib/demo_web/live/tabs/demo.html.heex b/demo/lib/demo_web/live/tabs/demo.html.heex index 16ae1bf..73c0538 100644 --- a/demo/lib/demo_web/live/tabs/demo.html.heex +++ b/demo/lib/demo_web/live/tabs/demo.html.heex @@ -365,6 +365,17 @@

It will totally take over rendering for that call, so that you can render totally custom toasts. It receives all the assigns of the built in toast function. See the default implementation in GitHub for an example.

+ +

+ If you want every call to + send_toast + to use a custom function, you can also define it up in the call to <.link + class="text-blue-700 hover:text-blue-500 underline" + href="https://hexdocs.pm/live_toast/LiveToast.html#toast_group/1" + > + toast_group + . +

<.button phx-click={ JS.push("toast", diff --git a/demo/test/demo_web/live/send_toast_test.exs b/demo/test/demo_web/live/send_toast_test.exs index 2246ca9..bf1a152 100644 --- a/demo/test/demo_web/live/send_toast_test.exs +++ b/demo/test/demo_web/live/send_toast_test.exs @@ -108,6 +108,54 @@ defmodule DemoWeb.SendToastTest do defp centered_corner(_corner), do: :top_center end + defmodule DefaultComponentLive do + @moduledoc false + + use Phoenix.LiveView + + def mount(_params, _session, socket), do: {:ok, socket} + + def handle_event("send_default", _, socket) do + LiveToast.send_toast(:info, "Rendered by the host default.", uuid: "component-precedence") + + {:noreply, socket} + end + + def handle_event("send_override", _, socket) do + LiveToast.send_toast(:info, "Rendered by the per-toast override.", + component: &override_toast/1, + uuid: "component-precedence" + ) + + {:noreply, socket} + end + + def render(assigns) do + ~H""" + + + + """ + end + + defp default_toast(assigns) do + ~H""" +

{@body}

+ """ + end + + defp override_toast(assigns) do + ~H""" +

{@body}

+ """ + end + end + defmodule ConnectionNotificationLive do @moduledoc false @@ -216,6 +264,29 @@ defmodule DemoWeb.SendToastTest do refute html =~ ~s(data-metadata-icon) assert html =~ ~s(data-reference="receipt-123") end + + test "uses the host default component unless a toast supplies an override", %{conn: conn} do + {:ok, view, _html} = live_isolated(conn, DefaultComponentLive) + + view + |> element("button", "Send Default Component Toast") + |> render_click() + + html = render(view) + + assert html =~ ~s(data-toast-renderer="default") + assert html =~ "Rendered by the host default." + + view + |> element("button", "Send Override Component Toast") + |> render_click() + + html = render(view) + + assert html =~ ~s(data-toast-renderer="override") + assert html =~ "Rendered by the per-toast override." + refute html =~ ~s(data-toast-renderer="default") + end end describe "centered positioning" do diff --git a/lib/live_toast.ex b/lib/live_toast.ex index 001526d..abd28f9 100644 --- a/lib/live_toast.ex +++ b/lib/live_toast.ex @@ -295,6 +295,11 @@ defmodule LiveToast do doc: "function to override the toast classes" ) + attr(:toast_component_fn, :any, + default: nil, + doc: "default component function used to render programmatic toasts" + ) + attr :toasts_sync, :list, required: true, doc: "toasts that get synchronized when calling `put_toast`" attr :flash_duration, :integer, default: 0, doc: "if provided clears flash after provided milliseconds" @@ -325,6 +330,7 @@ defmodule LiveToast do flash_duration={@flash_duration} client_error_delay={@client_error_delay} toast_class_fn={@toast_class_fn} + toast_component_fn={@toast_component_fn} group_class_fn={@group_class_fn} connection_notifications={@connection_notifications} client_error={@client_error} diff --git a/lib/live_toast/live_component.ex b/lib/live_toast/live_component.ex index e41e08e..5d1ef8a 100644 --- a/lib/live_toast/live_component.ex +++ b/lib/live_toast/live_component.ex @@ -117,7 +117,7 @@ defmodule LiveToast.LiveComponent do duration={duration} kind={k} toast_class_fn={@toast_class_fn} - component={component} + component={component || @toast_component_fn} icon={icon} action={action} metadata={metadata}