@indxsearch/intrface 3.12.0 → 3.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/components/AskPanel.d.ts +43 -0
- package/dist/components/SearchInput.d.ts +12 -0
- package/dist/components/SearchResults.d.ts +12 -0
- package/dist/context/SearchContext.d.ts +22 -0
- package/dist/context/useSearchExecution.d.ts +3 -1
- package/dist/hooks/useAsk.d.ts +89 -0
- package/dist/hooks/useFilterSuggestion.d.ts +42 -0
- package/dist/hooks/useSearchOrAsk.d.ts +52 -0
- package/dist/index.cjs.js +8 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.es.js +1644 -724
- package/dist/intrface.css +1 -1
- package/dist/utils/answerMarkdown.d.ts +11 -0
- package/dist/utils/askPhrases.d.ts +24 -0
- package/dist/utils/searchOrAsk.d.ts +72 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.13.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- When the page searches something other than what the visitor typed, the search also carries the typed text. The statistics then count a visitor's typing as one search, instead of a search for every step along the way.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @indxsearch/systm@2.21.1
|
|
10
|
+
|
|
11
|
+
## 3.13.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- SearchResults takes `showScore`, to show or hide each result's score from code. Given, it wins over the toggle in SearchSettingsPanel; left out, the toggle decides, as before.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- bac9b80: SearchField has a built-in Clear button. It shows while the field holds text and puts the focus back in the field. Turn it off with `clearable={false}`. SearchInput keeps its own Clear, which also resets the filters.
|
|
20
|
+
- Updated dependencies [ffda712]
|
|
21
|
+
- Updated dependencies
|
|
22
|
+
- Updated dependencies [bac9b80]
|
|
23
|
+
- Updated dependencies
|
|
24
|
+
- Updated dependencies [f1bb38b]
|
|
25
|
+
- @indxsearch/systm@2.21.0
|
|
26
|
+
|
|
3
27
|
## 3.12.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { AskSource, AskStatus, AskFilters } from '../hooks/useAsk';
|
|
3
|
+
export interface AskPanelProps {
|
|
4
|
+
/** The question to answer. A new value asks it and starts a new conversation; null or empty
|
|
5
|
+
* shows nothing. To ask the same text again, give the panel a new `key`. */
|
|
6
|
+
question: string | null;
|
|
7
|
+
/** Lets the visitor ask follow-up questions under the answer. Each is answered with the
|
|
8
|
+
* conversation so far (the server uses the last three turns), and the earlier turns stay on
|
|
9
|
+
* screen above it. */
|
|
10
|
+
followUps?: boolean;
|
|
11
|
+
/** Called when the visitor picks a cited source. Look the record up by its documentKey. */
|
|
12
|
+
onSourceClick?: (source: AskSource) => void;
|
|
13
|
+
/** The label over each answer. Default "Answer". */
|
|
14
|
+
label?: string;
|
|
15
|
+
/** Renders the answer text, for a page with a markdown renderer of its own. `cite(n)` gives the
|
|
16
|
+
* citation mark for source n. Default: intrface's own markdown (paragraphs, headings, lists,
|
|
17
|
+
* code blocks, inline code, bold, italics, links), with [n] as citation marks. */
|
|
18
|
+
renderAnswer?: (answer: string, cite: (n: number) => React.ReactNode) => React.ReactNode;
|
|
19
|
+
/** Shown under the answer as "Ask a follow-up" when `followUps` is off: e.g. back to the
|
|
20
|
+
* search field. With `followUps` on, that button goes to the follow-up field instead. */
|
|
21
|
+
onFollowUp?: () => void;
|
|
22
|
+
/** On a catalogue, called with the filters a description was searched with, as soon as they are
|
|
23
|
+
* known: give them to `useFilterSuggestion().apply` so the page's list shows the same set. */
|
|
24
|
+
onFilters?: (filters: AskFilters) => void;
|
|
25
|
+
/** How a filter reads on its chip. Default: a text value as itself, a yes/no by its field's
|
|
26
|
+
* name, a range by its bounds. */
|
|
27
|
+
filterLabel?: (filter: AskFilters['filters'][number]) => string;
|
|
28
|
+
/** Told when the answer starts and stops streaming, e.g. to show a Stop button elsewhere. */
|
|
29
|
+
onStatusChange?: (status: AskStatus) => void;
|
|
30
|
+
/** Fills the height its container gives it, for a panel beside the results: the conversation
|
|
31
|
+
* scrolls on its own, the follow-up field stays at the bottom, and the view follows an answer
|
|
32
|
+
* as it streams while the visitor is at the end of it. Give the container a height (or make it
|
|
33
|
+
* a flex child that has one). Without it the panel is as tall as its content. */
|
|
34
|
+
fill?: boolean;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* An answer to a question, written from the dataset's records by Search or ask: the question, the
|
|
39
|
+
* answer as it streams, the sources it cites, and what to do when it fails or is limited. With
|
|
40
|
+
* `followUps`, a conversation: a field under the answer asks the next question with the earlier
|
|
41
|
+
* ones as context. Pair it with `SearchInput`'s `onAsk`, or `useSearchOrAsk` (when to offer).
|
|
42
|
+
*/
|
|
43
|
+
export declare const AskPanel: React.FC<AskPanelProps>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { InputSize } from '@indxsearch/systm';
|
|
3
|
+
import { SearchOrAskState } from '../hooks/useSearchOrAsk';
|
|
3
4
|
export interface SearchInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
4
5
|
inputSize?: InputSize;
|
|
5
6
|
/** One Clear button that resets the query and the filters, shown whenever there is either. */
|
|
@@ -8,5 +9,16 @@ export interface SearchInputProps extends React.InputHTMLAttributes<HTMLInputEle
|
|
|
8
9
|
/** Chips that say what the search is doing: the number of active filters, "Nearest" when no
|
|
9
10
|
* result reached the coverage bar, and "No results". */
|
|
10
11
|
showStatus?: boolean;
|
|
12
|
+
/** Search or ask: when given, and the dataset has it switched on, an offer to ask appears in
|
|
13
|
+
* the chip row while the visitor types something an answer would serve. A strong offer also
|
|
14
|
+
* makes Enter ask. Called with the text to ask; show the answer with `AskPanel`. */
|
|
15
|
+
onAsk?: (text: string) => void;
|
|
16
|
+
/** The offer, when the page runs `useSearchOrAsk` itself (to show it elsewhere too, or to use
|
|
17
|
+
* `describes`): the field then shows this one and does not judge again. */
|
|
18
|
+
searchOrAsk?: SearchOrAskState;
|
|
19
|
+
/** Where the offer to ask shows. `chip` (default): a button in the field's chip row. `below`: a
|
|
20
|
+
* row of its own under the field, as on the Indx docs: a full-size button and an Enter hint.
|
|
21
|
+
* The row keeps its height while Search or ask is on, so an offer appearing moves nothing under it. */
|
|
22
|
+
askOffer?: 'chip' | 'below';
|
|
11
23
|
}
|
|
12
24
|
export declare const SearchInput: React.FC<SearchInputProps>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { SearchResult as SearchResultData } from '../context/SearchContext';
|
|
3
|
+
import { SearchOrAskState } from '../hooks/useSearchOrAsk';
|
|
3
4
|
export interface SearchResultsProps {
|
|
4
5
|
fields?: string[];
|
|
5
6
|
resultsPerPage?: number;
|
|
@@ -16,6 +17,17 @@ export interface SearchResultsProps {
|
|
|
16
17
|
* result, so the dataset's statistics get click-through and click position.
|
|
17
18
|
*/
|
|
18
19
|
children: (item: Record<string, any>, meta: SearchResultMeta) => React.ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* The offer, when the page runs `useSearchOrAsk`: while it is strong and the dataset has the
|
|
22
|
+
* rule on, the list shows coverage hits only (up to the truncation point), and nothing when
|
|
23
|
+
* nothing is confirmed, so the offer stands alone. Without it the list is never cut.
|
|
24
|
+
*/
|
|
25
|
+
searchOrAsk?: SearchOrAskState;
|
|
26
|
+
/**
|
|
27
|
+
* Shows each result's score beside it. Given, it wins over the `showScore` search setting (the
|
|
28
|
+
* toggle in SearchSettingsPanel); left out, that setting decides, and it is on by default.
|
|
29
|
+
*/
|
|
30
|
+
showScore?: boolean;
|
|
19
31
|
}
|
|
20
32
|
export interface SearchResultMeta {
|
|
21
33
|
result: SearchResultData;
|
|
@@ -63,6 +63,11 @@ export interface SearchContextType {
|
|
|
63
63
|
authErrorInfo?: SearchErrorInfo;
|
|
64
64
|
retry?: () => void;
|
|
65
65
|
allowEmptySearch: boolean;
|
|
66
|
+
facetsEnabled: boolean;
|
|
67
|
+
datasetBounds: Record<string, {
|
|
68
|
+
min: number;
|
|
69
|
+
max: number;
|
|
70
|
+
}>;
|
|
66
71
|
url: string;
|
|
67
72
|
team: string;
|
|
68
73
|
dataset: string;
|
|
@@ -82,7 +87,19 @@ export interface SearchContextType {
|
|
|
82
87
|
fetchMoreResults: (newMax: number) => void;
|
|
83
88
|
selectResult?: (result: SearchResult) => Promise<void>;
|
|
84
89
|
sessionId?: string;
|
|
90
|
+
source?: string;
|
|
91
|
+
count?: boolean;
|
|
92
|
+
/** What the search runs on: `state.query`, or what `searchTextOf` or a registered rewrite made of it. */
|
|
93
|
+
searchText?: string;
|
|
94
|
+
/** Searches the typed text as it is, this once: the way back from a rewrite ("Search for your exact words"). */
|
|
95
|
+
searchAsTyped?: () => void;
|
|
96
|
+
/** Registers what the search runs on for what is typed, for a hook inside the provider
|
|
97
|
+
* (useSearchOrAsk's Ask phrases); null takes it off. The provider's own `searchTextOf` wins. */
|
|
98
|
+
setSearchRewrite?: (rewrite: ((typed: string) => string) | null) => void;
|
|
85
99
|
}
|
|
100
|
+
/** The field's placeholder unless the page sets one. SearchInput says "Search or ask" instead
|
|
101
|
+
* while asking is on, so it must know this one from a page's own. */
|
|
102
|
+
export declare const DEFAULT_PLACEHOLDER = "Type to search";
|
|
86
103
|
export declare const SearchContext: React.Context<SearchContextType | undefined>;
|
|
87
104
|
export declare const SearchProvider: React.FC<{
|
|
88
105
|
children: React.ReactNode;
|
|
@@ -101,5 +118,10 @@ export declare const SearchProvider: React.FC<{
|
|
|
101
118
|
preAuthenticatedToken?: string;
|
|
102
119
|
source?: string;
|
|
103
120
|
count?: boolean;
|
|
121
|
+
/** The text to search for what is typed, when it is not the typed text itself: the field keeps
|
|
122
|
+
* showing what the visitor typed, and the search runs on this. Search or ask's Ask phrases use
|
|
123
|
+
* it ("help me find the movie about the green ogre" searches "green ogre"). Called on every
|
|
124
|
+
* render with the typed text; return it unchanged to search it as typed. */
|
|
125
|
+
searchTextOf?: (typed: string) => string;
|
|
104
126
|
}>;
|
|
105
127
|
export declare const useSearchContext: () => SearchContextType;
|
|
@@ -15,9 +15,11 @@ export interface UseSearchExecutionOptions {
|
|
|
15
15
|
sessionId: string;
|
|
16
16
|
source?: string;
|
|
17
17
|
count: boolean;
|
|
18
|
+
/** The text to search for what is typed (SearchProvider's `searchTextOf`). Absent: the typed text. */
|
|
19
|
+
searchTextOf?: (typed: string) => string;
|
|
18
20
|
}
|
|
19
21
|
export interface UseSearchExecutionResult {
|
|
20
22
|
/** Runs the last search again, after a failure. */
|
|
21
23
|
retrySearch: () => void;
|
|
22
24
|
}
|
|
23
|
-
export declare function useSearchExecution({ state, setState, authenticatedFetch, auth, url, team, dataset, allowEmptySearch, facetsEnabled, enableDebugLogs, shouldFetchMore, sessionId, source, count, }: UseSearchExecutionOptions): UseSearchExecutionResult;
|
|
25
|
+
export declare function useSearchExecution({ state, setState, authenticatedFetch, auth, url, team, dataset, allowEmptySearch, facetsEnabled, enableDebugLogs, shouldFetchMore, sessionId, source, count, searchTextOf, }: UseSearchExecutionOptions): UseSearchExecutionResult;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** A record the answer may use, numbered as the answer cites it ([n]). */
|
|
2
|
+
export interface AskSource {
|
|
3
|
+
n: number;
|
|
4
|
+
documentKey: number;
|
|
5
|
+
title: string;
|
|
6
|
+
}
|
|
7
|
+
/** An earlier question and its answer, sent with a follow-up so the answer can build on it. */
|
|
8
|
+
export interface AskTurn {
|
|
9
|
+
question: string;
|
|
10
|
+
answer: string;
|
|
11
|
+
/** On a catalogue, the list that turn put on the page: a follow-up is about it. */
|
|
12
|
+
shown?: {
|
|
13
|
+
filters: AskFilters['filters'];
|
|
14
|
+
text: string;
|
|
15
|
+
sort?: AskFilters['sort'];
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export type AskStatus = 'idle' | 'searching' | 'writing' | 'answered' | 'error' | 'limited';
|
|
19
|
+
export interface AskState {
|
|
20
|
+
question: string;
|
|
21
|
+
status: AskStatus;
|
|
22
|
+
/** The answer as written so far, citing sources as [n]. */
|
|
23
|
+
answer: string;
|
|
24
|
+
sources: AskSource[];
|
|
25
|
+
/** Why it failed, when status is 'error': the server's code (nothingFound, upstreamBusy, failed,
|
|
26
|
+
* or an HTTP problem code) and a sentence for the page. */
|
|
27
|
+
error?: {
|
|
28
|
+
code: string;
|
|
29
|
+
message: string;
|
|
30
|
+
};
|
|
31
|
+
/** When status is 'limited': seconds until asking again may succeed. */
|
|
32
|
+
retryAfterSeconds?: number;
|
|
33
|
+
/** The server's id for this ask (Indx-Ask-Id). A source opened is reported against it. */
|
|
34
|
+
askId?: string;
|
|
35
|
+
/** On a catalogue, a description's filters, as the server searched with them, and what it found. */
|
|
36
|
+
filters?: AskFilters;
|
|
37
|
+
/** What the agent has done so far ("Searching: Folkehøyskole, by Elevtall"), while it works. */
|
|
38
|
+
steps: string[];
|
|
39
|
+
}
|
|
40
|
+
/** What a catalogue's description was searched with: filters, words no filter covers, and the count. */
|
|
41
|
+
export interface AskFilters {
|
|
42
|
+
filters: {
|
|
43
|
+
field: string;
|
|
44
|
+
value?: string | null;
|
|
45
|
+
min?: number | null;
|
|
46
|
+
max?: number | null;
|
|
47
|
+
}[];
|
|
48
|
+
text: string;
|
|
49
|
+
/** An order the description asked for ("the largest"): a Sortable field. */
|
|
50
|
+
sort?: {
|
|
51
|
+
field: string;
|
|
52
|
+
descending: boolean;
|
|
53
|
+
} | null;
|
|
54
|
+
found: number;
|
|
55
|
+
/** True when the count is a cap: there are more. */
|
|
56
|
+
more: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Asks the dataset a question (`search-or-ask/ask`) and follows the answer as it streams: the
|
|
60
|
+
* sources first, then the text, then done. One question at a time; asking again, or `stop`, ends
|
|
61
|
+
* the one in flight and keeps what had arrived. The answer uses the dataset's records and nothing
|
|
62
|
+
* else, and says so when they do not hold it.
|
|
63
|
+
*/
|
|
64
|
+
export declare function useAsk(): {
|
|
65
|
+
ask: (question: string, history?: AskTurn[]) => Promise<void>;
|
|
66
|
+
stop: () => void | undefined;
|
|
67
|
+
reset: () => void;
|
|
68
|
+
openSource: (source: AskSource, ofAsk?: string) => Promise<void>;
|
|
69
|
+
busy: boolean;
|
|
70
|
+
question: string;
|
|
71
|
+
status: AskStatus;
|
|
72
|
+
/** The answer as written so far, citing sources as [n]. */
|
|
73
|
+
answer: string;
|
|
74
|
+
sources: AskSource[];
|
|
75
|
+
/** Why it failed, when status is 'error': the server's code (nothingFound, upstreamBusy, failed,
|
|
76
|
+
* or an HTTP problem code) and a sentence for the page. */
|
|
77
|
+
error?: {
|
|
78
|
+
code: string;
|
|
79
|
+
message: string;
|
|
80
|
+
};
|
|
81
|
+
/** When status is 'limited': seconds until asking again may succeed. */
|
|
82
|
+
retryAfterSeconds?: number;
|
|
83
|
+
/** The server's id for this ask (Indx-Ask-Id). A source opened is reported against it. */
|
|
84
|
+
askId?: string;
|
|
85
|
+
/** On a catalogue, a description's filters, as the server searched with them, and what it found. */
|
|
86
|
+
filters?: AskFilters;
|
|
87
|
+
/** What the agent has done so far ("Searching: Folkehøyskole, by Elevtall"), while it works. */
|
|
88
|
+
steps: string[];
|
|
89
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SearchOrAskState } from './useSearchOrAsk';
|
|
2
|
+
/** One filter a description asked for: a value (text, or "true"/"false") or a number range. */
|
|
3
|
+
export interface FilterSuggestion {
|
|
4
|
+
field: string;
|
|
5
|
+
value?: string | null;
|
|
6
|
+
min?: number | null;
|
|
7
|
+
max?: number | null;
|
|
8
|
+
}
|
|
9
|
+
export interface FilterSuggestionResult {
|
|
10
|
+
filters: FilterSuggestion[];
|
|
11
|
+
/** What no filter covers, to search for; empty when the filters cover it all. */
|
|
12
|
+
text: string;
|
|
13
|
+
/** An order the description asked for, on a Sortable field. */
|
|
14
|
+
sort?: {
|
|
15
|
+
field: string;
|
|
16
|
+
descending: boolean;
|
|
17
|
+
} | null;
|
|
18
|
+
}
|
|
19
|
+
export declare function localFilters(text: string, facets: Record<string, {
|
|
20
|
+
key: string;
|
|
21
|
+
}[]> | null | undefined): FilterSuggestionResult | null;
|
|
22
|
+
export interface UseFilterSuggestionOptions {
|
|
23
|
+
/** The offer from `useSearchOrAsk`. With it, a description is turned into filters while the
|
|
24
|
+
* visitor types, the way the dataset's `filtersWhileTyping` says: facet values at once, the
|
|
25
|
+
* model for the rest, or nothing until Ask. */
|
|
26
|
+
auto?: SearchOrAskState;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Search or ask on a catalogue: turns a description of what to list ("private videregående i
|
|
30
|
+
* bergen") into filters on the dataset's own fields (`search-or-ask/filters`), and applies them
|
|
31
|
+
* to the search, where ActiveFiltersPanel shows them and the visitor can remove each. Ask for it
|
|
32
|
+
* when `useSearchOrAsk` says `describes`, or hand it the offer (`auto`) and it acts on its own.
|
|
33
|
+
*/
|
|
34
|
+
export declare function useFilterSuggestion(options?: UseFilterSuggestionOptions): {
|
|
35
|
+
suggestion: FilterSuggestionResult | null;
|
|
36
|
+
forText: string;
|
|
37
|
+
loading: boolean;
|
|
38
|
+
suggest: (text: string) => Promise<void>;
|
|
39
|
+
apply: (result: FilterSuggestionResult) => void;
|
|
40
|
+
clear: () => void;
|
|
41
|
+
appliedText: string | null;
|
|
42
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CutRule, Offer } from '../utils/searchOrAsk';
|
|
2
|
+
export interface UseSearchOrAskOptions {
|
|
3
|
+
/** false keeps the hook quiet: no settings read, no judgement. Default true. */
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
/** The text to judge. Defaults to the search query of the surrounding SearchProvider. */
|
|
6
|
+
text?: string;
|
|
7
|
+
/** How long the visitor must pause before the server is asked. Default 300 ms. */
|
|
8
|
+
pauseMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface SearchOrAskState {
|
|
11
|
+
/** True once the dataset's settings say Search or ask is on and the instance can run it. Until
|
|
12
|
+
* then, and for good when it is off, the offer stays 'none' and nothing is sent. */
|
|
13
|
+
available: boolean;
|
|
14
|
+
/** What to show: nothing, a quiet "ask about this", or a strong offer where Enter asks. */
|
|
15
|
+
offer: Offer;
|
|
16
|
+
/** The latest probability from the server, for a readout; null before the first judgement. */
|
|
17
|
+
p: number | null;
|
|
18
|
+
/** The judge's reading of whether the top results could answer what is typed; null when it did not say. */
|
|
19
|
+
answerable: number | null;
|
|
20
|
+
/** The text the offer is about: what would be asked. */
|
|
21
|
+
text: string;
|
|
22
|
+
/** On a catalogue: the probability the visitor describes what to list. Null elsewhere. */
|
|
23
|
+
criteria: number | null;
|
|
24
|
+
/** On a catalogue: the text describes what to list, so it can become filters (useFilterSuggestion). */
|
|
25
|
+
describes: boolean;
|
|
26
|
+
/** The list should show coverage hits only: the offer is strong and the dataset has the rule on
|
|
27
|
+
* (`cutWhileAsking`). SearchResults applies it when handed this state; `visibleResults` is the rule. */
|
|
28
|
+
cutResults: boolean;
|
|
29
|
+
/** The cut's two lines, the dataset's, for `visibleResults`. */
|
|
30
|
+
cutRule: CutRule;
|
|
31
|
+
/** The page's searches run with whole-word coverage: the offer is strong and the dataset has
|
|
32
|
+
* that rule on. The hook sets and clears it on the search context itself. */
|
|
33
|
+
strictCoverage: boolean;
|
|
34
|
+
/** On a catalogue, what to do with a description while typing (the dataset's `filtersWhileTyping`):
|
|
35
|
+
* 'off' leaves the list until Ask, 'facets' applies typed facet values at once, 'model' also asks
|
|
36
|
+
* the filters route for the rest. `useFilterSuggestion({ auto })` acts on it. */
|
|
37
|
+
filtersWhileTyping: 'off' | 'facets' | 'model';
|
|
38
|
+
/** The offer is for what is in the field now: the field still extends the text it was judged on.
|
|
39
|
+
* Typing on from a question keeps it (the hook does not ask again while the text only grows);
|
|
40
|
+
* backspacing into it, or changing it, does not, until the judge has read the new text. Show an
|
|
41
|
+
* offer only while this holds, or it blinks out on every keystroke or lingers after a change. */
|
|
42
|
+
stands: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Decides, while the visitor types, whether to offer an answer beside the results. Reads the
|
|
46
|
+
* dataset's Search or ask settings once, then on each typing pause asks the server's judge
|
|
47
|
+
* (`search-or-ask/intent`) when the rules allow, keeps only the newest answer, and applies the
|
|
48
|
+
* dataset's thresholds with hysteresis. It never asks again while the text only grows and the
|
|
49
|
+
* offer is already strong. A failure of any kind leaves the offer at 'none': the search itself is
|
|
50
|
+
* never affected.
|
|
51
|
+
*/
|
|
52
|
+
export declare function useSearchOrAsk(options?: UseSearchOrAskOptions): SearchOrAskState;
|