Skip to content

Commit

Permalink
feature: arbitrary severity levels
Browse files Browse the repository at this point in the history
  • Loading branch information
srcrip committed Jul 6, 2024
1 parent 675a725 commit 1842c30
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 34 deletions.
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,47 @@ And then use it to override the default styles:
<LiveToast.toast_group flash={@flash} connected={assigns[:socket] != nil} toast_class_fn={&MyModule.toast_class_fn/1} />
```

### Custom Severity Levels

New Phoenix projects [use `:info` and `:error`](https://hexdocs.pm/phoenix/controllers.html#flash-messages)
as the default severity levels for flash messages, so this is likely what you're already using. If you need to add an
additional severity level, like `:warning`, you can pass a list of these values to the `kind` attribute:

```heex
<LiveToast.toast_group
flash={@flash}
connected={assigns[:socket] != nil}
kinds={[:info, :error, :warning]}
toast_class_fn={&custom_toast_class_fn/1}
/>
```

If this value is not set, it defaults to `[:info, :error]`.

Setting `kind` will allow these new severity levels to be displayed, but it won't change how they look. To do that, you
need to override [`toast_class_fn/1`](https://hexdocs.pm/live_toast/LiveToast.html#toast_class_fn/1). For example:

```elixir
# Note that this is just the default with one line added to handle the new `:warning` level.
def custom_toast_class_fn(assigns) do
[
# base classes
"bg-white group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2",
# start hidden if javascript is enabled
"[@media(scripting:enabled)]:opacity-0 [@media(scripting:enabled){[data-phx-main]_&}]:opacity-100",
# used to hide the disconnected flashes
if(assigns[:rest][:hidden] == true, do: "hidden", else: "flex"),
# override styles per severity
assigns[:kind] == :info && "text-black",
assigns[:kind] == :error && "!text-red-700 !bg-red-100 border-red-200",
assigns[:kind] == :warning && "!text-amber-700 !bg-amber-100 border-amber-200"
]
end
```

Then just make sure you've passed it to the `live_group` component as seen above.


### JavaScript Options

You can also change some options about the LiveView hook when it is initialized. Such as:
Expand Down
10 changes: 1 addition & 9 deletions assets/js/live_toast/live_toast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,7 @@ function isHidden(el: HTMLElement | null) {
}

function isFlash(el: HTMLElement) {
if (
['server-error', 'client-error', 'flash-info', 'flash-error'].includes(
el.id,
)
) {
return true
} else {
return false
}
return el.dataset.component === 'flash'
}

// number of flashes that aren't hidden
Expand Down
15 changes: 15 additions & 0 deletions demo/lib/demo_web/components/layouts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,19 @@ defmodule DemoWeb.Layouts do
use DemoWeb, :html

embed_templates("layouts/*")

def demo_toast_class_fn(assigns) do
[
# base classes
"bg-white group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2",
# start hidden if javascript is enabled
"[@media(scripting:enabled)]:opacity-0 [@media(scripting:enabled){[data-phx-main]_&}]:opacity-100",
# used to hide the disconnected flashes
if(assigns[:rest][:hidden] == true, do: "hidden", else: "flex"),
# override styles per severity
assigns[:kind] == :info && "text-black",
assigns[:kind] == :error && "!text-red-700 !bg-red-100 border-red-200",
assigns[:kind] == :warn && "!text-amber-700 !bg-amber-100 border-amber-200"
]
end
end
2 changes: 2 additions & 0 deletions demo/lib/demo_web/components/layouts/app.html.heex
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<div class="grow p-3 md:p-6 mx-auto max-screen-4xl">
<LiveToast.toast_group
toast_class_fn={&demo_toast_class_fn/1}
flash={@flash}
kinds={[:info, :error, :warn]}
connected={assigns[:socket] != nil}
{
if assigns[:settings] do
Expand Down
2 changes: 2 additions & 0 deletions demo/lib/demo_web/live/home_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ defmodule DemoWeb.HomeLive do
case kind do
"info" -> :info
"error" -> :error
"warn" -> :warn
end,
body,
title: title,
Expand All @@ -135,6 +136,7 @@ defmodule DemoWeb.HomeLive do
case kind do
"info" -> :info
"error" -> :error
"warn" -> :warn
end,
"This is a flash message."
)
Expand Down
9 changes: 9 additions & 0 deletions demo/lib/demo_web/live/tabs/demo.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@
Error Flash
</.button>
</div>

<p class="mt-6 mb-4">
You can also use arbitrary severity levels. If you want to add another level like "warning", refer to [the documentation here](https://hexdocs.pm/live_toast/readme.html#custom-severity-levels).
</p>
<div class="flex flex-wrap gap-3">
<.button phx-click="flash" phx-value-kind="warn">
Warning Flash
</.button>
</div>
</div>

<div class="mb-12">
Expand Down
27 changes: 15 additions & 12 deletions lib/live_toast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ defmodule LiveToast do
kind: atom(),
msg: binary(),
title: binary() | nil,
icon: (map() -> binary()) | nil,
action: (map() -> binary()) | nil,
component: (map() -> binary()) | nil,
icon: component_fn() | nil,
action: component_fn() | nil,
component: component_fn() | nil,
duration: non_neg_integer() | nil,
container_id: binary() | nil,
uuid: Ecto.UUID.t() | nil
Expand All @@ -39,13 +39,13 @@ defmodule LiveToast do

@typedoc "Set of public options to augment the default toast behavior."
@type option() ::
{:title, binary()}
| {:icon, component_fn()}
| {:action, component_fn()}
| {:component, component_fn()}
| {:duration, non_neg_integer()}
| {:container_id, binary()}
| {:uuid, Ecto.UUID.t()}
{:title, binary() | nil}
| {:icon, component_fn() | nil}
| {:action, component_fn() | nil}
| {:component, component_fn() | nil}
| {:duration, non_neg_integer() | nil}
| {:container_id, binary() | nil}
| {:uuid, Ecto.UUID.t() | nil}

@doc """
Send a new toast message to the LiveToast component.
Expand Down Expand Up @@ -141,20 +141,21 @@ defmodule LiveToast do
def toast_class_fn(assigns) do
[
# base classes
"group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2",
"bg-white group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2",
# start hidden if javascript is enabled
"[@media(scripting:enabled)]:opacity-0 [@media(scripting:enabled){[data-phx-main]_&}]:opacity-100",
# used to hide the disconnected flashes
if(assigns[:rest][:hidden] == true, do: "hidden", else: "flex"),
# override styles per severity
assigns[:kind] == :info && "bg-white text-black",
assigns[:kind] == :info && "text-black",
assigns[:kind] == :error && "!text-red-700 !bg-red-100 border-red-200"
]
end

attr(:flash, :map, required: true, doc: "the map of flash messages")
attr(:id, :string, default: "toast-group", doc: "the optional id of flash container")
attr(:connected, :boolean, default: false, doc: "whether we're in a liveview or not")
attr(:kinds, :list, default: [:info, :error], doc: "the valid severity level kinds")

attr(:corner, :atom,
values: [:top_left, :top_right, :bottom_left, :bottom_right],
Expand All @@ -181,13 +182,15 @@ defmodule LiveToast do
corner={@corner}
toast_class_fn={@toast_class_fn}
f={@flash}
kinds={@kinds}
/>
<Components.flash_group
:if={!@connected}
id={@id}
corner={@corner}
toast_class_fn={@toast_class_fn}
flash={@flash}
kinds={@kinds}
/>
"""
end
Expand Down
23 changes: 11 additions & 12 deletions lib/live_toast/components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -119,29 +119,25 @@ defmodule LiveToast.Components do
doc: "function to override the look of the toasts"
)

attr(:kinds, :list, required: true, doc: "the valid severity level kinds")

@doc false
def flashes(assigns) do
~H"""
<.toast
:for={level <- @kinds}
data-component="flash"
corner={@corner}
class_fn={@toast_class_fn}
duration={0}
kind={:info}
title="Info"
phx-update="ignore"
flash={@f}
/>
<.toast
corner={@corner}
class_fn={@toast_class_fn}
duration={0}
kind={:error}
title="Error"
kind={level}
title={String.capitalize(to_string(level))}
phx-update="ignore"
flash={@f}
/>
<.toast
data-component="flash"
corner={@corner}
class_fn={@toast_class_fn}
id="client-error"
Expand All @@ -157,6 +153,7 @@ defmodule LiveToast.Components do
</.toast>
<.toast
data-component="flash"
corner={@corner}
class_fn={@toast_class_fn}
id="server-error"
Expand Down Expand Up @@ -187,6 +184,8 @@ defmodule LiveToast.Components do
doc: "function to override the look of the toasts"
)

attr(:kinds, :list, required: true, doc: "the valid severity level kinds")

# Used to render flashes-only on regular non-LV pages.
@doc false
def flash_group(assigns) do
Expand All @@ -213,7 +212,7 @@ defmodule LiveToast.Components do

~H"""
<div id={assigns[:id] || "flash-group"} class={@class}>
<.flashes f={@flash} corner={@corner} toast_class_fn={@toast_class_fn} />
<.flashes f={@flash} corner={@corner} toast_class_fn={@toast_class_fn} kinds={@kinds} />
</div>
"""
end
Expand Down
2 changes: 1 addition & 1 deletion lib/live_toast/live_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ defmodule LiveToast.LiveComponent do
</Components.toast>
</div>
<Components.flashes f={@f} corner={@corner} toast_class_fn={@toast_class_fn} />
<Components.flashes f={@f} corner={@corner} toast_class_fn={@toast_class_fn} kinds={@kinds} />
</div>
"""
end
Expand Down

0 comments on commit 1842c30

Please sign in to comment.