@fluid-topics/ft-text-field 1.2.28 → 1.2.30
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-suggestion.d.ts +1 -1
- package/build/ft-text-field.d.ts +9 -3
- package/build/ft-text-field.js +85 -34
- package/build/ft-text-field.light.js +151 -141
- package/build/ft-text-field.min.js +213 -233
- 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
|
+
}
|
|
@@ -10,7 +10,7 @@ export declare class FtTextFieldSuggestion extends FtLitElement implements FtTex
|
|
|
10
10
|
private container?;
|
|
11
11
|
private assignedNodes;
|
|
12
12
|
static styles: import("lit").CSSResult;
|
|
13
|
-
render(): import("lit").TemplateResult<1>;
|
|
13
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
14
14
|
focus(options?: FocusOptions): void;
|
|
15
15
|
click(): void;
|
|
16
16
|
private confirmSuggestion;
|
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
|
-
|
|
43
|
-
protected render(): import("lit").TemplateResult<1>;
|
|
46
|
+
protected render(): import("lit-html").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,10 @@ 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
|
+
this.updateSuggestions();
|
|
158
186
|
}
|
|
159
187
|
if (props.has("value") && props.get("value") != null) {
|
|
160
188
|
this.hideSuggestions = false;
|
|
@@ -162,17 +190,22 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
162
190
|
if (props.has("dispatchedValue") && props.get("dispatchedValue") != null) {
|
|
163
191
|
this.hideSuggestions = true;
|
|
164
192
|
}
|
|
165
|
-
|
|
166
|
-
|
|
193
|
+
}
|
|
194
|
+
async updateSuggestions() {
|
|
195
|
+
if (this.suggestionsProvider) {
|
|
196
|
+
this.providedSuggestions = await this.suggestionsProvider(this.value);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
this.filterSuggestionsIfNeeded();
|
|
167
200
|
}
|
|
168
201
|
}
|
|
169
202
|
filterSuggestionsIfNeeded() {
|
|
170
203
|
if (this.filterSuggestions) {
|
|
171
|
-
this.
|
|
172
|
-
this.visibleSuggestions = this.
|
|
204
|
+
this.slottedSuggestions.forEach(s => s.hidden = !s.getValue().toLowerCase().includes(this.value.toLowerCase()));
|
|
205
|
+
this.visibleSuggestions = this.slottedSuggestions.filter(s => !s.hidden);
|
|
173
206
|
}
|
|
174
207
|
else {
|
|
175
|
-
this.visibleSuggestions = this.
|
|
208
|
+
this.visibleSuggestions = this.slottedSuggestions;
|
|
176
209
|
}
|
|
177
210
|
if (this.newValueSuggestion) {
|
|
178
211
|
this.visibleSuggestions = [...this.visibleSuggestions, this.newValueSuggestion];
|
|
@@ -184,9 +217,15 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
184
217
|
if (props.has("focused") && !this.hideSuggestions && this.visibleSuggestions.length > 0) {
|
|
185
218
|
this.setSuggestionPosition();
|
|
186
219
|
}
|
|
220
|
+
if (props.has("value") && this.suggestionsProvider) {
|
|
221
|
+
this.visibleSuggestions = [...this.providedSuggestionsInDom];
|
|
222
|
+
}
|
|
187
223
|
if (props.has("autocomplete")) {
|
|
188
224
|
this.setupWatchAutofill();
|
|
189
225
|
}
|
|
226
|
+
if (this.suggestionsShouldBeDisplayed()) {
|
|
227
|
+
this.setSuggestionPosition();
|
|
228
|
+
}
|
|
190
229
|
}
|
|
191
230
|
setupWatchAutofill() {
|
|
192
231
|
var _a;
|
|
@@ -283,6 +322,9 @@ class FtTextField extends toFtFormComponent(FtLitElement, "textbox") {
|
|
|
283
322
|
this.suggestionsContainer.style.top = `${y}px`;
|
|
284
323
|
});
|
|
285
324
|
}
|
|
325
|
+
suggestionsShouldBeDisplayed() {
|
|
326
|
+
return !this.hideSuggestions && (this.visibleSuggestions.length || this.providedSuggestions.length);
|
|
327
|
+
}
|
|
286
328
|
}
|
|
287
329
|
FtTextField.elementDefinitions = {
|
|
288
330
|
"ft-input-label": FtInputLabel,
|
|
@@ -357,6 +399,9 @@ __decorate([
|
|
|
357
399
|
__decorate([
|
|
358
400
|
property({ type: String })
|
|
359
401
|
], FtTextField.prototype, "autocomplete", void 0);
|
|
402
|
+
__decorate([
|
|
403
|
+
property({ attribute: false })
|
|
404
|
+
], FtTextField.prototype, "suggestionsProvider", void 0);
|
|
360
405
|
__decorate([
|
|
361
406
|
state()
|
|
362
407
|
], FtTextField.prototype, "focused", void 0);
|
|
@@ -369,6 +414,9 @@ __decorate([
|
|
|
369
414
|
__decorate([
|
|
370
415
|
state()
|
|
371
416
|
], FtTextField.prototype, "visibleSuggestions", void 0);
|
|
417
|
+
__decorate([
|
|
418
|
+
state()
|
|
419
|
+
], FtTextField.prototype, "providedSuggestions", void 0);
|
|
372
420
|
__decorate([
|
|
373
421
|
query(".ft-text-field--main-panel")
|
|
374
422
|
], FtTextField.prototype, "mainPanel", void 0);
|
|
@@ -381,7 +429,10 @@ __decorate([
|
|
|
381
429
|
__decorate([
|
|
382
430
|
query(".ft-text-field--suggestions")
|
|
383
431
|
], FtTextField.prototype, "suggestionsContainer", void 0);
|
|
432
|
+
__decorate([
|
|
433
|
+
queryAll("ft-text-field-suggestion")
|
|
434
|
+
], FtTextField.prototype, "providedSuggestionsInDom", void 0);
|
|
384
435
|
__decorate([
|
|
385
436
|
queryAssignedElements({ selector: "ft-text-field-suggestion" })
|
|
386
|
-
], FtTextField.prototype, "
|
|
437
|
+
], FtTextField.prototype, "slottedSuggestions", void 0);
|
|
387
438
|
export { FtTextField };
|