let debounceTimer = null; export function initNpmSearch(onSelect) { const input = document.getElementById('npm-search-input'); const results = document.getElementById('npm-search-results'); if (!input || !results) return; input.addEventListener('input', () => { clearTimeout(debounceTimer); const q = input.value.trim(); if (q.length < 2) { results.classList.add('hidden'); results.innerHTML = ''; return; } debounceTimer = setTimeout(() => searchNpm(q, results, input, onSelect), 300); }); input.addEventListener('keydown', (e) => { if (e.key === 'Escape') { results.classList.add('hidden'); } }); document.addEventListener('click', (e) => { if (!input.contains(e.target) && !results.contains(e.target)) { results.classList.add('hidden'); } }); } async function searchNpm(query, container, input, onSelect) { try { const res = await fetch(`https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(query)}&size=8`); if (!res.ok) return; const data = await res.json(); const packages = data.objects || []; if (!packages.length) { container.innerHTML = '
No packages found
'; container.classList.remove('hidden'); return; } container.innerHTML = packages.map(p => { const pkg = p.package; const desc = (pkg.description || '').slice(0, 80); return `
${esc(pkg.name)} ${esc(pkg.version)}
${esc(desc)}
`; }).join(''); container.querySelectorAll('.npm-result').forEach(el => { el.addEventListener('click', () => { const name = el.dataset.name; const url = `https://esm.sh/${name}`; onSelect({ name, url, type: 'js' }); input.value = ''; container.classList.add('hidden'); }); }); container.classList.remove('hidden'); } catch (_) { container.classList.add('hidden'); } } function esc(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; }