70 lines
2.4 KiB
JavaScript
70 lines
2.4 KiB
JavaScript
// MNote UI 基础运行时:全局 portal 与 toast API。
|
|||
|
|
(function initMnoteUiRuntime() {
|
||
|
|
if (window.__mnoteUiRuntimeStarted) return;
|
||
|
|
window.__mnoteUiRuntimeStarted = true;
|
||
|
|
|
||
|
|
function ensurePortalRoot() {
|
||
|
|
var root = document.getElementById('mnote-portal-root');
|
||
|
|
if (root instanceof HTMLElement) return root;
|
||
|
|
root = document.createElement('div');
|
||
|
|
root.id = 'mnote-portal-root';
|
||
|
|
root.setAttribute('data-mnote-portal-root', 'true');
|
||
|
|
document.body.appendChild(root);
|
||
|
|
return root;
|
||
|
|
}
|
||
|
|
|
||
|
|
function ensureToastRegion() {
|
||
|
|
var root = ensurePortalRoot();
|
||
|
|
var region = root.querySelector('[data-mnote-toast-region="true"]');
|
||
|
|
if (region instanceof HTMLElement) return region;
|
||
|
|
region = document.createElement('div');
|
||
|
|
region.className = 'mnote-toast-region';
|
||
|
|
region.setAttribute('data-mnote-toast-region', 'true');
|
||
|
|
region.setAttribute('role', 'status');
|
||
|
|
region.setAttribute('aria-live', 'polite');
|
||
|
|
root.appendChild(region);
|
||
|
|
return region;
|
||
|
|
}
|
||
|
|
|
||
|
|
function toast(message, options) {
|
||
|
|
var text = String(message || '').trim();
|
||
|
|
if (!text) return null;
|
||
|
|
var config = options || {};
|
||
|
|
var kind = String(config.kind || config.type || 'info').trim() || 'info';
|
||
|
|
var timeoutMs = Number(config.timeoutMs || config.duration || 3200);
|
||
|
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 800) timeoutMs = 3200;
|
||
|
|
var region = ensureToastRegion();
|
||
|
|
var item = document.createElement('div');
|
||
|
|
item.className = 'mnote-toast mnote-toast--' + kind;
|
||
|
|
item.setAttribute('data-mnote-toast', 'true');
|
||
|
|
item.setAttribute('data-kind', kind);
|
||
|
|
item.textContent = text;
|
||
|
|
region.appendChild(item);
|
||
|
|
requestAnimationFrame(function showToast() {
|
||
|
|
item.classList.add('mnote-toast--visible');
|
||
|
|
});
|
||
|
|
window.setTimeout(function hideToast() {
|
||
|
|
item.classList.remove('mnote-toast--visible');
|
||
|
|
window.setTimeout(function removeToast() {
|
||
|
|
if (item.parentNode) item.parentNode.removeChild(item);
|
||
|
|
}, 180);
|
||
|
|
}, timeoutMs);
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
|
||
|
|
window.mnote = window.mnote || {};
|
||
|
|
window.mnote.ensurePortalRoot = ensurePortalRoot;
|
||
|
|
window.mnote.toast = toast;
|
||
|
|
|
||
|
|
window.addEventListener('mnote:toast', function onMnoteToast(event) {
|
||
|
|
var detail = event && event.detail ? event.detail : {};
|
||
|
|
toast(detail.message, detail);
|
||
|
|
});
|
||
|
|
|
||
|
|
if (document.readyState === 'loading') {
|
||
|
|
document.addEventListener('DOMContentLoaded', ensurePortalRoot, { once: true });
|
||
|
|
} else {
|
||
|
|
ensurePortalRoot();
|
||
|
|
}
|
||
|
|
})();
|