@mitodl/smoot-design 0.0.0-a2e4e1e → 0.0.0-bafccd3

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 (98) hide show
  1. package/README.md +4 -0
  2. package/dist/bundles/{remoteTutorDrawer.es.js → aiDrawerManager.es.js} +17612 -17240
  3. package/dist/bundles/aiDrawerManager.es.js.map +1 -0
  4. package/dist/bundles/aiDrawerManager.umd.js +245 -0
  5. package/dist/bundles/aiDrawerManager.umd.js.map +1 -0
  6. package/dist/cjs/VERSION.d.ts +12 -0
  7. package/dist/cjs/VERSION.js +15 -0
  8. package/dist/cjs/ai.d.ts +3 -3
  9. package/dist/cjs/ai.js +5 -1
  10. package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.d.ts → AiDrawer/AiDrawer.d.ts} +11 -13
  11. package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.js → AiDrawer/AiDrawer.js} +27 -41
  12. package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts → AiDrawer/AiDrawer.stories.d.ts} +4 -3
  13. package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.js → AiDrawer/AiDrawer.stories.js} +32 -51
  14. package/dist/cjs/bundles/AiDrawer/AiDrawerManager.d.ts +12 -0
  15. package/dist/cjs/bundles/AiDrawer/AiDrawerManager.js +51 -0
  16. package/dist/cjs/bundles/AiDrawer/AiDrawerManager.stories.d.ts +6 -0
  17. package/dist/cjs/bundles/AiDrawer/AiDrawerManager.stories.js +267 -0
  18. package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.test.js → AiDrawer/AiDrawerManager.test.js} +22 -18
  19. package/dist/cjs/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.js +1 -1
  20. package/dist/cjs/bundles/aiDrawerManager.d.ts +6 -0
  21. package/dist/cjs/bundles/aiDrawerManager.js +44 -0
  22. package/dist/cjs/components/AiChat/AiChat.d.ts +3 -3
  23. package/dist/cjs/components/AiChat/AiChat.js +65 -53
  24. package/dist/cjs/components/AiChat/AiChat.stories.d.ts +0 -4
  25. package/dist/cjs/components/AiChat/AiChat.stories.js +5 -54
  26. package/dist/cjs/components/AiChat/AiChatContext.d.ts +26 -0
  27. package/dist/cjs/components/AiChat/AiChatContext.js +106 -0
  28. package/dist/cjs/components/AiChat/AiChatContext.stories.d.ts +14 -0
  29. package/dist/cjs/components/AiChat/AiChatContext.stories.js +75 -0
  30. package/dist/cjs/components/AiChat/AiChatMarkdown.stories.d.ts +15 -0
  31. package/dist/cjs/components/AiChat/AiChatMarkdown.stories.js +282 -0
  32. package/dist/cjs/components/AiChat/Markdown.d.ts +7 -0
  33. package/dist/cjs/components/AiChat/Markdown.js +14 -0
  34. package/dist/cjs/components/AiChat/test-utils/api.js +40 -1
  35. package/dist/cjs/components/AiChat/types.d.ts +25 -11
  36. package/dist/cjs/components/AiChat/types.js +1 -1
  37. package/dist/cjs/components/AiChat/utils.d.ts +1 -1
  38. package/dist/cjs/components/AiChat/utils.js +1 -1
  39. package/dist/cjs/components/LinkAdapter/LinkAdapter.js +1 -1
  40. package/dist/cjs/components/TabButtons/TabButtonList.js +1 -1
  41. package/dist/cjs/index.d.ts +1 -0
  42. package/dist/cjs/index.js +3 -1
  43. package/dist/cjs/utils/retryingFetch.d.ts +19 -0
  44. package/dist/cjs/utils/retryingFetch.js +98 -0
  45. package/dist/cjs/utils/retryingFetch.test.js +48 -0
  46. package/dist/esm/VERSION.d.ts +12 -0
  47. package/dist/esm/VERSION.js +12 -0
  48. package/dist/esm/ai.d.ts +3 -3
  49. package/dist/esm/ai.js +2 -1
  50. package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.d.ts → AiDrawer/AiDrawer.d.ts} +11 -13
  51. package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.js → AiDrawer/AiDrawer.js} +26 -40
  52. package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts → AiDrawer/AiDrawer.stories.d.ts} +4 -3
  53. package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.js → AiDrawer/AiDrawer.stories.js} +31 -50
  54. package/dist/esm/bundles/AiDrawer/AiDrawerManager.d.ts +12 -0
  55. package/dist/esm/bundles/AiDrawer/AiDrawerManager.js +48 -0
  56. package/dist/esm/bundles/AiDrawer/AiDrawerManager.stories.d.ts +6 -0
  57. package/dist/esm/bundles/AiDrawer/AiDrawerManager.stories.js +264 -0
  58. package/dist/esm/bundles/AiDrawer/AiDrawerManager.test.d.ts +1 -0
  59. package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.test.js → AiDrawer/AiDrawerManager.test.js} +22 -18
  60. package/dist/esm/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.js +1 -1
  61. package/dist/esm/bundles/aiDrawerManager.d.ts +6 -0
  62. package/dist/esm/bundles/aiDrawerManager.js +41 -0
  63. package/dist/esm/components/AiChat/AiChat.d.ts +3 -3
  64. package/dist/esm/components/AiChat/AiChat.js +65 -54
  65. package/dist/esm/components/AiChat/AiChat.stories.d.ts +0 -4
  66. package/dist/esm/components/AiChat/AiChat.stories.js +4 -53
  67. package/dist/esm/components/AiChat/AiChatContext.d.ts +26 -0
  68. package/dist/esm/components/AiChat/AiChatContext.js +102 -0
  69. package/dist/esm/components/AiChat/AiChatContext.stories.d.ts +14 -0
  70. package/dist/esm/components/AiChat/AiChatContext.stories.js +72 -0
  71. package/dist/esm/components/AiChat/AiChatMarkdown.stories.d.ts +15 -0
  72. package/dist/esm/components/AiChat/AiChatMarkdown.stories.js +279 -0
  73. package/dist/esm/components/AiChat/Markdown.d.ts +7 -0
  74. package/dist/esm/components/AiChat/Markdown.js +12 -0
  75. package/dist/esm/components/AiChat/test-utils/api.js +40 -1
  76. package/dist/esm/components/AiChat/types.d.ts +25 -11
  77. package/dist/esm/components/AiChat/types.js +1 -1
  78. package/dist/esm/components/AiChat/utils.d.ts +1 -1
  79. package/dist/esm/components/AiChat/utils.js +1 -1
  80. package/dist/esm/components/LinkAdapter/LinkAdapter.js +1 -1
  81. package/dist/esm/components/TabButtons/TabButtonList.js +1 -1
  82. package/dist/esm/index.d.ts +1 -0
  83. package/dist/esm/index.js +1 -0
  84. package/dist/esm/utils/retryingFetch.d.ts +19 -0
  85. package/dist/esm/utils/retryingFetch.js +96 -0
  86. package/dist/esm/utils/retryingFetch.test.d.ts +1 -0
  87. package/dist/esm/utils/retryingFetch.test.js +46 -0
  88. package/dist/tsconfig.tsbuildinfo +1 -1
  89. package/package.json +11 -7
  90. package/dist/bundles/remoteTutorDrawer.umd.js +0 -207
  91. package/dist/cjs/bundles/remoteTutorDrawer.d.ts +0 -7
  92. package/dist/cjs/bundles/remoteTutorDrawer.js +0 -40
  93. package/dist/esm/bundles/remoteTutorDrawer.d.ts +0 -7
  94. package/dist/esm/bundles/remoteTutorDrawer.js +0 -37
  95. /package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts → AiDrawer/AiDrawerManager.test.d.ts} +0 -0
  96. /package/dist/cjs/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.d.ts +0 -0
  97. /package/dist/{esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts → cjs/utils/retryingFetch.test.d.ts} +0 -0
  98. /package/dist/esm/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.d.ts +0 -0
