smart-core.js

SmartCore

Three optional global UI primitives — <smart-toast>, <smart-loader>, and <smart-modal> — that wire up in one script tag and communicate with every other SmartComponent automatically via window CustomEvents.

Zero dependencies Event-driven Graceful degradation Dark mode
<script src="smart-core.js"></script>

Architecture

All three components follow the same decoupled pattern. They listen for events dispatched on window and react. Nothing else in your codebase needs a reference to them. If smart-core.js is not loaded, every other SmartComponent degrades silently — SmartTable falls back to window.confirm() for deletes, inline toasts for feedback, etc.

<!-- 1. Place singletons once, near the top of <body>.
        Loading order relative to the page doesn't matter. -->
<smart-toast position="top-right" max="5"></smart-toast>
<smart-modal></smart-modal>
<smart-loader></smart-loader>

<!-- 2. Fire from anywhere — no import, no reference required. -->
window.dispatchEvent(new CustomEvent('smart-toast',  { detail: { message, type } }));
window.dispatchEvent(new CustomEvent('smart-loader', { detail: { action: 'show' } }));
window.dispatchEvent(new CustomEvent('smart-confirm', { detail: { title, message, onConfirm }, cancelable: true }));
ComponentListens forFallback when absent
<smart-toast> smart-toast SmartTable shows its own inline toast below the table.
<smart-loader> smart-loader No overlay shown — your app continues unaffected.
<smart-modal> smart-confirm SmartTable runs window.confirm() instead.
<smart-toast>

SmartToast

Stacked, auto-dismissing toast notifications anchored to any corner of the viewport. Fire from anywhere with a single window.dispatchEvent() call — no import or element reference required.

5 types Progress bar Promise mode 6 positions Stack limit

Toast Types

Five semantic types — each with distinct icon and colour. Click any button to see a live toast fired on the real <smart-toast> instance mounted on this page.

Toasts appear bottom-right and auto-dismiss after 3.5 s. Hover to pause.

// Fire a toast from anywhere in your app
window.dispatchEvent(new CustomEvent('smart-toast', {
  detail: {
    message:  'File saved successfully.',
    type:     'success',  // 'success' | 'error' | 'warning' | 'info' | 'loading'
    duration: 3500,        // ms — 0 = persistent until dismissed
  }
}));

// From a Django view response — call after fetch()
async function save() {
  const res = await fetch('/api/save/', { method: 'POST', ... });
  const type = res.ok ? 'success' : 'error';
  window.dispatchEvent(new CustomEvent('smart-toast', {
    detail: { message: res.ok ? 'Saved!' : 'Save failed.', type }
  }));
}

Promise Mode

Pass a promise in the detail object and SmartToast shows a loading state automatically. When the promise resolves it switches to success; on rejection it shows the error message. Perfect for wrapping fetch() calls.

Has a 65% chance of resolving. Watch the toast transition from loading → success / error.

// Wrap any Promise — toast handles all three states automatically
const p = fetch('/api/process/', { method: 'POST' });

window.dispatchEvent(new CustomEvent('smart-toast', {
  detail: {
    promise: p,
    loading: 'Processing request…',
    success: 'Request completed!',
    error:   'Request failed — please retry.',
  }
}));

// Works with any thenable — not just fetch()
// On resolve: switches to success toast, auto-dismisses after 3 s
// On reject:  switches to error toast, auto-dismisses after 3 s

Reference

Element attributes

AttributeTypeDescriptionDefault
position string Stack anchor. One of: top-right, top-left, top-center, bottom-right, bottom-left, bottom-center. bottom-right
max number Maximum number of visible toasts. Oldest is dismissed when the limit is reached. 5

Event detail (smart-toast)

KeyTypeDescriptionDefault
message string Toast body text. HTML is escaped automatically. ""
type string success | error | warning | info | loading info
duration number Auto-dismiss delay in milliseconds. Pass 0 for a persistent toast. 3000
promise Promise Any thenable. When provided, shows a loading toast that transitions to success or error on settle. message is ignored.
loading string Message shown while the promise is pending. Loading…
success string Message shown when the promise resolves. Done!
error string Message shown when the promise rejects. Failed.
<!-- Minimal — one singleton anywhere in your base template -->
<smart-toast position="bottom-right" max="5"></smart-toast>

// Standard toast
window.dispatchEvent(new CustomEvent('smart-toast', {
  detail: { message: 'Done!', type: 'success', duration: 4000 }
}));

// Persistent — stays until user clicks ✕
window.dispatchEvent(new CustomEvent('smart-toast', {
  detail: { message: 'System maintenance in 5 min.', type: 'warning', duration: 0 }
}));
<smart-loader>

SmartLoader

Full-page or element-scoped overlay loader with a 200ms flicker-prevention delay. Show and hide it from anywhere via smart-loader window events. Stacks gracefully — multiple concurrent show calls resolve correctly when all matching hide calls arrive.

Full-page Scoped to element Flicker-prevention Concurrent-safe

Full-page & Scoped

The global loader covers the entire viewport with a blurred backdrop. The scoped variant positions itself absolutely inside any element with an id — set scope in the event detail to the target element's id.

Scoped target — loader appears here
// Full-page — covers entire viewport
window.dispatchEvent(new CustomEvent('smart-loader', {
  detail: { action: 'show' }
}));

// Hide when done
window.dispatchEvent(new CustomEvent('smart-loader', {
  detail: { action: 'hide' }
}));

// Scoped — overlays the element with id="myCard"
// The element needs no extra CSS — position is set automatically
window.dispatchEvent(new CustomEvent('smart-loader', {
  detail: { action: 'show', scope: 'myCard' }
}));
window.dispatchEvent(new CustomEvent('smart-loader', {
  detail: { action: 'hide', scope: 'myCard' }
}));

// Wrap an async operation
async function loadData() {
  window.dispatchEvent(new CustomEvent('smart-loader', { detail: { action: 'show' } }));
  try {
    const data = await fetch('/api/data/').then(r => r.json());
    renderData(data);
  } finally {
    window.dispatchEvent(new CustomEvent('smart-loader', { detail: { action: 'hide' } }));
  }
}

Reference

Element

<!-- One singleton anywhere in <body> — no attributes required -->
<smart-loader></smart-loader>

Event detail (smart-loader)

KeyTypeDescription
action string Required. "show" — display the loader (200ms delay). "hide" — dismiss it with a fade-out transition.
scope string Optional element id. When provided, the overlay is scoped to that element instead of covering the full page. The element's position is temporarily set to relative if needed.

The 200ms delay prevents a loading flash for operations that finish almost instantly (common on fast connections). If hide arrives before the delay expires, no overlay is shown at all.