@fluid-topics/ft-search-input 2.1.1 → 2.1.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/build/SearchInputMessages.d.ts +2 -1
- package/build/SearchInputMessages.js +1 -1
- package/build/ft-search-input-suggestion.d.ts +16 -11
- package/build/ft-search-input-suggestion.js +126 -73
- package/build/ft-search-input-suggestion.styles.js +12 -7
- package/build/ft-search-input.d.ts +4 -4
- package/build/ft-search-input.js +43 -37
- package/build/ft-search-input.light.js +284 -276
- package/build/ft-search-input.min.js +160 -152
- package/package.json +11 -11
|
@@ -4,6 +4,7 @@ export interface SearchInputMessages extends I18nMessages {
|
|
|
4
4
|
searchButton(): string;
|
|
5
5
|
clearButton(): string;
|
|
6
6
|
suggestionsLabel(): string;
|
|
7
|
-
ariaLiveSuggestions(
|
|
7
|
+
ariaLiveSuggestions(recentQueries: number, suggestions: number): string;
|
|
8
|
+
removeRecentQuery(query: string): string;
|
|
8
9
|
}
|
|
9
10
|
export declare const searchInputContext: I18nMessageContext<SearchInputMessages>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { I18nMessageContext } from "@fluid-topics/ft-i18n";
|
|
1
|
+
import { I18nMessageContext, } from "@fluid-topics/ft-i18n";
|
|
2
2
|
export const searchInputContext = I18nMessageContext.build("designedSearchInput");
|
|
@@ -10,16 +10,21 @@ export declare class FtSearchInputSuggestionManager {
|
|
|
10
10
|
constructor(ftSearchInput: FtSearchInput);
|
|
11
11
|
listboxId: string;
|
|
12
12
|
render(): import("lit-html").TemplateResult<1>;
|
|
13
|
+
private renderRecentQuery;
|
|
13
14
|
private renderSuggestion;
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
private renderOption;
|
|
16
|
+
private onRemoveRecentQuery;
|
|
17
|
+
private onSelectOption;
|
|
18
|
+
get activeElementId(): string | undefined;
|
|
19
|
+
get activeElement(): HTMLElement | undefined;
|
|
20
|
+
recentQueriesCount(): number;
|
|
21
|
+
suggestionsCount(): number;
|
|
22
|
+
optionsCount(): number;
|
|
23
|
+
private clearSelection;
|
|
24
|
+
selectNext(): void;
|
|
25
|
+
selectPrevious(): void;
|
|
26
|
+
selectLeft(): void;
|
|
27
|
+
private isRemovable;
|
|
28
|
+
selectRight(): void;
|
|
29
|
+
closeBox(): void;
|
|
25
30
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { wordWrap } from "@fluid-topics/ft-wc-utils";
|
|
2
|
-
import { html } from "lit";
|
|
1
|
+
import { wordWrap, } from "@fluid-topics/ft-wc-utils";
|
|
2
|
+
import { html, nothing, } from "lit";
|
|
3
3
|
import { suggestionStyles } from "./ft-search-input-suggestion.styles";
|
|
4
4
|
import { repeat } from "lit/directives/repeat.js";
|
|
5
|
-
import { FtIcon, FtIcons, FtIconVariants, resolveFileFormatIcon } from "@fluid-topics/ft-icon";
|
|
5
|
+
import { FtIcon, FtIcons, FtIconVariants, resolveFileFormatIcon, } from "@fluid-topics/ft-icon";
|
|
6
6
|
import { FtRipple } from "@fluid-topics/ft-ripple";
|
|
7
|
-
import { FtTypography } from "@fluid-topics/ft-typography";
|
|
7
|
+
import { FtTypography, FtTypographyVariants, } from "@fluid-topics/ft-typography";
|
|
8
8
|
import { SearchPlaceConverterProvider } from "@fluid-topics/ft-app-context";
|
|
9
9
|
import { searchInputContext } from "./SearchInputMessages";
|
|
10
|
+
import { FtButton } from "@fluid-topics/ft-button";
|
|
10
11
|
export class SuggestionSelectedEvent extends CustomEvent {
|
|
11
12
|
constructor(value) {
|
|
12
13
|
super("suggestion-selected", { detail: value });
|
|
@@ -18,59 +19,28 @@ export class FtSearchInputSuggestionManager {
|
|
|
18
19
|
this.listboxId = "ft-search-input-suggestion";
|
|
19
20
|
}
|
|
20
21
|
render() {
|
|
22
|
+
var _a;
|
|
21
23
|
const searchPlaceConverter = SearchPlaceConverterProvider.get();
|
|
24
|
+
const { recentQuerySuggestions } = this.ftSearchInput;
|
|
22
25
|
return html `
|
|
23
26
|
<div class="ft-search-input-suggestion ft-word-wrap"
|
|
24
27
|
id="${this.listboxId}"
|
|
25
28
|
role="listbox"
|
|
26
29
|
aria-label="${searchInputContext.messages.suggestionsLabel()}"
|
|
27
30
|
part="container">
|
|
28
|
-
${repeat(
|
|
29
|
-
return this.
|
|
31
|
+
${repeat(recentQuerySuggestions, (query) => query, (query, index) => {
|
|
32
|
+
return this.renderRecentQuery(index, query, searchPlaceConverter);
|
|
33
|
+
})}
|
|
34
|
+
${repeat((_a = this.ftSearchInput.suggestResults) !== null && _a !== void 0 ? _a : [], (suggest) => suggest.value, (suggest, index) => {
|
|
35
|
+
return this.renderSuggestion(recentQuerySuggestions.length + index, suggest, searchPlaceConverter);
|
|
30
36
|
})}
|
|
31
37
|
</div>
|
|
32
38
|
`;
|
|
33
39
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const content = html `
|
|
37
|
-
<ft-ripple ?activated=${this.ftSearchInput.selectedSuggestOptionId === id}></ft-ripple>
|
|
38
|
-
${this.getIcon(suggest)}
|
|
39
|
-
<ft-typography variant="body1">${suggest.value}</ft-typography>
|
|
40
|
-
`;
|
|
41
|
-
if (this.ftSearchInput.launchSearchPath) {
|
|
42
|
-
const suggestRequest = { ...this.ftSearchInput.request, query: suggest.value };
|
|
43
|
-
const launchSuggestUrl = searchPlaceConverter.serializeToCurrentPageIfPossible(suggestRequest, this.ftSearchInput.launchSearchPath);
|
|
44
|
-
return html `
|
|
45
|
-
<a href="${launchSuggestUrl}"
|
|
46
|
-
part="suggestion"
|
|
47
|
-
class="ft-search-input-suggestion--suggestion"
|
|
48
|
-
role="option"
|
|
49
|
-
id="${id}"
|
|
50
|
-
aria-selected="${this.ftSearchInput.selectedSuggestOptionId === id}"
|
|
51
|
-
tabindex="-1"
|
|
52
|
-
aria-label="${content}"
|
|
53
|
-
@click=${() => this.onSuggestSelected(suggest.value)}>
|
|
54
|
-
${content}
|
|
55
|
-
</a>
|
|
56
|
-
`;
|
|
57
|
-
}
|
|
58
|
-
return html `
|
|
59
|
-
<div part="suggestion"
|
|
60
|
-
class="ft-search-input-suggestion--suggestion"
|
|
61
|
-
role="option"
|
|
62
|
-
id="${id}"
|
|
63
|
-
aria-selected="${this.ftSearchInput.selectedSuggestOptionId === id}"
|
|
64
|
-
tabindex="-1"
|
|
65
|
-
@click=${() => this.onSuggestSelected(suggest.value)}>
|
|
66
|
-
${content}
|
|
67
|
-
</div>
|
|
68
|
-
`;
|
|
69
|
-
}
|
|
70
|
-
onSuggestSelected(suggest) {
|
|
71
|
-
this.ftSearchInput.onSuggestionSelected(suggest);
|
|
40
|
+
renderRecentQuery(index, query, searchPlaceConverter) {
|
|
41
|
+
return this.renderOption(index, query, "history", FtIconVariants.material, true, searchPlaceConverter);
|
|
72
42
|
}
|
|
73
|
-
|
|
43
|
+
renderSuggestion(index, suggest, searchPlaceConverter) {
|
|
74
44
|
const iconVariant = suggest.type === "DOCUMENT" ? FtIconVariants.file_format : FtIconVariants.fluid_topics;
|
|
75
45
|
let icon;
|
|
76
46
|
switch (suggest.type) {
|
|
@@ -90,56 +60,139 @@ export class FtSearchInputSuggestionManager {
|
|
|
90
60
|
icon = FtIcons.FILE_CODE;
|
|
91
61
|
break;
|
|
92
62
|
}
|
|
63
|
+
return this.renderOption(index, suggest.value, icon, iconVariant, false, searchPlaceConverter);
|
|
64
|
+
}
|
|
65
|
+
renderOption(index, query, icon, iconVariant, removable, searchPlaceConverter) {
|
|
66
|
+
const indexSelected = this.ftSearchInput.selectedSuggestOptionIndex === index;
|
|
67
|
+
const removeButtonSelected = this.ftSearchInput.selectedSuggestOptionRemove;
|
|
68
|
+
const href = this.ftSearchInput.launchSearchPath ? searchPlaceConverter.serializeToCurrentPageIfPossible({ ...this.ftSearchInput.request, query }, this.ftSearchInput.launchSearchPath) : nothing;
|
|
93
69
|
return html `
|
|
94
|
-
<
|
|
70
|
+
<div part="suggestion-container"
|
|
71
|
+
class="ft-search-input-suggestion--container">
|
|
72
|
+
<a href="${href}"
|
|
73
|
+
part="suggestion"
|
|
74
|
+
class="ft-search-input-suggestion--suggestion"
|
|
75
|
+
role="option"
|
|
76
|
+
id="suggestion-${index}"
|
|
77
|
+
aria-selected="${indexSelected}"
|
|
78
|
+
tabindex="-1"
|
|
79
|
+
@click=${() => this.onSelectOption(query)}
|
|
80
|
+
>
|
|
81
|
+
<ft-ripple ?activated=${indexSelected && !removeButtonSelected}></ft-ripple>
|
|
82
|
+
<ft-icon variant="${iconVariant}" value="${icon}" part="suggestion-icon"></ft-icon>
|
|
83
|
+
<ft-typography variant="${FtTypographyVariants.body1}">${query}</ft-typography>
|
|
84
|
+
</a>
|
|
85
|
+
${removable ? html `
|
|
86
|
+
<ft-button icon="${FtIcons.CLOSE}"
|
|
87
|
+
round
|
|
88
|
+
part="remove-suggestion"
|
|
89
|
+
class="ft-search-input-suggestion--remove"
|
|
90
|
+
id="remove-suggestion-${index}"
|
|
91
|
+
label="${searchInputContext.messages.removeRecentQuery(query)}"
|
|
92
|
+
tooltipPosition="left"
|
|
93
|
+
tabindex="-1"
|
|
94
|
+
?activated=${indexSelected && removeButtonSelected}
|
|
95
|
+
@click=${() => this.onRemoveRecentQuery(query)}>
|
|
96
|
+
</ft-button>
|
|
97
|
+
` : nothing}
|
|
98
|
+
</div>
|
|
95
99
|
`;
|
|
96
100
|
}
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
onRemoveRecentQuery(query) {
|
|
102
|
+
var _a;
|
|
103
|
+
(_a = this.ftSearchInput.stateManager) === null || _a === void 0 ? void 0 : _a.removeRecentQuery(query);
|
|
99
104
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return suggestions.length > 0 ? suggestions[suggestions.length - 1] : null;
|
|
105
|
+
onSelectOption(query) {
|
|
106
|
+
this.ftSearchInput.onSuggestionSelected(query);
|
|
103
107
|
}
|
|
104
|
-
|
|
105
|
-
|
|
108
|
+
get activeElementId() {
|
|
109
|
+
const { selectedSuggestOptionIndex, selectedSuggestOptionRemove } = this.ftSearchInput;
|
|
110
|
+
if (selectedSuggestOptionIndex === undefined) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
return (selectedSuggestOptionRemove ? "remove-suggestion-" : "suggestion-") + selectedSuggestOptionIndex;
|
|
106
114
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
get activeElement() {
|
|
116
|
+
var _a;
|
|
117
|
+
const id = this.activeElementId;
|
|
118
|
+
if (id === undefined) {
|
|
119
|
+
return undefined;
|
|
111
120
|
}
|
|
112
|
-
return
|
|
121
|
+
return (_a = this.ftSearchInput.shadowRoot.getElementById(id)) !== null && _a !== void 0 ? _a : undefined;
|
|
122
|
+
}
|
|
123
|
+
recentQueriesCount() {
|
|
124
|
+
return this.ftSearchInput.recentQuerySuggestions.length;
|
|
125
|
+
}
|
|
126
|
+
suggestionsCount() {
|
|
127
|
+
var _a, _b;
|
|
128
|
+
return (_b = (_a = this.ftSearchInput.suggestResults) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
129
|
+
}
|
|
130
|
+
optionsCount() {
|
|
131
|
+
return this.recentQueriesCount() + this.suggestionsCount();
|
|
113
132
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
clearSelection() {
|
|
134
|
+
this.ftSearchInput.selectedSuggestOptionIndex = undefined;
|
|
135
|
+
this.ftSearchInput.selectedSuggestOptionRemove = false;
|
|
136
|
+
}
|
|
137
|
+
selectNext() {
|
|
138
|
+
if (this.ftSearchInput.selectedSuggestOptionIndex === undefined) {
|
|
139
|
+
this.ftSearchInput.selectedSuggestOptionIndex = 0;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
this.ftSearchInput.selectedSuggestOptionIndex++;
|
|
143
|
+
if (this.ftSearchInput.selectedSuggestOptionIndex >= this.optionsCount()) {
|
|
144
|
+
this.clearSelection();
|
|
145
|
+
}
|
|
118
146
|
}
|
|
119
|
-
return divElement === null || divElement === void 0 ? void 0 : divElement.previousElementSibling;
|
|
120
147
|
}
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
this.ftSearchInput.
|
|
148
|
+
selectPrevious() {
|
|
149
|
+
if (this.ftSearchInput.selectedSuggestOptionIndex === undefined) {
|
|
150
|
+
this.ftSearchInput.selectedSuggestOptionIndex = this.optionsCount() - 1;
|
|
124
151
|
}
|
|
125
152
|
else {
|
|
126
|
-
this.ftSearchInput.
|
|
153
|
+
this.ftSearchInput.selectedSuggestOptionIndex--;
|
|
154
|
+
if (this.ftSearchInput.selectedSuggestOptionIndex < 0) {
|
|
155
|
+
this.clearSelection();
|
|
156
|
+
}
|
|
127
157
|
}
|
|
128
158
|
}
|
|
129
|
-
|
|
130
|
-
this.
|
|
159
|
+
selectLeft() {
|
|
160
|
+
const index = this.ftSearchInput.selectedSuggestOptionIndex;
|
|
161
|
+
if (index === undefined) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (this.ftSearchInput.selectedSuggestOptionRemove) {
|
|
165
|
+
this.ftSearchInput.selectedSuggestOptionRemove = false;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
this.clearSelection();
|
|
169
|
+
}
|
|
131
170
|
}
|
|
132
|
-
|
|
133
|
-
this.
|
|
171
|
+
isRemovable(index) {
|
|
172
|
+
return index < this.recentQueriesCount();
|
|
134
173
|
}
|
|
135
|
-
|
|
136
|
-
this.
|
|
174
|
+
selectRight() {
|
|
175
|
+
const index = this.ftSearchInput.selectedSuggestOptionIndex;
|
|
176
|
+
if (index === undefined) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (!this.ftSearchInput.selectedSuggestOptionRemove && this.isRemovable(index)) {
|
|
180
|
+
this.ftSearchInput.selectedSuggestOptionRemove = true;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.clearSelection();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
closeBox() {
|
|
187
|
+
this.ftSearchInput.displaySuggestListbox = false;
|
|
188
|
+
this.clearSelection();
|
|
137
189
|
}
|
|
138
190
|
}
|
|
139
191
|
FtSearchInputSuggestionManager.elementDefinitions = {
|
|
140
192
|
"ft-ripple": FtRipple,
|
|
141
193
|
"ft-typography": FtTypography,
|
|
142
194
|
"ft-icon": FtIcon,
|
|
195
|
+
"ft-button": FtButton,
|
|
143
196
|
};
|
|
144
197
|
FtSearchInputSuggestionManager.styles = [
|
|
145
198
|
wordWrap,
|
|
@@ -21,6 +21,17 @@ export const suggestionStyles = css `
|
|
|
21
21
|
box-shadow: ${FtSearchInputCssVariables.elevation02};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
.ft-search-input-suggestion--container {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.ft-search-input-suggestion--container:has([aria-selected="true"]),
|
|
30
|
+
.ft-search-input-suggestion--container:hover {
|
|
31
|
+
outline: none;
|
|
32
|
+
box-shadow: inset 3px 0 0 ${FtSearchBarCssVariables.activeItemBorderColor};
|
|
33
|
+
}
|
|
34
|
+
|
|
24
35
|
.ft-search-input-suggestion--suggestion {
|
|
25
36
|
text-decoration: none;
|
|
26
37
|
position: relative;
|
|
@@ -31,19 +42,13 @@ export const suggestionStyles = css `
|
|
|
31
42
|
cursor: pointer;
|
|
32
43
|
color: ${FtSearchInputCssVariables.colorOnSurface};
|
|
33
44
|
min-height: 44px;
|
|
45
|
+
flex-grow: 1;
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
.ft-search-input-suggestion--suggestion > *:not(ft-ripple) {
|
|
37
49
|
position: relative;
|
|
38
50
|
}
|
|
39
51
|
|
|
40
|
-
.ft-search-input-suggestion--suggestion[aria-selected="true"],
|
|
41
|
-
.ft-search-input-suggestion--suggestion:hover {
|
|
42
|
-
outline: none;
|
|
43
|
-
box-shadow: inset 3px 0 0 ${FtSearchBarCssVariables.activeItemBorderColor};
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
52
|
.ft-search-input-suggestion--suggestion ft-typography {
|
|
48
53
|
display: block;
|
|
49
54
|
flex-grow: 1;
|
|
@@ -12,9 +12,11 @@ export declare class FtSearchInput extends FtSearchInput_base implements FtSearc
|
|
|
12
12
|
request?: FtSearchRequest;
|
|
13
13
|
liveQuery: string;
|
|
14
14
|
suggestResults?: Array<FtSuggestResult>;
|
|
15
|
+
recentQuerySuggestions: string[];
|
|
15
16
|
private forceCloseSuggestion;
|
|
16
17
|
displaySuggestListbox: boolean;
|
|
17
|
-
|
|
18
|
+
selectedSuggestOptionIndex?: number;
|
|
19
|
+
selectedSuggestOptionRemove: boolean;
|
|
18
20
|
launchSearchPath?: string;
|
|
19
21
|
placeholder?: I18nAttributeValue;
|
|
20
22
|
useCustomSearchPath: boolean;
|
|
@@ -24,20 +26,18 @@ export declare class FtSearchInput extends FtSearchInput_base implements FtSearc
|
|
|
24
26
|
private launchSearchButton;
|
|
25
27
|
suggestions: FtSearchInputSuggestionManager;
|
|
26
28
|
protected render(): import("lit-html").TemplateResult<1>;
|
|
27
|
-
private renderLiveText;
|
|
28
29
|
private onSearchBarKeyDown;
|
|
29
30
|
private onSearchBarKeyUp;
|
|
30
31
|
private onInput;
|
|
31
32
|
private onClearInput;
|
|
32
33
|
launchSearch(query: string): void;
|
|
33
34
|
onSuggestionSelected(value: string): void;
|
|
34
|
-
get shouldDisplaySuggestions(): boolean;
|
|
35
35
|
private onClick;
|
|
36
36
|
private showSuggestionsOnFocus;
|
|
37
37
|
private onFocus;
|
|
38
38
|
focusInput(showSuggestions?: boolean): Promise<void>;
|
|
39
39
|
connectedCallback(): Promise<void>;
|
|
40
40
|
disconnectedCallback(): void;
|
|
41
|
-
private
|
|
41
|
+
private onPointerDown;
|
|
42
42
|
}
|
|
43
43
|
export {};
|
package/build/ft-search-input.js
CHANGED
|
@@ -17,37 +17,45 @@ import { FtButton } from "@fluid-topics/ft-button";
|
|
|
17
17
|
import { FtTypographyBody2 } from "@fluid-topics/ft-typography";
|
|
18
18
|
import { SearchPlaceConverterProvider } from "@fluid-topics/ft-app-context";
|
|
19
19
|
import { i18nAttribute, } from "@fluid-topics/ft-i18n/build/decorators/i18nAttribute";
|
|
20
|
+
const maxRecentQuerySuggestions = 5;
|
|
21
|
+
function selectRecentQuerySuggestions(state) {
|
|
22
|
+
const normalizedQuery = state.liveQuery.trim().toLowerCase();
|
|
23
|
+
return state.recentQueries.filter((q) => q.toLowerCase().includes(normalizedQuery)).slice(0, maxRecentQuerySuggestions);
|
|
24
|
+
}
|
|
20
25
|
export class FtSearchInput extends withI18n(FtSearchComponent) {
|
|
21
26
|
constructor() {
|
|
22
27
|
super();
|
|
23
28
|
this.liveQuery = "";
|
|
29
|
+
this.recentQuerySuggestions = [];
|
|
24
30
|
this.forceCloseSuggestion = false;
|
|
25
31
|
this.displaySuggestListbox = false;
|
|
32
|
+
this.selectedSuggestOptionRemove = false;
|
|
26
33
|
this.useCustomSearchPath = false;
|
|
27
34
|
this.triggerSearchOnClear = false;
|
|
28
35
|
this.focusOnDisplay = false;
|
|
29
36
|
this.suggestions = new FtSearchInputSuggestionManager(this);
|
|
30
37
|
this.showSuggestionsOnFocus = true;
|
|
31
|
-
this.
|
|
38
|
+
this.onPointerDown = (e) => {
|
|
32
39
|
const path = e.composedPath();
|
|
33
40
|
const inside = path.some((n) => n === this || n === this.shadowRoot);
|
|
34
41
|
if (!inside) {
|
|
35
|
-
this.
|
|
36
|
-
this.selectedSuggestOptionId = undefined;
|
|
42
|
+
this.suggestions.closeBox();
|
|
37
43
|
}
|
|
38
44
|
};
|
|
39
45
|
this.addI18nContext(searchInputContext);
|
|
40
46
|
}
|
|
41
47
|
render() {
|
|
42
|
-
var _a
|
|
48
|
+
var _a;
|
|
49
|
+
const hasSuggestions = this.suggestions.optionsCount() > 0;
|
|
43
50
|
const classes = {
|
|
44
51
|
"ft-search-input": true,
|
|
45
|
-
"ft-search-input--with-suggestions":
|
|
52
|
+
"ft-search-input--with-suggestions": hasSuggestions,
|
|
46
53
|
"ft-search-input--with-suggestions-closed": this.forceCloseSuggestion,
|
|
47
54
|
};
|
|
48
55
|
const liveRequest = { ...this.request, query: this.liveQuery };
|
|
49
56
|
const searchPage = this.useCustomSearchPath ? this.launchSearchPath : undefined;
|
|
50
57
|
const launchSearchUrl = SearchPlaceConverterProvider.get().serializeToCurrentPageIfPossible(liveRequest, searchPage);
|
|
58
|
+
const displaySuggestions = !this.forceCloseSuggestion && this.displaySuggestListbox && hasSuggestions;
|
|
51
59
|
return html `
|
|
52
60
|
<div class="${classMap(classes)}" @focusout=${() => this.forceCloseSuggestion = false} role="search">
|
|
53
61
|
<div class="ft-search-input--input-container" part="input-container" tabindex="-1">
|
|
@@ -56,12 +64,12 @@ export class FtSearchInput extends withI18n(FtSearchComponent) {
|
|
|
56
64
|
part="input"
|
|
57
65
|
type="search"
|
|
58
66
|
placeholder="${this.placeholder ? this.placeholder.message : searchInputContext.messages.placeholder()}"
|
|
59
|
-
|
|
67
|
+
value="${this.liveQuery}"
|
|
60
68
|
role="combobox"
|
|
61
69
|
aria-autocomplete="list"
|
|
62
70
|
aria-controls="${this.suggestions.listboxId}"
|
|
63
71
|
aria-expanded="${this.displaySuggestListbox}"
|
|
64
|
-
aria-activedescendant="${(
|
|
72
|
+
aria-activedescendant="${(_a = this.suggestions.activeElementId) !== null && _a !== void 0 ? _a : nothing}"
|
|
65
73
|
@input=${this.onInput}
|
|
66
74
|
@click=${this.onClick}
|
|
67
75
|
@focus=${this.onFocus}
|
|
@@ -69,9 +77,9 @@ export class FtSearchInput extends withI18n(FtSearchComponent) {
|
|
|
69
77
|
@keyup=${this.onSearchBarKeyUp}>
|
|
70
78
|
</div>
|
|
71
79
|
<div class="sr-only" aria-live="polite" aria-atomic="true">
|
|
72
|
-
${this.
|
|
80
|
+
${displaySuggestions ? searchInputContext.messages.ariaLiveSuggestions(this.suggestions.recentQueriesCount(), this.suggestions.suggestionsCount()) : ""}
|
|
73
81
|
</div>
|
|
74
|
-
${
|
|
82
|
+
${displaySuggestions ? this.suggestions.render() : nothing}
|
|
75
83
|
</div>
|
|
76
84
|
<div class="ft-search-input--actions" part="actions">
|
|
77
85
|
${this.liveQuery ? html `
|
|
@@ -97,14 +105,6 @@ export class FtSearchInput extends withI18n(FtSearchComponent) {
|
|
|
97
105
|
</div>
|
|
98
106
|
`;
|
|
99
107
|
}
|
|
100
|
-
renderLiveText() {
|
|
101
|
-
if (this.shouldDisplaySuggestions) {
|
|
102
|
-
return searchInputContext.messages.ariaLiveSuggestions(this.suggestResults.length);
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
return "";
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
108
|
onSearchBarKeyDown(e) {
|
|
109
109
|
this.forceCloseSuggestion = false;
|
|
110
110
|
if (!["Escape", "Tab", "Shift"].includes(e.key)) {
|
|
@@ -112,38 +112,42 @@ export class FtSearchInput extends withI18n(FtSearchComponent) {
|
|
|
112
112
|
}
|
|
113
113
|
switch (e.key) {
|
|
114
114
|
case "Tab":
|
|
115
|
-
this.
|
|
116
|
-
this.selectedSuggestOptionId = undefined;
|
|
115
|
+
this.suggestions.closeBox();
|
|
117
116
|
break;
|
|
118
117
|
case "Escape":
|
|
119
|
-
if (this.
|
|
118
|
+
if (this.displaySuggestListbox && this.suggestions.optionsCount() > 0) {
|
|
120
119
|
e.stopPropagation();
|
|
121
120
|
e.preventDefault();
|
|
122
|
-
this.
|
|
123
|
-
this.selectedSuggestOptionId = undefined;
|
|
121
|
+
this.suggestions.closeBox();
|
|
124
122
|
}
|
|
125
123
|
break;
|
|
126
124
|
case "ArrowDown":
|
|
127
125
|
e.stopPropagation();
|
|
128
126
|
e.preventDefault();
|
|
129
|
-
this.suggestions.
|
|
127
|
+
this.suggestions.selectNext();
|
|
130
128
|
break;
|
|
131
129
|
case "ArrowUp":
|
|
132
130
|
e.stopPropagation();
|
|
133
131
|
e.preventDefault();
|
|
134
|
-
this.suggestions.
|
|
132
|
+
this.suggestions.selectPrevious();
|
|
135
133
|
break;
|
|
136
134
|
case "ArrowLeft":
|
|
135
|
+
if (this.selectedSuggestOptionIndex !== undefined) {
|
|
136
|
+
e.stopPropagation();
|
|
137
|
+
e.preventDefault();
|
|
138
|
+
this.suggestions.selectLeft();
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
137
141
|
case "ArrowRight":
|
|
138
|
-
if (this.
|
|
142
|
+
if (this.selectedSuggestOptionIndex !== undefined) {
|
|
139
143
|
e.stopPropagation();
|
|
140
144
|
e.preventDefault();
|
|
141
|
-
this.suggestions.
|
|
145
|
+
this.suggestions.selectRight();
|
|
142
146
|
}
|
|
143
147
|
break;
|
|
144
148
|
case "Enter": {
|
|
145
149
|
// Select suggested option if applicable
|
|
146
|
-
const elementToClick = this.suggestions.
|
|
150
|
+
const elementToClick = this.suggestions.activeElement;
|
|
147
151
|
if (elementToClick) {
|
|
148
152
|
elementToClick.click();
|
|
149
153
|
break; // Clicking the selected suggestion will already launch a search
|
|
@@ -185,19 +189,15 @@ export class FtSearchInput extends withI18n(FtSearchComponent) {
|
|
|
185
189
|
this.input.focus();
|
|
186
190
|
}
|
|
187
191
|
launchSearch(query) {
|
|
188
|
-
var _a;
|
|
192
|
+
var _a, _b;
|
|
189
193
|
this.forceCloseSuggestion = true;
|
|
190
194
|
this.dispatchEvent(new CustomEvent("change", { detail: query }));
|
|
191
195
|
(_a = this.stateManager) === null || _a === void 0 ? void 0 : _a.setQuery(query);
|
|
196
|
+
(_b = this.stateManager) === null || _b === void 0 ? void 0 : _b.addRecentQuery(query);
|
|
192
197
|
}
|
|
193
198
|
onSuggestionSelected(value) {
|
|
194
199
|
this.launchSearch(value);
|
|
195
|
-
this.
|
|
196
|
-
this.suggestions.clearSelection();
|
|
197
|
-
}
|
|
198
|
-
get shouldDisplaySuggestions() {
|
|
199
|
-
var _a;
|
|
200
|
-
return !this.forceCloseSuggestion && this.displaySuggestListbox && ((_a = this.suggestResults) !== null && _a !== void 0 ? _a : []).length > 0;
|
|
200
|
+
this.suggestions.closeBox();
|
|
201
201
|
}
|
|
202
202
|
onClick() {
|
|
203
203
|
this.onFocus();
|
|
@@ -216,14 +216,14 @@ export class FtSearchInput extends withI18n(FtSearchComponent) {
|
|
|
216
216
|
}
|
|
217
217
|
async connectedCallback() {
|
|
218
218
|
super.connectedCallback();
|
|
219
|
-
document.addEventListener("pointerdown", this.
|
|
219
|
+
document.addEventListener("pointerdown", this.onPointerDown);
|
|
220
220
|
if (this.focusOnDisplay && !isTouchScreen) {
|
|
221
221
|
this.focusInput(false);
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
disconnectedCallback() {
|
|
225
225
|
super.disconnectedCallback();
|
|
226
|
-
document.removeEventListener("pointerdown", this.
|
|
226
|
+
document.removeEventListener("pointerdown", this.onPointerDown);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
FtSearchInput.elementDefinitions = {
|
|
@@ -246,6 +246,9 @@ __decorate([
|
|
|
246
246
|
__decorate([
|
|
247
247
|
redux()
|
|
248
248
|
], FtSearchInput.prototype, "suggestResults", void 0);
|
|
249
|
+
__decorate([
|
|
250
|
+
redux({ selector: selectRecentQuerySuggestions })
|
|
251
|
+
], FtSearchInput.prototype, "recentQuerySuggestions", void 0);
|
|
249
252
|
__decorate([
|
|
250
253
|
state()
|
|
251
254
|
], FtSearchInput.prototype, "forceCloseSuggestion", void 0);
|
|
@@ -254,7 +257,10 @@ __decorate([
|
|
|
254
257
|
], FtSearchInput.prototype, "displaySuggestListbox", void 0);
|
|
255
258
|
__decorate([
|
|
256
259
|
state()
|
|
257
|
-
], FtSearchInput.prototype, "
|
|
260
|
+
], FtSearchInput.prototype, "selectedSuggestOptionIndex", void 0);
|
|
261
|
+
__decorate([
|
|
262
|
+
state()
|
|
263
|
+
], FtSearchInput.prototype, "selectedSuggestOptionRemove", void 0);
|
|
258
264
|
__decorate([
|
|
259
265
|
property()
|
|
260
266
|
], FtSearchInput.prototype, "launchSearchPath", void 0);
|