forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1import { normalizeSearchParam } from '#shared/utils/url'
2import { debounce } from 'perfect-debounce'
3
4// Pages that have their own local filter using ?q
5const pagesWithLocalFilter = new Set(['~username', 'org'])
6
7export function useGlobalSearch() {
8 const { searchProvider } = useSearchProvider()
9 const searchProviderValue = computed(() => {
10 const p = normalizeSearchParam(route.query.p)
11 if (p === 'npm' || searchProvider.value === 'npm') return 'npm'
12 return 'algolia'
13 })
14 const router = useRouter()
15 const route = useRoute()
16 const searchQuery = useState<string>('search-query', () => {
17 if (pagesWithLocalFilter.has(route.name as string)) {
18 return ''
19 }
20 return normalizeSearchParam(route.query.q)
21 })
22
23 // clean search input when navigating away from search page
24 watch(
25 () => route.query.q,
26 urlQuery => {
27 const value = normalizeSearchParam(urlQuery)
28 if (!value) searchQuery.value = ''
29 if (!searchQuery.value) searchQuery.value = value
30 },
31 )
32 const updateUrlQueryImpl = (value: string, provider: 'npm' | 'algolia') => {
33 const isSameQuery = route.query.q === value && route.query.p === provider
34 // Don't navigate away from pages that use ?q for local filtering
35 if (pagesWithLocalFilter.has(route.name as string) || isSameQuery) {
36 return
37 }
38
39 if (route.name === 'search') {
40 router.replace({
41 query: {
42 ...route.query,
43 q: value || undefined,
44 p: provider === 'npm' ? 'npm' : undefined,
45 },
46 })
47 return
48 }
49 router.push({
50 name: 'search',
51 query: {
52 q: value,
53 p: provider === 'npm' ? 'npm' : undefined,
54 },
55 })
56 }
57 const updateUrlQuery = debounce(updateUrlQueryImpl, 250)
58
59 function flushUpdateUrlQuery() {
60 updateUrlQuery.flush()
61 }
62
63 const searchQueryValue = computed({
64 get: () => searchQuery.value,
65 set: async (value: string) => {
66 searchQuery.value = value
67
68 // Leading debounce implementation as it doesn't work properly out of the box (https://github.com/unjs/perfect-debounce/issues/43)
69 if (!updateUrlQuery.isPending()) {
70 updateUrlQueryImpl(value, searchProvider.value)
71 }
72 updateUrlQuery(value, searchProvider.value)
73 },
74 })
75 return { model: searchQueryValue, provider: searchProviderValue, flushUpdateUrlQuery }
76}