UNPKG

4.38 kBJavaScriptView Raw
1'use client';
2
3import * as React from 'react';
4import { unstable_useEventCallback as useEventCallback, unstable_useTimeout as useTimeout } from '@mui/utils';
5import extractEventHandlers from '@mui/utils/extractEventHandlers';
6/**
7 * The basic building block for creating custom snackbar.
8 *
9 * Demos:
10 *
11 * - [Snackbar](https://mui.com/base-ui/react-snackbar/#hook)
12 *
13 * API:
14 *
15 * - [useSnackbar API](https://mui.com/base-ui/react-snackbar/hooks-api/#use-snackbar)
16 */
17function useSnackbar(parameters = {}) {
18 const {
19 autoHideDuration = null,
20 disableWindowBlurListener = false,
21 onClose,
22 open,
23 resumeHideDuration
24 } = parameters;
25 const timerAutoHide = useTimeout();
26 React.useEffect(() => {
27 if (!open) {
28 return undefined;
29 }
30
31 /**
32 * @param {KeyboardEvent} nativeEvent
33 */
34 function handleKeyDown(nativeEvent) {
35 if (!nativeEvent.defaultPrevented) {
36 if (nativeEvent.key === 'Escape') {
37 // not calling `preventDefault` since we don't know if people may ignore this event e.g. a permanently open snackbar
38 onClose?.(nativeEvent, 'escapeKeyDown');
39 }
40 }
41 }
42 document.addEventListener('keydown', handleKeyDown);
43 return () => {
44 document.removeEventListener('keydown', handleKeyDown);
45 };
46 }, [open, onClose]);
47 const handleClose = useEventCallback((event, reason) => {
48 onClose?.(event, reason);
49 });
50 const setAutoHideTimer = useEventCallback(autoHideDurationParam => {
51 if (!onClose || autoHideDurationParam == null) {
52 return;
53 }
54 timerAutoHide.start(autoHideDurationParam, () => {
55 handleClose(null, 'timeout');
56 });
57 });
58 React.useEffect(() => {
59 if (open) {
60 setAutoHideTimer(autoHideDuration);
61 }
62 return timerAutoHide.clear;
63 }, [open, autoHideDuration, setAutoHideTimer, timerAutoHide]);
64 const handleClickAway = event => {
65 onClose?.(event, 'clickaway');
66 };
67
68 // Pause the timer when the user is interacting with the Snackbar
69 // or when the user hide the window.
70 const handlePause = timerAutoHide.clear;
71
72 // Restart the timer when the user is no longer interacting with the Snackbar
73 // or when the window is shown back.
74 const handleResume = React.useCallback(() => {
75 if (autoHideDuration != null) {
76 setAutoHideTimer(resumeHideDuration != null ? resumeHideDuration : autoHideDuration * 0.5);
77 }
78 }, [autoHideDuration, resumeHideDuration, setAutoHideTimer]);
79 const createHandleBlur = otherHandlers => event => {
80 const onBlurCallback = otherHandlers.onBlur;
81 onBlurCallback?.(event);
82 handleResume();
83 };
84 const createHandleFocus = otherHandlers => event => {
85 const onFocusCallback = otherHandlers.onFocus;
86 onFocusCallback?.(event);
87 handlePause();
88 };
89 const createMouseEnter = otherHandlers => event => {
90 const onMouseEnterCallback = otherHandlers.onMouseEnter;
91 onMouseEnterCallback?.(event);
92 handlePause();
93 };
94 const createMouseLeave = otherHandlers => event => {
95 const onMouseLeaveCallback = otherHandlers.onMouseLeave;
96 onMouseLeaveCallback?.(event);
97 handleResume();
98 };
99 React.useEffect(() => {
100 // TODO: window global should be refactored here
101 if (!disableWindowBlurListener && open) {
102 window.addEventListener('focus', handleResume);
103 window.addEventListener('blur', handlePause);
104 return () => {
105 window.removeEventListener('focus', handleResume);
106 window.removeEventListener('blur', handlePause);
107 };
108 }
109 return undefined;
110 }, [disableWindowBlurListener, open, handleResume, handlePause]);
111 const getRootProps = (externalProps = {}) => {
112 const externalEventHandlers = {
113 ...extractEventHandlers(parameters),
114 ...extractEventHandlers(externalProps)
115 };
116 return {
117 // ClickAwayListener adds an `onClick` prop which results in the alert not being announced.
118 // See https://github.com/mui/material-ui/issues/29080
119 role: 'presentation',
120 ...externalProps,
121 ...externalEventHandlers,
122 onBlur: createHandleBlur(externalEventHandlers),
123 onFocus: createHandleFocus(externalEventHandlers),
124 onMouseEnter: createMouseEnter(externalEventHandlers),
125 onMouseLeave: createMouseLeave(externalEventHandlers)
126 };
127 };
128 return {
129 getRootProps,
130 onClickAway: handleClickAway
131 };
132}
133export default useSnackbar;
\No newline at end of file