@fluid-topics/ft-combobox 1.3.26 → 1.3.28

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.
@@ -21,6 +21,7 @@ export declare class FtCombobox extends FtCombobox_base implements FtComboboxPro
21
21
  suggestionsProviderDebouncerTimeout?: number;
22
22
  private _value;
23
23
  get value(): string;
24
+ canOfferNewValue: boolean;
24
25
  set value(value: string);
25
26
  private filter;
26
27
  private isOpen;
@@ -71,9 +72,7 @@ export declare class FtCombobox extends FtCombobox_base implements FtComboboxPro
71
72
  private onComboboxFocus;
72
73
  private onComboboxBlur;
73
74
  private onBackgroundPointerUp;
74
- private onListboxPointerout;
75
75
  private onSuggestionClick;
76
- private onSuggestionPointerout;
77
76
  focus(): void;
78
77
  blur(): void;
79
78
  }
@@ -9,6 +9,7 @@ import { property, query, state } from "lit/decorators.js";
9
9
  import { repeat } from "lit/directives/repeat.js";
10
10
  import { classMap } from "lit/directives/class-map.js";
11
11
  import { ifDefined } from "lit/directives/if-defined.js";
12
+ import { when } from "lit/directives/when.js";
12
13
  import { Debouncer, FtLitElement, numberProperty, screenReaderStyles } from "@fluid-topics/ft-wc-utils";
13
14
  import { styles } from "./ft-combobox.styles";
14
15
  import { FtInputLabel } from "@fluid-topics/ft-input-label";
@@ -35,6 +36,7 @@ class FtCombobox extends withI18n(FtLitElement) {
35
36
  this.outlined = false;
36
37
  this.suggestionsProvider = () => [];
37
38
  this._value = "";
39
+ this.canOfferNewValue = true;
38
40
  this.filter = "";
39
41
  this.isOpen = false;
40
42
  this.comboboxHasVisualFocus = false;
@@ -43,8 +45,15 @@ class FtCombobox extends withI18n(FtLitElement) {
43
45
  this.visibleSuggestions = [];
44
46
  this.activeIndex = -1;
45
47
  this.onComboboxInput = () => {
46
- this.filter = this.input.value;
48
+ const newValue = this.input.value;
49
+ const hadValue = this._value !== "";
50
+ this.filter = newValue;
47
51
  this.activeIndex = -1;
52
+ // Dispatch change event when clearing the field after having a value
53
+ if (hadValue && newValue === "") {
54
+ this._value = "";
55
+ this.dispatchChangeEvent();
56
+ }
48
57
  this.updateSuggestions();
49
58
  const total = this.getTotalSuggestionsCount();
50
59
  if (total > 0) {
@@ -157,16 +166,15 @@ class FtCombobox extends withI18n(FtLitElement) {
157
166
  this.removeVisualFocusAll();
158
167
  };
159
168
  this.onBackgroundPointerUp = (event) => {
160
- const target = event.target;
161
- if (!this.contains(target)) {
169
+ // Use composedPath to handle Shadow DOM correctly
170
+ const path = event.composedPath();
171
+ const clickedInside = path.includes(this);
172
+ if (!clickedInside) {
162
173
  this.comboboxHasVisualFocus = false;
163
174
  this.removeVisualFocusAll();
164
175
  setTimeout(() => this.closeListbox(true), 300); // Inspired from the WCAG examples
165
176
  }
166
177
  };
167
- this.onListboxPointerout = () => {
168
- setTimeout(() => this.closeListbox(false), 300); // Inspired from the WCAG examples
169
- };
170
178
  this.onSuggestionClick = (suggestion) => {
171
179
  var _a;
172
180
  if (suggestion.kind === "new") {
@@ -177,9 +185,6 @@ class FtCombobox extends withI18n(FtLitElement) {
177
185
  }
178
186
  this.closeListbox(true);
179
187
  };
180
- this.onSuggestionPointerout = () => {
181
- setTimeout(() => this.closeListbox(false), 300); // Inspired from the WCAG examples
182
- };
183
188
  this.addI18nContext(comboboxContext, defaultComboboxMessages);
184
189
  }
185
190
  willUpdate(props) {
@@ -249,16 +254,17 @@ class FtCombobox extends withI18n(FtLitElement) {
249
254
  <div class="sr-only" aria-live="polite" aria-atomic="true">
250
255
  ${this.renderLiveText()}
251
256
  </div>
252
- <ul
253
- id="combobox-listbox"
254
- class="${classMap(listboxClasses)}"
255
- role="listbox"
256
- aria-label="${this.label || "Options"}"
257
- data-visible="${this.isOpen}"
258
- @pointerout=${this.onListboxPointerout}
259
- >
260
- ${repeat(this.visibleSuggestions, (option) => option.id, (option, index) => this.renderSuggestion(option, index))}
261
- </ul>
257
+ ${when(this.visibleSuggestions.length > 0, () => html `
258
+ <ul
259
+ id="combobox-listbox"
260
+ class="${classMap(listboxClasses)}"
261
+ role="listbox"
262
+ aria-label="${this.label || "Options"}"
263
+ data-visible="${this.isOpen}"
264
+ >
265
+ ${repeat(this.visibleSuggestions, (option) => option.id, (option, index) => this.renderSuggestion(option, index))}
266
+ </ul>`)}
267
+
262
268
  </div>
263
269
  ${this.helper ? html `
264
270
  <ft-typography class="ft-combobox--helper-text" variant="caption">
@@ -287,8 +293,8 @@ class FtCombobox extends withI18n(FtLitElement) {
287
293
  class="ft-combobox--option ${suggestion.kind === "new" ? "ft-combobox--option-new-value" : ""}"
288
294
  role="option"
289
295
  aria-selected="${index === this.activeIndex}"
296
+ @pointerdown=${(e) => e.preventDefault()}
290
297
  @click=${() => this.onSuggestionClick(suggestion)}
291
- @pointerout=${this.onSuggestionPointerout}
292
298
  >
293
299
  ${(() => {
294
300
  const isNewValue = suggestion.kind === "new" && !!this.suggestionsHelper;
@@ -322,7 +328,9 @@ class FtCombobox extends withI18n(FtLitElement) {
322
328
  shouldOfferNew() {
323
329
  var _a;
324
330
  const currentValue = ((_a = this.input) === null || _a === void 0 ? void 0 : _a.value) || this.value || "";
325
- return currentValue !== "" && !this.providedSuggestions.some((o) => o.label === currentValue);
331
+ return currentValue !== ""
332
+ && !this.providedSuggestions.some((o) => o.label === currentValue)
333
+ && this.canOfferNewValue;
326
334
  }
327
335
  getTotalSuggestionsCount() {
328
336
  return this.visibleSuggestions.length;
@@ -448,7 +456,7 @@ class FtCombobox extends withI18n(FtLitElement) {
448
456
  }
449
457
  dispatchChangeEvent() {
450
458
  this.dispatchEvent(new CustomEvent("change", {
451
- detail: { value: this._value },
459
+ detail: this._value,
452
460
  bubbles: true,
453
461
  composed: true,
454
462
  }));
@@ -604,6 +612,9 @@ __decorate([
604
612
  __decorate([
605
613
  property({ noAccessor: true })
606
614
  ], FtCombobox.prototype, "value", null);
615
+ __decorate([
616
+ property({ type: Boolean })
617
+ ], FtCombobox.prototype, "canOfferNewValue", void 0);
607
618
  __decorate([
608
619
  state()
609
620
  ], FtCombobox.prototype, "filter", void 0);