Skip to content

Commit e7819a7

Browse files
committed
toasts and focus handling
1 parent 7e7eb08 commit e7819a7

8 files changed

Lines changed: 239 additions & 79 deletions

File tree

packages/web-console/src/components/PopperToggle/index.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,23 +114,33 @@ export const PopperToggle = ({
114114
useTransition(container, _active, transitionTimeoutId)
115115

116116
useEffect(() => {
117-
setActive(typeof active === "undefined" ? _active || false : active)
118-
}, [active, _active])
117+
if (typeof active !== "undefined") {
118+
setActive(active)
119+
}
120+
}, [active])
121+
122+
useEffect(() => {
123+
document.body.appendChild(container)
124+
125+
return () => {
126+
clearTimeout(transitionTimeoutId.current)
127+
if (document.body.contains(container)) {
128+
document.body.removeChild(container)
129+
}
130+
}
131+
}, [container])
119132

120133
useEffect(() => {
121134
document.addEventListener("mousedown", handleMouseDown)
122135
document.addEventListener("touchstart", handleMouseDown)
123136
document.addEventListener("keydown", handleKeyDown)
124137

125138
return () => {
126-
// eslint-disable-next-line react-hooks/exhaustive-deps
127-
clearTimeout(transitionTimeoutId.current)
128139
document.removeEventListener("mousedown", handleMouseDown)
129140
document.removeEventListener("touchstart", handleMouseDown)
130141
document.removeEventListener("keydown", handleKeyDown)
131-
document.body.contains(container) && document.body.removeChild(container)
132142
}
133-
}, [container, handleMouseDown, handleKeyDown])
143+
}, [handleMouseDown, handleKeyDown])
134144

