@fluid-topics/ft-text-field 2.2.8 → 2.2.10

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.
@@ -3,18 +3,27 @@ import { FtTextFieldSuggestionProperties } from "./ft-text-field-suggestion.prop
3
3
  export declare class SuggestionSelectedEvent extends CustomEvent<string> {
4
4
  constructor(value: string);
5
5
  }
6
+ export declare class SuggestionRemovedEvent extends CustomEvent<string> {
7
+ constructor(value: string);
8
+ }
6
9
  export declare class FtTextFieldSuggestion extends FtLitElement implements FtTextFieldSuggestionProperties {
7
10
  static elementDefinitions: ElementDefinitionsMap;
8
11
  value?: string;
9
12
  helper?: string;
10
- private container?;
13
+ removable: boolean;
14
+ removeButtonLabel?: string;
15
+ private suggestion?;
16
+ private removeButton?;
11
17
  private assignedNodes;
12
18
  static styles: import("lit").CSSResult;
13
19
  render(): import("lit-html").TemplateResult<1>;
14
- focus(options?: FocusOptions): void;
15
- click(): void;
16
- private confirmSuggestion;
20
+ focus(options?: FocusOptions, targetRemoveButton?: boolean): void;
21
+ click(targetRemoveButton?: boolean): void;
22
+ isRemoveButtonFocused(): boolean;
23
+ private selectSuggestion;
24
+ private removeSuggestion;
17
25
  getValue(): string;
18
26
  getTextContent(): string;
19
- private onKeyDown;
27
+ private suggestionKeyDown;
28
+ private removeButtonKeyDown;
20
29
  }
@@ -8,61 +8,126 @@ import { FtLitElement, } from "@fluid-topics/ft-wc-utils";
8
8
  import { html, nothing, } from "lit";
9
9
  import { property, query, queryAssignedNodes, } from "lit/decorators.js";
10
10
  import { FtRipple } from "@fluid-topics/ft-ripple";
11
- import { FtTypography } from "@fluid-topics/ft-typography";
11
+ import { FtTypography, FtTypographyVariants, } from "@fluid-topics/ft-typography";
12
12
  import { suggestionStyles } from "./ft-text-field-suggestion.styles";
13
- import { FtIcon } from "@fluid-topics/ft-icon";
13
+ import { FtIcon, FtIcons, } from "@fluid-topics/ft-icon";
14
14
  import { classMap } from "lit/directives/class-map.js";
15
+ import { FtButton } from "@fluid-topics/ft-button";
15
16
  export class SuggestionSelectedEvent extends CustomEvent {
16
17
  constructor(value) {
17
18
  super("suggestion-selected", { detail: value, bubbles: true, composed: true });
18
19
  }
19
20
  }