@@ -0,0 +1,12 @@
1
+ /**
2
+ * This file is auto-generated at build time.
3
+ * Run node ./scripts/set_version.js to update the version.
4
+ * Do not update this file manually.
5
+ *
6
+ * NOTES:
7
+ * - In development, VERSION will always be "0.0.0"
8
+ * - The version should not simply be imported from package.json. This would
9
+ * result in all of the package.json being included in the bundled code, which
10
+ * is not desired.
11
+ */
12
+ export declare const VERSION = "0.0.0-bafccd3";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * This file is auto-generated at build time.
3
+ * Run node ./scripts/set_version.js to update the version.
4
+ * Do not update this file manually.
5
+ *
6
+ * NOTES:
7
+ * - In development, VERSION will always be "0.0.0"
8
+ * - The version should not simply be imported from package.json. This would
9
+ * result in all of the package.json being included in the bundled code, which
10
+ * is not desired.
11
+ */
12
+ export const VERSION = "0.0.0-bafccd3";
package/dist/esm/ai.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { AiChat } from "./components/AiChat/AiChat";
2
- export type { AiChatProps } from "./components/AiChat/AiChat";
3
- export type { AiChatMessage } from "./components/AiChat/types";
1
+ export { AiChat, AiChatDisplay } from "./components/AiChat/AiChat";
2
+ export { AiChatProvider, useAiChat } from "./components/AiChat/AiChatContext";
3
+ export type { AiChatMessage, AiChatContextProps, AiChatDisplayProps, AiChatProps, } from "./components/AiChat/types";
package/dist/esm/ai.js CHANGED
@@ -1 +1,2 @@
1
- export { AiChat } from "./components/AiChat/AiChat";
1
+ export { AiChat, AiChatDisplay } from "./components/AiChat/AiChat";
2
+ export { AiChatProvider, useAiChat } from "./components/AiChat/AiChatContext";
@@ -1,8 +1,7 @@
1
1
  import { FC } from "react";
