UNPKG

braid-design-system

Version:
159 lines (158 loc) • 6.11 kB
import { jsxs, jsx } from "react/jsx-runtime"; import assert from "assert"; import { forwardRef, useCallback, useEffect, cloneElement } from "react"; import { Box } from "../Box/Box.mjs"; import { ButtonIcon } from "../ButtonIcon/ButtonIcon.mjs"; import { Column } from "../Column/Column.mjs"; import { Columns } from "../Columns/Columns.mjs"; import { Inline } from "../Inline/Inline.mjs"; import { Stack } from "../Stack/Stack.mjs"; import { Text } from "../Text/Text.mjs"; import { TextLinkButton } from "../TextLinkButton/TextLinkButton.mjs"; import { Overlay } from "../private/Overlay/Overlay.mjs"; import { buildDataAttributes } from "../private/buildDataAttributes.mjs"; import { toastGap } from "./consts.mjs"; import { useTimeout } from "./useTimeout.mjs"; import { toast, collapsedToastContent } from "./Toast.css.mjs"; import { lineHeightContainer } from "../../css/lineHeightContainer.css.mjs"; import { IconClear } from "../icons/IconClear/IconClear.mjs"; import { IconPositive } from "../icons/IconPositive/IconPositive.mjs"; import { IconCritical } from "../icons/IconCritical/IconCritical.mjs"; const toneToIcon = { critical: IconCritical, positive: IconPositive }; const toastDuration = 10 * 1e3; const borderRadius = "large"; const Action = ({ label, onClick, removeToast }) => { const handleClick = useCallback( (event) => { event.stopPropagation(); removeToast(); onClick(); }, [removeToast, onClick] ); return /* @__PURE__ */ jsx(Text, { baseline: false, children: /* @__PURE__ */ jsx(Box, { component: "span", "aria-hidden": true, children: /* @__PURE__ */ jsx(TextLinkButton, { onClick: handleClick, hitArea: "large", children: label }) }) }); }; const ToastIcon = ({ tone, icon }) => { if (tone !== "neutral") { const Icon = toneToIcon[tone]; return /* @__PURE__ */ jsx(Icon, { tone }); } if (icon) { return cloneElement(icon, { tone }); } return null; }; const Toast = forwardRef( ({ toastKey, dedupeKey, message, description, tone, icon, onClose, closeLabel = "Close", action, shouldRemove, data, expanded = true, ...restProps }, ref) => { const remove = useCallback( () => onClose(dedupeKey, toastKey), [onClose, dedupeKey, toastKey] ); const { stopTimeout, startTimeout } = useTimeout({ duration: toastDuration, onTimeout: remove }); useEffect(() => { if (shouldRemove) { stopTimeout(); remove(); } }, [shouldRemove, remove, stopTimeout]); useEffect( () => expanded ? stopTimeout() : startTimeout(), [expanded, startTimeout, stopTimeout] ); assert( !icon || icon.props.size === void 0 && icon.props.tone === void 0, "Icons cannot set the 'size' or 'tone' prop when passed to a Toast component" ); assert( !icon || icon && tone === "neutral", `Icons cannot be customised on a Toast component using '${tone}' tone` ); const content = description ? /* @__PURE__ */ jsxs(Stack, { space: "xxsmall", children: [ /* @__PURE__ */ jsx(Text, { weight: "medium", tone, baseline: false, children: message }), description ? /* @__PURE__ */ jsx(Text, { baseline: false, tone: "secondary", children: description }) : null, action ? /* @__PURE__ */ jsx(Action, { removeToast: remove, ...action }, action.label) : null ] }) : /* @__PURE__ */ jsxs(Inline, { space: "xxsmall", children: [ /* @__PURE__ */ jsx(Box, { paddingRight: "medium", children: /* @__PURE__ */ jsx(Text, { weight: "medium", tone, baseline: false, children: message }) }), action ? /* @__PURE__ */ jsx(Action, { removeToast: remove, ...action }, action.label) : null ] }); return /* @__PURE__ */ jsx(Box, { position: "relative", width: "full", display: "flex", ref, children: /* @__PURE__ */ jsxs( Box, { role: "alert", textAlign: "left", background: { lightMode: "surfaceDark", darkMode: "surface" }, boxShadow: { lightMode: "borderNeutral", darkMode: "borderNeutralLight" }, borderRadius, paddingY: "medium", paddingX: "gutter", marginTop: toastGap, width: "full", position: "relative", className: toast, tabIndex: 0, outline: "focus", onClick: (event) => { event.stopPropagation(); }, ...buildDataAttributes({ data, validateRestProps: restProps }), children: [ /* @__PURE__ */ jsx(Box, { transition: "fast", className: collapsedToastContent, children: /* @__PURE__ */ jsxs(Columns, { space: "none", children: [ tone !== "neutral" || tone === "neutral" && icon ? /* @__PURE__ */ jsx(Column, { width: "content", children: /* @__PURE__ */ jsx(Box, { paddingRight: "small", children: /* @__PURE__ */ jsx(ToastIcon, { tone, icon }) }) }) : null, /* @__PURE__ */ jsx(Column, { children: content }), /* @__PURE__ */ jsx(Column, { width: "content", children: /* @__PURE__ */ jsx( Box, { width: "touchable", display: "flex", justifyContent: "flexEnd", alignItems: "center", className: lineHeightContainer.standard, "aria-hidden": true, children: /* @__PURE__ */ jsx( ButtonIcon, { icon: /* @__PURE__ */ jsx(IconClear, { tone: "secondary" }), variant: "transparent", onClick: (event) => { event.stopPropagation(); remove(); }, label: closeLabel, data: process.env.NODE_ENV !== "production" ? { testid: "clearToast" } : {} } ) } ) }) ] }) }), /* @__PURE__ */ jsx(Overlay, { visible: true, borderRadius, boxShadow: "large" }) ] } ) }); } ); export { Toast };