@meetelise/chat 1.6.4 → 1.8.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 (37) hide show
  1. package/index.ts +1 -0
  2. package/package.json +3 -3
  3. package/public/dist/index.d.ts +1 -0
  4. package/public/dist/index.js +2 -0
  5. package/public/dist/{bundle.js.LICENSE.txt → index.js.LICENSE.txt} +0 -0
  6. package/public/{ts-loader-build → dist/src}/InHouseLauncher.d.ts +0 -0
  7. package/public/{ts-loader-build → dist/src}/MEChat.d.ts +6 -3
  8. package/public/{ts-loader-build → dist/src}/analytics.d.ts +0 -0
  9. package/public/{ts-loader-build → dist/src}/chatID.d.ts +0 -0
  10. package/public/dist/src/createConversation.d.ts +4 -0
  11. package/public/{ts-loader-build → dist/src}/fetchBuildingInfo.d.ts +0 -12
  12. package/public/{ts-loader-build → dist/src}/launchDarklyManager.d.ts +0 -0
  13. package/public/dist/src/themes.d.ts +52 -0
  14. package/public/{ts-loader-build → dist/src}/utils.d.ts +0 -0
  15. package/public/index.html +1 -1
  16. package/src/InHouseLauncher.module.scss +7 -2
  17. package/src/MEChat.test.ts +11 -12
  18. package/src/MEChat.tsx +62 -54
  19. package/src/createConversation.ts +15 -21
  20. package/src/fetchBuildingInfo.ts +0 -14
  21. package/src/themes.ts +53 -14
  22. package/tsconfig.json +2 -2
  23. package/webpack.config.cjs +2 -2
  24. package/public/dist/bundle.js +0 -2
  25. package/public/ts-loader-build/createConversation.d.ts +0 -4
  26. package/public/ts-loader-build/getAvatarUrl.d.ts +0 -13
  27. package/public/ts-loader-build/getIcons.d.ts +0 -8
  28. package/public/ts-loader-build/installTalkJSStyles.d.ts +0 -8
  29. package/public/ts-loader-build/resolveTheme.d.ts +0 -15
  30. package/public/ts-loader-build/themes.d.ts +0 -179
  31. package/src/ChatBubble.d.ts +0 -11
  32. package/src/ChatBubble.module.scss +0 -58
  33. package/src/ChatBubble.tsx +0 -55
  34. package/src/getAvatarUrl.ts +0 -39
  35. package/src/getIcons.ts +0 -51
  36. package/src/installTalkJSStyles.ts +0 -26
  37. package/src/resolveTheme.ts +0 -44
@@ -0,0 +1,52 @@
1
+ export declare const enum ThemeId {
2
+ Light = "Light",
3
+ Dark = "Dark",
4
+ Purple = "Purple",
5
+ Blue = "Blue",
6
+ Teal = "Teal",
7
+ Green = "Green",
8
+ Yellow = "Yellow",
9
+ Orange = "Orange",
10
+ Pink = "Pink"
11
+ }
12
+ export declare type ThemeIdString = `${ThemeId}`;
13
+ export interface Theme {
14
+ chatHeader: {
15
+ backgroundColor: string;
16
+ textColor: string;
17
+ };
18
+ chatPaneBackgroundColor: string;
19
+ message: {
20
+ user: {
21
+ textColor: string;
22
+ backgroundColor: string;
23
+ };
24
+ agent: {
25
+ textColor: string;
26
+ backgroundColor: string;
27
+ };
28
+ };
29
+ }
30
+ export declare const defaultThemeId = ThemeId.Light;
31
+ export declare const lightMessage: {
32
+ user: {
33
+ textColor: string;
34
+ backgroundColor: string;
35
+ };
36
+ agent: {
37
+ textColor: string;
38
+ backgroundColor: string;
39
+ };
40
+ };
41
+ export declare const darkMessage: {
42
+ user: {
43
+ textColor: string;
44
+ backgroundColor: string;
45
+ };
46
+ agent: {
47
+ textColor: string;
48
+ backgroundColor: string;
49
+ };
50
+ };
51
+ /** If `themeId` is a valid `ThemeId`, returns the corresponding theme. Otherwise returns the default theme. */
52
+ export declare const getTheme: (themeId?: string | undefined) => Theme;
File without changes
package/public/index.html CHANGED
@@ -87,7 +87,7 @@
87
87
  </main>
