/** * The light popup stack: the frame-wide overlay entry this package owns. * * @module @dsh-plugin/session-notify/client/ui/ToastLayer */ import * as React from 'react' import { KindIcon, CloseIcon } from './icons.js' import { seatTranslator, useOwnStore } from './hooks.js' import { CSS } from './styles.js' const h = React.createElement export function ToastLayer(props) { const snapshot = useOwnStore(props.store) const toasts = snapshot.toasts const tr = seatTranslator(props, props.fallbackT) React.useEffect(() => { if (toasts.length === 0) return undefined const onKeyDown = (event) => { if (event.key !== 'Escape' || event.defaultPrevented) return const top = toasts[0] if (top === undefined) return event.preventDefault() props.dismiss(top.id) } document.addEventListener('keydown', onKeyDown) return () => { document.removeEventListener('keydown', onKeyDown) } }, [toasts, props]) if (toasts.length === 0) return null return h(React.Fragment, null, h('style', null, CSS), h('div', { className: 'dsn-stack', role: 'region', 'aria-live': 'polite' }, toasts.map((toast) => h('div', { key: toast.id, className: 'dsn-toast', role: toast.kind === 'completion' ? 'status' : 'alert', onMouseEnter: () => props.hold(toast.id), onMouseLeave: () => props.arm(toast.id), }, h('span', { className: `dsn-toast-icon is-${toast.kind}` }, h(KindIcon, { kind: toast.kind, size: 16 })), h('div', { className: 'dsn-toast-text' }, h('div', { className: 'dsn-toast-title' }, toast.title), h('div', { className: 'dsn-toast-desc' }, toast.body)), h('div', { className: 'dsn-toast-actions' }, h('button', { type: 'button', className: 'dsn-toast-action', onClick: () => { props.dismiss(toast.id) props.open(toast.sessionId) }, }, tr('toast.view')), h('button', { type: 'button', className: 'dsn-toast-close', 'aria-label': tr('toast.dismiss'), onClick: () => props.dismiss(toast.id), }, h(CloseIcon, { size: 14 }))))))) }