{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"command-palette-wired-whole-menu","type":"registry:block","title":"command palette (wired to the whole menu)","description":"\"add 149\" — the defining SaaS interaction. This one actually navigates the menu: try \"glass\" or \"128\".","author":"Motion Menu","categories":["role-nav","signature","k","wired-live"],"dependencies":["gsap","lenis"],"registryDependencies":[],"meta":{"number":"149","slug":"command-palette-wired-whole-menu","framework":"react","docs":"https://motion-menu-two.vercel.app/p/command-palette-wired-whole-menu.md"},"files":[{"path":"motion-menu/command-palette-wired-whole-menu.html","type":"registry:file","target":"motion-menu/command-palette-wired-whole-menu.html","content":"<article class=\"card\">\n        <header><span class=\"num\">149</span><h3>Command palette</h3><div class=\"tags\"><i>⌘K</i><i>wired live</i></div><a class=\"format-action\" data-format-link data-pattern-slug=\"command-palette-wired-whole-menu\" href=\"/r/command-palette-wired-whole-menu.json?framework=react\" title=\"Open the React registry output\">React ↗</a></header>\n        <div class=\"demo\" style=\"flex-direction:column; gap:1rem;\">\n          <button class=\"btn\" id=\"palette-open\">open the palette — or press ⌘K</button>\n          <p style=\"font-family:var(--mono); font-size:.68rem; color:var(--dim); text-align:center;\">it indexes every pattern on this page (<span id=\"mm-lab-count\">…</span>) —<br>type a name or number, Enter jumps you there</p>\n        </div>\n        <p class=\"order\">Say: <b>\"add 149\"</b> — the defining SaaS interaction. This one actually navigates the menu: try \"glass\" or \"128\".</p>\n      </article>"},{"path":"motion-menu/command-palette-wired-whole-menu.css","type":"registry:file","target":"motion-menu/command-palette-wired-whole-menu.css","content":".section-head { padding: 14vh 0 5vh; }\n\n.sec-body.closed { display: none; }\n\n.section-head .kicker { font-family: var(--mono); font-size: .75rem; letter-spacing: .3em; text-transform: uppercase; color: var(--acc); }\n\n.section-head h2 { font-size: clamp(2rem, 5vw, 4rem); letter-spacing: -0.03em; margin-top: .6rem; }\n\n.section-head p { color: var(--dim); margin-top: .8rem; max-width: 36rem; line-height: 1.6; }\n\n.card {\n    border: 1px solid var(--line); border-radius: 14px; background: var(--card);\n    overflow: hidden; display: flex; flex-direction: column;\n  }\n\n.card > header { display: flex; align-items: baseline; gap: .8rem; padding: 1.1rem 1.2rem .9rem; border-bottom: 1px solid var(--line); }\n\n.card .num { font-family: var(--mono); color: var(--acc); font-size: 1.05rem; }\n\n.card h3 { font-size: 1.02rem; font-weight: 600; letter-spacing: -0.01em; flex: 1; }\n\n.tags { display: flex; gap: .35rem; }\n\n.tags i {\n    font: 400 .62rem/1 var(--mono); font-style: normal; color: var(--dim);\n    border: 1px solid var(--line); border-radius: 99px; padding: .28em .6em; white-space: nowrap;\n  }\n\n.demo {\n    min-height: 250px; position: relative; display: flex; align-items: center; justify-content: center;\n    background: var(--bg2); overflow: hidden; flex: 1;\n  }\n\n.order { padding: .85rem 1.2rem; font-family: var(--mono); font-size: .72rem; color: var(--dim); border-top: 1px solid var(--line); }\n\n.order b { color: var(--txt); font-weight: 500; }\n\n.btn {\n    font: 500 .8rem/1 var(--mono); color: var(--txt); background: transparent;\n    border: 1px solid rgba(255,255,255,.25); border-radius: 99px; padding: .8em 1.6em;\n    transition: border-color .3s;\n  }\n\n.btn:hover { border-color: var(--acc); color: var(--acc); }\n\n.demo .btn.corner { position: absolute; top: 12px; right: 12px; padding: .55em 1em; font-size: .68rem; z-index: 5; }\n\n.ai-card .num { color: var(--acc2) !important; }\n\n.anchor-tip.show { opacity: 1; transform: translateY(0); }\n\n.rm-pop.show { opacity: 1; pointer-events: auto; transform: translateY(0); }\n\n#fin-modal.show { display: flex; }\n\n.brief a.btn { text-decoration: none; text-align: center; }\n\n#palette-overlay.show { display: flex; }\n\n.palette { width: min(520px, 92vw); background: var(--bg2); border: 1px solid rgba(255,255,255,.15); border-radius: 14px; overflow: hidden;\n    box-shadow: 0 30px 80px rgba(0,0,0,.6); }\n\n.palette input { width: 100%; background: transparent; border: 0; outline: 0; color: var(--txt);\n    font: 500 1rem var(--sans); padding: 1rem 1.2rem; border-bottom: 1px solid var(--line); }\n\n.palette .p-list { max-height: 46vh; overflow-y: auto; }\n\n.palette .p-item { display: flex; gap: .8rem; padding: .7rem 1.2rem; font: 400 .78rem var(--mono); color: var(--dim); cursor: pointer; align-items: baseline; }\n\n.palette .p-item .pn { color: var(--acc); flex: none; width: 34px; }\n\n.palette .p-item.sel, .palette .p-item:hover { background: rgba(183,255,46,.08); color: var(--txt); }\n\n.palette .p-hint { padding: .5rem 1.2rem; font: 400 .6rem var(--mono); color: var(--dim); border-top: 1px solid var(--line); }\n\n.demo:has(.hascheck input:checked) .hasbtn { border-color: var(--acc); color: var(--acc); pointer-events: auto; opacity: 1; }"},{"path":"components/motion-menu/command-palette-wired-whole-menu.tsx","type":"registry:component","content":"// @ts-nocheck — generated wrapper; inlined pattern JS is imperative DOM code, not authored TS.\n\"use client\";\n// command palette (wired to the whole menu) — Motion Menu\nimport { useEffect, useRef } from \"react\";\n\nconst MARKUP = \"<article class=\\\"card\\\">\\n        <header><span class=\\\"num\\\">149</span><h3>Command palette</h3><div class=\\\"tags\\\"><i>\\u2318K</i><i>wired live</i></div><a class=\\\"format-action\\\" data-format-link data-pattern-slug=\\\"command-palette-wired-whole-menu\\\" href=\\\"/r/command-palette-wired-whole-menu.json?framework=react\\\" title=\\\"Open the React registry output\\\">React \\u2197</a></header>\\n        <div class=\\\"demo\\\" style=\\\"flex-direction:column; gap:1rem;\\\">\\n          <button class=\\\"btn\\\" id=\\\"palette-open\\\">open the palette \\u2014 or press \\u2318K</button>\\n          <p style=\\\"font-family:var(--mono); font-size:.68rem; color:var(--dim); text-align:center;\\\">it indexes every pattern on this page (<span id=\\\"mm-lab-count\\\">\\u2026</span>) \\u2014<br>type a name or number, Enter jumps you there</p>\\n        </div>\\n        <p class=\\\"order\\\">Say: <b>\\\"add 149\\\"</b> \\u2014 the defining SaaS interaction. This one actually navigates the menu: try \\\"glass\\\" or \\\"128\\\".</p>\\n      </article>\";\n\nexport function CommandPaletteWiredWholeMenu() {\n  const hostRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const host = hostRef.current;\n    if (!host) return;\n    const $ = (s: string) => host.querySelector(s) as HTMLElement | null;\n    let disposed = false;\n    const cleanup: Array<() => void> = [];\n\n    (async () => {\n      if (disposed) return;\n      try {\n        /* ---- 149 · command palette (wired to the whole menu) ---- */\n        {\n          const overlay = document.createElement('div');\n          overlay.id = 'palette-overlay';\n          overlay.innerHTML = `<div class=\"palette\">\n            <input id=\"palette-input\" placeholder=\"search patterns — try 'glass', 'quote', or a number…\" autocomplete=\"off\">\n            <div class=\"p-list\" id=\"palette-list\"></div>\n            <div class=\"p-hint\">↑↓ navigate · Enter jump · Esc close</div>\n          </div>`;\n          document.body.appendChild(overlay);\n          const input = overlay.querySelector('#palette-input');\n          const listEl = overlay.querySelector('#palette-list');\n          let index = null, results = [], sel = 0;\n          function buildIndex() {\n            if (index) return;\n            index = [...document.querySelectorAll('article.card')].map((card) => ({\n              num: card.querySelector('.num')?.textContent.trim() || '',\n              title: card.querySelector('h3')?.textContent.trim() || '',\n              card,\n            })).filter((x) => x.num);\n          }\n          // The palette indexes every article.card on the page — state that count instead of a\n          // number typed at authoring time, which drifts the moment a card is added or removed\n          // (this one read \"158\" while the page had grown to 566).\n          buildIndex();\n          input.placeholder = `search ${index.length} patterns — try 'glass', 'quote', or a number…`;\n          const labCount = document.getElementById('mm-lab-count');\n          if (labCount) labCount.textContent = index.length;\n          function renderList(q) {\n            const query = q.trim().toLowerCase();\n            results = index.filter((x) => !query || x.num.includes(query) || x.title.toLowerCase().includes(query))\n              .sort((a, b) => {\n                const as = a.title.toLowerCase().startsWith(query) || a.num === query ? 0 : 1;\n                const bs = b.title.toLowerCase().startsWith(query) || b.num === query ? 0 : 1;\n                return as - bs;\n              }).slice(0, 9);\n            sel = 0;\n            listEl.innerHTML = results.map((x, i) =>\n              `<div class=\"p-item${i === 0 ? ' sel' : ''}\" data-i=\"${i}\"><span class=\"pn\">${x.num}</span><span>${x.title}</span></div>`).join('')\n              || '<div class=\"p-item\">nothing matches</div>';\n            listEl.querySelectorAll('.p-item[data-i]').forEach((el) => el.addEventListener('click', () => jump(results[Number(el.dataset.i)])));\n          }\n          function jump(hit) {\n            if (!hit) return;\n            close();\n            const body = hit.card.closest('.sec-body');\n            if (body?.classList.contains('closed')) {\n              body.previousElementSibling.querySelector('.section-head').click();\n            }\n            requestAnimationFrame(() => {\n              const y = window.scrollY + hit.card.getBoundingClientRect().top - innerHeight * 0.18;\n              (window.lenis ? window.lenis.scrollTo(y, { duration: 1 }) : window.scrollTo(0, y));\n              gsap.fromTo(hit.card, { boxShadow: '0 0 0 2px rgba(183,255,46,0.9)' },\n                { boxShadow: '0 0 0 2px rgba(183,255,46,0)', duration: 1.6, delay: 0.6 });\n            });\n          }\n          function open() {\n            buildIndex();\n            overlay.classList.add('show');\n            input.value = '';\n            renderList('');\n            input.focus();\n          }\n          function close() { overlay.classList.remove('show'); }\n          document.getElementById('palette-open').addEventListener('click', open);\n          window.addEventListener('keydown', (e) => {\n            if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); overlay.classList.contains('show') ? close() : open(); }\n            if (!overlay.classList.contains('show')) return;\n            if (e.key === 'Escape') close();\n            if (e.key === 'ArrowDown') { sel = Math.min(sel + 1, results.length - 1); paint(); e.preventDefault(); }\n            if (e.key === 'ArrowUp') { sel = Math.max(sel - 1, 0); paint(); e.preventDefault(); }\n            if (e.key === 'Enter') jump(results[sel]);\n          });\n          function paint() {\n            listEl.querySelectorAll('.p-item').forEach((el, i) => el.classList.toggle('sel', i === sel));\n          }\n          input.addEventListener('input', () => renderList(input.value));\n          overlay.addEventListener('click', (e) => { if (e.target === overlay) close(); });\n        }\n      } catch (err: any) {\n        console.warn(\"[motion-menu] command-palette-wired-whole-menu failed to start:\", err);\n      }\n    })();\n\n    return () => {\n      disposed = true;\n      cleanup.forEach((fn) => { try { fn(); } catch (_) {} });\n    };\n  }, []);\n\n  return <div ref={hostRef} dangerouslySetInnerHTML={{ __html: MARKUP }} />;\n}\n\nexport default CommandPaletteWiredWholeMenu;\n"}]}