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