{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "pop", "type": "registry:item", "title": "aesthetic Popover", "description": "Aesthetic Popover primitive, v0.25.0. Installs ae-menu, ae-menu-item, ae-pop, ae-pop-positioner, ae-pop-surface without the full stylesheet. Recipes: pop.js.", "registryDependencies": [ "https://aesthetic.mistystep.io/r/aesthetic-base.json" ], "meta": { "version": "0.25.0", "tier": "primitive", "route": "pop", "classes": [ "ae-menu", "ae-menu-item", "ae-pop", "ae-pop-positioner", "ae-pop-surface" ], "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-ink-muted", "--ae-line", "--ae-ink-muted-dark", "--ae-line-dark", "--ae-w-medium", "--ae-radius", "--ae-z-pop" ], "recipes": ["pop.js"] }, "files": [ { "path": "registry/pop/aesthetic.pop.css", "type": "registry:file", "target": "~/aesthetic.pop.css", "content": "/* aesthetic pop v0.25.0 — generated by scripts/build-registry.mjs. */\n@import './aesthetic.base.css';\n\n:root {\n --ae-ink-muted: #737373;\n --ae-line: #e9e9e9;\n --ae-ink-muted-dark: #8f8f8f;\n --ae-line-dark: #262626;\n --ae-w-medium: 550;\n --ae-radius: 0;\n --ae-z-pop: 50;\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not(.light):not([data-ae-mode='light']) {\n --ae-ink-muted: var(--ae-ink-muted-dark);\n --ae-line: var(--ae-line-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-ink-muted: var(--ae-ink-muted-dark);\n --ae-line: var(--ae-line-dark);\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not(.light):not([data-ae-mode='light']) .ae-pop,\n :root:not(.light):not([data-ae-mode='light']) .ae-pop-surface {\n background: var(--ae-wash);\n box-shadow: none;\n }\n}\n\n.ae-pop {\nposition: fixed;\n inset: auto;\n margin: 0;\n border: 1px solid var(--ae-line);\n background: var(--ae-surface);\n color: var(--ae-ink);\n width: max-content;\n max-width: 22em;\n padding: 1em 1.2em;\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.04),\n 0 8px 28px rgba(0, 0, 0, 0.06);\n}\n\n.ae-pop:popover-open {\nanimation: ae-enter var(--ae-quick) var(--ae-ease) both;\n}\n\n.ae-pop::backdrop {\nbackground: transparent;\n}\n\n.ae-pop > .ae-menu:only-child {\nmargin: -1em -1.2em;\n border: 0;\n}\n\n.dark .ae-pop,\n[data-ae-mode='dark'] .ae-pop {\nbackground: var(--ae-wash);\n box-shadow: none;\n}\n\n.ae-pop-positioner {\nz-index: var(--ae-z-pop);\n}\n\n.ae-pop-surface {\nposition: relative;\n z-index: var(--ae-z-pop);\n border: 1px solid var(--ae-line);\n background: var(--ae-surface);\n color: var(--ae-ink);\n width: max-content;\n max-width: 22em;\n padding: 1em 1.2em;\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.04),\n 0 8px 28px rgba(0, 0, 0, 0.06);\n outline: none;\n}\n\n.ae-pop-surface[data-open] {\nanimation: ae-enter var(--ae-quick) var(--ae-ease) both;\n}\n\n.ae-pop-surface > .ae-menu:only-child {\nmargin: -1em -1.2em;\n border: 0;\n}\n\n.dark .ae-pop-surface,\n[data-ae-mode='dark'] .ae-pop-surface {\nbackground: var(--ae-wash);\n box-shadow: none;\n}\n\n.ae-menu {\nmargin: 0 0 0.9em;\n padding: 0.3em 0;\n border: 1px solid var(--ae-line);\n background: var(--ae-surface);\n max-height: 14em;\n overflow-y: auto;\n}\n\n.ae-menu button,\n.ae-menu-item {\ndisplay: block;\n width: 100%;\n text-align: left;\n background: transparent;\n border: 0;\n border-radius: var(--ae-radius);\n font: inherit;\n font-size: 13px;\n line-height: 1.7;\n color: var(--ae-ink-muted);\n padding: 0.4em 1.1em;\n cursor: pointer;\n transition:\n color var(--ae-quick) var(--ae-ease),\n background-color var(--ae-quick) var(--ae-ease);\n}\n\n.ae-menu button:hover,\n.ae-menu-item:hover,\n.ae-menu-item[data-highlighted] {\nbackground: var(--ae-wash);\n color: var(--ae-ink);\n}\n\n.ae-menu button.is-sel,\n.ae-menu-item.is-sel {\ncolor: var(--ae-ink);\n font-weight: var(--ae-w-medium);\n}\n\n@keyframes ae-enter {\nfrom {\n opacity: 0;\n transform: translateY(6px);\n }\n}\n" }, { "path": "recipes/pop.js", "type": "registry:file", "target": "~/aesthetic.pop.js", "content": "/* the popover: geometry for the slip + roving tabindex for its menu.\n Native [popover] owns the top layer, light dismiss, and Escape; this\n recipe places the open slip by its invoker and wires arrow-key\n navigation for any .ae-menu inside.\n\n \n
*/\n(() => {\n if (window.aePop) return;\n window.aePop = true;\n document.addEventListener(\n 'toggle',\n (e) => {\n const pop = e.target;\n if (!(pop instanceof HTMLElement)) return;\n if (!pop.classList.contains('ae-pop')) return;\n if (e.newState !== 'open' || !pop.id) return;\n const inv = document.querySelector(`[popovertarget=\"${pop.id}\"]`);\n if (!inv) return;\n const r = inv.getBoundingClientRect();\n const pr = pop.getBoundingClientRect();\n let top = r.bottom + 6;\n if (top + pr.height > innerHeight - 8) top = r.top - pr.height - 6;\n const left = Math.min(r.left, innerWidth - pr.width - 8);\n pop.style.top = `${Math.max(8, top)}px`;\n pop.style.left = `${Math.max(8, left)}px`;\n\n /* roving tabindex: focus the selected item or the first item on\n open, then arrow-key through the menu */\n const menu = pop.querySelector('.ae-menu');\n if (!menu) return;\n const items = [...menu.querySelectorAll('button')].filter(\n (b) => !b.disabled,\n );\n if (items.length === 0) return;\n items.forEach((b) => (b.tabIndex = -1));\n const sel = menu.querySelector('button.is-sel') || items[0];\n sel.tabIndex = 0;\n sel.focus();\n },\n true,\n );\n\n /* arrow-key roving for .ae-menu inside popovers */\n document.addEventListener('keydown', (e) => {\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key)) return;\n const menu = e.target.closest('.ae-menu');\n if (!menu) return;\n const items = [...menu.querySelectorAll('button')].filter(\n (b) => !b.disabled,\n );\n if (items.length === 0) return;\n const i = items.indexOf(e.target);\n let next;\n if (e.key === 'ArrowDown') next = items[(i + 1) % items.length];\n else if (e.key === 'ArrowUp')\n next = items[(i - 1 + items.length) % items.length];\n else if (e.key === 'Home') next = items[0];\n else if (e.key === 'End') next = items[items.length - 1];\n if (!next) return;\n e.preventDefault();\n items.forEach((b) => (b.tabIndex = -1));\n next.tabIndex = 0;\n next.focus();\n });\n})();\n" } ] }