UNPKG

@arolariu/components

Version:

🎨 70+ beautiful, accessible React components built on Base UI. TypeScript-first, CSS Modules styling, tree-shakeable, SSR-ready. Perfect for modern web apps, design systems & rapid prototyping. Zero config, maximum flexibility! ⚡

457 lines (456 loc) • 18.5 kB
"use client"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { Toast } from "@base-ui/react/toast"; import { AlertCircle, BellRing, CheckCircle2, Info, LoaderCircle, TriangleAlert, X } from "lucide-react"; import { cn } from "../../lib/utilities.js"; import toast_module from "./toast.module.js"; import * as __rspack_external_react from "react"; const DEFAULT_TOAST_DURATION = 5000; const DEFAULT_TOAST_LIMIT = 3; const DEFAULT_TOAST_CLOSE_LABEL = "Close notification"; const DEFAULT_VIEWPORT_ARIA_LABEL = "Notifications"; const positionStyles = { "bottom-center": toast_module.viewportBottomCenter, "bottom-left": toast_module.viewportBottomLeft, "bottom-right": toast_module.viewportBottomRight, "top-center": toast_module.viewportTopCenter, "top-left": toast_module.viewportTopLeft, "top-right": toast_module.viewportTopRight }; const variantStyles = { default: toast_module["default"], error: toast_module.error, info: toast_module.info, loading: toast_module.loading, success: toast_module.success, warning: toast_module.warning }; const toastManager = Toast.createToastManager(); const toastHistory = []; const activeToasts = new Map(); const toastRecords = new Map(); const toasterRegistrations = new Map(); let toastSequence = 0; function createToastIdentifier(identifier) { if (void 0 !== identifier) return String(identifier); if ("function" == typeof globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID(); toastSequence += 1; return `toast-${String(toastSequence)}`; } function isRenderableFactory(value) { return "function" == typeof value; } function resolveRenderable(value) { const resolvedValue = isRenderableFactory(value) ? value() : value; return resolvedValue; } function getSnapshot(id, variant, title, description) { return { description, id, title, variant }; } function registerToast(snapshot) { activeToasts.set(snapshot.id, snapshot); toastHistory.push(snapshot); } function registerToastRecord(record) { toastRecords.set(record.snapshot.id, record); registerToast(record.snapshot); } function replaceToastHistorySnapshot(snapshot) { for(let index = toastHistory.length - 1; index >= 0; index -= 1)if (toastHistory[index]?.id === snapshot.id) { toastHistory[index] = snapshot; return; } toastHistory.push(snapshot); } function replaceToastRecord(record) { toastRecords.set(record.snapshot.id, record); activeToasts.set(record.snapshot.id, record.snapshot); replaceToastHistorySnapshot(record.snapshot); } function unregisterToast(toastId) { if (!toastId) { activeToasts.clear(); toastRecords.clear(); return; } activeToasts.delete(toastId); toastRecords.delete(toastId); } function getActiveToasterRegistration() { const registrations = [ ...toasterRegistrations.values() ]; return registrations.at(-1) ?? { closeButton: true, toastOptions: {} }; } function mergeToastOptions(options) { return { ...getActiveToasterRegistration().toastOptions, ...options }; } function isToastVariant(value) { return "default" === value || "error" === value || "info" === value || "loading" === value || "success" === value || "warning" === value; } function createToastMetadata(variant, options, closeButton, customContent) { return { action: options.action, cancel: options.cancel, className: options.className, closeButton, closeButtonAriaLabel: options.closeButtonAriaLabel ?? DEFAULT_TOAST_CLOSE_LABEL, customContent, descriptionClassName: options.descriptionClassName, style: options.style, variant }; } function createToastRecord({ id, message, options, variant, customContent }) { const activeRegistration = getActiveToasterRegistration(); const closeButton = options.closeButton ?? activeRegistration.closeButton; const title = void 0 === message ? void 0 : resolveRenderable(message); const description = resolveRenderable(options.description); const snapshot = getSnapshot(id, variant, title, description); return { metadata: createToastMetadata(variant, options, closeButton, customContent), options, snapshot }; } function createToastLifecycleHandlers(toastId, record) { return { onClose: ()=>{ record.options.onDismiss?.(activeToasts.get(toastId) ?? record.snapshot); }, onRemove: ()=>{ const snapshot = activeToasts.get(toastId) ?? record.snapshot; unregisterToast(toastId); record.options.onAutoClose?.(snapshot); } }; } function createToastAddPayload(record) { const lifecycleHandlers = createToastLifecycleHandlers(record.snapshot.id, record); return { description: record.snapshot.description, id: record.snapshot.id, priority: record.options.priority, timeout: record.options.duration, title: record.snapshot.title, type: record.snapshot.variant, data: record.metadata, ...lifecycleHandlers }; } function buildToastOptions(message, variant, options) { const mergedOptions = mergeToastOptions(options); const toastId = createToastIdentifier(mergedOptions.id); const record = createToastRecord({ id: toastId, message, options: mergedOptions, variant }); registerToastRecord(record); return createToastAddPayload(record); } function showToast(message, variant, options) { const payload = buildToastOptions(message, variant, options); return toastManager.add(payload); } function dismissToast(toastId) { if (void 0 === toastId) { unregisterToast(); toastManager.close(); return; } const normalizedToastId = String(toastId); unregisterToast(normalizedToastId); toastManager.close(normalizedToastId); return normalizedToastId; } function updateToast(toastId, options) { const normalizedToastId = String(toastId); const existingRecord = toastRecords.get(normalizedToastId); const mergedOptions = { ...existingRecord?.options, ...options }; const variant = options.variant ?? existingRecord?.snapshot.variant ?? "default"; const nextMessage = void 0 === options.message ? existingRecord?.snapshot.title : resolveRenderable(options.message); const nextDescription = void 0 === options.description ? existingRecord?.snapshot.description : resolveRenderable(options.description); const metadata = createToastMetadata(variant, mergedOptions, mergedOptions.closeButton ?? existingRecord?.metadata.closeButton ?? getActiveToasterRegistration().closeButton, existingRecord?.metadata.customContent); const record = { metadata, options: mergedOptions, snapshot: getSnapshot(normalizedToastId, variant, nextMessage, nextDescription) }; replaceToastRecord(record); const payload = { description: record.snapshot.description, priority: record.options.priority, timeout: record.options.duration, title: record.snapshot.title, type: record.snapshot.variant, data: record.metadata, ...createToastLifecycleHandlers(normalizedToastId, record) }; toastManager.update(normalizedToastId, payload); return normalizedToastId; } function resolvePromiseState(state, value) { if ("function" == typeof state) return Promise.resolve(state(value)); return Promise.resolve(state); } function isPromiseResolvedOptions(value) { return "object" == typeof value && null !== value && "message" in value; } function isToastAction(value) { if (/*#__PURE__*/ __rspack_external_react.isValidElement(value)) return false; return "object" == typeof value && null !== value && "label" in value && "onClick" in value; } function getVariantIcon(variant) { const icons = { default: /*#__PURE__*/ jsx(BellRing, { "aria-hidden": "true", className: toast_module.icon }), error: /*#__PURE__*/ jsx(AlertCircle, { "aria-hidden": "true", className: toast_module.icon }), info: /*#__PURE__*/ jsx(Info, { "aria-hidden": "true", className: toast_module.icon }), loading: /*#__PURE__*/ jsx(LoaderCircle, { "aria-hidden": "true", className: cn(toast_module.icon, toast_module.iconSpin) }), success: /*#__PURE__*/ jsx(CheckCircle2, { "aria-hidden": "true", className: toast_module.icon }), warning: /*#__PURE__*/ jsx(TriangleAlert, { "aria-hidden": "true", className: toast_module.icon }) }; return icons[variant]; } function ToastActions({ toastId, action, cancel }) { if (!action && !cancel) return null; const renderAction = (value, className)=>{ if (!value) return null; if (/*#__PURE__*/ __rspack_external_react.isValidElement(value)) return value; if (isToastAction(value)) return /*#__PURE__*/ jsx("button", { className: className, type: "button", onClick: (event)=>{ value.onClick(event); dismissToast(toastId); }, children: value.label }); return null; }; return /*#__PURE__*/ jsxs("div", { className: toast_module.actions, children: [ renderAction(cancel, toast_module.secondaryAction), renderAction(action, toast_module.primaryAction) ] }); } function ToastViewportContent() { const { toasts } = Toast.useToastManager(); return /*#__PURE__*/ jsx(Fragment, { children: toasts.map((toastItem)=>{ const variant = isToastVariant(toastItem.type) ? toastItem.type : "default"; const action = toastItem.data?.action; const cancel = toastItem.data?.cancel; return /*#__PURE__*/ jsx(Toast.Root, { toast: toastItem, className: cn(toast_module.root, variantStyles[variant], toastItem.data?.className), "data-variant": variant, style: toastItem.data?.style, children: /*#__PURE__*/ jsx(Toast.Content, { className: toast_module.content, children: toastItem.data?.customContent ?? /*#__PURE__*/ jsxs(Fragment, { children: [ /*#__PURE__*/ jsx("div", { className: toast_module.leading, children: getVariantIcon(variant) }), /*#__PURE__*/ jsxs("div", { className: toast_module.body, children: [ toastItem.title ? /*#__PURE__*/ jsx(Toast.Title, { className: toast_module.title, children: toastItem.title }) : null, toastItem.description ? /*#__PURE__*/ jsx(Toast.Description, { className: cn(toast_module.description, toastItem.data?.descriptionClassName), children: toastItem.description }) : null, /*#__PURE__*/ jsx(ToastActions, { action: action, cancel: cancel, toastId: toastItem.id }) ] }), toastItem.data?.closeButton ? /*#__PURE__*/ jsx(Toast.Close, { "aria-label": toastItem.data.closeButtonAriaLabel, className: toast_module.close, children: /*#__PURE__*/ jsx(X, { "aria-hidden": "true", className: toast_module.closeIcon }) }) : null ] }) }) }, toastItem.id); }) }); } const Toaster = /*#__PURE__*/ __rspack_external_react.forwardRef(({ className, closeButton = true, containerAriaLabel = DEFAULT_VIEWPORT_ARIA_LABEL, duration = DEFAULT_TOAST_DURATION, position = "bottom-right", style, toastOptions, visibleToasts = DEFAULT_TOAST_LIMIT }, forwardedRef)=>{ const toasterId = __rspack_external_react.useId(); __rspack_external_react.useEffect(()=>{ toasterRegistrations.set(toasterId, { closeButton, toastOptions: toastOptions ?? {} }); return ()=>{ toasterRegistrations.delete(toasterId); }; }, [ closeButton, toastOptions, toasterId ]); return /*#__PURE__*/ jsx(Toast.Provider, { limit: visibleToasts, timeout: duration, toastManager: toastManager, children: /*#__PURE__*/ jsx(Toast.Portal, { children: /*#__PURE__*/ jsx(Toast.Viewport, { ref: forwardedRef, "aria-label": containerAriaLabel, className: cn(toast_module.viewport, positionStyles[position], className), style: style, children: /*#__PURE__*/ jsx(ToastViewportContent, {}) }) }) }); }); Toaster.displayName = "Toaster"; const toast = (message, options)=>showToast(message, "default", options); toast.success = (message, options)=>showToast(message, "success", options); toast.error = (message, options)=>showToast(message, "error", options); toast.info = (message, options)=>showToast(message, "info", options); toast.warning = (message, options)=>showToast(message, "warning", options); toast.loading = (message, options)=>showToast(message, "loading", options); toast.message = (message, options)=>showToast(message, "default", options); toast.update = (toastId, options)=>updateToast(toastId, options); toast.dismiss = (toastId)=>dismissToast(toastId); toast.custom = (renderer, options)=>{ const mergedOptions = mergeToastOptions(options); const toastId = createToastIdentifier(mergedOptions.id); const record = createToastRecord({ customContent: renderer(toastId), id: toastId, options: mergedOptions, variant: "default" }); registerToastRecord(record); toastManager.add(createToastAddPayload(record)); return toastId; }; function mergePromiseToastOptions(baseOptions, override) { if (!override) return baseOptions; return { action: override.action ?? baseOptions.action, cancel: override.cancel ?? baseOptions.cancel, className: override.className ?? baseOptions.className, closeButton: override.closeButton ?? baseOptions.closeButton, closeButtonAriaLabel: override.closeButtonAriaLabel ?? baseOptions.closeButtonAriaLabel, description: override.description ?? baseOptions.description, descriptionClassName: override.descriptionClassName ?? baseOptions.descriptionClassName, duration: override.duration ?? baseOptions.duration, id: override.id ?? baseOptions.id, onAutoClose: override.onAutoClose ?? baseOptions.onAutoClose, onDismiss: override.onDismiss ?? baseOptions.onDismiss, priority: override.priority ?? baseOptions.priority, style: override.style ?? baseOptions.style }; } function getPromiseBaseOptions(options) { return { action: options?.action, cancel: options?.cancel, className: options?.className, closeButton: options?.closeButton, closeButtonAriaLabel: options?.closeButtonAriaLabel, description: options?.description, descriptionClassName: options?.descriptionClassName, duration: options?.duration, id: options?.id, onAutoClose: options?.onAutoClose, onDismiss: options?.onDismiss, priority: options?.priority, style: options?.style }; } function showResolvedPromiseToast(loadingToastId, variant, resolvedState, baseOptions) { if (!resolvedState) { if (loadingToastId) dismissToast(loadingToastId); return; } const overrideOptions = isPromiseResolvedOptions(resolvedState) ? resolvedState : void 0; const message = isPromiseResolvedOptions(resolvedState) ? resolvedState.message : resolvedState; const mergedOptions = mergePromiseToastOptions(baseOptions, overrideOptions); if (loadingToastId) return void toast.update(loadingToastId, { ...mergedOptions, message, variant }); showToast(message, variant, mergedOptions); } toast.promise = async function(promiseValue, options) { const pendingPromise = "function" == typeof promiseValue ? promiseValue() : promiseValue; const baseOptions = getPromiseBaseOptions(options); const loadingState = options?.loading; const loadingOptions = isPromiseResolvedOptions(loadingState) ? loadingState : void 0; const loadingMessage = isPromiseResolvedOptions(loadingState) ? loadingState.message : loadingState; const loadingToastId = loadingMessage ? toast.loading(loadingMessage, mergePromiseToastOptions(baseOptions, loadingOptions)) : void 0; try { const result = await pendingPromise; const successState = await resolvePromiseState(options?.success, result); showResolvedPromiseToast(loadingToastId, "success", successState, baseOptions); return result; } catch (error) { const errorState = await resolvePromiseState(options?.error, error); showResolvedPromiseToast(loadingToastId, "error", errorState, baseOptions); throw error; } finally{ const handleFinally = options?.finally; if (handleFinally) await handleFinally(); } }; toast.getToasts = ()=>[ ...activeToasts.values() ]; toast.getHistory = ()=>[ ...toastHistory ]; export { Toaster, toast }; //# sourceMappingURL=toast.js.map