@radix-ui/react-toast
Advanced tools
Comparing version 1.2.0-rc.2 to 1.2.0-rc.3
1310
dist/index.js
"use strict"; | ||
"use client"; | ||
(() => { | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { | ||
get: (a, b) => (typeof require !== "undefined" ? require : a)[b] | ||
}) : x)(function(x) { | ||
if (typeof require !== "undefined") return require.apply(this, arguments); | ||
throw Error('Dynamic require of "' + x + '" is not supported'); | ||
}); | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
// packages/react/toast/src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
Action: () => Action, | ||
Close: () => Close, | ||
Description: () => Description, | ||
Provider: () => Provider, | ||
Root: () => Root2, | ||
Title: () => Title, | ||
Toast: () => Toast, | ||
ToastAction: () => ToastAction, | ||
ToastClose: () => ToastClose, | ||
ToastDescription: () => ToastDescription, | ||
ToastProvider: () => ToastProvider, | ||
ToastTitle: () => ToastTitle, | ||
ToastViewport: () => ToastViewport, | ||
Viewport: () => Viewport, | ||
createToastScope: () => createToastScope | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// packages/react/toast/src/Toast.tsx | ||
var React = __toESM(require("react")); | ||
var ReactDOM = __toESM(require("react-dom")); | ||
var import_primitive = require("@radix-ui/primitive"); | ||
var import_react_compose_refs = require("@radix-ui/react-compose-refs"); | ||
var import_react_collection = require("@radix-ui/react-collection"); | ||
var import_react_context = require("@radix-ui/react-context"); | ||
var DismissableLayer = __toESM(require("@radix-ui/react-dismissable-layer")); | ||
var import_react_portal = require("@radix-ui/react-portal"); | ||
var import_react_presence = require("@radix-ui/react-presence"); | ||
var import_react_primitive = require("@radix-ui/react-primitive"); | ||
var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref"); | ||
var import_react_use_controllable_state = require("@radix-ui/react-use-controllable-state"); | ||
var import_react_use_layout_effect = require("@radix-ui/react-use-layout-effect"); | ||
var import_react_visually_hidden = require("@radix-ui/react-visually-hidden"); | ||
var import_jsx_runtime = require("react/jsx-runtime"); | ||
var PROVIDER_NAME = "ToastProvider"; | ||
var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)("Toast"); | ||
var [createToastContext, createToastScope] = (0, import_react_context.createContextScope)("Toast", [createCollectionScope]); | ||
var [ToastProviderProvider, useToastProviderContext] = createToastContext(PROVIDER_NAME); | ||
var ToastProvider = (props) => { | ||
const { | ||
__scopeToast, | ||
label = "Notification", | ||
duration = 5e3, | ||
swipeDirection = "right", | ||
swipeThreshold = 50, | ||
children | ||
} = props; | ||
const [viewport, setViewport] = React.useState(null); | ||
const [toastCount, setToastCount] = React.useState(0); | ||
const isFocusedToastEscapeKeyDownRef = React.useRef(false); | ||
const isClosePausedRef = React.useRef(false); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope: __scopeToast, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
ToastProviderProvider, | ||
{ | ||
scope: __scopeToast, | ||
label, | ||
duration, | ||
swipeDirection, | ||
swipeThreshold, | ||
toastCount, | ||
viewport, | ||
onViewportChange: setViewport, | ||
onToastAdd: React.useCallback(() => setToastCount((prevCount) => prevCount + 1), []), | ||
onToastRemove: React.useCallback(() => setToastCount((prevCount) => prevCount - 1), []), | ||
isFocusedToastEscapeKeyDownRef, | ||
isClosePausedRef, | ||
children | ||
} | ||
return to; | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
// packages/react/toast/src/Toast.tsx | ||
var React = __toESM(__require("react")); | ||
var ReactDOM = __toESM(__require("react-dom")); | ||
var import_primitive = __require("@radix-ui/primitive"); | ||
var import_react_compose_refs = __require("@radix-ui/react-compose-refs"); | ||
var import_react_collection = __require("@radix-ui/react-collection"); | ||
var import_react_context = __require("@radix-ui/react-context"); | ||
var DismissableLayer = __toESM(__require("@radix-ui/react-dismissable-layer")); | ||
var import_react_portal = __require("@radix-ui/react-portal"); | ||
var import_react_presence = __require("@radix-ui/react-presence"); | ||
var import_react_primitive = __require("@radix-ui/react-primitive"); | ||
var import_react_use_callback_ref = __require("@radix-ui/react-use-callback-ref"); | ||
var import_react_use_controllable_state = __require("@radix-ui/react-use-controllable-state"); | ||
var import_react_use_layout_effect = __require("@radix-ui/react-use-layout-effect"); | ||
var import_react_visually_hidden = __require("@radix-ui/react-visually-hidden"); | ||
var import_jsx_runtime = __require("react/jsx-runtime"); | ||
var PROVIDER_NAME = "ToastProvider"; | ||
var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)("Toast"); | ||
var [createToastContext, createToastScope] = (0, import_react_context.createContextScope)("Toast", [createCollectionScope]); | ||
var [ToastProviderProvider, useToastProviderContext] = createToastContext(PROVIDER_NAME); | ||
var ToastProvider = (props) => { | ||
) }); | ||
}; | ||
ToastProvider.propTypes = { | ||
label(props) { | ||
if (props.label && typeof props.label === "string" && !props.label.trim()) { | ||
const error = `Invalid prop \`label\` supplied to \`${PROVIDER_NAME}\`. Expected non-empty \`string\`.`; | ||
return new Error(error); | ||
} | ||
return null; | ||
} | ||
}; | ||
ToastProvider.displayName = PROVIDER_NAME; | ||
var VIEWPORT_NAME = "ToastViewport"; | ||
var VIEWPORT_DEFAULT_HOTKEY = ["F8"]; | ||
var VIEWPORT_PAUSE = "toast.viewportPause"; | ||
var VIEWPORT_RESUME = "toast.viewportResume"; | ||
var ToastViewport = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
__scopeToast, | ||
label = "Notification", | ||
duration = 5e3, | ||
swipeDirection = "right", | ||
swipeThreshold = 50, | ||
children | ||
hotkey = VIEWPORT_DEFAULT_HOTKEY, | ||
label = "Notifications ({hotkey})", | ||
...viewportProps | ||
} = props; | ||
const [viewport, setViewport] = React.useState(null); | ||
const [toastCount, setToastCount] = React.useState(0); | ||
const isFocusedToastEscapeKeyDownRef = React.useRef(false); | ||
const isClosePausedRef = React.useRef(false); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope: __scopeToast, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
ToastProviderProvider, | ||
{ | ||
scope: __scopeToast, | ||
label, | ||
duration, | ||
swipeDirection, | ||
swipeThreshold, | ||
toastCount, | ||
viewport, | ||
onViewportChange: setViewport, | ||
onToastAdd: React.useCallback(() => setToastCount((prevCount) => prevCount + 1), []), | ||
onToastRemove: React.useCallback(() => setToastCount((prevCount) => prevCount - 1), []), | ||
isFocusedToastEscapeKeyDownRef, | ||
isClosePausedRef, | ||
children | ||
const context = useToastProviderContext(VIEWPORT_NAME, __scopeToast); | ||
const getItems = useCollection(__scopeToast); | ||
const wrapperRef = React.useRef(null); | ||
const headFocusProxyRef = React.useRef(null); | ||
const tailFocusProxyRef = React.useRef(null); | ||
const ref = React.useRef(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref, context.onViewportChange); | ||
const hotkeyLabel = hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, ""); | ||
const hasToasts = context.toastCount > 0; | ||
React.useEffect(() => { | ||
const handleKeyDown = (event) => { | ||
const isHotkeyPressed = hotkey.every((key) => event[key] || event.code === key); | ||
if (isHotkeyPressed) ref.current?.focus(); | ||
}; | ||
document.addEventListener("keydown", handleKeyDown); | ||
return () => document.removeEventListener("keydown", handleKeyDown); | ||
}, [hotkey]); | ||
React.useEffect(() => { | ||
const wrapper = wrapperRef.current; | ||
const viewport = ref.current; | ||
if (hasToasts && wrapper && viewport) { | ||
const handlePause = () => { | ||
if (!context.isClosePausedRef.current) { | ||
const pauseEvent = new CustomEvent(VIEWPORT_PAUSE); | ||
viewport.dispatchEvent(pauseEvent); | ||
context.isClosePausedRef.current = true; | ||
} | ||
}; | ||
const handleResume = () => { | ||
if (context.isClosePausedRef.current) { | ||
const resumeEvent = new CustomEvent(VIEWPORT_RESUME); | ||
viewport.dispatchEvent(resumeEvent); | ||
context.isClosePausedRef.current = false; | ||
} | ||
}; | ||
const handleFocusOutResume = (event) => { | ||
const isFocusMovingOutside = !wrapper.contains(event.relatedTarget); | ||
if (isFocusMovingOutside) handleResume(); | ||
}; | ||
const handlePointerLeaveResume = () => { | ||
const isFocusInside = wrapper.contains(document.activeElement); | ||
if (!isFocusInside) handleResume(); | ||
}; | ||
wrapper.addEventListener("focusin", handlePause); | ||
wrapper.addEventListener("focusout", handleFocusOutResume); | ||
wrapper.addEventListener("pointermove", handlePause); | ||
wrapper.addEventListener("pointerleave", handlePointerLeaveResume); | ||
window.addEventListener("blur", handlePause); | ||
window.addEventListener("focus", handleResume); | ||
return () => { | ||
wrapper.removeEventListener("focusin", handlePause); | ||
wrapper.removeEventListener("focusout", handleFocusOutResume); | ||
wrapper.removeEventListener("pointermove", handlePause); | ||
wrapper.removeEventListener("pointerleave", handlePointerLeaveResume); | ||
window.removeEventListener("blur", handlePause); | ||
window.removeEventListener("focus", handleResume); | ||
}; | ||
} | ||
) }); | ||
}; | ||
ToastProvider.propTypes = { | ||
label(props) { | ||
if (props.label && typeof props.label === "string" && !props.label.trim()) { | ||
const error = `Invalid prop \`label\` supplied to \`${PROVIDER_NAME}\`. Expected non-empty \`string\`.`; | ||
return new Error(error); | ||
} | ||
return null; | ||
} | ||
}; | ||
ToastProvider.displayName = PROVIDER_NAME; | ||
var VIEWPORT_NAME = "ToastViewport"; | ||
var VIEWPORT_DEFAULT_HOTKEY = ["F8"]; | ||
var VIEWPORT_PAUSE = "toast.viewportPause"; | ||
var VIEWPORT_RESUME = "toast.viewportResume"; | ||
var ToastViewport = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
__scopeToast, | ||
hotkey = VIEWPORT_DEFAULT_HOTKEY, | ||
label = "Notifications ({hotkey})", | ||
...viewportProps | ||
} = props; | ||
const context = useToastProviderContext(VIEWPORT_NAME, __scopeToast); | ||
const getItems = useCollection(__scopeToast); | ||
const wrapperRef = React.useRef(null); | ||
const headFocusProxyRef = React.useRef(null); | ||
const tailFocusProxyRef = React.useRef(null); | ||
const ref = React.useRef(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref, context.onViewportChange); | ||
const hotkeyLabel = hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, ""); | ||
const hasToasts = context.toastCount > 0; | ||
React.useEffect(() => { | ||
}, [hasToasts, context.isClosePausedRef]); | ||
const getSortedTabbableCandidates = React.useCallback( | ||
({ tabbingDirection }) => { | ||
const toastItems = getItems(); | ||
const tabbableCandidates = toastItems.map((toastItem) => { | ||
const toastNode = toastItem.ref.current; | ||
const toastTabbableCandidates = [toastNode, ...getTabbableCandidates(toastNode)]; | ||
return tabbingDirection === "forwards" ? toastTabbableCandidates : toastTabbableCandidates.reverse(); | ||
}); | ||
return (tabbingDirection === "forwards" ? tabbableCandidates.reverse() : tabbableCandidates).flat(); | ||
}, | ||
[getItems] | ||
); | ||
React.useEffect(() => { | ||
const viewport = ref.current; | ||
if (viewport) { | ||
const handleKeyDown = (event) => { | ||
const isHotkeyPressed = hotkey.every((key) => event[key] || event.code === key); | ||
if (isHotkeyPressed) ref.current?.focus(); | ||
}; | ||
document.addEventListener("keydown", handleKeyDown); | ||
return () => document.removeEventListener("keydown", handleKeyDown); | ||
}, [hotkey]); | ||
React.useEffect(() => { | ||
const wrapper = wrapperRef.current; | ||
const viewport = ref.current; | ||
if (hasToasts && wrapper && viewport) { | ||
const handlePause = () => { | ||
if (!context.isClosePausedRef.current) { | ||
const pauseEvent = new CustomEvent(VIEWPORT_PAUSE); | ||
viewport.dispatchEvent(pauseEvent); | ||
context.isClosePausedRef.current = true; | ||
const isMetaKey = event.altKey || event.ctrlKey || event.metaKey; | ||
const isTabKey = event.key === "Tab" && !isMetaKey; | ||
if (isTabKey) { | ||
const focusedElement = document.activeElement; | ||
const isTabbingBackwards = event.shiftKey; | ||
const targetIsViewport = event.target === viewport; | ||
if (targetIsViewport && isTabbingBackwards) { | ||
headFocusProxyRef.current?.focus(); | ||
return; | ||
} | ||
}; | ||
const handleResume = () => { | ||
if (context.isClosePausedRef.current) { | ||
const resumeEvent = new CustomEvent(VIEWPORT_RESUME); | ||
viewport.dispatchEvent(resumeEvent); | ||
context.isClosePausedRef.current = false; | ||
const tabbingDirection = isTabbingBackwards ? "backwards" : "forwards"; | ||
const sortedCandidates = getSortedTabbableCandidates({ tabbingDirection }); | ||
const index = sortedCandidates.findIndex((candidate) => candidate === focusedElement); | ||
if (focusFirst(sortedCandidates.slice(index + 1))) { | ||
event.preventDefault(); | ||
} else { | ||
isTabbingBackwards ? headFocusProxyRef.current?.focus() : tailFocusProxyRef.current?.focus(); | ||
} | ||
}; | ||
const handleFocusOutResume = (event) => { | ||
const isFocusMovingOutside = !wrapper.contains(event.relatedTarget); | ||
if (isFocusMovingOutside) handleResume(); | ||
}; | ||
const handlePointerLeaveResume = () => { | ||
const isFocusInside = wrapper.contains(document.activeElement); | ||
if (!isFocusInside) handleResume(); | ||
}; | ||
wrapper.addEventListener("focusin", handlePause); | ||
wrapper.addEventListener("focusout", handleFocusOutResume); | ||
wrapper.addEventListener("pointermove", handlePause); | ||
wrapper.addEventListener("pointerleave", handlePointerLeaveResume); | ||
window.addEventListener("blur", handlePause); | ||
window.addEventListener("focus", handleResume); | ||
return () => { | ||
wrapper.removeEventListener("focusin", handlePause); | ||
wrapper.removeEventListener("focusout", handleFocusOutResume); | ||
wrapper.removeEventListener("pointermove", handlePause); | ||
wrapper.removeEventListener("pointerleave", handlePointerLeaveResume); | ||
window.removeEventListener("blur", handlePause); | ||
window.removeEventListener("focus", handleResume); | ||
}; | ||
} | ||
}, [hasToasts, context.isClosePausedRef]); | ||
const getSortedTabbableCandidates = React.useCallback( | ||
({ tabbingDirection }) => { | ||
const toastItems = getItems(); | ||
const tabbableCandidates = toastItems.map((toastItem) => { | ||
const toastNode = toastItem.ref.current; | ||
const toastTabbableCandidates = [toastNode, ...getTabbableCandidates(toastNode)]; | ||
return tabbingDirection === "forwards" ? toastTabbableCandidates : toastTabbableCandidates.reverse(); | ||
}); | ||
return (tabbingDirection === "forwards" ? tabbableCandidates.reverse() : tabbableCandidates).flat(); | ||
}, | ||
[getItems] | ||
); | ||
React.useEffect(() => { | ||
const viewport = ref.current; | ||
if (viewport) { | ||
const handleKeyDown = (event) => { | ||
const isMetaKey = event.altKey || event.ctrlKey || event.metaKey; | ||
const isTabKey = event.key === "Tab" && !isMetaKey; | ||
if (isTabKey) { | ||
const focusedElement = document.activeElement; | ||
const isTabbingBackwards = event.shiftKey; | ||
const targetIsViewport = event.target === viewport; | ||
if (targetIsViewport && isTabbingBackwards) { | ||
headFocusProxyRef.current?.focus(); | ||
return; | ||
} | ||
}; | ||
viewport.addEventListener("keydown", handleKeyDown); | ||
return () => viewport.removeEventListener("keydown", handleKeyDown); | ||
} | ||
}, [getItems, getSortedTabbableCandidates]); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( | ||
DismissableLayer.Branch, | ||
{ | ||
ref: wrapperRef, | ||
role: "region", | ||
"aria-label": label.replace("{hotkey}", hotkeyLabel), | ||
tabIndex: -1, | ||
style: { pointerEvents: hasToasts ? void 0 : "none" }, | ||
children: [ | ||
hasToasts && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
FocusProxy, | ||
{ | ||
ref: headFocusProxyRef, | ||
onFocusFromOutsideViewport: () => { | ||
const tabbableCandidates = getSortedTabbableCandidates({ | ||
tabbingDirection: "forwards" | ||
}); | ||
focusFirst(tabbableCandidates); | ||
} | ||
const tabbingDirection = isTabbingBackwards ? "backwards" : "forwards"; | ||
const sortedCandidates = getSortedTabbableCandidates({ tabbingDirection }); | ||
const index = sortedCandidates.findIndex((candidate) => candidate === focusedElement); | ||
if (focusFirst(sortedCandidates.slice(index + 1))) { | ||
event.preventDefault(); | ||
} else { | ||
isTabbingBackwards ? headFocusProxyRef.current?.focus() : tailFocusProxyRef.current?.focus(); | ||
} | ||
), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: __scopeToast, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.ol, { tabIndex: -1, ...viewportProps, ref: composedRefs }) }), | ||
hasToasts && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
FocusProxy, | ||
{ | ||
ref: tailFocusProxyRef, | ||
onFocusFromOutsideViewport: () => { | ||
const tabbableCandidates = getSortedTabbableCandidates({ | ||
tabbingDirection: "backwards" | ||
}); | ||
focusFirst(tabbableCandidates); | ||
} | ||
} | ||
}; | ||
viewport.addEventListener("keydown", handleKeyDown); | ||
return () => viewport.removeEventListener("keydown", handleKeyDown); | ||
) | ||
] | ||
} | ||
); | ||
} | ||
); | ||
ToastViewport.displayName = VIEWPORT_NAME; | ||
var FOCUS_PROXY_NAME = "ToastFocusProxy"; | ||
var FocusProxy = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, onFocusFromOutsideViewport, ...proxyProps } = props; | ||
const context = useToastProviderContext(FOCUS_PROXY_NAME, __scopeToast); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_visually_hidden.VisuallyHidden, | ||
{ | ||
"aria-hidden": true, | ||
tabIndex: 0, | ||
...proxyProps, | ||
ref: forwardedRef, | ||
style: { position: "fixed" }, | ||
onFocus: (event) => { | ||
const prevFocusedElement = event.relatedTarget; | ||
const isFocusFromOutsideViewport = !context.viewport?.contains(prevFocusedElement); | ||
if (isFocusFromOutsideViewport) onFocusFromOutsideViewport(); | ||
} | ||
}, [getItems, getSortedTabbableCandidates]); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( | ||
DismissableLayer.Branch, | ||
{ | ||
ref: wrapperRef, | ||
role: "region", | ||
"aria-label": label.replace("{hotkey}", hotkeyLabel), | ||
tabIndex: -1, | ||
style: { pointerEvents: hasToasts ? void 0 : "none" }, | ||
children: [ | ||
hasToasts && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
FocusProxy, | ||
{ | ||
ref: headFocusProxyRef, | ||
onFocusFromOutsideViewport: () => { | ||
const tabbableCandidates = getSortedTabbableCandidates({ | ||
tabbingDirection: "forwards" | ||
}); | ||
focusFirst(tabbableCandidates); | ||
} | ||
} | ||
), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: __scopeToast, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.ol, { tabIndex: -1, ...viewportProps, ref: composedRefs }) }), | ||
hasToasts && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
FocusProxy, | ||
{ | ||
ref: tailFocusProxyRef, | ||
onFocusFromOutsideViewport: () => { | ||
const tabbableCandidates = getSortedTabbableCandidates({ | ||
tabbingDirection: "backwards" | ||
}); | ||
focusFirst(tabbableCandidates); | ||
} | ||
} | ||
) | ||
] | ||
} | ||
); | ||
} | ||
); | ||
ToastViewport.displayName = VIEWPORT_NAME; | ||
var FOCUS_PROXY_NAME = "ToastFocusProxy"; | ||
var FocusProxy = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, onFocusFromOutsideViewport, ...proxyProps } = props; | ||
const context = useToastProviderContext(FOCUS_PROXY_NAME, __scopeToast); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_visually_hidden.VisuallyHidden, | ||
{ | ||
"aria-hidden": true, | ||
tabIndex: 0, | ||
...proxyProps, | ||
ref: forwardedRef, | ||
style: { position: "fixed" }, | ||
onFocus: (event) => { | ||
const prevFocusedElement = event.relatedTarget; | ||
const isFocusFromOutsideViewport = !context.viewport?.contains(prevFocusedElement); | ||
if (isFocusFromOutsideViewport) onFocusFromOutsideViewport(); | ||
} | ||
} | ||
); | ||
} | ||
); | ||
FocusProxy.displayName = FOCUS_PROXY_NAME; | ||
var TOAST_NAME = "Toast"; | ||
var TOAST_SWIPE_START = "toast.swipeStart"; | ||
var TOAST_SWIPE_MOVE = "toast.swipeMove"; | ||
var TOAST_SWIPE_CANCEL = "toast.swipeCancel"; | ||
var TOAST_SWIPE_END = "toast.swipeEnd"; | ||
var Toast = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { forceMount, open: openProp, defaultOpen, onOpenChange, ...toastProps } = props; | ||
const [open = true, setOpen] = (0, import_react_use_controllable_state.useControllableState)({ | ||
prop: openProp, | ||
defaultProp: defaultOpen, | ||
onChange: onOpenChange | ||
}); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
ToastImpl, | ||
{ | ||
open, | ||
...toastProps, | ||
ref: forwardedRef, | ||
onClose: () => setOpen(false), | ||
onPause: (0, import_react_use_callback_ref.useCallbackRef)(props.onPause), | ||
onResume: (0, import_react_use_callback_ref.useCallbackRef)(props.onResume), | ||
onSwipeStart: (0, import_primitive.composeEventHandlers)(props.onSwipeStart, (event) => { | ||
event.currentTarget.setAttribute("data-swipe", "start"); | ||
}), | ||
onSwipeMove: (0, import_primitive.composeEventHandlers)(props.onSwipeMove, (event) => { | ||
const { x, y } = event.detail.delta; | ||
event.currentTarget.setAttribute("data-swipe", "move"); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-move-x", `${x}px`); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-move-y", `${y}px`); | ||
}), | ||
onSwipeCancel: (0, import_primitive.composeEventHandlers)(props.onSwipeCancel, (event) => { | ||
event.currentTarget.setAttribute("data-swipe", "cancel"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-x"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-y"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-end-x"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-end-y"); | ||
}), | ||
onSwipeEnd: (0, import_primitive.composeEventHandlers)(props.onSwipeEnd, (event) => { | ||
const { x, y } = event.detail.delta; | ||
event.currentTarget.setAttribute("data-swipe", "end"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-x"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-y"); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-end-x", `${x}px`); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-end-y", `${y}px`); | ||
setOpen(false); | ||
}) | ||
} | ||
) }); | ||
} | ||
); | ||
Toast.displayName = TOAST_NAME; | ||
var [ToastInteractiveProvider, useToastInteractiveContext] = createToastContext(TOAST_NAME, { | ||
onClose() { | ||
} | ||
}); | ||
var ToastImpl = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
__scopeToast, | ||
type = "foreground", | ||
duration: durationProp, | ||
} | ||
); | ||
} | ||
); | ||
FocusProxy.displayName = FOCUS_PROXY_NAME; | ||
var TOAST_NAME = "Toast"; | ||
var TOAST_SWIPE_START = "toast.swipeStart"; | ||
var TOAST_SWIPE_MOVE = "toast.swipeMove"; | ||
var TOAST_SWIPE_CANCEL = "toast.swipeCancel"; | ||
var TOAST_SWIPE_END = "toast.swipeEnd"; | ||
var Toast = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { forceMount, open: openProp, defaultOpen, onOpenChange, ...toastProps } = props; | ||
const [open = true, setOpen] = (0, import_react_use_controllable_state.useControllableState)({ | ||
prop: openProp, | ||
defaultProp: defaultOpen, | ||
onChange: onOpenChange | ||
}); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
ToastImpl, | ||
{ | ||
open, | ||
onClose, | ||
onEscapeKeyDown, | ||
onPause, | ||
onResume, | ||
onSwipeStart, | ||
onSwipeMove, | ||
onSwipeCancel, | ||
onSwipeEnd, | ||
...toastProps | ||
} = props; | ||
const context = useToastProviderContext(TOAST_NAME, __scopeToast); | ||
const [node, setNode] = React.useState(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node2) => setNode(node2)); | ||
const pointerStartRef = React.useRef(null); | ||
const swipeDeltaRef = React.useRef(null); | ||
const duration = durationProp || context.duration; | ||
const closeTimerStartTimeRef = React.useRef(0); | ||
const closeTimerRemainingTimeRef = React.useRef(duration); | ||
const closeTimerRef = React.useRef(0); | ||
const { onToastAdd, onToastRemove } = context; | ||
const handleClose = (0, import_react_use_callback_ref.useCallbackRef)(() => { | ||
const isFocusInToast = node?.contains(document.activeElement); | ||
if (isFocusInToast) context.viewport?.focus(); | ||
onClose(); | ||
}); | ||
const startTimer = React.useCallback( | ||
(duration2) => { | ||
if (!duration2 || duration2 === Infinity) return; | ||
...toastProps, | ||
ref: forwardedRef, | ||
onClose: () => setOpen(false), | ||
onPause: (0, import_react_use_callback_ref.useCallbackRef)(props.onPause), | ||
onResume: (0, import_react_use_callback_ref.useCallbackRef)(props.onResume), | ||
onSwipeStart: (0, import_primitive.composeEventHandlers)(props.onSwipeStart, (event) => { | ||
event.currentTarget.setAttribute("data-swipe", "start"); | ||
}), | ||
onSwipeMove: (0, import_primitive.composeEventHandlers)(props.onSwipeMove, (event) => { | ||
const { x, y } = event.detail.delta; | ||
event.currentTarget.setAttribute("data-swipe", "move"); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-move-x", `${x}px`); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-move-y", `${y}px`); | ||
}), | ||
onSwipeCancel: (0, import_primitive.composeEventHandlers)(props.onSwipeCancel, (event) => { | ||
event.currentTarget.setAttribute("data-swipe", "cancel"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-x"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-y"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-end-x"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-end-y"); | ||
}), | ||
onSwipeEnd: (0, import_primitive.composeEventHandlers)(props.onSwipeEnd, (event) => { | ||
const { x, y } = event.detail.delta; | ||
event.currentTarget.setAttribute("data-swipe", "end"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-x"); | ||
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-y"); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-end-x", `${x}px`); | ||
event.currentTarget.style.setProperty("--radix-toast-swipe-end-y", `${y}px`); | ||
setOpen(false); | ||
}) | ||
} | ||
) }); | ||
} | ||
); | ||
Toast.displayName = TOAST_NAME; | ||
var [ToastInteractiveProvider, useToastInteractiveContext] = createToastContext(TOAST_NAME, { | ||
onClose() { | ||
} | ||
}); | ||
var ToastImpl = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { | ||
__scopeToast, | ||
type = "foreground", | ||
duration: durationProp, | ||
open, | ||
onClose, | ||
onEscapeKeyDown, | ||
onPause, | ||
onResume, | ||
onSwipeStart, | ||
onSwipeMove, | ||
onSwipeCancel, | ||
onSwipeEnd, | ||
...toastProps | ||
} = props; | ||
const context = useToastProviderContext(TOAST_NAME, __scopeToast); | ||
const [node, setNode] = React.useState(null); | ||
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node2) => setNode(node2)); | ||
const pointerStartRef = React.useRef(null); | ||
const swipeDeltaRef = React.useRef(null); | ||
const duration = durationProp || context.duration; | ||
const closeTimerStartTimeRef = React.useRef(0); | ||
const closeTimerRemainingTimeRef = React.useRef(duration); | ||
const closeTimerRef = React.useRef(0); | ||
const { onToastAdd, onToastRemove } = context; | ||
const handleClose = (0, import_react_use_callback_ref.useCallbackRef)(() => { | ||
const isFocusInToast = node?.contains(document.activeElement); | ||
if (isFocusInToast) context.viewport?.focus(); | ||
onClose(); | ||
}); | ||
const startTimer = React.useCallback( | ||
(duration2) => { | ||
if (!duration2 || duration2 === Infinity) return; | ||
window.clearTimeout(closeTimerRef.current); | ||
closeTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime(); | ||
closeTimerRef.current = window.setTimeout(handleClose, duration2); | ||
}, | ||
[handleClose] | ||
); | ||
React.useEffect(() => { | ||
const viewport = context.viewport; | ||
if (viewport) { | ||
const handleResume = () => { | ||
startTimer(closeTimerRemainingTimeRef.current); | ||
onResume?.(); | ||
}; | ||
const handlePause = () => { | ||
const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - closeTimerStartTimeRef.current; | ||
closeTimerRemainingTimeRef.current = closeTimerRemainingTimeRef.current - elapsedTime; | ||
window.clearTimeout(closeTimerRef.current); | ||
closeTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime(); | ||
closeTimerRef.current = window.setTimeout(handleClose, duration2); | ||
}, | ||
[handleClose] | ||
); | ||
React.useEffect(() => { | ||
const viewport = context.viewport; | ||
if (viewport) { | ||
const handleResume = () => { | ||
startTimer(closeTimerRemainingTimeRef.current); | ||
onResume?.(); | ||
}; | ||
const handlePause = () => { | ||
const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - closeTimerStartTimeRef.current; | ||
closeTimerRemainingTimeRef.current = closeTimerRemainingTimeRef.current - elapsedTime; | ||
window.clearTimeout(closeTimerRef.current); | ||
onPause?.(); | ||
}; | ||
viewport.addEventListener(VIEWPORT_PAUSE, handlePause); | ||
viewport.addEventListener(VIEWPORT_RESUME, handleResume); | ||
return () => { | ||
viewport.removeEventListener(VIEWPORT_PAUSE, handlePause); | ||
viewport.removeEventListener(VIEWPORT_RESUME, handleResume); | ||
}; | ||
onPause?.(); | ||
}; | ||
viewport.addEventListener(VIEWPORT_PAUSE, handlePause); | ||
viewport.addEventListener(VIEWPORT_RESUME, handleResume); | ||
return () => { | ||
viewport.removeEventListener(VIEWPORT_PAUSE, handlePause); | ||
viewport.removeEventListener(VIEWPORT_RESUME, handleResume); | ||
}; | ||
} | ||
}, [context.viewport, duration, onPause, onResume, startTimer]); | ||
React.useEffect(() => { | ||
if (open && !context.isClosePausedRef.current) startTimer(duration); | ||
}, [open, duration, context.isClosePausedRef, startTimer]); | ||
React.useEffect(() => { | ||
onToastAdd(); | ||
return () => onToastRemove(); | ||
}, [onToastAdd, onToastRemove]); | ||
const announceTextContent = React.useMemo(() => { | ||
return node ? getAnnounceTextContent(node) : null; | ||
}, [node]); | ||
if (!context.viewport) return null; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
announceTextContent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
ToastAnnounce, | ||
{ | ||
__scopeToast, | ||
role: "status", | ||
"aria-live": type === "foreground" ? "assertive" : "polite", | ||
"aria-atomic": true, | ||
children: announceTextContent | ||
} | ||
}, [context.viewport, duration, onPause, onResume, startTimer]); | ||
React.useEffect(() => { | ||
if (open && !context.isClosePausedRef.current) startTimer(duration); | ||
}, [open, duration, context.isClosePausedRef, startTimer]); | ||
React.useEffect(() => { | ||
onToastAdd(); | ||
return () => onToastRemove(); | ||
}, [onToastAdd, onToastRemove]); | ||
const announceTextContent = React.useMemo(() => { | ||
return node ? getAnnounceTextContent(node) : null; | ||
}, [node]); | ||
if (!context.viewport) return null; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
announceTextContent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
ToastAnnounce, | ||
), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastInteractiveProvider, { scope: __scopeToast, onClose: handleClose, children: ReactDOM.createPortal( | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.ItemSlot, { scope: __scopeToast, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
DismissableLayer.Root, | ||
{ | ||
__scopeToast, | ||
role: "status", | ||
"aria-live": type === "foreground" ? "assertive" : "polite", | ||
"aria-atomic": true, | ||
children: announceTextContent | ||
} | ||
), | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastInteractiveProvider, { scope: __scopeToast, onClose: handleClose, children: ReactDOM.createPortal( | ||
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.ItemSlot, { scope: __scopeToast, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
DismissableLayer.Root, | ||
{ | ||
asChild: true, | ||
onEscapeKeyDown: (0, import_primitive.composeEventHandlers)(onEscapeKeyDown, () => { | ||
if (!context.isFocusedToastEscapeKeyDownRef.current) handleClose(); | ||
context.isFocusedToastEscapeKeyDownRef.current = false; | ||
}), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.li, | ||
{ | ||
role: "status", | ||
"aria-live": "off", | ||
"aria-atomic": true, | ||
tabIndex: 0, | ||
"data-state": open ? "open" : "closed", | ||
"data-swipe-direction": context.swipeDirection, | ||
...toastProps, | ||
ref: composedRefs, | ||
style: { userSelect: "none", touchAction: "none", ...props.style }, | ||
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => { | ||
if (event.key !== "Escape") return; | ||
onEscapeKeyDown?.(event.nativeEvent); | ||
if (!event.nativeEvent.defaultPrevented) { | ||
context.isFocusedToastEscapeKeyDownRef.current = true; | ||
handleClose(); | ||
} | ||
}), | ||
onPointerDown: (0, import_primitive.composeEventHandlers)(props.onPointerDown, (event) => { | ||
if (event.button !== 0) return; | ||
pointerStartRef.current = { x: event.clientX, y: event.clientY }; | ||
}), | ||
onPointerMove: (0, import_primitive.composeEventHandlers)(props.onPointerMove, (event) => { | ||
if (!pointerStartRef.current) return; | ||
const x = event.clientX - pointerStartRef.current.x; | ||
const y = event.clientY - pointerStartRef.current.y; | ||
const hasSwipeMoveStarted = Boolean(swipeDeltaRef.current); | ||
const isHorizontalSwipe = ["left", "right"].includes(context.swipeDirection); | ||
const clamp = ["left", "up"].includes(context.swipeDirection) ? Math.min : Math.max; | ||
const clampedX = isHorizontalSwipe ? clamp(0, x) : 0; | ||
const clampedY = !isHorizontalSwipe ? clamp(0, y) : 0; | ||
const moveStartBuffer = event.pointerType === "touch" ? 10 : 2; | ||
const delta = { x: clampedX, y: clampedY }; | ||
asChild: true, | ||
onEscapeKeyDown: (0, import_primitive.composeEventHandlers)(onEscapeKeyDown, () => { | ||
if (!context.isFocusedToastEscapeKeyDownRef.current) handleClose(); | ||
context.isFocusedToastEscapeKeyDownRef.current = false; | ||
}), | ||
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.li, | ||
{ | ||
role: "status", | ||
"aria-live": "off", | ||
"aria-atomic": true, | ||
tabIndex: 0, | ||
"data-state": open ? "open" : "closed", | ||
"data-swipe-direction": context.swipeDirection, | ||
...toastProps, | ||
ref: composedRefs, | ||
style: { userSelect: "none", touchAction: "none", ...props.style }, | ||
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => { | ||
if (event.key !== "Escape") return; | ||
onEscapeKeyDown?.(event.nativeEvent); | ||
if (!event.nativeEvent.defaultPrevented) { | ||
context.isFocusedToastEscapeKeyDownRef.current = true; | ||
handleClose(); | ||
} | ||
}), | ||
onPointerDown: (0, import_primitive.composeEventHandlers)(props.onPointerDown, (event) => { | ||
if (event.button !== 0) return; | ||
pointerStartRef.current = { x: event.clientX, y: event.clientY }; | ||
}), | ||
onPointerMove: (0, import_primitive.composeEventHandlers)(props.onPointerMove, (event) => { | ||
if (!pointerStartRef.current) return; | ||
const x = event.clientX - pointerStartRef.current.x; | ||
const y = event.clientY - pointerStartRef.current.y; | ||
const hasSwipeMoveStarted = Boolean(swipeDeltaRef.current); | ||
const isHorizontalSwipe = ["left", "right"].includes(context.swipeDirection); | ||
const clamp = ["left", "up"].includes(context.swipeDirection) ? Math.min : Math.max; | ||
const clampedX = isHorizontalSwipe ? clamp(0, x) : 0; | ||
const clampedY = !isHorizontalSwipe ? clamp(0, y) : 0; | ||
const moveStartBuffer = event.pointerType === "touch" ? 10 : 2; | ||
const delta = { x: clampedX, y: clampedY }; | ||
const eventDetail = { originalEvent: event, delta }; | ||
if (hasSwipeMoveStarted) { | ||
swipeDeltaRef.current = delta; | ||
handleAndDispatchCustomEvent(TOAST_SWIPE_MOVE, onSwipeMove, eventDetail, { | ||
discrete: false | ||
}); | ||
} else if (isDeltaInDirection(delta, context.swipeDirection, moveStartBuffer)) { | ||
swipeDeltaRef.current = delta; | ||
handleAndDispatchCustomEvent(TOAST_SWIPE_START, onSwipeStart, eventDetail, { | ||
discrete: false | ||
}); | ||
event.target.setPointerCapture(event.pointerId); | ||
} else if (Math.abs(x) > moveStartBuffer || Math.abs(y) > moveStartBuffer) { | ||
pointerStartRef.current = null; | ||
} | ||
}), | ||
onPointerUp: (0, import_primitive.composeEventHandlers)(props.onPointerUp, (event) => { | ||
const delta = swipeDeltaRef.current; | ||
const target = event.target; | ||
if (target.hasPointerCapture(event.pointerId)) { | ||
target.releasePointerCapture(event.pointerId); | ||
} | ||
swipeDeltaRef.current = null; | ||
pointerStartRef.current = null; | ||
if (delta) { | ||
const toast = event.currentTarget; | ||
const eventDetail = { originalEvent: event, delta }; | ||
if (hasSwipeMoveStarted) { | ||
swipeDeltaRef.current = delta; | ||
handleAndDispatchCustomEvent(TOAST_SWIPE_MOVE, onSwipeMove, eventDetail, { | ||
discrete: false | ||
if (isDeltaInDirection(delta, context.swipeDirection, context.swipeThreshold)) { | ||
handleAndDispatchCustomEvent(TOAST_SWIPE_END, onSwipeEnd, eventDetail, { | ||
discrete: true | ||
}); | ||
} else if (isDeltaInDirection(delta, context.swipeDirection, moveStartBuffer)) { | ||
swipeDeltaRef.current = delta; | ||
handleAndDispatchCustomEvent(TOAST_SWIPE_START, onSwipeStart, eventDetail, { | ||
discrete: false | ||
}); | ||
event.target.setPointerCapture(event.pointerId); | ||
} else if (Math.abs(x) > moveStartBuffer || Math.abs(y) > moveStartBuffer) { | ||
pointerStartRef.current = null; | ||
} | ||
}), | ||
onPointerUp: (0, import_primitive.composeEventHandlers)(props.onPointerUp, (event) => { | ||
const delta = swipeDeltaRef.current; | ||
const target = event.target; | ||
if (target.hasPointerCapture(event.pointerId)) { | ||
target.releasePointerCapture(event.pointerId); | ||
} | ||
swipeDeltaRef.current = null; | ||
pointerStartRef.current = null; | ||
if (delta) { | ||
const toast = event.currentTarget; | ||
const eventDetail = { originalEvent: event, delta }; | ||
if (isDeltaInDirection(delta, context.swipeDirection, context.swipeThreshold)) { | ||
handleAndDispatchCustomEvent(TOAST_SWIPE_END, onSwipeEnd, eventDetail, { | ||
} else { | ||
handleAndDispatchCustomEvent( | ||
TOAST_SWIPE_CANCEL, | ||
onSwipeCancel, | ||
eventDetail, | ||
{ | ||
discrete: true | ||
}); | ||
} else { | ||
handleAndDispatchCustomEvent( | ||
TOAST_SWIPE_CANCEL, | ||
onSwipeCancel, | ||
eventDetail, | ||
{ | ||
discrete: true | ||
} | ||
); | ||
} | ||
toast.addEventListener("click", (event2) => event2.preventDefault(), { | ||
once: true | ||
}); | ||
} | ||
); | ||
} | ||
}) | ||
} | ||
) | ||
} | ||
) }), | ||
context.viewport | ||
) }) | ||
] }); | ||
toast.addEventListener("click", (event2) => event2.preventDefault(), { | ||
once: true | ||
}); | ||
} | ||
}) | ||
} | ||
) | ||
} | ||
) }), | ||
context.viewport | ||
) }) | ||
] }); | ||
} | ||
); | ||
ToastImpl.propTypes = { | ||
type(props) { | ||
if (props.type && !["foreground", "background"].includes(props.type)) { | ||
const error = `Invalid prop \`type\` supplied to \`${TOAST_NAME}\`. Expected \`foreground | background\`.`; | ||
return new Error(error); | ||
} | ||
); | ||
ToastImpl.propTypes = { | ||
type(props) { | ||
if (props.type && !["foreground", "background"].includes(props.type)) { | ||
const error = `Invalid prop \`type\` supplied to \`${TOAST_NAME}\`. Expected \`foreground | background\`.`; | ||
return new Error(error); | ||
} | ||
return null; | ||
return null; | ||
} | ||
}; | ||
var ToastAnnounce = (props) => { | ||
const { __scopeToast, children, ...announceProps } = props; | ||
const context = useToastProviderContext(TOAST_NAME, __scopeToast); | ||
const [renderAnnounceText, setRenderAnnounceText] = React.useState(false); | ||
const [isAnnounced, setIsAnnounced] = React.useState(false); | ||
useNextFrame(() => setRenderAnnounceText(true)); | ||
React.useEffect(() => { | ||
const timer = window.setTimeout(() => setIsAnnounced(true), 1e3); | ||
return () => window.clearTimeout(timer); | ||
}, []); | ||
return isAnnounced ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_portal.Portal, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_visually_hidden.VisuallyHidden, { ...announceProps, children: renderAnnounceText && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
context.label, | ||
" ", | ||
children | ||
] }) }) }); | ||
}; | ||
var TITLE_NAME = "ToastTitle"; | ||
var ToastTitle = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, ...titleProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...titleProps, ref: forwardedRef }); | ||
} | ||
); | ||
ToastTitle.displayName = TITLE_NAME; | ||
var DESCRIPTION_NAME = "ToastDescription"; | ||
var ToastDescription = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, ...descriptionProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...descriptionProps, ref: forwardedRef }); | ||
} | ||
); | ||
ToastDescription.displayName = DESCRIPTION_NAME; | ||
var ACTION_NAME = "ToastAction"; | ||
var ToastAction = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { altText, ...actionProps } = props; | ||
if (!altText) return null; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastAnnounceExclude, { altText, asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastClose, { ...actionProps, ref: forwardedRef }) }); | ||
} | ||
); | ||
ToastAction.propTypes = { | ||
altText(props) { | ||
if (!props.altText) { | ||
return new Error(`Missing prop \`altText\` expected on \`${ACTION_NAME}\``); | ||
} | ||
}; | ||
var ToastAnnounce = (props) => { | ||
const { __scopeToast, children, ...announceProps } = props; | ||
const context = useToastProviderContext(TOAST_NAME, __scopeToast); | ||
const [renderAnnounceText, setRenderAnnounceText] = React.useState(false); | ||
const [isAnnounced, setIsAnnounced] = React.useState(false); | ||
useNextFrame(() => setRenderAnnounceText(true)); | ||
React.useEffect(() => { | ||
const timer = window.setTimeout(() => setIsAnnounced(true), 1e3); | ||
return () => window.clearTimeout(timer); | ||
}, []); | ||
return isAnnounced ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_portal.Portal, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_visually_hidden.VisuallyHidden, { ...announceProps, children: renderAnnounceText && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | ||
context.label, | ||
" ", | ||
children | ||
] }) }) }); | ||
}; | ||
var TITLE_NAME = "ToastTitle"; | ||
var ToastTitle = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, ...titleProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...titleProps, ref: forwardedRef }); | ||
} | ||
); | ||
ToastTitle.displayName = TITLE_NAME; | ||
var DESCRIPTION_NAME = "ToastDescription"; | ||
var ToastDescription = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, ...descriptionProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...descriptionProps, ref: forwardedRef }); | ||
} | ||
); | ||
ToastDescription.displayName = DESCRIPTION_NAME; | ||
var ACTION_NAME = "ToastAction"; | ||
var ToastAction = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { altText, ...actionProps } = props; | ||
if (!altText) return null; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastAnnounceExclude, { altText, asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastClose, { ...actionProps, ref: forwardedRef }) }); | ||
} | ||
); | ||
ToastAction.propTypes = { | ||
altText(props) { | ||
if (!props.altText) { | ||
return new Error(`Missing prop \`altText\` expected on \`${ACTION_NAME}\``); | ||
return null; | ||
} | ||
}; | ||
ToastAction.displayName = ACTION_NAME; | ||
var CLOSE_NAME = "ToastClose"; | ||
var ToastClose = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, ...closeProps } = props; | ||
const interactiveContext = useToastInteractiveContext(CLOSE_NAME, __scopeToast); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastAnnounceExclude, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.button, | ||
{ | ||
type: "button", | ||
...closeProps, | ||
ref: forwardedRef, | ||
onClick: (0, import_primitive.composeEventHandlers)(props.onClick, interactiveContext.onClose) | ||
} | ||
return null; | ||
) }); | ||
} | ||
); | ||
ToastClose.displayName = CLOSE_NAME; | ||
var ToastAnnounceExclude = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeToast, altText, ...announceExcludeProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.div, | ||
{ | ||
"data-radix-toast-announce-exclude": "", | ||
"data-radix-toast-announce-alt": altText || void 0, | ||
...announceExcludeProps, | ||
ref: forwardedRef | ||
} | ||
}; | ||
ToastAction.displayName = ACTION_NAME; | ||
var CLOSE_NAME = "ToastClose"; | ||
var ToastClose = React.forwardRef( | ||
(props, forwardedRef) => { | ||
const { __scopeToast, ...closeProps } = props; | ||
const interactiveContext = useToastInteractiveContext(CLOSE_NAME, __scopeToast); | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastAnnounceExclude, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.button, | ||
{ | ||
type: "button", | ||
...closeProps, | ||
ref: forwardedRef, | ||
onClick: (0, import_primitive.composeEventHandlers)(props.onClick, interactiveContext.onClose) | ||
} | ||
) }); | ||
} | ||
); | ||
ToastClose.displayName = CLOSE_NAME; | ||
var ToastAnnounceExclude = React.forwardRef((props, forwardedRef) => { | ||
const { __scopeToast, altText, ...announceExcludeProps } = props; | ||
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
import_react_primitive.Primitive.div, | ||
{ | ||
"data-radix-toast-announce-exclude": "", | ||
"data-radix-toast-announce-alt": altText || void 0, | ||
...announceExcludeProps, | ||
ref: forwardedRef | ||
} | ||
); | ||
}); | ||
function getAnnounceTextContent(container) { | ||
const textContent = []; | ||
const childNodes = Array.from(container.childNodes); | ||
childNodes.forEach((node) => { | ||
if (node.nodeType === node.TEXT_NODE && node.textContent) textContent.push(node.textContent); | ||
if (isHTMLElement(node)) { | ||
const isHidden = node.ariaHidden || node.hidden || node.style.display === "none"; | ||
const isExcluded = node.dataset.radixToastAnnounceExclude === ""; | ||
if (!isHidden) { | ||
if (isExcluded) { | ||
const altText = node.dataset.radixToastAnnounceAlt; | ||
if (altText) textContent.push(altText); | ||
} else { | ||
textContent.push(...getAnnounceTextContent(node)); | ||
} | ||
}); | ||
function getAnnounceTextContent(container) { | ||
const textContent = []; | ||
const childNodes = Array.from(container.childNodes); | ||
childNodes.forEach((node) => { | ||
if (node.nodeType === node.TEXT_NODE && node.textContent) textContent.push(node.textContent); | ||
if (isHTMLElement(node)) { | ||
const isHidden = node.ariaHidden || node.hidden || node.style.display === "none"; | ||
const isExcluded = node.dataset.radixToastAnnounceExclude === ""; | ||
if (!isHidden) { | ||
if (isExcluded) { | ||
const altText = node.dataset.radixToastAnnounceAlt; | ||
if (altText) textContent.push(altText); | ||
} else { | ||
textContent.push(...getAnnounceTextContent(node)); | ||
} | ||
} | ||
}); | ||
return textContent; | ||
} | ||
function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) { | ||
const currentTarget = detail.originalEvent.currentTarget; | ||
const event = new CustomEvent(name, { bubbles: true, cancelable: true, detail }); | ||
if (handler) currentTarget.addEventListener(name, handler, { once: true }); | ||
if (discrete) { | ||
(0, import_react_primitive.dispatchDiscreteCustomEvent)(currentTarget, event); | ||
} else { | ||
currentTarget.dispatchEvent(event); | ||
} | ||
}); | ||
return textContent; | ||
} | ||
function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) { | ||
const currentTarget = detail.originalEvent.currentTarget; | ||
const event = new CustomEvent(name, { bubbles: true, cancelable: true, detail }); | ||
if (handler) currentTarget.addEventListener(name, handler, { once: true }); | ||
if (discrete) { | ||
(0, import_react_primitive.dispatchDiscreteCustomEvent)(currentTarget, event); | ||
} else { | ||
currentTarget.dispatchEvent(event); | ||
} | ||
var isDeltaInDirection = (delta, direction, threshold = 0) => { | ||
const deltaX = Math.abs(delta.x); | ||
const deltaY = Math.abs(delta.y); | ||
const isDeltaX = deltaX > deltaY; | ||
if (direction === "left" || direction === "right") { | ||
return isDeltaX && deltaX > threshold; | ||
} else { | ||
return !isDeltaX && deltaY > threshold; | ||
} | ||
var isDeltaInDirection = (delta, direction, threshold = 0) => { | ||
const deltaX = Math.abs(delta.x); | ||
const deltaY = Math.abs(delta.y); | ||
const isDeltaX = deltaX > deltaY; | ||
if (direction === "left" || direction === "right") { | ||
return isDeltaX && deltaX > threshold; | ||
} else { | ||
return !isDeltaX && deltaY > threshold; | ||
} | ||
}; | ||
function useNextFrame(callback = () => { | ||
}) { | ||
const fn = (0, import_react_use_callback_ref.useCallbackRef)(callback); | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
let raf1 = 0; | ||
let raf2 = 0; | ||
raf1 = window.requestAnimationFrame(() => raf2 = window.requestAnimationFrame(fn)); | ||
return () => { | ||
window.cancelAnimationFrame(raf1); | ||
window.cancelAnimationFrame(raf2); | ||
}; | ||
}, [fn]); | ||
} | ||
function isHTMLElement(node) { | ||
return node.nodeType === node.ELEMENT_NODE; | ||
} | ||
function getTabbableCandidates(container) { | ||
const nodes = []; | ||
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, { | ||
acceptNode: (node) => { | ||
const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden"; | ||
if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; | ||
return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; | ||
} | ||
}; | ||
function useNextFrame(callback = () => { | ||
}) { | ||
const fn = (0, import_react_use_callback_ref.useCallbackRef)(callback); | ||
(0, import_react_use_layout_effect.useLayoutEffect)(() => { | ||
let raf1 = 0; | ||
let raf2 = 0; | ||
raf1 = window.requestAnimationFrame(() => raf2 = window.requestAnimationFrame(fn)); | ||
return () => { | ||
window.cancelAnimationFrame(raf1); | ||
window.cancelAnimationFrame(raf2); | ||
}; | ||
}, [fn]); | ||
} | ||
function isHTMLElement(node) { | ||
return node.nodeType === node.ELEMENT_NODE; | ||
} | ||
function getTabbableCandidates(container) { | ||
const nodes = []; | ||
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, { | ||
acceptNode: (node) => { | ||
const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden"; | ||
if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; | ||
return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; | ||
} | ||
}); | ||
while (walker.nextNode()) nodes.push(walker.currentNode); | ||
return nodes; | ||
} | ||
function focusFirst(candidates) { | ||
const previouslyFocusedElement = document.activeElement; | ||
return candidates.some((candidate) => { | ||
if (candidate === previouslyFocusedElement) return true; | ||
candidate.focus(); | ||
return document.activeElement !== previouslyFocusedElement; | ||
}); | ||
} | ||
var Provider = ToastProvider; | ||
var Viewport = ToastViewport; | ||
var Root2 = Toast; | ||
var Title = ToastTitle; | ||
var Description = ToastDescription; | ||
var Action = ToastAction; | ||
var Close = ToastClose; | ||
})(); | ||
}); | ||
while (walker.nextNode()) nodes.push(walker.currentNode); | ||
return nodes; | ||
} | ||
function focusFirst(candidates) { | ||
const previouslyFocusedElement = document.activeElement; | ||
return candidates.some((candidate) => { | ||
if (candidate === previouslyFocusedElement) return true; | ||
candidate.focus(); | ||
return document.activeElement !== previouslyFocusedElement; | ||
}); | ||
} | ||
var Provider = ToastProvider; | ||
var Viewport = ToastViewport; | ||
var Root2 = Toast; | ||
var Title = ToastTitle; | ||
var Description = ToastDescription; | ||
var Action = ToastAction; | ||
var Close = ToastClose; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@radix-ui/react-toast", | ||
"version": "1.2.0-rc.2", | ||
"version": "1.2.0-rc.3", | ||
"license": "MIT", | ||
@@ -31,14 +31,14 @@ "exports": { | ||
"dependencies": { | ||
"@radix-ui/primitive": "1.1.0-rc.2", | ||
"@radix-ui/react-collection": "1.1.0-rc.2", | ||
"@radix-ui/react-compose-refs": "1.1.0-rc.2", | ||
"@radix-ui/react-context": "1.1.0-rc.2", | ||
"@radix-ui/react-dismissable-layer": "1.1.0-rc.2", | ||
"@radix-ui/react-portal": "1.1.0-rc.2", | ||
"@radix-ui/react-presence": "1.1.0-rc.2", | ||
"@radix-ui/react-primitive": "1.1.0-rc.2", | ||
"@radix-ui/react-use-callback-ref": "1.1.0-rc.2", | ||
"@radix-ui/react-use-controllable-state": "1.1.0-rc.2", | ||
"@radix-ui/react-use-layout-effect": "1.1.0-rc.2", | ||
"@radix-ui/react-visually-hidden": "1.1.0-rc.2" | ||
"@radix-ui/primitive": "1.1.0-rc.3", | ||
"@radix-ui/react-collection": "1.1.0-rc.3", | ||
"@radix-ui/react-compose-refs": "1.1.0-rc.3", | ||
"@radix-ui/react-context": "1.1.0-rc.3", | ||
"@radix-ui/react-dismissable-layer": "1.1.0-rc.3", | ||
"@radix-ui/react-portal": "1.1.0-rc.3", | ||
"@radix-ui/react-presence": "1.1.0-rc.3", | ||
"@radix-ui/react-primitive": "1.1.0-rc.3", | ||
"@radix-ui/react-use-callback-ref": "1.1.0-rc.3", | ||
"@radix-ui/react-use-controllable-state": "1.1.0-rc.3", | ||
"@radix-ui/react-use-layout-effect": "1.1.0-rc.3", | ||
"@radix-ui/react-visually-hidden": "1.1.0-rc.3" | ||
}, | ||
@@ -45,0 +45,0 @@ "peerDependencies": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
1489
0
182727
+ Added@radix-ui/primitive@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-collection@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-compose-refs@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-context@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-dismissable-layer@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-portal@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-presence@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-primitive@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-slot@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-callback-ref@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-controllable-state@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-escape-keydown@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-layout-effect@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-visually-hidden@1.1.0-rc.3(transitive)
- Removed@radix-ui/primitive@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-collection@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-compose-refs@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-context@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-dismissable-layer@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-portal@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-presence@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-primitive@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-slot@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-callback-ref@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-controllable-state@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-escape-keydown@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-layout-effect@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-visually-hidden@1.1.0-rc.2(transitive)