diff --git a/demo/dev.umd.html b/demo/dev.umd.html index 04281af..d49ccfa 100644 --- a/demo/dev.umd.html +++ b/demo/dev.umd.html @@ -182,6 +182,29 @@

Dummy input to test keyboard nav

minLength: 1, limit: 10, retainFocus: true, + hooks: { + updateHits: async (resultSet) => { + + const response = await fetch( + "https://raw.githubusercontent.com/digitalfortress-tech/typeahead-standalone/master/docs/assets/json/superheroes.json", + { + method: 'GET', + } + ); + + const text = await response.text(); + const data = text && JSON.parse(text); + + const hits = data.results.slice(0,10) + + // const hits = resultSet.hits.filter(hit => hit.popularity && hit.popularity > 50); + + return { + hits, + count: hits.length, + }; + } + }, templates: { suggestion: (item) => { const date = item.release_date diff --git a/src/common.d.ts b/src/common.d.ts index 8604e50..7e43f71 100644 --- a/src/common.d.ts +++ b/src/common.d.ts @@ -274,6 +274,19 @@ export interface typeaheadConfig { * It defaults to true. */ retainFocus?: boolean; + /** + * Hooks to be able to perform fine-tuning of results + */ + hooks?: { + /** + * The updateHits hook allows you to modify/filter/sort the search results before being rendered + * @param hits The found results + * @returns + */ + updateHits: ( + resultSet: Pick, 'hits' | 'query' | 'count'> + ) => Promise | Promise, 'hits' | 'count'>>; + }; } export interface ResultSet { diff --git a/src/typeahead-standalone.ts b/src/typeahead-standalone.ts index 6487f43..6fc6958 100644 --- a/src/typeahead-standalone.ts +++ b/src/typeahead-standalone.ts @@ -68,6 +68,9 @@ const typeahead = (config: typeaheadConfig): typeaheadR ...(config.classNames || {}), }; const listScrollOptions: ScrollIntoViewOptions = { block: 'nearest', ...(config.listScrollOptions || {}) }; + const hooks = { + updateHits: config.hooks?.updateHits || NOOP, + }; // validate presence of atleast one data-source if (!local && !prefetch && !remote) throw new Error('e02'); @@ -305,7 +308,18 @@ const typeahead = (config: typeaheadConfig): typeaheadR /** * Responsible for drawing/updating the view */ - const update = (): void => { + const update = async (): Promise => { + // hook to update Hits before displaying results from tree + const results_mod = await hooks.updateHits({ + hits: resultSet.hits, + query: resultSet.query, + count: resultSet.count, + }); + if (results_mod?.hits?.length) { + resultSet.hits = results_mod.hits; + resultSet.count = results_mod.count ?? results_mod.hits.length; + } + // No Matches if (noSuggestionsHandler()) return; @@ -521,7 +535,7 @@ const typeahead = (config: typeaheadConfig): typeaheadR startFetch(); }; - const startFetch = (): void => { + const startFetch = async (): Promise => { clearRemoteDebounceTimer(); const val = input.value.replace(/\s{2,}/g, ' ').trim(); @@ -533,7 +547,7 @@ const typeahead = (config: typeaheadConfig): typeaheadR // inject default suggestions if they were updated in the empty() template if (Array.isArray(emptyTemplateResp) && emptyTemplateResp.length) { resultSet.hits = normalizer(emptyTemplateResp, keys[0]) as T[]; - return update(); + return await update(); } // inject empty html template only if default suggestions aren't provided