copilot-chat-widget 0.1.16 → 0.1.18
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/README.md +15 -32
- package/dist/index.cjs +7 -1
- package/dist/index.mjs +194 -15
- package/package.json +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +338 -40
- package/src/widget-runtime.js +77 -77
package/README.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
# Copilot Chat Widget
|
|
2
2
|
|
|
3
|
-
Embeddable chat widget
|
|
3
|
+
Embeddable chat widget that can be added via NPM or a script tag.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
```bash
|
|
7
7
|
npm install copilot-chat-widget
|
|
8
8
|
# or
|
|
9
9
|
yarn add copilot-chat-widget
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Usage (NPM import)
|
|
13
13
|
```js
|
|
14
14
|
import { loadCopilotChatWidget } from "copilot-chat-widget";
|
|
15
15
|
|
|
16
16
|
loadCopilotChatWidget({
|
|
17
17
|
token: "YOUR_WIDGET_TOKEN",
|
|
18
|
-
// optional
|
|
18
|
+
// optional: baseUrl if backend is on a different origin
|
|
19
19
|
// baseUrl: "https://your-backend-domain"
|
|
20
20
|
});
|
|
21
21
|
```
|
|
22
|
-
`loadCopilotChatWidget` injects the standalone
|
|
22
|
+
`loadCopilotChatWidget` injects the standalone script (`chat-widget.min.js`) and bootstraps the widget using the provided `token`.
|
|
23
23
|
|
|
24
|
-
### React/Next.js
|
|
24
|
+
### React/Next.js example
|
|
25
25
|
```jsx
|
|
26
26
|
import { useEffect } from "react";
|
|
27
27
|
import { loadCopilotChatWidget } from "copilot-chat-widget";
|
|
@@ -30,7 +30,7 @@ export default function Page() {
|
|
|
30
30
|
useEffect(() => {
|
|
31
31
|
loadCopilotChatWidget({
|
|
32
32
|
token: process.env.NEXT_PUBLIC_CHAT_WIDGET_TOKEN,
|
|
33
|
-
baseUrl: process.env.NEXT_PUBLIC_WIDGET_BASE_URL // optional override
|
|
33
|
+
baseUrl: process.env.NEXT_PUBLIC_WIDGET_BASE_URL // optional override if backend is another origin
|
|
34
34
|
});
|
|
35
35
|
}, []);
|
|
36
36
|
|
|
@@ -38,43 +38,26 @@ export default function Page() {
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
##
|
|
41
|
+
## Usage (script tag)
|
|
42
42
|
```html
|
|
43
43
|
<script
|
|
44
|
-
src="https://
|
|
44
|
+
src="https://cdn.example.com/chat-widget.min.js"
|
|
45
45
|
data-token="YOUR_WIDGET_TOKEN"
|
|
46
|
-
data-base-url="https://your-backend-domain"
|
|
46
|
+
data-base-url="https://your-backend-domain" <!-- optional if backend is another origin -->
|
|
47
47
|
></script>
|
|
48
48
|
```
|
|
49
49
|
- `data-token`: required.
|
|
50
|
-
- `data-base-url`: optional override; if omitted, the widget uses the build-time `WIDGET_BASE_URL`, then falls back to the script/page origin.
|
|
51
|
-
- `data-autoload="false"`: insert script but call `window.CopilotChat.init()`
|
|
50
|
+
- `data-base-url`: optional override; if omitted, the widget uses the build-time default `WIDGET_BASE_URL`, then falls back to the script/page origin.
|
|
51
|
+
- `data-autoload="false"`: if you want to insert the script but call `window.CopilotChat.init()` manually.
|
|
52
52
|
|
|
53
53
|
## Configuration
|
|
54
54
|
- `token` (string, required): widget token.
|
|
55
|
-
- `baseUrl` (string): backend host serving `/api/chat-widget/config`. Needed when the embedding page is on a different origin.
|
|
56
|
-
- `autoload` (boolean): set `false` to defer bootstrap and call `window.CopilotChat.load()`
|
|
55
|
+
- `baseUrl` (string): backend host serving `/api/chat-widget/config`. Needed when the embedding page is on a different origin. If omitted, the widget uses `WIDGET_BASE_URL` (injected at build) then falls back to the script/page origin.
|
|
56
|
+
- `autoload` (boolean): set `false` to defer bootstrap and call `window.CopilotChat.load()` yourself.
|
|
57
57
|
|
|
58
|
-
Runtime controls:
|
|
58
|
+
Runtime controls (after script loads):
|
|
59
59
|
```js
|
|
60
60
|
window.CopilotChat.open(); // open widget
|
|
61
61
|
window.CopilotChat.close(); // close widget
|
|
62
62
|
window.CopilotChat.load(); // initialize if autoload=false
|
|
63
63
|
```
|
|
64
|
-
|
|
65
|
-
### Token resolution order
|
|
66
|
-
The widget looks for a token in this order:
|
|
67
|
-
1. `token` passed to `loadCopilotChatWidget`
|
|
68
|
-
2. `window.CopilotChatConfig.token` or `data-token` on the script tag
|
|
69
|
-
3. `token` query param on the script URL
|
|
70
|
-
4. `localStorage.copilotChatToken` (if previously provided)
|
|
71
|
-
5. Prompt (browser `window.prompt`) if none found, then store in `localStorage` for reuse
|
|
72
|
-
|
|
73
|
-
## Build & publish (for maintainers)
|
|
74
|
-
```bash
|
|
75
|
-
cd webui/widget
|
|
76
|
-
npm install
|
|
77
|
-
WIDGET_BASE_URL=https://your-backend-domain npm run build # embed default baseUrl into bundle
|
|
78
|
-
npm publish --access public
|
|
79
|
-
```
|
|
80
|
-
To use a different package name, update `name` in `webui/widget/package.json` before publishing.
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const k="http://localhost:3000",w=64,C=720,E=({iframeUrl:h,launcherIcon:u})=>{const d=document.querySelector("[data-copilot-widget-root]");d&&d.remove();const g=s=>{const o=document.querySelector("[data-copilot-checkout-toast]");o&&o.remove();const r=document.createElement("div");r.setAttribute("data-copilot-checkout-toast","true"),r.innerText=s,Object.assign(r.style,{position:"fixed",top:"20px",left:"50%",transform:"translateX(-50%)",padding:"12px 16px",background:"#0f172a",color:"white",borderRadius:"12px",boxShadow:"0 8px 24px rgba(0,0,0,0.25)",zIndex:2147483647,fontSize:"14px",fontWeight:"600",maxWidth:"420px",lineHeight:"1.4",textAlign:"center"}),document.body.appendChild(r),setTimeout(()=>{r.remove()},4500)},c=document.createElement("div");c.setAttribute("data-copilot-widget-root","true");const n=c.attachShadow({mode:"open"});document.body.appendChild(c);const t=document.createElement("button");t.type="button",t.setAttribute("aria-label","Open Copilot chat"),t.innerHTML=`
|
|
2
|
+
<img
|
|
3
|
+
src="${u}"
|
|
4
|
+
alt="Copilot chat launcher"
|
|
5
|
+
style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
|
|
6
|
+
/>
|
|
7
|
+
`,Object.assign(t.style,{position:"fixed",bottom:"24px",right:"24px",width:`${w}px`,height:`${w}px`,borderRadius:"50%",border:"none",background:"linear-gradient(135deg, #0078ff, #00c6ff)",color:"white",cursor:"pointer",zIndex:999998,display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 6px 14px rgba(0,0,0,0.25)",transition:"all 0.25s ease"}),t.onmouseover=()=>{t.style.transform="scale(1.12)",t.style.boxShadow="0 10px 25px rgba(0,0,0,0.3)"},t.onmouseout=()=>{t.style.transform="scale(1)",t.style.boxShadow="0 6px 14px rgba(0,0,0,0.25)"};const e=document.createElement("div");e.setAttribute("data-copilot-widget-root","true"),Object.assign(e.style,{display:"none",position:"fixed",bottom:`${w+36}px`,right:"24px",zIndex:"999999",transformOrigin:"bottom right",transform:"scale(0.8) translateY(20px)",opacity:"0",transition:"all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)"});const l=document.createElement("div"),f=document.createElement("div"),x=document.createElement("div");Object.assign(l.style,{position:"absolute",bottom:"-14px",right:"28px",width:"30px",height:"20px",pointerEvents:"none",display:"none",zIndex:"1"}),Object.assign(f.style,{position:"absolute",bottom:"0",left:"0",right:"0",margin:"0 auto",width:"0",height:"0",borderLeft:"15px solid transparent",borderRight:"15px solid transparent",borderTop:"15px solid rgba(15,23,42,0.1)"}),Object.assign(x.style,{position:"absolute",bottom:"2px",left:"0",right:"0",margin:"0 auto",width:"0",height:"0",borderLeft:"13px solid transparent",borderRight:"13px solid transparent",borderTop:"13px solid white",boxShadow:"0 6px 16px rgba(15,23,42,0.12)",borderRadius:"2px"}),l.appendChild(f),l.appendChild(x);const p=document.createElement("div");Object.assign(p.style,{width:`${C}px`,maxWidth:"calc(100vw - 48px)",height:`${Math.min(C,Math.max(320,window.innerHeight-140))}px`,maxHeight:"calc(100vh - 150px)",borderRadius:"20px",background:"white",border:"1px solid rgba(15,23,42,0.12)",boxShadow:"0 18px 45px rgba(15,23,42,0.16)",overflow:"hidden"}),n.appendChild(p);const i=document.createElement("iframe");i.src=h,i.title="Copilot chat widget",i.allow="clipboard-read; clipboard-write; microphone; camera; display-capture",i.setAttribute("scrolling","no"),Object.assign(i.style,{width:"100%",height:"100%",border:"none",display:"block",background:"transparent",overflow:"hidden"}),n.appendChild(p),p.appendChild(i),e.appendChild(l),e.appendChild(p),document.body.appendChild(t),document.body.appendChild(e);let a=!1;const m=()=>{a&&(a=!1,e.style.opacity="0",e.style.transform="scale(0.8) translateY(20px)",l.style.display="none",setTimeout(()=>{e.style.display="none"},250),t.style.transform="scale(1)")},v=s=>{const{data:o,source:r}=s||{};if(o?.type){if(o.type==="CART_CHECKOUT"&&r===i.contentWindow){console.log("[CopilotChat] Received checkout payload from widget:",o),g("Checkout message received from chat widget. Check console for payload.");return}if(o.type==="WIDGET_READY"&&r===i.contentWindow){i.contentWindow.postMessage({type:"INIT_WIDGET"},"*");return}o.type==="CHAT_CLOSED"&&m()}};window.addEventListener("message",v),t.onclick=s=>{s.stopPropagation(),a=!a,a?(e.style.display="block",l.style.display="block",requestAnimationFrame(()=>{e.style.opacity="1",e.style.transform="scale(1) translateY(0)"})):m()},document.addEventListener("click",s=>{const o=s.target;o&&a&&!e.contains(o)&&o!==t&&m()});const b={close:m,open:()=>{a||t.click()}};return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.close=b.close,window.CopilotChat.open=b.open,window.CopilotChat.controls=b,b};async function y(h={}){if(typeof window>"u"||typeof document>"u")return null;const u=window.CopilotChatConfig||{},d=h.token||u.token||typeof window<"u"&&window.localStorage?.getItem("copilotChatToken")||null;if(!d)return console.error("[CopilotChat] Missing token (provide via loadCopilotChatWidget({ token }) or window.CopilotChatConfig.token)."),null;const g=h.baseUrl||u.baseUrl||k,c=`${g.replace(/\/$/,"")}/api/chat-widget/config?token=${encodeURIComponent(d)}`;try{const n=await fetch(c,{credentials:"omit",mode:"cors"});if(!n.ok)throw new Error(`Server responded with ${n.status}`);const t=await n.json();if(!t?.iframeUrl||!t?.launcherIcon)throw new Error("Received incomplete widget configuration from server.");return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.token=d,window.CopilotChat.baseUrl=g,E({iframeUrl:t.iframeUrl,launcherIcon:t.launcherIcon})}catch(n){return console.error("[CopilotChat] Error during widget bootstrap:",n instanceof Error?n.message:n),null}}exports.default=y;exports.loadCopilotChatWidget=y;
|
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,199 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
1
|
+
const C = "http://localhost:3000";
|
|
2
|
+
const y = ({ iframeUrl: h, launcherIcon: u }) => {
|
|
3
|
+
const d = document.querySelector("[data-copilot-widget-root]");
|
|
4
|
+
d && d.remove();
|
|
5
|
+
const g = (s) => {
|
|
6
|
+
const o = document.querySelector("[data-copilot-checkout-toast]");
|
|
7
|
+
o && o.remove();
|
|
8
|
+
const r = document.createElement("div");
|
|
9
|
+
r.setAttribute("data-copilot-checkout-toast", "true"), r.innerText = s, Object.assign(r.style, {
|
|
10
|
+
position: "fixed",
|
|
11
|
+
top: "20px",
|
|
12
|
+
left: "50%",
|
|
13
|
+
transform: "translateX(-50%)",
|
|
14
|
+
padding: "12px 16px",
|
|
15
|
+
background: "#0f172a",
|
|
16
|
+
color: "white",
|
|
17
|
+
borderRadius: "12px",
|
|
18
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
19
|
+
zIndex: 2147483647,
|
|
20
|
+
fontSize: "14px",
|
|
21
|
+
fontWeight: "600",
|
|
22
|
+
maxWidth: "420px",
|
|
23
|
+
lineHeight: "1.4",
|
|
24
|
+
textAlign: "center"
|
|
25
|
+
}), document.body.appendChild(r), setTimeout(() => {
|
|
26
|
+
r.remove();
|
|
27
|
+
}, 4500);
|
|
28
|
+
}, c = document.createElement("div");
|
|
29
|
+
c.setAttribute("data-copilot-widget-root", "true");
|
|
30
|
+
const n = c.attachShadow({ mode: "open" });
|
|
31
|
+
document.body.appendChild(c);
|
|
32
|
+
const t = document.createElement("button");
|
|
33
|
+
t.type = "button", t.setAttribute("aria-label", "Open Copilot chat"), t.innerHTML = `
|
|
34
|
+
<img
|
|
35
|
+
src="${u}"
|
|
36
|
+
alt="Copilot chat launcher"
|
|
37
|
+
style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
|
|
38
|
+
/>
|
|
39
|
+
`, Object.assign(t.style, {
|
|
40
|
+
position: "fixed",
|
|
41
|
+
bottom: "24px",
|
|
42
|
+
right: "24px",
|
|
43
|
+
width: "64px",
|
|
44
|
+
height: "64px",
|
|
45
|
+
borderRadius: "50%",
|
|
46
|
+
border: "none",
|
|
47
|
+
background: "linear-gradient(135deg, #0078ff, #00c6ff)",
|
|
48
|
+
color: "white",
|
|
49
|
+
cursor: "pointer",
|
|
50
|
+
zIndex: 999998,
|
|
51
|
+
display: "flex",
|
|
52
|
+
alignItems: "center",
|
|
53
|
+
justifyContent: "center",
|
|
54
|
+
boxShadow: "0 6px 14px rgba(0,0,0,0.25)",
|
|
55
|
+
transition: "all 0.25s ease"
|
|
56
|
+
}), t.onmouseover = () => {
|
|
57
|
+
t.style.transform = "scale(1.12)", t.style.boxShadow = "0 10px 25px rgba(0,0,0,0.3)";
|
|
58
|
+
}, t.onmouseout = () => {
|
|
59
|
+
t.style.transform = "scale(1)", t.style.boxShadow = "0 6px 14px rgba(0,0,0,0.25)";
|
|
60
|
+
};
|
|
61
|
+
const e = document.createElement("div");
|
|
62
|
+
e.setAttribute("data-copilot-widget-root", "true"), Object.assign(e.style, {
|
|
63
|
+
display: "none",
|
|
64
|
+
position: "fixed",
|
|
65
|
+
bottom: "100px",
|
|
66
|
+
right: "24px",
|
|
67
|
+
zIndex: "999999",
|
|
68
|
+
transformOrigin: "bottom right",
|
|
69
|
+
transform: "scale(0.8) translateY(20px)",
|
|
70
|
+
opacity: "0",
|
|
71
|
+
transition: "all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)"
|
|
72
|
+
});
|
|
73
|
+
const l = document.createElement("div"), b = document.createElement("div"), f = document.createElement("div");
|
|
74
|
+
Object.assign(l.style, {
|
|
75
|
+
position: "absolute",
|
|
76
|
+
bottom: "-14px",
|
|
77
|
+
right: "28px",
|
|
78
|
+
width: "30px",
|
|
79
|
+
height: "20px",
|
|
80
|
+
pointerEvents: "none",
|
|
81
|
+
display: "none",
|
|
82
|
+
zIndex: "1"
|
|
83
|
+
}), Object.assign(b.style, {
|
|
84
|
+
position: "absolute",
|
|
85
|
+
bottom: "0",
|
|
86
|
+
left: "0",
|
|
87
|
+
right: "0",
|
|
88
|
+
margin: "0 auto",
|
|
89
|
+
width: "0",
|
|
90
|
+
height: "0",
|
|
91
|
+
borderLeft: "15px solid transparent",
|
|
92
|
+
borderRight: "15px solid transparent",
|
|
93
|
+
borderTop: "15px solid rgba(15,23,42,0.1)"
|
|
94
|
+
}), Object.assign(f.style, {
|
|
95
|
+
position: "absolute",
|
|
96
|
+
bottom: "2px",
|
|
97
|
+
left: "0",
|
|
98
|
+
right: "0",
|
|
99
|
+
margin: "0 auto",
|
|
100
|
+
width: "0",
|
|
101
|
+
height: "0",
|
|
102
|
+
borderLeft: "13px solid transparent",
|
|
103
|
+
borderRight: "13px solid transparent",
|
|
104
|
+
borderTop: "13px solid white",
|
|
105
|
+
boxShadow: "0 6px 16px rgba(15,23,42,0.12)",
|
|
106
|
+
borderRadius: "2px"
|
|
107
|
+
}), l.appendChild(b), l.appendChild(f);
|
|
108
|
+
const p = document.createElement("div");
|
|
109
|
+
Object.assign(p.style, {
|
|
110
|
+
width: "720px",
|
|
111
|
+
maxWidth: "calc(100vw - 48px)",
|
|
112
|
+
height: `${Math.min(720, Math.max(320, window.innerHeight - 140))}px`,
|
|
113
|
+
maxHeight: "calc(100vh - 150px)",
|
|
114
|
+
borderRadius: "20px",
|
|
115
|
+
background: "white",
|
|
116
|
+
border: "1px solid rgba(15,23,42,0.12)",
|
|
117
|
+
boxShadow: "0 18px 45px rgba(15,23,42,0.16)",
|
|
118
|
+
overflow: "hidden"
|
|
119
|
+
}), n.appendChild(p);
|
|
120
|
+
const i = document.createElement("iframe");
|
|
121
|
+
i.src = h, i.title = "Copilot chat widget", i.allow = "clipboard-read; clipboard-write; microphone; camera; display-capture", i.setAttribute("scrolling", "no"), Object.assign(i.style, {
|
|
122
|
+
width: "100%",
|
|
123
|
+
height: "100%",
|
|
124
|
+
border: "none",
|
|
125
|
+
display: "block",
|
|
126
|
+
background: "transparent",
|
|
127
|
+
overflow: "hidden"
|
|
128
|
+
}), n.appendChild(p), p.appendChild(i), e.appendChild(l), e.appendChild(p), document.body.appendChild(t), document.body.appendChild(e);
|
|
129
|
+
let a = !1;
|
|
130
|
+
const m = () => {
|
|
131
|
+
a && (a = !1, e.style.opacity = "0", e.style.transform = "scale(0.8) translateY(20px)", l.style.display = "none", setTimeout(() => {
|
|
132
|
+
e.style.display = "none";
|
|
133
|
+
}, 250), t.style.transform = "scale(1)");
|
|
134
|
+
}, x = (s) => {
|
|
135
|
+
const { data: o, source: r } = s || {};
|
|
136
|
+
if (o?.type) {
|
|
137
|
+
if (o.type === "CART_CHECKOUT" && r === i.contentWindow) {
|
|
138
|
+
console.log("[CopilotChat] Received checkout payload from widget:", o), g("Checkout message received from chat widget. Check console for payload.");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (o.type === "WIDGET_READY" && r === i.contentWindow) {
|
|
142
|
+
i.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
o.type === "CHAT_CLOSED" && m();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
window.addEventListener("message", x), t.onclick = (s) => {
|
|
149
|
+
s.stopPropagation(), a = !a, a ? (e.style.display = "block", l.style.display = "block", requestAnimationFrame(() => {
|
|
150
|
+
e.style.opacity = "1", e.style.transform = "scale(1) translateY(0)";
|
|
151
|
+
})) : m();
|
|
152
|
+
}, document.addEventListener("click", (s) => {
|
|
153
|
+
const o = s.target;
|
|
154
|
+
o && a && !e.contains(o) && o !== t && m();
|
|
155
|
+
});
|
|
156
|
+
const w = {
|
|
157
|
+
close: m,
|
|
158
|
+
open: () => {
|
|
159
|
+
a || t.click();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
return window.CopilotChat = window.CopilotChat || {}, window.CopilotChat.close = w.close, window.CopilotChat.open = w.open, window.CopilotChat.controls = w, w;
|
|
163
|
+
};
|
|
164
|
+
async function E(h = {}) {
|
|
3
165
|
if (typeof window > "u" || typeof document > "u")
|
|
4
166
|
return null;
|
|
5
|
-
const { token
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
167
|
+
const u = window.CopilotChatConfig || {}, d = h.token || u.token || typeof window < "u" && window.localStorage?.getItem("copilotChatToken") || null;
|
|
168
|
+
if (!d)
|
|
169
|
+
return console.error(
|
|
170
|
+
"[CopilotChat] Missing token (provide via loadCopilotChatWidget({ token }) or window.CopilotChatConfig.token)."
|
|
171
|
+
), null;
|
|
172
|
+
const g = h.baseUrl || u.baseUrl || C, c = `${g.replace(/\/$/, "")}/api/chat-widget/config?token=${encodeURIComponent(
|
|
173
|
+
d
|
|
174
|
+
)}`;
|
|
175
|
+
try {
|
|
176
|
+
const n = await fetch(c, {
|
|
177
|
+
credentials: "omit",
|
|
178
|
+
mode: "cors"
|
|
179
|
+
});
|
|
180
|
+
if (!n.ok)
|
|
181
|
+
throw new Error(`Server responded with ${n.status}`);
|
|
182
|
+
const t = await n.json();
|
|
183
|
+
if (!t?.iframeUrl || !t?.launcherIcon)
|
|
184
|
+
throw new Error("Received incomplete widget configuration from server.");
|
|
185
|
+
return window.CopilotChat = window.CopilotChat || {}, window.CopilotChat.token = d, window.CopilotChat.baseUrl = g, y({
|
|
186
|
+
iframeUrl: t.iframeUrl,
|
|
187
|
+
launcherIcon: t.launcherIcon
|
|
188
|
+
});
|
|
189
|
+
} catch (n) {
|
|
190
|
+
return console.error(
|
|
191
|
+
"[CopilotChat] Error during widget bootstrap:",
|
|
192
|
+
n instanceof Error ? n.message : n
|
|
193
|
+
), null;
|
|
194
|
+
}
|
|
16
195
|
}
|
|
17
196
|
export {
|
|
18
|
-
|
|
19
|
-
|
|
197
|
+
E as default,
|
|
198
|
+
E as loadCopilotChatWidget
|
|
20
199
|
};
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export interface CopilotChatOptions {
|
|
|
4
4
|
baseUrl?: string;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export function loadCopilotChatWidget(options: CopilotChatOptions):
|
|
7
|
+
export function loadCopilotChatWidget(options: CopilotChatOptions): unknown;
|
|
8
8
|
export default loadCopilotChatWidget;
|
package/src/index.js
CHANGED
|
@@ -1,40 +1,338 @@
|
|
|
1
|
-
const BUILD_BASE_URL =
|
|
2
|
-
typeof __WIDGET_BASE_URL__ !== "undefined" && __WIDGET_BASE_URL__
|
|
3
|
-
? __WIDGET_BASE_URL__
|
|
4
|
-
: undefined;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
const BUILD_BASE_URL =
|
|
2
|
+
typeof __WIDGET_BASE_URL__ !== "undefined" && __WIDGET_BASE_URL__
|
|
3
|
+
? __WIDGET_BASE_URL__
|
|
4
|
+
: undefined;
|
|
5
|
+
|
|
6
|
+
const BUTTON_SIZE = 64;
|
|
7
|
+
const IFRAME_SIZE = 720;
|
|
8
|
+
|
|
9
|
+
const buildWidget = ({ iframeUrl, launcherIcon }) => {
|
|
10
|
+
const existingRoot = document.querySelector("[data-copilot-widget-root]");
|
|
11
|
+
if (existingRoot) {
|
|
12
|
+
existingRoot.remove();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const showCheckoutToast = (message) => {
|
|
16
|
+
const existingToast = document.querySelector("[data-copilot-checkout-toast]");
|
|
17
|
+
if (existingToast) {
|
|
18
|
+
existingToast.remove();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const toast = document.createElement("div");
|
|
22
|
+
toast.setAttribute("data-copilot-checkout-toast", "true");
|
|
23
|
+
toast.innerText = message;
|
|
24
|
+
|
|
25
|
+
Object.assign(toast.style, {
|
|
26
|
+
position: "fixed",
|
|
27
|
+
top: "20px",
|
|
28
|
+
left: "50%",
|
|
29
|
+
transform: "translateX(-50%)",
|
|
30
|
+
padding: "12px 16px",
|
|
31
|
+
background: "#0f172a",
|
|
32
|
+
color: "white",
|
|
33
|
+
borderRadius: "12px",
|
|
34
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
35
|
+
zIndex: 2147483647,
|
|
36
|
+
fontSize: "14px",
|
|
37
|
+
fontWeight: "600",
|
|
38
|
+
maxWidth: "420px",
|
|
39
|
+
lineHeight: "1.4",
|
|
40
|
+
textAlign: "center",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
document.body.appendChild(toast);
|
|
44
|
+
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
toast.remove();
|
|
47
|
+
}, 4500);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Shadow DOM container
|
|
51
|
+
const containerHost = document.createElement("div");
|
|
52
|
+
containerHost.setAttribute("data-copilot-widget-root", "true");
|
|
53
|
+
const shadow = containerHost.attachShadow({ mode: "open" });
|
|
54
|
+
document.body.appendChild(containerHost);
|
|
55
|
+
|
|
56
|
+
// Button
|
|
57
|
+
const btn = document.createElement("button");
|
|
58
|
+
btn.type = "button";
|
|
59
|
+
btn.setAttribute("aria-label", "Open Copilot chat");
|
|
60
|
+
btn.innerHTML = `
|
|
61
|
+
<img
|
|
62
|
+
src="${launcherIcon}"
|
|
63
|
+
alt="Copilot chat launcher"
|
|
64
|
+
style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
|
|
65
|
+
/>
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
Object.assign(btn.style, {
|
|
69
|
+
position: "fixed",
|
|
70
|
+
bottom: "24px",
|
|
71
|
+
right: "24px",
|
|
72
|
+
width: `${BUTTON_SIZE}px`,
|
|
73
|
+
height: `${BUTTON_SIZE}px`,
|
|
74
|
+
borderRadius: "50%",
|
|
75
|
+
border: "none",
|
|
76
|
+
background: "linear-gradient(135deg, #0078ff, #00c6ff)",
|
|
77
|
+
color: "white",
|
|
78
|
+
cursor: "pointer",
|
|
79
|
+
zIndex: 999998,
|
|
80
|
+
display: "flex",
|
|
81
|
+
alignItems: "center",
|
|
82
|
+
justifyContent: "center",
|
|
83
|
+
boxShadow: "0 6px 14px rgba(0,0,0,0.25)",
|
|
84
|
+
transition: "all 0.25s ease",
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
btn.onmouseover = () => {
|
|
88
|
+
btn.style.transform = "scale(1.12)";
|
|
89
|
+
btn.style.boxShadow = "0 10px 25px rgba(0,0,0,0.3)";
|
|
90
|
+
};
|
|
91
|
+
btn.onmouseout = () => {
|
|
92
|
+
btn.style.transform = "scale(1)";
|
|
93
|
+
btn.style.boxShadow = "0 6px 14px rgba(0,0,0,0.25)";
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const container = document.createElement("div");
|
|
97
|
+
container.setAttribute("data-copilot-widget-root", "true");
|
|
98
|
+
Object.assign(container.style, {
|
|
99
|
+
display: "none",
|
|
100
|
+
position: "fixed",
|
|
101
|
+
bottom: `${BUTTON_SIZE + 36}px`,
|
|
102
|
+
right: "24px",
|
|
103
|
+
zIndex: "999999",
|
|
104
|
+
transformOrigin: "bottom right",
|
|
105
|
+
transform: "scale(0.8) translateY(20px)",
|
|
106
|
+
opacity: "0",
|
|
107
|
+
transition: "all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const arrow = document.createElement("div");
|
|
111
|
+
const arrowBorder = document.createElement("div");
|
|
112
|
+
const arrowFill = document.createElement("div");
|
|
113
|
+
|
|
114
|
+
Object.assign(arrow.style, {
|
|
115
|
+
position: "absolute",
|
|
116
|
+
bottom: "-14px",
|
|
117
|
+
right: "28px",
|
|
118
|
+
width: "30px",
|
|
119
|
+
height: "20px",
|
|
120
|
+
pointerEvents: "none",
|
|
121
|
+
display: "none",
|
|
122
|
+
zIndex: "1",
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
Object.assign(arrowBorder.style, {
|
|
126
|
+
position: "absolute",
|
|
127
|
+
bottom: "0",
|
|
128
|
+
left: "0",
|
|
129
|
+
right: "0",
|
|
130
|
+
margin: "0 auto",
|
|
131
|
+
width: "0",
|
|
132
|
+
height: "0",
|
|
133
|
+
borderLeft: "15px solid transparent",
|
|
134
|
+
borderRight: "15px solid transparent",
|
|
135
|
+
borderTop: "15px solid rgba(15,23,42,0.1)",
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
Object.assign(arrowFill.style, {
|
|
139
|
+
position: "absolute",
|
|
140
|
+
bottom: "2px",
|
|
141
|
+
left: "0",
|
|
142
|
+
right: "0",
|
|
143
|
+
margin: "0 auto",
|
|
144
|
+
width: "0",
|
|
145
|
+
height: "0",
|
|
146
|
+
borderLeft: "13px solid transparent",
|
|
147
|
+
borderRight: "13px solid transparent",
|
|
148
|
+
borderTop: "13px solid white",
|
|
149
|
+
boxShadow: "0 6px 16px rgba(15,23,42,0.12)",
|
|
150
|
+
borderRadius: "2px",
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
arrow.appendChild(arrowBorder);
|
|
154
|
+
arrow.appendChild(arrowFill);
|
|
155
|
+
|
|
156
|
+
const frameWrapper = document.createElement("div");
|
|
157
|
+
Object.assign(frameWrapper.style, {
|
|
158
|
+
width: `${IFRAME_SIZE}px`,
|
|
159
|
+
maxWidth: "calc(100vw - 48px)",
|
|
160
|
+
height: `${Math.min(IFRAME_SIZE, Math.max(320, window.innerHeight - 140))}px`,
|
|
161
|
+
maxHeight: "calc(100vh - 150px)",
|
|
162
|
+
borderRadius: "20px",
|
|
163
|
+
background: "white",
|
|
164
|
+
border: "1px solid rgba(15,23,42,0.12)",
|
|
165
|
+
boxShadow: "0 18px 45px rgba(15,23,42,0.16)",
|
|
166
|
+
overflow: "hidden",
|
|
167
|
+
});
|
|
168
|
+
shadow.appendChild(frameWrapper);
|
|
169
|
+
|
|
170
|
+
const iframe = document.createElement("iframe");
|
|
171
|
+
iframe.src = iframeUrl;
|
|
172
|
+
iframe.title = "Copilot chat widget";
|
|
173
|
+
iframe.allow = "clipboard-read; clipboard-write; microphone; camera; display-capture";
|
|
174
|
+
iframe.setAttribute("scrolling", "no");
|
|
175
|
+
Object.assign(iframe.style, {
|
|
176
|
+
width: "100%",
|
|
177
|
+
height: "100%",
|
|
178
|
+
border: "none",
|
|
179
|
+
display: "block",
|
|
180
|
+
background: "transparent",
|
|
181
|
+
overflow: "hidden",
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
shadow.appendChild(frameWrapper);
|
|
185
|
+
frameWrapper.appendChild(iframe);
|
|
186
|
+
|
|
187
|
+
container.appendChild(arrow);
|
|
188
|
+
container.appendChild(frameWrapper);
|
|
189
|
+
document.body.appendChild(btn);
|
|
190
|
+
document.body.appendChild(container);
|
|
191
|
+
|
|
192
|
+
let isOpen = false;
|
|
193
|
+
|
|
194
|
+
const closeChat = () => {
|
|
195
|
+
if (!isOpen) return;
|
|
196
|
+
isOpen = false;
|
|
197
|
+
container.style.opacity = "0";
|
|
198
|
+
container.style.transform = "scale(0.8) translateY(20px)";
|
|
199
|
+
arrow.style.display = "none";
|
|
200
|
+
setTimeout(() => {
|
|
201
|
+
container.style.display = "none";
|
|
202
|
+
}, 250);
|
|
203
|
+
btn.style.transform = "scale(1)";
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const handleWidgetMessage = (event) => {
|
|
207
|
+
const { data, source } = event || {};
|
|
208
|
+
if (!data?.type) return;
|
|
209
|
+
|
|
210
|
+
if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
|
|
211
|
+
console.log("[CopilotChat] Received checkout payload from widget:", data);
|
|
212
|
+
showCheckoutToast("Checkout message received from chat widget. Check console for payload.");
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (data.type === "WIDGET_READY" && source === iframe.contentWindow) {
|
|
217
|
+
iframe.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (data.type === "CHAT_CLOSED") {
|
|
222
|
+
closeChat();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
window.addEventListener("message", handleWidgetMessage);
|
|
227
|
+
|
|
228
|
+
btn.onclick = (event) => {
|
|
229
|
+
event.stopPropagation();
|
|
230
|
+
isOpen = !isOpen;
|
|
231
|
+
if (isOpen) {
|
|
232
|
+
container.style.display = "block";
|
|
233
|
+
arrow.style.display = "block";
|
|
234
|
+
requestAnimationFrame(() => {
|
|
235
|
+
container.style.opacity = "1";
|
|
236
|
+
container.style.transform = "scale(1) translateY(0)";
|
|
237
|
+
});
|
|
238
|
+
} else {
|
|
239
|
+
closeChat();
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
document.addEventListener("click", (event) => {
|
|
244
|
+
const target = event.target;
|
|
245
|
+
if (!target) return;
|
|
246
|
+
if (isOpen && !container.contains(target) && target !== btn) {
|
|
247
|
+
closeChat();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const controls = {
|
|
252
|
+
close: closeChat,
|
|
253
|
+
open: () => {
|
|
254
|
+
if (!isOpen) {
|
|
255
|
+
btn.click();
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
window.CopilotChat = window.CopilotChat || {};
|
|
261
|
+
window.CopilotChat.close = controls.close;
|
|
262
|
+
window.CopilotChat.open = controls.open;
|
|
263
|
+
window.CopilotChat.controls = controls;
|
|
264
|
+
|
|
265
|
+
return controls;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export async function loadCopilotChatWidget(options = {}) {
|
|
269
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const globalConfig = window.CopilotChatConfig || {};
|
|
274
|
+
const token =
|
|
275
|
+
options.token ||
|
|
276
|
+
globalConfig.token ||
|
|
277
|
+
(typeof window !== "undefined"
|
|
278
|
+
? window.localStorage?.getItem("copilotChatToken") || null
|
|
279
|
+
: null);
|
|
280
|
+
|
|
281
|
+
if (!token) {
|
|
282
|
+
console.error(
|
|
283
|
+
"[CopilotChat] Missing token (provide via loadCopilotChatWidget({ token }) or window.CopilotChatConfig.token)."
|
|
284
|
+
);
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const baseUrl =
|
|
289
|
+
options.baseUrl ||
|
|
290
|
+
globalConfig.baseUrl ||
|
|
291
|
+
BUILD_BASE_URL ||
|
|
292
|
+
(typeof window !== "undefined" && window.location?.origin) ||
|
|
293
|
+
null;
|
|
294
|
+
|
|
295
|
+
if (!baseUrl) {
|
|
296
|
+
console.error(
|
|
297
|
+
"[CopilotChat] Missing baseUrl (set via loadCopilotChatWidget({ baseUrl }), window.CopilotChatConfig.baseUrl, or WIDGET_BASE_URL)."
|
|
298
|
+
);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const url = `${baseUrl.replace(/\/$/, "")}/api/chat-widget/config?token=${encodeURIComponent(
|
|
303
|
+
token
|
|
304
|
+
)}`;
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
const response = await fetch(url, {
|
|
308
|
+
credentials: "omit",
|
|
309
|
+
mode: "cors",
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
if (!response.ok) {
|
|
313
|
+
throw new Error(`Server responded with ${response.status}`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const remoteConfig = await response.json();
|
|
317
|
+
if (!remoteConfig?.iframeUrl || !remoteConfig?.launcherIcon) {
|
|
318
|
+
throw new Error("Received incomplete widget configuration from server.");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
window.CopilotChat = window.CopilotChat || {};
|
|
322
|
+
window.CopilotChat.token = token;
|
|
323
|
+
window.CopilotChat.baseUrl = baseUrl;
|
|
324
|
+
|
|
325
|
+
return buildWidget({
|
|
326
|
+
iframeUrl: remoteConfig.iframeUrl,
|
|
327
|
+
launcherIcon: remoteConfig.launcherIcon,
|
|
328
|
+
});
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error(
|
|
331
|
+
"[CopilotChat] Error during widget bootstrap:",
|
|
332
|
+
error instanceof Error ? error.message : error
|
|
333
|
+
);
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export default loadCopilotChatWidget;
|
package/src/widget-runtime.js
CHANGED
|
@@ -57,47 +57,47 @@
|
|
|
57
57
|
|
|
58
58
|
return candidate || null;
|
|
59
59
|
};
|
|
60
|
-
|
|
61
|
-
const buildWidget = ({ iframeUrl, launcherIcon }) => {
|
|
62
|
-
const existingRoot = document.querySelector("[data-copilot-widget-root]");
|
|
63
|
-
if (existingRoot) {
|
|
64
|
-
existingRoot.remove();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const showCheckoutToast = (message) => {
|
|
68
|
-
const existingToast = document.querySelector("[data-copilot-checkout-toast]");
|
|
69
|
-
if (existingToast) {
|
|
70
|
-
existingToast.remove();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const toast = document.createElement("div");
|
|
74
|
-
toast.setAttribute("data-copilot-checkout-toast", "true");
|
|
75
|
-
toast.innerText = message;
|
|
76
|
-
|
|
77
|
-
Object.assign(toast.style, {
|
|
78
|
-
position: "fixed",
|
|
79
|
-
top: "20px",
|
|
80
|
-
left: "50%",
|
|
81
|
-
transform: "translateX(-50%)",
|
|
82
|
-
padding: "12px 16px",
|
|
83
|
-
background: "#0f172a",
|
|
84
|
-
color: "white",
|
|
85
|
-
borderRadius: "12px",
|
|
86
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
87
|
-
zIndex: 2147483647,
|
|
88
|
-
fontSize: "14px",
|
|
89
|
-
fontWeight: "600",
|
|
90
|
-
maxWidth: "420px",
|
|
91
|
-
lineHeight: "1.4",
|
|
92
|
-
textAlign: "center",
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
document.body.appendChild(toast);
|
|
96
|
-
|
|
97
|
-
setTimeout(() => {
|
|
98
|
-
toast.remove();
|
|
99
|
-
}, 4500);
|
|
100
|
-
};
|
|
60
|
+
|
|
61
|
+
const buildWidget = ({ iframeUrl, launcherIcon }) => {
|
|
62
|
+
const existingRoot = document.querySelector("[data-copilot-widget-root]");
|
|
63
|
+
if (existingRoot) {
|
|
64
|
+
existingRoot.remove();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const showCheckoutToast = (message) => {
|
|
68
|
+
const existingToast = document.querySelector("[data-copilot-checkout-toast]");
|
|
69
|
+
if (existingToast) {
|
|
70
|
+
existingToast.remove();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const toast = document.createElement("div");
|
|
74
|
+
toast.setAttribute("data-copilot-checkout-toast", "true");
|
|
75
|
+
toast.innerText = message;
|
|
76
|
+
|
|
77
|
+
Object.assign(toast.style, {
|
|
78
|
+
position: "fixed",
|
|
79
|
+
top: "20px",
|
|
80
|
+
left: "50%",
|
|
81
|
+
transform: "translateX(-50%)",
|
|
82
|
+
padding: "12px 16px",
|
|
83
|
+
background: "#0f172a",
|
|
84
|
+
color: "white",
|
|
85
|
+
borderRadius: "12px",
|
|
86
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
87
|
+
zIndex: 2147483647,
|
|
88
|
+
fontSize: "14px",
|
|
89
|
+
fontWeight: "600",
|
|
90
|
+
maxWidth: "420px",
|
|
91
|
+
lineHeight: "1.4",
|
|
92
|
+
textAlign: "center",
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
document.body.appendChild(toast);
|
|
96
|
+
|
|
97
|
+
setTimeout(() => {
|
|
98
|
+
toast.remove();
|
|
99
|
+
}, 4500);
|
|
100
|
+
};
|
|
101
101
|
|
|
102
102
|
// ---------- Shadow DOM container ----------
|
|
103
103
|
const containerHost = document.createElement("div");
|
|
@@ -256,42 +256,42 @@
|
|
|
256
256
|
btn.style.transform = "scale(1)";
|
|
257
257
|
};
|
|
258
258
|
|
|
259
|
-
const handleWidgetMessage = (event) => {
|
|
260
|
-
const { data, source } = event || {};
|
|
261
|
-
if (!data?.type) return;
|
|
262
|
-
|
|
263
|
-
if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
|
|
264
|
-
console.log("[CopilotChat] Received checkout payload from widget:", data);
|
|
265
|
-
showCheckoutToast("Checkout message received from chat widget. Check console for payload.");
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (data.type === "WIDGET_READY" && source === iframe.contentWindow) {
|
|
270
|
-
iframe.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (data.type === "CHAT_CLOSED") {
|
|
275
|
-
closeChat();
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
btn.onclick = (event) => {
|
|
280
|
-
event.stopPropagation();
|
|
281
|
-
isOpen = !isOpen;
|
|
282
|
-
if (isOpen) {
|
|
283
|
-
container.style.display = "block";
|
|
284
|
-
arrow.style.display = "block";
|
|
285
|
-
requestAnimationFrame(() => {
|
|
286
|
-
container.style.opacity = "1";
|
|
287
|
-
container.style.transform = "scale(1) translateY(0)";
|
|
288
|
-
});
|
|
289
|
-
} else {
|
|
290
|
-
closeChat();
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
window.addEventListener("message", handleWidgetMessage);
|
|
259
|
+
const handleWidgetMessage = (event) => {
|
|
260
|
+
const { data, source } = event || {};
|
|
261
|
+
if (!data?.type) return;
|
|
262
|
+
|
|
263
|
+
if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
|
|
264
|
+
console.log("[CopilotChat] Received checkout payload from widget:", data);
|
|
265
|
+
showCheckoutToast("Checkout message received from chat widget. Check console for payload.");
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (data.type === "WIDGET_READY" && source === iframe.contentWindow) {
|
|
270
|
+
iframe.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (data.type === "CHAT_CLOSED") {
|
|
275
|
+
closeChat();
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
btn.onclick = (event) => {
|
|
280
|
+
event.stopPropagation();
|
|
281
|
+
isOpen = !isOpen;
|
|
282
|
+
if (isOpen) {
|
|
283
|
+
container.style.display = "block";
|
|
284
|
+
arrow.style.display = "block";
|
|
285
|
+
requestAnimationFrame(() => {
|
|
286
|
+
container.style.opacity = "1";
|
|
287
|
+
container.style.transform = "scale(1) translateY(0)";
|
|
288
|
+
});
|
|
289
|
+
} else {
|
|
290
|
+
closeChat();
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
window.addEventListener("message", handleWidgetMessage);
|
|
295
295
|
|
|
296
296
|
document.addEventListener("click", (event) => {
|
|
297
297
|
const target = event.target;
|