-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
useToast.ts
105 lines (96 loc) · 3.37 KB
/
useToast.ts
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
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {AriaButtonProps} from '@react-types/button';
import {AriaLabelingProps, DOMAttributes, FocusableElement, RefObject} from '@react-types/shared';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {QueuedToast, ToastState} from '@react-stately/toast';
import React, {useEffect} from 'react';
import {useId, useSlotId} from '@react-aria/utils';
import {useLocalizedStringFormatter} from '@react-aria/i18n';
export interface AriaToastProps<T> extends AriaLabelingProps {
/** The toast object. */
toast: QueuedToast<T>
}
export interface ToastAria {
/** Props for the toast container, non-modal dialog element. */
toastProps: DOMAttributes,
/** Props for the toast content alert message. */
contentProps: DOMAttributes,
/** Props for the toast title element. */
titleProps: DOMAttributes,
/** Props for the toast description element, if any. */
descriptionProps: DOMAttributes,
/** Props for the toast close button. */
closeButtonProps: AriaButtonProps
}
/**
* Provides the behavior and accessibility implementation for a toast component.
* Toasts display brief, temporary notifications of actions, errors, or other events in an application.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function useToast<T>(props: AriaToastProps<T>, state: ToastState<T>, ref: RefObject<FocusableElement | null>): ToastAria {
let {
key,
timer,
timeout,
animation
} = props.toast;
useEffect(() => {
if (!timer) {
return;
}
timer.reset(timeout);
return () => {
timer.pause();
};
}, [timer, timeout]);
let [isEntered, setIsEntered] = React.useState(false);
useEffect(() => {
if (animation === 'entering' || animation === 'queued') {
setIsEntered(true);
}
}, [animation]);
let titleId = useId();
let descriptionId = useSlotId();
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/toast');
return {
toastProps: {
role: 'alertdialog',
'aria-modal': 'false',
'aria-label': props['aria-label'],
'aria-labelledby': props['aria-labelledby'] || titleId,
'aria-describedby': props['aria-describedby'] || descriptionId,
'aria-details': props['aria-details'],
// Hide toasts that are animating out so VoiceOver doesn't announce them.
'aria-hidden': animation === 'exiting' ? 'true' : undefined,
tabIndex: 0
},
contentProps: {
role: 'alert',
'aria-atomic': 'true',
style: {
visibility: isEntered || animation === null ? 'visible' : 'hidden'
}
},
titleProps: {
id: titleId
},
descriptionProps: {
id: descriptionId
},
closeButtonProps: {
'aria-label': stringFormatter.format('close'),
onPress: () => state.close(key)
}
};
}