@mantine/notifications 9.5.2 → 9.6.1

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.
@@ -6,21 +6,73 @@ let _mantine_core = require("@mantine/core");
6
6
  let react_jsx_runtime = require("react/jsx-runtime");
7
7
  //#region packages/@mantine/notifications/src/NotificationContainer.tsx
8
8
  const SCROLL_DISMISS_RESET_TIMEOUT = 120;
9
- function NotificationContainer({ data, onHide, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, paused, onHoverStart, onHoverEnd, ref, style, ...others }) {
9
+ const MAX_VISIBLE_STACK_DEPTH = 4;
10
+ /**
11
+ * Props that belong to the default `Notification` rendering or to the Styles API and must
12
+ * not reach the plain `div` used for custom rendering. Everything else is a valid div prop
13
+ * and is forwarded – an allow list would silently drop supported props like `onClick`,
14
+ * `dir`, `lang` or `hidden`.
15
+ */
16
+ const NON_DOM_PROPS = /* @__PURE__ */ new Set([
17
+ "classNames",
18
+ "styles",
19
+ "unstyled",
20
+ "vars",
21
+ "attributes",
22
+ "variant",
23
+ "color",
24
+ "radius",
25
+ "icon",
26
+ "title",
27
+ "loading",
28
+ "withBorder",
29
+ "withCloseButton",
30
+ "closeButtonProps",
31
+ "className",
32
+ "style",
33
+ "role",
34
+ "ref",
35
+ "children",
36
+ "mod"
37
+ ]);
38
+ function pickDomProps(props) {
39
+ const { rest } = (0, _mantine_core.extractStyleProps)(props);
40
+ return Object.fromEntries(Object.entries(rest).filter(([key, value]) => !NON_DOM_PROPS.has(key) && value !== void 0));
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 }) {
10
43
  const [offset, setOffset] = (0, react.useState)(0);
11
44
  const [dismissed, setDismissed] = (0, react.useState)(false);
12
45
  const [dismissDirection, setDismissDirection] = (0, react.useState)(1);
13
46
  const [scrollDismissActive, setScrollDismissActive] = (0, react.useState)(false);
14
47
  const theme = (0, _mantine_core.useMantineTheme)();
15
- const { autoClose: _autoClose, message, allowClose, position: _position, style: dataStyle, withCloseButton, 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, __sequence: _sequence, ...notificationProps } = data;
16
49
  const autoCloseDuration = require_get_auto_close.getAutoClose(autoClose, data.autoClose);
17
50
  const autoCloseTimeout = (0, react.useRef)(-1);
18
51
  const hideTimeout = (0, react.useRef)(-1);
19
52
  const scrollDismissTimeout = (0, react.useRef)(-1);
20
53
  const notificationRef = (0, react.useRef)(null);
21
54
  const hoveredRef = (0, react.useRef)(false);
55
+ const focusedRef = (0, react.useRef)(false);
56
+ const contributedActiveRef = (0, react.useRef)(false);
22
57
  const offsetRef = (0, react.useRef)(0);
23
58
  const isCloseDisabled = allowClose === false;
59
+ const syncActive = () => {
60
+ const shouldContribute = hoveredRef.current || focusedRef.current;
61
+ if (shouldContribute && !contributedActiveRef.current) {
62
+ contributedActiveRef.current = true;
63
+ onHoverStart?.();
64
+ } else if (!shouldContribute && contributedActiveRef.current) {
65
+ contributedActiveRef.current = false;
66
+ onHoverEnd?.();
67
+ }
68
+ };
69
+ const releaseActive = (0, react.useEffectEvent)(() => {
70
+ if (contributedActiveRef.current) {
71
+ contributedActiveRef.current = false;
72
+ onHoverEnd?.();
73
+ }
74
+ });
75
+ (0, react.useEffect)(() => () => releaseActive(), []);
24
76
  const cancelAutoClose = () => window.clearTimeout(autoCloseTimeout.current);
25
77
  const cancelHide = () => window.clearTimeout(hideTimeout.current);
26
78
  const cancelScrollDismissReset = () => window.clearTimeout(scrollDismissTimeout.current);
@@ -34,8 +86,12 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
34
86
  cancelHide();
35
87
  cancelScrollDismissReset();
36
88
  };
89
+ const pausedRef = (0, react.useRef)(paused);
90
+ (0, react.useEffect)(() => {
91
+ pausedRef.current = paused;
92
+ });
37
93
  const handleAutoClose = () => {
38
- if (dismissed || active || paused || hoveredRef.current || typeof autoCloseDuration !== "number") return;
94
+ if (dismissed || active || hoveredRef.current || focusedRef.current || pausedRef.current || typeof autoCloseDuration !== "number") return;
39
95
  cancelAutoClose();
40
96
  autoCloseTimeout.current = window.setTimeout(handleHide, autoCloseDuration);
41
97
  };
@@ -102,22 +158,49 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
102
158
  const baseOpacity = typeof baseStyle.opacity === "number" ? baseStyle.opacity : 1;
