@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.
@@ -0,0 +1,2 @@
1
+ import { FtTextFieldSuggestionDefinition } from "./models";
2
+ export declare function basicSuggestionsProvider(values: Array<string | FtTextFieldSuggestionDefinition>, maxSuggest?: number): (query: string) => FtTextFieldSuggestionDefinition[];
@@ -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;
@@ -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
- suggestions: FtTextFieldSuggestion[];
43
+ providedSuggestionsInDom: FtTextFieldSuggestion[];
44
+ slottedSuggestions: FtTextFieldSuggestion[];
41
45
  focus(): void;
42
- constructor();
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 {};
@@ -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.hideSuggestions || this.visibleSuggestions.length == 0,
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
- <slot @slotchange=${() => this.filterSuggestionsIfNeeded()}></slot>
113
- ${this.filterSuggestions && (this.value && this.value != "") ? html `
114
- <ft-text-field-suggestion class="ft-text-field-suggestion--new-value" helper="${this.suggestionsHelper}">
115
- ${this.value}
116
- </ft-text-field-suggestion>
117
- ` : nothing}
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") || props.has("filterSuggestions")) {
157
- this.filterSuggestionsIfNeeded();
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
- if (props.has("visibleSuggestions") && this.visibleSuggestions.length) {
166
- this.setSuggestionPosition();
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.suggestions.forEach(s => s.hidden = !s.getValue().toLowerCase().includes(this.value.toLowerCase()));
172
- this.visibleSuggestions = this.suggestions.filter(s => !s.hidden);
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.suggestions;
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, "suggestions", void 0);
437
+ ], FtTextField.prototype, "slottedSuggestions", void 0);
387
438
  export { FtTextField };