@super_studio/ecforce-ai-agent-react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/agent-frame.d.ts +32 -0
- package/dist/agent-frame.d.ts.map +1 -0
- package/dist/chatbot-popover.d.ts +3 -0
- package/dist/chatbot-popover.d.ts.map +1 -0
- package/dist/chatbot.css +166 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +252 -0
- package/dist/index.mjs +252 -0
- package/dist/popover.d.ts +9 -0
- package/dist/popover.d.ts.map +1 -0
- package/package.json +44 -0
- package/src/agent-frame.tsx +180 -0
- package/src/chatbot-popover.tsx +54 -0
- package/src/chatbot.css +166 -0
- package/src/constants.ts +1 -0
- package/src/index.ts +3 -0
- package/src/popover.tsx +54 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
TODO
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
type MCP = {
|
|
2
|
+
name: string;
|
|
3
|
+
url: string;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
export type InitProps = {
|
|
7
|
+
mcps?: MCP[];
|
|
8
|
+
};
|
|
9
|
+
export type AgentFrameProps = {
|
|
10
|
+
agentId: string;
|
|
11
|
+
mcps?: MCP[];
|
|
12
|
+
appName?: string;
|
|
13
|
+
url?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
export type AgentElement = {
|
|
17
|
+
/**
|
|
18
|
+
* Push a new list of MCPs to the embedded agent.
|
|
19
|
+
*/
|
|
20
|
+
setMcps: (mcps: MCP[]) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Set the app name for the embedded agent.
|
|
23
|
+
*/
|
|
24
|
+
setAppName: (appName: string) => void;
|
|
25
|
+
/**
|
|
26
|
+
* `true` once the iframe has sent the `CHATBOT_READY` handshake message.
|
|
27
|
+
*/
|
|
28
|
+
isReady: boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare const AgentFrame: import("react").ForwardRefExoticComponent<AgentFrameProps & import("react").RefAttributes<AgentElement>>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=agent-frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-frame.d.ts","sourceRoot":"","sources":["../src/agent-frame.tsx"],"names":[],"mappings":"AAcA,KAAK,GAAG,GAAG;IACT,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;CACd,CAAC;AAiBF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC/B;;OAEG;IACH,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,UAAU,0GAmHtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatbot-popover.d.ts","sourceRoot":"","sources":["../src/chatbot-popover.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAGvB,eAAO,MAAM,cAAc,0GA2B1B,CAAC"}
|
package/dist/chatbot.css
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/* Chatbot Trigger Button */
|
|
2
|
+
.chatbot-trigger {
|
|
3
|
+
position: fixed;
|
|
4
|
+
bottom: 1rem;
|
|
5
|
+
right: 1rem;
|
|
6
|
+
z-index: 50;
|
|
7
|
+
border-radius: 9999px;
|
|
8
|
+
border: 1px solid #f0f2f7;
|
|
9
|
+
background-color: #ffffff;
|
|
10
|
+
padding: 0.375rem;
|
|
11
|
+
color: #0061ff;
|
|
12
|
+
box-shadow:
|
|
13
|
+
0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
|
14
|
+
0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
|
15
|
+
transition: colors 200ms ease-in-out;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.chatbot-trigger:hover {
|
|
20
|
+
background-color: #f0f2f7;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Popover Backdrop */
|
|
24
|
+
.chatbot-popover-backdrop {
|
|
25
|
+
position: fixed;
|
|
26
|
+
top: 0;
|
|
27
|
+
right: 0;
|
|
28
|
+
bottom: 0;
|
|
29
|
+
left: 0;
|
|
30
|
+
z-index: 30;
|
|
31
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
32
|
+
animation: fade-in 150ms ease-out;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Popover Content */
|
|
36
|
+
.chatbot-popover-content {
|
|
37
|
+
z-index: 50;
|
|
38
|
+
border-radius: 2rem;
|
|
39
|
+
background-color: #f7f9fa;
|
|
40
|
+
box-shadow:
|
|
41
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
42
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
43
|
+
outline: none;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
height: 80vh;
|
|
46
|
+
width: 600px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Animation states */
|
|
50
|
+
.chatbot-popover-content[data-state="closed"] {
|
|
51
|
+
display: none;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.chatbot-popover-content[data-state="open"] {
|
|
55
|
+
animation:
|
|
56
|
+
zoom-in 150ms ease-out,
|
|
57
|
+
fade-in 150ms ease-out;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.chatbot-popover-content[data-state="closed"] {
|
|
61
|
+
animation:
|
|
62
|
+
zoom-out 150ms ease-in,
|
|
63
|
+
fade-out 150ms ease-in;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Side-specific slide animations */
|
|
67
|
+
.chatbot-popover-content[data-side="bottom"] {
|
|
68
|
+
animation:
|
|
69
|
+
zoom-in 150ms ease-out,
|
|
70
|
+
fade-in 150ms ease-out,
|
|
71
|
+
slide-in-from-top 150ms ease-out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.chatbot-popover-content[data-side="top"] {
|
|
75
|
+
animation:
|
|
76
|
+
zoom-in 150ms ease-out,
|
|
77
|
+
fade-in 150ms ease-out,
|
|
78
|
+
slide-in-from-bottom 150ms ease-out;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.chatbot-popover-content[data-side="left"] {
|
|
82
|
+
animation:
|
|
83
|
+
zoom-in 150ms ease-out,
|
|
84
|
+
fade-in 150ms ease-out,
|
|
85
|
+
slide-in-from-right 150ms ease-out;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.chatbot-popover-content[data-side="right"] {
|
|
89
|
+
animation:
|
|
90
|
+
zoom-in 150ms ease-out,
|
|
91
|
+
fade-in 150ms ease-out,
|
|
92
|
+
slide-in-from-left 150ms ease-out;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Keyframe Animations */
|
|
96
|
+
@keyframes fade-in {
|
|
97
|
+
from {
|
|
98
|
+
opacity: 0;
|
|
99
|
+
}
|
|
100
|
+
to {
|
|
101
|
+
opacity: 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@keyframes fade-out {
|
|
106
|
+
from {
|
|
107
|
+
opacity: 1;
|
|
108
|
+
}
|
|
109
|
+
to {
|
|
110
|
+
opacity: 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@keyframes zoom-in {
|
|
115
|
+
from {
|
|
116
|
+
transform: scale(0.95);
|
|
117
|
+
}
|
|
118
|
+
to {
|
|
119
|
+
transform: scale(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@keyframes zoom-out {
|
|
124
|
+
from {
|
|
125
|
+
transform: scale(1);
|
|
126
|
+
}
|
|
127
|
+
to {
|
|
128
|
+
transform: scale(0.95);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes slide-in-from-top {
|
|
133
|
+
from {
|
|
134
|
+
transform: translateY(-0.5rem);
|
|
135
|
+
}
|
|
136
|
+
to {
|
|
137
|
+
transform: translateY(0);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@keyframes slide-in-from-bottom {
|
|
142
|
+
from {
|
|
143
|
+
transform: translateY(0.5rem);
|
|
144
|
+
}
|
|
145
|
+
to {
|
|
146
|
+
transform: translateY(0);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@keyframes slide-in-from-left {
|
|
151
|
+
from {
|
|
152
|
+
transform: translateX(-0.5rem);
|
|
153
|
+
}
|
|
154
|
+
to {
|
|
155
|
+
transform: translateX(0);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@keyframes slide-in-from-right {
|
|
160
|
+
from {
|
|
161
|
+
transform: translateX(0.5rem);
|
|
162
|
+
}
|
|
163
|
+
to {
|
|
164
|
+
transform: translateX(0);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,wCAAwC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }"use client";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
|
+
var __objRest = (source, exclude) => {
|
|
22
|
+
var target = {};
|
|
23
|
+
for (var prop in source)
|
|
24
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
25
|
+
target[prop] = source[prop];
|
|
26
|
+
if (source != null && __getOwnPropSymbols)
|
|
27
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
28
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
}
|
|
31
|
+
return target;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/agent-frame.tsx
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
var _react = require('react'); var React = _interopRequireWildcard(_react);
|
|
43
|
+
|
|
44
|
+
// src/constants.ts
|
|
45
|
+
var PROD_CHATBOT_URL = "https://ecforce-ai-agent.vercel.app";
|
|
46
|
+
|
|
47
|
+
// src/agent-frame.tsx
|
|
48
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
49
|
+
var AgentFrame = _react.forwardRef.call(void 0,
|
|
50
|
+
({ agentId, mcps = [], appName, className, url }, ref) => {
|
|
51
|
+
var _a;
|
|
52
|
+
const chatbotUrl = (_a = url != null ? url : process.env.CHATBOT_URL) != null ? _a : PROD_CHATBOT_URL;
|
|
53
|
+
const iframeRef = _react.useRef.call(void 0, null);
|
|
54
|
+
const [isReady, setIsReady] = _react.useState.call(void 0, false);
|
|
55
|
+
const [hasInitialized, setHasInitialized] = _react.useState.call(void 0, false);
|
|
56
|
+
const [currentMcps, setCurrentMcps] = _react.useState.call(void 0, mcps);
|
|
57
|
+
const postMessage = _react.useCallback.call(void 0, (message) => {
|
|
58
|
+
var _a2;
|
|
59
|
+
if ((_a2 = iframeRef.current) == null ? void 0 : _a2.contentWindow) {
|
|
60
|
+
iframeRef.current.contentWindow.postMessage(message, "*");
|
|
61
|
+
}
|
|
62
|
+
}, []);
|
|
63
|
+
const init = _react.useCallback.call(void 0,
|
|
64
|
+
(props) => {
|
|
65
|
+
postMessage(__spreadValues({
|
|
66
|
+
type: "init"
|
|
67
|
+
}, props));
|
|
68
|
+
},
|
|
69
|
+
[postMessage]
|
|
70
|
+
);
|
|
71
|
+
const setMcps = _react.useCallback.call(void 0,
|
|
72
|
+
(mcps2) => {
|
|
73
|
+
postMessage({ type: "mcps", mcps: mcps2 });
|
|
74
|
+
},
|
|
75
|
+
[postMessage]
|
|
76
|
+
);
|
|
77
|
+
const setAppName = _react.useCallback.call(void 0,
|
|
78
|
+
(appName2) => {
|
|
79
|
+
postMessage({ type: "appName", appName: appName2 });
|
|
80
|
+
},
|
|
81
|
+
[postMessage]
|
|
82
|
+
);
|
|
83
|
+
_react.useImperativeHandle.call(void 0,
|
|
84
|
+
ref,
|
|
85
|
+
() => ({
|
|
86
|
+
setMcps,
|
|
87
|
+
setAppName,
|
|
88
|
+
get isReady() {
|
|
89
|
+
return isReady;
|
|
90
|
+
}
|
|
91
|
+
}),
|
|
92
|
+
[setMcps, setAppName, isReady]
|
|
93
|
+
);
|
|
94
|
+
_react.useEffect.call(void 0, () => {
|
|
95
|
+
const iframe = iframeRef.current;
|
|
96
|
+
if (!iframe) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const handleMessage = (event) => {
|
|
100
|
+
var _a2;
|
|
101
|
+
if (process.env.NODE_ENV === "development") {
|
|
102
|
+
console.log("iframe message", event.data);
|
|
103
|
+
}
|
|
104
|
+
if (((_a2 = event.data) == null ? void 0 : _a2.type) === "CHATBOT_READY") {
|
|
105
|
+
setIsReady(true);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const handleIframeLoad = () => {
|
|
109
|
+
window.addEventListener("message", handleMessage);
|
|
110
|
+
};
|
|
111
|
+
iframe.addEventListener("load", handleIframeLoad);
|
|
112
|
+
return () => {
|
|
113
|
+
window.removeEventListener("message", handleMessage);
|
|
114
|
+
iframe.removeEventListener("load", handleIframeLoad);
|
|
115
|
+
};
|
|
116
|
+
}, []);
|
|
117
|
+
_react.useEffect.call(void 0, () => {
|
|
118
|
+
if (isReady && !hasInitialized) {
|
|
119
|
+
setHasInitialized(true);
|
|
120
|
+
init({ mcps });
|
|
121
|
+
if (appName) {
|
|
122
|
+
setAppName(appName);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}, [isReady, init, mcps, appName, hasInitialized, setAppName]);
|
|
126
|
+
_react.useEffect.call(void 0, () => {
|
|
127
|
+
if (JSON.stringify(currentMcps) !== JSON.stringify(mcps)) {
|
|
128
|
+
setCurrentMcps(mcps);
|
|
129
|
+
setMcps(mcps);
|
|
130
|
+
}
|
|
131
|
+
}, [setMcps, mcps, currentMcps]);
|
|
132
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
133
|
+
"iframe",
|
|
134
|
+
{
|
|
135
|
+
ref: iframeRef,
|
|
136
|
+
src: `${chatbotUrl}/embed/${agentId}`,
|
|
137
|
+
className,
|
|
138
|
+
allow: "clipboard-write",
|
|
139
|
+
style: {
|
|
140
|
+
width: "100%",
|
|
141
|
+
height: "100%"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
AgentFrame.displayName = "AgentFrame";
|
|
148
|
+
|
|
149
|
+
// src/chatbot-popover.tsx
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
// src/popover.tsx
|
|
153
|
+
var _reactpopover = require('@radix-ui/react-popover'); var PopoverPrimitive = _interopRequireWildcard(_reactpopover);
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
var Popover = PopoverPrimitive.Root;
|
|
157
|
+
var PopoverTrigger = React.forwardRef((_a, ref) => {
|
|
158
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
159
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
160
|
+
PopoverPrimitive.Trigger,
|
|
161
|
+
__spreadValues({
|
|
162
|
+
ref,
|
|
163
|
+
className: `chatbot-trigger ${className}`
|
|
164
|
+
}, props)
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
PopoverTrigger.displayName = PopoverPrimitive.Trigger.displayName;
|
|
168
|
+
var PopoverContent = React.forwardRef(
|
|
169
|
+
(_a, ref) => {
|
|
170
|
+
var _b = _a, {
|
|
171
|
+
className,
|
|
172
|
+
align = "center",
|
|
173
|
+
backdrop,
|
|
174
|
+
sideOffset = 4,
|
|
175
|
+
forceMount
|
|
176
|
+
} = _b, props = __objRest(_b, [
|
|
177
|
+
"className",
|
|
178
|
+
"align",
|
|
179
|
+
"backdrop",
|
|
180
|
+
"sideOffset",
|
|
181
|
+
"forceMount"
|
|
182
|
+
]);
|
|
183
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverPrimitive.Portal, { forceMount, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
184
|
+
backdrop && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "chatbot-popover-backdrop" }),
|
|
185
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
186
|
+
PopoverPrimitive.Content,
|
|
187
|
+
__spreadValues({
|
|
188
|
+
ref,
|
|
189
|
+
align,
|
|
190
|
+
sideOffset,
|
|
191
|
+
forceMount,
|
|
192
|
+
className: `chatbot-popover-content ${className}`
|
|
193
|
+
}, props)
|
|
194
|
+
)
|
|
195
|
+
] }) });
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
199
|
+
|
|
200
|
+
// src/chatbot-popover.tsx
|
|
201
|
+
|
|
202
|
+
var ChatbotPopover = _react.forwardRef.call(void 0,
|
|
203
|
+
(props, ref) => {
|
|
204
|
+
const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
|
|
205
|
+
const [hasOpened, setHasOpened] = _react.useState.call(void 0, false);
|
|
206
|
+
const handleOpenChange = (open) => {
|
|
207
|
+
setIsOpen(open);
|
|
208
|
+
if (open && !hasOpened) {
|
|
209
|
+
setHasOpened(true);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Popover, { open: isOpen, onOpenChange: handleOpenChange, children: [
|
|
213
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, PopoverTrigger, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EcforceAiIcon, {}) }),
|
|
214
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
215
|
+
PopoverContent,
|
|
216
|
+
{
|
|
217
|
+
align: "end",
|
|
218
|
+
backdrop: isOpen,
|
|
219
|
+
forceMount: hasOpened || void 0,
|
|
220
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AgentFrame, __spreadProps(__spreadValues({}, props), { ref }))
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
] });
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
function EcforceAiIcon() {
|
|
227
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
228
|
+
"svg",
|
|
229
|
+
{
|
|
230
|
+
width: "24",
|
|
231
|
+
height: "24",
|
|
232
|
+
viewBox: "0 0 24 24",
|
|
233
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
234
|
+
fill: "currentColor",
|
|
235
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
236
|
+
"path",
|
|
237
|
+
{
|
|
238
|
+
fillRule: "evenodd",
|
|
239
|
+
clipRule: "evenodd",
|
|
240
|
+
d: "M9.2 13.704s3.7-.812 4.325-3.74c.624-2.93.76-3.364 1.112-3.364.352 0 .42.309.5.618.08.309.51 2.276.613 2.745.102.47.783 2.93 3.712 3.616 2.93.686 3.338.697 3.338 1.12 0 .459-2.361.859-3.338 1.122-.976.263-3.042 1.007-3.587 3.49-.534 2.482-.681 3.489-1.238 3.489-.556 0-.545-.584-.613-.87-.068-.286-.34-1.819-.5-2.494-.147-.675-1.044-2.837-2.962-3.363-1.93-.527-3.962-.847-3.962-1.373s2.134-.824 2.6-.995ZM2.462 4.613s1.785-.39 2.08-1.798c.296-1.409.365-1.615.535-1.615.17 0 .205.149.239.298s.25 1.088.296 1.317c.045.229.375 1.409 1.785 1.74 1.41.333 1.603.333 1.603.54 0 .217-1.137.412-1.603.538-.466.126-1.467.48-1.729 1.683C5.407 8.507 5.338 9 5.078 9c-.262 0-.262-.286-.296-.424-.035-.137-.16-.882-.24-1.202-.079-.321-.5-1.363-1.432-1.615-.932-.252-1.91-.413-1.91-.665 0-.252 1.023-.4 1.25-.48h.012Z"
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
exports.AgentFrame = AgentFrame; exports.ChatbotPopover = ChatbotPopover; exports.Popover = Popover; exports.PopoverContent = PopoverContent; exports.PopoverTrigger = PopoverTrigger;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
|
+
var __objRest = (source, exclude) => {
|
|
22
|
+
var target = {};
|
|
23
|
+
for (var prop in source)
|
|
24
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
25
|
+
target[prop] = source[prop];
|
|
26
|
+
if (source != null && __getOwnPropSymbols)
|
|
27
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
28
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
}
|
|
31
|
+
return target;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/agent-frame.tsx
|
|
35
|
+
import {
|
|
36
|
+
forwardRef,
|
|
37
|
+
useCallback,
|
|
38
|
+
useEffect,
|
|
39
|
+
useImperativeHandle,
|
|
40
|
+
useRef,
|
|
41
|
+
useState
|
|
42
|
+
} from "react";
|
|
43
|
+
|
|
44
|
+
// src/constants.ts
|
|
45
|
+
var PROD_CHATBOT_URL = "https://ecforce-ai-agent.vercel.app";
|
|
46
|
+
|
|
47
|
+
// src/agent-frame.tsx
|
|
48
|
+
import { jsx } from "react/jsx-runtime";
|
|
49
|
+
var AgentFrame = forwardRef(
|
|
50
|
+
({ agentId, mcps = [], appName, className, url }, ref) => {
|
|
51
|
+
var _a;
|
|
52
|
+
const chatbotUrl = (_a = url != null ? url : process.env.CHATBOT_URL) != null ? _a : PROD_CHATBOT_URL;
|
|
53
|
+
const iframeRef = useRef(null);
|
|
54
|
+
const [isReady, setIsReady] = useState(false);
|
|
55
|
+
const [hasInitialized, setHasInitialized] = useState(false);
|
|
56
|
+
const [currentMcps, setCurrentMcps] = useState(mcps);
|
|
57
|
+
const postMessage = useCallback((message) => {
|
|
58
|
+
var _a2;
|
|
59
|
+
if ((_a2 = iframeRef.current) == null ? void 0 : _a2.contentWindow) {
|
|
60
|
+
iframeRef.current.contentWindow.postMessage(message, "*");
|
|
61
|
+
}
|
|
62
|
+
}, []);
|
|
63
|
+
const init = useCallback(
|
|
64
|
+
(props) => {
|
|
65
|
+
postMessage(__spreadValues({
|
|
66
|
+
type: "init"
|
|
67
|
+
}, props));
|
|
68
|
+
},
|
|
69
|
+
[postMessage]
|
|
70
|
+
);
|
|
71
|
+
const setMcps = useCallback(
|
|
72
|
+
(mcps2) => {
|
|
73
|
+
postMessage({ type: "mcps", mcps: mcps2 });
|
|
74
|
+
},
|
|
75
|
+
[postMessage]
|
|
76
|
+
);
|
|
77
|
+
const setAppName = useCallback(
|
|
78
|
+
(appName2) => {
|
|
79
|
+
postMessage({ type: "appName", appName: appName2 });
|
|
80
|
+
},
|
|
81
|
+
[postMessage]
|
|
82
|
+
);
|
|
83
|
+
useImperativeHandle(
|
|
84
|
+
ref,
|
|
85
|
+
() => ({
|
|
86
|
+
setMcps,
|
|
87
|
+
setAppName,
|
|
88
|
+
get isReady() {
|
|
89
|
+
return isReady;
|
|
90
|
+
}
|
|
91
|
+
}),
|
|
92
|
+
[setMcps, setAppName, isReady]
|
|
93
|
+
);
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
const iframe = iframeRef.current;
|
|
96
|
+
if (!iframe) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const handleMessage = (event) => {
|
|
100
|
+
var _a2;
|
|
101
|
+
if (process.env.NODE_ENV === "development") {
|
|
102
|
+
console.log("iframe message", event.data);
|
|
103
|
+
}
|
|
104
|
+
if (((_a2 = event.data) == null ? void 0 : _a2.type) === "CHATBOT_READY") {
|
|
105
|
+
setIsReady(true);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const handleIframeLoad = () => {
|
|
109
|
+
window.addEventListener("message", handleMessage);
|
|
110
|
+
};
|
|
111
|
+
iframe.addEventListener("load", handleIframeLoad);
|
|
112
|
+
return () => {
|
|
113
|
+
window.removeEventListener("message", handleMessage);
|
|
114
|
+
iframe.removeEventListener("load", handleIframeLoad);
|
|
115
|
+
};
|
|
116
|
+
}, []);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (isReady && !hasInitialized) {
|
|
119
|
+
setHasInitialized(true);
|
|
120
|
+
init({ mcps });
|
|
121
|
+
if (appName) {
|
|
122
|
+
setAppName(appName);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}, [isReady, init, mcps, appName, hasInitialized, setAppName]);
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (JSON.stringify(currentMcps) !== JSON.stringify(mcps)) {
|
|
128
|
+
setCurrentMcps(mcps);
|
|
129
|
+
setMcps(mcps);
|
|
130
|
+
}
|
|
131
|
+
}, [setMcps, mcps, currentMcps]);
|
|
132
|
+
return /* @__PURE__ */ jsx(
|
|
133
|
+
"iframe",
|
|
134
|
+
{
|
|
135
|
+
ref: iframeRef,
|
|
136
|
+
src: `${chatbotUrl}/embed/${agentId}`,
|
|
137
|
+
className,
|
|
138
|
+
allow: "clipboard-write",
|
|
139
|
+
style: {
|
|
140
|
+
width: "100%",
|
|
141
|
+
height: "100%"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
AgentFrame.displayName = "AgentFrame";
|
|
148
|
+
|
|
149
|
+
// src/chatbot-popover.tsx
|
|
150
|
+
import { forwardRef as forwardRef3, useState as useState2 } from "react";
|
|
151
|
+
|
|
152
|
+
// src/popover.tsx
|
|
153
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
154
|
+
import * as React from "react";
|
|
155
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
156
|
+
var Popover = PopoverPrimitive.Root;
|
|
157
|
+
var PopoverTrigger = React.forwardRef((_a, ref) => {
|
|
158
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
159
|
+
return /* @__PURE__ */ jsx2(
|
|
160
|
+
PopoverPrimitive.Trigger,
|
|
161
|
+
__spreadValues({
|
|
162
|
+
ref,
|
|
163
|
+
className: `chatbot-trigger ${className}`
|
|
164
|
+
}, props)
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
PopoverTrigger.displayName = PopoverPrimitive.Trigger.displayName;
|
|
168
|
+
var PopoverContent = React.forwardRef(
|
|
169
|
+
(_a, ref) => {
|
|
170
|
+
var _b = _a, {
|
|
171
|
+
className,
|
|
172
|
+
align = "center",
|
|
173
|
+
backdrop,
|
|
174
|
+
sideOffset = 4,
|
|
175
|
+
forceMount
|
|
176
|
+
} = _b, props = __objRest(_b, [
|
|
177
|
+
"className",
|
|
178
|
+
"align",
|
|
179
|
+
"backdrop",
|
|
180
|
+
"sideOffset",
|
|
181
|
+
"forceMount"
|
|
182
|
+
]);
|
|
183
|
+
return /* @__PURE__ */ jsx2(PopoverPrimitive.Portal, { forceMount, children: /* @__PURE__ */ jsxs("div", { children: [
|
|
184
|
+
backdrop && /* @__PURE__ */ jsx2("div", { className: "chatbot-popover-backdrop" }),
|
|
185
|
+
/* @__PURE__ */ jsx2(
|
|
186
|
+
PopoverPrimitive.Content,
|
|
187
|
+
__spreadValues({
|
|
188
|
+
ref,
|
|
189
|
+
align,
|
|
190
|
+
sideOffset,
|
|
191
|
+
forceMount,
|
|
192
|
+
className: `chatbot-popover-content ${className}`
|
|
193
|
+
}, props)
|
|
194
|
+
)
|
|
195
|
+
] }) });
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
199
|
+
|
|
200
|
+
// src/chatbot-popover.tsx
|
|
201
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
202
|
+
var ChatbotPopover = forwardRef3(
|
|
203
|
+
(props, ref) => {
|
|
204
|
+
const [isOpen, setIsOpen] = useState2(false);
|
|
205
|
+
const [hasOpened, setHasOpened] = useState2(false);
|
|
206
|
+
const handleOpenChange = (open) => {
|
|
207
|
+
setIsOpen(open);
|
|
208
|
+
if (open && !hasOpened) {
|
|
209
|
+
setHasOpened(true);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
return /* @__PURE__ */ jsxs2(Popover, { open: isOpen, onOpenChange: handleOpenChange, children: [
|
|
213
|
+
/* @__PURE__ */ jsx3(PopoverTrigger, { children: /* @__PURE__ */ jsx3(EcforceAiIcon, {}) }),
|
|
214
|
+
/* @__PURE__ */ jsx3(
|
|
215
|
+
PopoverContent,
|
|
216
|
+
{
|
|
217
|
+
align: "end",
|
|
218
|
+
backdrop: isOpen,
|
|
219
|
+
forceMount: hasOpened || void 0,
|
|
220
|
+
children: /* @__PURE__ */ jsx3(AgentFrame, __spreadProps(__spreadValues({}, props), { ref }))
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
] });
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
function EcforceAiIcon() {
|
|
227
|
+
return /* @__PURE__ */ jsx3(
|
|
228
|
+
"svg",
|
|
229
|
+
{
|
|
230
|
+
width: "24",
|
|
231
|
+
height: "24",
|
|
232
|
+
viewBox: "0 0 24 24",
|
|
233
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
234
|
+
fill: "currentColor",
|
|
235
|
+
children: /* @__PURE__ */ jsx3(
|
|
236
|
+
"path",
|
|
237
|
+
{
|
|
238
|
+
fillRule: "evenodd",
|
|
239
|
+
clipRule: "evenodd",
|
|
240
|
+
d: "M9.2 13.704s3.7-.812 4.325-3.74c.624-2.93.76-3.364 1.112-3.364.352 0 .42.309.5.618.08.309.51 2.276.613 2.745.102.47.783 2.93 3.712 3.616 2.93.686 3.338.697 3.338 1.12 0 .459-2.361.859-3.338 1.122-.976.263-3.042 1.007-3.587 3.49-.534 2.482-.681 3.489-1.238 3.489-.556 0-.545-.584-.613-.87-.068-.286-.34-1.819-.5-2.494-.147-.675-1.044-2.837-2.962-3.363-1.93-.527-3.962-.847-3.962-1.373s2.134-.824 2.6-.995ZM2.462 4.613s1.785-.39 2.08-1.798c.296-1.409.365-1.615.535-1.615.17 0 .205.149.239.298s.25 1.088.296 1.317c.045.229.375 1.409 1.785 1.74 1.41.333 1.603.333 1.603.54 0 .217-1.137.412-1.603.538-.466.126-1.467.48-1.729 1.683C5.407 8.507 5.338 9 5.078 9c-.262 0-.262-.286-.296-.424-.035-.137-.16-.882-.24-1.202-.079-.321-.5-1.363-1.432-1.615-.932-.252-1.91-.413-1.91-.665 0-.252 1.023-.4 1.25-.48h.012Z"
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
export {
|
|
247
|
+
AgentFrame,
|
|
248
|
+
ChatbotPopover,
|
|
249
|
+
Popover,
|
|
250
|
+
PopoverContent,
|
|
251
|
+
PopoverTrigger
|
|
252
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const Popover: React.FC<PopoverPrimitive.PopoverProps>;
|
|
4
|
+
declare const PopoverTrigger: React.ForwardRefExoticComponent<Omit<PopoverPrimitive.PopoverTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
5
|
+
declare const PopoverContent: React.ForwardRefExoticComponent<Omit<PopoverPrimitive.PopoverContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
6
|
+
backdrop?: boolean;
|
|
7
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
+
export { Popover, PopoverTrigger, PopoverContent };
|
|
9
|
+
//# sourceMappingURL=popover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../src/popover.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,QAAA,MAAM,OAAO,yCAAwB,CAAC;AAEtC,QAAA,MAAM,cAAc,sKASlB,CAAC;AAGH,QAAA,MAAM,cAAc;eAGL,OAAO;wCA4BrB,CAAC;AAGF,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@super_studio/ecforce-ai-agent-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"module": "dist/index.mjs",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src/**/*.ts",
|
|
11
|
+
"src/**/*.tsx",
|
|
12
|
+
"src/**/*.css"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./dist/index.mjs",
|
|
17
|
+
"require": "./dist/index.js",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./chatbot.css": "./dist/chatbot.css"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": ">=16",
|
|
24
|
+
"react-dom": ">=16"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^20",
|
|
28
|
+
"@types/react": "^19",
|
|
29
|
+
"@types/react-dom": "^19",
|
|
30
|
+
"npm-run-all": "4.1.5",
|
|
31
|
+
"react": "19.1.0",
|
|
32
|
+
"react-dom": "19.1.0",
|
|
33
|
+
"tsup": "8.5.0"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@radix-ui/react-popover": "1.1.14"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"dev": "npm-run-all --parallel dev:main dev:types",
|
|
40
|
+
"dev:main": "tsup --watch",
|
|
41
|
+
"dev:types": "tsc -p tsconfig.build.json --watch",
|
|
42
|
+
"build": "tsup && tsc -p tsconfig.build.json"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { PROD_CHATBOT_URL } from "./constants";
|
|
10
|
+
|
|
11
|
+
type IframeMessage = {
|
|
12
|
+
type: "CHATBOT_READY";
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type MCP = {
|
|
16
|
+
name: string;
|
|
17
|
+
url: string;
|
|
18
|
+
headers?: Record<string, string>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type InitProps = {
|
|
22
|
+
mcps?: MCP[];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type ParentMessage =
|
|
26
|
+
| {
|
|
27
|
+
type: "mcps";
|
|
28
|
+
mcps: MCP[];
|
|
29
|
+
}
|
|
30
|
+
| {
|
|
31
|
+
type: "appName";
|
|
32
|
+
appName: string;
|
|
33
|
+
}
|
|
34
|
+
| {
|
|
35
|
+
type: "init";
|
|
36
|
+
mcps?: MCP[];
|
|
37
|
+
appName?: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type AgentFrameProps = {
|
|
41
|
+
agentId: string;
|
|
42
|
+
mcps?: MCP[];
|
|
43
|
+
appName?: string;
|
|
44
|
+
url?: string;
|
|
45
|
+
className?: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type AgentElement = {
|
|
49
|
+
/**
|
|
50
|
+
* Push a new list of MCPs to the embedded agent.
|
|
51
|
+
*/
|
|
52
|
+
setMcps: (mcps: MCP[]) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Set the app name for the embedded agent.
|
|
55
|
+
*/
|
|
56
|
+
setAppName: (appName: string) => void;
|
|
57
|
+
/**
|
|
58
|
+
* `true` once the iframe has sent the `CHATBOT_READY` handshake message.
|
|
59
|
+
*/
|
|
60
|
+
isReady: boolean;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const AgentFrame = forwardRef<AgentElement, AgentFrameProps>(
|
|
64
|
+
({ agentId, mcps = [], appName, className, url }, ref) => {
|
|
65
|
+
const chatbotUrl = url ?? process.env.CHATBOT_URL ?? PROD_CHATBOT_URL;
|
|
66
|
+
|
|
67
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
68
|
+
const [isReady, setIsReady] = useState(false);
|
|
69
|
+
const [hasInitialized, setHasInitialized] = useState(false);
|
|
70
|
+
const [currentMcps, setCurrentMcps] = useState<MCP[]>(mcps);
|
|
71
|
+
|
|
72
|
+
// helper to post message to the iframe
|
|
73
|
+
const postMessage = useCallback((message: ParentMessage) => {
|
|
74
|
+
if (iframeRef.current?.contentWindow) {
|
|
75
|
+
iframeRef.current.contentWindow.postMessage(message, "*");
|
|
76
|
+
}
|
|
77
|
+
}, []);
|
|
78
|
+
|
|
79
|
+
const init = useCallback(
|
|
80
|
+
(props: InitProps) => {
|
|
81
|
+
postMessage({
|
|
82
|
+
type: "init",
|
|
83
|
+
...props,
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
[postMessage],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const setMcps = useCallback(
|
|
90
|
+
(mcps: MCP[]) => {
|
|
91
|
+
postMessage({ type: "mcps", mcps });
|
|
92
|
+
},
|
|
93
|
+
[postMessage],
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const setAppName = useCallback(
|
|
97
|
+
(appName: string) => {
|
|
98
|
+
postMessage({ type: "appName", appName });
|
|
99
|
+
},
|
|
100
|
+
[postMessage],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Expose imperative API to parents.
|
|
104
|
+
useImperativeHandle(
|
|
105
|
+
ref,
|
|
106
|
+
() => ({
|
|
107
|
+
setMcps,
|
|
108
|
+
setAppName,
|
|
109
|
+
get isReady() {
|
|
110
|
+
return isReady;
|
|
111
|
+
},
|
|
112
|
+
}),
|
|
113
|
+
[setMcps, setAppName, isReady],
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
// Initialize and setup listeners
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
const iframe = iframeRef.current;
|
|
119
|
+
if (!iframe) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const handleMessage = (event: MessageEvent<IframeMessage>) => {
|
|
124
|
+
if (process.env.NODE_ENV === "development") {
|
|
125
|
+
console.log("iframe message", event.data);
|
|
126
|
+
}
|
|
127
|
+
// When the iframe is ready, set isReady flag to kick off the initialization
|
|
128
|
+
if (event.data?.type === "CHATBOT_READY") {
|
|
129
|
+
setIsReady(true);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const handleIframeLoad = () => {
|
|
134
|
+
window.addEventListener("message", handleMessage);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
iframe.addEventListener("load", handleIframeLoad);
|
|
138
|
+
|
|
139
|
+
return () => {
|
|
140
|
+
window.removeEventListener("message", handleMessage);
|
|
141
|
+
iframe.removeEventListener("load", handleIframeLoad);
|
|
142
|
+
};
|
|
143
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
144
|
+
}, []); // Only setup the message listeners once
|
|
145
|
+
|
|
146
|
+
// initialize the chatbot
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (isReady && !hasInitialized) {
|
|
149
|
+
setHasInitialized(true);
|
|
150
|
+
init({ mcps });
|
|
151
|
+
if (appName) {
|
|
152
|
+
setAppName(appName);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}, [isReady, init, mcps, appName, hasInitialized, setAppName]);
|
|
156
|
+
|
|
157
|
+
// set mcps every time they change
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
if (JSON.stringify(currentMcps) !== JSON.stringify(mcps)) {
|
|
160
|
+
setCurrentMcps(mcps);
|
|
161
|
+
setMcps(mcps);
|
|
162
|
+
}
|
|
163
|
+
}, [setMcps, mcps, currentMcps]);
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<iframe
|
|
167
|
+
ref={iframeRef}
|
|
168
|
+
src={`${chatbotUrl}/embed/${agentId}`}
|
|
169
|
+
className={className}
|
|
170
|
+
allow="clipboard-write"
|
|
171
|
+
style={{
|
|
172
|
+
width: "100%",
|
|
173
|
+
height: "100%",
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
AgentFrame.displayName = "AgentFrame";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { forwardRef, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
AgentFrame,
|
|
4
|
+
type AgentElement,
|
|
5
|
+
type AgentFrameProps,
|
|
6
|
+
} from "./agent-frame";
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover";
|
|
8
|
+
|
|
9
|
+
export const ChatbotPopover = forwardRef<AgentElement, AgentFrameProps>(
|
|
10
|
+
(props, ref) => {
|
|
11
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
12
|
+
const [hasOpened, setHasOpened] = useState(false);
|
|
13
|
+
|
|
14
|
+
const handleOpenChange = (open: boolean) => {
|
|
15
|
+
setIsOpen(open);
|
|
16
|
+
if (open && !hasOpened) {
|
|
17
|
+
setHasOpened(true);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Popover open={isOpen} onOpenChange={handleOpenChange}>
|
|
23
|
+
<PopoverTrigger>
|
|
24
|
+
<EcforceAiIcon />
|
|
25
|
+
</PopoverTrigger>
|
|
26
|
+
<PopoverContent
|
|
27
|
+
align="end"
|
|
28
|
+
backdrop={isOpen}
|
|
29
|
+
forceMount={hasOpened || undefined} // チャットのStateを保持するために必要
|
|
30
|
+
>
|
|
31
|
+
<AgentFrame {...props} ref={ref} />
|
|
32
|
+
</PopoverContent>
|
|
33
|
+
</Popover>
|
|
34
|
+
);
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
function EcforceAiIcon() {
|
|
39
|
+
return (
|
|
40
|
+
<svg
|
|
41
|
+
width="24"
|
|
42
|
+
height="24"
|
|
43
|
+
viewBox="0 0 24 24"
|
|
44
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
45
|
+
fill="currentColor"
|
|
46
|
+
>
|
|
47
|
+
<path
|
|
48
|
+
fillRule="evenodd"
|
|
49
|
+
clipRule="evenodd"
|
|
50
|
+
d="M9.2 13.704s3.7-.812 4.325-3.74c.624-2.93.76-3.364 1.112-3.364.352 0 .42.309.5.618.08.309.51 2.276.613 2.745.102.47.783 2.93 3.712 3.616 2.93.686 3.338.697 3.338 1.12 0 .459-2.361.859-3.338 1.122-.976.263-3.042 1.007-3.587 3.49-.534 2.482-.681 3.489-1.238 3.489-.556 0-.545-.584-.613-.87-.068-.286-.34-1.819-.5-2.494-.147-.675-1.044-2.837-2.962-3.363-1.93-.527-3.962-.847-3.962-1.373s2.134-.824 2.6-.995ZM2.462 4.613s1.785-.39 2.08-1.798c.296-1.409.365-1.615.535-1.615.17 0 .205.149.239.298s.25 1.088.296 1.317c.045.229.375 1.409 1.785 1.74 1.41.333 1.603.333 1.603.54 0 .217-1.137.412-1.603.538-.466.126-1.467.48-1.729 1.683C5.407 8.507 5.338 9 5.078 9c-.262 0-.262-.286-.296-.424-.035-.137-.16-.882-.24-1.202-.079-.321-.5-1.363-1.432-1.615-.932-.252-1.91-.413-1.91-.665 0-.252 1.023-.4 1.25-.48h.012Z"
|
|
51
|
+
/>
|
|
52
|
+
</svg>
|
|
53
|
+
);
|
|
54
|
+
}
|
package/src/chatbot.css
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/* Chatbot Trigger Button */
|
|
2
|
+
.chatbot-trigger {
|
|
3
|
+
position: fixed;
|
|
4
|
+
bottom: 1rem;
|
|
5
|
+
right: 1rem;
|
|
6
|
+
z-index: 50;
|
|
7
|
+
border-radius: 9999px;
|
|
8
|
+
border: 1px solid #f0f2f7;
|
|
9
|
+
background-color: #ffffff;
|
|
10
|
+
padding: 0.375rem;
|
|
11
|
+
color: #0061ff;
|
|
12
|
+
box-shadow:
|
|
13
|
+
0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
|
14
|
+
0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
|
15
|
+
transition: colors 200ms ease-in-out;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.chatbot-trigger:hover {
|
|
20
|
+
background-color: #f0f2f7;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Popover Backdrop */
|
|
24
|
+
.chatbot-popover-backdrop {
|
|
25
|
+
position: fixed;
|
|
26
|
+
top: 0;
|
|
27
|
+
right: 0;
|
|
28
|
+
bottom: 0;
|
|
29
|
+
left: 0;
|
|
30
|
+
z-index: 30;
|
|
31
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
32
|
+
animation: fade-in 150ms ease-out;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Popover Content */
|
|
36
|
+
.chatbot-popover-content {
|
|
37
|
+
z-index: 50;
|
|
38
|
+
border-radius: 2rem;
|
|
39
|
+
background-color: #f7f9fa;
|
|
40
|
+
box-shadow:
|
|
41
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
42
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
43
|
+
outline: none;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
height: 80vh;
|
|
46
|
+
width: 600px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Animation states */
|
|
50
|
+
.chatbot-popover-content[data-state="closed"] {
|
|
51
|
+
display: none;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.chatbot-popover-content[data-state="open"] {
|
|
55
|
+
animation:
|
|
56
|
+
zoom-in 150ms ease-out,
|
|
57
|
+
fade-in 150ms ease-out;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.chatbot-popover-content[data-state="closed"] {
|
|
61
|
+
animation:
|
|
62
|
+
zoom-out 150ms ease-in,
|
|
63
|
+
fade-out 150ms ease-in;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Side-specific slide animations */
|
|
67
|
+
.chatbot-popover-content[data-side="bottom"] {
|
|
68
|
+
animation:
|
|
69
|
+
zoom-in 150ms ease-out,
|
|
70
|
+
fade-in 150ms ease-out,
|
|
71
|
+
slide-in-from-top 150ms ease-out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.chatbot-popover-content[data-side="top"] {
|
|
75
|
+
animation:
|
|
76
|
+
zoom-in 150ms ease-out,
|
|
77
|
+
fade-in 150ms ease-out,
|
|
78
|
+
slide-in-from-bottom 150ms ease-out;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.chatbot-popover-content[data-side="left"] {
|
|
82
|
+
animation:
|
|
83
|
+
zoom-in 150ms ease-out,
|
|
84
|
+
fade-in 150ms ease-out,
|
|
85
|
+
slide-in-from-right 150ms ease-out;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.chatbot-popover-content[data-side="right"] {
|
|
89
|
+
animation:
|
|
90
|
+
zoom-in 150ms ease-out,
|
|
91
|
+
fade-in 150ms ease-out,
|
|
92
|
+
slide-in-from-left 150ms ease-out;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Keyframe Animations */
|
|
96
|
+
@keyframes fade-in {
|
|
97
|
+
from {
|
|
98
|
+
opacity: 0;
|
|
99
|
+
}
|
|
100
|
+
to {
|
|
101
|
+
opacity: 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@keyframes fade-out {
|
|
106
|
+
from {
|
|
107
|
+
opacity: 1;
|
|
108
|
+
}
|
|
109
|
+
to {
|
|
110
|
+
opacity: 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@keyframes zoom-in {
|
|
115
|
+
from {
|
|
116
|
+
transform: scale(0.95);
|
|
117
|
+
}
|
|
118
|
+
to {
|
|
119
|
+
transform: scale(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@keyframes zoom-out {
|
|
124
|
+
from {
|
|
125
|
+
transform: scale(1);
|
|
126
|
+
}
|
|
127
|
+
to {
|
|
128
|
+
transform: scale(0.95);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes slide-in-from-top {
|
|
133
|
+
from {
|
|
134
|
+
transform: translateY(-0.5rem);
|
|
135
|
+
}
|
|
136
|
+
to {
|
|
137
|
+
transform: translateY(0);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@keyframes slide-in-from-bottom {
|
|
142
|
+
from {
|
|
143
|
+
transform: translateY(0.5rem);
|
|
144
|
+
}
|
|
145
|
+
to {
|
|
146
|
+
transform: translateY(0);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@keyframes slide-in-from-left {
|
|
151
|
+
from {
|
|
152
|
+
transform: translateX(-0.5rem);
|
|
153
|
+
}
|
|
154
|
+
to {
|
|
155
|
+
transform: translateX(0);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@keyframes slide-in-from-right {
|
|
160
|
+
from {
|
|
161
|
+
transform: translateX(0.5rem);
|
|
162
|
+
}
|
|
163
|
+
to {
|
|
164
|
+
transform: translateX(0);
|
|
165
|
+
}
|
|
166
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const PROD_CHATBOT_URL = "https://ecforce-ai-agent.vercel.app";
|
package/src/index.ts
ADDED
package/src/popover.tsx
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
const Popover = PopoverPrimitive.Root;
|
|
7
|
+
|
|
8
|
+
const PopoverTrigger = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof PopoverPrimitive.Trigger>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>
|
|
11
|
+
>(({ className, ...props }, ref) => (
|
|
12
|
+
<PopoverPrimitive.Trigger
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={`chatbot-trigger ${className}`}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
));
|
|
18
|
+
PopoverTrigger.displayName = PopoverPrimitive.Trigger.displayName;
|
|
19
|
+
|
|
20
|
+
const PopoverContent = React.forwardRef<
|
|
21
|
+
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
22
|
+
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {
|
|
23
|
+
backdrop?: boolean;
|
|
24
|
+
}
|
|
25
|
+
>(
|
|
26
|
+
(
|
|
27
|
+
{
|
|
28
|
+
className,
|
|
29
|
+
align = "center",
|
|
30
|
+
backdrop,
|
|
31
|
+
sideOffset = 4,
|
|
32
|
+
forceMount,
|
|
33
|
+
...props
|
|
34
|
+
},
|
|
35
|
+
ref,
|
|
36
|
+
) => (
|
|
37
|
+
<PopoverPrimitive.Portal forceMount={forceMount}>
|
|
38
|
+
<div>
|
|
39
|
+
{backdrop && <div className="chatbot-popover-backdrop" />}
|
|
40
|
+
<PopoverPrimitive.Content
|
|
41
|
+
ref={ref}
|
|
42
|
+
align={align}
|
|
43
|
+
sideOffset={sideOffset}
|
|
44
|
+
forceMount={forceMount}
|
|
45
|
+
className={`chatbot-popover-content ${className}`}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
</PopoverPrimitive.Portal>
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
53
|
+
|
|
54
|
+
export { Popover, PopoverTrigger, PopoverContent };
|