UNPKG

@konstructio/ui

Version:

A set of reusable and customizable React components built for konstruct.io

507 lines (506 loc) 18.8 kB
import { jsx as i, jsxs as A, Fragment as ae } from "react/jsx-runtime"; import { S as B } from "../../index-BvoZGpli.js"; import * as n from "react"; import { useRef as xe, useEffect as be, useMemo as re, isValidElement as ne, useCallback as ge } from "react"; import * as Se from "react-dom"; import { P as D, c as Ne, a as Ie, b as x, d as Ae, u as De } from "../../index-DKfEnhKr.js"; import { u as ie } from "../../index-DLcqcWxM.js"; import { c as _e } from "../../index-BG8O18ZY.js"; import { B as Fe, R as Le } from "../../index-BlSRBdPy.js"; import { P as Me } from "../../index-DMb4KD0b.js"; import { P as Oe } from "../../index-AV6ZtGhy.js"; import { u as X } from "../../index-0ioNhtNM.js"; import { R as ke } from "../../index-BKjcReYh.js"; import { cn as j } from "../../utils/index.js"; import { closeToastVariants as Ve, toastVariants as Ke, viewportToastVariants as He } from "./Toast.variants.js"; import { X as We } from "../../x-Eoa9FJjA.js"; var Ue = Object.freeze({ // See: https://github.com/twbs/bootstrap/blob/main/scss/mixins/_visually-hidden.scss position: "absolute", border: 0, width: 1, height: 1, padding: 0, margin: -1, overflow: "hidden", clip: "rect(0, 0, 0, 0)", whiteSpace: "nowrap", wordWrap: "normal" }), Xe = "VisuallyHidden", Q = n.forwardRef( (e, o) => /* @__PURE__ */ i( D.span, { ...e, ref: o, style: { ...Ue, ...e.style } } ) ); Q.displayName = Xe; var Z = "ToastProvider", [ee, Ye, $e] = _e("Toast"), [ce, St] = Ne("Toast", [$e]), [Be, Y] = ce(Z), ue = (e) => { const { __scopeToast: o, label: r = "Notification", duration: t = 5e3, swipeDirection: u = "right", swipeThreshold: d = 50, children: f } = e, [w, v] = n.useState(null), [c, E] = n.useState(0), T = n.useRef(!1), N = n.useRef(!1); return r.trim() || console.error( `Invalid prop \`label\` supplied to \`${Z}\`. Expected non-empty \`string\`.` ), /* @__PURE__ */ i(ee.Provider, { scope: o, children: /* @__PURE__ */ i( Be, { scope: o, label: r, duration: t, swipeDirection: u, swipeThreshold: d, toastCount: c, viewport: w, onViewportChange: v, onToastAdd: n.useCallback(() => E((R) => R + 1), []), onToastRemove: n.useCallback(() => E((R) => R - 1), []), isFocusedToastEscapeKeyDownRef: T, isClosePausedRef: N, children: f } ) }); }; ue.displayName = Z; var le = "ToastViewport", je = ["F8"], z = "toast.viewportPause", G = "toast.viewportResume", de = n.forwardRef( (e, o) => { const { __scopeToast: r, hotkey: t = je, label: u = "Notifications ({hotkey})", ...d } = e, f = Y(le, r), w = Ye(r), v = n.useRef(null), c = n.useRef(null), E = n.useRef(null), T = n.useRef(null), N = ie(o, T, f.onViewportChange), R = t.join("+").replace(/Key/g, "").replace(/Digit/g, ""), b = f.toastCount > 0; n.useEffect(() => { const s = (h) => { t.length !== 0 && t.every((m) => h[m] || h.code === m) && T.current?.focus(); }; return document.addEventListener("keydown", s), () => document.removeEventListener("keydown", s); }, [t]), n.useEffect(() => { const s = v.current, h = T.current; if (b && s && h) { const p = () => { if (!f.isClosePausedRef.current) { const y = new CustomEvent(z); h.dispatchEvent(y), f.isClosePausedRef.current = !0; } }, m = () => { if (f.isClosePausedRef.current) { const y = new CustomEvent(G); h.dispatchEvent(y), f.isClosePausedRef.current = !1; } }, P = (y) => { !s.contains(y.relatedTarget) && m(); }, C = () => { s.contains(document.activeElement) || m(); }; return s.addEventListener("focusin", p), s.addEventListener("focusout", P), s.addEventListener("pointermove", p), s.addEventListener("pointerleave", C), window.addEventListener("blur", p), window.addEventListener("focus", m), () => { s.removeEventListener("focusin", p), s.removeEventListener("focusout", P), s.removeEventListener("pointermove", p), s.removeEventListener("pointerleave", C), window.removeEventListener("blur", p), window.removeEventListener("focus", m); }; } }, [b, f.isClosePausedRef]); const l = n.useCallback( ({ tabbingDirection: s }) => { const p = w().map((m) => { const P = m.ref.current, C = [P, ...at(P)]; return s === "forwards" ? C : C.reverse(); }); return (s === "forwards" ? p.reverse() : p).flat(); }, [w] ); return n.useEffect(() => { const s = T.current; if (s) { const h = (p) => { const m = p.altKey || p.ctrlKey || p.metaKey; if (p.key === "Tab" && !m) { const C = document.activeElement, y = p.shiftKey; if (p.target === s && y) { c.current?.focus(); return; } const F = l({ tabbingDirection: y ? "backwards" : "forwards" }), V = F.findIndex((I) => I === C); q(F.slice(V + 1)) ? p.preventDefault() : y ? c.current?.focus() : E.current?.focus(); } }; return s.addEventListener("keydown", h), () => s.removeEventListener("keydown", h); } }, [w, l]), /* @__PURE__ */ A( Fe, { ref: v, role: "region", "aria-label": u.replace("{hotkey}", R), tabIndex: -1, style: { pointerEvents: b ? void 0 : "none" }, children: [ b && /* @__PURE__ */ i( J, { ref: c, onFocusFromOutsideViewport: () => { const s = l({ tabbingDirection: "forwards" }); q(s); } } ), /* @__PURE__ */ i(ee.Slot, { scope: r, children: /* @__PURE__ */ i(D.ol, { tabIndex: -1, ...d, ref: N }) }), b && /* @__PURE__ */ i( J, { ref: E, onFocusFromOutsideViewport: () => { const s = l({ tabbingDirection: "backwards" }); q(s); } } ) ] } ); } ); de.displayName = le; var fe = "ToastFocusProxy", J = n.forwardRef( (e, o) => { const { __scopeToast: r, onFocusFromOutsideViewport: t, ...u } = e, d = Y(fe, r); return /* @__PURE__ */ i( Q, { tabIndex: 0, ...u, ref: o, style: { position: "fixed" }, onFocus: (f) => { const w = f.relatedTarget; !d.viewport?.contains(w) && t(); } } ); } ); J.displayName = fe; var O = "Toast", qe = "toast.swipeStart", ze = "toast.swipeMove", Ge = "toast.swipeCancel", Je = "toast.swipeEnd", pe = n.forwardRef( (e, o) => { const { forceMount: r, open: t, defaultOpen: u, onOpenChange: d, ...f } = e, [w, v] = Ie({ prop: t, defaultProp: u ?? !0, onChange: d, caller: O }); return /* @__PURE__ */ i(Oe, { present: r || w, children: /* @__PURE__ */ i( et, { open: w, ...f, ref: o, onClose: () => v(!1), onPause: X(e.onPause), onResume: X(e.onResume), onSwipeStart: x(e.onSwipeStart, (c) => { c.currentTarget.setAttribute("data-swipe", "start"); }), onSwipeMove: x(e.onSwipeMove, (c) => { const { x: E, y: T } = c.detail.delta; c.currentTarget.setAttribute("data-swipe", "move"), c.currentTarget.style.setProperty("--radix-toast-swipe-move-x", `${E}px`), c.currentTarget.style.setProperty("--radix-toast-swipe-move-y", `${T}px`); }), onSwipeCancel: x(e.onSwipeCancel, (c) => { c.currentTarget.setAttribute("data-swipe", "cancel"), c.currentTarget.style.removeProperty("--radix-toast-swipe-move-x"), c.currentTarget.style.removeProperty("--radix-toast-swipe-move-y"), c.currentTarget.style.removeProperty("--radix-toast-swipe-end-x"), c.currentTarget.style.removeProperty("--radix-toast-swipe-end-y"); }), onSwipeEnd: x(e.onSwipeEnd, (c) => { const { x: E, y: T } = c.detail.delta; c.currentTarget.setAttribute("data-swipe", "end"), c.currentTarget.style.removeProperty("--radix-toast-swipe-move-x"), c.currentTarget.style.removeProperty("--radix-toast-swipe-move-y"), c.currentTarget.style.setProperty("--radix-toast-swipe-end-x", `${E}px`), c.currentTarget.style.setProperty("--radix-toast-swipe-end-y", `${T}px`), v(!1); }) } ) }); } ); pe.displayName = O; var [Qe, Ze] = ce(O, { onClose() { } }), et = n.forwardRef( (e, o) => { const { __scopeToast: r, type: t = "foreground", duration: u, open: d, onClose: f, onEscapeKeyDown: w, onPause: v, onResume: c, onSwipeStart: E, onSwipeMove: T, onSwipeCancel: N, onSwipeEnd: R, ...b } = e, l = Y(O, r), [s, h] = n.useState(null), p = ie(o, (a) => h(a)), m = n.useRef(null), P = n.useRef(null), C = u || l.duration, y = n.useRef(0), _ = n.useRef(C), k = n.useRef(0), { onToastAdd: F, onToastRemove: V } = l, I = X(() => { s?.contains(document.activeElement) && l.viewport?.focus(), f(); }), K = n.useCallback( (a) => { !a || a === 1 / 0 || (window.clearTimeout(k.current), y.current = (/* @__PURE__ */ new Date()).getTime(), k.current = window.setTimeout(I, a)); }, [I] ); n.useEffect(() => { const a = l.viewport; if (a) { const g = () => { K(_.current), c?.(); }, S = () => { const L = (/* @__PURE__ */ new Date()).getTime() - y.current; _.current = _.current - L, window.clearTimeout(k.current), v?.(); }; return a.addEventListener(z, S), a.addEventListener(G, g), () => { a.removeEventListener(z, S), a.removeEventListener(G, g); }; } }, [l.viewport, C, v, c, K]), n.useEffect(() => { d && !l.isClosePausedRef.current && K(C); }, [d, C, l.isClosePausedRef, K]), n.useEffect(() => (F(), () => V()), [F, V]); const te = n.useMemo(() => s ? Pe(s) : null, [s]); return l.viewport ? /* @__PURE__ */ A(ae, { children: [ te && /* @__PURE__ */ i( tt, { __scopeToast: r, role: "status", "aria-live": t === "foreground" ? "assertive" : "polite", children: te } ), /* @__PURE__ */ i(Qe, { scope: r, onClose: I, children: Se.createPortal( /* @__PURE__ */ i(ee.ItemSlot, { scope: r, children: /* @__PURE__ */ i( Le, { asChild: !0, onEscapeKeyDown: x(w, () => { l.isFocusedToastEscapeKeyDownRef.current || I(), l.isFocusedToastEscapeKeyDownRef.current = !1; }), children: /* @__PURE__ */ i( D.li, { tabIndex: 0, "data-state": d ? "open" : "closed", "data-swipe-direction": l.swipeDirection, ...b, ref: p, style: { userSelect: "none", touchAction: "none", ...e.style }, onKeyDown: x(e.onKeyDown, (a) => { a.key === "Escape" && (w?.(a.nativeEvent), a.nativeEvent.defaultPrevented || (l.isFocusedToastEscapeKeyDownRef.current = !0, I())); }), onPointerDown: x(e.onPointerDown, (a) => { a.button === 0 && (m.current = { x: a.clientX, y: a.clientY }); }), onPointerMove: x(e.onPointerMove, (a) => { if (!m.current) return; const g = a.clientX - m.current.x, S = a.clientY - m.current.y, L = !!P.current, M = ["left", "right"].includes(l.swipeDirection), H = ["left", "up"].includes(l.swipeDirection) ? Math.min : Math.max, Ce = M ? H(0, g) : 0, Re = M ? 0 : H(0, S), $ = a.pointerType === "touch" ? 10 : 2, W = { x: Ce, y: Re }, oe = { originalEvent: a, delta: W }; L ? (P.current = W, U(ze, T, oe, { discrete: !1 })) : se(W, l.swipeDirection, $) ? (P.current = W, U(qe, E, oe, { discrete: !1 }), a.target.setPointerCapture(a.pointerId)) : (Math.abs(g) > $ || Math.abs(S) > $) && (m.current = null); }), onPointerUp: x(e.onPointerUp, (a) => { const g = P.current, S = a.target; if (S.hasPointerCapture(a.pointerId) && S.releasePointerCapture(a.pointerId), P.current = null, m.current = null, g) { const L = a.currentTarget, M = { originalEvent: a, delta: g }; se(g, l.swipeDirection, l.swipeThreshold) ? U(Je, R, M, { discrete: !0 }) : U( Ge, N, M, { discrete: !0 } ), L.addEventListener("click", (H) => H.preventDefault(), { once: !0 }); } }) } ) } ) }), l.viewport ) }) ] }) : null; } ), tt = (e) => { const { __scopeToast: o, children: r, ...t } = e, u = Y(O, o), [d, f] = n.useState(!1), [w, v] = n.useState(!1); return nt(() => f(!0)), n.useEffect(() => { const c = window.setTimeout(() => v(!0), 1e3); return () => window.clearTimeout(c); }, []), w ? null : /* @__PURE__ */ i(Me, { asChild: !0, children: /* @__PURE__ */ i(Q, { ...t, children: d && /* @__PURE__ */ A(ae, { children: [ u.label, " ", r ] }) }) }); }, ot = "ToastTitle", me = n.forwardRef( (e, o) => { const { __scopeToast: r, ...t } = e; return /* @__PURE__ */ i(D.div, { ...t, ref: o }); } ); me.displayName = ot; var rt = "ToastDescription", we = n.forwardRef( (e, o) => { const { __scopeToast: r, ...t } = e; return /* @__PURE__ */ i(D.div, { ...t, ref: o }); } ); we.displayName = rt; var Te = "ToastAction", ve = n.forwardRef( (e, o) => { const { altText: r, ...t } = e; return r.trim() ? /* @__PURE__ */ i(he, { altText: r, asChild: !0, children: /* @__PURE__ */ i(ye, { ...t, ref: o }) }) : (console.error( `Invalid prop \`altText\` supplied to \`${Te}\`. Expected non-empty \`string\`.` ), null); } ); ve.displayName = Te; var Ee = "ToastClose", ye = n.forwardRef( (e, o) => { const { __scopeToast: r, ...t } = e, u = Ze(Ee, r); return /* @__PURE__ */ i(he, { asChild: !0, children: /* @__PURE__ */ i( D.button, { type: "button", ...t, ref: o, onClick: x(e.onClick, u.onClose) } ) }); } ); ye.displayName = Ee; var he = n.forwardRef((e, o) => { const { __scopeToast: r, altText: t, ...u } = e; return /* @__PURE__ */ i( D.div, { "data-radix-toast-announce-exclude": "", "data-radix-toast-announce-alt": t || void 0, ...u, ref: o } ); }); function Pe(e) { const o = []; return Array.from(e.childNodes).forEach((t) => { if (t.nodeType === t.TEXT_NODE && t.textContent && o.push(t.textContent), st(t)) { const u = t.ariaHidden || t.hidden || t.style.display === "none", d = t.dataset.radixToastAnnounceExclude === ""; if (!u) if (d) { const f = t.dataset.radixToastAnnounceAlt; f && o.push(f); } else o.push(...Pe(t)); } }), o; } function U(e, o, r, { discrete: t }) { const u = r.originalEvent.currentTarget, d = new CustomEvent(e, { bubbles: !0, cancelable: !0, detail: r }); o && u.addEventListener(e, o, { once: !0 }), t ? Ae(u, d) : u.dispatchEvent(d); } var se = (e, o, r = 0) => { const t = Math.abs(e.x), u = Math.abs(e.y), d = t > u; return o === "left" || o === "right" ? d && t > r : !d && u > r; }; function nt(e = () => { }) { const o = X(e); De(() => { let r = 0, t = 0; return r = window.requestAnimationFrame(() => t = window.requestAnimationFrame(o)), () => { window.cancelAnimationFrame(r), window.cancelAnimationFrame(t); }; }, [o]); } function st(e) { return e.nodeType === e.ELEMENT_NODE; } function at(e) { const o = [], r = document.createTreeWalker(e, NodeFilter.SHOW_ELEMENT, { acceptNode: (t) => { const u = t.tagName === "INPUT" && t.type === "hidden"; return t.disabled || t.hidden || u ? NodeFilter.FILTER_SKIP : t.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; } }); for (; r.nextNode(); ) o.push(r.currentNode); return o; } function q(e) { const o = document.activeElement; return e.some((r) => r === o ? !0 : (r.focus(), document.activeElement !== o)); } var it = ue, ct = de, ut = pe, lt = me, dt = we, ft = ve; const Nt = ({ title: e, duration: o = 5e3, titleClassName: r, descriptionClassName: t, description: u, children: d, theme: f, showCloseButton: w = !0, closeButtonClassName: v, className: c, open: E = !1, setOpen: T, variant: N }) => { const R = xe(0); be(() => () => clearTimeout(R.current), []); const b = re(() => ne(e) ? /* @__PURE__ */ i(B, { className: r, children: e }) : e, [e, r]), l = re(() => ne(u) ? /* @__PURE__ */ i(B, { className: t, children: u }) : u, [u, t]), s = ge(() => { T(!1), R.current = window.setTimeout(() => T(!0), 100); }, [T]); return /* @__PURE__ */ A(it, { swipeDirection: "right", duration: o, children: [ /* @__PURE__ */ i(B, { onClick: s, children: d }), /* @__PURE__ */ A( ut, { className: j(Ke({ variant: N, className: c })), "data-theme": f, open: E, onOpenChange: T, children: [ /* @__PURE__ */ A("div", { className: "flex gap-2 items-center flex-1", children: [ /* @__PURE__ */ i(lt, { asChild: !0, className: r, children: b }), l && /* @__PURE__ */ i(dt, { asChild: !0, children: l }) ] }), w && /* @__PURE__ */ i(ft, { asChild: !0, altText: "Close the toast", children: /* @__PURE__ */ A("button", { type: "button", className: "absolute right-1.5 top-1.5", children: [ /* @__PURE__ */ i( We, { className: j( Ve({ className: v }) ) } ), /* @__PURE__ */ i(ke, { children: "Close toast" }) ] }) }) ] } ), /* @__PURE__ */ i(ct, { className: j(He()) }) ] }); }; export { Nt as Toast };