88
88
  <script type="module">
89
89
  import { debounce } from "https://cdn.skypack.dev/lodash";
90
- import MEChat from "./dist/bundle.js";
90
+ import MEChat from "./dist/index.js";
91
91
  const chat = MEChat.start({
92
92
  organization: "test-company",
93
93
  building: "e2e-test-yardi-building",
@@ -12,6 +12,7 @@ $glowBarGif: url("https://s3.us-west-2.amazonaws.com/meetelise.com/HorizontalBar
12
12
  all: revert;
13
13
  }
14
14
 
15
+ user-select: none;
15
16
  position: fixed;
16
17
  display: flex;
17
18
  justify-content: space-evenly;
@@ -19,11 +20,15 @@ $glowBarGif: url("https://s3.us-west-2.amazonaws.com/meetelise.com/HorizontalBar
19
20
  color: #202020;
20
21
  background-color: rgba(white, 0.8);
21
22
  backdrop-filter: blur(10px);
23
+ box-shadow: 0px 8px 8px 4px rgba(0, 0, 0, 0.25);
22
24
  font-family: Poppins;
23
25
 
24
26
  &:hover {
25
- filter: brightness(150%);
26
- background: blue;
27
+ background: radial-gradient(
28
+ 36.85% 65.32% at 50% 106.31%,
29
+ #03ecc4 0%,
30
+ rgba(131, 129, 142, 1) 100%
31
+ );
27
32
  }
28
33
 
29
34
  &.mobile {
@@ -1,8 +1,6 @@
1
1
  import { expect } from "@esm-bundle/chai";
2
2
  import { stub, restore } from "sinon/pkg/sinon-esm";
3
- import MEChat from "../public/dist/bundle";
4
-
5
- const TIMEOUT = 15000;
3
+ import MEChat from "../public/dist/index";
6
4
 
7
5
  const stubResponse = {
8
6
  json: stub().resolves({
@@ -27,7 +25,7 @@ const stubResponse = {
27
25
 
28
26
  const waitForElementWithSelectorToExist = async (
29
27
  selector: string,
30
- target: Node = document.querySelector("body")
28
+ target: Node = document.body
31
29
  ): Promise<void> => {
32
30
  return new Promise<void>((resolve) => {
33
31
  // in case the element already exists
@@ -43,12 +41,14 @@ const waitForElementWithSelectorToExist = async (
43
41
  });
44
42
  };
45
43
 
44
+ const wait = (delay, ...args) =>
45
+ new Promise((resolve) => setTimeout(resolve, delay, ...args));
46
+
46
47
  afterEach(() => {
47
48
  restore();
48
49
  });
49
50
 
50
- it.skip("shows the launcher", async function (done) {
51
- this.timeout(TIMEOUT);
51
+ it("shows the launcher", async function () {
52
52
  // Given an API that returns this building theme
53
53
  stub(window, "fetch").resolves(stubResponse);
54
54
 
@@ -71,21 +71,20 @@ it.skip("shows the launcher", async function (done) {
71
71
  const popupDisplay = popupStyle.getPropertyValue("display");
72
72
  expect(popupDisplay).to.equal("none");
73
73
 
74
- // When I click the launcher
75
74
  launcher.click();
75
+ // Without waiting, the popup doesn't open in time for the next assertion
76
+ await wait(0);
76
77
 
77
78
  // Then the popup should be visible
78
79
  const popupStyle2 = window.getComputedStyle(popup);
79
80
  const popupDisplay2 = popupStyle2.getPropertyValue("display");
80
81
  expect(popupDisplay2).not.to.equal("none");
81
- done();
82
+
82
83
  // Ideally, expect welcome message, but we can't select inside the iframe
83
84
  // Ideally, expect theme colors, but we can't select inside the iframe
84
85
  });
85
86
 
86
- it.skip("works via the programmatic interface", async function () {
87
- this.timeout(TIMEOUT);
88
-
87
+ it("works via the programmatic interface", async function () {
89
88
  // Given an API that returns this building theme
90
89
  stub(window, "fetch").resolves(stubResponse);
91
90
 
@@ -95,7 +94,7 @@ it.skip("works via the programmatic interface", async function () {
95
94
  building: "unit-test-building",
96
95
  });
97
96
 
98
- await waitForElementWithSelectorToExist(".meetelise-chat.launcher");
97
+ await waitForElementWithSelectorToExist(".meetelise-chat.launcher > div");
99
98
 
100
99
  // Ideally, verify behavior, but this will at least verify nothing throws
101
100
  chat.show();
package/src/MEChat.tsx CHANGED
@@ -6,14 +6,15 @@ import Talk from "talkjs";
6
6
  import fetchBuildingInfo, { Building } from "./fetchBuildingInfo";
7
7
  import { getChatID, createChatID } from "./chatID";
8
8
  import createConversation from "./createConversation";
9
- import installTalkJSStyles from "./installTalkJSStyles";
10
- import resolveTheme, { Theme } from "./resolveTheme";
9
+ import { Theme, ThemeIdString } from "./themes";
11
10
  import Analytics from "./analytics";
12
11
  import { isMobile } from "./utils";
13
12
  import InHouseLauncher from "./InHouseLauncher";
14
13
  import LaunchDarkly from "./launchDarklyManager";
15
14
  import styles from "./MEChat.module.scss";
16
- import { defaultThemeId, themesById } from "./themes";
15
+ import { getTheme } from "./themes";
16
+
17
+ const LAUNCHER_CLASSES = ["meetelise-chat", "launcher"];
17
18
 
18
19
  /**
19
20
  * The interface to MeetElise chat.
@@ -65,21 +66,26 @@ export default class MEChat {
65
66
  * Clear all messages from the window and start a new conversation.
66
67
  */
67
68
  restartConversation(): void {
68
- Promise.all([MEChat.session, this.building, this.popup]).then(
69
- ([session, building, popup]) => {
70
- this.chatId = createChatID(this.orgSlug, this.buildingSlug);
71
- this.analytics.chatId = this.chatId;
72
- popup.select(
73
- createConversation(
74
- session,
75
- building,
76
- resolveTheme(building, this.theme),
77
- this.chatId,
78
- this.isMobile
79
- )
80
- );
81
- }
82
- );
69
+ Promise.all([
70
+ MEChat.session,
71
+ this.building,
72
+ this.theme,
73
+ this.avatarSrc,
74
+ this.popup,
75
+ ]).then(([session, building, theme, avatarSrc, popup]) => {
76
+ this.chatId = createChatID(this.orgSlug, this.buildingSlug);
77
+ this.analytics.chatId = this.chatId;
78
+ popup.select(
79
+ createConversation(
80
+ session,
81
+ building,
82
+ theme,
83
+ avatarSrc || building.avatarSrc,
84
+ this.chatId,
85
+ this.isMobile
86
+ )
87
+ );
88
+ });
83
89
  }
84
90
 
85
91
  /**
@@ -87,29 +93,28 @@ export default class MEChat {
87
93
  *
88
94
  * @param theme The updated theme
89
95
  */
90
- setTheme(theme: Partial<Theme>): void {
96
+ // TODO: probably want to replace theme argument with themeId, avatarSrc
97
+ setTheme(newTheme: Partial<Theme>): void {
91
98
  const focusedElement = document.activeElement;
92
99
  Promise.all([
93
100
  MEChat.session,
94
101
  this.building,
102
+ this.theme,
103
+ this.avatarSrc,
95
104
  this.popup,
96
105
  LaunchDarkly.isReady,
97
106
  ])
98
- .then(([session, building, popup]) => {
99
- const resolvedTheme = (this.theme = resolveTheme(building, {
100
- ...this.theme,
101
- ...theme,
102
- }));
107
+ .then(([session, building, theme, avatarSrc, popup]) => {
103
108
  popup.select(
104
109
  createConversation(
105
110
  session,
106
111
  building,
107
- resolvedTheme,
112
+ { ...theme, ...newTheme },
113
+ avatarSrc || building.avatarSrc,
108
114
  this.chatId,
109
115
  this.isMobile
110
116
  )
111
117
  );
112
- installTalkJSStyles(resolvedTheme);
113
118
  return new Promise(requestAnimationFrame);
114
119
  })
115
120
  .then(() => {
@@ -148,19 +153,15 @@ export default class MEChat {
148
153
  const chatTappedHandler = async () => {
149
154
  ReactDOM.unmountComponentAtNode(targetElement);
150
155
  (await this.popup).show();
156
+ this.analytics.ping("open");
151
157
  };
152
- const building = await this.building;
153
- let theme = themesById[defaultThemeId];
154
- if (Object.keys(themesById).includes(building.themeId)) {
155
- theme = themesById[building.themeId as keyof typeof themesById];
156
- }
157
158
  ReactDOM.render(
158
159
  <InHouseLauncher
159
160
  onChatTapped={chatTappedHandler}
160
161
  mobile={this.isMobile}
161
162
  firstMount={firstMount}
162
- backgroundColor={theme.chatPaneBackgroundColor}
163
- textColor={theme.chatHeader.textColor}
163
+ backgroundColor={(await this.theme).chatPaneBackgroundColor}
164
+ textColor={(await this.theme).chatHeader.textColor}
164
165
  />,
165
166
  targetElement
166
167
  );
@@ -170,7 +171,9 @@ export default class MEChat {
170
171
  const inHouseLauncherTarget = document.createElement("div");
171
172
  inHouseLauncherTarget.classList.add(
172
173
  styles.inHouseLauncherContainer,
173
- this.isMobile ? styles.mobile : styles.desktop
174
+ this.isMobile ? styles.mobile : styles.desktop,
175
+ ...LAUNCHER_CLASSES,
176
+ styles.shouldBeVisible
174
177
  );
175
178
  document.body.appendChild(inHouseLauncherTarget);
176
179
  this.mountInHouseLauncher(inHouseLauncherTarget, true);
@@ -185,37 +188,46 @@ export default class MEChat {
185
188
  private popup: Promise<Talk.Popup>;
186
189
  private launcher: Promise<HTMLElement>;
187
190
  private building: Promise<Building>;
188
- private theme: Partial<Theme>;
191
+ private themeId?: ThemeIdString;
192
+ private theme: Promise<Theme>;
193
+ private avatarSrc?: Promise<null | string>;
189
194
  private chatId: string;
190
195
  private analytics: Analytics;
191
196
  private launchDarklyClient: LDClient.LDClient;
192
197
  private useInHouseLauncher: boolean;
193
198
  private isMobile: boolean;
194
199
 
195
- private constructor({ organization, building, theme = {} }: Options) {
200
+ private constructor({ organization, building, themeId, avatarSrc }: Options) {
196
201
  this.orgSlug = organization;
197
202
  this.buildingSlug = building;
198
203
  this.chatId = getChatID(organization, building);
199
204
  this.analytics = new Analytics(organization, building, this.chatId);
200
205
  this.launchDarklyClient = LaunchDarkly.getClient(this.chatId);
201
206
  this.analytics.ping("load");
202
- this.theme = theme;
203
207
  this.building = fetchBuildingInfo(organization, building);
208
+ this.themeId = themeId;
209
+ this.theme = this.building.then((building) =>
210
+ getTheme(themeId || building.themeId)
211
+ );
212
+ this.avatarSrc = this.building.then(
213
+ (building) => avatarSrc || building.avatarSrc
214
+ );
204
215
  this.useInHouseLauncher = true;
205
216
  this.isMobile = isMobile();
206
217
 
207
218
  this.popup = Promise.all([
208
219
  this.building,
220
+ this.theme,
221
+ this.avatarSrc,
209
222
  MEChat.session,
210
223
  LaunchDarkly.isReady,
211
- ]).then(async ([building, session]) => {
212
- const resolvedTheme = (this.theme = resolveTheme(building, theme));
213
- installTalkJSStyles(resolvedTheme);
214
- const p = session.createPopup(
224
+ ]).then(async ([building, theme, avatarSrc, session]) => {
225
+ const popup = session.createPopup(
215
226
  createConversation(
216
227
  session,
217
228
  building,
218
- resolvedTheme,
229
+ theme,
230
+ avatarSrc || building.avatarSrc,
219
231
  this.chatId,
220
232
  this.isMobile
221
233
  ),
@@ -225,9 +237,6 @@ export default class MEChat {
225
237
  messageField: { placeholder: "Ask a question..." },
226
238
  }
227
239
  );
228
- p.on("open", () => {
229
- this.analytics.ping("open");
230
- });
231
240
  if (building.conversationMaintenanceMode) {
232
241
  return new Promise(() => {
233
242
  // If in maintenance mode, we return an always-pending Promise
@@ -237,7 +246,7 @@ export default class MEChat {
237
246
  );
238
247
  });
239
248
  }
240
- await p.mount({ show: false });
249
+ await popup.mount({ show: false });
241
250
  const talkjsPopupElement = document.querySelector(".__talkjs_popup");
242
251
  if (!talkjsPopupElement) throw new Error("Failed to find chat window");
243
252
  talkjsPopupElement.classList.add("meetelise-chat", "pane");
@@ -245,7 +254,7 @@ export default class MEChat {
245
254
  talkjsPopupElement.classList.add(styles.desktop);
246
255
  }
247
256
  (talkjsPopupElement as HTMLElement).style.zIndex = "99999999999";
248
- return p;
257
+ return popup;
249
258
  });
250
259
 
251
260
  this.launcher = Promise.all([this.popup, LaunchDarkly.isReady]).then(
@@ -262,14 +271,12 @@ export default class MEChat {
262
271
  if (!talkjsLauncherElement)
263
272
  throw new Error("MeetElise Chat: Could not locate launcher.");
264
273
  launcherElement = talkjsLauncherElement;
274
+ launcherElement.classList.add(
275
+ ...LAUNCHER_CLASSES,
276
+ styles.shouldBeVisible
277
+ );
265
278
  }
266
279
 
267
- launcherElement.classList.add(
268
- "meetelise-chat",
269
- "launcher",
270
- styles.shouldBeVisible
271
- );
272
-
273
280
  return launcherElement;
274
281
  }
275
282
  );
@@ -279,5 +286,6 @@ export default class MEChat {
279
286
  export interface Options {
280
287
  building: string;
281
288
  organization: string;
282
- theme?: Partial<Theme>;
289
+ themeId?: ThemeIdString;
290
+ avatarSrc?: string;
283
291
  }
@@ -1,8 +1,7 @@
1
1
  import Talk from "talkjs";
2
2
  import { Building } from "./fetchBuildingInfo";
3
- import getAvatarUrl from "./getAvatarUrl";
4
- import { Theme } from "./resolveTheme";
5
- import { defaultThemeId, themesById } from "./themes";
3
+ import { Theme } from "./themes";
4
+ import { darkMessage } from "./themes";
6
5
 
7
6
  const defaultAvatarUrl =
8
7
  "https://s3.us-west-2.amazonaws.com/meetelise.com/looping-gradient.gif";
@@ -11,6 +10,7 @@ export default function createConversation(
11
10
  session: Talk.Session,
12
11
  building: Building,
13
12
  theme: Theme,
13
+ avatarSrc: Building["avatarSrc"],
14
14
  chatID: string,
15
15
  isMobile: boolean
16
16
  ): Talk.ConversationBuilder {
@@ -18,39 +18,33 @@ export default function createConversation(
18
18
  id: `building_${building.id}`,
19
19
  name: building.userFirstName,
20
20
  email: null,
21
- photoUrl: getAvatarUrl(building),
22
21
  role: "Default",
23
22
  welcomeMessage: building.welcomeMessage,
24
23
  });
25
24
  const conversation = session.getOrCreateConversation(chatID);
26
- conversation.subject = theme.chatTitle;
27
25
  conversation.setParticipant(session.me);
28
26
  conversation.setParticipant(agent);
29
- // TODO: duplicate identifier theme
30
- // TODO: typescript abuse
31
- let themeId = defaultThemeId;
32
- if (Object.keys(themesById).includes(building.themeId)) {
33
- themeId = building.themeId as keyof typeof themesById;
34
- }
35
- const _theme = themesById[themeId];
27
+ conversation.subject = building.chatTitle ?? building.userFirstName;
36
28
  conversation.custom = {
37
29
  buildingId: building.id.toString(),
38
30
  userId: building.userId.toString(),
39
31
  orgId: building.orgId.toString(),
40
- subtitle: theme.chatSubtitle ?? null,
32
+ subtitle: building.chatSubtitle,
41
33
  url: location.href,
42
34
  buildingName: building.name,
43
35
  isMobile: isMobile.toString(),
44
- chatHeaderBackgroundColor: _theme.chatHeader.backgroundColor,
45
- chatHeaderTextColor: _theme.chatHeader.textColor,
46
- chatPaneBackgroundColor: _theme.chatPaneBackgroundColor,
47
- userMessageTextColor: _theme.message.user.textColor,
48
- userMessageBackgroundColor: _theme.message.user.backgroundColor,
49
- agentMessageTextColor: _theme.message.agent.textColor,
50
- agentMessageBackgroundColor: _theme.message.agent.backgroundColor,
36
+ chatHeaderBackgroundColor: theme.chatHeader.backgroundColor,
37
+ chatHeaderTextColor: theme.chatHeader.textColor,
38
+ chatPaneBackgroundColor: theme.chatPaneBackgroundColor,
39
+ userMessageTextColor: theme.message.user.textColor,
40
+ userMessageBackgroundColor: theme.message.user.backgroundColor,
41
+ agentMessageTextColor: theme.message.agent.textColor,
42
+ agentMessageBackgroundColor: theme.message.agent.backgroundColor,
43
+ // it is sometimes helpful to know inside TalkJS if the theme is a light theme (examples: Light, Teal, Yellow) or a dark theme (Dark, Purple, Green)
44
+ isLightTheme: (theme.message === darkMessage).toString(),
51
45
  avatarUrl:
52
46
  building.avatarType === "image" && building.avatarSrc
53
- ? building.avatarSrc
47
+ ? avatarSrc
54
48
  : defaultAvatarUrl,
55
49
  // uncomment this to test changes to the default avatar if your test building has its own avatar
56
50
  // avatarUrl: defaultAvatarUrl,
@@ -3,31 +3,17 @@
3
3
  */
4
4
  export interface Building {
5
5
  id: number;
6
-
7
6
  themeId: string;
8
- avatarInitials: string | null;
9
7
  avatarSrc: string | null;
10
8
  avatarType: "image" | "initials" | null;
11
9
  chatSubtitle: string | null;
12
10
  chatTitle: string | null;
13
- logoSrc: string | null;
14
11
  name: string;
15
- primaryColor: string | null;
16
12
  userFirstName: string;
17
13
  userId: number;
18
- userLastName: string | null;
19
14
  welcomeMessage: string | null;
20
15
  conversationMaintenanceMode: boolean;
21
16
  orgId: number;
22
- // old: not sure if still present in API response, but we're not using (may have mised a few above)
23
- backgroundColor: string | null;
24
- bannerColor: string | null;
25
- bannerTextColor: string | null;
26
- launchButtonColor: string | null;
27
- launchButtonIconColor: string | null;
28
- launchButtonSize: string | null;
29
- messageColor: string | null;
30
- messageTextColor: string | null;
31
17
  }
32
18
 
33
19
  /**
package/src/themes.ts CHANGED
@@ -1,8 +1,39 @@
1
- export const white = "#FFFFFF";
2
- export const darkGray = "#202020";
3
- export const lightGray = "#83818E";
1
+ const white = "#FFFFFF";
2
+ const darkGray = "#202020";
3
+ const lightGray = "#83818E";
4
4
 
5
- export const defaultThemeId = "Light" as keyof typeof themesById;
5
+ export const enum ThemeId {
6
+ Light = "Light",
7
+ Dark = "Dark",
8
+ Purple = "Purple",
9
+ Blue = "Blue",
10
+ Teal = "Teal",
11
+ Green = "Green",
12
+ Yellow = "Yellow",
13
+ Orange = "Orange",
14
+ Pink = "Pink",
15
+ }
16
+ export type ThemeIdString = `${ThemeId}`;
17
+
18
+ export interface Theme {
19
+ chatHeader: {
20
+ backgroundColor: string;
21
+ textColor: string;
22
+ };
23
+ chatPaneBackgroundColor: string;
24
+ message: {
25
+ user: {
26
+ textColor: string;
27
+ backgroundColor: string;
28
+ };
29
+ agent: {
30
+ textColor: string;
31
+ backgroundColor: string;
32
+ };
33
+ };
34
+ }
35
+
36
+ export const defaultThemeId = ThemeId.Light;
6
37
 
7
38
  export const lightMessage = {
8
39
  user: { textColor: white, backgroundColor: lightGray },
@@ -12,8 +43,8 @@ export const darkMessage = {
12
43
  user: { textColor: white, backgroundColor: lightGray },
13
44
  agent: { textColor: white, backgroundColor: darkGray },
14
45
  };
15
- export const themesById = {
16
- Light: {
46
+ const themesById = {
47
+ [ThemeId.Light]: {
17
48
  chatHeader: {
18
49
  backgroundColor: white,
19
50
  textColor: darkGray,
@@ -21,7 +52,7 @@ export const themesById = {
21
52
  chatPaneBackgroundColor: "rgba(255, 255, 255, 0.9)",
22
53
  message: darkMessage,
23
54
  },
24
- Dark: {
55
+ [ThemeId.Dark]: {
25
56
  chatHeader: {
26
57
  backgroundColor: darkGray,
27
58
  textColor: white,
@@ -29,7 +60,7 @@ export const themesById = {
29
60
  chatPaneBackgroundColor: "rgba(32, 32, 32, 0.9)",
30
61
  message: lightMessage,
31
62
  },
32
- Purple: {
63
+ [ThemeId.Purple]: {
33
64
  chatHeader: {
34
65
  backgroundColor: "#550098",
35
66
  textColor: white,
@@ -37,7 +68,7 @@ export const themesById = {
37
68
  chatPaneBackgroundColor: "rgba(85, 0, 152, 0.6)",
38
69
  message: lightMessage,
39
70
  },
40
- Blue: {
71
+ [ThemeId.Blue]: {
41
72
  chatHeader: {
42
73
  backgroundColor: "#0814E5",
43
74
  textColor: white,
@@ -45,7 +76,7 @@ export const themesById = {
45
76
  chatPaneBackgroundColor: "rgba(4, 17, 245, 0.6)",
46
77
  message: lightMessage,
47
78
  },
48
- Teal: {
79
+ [ThemeId.Teal]: {
49
80
  chatHeader: {
50
81
  backgroundColor: "#6EE7ED",
51
82
  textColor: darkGray,
@@ -53,7 +84,7 @@ export const themesById = {
53
84
  chatPaneBackgroundColor: "rgba(115, 247, 253, 0.8)",
54
85
  message: darkMessage,
55
86
  },
56
- Green: {
87
+ [ThemeId.Green]: {
57
88
  chatHeader: {
58
89
  backgroundColor: "#147B0E",
59
90
  textColor: white,
@@ -61,7 +92,7 @@ export const themesById = {
61
92
  chatPaneBackgroundColor: "rgba(13, 141, 5, 0.6)",
62
93
  message: lightMessage,
63
94
  },
64
- Yellow: {
95
+ [ThemeId.Yellow]: {
65
96
  chatHeader: {
66
97
  backgroundColor: "#F1E54F",
67
98
  textColor: darkGray,
@@ -69,7 +100,7 @@ export const themesById = {
69
100
  chatPaneBackgroundColor: "rgba(251, 239, 80, 0.9)",
70
101
  message: darkMessage,
71
102
  },
72
- Orange: {
103
+ [ThemeId.Orange]: {
73
104
  chatHeader: {
74
105
  backgroundColor: "#C06C31",
75
106
  textColor: white,
@@ -77,7 +108,7 @@ export const themesById = {
77
108
  chatPaneBackgroundColor: "rgba(238, 126, 49, 0.7)",
78
109
  message: lightMessage,
79
110
  },
80
- Pink: {
111
+ [ThemeId.Pink]: {
81
112
  chatHeader: {
82
113
  backgroundColor: "#A24599",
83
114
  textColor: white,
@@ -86,3 +117,11 @@ export const themesById = {
86
117
  message: lightMessage,
87
118
  },
88
119
  };
120
+
121
+ /** If `themeId` is a valid `ThemeId`, returns the corresponding theme. Otherwise returns the default theme. */
122
+ export const getTheme = (themeId?: ThemeId | string): Theme =>
123
+ themesById[
124
+ themeId && Object.keys(themesById).includes(themeId)
125
+ ? (themeId as ThemeIdString)
126
+ : defaultThemeId
127
+ ];
package/tsconfig.json CHANGED
@@ -17,7 +17,7 @@
17
17
  // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
18
18
  "sourceMap": true /* Generates corresponding '.map' file. */,
19
19
  // "outFile": "./", /* Concatenate and emit output to single file. */
20
- "outDir": "./public/ts-loader-build" /* Redirect output structure to the directory. */,
20
+ "outDir": "./public/dist" /* Redirect output structure to the directory. */,
21
21
  // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
22
22
  // "composite": true, /* Enable project compilation */
23
23
  // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
@@ -73,5 +73,5 @@
73
73
  "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
74
74
  "plugins": [{ "name": "typescript-plugin-css-modules" }]
75
75
  },
76
- "include": ["./src/MEChat.tsx", "declarations.d.ts"]
76
+ "include": ["./src/MEChat.tsx", "declarations.d.ts", "index.ts"]
77
77
  }
@@ -38,8 +38,8 @@ module.exports = (env) => {
38
38
  outputModule: !env.isDemoApp,
39
39
  },
40
40
  output: {
41
- filename: "bundle.js",
42
- sourceMapFilename: "bundle.js.map",
41
+ filename: "index.js",
42
+ sourceMapFilename: "index.js.map",
43
43
  ...(env.isDemoApp
44
44
  ? {
45
45
  path: path.resolve(__dirname, "./public/demo/built"),