copilot-chat-widget 0.1.13 → 0.1.15
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 +80 -72
- package/dist/chat-widget.min.js +3 -3
- package/package.json +3 -1
- package/src/index.js +23 -23
- package/src/widget-runtime.js +83 -41
package/README.md
CHANGED
|
@@ -1,72 +1,80 @@
|
|
|
1
|
-
# Copilot Chat Widget
|
|
2
|
-
|
|
3
|
-
Embeddable chat widget ready for CDN drop-in or npm import.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
```bash
|
|
7
|
-
npm install copilot-chat-widget
|
|
8
|
-
# or
|
|
9
|
-
yarn add copilot-chat-widget
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
## Quick start (npm / bundler)
|
|
13
|
-
```js
|
|
14
|
-
import { loadCopilotChatWidget } from "copilot-chat-widget";
|
|
15
|
-
|
|
16
|
-
loadCopilotChatWidget({
|
|
17
|
-
token: "YOUR_WIDGET_TOKEN",
|
|
18
|
-
// optional when backend is another origin:
|
|
19
|
-
// baseUrl: "https://your-backend-domain"
|
|
20
|
-
});
|
|
21
|
-
```
|
|
22
|
-
`loadCopilotChatWidget` injects the standalone bundle (`chat-widget.min.js`) and boots the widget with the given token.
|
|
23
|
-
|
|
24
|
-
### React/Next.js
|
|
25
|
-
```jsx
|
|
26
|
-
import { useEffect } from "react";
|
|
27
|
-
import { loadCopilotChatWidget } from "copilot-chat-widget";
|
|
28
|
-
|
|
29
|
-
export default function Page() {
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
loadCopilotChatWidget({
|
|
32
|
-
token: process.env.NEXT_PUBLIC_CHAT_WIDGET_TOKEN,
|
|
33
|
-
baseUrl: process.env.NEXT_PUBLIC_WIDGET_BASE_URL // optional override
|
|
34
|
-
});
|
|
35
|
-
}, []);
|
|
36
|
-
|
|
37
|
-
return <main>Your page content</main>;
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Quick start (script tag)
|
|
42
|
-
```html
|
|
43
|
-
<script
|
|
44
|
-
src="https://unpkg.com/copilot-chat-widget/dist/chat-widget.min.js"
|
|
45
|
-
data-token="YOUR_WIDGET_TOKEN"
|
|
46
|
-
data-base-url="https://your-backend-domain" <!-- optional if backend is another origin -->
|
|
47
|
-
></script>
|
|
48
|
-
```
|
|
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()` yourself.
|
|
52
|
-
|
|
53
|
-
## Configuration
|
|
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. Fallback order: `baseUrl` option/data attribute → `WIDGET_BASE_URL` (build-time) → script/page origin.
|
|
56
|
-
- `autoload` (boolean): set `false` to defer bootstrap and call `window.CopilotChat.load()` manually.
|
|
57
|
-
|
|
58
|
-
Runtime controls:
|
|
59
|
-
```js
|
|
60
|
-
window.CopilotChat.open(); // open widget
|
|
61
|
-
window.CopilotChat.close(); // close widget
|
|
62
|
-
window.CopilotChat.load(); // initialize if autoload=false
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
1
|
+
# Copilot Chat Widget
|
|
2
|
+
|
|
3
|
+
Embeddable chat widget ready for CDN drop-in or npm import.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
```bash
|
|
7
|
+
npm install copilot-chat-widget
|
|
8
|
+
# or
|
|
9
|
+
yarn add copilot-chat-widget
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick start (npm / bundler)
|
|
13
|
+
```js
|
|
14
|
+
import { loadCopilotChatWidget } from "copilot-chat-widget";
|
|
15
|
+
|
|
16
|
+
loadCopilotChatWidget({
|
|
17
|
+
token: "YOUR_WIDGET_TOKEN",
|
|
18
|
+
// optional when backend is another origin:
|
|
19
|
+
// baseUrl: "https://your-backend-domain"
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
`loadCopilotChatWidget` injects the standalone bundle (`chat-widget.min.js`) and boots the widget with the given token.
|
|
23
|
+
|
|
24
|
+
### React/Next.js
|
|
25
|
+
```jsx
|
|
26
|
+
import { useEffect } from "react";
|
|
27
|
+
import { loadCopilotChatWidget } from "copilot-chat-widget";
|
|
28
|
+
|
|
29
|
+
export default function Page() {
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
loadCopilotChatWidget({
|
|
32
|
+
token: process.env.NEXT_PUBLIC_CHAT_WIDGET_TOKEN,
|
|
33
|
+
baseUrl: process.env.NEXT_PUBLIC_WIDGET_BASE_URL // optional override
|
|
34
|
+
});
|
|
35
|
+
}, []);
|
|
36
|
+
|
|
37
|
+
return <main>Your page content</main>;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick start (script tag)
|
|
42
|
+
```html
|
|
43
|
+
<script
|
|
44
|
+
src="https://unpkg.com/copilot-chat-widget/dist/chat-widget.min.js"
|
|
45
|
+
data-token="YOUR_WIDGET_TOKEN"
|
|
46
|
+
data-base-url="https://your-backend-domain" <!-- optional if backend is another origin -->
|
|
47
|
+
></script>
|
|
48
|
+
```
|
|
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()` yourself.
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
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. Fallback order: `baseUrl` option/data attribute → `WIDGET_BASE_URL` (build-time) → script/page origin.
|
|
56
|
+
- `autoload` (boolean): set `false` to defer bootstrap and call `window.CopilotChat.load()` manually.
|
|
57
|
+
|
|
58
|
+
Runtime controls:
|
|
59
|
+
```js
|
|
60
|
+
window.CopilotChat.open(); // open widget
|
|
61
|
+
window.CopilotChat.close(); // close widget
|
|
62
|
+
window.CopilotChat.load(); // initialize if autoload=false
|
|
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/chat-widget.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
(function(){"use strict";(()=>{if(typeof window>"u"||typeof document>"u"||window.__copilotWidgetLoaded)return;window.__copilotWidgetLoaded=!0;const
|
|
1
|
+
(function(){"use strict";(()=>{if(typeof window>"u"||typeof document>"u"||window.__copilotWidgetLoaded)return;window.__copilotWidgetLoaded=!0;const S="http://localhost:3000",g=64,C=720,b=document.currentScript,y=t=>{if(!t?.src)return{};try{const s=new URL(t.src,window.location.href),o={};return s.searchParams.forEach((d,c)=>{o[c]=d}),o}catch(s){return console.warn("[CopilotChat] Failed to parse script query params:",s),{}}},T=t=>{document.readyState==="complete"||document.readyState==="interactive"?setTimeout(t,0):document.addEventListener("DOMContentLoaded",t)},x=()=>b||Array.from(document.querySelectorAll("script")).reverse().find(o=>o.dataset?.token||o.src&&o.src.includes("chat-widget"))||null,I=({iframeUrl:t,launcherIcon:s})=>{const o=document.querySelector("[data-copilot-widget-root]");o&&o.remove();const d=document.createElement("div");d.setAttribute("data-copilot-widget-root","true");const c=d.attachShadow({mode:"open"});document.body.appendChild(d);const e=document.createElement("button");e.type="button",e.setAttribute("aria-label","Open Copilot chat"),e.innerHTML=`
|
|
2
2
|
<img
|
|
3
|
-
src="${
|
|
3
|
+
src="${s}"
|
|
4
4
|
alt="Copilot chat launcher"
|
|
5
5
|
style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
|
|
6
6
|
/>
|
|
7
|
-
`,Object.assign(e.style,{position:"fixed",bottom:"24px",right:"24px",width:`${
|
|
7
|
+
`,Object.assign(e.style,{position:"fixed",bottom:"24px",right:"24px",width:`${g}px`,height:`${g}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"}),e.onmouseover=()=>{e.style.transform="scale(1.12)",e.style.boxShadow="0 10px 25px rgba(0,0,0,0.3)"},e.onmouseout=()=>{e.style.transform="scale(1)",e.style.boxShadow="0 6px 14px rgba(0,0,0,0.25)"};const n=document.createElement("div");n.setAttribute("data-copilot-widget-root","true"),Object.assign(n.style,{display:"none",position:"fixed",bottom:`${g+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 h=document.createElement("div"),i=document.createElement("div"),r=document.createElement("div");Object.assign(h.style,{position:"absolute",bottom:"-14px",right:"28px",width:"30px",height:"20px",pointerEvents:"none",display:"none",zIndex:"1"}),Object.assign(i.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(r.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"}),h.appendChild(i),h.appendChild(r);const u=document.createElement("div");Object.assign(u.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"}),c.appendChild(u);const a=document.createElement("iframe");a.src=t,a.title="Copilot chat widget",a.allow="clipboard-read; clipboard-write; microphone; camera; display-capture",a.setAttribute("scrolling","no"),Object.assign(a.style,{width:"100%",height:"100%",border:"none",display:"block",background:"transparent",overflow:"hidden"}),c.appendChild(u),u.appendChild(a),n.appendChild(h),n.appendChild(u),document.body.appendChild(e),document.body.appendChild(n);let l=!1;const f=()=>{l&&(l=!1,n.style.opacity="0",n.style.transform="scale(0.8) translateY(20px)",h.style.display="none",setTimeout(()=>{n.style.display="none"},250),e.style.transform="scale(1)")},O=w=>{const{data:p,source:v}=w||{};if(p?.type){if(p.type==="CART_CHECKOUT"&&v===a.contentWindow){console.log("[CopilotChat] Received checkout payload from widget:",p),showCheckoutToast("Checkout message received from chat widget. Check console for payload.");return}if(p.type==="WIDGET_READY"&&v===a.contentWindow){a.contentWindow.postMessage({type:"INIT_WIDGET"},"*");return}p.type==="CHAT_CLOSED"&&f()}};e.onclick=w=>{w.stopPropagation(),l=!l,l?(n.style.display="block",h.style.display="block",requestAnimationFrame(()=>{n.style.opacity="1",n.style.transform="scale(1) translateY(0)"})):f()},window.addEventListener("message",O),document.addEventListener("click",w=>{const p=w.target;p&&l&&!n.contains(p)&&p!==e&&f()});const m={close:f,open:()=>{l||e.click()}};return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.close=m.close,window.CopilotChat.open=m.open,window.CopilotChat.controls=m,m},k=t=>{console.error(`[CopilotChat] ${t}`)},U=()=>{const t=x();if(!t)return!1;const s=y(t),o=t.dataset||{},d=o.token||s.token,c=typeof window<"u"&&window.CopilotChatConfig&&window.CopilotChatConfig.token;return(d||c)&&o.autoload!=="false"},E=async(t={})=>{const s=t.scriptEl||x(),o=window.CopilotChatConfig||{},d=s?.dataset||{},c=y(s),n=(()=>{const i=t.token||o.token||d.token||c.token;if(i)return i;try{const r=window.localStorage.getItem("copilotChatToken");if(r)return r}catch{}if(typeof window<"u"&&typeof window.prompt=="function"){const r=window.prompt("Enter your Copilot Chat token:");if(r){try{window.localStorage.setItem("copilotChatToken",r)}catch{}return r}}return null})();if(!n)return k("Missing token (provide via init config, window.CopilotChatConfig.token, or data-token attribute)."),null;const h=t.baseUrl||o.baseUrl||d.baseUrl||c.baseUrl||S;try{const i=await fetch(`${h}/api/chat-widget/config?token=${encodeURIComponent(n)}`,{credentials:"omit",mode:"cors"});if(!i.ok)throw new Error(`Server responded with ${i.status}`);const r=await i.json();if(!r?.iframeUrl||!r?.launcherIcon)throw new Error("Received incomplete widget configuration from server.");return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.init=(a={})=>{const l={iframeUrl:a.iframeUrl||r.iframeUrl,launcherIcon:a.launcherIcon||r.launcherIcon};return I(l)},window.CopilotChat.init(t)}catch(i){return k(i instanceof Error?i.message:"Unknown error during widget bootstrap."),null}};U()&&T(()=>{E()}),window.CopilotChat=window.CopilotChat||{},window.CopilotChat.load=E})()})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "copilot-chat-widget",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Embeddable Copilot chat widget that can be loaded via NPM or a script tag.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
"types": "./src/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./src/index.d.ts",
|
|
11
12
|
"import": "./dist/index.mjs",
|
|
12
13
|
"require": "./dist/index.cjs"
|
|
13
14
|
},
|
|
15
|
+
"./package.json": "./package.json",
|
|
14
16
|
"./dist/chat-widget.min.js": "./dist/chat-widget.min.js"
|
|
15
17
|
},
|
|
16
18
|
"files": [
|
package/src/index.js
CHANGED
|
@@ -10,31 +10,31 @@ export function loadCopilotChatWidget(options = {}) {
|
|
|
10
10
|
|
|
11
11
|
const { token, autoload, baseUrl = BUILD_BASE_URL } = options;
|
|
12
12
|
|
|
13
|
-
//
|
|
13
|
+
// Persist config for the runtime script
|
|
14
14
|
window.CopilotChatConfig = {
|
|
15
15
|
...window.CopilotChatConfig,
|
|
16
16
|
...options,
|
|
17
17
|
baseUrl: baseUrl || window.CopilotChatConfig?.baseUrl || undefined,
|
|
18
18
|
};
|
|
19
|
-
|
|
20
|
-
const existing = document.getElementById("copilot-chat-widget-loader");
|
|
21
|
-
if (existing) {
|
|
22
|
-
if (token) existing.dataset.token = token;
|
|
23
|
-
if (baseUrl) existing.dataset.baseUrl = baseUrl;
|
|
24
|
-
if (autoload === false) existing.dataset.autoload = "false";
|
|
25
|
-
return existing;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const script = document.createElement("script");
|
|
29
|
-
script.id = "copilot-chat-widget-loader";
|
|
30
|
-
script.src = new URL("./chat-widget.min.js", import.meta.url).href;
|
|
31
|
-
script.async = true;
|
|
32
|
-
if (token) script.dataset.token = token;
|
|
33
|
-
if (baseUrl) script.dataset.baseUrl = baseUrl;
|
|
34
|
-
if (autoload === false) script.dataset.autoload = "false";
|
|
35
|
-
|
|
36
|
-
document.body.appendChild(script);
|
|
37
|
-
return script;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export default loadCopilotChatWidget;
|
|
19
|
+
|
|
20
|
+
const existing = document.getElementById("copilot-chat-widget-loader");
|
|
21
|
+
if (existing) {
|
|
22
|
+
if (token) existing.dataset.token = token;
|
|
23
|
+
if (baseUrl) existing.dataset.baseUrl = baseUrl;
|
|
24
|
+
if (autoload === false) existing.dataset.autoload = "false";
|
|
25
|
+
return existing;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const script = document.createElement("script");
|
|
29
|
+
script.id = "copilot-chat-widget-loader";
|
|
30
|
+
script.src = new URL("./chat-widget.min.js", import.meta.url).href;
|
|
31
|
+
script.async = true;
|
|
32
|
+
if (token) script.dataset.token = token;
|
|
33
|
+
if (baseUrl) script.dataset.baseUrl = baseUrl;
|
|
34
|
+
if (autoload === false) script.dataset.autoload = "false";
|
|
35
|
+
|
|
36
|
+
document.body.appendChild(script);
|
|
37
|
+
return script;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default loadCopilotChatWidget;
|
package/src/widget-runtime.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
(() => {
|
|
2
|
-
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
3
|
-
if (window.__copilotWidgetLoaded) return;
|
|
4
|
-
window.__copilotWidgetLoaded = true;
|
|
5
|
-
|
|
6
|
-
const BUILD_BASE_URL =
|
|
7
|
-
typeof __WIDGET_BASE_URL__ !== "undefined" && __WIDGET_BASE_URL__
|
|
8
|
-
? __WIDGET_BASE_URL__
|
|
9
|
-
: undefined;
|
|
10
|
-
const BUTTON_SIZE = 64;
|
|
11
|
-
const IFRAME_SIZE = 720;
|
|
12
|
-
const embeddingScript = document.currentScript;
|
|
2
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
3
|
+
if (window.__copilotWidgetLoaded) return;
|
|
4
|
+
window.__copilotWidgetLoaded = true;
|
|
5
|
+
|
|
6
|
+
const BUILD_BASE_URL =
|
|
7
|
+
typeof __WIDGET_BASE_URL__ !== "undefined" && __WIDGET_BASE_URL__
|
|
8
|
+
? __WIDGET_BASE_URL__
|
|
9
|
+
: undefined;
|
|
10
|
+
const BUTTON_SIZE = 64;
|
|
11
|
+
const IFRAME_SIZE = 720;
|
|
12
|
+
const embeddingScript = document.currentScript;
|
|
13
13
|
|
|
14
14
|
const readQueryConfig = (scriptEl) => {
|
|
15
15
|
if (!scriptEl?.src) return {};
|
|
@@ -221,26 +221,42 @@
|
|
|
221
221
|
btn.style.transform = "scale(1)";
|
|
222
222
|
};
|
|
223
223
|
|
|
224
|
-
|
|
225
|
-
event
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
224
|
+
const handleWidgetMessage = (event) => {
|
|
225
|
+
const { data, source } = event || {};
|
|
226
|
+
if (!data?.type) return;
|
|
227
|
+
|
|
228
|
+
if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
|
|
229
|
+
console.log("[CopilotChat] Received checkout payload from widget:", data);
|
|
230
|
+
showCheckoutToast("Checkout message received from chat widget. Check console for payload.");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (data.type === "WIDGET_READY" && source === iframe.contentWindow) {
|
|
235
|
+
iframe.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (data.type === "CHAT_CLOSED") {
|
|
240
|
+
closeChat();
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
btn.onclick = (event) => {
|
|
245
|
+
event.stopPropagation();
|
|
246
|
+
isOpen = !isOpen;
|
|
247
|
+
if (isOpen) {
|
|
248
|
+
container.style.display = "block";
|
|
249
|
+
arrow.style.display = "block";
|
|
250
|
+
requestAnimationFrame(() => {
|
|
251
|
+
container.style.opacity = "1";
|
|
252
|
+
container.style.transform = "scale(1) translateY(0)";
|
|
253
|
+
});
|
|
254
|
+
} else {
|
|
255
|
+
closeChat();
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
window.addEventListener("message", handleWidgetMessage);
|
|
244
260
|
|
|
245
261
|
document.addEventListener("click", (event) => {
|
|
246
262
|
const target = event.target;
|
|
@@ -287,22 +303,48 @@
|
|
|
287
303
|
const datasetConfig = scriptEl?.dataset || {};
|
|
288
304
|
const queryConfig = readQueryConfig(scriptEl);
|
|
289
305
|
|
|
290
|
-
const
|
|
306
|
+
const resolveToken = () => {
|
|
307
|
+
const fromConfig = config.token || globalConfig.token || datasetConfig.token || queryConfig.token;
|
|
308
|
+
if (fromConfig) return fromConfig;
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
const stored = window.localStorage.getItem("copilotChatToken");
|
|
312
|
+
if (stored) return stored;
|
|
313
|
+
} catch (error) {
|
|
314
|
+
// ignore storage errors
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (typeof window !== "undefined" && typeof window.prompt === "function") {
|
|
318
|
+
const entered = window.prompt("Enter your Copilot Chat token:");
|
|
319
|
+
if (entered) {
|
|
320
|
+
try {
|
|
321
|
+
window.localStorage.setItem("copilotChatToken", entered);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
// ignore storage errors
|
|
324
|
+
}
|
|
325
|
+
return entered;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return null;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const token = resolveToken();
|
|
291
333
|
|
|
292
334
|
if (!token) {
|
|
293
335
|
handleError("Missing token (provide via init config, window.CopilotChatConfig.token, or data-token attribute).");
|
|
294
336
|
return null;
|
|
295
337
|
}
|
|
296
338
|
|
|
297
|
-
const baseUrl =
|
|
298
|
-
config.baseUrl ||
|
|
299
|
-
globalConfig.baseUrl ||
|
|
300
|
-
datasetConfig.baseUrl ||
|
|
301
|
-
queryConfig.baseUrl ||
|
|
302
|
-
BUILD_BASE_URL ||
|
|
303
|
-
inferBaseUrlFromScript(scriptEl) ||
|
|
304
|
-
(typeof window !== "undefined" && window.location?.origin) ||
|
|
305
|
-
null;
|
|
339
|
+
const baseUrl =
|
|
340
|
+
config.baseUrl ||
|
|
341
|
+
globalConfig.baseUrl ||
|
|
342
|
+
datasetConfig.baseUrl ||
|
|
343
|
+
queryConfig.baseUrl ||
|
|
344
|
+
BUILD_BASE_URL ||
|
|
345
|
+
inferBaseUrlFromScript(scriptEl) ||
|
|
346
|
+
(typeof window !== "undefined" && window.location?.origin) ||
|
|
347
|
+
null;
|
|
306
348
|
|
|
307
349
|
if (!baseUrl) {
|
|
308
350
|
handleError("Unable to resolve base URL from embedding script or window.location.");
|