{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "toast", "type": "registry:item", "title": "aesthetic Toast", "description": "Aesthetic Toast primitive, v0.25.0. Installs ae-err, ae-icon, ae-ok, ae-toast, ae-toast-x, ae-toasts, ae-warn without the full stylesheet. Recipes: toast.js.", "registryDependencies": [ "https://aesthetic.mistystep.io/r/aesthetic-base.json" ], "meta": { "version": "0.25.0", "tier": "primitive", "route": "toast", "classes": [ "ae-err", "ae-icon", "ae-ok", "ae-toast", "ae-toast-x", "ae-toasts", "ae-warn" ], "attributes": [], "tokens": [ "--ae-surface", "--ae-wash", "--ae-ink", "--ae-ink-faint", "--ae-accent", "--ae-surface-dark", "--ae-wash-dark", "--ae-ink-dark", "--ae-ink-faint-dark", "--ae-accent-dark", "--ae-font", "--ae-font-mono", "--ae-w-regular", "--ae-ease", "--ae-quick", "--ae-line", "--ae-ok", "--ae-warn", "--ae-err", "--ae-line-dark", "--ae-ok-dark", "--ae-warn-dark", "--ae-err-dark", "--ae-z-toast", "--ae-soft" ], "recipes": ["toast.js"] }, "files": [ { "path": "registry/toast/aesthetic.toast.css", "type": "registry:file", "target": "~/aesthetic.toast.css", "content": "/* aesthetic toast v0.25.0 — generated by scripts/build-registry.mjs. */\n@import './aesthetic.base.css';\n\n:root {\n --ae-line: #e9e9e9;\n --ae-ok: #15714b;\n --ae-warn: #8a5f32;\n --ae-err: #a84138;\n --ae-line-dark: #262626;\n --ae-ok-dark: #6fd2a8;\n --ae-warn-dark: #c49d72;\n --ae-err-dark: #e58379;\n --ae-z-toast: 100;\n --ae-soft: 240ms;\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not(.light):not([data-ae-mode='light']) {\n --ae-line: var(--ae-line-dark);\n --ae-ok: var(--ae-ok-dark);\n --ae-warn: var(--ae-warn-dark);\n --ae-err: var(--ae-err-dark);\n }\n}\n\n.light,\n[data-ae-mode='light'] {\n color-scheme: light;\n}\n\n:root.dark,\n:root[data-ae-mode='dark'] {\n color-scheme: dark;\n --ae-line: var(--ae-line-dark);\n --ae-ok: var(--ae-ok-dark);\n --ae-warn: var(--ae-warn-dark);\n --ae-err: var(--ae-err-dark);\n}\n\n.ae-icon {\nwidth: 1.2em;\n height: 1.2em;\n stroke: currentColor;\n stroke-width: 1.5;\n stroke-linecap: round;\n stroke-linejoin: round;\n fill: none;\n vertical-align: -0.2em;\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not(.light):not([data-ae-mode='light']) .ae-toast {\n background: var(--ae-wash);\n box-shadow: none;\n }\n}\n\n.ae-toasts {\nposition: fixed;\n right: 1.4em;\n bottom: 1.4em;\n z-index: var(--ae-z-toast);\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 0.6em;\n}\n\n.ae-toast {\ndisplay: flex;\n align-items: baseline;\n gap: 0.6em;\n background: var(--ae-surface);\n border: 1px solid var(--ae-line);\n color: var(--ae-ink);\n font-size: 13px;\n line-height: 1.6;\n padding: 0.7em 1.1em;\n max-width: 26em;\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.04),\n 0 8px 28px rgba(0, 0, 0, 0.06);\n animation: ae-enter var(--ae-soft) var(--ae-ease) both;\n}\n\n.ae-toast.is-leaving {\nopacity: 0;\n transition: opacity var(--ae-quick) var(--ae-ease);\n}\n\n.ae-toast-x {\nbackground: transparent;\n border: 0;\n padding: 0;\n margin-left: 0.4em;\n min-width: 24px;\n min-height: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: 13px;\n line-height: inherit;\n color: var(--ae-ink-faint);\n cursor: pointer;\n transition: color var(--ae-quick) var(--ae-ease);\n}\n\n.ae-toast-x:hover {\ncolor: var(--ae-ink);\n}\n\n.dark .ae-toast,\n[data-ae-mode='dark'] .ae-toast {\nbackground: var(--ae-wash);\n box-shadow: none;\n}\n\n.ae-ok {\ncolor: var(--ae-ok);\n}\n\n.ae-warn {\ncolor: var(--ae-warn);\n}\n\n.ae-err {\ncolor: var(--ae-err);\n}\n\n@keyframes ae-enter {\nfrom {\n opacity: 0;\n transform: translateY(6px);\n }\n}\n" }, { "path": "recipes/toast.js", "type": "registry:file", "target": "~/aesthetic.toast.js", "content": "/* the toast: news arrives at the edge and waits to be read.\n window.aeToast('Saved.', { status: 'ok' }) — ok|warn|err puts the\n hue on the glyph, the words stay ink. Toasts persist until\n dismissed or pushed out (the tray keeps four); pass { timeout: ms }\n to opt into self-dismissal — it is never the default. */\n(() => {\n if (window.aeToast) return;\n const ICONS = {\n ok: '',\n warn: '',\n err: '',\n };\n\n let tray = null;\n const ensureTray = () => {\n if (!tray) {\n tray = document.createElement('div');\n tray.className = 'ae-toasts';\n document.body.appendChild(tray);\n }\n return tray;\n };\n\n const dismiss = (toast) => {\n if (!toast.isConnected) return;\n toast.classList.add('is-leaving');\n setTimeout(() => toast.remove(), 200);\n };\n\n window.aeToast = (message, opts) => {\n const { status, timeout } = opts || {};\n const toast = document.createElement('div');\n toast.className = 'ae-toast';\n toast.setAttribute('role', 'status');\n if (status && ICONS[status]) {\n const i = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n i.setAttribute('class', `ae-icon ae-${status}`);\n i.setAttribute('viewBox', '0 0 24 24');\n i.innerHTML = ICONS[status];\n toast.appendChild(i);\n }\n toast.appendChild(document.createTextNode(message));\n const x = document.createElement('button');\n x.className = 'ae-toast-x';\n x.setAttribute('aria-label', 'dismiss');\n x.textContent = '✕';\n x.addEventListener('click', () => dismiss(toast));\n toast.appendChild(x);\n\n const t = ensureTray();\n t.appendChild(toast);\n while (t.children.length > 4) t.firstElementChild.remove();\n if (timeout) setTimeout(() => dismiss(toast), timeout);\n return toast;\n };\n})();\n" } ] }