@meetelise/chat 1.11.0 → 1.12.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.
Files changed (56) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/.github/workflows/release.yml +1 -0
  3. package/.vscode/settings.json +6 -1
  4. package/CONTRIBUTING.md +8 -0
  5. package/package.json +9 -10
  6. package/public/demo/index.html +78 -11
  7. package/public/dist/index.js +1714 -1
  8. package/public/dist/index.js.LICENSE.txt +26 -14
  9. package/public/index.html +2 -1
  10. package/src/MEChat.test.ts +5 -5
  11. package/src/MEChat.ts +53 -0
  12. package/src/WebComponent/InHouseLauncher.ts +446 -0
  13. package/src/WebComponent/MEChat.css +5 -0
  14. package/src/WebComponent/MEChat.ts +282 -0
  15. package/src/WebComponent/OfficeHours.ts +73 -0
  16. package/src/WebComponent/Scheduler/date-picker.ts +320 -0
  17. package/src/WebComponent/Scheduler/me-select.ts +244 -0
  18. package/src/WebComponent/Scheduler/time-picker.ts +101 -0
  19. package/src/WebComponent/Scheduler/tour-scheduler.ts +383 -0
  20. package/src/WebComponent/Scheduler/tour-type-option.ts +92 -0
  21. package/src/WebComponent/actions/ActionConfirmButton.ts +94 -0
  22. package/src/WebComponent/actions/CallUsWindow.ts +110 -0
  23. package/src/WebComponent/actions/DetailsWindow.ts +109 -0
  24. package/src/WebComponent/actions/EmailUsWindow.ts +432 -0
  25. package/src/WebComponent/actions/InputStyles.ts +31 -0
  26. package/src/WebComponent/actions/TextUsWindow.ts +226 -0
  27. package/src/WebComponent/actions/formatPhoneNumber.ts +42 -0
  28. package/src/WebComponent/inHouseLauncherStyles.ts +300 -0
  29. package/src/WebComponent/index.ts +2 -0
  30. package/src/WebComponent/utils.ts +82 -0
  31. package/src/fetchBuildingInfo.ts +1 -0
  32. package/src/getAvailabilities.ts +71 -0
  33. package/src/themes.ts +5 -3
  34. package/tsconfig.json +9 -3
  35. package/web-test-runner.config.js +0 -6
  36. package/webpack.config.cjs +8 -25
  37. package/public/dist/index.d.ts +0 -1
  38. package/public/dist/src/ChatButton.d.ts +0 -9
  39. package/public/dist/src/ChatIcon.d.ts +0 -6
  40. package/public/dist/src/InHouseLauncher.d.ts +0 -11
  41. package/public/dist/src/MEChat.d.ts +0 -73
  42. package/public/dist/src/analytics.d.ts +0 -34
  43. package/public/dist/src/assetUrls.d.ts +0 -2
  44. package/public/dist/src/chatID.d.ts +0 -11
  45. package/public/dist/src/createConversation.d.ts +0 -4
  46. package/public/dist/src/fetchBuildingInfo.d.ts +0 -25
  47. package/public/dist/src/themes.d.ts +0 -52
  48. package/public/dist/src/utils.d.ts +0 -2
  49. package/src/ChatButton.module.scss +0 -51
  50. package/src/ChatButton.tsx +0 -38
  51. package/src/ChatIcon.tsx +0 -26
  52. package/src/DemoApp.tsx +0 -113
  53. package/src/InHouseLauncher.module.scss +0 -139
  54. package/src/InHouseLauncher.tsx +0 -69
  55. package/src/MEChat.module.scss +0 -22
  56. package/src/MEChat.tsx +0 -293