2
- import { AiChatMessage } from "../../components/AiChat/types";
3
- import type { AiChatProps } from "../../components/AiChat/AiChat";
4
- type RemoteTutorDrawerInitMessage = {
5
- type: "smoot-design::tutor-drawer-open";
2
+ import type { AiChatProps, AiChatMessage } from "../../components/AiChat/types";
3
+ type AiDrawerInitMessage = {
4
+ type: "smoot-design::ai-drawer-open" | "smoot-design::tutor-drawer-open";
6
5
  payload: {
7
6
  blockType?: "problem" | "video";
8
7
  target?: string;
@@ -24,13 +23,8 @@ type RemoteTutorDrawerInitMessage = {
24
23
  };
25
24
  };
26
25
  };
27
- type RemoteTutorDrawerProps = {
26
+ type AiDrawerProps = {
28
27
  className?: string;
29
- /**
30
- * The origin of the messages that will be received to open the chat.
31
- * The drawer will ignore all message events not from this origin.
32
- */
33
- messageOrigin: string;
34
28
  /**
35
29
  * Transform the body of the request before sending it to the server.
36
30
  * Its result will be merged with the per-message requestBody opt, with
@@ -50,8 +44,12 @@ type RemoteTutorDrawerProps = {
50
44
  /**
51
45
  * Pass to target a specific drawer instance where multiple are on the page.
52
46
  */
47
+ /** @deprecated The AiDrawerManager now handles multiple AiDrawer instance removing the need to target */
53
48
  target?: string;
49
+ payload?: AiDrawerInitMessage["payload"];
50
+ open?: boolean;
51
+ onClose?: () => void;
54
52
  };
55
- declare const RemoteTutorDrawer: FC<RemoteTutorDrawerProps>;
56
- export { RemoteTutorDrawer };
57
- export type { RemoteTutorDrawerProps, RemoteTutorDrawerInitMessage };
53
+ declare const AiDrawer: FC<AiDrawerProps>;
54
+ export { AiDrawer };
55
+ export type { AiDrawerProps, AiDrawerInitMessage };
@@ -22,6 +22,7 @@ import TabPanel from "@mui/lab/TabPanel";
22
22
  import { AiChat } from "../../components/AiChat/AiChat";
23
23
  import { ActionButton } from "../../components/Button/ActionButton";
24
24
  import { FlashcardsScreen } from "./FlashcardsScreen";
25
+ import { VERSION } from "../../VERSION";
25
26
  const Header = styled.div(({ theme }) => ({
26
27
  display: "flex",
27
28
  alignItems: "center",
@@ -149,6 +150,12 @@ const useContentFetch = (contentUrl) => {
149
150
  }, [contentUrl]);
150
151
  return { response, loading };
151
152
  };
153
+ const DEFAULT_PROBLEM_INITIAL_MESSAGES = [
154
+ {
155
+ role: "assistant",
156
+ content: "Let's try to work on this problem together. It would be great to hear how you're thinking about solving it. Can you walk me through the approach you're considering?",
157
+ },
158
+ ];
152
159
  const DEFAULT_VIDEO_ENTRY_SCREEN_TITLE = "What do you want to know about this video?";
153
160
  const DEFAULT_VIDEO_STARTERS = [
154
161
  { content: "What are the most important concepts introduced in the video?" },
@@ -157,23 +164,21 @@ const DEFAULT_VIDEO_STARTERS = [
157
164
  },
158
165
  { content: "What are the key terms introduced in this video?" },
159
166
  ];
160
- const ChatComponent = ({ payload, transformBody, fetchOpts, scrollElement, entryScreenEnabled, entryScreenTitle, conversationStarters, hasTabs, }) => {
167
+ const ChatComponent = ({ payload, transformBody, fetchOpts, scrollElement, entryScreenEnabled, entryScreenTitle, conversationStarters, initialMessages, hasTabs, needsMathJax, }) => {
161
168
  if (!payload)
162
169
  return null;
163
- return (React.createElement(StyledAiChat, { chatId: payload.chatId, conversationStarters: conversationStarters, initialMessages: payload.initialMessages, scrollElement: scrollElement, entryScreenEnabled: entryScreenEnabled, entryScreenTitle: entryScreenTitle, requestOpts: {
170
+ return (React.createElement(StyledAiChat, { key: payload.chatId, chatId: payload.chatId, conversationStarters: conversationStarters, initialMessages: initialMessages, scrollElement: scrollElement, entryScreenEnabled: entryScreenEnabled, entryScreenTitle: entryScreenTitle, requestOpts: {
164
171
  transformBody: (messages) => (Object.assign(Object.assign({}, payload.requestBody), transformBody === null || transformBody === void 0 ? void 0 : transformBody(messages))),
165
172
  apiUrl: payload.apiUrl,
166
173
  fetchOpts: Object.assign(Object.assign({}, DEFAULT_FETCH_OPTS), fetchOpts),
167
- }, hasTabs: hasTabs }));
174
+ }, hasTabs: hasTabs, useMathJax: needsMathJax }));
168
175
  };
169
176
  const randomItems = (array, count) => {
170
177
  const shuffled = [...array].sort(() => 0.5 - Math.random());
171
178
  return shuffled.slice(0, count);
172
179
  };
173
- const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className, fetchOpts, target, }) => {
174
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
175
- const [open, setOpen] = useState(false);
176
- const [payload, setPayload] = useState(null);
180
+ const AiDrawer = ({ transformBody = identity, className, fetchOpts, payload, open, onClose, }) => {
181
+ var _a, _b, _c, _d, _e, _f, _g;
177
182
  const [tab, setTab] = useState("chat");
178
183
  const { response } = useContentFetch((_a = payload === null || payload === void 0 ? void 0 : payload.summary) === null || _a === void 0 ? void 0 : _a.apiUrl);
179
184
  const [_wasKeyboardFocus, setWasKeyboardFocus] = useState(false);
@@ -193,25 +198,6 @@ const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className,
193
198
  setScrollElement(node);
194
199
  }
195
200
  };
196
- useEffect(() => {
197
- const cb = (event) => {
198
- if (event.origin !== messageOrigin) {
199
- if (process.env.NODE_ENV === "development") {
200
- console.warn(`RemoteTutorDrawer: received message from unexpected origin: ${event.origin}`);
201
- }
202
- return;
203
- }
204
- if (event.data.type === "smoot-design::tutor-drawer-open" &&
205
- event.data.payload.target === target) {
206
- setOpen(true);
207
- setPayload(event.data.payload);
208
- }
209
- };
210
- window.addEventListener("message", cb);
211
- return () => {
212
- window.removeEventListener("message", cb);
213
- };
214
- }, [messageOrigin, target]);
215
201
  useEffect(() => {
216
202
  var _a;
217
203
  (_a = scrollElement === null || scrollElement === void 0 ? void 0 : scrollElement.scrollTo) === null || _a === void 0 ? void 0 : _a.call(scrollElement, {
@@ -230,11 +216,11 @@ const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className,
230
216
  : DEFAULT_VIDEO_STARTERS));
231
217
  }, [payload, response]);
232
218
  if (!payload) {
233
- return React.createElement("div", { "data-testid": "remote-tutor-drawer-waiting" });
219
+ return React.createElement("div", { "data-testid": "ai-drawer-waiting" });
234
220
  }
235
- const { blockType, chat } = payload;
221
+ const { title, blockType, chat } = payload;
236
222
  const hasTabs = blockType === "video";
237
- return (React.createElement(Drawer, { "data-testid": "remote-tutor-drawer", className: className, PaperProps: {
223
+ return (React.createElement(Drawer, { "data-smoot-version": VERSION, className: className, PaperProps: {
238
224
  ref: paperRefCallback,
239
225
  sx: {
240
226
  width: "900px",
@@ -245,29 +231,29 @@ const RemoteTutorDrawer = ({ messageOrigin, transformBody = identity, className,
245
231
  md: "0 32px",
246
232
  },
247
233
  },
248
- }, anchor: "right", open: open, onClose: () => setOpen(false) },
234
+ }, anchor: "right", open: open, onClose: onClose, role: "dialog", "aria-modal": "true", keepMounted: true },
249
235
  React.createElement(Header, null,
250
236
  React.createElement(Title, null,
251
- payload.title ? React.createElement(RiSparkling2Line, null) : null,
252
- React.createElement(Typography, { variant: "body1", component: "h2" }, ((_b = payload.title) === null || _b === void 0 ? void 0 : _b.includes("AskTIM")) ? (React.createElement(React.Fragment, null,
237
+ title ? React.createElement(RiSparkling2Line, null) : null,
238
+ React.createElement(Typography, { variant: "body1", component: "h1" }, (title === null || title === void 0 ? void 0 : title.includes("AskTIM")) ? (React.createElement(React.Fragment, null,
253
239
  "Ask",
254
240
  React.createElement("strong", null, "TIM"),
255
- payload.title.replace("AskTIM", ""))) : (payload.title))),
256
- React.createElement(CloseButton, { variant: "text", size: "medium", onClick: () => setOpen(false), "aria-label": "Close" },
241
+ title.replace("AskTIM", ""))) : (title))),
242
+ React.createElement(CloseButton, { variant: "text", size: "medium", onClick: onClose, "aria-label": "Close" },
257
243
  React.createElement(RiCloseLine, null))),
258
- blockType === "problem" ? (React.createElement(ChatComponent, { payload: chat, transformBody: transformBody, fetchOpts: fetchOpts, scrollElement: scrollElement, entryScreenEnabled: (_d = (_c = payload.chat) === null || _c === void 0 ? void 0 : _c.entryScreenEnabled) !== null && _d !== void 0 ? _d : false, entryScreenTitle: payload.chat.entryScreenTitle, hasTabs: hasTabs })) : null,
244
+ blockType === "problem" ? (React.createElement(ChatComponent, { payload: chat, transformBody: transformBody, fetchOpts: fetchOpts, scrollElement: scrollElement, entryScreenEnabled: (_b = chat === null || chat === void 0 ? void 0 : chat.entryScreenEnabled) !== null && _b !== void 0 ? _b : false, entryScreenTitle: chat.entryScreenTitle, initialMessages: chat.initialMessages || DEFAULT_PROBLEM_INITIAL_MESSAGES, hasTabs: hasTabs, needsMathJax: true })) : null,
259
245
  blockType === "video" ? (React.createElement(TabContext, { value: tab },
260
246
  React.createElement(StyledTabButtonList, { styleVariant: "chat", onChange: (e, tab) => setTab(tab) },
261
247
  React.createElement(TabButton, { value: "chat", label: "Chat" }),
262
- ((_e = response === null || response === void 0 ? void 0 : response.flashcards) === null || _e === void 0 ? void 0 : _e.length) ? (React.createElement(TabButton, { value: "flashcards", label: "Flashcards", onMouseDown: handleMouseDown, onFocus: handleFocus })) : null,
248
+ ((_c = response === null || response === void 0 ? void 0 : response.flashcards) === null || _c === void 0 ? void 0 : _c.length) ? (React.createElement(TabButton, { value: "flashcards", label: "Flashcards", onMouseDown: handleMouseDown, onFocus: handleFocus })) : null,
263
249
  React.createElement(TabButton, { value: "summary", label: "Summary" })),
264
250
  React.createElement(StyledTabPanel, { value: "chat", keepMounted: true },
265
- React.createElement(ChatComponent, { payload: Object.assign({}, chat), transformBody: transformBody, fetchOpts: fetchOpts, scrollElement: scrollElement, entryScreenEnabled: (_g = (_f = payload.chat) === null || _f === void 0 ? void 0 : _f.entryScreenEnabled) !== null && _g !== void 0 ? _g : true, entryScreenTitle: (_h = payload.chat.entryScreenTitle) !== null && _h !== void 0 ? _h : DEFAULT_VIDEO_ENTRY_SCREEN_TITLE, conversationStarters: conversationStarters, hasTabs: hasTabs })),
266
- ((_j = response === null || response === void 0 ? void 0 : response.flashcards) === null || _j === void 0 ? void 0 : _j.length) ? (React.createElement(StyledTabPanel, { value: "flashcards" },
251
+ React.createElement(ChatComponent, { payload: chat, transformBody: transformBody, fetchOpts: fetchOpts, scrollElement: scrollElement, entryScreenEnabled: (_d = chat === null || chat === void 0 ? void 0 : chat.entryScreenEnabled) !== null && _d !== void 0 ? _d : true, entryScreenTitle: (_e = chat.entryScreenTitle) !== null && _e !== void 0 ? _e : DEFAULT_VIDEO_ENTRY_SCREEN_TITLE, conversationStarters: conversationStarters, initialMessages: chat.initialMessages, hasTabs: hasTabs, needsMathJax: false })),
252
+ ((_f = response === null || response === void 0 ? void 0 : response.flashcards) === null || _f === void 0 ? void 0 : _f.length) ? (React.createElement(StyledTabPanel, { value: "flashcards" },
267
253
  React.createElement(FlashcardsScreen, { flashcards: response === null || response === void 0 ? void 0 : response.flashcards, wasKeyboardFocus: _wasKeyboardFocus }))) : null,
268
254
  React.createElement(StyledTabPanel, { value: "summary" },
269
255
  React.createElement(Typography, { variant: "h4", component: "h4" }),
270
256
  React.createElement(StyledHTML, null,
271
- React.createElement(Markdown, { rehypePlugins: [rehypeRaw] }, (_k = response === null || response === void 0 ? void 0 : response.summary) !== null && _k !== void 0 ? _k : ""))))) : null));
257
+ React.createElement(Markdown, { rehypePlugins: [rehypeRaw] }, (_g = response === null || response === void 0 ? void 0 : response.summary) !== null && _g !== void 0 ? _g : ""))))) : null));
272
258
  };
