Packages

A shadcn/ui-inspired UI library for Gleam and Lustre

Current section

Files

Jump to
glizzy src ui toast.gleam
Raw

src/ui/toast.gleam

// MIT License
// Copyright (c) 2026 Koncreate
// See LICENSE for details
import gleam/option.{type Option, None, Some}
import gleam/string
import lustre/attribute.{type Attribute, attribute, class}
import lustre/element.{type Element}
import lustre/element/html
import ui/keyboard.{type Key, Escape, decode_key}
import ui/size as size_helpers
pub type Variant {
Default
Success
Warning
Error
}
pub type Size {
Small
Medium
Large
}
/// Messages for toast keyboard navigation
pub type Msg {
Dismiss
}
pub fn toast(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
html.div(
[
class(
[
"rounded-md border p-4 shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out",
]
|> string.join(" "),
),
attribute("role", "status"),
attribute("aria-live", "polite"),
..attributes
],
children,
)
}
pub fn title(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
html.p([class("text-sm font-semibold"), ..attributes], children)
}
pub fn description(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
html.p([class("text-sm text-muted-foreground"), ..attributes], children)
}
pub fn variant(v: Variant) -> Attribute(a) {
case v {
Default -> class("bg-background text-foreground")
Success -> class("border-green-500/30 bg-green-500/10 text-green-900")
Warning -> class("border-amber-500/30 bg-amber-500/10 text-amber-900")
Error -> class("border-red-500/30 bg-red-500/10 text-red-900")
}
}
pub fn size(s: Size) -> Attribute(a) {
case s {
Small -> class(size_helpers.text_class(size_helpers.Small))
Medium -> class(size_helpers.text_class(size_helpers.Medium))
Large -> class(size_helpers.text_class(size_helpers.Large))
}
}
// ============================================================================
// Keyboard Navigation
// ============================================================================
/// Keymap for toast keyboard navigation
///
/// ## Keyboard interactions:
/// - **Escape**: Dismiss toast
///
/// Follows WAI-ARIA [Status Message](https://www.w3.org/WAI/ARIA/apg/patterns/statusmessage/) pattern.
pub fn keymap(key_event: keyboard.KeyEvent) -> Option(Msg) {
let key = decode_key(key_event.key)
case key {
Escape -> Some(Dismiss)
_ -> None
}
}