135145
return (
136146
<>

packages/web-console/src/components/Toast/index.tsx

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,132 @@ import React from "react"
22
import {
33
ToastContainer as RTToastContainer,
44
ToastContainerProps,
5-
toast as _toast,
5+
toast as rtToast,
66
Slide,
77
ToastOptions as RTToastOptions,
8+
ToastContent,
89
} from "react-toastify"
910
import { useNotificationCenter as RTNotificationCenter } from "react-toastify/addons/use-notification-center"
1011
import { NotificationCenterItem as RNotificationCenterItem } from "react-toastify/addons/use-notification-center/useNotificationCenter"
1112
import { BadgeType } from "../../scenes/Import/ImportCSVFiles/types"
1213
import {
13-
Check,
1414
CloseCircle,
1515
ErrorWarning,
1616
Information,
1717
} from "@styled-icons/remix-line"
18+
import { CheckmarkOutline } from "@styled-icons/evaicons-outline"
1819
import { theme } from "../../theme"
1920

2021
import "react-toastify/dist/ReactToastify.css"
22+
import "../../styles/_toast.scss"
2123

2224
interface StyledIconProps
2325
extends React.PropsWithRef<React.SVGProps<SVGSVGElement>> {
2426
size?: number | string
2527
title?: string | null
2628
}
2729

28-
export const toast = _toast
30+
export type ToastOptions = RTToastOptions
2931

3032
export const useNotificationCenter = RTNotificationCenter
3133

3234
export type NotificationCenterItem<Data> = RNotificationCenterItem<Data>
3335

34-
export type ToastOptions = RTToastOptions
35-
3636
export const ToastIcon = ({
3737
type,
38+
size = 18,
3839
...props
3940
}: StyledIconProps & {
4041
type: BadgeType
4142
}) => {
4243
switch (type) {
4344
case BadgeType.SUCCESS:
44-
return <Check {...props} color={theme.color.green} />
45+
return <CheckmarkOutline {...props} size={size} color={theme.color.green} />
4546
case BadgeType.WARNING:
46-
return <ErrorWarning {...props} color={theme.color.orange} />
47+
return <ErrorWarning {...props} size={size} color={theme.color.orange} />
4748
case BadgeType.ERROR:
48-
return <CloseCircle {...props} color={theme.color.red} />
49+
return <CloseCircle {...props} size={size} color={theme.color.red} />
4950
case BadgeType.INFO:
5051
default:
51-
return <Information {...props} color={theme.color.cyan} />
52+
return <Information {...props} size={size} color={theme.color.cyan} />
5253
}
5354
}
5455

56+
const toast = {
57+
info: (content: ToastContent, options?: ToastOptions) => {
58+
return rtToast.info(content, {
59+
icon: <ToastIcon type={BadgeType.INFO} />,
60+
className: "toast-info-container",
61+
progressStyle: {
62+
background: theme.color.cyan,
63+
},
64+
style: {
65+
borderColor: theme.color.cyan,
66+
background: theme.color.backgroundLighter,
67+
},
68+
...options,
69+
})
70+
},
71+
success: (content: ToastContent, options?: ToastOptions) => {
72+
return rtToast.success(content, {
73+
icon: <ToastIcon type={BadgeType.SUCCESS} />,
74+
className: "toast-success-container",
75+
progressStyle: {
76+
background: theme.color.green,
77+
},
78+
style: {
79+
borderColor: theme.color.green,
80+
background: theme.color.backgroundLighter,
81+
},
82+
...options,
83+
})
84+
},
85+
warning: (content: ToastContent, options?: ToastOptions) => {
86+
return rtToast.warning(content, {
87+
icon: <ToastIcon type={BadgeType.WARNING} />,
88+
className: "toast-warning-container",
89+
progressStyle: {
90+
background: theme.color.orange,
91+
},
92+
style: {
93+
borderColor: theme.color.orange,
94+
background: theme.color.backgroundLighter,
95+
},
96+
...options,
97+
})
98+
},
99+
error: (content: ToastContent, options?: ToastOptions) => {
100+
return rtToast.error(content, {
101+
icon: <ToastIcon type={BadgeType.ERROR} />,
102+
progressStyle: {
103+
background: theme.color.red,
104+
},
105+
className: "toast-error-container",
106+
style: {
107+
borderColor: theme.color.red,
108+
background: theme.color.backgroundLighter,
109+
},
110+
...options,
111+
})
112+
},
113+
dismiss: rtToast.dismiss,
114+
isActive: rtToast.isActive,
115+
}
116+
117+
export { toast }
118+
55119
export const ToastContainer = (props?: ToastContainerProps) => {
56120
const mergedProps: ToastContainerProps = {
57121
autoClose: 3000,
58122
draggable: false,
59123
position: "top-right",
60124
theme: "dark",
61125
transition: Slide,
126+
hideProgressBar: false,
127+
closeButton: true,
128+
closeOnClick: true,
129+
pauseOnHover: true,
130+
pauseOnFocusLoss: false,
62131
...props,
63132
}
64133

packages/web-console/src/components/TopBar/InstanceSettingsPopper.tsx

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,12 @@ const ErrorText = styled(Text)`
226226
margin-top: 0.2rem;
227227
`
228228

229-
const Footer = styled.div`
230-
display: flex;
231-
flex-direction: column;
232-
align-items: center;
233-
`
234-
235229
type Props = {
236230
active: boolean
237231
onToggle: (active: boolean) => void
238232
values: Preferences
239233
onSave: (values: Preferences) => Promise<void>
240234
onValuesChange: (values: Preferences) => void
241-
error: string | null
242235
trigger: ReactNode
243236
}
244237

@@ -248,7 +241,6 @@ export const InstanceSettingsPopper = ({
248241
values,
249242
onSave,
250243
onValuesChange,
251-
error,
252244
trigger,
253245
}: Props) => {
254246
const [isSaving, setIsSaving] = useState(false)
@@ -457,26 +449,23 @@ export const InstanceSettingsPopper = ({
457449
</ColorPickerContainer>
458450
)}
459451
</FormGroup>
460-
<Footer>
461-
{error && <ErrorText>{error}</ErrorText>}
462-
<Buttons>
463-
<StyledButton
464-
type="submit"
465-
prefixIcon={isSaving ? <Loader /> : undefined}
466-
data-hook="topbar-instance-save-button"
467-
>
468-
Save
469-
</StyledButton>
470-
<StyledButton
471-
type="button"
472-
onClick={() => onToggle(false)}
473-
skin="secondary"
474-
data-hook="topbar-instance-cancel-button"
475-
>
476-
Cancel
477-
</StyledButton>
478-
</Buttons>
479-
</Footer>
452+
<Buttons>
453+
<StyledButton
454+
type="submit"
455+
prefixIcon={isSaving ? <Loader /> : undefined}
456+
data-hook="topbar-instance-save-button"
457+
>
458+
Save
459+
</StyledButton>
460+
<StyledButton
461+
type="button"
462+
onClick={() => onToggle(false)}
463+
skin="secondary"
464+
data-hook="topbar-instance-cancel-button"
465+
>
466+
Cancel
467+
</StyledButton>
468+
</Buttons>
480469
</StyledForm>
481470
</Wrapper>
482471
</PopperToggle>

0 commit comments

Comments
 (0)