@zag-js/toast
Version:
Core logic for the toast widget implemented as a state machine
122 lines (121 loc) • 3.7 kB
JavaScript
// 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
};