21
+ export class SuggestionRemovedEvent extends CustomEvent {
22
+ constructor(value) {
23
+ super("suggestion-removed", { detail: value, bubbles: true, composed: true });
24
+ }
25
+ }
20
26
  export class FtTextFieldSuggestion extends FtLitElement {
27
+ constructor() {
28
+ super(...arguments);
29
+ this.removable = false;
30
+ }
21
31
  render() {
22
32
  const classes = {
23
33
  "ft-text-field-suggestion": true,
24
34
  "ft-text-field-suggestion--with-helper": !!this.helper,
25
35
  };
26
36
  return html `
27
- <div class="${classMap(classes)}"
28
- tabindex="-1"
29
- @keydown=${this.onKeyDown}
30
- @click=${this.confirmSuggestion}>
31
- <ft-ripple></ft-ripple>
32
- ${this.helper ? html `
33
- <ft-typography class="ft-text-field-suggestion--helper-text" variant="caption">
34
- ${this.helper}
35
- </ft-typography>` : nothing}
36
- <ft-typography part="label"
37
- variant="body1"
38
- class="ft-text-field-suggestion--label">
39
- <slot></slot>
40
- </ft-typography>
37
+ <div class="${classMap(classes)}">
38
+ <div
39
+ class="ft-text-field-suggestion--suggestion"
40
+ tabindex="-1"
41
+ @keydown=${this.suggestionKeyDown}
42
+ @click=${this.selectSuggestion}
43
+ >
44
+ <ft-ripple></ft-ripple>
45
+ ${this.helper ? html `
46
+ <ft-typography class="ft-text-field-suggestion--helper-text" variant="caption">
47
+ ${this.helper}
48
+ </ft-typography>` : nothing}
49
+ <ft-typography part="label"
50
+ variant="${FtTypographyVariants.body1}"
51
+ class="ft-text-field-suggestion--label">
52
+ <slot></slot>
53
+ </ft-typography>
54
+ </div>
55
+ ${this.removable ? html `
56
+ <ft-button icon="${FtIcons.CLOSE}"
57
+ part="remove-button"
58
+ class="ft-text-field-suggestion--remove"
59
+ round
60
+ label="${this.removeButtonLabel}"
61
+ tooltipPosition="left"
62
+ tabindex="-1"
63
+ @keydown=${this.removeButtonKeyDown}
64
+ @click=${this.removeSuggestion}>
65
+ </ft-button>
66
+ ` : nothing}
41
67
  </div>
42
68
  `;
43
69
  }
44
- focus(options) {
45
- var _a;
46
- (_a = this.container) === null || _a === void 0 ? void 0 : _a.focus(options);
70
+ focus(options, targetRemoveButton) {
71
+ var _a, _b;
72
+ if (targetRemoveButton && this.removable) {
73
+ (_a = this.removeButton) === null || _a === void 0 ? void 0 : _a.focus();
74
+ }
75
+ else {
76
+ (_b = this.suggestion) === null || _b === void 0 ? void 0 : _b.focus(options);
77
+ }
47
78
  }
48
- click() {
79
+ click(targetRemoveButton) {
49
80
  var _a;
50
- (_a = this.container) === null || _a === void 0 ? void 0 : _a.click();
81
+ (_a = (targetRemoveButton ? this.removeButton : this.suggestion)) === null || _a === void 0 ? void 0 : _a.click();
51
82
  }
52
- confirmSuggestion() {
83
+ isRemoveButtonFocused() {
84
+ var _a, _b;
85
+ return (_b = (_a = this.removeButton) === null || _a === void 0 ? void 0 : _a.matches(":focus-within")) !== null && _b !== void 0 ? _b : false;
86
+ }
87
+ selectSuggestion() {
53
88
  this.dispatchEvent(new SuggestionSelectedEvent(this.getValue()));
54
89
  }
90
+ removeSuggestion() {
91
+ this.dispatchEvent(new SuggestionRemovedEvent(this.getValue()));
92
+ }
55
93
  getValue() {
56
94
  return this.value || this.getTextContent();
57
95
  }
58
96
  getTextContent() {
59
97
  return this.assignedNodes.map((n) => n.textContent).join("").trim();
60
98
  }
61
- onKeyDown(event) {
62
- if (["Enter", " "].includes(event.key)) {
63
- event.preventDefault();
64
- event.stopPropagation();
65
- this.confirmSuggestion();
99
+ suggestionKeyDown(event) {
100
+ var _a;
101
+ switch (event.key) {
102
+ case "Enter":
103
+ case " ":
104
+ event.preventDefault();
105
+ event.stopPropagation();
106
+ this.selectSuggestion();
107
+ break;
108
+ case "ArrowRight":
109
+ if (this.removable) {
110
+ event.preventDefault();
111
+ event.stopPropagation();
112
+ (_a = this.removeButton) === null || _a === void 0 ? void 0 : _a.focus();
113
+ }
114
+ break;
115
+ }
116
+ }
117
+ removeButtonKeyDown(event) {
118
+ var _a;
119
+ switch (event.key) {
120
+ case "Enter":
121
+ case " ":
122
+ event.preventDefault();
123
+ event.stopPropagation();
124
+ this.removeSuggestion();
125
+ break;
126
+ case "ArrowLeft":
127
+ event.preventDefault();
128
+ event.stopPropagation();
129
+ (_a = this.suggestion) === null || _a === void 0 ? void 0 : _a.focus();
130
+ break;
66
131
  }
67
132
  }
68
133
  }
@@ -70,6 +135,7 @@ FtTextFieldSuggestion.elementDefinitions = {
70
135
  "ft-ripple": FtRipple,
71
136
  "ft-typography": FtTypography,
72
137
  "ft-icon": FtIcon,
138
+ "ft-button": FtButton,
73
139
  };
74
140
  FtTextFieldSuggestion.styles = suggestionStyles;
75
141
  __decorate([
@@ -79,8 +145,17 @@ __decorate([
79
145
  property()
80
146
  ], FtTextFieldSuggestion.prototype, "helper", void 0);
81
147
  __decorate([
82
- query(".ft-text-field-suggestion")
83
- ], FtTextFieldSuggestion.prototype, "container", void 0);
148
+ property({ type: Boolean })
149
+ ], FtTextFieldSuggestion.prototype, "removable", void 0);
150
+ __decorate([
151
+ property()
152
+ ], FtTextFieldSuggestion.prototype, "removeButtonLabel", void 0);
153
+ __decorate([
154
+ query(".ft-text-field-suggestion--suggestion")
155
+ ], FtTextFieldSuggestion.prototype, "suggestion", void 0);
156
+ __decorate([
157
+ query(".ft-text-field-suggestion--remove")
158
+ ], FtTextFieldSuggestion.prototype, "removeButton", void 0);
84
159
  __decorate([
85
160
  queryAssignedNodes()
86
161
  ], FtTextFieldSuggestion.prototype, "assignedNodes", void 0);
@@ -2,28 +2,34 @@ import { css } from "lit";
2
2
  import { FtTextFieldCssVariables } from "./ft-text-field.styles";
3
3
  // language=CSS
4
4
  export const suggestionStyles = css `
5
- .ft-text-field-suggestion {
5
+ .ft-text-field-suggestion--suggestion {
6
6
  position: relative;
7
7
  padding: 8px 16px;
8
8
  cursor: pointer;
9
9
  min-height: 44px;
10
10
  box-sizing: border-box;
11
+ }
12
+
13
+ .ft-text-field-suggestion--suggestion,
14
+ .ft-text-field-suggestion--remove {
11
15
  outline: none;
12
16
  }
13
17
 
14
18
  .ft-text-field-suggestion,
19
+ .ft-text-field-suggestion--suggestion,
15
20
  .ft-text-field-suggestion--label {
16
21
  display: flex;
17
22
  align-items: center;
18
- gap: 8px;
19
23
  }
20
24
 
25
+ .ft-text-field-suggestion--suggestion,
21
26
  .ft-text-field-suggestion--label {
22
27
  flex-grow: 1;
23
28
  flex-shrink: 1;
29
+ gap: 8px;
24
30
  }
25
31
 
26
- .ft-text-field-suggestion--with-helper {
32
+ .ft-text-field-suggestion--with-helper > .ft-text-field-suggestion--suggestion {
27
33
  display: flex;
28
34
  flex-direction: column;
29
35
  align-items: flex-start;
@@ -49,7 +49,6 @@ export declare class FtTextField extends FtTextField_base implements FtTextField
49
49
  protected render(): import("lit-html").TemplateResult<1>;
50
50
  private resolveInputType;
51
51
  private renderSuggestions;
52
- private onSuggestionClick;
53
52
  private renderPasswordIcon;
54
53
  private renderIcon;
55
54
  protected update(props: PropertyValues): void;
@@ -68,6 +67,7 @@ export declare class FtTextField extends FtTextField_base implements FtTextField
68
67
  private handleClick;
69
68
  private handleKeyboardNavigation;
70
69
  private onSuggestionSelected;
70
+ private onSuggestionRemoved;
71
71
  private onFocus;
72
72
  private onMainPanelBlur;
73
73
  private togglePasswordVisibility;
@@ -127,7 +127,9 @@ export class FtTextField extends toFtFormComponent(FtLitElement) {
127
127
  </div>
128
128
  <div class="ft-text-field--suggestions"
129
129
  part="suggestions"
130
- @suggestion-selected=${this.onSuggestionSelected}>
130
+ @suggestion-selected=${this.onSuggestionSelected}
131
+ @suggestion-removed=${this.onSuggestionRemoved}
132
+ >
131
133
  ${this.renderSuggestions()}
132
134
  ${!this.hideCurrentValueSuggestion && shouldDisplayQueryAsNewSuggestion
133
135
  ? html `
@@ -159,15 +161,19 @@ export class FtTextField extends toFtFormComponent(FtLitElement) {
159
161
  renderSuggestions() {
160
162
  if (this.suggestionsProvider) {
161
163
  return html `
162
- ${repeat(this.providedSuggestions, (suggestion) => html `
163
- <ft-text-field-suggestion part="suggestion" value="${suggestion.value}" @click=${(e) => this.onSuggestionClick(e, suggestion.clickHandler)}>
164
- ${suggestion.icon ? html `
165
- <ft-icon .value=${suggestion.icon}></ft-icon>
166
- `
167
- : nothing}
164
+ ${repeat(this.providedSuggestions, (suggestion) => {
165
+ var _a;
166
+ return html `
167
+ <ft-text-field-suggestion part="suggestion"
168
+ value="${suggestion.value}"
169
+ ?removable=${suggestion.removable} }
170
+ removeButtonLabel="${(_a = suggestion.removeButtonLabel) !== null && _a !== void 0 ? _a : nothing}"
171
+ >
172
+ ${suggestion.icon ? html `<ft-icon .value=${suggestion.icon}></ft-icon>` : nothing}
168
173
  ${suggestion.label}
169
174
  </ft-text-field-suggestion>
170
- `)}
175
+ `;
176
+ })}
171
177
  `;
172
178
  }
173
179
  else {
@@ -176,12 +182,6 @@ export class FtTextField extends toFtFormComponent(FtLitElement) {
176
182
  `;
177
183
  }
178
184
  }
179
- onSuggestionClick(event, handler) {
180
- if (handler) {
181
- event.preventDefault();
182
- handler(event);
183
- }
184
- }
185
185
  renderPasswordIcon() {
186
186
  return html `
187
187
  <ft-icon class="ft-text-field--icon"
@@ -251,7 +251,7 @@ export class FtTextField extends toFtFormComponent(FtLitElement) {
251
251
  if (props.has("focused") && !this.hideSuggestions && this.visibleSuggestions.length > 0) {
252
252
  this.setSuggestionPosition();
253
253
  }
254
- if (props.has("value") && this.suggestionsProvider) {
254
+ if (props.has("providedSuggestions")) {
255
255
  this.visibleSuggestions = [...this.providedSuggestionsInDom];
256
256
  }
257
257
  if (props.has("autocomplete")) {
@@ -316,12 +316,12 @@ export class FtTextField extends toFtFormComponent(FtLitElement) {
316
316
  this.hideSuggestions = false;
317
317
  }
318
318
  handleKeyboardNavigation(event) {
319
- var _a;
319
+ var _a, _b;
320
320
  if ((event.key === "ArrowDown" || event.key === "ArrowUp")) {
321
321
  event.preventDefault();
322
322
  event.stopPropagation();
323
323
  this.hideSuggestions = false;
324
- const currentSuggestion = this.visibleSuggestions.findIndex((element) => element.matches((":focus-within")));
324
+ const currentSuggestion = this.visibleSuggestions.findIndex((element) => element.matches(":focus-within"));
325
325
  let target;
326
326
  if (event.key === "ArrowDown") {
327
327
  target = currentSuggestion < this.visibleSuggestions.length - 1 ? currentSuggestion + 1 : 0;
@@ -329,7 +329,7 @@ export class FtTextField extends toFtFormComponent(FtLitElement) {
329
329
  else {
330
330
  target = currentSuggestion > 0 ? currentSuggestion - 1 : this.visibleSuggestions.length - 1;
331
331
  }
332
- (_a = this.visibleSuggestions[target]) === null || _a === void 0 ? void 0 : _a.focus();
332
+ (_a = this.visibleSuggestions[target]) === null || _a === void 0 ? void 0 : _a.focus(undefined, (_b = this.visibleSuggestions[currentSuggestion]) === null || _b === void 0 ? void 0 : _b.isRemoveButtonFocused());
333
333
  }
334
334
  if (event.key == "Escape" || event.key == "Enter") {
335
335
  this.hideSuggestions = true;
@@ -341,6 +341,10 @@ export class FtTextField extends toFtFormComponent(FtLitElement) {
341
341
  (_a = this.input) === null || _a === void 0 ? void 0 : _a.focus();
342
342
  setTimeout(() => this.hideSuggestions = true, 0);
343
343
  }
344
+ onSuggestionRemoved() {
345
+ // update suggestions after all handlers processed the event
346
+ setTimeout(() => this.updateSuggestions());
347
+ }
344
348
  onFocus() {
345
349
  this.focused = true;
346
350
  this.hideSuggestions = false;