103
159
  const swipeOpacity = dismissed ? 0 : 1 - Math.min(Math.abs(offset) / 200, 1) * .6;
104
160
  const resolvedTransitionDuration = baseStyle.transitionDuration ?? `${transitionDuration}ms, ${transitionDuration}ms, ${transitionDuration}ms`;
161
+ const isStackedLayout = layout === "stacked";
162
+ const isStacked = isStackedLayout && stackIndex !== void 0 && stackIndex > 0;
163
+ const isCollapsed = isStacked && !stackExpanded;
164
+ const isExiting = transitionState === "exiting" || transitionState === "exited";
165
+ const stackDirection = stackPosition?.startsWith("top") ? 1 : -1;
166
+ const stackDepth = Math.min(stackIndex ?? 0, MAX_VISIBLE_STACK_DEPTH);
167
+ const collapsedOffset = isCollapsed ? stackDepth * 10 * stackDirection : 0;
168
+ const staggerDelay = isStackedLayout ? (stackIndex || 0) * 30 : 0;
169
+ const isDragging = active || scrollDismissActive;
170
+ const getStackedTransform = () => {
171
+ if (!isStackedLayout) return "var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)";
172
+ if (isExiting) return `translateY(${stackExpanded ? stackExpandedOffset || 0 : collapsedOffset}px) var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)`;
173
+ if (stackExpanded) return `translateY(${stackExpandedOffset || 0}px) translate3d(var(--notifications-swipe-offset), 0, 0)`;
174
+ if (isStacked) return `scale(${1 - stackDepth * .03}) translateY(${collapsedOffset}px)`;
175
+ return "var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)";
176
+ };
105
177
  const notificationStyle = {
106
178
  ...baseStyle,
179
+ ...isStackedLayout ? { maxHeight: void 0 } : {},
107
180
  ["--notifications-state-transform"]: typeof baseStyle.transform === "string" ? baseStyle.transform : "translateX(0)",
108
181
  ["--notifications-state-opacity"]: String(baseOpacity),
109
182
  ["--notifications-swipe-offset"]: `${offset}px`,
110
183
  ["--notifications-swipe-opacity"]: String(swipeOpacity),
111
- transform: "var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)",
184
+ transform: getStackedTransform(),
112
185
  opacity: "calc(var(--notifications-state-opacity) * var(--notifications-swipe-opacity))",
113
- transitionDuration: active || scrollDismissActive ? "0ms, 0ms, 0ms" : resolvedTransitionDuration,
186
+ transitionDuration: isDragging ? "0ms, 0ms, 0ms" : resolvedTransitionDuration,
114
187
  cursor: "default",
115
- touchAction: "pan-y"
188
+ touchAction: "pan-y",
189
+ ...isStackedLayout ? {
190
+ gridArea: "1 / 1",
191
+ zIndex: (stackSize || 5) - (stackIndex ?? 0),
192
+ pointerEvents: isCollapsed ? "none" : void 0,
193
+ alignSelf: stackDirection === 1 ? "start" : "end",
194
+ transitionProperty: isDragging ? "none" : "transform, opacity",
195
+ transitionDuration: `${transitionDuration}ms, ${transitionDuration}ms`,
196
+ transitionTimingFunction: "cubic-bezier(.51,.3,0,1.21), ease",
197
+ transitionDelay: isDragging || isExiting ? "0ms" : `${staggerDelay}ms`
198
+ } : {}
116
199
  };
117
200
  const handleMouseEnter = () => {
118
201
  hoveredRef.current = true;
119
202
  cancelAutoClose();
120
- onHoverStart?.();
203
+ syncActive();
121
204
  };
122
205
  const handleMouseLeave = () => {
123
206
  hoveredRef.current = false;
@@ -125,7 +208,20 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
125
208
  resetSwipe();
126
209
  handleAutoClose();
127
210
  }
128
- onHoverEnd?.();
211
+ syncActive();
212
+ };
213
+ const handleFocusCapture = isStackedLayout ? () => {
214
+ focusedRef.current = true;
215
+ cancelAutoClose();
216
+ syncActive();
217
+ } : void 0;
218
+ const handleBlurCapture = isStackedLayout ? () => {
219
+ focusedRef.current = false;
220
+ if (!scrollDismissActive) handleAutoClose();
221
+ syncActive();
222
+ } : void 0;
223
+ const handlePointerDownCapture = (event) => {
224
+ if (isStackedLayout && (event.pointerType === "touch" || event.pointerType === "pen")) onExpandRequest?.();
129
225
  };
