close toasts notifications by clicking

Massimo Melina committed Jul 4, 2024 at 11:53 UTC 856c4c667146f4502cd1c86ec6b6c08323a6a13b
1 file changed +15 -5
frontend/src/toasts.ts
+15 -5
@@ -12,7 +12,7 @@ type Content = string | ReactElement
12 export function toast(content: Content, type: ToastType='info', { timeout=5_000 }: { timeout?: number } & Omit<ToastOptions, 'id' | 'content' | 'type'>={}) {
13 console.debug("toast", content)
14 const id = Math.random()
15 - toasts.push({ id, content, type })
15 + toasts.push({ id, content, type, close })
16 const closed = pendingPromise()
17 setTimeout(close, timeout)
18 return {
@@ -29,12 +29,15 @@ export function toast(content: Content, type: ToastType='info', { timeout=5_000
29 }
30
31 interface ToastOptions extends Omit<Partial<HTMLAttributes<HTMLDivElement>>, 'id' | 'content'> {
32 - id: number
32 content: Content
33 type: ToastType
34 +}
35 +interface ToastRecord extends ToastOptions {
36 + id: number
37 closed?: boolean
38 + close: () => void
39 }
37 -const toasts = proxy<ToastOptions[]>([])
40 +const toasts = proxy<ToastRecord[]>([])
41
42 export function Toasts() {
43 const snap = useSnapshot(toasts)
@@ -44,7 +47,7 @@ export function Toasts() {
47 )
48 }
49
47 -function Toast({ content, type, closed, id, ...props }: ToastOptions) {
50 +function Toast({ content, type, closed, id, close, ...props }: ToastRecord) {
51 const [addClass, setAddClass] = useState('before')
52 const [height, setHeight] = useState('')
53 useEffect(() => {
@@ -59,7 +62,14 @@ function Toast({ content, type, closed, id, ...props }: ToastOptions) {
62 }, [addClass])
63 const ref = useRef<HTMLDivElement | null>()
64 content = useMemo(() => isValidElement(content) ? cloneElement(content) : content, [content]) // proxied elements are frozen, and crash
62 - return h('div', { ...props, ref, style: { height }, onTransitionEnd, className: `toast ${addClass} ${_.isString(type) ? 'toast-' + type : ''} ${props.className || ''}`},
65 + return h('div', {
66 + ...props,
67 + ref,
68 + style: { height },
69 + onTransitionEnd,
70 + onClick: close,
71 + className: `toast ${addClass} ${_.isString(type) ? 'toast-' + type : ''} ${props.className || ''}`
72 + },
73 h('div', { className: 'toast-icon' }, isValidElement(type) ? type : hIcon(type)),
74 h('div', { className: 'toast-content' }, content)
75 )