@fluid-topics/ft-text-field 1.2.28 → 1.2.29
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/TextFieldSuggestionProvider.d.ts +2 -0
- package/build/TextFieldSuggestionProvider.js +18 -0
- package/build/ft-text-field.d.ts +8 -2
- package/build/ft-text-field.js +86 -34
- package/build/ft-text-field.light.js +137 -127
- package/build/ft-text-field.min.js +109 -99
- package/build/ft-text-field.properties.d.ts +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/models.d.ts +7 -0
- package/build/models.js +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function basicSuggestionsProvider(values, maxSuggest = 20) {
|
|
2
|
+
return (query) => values.map(value => typeof value == "string" ? ({ value: value, label: value }) : value)
|
|
3
|
+
.filter(v => v.label.toLowerCase().includes(query.toLowerCase()))
|
|
4
|
+
.sort((a, b) => alphabeticalSortWithPriorToStartWithQuery(a.label, b.label, query))
|
|
5
|
+
.slice(0, maxSuggest);
|
|
6
|
+
}
|
|
7
|
+
function alphabeticalSortWithPriorToStartWithQuery(a, b, query) {
|
|
8
|
+
const lowerA = a.toLowerCase();
|
|
9
|
+
const lowerB = b.toLowerCase();
|
|
10
|
+
const lowerQuery = query.toLowerCase();
|
|
11
|
+
if (lowerA.startsWith(lowerQuery) && !lowerB.includes(lowerQuery)) {
|
|
12
|
+
return -1;
|
|
13
|
+
}
|
|
14
|
+
if (lowerB.startsWith(lowerQuery) && !lowerA.startsWith(lowerQuery)) {
|
|
15
|
+
return 1;
|
|
16
|
+
}
|
|
17
|
+
return lowerA.localeCompare(lowerB);
|
|
18
|
+
}
|
package/build/ft-text-field.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { PropertyValues } from "lit";
|
|
|
2
2
|
import { ElementDefinitionsMap, FtLitElement } from "@fluid-topics/ft-wc-utils";
|
|
3
3
|
import { FtTextFieldProperties } from "./ft-text-field.properties";
|
|
4
4
|
import { FtTextFieldSuggestion } from "./ft-text-field-suggestion";
|
|
5
|
+
import { FtTextFieldSuggestionDefinition } from "./models";
|
|
5
6
|
declare const FtTextField_base: import("@fluid-topics/ft-wc-utils").FtFormComponentType<typeof FtLitElement>;
|
|
6
7
|
export declare class FtTextField extends FtTextField_base implements FtTextFieldProperties {
|
|
7
8
|
static elementDefinitions: ElementDefinitionsMap;
|
|
@@ -29,22 +30,26 @@ export declare class FtTextField extends FtTextField_base implements FtTextField
|
|
|
29
30
|
maxLength?: number;
|
|
30
31
|
password: boolean;
|
|
31
32
|
autocomplete?: string;
|
|
33
|
+
suggestionsProvider?: (query: string) => FtTextFieldSuggestionDefinition[] | Promise<FtTextFieldSuggestionDefinition[]>;
|
|
32
34
|
focused: boolean;
|
|
33
35
|
hidePassword: boolean;
|
|
34
36
|
hideSuggestions: boolean;
|
|
35
37
|
visibleSuggestions: FtTextFieldSuggestion[];
|
|
38
|
+
providedSuggestions: FtTextFieldSuggestionDefinition[];
|
|
36
39
|
mainPanel?: HTMLElement;
|
|
37
40
|
input?: HTMLInputElement;
|
|
38
41
|
newValueSuggestion?: FtTextFieldSuggestion;
|
|
39
42
|
suggestionsContainer?: HTMLElement;
|
|
40
|
-
|
|
43
|
+
providedSuggestionsInDom: FtTextFieldSuggestion[];
|
|
44
|
+
slottedSuggestions: FtTextFieldSuggestion[];
|
|
41
45
|
focus(): void;
|
|
42
|
-
constructor();
|
|
43
46
|
protected render(): import("lit").TemplateResult<1>;
|
|
44
47
|
private resolveInputType;
|
|
48
|
+
private renderSuggestions;
|
|
45
49
|
private renderPasswordIcon;
|
|
46
50
|
private renderIcon;
|
|
47
51
|
protected update(props: PropertyValues): void;
|
|
52
|
+
private updateSuggestions;
|
|
48
53
|
private filterSuggestionsIfNeeded;
|
|
49
54
|
protected contentAvailableCallback(props: PropertyValues): void;
|
|
50
55
|
private watchAutofillInterval?;
|
|
@@ -62,5 +67,6 @@ export declare class FtTextField extends FtTextField_base implements FtTextField
|
|
|
62
67
|
private togglePasswordVisibility;
|
|
63
68
|
private isPasswordField;
|
|
64
69
|
private setSuggestionPosition;
|
|
70
|
+
private suggestionsShouldBeDisplayed;
|
|
65
71
|
}
|
|
66
72
|
export {};
|
package/build/ft-text-field.js
CHANGED
|
@@ -5,7 +5,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html, nothing } from "lit";
|
|
8
|
-
import { property, query, queryAssignedElements, state } from "lit/decorators.js";
|
|
8
|
+
import { property, query, queryAll, queryAssignedElements, state } from "lit/decorators.js";
|
|
9
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
9
10
|
import { classMap } from "lit/directives/class-map.js";
|
|
10
11
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
11
12
|
import { computeFlipOffsetPosition, FtLitElement, noTextInputDefaultClearButton, toFtFormComponent } from "@fluid-topics/ft-wc-utils";
|
|
@@ -16,6 +17,25 @@ import { FtIcon, FtIcons } from "@fluid-topics/ft-icon";
|
|
|
16
17
|
import { FtTextFieldCssVariables, styles } from "./ft-text-field.styles";
|
|
17
18
|
import { FtTextFieldSuggestion } from "./ft-text-field-suggestion";
|
|
18
19
|
class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
20
|
+
constructor() {
|
|
21
|
+
super(...arguments);
|
|
22
|
+
this._value = "";
|
|
23
|
+
this.dispatchedValue = "";
|
|
24
|
+
this.outlined = false;
|
|
25
|
+
this.disabled = false;
|
|
26
|
+
this.error = false;
|
|
27
|
+
this.fixedMenuPosition = false;
|
|
28
|
+
this.prefix = null;
|
|
29
|
+
this.passwordHiddenIcon = FtIcons.EYE_SLASH;
|
|
30
|
+
this.passwordRevealedIcon = FtIcons.EYE;
|
|
31
|
+
this.filterSuggestions = false;
|
|
32
|
+
this.password = false;
|
|
33
|
+
this.focused = false;
|
|
34
|
+
this.hidePassword = true;
|
|
35
|
+
this.hideSuggestions = false;
|
|
36
|
+
this.visibleSuggestions = [];
|
|
37
|
+
this.providedSuggestions = [];
|
|
38
|
+
}
|
|
19
39
|
/*
|
|
20
40
|
* We prevent lit from creating setter and getter to differentiate
|
|
21
41
|
* when the value change comes from inside or outside the component
|
|
@@ -40,24 +60,6 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
40
60
|
var _a;
|
|
41
61
|
(_a = this.input) === null || _a === void 0 ? void 0 : _a.focus();
|
|
42
62
|
}
|
|
43
|
-
constructor() {
|
|
44
|
-
super();
|
|
45
|
-
this._value = "";
|
|
46
|
-
this.dispatchedValue = "";
|
|
47
|
-
this.outlined = false;
|
|
48
|
-
this.disabled = false;
|
|
49
|
-
this.error = false;
|
|
50
|
-
this.fixedMenuPosition = false;
|
|
51
|
-
this.prefix = null;
|
|
52
|
-
this.passwordHiddenIcon = FtIcons.EYE_SLASH;
|
|
53
|
-
this.passwordRevealedIcon = FtIcons.EYE;
|
|
54
|
-
this.filterSuggestions = false;
|
|
55
|
-
this.password = false;
|
|
56
|
-
this.focused = false;
|
|
57
|
-
this.hidePassword = true;
|
|
58
|
-
this.hideSuggestions = false;
|
|
59
|
-
this.visibleSuggestions = [];
|
|
60
|
-
}
|
|
61
63
|
render() {
|
|
62
64
|
const classes = {
|
|
63
65
|
"ft-text-field": true,
|
|
@@ -69,11 +71,14 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
69
71
|
"ft-text-field--in-error": this.error,
|
|
70
72
|
"ft-text-field--fixed": this.fixedMenuPosition,
|
|
71
73
|
"ft-text-field--with-prefix": !!this.prefix,
|
|
72
|
-
"ft-text-field--hide-suggestions": this.
|
|
74
|
+
"ft-text-field--hide-suggestions": !this.suggestionsShouldBeDisplayed(),
|
|
73
75
|
"ft-text-field--raised-label": this.focused || this.value != "",
|
|
74
76
|
"ft-text-field--with-icon": !!this.icon,
|
|
75
77
|
"ft-text-field--with-password": this.isPasswordField()
|
|
76
78
|
};
|
|
79
|
+
const suggestionsAreProvidedAndQueryNotInPossiblesValues = this.suggestionsProvider && this.value && this.value != "" && !this.providedSuggestions.map(p => p.label).includes(this.value);
|
|
80
|
+
const suggestionsFromSlotAndQueryNotEmpty = !this.suggestionsProvider && this.filterSuggestions && this.value && this.value != "";
|
|
81
|
+
const shouldDisplayQueryAsNewSuggestion = suggestionsFromSlotAndQueryNotEmpty || suggestionsAreProvidedAndQueryNotInPossiblesValues;
|
|
77
82
|
return html `
|
|
78
83
|
<div class="${classMap(classes)}">
|
|
79
84
|
<div class="ft-text-field--main-panel"
|
|
@@ -109,12 +114,14 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
109
114
|
</div>
|
|
110
115
|
<div class="ft-text-field--suggestions"
|
|
111
116
|
@suggestion-selected=${this.onSuggestionSelected}>
|
|
112
|
-
|
|
113
|
-
${
|
|
114
|
-
|
|
115
|
-
${this.
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
${this.renderSuggestions()}
|
|
118
|
+
${shouldDisplayQueryAsNewSuggestion
|
|
119
|
+
? html `
|
|
120
|
+
<ft-text-field-suggestion class="ft-text-field-suggestion--new-value" helper="${this.suggestionsHelper}">
|
|
121
|
+
${this.value}
|
|
122
|
+
</ft-text-field-suggestion>
|
|
123
|
+
`
|
|
124
|
+
: nothing}
|
|
118
125
|
</div>
|
|
119
126
|
</div>
|
|
120
127
|
${this.helper ? html `
|
|
@@ -132,6 +139,25 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
132
139
|
}
|
|
133
140
|
return (_a = this.type) !== null && _a !== void 0 ? _a : "text";
|
|
134
141
|
}
|
|
142
|
+
renderSuggestions() {
|
|
143
|
+
if (this.suggestionsProvider) {
|
|
144
|
+
return html `
|
|
145
|
+
${repeat(this.providedSuggestions, suggestion => html `
|
|
146
|
+
<ft-text-field-suggestion value=${suggestion.value} @click=${suggestion.clickHandler}>
|
|
147
|
+
${suggestion.icon ? html `
|
|
148
|
+
<ft-icon .value=${suggestion.icon}></ft-icon>
|
|
149
|
+
`
|
|
150
|
+
: nothing}
|
|
151
|
+
${suggestion.label}
|
|
152
|
+
</ft-text-field-suggestion>`)}
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
return html `
|
|
157
|
+
<slot @slotchange=${() => this.filterSuggestionsIfNeeded()}></slot>
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
135
161
|
renderPasswordIcon() {
|
|
136
162
|
return html `
|
|
137
163
|
<ft-icon class="ft-text-field--icon"
|
|
@@ -153,8 +179,11 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
153
179
|
}
|
|
154
180
|
update(props) {
|
|
155
181
|
super.update(props);
|
|
156
|
-
if (props.has("value")
|
|
157
|
-
|
|
182
|
+
if (props.has("value")
|
|
183
|
+
|| props.has("filterSuggestions")
|
|
184
|
+
|| props.has("suggestionsProvider")
|
|
185
|
+
|| props.has("hideSuggestions")) {
|
|
186
|
+
this.updateSuggestions();
|
|
158
187
|
}
|
|
159
188
|
if (props.has("value") && props.get("value") != null) {
|
|
160
189
|
this.hideSuggestions = false;
|
|
@@ -162,17 +191,22 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
162
191
|
if (props.has("dispatchedValue") && props.get("dispatchedValue") != null) {
|
|
163
192
|
this.hideSuggestions = true;
|
|
164
193
|
}
|
|
165
|
-
|
|
166
|
-
|
|
194
|
+
}
|
|
195
|
+
async updateSuggestions() {
|
|
196
|
+
if (this.suggestionsProvider) {
|
|
197
|
+
this.providedSuggestions = await this.suggestionsProvider(this.value);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
this.filterSuggestionsIfNeeded();
|
|
167
201
|
}
|
|
168
202
|
}
|
|
169
203
|
filterSuggestionsIfNeeded() {
|
|
170
204
|
if (this.filterSuggestions) {
|
|
171
|
-
this.
|
|
172
|
-
this.visibleSuggestions = this.
|
|
205
|
+
this.slottedSuggestions.forEach(s => s.hidden = !s.getValue().toLowerCase().includes(this.value.toLowerCase()));
|
|
206
|
+
this.visibleSuggestions = this.slottedSuggestions.filter(s => !s.hidden);
|
|
173
207
|
}
|
|
174
208
|
else {
|
|
175
|
-
this.visibleSuggestions = this.
|
|
209
|
+
this.visibleSuggestions = this.slottedSuggestions;
|
|
176
210
|
}
|
|
177
211
|
if (this.newValueSuggestion) {
|
|
178
212
|
this.visibleSuggestions = [...this.visibleSuggestions, this.newValueSuggestion];
|
|
@@ -184,9 +218,15 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
184
218
|
if (props.has("focused") && !this.hideSuggestions && this.visibleSuggestions.length > 0) {
|
|
185
219
|
this.setSuggestionPosition();
|
|
186
220
|
}
|
|
221
|
+
if (props.has("value") && this.suggestionsProvider) {
|
|
222
|
+
this.visibleSuggestions = [...this.providedSuggestionsInDom];
|
|
223
|
+
}
|
|
187
224
|
if (props.has("autocomplete")) {
|
|
188
225
|
this.setupWatchAutofill();
|
|
189
226
|
}
|
|
227
|
+
if (this.suggestionsShouldBeDisplayed()) {
|
|
228
|
+
this.setSuggestionPosition();
|
|
229
|
+
}
|
|
190
230
|
}
|
|
191
231
|
setupWatchAutofill() {
|
|
192
232
|
var _a;
|
|
@@ -283,6 +323,9 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
283
323
|
this.suggestionsContainer.style.top = `${y}px`;
|
|
284
324
|
});
|
|
285
325
|
}
|
|
326
|
+
suggestionsShouldBeDisplayed() {
|
|
327
|
+
return !this.hideSuggestions && (this.visibleSuggestions.length || this.providedSuggestions.length);
|
|
328
|
+
}
|
|
286
329
|
}
|
|
287
330
|
FtTextField.elementDefinitions = {
|
|
288
331
|
"ft-input-label": FtInputLabel,
|
|
@@ -357,6 +400,9 @@ __decorate([
|
|
|
357
400
|
__decorate([
|
|
358
401
|
property({ type: String })
|
|
359
402
|
], FtTextField.prototype, "autocomplete", void 0);
|
|
403
|
+
__decorate([
|
|
404
|
+
property({ attribute: false })
|
|
405
|
+
], FtTextField.prototype, "suggestionsProvider", void 0);
|
|
360
406
|
__decorate([
|
|
361
407
|
state()
|
|
362
408
|
], FtTextField.prototype, "focused", void 0);
|
|
@@ -369,6 +415,9 @@ __decorate([
|
|
|
369
415
|
__decorate([
|
|
370
416
|
state()
|
|
371
417
|
], FtTextField.prototype, "visibleSuggestions", void 0);
|
|
418
|
+
__decorate([
|
|
419
|
+
state()
|
|
420
|
+
], FtTextField.prototype, "providedSuggestions", void 0);
|
|
372
421
|
__decorate([
|
|
373
422
|
query(".ft-text-field--main-panel")
|
|
374
423
|
], FtTextField.prototype, "mainPanel", void 0);
|
|
@@ -381,7 +430,10 @@ __decorate([
|
|
|
381
430
|
__decorate([
|
|
382
431
|
query(".ft-text-field--suggestions")
|
|
383
432
|
], FtTextField.prototype, "suggestionsContainer", void 0);
|
|
433
|
+
__decorate([
|
|
434
|
+
queryAll("ft-text-field-suggestion")
|
|
435
|
+
], FtTextField.prototype, "providedSuggestionsInDom", void 0);
|
|
384
436
|
__decorate([
|
|
385
437
|
queryAssignedElements({ selector: "ft-text-field-suggestion" })
|
|
386
|
-
], FtTextField.prototype, "
|
|
438
|
+
], FtTextField.prototype, "slottedSuggestions", void 0);
|
|
387
439
|
export { FtTextField };
|