@super_studio/ecforce-ai-agent-react 1.0.0 → 1.1.0-canary.1
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.
- package/dist/components/chatbot-frame.d.mts +2 -2
- package/dist/components/lottie-ai-icon.mjs +6 -8
- package/dist/components/lottie-ai-icon.mjs.map +1 -1
- package/dist/components/provider/chatbot-provider.d.mts +3 -1
- package/dist/components/provider/chatbot-provider.d.mts.map +1 -1
- package/dist/components/provider/chatbot-provider.mjs +2 -1
- package/dist/components/provider/chatbot-provider.mjs.map +1 -1
- package/dist/components/provider/use-chatbot-frame-handler.d.mts +13 -1
- package/dist/components/provider/use-chatbot-frame-handler.d.mts.map +1 -1
- package/dist/components/provider/use-chatbot-frame-handler.mjs +31 -1
- package/dist/components/provider/use-chatbot-frame-handler.mjs.map +1 -1
- package/dist/components/sheet.d.mts +2 -2
- package/package.json +1 -1
- package/src/components/lottie-ai-icon.tsx +5 -8
- package/src/components/provider/chatbot-provider.tsx +5 -0
- package/src/components/provider/use-chatbot-frame-handler.tsx +62 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime3 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/components/chatbot-frame.d.ts
|
|
4
4
|
type ChatbotFrameProps = {
|
|
@@ -37,7 +37,7 @@ declare function ChatbotFrame({
|
|
|
37
37
|
enabled,
|
|
38
38
|
url,
|
|
39
39
|
className
|
|
40
|
-
}: ChatbotFrameProps):
|
|
40
|
+
}: ChatbotFrameProps): react_jsx_runtime3.JSX.Element;
|
|
41
41
|
type SessionData = {
|
|
42
42
|
token: string;
|
|
43
43
|
expiresAt: string;
|
|
@@ -4,17 +4,17 @@ import * as React$1 from "react";
|
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
//#region src/components/lottie-ai-icon.tsx
|
|
7
|
-
function LottieAiIcon({ src, width = 18, height = 18, loop = true, autoplay = false,
|
|
7
|
+
function LottieAiIcon({ src, width = 18, height = 18, loop = true, autoplay = false, fallback }) {
|
|
8
8
|
const containerRef = React$1.useRef(null);
|
|
9
9
|
const [ready, setReady] = React$1.useState(false);
|
|
10
10
|
React$1.useEffect(() => {
|
|
11
11
|
if (typeof window === "undefined") return;
|
|
12
|
-
if (!document.querySelector("script[data-dotlottie-
|
|
12
|
+
if (!document.querySelector("script[data-dotlottie-wc]")) {
|
|
13
13
|
const scriptEl = document.createElement("script");
|
|
14
14
|
scriptEl.type = "module";
|
|
15
15
|
scriptEl.async = true;
|
|
16
|
-
scriptEl.src = "https://unpkg.com/@dotlottie
|
|
17
|
-
scriptEl.setAttribute("data-dotlottie-
|
|
16
|
+
scriptEl.src = "https://unpkg.com/@lottiefiles/dotlottie-wc@0.9.8/dist/dotlottie-wc.js";
|
|
17
|
+
scriptEl.setAttribute("data-dotlottie-wc", "true");
|
|
18
18
|
scriptEl.onload = () => setReady(true);
|
|
19
19
|
scriptEl.onerror = () => setReady(false);
|
|
20
20
|
document.head.appendChild(scriptEl);
|
|
@@ -24,12 +24,11 @@ function LottieAiIcon({ src, width = 18, height = 18, loop = true, autoplay = fa
|
|
|
24
24
|
if (!ready || !containerRef.current) return;
|
|
25
25
|
const container = containerRef.current;
|
|
26
26
|
container.innerHTML = "";
|
|
27
|
-
const player = document.createElement("dotlottie-
|
|
27
|
+
const player = document.createElement("dotlottie-wc");
|
|
28
28
|
player.setAttribute("src", src);
|
|
29
29
|
player.setAttribute("style", `width:${width}px;height:${height}px`);
|
|
30
30
|
if (loop) player.setAttribute("loop", "");
|
|
31
31
|
if (autoplay) player.setAttribute("autoplay", "");
|
|
32
|
-
if (hover) player.setAttribute("hover", "");
|
|
33
32
|
container.appendChild(player);
|
|
34
33
|
return () => {
|
|
35
34
|
container.innerHTML = "";
|
|
@@ -40,8 +39,7 @@ function LottieAiIcon({ src, width = 18, height = 18, loop = true, autoplay = fa
|
|
|
40
39
|
width,
|
|
41
40
|
height,
|
|
42
41
|
loop,
|
|
43
|
-
autoplay
|
|
44
|
-
hover
|
|
42
|
+
autoplay
|
|
45
43
|
]);
|
|
46
44
|
return /* @__PURE__ */ jsx("div", {
|
|
47
45
|
ref: containerRef,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lottie-ai-icon.mjs","names":["React"],"sources":["../../src/components/lottie-ai-icon.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\ntype LottieAiIconProps = {\n src: string;\n width?: number;\n height?: number;\n loop?: boolean;\n autoplay?: boolean;\n
|
|
1
|
+
{"version":3,"file":"lottie-ai-icon.mjs","names":["React"],"sources":["../../src/components/lottie-ai-icon.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\ntype LottieAiIconProps = {\n src: string;\n width?: number;\n height?: number;\n loop?: boolean;\n autoplay?: boolean;\n fallback?: React.ReactNode;\n};\n\nexport function LottieAiIcon({\n src,\n width = 18,\n height = 18,\n loop = true,\n autoplay = false,\n fallback,\n}: LottieAiIconProps) {\n const containerRef = React.useRef<HTMLDivElement>(null);\n const [ready, setReady] = React.useState(false);\n\n React.useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const existing = document.querySelector(\"script[data-dotlottie-wc]\");\n if (!existing) {\n const scriptEl = document.createElement(\"script\");\n scriptEl.type = \"module\";\n scriptEl.async = true;\n scriptEl.src =\n \"https://unpkg.com/@lottiefiles/dotlottie-wc@0.9.8/dist/dotlottie-wc.js\";\n scriptEl.setAttribute(\"data-dotlottie-wc\", \"true\");\n scriptEl.onload = () => setReady(true);\n scriptEl.onerror = () => setReady(false);\n document.head.appendChild(scriptEl);\n } else {\n setReady(true);\n }\n }, []);\n\n React.useEffect(() => {\n if (!ready || !containerRef.current) return;\n const container = containerRef.current;\n container.innerHTML = \"\";\n const player = document.createElement(\"dotlottie-wc\");\n player.setAttribute(\"src\", src);\n player.setAttribute(\"style\", `width:${width}px;height:${height}px`);\n if (loop) player.setAttribute(\"loop\", \"\");\n if (autoplay) player.setAttribute(\"autoplay\", \"\");\n container.appendChild(player);\n return () => {\n container.innerHTML = \"\";\n };\n }, [ready, src, width, height, loop, autoplay]);\n\n return (\n <div ref={containerRef} aria-hidden=\"true\">\n {!ready &&\n (fallback ?? (\n <svg\n width={width}\n height={height}\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;AAaA,SAAgB,aAAa,EAC3B,KACA,QAAQ,IACR,SAAS,IACT,OAAO,MACP,WAAW,OACX,YACoB;CACpB,MAAM,eAAeA,QAAM,OAAuB,KAAK;CACvD,MAAM,CAAC,OAAO,YAAYA,QAAM,SAAS,MAAM;AAE/C,SAAM,gBAAgB;AACpB,MAAI,OAAO,WAAW,YAAa;AAGnC,MAAI,CADa,SAAS,cAAc,4BAA4B,EACrD;GACb,MAAM,WAAW,SAAS,cAAc,SAAS;AACjD,YAAS,OAAO;AAChB,YAAS,QAAQ;AACjB,YAAS,MACP;AACF,YAAS,aAAa,qBAAqB,OAAO;AAClD,YAAS,eAAe,SAAS,KAAK;AACtC,YAAS,gBAAgB,SAAS,MAAM;AACxC,YAAS,KAAK,YAAY,SAAS;QAEnC,UAAS,KAAK;IAEf,EAAE,CAAC;AAEN,SAAM,gBAAgB;AACpB,MAAI,CAAC,SAAS,CAAC,aAAa,QAAS;EACrC,MAAM,YAAY,aAAa;AAC/B,YAAU,YAAY;EACtB,MAAM,SAAS,SAAS,cAAc,eAAe;AACrD,SAAO,aAAa,OAAO,IAAI;AAC/B,SAAO,aAAa,SAAS,SAAS,MAAM,YAAY,OAAO,IAAI;AACnE,MAAI,KAAM,QAAO,aAAa,QAAQ,GAAG;AACzC,MAAI,SAAU,QAAO,aAAa,YAAY,GAAG;AACjD,YAAU,YAAY,OAAO;AAC7B,eAAa;AACX,aAAU,YAAY;;IAEvB;EAAC;EAAO;EAAK;EAAO;EAAQ;EAAM;EAAS,CAAC;AAE/C,QACE,oBAAC;EAAI,KAAK;EAAc,eAAY;YACjC,CAAC,UACC,sDACC,oBAAC;GACQ;GACC;GACR,SAAQ;GACR,MAAK;IACL;GAEF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InitProps, MCP } from "./use-chatbot-frame-handler.mjs";
|
|
1
|
+
import { InitProps, MCP, SendAppMessagePayload } from "./use-chatbot-frame-handler.mjs";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
|
|
@@ -26,6 +26,8 @@ type ChatbotContextType = {
|
|
|
26
26
|
setAppName: (appName: string) => void;
|
|
27
27
|
/** セッショントークンを設定 */
|
|
28
28
|
setSessionToken: (sessionToken: string) => void;
|
|
29
|
+
/** アプリからメッセージを送信 */
|
|
30
|
+
sendAppMessage: (payload: SendAppMessagePayload) => void;
|
|
29
31
|
/** チャットボットが準備できたか */
|
|
30
32
|
isReady: boolean;
|
|
31
33
|
/** チャットボットが初期化されたか */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatbot-provider.d.mts","names":[],"sources":["../../../src/components/provider/chatbot-provider.tsx"],"sourcesContent":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"chatbot-provider.d.mts","names":[],"sources":["../../../src/components/provider/chatbot-provider.tsx"],"sourcesContent":[],"mappings":";;;;;KAWK,kBAAA;;;EAAA;EAgBW,IAAA,EAAA,OAAA;EAEE;EAMU,OAAA,EAAA,CAAA,IAAA,EAAA,OAAA,EAAA,GAAA,IAAA;EASF;EAAiB,UAAA,EAAA,OAAA;EAO3B;EAQX,aAAA,EAAA,CAAA,QAAoB,EAAA,OAAA,EACb,GAAA,IAAM;EAGF;EAAkB,YAAA,EAAA,OAAA;EAAY;EAAoB,eAAA,EAAA,CAAA,UAAA,EAAA,OAAA,EAAA,GAAA,IAAA;EAAA;gBApClD;;kBAEE;;;;;;4BAMU;;;;;;;;;0BASF;;iBAOV,UAAA,CAAA,GAAU;KAQrB,oBAAA;YACO,KAAA,CAAM;;iBAGF,eAAA;;GAA8B,uBAAoB,kBAAA,CAAA,GAAA,CAAA"}
|
|
@@ -14,7 +14,7 @@ function useChatbot() {
|
|
|
14
14
|
}
|
|
15
15
|
function ChatbotProvider({ children }) {
|
|
16
16
|
const { hasOpened, open, isExpanded, isFullScreen, setOpen, setIsExpanded, setIsFullScreen } = useChatbotWindowStates();
|
|
17
|
-
const { setMcps, setAppName, setSessionToken, init, isReady, isInitialized, setIframeEl } = useChatbotFrameHandler({
|
|
17
|
+
const { setMcps, setAppName, setSessionToken, sendAppMessage, init, isReady, isInitialized, setIframeEl } = useChatbotFrameHandler({
|
|
18
18
|
setOpen,
|
|
19
19
|
setIsExpanded,
|
|
20
20
|
setIsFullScreen
|
|
@@ -28,6 +28,7 @@ function ChatbotProvider({ children }) {
|
|
|
28
28
|
isFullScreen,
|
|
29
29
|
setIsFullScreen,
|
|
30
30
|
setSessionToken,
|
|
31
|
+
sendAppMessage,
|
|
31
32
|
init,
|
|
32
33
|
setMcps,
|
|
33
34
|
setAppName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatbot-provider.mjs","names":[],"sources":["../../../src/components/provider/chatbot-provider.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport {\n useChatbotFrameHandler,\n type InitProps,\n type MCP,\n} from \"./use-chatbot-frame-handler\";\nimport { useChatbotWindowStates } from \"./use-chatbot-window-states\";\n\ntype ChatbotContextType = {\n /** 1回チャットボットを開いたら、固定でtrueになる */\n hasOpened: boolean;\n /** チャットボットを開いているか */\n open: boolean;\n /** チャットボットを開く */\n setOpen: (open: boolean) => void;\n /** チャットボットを展開しているか */\n isExpanded: boolean;\n /** チャットボットを展開する */\n setIsExpanded: (expanded: boolean) => void;\n /** チャットボットをフルスクリーンにしているか */\n isFullScreen: boolean;\n /** チャットボットをフルスクリーンにする */\n setIsFullScreen: (fullScreen: boolean) => void;\n /** チャットボットを初期化 */\n init: (props: InitProps) => void;\n /** MCPを設定 */\n setMcps: (mcps: MCP[]) => void;\n /** アプリ名を設定 */\n setAppName: (appName: string) => void;\n /** セッショントークンを設定 */\n setSessionToken: (sessionToken: string) => void;\n /** チャットボットが準備できたか */\n isReady: boolean;\n /** チャットボットが初期化されたか */\n isInitialized: boolean;\n /**\n * @internal\n * チャットボットのiframe要素を設定\n */\n setIframeEl: (iframeEl: HTMLIFrameElement | null) => void;\n};\n\nconst ChatbotContext = React.createContext<ChatbotContextType | undefined>(\n undefined,\n);\n\nexport function useChatbot() {\n const context = React.useContext(ChatbotContext);\n if (!context) {\n throw new Error(\"useChatbot must be used within a ChatbotProvider\");\n }\n return context;\n}\n\ntype ChatbotProviderProps = {\n children: React.ReactNode;\n};\n\nexport function ChatbotProvider({ children }: ChatbotProviderProps) {\n const {\n hasOpened,\n open,\n isExpanded,\n isFullScreen,\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n } = useChatbotWindowStates();\n const {\n setMcps,\n setAppName,\n setSessionToken,\n init,\n isReady,\n isInitialized,\n setIframeEl,\n } = useChatbotFrameHandler({\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n });\n\n const value = {\n hasOpened,\n open,\n setOpen,\n isExpanded,\n setIsExpanded,\n isFullScreen,\n setIsFullScreen,\n setSessionToken,\n init,\n setMcps,\n setAppName,\n isReady,\n isInitialized,\n setIframeEl,\n };\n\n return (\n <ChatbotContext.Provider value={value}>{children}</ChatbotContext.Provider>\n );\n}\n"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"chatbot-provider.mjs","names":[],"sources":["../../../src/components/provider/chatbot-provider.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport {\n type SendAppMessagePayload,\n useChatbotFrameHandler,\n type InitProps,\n type MCP,\n} from \"./use-chatbot-frame-handler\";\nimport { useChatbotWindowStates } from \"./use-chatbot-window-states\";\n\ntype ChatbotContextType = {\n /** 1回チャットボットを開いたら、固定でtrueになる */\n hasOpened: boolean;\n /** チャットボットを開いているか */\n open: boolean;\n /** チャットボットを開く */\n setOpen: (open: boolean) => void;\n /** チャットボットを展開しているか */\n isExpanded: boolean;\n /** チャットボットを展開する */\n setIsExpanded: (expanded: boolean) => void;\n /** チャットボットをフルスクリーンにしているか */\n isFullScreen: boolean;\n /** チャットボットをフルスクリーンにする */\n setIsFullScreen: (fullScreen: boolean) => void;\n /** チャットボットを初期化 */\n init: (props: InitProps) => void;\n /** MCPを設定 */\n setMcps: (mcps: MCP[]) => void;\n /** アプリ名を設定 */\n setAppName: (appName: string) => void;\n /** セッショントークンを設定 */\n setSessionToken: (sessionToken: string) => void;\n /** アプリからメッセージを送信 */\n sendAppMessage: (payload: SendAppMessagePayload) => void;\n /** チャットボットが準備できたか */\n isReady: boolean;\n /** チャットボットが初期化されたか */\n isInitialized: boolean;\n /**\n * @internal\n * チャットボットのiframe要素を設定\n */\n setIframeEl: (iframeEl: HTMLIFrameElement | null) => void;\n};\n\nconst ChatbotContext = React.createContext<ChatbotContextType | undefined>(\n undefined,\n);\n\nexport function useChatbot() {\n const context = React.useContext(ChatbotContext);\n if (!context) {\n throw new Error(\"useChatbot must be used within a ChatbotProvider\");\n }\n return context;\n}\n\ntype ChatbotProviderProps = {\n children: React.ReactNode;\n};\n\nexport function ChatbotProvider({ children }: ChatbotProviderProps) {\n const {\n hasOpened,\n open,\n isExpanded,\n isFullScreen,\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n } = useChatbotWindowStates();\n const {\n setMcps,\n setAppName,\n setSessionToken,\n sendAppMessage,\n init,\n isReady,\n isInitialized,\n setIframeEl,\n } = useChatbotFrameHandler({\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n });\n\n const value = {\n hasOpened,\n open,\n setOpen,\n isExpanded,\n setIsExpanded,\n isFullScreen,\n setIsFullScreen,\n setSessionToken,\n sendAppMessage,\n init,\n setMcps,\n setAppName,\n isReady,\n isInitialized,\n setIframeEl,\n };\n\n return (\n <ChatbotContext.Provider value={value}>{children}</ChatbotContext.Provider>\n );\n}\n"],"mappings":";;;;;;;;AA+CA,MAAM,iBAAiB,MAAM,cAC3B,OACD;AAED,SAAgB,aAAa;CAC3B,MAAM,UAAU,MAAM,WAAW,eAAe;AAChD,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,mDAAmD;AAErE,QAAO;;AAOT,SAAgB,gBAAgB,EAAE,YAAkC;CAClE,MAAM,EACJ,WACA,MACA,YACA,cACA,SACA,eACA,oBACE,wBAAwB;CAC5B,MAAM,EACJ,SACA,YACA,iBACA,gBACA,MACA,SACA,eACA,gBACE,uBAAuB;EACzB;EACA;EACA;EACD,CAAC;CAEF,MAAM,QAAQ;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;AAED,QACE,oBAAC,eAAe;EAAgB;EAAQ;GAAmC"}
|
|
@@ -12,6 +12,18 @@ type InitProps = {
|
|
|
12
12
|
appName?: string;
|
|
13
13
|
sessionToken?: string;
|
|
14
14
|
};
|
|
15
|
+
type AppMessageAttachment = {
|
|
16
|
+
fileName: string;
|
|
17
|
+
mediaType: string;
|
|
18
|
+
url: string;
|
|
19
|
+
};
|
|
20
|
+
type SendAppMessagePayload = {
|
|
21
|
+
title?: string;
|
|
22
|
+
message: string;
|
|
23
|
+
hiddenMessage?: string;
|
|
24
|
+
startOnNewChat?: boolean;
|
|
25
|
+
attachments?: AppMessageAttachment[];
|
|
26
|
+
};
|
|
15
27
|
//#endregion
|
|
16
|
-
export { InitProps, MCP };
|
|
28
|
+
export { InitProps, MCP, SendAppMessagePayload };
|
|
17
29
|
//# sourceMappingURL=use-chatbot-frame-handler.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-chatbot-frame-handler.d.mts","names":[],"sources":["../../../src/components/provider/use-chatbot-frame-handler.tsx"],"sourcesContent":[],"mappings":";;;;KAcY,GAAA;;;YAGA;;KAGA,SAAA;SACH"}
|
|
1
|
+
{"version":3,"file":"use-chatbot-frame-handler.d.mts","names":[],"sources":["../../../src/components/provider/use-chatbot-frame-handler.tsx"],"sourcesContent":[],"mappings":";;;;KAcY,GAAA;;;YAGA;;KAGA,SAAA;SACH;;;;KAKG,oBAAA;;;;;KAMA,qBAAA;;;;;gBAKI"}
|
|
@@ -8,11 +8,14 @@ function useChatbotFrameHandler({ setOpen, setIsExpanded, setIsFullScreen }) {
|
|
|
8
8
|
const [iframeEl, setIframeEl] = React.useState(null);
|
|
9
9
|
const [isReady, setIsReady] = React.useState(false);
|
|
10
10
|
const [isInitialized, setIsInitialized] = React.useState(false);
|
|
11
|
+
const pendingAppMessageRef = React.useRef(null);
|
|
11
12
|
const postMessage = React.useCallback((message) => {
|
|
12
13
|
if (iframeEl === null || iframeEl === void 0 ? void 0 : iframeEl.contentWindow) {
|
|
13
14
|
if (process.env.NODE_ENV === "development") console.log("sending message to iframe", message);
|
|
14
15
|
iframeEl.contentWindow.postMessage(message, "*");
|
|
16
|
+
return true;
|
|
15
17
|
}
|
|
18
|
+
return false;
|
|
16
19
|
}, [iframeEl]);
|
|
17
20
|
const init = React.useCallback((props) => {
|
|
18
21
|
postMessage(_objectSpread2({ type: "init" }, props));
|
|
@@ -35,11 +38,35 @@ function useChatbotFrameHandler({ setOpen, setIsExpanded, setIsFullScreen }) {
|
|
|
35
38
|
sessionToken
|
|
36
39
|
});
|
|
37
40
|
}, [postMessage]);
|
|
41
|
+
const flushPendingAppMessage = React.useCallback(() => {
|
|
42
|
+
const pendingPayload = pendingAppMessageRef.current;
|
|
43
|
+
if (!pendingPayload || !isReady || !isInitialized) return false;
|
|
44
|
+
const sent = postMessage({
|
|
45
|
+
type: "appMessage",
|
|
46
|
+
payload: pendingPayload
|
|
47
|
+
});
|
|
48
|
+
if (sent) pendingAppMessageRef.current = null;
|
|
49
|
+
return sent;
|
|
50
|
+
}, [
|
|
51
|
+
isInitialized,
|
|
52
|
+
isReady,
|
|
53
|
+
postMessage
|
|
54
|
+
]);
|
|
55
|
+
const sendAppMessage = React.useCallback((payload) => {
|
|
56
|
+
var _payload$startOnNewCh;
|
|
57
|
+
pendingAppMessageRef.current = _objectSpread2(_objectSpread2({}, payload), {}, { startOnNewChat: (_payload$startOnNewCh = payload.startOnNewChat) !== null && _payload$startOnNewCh !== void 0 ? _payload$startOnNewCh : true });
|
|
58
|
+
setOpen(true);
|
|
59
|
+
flushPendingAppMessage();
|
|
60
|
+
}, [flushPendingAppMessage, setOpen]);
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
flushPendingAppMessage();
|
|
63
|
+
}, [flushPendingAppMessage]);
|
|
38
64
|
React.useEffect(() => {
|
|
39
65
|
const iframe = iframeEl;
|
|
40
66
|
if (!iframe) return;
|
|
41
67
|
const handleMessage = (event) => {
|
|
42
68
|
var _event$data;
|
|
69
|
+
if (event.source !== iframe.contentWindow) return;
|
|
43
70
|
if (process.env.NODE_ENV === "development") console.log("iframe message", event.data);
|
|
44
71
|
switch ((_event$data = event.data) === null || _event$data === void 0 ? void 0 : _event$data.type) {
|
|
45
72
|
case "CHATBOT_READY":
|
|
@@ -69,8 +96,10 @@ function useChatbotFrameHandler({ setOpen, setIsExpanded, setIsFullScreen }) {
|
|
|
69
96
|
}
|
|
70
97
|
};
|
|
71
98
|
const handleIframeLoad = () => {
|
|
72
|
-
|
|
99
|
+
setIsReady(false);
|
|
100
|
+
setIsInitialized(false);
|
|
73
101
|
};
|
|
102
|
+
window.addEventListener("message", handleMessage);
|
|
74
103
|
iframe.addEventListener("load", handleIframeLoad);
|
|
75
104
|
return () => {
|
|
76
105
|
window.removeEventListener("message", handleMessage);
|
|
@@ -82,6 +111,7 @@ function useChatbotFrameHandler({ setOpen, setIsExpanded, setIsFullScreen }) {
|
|
|
82
111
|
setMcps,
|
|
83
112
|
setAppName,
|
|
84
113
|
setSessionToken,
|
|
114
|
+
sendAppMessage,
|
|
85
115
|
setIframeEl,
|
|
86
116
|
isReady,
|
|
87
117
|
isInitialized
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-chatbot-frame-handler.mjs","names":[],"sources":["../../../src/components/provider/use-chatbot-frame-handler.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\n\nexport type IframeMessage =\n | { type: \"CHATBOT_READY\" }\n | { type: \"CHATBOT_INITIALIZED\" }\n | { type: \"CLOSE_CHATBOT\" }\n | { type: \"EXPAND_CHATBOT\" }\n | { type: \"SHRINK_CHATBOT\" }\n | { type: \"FULLSCREEN_CHATBOT\" }\n | { type: \"EXIT_FULLSCREEN_CHATBOT\" }\n | { type: \"RELOAD_CHATBOT\" };\n\nexport type MCP = {\n name: string;\n url: string;\n headers?: Record<string, string>;\n};\n\nexport type InitProps = {\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n};\n\nexport type ParentMessage =\n | {\n type: \"mcps\";\n mcps: MCP[];\n }\n | {\n type: \"appName\";\n appName: string;\n }\n | {\n type: \"sessionToken\";\n sessionToken: string;\n }\n | {\n type: \"init\";\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n };\n\nexport function useChatbotFrameHandler({\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n}: {\n setOpen: (open: boolean) => void;\n setIsExpanded: (expanded: boolean) => void;\n setIsFullScreen: (fullScreen: boolean) => void;\n}) {\n const [iframeEl, setIframeEl] = React.useState<HTMLIFrameElement | null>(\n null,\n );\n const [isReady, setIsReady] = React.useState(false);\n const [isInitialized, setIsInitialized] = React.useState(false);\n\n // helper to post message to the iframe\n const postMessage = React.useCallback(\n (message: ParentMessage) => {\n if (iframeEl?.contentWindow) {\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"sending message to iframe\", message);\n }\n iframeEl.contentWindow.postMessage(message, \"*\");\n }\n },\n [iframeEl],\n );\n\n const init = React.useCallback(\n (props: InitProps) => {\n postMessage({\n type: \"init\",\n ...props,\n });\n },\n [postMessage],\n );\n\n const setMcps = React.useCallback(\n (mcps: MCP[]) => {\n postMessage({ type: \"mcps\", mcps });\n },\n [postMessage],\n );\n\n const setAppName = React.useCallback(\n (appName: string) => {\n postMessage({ type: \"appName\", appName });\n },\n [postMessage],\n );\n\n const setSessionToken = React.useCallback(\n (sessionToken: string) => {\n postMessage({ type: \"sessionToken\", sessionToken });\n },\n [postMessage],\n );\n\n // Initialize and setup listeners\n React.useEffect(() => {\n const iframe = iframeEl;\n if (!iframe) {\n return;\n }\n\n const handleMessage = (event: MessageEvent<IframeMessage>) => {\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"iframe message\", event.data);\n }\n // Handle iframe messages\n switch (event.data?.type) {\n case \"CHATBOT_READY\":\n setIsReady(true);\n break;\n case \"CHATBOT_INITIALIZED\":\n setIsInitialized(true);\n break;\n case \"CLOSE_CHATBOT\":\n setOpen(false);\n break;\n case \"EXPAND_CHATBOT\":\n setIsExpanded(true);\n break;\n case \"SHRINK_CHATBOT\":\n setIsExpanded(false);\n break;\n case \"FULLSCREEN_CHATBOT\":\n setIsFullScreen(true);\n break;\n case \"EXIT_FULLSCREEN_CHATBOT\":\n setIsFullScreen(false);\n break;\n case \"RELOAD_CHATBOT\":\n // reload iframe\n iframe.src = iframe.src;\n break;\n }\n };\n\n const handleIframeLoad = () => {\n window.addEventListener(\"message\", handleMessage);\n
|
|
1
|
+
{"version":3,"file":"use-chatbot-frame-handler.mjs","names":[],"sources":["../../../src/components/provider/use-chatbot-frame-handler.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\n\nexport type IframeMessage =\n | { type: \"CHATBOT_READY\" }\n | { type: \"CHATBOT_INITIALIZED\" }\n | { type: \"CLOSE_CHATBOT\" }\n | { type: \"EXPAND_CHATBOT\" }\n | { type: \"SHRINK_CHATBOT\" }\n | { type: \"FULLSCREEN_CHATBOT\" }\n | { type: \"EXIT_FULLSCREEN_CHATBOT\" }\n | { type: \"RELOAD_CHATBOT\" };\n\nexport type MCP = {\n name: string;\n url: string;\n headers?: Record<string, string>;\n};\n\nexport type InitProps = {\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n};\n\nexport type AppMessageAttachment = {\n fileName: string;\n mediaType: string;\n url: string;\n};\n\nexport type SendAppMessagePayload = {\n title?: string;\n message: string;\n hiddenMessage?: string;\n startOnNewChat?: boolean;\n attachments?: AppMessageAttachment[];\n};\n\nexport type ParentMessage =\n | {\n type: \"mcps\";\n mcps: MCP[];\n }\n | {\n type: \"appName\";\n appName: string;\n }\n | {\n type: \"sessionToken\";\n sessionToken: string;\n }\n | {\n type: \"init\";\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n }\n | {\n type: \"appMessage\";\n payload: SendAppMessagePayload;\n };\n\nexport function useChatbotFrameHandler({\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n}: {\n setOpen: (open: boolean) => void;\n setIsExpanded: (expanded: boolean) => void;\n setIsFullScreen: (fullScreen: boolean) => void;\n}) {\n const [iframeEl, setIframeEl] = React.useState<HTMLIFrameElement | null>(\n null,\n );\n const [isReady, setIsReady] = React.useState(false);\n const [isInitialized, setIsInitialized] = React.useState(false);\n const pendingAppMessageRef = React.useRef<SendAppMessagePayload | null>(null);\n\n // helper to post message to the iframe\n const postMessage = React.useCallback(\n (message: ParentMessage) => {\n if (iframeEl?.contentWindow) {\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"sending message to iframe\", message);\n }\n iframeEl.contentWindow.postMessage(message, \"*\");\n return true;\n }\n return false;\n },\n [iframeEl],\n );\n\n const init = React.useCallback(\n (props: InitProps) => {\n postMessage({\n type: \"init\",\n ...props,\n });\n },\n [postMessage],\n );\n\n const setMcps = React.useCallback(\n (mcps: MCP[]) => {\n postMessage({ type: \"mcps\", mcps });\n },\n [postMessage],\n );\n\n const setAppName = React.useCallback(\n (appName: string) => {\n postMessage({ type: \"appName\", appName });\n },\n [postMessage],\n );\n\n const setSessionToken = React.useCallback(\n (sessionToken: string) => {\n postMessage({ type: \"sessionToken\", sessionToken });\n },\n [postMessage],\n );\n\n const flushPendingAppMessage = React.useCallback(() => {\n const pendingPayload = pendingAppMessageRef.current;\n if (!pendingPayload || !isReady || !isInitialized) {\n return false;\n }\n\n const sent = postMessage({\n type: \"appMessage\",\n payload: pendingPayload,\n });\n\n if (sent) {\n pendingAppMessageRef.current = null;\n }\n\n return sent;\n }, [isInitialized, isReady, postMessage]);\n\n const sendAppMessage = React.useCallback(\n (payload: SendAppMessagePayload) => {\n pendingAppMessageRef.current = {\n ...payload,\n startOnNewChat: payload.startOnNewChat ?? true,\n };\n setOpen(true);\n flushPendingAppMessage();\n },\n [flushPendingAppMessage, setOpen],\n );\n\n React.useEffect(() => {\n flushPendingAppMessage();\n }, [flushPendingAppMessage]);\n\n // Initialize and setup listeners\n React.useEffect(() => {\n const iframe = iframeEl;\n if (!iframe) {\n return;\n }\n\n const handleMessage = (event: MessageEvent<IframeMessage>) => {\n if (event.source !== iframe.contentWindow) {\n return;\n }\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"iframe message\", event.data);\n }\n // Handle iframe messages\n switch (event.data?.type) {\n case \"CHATBOT_READY\":\n setIsReady(true);\n break;\n case \"CHATBOT_INITIALIZED\":\n setIsInitialized(true);\n break;\n case \"CLOSE_CHATBOT\":\n setOpen(false);\n break;\n case \"EXPAND_CHATBOT\":\n setIsExpanded(true);\n break;\n case \"SHRINK_CHATBOT\":\n setIsExpanded(false);\n break;\n case \"FULLSCREEN_CHATBOT\":\n setIsFullScreen(true);\n break;\n case \"EXIT_FULLSCREEN_CHATBOT\":\n setIsFullScreen(false);\n break;\n case \"RELOAD_CHATBOT\":\n // reload iframe\n iframe.src = iframe.src;\n break;\n }\n };\n\n const handleIframeLoad = () => {\n setIsReady(false);\n setIsInitialized(false);\n };\n\n window.addEventListener(\"message\", handleMessage);\n iframe.addEventListener(\"load\", handleIframeLoad);\n\n return () => {\n window.removeEventListener(\"message\", handleMessage);\n iframe.removeEventListener(\"load\", handleIframeLoad);\n };\n }, [iframeEl]); // Run when iframe gets mounted\n\n return {\n init,\n setMcps,\n setAppName,\n setSessionToken,\n sendAppMessage,\n setIframeEl,\n isReady,\n isInitialized,\n };\n}\n"],"mappings":";;;;;;AAgEA,SAAgB,uBAAuB,EACrC,SACA,eACA,mBAKC;CACD,MAAM,CAAC,UAAU,eAAe,MAAM,SACpC,KACD;CACD,MAAM,CAAC,SAAS,cAAc,MAAM,SAAS,MAAM;CACnD,MAAM,CAAC,eAAe,oBAAoB,MAAM,SAAS,MAAM;CAC/D,MAAM,uBAAuB,MAAM,OAAqC,KAAK;CAG7E,MAAM,cAAc,MAAM,aACvB,YAA2B;AAC1B,0DAAI,SAAU,eAAe;AAC3B,OAAI,QAAQ,IAAI,aAAa,cAC3B,SAAQ,IAAI,6BAA6B,QAAQ;AAEnD,YAAS,cAAc,YAAY,SAAS,IAAI;AAChD,UAAO;;AAET,SAAO;IAET,CAAC,SAAS,CACX;CAED,MAAM,OAAO,MAAM,aAChB,UAAqB;AACpB,+BACE,MAAM,UACH,OACH;IAEJ,CAAC,YAAY,CACd;CAED,MAAM,UAAU,MAAM,aACnB,SAAgB;AACf,cAAY;GAAE,MAAM;GAAQ;GAAM,CAAC;IAErC,CAAC,YAAY,CACd;CAED,MAAM,aAAa,MAAM,aACtB,YAAoB;AACnB,cAAY;GAAE,MAAM;GAAW;GAAS,CAAC;IAE3C,CAAC,YAAY,CACd;CAED,MAAM,kBAAkB,MAAM,aAC3B,iBAAyB;AACxB,cAAY;GAAE,MAAM;GAAgB;GAAc,CAAC;IAErD,CAAC,YAAY,CACd;CAED,MAAM,yBAAyB,MAAM,kBAAkB;EACrD,MAAM,iBAAiB,qBAAqB;AAC5C,MAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,cAClC,QAAO;EAGT,MAAM,OAAO,YAAY;GACvB,MAAM;GACN,SAAS;GACV,CAAC;AAEF,MAAI,KACF,sBAAqB,UAAU;AAGjC,SAAO;IACN;EAAC;EAAe;EAAS;EAAY,CAAC;CAEzC,MAAM,iBAAiB,MAAM,aAC1B,YAAmC;;AAClC,uBAAqB,4CAChB,gBACH,yCAAgB,QAAQ,uFAAkB;AAE5C,UAAQ,KAAK;AACb,0BAAwB;IAE1B,CAAC,wBAAwB,QAAQ,CAClC;AAED,OAAM,gBAAgB;AACpB,0BAAwB;IACvB,CAAC,uBAAuB,CAAC;AAG5B,OAAM,gBAAgB;EACpB,MAAM,SAAS;AACf,MAAI,CAAC,OACH;EAGF,MAAM,iBAAiB,UAAuC;;AAC5D,OAAI,MAAM,WAAW,OAAO,cAC1B;AAEF,OAAI,QAAQ,IAAI,aAAa,cAC3B,SAAQ,IAAI,kBAAkB,MAAM,KAAK;AAG3C,0BAAQ,MAAM,gEAAM,MAApB;IACE,KAAK;AACH,gBAAW,KAAK;AAChB;IACF,KAAK;AACH,sBAAiB,KAAK;AACtB;IACF,KAAK;AACH,aAAQ,MAAM;AACd;IACF,KAAK;AACH,mBAAc,KAAK;AACnB;IACF,KAAK;AACH,mBAAc,MAAM;AACpB;IACF,KAAK;AACH,qBAAgB,KAAK;AACrB;IACF,KAAK;AACH,qBAAgB,MAAM;AACtB;IACF,KAAK;AAEH,YAAO,MAAM,OAAO;AACpB;;;EAIN,MAAM,yBAAyB;AAC7B,cAAW,MAAM;AACjB,oBAAiB,MAAM;;AAGzB,SAAO,iBAAiB,WAAW,cAAc;AACjD,SAAO,iBAAiB,QAAQ,iBAAiB;AAEjD,eAAa;AACX,UAAO,oBAAoB,WAAW,cAAc;AACpD,UAAO,oBAAoB,QAAQ,iBAAiB;;IAErD,CAAC,SAAS,CAAC;AAEd,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as React$1 from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime1 from "react/jsx-runtime";
|
|
3
3
|
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
4
4
|
|
|
5
5
|
//#region src/components/sheet.d.ts
|
|
6
6
|
declare function Sheet({
|
|
7
7
|
...props
|
|
8
|
-
}: React$1.ComponentProps<typeof SheetPrimitive.Root>):
|
|
8
|
+
}: React$1.ComponentProps<typeof SheetPrimitive.Root>): react_jsx_runtime1.JSX.Element;
|
|
9
9
|
declare const SheetTrigger: React$1.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogTriggerProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
10
10
|
declare const SheetClose: React$1.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogCloseProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
11
11
|
declare const SheetContent: React$1.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogContentProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
package/package.json
CHANGED
|
@@ -8,7 +8,6 @@ type LottieAiIconProps = {
|
|
|
8
8
|
height?: number;
|
|
9
9
|
loop?: boolean;
|
|
10
10
|
autoplay?: boolean;
|
|
11
|
-
hover?: boolean;
|
|
12
11
|
fallback?: React.ReactNode;
|
|
13
12
|
};
|
|
14
13
|
|
|
@@ -18,7 +17,6 @@ export function LottieAiIcon({
|
|
|
18
17
|
height = 18,
|
|
19
18
|
loop = true,
|
|
20
19
|
autoplay = false,
|
|
21
|
-
hover = false,
|
|
22
20
|
fallback,
|
|
23
21
|
}: LottieAiIconProps) {
|
|
24
22
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
@@ -27,14 +25,14 @@ export function LottieAiIcon({
|
|
|
27
25
|
React.useEffect(() => {
|
|
28
26
|
if (typeof window === "undefined") return;
|
|
29
27
|
|
|
30
|
-
const existing = document.querySelector("script[data-dotlottie-
|
|
28
|
+
const existing = document.querySelector("script[data-dotlottie-wc]");
|
|
31
29
|
if (!existing) {
|
|
32
30
|
const scriptEl = document.createElement("script");
|
|
33
31
|
scriptEl.type = "module";
|
|
34
32
|
scriptEl.async = true;
|
|
35
33
|
scriptEl.src =
|
|
36
|
-
"https://unpkg.com/@dotlottie
|
|
37
|
-
scriptEl.setAttribute("data-dotlottie-
|
|
34
|
+
"https://unpkg.com/@lottiefiles/dotlottie-wc@0.9.8/dist/dotlottie-wc.js";
|
|
35
|
+
scriptEl.setAttribute("data-dotlottie-wc", "true");
|
|
38
36
|
scriptEl.onload = () => setReady(true);
|
|
39
37
|
scriptEl.onerror = () => setReady(false);
|
|
40
38
|
document.head.appendChild(scriptEl);
|
|
@@ -47,17 +45,16 @@ export function LottieAiIcon({
|
|
|
47
45
|
if (!ready || !containerRef.current) return;
|
|
48
46
|
const container = containerRef.current;
|
|
49
47
|
container.innerHTML = "";
|
|
50
|
-
const player = document.createElement("dotlottie-
|
|
48
|
+
const player = document.createElement("dotlottie-wc");
|
|
51
49
|
player.setAttribute("src", src);
|
|
52
50
|
player.setAttribute("style", `width:${width}px;height:${height}px`);
|
|
53
51
|
if (loop) player.setAttribute("loop", "");
|
|
54
52
|
if (autoplay) player.setAttribute("autoplay", "");
|
|
55
|
-
if (hover) player.setAttribute("hover", "");
|
|
56
53
|
container.appendChild(player);
|
|
57
54
|
return () => {
|
|
58
55
|
container.innerHTML = "";
|
|
59
56
|
};
|
|
60
|
-
}, [ready, src, width, height, loop, autoplay
|
|
57
|
+
}, [ready, src, width, height, loop, autoplay]);
|
|
61
58
|
|
|
62
59
|
return (
|
|
63
60
|
<div ref={containerRef} aria-hidden="true">
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
import {
|
|
5
|
+
type SendAppMessagePayload,
|
|
5
6
|
useChatbotFrameHandler,
|
|
6
7
|
type InitProps,
|
|
7
8
|
type MCP,
|
|
@@ -31,6 +32,8 @@ type ChatbotContextType = {
|
|
|
31
32
|
setAppName: (appName: string) => void;
|
|
32
33
|
/** セッショントークンを設定 */
|
|
33
34
|
setSessionToken: (sessionToken: string) => void;
|
|
35
|
+
/** アプリからメッセージを送信 */
|
|
36
|
+
sendAppMessage: (payload: SendAppMessagePayload) => void;
|
|
34
37
|
/** チャットボットが準備できたか */
|
|
35
38
|
isReady: boolean;
|
|
36
39
|
/** チャットボットが初期化されたか */
|
|
@@ -72,6 +75,7 @@ export function ChatbotProvider({ children }: ChatbotProviderProps) {
|
|
|
72
75
|
setMcps,
|
|
73
76
|
setAppName,
|
|
74
77
|
setSessionToken,
|
|
78
|
+
sendAppMessage,
|
|
75
79
|
init,
|
|
76
80
|
isReady,
|
|
77
81
|
isInitialized,
|
|
@@ -91,6 +95,7 @@ export function ChatbotProvider({ children }: ChatbotProviderProps) {
|
|
|
91
95
|
isFullScreen,
|
|
92
96
|
setIsFullScreen,
|
|
93
97
|
setSessionToken,
|
|
98
|
+
sendAppMessage,
|
|
94
99
|
init,
|
|
95
100
|
setMcps,
|
|
96
101
|
setAppName,
|
|
@@ -24,6 +24,20 @@ export type InitProps = {
|
|
|
24
24
|
sessionToken?: string;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
export type AppMessageAttachment = {
|
|
28
|
+
fileName: string;
|
|
29
|
+
mediaType: string;
|
|
30
|
+
url: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type SendAppMessagePayload = {
|
|
34
|
+
title?: string;
|
|
35
|
+
message: string;
|
|
36
|
+
hiddenMessage?: string;
|
|
37
|
+
startOnNewChat?: boolean;
|
|
38
|
+
attachments?: AppMessageAttachment[];
|
|
39
|
+
};
|
|
40
|
+
|
|
27
41
|
export type ParentMessage =
|
|
28
42
|
| {
|
|
29
43
|
type: "mcps";
|
|
@@ -42,6 +56,10 @@ export type ParentMessage =
|
|
|
42
56
|
mcps?: MCP[];
|
|
43
57
|
appName?: string;
|
|
44
58
|
sessionToken?: string;
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
type: "appMessage";
|
|
62
|
+
payload: SendAppMessagePayload;
|
|
45
63
|
};
|
|
46
64
|
|
|
47
65
|
export function useChatbotFrameHandler({
|
|
@@ -58,6 +76,7 @@ export function useChatbotFrameHandler({
|
|
|
58
76
|
);
|
|
59
77
|
const [isReady, setIsReady] = React.useState(false);
|
|
60
78
|
const [isInitialized, setIsInitialized] = React.useState(false);
|
|
79
|
+
const pendingAppMessageRef = React.useRef<SendAppMessagePayload | null>(null);
|
|
61
80
|
|
|
62
81
|
// helper to post message to the iframe
|
|
63
82
|
const postMessage = React.useCallback(
|
|
@@ -67,7 +86,9 @@ export function useChatbotFrameHandler({
|
|
|
67
86
|
console.log("sending message to iframe", message);
|
|
68
87
|
}
|
|
69
88
|
iframeEl.contentWindow.postMessage(message, "*");
|
|
89
|
+
return true;
|
|
70
90
|
}
|
|
91
|
+
return false;
|
|
71
92
|
},
|
|
72
93
|
[iframeEl],
|
|
73
94
|
);
|
|
@@ -103,6 +124,40 @@ export function useChatbotFrameHandler({
|
|
|
103
124
|
[postMessage],
|
|
104
125
|
);
|
|
105
126
|
|
|
127
|
+
const flushPendingAppMessage = React.useCallback(() => {
|
|
128
|
+
const pendingPayload = pendingAppMessageRef.current;
|
|
129
|
+
if (!pendingPayload || !isReady || !isInitialized) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const sent = postMessage({
|
|
134
|
+
type: "appMessage",
|
|
135
|
+
payload: pendingPayload,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (sent) {
|
|
139
|
+
pendingAppMessageRef.current = null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return sent;
|
|
143
|
+
}, [isInitialized, isReady, postMessage]);
|
|
144
|
+
|
|
145
|
+
const sendAppMessage = React.useCallback(
|
|
146
|
+
(payload: SendAppMessagePayload) => {
|
|
147
|
+
pendingAppMessageRef.current = {
|
|
148
|
+
...payload,
|
|
149
|
+
startOnNewChat: payload.startOnNewChat ?? true,
|
|
150
|
+
};
|
|
151
|
+
setOpen(true);
|
|
152
|
+
flushPendingAppMessage();
|
|
153
|
+
},
|
|
154
|
+
[flushPendingAppMessage, setOpen],
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
React.useEffect(() => {
|
|
158
|
+
flushPendingAppMessage();
|
|
159
|
+
}, [flushPendingAppMessage]);
|
|
160
|
+
|
|
106
161
|
// Initialize and setup listeners
|
|
107
162
|
React.useEffect(() => {
|
|
108
163
|
const iframe = iframeEl;
|
|
@@ -111,6 +166,9 @@ export function useChatbotFrameHandler({
|
|
|
111
166
|
}
|
|
112
167
|
|
|
113
168
|
const handleMessage = (event: MessageEvent<IframeMessage>) => {
|
|
169
|
+
if (event.source !== iframe.contentWindow) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
114
172
|
if (process.env.NODE_ENV === "development") {
|
|
115
173
|
console.log("iframe message", event.data);
|
|
116
174
|
}
|
|
@@ -145,9 +203,11 @@ export function useChatbotFrameHandler({
|
|
|
145
203
|
};
|
|
146
204
|
|
|
147
205
|
const handleIframeLoad = () => {
|
|
148
|
-
|
|
206
|
+
setIsReady(false);
|
|
207
|
+
setIsInitialized(false);
|
|
149
208
|
};
|
|
150
209
|
|
|
210
|
+
window.addEventListener("message", handleMessage);
|
|
151
211
|
iframe.addEventListener("load", handleIframeLoad);
|
|
152
212
|
|
|
153
213
|
return () => {
|
|
@@ -161,6 +221,7 @@ export function useChatbotFrameHandler({
|
|
|
161
221
|
setMcps,
|
|
162
222
|
setAppName,
|
|
163
223
|
setSessionToken,
|
|
224
|
+
sendAppMessage,
|
|
164
225
|
setIframeEl,
|
|
165
226
|
isReady,
|
|
166
227
|
isInitialized,
|