-
Notifications
You must be signed in to change notification settings - Fork 0
/
state.ts
113 lines (105 loc) · 3.15 KB
/
state.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { InputSearchQuery, SearchResult } from "../api/search/generated"
import { AutocompleteConfig } from "../config"
import { History } from "./history"
import { Cancellable, makeCancellable } from "./promise"
import { search } from "../search"
import { SearchAutocompleteOptions } from "../autocomplete"
/**
* @group Autocomplete
* @category Core
*/
export interface DefaultState {
/**
* The current search query object.
*/
query?: InputSearchQuery
/**
* The current search response.
*/
response?: SearchResult
/**
* The history items.
*/
history?: { item: string }[]
}
export type StateActions<State> = {
updateState(inputValue?: string): PromiseLike<State>
addHistoryItem(item: string): PromiseLike<State>
removeHistoryItem(item: string): PromiseLike<State>
clearHistory(): PromiseLike<State>
}
export const getStateActions = <State>({
config,
history,
input,
}: {
config: Required<AutocompleteConfig<State>>
history?: History
input: HTMLInputElement
}): StateActions<State> => {
let cancellable: Cancellable<State> | undefined
const fetchState = (
value: string,
config: AutocompleteConfig<State>,
options?: SearchAutocompleteOptions
): PromiseLike<State> => {
if (typeof config.fetch === "function") {
return config.fetch(value)
} else {
// @ts-expect-error type mismatch
return search(
{
query: value,
...config.fetch,
},
{
track: config.nostoAnalytics ? "autocomplete" : undefined,
redirect: false,
...options,
}
)
}
}
function getHistoryState(query: string): PromiseLike<State> {
// @ts-expect-error type mismatch
return Promise.resolve({
query: {
query,
},
history: history?.getItems(),
})
}
return {
updateState: (inputValue?: string, options?: SearchAutocompleteOptions): PromiseLike<State> => {
cancellable?.cancel()
if (inputValue && inputValue.length >= config.minQueryLength) {
cancellable = makeCancellable(fetchState(inputValue, config, options))
return cancellable.promise
} else if (history) {
return getHistoryState(inputValue ?? "")
}
return (
// @ts-expect-error type mismatch
cancellable?.promise ?? Promise.resolve<State>({})
)
},
addHistoryItem: (item: string) => {
if (history) {
history.add(item)
}
return getHistoryState(input.value)
},
removeHistoryItem: (item: string) => {
if (history) {
history.remove(item)
}
return getHistoryState(input.value)
},
clearHistory: () => {
if (history) {
history.clear()
}
return getHistoryState(input.value)
},
}
}