130
226
  const handleWheel = (0, react.useEffectEvent)((event) => {
131
227
  if (dismissed || active) return;
@@ -189,15 +285,52 @@ function NotificationContainer({ data, onHide, autoClose, transitionDuration, al
189
285
  else handleAutoClose();
190
286
  return cancelAutoClose;
191
287
  }, [paused]);
288
+ const consumerProps = {
289
+ ...others,
290
+ ...notificationProps
291
+ };
292
+ const interactionProps = {
293
+ style: notificationStyle,
294
+ inert: isCollapsed,
295
+ onMouseEnter: (event) => {
296
+ consumerProps.onMouseEnter?.(event);
297
+ handleMouseEnter();
298
+ },
299
+ onMouseLeave: (event) => {
300
+ consumerProps.onMouseLeave?.(event);
301
+ handleMouseLeave();
302
+ },
303
+ onFocusCapture: (event) => {
304
+ consumerProps.onFocusCapture?.(event);
305
+ handleFocusCapture?.();
306
+ },
307
+ onBlurCapture: (event) => {
308
+ consumerProps.onBlurCapture?.(event);
309
+ handleBlurCapture?.();
310
+ },
311
+ onPointerDownCapture: (event) => {
312
+ consumerProps.onPointerDownCapture?.(event);
313
+ handlePointerDownCapture(event);
314
+ }
315
+ };
316
+ if (renderNotification) {
317
+ const classNames = [others.className, notificationProps.className].filter(Boolean).join(" ");
318
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
319
+ ref: mergedRef,
320
+ role: notificationProps.role || others.role || "alert",
321
+ ...pickDomProps(consumerProps),
322
+ className: classNames || void 0,
323
+ ...interactionProps,
324
+ children: renderNotification(data)
325
+ });
326
+ }
192
327
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Notification, {
193
328
  ref: mergedRef,
194
329
  ...others,
195
- style: notificationStyle,
196
330
  ...notificationProps,
331
+ ...interactionProps,
197
332
  withCloseButton: isCloseDisabled ? false : withCloseButton,
198
333
  onClose: handleHide,
199
- onMouseEnter: handleMouseEnter,
200
- onMouseLeave: handleMouseLeave,
201
334
  children: message
202
335
  });