273
- export { RemoteTutorDrawer };
259
+ export { AiDrawer };
@@ -1,9 +1,10 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
- import { RemoteTutorDrawer } from "./RemoteTutorDrawer";
3
- declare const meta: Meta<typeof RemoteTutorDrawer>;
2
+ import { AiDrawer } from "./AiDrawer";
3
+ declare const meta: Meta<typeof AiDrawer>;
4
4
  export default meta;
5
- type Story = StoryObj<typeof RemoteTutorDrawer>;
5
+ type Story = StoryObj<typeof AiDrawer>;
6
6
  export declare const ProblemStory: Story;
7
+ export declare const ProblemDefaultInitialMessagesStory: Story;
7
8
  export declare const EntryScreenStory: Story;
8
9
  /**
9
10
  * The chat entry screen is shown by default for the video blocks Tutor drawer.
@@ -1,9 +1,10 @@
1
1
  /* eslint-disable react-hooks/rules-of-hooks */
2
2
  import * as React from "react";
3
- import invariant from "tiny-invariant";
4
3
  import { http, HttpResponse } from "msw";
5
4
  import { handlers } from "../../components/AiChat/test-utils/api";
6
- import { RemoteTutorDrawer, } from "./RemoteTutorDrawer";
5
+ import { AiDrawer } from "./AiDrawer";
6
+ import { MathJaxContext } from "better-react-mathjax";
7
+ import Button from "@mui/material/Button";
7
8
  const TEST_API_STREAMING = "http://localhost:4567/streaming";
