Sign In

scrollsheet

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scrollsheet - npm Package Compare versions

Comparing version
1.0.0-beta.1
to
1.0.0-beta.2
dist/auto/drawer-HVSMFDtk.mjs

Sorry, the diff of this file is too big to display

+947
"use client";
import { c as prefersReducedMotion, h as warnOnce, n as useCloseWatcher, r as createStyleInjector, t as cn } from "./cn-CActSFFr.mjs";
import * as React from "react";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { createPortal } from "react-dom";
//#region packages/scrollsheet/src/toast/state.ts
let toasts = [];
const listeners = new Set();
let uid = 0;
const MAX_HISTORY_SIZE = 100;
let history = [];
function trimHistory() {
let toRemove = history.length - MAX_HISTORY_SIZE;
if (toRemove <= 0) return;
const liveIds = new Set(toasts.map((t) => t.id));
history = history.filter((record) => {
if (toRemove > 0 && !liveIds.has(record.id)) {
toRemove -= 1;
return false;
}
return true;
});
}
function recordHistory(record) {
const index = history.findIndex((t) => t.id === record.id);
if (index === -1) {
history = [...history, record];
trimHistory();
return;
}
history = history.map((t, i) => i === index ? record : t);
}
function nextId() {
uid += 1;
return uid;
}
function publish() {
for (const listener of listeners) listener();
}
function subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
function getSnapshot() {
return toasts;
}
const EMPTY_TOASTS = [];
function getServerSnapshot() {
return EMPTY_TOASTS;
}
function upsert(id, patch, fallbackType) {
const resolvedId = id ?? nextId();
const index = toasts.findIndex((t) => t.id === resolvedId);
const type = patch.type ?? fallbackType;
let record;
if (index === -1) {
record = {
dismissible: true,
...patch,
id: resolvedId,
type,
createdAt: Date.now()
};
toasts = [...toasts, record];
} else {
record = {
...toasts[index],
...patch,
id: resolvedId,
type
};
toasts = toasts.map((t, i) => i === index ? record : t);
}
recordHistory(record);
publish();
return resolvedId;
}
function dismiss(id) {
if (id === void 0) {
const swept = new Set(toasts);
for (const t of swept) {
if (!toasts.includes(t)) continue;
t.onDismiss?.(t);
}
toasts = toasts.filter((t) => !swept.has(t));
publish();
return;
}
const existing = toasts.find((t) => t.id === id);
if (!existing) return id;
existing.onDismiss?.(existing);
toasts = toasts.filter((t) => t !== existing);
publish();
return id;
}
function expire(id) {
const existing = toasts.find((t) => t.id === id);
if (!existing) return;
existing.onAutoClose?.(existing);
toasts = toasts.filter((t) => t !== existing);
publish();
}
function baseToast(message, data) {
return upsert(data?.id, {
...data,
title: message
}, "default");
}
function withType(type) {
return (message, data) => upsert(data?.id, {
...data,
title: message
}, type);
}
const toastImpl = baseToast;
toastImpl.success = withType("success");
toastImpl.error = withType("error");
toastImpl.info = withType("info");
toastImpl.warning = withType("warning");
toastImpl.loading = withType("loading");
toastImpl.message = withType("default");
toastImpl.custom = (jsx, data) => {
const id = data?.id ?? nextId();
return upsert(id, {
...data,
jsx: jsx(id)
}, "default");
};
function isHttpResponse(value) {
return typeof value === "object" && value !== null && "ok" in value && typeof value.ok === "boolean" && "status" in value && typeof value.status === "number";
}
function isPromiseExtendedResult(value) {
return typeof value === "object" && value !== null && !React.isValidElement(value);
}
function applyPromiseSettlement(id, resolved, fallbackTitle, description, type) {
if (isPromiseExtendedResult(resolved)) {
const { message, ...rest } = resolved;
upsert(id, {
description,
...rest,
title: message ?? fallbackTitle,
type
}, type);
return;
}
upsert(id, {
title: resolved ?? fallbackTitle,
description,
type
}, type);
}
function promiseImpl(promiseOrFn, data) {
const { loading, success, error, finally: onFinally, description, ...rest } = data;
const id = upsert(data.id, {
...rest,
description: typeof description === "function" ? void 0 : description,
title: loading,
type: "loading"
}, "loading");
const settle = typeof promiseOrFn === "function" ? promiseOrFn() : promiseOrFn;
let settled;
const chain = settle.then(async (result) => {
if (isHttpResponse(result) && !result.ok) {
settled = {
ok: false,
reason: result
};
const statusMessage = `HTTP error! status: ${result.status}`;
const resolvedDescription = typeof description === "function" ? await description(statusMessage) : description;
const resolved = typeof error === "function" ? await error(statusMessage) : error;
applyPromiseSettlement(id, resolved, "Error", resolvedDescription, "error");
return;
}
if (result instanceof Error) {
settled = {
ok: false,
reason: result
};
const resolvedDescription = typeof description === "function" ? await description(result) : description;
const resolved = typeof error === "function" ? await error(result) : error;
applyPromiseSettlement(id, resolved, "Error", resolvedDescription, "error");
return;
}
settled = {
ok: true,
value: result
};
const resolvedDescription = typeof description === "function" ? await description(result) : description;
const resolved = typeof success === "function" ? await success(result) : success;
applyPromiseSettlement(id, resolved, "Success", resolvedDescription, "success");
}).catch(async (err) => {
settled = {
ok: false,
reason: err
};
const resolvedDescription = typeof description === "function" ? await description(err) : description;
const resolved = typeof error === "function" ? await error(err) : error;
applyPromiseSettlement(id, resolved, "Error", resolvedDescription, "error");
}).finally(() => onFinally?.());
const unwrap = () => chain.then(() => {
if (!settled) throw new Error("scrollsheet toast.promise: chain settled with no outcome");
if (settled.ok) return settled.value;
throw settled.reason;
});
return Object.assign(id, { unwrap });
}
toastImpl.promise = promiseImpl;
toastImpl.dismiss = dismiss;
toastImpl.getToasts = () => toasts;
toastImpl.getHistory = () => history;
const toast = toastImpl;
function useSonner() {
return { toasts: React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) };
}
const useToasts = useSonner;
function selectToasterToasts(all, toasterId) {
return all.filter((t) => toasterId === void 0 ? t.toasterId === void 0 : t.toasterId === toasterId);
}
function selectPositionToasts(all, position, defaultPosition) {
return all.filter((t) => t.position === void 0 ? position === defaultPosition : t.position === position);
}
function selectToastWindow(toasts, visibleToasts) {
const newestFirst = [...toasts].reverse();
return {
visible: newestFirst.slice(0, visibleToasts),
hidden: newestFirst.slice(visibleToasts)
};
}
//#endregion
//#region packages/scrollsheet/src/toast/toast-styles.ts
const { injectDocument, injectShadowRoot } = createStyleInjector(`.scrollsheet-toast{border-radius:var(--scrollsheet-toast-radius,14px);color:#18181b;background:#fff;border:1px solid #00000014;align-items:flex-start;gap:10px;padding:16px;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;font-size:13px;display:flex;position:relative;box-shadow:0 4px 12px #0000001a}.scrollsheet-toast[data-scrollsheet-custom]{box-shadow:none;background:0 0;border:none;padding:0}.scrollsheet-toast-icon{color:#fff;background:#6b7280;border-radius:50%;flex:none;place-items:center;width:18px;height:18px;margin-top:1px;font-size:11px;line-height:1;display:grid}.scrollsheet-toast-icon[data-type=success]{background:#22c55e}.scrollsheet-toast-icon[data-type=error]{background:#ef4444}.scrollsheet-toast-icon[data-type=warning]{background:#f59e0b}.scrollsheet-toast-icon[data-type=info]{background:#3b82f6}.scrollsheet-toast-icon[data-type=loading]{background:0 0}.scrollsheet-toast-spinner{border:2px solid #00000026;border-top-color:#0000008c;border-radius:50%;width:14px;height:14px;animation:.6s linear infinite scrollsheet-toast-spin}@keyframes scrollsheet-toast-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.scrollsheet-toast-spinner{animation-duration:1.6s}}.scrollsheet-toast-body{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.scrollsheet-toast-title{font-size:13px;font-weight:500;line-height:1.35}.scrollsheet-toast-description{color:#0009;font-size:13px;line-height:1.4}.scrollsheet-toast-actions{flex:none;align-items:center;gap:6px;display:flex}.scrollsheet-toast-action,.scrollsheet-toast-cancel{cursor:pointer;border:none;border-radius:4px;height:24px;padding:0 8px;font-size:12px;font-weight:500}.scrollsheet-toast-action{color:#fff;background:#18181b}.scrollsheet-toast-cancel{color:#18181b;background:#0000000f}.scrollsheet-toast-close{color:#00000080;cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;place-items:center;width:20px;height:20px;padding:0;font-size:14px;line-height:1;display:grid}.scrollsheet-toast-close:hover{background:#0000000f}[data-scrollsheet-toaster]{z-index:2147483647;width:min(356px, calc(100vw - 2 * var(--scrollsheet-toast-offset,var(--sonner-offset,24px))));outline:none;margin:0;padding:0;list-style:none;transition:transform .4s;position:fixed}[data-scrollsheet-toaster][data-x-position=right]{right:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=center]{left:50%;transform:translate(-50%)}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}.scrollsheet-toast{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);opacity:0;transform:var(--scrollsheet-toast-y);touch-action:none;box-sizing:border-box;overflow-wrap:anywhere;transition:transform .25s,opacity .25s,height .25s;position:absolute;left:0;right:0}.scrollsheet-toast[data-y-position=top]{--scrollsheet-toast-lift:1;--scrollsheet-toast-y:translateY(-100%);top:0}.scrollsheet-toast[data-y-position=bottom]{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);bottom:0}.scrollsheet-toast[data-mounted]{--scrollsheet-toast-y:translateY(0);opacity:1}.scrollsheet-toast[data-expanded=false][data-front=false]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-gap,var(--sonner-gap,14px)) * var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)))) scale(calc(1 - var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)) * .05));height:var(--scrollsheet-toast-front-height,var(--sonner-front-height,auto));overflow:hidden}.scrollsheet-toast[data-expanded=false][data-front=false]>*{opacity:0}.scrollsheet-toast[data-mounted][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px))));height:var(--scrollsheet-toast-initial-height,var(--sonner-initial-height,auto))}.scrollsheet-toast[data-visible=false]{opacity:0;pointer-events:none}.scrollsheet-toast[data-removed]{pointer-events:none}.scrollsheet-toast[data-removed][data-front=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px)) + var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=false]{--scrollsheet-toast-y:translateY(40%);opacity:0}.scrollsheet-toast[data-swiping=true]{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));transition:none}.scrollsheet-toast[data-swiped=true]{-webkit-user-select:none;user-select:none}.scrollsheet-toast[data-swipe-out=true]{animation:.2s ease-out forwards scrollsheet-toast-swipe-out}.scrollsheet-toast[data-swipe-direction=left]{--scrollsheet-toast-swipe-out-x:-1}.scrollsheet-toast[data-swipe-direction=right]{--scrollsheet-toast-swipe-out-x:1}.scrollsheet-toast[data-swipe-direction=up]{--scrollsheet-toast-swipe-out-y:-1}.scrollsheet-toast[data-swipe-direction=down]{--scrollsheet-toast-swipe-out-y:1}@keyframes scrollsheet-toast-swipe-out{0%{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));opacity:1}to{transform:var(--scrollsheet-toast-y) translateY(calc(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px)) + var(--scrollsheet-toast-swipe-out-y,var(--sonner-swipe-out-y,0)) * 100%)) translateX(calc(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)) + var(--scrollsheet-toast-swipe-out-x,var(--sonner-swipe-out-x,0)) * 100%));opacity:0}}@media (prefers-reduced-motion:reduce){[data-scrollsheet-toaster],.scrollsheet-toast{transition:none!important;animation:none!important}}@media (max-width:600px){[data-scrollsheet-toaster]{right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));width:100%}[data-scrollsheet-toaster] .scrollsheet-toast{width:calc(100% - var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px)) * 2);left:0;right:0}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-x-position=center]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));transform:none}}`, "data-sonner-toast-styles");
function injectToastStyles(nonce) {
injectDocument(nonce);
}
function injectToastStylesInto(root, nonce) {
injectShadowRoot(root, nonce);
}
//#endregion
//#region packages/scrollsheet/src/toast/toaster.tsx
function resolveVisibleToasts(count) {
if (count === void 0) return 3;
return Math.max(1, Math.floor(count));
}
function useMountedFlag() {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
if (prefersReducedMotion()) {
setMounted(true);
return;
}
let raf2 = 0;
const raf1 = requestAnimationFrame(() => {
raf2 = requestAnimationFrame(() => setMounted(true));
});
return () => {
cancelAnimationFrame(raf1);
cancelAnimationFrame(raf2);
};
}, []);
return mounted;
}
function useIsDocumentHidden() {
const [hidden, setHidden] = React.useState(() => typeof document !== "undefined" && document.hidden);
React.useEffect(() => {
const onVisibilityChange = () => setHidden(document.hidden);
document.addEventListener("visibilitychange", onVisibilityChange);
return () => document.removeEventListener("visibilitychange", onVisibilityChange);
}, []);
return hidden;
}
const EMPTY_RECORDS = [];
const EMPTY_MAP = new Map();
function toIdMap(records) {
return new Map(records.map((r) => [r.id, r]));
}
function sameIds(a, b) {
if (a.size !== b.size) return false;
for (const id of a.keys()) if (!b.has(id)) return false;
return true;
}
function useToastExit(live, queued = EMPTY_RECORDS, exitMs = 220) {
const [exiting, setExiting] = React.useState(() => EMPTY_MAP);
const [prevLive, setPrevLive] = React.useState(() => toIdMap(live));
const timersRef = React.useRef(new Map());
const liveIds = new Set(live.map((r) => r.id));
let renderExiting = exiting;
if (!sameIds(prevLive, liveIds)) {
const queuedIds = new Set(queued.map((r) => r.id));
const justRemoved = [];
for (const [id, record] of prevLive) {
if (liveIds.has(id)) continue;
if (queuedIds.has(id)) continue;
justRemoved.push(record);
}
setPrevLive(toIdMap(live));
if (justRemoved.length > 0) {
const next = new Map(exiting);
for (const record of justRemoved) next.set(record.id, record);
renderExiting = next;
setExiting(next);
}
}
React.useEffect(() => {
const reduced = prefersReducedMotion();
for (const [id] of exiting) {
if (timersRef.current.has(id)) continue;
const timer = setTimeout(() => {
timersRef.current.delete(id);
setExiting((prev) => {
if (!prev.has(id)) return prev;
const next = new Map(prev);
next.delete(id);
return next;
});
}, reduced ? 0 : exitMs);
timersRef.current.set(id, timer);
}
for (const [id, timer] of timersRef.current) if (!exiting.has(id)) {
clearTimeout(timer);
timersRef.current.delete(id);
}
}, [exiting, exitMs]);
React.useEffect(() => {
const timers = timersRef.current;
return () => {
for (const timer of timers.values()) clearTimeout(timer);
timers.clear();
};
}, []);
const rows = live.map((record) => ({
record,
exiting: false
}));
for (const [id, record] of renderExiting) if (!liveIds.has(id)) rows.push({
record,
exiting: true
});
return rows;
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/shell-selectors.ts
function splitPosition(position) {
const [y, x] = position.split("-");
return {
y,
x
};
}
function computePossiblePositions(defaultPosition, toasts) {
const seen = new Set([defaultPosition]);
for (const t of toasts) if (t.position) seen.add(t.position);
return [...seen];
}
function computeRowOffsets(newestFirst, heights, gap) {
let cumulativeHeight = 0;
return newestFirst.map((record, index) => {
const stackOffset = index * gap + cumulativeHeight;
cumulativeHeight += heights.get(record.id) ?? 0;
return {
id: record.id,
index,
toastsBefore: index,
stackOffset
};
});
}
function findNewestDismissible(toasts) {
for (let i = toasts.length - 1; i >= 0; i -= 1) {
const t = toasts[i];
if (t && t.dismissible !== false) return t;
}
}
const SWIPE_VELOCITY_THRESHOLD = .11;
function getDefaultSwipeDirections(position) {
const { y, x } = splitPosition(position);
const directions = [y];
if (x === "left" || x === "right") directions.push(x);
return directions;
}
function lockSwipeAxis(dx, dy) {
if (Math.abs(dx) <= 1 && Math.abs(dy) <= 1) return null;
return Math.abs(dx) > Math.abs(dy) ? "x" : "y";
}
function dampenSwipeDelta(delta) {
const dampened = delta * (1 / (1.5 + Math.abs(delta) / 20));
return Math.abs(dampened) < Math.abs(delta) ? dampened : delta;
}
function computeSwipeAxisAmount(axis, delta, directions) {
const negativeDir = axis === "x" ? "left" : "top";
const positiveDir = axis === "x" ? "right" : "bottom";
if (!(directions.includes(negativeDir) || directions.includes(positiveDir))) return 0;
return directions.includes(negativeDir) && delta < 0 || directions.includes(positiveDir) && delta > 0 ? delta : dampenSwipeDelta(delta);
}
function isSwipeReleaseAllowed(axis, amount, directions) {
if (axis === "x") return directions.includes(amount > 0 ? "right" : "left");
return directions.includes(amount > 0 ? "bottom" : "top");
}
function shouldDismissOnSwipeRelease(amount, velocity, thresholdPx = 45, velocityThreshold = SWIPE_VELOCITY_THRESHOLD) {
return Math.abs(amount) >= thresholdPx || velocity > velocityThreshold;
}
function resolveSwipeOutDirection(axis, amount) {
if (axis === "x") return amount > 0 ? "right" : "left";
return amount > 0 ? "down" : "up";
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/use-toast-swipe.ts
const ZERO_AMOUNT = {
x: 0,
y: 0
};
function useToastSwipe(elRef, enabled, directions, onSwipeDismiss) {
const draggingRef = React.useRef(false);
const axisRef = React.useRef(null);
const startRef = React.useRef(ZERO_AMOUNT);
const amountRef = React.useRef(ZERO_AMOUNT);
const dragStartRef = React.useRef(0);
const onSwipeDismissRef = React.useRef(onSwipeDismiss);
onSwipeDismissRef.current = onSwipeDismiss;
const onPointerDown = React.useCallback((event) => {
if (!enabled || event.button !== 0) return;
if (event.target.tagName === "BUTTON") return;
const el = elRef.current;
if (!el) return;
draggingRef.current = true;
axisRef.current = null;
amountRef.current = ZERO_AMOUNT;
startRef.current = {
x: event.clientX,
y: event.clientY
};
dragStartRef.current = Date.now();
el.setPointerCapture(event.pointerId);
el.setAttribute("data-swiping", "true");
}, [enabled, elRef]);
const onPointerMove = React.useCallback((event) => {
if (!draggingRef.current) return;
const el = elRef.current;
if (!el) return;
if ((window.getSelection?.()?.toString().length ?? 0) > 0) return;
const start = startRef.current;
const dx = event.clientX - start.x;
const dy = event.clientY - start.y;
if (axisRef.current === null) axisRef.current = lockSwipeAxis(dx, dy);
const axis = axisRef.current;
if (axis === null) return;
const resolved = computeSwipeAxisAmount(axis, axis === "x" ? dx : dy, directions);
const amount = axis === "x" ? {
x: resolved,
y: 0
} : {
x: 0,
y: resolved
};
amountRef.current = amount;
if (resolved !== 0) el.setAttribute("data-swiped", "true");
el.style.setProperty("--scrollsheet-toast-swipe-x", `${amount.x}px`);
el.style.setProperty("--scrollsheet-toast-swipe-y", `${amount.y}px`);
}, [elRef, directions]);
const release = React.useCallback(() => {
if (!draggingRef.current) return;
draggingRef.current = false;
const el = elRef.current;
const axis = axisRef.current;
axisRef.current = null;
if (!el) return;
if (axis === null) {
el.setAttribute("data-swiping", "false");
return;
}
const amount = axis === "x" ? amountRef.current.x : amountRef.current.y;
const elapsed = Math.max(1, Date.now() - dragStartRef.current);
const velocity = Math.abs(amount) / elapsed;
if (isSwipeReleaseAllowed(axis, amount, directions) && shouldDismissOnSwipeRelease(amount, velocity)) {
const direction = resolveSwipeOutDirection(axis, amount);
el.setAttribute("data-swipe-direction", direction);
if (prefersReducedMotion()) {
el.setAttribute("data-swipe-out", "true");
onSwipeDismissRef.current();
return;
}
const onAnimEnd = () => {
el.removeEventListener("animationend", onAnimEnd);
onSwipeDismissRef.current();
};
el.addEventListener("animationend", onAnimEnd);
el.setAttribute("data-swipe-out", "true");
return;
}
el.setAttribute("data-swiping", "false");
el.setAttribute("data-swiped", "false");
el.style.setProperty("--scrollsheet-toast-swipe-x", "0px");
el.style.setProperty("--scrollsheet-toast-swipe-y", "0px");
}, [elRef, directions]);
return {
onPointerDown,
onPointerMove,
onPointerUp: React.useCallback((event) => {
if (elRef.current?.hasPointerCapture(event.pointerId)) elRef.current.releasePointerCapture(event.pointerId);
release();
}, [elRef, release]),
onPointerCancel: React.useCallback(() => release(), [release])
};
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/toast-row.tsx
function ToastIcon({ type, icons, spinnerClassName }) {
if (type === "loading") {
if (icons?.loading) return jsx(Fragment, { children: icons.loading });
return jsx("span", { className: spinnerClassName });
}
switch (type) {
case "success": return jsx(Fragment, { children: icons?.success ?? "✓" });
case "error": return jsx(Fragment, { children: icons?.error ?? "✕" });
case "warning": return jsx(Fragment, { children: icons?.warning ?? "!" });
case "info": return jsx(Fragment, { children: icons?.info ?? "i" });
default: return null;
}
}
function ToastRow({ record, index, total, toastsBefore, stackOffset, height, frontHeight, visible, expanded, removed, yPosition, xPosition, closeButton, directions, onDismiss, observe, toasterClassNames, icons, toasterCloseButtonAriaLabel }) {
const role = record.type === "error" ? "alert" : "status";
const mounted = useMountedFlag();
const elRef = React.useRef(null);
const dismissible = record.dismissible !== false;
const isFront = index === 0;
const setRefs = React.useCallback((el) => {
elRef.current = el;
observe(record.id, el);
}, [observe, record.id]);
const swipeHandlers = useToastSwipe(elRef, !removed && dismissible && record.type !== "loading", directions, () => onDismiss(record));
React.useEffect(() => {
const el = elRef.current;
if (el) el.inert = removed;
}, [removed]);
const style = {
"--scrollsheet-toast-toasts-before": toastsBefore,
"--scrollsheet-toast-stack-offset": `${stackOffset}px`,
"--scrollsheet-toast-front-height": frontHeight !== void 0 ? `${frontHeight}px` : "0px",
"--scrollsheet-toast-initial-height": height !== void 0 ? `${height}px` : "auto",
zIndex: Math.max(0, total - index)
};
const rootClassName = cn("scrollsheet-toast", "sonner-toast", record.className, toasterClassNames?.toast, record.classNames?.toast, toasterClassNames?.default, toasterClassNames?.[record.type], record.classNames?.[record.type]);
const motionAttrs = {
"data-mounted": mounted ? "" : void 0,
"data-removed": removed ? "" : void 0,
"data-visible": visible ? "true" : "false",
"data-front": isFront ? "true" : "false",
"data-expanded": expanded ? "true" : "false",
"data-y-position": yPosition,
"data-x-position": xPosition,
"data-index": index,
"data-dismissible": dismissible ? "true" : "false",
"data-swiping": "false",
"data-swiped": "false",
"aria-hidden": removed ? "true" : void 0
};
if (record.jsx !== void 0) return jsx("div", {
ref: setRefs,
className: rootClassName,
"data-scrollsheet-toast": "",
"data-sonner-toast": "",
"data-scrollsheet-custom": "",
"data-sonner-custom": "",
"data-testid": record.testId,
role,
style,
...motionAttrs,
...swipeHandlers,
children: record.jsx
});
const showCloseButton = closeButton && dismissible && record.type !== "loading";
const hasActions = Boolean(record.action || record.cancel || showCloseButton);
const closeButtonAriaLabel = record.closeButtonAriaLabel ?? toasterCloseButtonAriaLabel ?? "Close toast";
return jsxs("div", {
ref: setRefs,
className: rootClassName,
"data-scrollsheet-toast": "",
"data-sonner-toast": "",
"data-type": record.type,
"data-testid": record.testId,
role,
style,
...motionAttrs,
...swipeHandlers,
children: [
jsx("span", {
className: cn("scrollsheet-toast-icon", "sonner-toast-icon", toasterClassNames?.icon, record.classNames?.icon),
"data-type": record.type,
"aria-hidden": "true",
children: record.icon ?? jsx(ToastIcon, {
type: record.type,
icons,
spinnerClassName: cn("scrollsheet-toast-spinner", "sonner-toast-spinner", toasterClassNames?.loader, record.classNames?.loader)
})
}),
jsxs("div", {
className: cn("scrollsheet-toast-body", "sonner-toast-body", toasterClassNames?.content, record.classNames?.content),
children: [record.title !== void 0 && jsx("div", {
className: cn("scrollsheet-toast-title", "sonner-toast-title", toasterClassNames?.title, record.classNames?.title),
children: record.title
}), record.description !== void 0 && jsx("div", {
className: cn("scrollsheet-toast-description", "sonner-toast-description", toasterClassNames?.description, record.classNames?.description),
children: record.description
})]
}),
hasActions && jsxs("div", {
className: "scrollsheet-toast-actions sonner-toast-actions",
children: [
record.cancel && jsx("button", {
type: "button",
className: cn("scrollsheet-toast-cancel", "sonner-toast-cancel", toasterClassNames?.cancelButton, record.classNames?.cancelButton),
onClick: (event) => {
if (!dismissible) return;
record.cancel?.onClick(event);
onDismiss(record);
},
children: record.cancel.label
}),
record.action && jsx("button", {
type: "button",
className: cn("scrollsheet-toast-action", "sonner-toast-action", toasterClassNames?.actionButton, record.classNames?.actionButton),
onClick: (event) => {
record.action?.onClick(event);
if (event.defaultPrevented) return;
onDismiss(record);
},
children: record.action.label
}),
showCloseButton && jsx("button", {
type: "button",
className: cn("scrollsheet-toast-close", "sonner-toast-close", toasterClassNames?.closeButton, record.classNames?.closeButton),
"aria-label": closeButtonAriaLabel,
onClick: () => onDismiss(record),
children: icons?.close ?? "×"
})
]
})
]
});
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/use-toast-heights.ts
function useToastHeights() {
const [heights, setHeights] = React.useState(() => new Map());
const observersRef = React.useRef(new Map());
const setHeight = React.useCallback((id, height) => {
setHeights((prev) => prev.get(id) === height ? prev : new Map(prev).set(id, height));
}, []);
const forget = React.useCallback((id) => {
observersRef.current.get(id)?.disconnect();
observersRef.current.delete(id);
setHeights((prev) => {
if (!prev.has(id)) return prev;
const next = new Map(prev);
next.delete(id);
return next;
});
}, []);
const observe = React.useCallback((id, el) => {
const observers = observersRef.current;
observers.get(id)?.disconnect();
observers.delete(id);
if (!el || typeof ResizeObserver === "undefined") return;
const ro = new ResizeObserver(() => setHeight(id, el.getBoundingClientRect().height));
ro.observe(el);
observers.set(id, ro);
setHeight(id, el.getBoundingClientRect().height);
}, [setHeight]);
React.useEffect(() => {
const observers = observersRef.current;
return () => {
for (const ro of observers.values()) ro.disconnect();
observers.clear();
};
}, []);
return {
heights,
observe,
forget
};
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/toaster-shell.tsx
const DEFAULT_HOTKEY = ["altKey", "KeyT"];
function PositionGroup({ position, defaultPosition, toasts, visibleToasts, gap, expanded, closeButton, swipeDirections, toastOptions, icons, className, baseStyle, registerListEl, dismissRow, onHoverEnter, onHoverLeave, onInteractingChange }) {
const directions = React.useMemo(() => swipeDirections ?? getDefaultSwipeDirections(position), [swipeDirections, position]);
const positionToasts = React.useMemo(() => selectPositionToasts(toasts, position, defaultPosition), [
toasts,
position,
defaultPosition
]);
const newestFirst = React.useMemo(() => [...positionToasts].reverse(), [positionToasts]);
const window_ = React.useMemo(() => selectToastWindow(positionToasts, visibleToasts), [positionToasts, visibleToasts]);
const visibleIds = React.useMemo(() => new Set(window_.visible.map((t) => t.id)), [window_]);
const { heights, observe, forget } = useToastHeights();
const exitRows = useToastExit(newestFirst);
const exitingIds = React.useMemo(() => new Set(exitRows.filter((r) => r.exiting).map((r) => r.record.id)), [exitRows]);
React.useEffect(() => {
for (const id of exitingIds) forget(id);
}, [exitingIds, forget]);
const offsets = React.useMemo(() => computeRowOffsets(newestFirst, heights, gap), [
newestFirst,
heights,
gap
]);
const offsetById = React.useMemo(() => new Map(offsets.map((o) => [o.id, o])), [offsets]);
const lastOffsetRef = React.useRef(new Map());
for (const o of offsets) lastOffsetRef.current.set(o.id, o);
if (lastOffsetRef.current.size > offsets.length) {
const keep = new Set([...offsets.map((o) => o.id), ...exitingIds]);
for (const id of [...lastOffsetRef.current.keys()]) if (!keep.has(id)) lastOffsetRef.current.delete(id);
}
const frontHeight = heights.get(newestFirst[0]?.id ?? "");
const { y, x } = splitPosition(position);
const listRef = React.useCallback((el) => registerListEl(position, el), [registerListEl, position]);
if (exitRows.length === 0) return null;
return jsx("ol", {
ref: listRef,
"data-scrollsheet-toaster": "",
"data-sonner-toaster": "",
"data-scrollsheet-theme": "light",
"data-sonner-theme": "light",
"data-y-position": y,
"data-x-position": x,
tabIndex: -1,
className,
style: {
...baseStyle,
"--scrollsheet-toast-gap": `${gap}px`,
"--scrollsheet-toast-front-height": frontHeight !== void 0 ? `${frontHeight}px` : void 0
},
onMouseEnter: onHoverEnter,
onMouseMove: onHoverEnter,
onMouseLeave: onHoverLeave,
onPointerDown: (event) => {
if (event.target.dataset.dismissible === "false") return;
onInteractingChange(true);
},
onPointerUp: () => onInteractingChange(false),
children: exitRows.map(({ record, exiting }) => {
const offset = offsetById.get(record.id) ?? lastOffsetRef.current.get(record.id);
const index = offset?.index ?? newestFirst.length;
return jsx(ToastRow, {
record,
index,
total: newestFirst.length,
toastsBefore: offset?.toastsBefore ?? index,
stackOffset: offset?.stackOffset ?? 0,
height: heights.get(record.id),
frontHeight,
visible: visibleIds.has(record.id),
expanded,
removed: exiting,
yPosition: y,
xPosition: x,
closeButton,
directions,
onDismiss: dismissRow,
observe,
toasterClassNames: toastOptions?.classNames,
icons,
toasterCloseButtonAriaLabel: toastOptions?.closeButtonAriaLabel
}, record.id);
})
});
}
function resolveShellPosition(position) {
return position ?? "bottom-right";
}
function ToasterShell({ id, toasterId, position, theme, richColors, expand: forceExpand, visibleToasts: visibleToastsProp, closeButton = false, duration: durationProp, gap = 14, offset, swipeDirections, toastOptions, icons, className, style, containerAriaLabel = "Notifications", hotkey = DEFAULT_HOTKEY, nonce }) {
const resolvedId = id ?? toasterId;
if (toasterId !== void 0) warnOnce("toaster-id-deprecated", "[scrollsheet Toaster] Toaster's \"toasterId\" prop is deprecated — use \"id\" instead.");
const { toasts: allToasts } = useSonner();
const toasts = React.useMemo(() => selectToasterToasts(allToasts, resolvedId), [allToasts, resolvedId]);
const defaultPosition = resolveShellPosition(position);
const possiblePositions = React.useMemo(() => computePossiblePositions(defaultPosition, toasts), [defaultPosition, toasts]);
const visibleToasts = resolveVisibleToasts(visibleToastsProp);
const defaultDuration = durationProp ?? toastOptions?.duration ?? 4e3;
if (theme !== void 0 && theme !== "light") warnOnce("shell-theme", `[scrollsheet Toaster] theme="${theme}" isn't implemented yet — v1 always renders the static light card real Sonner ships by default.`);
if (richColors) warnOnce("shell-rich-colors", "[scrollsheet Toaster] richColors isn't implemented yet — toasts render with their default icon color only.");
React.useEffect(() => {
injectToastStyles(nonce);
}, [nonce]);
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => setMounted(true), []);
const [hovered, setHovered] = React.useState(false);
const [hotkeyExpanded, setHotkeyExpanded] = React.useState(false);
const [interacting, setInteracting] = React.useState(false);
const expanded = Boolean(forceExpand) || hovered || hotkeyExpanded;
const isDocumentHidden = useIsDocumentHidden();
const handleHoverEnter = React.useCallback(() => setHovered(true), []);
const handleHoverLeave = React.useCallback(() => {
if (!interacting) setHovered(false);
}, [interacting]);
const dismissRow = React.useCallback((record) => {
toast.dismiss(record.id);
}, []);
const listElsRef = React.useRef(new Map());
const registerListEl = React.useCallback((pos, el) => {
if (el) listElsRef.current.set(pos, el);
else listElsRef.current.delete(pos);
}, []);
React.useEffect(() => {
if (hotkey.length === 0) return;
const handleKeyDown = (event) => {
if (hotkey.every((key) => event[key] || event.code === key)) {
setHotkeyExpanded(true);
const [firstList] = listElsRef.current.values();
firstList?.focus({ preventScroll: true });
}
if (event.code !== "Escape") return;
const active = document.activeElement;
const focusedEntry = [...listElsRef.current.entries()].find(([, el]) => active === el || el.contains(active));
if (!focusedEntry) return;
if (hotkeyExpanded) {
setHotkeyExpanded(false);
return;
}
const [focusedPosition] = focusedEntry;
const positionToasts = selectPositionToasts(toasts, focusedPosition, defaultPosition);
const front = positionToasts[positionToasts.length - 1];
if (front) dismissRow(front);
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [
hotkey,
hotkeyExpanded,
toasts,
defaultPosition,
dismissRow
]);
const timersRef = React.useRef(new Map());
React.useEffect(() => {
const timers = timersRef.current;
const liveIds = new Set(toasts.map((t) => t.id));
for (const [id, entry] of timers) {
if (liveIds.has(id)) continue;
if (entry.timer) clearTimeout(entry.timer);
timers.delete(id);
}
const paused = expanded || interacting || isDocumentHidden;
for (const t of toasts) {
if (t.type === "loading") {
const stale = timers.get(t.id);
if (stale) {
if (stale.timer) clearTimeout(stale.timer);
timers.delete(t.id);
}
continue;
}
const ms = t.duration ?? toastOptions?.duration ?? defaultDuration;
const existing = timers.get(t.id);
if (!existing || existing.record !== t) {
if (existing?.timer) clearTimeout(existing.timer);
const entry = {
timer: null,
startedAt: 0,
remaining: ms,
record: t
};
timers.set(t.id, entry);
if (Number.isFinite(ms) && !paused) {
entry.startedAt = Date.now();
entry.timer = setTimeout(() => {
timersRef.current.delete(t.id);
expire(t.id);
}, ms);
}
continue;
}
if (paused) {
if (existing.timer) {
clearTimeout(existing.timer);
const elapsed = Date.now() - existing.startedAt;
existing.remaining = Math.max(0, existing.remaining - elapsed);
existing.timer = null;
}
continue;
}
if (existing.timer || !Number.isFinite(existing.remaining)) continue;
existing.startedAt = Date.now();
existing.timer = setTimeout(() => {
timersRef.current.delete(t.id);
expire(t.id);
}, existing.remaining);
}
}, [
toasts,
expanded,
interacting,
isDocumentHidden,
defaultDuration,
toastOptions?.duration
]);
React.useEffect(() => {
const timers = timersRef.current;
return () => {
for (const entry of timers.values()) if (entry.timer) clearTimeout(entry.timer);
timers.clear();
};
}, []);
useCloseWatcher({
present: toasts.length > 0,
nonModal: true,
escapeDismissible: true,
onClose: () => {
const target = findNewestDismissible(toasts);
if (target) dismissRow(target);
}
});
if (!mounted || typeof document === "undefined") return null;
const offsetValue = offset !== void 0 ? typeof offset === "number" ? `${offset}px` : offset : void 0;
const baseStyle = {
...style,
"--scrollsheet-toast-offset": offsetValue
};
return createPortal(jsx("section", {
"aria-label": containerAriaLabel,
tabIndex: -1,
"aria-live": "polite",
"aria-relevant": "additions text",
"aria-atomic": "false",
suppressHydrationWarning: true,
"data-react-aria-top-layer": "",
children: possiblePositions.map((groupPosition) => jsx(PositionGroup, {
position: groupPosition,
defaultPosition,
toasts,
visibleToasts,
gap,
expanded,
closeButton,
swipeDirections,
toastOptions,
icons,
className,
baseStyle,
registerListEl,
dismissRow,
onHoverEnter: handleHoverEnter,
onHoverLeave: handleHoverLeave,
onInteractingChange: setInteracting
}, groupPosition))
}), document.body);
}
//#endregion
export { useSonner as a, toast as i, resolveVisibleToasts as n, useToasts as o, injectToastStylesInto as r, ToasterShell as t };

Sorry, the diff of this file is too big to display

+1
-1
"use client";
"use client";
import { a as NestedRoot, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, g as Title, h as Description, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange, x as Trigger } from "./drawer-DjGdqpHe.mjs";
import { a as NestedRoot, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, g as Title, h as Description, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange, x as Trigger } from "./drawer-HVSMFDtk.mjs";
export { DrawerClose as Close, Content, Description, Drawer, Handle, NestedRoot, Overlay, Portal, Root, Title, Trigger, composeHandleClick, composeOpenChange, hasMultipleSnapPoints, resolveCloseThreshold, resolveFadeFromIndex };
"use client";
import { S as Root, _ as Handle, b as spring, g as Title, h as Description, m as Close, n as Drawer, v as Content, x as Trigger, y as injectStylesInto } from "./drawer-DjGdqpHe.mjs";
import { S as Root, _ as Handle, b as spring, g as Title, h as Description, m as Close, n as Drawer, v as Content, x as Trigger, y as injectStylesInto } from "./drawer-HVSMFDtk.mjs";
import { o as hasDialogSupport } from "./cn-CActSFFr.mjs";
import { a as useSonner, i as toast, o as useToasts, r as injectToastStylesInto, t as ToasterShell } from "./toast-DKgHZqNc.mjs";
import { a as useSonner, i as toast, o as useToasts, r as injectToastStylesInto, t as ToasterShell } from "./toast-BByAtKPq.mjs";
//#region packages/scrollsheet/src/index.ts

@@ -6,0 +6,0 @@ function isSupported() {

"use client";
"use client";
import { a as useSonner, i as toast, n as resolveVisibleToasts, o as useToasts, r as injectToastStylesInto, t as ToasterShell } from "./toast-DKgHZqNc.mjs";
import { a as useSonner, i as toast, n as resolveVisibleToasts, o as useToasts, r as injectToastStylesInto, t as ToasterShell } from "./toast-BByAtKPq.mjs";
export { ToasterShell as Toaster, injectToastStylesInto, resolveVisibleToasts, toast, useSonner, useToasts };
"use client";
"use client";
import { a as NestedRoot, b as Trigger, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, g as Title, h as Description, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange } from "./drawer-FytErbvx.mjs";
import { a as NestedRoot, b as Trigger, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, g as Title, h as Description, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange } from "./drawer-BXqx0bTN.mjs";
export { DrawerClose as Close, Content, Description, Drawer, Handle, NestedRoot, Overlay, Portal, Root, Title, Trigger, composeHandleClick, composeOpenChange, hasMultipleSnapPoints, resolveCloseThreshold, resolveFadeFromIndex };
"use client";
import { _ as Handle, b as Trigger, g as Title, h as Description, m as Close, n as Drawer, v as Content, x as Root, y as injectStylesInto } from "./drawer-FytErbvx.mjs";
import { _ as Handle, b as Trigger, g as Title, h as Description, m as Close, n as Drawer, v as Content, x as Root, y as injectStylesInto } from "./drawer-BXqx0bTN.mjs";
import { o as hasDialogSupport } from "./cn-CActSFFr.mjs";

@@ -4,0 +4,0 @@ import { a as spring } from "./animate-D5TGKlub.mjs";

@@ -1,1 +0,1 @@

.scrollsheet-toast{color:#18181b;background:#fff;border:1px solid #00000014;border-radius:8px;align-items:flex-start;gap:10px;padding:16px;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;font-size:13px;display:flex;position:relative;box-shadow:0 4px 12px #0000001a}.scrollsheet-toast[data-scrollsheet-custom]{box-shadow:none;background:0 0;border:none;padding:0}.scrollsheet-toast-icon{color:#fff;background:#6b7280;border-radius:50%;flex:none;place-items:center;width:18px;height:18px;margin-top:1px;font-size:11px;line-height:1;display:grid}.scrollsheet-toast-icon[data-type=success]{background:#22c55e}.scrollsheet-toast-icon[data-type=error]{background:#ef4444}.scrollsheet-toast-icon[data-type=warning]{background:#f59e0b}.scrollsheet-toast-icon[data-type=info]{background:#3b82f6}.scrollsheet-toast-icon[data-type=loading]{background:0 0}.scrollsheet-toast-spinner{border:2px solid #00000026;border-top-color:#0000008c;border-radius:50%;width:14px;height:14px;animation:.6s linear infinite scrollsheet-toast-spin}@keyframes scrollsheet-toast-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.scrollsheet-toast-spinner{animation-duration:1.6s}}.scrollsheet-toast-body{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.scrollsheet-toast-title{font-size:13px;font-weight:500;line-height:1.35}.scrollsheet-toast-description{color:#0009;font-size:13px;line-height:1.4}.scrollsheet-toast-actions{flex:none;align-items:center;gap:6px;display:flex}.scrollsheet-toast-action,.scrollsheet-toast-cancel{cursor:pointer;border:none;border-radius:4px;height:24px;padding:0 8px;font-size:12px;font-weight:500}.scrollsheet-toast-action{color:#fff;background:#18181b}.scrollsheet-toast-cancel{color:#18181b;background:#0000000f}.scrollsheet-toast-close{color:#00000080;cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;place-items:center;width:20px;height:20px;padding:0;font-size:14px;line-height:1;display:grid}.scrollsheet-toast-close:hover{background:#0000000f}[data-scrollsheet-toaster]{z-index:2147483647;width:min(356px, calc(100vw - 2 * var(--scrollsheet-toast-offset,var(--sonner-offset,24px))));outline:none;margin:0;padding:0;list-style:none;transition:transform .4s;position:fixed}[data-scrollsheet-toaster][data-x-position=right]{right:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=center]{left:50%;transform:translate(-50%)}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}.scrollsheet-toast{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);opacity:0;transform:var(--scrollsheet-toast-y);touch-action:none;box-sizing:border-box;overflow-wrap:anywhere;transition:transform .25s,opacity .25s,height .25s;position:absolute;left:0;right:0}.scrollsheet-toast[data-y-position=top]{--scrollsheet-toast-lift:1;--scrollsheet-toast-y:translateY(-100%);top:0}.scrollsheet-toast[data-y-position=bottom]{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);bottom:0}.scrollsheet-toast[data-mounted]{--scrollsheet-toast-y:translateY(0);opacity:1}.scrollsheet-toast[data-expanded=false][data-front=false]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-gap,var(--sonner-gap,14px)) * var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)))) scale(calc(-1 * (1 + var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)) * .05)));height:var(--scrollsheet-toast-front-height,var(--sonner-front-height,auto));overflow:hidden}.scrollsheet-toast[data-expanded=false][data-front=false]>*{opacity:0}.scrollsheet-toast[data-mounted][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px))));height:var(--scrollsheet-toast-initial-height,var(--sonner-initial-height,auto))}.scrollsheet-toast[data-visible=false]{opacity:0;pointer-events:none}.scrollsheet-toast[data-removed]{pointer-events:none}.scrollsheet-toast[data-removed][data-front=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px)) + var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=false]{--scrollsheet-toast-y:translateY(40%);opacity:0}.scrollsheet-toast[data-swiping=true]{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));transition:none}.scrollsheet-toast[data-swiped=true]{-webkit-user-select:none;user-select:none}.scrollsheet-toast[data-swipe-out=true]{animation:.2s ease-out forwards scrollsheet-toast-swipe-out}.scrollsheet-toast[data-swipe-direction=left]{--scrollsheet-toast-swipe-out-x:-1}.scrollsheet-toast[data-swipe-direction=right]{--scrollsheet-toast-swipe-out-x:1}.scrollsheet-toast[data-swipe-direction=up]{--scrollsheet-toast-swipe-out-y:-1}.scrollsheet-toast[data-swipe-direction=down]{--scrollsheet-toast-swipe-out-y:1}@keyframes scrollsheet-toast-swipe-out{0%{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));opacity:1}to{transform:var(--scrollsheet-toast-y) translateY(calc(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px)) + var(--scrollsheet-toast-swipe-out-y,var(--sonner-swipe-out-y,0)) * 100%)) translateX(calc(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)) + var(--scrollsheet-toast-swipe-out-x,var(--sonner-swipe-out-x,0)) * 100%));opacity:0}}@media (prefers-reduced-motion:reduce){[data-scrollsheet-toaster],.scrollsheet-toast{transition:none!important;animation:none!important}}@media (max-width:600px){[data-scrollsheet-toaster]{right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));width:100%}[data-scrollsheet-toaster] .scrollsheet-toast{width:calc(100% - var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px)) * 2);left:0;right:0}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-x-position=center]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));transform:none}}
.scrollsheet-toast{border-radius:var(--scrollsheet-toast-radius,14px);color:#18181b;background:#fff;border:1px solid #00000014;align-items:flex-start;gap:10px;padding:16px;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;font-size:13px;display:flex;position:relative;box-shadow:0 4px 12px #0000001a}.scrollsheet-toast[data-scrollsheet-custom]{box-shadow:none;background:0 0;border:none;padding:0}.scrollsheet-toast-icon{color:#fff;background:#6b7280;border-radius:50%;flex:none;place-items:center;width:18px;height:18px;margin-top:1px;font-size:11px;line-height:1;display:grid}.scrollsheet-toast-icon[data-type=success]{background:#22c55e}.scrollsheet-toast-icon[data-type=error]{background:#ef4444}.scrollsheet-toast-icon[data-type=warning]{background:#f59e0b}.scrollsheet-toast-icon[data-type=info]{background:#3b82f6}.scrollsheet-toast-icon[data-type=loading]{background:0 0}.scrollsheet-toast-spinner{border:2px solid #00000026;border-top-color:#0000008c;border-radius:50%;width:14px;height:14px;animation:.6s linear infinite scrollsheet-toast-spin}@keyframes scrollsheet-toast-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.scrollsheet-toast-spinner{animation-duration:1.6s}}.scrollsheet-toast-body{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.scrollsheet-toast-title{font-size:13px;font-weight:500;line-height:1.35}.scrollsheet-toast-description{color:#0009;font-size:13px;line-height:1.4}.scrollsheet-toast-actions{flex:none;align-items:center;gap:6px;display:flex}.scrollsheet-toast-action,.scrollsheet-toast-cancel{cursor:pointer;border:none;border-radius:4px;height:24px;padding:0 8px;font-size:12px;font-weight:500}.scrollsheet-toast-action{color:#fff;background:#18181b}.scrollsheet-toast-cancel{color:#18181b;background:#0000000f}.scrollsheet-toast-close{color:#00000080;cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;place-items:center;width:20px;height:20px;padding:0;font-size:14px;line-height:1;display:grid}.scrollsheet-toast-close:hover{background:#0000000f}[data-scrollsheet-toaster]{z-index:2147483647;width:min(356px, calc(100vw - 2 * var(--scrollsheet-toast-offset,var(--sonner-offset,24px))));outline:none;margin:0;padding:0;list-style:none;transition:transform .4s;position:fixed}[data-scrollsheet-toaster][data-x-position=right]{right:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=center]{left:50%;transform:translate(-50%)}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}.scrollsheet-toast{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);opacity:0;transform:var(--scrollsheet-toast-y);touch-action:none;box-sizing:border-box;overflow-wrap:anywhere;transition:transform .25s,opacity .25s,height .25s;position:absolute;left:0;right:0}.scrollsheet-toast[data-y-position=top]{--scrollsheet-toast-lift:1;--scrollsheet-toast-y:translateY(-100%);top:0}.scrollsheet-toast[data-y-position=bottom]{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);bottom:0}.scrollsheet-toast[data-mounted]{--scrollsheet-toast-y:translateY(0);opacity:1}.scrollsheet-toast[data-expanded=false][data-front=false]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-gap,var(--sonner-gap,14px)) * var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)))) scale(calc(1 - var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)) * .05));height:var(--scrollsheet-toast-front-height,var(--sonner-front-height,auto));overflow:hidden}.scrollsheet-toast[data-expanded=false][data-front=false]>*{opacity:0}.scrollsheet-toast[data-mounted][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px))));height:var(--scrollsheet-toast-initial-height,var(--sonner-initial-height,auto))}.scrollsheet-toast[data-visible=false]{opacity:0;pointer-events:none}.scrollsheet-toast[data-removed]{pointer-events:none}.scrollsheet-toast[data-removed][data-front=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px)) + var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=false]{--scrollsheet-toast-y:translateY(40%);opacity:0}.scrollsheet-toast[data-swiping=true]{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));transition:none}.scrollsheet-toast[data-swiped=true]{-webkit-user-select:none;user-select:none}.scrollsheet-toast[data-swipe-out=true]{animation:.2s ease-out forwards scrollsheet-toast-swipe-out}.scrollsheet-toast[data-swipe-direction=left]{--scrollsheet-toast-swipe-out-x:-1}.scrollsheet-toast[data-swipe-direction=right]{--scrollsheet-toast-swipe-out-x:1}.scrollsheet-toast[data-swipe-direction=up]{--scrollsheet-toast-swipe-out-y:-1}.scrollsheet-toast[data-swipe-direction=down]{--scrollsheet-toast-swipe-out-y:1}@keyframes scrollsheet-toast-swipe-out{0%{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));opacity:1}to{transform:var(--scrollsheet-toast-y) translateY(calc(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px)) + var(--scrollsheet-toast-swipe-out-y,var(--sonner-swipe-out-y,0)) * 100%)) translateX(calc(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)) + var(--scrollsheet-toast-swipe-out-x,var(--sonner-swipe-out-x,0)) * 100%));opacity:0}}@media (prefers-reduced-motion:reduce){[data-scrollsheet-toaster],.scrollsheet-toast{transition:none!important;animation:none!important}}@media (max-width:600px){[data-scrollsheet-toaster]{right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));width:100%}[data-scrollsheet-toaster] .scrollsheet-toast{width:calc(100% - var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px)) * 2);left:0;right:0}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-x-position=center]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));transform:none}}
{
"name": "scrollsheet",
"version": "1.0.0-beta.1",
"version": "1.0.0-beta.2",
"publishConfig": {

@@ -5,0 +5,0 @@ "tag": "beta"

Sorry, the diff of this file is too big to display

"use client";
import { c as prefersReducedMotion, h as warnOnce, n as useCloseWatcher, r as createStyleInjector, t as cn } from "./cn-CActSFFr.mjs";
import * as React from "react";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { createPortal } from "react-dom";
//#region packages/scrollsheet/src/toast/state.ts
let toasts = [];
const listeners = new Set();
let uid = 0;
const MAX_HISTORY_SIZE = 100;
let history = [];
function trimHistory() {
let toRemove = history.length - MAX_HISTORY_SIZE;
if (toRemove <= 0) return;
const liveIds = new Set(toasts.map((t) => t.id));
history = history.filter((record) => {
if (toRemove > 0 && !liveIds.has(record.id)) {
toRemove -= 1;
return false;
}
return true;
});
}
function recordHistory(record) {
const index = history.findIndex((t) => t.id === record.id);
if (index === -1) {
history = [...history, record];
trimHistory();
return;
}
history = history.map((t, i) => i === index ? record : t);
}
function nextId() {
uid += 1;
return uid;
}
function publish() {
for (const listener of listeners) listener();
}
function subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
function getSnapshot() {
return toasts;
}
const EMPTY_TOASTS = [];
function getServerSnapshot() {
return EMPTY_TOASTS;
}
function upsert(id, patch, fallbackType) {
const resolvedId = id ?? nextId();
const index = toasts.findIndex((t) => t.id === resolvedId);
const type = patch.type ?? fallbackType;
let record;
if (index === -1) {
record = {
dismissible: true,
...patch,
id: resolvedId,
type,
createdAt: Date.now()
};
toasts = [...toasts, record];
} else {
record = {
...toasts[index],
...patch,
id: resolvedId,
type
};
toasts = toasts.map((t, i) => i === index ? record : t);
}
recordHistory(record);
publish();
return resolvedId;
}
function dismiss(id) {
if (id === void 0) {
const swept = new Set(toasts);
for (const t of swept) {
if (!toasts.includes(t)) continue;
t.onDismiss?.(t);
}
toasts = toasts.filter((t) => !swept.has(t));
publish();
return;
}
const existing = toasts.find((t) => t.id === id);
if (!existing) return id;
existing.onDismiss?.(existing);
toasts = toasts.filter((t) => t !== existing);
publish();
return id;
}
function expire(id) {
const existing = toasts.find((t) => t.id === id);
if (!existing) return;
existing.onAutoClose?.(existing);
toasts = toasts.filter((t) => t !== existing);
publish();
}
function baseToast(message, data) {
return upsert(data?.id, {
...data,
title: message
}, "default");
}
function withType(type) {
return (message, data) => upsert(data?.id, {
...data,
title: message
}, type);
}
const toastImpl = baseToast;
toastImpl.success = withType("success");
toastImpl.error = withType("error");
toastImpl.info = withType("info");
toastImpl.warning = withType("warning");
toastImpl.loading = withType("loading");
toastImpl.message = withType("default");
toastImpl.custom = (jsx, data) => {
const id = data?.id ?? nextId();
return upsert(id, {
...data,
jsx: jsx(id)
}, "default");
};
function isHttpResponse(value) {
return typeof value === "object" && value !== null && "ok" in value && typeof value.ok === "boolean" && "status" in value && typeof value.status === "number";
}
function isPromiseExtendedResult(value) {
return typeof value === "object" && value !== null && !React.isValidElement(value);
}
function applyPromiseSettlement(id, resolved, fallbackTitle, description, type) {
if (isPromiseExtendedResult(resolved)) {
const { message, ...rest } = resolved;
upsert(id, {
description,
...rest,
title: message ?? fallbackTitle,
type
}, type);
return;
}
upsert(id, {
title: resolved ?? fallbackTitle,
description,
type
}, type);
}
function promiseImpl(promiseOrFn, data) {
const { loading, success, error, finally: onFinally, description, ...rest } = data;
const id = upsert(data.id, {
...rest,
description: typeof description === "function" ? void 0 : description,
title: loading,
type: "loading"
}, "loading");
const settle = typeof promiseOrFn === "function" ? promiseOrFn() : promiseOrFn;
let settled;
const chain = settle.then(async (result) => {
if (isHttpResponse(result) && !result.ok) {
settled = {
ok: false,
reason: result
};
const statusMessage = `HTTP error! status: ${result.status}`;
const resolvedDescription = typeof description === "function" ? await description(statusMessage) : description;
const resolved = typeof error === "function" ? await error(statusMessage) : error;
applyPromiseSettlement(id, resolved, "Error", resolvedDescription, "error");
return;
}
if (result instanceof Error) {
settled = {
ok: false,
reason: result
};
const resolvedDescription = typeof description === "function" ? await description(result) : description;
const resolved = typeof error === "function" ? await error(result) : error;
applyPromiseSettlement(id, resolved, "Error", resolvedDescription, "error");
return;
}
settled = {
ok: true,
value: result
};
const resolvedDescription = typeof description === "function" ? await description(result) : description;
const resolved = typeof success === "function" ? await success(result) : success;
applyPromiseSettlement(id, resolved, "Success", resolvedDescription, "success");
}).catch(async (err) => {
settled = {
ok: false,
reason: err
};
const resolvedDescription = typeof description === "function" ? await description(err) : description;
const resolved = typeof error === "function" ? await error(err) : error;
applyPromiseSettlement(id, resolved, "Error", resolvedDescription, "error");
}).finally(() => onFinally?.());
const unwrap = () => chain.then(() => {
if (!settled) throw new Error("scrollsheet toast.promise: chain settled with no outcome");
if (settled.ok) return settled.value;
throw settled.reason;
});
return Object.assign(id, { unwrap });
}
toastImpl.promise = promiseImpl;
toastImpl.dismiss = dismiss;
toastImpl.getToasts = () => toasts;
toastImpl.getHistory = () => history;
const toast = toastImpl;
function useSonner() {
return { toasts: React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) };
}
const useToasts = useSonner;
function selectToasterToasts(all, toasterId) {
return all.filter((t) => toasterId === void 0 ? t.toasterId === void 0 : t.toasterId === toasterId);
}
function selectPositionToasts(all, position, defaultPosition) {
return all.filter((t) => t.position === void 0 ? position === defaultPosition : t.position === position);
}
function selectToastWindow(toasts, visibleToasts) {
const newestFirst = [...toasts].reverse();
return {
visible: newestFirst.slice(0, visibleToasts),
hidden: newestFirst.slice(visibleToasts)
};
}
//#endregion
//#region packages/scrollsheet/src/toast/toast-styles.ts
const { injectDocument, injectShadowRoot } = createStyleInjector(`.scrollsheet-toast{color:#18181b;background:#fff;border:1px solid #00000014;border-radius:8px;align-items:flex-start;gap:10px;padding:16px;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;font-size:13px;display:flex;position:relative;box-shadow:0 4px 12px #0000001a}.scrollsheet-toast[data-scrollsheet-custom]{box-shadow:none;background:0 0;border:none;padding:0}.scrollsheet-toast-icon{color:#fff;background:#6b7280;border-radius:50%;flex:none;place-items:center;width:18px;height:18px;margin-top:1px;font-size:11px;line-height:1;display:grid}.scrollsheet-toast-icon[data-type=success]{background:#22c55e}.scrollsheet-toast-icon[data-type=error]{background:#ef4444}.scrollsheet-toast-icon[data-type=warning]{background:#f59e0b}.scrollsheet-toast-icon[data-type=info]{background:#3b82f6}.scrollsheet-toast-icon[data-type=loading]{background:0 0}.scrollsheet-toast-spinner{border:2px solid #00000026;border-top-color:#0000008c;border-radius:50%;width:14px;height:14px;animation:.6s linear infinite scrollsheet-toast-spin}@keyframes scrollsheet-toast-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.scrollsheet-toast-spinner{animation-duration:1.6s}}.scrollsheet-toast-body{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.scrollsheet-toast-title{font-size:13px;font-weight:500;line-height:1.35}.scrollsheet-toast-description{color:#0009;font-size:13px;line-height:1.4}.scrollsheet-toast-actions{flex:none;align-items:center;gap:6px;display:flex}.scrollsheet-toast-action,.scrollsheet-toast-cancel{cursor:pointer;border:none;border-radius:4px;height:24px;padding:0 8px;font-size:12px;font-weight:500}.scrollsheet-toast-action{color:#fff;background:#18181b}.scrollsheet-toast-cancel{color:#18181b;background:#0000000f}.scrollsheet-toast-close{color:#00000080;cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;place-items:center;width:20px;height:20px;padding:0;font-size:14px;line-height:1;display:grid}.scrollsheet-toast-close:hover{background:#0000000f}[data-scrollsheet-toaster]{z-index:2147483647;width:min(356px, calc(100vw - 2 * var(--scrollsheet-toast-offset,var(--sonner-offset,24px))));outline:none;margin:0;padding:0;list-style:none;transition:transform .4s;position:fixed}[data-scrollsheet-toaster][data-x-position=right]{right:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-x-position=center]{left:50%;transform:translate(-50%)}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-offset,var(--sonner-offset,24px))}.scrollsheet-toast{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);opacity:0;transform:var(--scrollsheet-toast-y);touch-action:none;box-sizing:border-box;overflow-wrap:anywhere;transition:transform .25s,opacity .25s,height .25s;position:absolute;left:0;right:0}.scrollsheet-toast[data-y-position=top]{--scrollsheet-toast-lift:1;--scrollsheet-toast-y:translateY(-100%);top:0}.scrollsheet-toast[data-y-position=bottom]{--scrollsheet-toast-lift:-1;--scrollsheet-toast-y:translateY(100%);bottom:0}.scrollsheet-toast[data-mounted]{--scrollsheet-toast-y:translateY(0);opacity:1}.scrollsheet-toast[data-expanded=false][data-front=false]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-gap,var(--sonner-gap,14px)) * var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)))) scale(calc(-1 * (1 + var(--scrollsheet-toast-toasts-before,var(--sonner-toasts-before,0)) * .05)));height:var(--scrollsheet-toast-front-height,var(--sonner-front-height,auto));overflow:hidden}.scrollsheet-toast[data-expanded=false][data-front=false]>*{opacity:0}.scrollsheet-toast[data-mounted][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px))));height:var(--scrollsheet-toast-initial-height,var(--sonner-initial-height,auto))}.scrollsheet-toast[data-visible=false]{opacity:0;pointer-events:none}.scrollsheet-toast[data-removed]{pointer-events:none}.scrollsheet-toast[data-removed][data-front=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=true]{--scrollsheet-toast-y:translateY(calc(var(--scrollsheet-toast-lift) * var(--scrollsheet-toast-stack-offset,var(--sonner-stack-offset,0px)) + var(--scrollsheet-toast-lift) * -100%));opacity:0}.scrollsheet-toast[data-removed][data-front=false][data-expanded=false]{--scrollsheet-toast-y:translateY(40%);opacity:0}.scrollsheet-toast[data-swiping=true]{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));transition:none}.scrollsheet-toast[data-swiped=true]{-webkit-user-select:none;user-select:none}.scrollsheet-toast[data-swipe-out=true]{animation:.2s ease-out forwards scrollsheet-toast-swipe-out}.scrollsheet-toast[data-swipe-direction=left]{--scrollsheet-toast-swipe-out-x:-1}.scrollsheet-toast[data-swipe-direction=right]{--scrollsheet-toast-swipe-out-x:1}.scrollsheet-toast[data-swipe-direction=up]{--scrollsheet-toast-swipe-out-y:-1}.scrollsheet-toast[data-swipe-direction=down]{--scrollsheet-toast-swipe-out-y:1}@keyframes scrollsheet-toast-swipe-out{0%{transform:var(--scrollsheet-toast-y) translateY(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px))) translateX(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)));opacity:1}to{transform:var(--scrollsheet-toast-y) translateY(calc(var(--scrollsheet-toast-swipe-y,var(--sonner-swipe-y,0px)) + var(--scrollsheet-toast-swipe-out-y,var(--sonner-swipe-out-y,0)) * 100%)) translateX(calc(var(--scrollsheet-toast-swipe-x,var(--sonner-swipe-x,0px)) + var(--scrollsheet-toast-swipe-out-x,var(--sonner-swipe-out-x,0)) * 100%));opacity:0}}@media (prefers-reduced-motion:reduce){[data-scrollsheet-toaster],.scrollsheet-toast{transition:none!important;animation:none!important}}@media (max-width:600px){[data-scrollsheet-toaster]{right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));width:100%}[data-scrollsheet-toaster] .scrollsheet-toast{width:calc(100% - var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px)) * 2);left:0;right:0}[data-scrollsheet-toaster][data-x-position=left]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=bottom]{bottom:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-y-position=top]{top:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px))}[data-scrollsheet-toaster][data-x-position=center]{left:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));right:var(--scrollsheet-toast-mobile-offset,var(--sonner-mobile-offset,16px));transform:none}}`, "data-sonner-toast-styles");
function injectToastStyles(nonce) {
injectDocument(nonce);
}
function injectToastStylesInto(root, nonce) {
injectShadowRoot(root, nonce);
}
//#endregion
//#region packages/scrollsheet/src/toast/toaster.tsx
function resolveVisibleToasts(count) {
if (count === void 0) return 3;
return Math.max(1, Math.floor(count));
}
function useMountedFlag() {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
if (prefersReducedMotion()) {
setMounted(true);
return;
}
let raf2 = 0;
const raf1 = requestAnimationFrame(() => {
raf2 = requestAnimationFrame(() => setMounted(true));
});
return () => {
cancelAnimationFrame(raf1);
cancelAnimationFrame(raf2);
};
}, []);
return mounted;
}
function useIsDocumentHidden() {
const [hidden, setHidden] = React.useState(() => typeof document !== "undefined" && document.hidden);
React.useEffect(() => {
const onVisibilityChange = () => setHidden(document.hidden);
document.addEventListener("visibilitychange", onVisibilityChange);
return () => document.removeEventListener("visibilitychange", onVisibilityChange);
}, []);
return hidden;
}
const EMPTY_RECORDS = [];
const EMPTY_MAP = new Map();
function toIdMap(records) {
return new Map(records.map((r) => [r.id, r]));
}
function sameIds(a, b) {
if (a.size !== b.size) return false;
for (const id of a.keys()) if (!b.has(id)) return false;
return true;
}
function useToastExit(live, queued = EMPTY_RECORDS, exitMs = 220) {
const [exiting, setExiting] = React.useState(() => EMPTY_MAP);
const [prevLive, setPrevLive] = React.useState(() => toIdMap(live));
const timersRef = React.useRef(new Map());
const liveIds = new Set(live.map((r) => r.id));
let renderExiting = exiting;
if (!sameIds(prevLive, liveIds)) {
const queuedIds = new Set(queued.map((r) => r.id));
const justRemoved = [];
for (const [id, record] of prevLive) {
if (liveIds.has(id)) continue;
if (queuedIds.has(id)) continue;
justRemoved.push(record);
}
setPrevLive(toIdMap(live));
if (justRemoved.length > 0) {
const next = new Map(exiting);
for (const record of justRemoved) next.set(record.id, record);
renderExiting = next;
setExiting(next);
}
}
React.useEffect(() => {
const reduced = prefersReducedMotion();
for (const [id] of exiting) {
if (timersRef.current.has(id)) continue;
const timer = setTimeout(() => {
timersRef.current.delete(id);
setExiting((prev) => {
if (!prev.has(id)) return prev;
const next = new Map(prev);
next.delete(id);
return next;
});
}, reduced ? 0 : exitMs);
timersRef.current.set(id, timer);
}
for (const [id, timer] of timersRef.current) if (!exiting.has(id)) {
clearTimeout(timer);
timersRef.current.delete(id);
}
}, [exiting, exitMs]);
React.useEffect(() => {
const timers = timersRef.current;
return () => {
for (const timer of timers.values()) clearTimeout(timer);
timers.clear();
};
}, []);
const rows = live.map((record) => ({
record,
exiting: false
}));
for (const [id, record] of renderExiting) if (!liveIds.has(id)) rows.push({
record,
exiting: true
});
return rows;
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/shell-selectors.ts
function splitPosition(position) {
const [y, x] = position.split("-");
return {
y,
x
};
}
function computePossiblePositions(defaultPosition, toasts) {
const seen = new Set([defaultPosition]);
for (const t of toasts) if (t.position) seen.add(t.position);
return [...seen];
}
function computeRowOffsets(newestFirst, heights, gap) {
let cumulativeHeight = 0;
return newestFirst.map((record, index) => {
const stackOffset = index * gap + cumulativeHeight;
cumulativeHeight += heights.get(record.id) ?? 0;
return {
id: record.id,
index,
toastsBefore: index,
stackOffset
};
});
}
function findNewestDismissible(toasts) {
for (let i = toasts.length - 1; i >= 0; i -= 1) {
const t = toasts[i];
if (t && t.dismissible !== false) return t;
}
}
const SWIPE_VELOCITY_THRESHOLD = .11;
function getDefaultSwipeDirections(position) {
const { y, x } = splitPosition(position);
const directions = [y];
if (x === "left" || x === "right") directions.push(x);
return directions;
}
function lockSwipeAxis(dx, dy) {
if (Math.abs(dx) <= 1 && Math.abs(dy) <= 1) return null;
return Math.abs(dx) > Math.abs(dy) ? "x" : "y";
}
function dampenSwipeDelta(delta) {
const dampened = delta * (1 / (1.5 + Math.abs(delta) / 20));
return Math.abs(dampened) < Math.abs(delta) ? dampened : delta;
}
function computeSwipeAxisAmount(axis, delta, directions) {
const negativeDir = axis === "x" ? "left" : "top";
const positiveDir = axis === "x" ? "right" : "bottom";
if (!(directions.includes(negativeDir) || directions.includes(positiveDir))) return 0;
return directions.includes(negativeDir) && delta < 0 || directions.includes(positiveDir) && delta > 0 ? delta : dampenSwipeDelta(delta);
}
function isSwipeReleaseAllowed(axis, amount, directions) {
if (axis === "x") return directions.includes(amount > 0 ? "right" : "left");
return directions.includes(amount > 0 ? "bottom" : "top");
}
function shouldDismissOnSwipeRelease(amount, velocity, thresholdPx = 45, velocityThreshold = SWIPE_VELOCITY_THRESHOLD) {
return Math.abs(amount) >= thresholdPx || velocity > velocityThreshold;
}
function resolveSwipeOutDirection(axis, amount) {
if (axis === "x") return amount > 0 ? "right" : "left";
return amount > 0 ? "down" : "up";
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/use-toast-swipe.ts
const ZERO_AMOUNT = {
x: 0,
y: 0
};
function useToastSwipe(elRef, enabled, directions, onSwipeDismiss) {
const draggingRef = React.useRef(false);
const axisRef = React.useRef(null);
const startRef = React.useRef(ZERO_AMOUNT);
const amountRef = React.useRef(ZERO_AMOUNT);
const dragStartRef = React.useRef(0);
const onSwipeDismissRef = React.useRef(onSwipeDismiss);
onSwipeDismissRef.current = onSwipeDismiss;
const onPointerDown = React.useCallback((event) => {
if (!enabled || event.button !== 0) return;
if (event.target.tagName === "BUTTON") return;
const el = elRef.current;
if (!el) return;
draggingRef.current = true;
axisRef.current = null;
amountRef.current = ZERO_AMOUNT;
startRef.current = {
x: event.clientX,
y: event.clientY
};
dragStartRef.current = Date.now();
el.setPointerCapture(event.pointerId);
el.setAttribute("data-swiping", "true");
}, [enabled, elRef]);
const onPointerMove = React.useCallback((event) => {
if (!draggingRef.current) return;
const el = elRef.current;
if (!el) return;
if ((window.getSelection?.()?.toString().length ?? 0) > 0) return;
const start = startRef.current;
const dx = event.clientX - start.x;
const dy = event.clientY - start.y;
if (axisRef.current === null) axisRef.current = lockSwipeAxis(dx, dy);
const axis = axisRef.current;
if (axis === null) return;
const resolved = computeSwipeAxisAmount(axis, axis === "x" ? dx : dy, directions);
const amount = axis === "x" ? {
x: resolved,
y: 0
} : {
x: 0,
y: resolved
};
amountRef.current = amount;
if (resolved !== 0) el.setAttribute("data-swiped", "true");
el.style.setProperty("--scrollsheet-toast-swipe-x", `${amount.x}px`);
el.style.setProperty("--scrollsheet-toast-swipe-y", `${amount.y}px`);
}, [elRef, directions]);
const release = React.useCallback(() => {
if (!draggingRef.current) return;
draggingRef.current = false;
const el = elRef.current;
const axis = axisRef.current;
axisRef.current = null;
if (!el) return;
if (axis === null) {
el.setAttribute("data-swiping", "false");
return;
}
const amount = axis === "x" ? amountRef.current.x : amountRef.current.y;
const elapsed = Math.max(1, Date.now() - dragStartRef.current);
const velocity = Math.abs(amount) / elapsed;
if (isSwipeReleaseAllowed(axis, amount, directions) && shouldDismissOnSwipeRelease(amount, velocity)) {
const direction = resolveSwipeOutDirection(axis, amount);
el.setAttribute("data-swipe-direction", direction);
if (prefersReducedMotion()) {
el.setAttribute("data-swipe-out", "true");
onSwipeDismissRef.current();
return;
}
const onAnimEnd = () => {
el.removeEventListener("animationend", onAnimEnd);
onSwipeDismissRef.current();
};
el.addEventListener("animationend", onAnimEnd);
el.setAttribute("data-swipe-out", "true");
return;
}
el.setAttribute("data-swiping", "false");
el.setAttribute("data-swiped", "false");
el.style.setProperty("--scrollsheet-toast-swipe-x", "0px");
el.style.setProperty("--scrollsheet-toast-swipe-y", "0px");
}, [elRef, directions]);
return {
onPointerDown,
onPointerMove,
onPointerUp: React.useCallback((event) => {
if (elRef.current?.hasPointerCapture(event.pointerId)) elRef.current.releasePointerCapture(event.pointerId);
release();
}, [elRef, release]),
onPointerCancel: React.useCallback(() => release(), [release])
};
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/toast-row.tsx
function ToastIcon({ type, icons, spinnerClassName }) {
if (type === "loading") {
if (icons?.loading) return jsx(Fragment, { children: icons.loading });
return jsx("span", { className: spinnerClassName });
}
switch (type) {
case "success": return jsx(Fragment, { children: icons?.success ?? "✓" });
case "error": return jsx(Fragment, { children: icons?.error ?? "✕" });
case "warning": return jsx(Fragment, { children: icons?.warning ?? "!" });
case "info": return jsx(Fragment, { children: icons?.info ?? "i" });
default: return null;
}
}
function ToastRow({ record, index, total, toastsBefore, stackOffset, height, frontHeight, visible, expanded, removed, yPosition, xPosition, closeButton, directions, onDismiss, observe, toasterClassNames, icons, toasterCloseButtonAriaLabel }) {
const role = record.type === "error" ? "alert" : "status";
const mounted = useMountedFlag();
const elRef = React.useRef(null);
const dismissible = record.dismissible !== false;
const isFront = index === 0;
const setRefs = React.useCallback((el) => {
elRef.current = el;
observe(record.id, el);
}, [observe, record.id]);
const swipeHandlers = useToastSwipe(elRef, !removed && dismissible && record.type !== "loading", directions, () => onDismiss(record));
React.useEffect(() => {
const el = elRef.current;
if (el) el.inert = removed;
}, [removed]);
const style = {
"--scrollsheet-toast-toasts-before": toastsBefore,
"--scrollsheet-toast-stack-offset": `${stackOffset}px`,
"--scrollsheet-toast-front-height": frontHeight !== void 0 ? `${frontHeight}px` : "0px",
"--scrollsheet-toast-initial-height": height !== void 0 ? `${height}px` : "auto",
zIndex: Math.max(0, total - index)
};
const rootClassName = cn("scrollsheet-toast", "sonner-toast", record.className, toasterClassNames?.toast, record.classNames?.toast, toasterClassNames?.default, toasterClassNames?.[record.type], record.classNames?.[record.type]);
const motionAttrs = {
"data-mounted": mounted ? "" : void 0,
"data-removed": removed ? "" : void 0,
"data-visible": visible ? "true" : "false",
"data-front": isFront ? "true" : "false",
"data-expanded": expanded ? "true" : "false",
"data-y-position": yPosition,
"data-x-position": xPosition,
"data-index": index,
"data-dismissible": dismissible ? "true" : "false",
"data-swiping": "false",
"data-swiped": "false",
"aria-hidden": removed ? "true" : void 0
};
if (record.jsx !== void 0) return jsx("div", {
ref: setRefs,
className: rootClassName,
"data-scrollsheet-toast": "",
"data-sonner-toast": "",
"data-scrollsheet-custom": "",
"data-sonner-custom": "",
"data-testid": record.testId,
role,
style,
...motionAttrs,
...swipeHandlers,
children: record.jsx
});
const showCloseButton = closeButton && dismissible && record.type !== "loading";
const hasActions = Boolean(record.action || record.cancel || showCloseButton);
const closeButtonAriaLabel = record.closeButtonAriaLabel ?? toasterCloseButtonAriaLabel ?? "Close toast";
return jsxs("div", {
ref: setRefs,
className: rootClassName,
"data-scrollsheet-toast": "",
"data-sonner-toast": "",
"data-type": record.type,
"data-testid": record.testId,
role,
style,
...motionAttrs,
...swipeHandlers,
children: [
jsx("span", {
className: cn("scrollsheet-toast-icon", "sonner-toast-icon", toasterClassNames?.icon, record.classNames?.icon),
"data-type": record.type,
"aria-hidden": "true",
children: record.icon ?? jsx(ToastIcon, {
type: record.type,
icons,
spinnerClassName: cn("scrollsheet-toast-spinner", "sonner-toast-spinner", toasterClassNames?.loader, record.classNames?.loader)
})
}),
jsxs("div", {
className: cn("scrollsheet-toast-body", "sonner-toast-body", toasterClassNames?.content, record.classNames?.content),
children: [record.title !== void 0 && jsx("div", {
className: cn("scrollsheet-toast-title", "sonner-toast-title", toasterClassNames?.title, record.classNames?.title),
children: record.title
}), record.description !== void 0 && jsx("div", {
className: cn("scrollsheet-toast-description", "sonner-toast-description", toasterClassNames?.description, record.classNames?.description),
children: record.description
})]
}),
hasActions && jsxs("div", {
className: "scrollsheet-toast-actions sonner-toast-actions",
children: [
record.cancel && jsx("button", {
type: "button",
className: cn("scrollsheet-toast-cancel", "sonner-toast-cancel", toasterClassNames?.cancelButton, record.classNames?.cancelButton),
onClick: (event) => {
if (!dismissible) return;
record.cancel?.onClick(event);
onDismiss(record);
},
children: record.cancel.label
}),
record.action && jsx("button", {
type: "button",
className: cn("scrollsheet-toast-action", "sonner-toast-action", toasterClassNames?.actionButton, record.classNames?.actionButton),
onClick: (event) => {
record.action?.onClick(event);
if (event.defaultPrevented) return;
onDismiss(record);
},
children: record.action.label
}),
showCloseButton && jsx("button", {
type: "button",
className: cn("scrollsheet-toast-close", "sonner-toast-close", toasterClassNames?.closeButton, record.classNames?.closeButton),
"aria-label": closeButtonAriaLabel,
onClick: () => onDismiss(record),
children: icons?.close ?? "×"
})
]
})
]
});
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/use-toast-heights.ts
function useToastHeights() {
const [heights, setHeights] = React.useState(() => new Map());
const observersRef = React.useRef(new Map());
const setHeight = React.useCallback((id, height) => {
setHeights((prev) => prev.get(id) === height ? prev : new Map(prev).set(id, height));
}, []);
const forget = React.useCallback((id) => {
observersRef.current.get(id)?.disconnect();
observersRef.current.delete(id);
setHeights((prev) => {
if (!prev.has(id)) return prev;
const next = new Map(prev);
next.delete(id);
return next;
});
}, []);
const observe = React.useCallback((id, el) => {
const observers = observersRef.current;
observers.get(id)?.disconnect();
observers.delete(id);
if (!el || typeof ResizeObserver === "undefined") return;
const ro = new ResizeObserver(() => setHeight(id, el.getBoundingClientRect().height));
ro.observe(el);
observers.set(id, ro);
setHeight(id, el.getBoundingClientRect().height);
}, [setHeight]);
React.useEffect(() => {
const observers = observersRef.current;
return () => {
for (const ro of observers.values()) ro.disconnect();
observers.clear();
};
}, []);
return {
heights,
observe,
forget
};
}
//#endregion
//#region packages/scrollsheet/src/toast/shell/toaster-shell.tsx
const DEFAULT_HOTKEY = ["altKey", "KeyT"];
function PositionGroup({ position, defaultPosition, toasts, visibleToasts, gap, expanded, closeButton, swipeDirections, toastOptions, icons, className, baseStyle, registerListEl, dismissRow, onHoverEnter, onHoverLeave, onInteractingChange }) {
const directions = React.useMemo(() => swipeDirections ?? getDefaultSwipeDirections(position), [swipeDirections, position]);
const positionToasts = React.useMemo(() => selectPositionToasts(toasts, position, defaultPosition), [
toasts,
position,
defaultPosition
]);
const newestFirst = React.useMemo(() => [...positionToasts].reverse(), [positionToasts]);
const window_ = React.useMemo(() => selectToastWindow(positionToasts, visibleToasts), [positionToasts, visibleToasts]);
const visibleIds = React.useMemo(() => new Set(window_.visible.map((t) => t.id)), [window_]);
const { heights, observe, forget } = useToastHeights();
const exitRows = useToastExit(newestFirst);
const exitingIds = React.useMemo(() => new Set(exitRows.filter((r) => r.exiting).map((r) => r.record.id)), [exitRows]);
React.useEffect(() => {
for (const id of exitingIds) forget(id);
}, [exitingIds, forget]);
const offsets = React.useMemo(() => computeRowOffsets(newestFirst, heights, gap), [
newestFirst,
heights,
gap
]);
const offsetById = React.useMemo(() => new Map(offsets.map((o) => [o.id, o])), [offsets]);
const lastOffsetRef = React.useRef(new Map());
for (const o of offsets) lastOffsetRef.current.set(o.id, o);
if (lastOffsetRef.current.size > offsets.length) {
const keep = new Set([...offsets.map((o) => o.id), ...exitingIds]);
for (const id of [...lastOffsetRef.current.keys()]) if (!keep.has(id)) lastOffsetRef.current.delete(id);
}
const frontHeight = heights.get(newestFirst[0]?.id ?? "");
const { y, x } = splitPosition(position);
const listRef = React.useCallback((el) => registerListEl(position, el), [registerListEl, position]);
if (exitRows.length === 0) return null;
return jsx("ol", {
ref: listRef,
"data-scrollsheet-toaster": "",
"data-sonner-toaster": "",
"data-scrollsheet-theme": "light",
"data-sonner-theme": "light",
"data-y-position": y,
"data-x-position": x,
tabIndex: -1,
className,
style: {
...baseStyle,
"--scrollsheet-toast-gap": `${gap}px`,
"--scrollsheet-toast-front-height": frontHeight !== void 0 ? `${frontHeight}px` : void 0
},
onMouseEnter: onHoverEnter,
onMouseMove: onHoverEnter,
onMouseLeave: onHoverLeave,
onPointerDown: (event) => {
if (event.target.dataset.dismissible === "false") return;
onInteractingChange(true);
},
onPointerUp: () => onInteractingChange(false),
children: exitRows.map(({ record, exiting }) => {
const offset = offsetById.get(record.id) ?? lastOffsetRef.current.get(record.id);
const index = offset?.index ?? newestFirst.length;
return jsx(ToastRow, {
record,
index,
total: newestFirst.length,
toastsBefore: offset?.toastsBefore ?? index,
stackOffset: offset?.stackOffset ?? 0,
height: heights.get(record.id),
frontHeight,
visible: visibleIds.has(record.id),
expanded,
removed: exiting,
yPosition: y,
xPosition: x,
closeButton,
directions,
onDismiss: dismissRow,
observe,
toasterClassNames: toastOptions?.classNames,
icons,
toasterCloseButtonAriaLabel: toastOptions?.closeButtonAriaLabel
}, record.id);
})
});
}
function resolveShellPosition(position) {
return position ?? "bottom-right";
}
function ToasterShell({ id, toasterId, position, theme, richColors, expand: forceExpand, visibleToasts: visibleToastsProp, closeButton = false, duration: durationProp, gap = 14, offset, swipeDirections, toastOptions, icons, className, style, containerAriaLabel = "Notifications", hotkey = DEFAULT_HOTKEY, nonce }) {
const resolvedId = id ?? toasterId;
if (toasterId !== void 0) warnOnce("toaster-id-deprecated", "[scrollsheet Toaster] Toaster's \"toasterId\" prop is deprecated — use \"id\" instead.");
const { toasts: allToasts } = useSonner();
const toasts = React.useMemo(() => selectToasterToasts(allToasts, resolvedId), [allToasts, resolvedId]);
const defaultPosition = resolveShellPosition(position);
const possiblePositions = React.useMemo(() => computePossiblePositions(defaultPosition, toasts), [defaultPosition, toasts]);
const visibleToasts = resolveVisibleToasts(visibleToastsProp);
const defaultDuration = durationProp ?? toastOptions?.duration ?? 4e3;
if (theme !== void 0 && theme !== "light") warnOnce("shell-theme", `[scrollsheet Toaster] theme="${theme}" isn't implemented yet — v1 always renders the static light card real Sonner ships by default.`);
if (richColors) warnOnce("shell-rich-colors", "[scrollsheet Toaster] richColors isn't implemented yet — toasts render with their default icon color only.");
React.useEffect(() => {
injectToastStyles(nonce);
}, [nonce]);
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => setMounted(true), []);
const [hovered, setHovered] = React.useState(false);
const [hotkeyExpanded, setHotkeyExpanded] = React.useState(false);
const [interacting, setInteracting] = React.useState(false);
const expanded = Boolean(forceExpand) || hovered || hotkeyExpanded;
const isDocumentHidden = useIsDocumentHidden();
const handleHoverEnter = React.useCallback(() => setHovered(true), []);
const handleHoverLeave = React.useCallback(() => {
if (!interacting) setHovered(false);
}, [interacting]);
const dismissRow = React.useCallback((record) => {
toast.dismiss(record.id);
}, []);
const listElsRef = React.useRef(new Map());
const registerListEl = React.useCallback((pos, el) => {
if (el) listElsRef.current.set(pos, el);
else listElsRef.current.delete(pos);
}, []);
React.useEffect(() => {
if (hotkey.length === 0) return;
const handleKeyDown = (event) => {
if (hotkey.every((key) => event[key] || event.code === key)) {
setHotkeyExpanded(true);
const [firstList] = listElsRef.current.values();
firstList?.focus({ preventScroll: true });
}
if (event.code !== "Escape") return;
const active = document.activeElement;
const focusedEntry = [...listElsRef.current.entries()].find(([, el]) => active === el || el.contains(active));
if (!focusedEntry) return;
if (hotkeyExpanded) {
setHotkeyExpanded(false);
return;
}
const [focusedPosition] = focusedEntry;
const positionToasts = selectPositionToasts(toasts, focusedPosition, defaultPosition);
const front = positionToasts[positionToasts.length - 1];
if (front) dismissRow(front);
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [
hotkey,
hotkeyExpanded,
toasts,
defaultPosition,
dismissRow
]);
const timersRef = React.useRef(new Map());
React.useEffect(() => {
const timers = timersRef.current;
const liveIds = new Set(toasts.map((t) => t.id));
for (const [id, entry] of timers) {
if (liveIds.has(id)) continue;
if (entry.timer) clearTimeout(entry.timer);
timers.delete(id);
}
const paused = expanded || interacting || isDocumentHidden;
for (const t of toasts) {
if (t.type === "loading") {
const stale = timers.get(t.id);
if (stale) {
if (stale.timer) clearTimeout(stale.timer);
timers.delete(t.id);
}
continue;
}
const ms = t.duration ?? toastOptions?.duration ?? defaultDuration;
const existing = timers.get(t.id);
if (!existing || existing.record !== t) {
if (existing?.timer) clearTimeout(existing.timer);
const entry = {
timer: null,
startedAt: 0,
remaining: ms,
record: t
};
timers.set(t.id, entry);
if (Number.isFinite(ms) && !paused) {
entry.startedAt = Date.now();
entry.timer = setTimeout(() => {
timersRef.current.delete(t.id);
expire(t.id);
}, ms);
}
continue;
}
if (paused) {
if (existing.timer) {
clearTimeout(existing.timer);
const elapsed = Date.now() - existing.startedAt;
existing.remaining = Math.max(0, existing.remaining - elapsed);
existing.timer = null;
}
continue;
}
if (existing.timer || !Number.isFinite(existing.remaining)) continue;
existing.startedAt = Date.now();
existing.timer = setTimeout(() => {
timersRef.current.delete(t.id);
expire(t.id);
}, existing.remaining);
}
}, [
toasts,
expanded,
interacting,
isDocumentHidden,
defaultDuration,
toastOptions?.duration
]);
React.useEffect(() => {
const timers = timersRef.current;
return () => {
for (const entry of timers.values()) if (entry.timer) clearTimeout(entry.timer);
timers.clear();
};
}, []);
useCloseWatcher({
present: toasts.length > 0,
nonModal: true,
escapeDismissible: true,
onClose: () => {
const target = findNewestDismissible(toasts);
if (target) dismissRow(target);
}
});
if (!mounted || typeof document === "undefined") return null;
const offsetValue = offset !== void 0 ? typeof offset === "number" ? `${offset}px` : offset : void 0;
const baseStyle = {
...style,
"--scrollsheet-toast-offset": offsetValue
};
return createPortal(jsx("section", {
"aria-label": containerAriaLabel,
tabIndex: -1,
"aria-live": "polite",
"aria-relevant": "additions text",
"aria-atomic": "false",
suppressHydrationWarning: true,
"data-react-aria-top-layer": "",
children: possiblePositions.map((groupPosition) => jsx(PositionGroup, {
position: groupPosition,
defaultPosition,
toasts,
visibleToasts,
gap,
expanded,
closeButton,
swipeDirections,
toastOptions,
icons,
className,
baseStyle,
registerListEl,
dismissRow,
onHoverEnter: handleHoverEnter,
onHoverLeave: handleHoverLeave,
onInteractingChange: setInteracting
}, groupPosition))
}), document.body);
}
//#endregion
export { useSonner as a, toast as i, resolveVisibleToasts as n, useToasts as o, injectToastStylesInto as r, ToasterShell as t };

Sorry, the diff of this file is too big to display