203
336
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationContainer.cjs","names":["getAutoClose","Notification"],"sources":["../src/NotificationContainer.tsx"],"sourcesContent":["import { useEffect, useEffectEvent, useRef, useState } from 'react';\nimport { getStyleObject, Notification, NotificationProps, useMantineTheme } 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 ref?: React.Ref<HTMLDivElement>;\n}\n\nexport function NotificationContainer({\n data,\n onHide,\n autoClose,\n transitionDuration,\n allowDragDismiss,\n allowScrollDismiss,\n paused,\n onHoverStart,\n onHoverEnd,\n ref,\n style,\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 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 offsetRef = useRef(0);\n const isCloseDisabled = allowClose === false;\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 const handleAutoClose = () => {\n if (\n dismissed ||\n active ||\n paused ||\n hoveredRef.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 const notificationStyle = {\n ...baseStyle,\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:\n 'var(--notifications-state-transform) translate3d(var(--notifications-swipe-offset), 0, 0)',\n opacity: 'calc(var(--notifications-state-opacity) * var(--notifications-swipe-opacity))',\n transitionDuration:\n active || scrollDismissActive ? '0ms, 0ms, 0ms' : resolvedTransitionDuration,\n cursor: 'default',\n touchAction: 'pan-y',\n } as React.CSSProperties;\n\n const handleMouseEnter = () => {\n hoveredRef.current = true;\n cancelAutoClose();\n onHoverStart?.();\n };\n\n const handleMouseLeave = () => {\n hoveredRef.current = false;\n if (!scrollDismissActive) {\n resetSwipe();\n handleAutoClose();\n }\n onHoverEnd?.();\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 return (\n <Notification\n ref={mergedRef}\n {...others}\n style={notificationStyle}\n {...notificationProps}\n withCloseButton={isCloseDisabled ? false : withCloseButton}\n onClose={handleHide}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n {message}\n </Notification>\n );\n}\n\nNotificationContainer.displayName = '@mantine/notifications/NotificationContainer';\n"],"mappings":";;;;;;;AAMA,MAAM,+BAA+B;AAerC,SAAgB,sBAAsB,EACpC,MACA,QACA,WACA,oBACA,kBACA,oBACA,QACA,cACA,YACA,KACA,OACA,GAAG,UAC0B;CAC7B,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,CAAC;CACtC,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAyB,KAAK;CAChD,MAAM,CAAC,kBAAkB,wBAAA,GAAA,MAAA,SAAA,CAAwC,CAAC;CAClE,MAAM,CAAC,qBAAqB,2BAAA,GAAA,MAAA,SAAA,CAAmC,KAAK;CACpE,MAAM,SAAA,GAAA,cAAA,gBAAA,CAAwB;CAC9B,MAAM,EACJ,WAAW,YACX,SACA,YACA,UAAU,WACV,OAAO,WACP,iBACA,QAAQ,SACR,UAAU,WACV,YAAY,WACZ,GAAG,sBACD;CACJ,MAAM,oBAAoBA,uBAAAA,aAAa,WAAW,KAAK,SAAS;CAChE,MAAM,oBAAA,GAAA,MAAA,OAAA,CAAkC,EAAE;CAC1C,MAAM,eAAA,GAAA,MAAA,OAAA,CAA6B,EAAE;CACrC,MAAM,wBAAA,GAAA,MAAA,OAAA,CAAsC,EAAE;CAC9C,MAAM,mBAAA,GAAA,MAAA,OAAA,CAAyC,IAAI;CACnD,MAAM,cAAA,GAAA,MAAA,OAAA,CAAoB,KAAK;CAC/B,MAAM,aAAA,GAAA,MAAA,OAAA,CAAmB,CAAC;CAC1B,MAAM,kBAAkB,eAAe;CAEvC,MAAM,wBAAwB,OAAO,aAAa,iBAAiB,OAAO;CAC1E,MAAM,mBAAmB,OAAO,aAAa,YAAY,OAAO;CAChE,MAAM,iCAAiC,OAAO,aAAa,qBAAqB,OAAO;CAEvF,MAAM,kBAAkB,UAAkB;EACxC,UAAU,UAAU;EACpB,UAAU,KAAK;CACjB;CAEA,MAAM,mBAAmB;EACvB,OAAO,KAAK,EAAG;EACf,gBAAgB;EAChB,WAAW;EACX,yBAAyB;CAC3B;CAEA,MAAM,wBAAwB;EAC5B,IACE,aACA,UACA,UACA,WAAW,WACX,OAAO,sBAAsB,UAE7B;EAGF,gBAAgB;EAChB,iBAAiB,UAAU,OAAO,WAAW,YAAY,iBAAiB;CAC5E;CAEA,MAAM,iBAAiB,cAAsB;EAE3C,OAAO,cADO,gBAAgB,SAAS,eAAe,OAC1B;CAC9B;CAEA,MAAM,iBAAiB,UAAkB,aAAqB;EAC5D,MAAM,QAAQ,gBAAgB,SAAS,eAAe;EACtD,OAAO,KAAK,IAAI,QAAQ,IAAI,QAAQ,OAAQ,WAAW;CACzD;CAEA,MAAM,mBAAmB;EACvB,yBAAyB;EACzB,uBAAuB,KAAK;EAC5B,eAAe,CAAC;CAClB;CAEA,MAAM,uBAAuB,cAAsB;EACjD,oBAAoB,SAAS;EAC7B,aAAa,IAAI;EACjB,uBAAuB,KAAK;EAC5B,eAAe,cAAc,SAAS,CAAC;EACvC,gBAAgB;EAChB,WAAW;EACX,yBAAyB;EACzB,YAAY,UAAU,OAAO,WAAW,YAAY,kBAAkB;CACxE;CAEA,MAAM,mCAAmC;EACvC,yBAAyB;EACzB,qBAAqB,UAAU,OAAO,iBAAiB;GACrD,uBAAuB,KAAK;GAC5B,eAAe,CAAC;GAChB,gBAAgB;EAClB,GAAG,4BAA4B;CACjC;CAEA,MAAM,EAAE,KAAK,SAAS,YAAA,GAAA,eAAA,QAAA,EACnB,UAAU;EACT,IAAI,WACF;EAGF,IAAI,MAAM,OACR,gBAAgB;EAGlB,IAAI,MAAM,MAAM;GACd,IAAI,MAAM,OAAO,MAAM,UAAU;IAC/B,eAAe,CAAC;IAChB,gBAAgB;IAChB;GACF;GAEA,MAAM,WAAW,MAAM,SAAS;GAChC,MAAM,YACJ,aAAa,IAAK,MAAM,UAAU,OAAO,KAAK,KAAK,IAAK,WAAW,IAAI,IAAI;GAE7E,IAAI,cAAc,UAAU,MAAM,SAAS,EAAE,GAC3C,oBAAoB,SAAS;QACxB;IACL,eAAe,CAAC;IAChB,gBAAgB;GAClB;EACF,OACE,eAAe,MAAM,SAAS,EAAE;CAEpC,GACA;EACE,MAAM;EACN,WAAW;EACX,YAAY;EACZ,SAAS,oBAAoB,CAAC,mBAAmB,CAAC;CACpD,CACF;CAEA,MAAM,aAAA,GAAA,eAAA,aAAA,CAAyB,KAAK,iBAAiB,OAAO;CAC5D,MAAM,iBAAA,GAAA,cAAA,eAAA,CAA+B,OAAO,KAAK;CACjD,MAAM,qBAAA,GAAA,cAAA,eAAA,CAAmC,WAAW,KAAK;CACzD,MAAM,YAAY;EAAE,GAAG;EAAe,GAAG;CAAkB;CAC3D,MAAM,cAAc,OAAO,UAAU,YAAY,WAAW,UAAU,UAAU;CAChF,MAAM,eAAe,YAAY,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC,IAAI;CAC/E,MAAM,6BACJ,UAAU,sBACV,GAAG,mBAAmB,MAAM,mBAAmB,MAAM,mBAAmB;CAC1E,MAAM,oBAAoB;EACxB,GAAG;GACF,oCACC,OAAO,UAAU,cAAc,WAAW,UAAU,YAAY;GACjE,kCAA4C,OAAO,WAAW;GAC9D,iCAA2C,GAAG,OAAO;GACrD,kCAA4C,OAAO,YAAY;EAChE,WACE;EACF,SAAS;EACT,oBACE,UAAU,sBAAsB,kBAAkB;EACpD,QAAQ;EACR,aAAa;CACf;CAEA,MAAM,yBAAyB;EAC7B,WAAW,UAAU;EACrB,gBAAgB;EAChB,eAAe;CACjB;CAEA,MAAM,yBAAyB;EAC7B,WAAW,UAAU;EACrB,IAAI,CAAC,qBAAqB;GACxB,WAAW;GACX,gBAAgB;EAClB;EACA,aAAa;CACf;CAEA,MAAM,eAAA,GAAA,MAAA,eAAA,EAA8B,UAAsB;EACxD,IAAI,aAAa,QACf;EAGF,MAAM,kBAAkB,MAAM,kBAAkB;EAChD,IAAI,CAAC,mBAAmB,CAAC,WAAW,SAClC;EAGF,MAAM,EAAE,QAAQ,WAAW;EAC3B,IAAI,KAAK,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,WAAW,GACrD;EAGF,IAAI,CAAC,sBAAsB,iBACzB;EAGF,IAAI,CAAC,iBAAiB;GACpB,MAAM,eAAe;GACrB,MAAM,gBAAgB;EACxB;EAEA,gBAAgB;EAChB,uBAAuB,IAAI;EAE3B,MAAM,aAAa,UAAU,UAAU;EACvC,MAAM,YAAY,aAAa,IAAI,IAAI;EAEvC,IAAI,cAAc,YAAY,CAAC,GAAG;GAChC,oBAAoB,SAAS;GAC7B;EACF;EAEA,eAAe,UAAU;EACzB,2BAA2B;CAC7B,CAAC;CAED,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,qBACH;EAGF,SAAS,iBAAiB,SAAS,aAAa,EAAE,SAAS,MAAM,CAAC;EAClE,aAAa,SAAS,oBAAoB,SAAS,aAAa,EAAE,SAAS,MAAM,CAAQ;CAC3F,GAAG,CAAC,mBAAmB,CAAC;CAExB,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,qBAAqB;GACzB,IAAI,WACF,eAAe,cAAc,gBAAgB,CAAC;EAElD;EAEA,OAAO,iBAAiB,UAAU,YAAY;EAC9C,aAAa,OAAO,oBAAoB,UAAU,YAAY;CAChE,GAAG,CAAC,kBAAkB,SAAS,CAAC;CAEhC,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,OAAO,gBAAgB;EAC7B,IAAI,CAAC,MACH;EAGF,KAAK,iBAAiB,SAAS,aAAa,EAAE,SAAS,MAAM,CAAC;EAC9D,aAAa,KAAK,oBAAoB,SAAS,aAAa,EAAE,SAAS,MAAM,CAAQ;CACvF,GAAG,CAAC,CAAC;CAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,aAAa;GACX,WAAW;GACX,yBAAyB;EAC3B;CACF,GAAG,CAAC,CAAC;CAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,KAAK,SAAS,IAAI;CACpB,GAAG,CAAC,CAAC;CAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,gBAAgB;EAChB,OAAO;CACT,GAAG;EAAC;EAAmB;EAAQ;CAAS,CAAC;CAEzC,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,QACF,gBAAgB;OAEhB,gBAAgB;EAGlB,OAAO;CACT,GAAG,CAAC,MAAM,CAAC;CAEX,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,cAAD;EACE,KAAK;EACL,GAAI;EACJ,OAAO;EACP,GAAI;EACJ,iBAAiB,kBAAkB,QAAQ;EAC3C,SAAS;EACT,cAAc;EACd,cAAc;YAEb;CACW,CAAA;AAElB;AAEA,sBAAsB,cAAc"}
1
+ {"version":3,"file":"NotificationContainer.cjs","names":["extractStyleProps","useState","useMantineTheme","getAutoClose","useRef","useEffectEvent","useDrag","useMergedRef","getStyleObject","Notification"],"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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"}
@@ -11,6 +11,10 @@ let _mantine_core = require("@mantine/core");
11
11
  let react_jsx_runtime = require("react/jsx-runtime");
12
12
  //#region packages/@mantine/notifications/src/Notifications.tsx
13
13
  const Transition = react_transition_group.Transition;
14
+ /** Vertical gap between notifications of an expanded stack, in px */
15
+ const STACK_EXPANDED_GAP = 16;
16
+ /** Offset step used for a notification that has not been measured yet, in px */
17
+ const FALLBACK_NOTIFICATION_HEIGHT = 80;
14
18
  const defaultProps = {
15
19
  position: "bottom-right",
16
20
  autoClose: 4e3,
@@ -23,7 +27,8 @@ const defaultProps = {
23
27
  zIndex: (0, _mantine_core.getDefaultZIndex)("overlay"),
24
28
  store: require_notifications_store.notificationsStore,
25
29
  withinPortal: true,
26
- pauseResetOnHover: "all"
30
+ pauseResetOnHover: "all",
31
+ layout: "default"
27
32
  };
28
33
  const varsResolver = (0, _mantine_core.createVarsResolver)((_, { zIndex, containerWidth }) => ({ root: {
29
34
  "--notifications-z-index": zIndex?.toString(),
@@ -31,16 +36,134 @@ const varsResolver = (0, _mantine_core.createVarsResolver)((_, { zIndex, contain
31
36
  } }));
32
37
  const Notifications = (0, _mantine_core.factory)((_props) => {
33
38
  const props = (0, _mantine_core.useProps)("Notifications", defaultProps, _props);
34
- const { classNames, className, style, styles, unstyled, vars, attributes, position, autoClose, transitionDuration, allowDragDismiss, allowScrollDismiss, containerWidth, notificationMaxHeight, limit, zIndex, store, portalProps, withinPortal, pauseResetOnHover, ...others } = 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;
35
40
  const theme = (0, _mantine_core.useMantineTheme)();
36
41
  const data = require_notifications_store.useNotifications(store);
37
42
  const forceUpdate = (0, _mantine_hooks.useForceUpdate)();
38
43
  const shouldReduceMotion = (0, _mantine_hooks.useReducedMotion)();
39
44
  const refs = (0, react.useRef)({});
40
45
  const previousLength = (0, react.useRef)(0);
41
- const [hoveredCount, setHoveredCount] = (0, react.useState)(0);
42
- const handleHoverStart = (0, react.useCallback)(() => setHoveredCount((c) => c + 1), []);
43
- const handleHoverEnd = (0, react.useCallback)(() => setHoveredCount((c) => Math.max(0, c - 1)), []);
46
+ const [hoveredCounts, setHoveredCounts] = (0, react.useState)({});
47
+ const [expandedPositions, setExpandedPositions] = (0, react.useState)({});
48
+ const [hoveredGroups, setHoveredGroups] = (0, react.useState)({});
49
+ const [pinnedPosition, setPinnedPosition] = (0, react.useState)(null);
50
+ const collapseTimeouts = (0, react.useRef)({});
51
+ const hoveredCount = Object.values(hoveredCounts).reduce((acc, count) => acc + (count ?? 0), 0) + Object.values(hoveredGroups).filter(Boolean).length;
52
+ const handleHoverStart = (0, react.useCallback)((pos) => setHoveredCounts((current) => ({
53
+ ...current,
54
+ [pos]: (current[pos] ?? 0) + 1
55
+ })), []);
56
+ const handleHoverEnd = (0, react.useCallback)((pos) => setHoveredCounts((current) => ({
57
+ ...current,
58
+ [pos]: Math.max(0, (current[pos] ?? 0) - 1)
59
+ })), []);
60
+ const getGroupHoverProps = (0, react.useCallback)((pos) => layout === "stacked" ? {
61
+ onMouseEnter: () => setHoveredGroups((current) => ({
62
+ ...current,
63
+ [pos]: true
64
+ })),
65
+ onMouseLeave: () => setHoveredGroups((current) => ({
66
+ ...current,
67
+ [pos]: false
68
+ }))
69
+ } : {}, [layout]);
70
+ const handleExpandRequest = (0, react.useCallback)((pos) => setPinnedPosition(pos), []);
71
+ (0, react.useEffect)(() => {
72
+ if (layout !== "stacked") return;
73
+ const timeouts = collapseTimeouts.current;
74
+ require_get_grouped_notifications.positions.forEach((pos) => {
75
+ if ((hoveredCounts[pos] ?? 0) > 0 || hoveredGroups[pos] || pinnedPosition === pos) {
76
+ window.clearTimeout(timeouts[pos]);
77
+ setExpandedPositions((current) => current[pos] ? current : {
78
+ ...current,
79
+ [pos]: true
80
+ });
81
+ } else timeouts[pos] = window.setTimeout(() => {
82
+ setExpandedPositions((current) => current[pos] ? {
83
+ ...current,
84
+ [pos]: false
85
+ } : current);
86
+ }, 200);
87
+ });
88
+ return () => require_get_grouped_notifications.positions.forEach((pos) => window.clearTimeout(timeouts[pos]));
89
+ }, [
90
+ hoveredCounts,
91
+ hoveredGroups,
92
+ pinnedPosition,
93
+ layout
94
+ ]);
95
+ (0, react.useEffect)(() => {
96
+ if (!pinnedPosition) return;
97
+ const handlePointerDown = (event) => {
98
+ const target = event.target;
99
+ if (!(target !== null && Object.values(refs.current).some((element) => element?.contains(target)))) setPinnedPosition(null);
100
+ };
101
+ document.addEventListener("pointerdown", handlePointerDown);
102
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
103
+ }, [pinnedPosition]);
104
+ const grouped = require_get_grouped_notifications.getGroupedNotifications(data.notifications, position);
105
+ const pinnedCount = pinnedPosition ? grouped[pinnedPosition].length : 0;
106
+ (0, react.useEffect)(() => {
107
+ if (layout !== "stacked" || pinnedPosition !== null && pinnedCount === 0) setPinnedPosition(null);
108
+ }, [
109
+ pinnedCount,
110
+ pinnedPosition,
111
+ layout
112
+ ]);
113
+ (0, react.useEffect)(() => {
114
+ if (layout !== "stacked") setHoveredGroups((current) => Object.values(current).some(Boolean) ? {} : current);
115
+ }, [layout]);
116
+ const resizeObserver = (0, react.useRef)(null);
117
+ const measuredHeights = (0, react.useRef)({});
118
+ const observedIds = (0, react.useRef)(/* @__PURE__ */ new WeakMap());
119
+ const measureNotification = (0, react.useCallback)((id, element) => {
120
+ const height = element.offsetHeight;
121
+ if (measuredHeights.current[id] === height) return false;
122
+ measuredHeights.current[id] = height;
123
+ return true;
124
+ }, []);
125
+ (0, react.useEffect)(() => {
126
+ if (layout !== "stacked" || typeof ResizeObserver === "undefined") return;
127
+ const observer = new ResizeObserver((entries) => {
128
+ let changed = false;
129
+ entries.forEach((entry) => {
130
+ const id = observedIds.current.get(entry.target);
131
+ if (id && measureNotification(id, entry.target)) changed = true;
132
+ });
133
+ if (changed) forceUpdate();
134
+ });
135
+ resizeObserver.current = observer;
136
+ Object.values(refs.current).forEach((element) => element && observer.observe(element));
137
+ return () => {
138
+ observer.disconnect();
139
+ resizeObserver.current = null;
140
+ };
141
+ }, [
142
+ layout,
143
+ forceUpdate,
144
+ measureNotification
145
+ ]);
146
+ const refCallbacks = (0, react.useRef)({});
147
+ const getNotificationRef = (0, react.useCallback)((id) => {
148
+ if (!refCallbacks.current[id]) refCallbacks.current[id] = (node) => {
149
+ const previous = refs.current[id];
150
+ if (previous && previous !== node) {
151
+ resizeObserver.current?.unobserve(previous);
152
+ observedIds.current.delete(previous);
153
+ }
154
+ if (node) {
155
+ refs.current[id] = node;
156
+ observedIds.current.set(node, id);
157
+ measureNotification(id, node);
158
+ resizeObserver.current?.observe(node);
159
+ } else {
160
+ delete refs.current[id];
161
+ delete refCallbacks.current[id];
162
+ delete measuredHeights.current[id];
163
+ }
164
+ };
165
+ return refCallbacks.current[id];
166
+ }, [measureNotification]);
44
167
  const duration = (theme.respectReducedMotion ? shouldReduceMotion : false) ? 1 : transitionDuration;
45
168
  const getStyles = (0, _mantine_core.useStyles)({
46
169
  name: "Notifications",
@@ -66,37 +189,57 @@ const Notifications = (0, _mantine_core.factory)((_props) => {
66
189
  if (data.notifications.length > previousLength.current) setTimeout(() => forceUpdate(), 0);
67
190
  previousLength.current = data.notifications.length;
68
191
  }, [data.notifications]);
69
- const grouped = require_get_grouped_notifications.getGroupedNotifications(data.notifications, position);
70
192
  const groupedComponents = require_get_grouped_notifications.positions.reduce((acc, pos) => {
71
- acc[pos] = grouped[pos].map(({ style: notificationStyle, ...notification }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Transition, {
72
- timeout: duration,
73
- onEnter: () => refs.current[notification.id].offsetHeight,
74
- nodeRef: { current: refs.current[notification.id] },
75
- children: (state) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_NotificationContainer.NotificationContainer, {
76
- ref: (node) => {
77
- if (node) refs.current[notification.id] = node;
78
- else delete refs.current[notification.id];
79
- },
80
- data: notification,
81
- onHide: (id) => require_notifications_store.hideNotification(id, store),
82
- autoClose,
83
- transitionDuration: duration,
84
- allowDragDismiss,
85
- allowScrollDismiss,
86
- paused: pauseResetOnHover === "all" ? hoveredCount > 0 : false,
87
- onHoverStart: handleHoverStart,
88
- onHoverEnd: handleHoverEnd,
89
- ...getStyles("notification", { style: {
90
- ...require_get_notification_state_styles.getNotificationStateStyles({
91
- state,
92
- position: pos,
93
- transitionDuration: duration,
94
- maxHeight: notificationMaxHeight
95
- }),
96
- ...notificationStyle
97
- } })
98
- })
99
- }, notification.id));
193
+ const groupLength = grouped[pos].length;
194
+ const expandedOffsets = new Array(groupLength).fill(0);
195
+ const stackExpanded = layout === "stacked" && !!expandedPositions[pos];
196
+ const stackOrder = layout === "stacked" ? [...grouped[pos]].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0) || (b.__sequence ?? 0) - (a.__sequence ?? 0)) : grouped[pos];
197
+ if (stackExpanded && groupLength > 0) {
198
+ const direction = pos.startsWith("top") ? 1 : -1;
199
+ let cumOffset = 0;
200
+ for (let i = 0; i < groupLength; i += 1) {
201
+ expandedOffsets[i] = cumOffset * direction;
202
+ cumOffset += (measuredHeights.current[stackOrder[i].id] || FALLBACK_NOTIFICATION_HEIGHT) + STACK_EXPANDED_GAP;
203
+ }
204
+ }
205
+ acc[pos] = stackOrder.map((item, stackIndex) => {
206
+ const { style: notificationStyle, ...notification } = item;
207
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Transition, {
208
+ timeout: duration,
209
+ onEnter: () => refs.current[notification.id].offsetHeight,
210
+ nodeRef: { current: refs.current[notification.id] },
211
+ children: (state) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_NotificationContainer.NotificationContainer, {
212
+ ref: getNotificationRef(notification.id),
213
+ data: notification,
214
+ onHide: (id) => require_notifications_store.hideNotification(id, store),
215
+ autoClose,
216
+ transitionDuration: duration,
217
+ allowDragDismiss,
218
+ allowScrollDismiss,
219
+ paused: (pauseResetOnHover === "all" ? hoveredCount > 0 : false) || layout === "stacked" && !stackExpanded && stackIndex > 0,
220
+ onHoverStart: () => handleHoverStart(pos),
221
+ onHoverEnd: () => handleHoverEnd(pos),
222
+ onExpandRequest: () => handleExpandRequest(pos),
223
+ renderNotification: "renderNotification" in notification ? notification.renderNotification : renderNotification,
224
+ layout,
225
+ stackIndex,
226
+ stackSize: groupLength,
227
+ stackPosition: pos,
228
+ stackExpanded,
229
+ stackExpandedOffset: expandedOffsets[stackIndex],
230
+ transitionState: state,
231
+ ...getStyles("notification", { style: {
232
+ ...require_get_notification_state_styles.getNotificationStateStyles({
233
+ state,
234
+ position: pos,
235
+ transitionDuration: duration,
236
+ maxHeight: notificationMaxHeight
237
+ }),
238
+ ...notificationStyle
239
+ } })
240
+ })
241
+ }, notification.id);
242
+ });
100
243
  return acc;
101
244
  }, {});
102
245
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.OptionalPortal, {
@@ -106,38 +249,62 @@ const Notifications = (0, _mantine_core.factory)((_props) => {
106
249
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
107
250
  ...getStyles("root"),
108
251
  "data-position": "top-center",
252
+ "data-layout": layout,
109
253
  ...others,
110
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, { children: groupedComponents["top-center"] })
254
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, {
255
+ ...getGroupHoverProps("top-center"),
256
+ children: groupedComponents["top-center"]
257
+ })
111
258
  }),
112
259
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
113
260
  ...getStyles("root"),
114
261
  "data-position": "top-left",
262
+ "data-layout": layout,
115
263
  ...others,
116
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, { children: groupedComponents["top-left"] })
264
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, {
265
+ ...getGroupHoverProps("top-left"),
266
+ children: groupedComponents["top-left"]
267
+ })
117
268
  }),
118
269
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
119
270
  ...getStyles("root", { className: _mantine_core.RemoveScroll.classNames.fullWidth }),
120
271
  "data-position": "top-right",
272
+ "data-layout": layout,
121
273
  ...others,
122
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, { children: groupedComponents["top-right"] })
274
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, {
275
+ ...getGroupHoverProps("top-right"),
276
+ children: groupedComponents["top-right"]
277
+ })
123
278
  }),
124
279
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
125
280
  ...getStyles("root", { className: _mantine_core.RemoveScroll.classNames.fullWidth }),
126
281
  "data-position": "bottom-right",
282
+ "data-layout": layout,
127
283
  ...others,
128
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, { children: groupedComponents["bottom-right"] })
284
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, {
285
+ ...getGroupHoverProps("bottom-right"),
286
+ children: groupedComponents["bottom-right"]
287
+ })
129
288
  }),
130
289
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
131
290
  ...getStyles("root"),
132
291
  "data-position": "bottom-left",
292
+ "data-layout": layout,
133
293
  ...others,
134
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, { children: groupedComponents["bottom-left"] })
294
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, {
295
+ ...getGroupHoverProps("bottom-left"),
296
+ children: groupedComponents["bottom-left"]
297
+ })
135
298
  }),
136
299
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Box, {
137
300
  ...getStyles("root"),
138
301
  "data-position": "bottom-center",
302
+ "data-layout": layout,
139
303
  ...others,
140
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, { children: groupedComponents["bottom-center"] })
304
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.TransitionGroup, {
305
+ ...getGroupHoverProps("bottom-center"),
306
+ children: groupedComponents["bottom-center"]
307
+ })
141
308
  })
142
309
  ]
143
310
  });