♻️ refactor(client): 浏览器半拆成 src 模块,client.js 改由构建产出
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* The light in-app popup stack: its lifetime, its ordering, and its bound.
|
||||
*
|
||||
* @module @dsh-plugin/session-notify/client/core/toasts
|
||||
*/
|
||||
|
||||
import { TOAST_DURATION_MS, TOAST_LIMIT } from '../constants.js'
|
||||
|
||||
/**
|
||||
* Build the popup stack over one store.
|
||||
* @param deps - the plugin store, and the copy table a candidate is rendered with.
|
||||
* @returns the stack's operations, including the three the popup element calls back into.
|
||||
*/
|
||||
export function createToastStack({ store, copy }) {
|
||||
const timers = new Map()
|
||||
let seq = 0
|
||||
|
||||
/** Drop one popup and cancel its lifetime timer. */
|
||||
const closeToast = (id) => {
|
||||
const timer = timers.get(id)
|
||||
if (timer !== undefined) {
|
||||
clearTimeout(timer)
|
||||
timers.delete(id)
|
||||
}
|
||||
const snapshot = store.getSnapshot()
|
||||
if (!snapshot.toasts.some((toast) => toast.id === id)) return
|
||||
store.set({ ...snapshot, toasts: snapshot.toasts.filter((toast) => toast.id !== id) })
|
||||
}
|
||||
|
||||
/** Arm one popup's lifetime; hovering calls `hold` first, then this again. */
|
||||
const armToast = (id) => {
|
||||
const timer = timers.get(id)
|
||||
if (timer !== undefined) clearTimeout(timer)
|
||||
timers.set(id, setTimeout(() => closeToast(id), TOAST_DURATION_MS))
|
||||
}
|
||||
|
||||
/** Pause one popup's lifetime while the pointer rests on it. */
|
||||
const holdToast = (id) => {
|
||||
const timer = timers.get(id)
|
||||
if (timer === undefined) return
|
||||
clearTimeout(timer)
|
||||
timers.delete(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Show one light in-app popup: the trigger as the title, the conversation
|
||||
* and its detail as the description, so the heading says what happened and
|
||||
* the line under it says where.
|
||||
*/
|
||||
const showToast = (candidate) => {
|
||||
const notice = copy.copyFor(candidate)
|
||||
seq += 1
|
||||
const toast = {
|
||||
id: `dsn-${String(seq)}`,
|
||||
kind: notice.kind,
|
||||
title: notice.title,
|
||||
body: notice.body,
|
||||
sessionId: candidate.sessionId,
|
||||
}
|
||||
const snapshot = store.getSnapshot()
|
||||
const next = [toast, ...snapshot.toasts]
|
||||
for (const dropped of next.slice(TOAST_LIMIT)) {
|
||||
const timer = timers.get(dropped.id)
|
||||
if (timer !== undefined) {
|
||||
clearTimeout(timer)
|
||||
timers.delete(dropped.id)
|
||||
}
|
||||
}
|
||||
store.set({ ...snapshot, toasts: next.slice(0, TOAST_LIMIT) })
|
||||
armToast(toast.id)
|
||||
}
|
||||
|
||||
/** Cancel every lifetime timer: the plugin is being disposed, so nothing may fire later. */
|
||||
const dispose = () => {
|
||||
for (const timer of timers.values()) clearTimeout(timer)
|
||||
timers.clear()
|
||||
}
|
||||
|
||||
return { showToast, closeToast, armToast, holdToast, dispose }
|
||||
}
|
||||
Reference in New Issue
Block a user