@meetelise/chat 1.50.5 → 1.51.0

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.
@@ -871,7 +871,6 @@ export class TourScheduler extends LitElement {
871
871
  unit: selectedUnit,
872
872
  conversationTrackingId: this.leadSourceClient?.chatId ?? null,
873
873
  });
874
-
875
874
  const data = {
876
875
  referrer: document.referrer,
877
876
  email_address: this.email,
@@ -29,20 +29,47 @@ export class MESelect extends LitElement {
29
29
  @state()
30
30
  private activeOptionIndex: number | null = null;
31
31
 
32
+ @state()
33
+ private searchTerm = "";
34
+
32
35
  @query("#select", true)
33
36
  meSelect!: HTMLDivElement;
34
37
 
38
+ @query("#selectText", true)
39
+ selectInput!: HTMLInputElement;
40
+
35
41
  focus = (): void => {
36
- this.meSelect.focus();
42
+ this.selectInput.focus();
43
+ };
44
+
45
+ private closeSelect = (): void => {
46
+ this.isOpen = false;
47
+ this.searchTerm = "";
48
+ this.activeOption = null;
49
+ this.activeOptionIndex = null;
50
+ };
51
+
52
+ private openSelect = (): void => {
53
+ this.isOpen = true;
37
54
  };
38
55
 
39
56
  toggleSelect = (): void => {
40
57
  if (this.isOpen) {
41
- this.activeOption = null;
58
+ this.closeSelect();
59
+ } else {
60
+ this.openSelect();
61
+ this.selectInput.focus();
42
62
  }
43
- this.isOpen = !this.isOpen;
44
63
  };
45
64
 
65
+ private get visibleOptions(): MeSelectOption[] {
66
+ const searchTerm = this.searchTerm.trim().toLowerCase();
67
+ if (!searchTerm) return this.options;
68
+ return this.options.filter((option) =>
69
+ option.label.toLowerCase().includes(searchTerm)
70
+ );
71
+ }
72
+
46
73
  setSelectedOption = (option: MeSelectOption, closeSelect = true): void => {
47
74
  if (this.value !== option.value) {
48
75
  this.value = option.value;
@@ -51,8 +78,7 @@ export class MESelect extends LitElement {
51
78
  }
52
79
 
53
80
  if (closeSelect) {
54
- this.isOpen = !this.isOpen;
55
- this.activeOption = null;
81
+ this.closeSelect();
56
82
  }
57
83
 
58
84
  if (!this.value) {
@@ -86,6 +112,12 @@ export class MESelect extends LitElement {
86
112
  }
87
113
  }
88
114
 
115
+ private handleSearchInput = (e: Event): void => {
116
+ this.searchTerm = (e.target as HTMLInputElement).value;
117
+ this.activeOption = null;
118
+ this.activeOptionIndex = null;
119
+ };
120
+
89
121
  constructor() {
90
122
  super();
91
123
  // TODO: the current thing works, but want to investigate more. why doesn't it work with `this`?
@@ -94,8 +126,8 @@ export class MESelect extends LitElement {
94
126
  // – for example, to Window, Document, or some element in the main DOM – you should add the
95
127
  // listener in connectedCallback and remove it in disconnectedCallback." (https://lit.dev/docs/components/events/)
96
128
  document.addEventListener("click", (event: MouseEvent) => {
97
- if (!event.composedPath().includes(this.meSelect)) {
98
- this.isOpen = false;
129
+ if (!event.composedPath().includes(this)) {
130
+ this.closeSelect();
99
131
  }
100
132
  });
101
133
  }
@@ -120,6 +152,7 @@ export class MESelect extends LitElement {
120
152
  height: 14px;
121
153
  display: flex;
122
154
  align-items: center;
155
+ color: inherit;
123
156
  }
124
157
 
125
158
  ul {
@@ -215,6 +248,13 @@ export class MESelect extends LitElement {
215
248
  render(): TemplateResult {
216
249
  const activeIndex = this.activeOptionIndex;
217
250
  const accessibleName = this.placeholder ?? "Select";
251
+ const visibleOptions = this.visibleOptions;
252
+ const selectedLabel = this.options.find(
253
+ (o) => o.value === this.value
254
+ )?.label;
255
+ const inputValue = this.isOpen
256
+ ? this.searchTerm
257
+ : selectedLabel || this.value || "";
218
258
  return html`
219
259
  <div id="outer-select-container">
220
260
  <div
@@ -224,34 +264,24 @@ export class MESelect extends LitElement {
224
264
  ["webchat-font__desktop"]: !isMobile(),
225
265
  ["webchat-font__mobile"]: isMobile(),
226
266
  })}
227
- tabindex="0"
228
- role="combobox"
229
- aria-haspopup="listbox"
230
- aria-expanded=${this.isOpen ? "true" : "false"}
231
- aria-controls=${this.listboxId}
232
- aria-label=${accessibleName}
233
- aria-activedescendant=${this.isOpen && activeIndex != null
234
- ? this.optionId(activeIndex)
235
- : ""}
236
- @click=${() => (this.isOpen = !this.isOpen)}
267
+ @mousedown=${(e: MouseEvent) => {
268
+ if (e.target !== this.selectInput) e.preventDefault();
269
+ }}
270
+ @click=${this.toggleSelect}
237
271
  @keydown="${(e: KeyboardEvent) => {
238
272
  switch (e.key) {
239
273
  case "Enter":
240
- case " ":
241
274
  e.preventDefault();
242
275
  if (this.isOpen && this.activeOption) {
243
276
  this.setSelectedOption(this.activeOption);
244
- } else {
245
- this.toggleSelect();
277
+ } else if (!this.isOpen) {
278
+ this.openSelect();
246
279
  }
247
280
  break;
248
281
  case "Escape":
249
- e.preventDefault();
250
- this.isOpen = false;
251
- break;
252
- case "Tab":
253
282
  if (this.isOpen) {
254
283
  e.preventDefault();
284
+ this.closeSelect();
255
285
  }
256
286
  break;
257
287
  case "ArrowUp":
@@ -261,41 +291,55 @@ export class MESelect extends LitElement {
261
291
  0,
262
292
  this.activeOptionIndex - 1
263
293
  );
264
- this.activeOption = this.options[this.activeOptionIndex];
294
+ this.activeOption = visibleOptions[this.activeOptionIndex];
265
295
  this.adjustScrollToActiveOption();
266
296
  }
267
297
  break;
268
-
269
298
  case "ArrowDown":
270
299
  e.preventDefault();
271
- if (this.isOpen) {
300
+ if (this.isOpen && visibleOptions.length > 0) {
272
301
  if (this.activeOptionIndex == null) {
273
302
  this.activeOptionIndex = 0;
274
- } else if (this.activeOptionIndex < this.options.length - 1) {
303
+ } else if (
304
+ this.activeOptionIndex <
305
+ visibleOptions.length - 1
306
+ ) {
275
307
  this.activeOptionIndex++;
276
308
  }
277
- this.activeOption = this.options[this.activeOptionIndex];
309
+ this.activeOption = visibleOptions[this.activeOptionIndex];
278
310
  this.adjustScrollToActiveOption();
279
311
  }
280
312
  break;
281
313
  }
282
314
  }}"
283
315
  >
284
- ${this.options.find((o) => o.value === this.value)?.label
285
- ? html` <span id="selectText"
286
- >${this.options.find((o) => o.value === this.value)?.label ??
287
- this.placeholder}</span
288
- >`
289
- : html` <input
290
- readonly
291
- tabindex="-1"
292
- placeholder="${this.placeholder}"
293
- .value="${this.options.find((o) => o.value === this.value)
294
- ?.label ||
295
- this.value ||
296
- ""}"
297
- id="selectText"
298
- />`}
316
+ <input
317
+ id="selectText"
318
+ role="combobox"
319
+ aria-haspopup="listbox"
320
+ aria-expanded=${this.isOpen ? "true" : "false"}
321
+ aria-controls=${this.listboxId}
322
+ aria-label=${accessibleName}
323
+ aria-autocomplete="list"
324
+ aria-activedescendant=${this.isOpen && activeIndex != null
325
+ ? this.optionId(activeIndex)
326
+ : ""}
327
+ autocomplete="off"
328
+ ?readonly=${!this.isOpen}
329
+ .value=${inputValue}
330
+ placeholder=${this.isOpen
331
+ ? selectedLabel || this.placeholder
332
+ : this.placeholder}
333
+ @click=${(e: Event) => {
334
+ e.stopPropagation();
335
+ if (!this.isOpen) this.openSelect();
336
+ }}
337
+ @focus=${() => {
338
+ if (!this.isOpen) this.openSelect();
339
+ }}
340
+ @blur=${this.closeSelect}
341
+ @input=${this.handleSearchInput}
342
+ />
299
343
 
300
344
  <svg
301
345
  width="10"
@@ -312,7 +356,7 @@ export class MESelect extends LitElement {
312
356
  </div>
313
357
  ${this.isOpen
314
358
  ? html`<ul id=${this.listboxId} role="listbox">
315
- ${this.options.map(
359
+ ${visibleOptions.map(
316
360
  (option, index) =>
317
361
  html`<li
318
362
  id=${this.optionId(index)}
@@ -320,6 +364,7 @@ export class MESelect extends LitElement {
320
364
  aria-selected=${this.value === option.value
321
365
  ? "true"
322
366
  : "false"}
367
+ @mousedown=${(e: MouseEvent) => e.preventDefault()}
323
368
  @click="${() => this.setSelectedOption(option)}"
324
369
  @mousemove="${() => {
325
370
  this.activeOption = option;
@@ -45,21 +45,42 @@ const formDisclaimer = ({
45
45
  ? CANADA_PRIVACY_POLICY_URL
46
46
  : "http://bit.ly/me_privacy_policy";
47
47
 
48
- if (phoneNumberInput && isCanadianBuilding(country)) {
48
+ if ((emailInput || phoneNumberInput) && isCanadianBuilding(country)) {
49
+ if (clickingButtonText === "schedule tour") {
50
+ return html` <div style=${styleMap(disclaimerStyles.container)}>
51
+ By providing your number and/or email address and clicking schedule
52
+ tour, you consent to receive recurring commercial electronic messages
53
+ and calls from or on behalf of ${orgLegalName} at the provided number
54
+ and/or email address. Messages may be AI or human generated.
55
+ StdMsg&DataRatesMayApply. You consent to this
56
+ <a
57
+ style=${styleMap(disclaimerStyles.link)}
58
+ href=${policyUrl}
59
+ target="_blank"
60
+ rel="noopener noreferrer"
61
+ >privacy policy</a
62
+ >, including having your number, email address, and communications
63
+ recorded and used by our service provider EliseAI to generate responses
64
+ and improve their services. You may withdraw your consent at any time by
65
+ unsubscribing or contacting us.
66
+ </div>`;
67
+ }
68
+
49
69
  return html` <div style=${styleMap(disclaimerStyles.container)}>
50
- By providing your number and clicking ${clickingButtonText}, you consent
51
- to receive recurring commercial electronic messages from or on behalf of
52
- ${orgLegalName} at this number. Messages may be AI or human generated. Msg
53
- & Data rates may apply. You consent to this
70
+ By providing your email address and/or number and clicking send, you
71
+ consent to receive recurring commercial electronic messages and calls from
72
+ or on behalf of ${orgLegalName} at that email address and/or number.
73
+ Messages may be AI or human generated. You consent to this
54
74
  <a
55
75
  style=${styleMap(disclaimerStyles.link)}
56
76
  href=${policyUrl}
57
77
  target="_blank"
58
78
  rel="noopener noreferrer"
59
79
  >privacy policy</a
60
- >, including having your number and communications recorded and used by
61
- our service provider to generate responses and improve their services. You
62
- may withdraw your consent at any time by unsubscribing or contacting us.
80
+ >, including having your email address, number, and communications
81
+ recorded and used by our service provider EliseAI to generate responses
82
+ and improve their services. You may withdraw your consent at any time by
83
+ unsubscribing or contacting us.
63
84
  </div>`;
64
85
  }
65
86
 
@@ -108,24 +129,6 @@ const formDisclaimer = ({
108
129
  third party.
109
130
  </div>`;
110
131
  }
111
- if (emailInput && isCanadianBuilding(country)) {
112
- return html` <div style=${styleMap(disclaimerStyles.container)}>
113
- By providing your email address and clicking ${clickingButtonText}, you
114
- consent to receive recurring commercial electronic messages from or on
115
- behalf of ${orgLegalName} at that email address. Messages may be AI or
116
- human generated. You consent to this
117
- <a
118
- style=${styleMap(disclaimerStyles.link)}
119
- href=${policyUrl}
120
- target="_blank"
121
- rel="noopener noreferrer"
122
- >privacy policy</a
123
- >, including having your email address and communications recorded and
124
- used by our service provider EliseAI to generate responses and improve
125
- their services. You may withdraw your consent at any time by unsubscribing
126
- or contacting us.
127
- </div>`;
128
- }
129
132
  if (emailInput) {
130
133
  return html` <div style=${styleMap(disclaimerStyles.container)}>
131
134
  By entering your email and clicking ${clickingButtonText}, you consent to