8
9
  const CONTENT_FILE_URL = "http://localhost:4567/api/v1/contentfiles/?edx_module_id=1";
9
10
  const INITIAL_MESSAGES = [
@@ -17,50 +18,22 @@ const STARTERS = [
17
18
  { content: "I want to understand global warming. " },
18
19
  { content: "I am curious about AI applications for business" },
19
20
  ];
20
- const buildIFrame = (payload) => (el) => {
21
- var _a;
22
- if (!el)
23
- return;
24
- const doc = el.contentDocument;
25
- const parent = (_a = el.contentWindow) === null || _a === void 0 ? void 0 : _a.parent;
26
- invariant(doc && parent);
27
- const button = doc.createElement("button");
28
- button.textContent = "Open drawer (send message to parent)";
29
- doc.body.appendChild(button);
30
- const div = doc.createElement("div");
31
- doc.body.appendChild(div);
32
- const label = doc.createElement("label");
33
- label.textContent = "Message Data:";
34
- div.appendChild(label);
35
- const textarea = doc.createElement("textarea");
36
- div.append(textarea);
37
- textarea.style["display"] = "block";
38
- textarea.style["width"] = "100%";
39
- textarea.style["height"] = "500px";
40
- const message = {
41
- type: "smoot-design::tutor-drawer-open",
42
- payload,
43
- };
44
- textarea.value = JSON.stringify(message, null, 2);
45
- button.addEventListener("click", () => {
46
- parent.postMessage(JSON.parse(textarea.value));
47
- });
48
- };
49
- const IFrame = ({ payload }) => {
50
- return (React.createElement("iframe", { width: "100%", height: "600px", ref: buildIFrame(payload), title: "button frame" }));
51
- };
52
21
  const meta = {
53
- title: "smoot-design/AI/RemoteTutorDrawer",
54
- render: ({ target }, { parameters: { payload } }) => (React.createElement(React.Fragment, null,
55
- React.createElement(IFrame, { payload: payload }),
56
- React.createElement(RemoteTutorDrawer, { target: target, messageOrigin: "http://localhost:6006" }))),
22
+ title: "smoot-design/AI/AiDrawer",
23
+ component: AiDrawer,
24
+ render: ({ payload }) => {
25
+ const [open, setOpen] = React.useState(false);
26
+ return (React.createElement(React.Fragment, null,
27
+ React.createElement(Button, { variant: "outlined", onClick: () => setOpen(true) }, "Open Drawer"),
28
+ React.createElement("p", null, "Message data:"),
29
+ React.createElement("pre", null, JSON.stringify({ payload }, null, 2)),
30
+ React.createElement(MathJaxContext, null,
31
+ React.createElement(AiDrawer, { payload: payload, open: open, onClose: () => setOpen(false) }))));
32
+ },
57
33
  };
58
34
  export default meta;
59
35
  export const ProblemStory = {
60
36
  args: {
61
- target: "problem-frame",
62
- },
63
- parameters: {
64
37
  payload: {
65
38
  blockType: "problem",
66
39
  target: "problem-frame",
@@ -73,11 +46,21 @@ export const ProblemStory = {
73
46
  },
74
47
  },
75
48
  };
76
- export const EntryScreenStory = {
49
+ export const ProblemDefaultInitialMessagesStory = {
77
50
  args: {
78
- target: "entry-screen-frame",
51
+ payload: {
52
+ blockType: "problem",
53
+ target: "problem-frame-default-initial-messages",
54
+ title: "AskTIM for help with Problem: Derivatives 1.1",
55
+ chat: {
56
+ apiUrl: TEST_API_STREAMING,
57
+ conversationStarters: STARTERS,
58
+ },
59
+ },
79
60
  },
80
- parameters: {
61
+ };
62
+ export const EntryScreenStory = {
63
+ args: {
81
64
  payload: {
82
65
  blockType: "problem",
83
66
  target: "entry-screen-frame",
@@ -96,9 +79,6 @@ export const EntryScreenStory = {
96
79
  */
97
80
  export const VideoStory = {
98
81
  args: {
99
- target: "video-frame",
100
- },
101
- parameters: {
102
82
  payload: {
103
83
  blockType: "video",
104
84
  target: "video-frame",
@@ -110,6 +90,8 @@ export const VideoStory = {
110
90
  apiUrl: CONTENT_FILE_URL,
111
91
  },
112
92
  },
93
+ },
94
+ parameters: {
113
95
  msw: {
114
96
  handlers: [
115
97
  http.get(CONTENT_FILE_URL, () => {
@@ -126,9 +108,6 @@ export const VideoStory = {
126
108
  */
127
109
  export const FlashcardConversationStartersStory = {
128
110
  args: {
129
- target: "starters-frame",
130
- },
131
- parameters: {
132
111
  payload: {
133
112
  blockType: "video",
134
113
  target: "starters-frame",
@@ -139,6 +118,8 @@ export const FlashcardConversationStartersStory = {
139
118
  apiUrl: CONTENT_FILE_URL,
140
119
  },
141
120
  },
121
+ },
122
+ parameters: {
142
123
  msw: {
143
124
  handlers: [
144
125
  http.get(CONTENT_FILE_URL, () => {
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ import type { AiDrawerProps } from "./AiDrawer";
3
+ type AiDrawerManagerProps = {
4
+ /**
5
+ * The origin of the messages that will be received to open the chat.
6
+ * The drawer will ignore all message events not from this origin.
7
+ */
8
+ messageOrigin: string;
9
+ } & AiDrawerProps;
10
+ declare const AiDrawerManager: ({ className, messageOrigin, transformBody, fetchOpts, target, }: AiDrawerManagerProps) => React.JSX.Element;
11
+ export { AiDrawerManager };
12
+ export type { AiDrawerManagerProps };
@@ -0,0 +1,48 @@
1
+ import * as React from "react";
2
+ import { useEffect, useState } from "react";
3
+ import { AiDrawer } from "./AiDrawer";
4
+ import { MathJaxContext } from "better-react-mathjax";
5
+ const hashPayload = (payload) => {
6
+ const str = JSON.stringify(payload);
7
+ let hash = 5381;
8
+ for (let i = 0; i < str.length; i++) {
9
+ hash = (hash << 5) + hash + str.charCodeAt(i);
10
+ hash = hash & hash;
11
+ }
12
+ return Math.abs(hash).toString(36);
13
+ };
14
+ const AiDrawerManager = ({ className, messageOrigin, transformBody, fetchOpts, target, }) => {
15
+ const [drawerStates, setDrawerStates] = useState({});
16
+ useEffect(() => {
17
+ const cb = (event) => {
18
+ if (event.origin !== messageOrigin) {
19
+ if (process.env.NODE_ENV === "development") {
20
+ console.warn(`AiDrawerManager: received message from unexpected origin: ${event.origin}`);
21
+ }
22
+ return;
23
+ }
24
+ if ([
25
+ "smoot-design::ai-drawer-open",
26
+ "smoot-design::tutor-drawer-open", // legacy
27
+ ].includes(event.data.type)) {
28
+ const key = hashPayload(event.data.payload);
29
+ event.data.payload.chat.chatId = event.data.payload.chat.chatId || key;
30
+ setDrawerStates((prev) => (Object.assign(Object.assign({}, prev), { [key]: { key, open: false, payload: event.data.payload } })));
31
+ requestAnimationFrame(() => {
32
+ setDrawerStates((prev) => (Object.assign(Object.assign({}, prev), { [key]: Object.assign(Object.assign({}, prev[key]), { open: true }) })));
33
+ });
34
+ }
35
+ };
36
+ window.addEventListener("message", cb);
37
+ return () => {
38
+ window.removeEventListener("message", cb);
39
+ };
40
+ }, [messageOrigin, target]);
41
+ if (Object.values(drawerStates).length === 0) {
42
+ return React.createElement("div", { "data-testid": "ai-drawer-manager-waiting" });
43
+ }
44
+ return (React.createElement(MathJaxContext, null, Object.values(drawerStates).map(({ key, open, payload }) => (React.createElement(AiDrawer, { key: key, className: className, transformBody: transformBody, fetchOpts: fetchOpts, payload: payload, open: open, onClose: () => {
45
+ setDrawerStates((prev) => (Object.assign(Object.assign({}, prev), { [key]: Object.assign(Object.assign({}, prev[key]), { open: false }) })));
46
+ } })))));
47
+ };
48
+ export { AiDrawerManager };
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { AiDrawerManager } from "./AiDrawerManager";
3
+ declare const meta: Meta<typeof AiDrawerManager>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof AiDrawerManager>;
6
+ export declare const AiDrawerManagerStory: Story;