@mantine/notifications 9.6.3 → 9.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/NotificationContainer.cjs +44 -5
- package/cjs/NotificationContainer.cjs.map +1 -1
- package/cjs/Notifications.cjs +6 -2
- package/cjs/Notifications.cjs.map +1 -1
- package/cjs/Notifications.module.cjs +4 -1
- package/cjs/Notifications.module.cjs.map +1 -1
- package/cjs/index.cjs +1 -0
- package/cjs/notifications.store.cjs +42 -0
- package/cjs/notifications.store.cjs.map +1 -1
- package/esm/NotificationContainer.mjs +46 -7
- package/esm/NotificationContainer.mjs.map +1 -1
- package/esm/Notifications.mjs +6 -2
- package/esm/Notifications.mjs.map +1 -1
- package/esm/Notifications.module.mjs +4 -1
- package/esm/Notifications.module.mjs.map +1 -1
- package/esm/index.mjs +2 -2
- package/esm/notifications.store.mjs +42 -1
- package/esm/notifications.store.mjs.map +1 -1
- package/lib/NotificationContainer.d.ts +3 -1
- package/lib/Notifications.d.ts +5 -1
- package/lib/index.d.mts +2 -2
- package/lib/index.d.ts +2 -2
- package/lib/notifications.store.d.ts +15 -0
- package/package.json +6 -6
- package/styles.css +40 -0
- package/styles.layer.css +40 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { getAutoClose } from "./get-auto-close/get-auto-close.mjs";
|
|
3
|
-
import { useDrag, useMergedRef } from "@mantine/hooks";
|
|
3
|
+
import { useDidUpdate, useDrag, useMergedRef } from "@mantine/hooks";
|
|
4
4
|
import { useEffect, useEffectEvent, useRef, useState } from "react";
|
|
5
5
|
import { Notification, extractStyleProps, getStyleObject, useMantineTheme } from "@mantine/core";
|
|
6
|
-
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region packages/@mantine/notifications/src/NotificationContainer.tsx
|
|
8
8
|
const SCROLL_DISMISS_RESET_TIMEOUT = 120;
|
|
9
9
|
const MAX_VISIBLE_STACK_DEPTH = 4;
|
|
@@ -39,14 +39,19 @@ function pickDomProps(props) {
|
|
|
39
39
|
const { rest } = extractStyleProps(props);
|
|
40
40
|
return Object.fromEntries(Object.entries(rest).filter(([key, value]) => !NON_DOM_PROPS.has(key) && value !== void 0));
|
|
41
41
|
}
|
|
42
|
-
function NotificationContainer({ data, onHide, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, paused, onHoverStart, onHoverEnd, onExpandRequest, ref, style, renderNotification, layout, stackIndex, stackSize, stackPosition, stackExpanded, stackExpandedOffset, transitionState, ...others }) {
|
|
42
|
+
function NotificationContainer({ data, onHide, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, paused, withAutoCloseProgress, progressProps, onHoverStart, onHoverEnd, onExpandRequest, ref, style, renderNotification, layout, stackIndex, stackSize, stackPosition, stackExpanded, stackExpandedOffset, transitionState, ...others }) {
|
|
43
43
|
const [offset, setOffset] = useState(0);
|
|
44
44
|
const [dismissed, setDismissed] = useState(false);
|
|
45
45
|
const [dismissDirection, setDismissDirection] = useState(1);
|
|
46
46
|
const [scrollDismissActive, setScrollDismissActive] = useState(false);
|
|
47
47
|
const theme = useMantineTheme();
|
|
48
|
-
const { autoClose: _autoClose, message, allowClose, position: _position, style: dataStyle, withCloseButton, renderNotification: _renderNotification, onOpen: _onOpen, priority: _priority, __sequence: _sequence, ...notificationProps } = data;
|
|
48
|
+
const { autoClose: _autoClose, message, allowClose, position: _position, style: dataStyle, withCloseButton, renderNotification: _renderNotification, onOpen: _onOpen, priority: _priority, withAutoCloseProgress: _withAutoCloseProgress, __sequence: _sequence, ...notificationProps } = data;
|
|
49
49
|
const autoCloseDuration = getAutoClose(autoClose, data.autoClose);
|
|
50
|
+
const [autoCloseProgress, setAutoCloseProgress] = useState({
|
|
51
|
+
running: false,
|
|
52
|
+
cycle: 0
|
|
53
|
+
});
|
|
54
|
+
const hasAutoCloseProgress = (data.withAutoCloseProgress ?? withAutoCloseProgress) && typeof autoCloseDuration === "number";
|
|
50
55
|
const autoCloseTimeout = useRef(-1);
|
|
51
56
|
const hideTimeout = useRef(-1);
|
|
52
57
|
const scrollDismissTimeout = useRef(-1);
|
|
@@ -73,7 +78,13 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
|
|
|
73
78
|
}
|
|
74
79
|
});
|
|
75
80
|
useEffect(() => () => releaseActive(), []);
|
|
76
|
-
const cancelAutoClose = () =>
|
|
81
|
+
const cancelAutoClose = () => {
|
|
82
|
+
window.clearTimeout(autoCloseTimeout.current);
|
|
83
|
+
setAutoCloseProgress((current) => current.running ? {
|
|
84
|
+
...current,
|
|
85
|
+
running: false
|
|
86
|
+
} : current);
|
|
87
|
+
};
|
|
77
88
|
const cancelHide = () => window.clearTimeout(hideTimeout.current);
|
|
78
89
|
const cancelScrollDismissReset = () => window.clearTimeout(scrollDismissTimeout.current);
|
|
79
90
|
const setSwipeOffset = (value) => {
|
|
@@ -94,6 +105,10 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
|
|
|
94
105
|
if (dismissed || active || hoveredRef.current || focusedRef.current || pausedRef.current || typeof autoCloseDuration !== "number") return;
|
|
95
106
|
cancelAutoClose();
|
|
96
107
|
autoCloseTimeout.current = window.setTimeout(handleHide, autoCloseDuration);
|
|
108
|
+
setAutoCloseProgress((current) => ({
|
|
109
|
+
running: true,
|
|
110
|
+
cycle: current.cycle + 1
|
|
111
|
+
}));
|
|
97
112
|
};
|
|
98
113
|
const getExitOffset = (direction) => {
|
|
99
114
|
return direction * ((notificationRef.current?.offsetWidth ?? 440) + 40);
|
|
@@ -272,6 +287,19 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
|
|
|
272
287
|
useEffect(() => {
|
|
273
288
|
data.onOpen?.(data);
|
|
274
289
|
}, []);
|
|
290
|
+
const previousTransitionState = useRef(transitionState);
|
|
291
|
+
useEffect(() => {
|
|
292
|
+
const wasExiting = previousTransitionState.current === "exiting";
|
|
293
|
+
previousTransitionState.current = transitionState;
|
|
294
|
+
if (transitionState !== "entering" || !wasExiting) return;
|
|
295
|
+
cancelHide();
|
|
296
|
+
if (dismissed) {
|
|
297
|
+
setDismissed(false);
|
|
298
|
+
setScrollDismissActive(false);
|
|
299
|
+
setSwipeOffset(0);
|
|
300
|
+
} else handleAutoClose();
|
|
301
|
+
data.onOpen?.(data);
|
|
302
|
+
}, [transitionState]);
|
|
275
303
|
useEffect(() => {
|
|
276
304
|
handleAutoClose();
|
|
277
305
|
return cancelAutoClose;
|
|
@@ -280,6 +308,9 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
|
|
|
280
308
|
active,
|
|
281
309
|
dismissed
|
|
282
310
|
]);
|
|
311
|
+
useDidUpdate(() => {
|
|
312
|
+
if (hasAutoCloseProgress) handleAutoClose();
|
|
313
|
+
}, [hasAutoCloseProgress]);
|
|
283
314
|
useEffect(() => {
|
|
284
315
|
if (paused) cancelAutoClose();
|
|
285
316
|
else handleAutoClose();
|
|
@@ -324,14 +355,22 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
|
|
|
324
355
|
children: renderNotification(data)
|
|
325
356
|
});
|
|
326
357
|
}
|
|
327
|
-
return /* @__PURE__ */
|
|
358
|
+
return /* @__PURE__ */ jsxs(Notification, {
|
|
328
359
|
ref: mergedRef,
|
|
329
360
|
...others,
|
|
330
361
|
...notificationProps,
|
|
331
362
|
...interactionProps,
|
|
332
363
|
withCloseButton: isCloseDisabled ? false : withCloseButton,
|
|
333
364
|
onClose: handleHide,
|
|
334
|
-
children: message
|
|
365
|
+
children: [message, hasAutoCloseProgress && /* @__PURE__ */ jsx("div", {
|
|
366
|
+
"aria-hidden": true,
|
|
367
|
+
...progressProps,
|
|
368
|
+
"data-paused": !autoCloseProgress.running || void 0,
|
|
369
|
+
style: {
|
|
370
|
+
...progressProps.style,
|
|
371
|
+
["--notifications-progress-duration"]: `${autoCloseDuration}ms`
|
|
372
|
+
}
|
|
373
|
+
}, autoCloseProgress.cycle)]
|
|
335
374
|
});
|
|
336
375
|
}
|
|
337
376
|
NotificationContainer.displayName = "@mantine/notifications/NotificationContainer";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationContainer.mjs","names":[],"sources":["../src/NotificationContainer.tsx"],"sourcesContent":["import { useEffect, useEffectEvent, useRef, useState } from 'react';\nimport {\n extractStyleProps,\n getStyleObject,\n Notification,\n NotificationProps,\n useMantineTheme,\n} from '@mantine/core';\nimport { useDrag, useMergedRef } from '@mantine/hooks';\nimport { getAutoClose } from './get-auto-close/get-auto-close';\nimport { NotificationData } from './notifications.store';\n\nconst SCROLL_DISMISS_RESET_TIMEOUT = 120;\n\ninterface NotificationContainerProps extends NotificationProps {\n data: NotificationData;\n onHide: (id: string) => void;\n autoClose: number | false;\n transitionDuration: number;\n allowDragDismiss: boolean;\n allowScrollDismiss: boolean;\n paused: boolean;\n onHoverStart?: () => void;\n onHoverEnd?: () => void;\n onExpandRequest?: () => void;\n ref?: React.Ref<HTMLDivElement>;\n renderNotification?: ((notification: NotificationData) => React.ReactNode) | null;\n layout?: 'default' | 'stacked';\n stackIndex?: number;\n stackSize?: number;\n stackPosition?: string;\n stackExpanded?: boolean;\n stackExpandedOffset?: number;\n transitionState?: string;\n}\n\nconst MAX_VISIBLE_STACK_DEPTH = 4;\n\n/**\n * Props that belong to the default `Notification` rendering or to the Styles API and must\n * not reach the plain `div` used for custom rendering. Everything else is a valid div prop\n * and is forwarded – an allow list would silently drop supported props like `onClick`,\n * `dir`, `lang` or `hidden`.\n */\nconst NON_DOM_PROPS = new Set([\n 'classNames',\n 'styles',\n 'unstyled',\n 'vars',\n 'attributes',\n 'variant',\n 'color',\n 'radius',\n 'icon',\n 'title',\n 'loading',\n 'withBorder',\n 'withCloseButton',\n 'closeButtonProps',\n 'className',\n 'style',\n 'role',\n 'ref',\n 'children',\n 'mod',\n]);\n\nfunction pickDomProps(props: Record<string, any>) {\n // Mantine style props (`mt`, `bg`, `w`, …) are valid `NotificationProps` but are not DOM\n // attributes, so they are separated out rather than leaked onto the element.\n const { rest } = extractStyleProps(props);\n\n return Object.fromEntries(\n Object.entries(rest).filter(([key, value]) => !NON_DOM_PROPS.has(key) && value !== undefined)\n );\n}\n\nexport function NotificationContainer({\n data,\n onHide,\n autoClose,\n transitionDuration,\n allowDragDismiss,\n allowScrollDismiss,\n paused,\n onHoverStart,\n onHoverEnd,\n onExpandRequest,\n ref,\n style,\n renderNotification,\n layout,\n stackIndex,\n stackSize,\n stackPosition,\n stackExpanded,\n stackExpandedOffset,\n transitionState,\n ...others\n}: NotificationContainerProps) {\n const [offset, setOffset] = useState(0);\n const [dismissed, setDismissed] = useState(false);\n const [dismissDirection, setDismissDirection] = useState<-1 | 1>(1);\n const [scrollDismissActive, setScrollDismissActive] = useState(false);\n const theme = useMantineTheme();\n const {\n autoClose: _autoClose,\n message,\n allowClose,\n position: _position,\n style: dataStyle,\n withCloseButton,\n renderNotification: _renderNotification,\n onOpen: _onOpen,\n priority: _priority,\n __sequence: _sequence,\n ...notificationProps\n } = data as NotificationData & { __sequence?: number };\n const autoCloseDuration = getAutoClose(autoClose, data.autoClose);\n const autoCloseTimeout = useRef<number>(-1);\n const hideTimeout = useRef<number>(-1);\n const scrollDismissTimeout = useRef<number>(-1);\n const notificationRef = useRef<HTMLDivElement>(null);\n const hoveredRef = useRef(false);\n const focusedRef = useRef(false);\n\n // Hover and focus both keep the notification \"active\". The contribution to the parent\n // counter is tracked so it can be released on unmount – a notification dismissed while\n // hovered or focused never fires `mouseleave` or `blur`, which would otherwise leave the\n // stack expanded and auto close paused forever.\n const contributedActiveRef = useRef(false);\n const offsetRef = useRef(0);\n const isCloseDisabled = allowClose === false;\n\n const syncActive = () => {\n const shouldContribute = hoveredRef.current || focusedRef.current;\n\n if (shouldContribute && !contributedActiveRef.current) {\n contributedActiveRef.current = true;\n onHoverStart?.();\n } else if (!shouldContribute && contributedActiveRef.current) {\n contributedActiveRef.current = false;\n onHoverEnd?.();\n }\n };\n\n const releaseActive = useEffectEvent(() => {\n if (contributedActiveRef.current) {\n contributedActiveRef.current = false;\n onHoverEnd?.();\n }\n });\n\n useEffect(() => () => releaseActive(), []);\n\n const cancelAutoClose = () => window.clearTimeout(autoCloseTimeout.current);\n const cancelHide = () => window.clearTimeout(hideTimeout.current);\n const cancelScrollDismissReset = () => window.clearTimeout(scrollDismissTimeout.current);\n\n const setSwipeOffset = (value: number) => {\n offsetRef.current = value;\n setOffset(value);\n };\n\n const handleHide = () => {\n onHide(data.id!);\n cancelAutoClose();\n cancelHide();\n cancelScrollDismissReset();\n };\n\n // `handleAutoClose` is also called from timeouts scheduled in earlier renders, so the\n // latest `paused` is read through a ref. Written in an effect rather than during render –\n // this effect is declared before every effect that calls `handleAutoClose`, so it is\n // always up to date by the time they run.\n const pausedRef = useRef(paused);\n\n useEffect(() => {\n pausedRef.current = paused;\n });\n\n const handleAutoClose = () => {\n if (\n dismissed ||\n active ||\n hoveredRef.current ||\n focusedRef.current ||\n pausedRef.current ||\n typeof autoCloseDuration !== 'number'\n ) {\n return;\n }\n\n cancelAutoClose();\n autoCloseTimeout.current = window.setTimeout(handleHide, autoCloseDuration);\n };\n\n const getExitOffset = (direction: -1 | 1) => {\n const width = notificationRef.current?.offsetWidth ?? 440;\n return direction * (width + 40);\n };\n\n const shouldDismiss = (movement: number, velocity: number) => {\n const width = notificationRef.current?.offsetWidth ?? 440;\n return Math.abs(movement) > width * 0.35 || velocity > 0.5;\n };\n\n const resetSwipe = () => {\n cancelScrollDismissReset();\n setScrollDismissActive(false);\n setSwipeOffset(0);\n };\n\n const dismissNotification = (direction: -1 | 1) => {\n setDismissDirection(direction);\n setDismissed(true);\n setScrollDismissActive(false);\n setSwipeOffset(getExitOffset(direction));\n cancelAutoClose();\n cancelHide();\n cancelScrollDismissReset();\n hideTimeout.current = window.setTimeout(handleHide, transitionDuration);\n };\n\n const scheduleScrollDismissReset = () => {\n cancelScrollDismissReset();\n scrollDismissTimeout.current = window.setTimeout(() => {\n setScrollDismissActive(false);\n setSwipeOffset(0);\n handleAutoClose();\n }, SCROLL_DISMISS_RESET_TIMEOUT);\n };\n\n const { ref: dragRef, active } = useDrag<HTMLDivElement>(\n (state) => {\n if (dismissed) {\n return;\n }\n\n if (state.first) {\n cancelAutoClose();\n }\n\n if (state.last) {\n if (state.tap || state.canceled) {\n setSwipeOffset(0);\n handleAutoClose();\n return;\n }\n\n const movement = state.movement[0];\n const direction =\n movement === 0 ? (state.direction[0] === -1 ? -1 : 1) : movement > 0 ? 1 : -1;\n\n if (shouldDismiss(movement, state.velocity[0])) {\n dismissNotification(direction);\n } else {\n setSwipeOffset(0);\n handleAutoClose();\n }\n } else {\n setSwipeOffset(state.movement[0]);\n }\n },\n {\n axis: 'x',\n threshold: 5,\n filterTaps: true,\n enabled: allowDragDismiss && !isCloseDisabled && !dismissed,\n }\n );\n\n const mergedRef = useMergedRef(ref, notificationRef, dragRef);\n const resolvedStyle = getStyleObject(style, theme);\n const resolvedDataStyle = getStyleObject(dataStyle, theme);\n const baseStyle = { ...resolvedStyle, ...resolvedDataStyle };\n const baseOpacity = typeof baseStyle.opacity === 'number' ? baseStyle.opacity : 1;\n const swipeOpacity = dismissed ? 0 : 1 - Math.min(Math.abs(offset) / 200, 1) * 0.6;\n const resolvedTransitionDuration =\n baseStyle.transitionDuration ??\n `${transitionDuration}ms, ${transitionDuration}ms, ${transitionDuration}ms`;\n\n const isStackedLayout = layout === 'stacked';\n const isStacked = isStackedLayout && stackIndex !== undefined && stackIndex > 0;\n const isCollapsed = isStacked && !stackExpanded;\n const isExiting = transitionState === 'exiting' || transitionState === 'exited';\n const stackDirection = stackPosition?.startsWith('top') ? 1 : -1;\n\n // Only a few layers are visible behind the front notification – without a cap the scale\n // below reaches 0 at 34 stacked notifications and inverts beyond that, which `limit` can\n // easily exceed.\n const stackDepth = Math.min(stackIndex ?? 0, MAX_VISIBLE_STACK_DEPTH);\n const collapsedOffset = isCollapsed ? stackDepth * 10 * stackDirection : 0;\n const staggerDelay = isStackedLayout ? (stackIndex || 0) * 30 : 0;\n const isDragging = active || scrollDismissActive;\n\n const getStackedTransform = () => {\n if (!isStackedLayout) {\n return 'var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)';\n }\n\n if (isExiting) {\n const exitOffset = stackExpanded ? stackExpandedOffset || 0 : collapsedOffset;\n return `translateY(${exitOffset}px) var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)`;\n }\n\n if (stackExpanded) {\n return `translateY(${stackExpandedOffset || 0}px) translate3d(var(--notifications-swipe-offset), 0, 0)`;\n }\n\n if (isStacked) {\n return `scale(${1 - stackDepth * 0.03}) translateY(${collapsedOffset}px)`;\n }\n\n return 'var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)';\n };\n\n const notificationStyle = {\n ...baseStyle,\n ...(isStackedLayout ? { maxHeight: undefined } : {}),\n ['--notifications-state-transform' as string]:\n typeof baseStyle.transform === 'string' ? baseStyle.transform : 'translateX(0)',\n ['--notifications-state-opacity' as string]: String(baseOpacity),\n ['--notifications-swipe-offset' as string]: `${offset}px`,\n ['--notifications-swipe-opacity' as string]: String(swipeOpacity),\n transform: getStackedTransform(),\n opacity: 'calc(var(--notifications-state-opacity) * var(--notifications-swipe-opacity))',\n transitionDuration: isDragging ? '0ms, 0ms, 0ms' : resolvedTransitionDuration,\n cursor: 'default',\n touchAction: 'pan-y',\n ...(isStackedLayout\n ? {\n gridArea: '1 / 1' as const,\n // `z-index` is not animatable, so it must not depend on `stackExpanded` – flipping\n // the stack to a single layer on hover repaints every notification in front of the\n // first one a frame before the reveal transform has moved anything.\n zIndex: (stackSize || 5) - (stackIndex ?? 0),\n pointerEvents: isCollapsed ? ('none' as const) : undefined,\n alignSelf: stackDirection === 1 ? ('start' as const) : ('end' as const),\n transitionProperty: isDragging ? 'none' : 'transform, opacity',\n transitionDuration: `${transitionDuration}ms, ${transitionDuration}ms`,\n transitionTimingFunction: 'cubic-bezier(.51,.3,0,1.21), ease',\n transitionDelay: isDragging || isExiting ? '0ms' : `${staggerDelay}ms`,\n }\n : {}),\n } as React.CSSProperties;\n\n const handleMouseEnter = () => {\n hoveredRef.current = true;\n cancelAutoClose();\n syncActive();\n };\n\n const handleMouseLeave = () => {\n hoveredRef.current = false;\n if (!scrollDismissActive) {\n resetSwipe();\n handleAutoClose();\n }\n syncActive();\n };\n\n // Keyboard users never trigger the hover handlers, and touch devices have no hover at\n // all – both need a way to expand a collapsed stack. Scoped to the stacked layout: its\n // only purpose is keeping the stack expanded, and applying it everywhere would silently\n // change the default layout, where a notification that merely contains the focused\n // element (an action button the user just clicked) would stop auto closing.\n const handleFocusCapture = isStackedLayout\n ? () => {\n focusedRef.current = true;\n cancelAutoClose();\n syncActive();\n }\n : undefined;\n\n const handleBlurCapture = isStackedLayout\n ? () => {\n focusedRef.current = false;\n if (!scrollDismissActive) {\n handleAutoClose();\n }\n syncActive();\n }\n : undefined;\n\n const handlePointerDownCapture = (event: React.PointerEvent) => {\n // Explicitly opt in for touch and pen: hover already covers the mouse, and an unknown\n // pointer type should not pin the stack open.\n if (isStackedLayout && (event.pointerType === 'touch' || event.pointerType === 'pen')) {\n onExpandRequest?.();\n }\n };\n\n const handleWheel = useEffectEvent((event: WheelEvent) => {\n if (dismissed || active) {\n return;\n }\n\n const isDocumentEvent = event.currentTarget === document;\n if (!isDocumentEvent && !hoveredRef.current) {\n return;\n }\n\n const { deltaX, deltaY } = event;\n if (Math.abs(deltaX) <= Math.abs(deltaY) || deltaX === 0) {\n return;\n }\n\n if (!allowScrollDismiss || isCloseDisabled) {\n return;\n }\n\n if (!isDocumentEvent) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n cancelAutoClose();\n setScrollDismissActive(true);\n\n const nextOffset = offsetRef.current - deltaX;\n const direction = nextOffset > 0 ? 1 : -1;\n\n if (shouldDismiss(nextOffset, 0)) {\n dismissNotification(direction);\n return;\n }\n\n setSwipeOffset(nextOffset);\n scheduleScrollDismissReset();\n });\n\n useEffect(() => {\n if (!scrollDismissActive) {\n return undefined;\n }\n\n document.addEventListener('wheel', handleWheel, { passive: false });\n return () => document.removeEventListener('wheel', handleWheel, { passive: false } as any);\n }, [scrollDismissActive]);\n\n useEffect(() => {\n const handleResize = () => {\n if (dismissed) {\n setSwipeOffset(getExitOffset(dismissDirection));\n }\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [dismissDirection, dismissed]);\n\n useEffect(() => {\n const node = notificationRef.current;\n if (!node) {\n return undefined;\n }\n\n node.addEventListener('wheel', handleWheel, { passive: false });\n return () => node.removeEventListener('wheel', handleWheel, { passive: false } as any);\n }, []);\n\n useEffect(() => {\n return () => {\n cancelHide();\n cancelScrollDismissReset();\n };\n }, []);\n\n useEffect(() => {\n data.onOpen?.(data);\n }, []);\n\n useEffect(() => {\n handleAutoClose();\n return cancelAutoClose;\n }, [autoCloseDuration, active, dismissed]);\n\n useEffect(() => {\n if (paused) {\n cancelAutoClose();\n } else {\n handleAutoClose();\n }\n\n return cancelAutoClose;\n }, [paused]);\n\n const consumerProps: Record<string, any> = { ...others, ...notificationProps };\n\n // The interaction handlers below are internal, but the same events are part of the public\n // props of both `Notifications` and every notification – they are composed with whatever\n // the consumer passed instead of replacing it.\n const interactionProps = {\n style: notificationStyle,\n // A collapsed notification is hidden behind the one in front of it – `pointer-events`\n // alone does not take its controls out of the tab order or hide them from a screen\n // reader, so it is fully inert until the stack is expanded.\n inert: isCollapsed,\n onMouseEnter: (event: React.MouseEvent<HTMLDivElement>) => {\n consumerProps.onMouseEnter?.(event);\n handleMouseEnter();\n },\n onMouseLeave: (event: React.MouseEvent<HTMLDivElement>) => {\n consumerProps.onMouseLeave?.(event);\n handleMouseLeave();\n },\n onFocusCapture: (event: React.FocusEvent<HTMLDivElement>) => {\n consumerProps.onFocusCapture?.(event);\n handleFocusCapture?.();\n },\n onBlurCapture: (event: React.FocusEvent<HTMLDivElement>) => {\n consumerProps.onBlurCapture?.(event);\n handleBlurCapture?.();\n },\n onPointerDownCapture: (event: React.PointerEvent<HTMLDivElement>) => {\n consumerProps.onPointerDownCapture?.(event);\n handlePointerDownCapture(event);\n },\n };\n\n if (renderNotification) {\n const classNames = [others.className, notificationProps.className].filter(Boolean).join(' ');\n\n return (\n <div\n ref={mergedRef}\n role={notificationProps.role || others.role || 'alert'}\n {...pickDomProps(consumerProps)}\n className={classNames || undefined}\n {...interactionProps}\n >\n {renderNotification(data)}\n </div>\n );\n }\n\n return (\n <Notification\n ref={mergedRef}\n {...others}\n {...notificationProps}\n {...interactionProps}\n withCloseButton={isCloseDisabled ? false : withCloseButton}\n onClose={handleHide}\n >\n {message}\n </Notification>\n );\n}\n\nNotificationContainer.displayName = '@mantine/notifications/NotificationContainer';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NotificationContainer.mjs","names":[],"sources":["../src/NotificationContainer.tsx"],"sourcesContent":["import { useEffect, useEffectEvent, useRef, useState } from 'react';\nimport {\n extractStyleProps,\n getStyleObject,\n Notification,\n NotificationProps,\n useMantineTheme,\n} from '@mantine/core';\nimport { useDidUpdate, useDrag, useMergedRef } from '@mantine/hooks';\nimport { getAutoClose } from './get-auto-close/get-auto-close';\nimport { NotificationData } from './notifications.store';\n\nconst SCROLL_DISMISS_RESET_TIMEOUT = 120;\n\ninterface NotificationContainerProps extends NotificationProps {\n data: NotificationData;\n onHide: (id: string) => void;\n autoClose: number | false;\n transitionDuration: number;\n allowDragDismiss: boolean;\n allowScrollDismiss: boolean;\n paused: boolean;\n withAutoCloseProgress: boolean;\n progressProps: Record<string, any>;\n onHoverStart?: () => void;\n onHoverEnd?: () => void;\n onExpandRequest?: () => void;\n ref?: React.Ref<HTMLDivElement>;\n renderNotification?: ((notification: NotificationData) => React.ReactNode) | null;\n layout?: 'default' | 'stacked';\n stackIndex?: number;\n stackSize?: number;\n stackPosition?: string;\n stackExpanded?: boolean;\n stackExpandedOffset?: number;\n transitionState?: string;\n}\n\nconst MAX_VISIBLE_STACK_DEPTH = 4;\n\n/**\n * Props that belong to the default `Notification` rendering or to the Styles API and must\n * not reach the plain `div` used for custom rendering. Everything else is a valid div prop\n * and is forwarded – an allow list would silently drop supported props like `onClick`,\n * `dir`, `lang` or `hidden`.\n */\nconst NON_DOM_PROPS = new Set([\n 'classNames',\n 'styles',\n 'unstyled',\n 'vars',\n 'attributes',\n 'variant',\n 'color',\n 'radius',\n 'icon',\n 'title',\n 'loading',\n 'withBorder',\n 'withCloseButton',\n 'closeButtonProps',\n 'className',\n 'style',\n 'role',\n 'ref',\n 'children',\n 'mod',\n]);\n\nfunction pickDomProps(props: Record<string, any>) {\n // Mantine style props (`mt`, `bg`, `w`, …) are valid `NotificationProps` but are not DOM\n // attributes, so they are separated out rather than leaked onto the element.\n const { rest } = extractStyleProps(props);\n\n return Object.fromEntries(\n Object.entries(rest).filter(([key, value]) => !NON_DOM_PROPS.has(key) && value !== undefined)\n );\n}\n\nexport function NotificationContainer({\n data,\n onHide,\n autoClose,\n transitionDuration,\n allowDragDismiss,\n allowScrollDismiss,\n paused,\n withAutoCloseProgress,\n progressProps,\n onHoverStart,\n onHoverEnd,\n onExpandRequest,\n ref,\n style,\n renderNotification,\n layout,\n stackIndex,\n stackSize,\n stackPosition,\n stackExpanded,\n stackExpandedOffset,\n transitionState,\n ...others\n}: NotificationContainerProps) {\n const [offset, setOffset] = useState(0);\n const [dismissed, setDismissed] = useState(false);\n const [dismissDirection, setDismissDirection] = useState<-1 | 1>(1);\n const [scrollDismissActive, setScrollDismissActive] = useState(false);\n const theme = useMantineTheme();\n const {\n autoClose: _autoClose,\n message,\n allowClose,\n position: _position,\n style: dataStyle,\n withCloseButton,\n renderNotification: _renderNotification,\n onOpen: _onOpen,\n priority: _priority,\n withAutoCloseProgress: _withAutoCloseProgress,\n __sequence: _sequence,\n ...notificationProps\n } = data as NotificationData & { __sequence?: number };\n const autoCloseDuration = getAutoClose(autoClose, data.autoClose);\n const [autoCloseProgress, setAutoCloseProgress] = useState({ running: false, cycle: 0 });\n const hasAutoCloseProgress =\n (data.withAutoCloseProgress ?? withAutoCloseProgress) && typeof autoCloseDuration === 'number';\n const autoCloseTimeout = useRef<number>(-1);\n const hideTimeout = useRef<number>(-1);\n const scrollDismissTimeout = useRef<number>(-1);\n const notificationRef = useRef<HTMLDivElement>(null);\n const hoveredRef = useRef(false);\n const focusedRef = useRef(false);\n\n // Hover and focus both keep the notification \"active\". The contribution to the parent\n // counter is tracked so it can be released on unmount – a notification dismissed while\n // hovered or focused never fires `mouseleave` or `blur`, which would otherwise leave the\n // stack expanded and auto close paused forever.\n const contributedActiveRef = useRef(false);\n const offsetRef = useRef(0);\n const isCloseDisabled = allowClose === false;\n\n const syncActive = () => {\n const shouldContribute = hoveredRef.current || focusedRef.current;\n\n if (shouldContribute && !contributedActiveRef.current) {\n contributedActiveRef.current = true;\n onHoverStart?.();\n } else if (!shouldContribute && contributedActiveRef.current) {\n contributedActiveRef.current = false;\n onHoverEnd?.();\n }\n };\n\n const releaseActive = useEffectEvent(() => {\n if (contributedActiveRef.current) {\n contributedActiveRef.current = false;\n onHoverEnd?.();\n }\n });\n\n useEffect(() => () => releaseActive(), []);\n\n const cancelAutoClose = () => {\n window.clearTimeout(autoCloseTimeout.current);\n setAutoCloseProgress((current) => (current.running ? { ...current, running: false } : current));\n };\n const cancelHide = () => window.clearTimeout(hideTimeout.current);\n const cancelScrollDismissReset = () => window.clearTimeout(scrollDismissTimeout.current);\n\n const setSwipeOffset = (value: number) => {\n offsetRef.current = value;\n setOffset(value);\n };\n\n const handleHide = () => {\n onHide(data.id!);\n cancelAutoClose();\n cancelHide();\n cancelScrollDismissReset();\n };\n\n // `handleAutoClose` is also called from timeouts scheduled in earlier renders, so the\n // latest `paused` is read through a ref. Written in an effect rather than during render –\n // this effect is declared before every effect that calls `handleAutoClose`, so it is\n // always up to date by the time they run.\n const pausedRef = useRef(paused);\n\n useEffect(() => {\n pausedRef.current = paused;\n });\n\n const handleAutoClose = () => {\n if (\n dismissed ||\n active ||\n hoveredRef.current ||\n focusedRef.current ||\n pausedRef.current ||\n typeof autoCloseDuration !== 'number'\n ) {\n return;\n }\n\n cancelAutoClose();\n autoCloseTimeout.current = window.setTimeout(handleHide, autoCloseDuration);\n setAutoCloseProgress((current) => ({ running: true, cycle: current.cycle + 1 }));\n };\n\n const getExitOffset = (direction: -1 | 1) => {\n const width = notificationRef.current?.offsetWidth ?? 440;\n return direction * (width + 40);\n };\n\n const shouldDismiss = (movement: number, velocity: number) => {\n const width = notificationRef.current?.offsetWidth ?? 440;\n return Math.abs(movement) > width * 0.35 || velocity > 0.5;\n };\n\n const resetSwipe = () => {\n cancelScrollDismissReset();\n setScrollDismissActive(false);\n setSwipeOffset(0);\n };\n\n const dismissNotification = (direction: -1 | 1) => {\n setDismissDirection(direction);\n setDismissed(true);\n setScrollDismissActive(false);\n setSwipeOffset(getExitOffset(direction));\n cancelAutoClose();\n cancelHide();\n cancelScrollDismissReset();\n hideTimeout.current = window.setTimeout(handleHide, transitionDuration);\n };\n\n const scheduleScrollDismissReset = () => {\n cancelScrollDismissReset();\n scrollDismissTimeout.current = window.setTimeout(() => {\n setScrollDismissActive(false);\n setSwipeOffset(0);\n handleAutoClose();\n }, SCROLL_DISMISS_RESET_TIMEOUT);\n };\n\n const { ref: dragRef, active } = useDrag<HTMLDivElement>(\n (state) => {\n if (dismissed) {\n return;\n }\n\n if (state.first) {\n cancelAutoClose();\n }\n\n if (state.last) {\n if (state.tap || state.canceled) {\n setSwipeOffset(0);\n handleAutoClose();\n return;\n }\n\n const movement = state.movement[0];\n const direction =\n movement === 0 ? (state.direction[0] === -1 ? -1 : 1) : movement > 0 ? 1 : -1;\n\n if (shouldDismiss(movement, state.velocity[0])) {\n dismissNotification(direction);\n } else {\n setSwipeOffset(0);\n handleAutoClose();\n }\n } else {\n setSwipeOffset(state.movement[0]);\n }\n },\n {\n axis: 'x',\n threshold: 5,\n filterTaps: true,\n enabled: allowDragDismiss && !isCloseDisabled && !dismissed,\n }\n );\n\n const mergedRef = useMergedRef(ref, notificationRef, dragRef);\n const resolvedStyle = getStyleObject(style, theme);\n const resolvedDataStyle = getStyleObject(dataStyle, theme);\n const baseStyle = { ...resolvedStyle, ...resolvedDataStyle };\n const baseOpacity = typeof baseStyle.opacity === 'number' ? baseStyle.opacity : 1;\n const swipeOpacity = dismissed ? 0 : 1 - Math.min(Math.abs(offset) / 200, 1) * 0.6;\n const resolvedTransitionDuration =\n baseStyle.transitionDuration ??\n `${transitionDuration}ms, ${transitionDuration}ms, ${transitionDuration}ms`;\n\n const isStackedLayout = layout === 'stacked';\n const isStacked = isStackedLayout && stackIndex !== undefined && stackIndex > 0;\n const isCollapsed = isStacked && !stackExpanded;\n const isExiting = transitionState === 'exiting' || transitionState === 'exited';\n const stackDirection = stackPosition?.startsWith('top') ? 1 : -1;\n\n // Only a few layers are visible behind the front notification – without a cap the scale\n // below reaches 0 at 34 stacked notifications and inverts beyond that, which `limit` can\n // easily exceed.\n const stackDepth = Math.min(stackIndex ?? 0, MAX_VISIBLE_STACK_DEPTH);\n const collapsedOffset = isCollapsed ? stackDepth * 10 * stackDirection : 0;\n const staggerDelay = isStackedLayout ? (stackIndex || 0) * 30 : 0;\n const isDragging = active || scrollDismissActive;\n\n const getStackedTransform = () => {\n if (!isStackedLayout) {\n return 'var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)';\n }\n\n if (isExiting) {\n const exitOffset = stackExpanded ? stackExpandedOffset || 0 : collapsedOffset;\n return `translateY(${exitOffset}px) var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)`;\n }\n\n if (stackExpanded) {\n return `translateY(${stackExpandedOffset || 0}px) translate3d(var(--notifications-swipe-offset), 0, 0)`;\n }\n\n if (isStacked) {\n return `scale(${1 - stackDepth * 0.03}) translateY(${collapsedOffset}px)`;\n }\n\n return 'var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)';\n };\n\n const notificationStyle = {\n ...baseStyle,\n ...(isStackedLayout ? { maxHeight: undefined } : {}),\n ['--notifications-state-transform' as string]:\n typeof baseStyle.transform === 'string' ? baseStyle.transform : 'translateX(0)',\n ['--notifications-state-opacity' as string]: String(baseOpacity),\n ['--notifications-swipe-offset' as string]: `${offset}px`,\n ['--notifications-swipe-opacity' as string]: String(swipeOpacity),\n transform: getStackedTransform(),\n opacity: 'calc(var(--notifications-state-opacity) * var(--notifications-swipe-opacity))',\n transitionDuration: isDragging ? '0ms, 0ms, 0ms' : resolvedTransitionDuration,\n cursor: 'default',\n touchAction: 'pan-y',\n ...(isStackedLayout\n ? {\n gridArea: '1 / 1' as const,\n // `z-index` is not animatable, so it must not depend on `stackExpanded` – flipping\n // the stack to a single layer on hover repaints every notification in front of the\n // first one a frame before the reveal transform has moved anything.\n zIndex: (stackSize || 5) - (stackIndex ?? 0),\n pointerEvents: isCollapsed ? ('none' as const) : undefined,\n alignSelf: stackDirection === 1 ? ('start' as const) : ('end' as const),\n transitionProperty: isDragging ? 'none' : 'transform, opacity',\n transitionDuration: `${transitionDuration}ms, ${transitionDuration}ms`,\n transitionTimingFunction: 'cubic-bezier(.51,.3,0,1.21), ease',\n transitionDelay: isDragging || isExiting ? '0ms' : `${staggerDelay}ms`,\n }\n : {}),\n } as React.CSSProperties;\n\n const handleMouseEnter = () => {\n hoveredRef.current = true;\n cancelAutoClose();\n syncActive();\n };\n\n const handleMouseLeave = () => {\n hoveredRef.current = false;\n if (!scrollDismissActive) {\n resetSwipe();\n handleAutoClose();\n }\n syncActive();\n };\n\n // Keyboard users never trigger the hover handlers, and touch devices have no hover at\n // all – both need a way to expand a collapsed stack. Scoped to the stacked layout: its\n // only purpose is keeping the stack expanded, and applying it everywhere would silently\n // change the default layout, where a notification that merely contains the focused\n // element (an action button the user just clicked) would stop auto closing.\n const handleFocusCapture = isStackedLayout\n ? () => {\n focusedRef.current = true;\n cancelAutoClose();\n syncActive();\n }\n : undefined;\n\n const handleBlurCapture = isStackedLayout\n ? () => {\n focusedRef.current = false;\n if (!scrollDismissActive) {\n handleAutoClose();\n }\n syncActive();\n }\n : undefined;\n\n const handlePointerDownCapture = (event: React.PointerEvent) => {\n // Explicitly opt in for touch and pen: hover already covers the mouse, and an unknown\n // pointer type should not pin the stack open.\n if (isStackedLayout && (event.pointerType === 'touch' || event.pointerType === 'pen')) {\n onExpandRequest?.();\n }\n };\n\n const handleWheel = useEffectEvent((event: WheelEvent) => {\n if (dismissed || active) {\n return;\n }\n\n const isDocumentEvent = event.currentTarget === document;\n if (!isDocumentEvent && !hoveredRef.current) {\n return;\n }\n\n const { deltaX, deltaY } = event;\n if (Math.abs(deltaX) <= Math.abs(deltaY) || deltaX === 0) {\n return;\n }\n\n if (!allowScrollDismiss || isCloseDisabled) {\n return;\n }\n\n if (!isDocumentEvent) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n cancelAutoClose();\n setScrollDismissActive(true);\n\n const nextOffset = offsetRef.current - deltaX;\n const direction = nextOffset > 0 ? 1 : -1;\n\n if (shouldDismiss(nextOffset, 0)) {\n dismissNotification(direction);\n return;\n }\n\n setSwipeOffset(nextOffset);\n scheduleScrollDismissReset();\n });\n\n useEffect(() => {\n if (!scrollDismissActive) {\n return undefined;\n }\n\n document.addEventListener('wheel', handleWheel, { passive: false });\n return () => document.removeEventListener('wheel', handleWheel, { passive: false } as any);\n }, [scrollDismissActive]);\n\n useEffect(() => {\n const handleResize = () => {\n if (dismissed) {\n setSwipeOffset(getExitOffset(dismissDirection));\n }\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [dismissDirection, dismissed]);\n\n useEffect(() => {\n const node = notificationRef.current;\n if (!node) {\n return undefined;\n }\n\n node.addEventListener('wheel', handleWheel, { passive: false });\n return () => node.removeEventListener('wheel', handleWheel, { passive: false } as any);\n }, []);\n\n useEffect(() => {\n return () => {\n cancelHide();\n cancelScrollDismissReset();\n };\n }, []);\n\n useEffect(() => {\n data.onOpen?.(data);\n }, []);\n\n const previousTransitionState = useRef(transitionState);\n\n useEffect(() => {\n const wasExiting = previousTransitionState.current === 'exiting';\n previousTransitionState.current = transitionState;\n\n if (transitionState !== 'entering' || !wasExiting) {\n return;\n }\n\n cancelHide();\n\n if (dismissed) {\n setDismissed(false);\n setScrollDismissActive(false);\n setSwipeOffset(0);\n } else {\n handleAutoClose();\n }\n\n data.onOpen?.(data);\n }, [transitionState]);\n\n useEffect(() => {\n handleAutoClose();\n return cancelAutoClose;\n }, [autoCloseDuration, active, dismissed]);\n\n useDidUpdate(() => {\n if (hasAutoCloseProgress) {\n handleAutoClose();\n }\n }, [hasAutoCloseProgress]);\n\n useEffect(() => {\n if (paused) {\n cancelAutoClose();\n } else {\n handleAutoClose();\n }\n\n return cancelAutoClose;\n }, [paused]);\n\n const consumerProps: Record<string, any> = { ...others, ...notificationProps };\n\n // The interaction handlers below are internal, but the same events are part of the public\n // props of both `Notifications` and every notification – they are composed with whatever\n // the consumer passed instead of replacing it.\n const interactionProps = {\n style: notificationStyle,\n // A collapsed notification is hidden behind the one in front of it – `pointer-events`\n // alone does not take its controls out of the tab order or hide them from a screen\n // reader, so it is fully inert until the stack is expanded.\n inert: isCollapsed,\n onMouseEnter: (event: React.MouseEvent<HTMLDivElement>) => {\n consumerProps.onMouseEnter?.(event);\n handleMouseEnter();\n },\n onMouseLeave: (event: React.MouseEvent<HTMLDivElement>) => {\n consumerProps.onMouseLeave?.(event);\n handleMouseLeave();\n },\n onFocusCapture: (event: React.FocusEvent<HTMLDivElement>) => {\n consumerProps.onFocusCapture?.(event);\n handleFocusCapture?.();\n },\n onBlurCapture: (event: React.FocusEvent<HTMLDivElement>) => {\n consumerProps.onBlurCapture?.(event);\n handleBlurCapture?.();\n },\n onPointerDownCapture: (event: React.PointerEvent<HTMLDivElement>) => {\n consumerProps.onPointerDownCapture?.(event);\n handlePointerDownCapture(event);\n },\n };\n\n if (renderNotification) {\n const classNames = [others.className, notificationProps.className].filter(Boolean).join(' ');\n\n return (\n <div\n ref={mergedRef}\n role={notificationProps.role || others.role || 'alert'}\n {...pickDomProps(consumerProps)}\n className={classNames || undefined}\n {...interactionProps}\n >\n {renderNotification(data)}\n </div>\n );\n }\n\n return (\n <Notification\n ref={mergedRef}\n {...others}\n {...notificationProps}\n {...interactionProps}\n withCloseButton={isCloseDisabled ? false : withCloseButton}\n onClose={handleHide}\n >\n {message}\n {hasAutoCloseProgress && (\n <div\n key={autoCloseProgress.cycle}\n aria-hidden\n {...progressProps}\n data-paused={!autoCloseProgress.running || undefined}\n style={{\n ...progressProps.style,\n ['--notifications-progress-duration' as string]: `${autoCloseDuration}ms`,\n }}\n />\n )}\n </Notification>\n );\n}\n\nNotificationContainer.displayName = '@mantine/notifications/NotificationContainer';\n"],"mappings":"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"}
|
package/esm/Notifications.mjs
CHANGED
|
@@ -28,7 +28,8 @@ const defaultProps = {
|
|
|
28
28
|
store: notificationsStore,
|
|
29
29
|
withinPortal: true,
|
|
30
30
|
pauseResetOnHover: "all",
|
|
31
|
-
layout: "default"
|
|
31
|
+
layout: "default",
|
|
32
|
+
withAutoCloseProgress: false
|
|
32
33
|
};
|
|
33
34
|
const varsResolver = createVarsResolver((_, { zIndex, containerWidth }) => ({ root: {
|
|
34
35
|
"--notifications-z-index": zIndex?.toString(),
|
|
@@ -36,7 +37,7 @@ const varsResolver = createVarsResolver((_, { zIndex, containerWidth }) => ({ ro
|
|
|
36
37
|
} }));
|
|
37
38
|
const Notifications = factory((_props) => {
|
|
38
39
|
const props = useProps("Notifications", defaultProps, _props);
|
|
39
|
-
const { classNames, className, style, styles, unstyled, vars, attributes, position, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, containerWidth, notificationMaxHeight, limit, zIndex, store, portalProps, withinPortal, pauseResetOnHover, renderNotification, layout, ...others } = props;
|
|
40
|
+
const { classNames, className, style, styles, unstyled, vars, attributes, position, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, containerWidth, notificationMaxHeight, limit, zIndex, store, portalProps, withinPortal, pauseResetOnHover, renderNotification, layout, withAutoCloseProgress, ...others } = props;
|
|
40
41
|
const theme = useMantineTheme();
|
|
41
42
|
const data = useNotifications(store);
|
|
42
43
|
const forceUpdate = useForceUpdate();
|
|
@@ -222,6 +223,8 @@ const Notifications = factory((_props) => {
|
|
|
222
223
|
onExpandRequest: () => handleExpandRequest(pos),
|
|
223
224
|
renderNotification: "renderNotification" in notification ? notification.renderNotification : renderNotification,
|
|
224
225
|
layout,
|
|
226
|
+
withAutoCloseProgress,
|
|
227
|
+
progressProps: getStyles("progress"),
|
|
225
228
|
stackIndex,
|
|
226
229
|
stackSize: groupLength,
|
|
227
230
|
stackPosition: pos,
|
|
@@ -315,6 +318,7 @@ Notifications.displayName = "@mantine/notifications/Notifications";
|
|
|
315
318
|
Notifications.show = notifications.show;
|
|
316
319
|
Notifications.hide = notifications.hide;
|
|
317
320
|
Notifications.update = notifications.update;
|
|
321
|
+
Notifications.promise = notifications.promise;
|
|
318
322
|
Notifications.clean = notifications.clean;
|
|
319
323
|
Notifications.cleanQueue = notifications.cleanQueue;
|
|
320
324
|
Notifications.updateState = notifications.updateState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Notifications.mjs","names":["Transition","_Transition","classes"],"sources":["../src/Notifications.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n Transition as _Transition,\n TransitionGroup,\n TransitionStatus,\n} from 'react-transition-group';\nimport {\n BasePortalProps,\n Box,\n BoxProps,\n createVarsResolver,\n ElementProps,\n factory,\n Factory,\n getDefaultZIndex,\n OptionalPortal,\n rem,\n RemoveScroll,\n StylesApiProps,\n useMantineTheme,\n useProps,\n useStyles,\n} from '@mantine/core';\nimport { useDidUpdate, useForceUpdate, useReducedMotion } from '@mantine/hooks';\nimport {\n getGroupedNotifications,\n positions,\n} from './get-grouped-notifications/get-grouped-notifications';\nimport { getNotificationStateStyles } from './get-notification-state-styles';\nimport { NotificationContainer } from './NotificationContainer';\nimport {\n hideNotification,\n NotificationData,\n NotificationPosition,\n notifications,\n NotificationsStore,\n notificationsStore,\n SequencedNotificationData,\n useNotifications,\n} from './notifications.store';\nimport classes from './Notifications.module.css';\n\nconst Transition: any = _Transition;\n\n/** Vertical gap between notifications of an expanded stack, in px */\nconst STACK_EXPANDED_GAP = 16;\n\n/** Offset step used for a notification that has not been measured yet, in px */\nconst FALLBACK_NOTIFICATION_HEIGHT = 80;\n\nexport type NotificationsStylesNames = 'root' | 'notification';\nexport type NotificationsCssVariables = {\n root: '--notifications-z-index' | '--notifications-container-width';\n};\n\nexport interface NotificationsProps\n extends BoxProps, StylesApiProps<NotificationsFactory>, ElementProps<'div'> {\n /** Notifications default position @default 'bottom-right' */\n position?: NotificationPosition;\n\n /** Auto close timeout for all notifications in ms, `false` to disable auto close, can be overwritten for individual notifications in `notifications.show` function @default 4000 */\n autoClose?: number | false;\n\n /** Notification transition duration in ms @default 250 */\n transitionDuration?: number;\n\n /** Determines whether notifications can be dismissed by dragging left or right @default true */\n allowDragDismiss?: boolean;\n\n /** Determines whether notifications can be dismissed with horizontal scroll gesture while hovered @default true */\n allowScrollDismiss?: boolean;\n\n /** Notification width, cannot exceed 100% @default 440 */\n containerWidth?: number | string;\n\n /** Notification `max-height`, used for transitions @default 200 */\n notificationMaxHeight?: number | string;\n\n /** Maximum number of notifications displayed at a time, other new notifications will be added to queue @default 5 */\n limit?: number;\n\n /** Notifications container z-index @default 400 */\n zIndex?: string | number;\n\n /** Props passed down to the `Portal` component */\n portalProps?: BasePortalProps;\n\n /** Store for notifications state, can be used to create multiple instances of notifications system in your application */\n store?: NotificationsStore;\n\n /** Determines whether notifications container should be rendered inside `Portal` @default true */\n withinPortal?: boolean;\n\n /** Determines which notifications should pause auto close on hover, `'all'` – pauses auto close for all notifications when any notification is hovered, `'notification'` – pauses auto close only for the hovered notification @default 'all' */\n pauseResetOnHover?: 'all' | 'notification';\n\n /** Custom render function that replaces the default notification, can be overridden per notification */\n renderNotification?: (notification: NotificationData) => React.ReactNode;\n\n /** Controls how notifications are positioned in the stack, `'default'` – standard vertical list, `'stacked'` – only first notification is fully visible, rest are stacked behind @default 'default' */\n layout?: 'default' | 'stacked';\n}\n\nexport type NotificationsFactory = Factory<{\n props: NotificationsProps;\n ref: HTMLDivElement;\n stylesNames: NotificationsStylesNames;\n vars: NotificationsCssVariables;\n staticComponents: {\n show: typeof notifications.show;\n hide: typeof notifications.hide;\n update: typeof notifications.update;\n clean: typeof notifications.clean;\n cleanQueue: typeof notifications.cleanQueue;\n updateState: typeof notifications.updateState;\n };\n}>;\n\nconst defaultProps = {\n position: 'bottom-right',\n autoClose: 4000,\n transitionDuration: 250,\n allowDragDismiss: true,\n allowScrollDismiss: true,\n containerWidth: 440,\n notificationMaxHeight: 200,\n limit: 5,\n zIndex: getDefaultZIndex('overlay'),\n store: notificationsStore,\n withinPortal: true,\n pauseResetOnHover: 'all',\n layout: 'default',\n} satisfies Partial<NotificationsProps>;\n\nconst varsResolver = createVarsResolver<NotificationsFactory>((_, { zIndex, containerWidth }) => ({\n root: {\n '--notifications-z-index': zIndex?.toString(),\n '--notifications-container-width': rem(containerWidth),\n },\n}));\n\nexport const Notifications = factory<NotificationsFactory>((_props) => {\n const props = useProps('Notifications', defaultProps, _props);\n const {\n classNames,\n className,\n style,\n styles,\n unstyled,\n vars,\n attributes,\n position,\n autoClose,\n transitionDuration,\n allowDragDismiss,\n allowScrollDismiss,\n containerWidth,\n notificationMaxHeight,\n limit,\n zIndex,\n store,\n portalProps,\n withinPortal,\n pauseResetOnHover,\n renderNotification,\n layout,\n ...others\n } = props;\n\n const theme = useMantineTheme();\n const data = useNotifications(store);\n const forceUpdate = useForceUpdate();\n const shouldReduceMotion = useReducedMotion();\n const refs = useRef<Record<string, HTMLDivElement>>({});\n const previousLength = useRef<number>(0);\n // Every position renders its own stack, so hover, expansion and pinning are tracked per\n // position – a single shared flag made hovering one corner expand all six of them.\n const [hoveredCounts, setHoveredCounts] = useState<Partial<Record<NotificationPosition, number>>>(\n {}\n );\n const [expandedPositions, setExpandedPositions] = useState<\n Partial<Record<NotificationPosition, boolean>>\n >({});\n const [hoveredGroups, setHoveredGroups] = useState<\n Partial<Record<NotificationPosition, boolean>>\n >({});\n const [pinnedPosition, setPinnedPosition] = useState<NotificationPosition | null>(null);\n const collapseTimeouts = useRef<Partial<Record<NotificationPosition, number>>>({});\n\n // `pauseResetOnHover=\"all\"` is documented as pausing every notification when any one of\n // them is hovered, so this stays global while the stack state above does not.\n const hoveredCount =\n Object.values(hoveredCounts).reduce((acc, count) => acc + (count ?? 0), 0) +\n Object.values(hoveredGroups).filter(Boolean).length;\n\n const handleHoverStart = useCallback(\n (pos: NotificationPosition) =>\n setHoveredCounts((current) => ({ ...current, [pos]: (current[pos] ?? 0) + 1 })),\n []\n );\n\n const handleHoverEnd = useCallback(\n (pos: NotificationPosition) =>\n setHoveredCounts((current) => ({ ...current, [pos]: Math.max(0, (current[pos] ?? 0) - 1) })),\n []\n );\n\n // Stacked hover is also tracked on the group element that wraps a stack, not only on the\n // individual notifications. When the hovered notification unmounts, React does not deliver\n // `onMouseEnter` to the one that slides under a stationary pointer: the browser dispatches\n // only a `mouseover` for the new target (no `mouseout`, the old node is gone), and the\n // enter/leave plugin drops it because its `relatedTarget` still resolves to a React\n // instance. The group is hovered throughout, so its state needs no event to stay correct\n // and the stack stays open until the pointer really leaves.\n // Kept apart from the notification counter above so that it can be released on its own –\n // the group has no unmount hook to fall back on the way a notification does.\n const getGroupHoverProps = useCallback(\n (pos: NotificationPosition) =>\n layout === 'stacked'\n ? {\n onMouseEnter: () => setHoveredGroups((current) => ({ ...current, [pos]: true })),\n onMouseLeave: () => setHoveredGroups((current) => ({ ...current, [pos]: false })),\n }\n : {},\n [layout]\n );\n\n // Touch devices have no hover, so tapping the stack pins it open until the next tap\n // outside of it. Without this the notifications behind the first one are unreachable.\n const handleExpandRequest = useCallback(\n (pos: NotificationPosition) => setPinnedPosition(pos),\n []\n );\n\n useEffect(() => {\n if (layout !== 'stacked') {\n return undefined;\n }\n\n const timeouts = collapseTimeouts.current;\n\n positions.forEach((pos) => {\n if ((hoveredCounts[pos] ?? 0) > 0 || hoveredGroups[pos] || pinnedPosition === pos) {\n window.clearTimeout(timeouts[pos]);\n setExpandedPositions((current) => (current[pos] ? current : { ...current, [pos]: true }));\n } else {\n timeouts[pos] = window.setTimeout(() => {\n setExpandedPositions((current) =>\n current[pos] ? { ...current, [pos]: false } : current\n );\n }, 200);\n }\n });\n\n return () => positions.forEach((pos) => window.clearTimeout(timeouts[pos]));\n }, [hoveredCounts, hoveredGroups, pinnedPosition, layout]);\n\n useEffect(() => {\n if (!pinnedPosition) {\n return undefined;\n }\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target as Node | null;\n const insideStack =\n target !== null && Object.values(refs.current).some((element) => element?.contains(target));\n\n if (!insideStack) {\n setPinnedPosition(null);\n }\n };\n\n document.addEventListener('pointerdown', handlePointerDown);\n return () => document.removeEventListener('pointerdown', handlePointerDown);\n }, [pinnedPosition]);\n\n const grouped = getGroupedNotifications(data.notifications, position);\n const pinnedCount = pinnedPosition ? grouped[pinnedPosition].length : 0;\n\n useEffect(() => {\n if (layout !== 'stacked' || (pinnedPosition !== null && pinnedCount === 0)) {\n setPinnedPosition(null);\n }\n }, [pinnedCount, pinnedPosition, layout]);\n\n // Leaving the stacked layout takes the handlers below out of the tree, so nothing can ever\n // deliver the `mouseleave` that would release the group and a stale flag would keep auto\n // close paused forever. Emptying a stack needs no such handling – the browser drops the\n // hover on its own once the last notification is removed, and releasing it here instead\n // would fire while the dismissed notification is still exiting under the pointer.\n useEffect(() => {\n if (layout !== 'stacked') {\n setHoveredGroups((current) => (Object.values(current).some(Boolean) ? {} : current));\n }\n }, [layout]);\n\n // Expanded stack offsets need the height of every notification. Measuring during render\n // would force a layout pass on every hover, focus and store update, so heights are cached\n // here and refreshed from the ResizeObserver – which also covers a notification that grows\n // after mount (image loads, async content, viewport reflow) and would otherwise leave the\n // ones after it overlapping or gapped until something else triggered a render.\n const resizeObserver = useRef<ResizeObserver | null>(null);\n const measuredHeights = useRef<Record<string, number>>({});\n const observedIds = useRef(new WeakMap<Element, string>());\n\n const measureNotification = useCallback((id: string, element: HTMLElement) => {\n const height = element.offsetHeight;\n\n if (measuredHeights.current[id] === height) {\n return false;\n }\n\n measuredHeights.current[id] = height;\n return true;\n }, []);\n\n useEffect(() => {\n if (layout !== 'stacked' || typeof ResizeObserver === 'undefined') {\n return undefined;\n }\n\n const observer = new ResizeObserver((entries) => {\n let changed = false;\n\n entries.forEach((entry) => {\n const id = observedIds.current.get(entry.target);\n\n if (id && measureNotification(id, entry.target as HTMLElement)) {\n changed = true;\n }\n });\n\n if (changed) {\n forceUpdate();\n }\n });\n\n resizeObserver.current = observer;\n Object.values(refs.current).forEach((element) => element && observer.observe(element));\n\n return () => {\n observer.disconnect();\n resizeObserver.current = null;\n };\n }, [layout, forceUpdate, measureNotification]);\n\n const refCallbacks = useRef<Record<string, (node: HTMLDivElement | null) => void>>({});\n\n const getNotificationRef = useCallback(\n (id: string) => {\n if (!refCallbacks.current[id]) {\n refCallbacks.current[id] = (node: HTMLDivElement | null) => {\n const previous = refs.current[id];\n\n if (previous && previous !== node) {\n resizeObserver.current?.unobserve(previous);\n observedIds.current.delete(previous);\n }\n\n if (node) {\n refs.current[id] = node;\n observedIds.current.set(node, id);\n // Measured here rather than during render – the commit phase is where a layout\n // read is already paid for, and the ResizeObserver keeps the value fresh after.\n measureNotification(id, node);\n resizeObserver.current?.observe(node);\n } else {\n delete refs.current[id];\n delete refCallbacks.current[id];\n delete measuredHeights.current[id];\n }\n };\n }\n\n return refCallbacks.current[id];\n },\n [measureNotification]\n );\n\n const reduceMotion = theme.respectReducedMotion ? shouldReduceMotion : false;\n const duration = reduceMotion ? 1 : transitionDuration;\n\n const getStyles = useStyles<NotificationsFactory>({\n name: 'Notifications',\n classes,\n props,\n className,\n style,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n useEffect(() => {\n store?.updateState((current) => ({\n ...current,\n limit: limit || 5,\n defaultPosition: position,\n }));\n }, [limit, position]);\n\n useDidUpdate(() => {\n if (data.notifications.length > previousLength.current) {\n setTimeout(() => forceUpdate(), 0);\n }\n previousLength.current = data.notifications.length;\n }, [data.notifications]);\n\n const groupedComponents = positions.reduce(\n (acc, pos) => {\n const groupLength = grouped[pos].length;\n const expandedOffsets: number[] = new Array(groupLength).fill(0);\n const stackExpanded = layout === 'stacked' && !!expandedPositions[pos];\n\n // `grouped[pos]` is sorted by priority descending, with equal priorities in insertion\n // order. A stack is rendered front to back, so `stackOrder[0]` is the notification in\n // front: the most urgent one, and the newest among equal priorities – only the\n // tie-break is reversed here. Taking the front from the end of the priority-sorted\n // array instead would put the *lowest* priority notification in front and leave an\n // urgent one inert behind it.\n // Rendering front first also keeps DOM order matching the visual stack – otherwise a\n // forward Tab from the front notification (the only focusable one while collapsed)\n // skips past the ones it just un-inerted and leaves the region. Placement is\n // unaffected: stacked notifications share one grid cell and are positioned by\n // transform and an explicit z-index.\n const stackOrder =\n layout === 'stacked'\n ? [...(grouped[pos] as SequencedNotificationData[])].sort(\n (a, b) =>\n (b.priority ?? 0) - (a.priority ?? 0) || (b.__sequence ?? 0) - (a.__sequence ?? 0)\n )\n : grouped[pos];\n\n if (stackExpanded && groupLength > 0) {\n const direction = pos.startsWith('top') ? 1 : -1;\n let cumOffset = 0;\n\n for (let i = 0; i < groupLength; i += 1) {\n expandedOffsets[i] = cumOffset * direction;\n cumOffset +=\n (measuredHeights.current[stackOrder[i].id!] || FALLBACK_NOTIFICATION_HEIGHT) +\n STACK_EXPANDED_GAP;\n }\n }\n\n acc[pos] = stackOrder.map((item, stackIndex) => {\n const { style: notificationStyle, ...notification } = item;\n\n return (\n <Transition\n key={notification.id}\n timeout={duration}\n onEnter={() => refs.current[notification.id!].offsetHeight}\n nodeRef={{ current: refs.current[notification.id!] }}\n >\n {(state: TransitionStatus) => (\n <NotificationContainer\n ref={getNotificationRef(notification.id!)}\n data={notification}\n onHide={(id) => hideNotification(id, store)}\n autoClose={autoClose}\n transitionDuration={duration}\n allowDragDismiss={allowDragDismiss}\n allowScrollDismiss={allowScrollDismiss}\n paused={\n (pauseResetOnHover === 'all' ? hoveredCount > 0 : false) ||\n (layout === 'stacked' && !stackExpanded && stackIndex > 0)\n }\n onHoverStart={() => handleHoverStart(pos)}\n onHoverEnd={() => handleHoverEnd(pos)}\n onExpandRequest={() => handleExpandRequest(pos)}\n renderNotification={\n 'renderNotification' in notification\n ? notification.renderNotification\n : renderNotification\n }\n layout={layout}\n stackIndex={stackIndex}\n stackSize={groupLength}\n stackPosition={pos}\n stackExpanded={stackExpanded}\n stackExpandedOffset={expandedOffsets[stackIndex]}\n transitionState={state}\n {...getStyles('notification', {\n style: {\n ...getNotificationStateStyles({\n state,\n position: pos,\n transitionDuration: duration,\n maxHeight: notificationMaxHeight,\n }),\n ...notificationStyle,\n },\n })}\n />\n )}\n </Transition>\n );\n });\n\n return acc;\n },\n {} as Record<NotificationPosition, React.ReactNode>\n );\n\n return (\n <OptionalPortal withinPortal={withinPortal} {...portalProps}>\n <Box {...getStyles('root')} data-position=\"top-center\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('top-center')}>\n {groupedComponents['top-center']}\n </TransitionGroup>\n </Box>\n\n <Box {...getStyles('root')} data-position=\"top-left\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('top-left')}>\n {groupedComponents['top-left']}\n </TransitionGroup>\n </Box>\n\n <Box\n {...getStyles('root', { className: RemoveScroll.classNames.fullWidth })}\n data-position=\"top-right\"\n data-layout={layout}\n {...others}\n >\n <TransitionGroup {...getGroupHoverProps('top-right')}>\n {groupedComponents['top-right']}\n </TransitionGroup>\n </Box>\n\n <Box\n {...getStyles('root', { className: RemoveScroll.classNames.fullWidth })}\n data-position=\"bottom-right\"\n data-layout={layout}\n {...others}\n >\n <TransitionGroup {...getGroupHoverProps('bottom-right')}>\n {groupedComponents['bottom-right']}\n </TransitionGroup>\n </Box>\n\n <Box {...getStyles('root')} data-position=\"bottom-left\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('bottom-left')}>\n {groupedComponents['bottom-left']}\n </TransitionGroup>\n </Box>\n\n <Box {...getStyles('root')} data-position=\"bottom-center\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('bottom-center')}>\n {groupedComponents['bottom-center']}\n </TransitionGroup>\n </Box>\n </OptionalPortal>\n );\n});\n\nNotifications.classes = classes;\nNotifications.varsResolver = varsResolver;\nNotifications.displayName = '@mantine/notifications/Notifications';\nNotifications.show = notifications.show;\nNotifications.hide = notifications.hide;\nNotifications.update = notifications.update;\nNotifications.clean = notifications.clean;\nNotifications.cleanQueue = notifications.cleanQueue;\nNotifications.updateState = notifications.updateState;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Notifications.mjs","names":["Transition","_Transition","classes"],"sources":["../src/Notifications.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n Transition as _Transition,\n TransitionGroup,\n TransitionStatus,\n} from 'react-transition-group';\nimport {\n BasePortalProps,\n Box,\n BoxProps,\n createVarsResolver,\n ElementProps,\n factory,\n Factory,\n getDefaultZIndex,\n OptionalPortal,\n rem,\n RemoveScroll,\n StylesApiProps,\n useMantineTheme,\n useProps,\n useStyles,\n} from '@mantine/core';\nimport { useDidUpdate, useForceUpdate, useReducedMotion } from '@mantine/hooks';\nimport {\n getGroupedNotifications,\n positions,\n} from './get-grouped-notifications/get-grouped-notifications';\nimport { getNotificationStateStyles } from './get-notification-state-styles';\nimport { NotificationContainer } from './NotificationContainer';\nimport {\n hideNotification,\n NotificationData,\n NotificationPosition,\n notifications,\n NotificationsStore,\n notificationsStore,\n SequencedNotificationData,\n useNotifications,\n} from './notifications.store';\nimport classes from './Notifications.module.css';\n\nconst Transition: any = _Transition;\n\n/** Vertical gap between notifications of an expanded stack, in px */\nconst STACK_EXPANDED_GAP = 16;\n\n/** Offset step used for a notification that has not been measured yet, in px */\nconst FALLBACK_NOTIFICATION_HEIGHT = 80;\n\nexport type NotificationsStylesNames = 'root' | 'notification' | 'progress';\nexport type NotificationsCssVariables = {\n root: '--notifications-z-index' | '--notifications-container-width';\n};\n\nexport interface NotificationsProps\n extends BoxProps, StylesApiProps<NotificationsFactory>, ElementProps<'div'> {\n /** Notifications default position @default 'bottom-right' */\n position?: NotificationPosition;\n\n /** Auto close timeout for all notifications in ms, `false` to disable auto close, can be overwritten for individual notifications in `notifications.show` function @default 4000 */\n autoClose?: number | false;\n\n /** Notification transition duration in ms @default 250 */\n transitionDuration?: number;\n\n /** Determines whether notifications can be dismissed by dragging left or right @default true */\n allowDragDismiss?: boolean;\n\n /** Determines whether notifications can be dismissed with horizontal scroll gesture while hovered @default true */\n allowScrollDismiss?: boolean;\n\n /** Notification width, cannot exceed 100% @default 440 */\n containerWidth?: number | string;\n\n /** Notification `max-height`, used for transitions @default 200 */\n notificationMaxHeight?: number | string;\n\n /** Maximum number of notifications displayed at a time, other new notifications will be added to queue @default 5 */\n limit?: number;\n\n /** Notifications container z-index @default 400 */\n zIndex?: string | number;\n\n /** Props passed down to the `Portal` component */\n portalProps?: BasePortalProps;\n\n /** Store for notifications state, can be used to create multiple instances of notifications system in your application */\n store?: NotificationsStore;\n\n /** Determines whether notifications container should be rendered inside `Portal` @default true */\n withinPortal?: boolean;\n\n /** Determines which notifications should pause auto close on hover, `'all'` – pauses auto close for all notifications when any notification is hovered, `'notification'` – pauses auto close only for the hovered notification @default 'all' */\n pauseResetOnHover?: 'all' | 'notification';\n\n /** Custom render function that replaces the default notification, can be overridden per notification */\n renderNotification?: (notification: NotificationData) => React.ReactNode;\n\n /** Controls how notifications are positioned in the stack, `'default'` – standard vertical list, `'stacked'` – only first notification is fully visible, rest are stacked behind @default 'default' */\n layout?: 'default' | 'stacked';\n\n /** Determines whether a progress line that fills up until the notification auto closes is displayed at the bottom of every notification, can be overwritten for individual notifications in `notifications.show` and `notifications.update` functions @default false */\n withAutoCloseProgress?: boolean;\n}\n\nexport type NotificationsFactory = Factory<{\n props: NotificationsProps;\n ref: HTMLDivElement;\n stylesNames: NotificationsStylesNames;\n vars: NotificationsCssVariables;\n staticComponents: {\n show: typeof notifications.show;\n hide: typeof notifications.hide;\n update: typeof notifications.update;\n promise: typeof notifications.promise;\n clean: typeof notifications.clean;\n cleanQueue: typeof notifications.cleanQueue;\n updateState: typeof notifications.updateState;\n };\n}>;\n\nconst defaultProps = {\n position: 'bottom-right',\n autoClose: 4000,\n transitionDuration: 250,\n allowDragDismiss: true,\n allowScrollDismiss: true,\n containerWidth: 440,\n notificationMaxHeight: 200,\n limit: 5,\n zIndex: getDefaultZIndex('overlay'),\n store: notificationsStore,\n withinPortal: true,\n pauseResetOnHover: 'all',\n layout: 'default',\n withAutoCloseProgress: false,\n} satisfies Partial<NotificationsProps>;\n\nconst varsResolver = createVarsResolver<NotificationsFactory>((_, { zIndex, containerWidth }) => ({\n root: {\n '--notifications-z-index': zIndex?.toString(),\n '--notifications-container-width': rem(containerWidth),\n },\n}));\n\nexport const Notifications = factory<NotificationsFactory>((_props) => {\n const props = useProps('Notifications', defaultProps, _props);\n const {\n classNames,\n className,\n style,\n styles,\n unstyled,\n vars,\n attributes,\n position,\n autoClose,\n transitionDuration,\n allowDragDismiss,\n allowScrollDismiss,\n containerWidth,\n notificationMaxHeight,\n limit,\n zIndex,\n store,\n portalProps,\n withinPortal,\n pauseResetOnHover,\n renderNotification,\n layout,\n withAutoCloseProgress,\n ...others\n } = props;\n\n const theme = useMantineTheme();\n const data = useNotifications(store);\n const forceUpdate = useForceUpdate();\n const shouldReduceMotion = useReducedMotion();\n const refs = useRef<Record<string, HTMLDivElement>>({});\n const previousLength = useRef<number>(0);\n // Every position renders its own stack, so hover, expansion and pinning are tracked per\n // position – a single shared flag made hovering one corner expand all six of them.\n const [hoveredCounts, setHoveredCounts] = useState<Partial<Record<NotificationPosition, number>>>(\n {}\n );\n const [expandedPositions, setExpandedPositions] = useState<\n Partial<Record<NotificationPosition, boolean>>\n >({});\n const [hoveredGroups, setHoveredGroups] = useState<\n Partial<Record<NotificationPosition, boolean>>\n >({});\n const [pinnedPosition, setPinnedPosition] = useState<NotificationPosition | null>(null);\n const collapseTimeouts = useRef<Partial<Record<NotificationPosition, number>>>({});\n\n // `pauseResetOnHover=\"all\"` is documented as pausing every notification when any one of\n // them is hovered, so this stays global while the stack state above does not.\n const hoveredCount =\n Object.values(hoveredCounts).reduce((acc, count) => acc + (count ?? 0), 0) +\n Object.values(hoveredGroups).filter(Boolean).length;\n\n const handleHoverStart = useCallback(\n (pos: NotificationPosition) =>\n setHoveredCounts((current) => ({ ...current, [pos]: (current[pos] ?? 0) + 1 })),\n []\n );\n\n const handleHoverEnd = useCallback(\n (pos: NotificationPosition) =>\n setHoveredCounts((current) => ({ ...current, [pos]: Math.max(0, (current[pos] ?? 0) - 1) })),\n []\n );\n\n // Stacked hover is also tracked on the group element that wraps a stack, not only on the\n // individual notifications. When the hovered notification unmounts, React does not deliver\n // `onMouseEnter` to the one that slides under a stationary pointer: the browser dispatches\n // only a `mouseover` for the new target (no `mouseout`, the old node is gone), and the\n // enter/leave plugin drops it because its `relatedTarget` still resolves to a React\n // instance. The group is hovered throughout, so its state needs no event to stay correct\n // and the stack stays open until the pointer really leaves.\n // Kept apart from the notification counter above so that it can be released on its own –\n // the group has no unmount hook to fall back on the way a notification does.\n const getGroupHoverProps = useCallback(\n (pos: NotificationPosition) =>\n layout === 'stacked'\n ? {\n onMouseEnter: () => setHoveredGroups((current) => ({ ...current, [pos]: true })),\n onMouseLeave: () => setHoveredGroups((current) => ({ ...current, [pos]: false })),\n }\n : {},\n [layout]\n );\n\n // Touch devices have no hover, so tapping the stack pins it open until the next tap\n // outside of it. Without this the notifications behind the first one are unreachable.\n const handleExpandRequest = useCallback(\n (pos: NotificationPosition) => setPinnedPosition(pos),\n []\n );\n\n useEffect(() => {\n if (layout !== 'stacked') {\n return undefined;\n }\n\n const timeouts = collapseTimeouts.current;\n\n positions.forEach((pos) => {\n if ((hoveredCounts[pos] ?? 0) > 0 || hoveredGroups[pos] || pinnedPosition === pos) {\n window.clearTimeout(timeouts[pos]);\n setExpandedPositions((current) => (current[pos] ? current : { ...current, [pos]: true }));\n } else {\n timeouts[pos] = window.setTimeout(() => {\n setExpandedPositions((current) =>\n current[pos] ? { ...current, [pos]: false } : current\n );\n }, 200);\n }\n });\n\n return () => positions.forEach((pos) => window.clearTimeout(timeouts[pos]));\n }, [hoveredCounts, hoveredGroups, pinnedPosition, layout]);\n\n useEffect(() => {\n if (!pinnedPosition) {\n return undefined;\n }\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target as Node | null;\n const insideStack =\n target !== null && Object.values(refs.current).some((element) => element?.contains(target));\n\n if (!insideStack) {\n setPinnedPosition(null);\n }\n };\n\n document.addEventListener('pointerdown', handlePointerDown);\n return () => document.removeEventListener('pointerdown', handlePointerDown);\n }, [pinnedPosition]);\n\n const grouped = getGroupedNotifications(data.notifications, position);\n const pinnedCount = pinnedPosition ? grouped[pinnedPosition].length : 0;\n\n useEffect(() => {\n if (layout !== 'stacked' || (pinnedPosition !== null && pinnedCount === 0)) {\n setPinnedPosition(null);\n }\n }, [pinnedCount, pinnedPosition, layout]);\n\n // Leaving the stacked layout takes the handlers below out of the tree, so nothing can ever\n // deliver the `mouseleave` that would release the group and a stale flag would keep auto\n // close paused forever. Emptying a stack needs no such handling – the browser drops the\n // hover on its own once the last notification is removed, and releasing it here instead\n // would fire while the dismissed notification is still exiting under the pointer.\n useEffect(() => {\n if (layout !== 'stacked') {\n setHoveredGroups((current) => (Object.values(current).some(Boolean) ? {} : current));\n }\n }, [layout]);\n\n // Expanded stack offsets need the height of every notification. Measuring during render\n // would force a layout pass on every hover, focus and store update, so heights are cached\n // here and refreshed from the ResizeObserver – which also covers a notification that grows\n // after mount (image loads, async content, viewport reflow) and would otherwise leave the\n // ones after it overlapping or gapped until something else triggered a render.\n const resizeObserver = useRef<ResizeObserver | null>(null);\n const measuredHeights = useRef<Record<string, number>>({});\n const observedIds = useRef(new WeakMap<Element, string>());\n\n const measureNotification = useCallback((id: string, element: HTMLElement) => {\n const height = element.offsetHeight;\n\n if (measuredHeights.current[id] === height) {\n return false;\n }\n\n measuredHeights.current[id] = height;\n return true;\n }, []);\n\n useEffect(() => {\n if (layout !== 'stacked' || typeof ResizeObserver === 'undefined') {\n return undefined;\n }\n\n const observer = new ResizeObserver((entries) => {\n let changed = false;\n\n entries.forEach((entry) => {\n const id = observedIds.current.get(entry.target);\n\n if (id && measureNotification(id, entry.target as HTMLElement)) {\n changed = true;\n }\n });\n\n if (changed) {\n forceUpdate();\n }\n });\n\n resizeObserver.current = observer;\n Object.values(refs.current).forEach((element) => element && observer.observe(element));\n\n return () => {\n observer.disconnect();\n resizeObserver.current = null;\n };\n }, [layout, forceUpdate, measureNotification]);\n\n const refCallbacks = useRef<Record<string, (node: HTMLDivElement | null) => void>>({});\n\n const getNotificationRef = useCallback(\n (id: string) => {\n if (!refCallbacks.current[id]) {\n refCallbacks.current[id] = (node: HTMLDivElement | null) => {\n const previous = refs.current[id];\n\n if (previous && previous !== node) {\n resizeObserver.current?.unobserve(previous);\n observedIds.current.delete(previous);\n }\n\n if (node) {\n refs.current[id] = node;\n observedIds.current.set(node, id);\n // Measured here rather than during render – the commit phase is where a layout\n // read is already paid for, and the ResizeObserver keeps the value fresh after.\n measureNotification(id, node);\n resizeObserver.current?.observe(node);\n } else {\n delete refs.current[id];\n delete refCallbacks.current[id];\n delete measuredHeights.current[id];\n }\n };\n }\n\n return refCallbacks.current[id];\n },\n [measureNotification]\n );\n\n const reduceMotion = theme.respectReducedMotion ? shouldReduceMotion : false;\n const duration = reduceMotion ? 1 : transitionDuration;\n\n const getStyles = useStyles<NotificationsFactory>({\n name: 'Notifications',\n classes,\n props,\n className,\n style,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n useEffect(() => {\n store?.updateState((current) => ({\n ...current,\n limit: limit || 5,\n defaultPosition: position,\n }));\n }, [limit, position]);\n\n useDidUpdate(() => {\n if (data.notifications.length > previousLength.current) {\n setTimeout(() => forceUpdate(), 0);\n }\n previousLength.current = data.notifications.length;\n }, [data.notifications]);\n\n const groupedComponents = positions.reduce(\n (acc, pos) => {\n const groupLength = grouped[pos].length;\n const expandedOffsets: number[] = new Array(groupLength).fill(0);\n const stackExpanded = layout === 'stacked' && !!expandedPositions[pos];\n\n // `grouped[pos]` is sorted by priority descending, with equal priorities in insertion\n // order. A stack is rendered front to back, so `stackOrder[0]` is the notification in\n // front: the most urgent one, and the newest among equal priorities – only the\n // tie-break is reversed here. Taking the front from the end of the priority-sorted\n // array instead would put the *lowest* priority notification in front and leave an\n // urgent one inert behind it.\n // Rendering front first also keeps DOM order matching the visual stack – otherwise a\n // forward Tab from the front notification (the only focusable one while collapsed)\n // skips past the ones it just un-inerted and leaves the region. Placement is\n // unaffected: stacked notifications share one grid cell and are positioned by\n // transform and an explicit z-index.\n const stackOrder =\n layout === 'stacked'\n ? [...(grouped[pos] as SequencedNotificationData[])].sort(\n (a, b) =>\n (b.priority ?? 0) - (a.priority ?? 0) || (b.__sequence ?? 0) - (a.__sequence ?? 0)\n )\n : grouped[pos];\n\n if (stackExpanded && groupLength > 0) {\n const direction = pos.startsWith('top') ? 1 : -1;\n let cumOffset = 0;\n\n for (let i = 0; i < groupLength; i += 1) {\n expandedOffsets[i] = cumOffset * direction;\n cumOffset +=\n (measuredHeights.current[stackOrder[i].id!] || FALLBACK_NOTIFICATION_HEIGHT) +\n STACK_EXPANDED_GAP;\n }\n }\n\n acc[pos] = stackOrder.map((item, stackIndex) => {\n const { style: notificationStyle, ...notification } = item;\n\n return (\n <Transition\n key={notification.id}\n timeout={duration}\n onEnter={() => refs.current[notification.id!].offsetHeight}\n nodeRef={{ current: refs.current[notification.id!] }}\n >\n {(state: TransitionStatus) => (\n <NotificationContainer\n ref={getNotificationRef(notification.id!)}\n data={notification}\n onHide={(id) => hideNotification(id, store)}\n autoClose={autoClose}\n transitionDuration={duration}\n allowDragDismiss={allowDragDismiss}\n allowScrollDismiss={allowScrollDismiss}\n paused={\n (pauseResetOnHover === 'all' ? hoveredCount > 0 : false) ||\n (layout === 'stacked' && !stackExpanded && stackIndex > 0)\n }\n onHoverStart={() => handleHoverStart(pos)}\n onHoverEnd={() => handleHoverEnd(pos)}\n onExpandRequest={() => handleExpandRequest(pos)}\n renderNotification={\n 'renderNotification' in notification\n ? notification.renderNotification\n : renderNotification\n }\n layout={layout}\n withAutoCloseProgress={withAutoCloseProgress}\n progressProps={getStyles('progress')}\n stackIndex={stackIndex}\n stackSize={groupLength}\n stackPosition={pos}\n stackExpanded={stackExpanded}\n stackExpandedOffset={expandedOffsets[stackIndex]}\n transitionState={state}\n {...getStyles('notification', {\n style: {\n ...getNotificationStateStyles({\n state,\n position: pos,\n transitionDuration: duration,\n maxHeight: notificationMaxHeight,\n }),\n ...notificationStyle,\n },\n })}\n />\n )}\n </Transition>\n );\n });\n\n return acc;\n },\n {} as Record<NotificationPosition, React.ReactNode>\n );\n\n return (\n <OptionalPortal withinPortal={withinPortal} {...portalProps}>\n <Box {...getStyles('root')} data-position=\"top-center\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('top-center')}>\n {groupedComponents['top-center']}\n </TransitionGroup>\n </Box>\n\n <Box {...getStyles('root')} data-position=\"top-left\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('top-left')}>\n {groupedComponents['top-left']}\n </TransitionGroup>\n </Box>\n\n <Box\n {...getStyles('root', { className: RemoveScroll.classNames.fullWidth })}\n data-position=\"top-right\"\n data-layout={layout}\n {...others}\n >\n <TransitionGroup {...getGroupHoverProps('top-right')}>\n {groupedComponents['top-right']}\n </TransitionGroup>\n </Box>\n\n <Box\n {...getStyles('root', { className: RemoveScroll.classNames.fullWidth })}\n data-position=\"bottom-right\"\n data-layout={layout}\n {...others}\n >\n <TransitionGroup {...getGroupHoverProps('bottom-right')}>\n {groupedComponents['bottom-right']}\n </TransitionGroup>\n </Box>\n\n <Box {...getStyles('root')} data-position=\"bottom-left\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('bottom-left')}>\n {groupedComponents['bottom-left']}\n </TransitionGroup>\n </Box>\n\n <Box {...getStyles('root')} data-position=\"bottom-center\" data-layout={layout} {...others}>\n <TransitionGroup {...getGroupHoverProps('bottom-center')}>\n {groupedComponents['bottom-center']}\n </TransitionGroup>\n </Box>\n </OptionalPortal>\n );\n});\n\nNotifications.classes = classes;\nNotifications.varsResolver = varsResolver;\nNotifications.displayName = '@mantine/notifications/Notifications';\nNotifications.show = notifications.show;\nNotifications.hide = notifications.hide;\nNotifications.update = notifications.update;\nNotifications.promise = notifications.promise;\nNotifications.clean = notifications.clean;\nNotifications.cleanQueue = notifications.cleanQueue;\nNotifications.updateState = notifications.updateState;\n"],"mappings":"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"}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
//#region packages/@mantine/notifications/src/Notifications.module.css
|
|
3
3
|
var Notifications_module_default = {
|
|
4
4
|
"root": "m_b37d9ac7",
|
|
5
|
-
"notification": "m_5ed0edd0"
|
|
5
|
+
"notification": "m_5ed0edd0",
|
|
6
|
+
"progress": "m_836192",
|
|
7
|
+
"notifications-progress": "m_5f780017",
|
|
8
|
+
"notifications-progress-fade-in": "m_bb245a60"
|
|
6
9
|
};
|
|
7
10
|
//#endregion
|
|
8
11
|
export { Notifications_module_default as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Notifications.module.mjs","names":[],"sources":["../src/Notifications.module.css"],"sourcesContent":[".root {\n width: calc(100% - var(--mantine-spacing-md) * 2);\n position: fixed;\n z-index: var(--notifications-z-index);\n max-width: var(--notifications-container-width);\n\n &:where([data-position='top-center']) {\n top: var(--mantine-spacing-md);\n left: 50%;\n transform: translateX(-50%);\n }\n\n &:where([data-position='top-left']) {\n top: var(--mantine-spacing-md);\n left: var(--mantine-spacing-md);\n }\n\n &:where([data-position='top-right']) {\n top: var(--mantine-spacing-md);\n right: var(--mantine-spacing-md);\n }\n\n &:where([data-position='bottom-center']) {\n bottom: var(--mantine-spacing-md);\n left: 50%;\n transform: translateX(-50%);\n }\n\n &:where([data-position='bottom-left']) {\n bottom: var(--mantine-spacing-md);\n left: var(--mantine-spacing-md);\n }\n\n &:where([data-position='bottom-right']) {\n bottom: var(--mantine-spacing-md);\n right: var(--mantine-spacing-md);\n }\n}\n\n.notification {\n &:where(& + &) {\n margin-top: var(--mantine-spacing-md);\n }\n\n :where([data-layout='stacked']) & {\n margin-top: 0;\n }\n}\n\n.root:where([data-layout='stacked']) {\n & > * {\n display: grid;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Notifications.module.mjs","names":[],"sources":["../src/Notifications.module.css"],"sourcesContent":[".root {\n width: calc(100% - var(--mantine-spacing-md) * 2);\n position: fixed;\n z-index: var(--notifications-z-index);\n max-width: var(--notifications-container-width);\n\n &:where([data-position='top-center']) {\n top: var(--mantine-spacing-md);\n left: 50%;\n transform: translateX(-50%);\n }\n\n &:where([data-position='top-left']) {\n top: var(--mantine-spacing-md);\n left: var(--mantine-spacing-md);\n }\n\n &:where([data-position='top-right']) {\n top: var(--mantine-spacing-md);\n right: var(--mantine-spacing-md);\n }\n\n &:where([data-position='bottom-center']) {\n bottom: var(--mantine-spacing-md);\n left: 50%;\n transform: translateX(-50%);\n }\n\n &:where([data-position='bottom-left']) {\n bottom: var(--mantine-spacing-md);\n left: var(--mantine-spacing-md);\n }\n\n &:where([data-position='bottom-right']) {\n bottom: var(--mantine-spacing-md);\n right: var(--mantine-spacing-md);\n }\n}\n\n.notification {\n &:where(& + &) {\n margin-top: var(--mantine-spacing-md);\n }\n\n :where([data-layout='stacked']) & {\n margin-top: 0;\n }\n}\n\n.root:where([data-layout='stacked']) {\n & > * {\n display: grid;\n }\n}\n\n.progress {\n position: absolute;\n bottom: 0;\n inset-inline-start: 0;\n width: 100%;\n height: 3px;\n background-color: var(--notification-color);\n transform: scaleX(0);\n transform-origin: left center;\n transition: opacity 200ms ease;\n animation:\n notifications-progress var(--notifications-progress-duration) linear forwards,\n notifications-progress-fade-in 200ms ease;\n\n @mixin rtl {\n transform-origin: right center;\n }\n\n &:where([data-paused]) {\n opacity: 0;\n animation-play-state: paused, running;\n }\n}\n\n@keyframes notifications-progress {\n from {\n transform: scaleX(0);\n }\n\n to {\n transform: scaleX(1);\n }\n}\n\n@keyframes notifications-progress-fade-in {\n from {\n opacity: 0;\n }\n}\n"],"mappings":""}
|
package/esm/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { cleanNotifications, cleanNotificationsQueue, createNotificationsStore, hideNotification, notifications, notificationsStore, showNotification, updateNotification, updateNotificationsState, useNotifications } from "./notifications.store.mjs";
|
|
1
|
+
import { cleanNotifications, cleanNotificationsQueue, createNotificationsStore, hideNotification, notifications, notificationsStore, promiseNotification, showNotification, updateNotification, updateNotificationsState, useNotifications } from "./notifications.store.mjs";
|
|
2
2
|
import { Notifications } from "./Notifications.mjs";
|
|
3
|
-
export { Notifications, cleanNotifications, cleanNotificationsQueue, createNotificationsStore, hideNotification, notifications, notificationsStore, showNotification, updateNotification, updateNotificationsState, useNotifications };
|
|
3
|
+
export { Notifications, cleanNotifications, cleanNotificationsQueue, createNotificationsStore, hideNotification, notifications, notificationsStore, promiseNotification, showNotification, updateNotification, updateNotificationsState, useNotifications };
|
|
@@ -79,6 +79,46 @@ function updateNotification(notification, store = notificationsStore) {
|
|
|
79
79
|
}));
|
|
80
80
|
return notification.id;
|
|
81
81
|
}
|
|
82
|
+
function resolvePromiseNotificationData(data, value) {
|
|
83
|
+
return typeof data === "function" ? data(value) : data;
|
|
84
|
+
}
|
|
85
|
+
function upsertNotification(notification, store) {
|
|
86
|
+
const state = store.getState();
|
|
87
|
+
return [...state.notifications, ...state.queue].some((item) => item.id === notification.id) ? updateNotification(notification, store) : showNotification(notification, store);
|
|
88
|
+
}
|
|
89
|
+
const pendingPromises = /* @__PURE__ */ new WeakMap();
|
|
90
|
+
function promiseNotification(promise, options, store = notificationsStore) {
|
|
91
|
+
const id = options.id || randomId();
|
|
92
|
+
const owners = pendingPromises.get(store) || /* @__PURE__ */ new Map();
|
|
93
|
+
const owner = {};
|
|
94
|
+
pendingPromises.set(store, owners);
|
|
95
|
+
owners.set(id, owner);
|
|
96
|
+
upsertNotification({
|
|
97
|
+
loading: true,
|
|
98
|
+
autoClose: false,
|
|
99
|
+
...options.loading,
|
|
100
|
+
id
|
|
101
|
+
}, store);
|
|
102
|
+
const settle = (data) => {
|
|
103
|
+
if (owners.get(id) !== owner) return;
|
|
104
|
+
owners.delete(id);
|
|
105
|
+
upsertNotification({
|
|
106
|
+
...options.loading,
|
|
107
|
+
loading: false,
|
|
108
|
+
autoClose: void 0,
|
|
109
|
+
...data,
|
|
110
|
+
id
|
|
111
|
+
}, store);
|
|
112
|
+
};
|
|
113
|
+
promise.then((value) => settle({
|
|
114
|
+
color: "teal",
|
|
115
|
+
...resolvePromiseNotificationData(options.success, value)
|
|
116
|
+
}), (error) => settle({
|
|
117
|
+
color: "red",
|
|
118
|
+
...resolvePromiseNotificationData(options.error, error)
|
|
119
|
+
}));
|
|
120
|
+
return promise;
|
|
121
|
+
}
|
|
82
122
|
function cleanNotifications(store = notificationsStore) {
|
|
83
123
|
updateNotificationsState(store, () => []);
|
|
84
124
|
}
|
|
@@ -90,11 +130,12 @@ const notifications = {
|
|
|
90
130
|
show: showNotification,
|
|
91
131
|
hide: hideNotification,
|
|
92
132
|
update: updateNotification,
|
|
133
|
+
promise: promiseNotification,
|
|
93
134
|
clean: cleanNotifications,
|
|
94
135
|
cleanQueue: cleanNotificationsQueue,
|
|
95
136
|
updateState: updateNotificationsState
|
|
96
137
|
};
|
|
97
138
|
//#endregion
|
|
98
|
-
export { cleanNotifications, cleanNotificationsQueue, createNotificationsStore, hideNotification, notifications, notificationsStore, showNotification, updateNotification, updateNotificationsState, useNotifications };
|
|
139
|
+
export { cleanNotifications, cleanNotificationsQueue, createNotificationsStore, hideNotification, notifications, notificationsStore, promiseNotification, showNotification, updateNotification, updateNotificationsState, useNotifications };
|
|
99
140
|
|
|
100
141
|
//# sourceMappingURL=notifications.store.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.store.mjs","names":[],"sources":["../src/notifications.store.ts"],"sourcesContent":["import { NotificationProps } from '@mantine/core';\nimport { randomId } from '@mantine/hooks';\nimport { createStore, MantineStore, useStore } from '@mantine/store';\n\nexport type NotificationPosition =\n | 'top-left'\n | 'top-right'\n | 'top-center'\n | 'bottom-left'\n | 'bottom-right'\n | 'bottom-center';\n\nexport interface NotificationData\n extends Omit<NotificationProps, 'onClose'>, Record<`data-${string}`, any> {\n /** Notification id, can be used to close or update notification */\n id?: string;\n\n /** Position of the notification, if not set, the position is determined based on `position` prop on Notifications component */\n position?: NotificationPosition;\n\n /** Notification message, required for all notifications */\n message: React.ReactNode;\n\n /** Display priority. Higher numbers are shown before lower ones when the number of\n * active notifications exceeds `limit`. Notifications with equal priority keep insertion\n * order (FIFO). @default 0 */\n priority?: number;\n\n /** Determines whether notification should be closed automatically,\n * number is auto close timeout in ms, overrides `autoClose` from `Notifications`\n * */\n autoClose?: boolean | number;\n\n /** Determines whether notification can be closed with close button, drag or horizontal scroll swipe, `true` by default */\n allowClose?: boolean;\n\n /** Called when notification closes */\n onClose?: (props: NotificationData) => void;\n\n /** Called when notification opens */\n onOpen?: (props: NotificationData) => void;\n\n /** Custom render function that replaces the default notification, overrides `renderNotification` from `Notifications`. Set to `null` to use default rendering when a global `renderNotification` is set. */\n renderNotification?: ((notification: NotificationData) => React.ReactNode) | null;\n}\n\nexport interface NotificationsState {\n notifications: NotificationData[];\n queue: NotificationData[];\n defaultPosition: NotificationPosition;\n limit: number;\n}\n\nexport type NotificationsStore = MantineStore<NotificationsState>;\n\nexport interface SequencedNotificationData extends NotificationData {\n __sequence?: number;\n}\n\nlet notificationSequence = 0;\n\nfunction getDistributedNotifications(\n data: SequencedNotificationData[],\n defaultPosition: NotificationPosition,\n limit: number\n) {\n const queue: NotificationData[] = [];\n const notifications: NotificationData[] = [];\n const groups = new Map<string, SequencedNotificationData[]>();\n\n for (const item of data) {\n const position = item.position || defaultPosition;\n const group = groups.get(position);\n if (group) {\n group.push(item);\n } else {\n groups.set(position, [item]);\n }\n }\n\n for (const group of groups.values()) {\n group.sort(\n (a, b) => (b.priority ?? 0) - (a.priority ?? 0) || (a.__sequence ?? 0) - (b.__sequence ?? 0)\n );\n group.forEach((item, index) => {\n if (index < limit) {\n notifications.push(item);\n } else {\n queue.push(item);\n }\n });\n }\n\n return { notifications, queue };\n}\n\nexport const createNotificationsStore = () =>\n createStore<NotificationsState>({\n notifications: [],\n queue: [],\n defaultPosition: 'bottom-right',\n limit: 5,\n });\n\nexport const notificationsStore = createNotificationsStore();\nexport const useNotifications = (store: NotificationsStore = notificationsStore) => useStore(store);\n\nexport function updateNotificationsState(\n store: NotificationsStore,\n update: (notifications: NotificationData[]) => NotificationData[]\n) {\n const state = store.getState();\n const notifications = update([...state.notifications, ...state.queue]);\n\n for (const item of notifications as SequencedNotificationData[]) {\n if (item.__sequence === undefined) {\n item.__sequence = notificationSequence;\n notificationSequence += 1;\n }\n }\n\n const updated = getDistributedNotifications(notifications, state.defaultPosition, state.limit);\n\n store.setState({\n notifications: updated.notifications,\n queue: updated.queue,\n limit: state.limit,\n defaultPosition: state.defaultPosition,\n });\n}\n\nexport function showNotification(\n notification: NotificationData,\n store: NotificationsStore = notificationsStore\n) {\n const id = notification.id || randomId();\n\n updateNotificationsState(store, (notifications) => {\n if (notification.id && notifications.some((n) => n.id === notification.id)) {\n return notifications;\n }\n\n return [...notifications, { ...notification, id }];\n });\n\n return id;\n}\n\nexport function hideNotification(id: string, store: NotificationsStore = notificationsStore) {\n updateNotificationsState(store, (notifications) =>\n notifications.filter((notification) => {\n if (notification.id === id) {\n notification.onClose?.(notification);\n return false;\n }\n\n return true;\n })\n );\n\n return id;\n}\n\nexport function updateNotification(\n notification: NotificationData,\n store: NotificationsStore = notificationsStore\n) {\n updateNotificationsState(store, (notifications) =>\n notifications.map((item) => {\n if (item.id === notification.id) {\n return { ...item, ...notification };\n }\n\n return item;\n })\n );\n\n return notification.id;\n}\n\nexport function cleanNotifications(store: NotificationsStore = notificationsStore) {\n updateNotificationsState(store, () => []);\n}\n\nexport function cleanNotificationsQueue(store: NotificationsStore = notificationsStore) {\n const { defaultPosition, limit } = store.getState();\n updateNotificationsState(\n store,\n (notifications) =>\n getDistributedNotifications(notifications, defaultPosition, limit).notifications\n );\n}\n\nexport const notifications = {\n show: showNotification,\n hide: hideNotification,\n update: updateNotification,\n clean: cleanNotifications,\n cleanQueue: cleanNotificationsQueue,\n updateState: updateNotificationsState,\n} as const;\n"],"mappings":";;;;AA2DA,IAAI,uBAAuB;AAE3B,SAAS,4BACP,MACA,iBACA,OACA;CACA,MAAM,QAA4B,CAAC;CACnC,MAAM,gBAAoC,CAAC;CAC3C,MAAM,yBAAS,IAAI,IAAyC;CAE5D,KAAK,MAAM,QAAQ,MAAM;EACvB,MAAM,WAAW,KAAK,YAAY;EAClC,MAAM,QAAQ,OAAO,IAAI,QAAQ;EACjC,IAAI,OACF,MAAM,KAAK,IAAI;OAEf,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC;CAE/B;CAEA,KAAK,MAAM,SAAS,OAAO,OAAO,GAAG;EACnC,MAAM,MACH,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,YAAY,OAAO,EAAE,cAAc,MAAM,EAAE,cAAc,EAC5F;EACA,MAAM,SAAS,MAAM,UAAU;GAC7B,IAAI,QAAQ,OACV,cAAc,KAAK,IAAI;QAEvB,MAAM,KAAK,IAAI;EAEnB,CAAC;CACH;CAEA,OAAO;EAAE;EAAe;CAAM;AAChC;AAEA,MAAa,iCACX,YAAgC;CAC9B,eAAe,CAAC;CAChB,OAAO,CAAC;CACR,iBAAiB;CACjB,OAAO;AACT,CAAC;AAEH,MAAa,qBAAqB,yBAAyB;AAC3D,MAAa,oBAAoB,QAA4B,uBAAuB,SAAS,KAAK;AAElG,SAAgB,yBACd,OACA,QACA;CACA,MAAM,QAAQ,MAAM,SAAS;CAC7B,MAAM,gBAAgB,OAAO,CAAC,GAAG,MAAM,eAAe,GAAG,MAAM,KAAK,CAAC;CAErE,KAAK,MAAM,QAAQ,eACjB,IAAI,KAAK,eAAe,KAAA,GAAW;EACjC,KAAK,aAAa;EAClB,wBAAwB;CAC1B;CAGF,MAAM,UAAU,4BAA4B,eAAe,MAAM,iBAAiB,MAAM,KAAK;CAE7F,MAAM,SAAS;EACb,eAAe,QAAQ;EACvB,OAAO,QAAQ;EACf,OAAO,MAAM;EACb,iBAAiB,MAAM;CACzB,CAAC;AACH;AAEA,SAAgB,iBACd,cACA,QAA4B,oBAC5B;CACA,MAAM,KAAK,aAAa,MAAM,SAAS;CAEvC,yBAAyB,QAAQ,kBAAkB;EACjD,IAAI,aAAa,MAAM,cAAc,MAAM,MAAM,EAAE,OAAO,aAAa,EAAE,GACvE,OAAO;EAGT,OAAO,CAAC,GAAG,eAAe;GAAE,GAAG;GAAc;EAAG,CAAC;CACnD,CAAC;CAED,OAAO;AACT;AAEA,SAAgB,iBAAiB,IAAY,QAA4B,oBAAoB;CAC3F,yBAAyB,QAAQ,kBAC/B,cAAc,QAAQ,iBAAiB;EACrC,IAAI,aAAa,OAAO,IAAI;GAC1B,aAAa,UAAU,YAAY;GACnC,OAAO;EACT;EAEA,OAAO;CACT,CAAC,CACH;CAEA,OAAO;AACT;AAEA,SAAgB,mBACd,cACA,QAA4B,oBAC5B;CACA,yBAAyB,QAAQ,kBAC/B,cAAc,KAAK,SAAS;EAC1B,IAAI,KAAK,OAAO,aAAa,IAC3B,OAAO;GAAE,GAAG;GAAM,GAAG;EAAa;EAGpC,OAAO;CACT,CAAC,CACH;CAEA,OAAO,aAAa;AACtB;AAEA,SAAgB,mBAAmB,QAA4B,oBAAoB;CACjF,yBAAyB,aAAa,CAAC,CAAC;AAC1C;AAEA,SAAgB,wBAAwB,QAA4B,oBAAoB;CACtF,MAAM,EAAE,iBAAiB,UAAU,MAAM,SAAS;CAClD,yBACE,QACC,kBACC,4BAA4B,eAAe,iBAAiB,KAAK,CAAC,CAAC,aACvE;AACF;AAEA,MAAa,gBAAgB;CAC3B,MAAM;CACN,MAAM;CACN,QAAQ;CACR,OAAO;CACP,YAAY;CACZ,aAAa;AACf"}
|
|
1
|
+
{"version":3,"file":"notifications.store.mjs","names":[],"sources":["../src/notifications.store.ts"],"sourcesContent":["import { NotificationProps } from '@mantine/core';\nimport { randomId } from '@mantine/hooks';\nimport { createStore, MantineStore, useStore } from '@mantine/store';\n\nexport type NotificationPosition =\n | 'top-left'\n | 'top-right'\n | 'top-center'\n | 'bottom-left'\n | 'bottom-right'\n | 'bottom-center';\n\nexport interface NotificationData\n extends Omit<NotificationProps, 'onClose'>, Record<`data-${string}`, any> {\n /** Notification id, can be used to close or update notification */\n id?: string;\n\n /** Position of the notification, if not set, the position is determined based on `position` prop on Notifications component */\n position?: NotificationPosition;\n\n /** Notification message, required for all notifications */\n message: React.ReactNode;\n\n /** Display priority. Higher numbers are shown before lower ones when the number of\n * active notifications exceeds `limit`. Notifications with equal priority keep insertion\n * order (FIFO). @default 0 */\n priority?: number;\n\n /** Determines whether notification should be closed automatically,\n * number is auto close timeout in ms, overrides `autoClose` from `Notifications`\n * */\n autoClose?: boolean | number;\n\n /** Determines whether notification can be closed with close button, drag or horizontal scroll swipe, `true` by default */\n allowClose?: boolean;\n\n /** Determines whether a progress line that fills up until the notification auto closes is displayed at the bottom of the notification, overrides `withAutoCloseProgress` from `Notifications` */\n withAutoCloseProgress?: boolean;\n\n /** Called when notification closes */\n onClose?: (props: NotificationData) => void;\n\n /** Called when notification opens */\n onOpen?: (props: NotificationData) => void;\n\n /** Custom render function that replaces the default notification, overrides `renderNotification` from `Notifications`. Set to `null` to use default rendering when a global `renderNotification` is set. */\n renderNotification?: ((notification: NotificationData) => React.ReactNode) | null;\n}\n\nexport interface NotificationsState {\n notifications: NotificationData[];\n queue: NotificationData[];\n defaultPosition: NotificationPosition;\n limit: number;\n}\n\nexport type NotificationsStore = MantineStore<NotificationsState>;\n\nexport interface SequencedNotificationData extends NotificationData {\n __sequence?: number;\n}\n\nlet notificationSequence = 0;\n\nfunction getDistributedNotifications(\n data: SequencedNotificationData[],\n defaultPosition: NotificationPosition,\n limit: number\n) {\n const queue: NotificationData[] = [];\n const notifications: NotificationData[] = [];\n const groups = new Map<string, SequencedNotificationData[]>();\n\n for (const item of data) {\n const position = item.position || defaultPosition;\n const group = groups.get(position);\n if (group) {\n group.push(item);\n } else {\n groups.set(position, [item]);\n }\n }\n\n for (const group of groups.values()) {\n group.sort(\n (a, b) => (b.priority ?? 0) - (a.priority ?? 0) || (a.__sequence ?? 0) - (b.__sequence ?? 0)\n );\n group.forEach((item, index) => {\n if (index < limit) {\n notifications.push(item);\n } else {\n queue.push(item);\n }\n });\n }\n\n return { notifications, queue };\n}\n\nexport const createNotificationsStore = () =>\n createStore<NotificationsState>({\n notifications: [],\n queue: [],\n defaultPosition: 'bottom-right',\n limit: 5,\n });\n\nexport const notificationsStore = createNotificationsStore();\nexport const useNotifications = (store: NotificationsStore = notificationsStore) => useStore(store);\n\nexport function updateNotificationsState(\n store: NotificationsStore,\n update: (notifications: NotificationData[]) => NotificationData[]\n) {\n const state = store.getState();\n const notifications = update([...state.notifications, ...state.queue]);\n\n for (const item of notifications as SequencedNotificationData[]) {\n if (item.__sequence === undefined) {\n item.__sequence = notificationSequence;\n notificationSequence += 1;\n }\n }\n\n const updated = getDistributedNotifications(notifications, state.defaultPosition, state.limit);\n\n store.setState({\n notifications: updated.notifications,\n queue: updated.queue,\n limit: state.limit,\n defaultPosition: state.defaultPosition,\n });\n}\n\nexport function showNotification(\n notification: NotificationData,\n store: NotificationsStore = notificationsStore\n) {\n const id = notification.id || randomId();\n\n updateNotificationsState(store, (notifications) => {\n if (notification.id && notifications.some((n) => n.id === notification.id)) {\n return notifications;\n }\n\n return [...notifications, { ...notification, id }];\n });\n\n return id;\n}\n\nexport function hideNotification(id: string, store: NotificationsStore = notificationsStore) {\n updateNotificationsState(store, (notifications) =>\n notifications.filter((notification) => {\n if (notification.id === id) {\n notification.onClose?.(notification);\n return false;\n }\n\n return true;\n })\n );\n\n return id;\n}\n\nexport function updateNotification(\n notification: NotificationData,\n store: NotificationsStore = notificationsStore\n) {\n updateNotificationsState(store, (notifications) =>\n notifications.map((item) => {\n if (item.id === notification.id) {\n return { ...item, ...notification };\n }\n\n return item;\n })\n );\n\n return notification.id;\n}\n\nexport type PromiseNotificationData = Omit<NotificationData, 'id'>;\n\nexport interface PromiseNotificationOptions<T> {\n /** Notification id, used for all three states, by default `id` is randomly generated */\n id?: string;\n\n /** Notification displayed while the promise is pending, `loading: true` and `autoClose: false` are applied by default */\n loading: PromiseNotificationData;\n\n /** Notification displayed when the promise resolves, `color: 'teal'` is applied by default. Function receives the resolved value. */\n success: PromiseNotificationData | ((value: T) => PromiseNotificationData);\n\n /** Notification displayed when the promise rejects, `color: 'red'` is applied by default. Function receives the rejection reason. */\n error: PromiseNotificationData | ((error: unknown) => PromiseNotificationData);\n}\n\nfunction resolvePromiseNotificationData<T>(\n data: PromiseNotificationData | ((value: T) => PromiseNotificationData),\n value: T\n) {\n return typeof data === 'function' ? data(value) : data;\n}\n\nfunction upsertNotification(notification: NotificationData, store: NotificationsStore) {\n const state = store.getState();\n const exists = [...state.notifications, ...state.queue].some(\n (item) => item.id === notification.id\n );\n\n return exists ? updateNotification(notification, store) : showNotification(notification, store);\n}\n\nconst pendingPromises = new WeakMap<NotificationsStore, Map<string, object>>();\n\nexport function promiseNotification<T>(\n promise: Promise<T>,\n options: PromiseNotificationOptions<T>,\n store: NotificationsStore = notificationsStore\n): Promise<T> {\n const id = options.id || randomId();\n const owners = pendingPromises.get(store) || new Map<string, object>();\n const owner = {};\n\n pendingPromises.set(store, owners);\n owners.set(id, owner);\n\n upsertNotification({ loading: true, autoClose: false, ...options.loading, id }, store);\n\n const settle = (data: PromiseNotificationData) => {\n if (owners.get(id) !== owner) {\n return;\n }\n\n owners.delete(id);\n upsertNotification(\n { ...options.loading, loading: false, autoClose: undefined, ...data, id },\n store\n );\n };\n\n promise.then(\n (value) => settle({ color: 'teal', ...resolvePromiseNotificationData(options.success, value) }),\n (error) => settle({ color: 'red', ...resolvePromiseNotificationData(options.error, error) })\n );\n\n return promise;\n}\n\nexport function cleanNotifications(store: NotificationsStore = notificationsStore) {\n updateNotificationsState(store, () => []);\n}\n\nexport function cleanNotificationsQueue(store: NotificationsStore = notificationsStore) {\n const { defaultPosition, limit } = store.getState();\n updateNotificationsState(\n store,\n (notifications) =>\n getDistributedNotifications(notifications, defaultPosition, limit).notifications\n );\n}\n\nexport const notifications = {\n show: showNotification,\n hide: hideNotification,\n update: updateNotification,\n promise: promiseNotification,\n clean: cleanNotifications,\n cleanQueue: cleanNotificationsQueue,\n updateState: updateNotificationsState,\n} as const;\n"],"mappings":"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"}
|
|
@@ -8,6 +8,8 @@ interface NotificationContainerProps extends NotificationProps {
|
|
|
8
8
|
allowDragDismiss: boolean;
|
|
9
9
|
allowScrollDismiss: boolean;
|
|
10
10
|
paused: boolean;
|
|
11
|
+
withAutoCloseProgress: boolean;
|
|
12
|
+
progressProps: Record<string, any>;
|
|
11
13
|
onHoverStart?: () => void;
|
|
12
14
|
onHoverEnd?: () => void;
|
|
13
15
|
onExpandRequest?: () => void;
|
|
@@ -21,7 +23,7 @@ interface NotificationContainerProps extends NotificationProps {
|
|
|
21
23
|
stackExpandedOffset?: number;
|
|
22
24
|
transitionState?: string;
|
|
23
25
|
}
|
|
24
|
-
export declare function NotificationContainer({ data, onHide, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, paused, onHoverStart, onHoverEnd, onExpandRequest, ref, style, renderNotification, layout, stackIndex, stackSize, stackPosition, stackExpanded, stackExpandedOffset, transitionState, ...others }: NotificationContainerProps): import("react").JSX.Element;
|
|
26
|
+
export declare function NotificationContainer({ data, onHide, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, paused, withAutoCloseProgress, progressProps, onHoverStart, onHoverEnd, onExpandRequest, ref, style, renderNotification, layout, stackIndex, stackSize, stackPosition, stackExpanded, stackExpandedOffset, transitionState, ...others }: NotificationContainerProps): import("react").JSX.Element;
|
|
25
27
|
export declare namespace NotificationContainer {
|
|
26
28
|
var displayName: string;
|
|
27
29
|
}
|
package/lib/Notifications.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BasePortalProps, BoxProps, ElementProps, Factory, StylesApiProps } from '@mantine/core';
|
|
2
2
|
import { NotificationData, NotificationPosition, notifications, NotificationsStore } from './notifications.store';
|
|
3
|
-
export type NotificationsStylesNames = 'root' | 'notification';
|
|
3
|
+
export type NotificationsStylesNames = 'root' | 'notification' | 'progress';
|
|
4
4
|
export type NotificationsCssVariables = {
|
|
5
5
|
root: '--notifications-z-index' | '--notifications-container-width';
|
|
6
6
|
};
|
|
@@ -35,6 +35,8 @@ export interface NotificationsProps extends BoxProps, StylesApiProps<Notificatio
|
|
|
35
35
|
renderNotification?: (notification: NotificationData) => React.ReactNode;
|
|
36
36
|
/** Controls how notifications are positioned in the stack, `'default'` – standard vertical list, `'stacked'` – only first notification is fully visible, rest are stacked behind @default 'default' */
|
|
37
37
|
layout?: 'default' | 'stacked';
|
|
38
|
+
/** Determines whether a progress line that fills up until the notification auto closes is displayed at the bottom of every notification, can be overwritten for individual notifications in `notifications.show` and `notifications.update` functions @default false */
|
|
39
|
+
withAutoCloseProgress?: boolean;
|
|
38
40
|
}
|
|
39
41
|
export type NotificationsFactory = Factory<{
|
|
40
42
|
props: NotificationsProps;
|
|
@@ -45,6 +47,7 @@ export type NotificationsFactory = Factory<{
|
|
|
45
47
|
show: typeof notifications.show;
|
|
46
48
|
hide: typeof notifications.hide;
|
|
47
49
|
update: typeof notifications.update;
|
|
50
|
+
promise: typeof notifications.promise;
|
|
48
51
|
clean: typeof notifications.clean;
|
|
49
52
|
cleanQueue: typeof notifications.cleanQueue;
|
|
50
53
|
updateState: typeof notifications.updateState;
|
|
@@ -59,6 +62,7 @@ export declare const Notifications: import("@mantine/core").MantineComponent<{
|
|
|
59
62
|
show: typeof notifications.show;
|
|
60
63
|
hide: typeof notifications.hide;
|
|
61
64
|
update: typeof notifications.update;
|
|
65
|
+
promise: typeof notifications.promise;
|
|
62
66
|
clean: typeof notifications.clean;
|
|
63
67
|
cleanQueue: typeof notifications.cleanQueue;
|
|
64
68
|
updateState: typeof notifications.updateState;
|