@@ -0,0 +1,244 @@
1
+ import { LitElement, html, TemplateResult, css } from "lit";
2
+ import { property, state, query } from "lit/decorators.js";
3
+ import { classMap } from "lit/directives/class-map.js";
4
+
5
+ // TODO: would be nice to mimic the usage of native <select> where the options are children
6
+
7
+ export class MESelect extends LitElement {
8
+ @property({ attribute: false })
9
+ options: string[] = [];
10
+
11
+ @property({ type: String })
12
+ placeholder?: string = "Select";
13
+
14
+ @property({ type: String })
15
+ defaultOption?: string;
16
+
17
+ @state()
18
+ private selected?: string;
19
+
20
+ @state()
21
+ private activeOption: string | null = null;
22
+
23
+ @state()
24
+ private isOpen?: boolean = false;
25
+
26
+ @query("#select")
27
+ meSelect!: HTMLDivElement;
28
+
29
+ toggleSelect = (): void => {
30
+ if (this.isOpen) {
31
+ this.activeOption = null;
32
+ }
33
+ this.isOpen = !this.isOpen;
34
+ };
35
+
36
+ setSelectedOption = (option: string, closeSelect = true): void => {
37
+ this.selected = option;
38
+ if (closeSelect) {
39
+ this.isOpen = !this.isOpen;
40
+ this.activeOption = null;
41
+ }
42
+ };
43
+
44
+ handleKeydown = (
45
+ keyOrKeys: string | string[],
46
+ callback: () => void
47
+ ): ((event: KeyboardEvent) => void) => {
48
+ return (e: KeyboardEvent) => {
49
+ if (typeof keyOrKeys === "string" && e.key === keyOrKeys) {
50
+ callback();
51
+ } else if (typeof keyOrKeys === "object" && keyOrKeys.includes(e.key)) {
52
+ callback();
53
+ }
54
+ };
55
+ };
56
+
57
+ constructor() {
58
+ super();
59
+ // TODO: the current thing works, but want to investigate more. why doesn't it work with `this`?
60
+ // https://lamplightdev.com/blog/2021/04/10/how-to-detect-clicks-outside-of-a-web-component/
61
+ // TODO: "If your component adds an event listener to anything except itself or its templated DOM
62
+ // – for example, to Window, Document, or some element in the main DOM – you should add the
63
+ // listener in connectedCallback and remove it in disconnectedCallback." (https://lit.dev/docs/components/events/)
64
+ document.addEventListener("click", (event: MouseEvent) => {
65
+ if (!event.composedPath().includes(this.meSelect)) {
66
+ this.isOpen = false;
67
+ }
68
+ });
69
+ }
70
+
71
+ static styles = css`
72
+ @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
73
+
74
+ :host {
75
+ --light-grey: #e3e3e3;
76
+ --active-option-color: #f5f7f9;
77
+ --light-border: 1px solid $light-border-color;
78
+ }
79
+
80
+ * {
81
+ box-sizing: border-box;
82
+ user-select: none;
83
+ font-family: Poppins;
84
+ font-size: 14px;
85
+ }
86
+
87
+ #select {
88
+ height: 50px;
89
+ min-width: 144px;
90
+ width: fit-content;
91
+ display: flex;
92
+ justify-content: space-between;
93
+ gap: 17px;
94
+ padding: 14.5px;
95
+ padding-right: 19.5px;
96
+ align-items: center;
97
+ background: white;
98
+ border: 1px solid #e3e3e3;
99
+ box-sizing: border-box;
100
+ box-shadow: 0px 1px 0px rgba(142, 142, 142, 0.2);
101
+ border-radius: 10px;
102
+ }
103
+
104
+ ul {
105
+ padding-left: 0;
106
+ margin-bottom: 0;
107
+ max-height: 200px;
108
+ overflow-y: scroll;
109
+ position: absolute;
110
+ min-height: 40px;
111
+ max-width: 400px;
112
+ background-color: white;
113
+ z-index: 20;
114
+ margin-top: 4px;
115
+ border: var(--light-border);
116
+ box-sizing: border-box;
117
+ box-shadow: 0px 4px 14px rgba(0, 0, 0, 0.15);
118
+ border-radius: 10px;
119
+ overflow: hidden;
120
+ }
121
+
122
+ .option {
123
+ list-style: none;
124
+ padding: 10px;
125
+ }
126
+
127
+ .option:first-child {
128
+ border-top-left-radius: 10px;
129
+ border-top-right-radius: 10px;
130
+ }
131
+
132
+ .option:last-child {
133
+ border-bottom-left-radius: 10px;
134
+ border-bottom-right-radius: 10px;
135
+ }
136
+
137
+ /* TODO: why two diff ones? copied from EWA but don't understand */
138
+ .option:active {
139
+ background-color: var(--light-grey);
140
+ }
141
+
142
+ .option.active {
143
+ background-color: var(--active-option-color);
144
+ }
145
+ `;
146
+ render(): TemplateResult {
147
+ return html`
148
+ <div>
149
+ <div
150
+ id="select"
151
+ tabindex="0"
152
+ @click=${() => (this.isOpen = !this.isOpen)}
153
+ @keydown="${(e: KeyboardEvent) => {
154
+ switch (e.key) {
155
+ case "Enter":
156
+ case " ":
157
+ e.preventDefault();
158
+ if (this.isOpen && this.activeOption) {
159
+ this.setSelectedOption(this.activeOption);
160
+ } else {
161
+ this.toggleSelect();
162
+ }
163
+ break;
164
+ case "Escape":
165
+ e.preventDefault();
166
+ this.isOpen = false;
167
+ break;
168
+ case "Tab":
169
+ if (this.isOpen) {
170
+ e.preventDefault();
171
+ }
172
+ break;
173
+ case "ArrowUp":
174
+ e.preventDefault();
175
+ if (this.isOpen && this.activeOption) {
176
+ if (this.options.indexOf(this.activeOption) > 0) {
177
+ this.activeOption =
178
+ this.options[this.options.indexOf(this.activeOption) - 1];
179
+ } else {
180
+ this.activeOption = null;
181
+ }
182
+ }
183
+ break;
184
+ case "ArrowDown":
185
+ e.preventDefault();
186
+ if (this.isOpen) {
187
+ if (!this.activeOption) {
188
+ this.activeOption = this.options[0];
189
+ } else if (
190
+ this.activeOption &&
191
+ this.options.indexOf(this.activeOption) <
192
+ this.options.length - 1
193
+ ) {
194
+ this.activeOption =
195
+ this.options[this.options.indexOf(this.activeOption) + 1];
196
+ }
197
+ }
198
+ break;
199
+ }
200
+ }}"
201
+ >
202
+ <span id="selectText">${this.selected ?? this.placeholder}</span>
203
+ <svg
204
+ width="10"
205
+ height="6"
206
+ viewBox="0 0 10 6"
207
+ fill="none"
208
+ xmlns="http://www.w3.org/2000/svg"
209
+ >
210
+ <path
211
+ d="M0.189941 1.25439L1.35369 0.0906372L4.84494 3.58189L8.33619 0.0906372L9.49994 1.25439L4.84494 5.90939L0.189941 1.25439Z"
212
+ fill="#83818E"
213
+ />
214
+ </svg>
215
+ </div>
216
+ ${this.isOpen
217
+ ? html`<ul>
218
+ ${this.options.map(
219
+ (option) =>
220
+ html`<li
221
+ @click="${() => this.setSelectedOption(option)}"
222
+ @keydown="${this.handleKeydown(["Enter", " "], () =>
223
+ this.setSelectedOption(option)
224
+ )}"
225
+ @mousemove="${() => {
226
+ this.activeOption = option;
227
+ }}"
228
+ @mouseleave="${() => {
229
+ this.activeOption = null;
230
+ }}"
231
+ class="option ${classMap({
232
+ active: this.activeOption === option,
233
+ })}"
234
+ >
235
+ ${option}
236
+ </li>`
237
+ )}
238
+ </ul>`
239
+ : ""}
240
+ </div>
241
+ `;
242
+ }
243
+ }
244
+ customElements.define("me-select", MESelect);
@@ -0,0 +1,101 @@
1
+ import { LitElement, html, TemplateResult, css } from "lit";
2
+ import { customElement, property, state } from "lit/decorators.js";
3
+ import { classMap } from "lit/directives/class-map.js";
4
+
5
+ @customElement("time-picker")
6
+ export class TimePicker extends LitElement {
7
+ @property({ attribute: false })
8
+ // options: string[] = [];
9
+ options: string[] = [
10
+ "9:10am",
11
+ "10:00am",
12
+ "11:00am",
13
+ "1:00pm",
14
+ "3:00pm",
15
+ "3:30pm",
16
+ "4:00pm",
17
+ "4:30pm",
18
+ "00:00pm",
19
+ ];
20
+
21
+ @state()
22
+ private selected?: string;
23
+
24
+ static styles = css`
25
+ * {
26
+ box-sizing: border-box;
27
+ }
28
+
29
+ #optionContainer {
30
+ margin-left: 14px;
31
+ display: flex;
32
+ flex-wrap: wrap;
33
+ column-gap: 14px;
34
+ row-gap: 19px;
35
+ min-width: 200px;
36
+ }
37
+
38
+ .option {
39
+ position: relative;
40
+ display: inline-block;
41
+ /* padding: 11px 14px; */
42
+ height: 40px;
43
+ width: 85px;
44
+ /* max-width: */
45
+ background: #e7e7e7;
46
+ border: 1px solid #ffffff;
47
+ border-radius: 10px;
48
+ color: #202020;
49
+ font-family: "Poppins";
50
+ font-style: normal;
51
+ font-weight: 400;
52
+ font-size: 14px;
53
+ text-align: center;
54
+ user-select: none;
55
+ }
56
+
57
+ .option > span {
58
+ position: absolute;
59
+ top: 50%;
60
+ left: 50%;
61
+ transform: translate(-50%, -50%);
62
+ }
63
+
64
+ .option.selected {
65
+ color: white;
66
+ background: #202020;
67
+ border: 3px solid #83818e;
68
+ border-radius: 10px;
69
+ }
70
+ `;
71
+ render(): TemplateResult {
72
+ return html`
73
+ <div
74
+ id="optionContainer"
75
+ @click="${(e: MouseEvent) => {
76
+ const target = e.target as HTMLElement | undefined;
77
+ if (target?.closest(".option:not(.selected)"))
78
+ this.selected = target.innerText;
79
+ }}"
80
+ @keydown="${(e: KeyboardEvent) => {
81
+ const target = e.target as HTMLElement | undefined;
82
+ if ([" ", "Enter"].includes(e.key) && target?.closest(".option")) {
83
+ e.preventDefault();
84
+ this.selected =
85
+ target.innerText !== this.selected ? target.innerText : undefined;
86
+ }
87
+ }}"
88
+ >
89
+ ${this.options.map(
90
+ (option) =>
91
+ html`<div
92
+ class="option ${classMap({ selected: this.selected === option })}"
93
+ tabindex="0"
94
+ >
95
+ <span>${option}</span>
96
+ </div>`
97
+ )}
98
+ </div>
99
+ `;
100
+ }
101
+ }