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
|
import { CSSProperties, ReactNode, useState, createContext } from "react";
import CloseIcon from '@material-ui/icons/Close';
function ToastArea(props: {
style?: CSSProperties
children?: ReactNode
rerender?: boolean;
}) {
return <div id="ToastArea" style={{
position: "fixed",
whiteSpace: "nowrap",
bottom: 12,
left: "50%",
transform: "translateX(-50%)",
zIndex: 1,
maxWidth: 600,
width: "calc(100% - 48px - 48px)",
margin: "0 24px",
...props.style
}}>{props.children}</div>
}
function Toast(props: {
text?: string
description?: string
icon?: ReactNode
children?: ReactNode
type?: "normal"|"confirmation"|"error"
style?: CSSProperties
}) {
var [visible, setVisibility] = useState(true);
setTimeout(() => setVisibility(false), 10e3);
return visible && <div style={{
padding: 0,
marginBottom: 12,
borderRadius: 6,
boxShadow: "0 8px 12px -4px #00000033",
color:
props.type === "confirmation" ? "var(--background)" : "var(--text)",
backgroundColor:
props.type === "normal" ? "var(--background)" :
props.type === "confirmation" ? "var(--disk-b)" :
props.type === "error" ? "var(--disk-a)" : "var(--background)",
...props.style
}}>
{
props.children ||
<div style={{
lineHeight: 0,
padding: 12,
minHeight: props.description ? 36 : 24,
position: "relative"
}}>
<div style={{
position: "absolute",
left: 12,
top: "50%",
transform: "translateY(-50%)"
}}>{props.icon}</div>
<div style={{
userSelect: "none",
position: "absolute",
left: props.icon ? 48 : 12,
top: "50%",
transform: "translateY(-50%)"
}}>
<h2 style={{ fontSize: 16 }}>{props.text}</h2>
<p>{props.description}</p>
</div>
<div style={{
cursor: "pointer",
position: "absolute",
right: 12,
top: "50%",
transform: "translateY(-50%)"
}} onClick={() => setVisibility(false)}>
<CloseIcon style={{ fontSize: 24 }}/>
</div>
</div>
}
</div>
}
export type toastSettings = {
message: string,
description?: string,
type: "confirmation"|"normal"|"error",
icon?: ReactNode
}
export type toastType = (settings: toastSettings) => void;
export var ToastContext = createContext<{ toast?: toastType }>({});
var toasts: Array<JSX.Element> = [];
export function ToastContextWrapper(props: { children?: ReactNode }) {
var [dummyState, rerender] = useState(false);
return <ToastContext.Provider value={{ toast: options => {
toasts.push(<Toast
type={options.type}
text={options.message}
description={options.description}
icon={options.icon}/>);
rerender(!dummyState);
} }}>
{ props.children }
<ToastArea rerender={dummyState}>
{toasts}
</ToastArea>
</ToastContext.Provider>
}
|