Source code for duck.html.components.snackbar

"""
Snackbar component for displaying brief messages at the top of the screen.
"""

from duck.html.components.container import FlexContainer
from duck.html.components.script import Script


[docs] class Snackbar(FlexContainer): """ Snackbar component to show notifications. """ allowed_types = {"info", "success", "error"} def __init__(self, text: str = None, type: str = "info", timeout: int = None, **kwargs): self.type = type self.timeout = timeout assert self.type in self.allowed_types, f"Snackbar type must be one of {self.allowed_types}." super().__init__(text=text or "", **kwargs)
[docs] def on_create(self): super().on_create() self.color = "#222" self.klass = f"snackbar snackbar-{self.type}" self.style["position"] = "fixed" self.style["top"] = "0" self.style["left"] = "0" self.style["right"] = "0" self.style["text-align"] = "center" self.style["padding"] = "12px 0" self.style["z-index"] = "9999" self.style["transition"] = "transform 0.3s, opacity 0.3s" self.style["transform"] = "translateY(-100%)" self.style["opacity"] = "0" self.style["backdrop-filter"] = self.style["-webkit-backdrop-filter"] = "blur(20px)" self.style["will-change"] = "transform, opacity" self.style["flex-direction"] = "column" self.style["justify-content"] = "center" self.style["align-items"] = "center" self.style["margin-bottom"] = "2px" bg = None if self.type == "error": bg = "#f44336" elif self.type == "info": bg = "#2196f3" elif self.type == "warning": bg = "#FFB300" else: bg = "#43a047" self.style["background"] = bg # Add script to handle show/hide logic. self.script = Script( inner_html=f""" // Track the current auto-hide timer for the snackbar if (!window._snackbarTimers) window._snackbarTimers = new WeakMap(); function showSnackbar(snackbar, type, timeout) {{ let bg = null; // Set background color based on type if (type === "error") bg = "#f44336"; else if (type === "info") bg = "#2196f3"; else if (type === "success") bg = "#43a047"; else if (type === "warning") bg = "#FFB300"; if (bg) {{ snackbar.style.background = bg; }} // Clear any previous auto-hide timer for this snackbar let prevTimer = window._snackbarTimers.get(snackbar); if (prevTimer) {{ clearTimeout(prevTimer); }} // Show the snackbar (reset transition if hiding) snackbar.style.display = "flex"; snackbar.style.transform = "translateY(0)"; snackbar.style.opacity = "1"; if (typeof timeout === "undefined" || timeout === null) timeout = {self.timeout or "null"}; if (timeout) {{ // Autohide: set new timer and track it let timer = setTimeout(function() {{ hideSnackbar(snackbar); window._snackbarTimers.delete(snackbar); }}, timeout); window._snackbarTimers.set(snackbar, timer); }} }} function hideSnackbar(snackbar) {{ snackbar.style.transform = "translateY(-100%)"; snackbar.style.opacity = "0"; function onTransitionEnd(e) {{ if (e.propertyName === "opacity") {{ snackbar.style.display = "none"; snackbar.removeEventListener("transitionend", onTransitionEnd); }} }} snackbar.addEventListener("transitionend", onTransitionEnd); // Clear any pending auto-hide timer let prevTimer = window._snackbarTimers.get(snackbar); if (prevTimer) {{ clearTimeout(prevTimer); window._snackbarTimers.delete(snackbar); }} }} """ ) self.add_child(self.script)
[docs] def show(self): """ Show the snackbar. """ self.style["transform"] = "translateY(0)" self.style["opacity"] = "1"
[docs] def hide(self): """ Hide the snackbar. """ self.style["transform"] = "translateY(-100%)" self.style["opacity"] = "0"