|
1 | | -import { normalizeSearchParam } from '#shared/utils/url' |
2 | | -import { debounce } from 'perfect-debounce' |
| 1 | +import { normalizeSearchParam } from "#shared/utils/url"; |
| 2 | +import { debounce } from "perfect-debounce"; |
3 | 3 |
|
4 | 4 | // Pages that have their own local filter using ?q |
5 | | -const pagesWithLocalFilter = new Set(['~username', 'org']) |
| 5 | +const pagesWithLocalFilter = new Set(["~username", "org"]); |
6 | 6 |
|
7 | | -const SEARCH_DEBOUNCE_MS = 100 |
| 7 | +const SEARCH_DEBOUNCE_MS = 100; |
8 | 8 |
|
9 | | -export function useGlobalSearch(place: 'header' | 'content' = 'content') { |
10 | | - const { settings } = useSettings() |
11 | | - const { searchProvider } = useSearchProvider() |
| 9 | +export function useGlobalSearch(place: "header" | "content" = "content") { |
| 10 | + const instantSearch = useInstantSearch(); |
| 11 | + const { searchProvider } = useSearchProvider(); |
12 | 12 | const searchProviderValue = computed(() => { |
13 | | - const p = normalizeSearchParam(route.query.p) |
14 | | - if (p === 'npm' || searchProvider.value === 'npm') return 'npm' |
15 | | - return 'algolia' |
16 | | - }) |
| 13 | + const p = normalizeSearchParam(route.query.p); |
| 14 | + if (p === "npm" || searchProvider.value === "npm") return "npm"; |
| 15 | + return "algolia"; |
| 16 | + }); |
17 | 17 |
|
18 | | - const router = useRouter() |
19 | | - const route = useRoute() |
| 18 | + const router = useRouter(); |
| 19 | + const route = useRoute(); |
20 | 20 | // Internally used searchQuery state |
21 | | - const searchQuery = useState<string>('search-query', () => { |
| 21 | + const searchQuery = useState<string>("search-query", () => { |
22 | 22 | if (pagesWithLocalFilter.has(route.name as string)) { |
23 | | - return '' |
| 23 | + return ""; |
24 | 24 | } |
25 | | - return normalizeSearchParam(route.query.q) |
26 | | - }) |
| 25 | + return normalizeSearchParam(route.query.q); |
| 26 | + }); |
27 | 27 |
|
28 | 28 | // Committed search query: last value submitted by user |
29 | 29 | // Syncs instantly when instantSearch is on, but only on Enter press when off |
30 | | - const committedSearchQuery = useState<string>('committed-search-query', () => searchQuery.value) |
| 30 | + const committedSearchQuery = useState<string>("committed-search-query", () => searchQuery.value); |
31 | 31 |
|
32 | 32 | const commitSearchQuery = debounce((val: string) => { |
33 | | - committedSearchQuery.value = val |
34 | | - }, SEARCH_DEBOUNCE_MS) |
| 33 | + committedSearchQuery.value = val; |
| 34 | + }, SEARCH_DEBOUNCE_MS); |
35 | 35 |
|
36 | 36 | // This is basically doing instant search as user types |
37 | | - watch(searchQuery, val => { |
38 | | - if (settings.value.instantSearch) { |
39 | | - commitSearchQuery(val) |
| 37 | + watch(searchQuery, (val) => { |
| 38 | + if (instantSearch.value) { |
| 39 | + commitSearchQuery(val); |
40 | 40 | } |
41 | | - }) |
| 41 | + }); |
42 | 42 |
|
43 | 43 | // clean search input when navigating away from search page |
44 | 44 | watch( |
45 | 45 | () => route.query.q, |
46 | | - urlQuery => { |
47 | | - const value = normalizeSearchParam(urlQuery) |
48 | | - if (!value) searchQuery.value = '' |
49 | | - if (!searchQuery.value) searchQuery.value = value |
| 46 | + (urlQuery) => { |
| 47 | + const value = normalizeSearchParam(urlQuery); |
| 48 | + if (!value) searchQuery.value = ""; |
| 49 | + if (!searchQuery.value) searchQuery.value = value; |
50 | 50 | }, |
51 | | - ) |
| 51 | + ); |
52 | 52 |
|
53 | 53 | // Updates URL when search query changes (immediately for instantSearch or after Enter hit otherwise) |
54 | | - const updateUrlQueryImpl = (value: string, provider: 'npm' | 'algolia') => { |
55 | | - const isSameQuery = route.query.q === value && route.query.p === provider |
| 54 | + const updateUrlQueryImpl = (value: string, provider: "npm" | "algolia") => { |
| 55 | + const isSameQuery = route.query.q === value && route.query.p === provider; |
56 | 56 | // Don't navigate away from pages that use ?q for local filtering |
57 | | - if ((pagesWithLocalFilter.has(route.name as string) && place === 'content') || isSameQuery) { |
58 | | - return |
| 57 | + if ((pagesWithLocalFilter.has(route.name as string) && place === "content") || isSameQuery) { |
| 58 | + return; |
59 | 59 | } |
60 | 60 |
|
61 | | - if (route.name === 'search') { |
| 61 | + if (route.name === "search") { |
62 | 62 | router.replace({ |
63 | 63 | query: { |
64 | 64 | ...route.query, |
65 | 65 | q: value || undefined, |
66 | | - p: provider === 'npm' ? 'npm' : undefined, |
| 66 | + p: provider === "npm" ? "npm" : undefined, |
67 | 67 | }, |
68 | | - }) |
69 | | - return |
| 68 | + }); |
| 69 | + return; |
70 | 70 | } |
71 | 71 | router.push({ |
72 | | - name: 'search', |
| 72 | + name: "search", |
73 | 73 | query: { |
74 | 74 | q: value, |
75 | | - p: provider === 'npm' ? 'npm' : undefined, |
| 75 | + p: provider === "npm" ? "npm" : undefined, |
76 | 76 | }, |
77 | | - }) |
78 | | - } |
| 77 | + }); |
| 78 | + }; |
79 | 79 |
|
80 | | - const updateUrlQuery = debounce(updateUrlQueryImpl, SEARCH_DEBOUNCE_MS) |
| 80 | + const updateUrlQuery = debounce(updateUrlQueryImpl, SEARCH_DEBOUNCE_MS); |
81 | 81 |
|
82 | 82 | function flushUpdateUrlQuery() { |
83 | 83 | // Commit the current query when explicitly submitted (Enter pressed) |
84 | | - commitSearchQuery.cancel() |
85 | | - committedSearchQuery.value = searchQuery.value |
| 84 | + commitSearchQuery.cancel(); |
| 85 | + committedSearchQuery.value = searchQuery.value; |
86 | 86 | // When instant search is off the debounce queue is empty, so call directly |
87 | | - if (!settings.value.instantSearch) { |
88 | | - updateUrlQueryImpl(searchQuery.value, searchProvider.value) |
| 87 | + if (!instantSearch.value) { |
| 88 | + updateUrlQueryImpl(searchQuery.value, searchProvider.value); |
89 | 89 | } else { |
90 | | - updateUrlQuery.flush() |
| 90 | + updateUrlQuery.flush(); |
91 | 91 | } |
92 | 92 | } |
93 | 93 |
|
94 | 94 | const searchQueryValue = computed({ |
95 | 95 | get: () => searchQuery.value, |
96 | 96 | set: async (value: string) => { |
97 | | - searchQuery.value = value |
| 97 | + searchQuery.value = value; |
98 | 98 |
|
99 | 99 | // When instant search is off, skip debounced URL updates |
100 | 100 | // Only explicitly called flushUpdateUrlQuery commits and navigates |
101 | | - if (!settings.value.instantSearch) return |
| 101 | + if (!instantSearch.value) return; |
102 | 102 |
|
103 | 103 | // Leading debounce implementation as it doesn't work properly out of the box (https://github.com/unjs/perfect-debounce/issues/43) |
104 | 104 | if (!updateUrlQuery.isPending()) { |
105 | | - updateUrlQueryImpl(value, searchProvider.value) |
| 105 | + updateUrlQueryImpl(value, searchProvider.value); |
106 | 106 | } |
107 | | - updateUrlQuery(value, searchProvider.value) |
| 107 | + updateUrlQuery(value, searchProvider.value); |
108 | 108 | }, |
109 | | - }) |
| 109 | + }); |
110 | 110 |
|
111 | 111 | return { |
112 | 112 | model: searchQueryValue, |
113 | 113 | committedModel: committedSearchQuery, |
114 | 114 | provider: searchProviderValue, |
115 | 115 | startSearch: flushUpdateUrlQuery, |
116 | | - } |
| 116 | + }; |
117 | 117 | } |
0 commit comments