/
Alert.tsx
153 lines (134 loc) · 3.66 KB
/
Alert.tsx
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
import { elementType } from 'prop-types-extra';
import { useUncontrolled } from 'uncontrollable';
import useEventCallback from '@restart/hooks/useEventCallback';
import { useBootstrapPrefix } from './ThemeProvider';
import Fade from './Fade';
import CloseButton from './CloseButton';
import { Variant } from './types';
import divWithClassName from './divWithClassName';
import createWithBsPrefix from './createWithBsPrefix';
import SafeAnchor from './SafeAnchor';
import { TransitionType } from './helpers';
export interface AlertProps extends React.HTMLProps<HTMLDivElement> {
bsPrefix?: string;
variant?: Variant;
dismissible?: boolean;
show?: boolean;
onClose?: (a: any, b: any) => void;
closeLabel?: string;
transition?: TransitionType;
}
const DivStyledAsH4 = divWithClassName('h4');
DivStyledAsH4.displayName = 'DivStyledAsH4';
const AlertHeading = createWithBsPrefix('alert-heading', {
Component: DivStyledAsH4,
});
const AlertLink = createWithBsPrefix('alert-link', {
Component: SafeAnchor,
});
type Alert = React.ForwardRefExoticComponent<AlertProps> & {
Link: typeof AlertLink;
Heading: typeof AlertHeading;
};
const propTypes = {
/**
* @default 'alert'
*/
bsPrefix: PropTypes.string,
/**
* The Alert visual variant
*
* @type {'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'dark' | 'light'}
*/
variant: PropTypes.string,
/**
* Renders a properly aligned dismiss button, as well as
* adding extra horizontal padding to the Alert.
*/
dismissible: PropTypes.bool,
/**
* Controls the visual state of the Alert.
*
* @controllable onClose
*/
show: PropTypes.bool,
/**
* Callback fired when alert is closed.
*
* @controllable show
*/
onClose: PropTypes.func,
/**
* Sets the text for alert close button.
*/
closeLabel: PropTypes.string,
/**
* Animate the alert dismissal. Defaults to using `<Fade>` animation or use
* `false` to disable. A custom `react-transition-group` Transition can also
* be provided.
*/
transition: PropTypes.oneOfType([PropTypes.bool, elementType]),
};
const defaultProps = {
show: true,
transition: Fade,
closeLabel: 'Close alert',
};
const Alert = (React.forwardRef<HTMLDivElement, AlertProps>(
(uncontrolledProps: AlertProps, ref) => {
const {
bsPrefix,
show,
closeLabel,
className,
children,
variant,
onClose,
dismissible,
transition,
...props
} = useUncontrolled(uncontrolledProps, {
show: 'onClose',
});
const prefix = useBootstrapPrefix(bsPrefix, 'alert');
const handleClose = useEventCallback((e) => {
if (onClose) {
onClose(false, e);
}
});
const Transition = transition === true ? Fade : transition;
const alert = (
<div
role="alert"
{...(Transition ? props : undefined)}
ref={ref}
className={classNames(
className,
prefix,
variant && `${prefix}-${variant}`,
dismissible && `${prefix}-dismissible`,
)}
>
{dismissible && (
<CloseButton onClick={handleClose} label={closeLabel} />
)}
{children}
</div>
);
if (!Transition) return show ? alert : null;
return (
<Transition unmountOnExit {...props} ref={undefined} in={show}>
{alert}
</Transition>
);
},
) as unknown) as Alert;
Alert.displayName = 'Alert';
Alert.defaultProps = defaultProps as any;
Alert.propTypes = propTypes;
Alert.Link = AlertLink;
Alert.Heading = AlertHeading;
export default Alert;