UNPKG

@zag-js/toast

Version:

Core logic for the toast widget implemented as a state machine

122 lines (121 loc) 3.7 kB
// src/toast.connect.ts import { dataAttr } from "@zag-js/dom-query"; import { parts } from "./toast.anatomy.mjs"; import * as dom from "./toast.dom.mjs"; import { getGhostAfterStyle, getGhostBeforeStyle, getPlacementStyle } from "./toast.utils.mjs"; function connect(service, normalize) { const { state, send, prop, scope, context, computed } = service; const translations = prop("translations"); const visible = state.hasTag("visible"); const paused = state.hasTag("paused"); const mounted = context.get("mounted"); const frontmost = computed("frontmost"); const placement = prop("parent").computed("placement"); const type = prop("type"); const stacked = prop("stacked"); const title = prop("title"); const description = prop("description"); const action = prop("action"); const [side, align = "center"] = placement.split("-"); return { type, title, description, placement, visible, paused, closable: !!prop("closable"), pause() { send({ type: "PAUSE" }); }, resume() { send({ type: "RESUME" }); }, dismiss() { send({ type: "DISMISS", src: "programmatic" }); }, getRootProps() { return normalize.element({ ...parts.root.attrs, dir: prop("dir"), id: dom.getRootId(scope), "data-state": visible ? "open" : "closed", "data-type": type, "data-placement": placement, "data-align": align, "data-side": side, "data-mounted": dataAttr(mounted), "data-paused": dataAttr(paused), "data-first": dataAttr(frontmost), "data-sibling": dataAttr(!frontmost), "data-stack": dataAttr(stacked), "data-overlap": dataAttr(!stacked), role: "status", "aria-atomic": "true", "aria-describedby": description ? dom.getDescriptionId(scope) : void 0, "aria-labelledby": title ? dom.getTitleId(scope) : void 0, tabIndex: 0, style: getPlacementStyle(service, visible), onKeyDown(event) { if (event.defaultPrevented) return; if (event.key == "Escape") { send({ type: "DISMISS", src: "keyboard" }); event.preventDefault(); } } }); }, /* Leave a ghost div to avoid setting hover to false when transitioning out */ getGhostBeforeProps() { return normalize.element({ "data-ghost": "before", style: getGhostBeforeStyle(service, visible) }); }, /* Needed to avoid setting hover to false when in between toasts */ getGhostAfterProps() { return normalize.element({ "data-ghost": "after", style: getGhostAfterStyle() }); }, getTitleProps() { return normalize.element({ ...parts.title.attrs, id: dom.getTitleId(scope) }); }, getDescriptionProps() { return normalize.element({ ...parts.description.attrs, id: dom.getDescriptionId(scope) }); }, getActionTriggerProps() { return normalize.button({ ...parts.actionTrigger.attrs, type: "button", onClick(event) { if (event.defaultPrevented) return; action?.onClick?.(); send({ type: "DISMISS", src: "user" }); } }); }, getCloseTriggerProps() { return normalize.button({ id: dom.getCloseTriggerId(scope), ...parts.closeTrigger.attrs, type: "button", "aria-label": translations?.closeTriggerLabel, onClick(event) { if (event.defaultPrevented) return; send({ type: "DISMISS", src: "user" }); } }); } }; } export { connect };