Promote classifier's local toast (classifier/css/base.css + showToast
in classifier/js/excel.js) into shared/toast.{js,css}. Every tool's
build.sh now concatenates them, so window.zddc.toast(msg, level, opts)
is callable from any tool.
API:
window.zddc.toast('Saved.', 'success');
window.zddc.toast('Could not load: ' + err.message, 'error');
window.zddc.toast('Note', 'info', { durationMs: 3000 });
Levels: info (default) | success | warning | error. Single-toast
policy — a second call replaces the first. Click anywhere on the
toast to dismiss. ARIA: error → role=alert/aria-live=assertive,
others → role=status/aria-live=polite.
Class prefix is .zddc-toast (BEM-ish) to avoid colliding with any
tool-local .toast rules. Classifier's existing showToast now
delegates to window.zddc.toast — call sites in excel.js +
selection.js are unchanged. Classifier's local .toast CSS block
deleted in favor of the shared one.
This commit only EXPOSES the API. Replacing the ~25 alert() call
sites scattered across archive/transmittal/mdedit/classifier with
toast calls is left as follow-up — each alert needs per-call review
to decide if it's truly non-blocking.
Five Playwright tests in tests/toast.spec.js lock the contract:
API exposure, level mapping, ARIA roles, single-toast replace,
click-to-dismiss.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
63 lines
2.5 KiB
JavaScript
63 lines
2.5 KiB
JavaScript
// shared/toast.js — non-blocking notification helper available to every
|
|
// tool via window.zddc.toast(msg, level, opts). Originated as classifier's
|
|
// local showToast (classifier/js/excel.js); promoted here so tools that
|
|
// today use alert() or silent console.error can switch to a uniform
|
|
// non-blocking surface.
|
|
//
|
|
// Usage:
|
|
// window.zddc.toast('Saved.', 'success');
|
|
// window.zddc.toast('Could not load: ' + err.message, 'error');
|
|
// window.zddc.toast('Note', 'info', { durationMs: 3000 });
|
|
//
|
|
// Levels: 'info' (default) | 'success' | 'warning' | 'error'.
|
|
// Each tool may also expose app.notify(msg, level) as a thin wrapper —
|
|
// see ARCHITECTURE.md for the convention.
|
|
(function () {
|
|
'use strict';
|
|
|
|
if (!window.zddc) window.zddc = {};
|
|
// Don't overwrite if a tool defined its own first.
|
|
if (typeof window.zddc.toast === 'function') return;
|
|
|
|
var DEFAULT_DURATION_MS = 5000;
|
|
var FADE_MS = 300;
|
|
|
|
function toast(message, level, opts) {
|
|
opts = opts || {};
|
|
var lvl = (level === 'success' || level === 'error' ||
|
|
level === 'warning') ? level : 'info';
|
|
|
|
// Single-toast policy: dismiss any existing toast immediately
|
|
// so the new one is always the most recent. Matches the
|
|
// classifier's prior behavior and avoids stack-of-toasts UX.
|
|
var existing = document.querySelector('.zddc-toast');
|
|
if (existing) existing.remove();
|
|
|
|
var el = document.createElement('div');
|
|
el.className = 'zddc-toast zddc-toast--' + lvl;
|
|
// ARIA: errors get assertive (interrupts SR queue), others polite.
|
|
el.setAttribute('role', lvl === 'error' ? 'alert' : 'status');
|
|
el.setAttribute('aria-live', lvl === 'error' ? 'assertive' : 'polite');
|
|
el.textContent = message == null ? '' : String(message);
|
|
document.body.appendChild(el);
|
|
|
|
var dur = typeof opts.durationMs === 'number' ?
|
|
opts.durationMs : DEFAULT_DURATION_MS;
|
|
var timer = setTimeout(function () {
|
|
el.classList.add('zddc-toast--fade');
|
|
setTimeout(function () {
|
|
if (el.parentNode) el.parentNode.removeChild(el);
|
|
}, FADE_MS);
|
|
}, dur);
|
|
|
|
// Click-to-dismiss. Useful for sticky errors the user wants gone.
|
|
el.addEventListener('click', function () {
|
|
clearTimeout(timer);
|
|
if (el.parentNode) el.parentNode.removeChild(el);
|
|
});
|
|
|
|
return el;
|
|
}
|
|
|
|
window.zddc.toast = toast;
|
|
})();
|