elastic-input 0.3.1 → 0.3.3
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/dist/elastic-input.es.js
CHANGED
|
@@ -1530,7 +1530,7 @@ class AutocompleteEngine {
|
|
|
1530
1530
|
return this.searchHistory.slice(0, this.maxSuggestions).map((h) => ({
|
|
1531
1531
|
text: AutocompleteEngine.wrapHistoryQuery(h.query),
|
|
1532
1532
|
label: h.label || h.query,
|
|
1533
|
-
description: h.
|
|
1533
|
+
description: h.description,
|
|
1534
1534
|
type: "history",
|
|
1535
1535
|
replaceStart: start,
|
|
1536
1536
|
replaceEnd: end,
|
|
@@ -2799,7 +2799,7 @@ function AutocompleteDropdown({
|
|
|
2799
2799
|
whiteSpace: "normal",
|
|
2800
2800
|
wordBreak: "break-all",
|
|
2801
2801
|
width: "100%"
|
|
2802
|
-
} }, highlightMatch(suggestion.label, suggestion.matchPartial, isSelected)), /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center", gap: "8px", width: "100%" } }, suggestion.description && /* @__PURE__ */ React.createElement("span", { className: "ei-dropdown-item-desc", style: { ...getDropdownItemDescStyle(), flex: 1 } }, suggestion.description), /* @__PURE__ */ React.createElement("span", { className: "ei-dropdown-item-type", style: { ...getDropdownItemTypeStyle(isSelected, mergedStyles), marginLeft: "auto" } }, "history")))
|
|
2802
|
+
} }, highlightMatch(suggestion.label, suggestion.matchPartial, isSelected)), /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center", gap: "8px", width: "100%" } }, suggestion.description != null && /* @__PURE__ */ React.createElement("span", { className: "ei-dropdown-item-desc", style: { ...getDropdownItemDescStyle(), flex: 1 } }, suggestion.description), /* @__PURE__ */ React.createElement("span", { className: "ei-dropdown-item-type", style: { ...getDropdownItemTypeStyle(isSelected, mergedStyles), marginLeft: "auto" } }, "history")))
|
|
2803
2803
|
);
|
|
2804
2804
|
}
|
|
2805
2805
|
if (suggestion.type === "savedSearch" && renderSavedSearchItem && suggestion.sourceData) {
|
|
@@ -3735,13 +3735,14 @@ function ElasticInput(props) {
|
|
|
3735
3735
|
const effectiveMaxSuggestions = maxSuggestions || DEFAULT_MAX_SUGGESTIONS;
|
|
3736
3736
|
const suggestDebounceMs = dropdownConfig == null ? void 0 : dropdownConfig.suggestDebounceMs;
|
|
3737
3737
|
const dropdownMaxHeightPx = parseInt((stylesProp == null ? void 0 : stylesProp.dropdownMaxHeight) || "300", 10) || 300;
|
|
3738
|
-
const enableSavedSearches = (featuresConfig == null ? void 0 : featuresConfig.savedSearches) ??
|
|
3739
|
-
const enableHistorySearch = (featuresConfig == null ? void 0 : featuresConfig.historySearch) ??
|
|
3738
|
+
const enableSavedSearches = (featuresConfig == null ? void 0 : featuresConfig.savedSearches) ?? !!savedSearches;
|
|
3739
|
+
const enableHistorySearch = (featuresConfig == null ? void 0 : featuresConfig.historySearch) ?? !!searchHistory;
|
|
3740
3740
|
const showSavedSearchHint = (dropdownConfig == null ? void 0 : dropdownConfig.showSavedSearchHint) ?? enableSavedSearches;
|
|
3741
3741
|
const showHistoryHint = (dropdownConfig == null ? void 0 : dropdownConfig.showHistoryHint) ?? enableHistorySearch;
|
|
3742
3742
|
const showOperators = (dropdownConfig == null ? void 0 : dropdownConfig.showOperators) !== false;
|
|
3743
3743
|
const triggerOnNavigation = (dropdownOpenIsCallback || dropdownMode !== "input") && (dropdownConfig == null ? void 0 : dropdownConfig.onNavigation) !== false;
|
|
3744
3744
|
const navigationDelay = (dropdownConfig == null ? void 0 : dropdownConfig.navigationDelay) ?? 0;
|
|
3745
|
+
const loadingDelay = (dropdownConfig == null ? void 0 : dropdownConfig.loadingDelay) ?? 0;
|
|
3745
3746
|
const renderFieldHint = dropdownConfig == null ? void 0 : dropdownConfig.renderFieldHint;
|
|
3746
3747
|
const renderHistoryItem = dropdownConfig == null ? void 0 : dropdownConfig.renderHistoryItem;
|
|
3747
3748
|
const renderSavedSearchItem = dropdownConfig == null ? void 0 : dropdownConfig.renderSavedSearchItem;
|
|
@@ -3786,6 +3787,7 @@ function ElasticInput(props) {
|
|
|
3786
3787
|
const abortControllerRef = React.useRef(null);
|
|
3787
3788
|
const highlightTimerRef = React.useRef(null);
|
|
3788
3789
|
const navDelayTimerRef = React.useRef(null);
|
|
3790
|
+
const loadingDelayTimerRef = React.useRef(null);
|
|
3789
3791
|
const asyncActiveRef = React.useRef(false);
|
|
3790
3792
|
const datePickerInitRef = React.useRef(null);
|
|
3791
3793
|
const datePickerReplaceRef = React.useRef(null);
|
|
@@ -3993,6 +3995,10 @@ function ElasticInput(props) {
|
|
|
3993
3995
|
asyncActiveRef.current = false;
|
|
3994
3996
|
(_a = abortControllerRef.current) == null ? void 0 : _a.abort();
|
|
3995
3997
|
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
3998
|
+
if (loadingDelayTimerRef.current) {
|
|
3999
|
+
clearTimeout(loadingDelayTimerRef.current);
|
|
4000
|
+
loadingDelayTimerRef.current = null;
|
|
4001
|
+
}
|
|
3996
4002
|
const init = computeDatePickerInit(result.context, parseDateProp);
|
|
3997
4003
|
const prevInit = datePickerInitRef.current;
|
|
3998
4004
|
datePickerInitRef.current = init;
|
|
@@ -4020,6 +4026,10 @@ function ElasticInput(props) {
|
|
|
4020
4026
|
asyncActiveRef.current = false;
|
|
4021
4027
|
(_b = abortControllerRef.current) == null ? void 0 : _b.abort();
|
|
4022
4028
|
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
4029
|
+
if (loadingDelayTimerRef.current) {
|
|
4030
|
+
clearTimeout(loadingDelayTimerRef.current);
|
|
4031
|
+
loadingDelayTimerRef.current = null;
|
|
4032
|
+
}
|
|
4023
4033
|
const newSuggestions = applyFieldHint(result.suggestions, result.context);
|
|
4024
4034
|
if (newSuggestions.length > 0) {
|
|
4025
4035
|
setSuggestions(newSuggestions);
|
|
@@ -4038,20 +4048,28 @@ function ElasticInput(props) {
|
|
|
4038
4048
|
const token = result.context.token;
|
|
4039
4049
|
const start = token ? token.start : offset;
|
|
4040
4050
|
const end = token ? token.end : offset;
|
|
4041
|
-
const
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4051
|
+
const showSpinner = () => {
|
|
4052
|
+
loadingDelayTimerRef.current = null;
|
|
4053
|
+
const loadingSuggestion = {
|
|
4054
|
+
text: "",
|
|
4055
|
+
label: "Searching...",
|
|
4056
|
+
type: "loading",
|
|
4057
|
+
replaceStart: start,
|
|
4058
|
+
replaceEnd: end
|
|
4059
|
+
};
|
|
4060
|
+
setSuggestions([loadingSuggestion]);
|
|
4061
|
+
if (!dropdownAlignToInput) setShowDropdown(false);
|
|
4062
|
+
setShowDatePicker(false);
|
|
4063
|
+
setSelectedSuggestionIndex(-1);
|
|
4064
|
+
showDropdownAtPosition(32, 300);
|
|
4048
4065
|
};
|
|
4049
|
-
|
|
4050
|
-
if (
|
|
4051
|
-
|
|
4052
|
-
|
|
4066
|
+
if (loadingDelayTimerRef.current) clearTimeout(loadingDelayTimerRef.current);
|
|
4067
|
+
if (loadingDelay > 0) {
|
|
4068
|
+
loadingDelayTimerRef.current = setTimeout(showSpinner, loadingDelay);
|
|
4069
|
+
} else {
|
|
4070
|
+
showSpinner();
|
|
4071
|
+
}
|
|
4053
4072
|
setAutocompleteContext(contextType);
|
|
4054
|
-
showDropdownAtPosition(32, 300);
|
|
4055
4073
|
}
|
|
4056
4074
|
if (willFetchAsync) {
|
|
4057
4075
|
const partial = result.context.partial;
|
|
@@ -4086,7 +4104,7 @@ function ElasticInput(props) {
|
|
|
4086
4104
|
mapped = fetched.map((h) => ({
|
|
4087
4105
|
text: AutocompleteEngine.wrapHistoryQuery(h.query),
|
|
4088
4106
|
label: h.label || h.query,
|
|
4089
|
-
description: h.
|
|
4107
|
+
description: h.description,
|
|
4090
4108
|
type: "history",
|
|
4091
4109
|
replaceStart: start,
|
|
4092
4110
|
replaceEnd: end,
|
|
@@ -4109,6 +4127,10 @@ function ElasticInput(props) {
|
|
|
4109
4127
|
matchPartial: partial
|
|
4110
4128
|
}));
|
|
4111
4129
|
}
|
|
4130
|
+
if (loadingDelayTimerRef.current) {
|
|
4131
|
+
clearTimeout(loadingDelayTimerRef.current);
|
|
4132
|
+
loadingDelayTimerRef.current = null;
|
|
4133
|
+
}
|
|
4112
4134
|
mapped = mapped.slice(0, effectiveMaxSuggestions);
|
|
4113
4135
|
if (mapped.length > 0) {
|
|
4114
4136
|
setSuggestions(mapped);
|
|
@@ -4130,6 +4152,10 @@ function ElasticInput(props) {
|
|
|
4130
4152
|
}
|
|
4131
4153
|
}
|
|
4132
4154
|
} catch (e) {
|
|
4155
|
+
if (loadingDelayTimerRef.current) {
|
|
4156
|
+
clearTimeout(loadingDelayTimerRef.current);
|
|
4157
|
+
loadingDelayTimerRef.current = null;
|
|
4158
|
+
}
|
|
4133
4159
|
if (!controller.signal.aborted) {
|
|
4134
4160
|
const errorMsg = e instanceof Error ? e.message : "Error loading suggestions";
|
|
4135
4161
|
const errorSuggestion = {
|
|
@@ -4147,7 +4173,7 @@ function ElasticInput(props) {
|
|
|
4147
4173
|
}
|
|
4148
4174
|
}, debounceMs);
|
|
4149
4175
|
}
|
|
4150
|
-
}, [fetchSuggestionsProp, savedSearches, searchHistory, suggestDebounceMs, applyFieldHint, computeDropdownPosition, showDropdownAtPosition, dropdownAlignToInput, dropdownOpen, dropdownOpenIsCallback, dropdownMode, showOperators, effectiveMaxSuggestions]);
|
|
4176
|
+
}, [fetchSuggestionsProp, savedSearches, searchHistory, suggestDebounceMs, applyFieldHint, computeDropdownPosition, showDropdownAtPosition, dropdownAlignToInput, dropdownOpen, dropdownOpenIsCallback, dropdownMode, showOperators, effectiveMaxSuggestions, loadingDelay]);
|
|
4151
4177
|
updateSuggestionsRef.current = updateSuggestionsFromTokens;
|
|
4152
4178
|
const closeDropdown = React.useCallback(() => {
|
|
4153
4179
|
var _a;
|
|
@@ -4348,6 +4374,7 @@ function ElasticInput(props) {
|
|
|
4348
4374
|
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
4349
4375
|
if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);
|
|
4350
4376
|
if (navDelayTimerRef.current) clearTimeout(navDelayTimerRef.current);
|
|
4377
|
+
if (loadingDelayTimerRef.current) clearTimeout(loadingDelayTimerRef.current);
|
|
4351
4378
|
(_a = abortControllerRef.current) == null ? void 0 : _a.abort();
|
|
4352
4379
|
};
|
|
4353
4380
|
}, []);
|
|
@@ -4662,6 +4689,12 @@ function ElasticInput(props) {
|
|
|
4662
4689
|
case "Enter":
|
|
4663
4690
|
if (s.selectedSuggestionIndex >= 0) {
|
|
4664
4691
|
const selected = s.suggestions[s.selectedSuggestionIndex];
|
|
4692
|
+
if (selected.type === "loading" || selected.type === "error") {
|
|
4693
|
+
e.preventDefault();
|
|
4694
|
+
closeDropdown();
|
|
4695
|
+
if (onSearch) onSearch(currentValueRef.current, s.ast);
|
|
4696
|
+
return;
|
|
4697
|
+
}
|
|
4665
4698
|
if (selected.type === "hint" && selected.text !== "#" && selected.text !== "!") {
|
|
4666
4699
|
e.preventDefault();
|
|
4667
4700
|
closeDropdown();
|
|
@@ -4684,7 +4717,10 @@ function ElasticInput(props) {
|
|
|
4684
4717
|
acceptSuggestion(selected, "Enter");
|
|
4685
4718
|
return;
|
|
4686
4719
|
}
|
|
4687
|
-
|
|
4720
|
+
e.preventDefault();
|
|
4721
|
+
closeDropdown();
|
|
4722
|
+
if (onSearch) onSearch(currentValueRef.current, s.ast);
|
|
4723
|
+
return;
|
|
4688
4724
|
case "Tab": {
|
|
4689
4725
|
if (onTabProp) {
|
|
4690
4726
|
e.preventDefault();
|
package/dist/types.d.ts
CHANGED
|
@@ -67,10 +67,10 @@ export interface SavedSearch {
|
|
|
67
67
|
export interface HistoryEntry {
|
|
68
68
|
/** The query string from the history entry. */
|
|
69
69
|
query: string;
|
|
70
|
-
/** Unix timestamp (ms) of when the query was executed. Used for ordering. */
|
|
71
|
-
timestamp?: number;
|
|
72
70
|
/** Optional label for display in the autocomplete dropdown. Falls back to `query`. */
|
|
73
71
|
label?: string;
|
|
72
|
+
/** Optional description shown below the label (e.g. date, category). Rendered as-is. */
|
|
73
|
+
description?: React.ReactNode;
|
|
74
74
|
}
|
|
75
75
|
/** An item returned by the async `fetchSuggestions` callback for field value autocomplete. */
|
|
76
76
|
export interface SuggestionItem {
|
|
@@ -241,6 +241,10 @@ export interface DropdownConfig {
|
|
|
241
241
|
* immediate. If the user types before the delay elapses, the timer is cancelled.
|
|
242
242
|
* Ignored when `onNavigation` is false. @default 0 */
|
|
243
243
|
navigationDelay?: number;
|
|
244
|
+
/** Delay in ms before showing the "Searching..." spinner on first entry into an
|
|
245
|
+
* async field. If the fetch resolves before the delay, the spinner never appears.
|
|
246
|
+
* Subsequent keystrokes preserve previous results regardless of this setting. @default 0 */
|
|
247
|
+
loadingDelay?: number;
|
|
244
248
|
/** Custom renderer for field value hints. Return a React element for rich content,
|
|
245
249
|
* or null/undefined for the default hint. */
|
|
246
250
|
renderFieldHint?: (field: FieldConfig, partial: string) => React.ReactNode | null | undefined;
|