@waysdrop/chat 1.0.1 → 1.0.4
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 +23 -8
- package/dist/index.cjs +198 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +198 -64
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -43,10 +43,12 @@ Mount `<ChatWidget />` once at the root of your app. It renders a floating butto
|
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
45
|
type ChatConfig = {
|
|
46
|
-
serverUrl: string
|
|
47
|
-
apiUrl: string
|
|
48
|
-
token?: string
|
|
49
|
-
visitorId?: string
|
|
46
|
+
serverUrl: string // Socket.IO server URL
|
|
47
|
+
apiUrl: string // REST base URL (used for file uploads)
|
|
48
|
+
token?: string // JWT for authenticated users — omit for visitor flow
|
|
49
|
+
visitorId?: string // Pass a returning visitor's ID to restore chat history
|
|
50
|
+
theme?: 'light' | 'dark' | 'system' // defaults to 'system'
|
|
51
|
+
primaryColor?: string // any valid CSS color — defaults to Waysdrop blue
|
|
50
52
|
}
|
|
51
53
|
```
|
|
52
54
|
|
|
@@ -60,7 +62,20 @@ saveVisitorId(id) // writes to localStorage
|
|
|
60
62
|
clearVisitorId() // clears — use on logout
|
|
61
63
|
```
|
|
62
64
|
|
|
63
|
-
**Authenticated flow** — pass a `token` (JWT). The socket server resolves the user from it. No `visitorId` needed.
|
|
65
|
+
**Authenticated flow** — pass a `token` (JWT). The socket server resolves the user from it. No `visitorId` needed. If the token changes at runtime (user logs in after mount), the widget automatically destroys the old socket connection and reconnects with the new token.
|
|
66
|
+
|
|
67
|
+
**Theming** — `theme` controls the color scheme. `system` follows the OS `prefers-color-scheme`. `light` and `dark` force it regardless of the OS setting. `primaryColor` accepts any valid CSS color value:
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
<ChatWidget
|
|
71
|
+
config={{
|
|
72
|
+
serverUrl: '...',
|
|
73
|
+
apiUrl: '...',
|
|
74
|
+
theme: 'dark',
|
|
75
|
+
primaryColor: '#7c3aed',
|
|
76
|
+
}}
|
|
77
|
+
/>
|
|
78
|
+
```
|
|
64
79
|
|
|
65
80
|
---
|
|
66
81
|
|
|
@@ -81,11 +96,11 @@ const {
|
|
|
81
96
|
visitorInfo, // VisitorInfo | null
|
|
82
97
|
setVisitorInfo,
|
|
83
98
|
sendMessage, // (content: string, info?: VisitorInfo) => void
|
|
84
|
-
sendFile, // (file: File, info?: VisitorInfo) => Promise<void>
|
|
99
|
+
sendFile, // (file: File, content?: string, info?: VisitorInfo) => Promise<void>
|
|
85
100
|
} = useChat(config)
|
|
86
101
|
```
|
|
87
102
|
|
|
88
|
-
`sendMessage` and `sendFile` accept an optional `VisitorInfo` argument for the first message in a visitor session
|
|
103
|
+
`sendMessage` and `sendFile` accept an optional `VisitorInfo` argument for the first message in a visitor session. `sendFile` also accepts an optional `content` string to send text alongside the file in a single message.
|
|
89
104
|
|
|
90
105
|
---
|
|
91
106
|
|
|
@@ -104,7 +119,7 @@ type ChatMessage = {
|
|
|
104
119
|
}
|
|
105
120
|
|
|
106
121
|
type VisitorInfo = {
|
|
107
|
-
email: string
|
|
122
|
+
email: string
|
|
108
123
|
name?: string
|
|
109
124
|
phone?: string
|
|
110
125
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -63,12 +63,15 @@ var import_css8 = require("@emotion/css");
|
|
|
63
63
|
// src/lib/upload.ts
|
|
64
64
|
var VISITOR_ID_KEY = "waysdrop_visitor_id";
|
|
65
65
|
var saveVisitorId = (id) => {
|
|
66
|
+
if (typeof window === "undefined") return;
|
|
66
67
|
localStorage.setItem(VISITOR_ID_KEY, id);
|
|
67
68
|
};
|
|
68
69
|
var loadVisitorId = () => {
|
|
70
|
+
if (typeof window === "undefined") return null;
|
|
69
71
|
return localStorage.getItem(VISITOR_ID_KEY);
|
|
70
72
|
};
|
|
71
73
|
var clearVisitorId = () => {
|
|
74
|
+
if (typeof window === "undefined") return;
|
|
72
75
|
localStorage.removeItem(VISITOR_ID_KEY);
|
|
73
76
|
};
|
|
74
77
|
var uploadFile = async (file, config) => {
|
|
@@ -102,8 +105,11 @@ var import_react = require("react");
|
|
|
102
105
|
// src/lib/socket.ts
|
|
103
106
|
var import_socket = require("socket.io-client");
|
|
104
107
|
var socket = null;
|
|
105
|
-
var
|
|
106
|
-
if (socket)
|
|
108
|
+
var createSocket = (config) => {
|
|
109
|
+
if (socket) {
|
|
110
|
+
socket.disconnect();
|
|
111
|
+
socket = null;
|
|
112
|
+
}
|
|
107
113
|
const { serverUrl, token, visitorId } = config;
|
|
108
114
|
socket = (0, import_socket.io)(serverUrl, {
|
|
109
115
|
transports: ["websocket", "polling"],
|
|
@@ -112,6 +118,10 @@ var getSocket = (config) => {
|
|
|
112
118
|
});
|
|
113
119
|
return socket;
|
|
114
120
|
};
|
|
121
|
+
var getSocket = (config) => {
|
|
122
|
+
if (socket) return socket;
|
|
123
|
+
return createSocket(config);
|
|
124
|
+
};
|
|
115
125
|
var destroySocket = () => {
|
|
116
126
|
if (socket) {
|
|
117
127
|
socket.disconnect();
|
|
@@ -163,7 +173,7 @@ var useChat = (config) => {
|
|
|
163
173
|
reset
|
|
164
174
|
} = useChatStore();
|
|
165
175
|
(0, import_react.useEffect)(() => {
|
|
166
|
-
const socket2 =
|
|
176
|
+
const socket2 = createSocket(config);
|
|
167
177
|
setStatus("connecting");
|
|
168
178
|
socket2.connect();
|
|
169
179
|
socket2.on("connected", (payload) => {
|
|
@@ -190,7 +200,7 @@ var useChat = (config) => {
|
|
|
190
200
|
destroySocket();
|
|
191
201
|
reset();
|
|
192
202
|
};
|
|
193
|
-
}, []);
|
|
203
|
+
}, [config.token]);
|
|
194
204
|
const sendMessage = (0, import_react.useCallback)(
|
|
195
205
|
(content, info) => {
|
|
196
206
|
var _a, _b;
|
|
@@ -208,14 +218,15 @@ var useChat = (config) => {
|
|
|
208
218
|
[config, visitorInfo]
|
|
209
219
|
);
|
|
210
220
|
const sendFile = (0, import_react.useCallback)(
|
|
211
|
-
async (file, info) => {
|
|
221
|
+
async (file, content, info) => {
|
|
212
222
|
var _a, _b;
|
|
213
223
|
const url = await uploadFile(file, config);
|
|
214
224
|
const socket2 = getSocket(config);
|
|
215
|
-
const dto = __spreadValues({
|
|
216
|
-
file: url
|
|
225
|
+
const dto = __spreadValues(__spreadProps(__spreadValues({
|
|
226
|
+
file: url
|
|
227
|
+
}, content ? { content } : {}), {
|
|
217
228
|
externalId: `file-${Date.now()}`
|
|
218
|
-
}, (info != null ? info : visitorInfo) ? {
|
|
229
|
+
}), (info != null ? info : visitorInfo) ? {
|
|
219
230
|
email: (info != null ? info : visitorInfo).email,
|
|
220
231
|
name: (_a = info != null ? info : visitorInfo) == null ? void 0 : _a.name,
|
|
221
232
|
phone: (_b = info != null ? info : visitorInfo) == null ? void 0 : _b.phone
|
|
@@ -734,7 +745,7 @@ var MessageBubble = ({ message }) => {
|
|
|
734
745
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: styles4.row(isCustomer), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: styles4.group(isCustomer), children: [
|
|
735
746
|
isBot && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: styles4.botLabel, children: "Ways AI" }),
|
|
736
747
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: styles4.bubble(isCustomer), children: [
|
|
737
|
-
message.file && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", { href: message.file, target: "_blank", rel: "noreferrer", className: styles4.fileLink, children: "\u{1F4CE} View attachment" }),
|
|
748
|
+
message.file && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", { href: message.file, target: "_blank", rel: "noreferrer", className: styles4.fileLink(!!message.content), children: "\u{1F4CE} View attachment" }),
|
|
738
749
|
message.content && (isBot ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MarkdownRenderer, { content: message.content }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: styles4.text, children: message.content }))
|
|
739
750
|
] }),
|
|
740
751
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: styles4.time, children: formatTime(message.createdAt) })
|
|
@@ -777,12 +788,13 @@ var styles4 = {
|
|
|
777
788
|
white-space: pre-wrap;
|
|
778
789
|
text-align: left;
|
|
779
790
|
`,
|
|
780
|
-
fileLink: import_css5.css`
|
|
791
|
+
fileLink: (hasContent) => import_css5.css`
|
|
781
792
|
font-size: 0.875rem;
|
|
782
793
|
color: inherit;
|
|
783
794
|
text-decoration: underline;
|
|
784
795
|
display: block;
|
|
785
796
|
text-align: left;
|
|
797
|
+
${hasContent ? "margin-bottom: 6px;" : ""}
|
|
786
798
|
`,
|
|
787
799
|
time: import_css5.css`
|
|
788
800
|
font-size: 10px;
|
|
@@ -815,13 +827,13 @@ var ChatInput = ({ onSendText, onSendFile, disabled, isThinking }) => {
|
|
|
815
827
|
if (!trimmed && !pendingFile || disabled || uploading) return;
|
|
816
828
|
if (pendingFile) {
|
|
817
829
|
setUploading(true);
|
|
818
|
-
onSendFile(pendingFile).finally(() => {
|
|
830
|
+
onSendFile(pendingFile, trimmed || void 0).finally(() => {
|
|
819
831
|
setUploading(false);
|
|
820
832
|
setPendingFile(null);
|
|
821
833
|
setPendingPreview(null);
|
|
834
|
+
setValue("");
|
|
822
835
|
});
|
|
823
|
-
}
|
|
824
|
-
if (trimmed) {
|
|
836
|
+
} else if (trimmed) {
|
|
825
837
|
onSendText(trimmed);
|
|
826
838
|
setValue("");
|
|
827
839
|
}
|
|
@@ -1102,35 +1114,102 @@ var ChatScreen = ({
|
|
|
1102
1114
|
};
|
|
1103
1115
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.wrapper, children: [
|
|
1104
1116
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.header, children: [
|
|
1105
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.iconBtn, onClick: onBack, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1117
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.iconBtn, onClick: onBack, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1118
|
+
"svg",
|
|
1119
|
+
{
|
|
1120
|
+
width: "18",
|
|
1121
|
+
height: "18",
|
|
1122
|
+
viewBox: "0 0 24 24",
|
|
1123
|
+
fill: "none",
|
|
1124
|
+
stroke: "currentColor",
|
|
1125
|
+
strokeWidth: "2",
|
|
1126
|
+
strokeLinecap: "round",
|
|
1127
|
+
strokeLinejoin: "round",
|
|
1128
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 18 9 12 15 6" })
|
|
1129
|
+
}
|
|
1130
|
+
) }),
|
|
1106
1131
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.headerCenter, children: [
|
|
1107
1132
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: styles6.headerTitle, children: "Support" }),
|
|
1108
1133
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: styles6.statusDot(connected) }),
|
|
1109
1134
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: styles6.statusLabel, children: connected ? "Online" : "Connecting..." })
|
|
1110
1135
|
] }),
|
|
1111
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.expandBtn, onClick: onExpand, children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1136
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.expandBtn, onClick: onExpand, children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1137
|
+
"svg",
|
|
1138
|
+
{
|
|
1139
|
+
width: "16",
|
|
1140
|
+
height: "16",
|
|
1141
|
+
viewBox: "0 0 24 24",
|
|
1142
|
+
fill: "none",
|
|
1143
|
+
stroke: "currentColor",
|
|
1144
|
+
strokeWidth: "2",
|
|
1145
|
+
strokeLinecap: "round",
|
|
1146
|
+
strokeLinejoin: "round",
|
|
1147
|
+
children: [
|
|
1148
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "4 14 10 14 10 20" }),
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "20 10 14 10 14 4" }),
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "10", y1: "14", x2: "3", y2: "21" }),
|
|
1151
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" })
|
|
1152
|
+
]
|
|
1153
|
+
}
|
|
1154
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1155
|
+
"svg",
|
|
1156
|
+
{
|
|
1157
|
+
width: "16",
|
|
1158
|
+
height: "16",
|
|
1159
|
+
viewBox: "0 0 24 24",
|
|
1160
|
+
fill: "none",
|
|
1161
|
+
stroke: "currentColor",
|
|
1162
|
+
strokeWidth: "2",
|
|
1163
|
+
strokeLinecap: "round",
|
|
1164
|
+
strokeLinejoin: "round",
|
|
1165
|
+
children: [
|
|
1166
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "9 21 3 21 3 15" }),
|
|
1168
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
|
|
1169
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
|
|
1170
|
+
]
|
|
1171
|
+
}
|
|
1172
|
+
) })
|
|
1122
1173
|
] }),
|
|
1123
1174
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.messagesWrap, children: [
|
|
1124
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1176
|
+
"div",
|
|
1177
|
+
{
|
|
1178
|
+
className: styles6.messages,
|
|
1179
|
+
ref: scrollRef,
|
|
1180
|
+
onScroll: handleScroll,
|
|
1181
|
+
children: [
|
|
1182
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: styles6.errorBanner, children: error.message }),
|
|
1183
|
+
messages.length === 0 && connected && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: styles6.emptyState, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "Send a message to start the conversation." }) }),
|
|
1184
|
+
messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageBubble, { message: msg }, msg.id)),
|
|
1185
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: bottomRef })
|
|
1186
|
+
]
|
|
1187
|
+
}
|
|
1188
|
+
),
|
|
1189
|
+
showScrollBtn && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1190
|
+
"button",
|
|
1191
|
+
{
|
|
1192
|
+
className: styles6.scrollBtn,
|
|
1193
|
+
onClick: () => {
|
|
1194
|
+
var _a;
|
|
1195
|
+
return (_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
1196
|
+
},
|
|
1197
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1198
|
+
"svg",
|
|
1199
|
+
{
|
|
1200
|
+
width: "14",
|
|
1201
|
+
height: "14",
|
|
1202
|
+
viewBox: "0 0 24 24",
|
|
1203
|
+
fill: "none",
|
|
1204
|
+
stroke: "currentColor",
|
|
1205
|
+
strokeWidth: "2.5",
|
|
1206
|
+
strokeLinecap: "round",
|
|
1207
|
+
strokeLinejoin: "round",
|
|
1208
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "6 9 12 15 18 9" })
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
}
|
|
1212
|
+
)
|
|
1134
1213
|
] }),
|
|
1135
1214
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1136
1215
|
ChatInput,
|
|
@@ -1196,7 +1275,9 @@ var styles6 = {
|
|
|
1196
1275
|
align-items: center;
|
|
1197
1276
|
justify-content: center;
|
|
1198
1277
|
flex-shrink: 0;
|
|
1199
|
-
transition:
|
|
1278
|
+
transition:
|
|
1279
|
+
color 0.15s,
|
|
1280
|
+
background 0.15s;
|
|
1200
1281
|
&:hover {
|
|
1201
1282
|
color: var(--wds-fg);
|
|
1202
1283
|
background: var(--wds-muted-bg);
|
|
@@ -1213,7 +1294,9 @@ var styles6 = {
|
|
|
1213
1294
|
align-items: center;
|
|
1214
1295
|
justify-content: center;
|
|
1215
1296
|
flex-shrink: 0;
|
|
1216
|
-
transition:
|
|
1297
|
+
transition:
|
|
1298
|
+
color 0.15s,
|
|
1299
|
+
background 0.15s;
|
|
1217
1300
|
&:hover {
|
|
1218
1301
|
color: var(--wds-fg);
|
|
1219
1302
|
background: var(--wds-muted-bg);
|
|
@@ -1270,8 +1353,10 @@ var styles6 = {
|
|
|
1270
1353
|
align-items: center;
|
|
1271
1354
|
justify-content: center;
|
|
1272
1355
|
cursor: pointer;
|
|
1273
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
|
1274
|
-
transition:
|
|
1356
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
1357
|
+
transition:
|
|
1358
|
+
color 0.15s,
|
|
1359
|
+
border-color 0.15s;
|
|
1275
1360
|
&:hover {
|
|
1276
1361
|
color: var(--wds-primary);
|
|
1277
1362
|
border-color: var(--wds-primary);
|
|
@@ -1281,16 +1366,74 @@ var styles6 = {
|
|
|
1281
1366
|
|
|
1282
1367
|
// src/components/ChatWidget.tsx
|
|
1283
1368
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1369
|
+
var LIGHT_VARS = `
|
|
1370
|
+
--wds-bg: oklch(1 0 0);
|
|
1371
|
+
--wds-fg: oklch(0.145 0 0);
|
|
1372
|
+
--wds-muted: oklch(0.556 0 0);
|
|
1373
|
+
--wds-muted-bg: oklch(0.97 0 0);
|
|
1374
|
+
--wds-border: oklch(0.922 0 0);
|
|
1375
|
+
`;
|
|
1376
|
+
var DARK_VARS = `
|
|
1377
|
+
--wds-bg: oklch(0.145 0 0);
|
|
1378
|
+
--wds-fg: oklch(0.985 0 0);
|
|
1379
|
+
--wds-muted: oklch(0.708 0 0);
|
|
1380
|
+
--wds-muted-bg: oklch(0.205 0 0);
|
|
1381
|
+
--wds-border: oklch(1 0 0 / 10%);
|
|
1382
|
+
`;
|
|
1383
|
+
function buildPrimaryVars(color) {
|
|
1384
|
+
return `
|
|
1385
|
+
--wds-primary: ${color};
|
|
1386
|
+
--wds-primary-soft: color-mix(in oklch, ${color} 12%, transparent);
|
|
1387
|
+
--wds-primary-border: color-mix(in oklch, ${color} 40%, transparent);
|
|
1388
|
+
`;
|
|
1389
|
+
}
|
|
1390
|
+
var DEFAULT_PRIMARY = "oklch(0.5811 0.2268 259.15)";
|
|
1391
|
+
function buildThemeStyle(theme, primaryColor) {
|
|
1392
|
+
const primary = buildPrimaryVars(primaryColor);
|
|
1393
|
+
if (theme === "light") {
|
|
1394
|
+
return `
|
|
1395
|
+
[data-wds-root] {
|
|
1396
|
+
${LIGHT_VARS}
|
|
1397
|
+
${primary}
|
|
1398
|
+
}
|
|
1399
|
+
`;
|
|
1400
|
+
}
|
|
1401
|
+
if (theme === "dark") {
|
|
1402
|
+
return `
|
|
1403
|
+
[data-wds-root] {
|
|
1404
|
+
${DARK_VARS}
|
|
1405
|
+
${primary}
|
|
1406
|
+
}
|
|
1407
|
+
`;
|
|
1408
|
+
}
|
|
1409
|
+
return `
|
|
1410
|
+
[data-wds-root] {
|
|
1411
|
+
${LIGHT_VARS}
|
|
1412
|
+
${primary}
|
|
1413
|
+
}
|
|
1414
|
+
@media (prefers-color-scheme: dark) {
|
|
1415
|
+
[data-wds-root] {
|
|
1416
|
+
${DARK_VARS}
|
|
1417
|
+
--wds-primary-soft: color-mix(in oklch, ${primaryColor} 15%, transparent);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
`;
|
|
1421
|
+
}
|
|
1284
1422
|
var ChatWidget = ({ config }) => {
|
|
1285
|
-
var _a, _b;
|
|
1286
1423
|
const [isOpen, setIsOpen] = (0, import_react5.useState)(false);
|
|
1287
1424
|
const [isExpanded, setIsExpanded] = (0, import_react5.useState)(false);
|
|
1288
1425
|
const [view, setView] = (0, import_react5.useState)("home");
|
|
1426
|
+
const [visitorId] = (0, import_react5.useState)(
|
|
1427
|
+
() => {
|
|
1428
|
+
var _a, _b;
|
|
1429
|
+
return (_b = (_a = config.visitorId) != null ? _a : loadVisitorId()) != null ? _b : void 0;
|
|
1430
|
+
}
|
|
1431
|
+
);
|
|
1289
1432
|
const reset = useChatStore((s) => s.reset);
|
|
1290
1433
|
const resolvedConfig = __spreadProps(__spreadValues({}, config), {
|
|
1291
|
-
visitorId
|
|
1434
|
+
visitorId
|
|
1292
1435
|
});
|
|
1293
|
-
const hasHistory = !!
|
|
1436
|
+
const hasHistory = !!visitorId;
|
|
1294
1437
|
const { status, messages, error, sendMessage, sendFile } = useChat(resolvedConfig);
|
|
1295
1438
|
const handleNewConversation = () => {
|
|
1296
1439
|
reset();
|
|
@@ -1305,6 +1448,19 @@ var ChatWidget = ({ config }) => {
|
|
|
1305
1448
|
document.body.style.overflow = "";
|
|
1306
1449
|
};
|
|
1307
1450
|
}, [isOpen]);
|
|
1451
|
+
(0, import_react5.useEffect)(() => {
|
|
1452
|
+
var _a, _b;
|
|
1453
|
+
const theme = (_a = config.theme) != null ? _a : "system";
|
|
1454
|
+
const primaryColor = (_b = config.primaryColor) != null ? _b : DEFAULT_PRIMARY;
|
|
1455
|
+
const style = buildThemeStyle(theme, primaryColor);
|
|
1456
|
+
const el = document.createElement("style");
|
|
1457
|
+
el.setAttribute("data-wds-theme", "");
|
|
1458
|
+
el.textContent = style;
|
|
1459
|
+
document.head.appendChild(el);
|
|
1460
|
+
return () => {
|
|
1461
|
+
document.head.removeChild(el);
|
|
1462
|
+
};
|
|
1463
|
+
}, [config.theme, config.primaryColor]);
|
|
1308
1464
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1309
1465
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1310
1466
|
FloatingButton,
|
|
@@ -1345,28 +1501,6 @@ var ChatWidget = ({ config }) => {
|
|
|
1345
1501
|
] });
|
|
1346
1502
|
};
|
|
1347
1503
|
import_css8.injectGlobal`
|
|
1348
|
-
:root {
|
|
1349
|
-
--wds-primary: oklch(0.5811 0.2268 259.15);
|
|
1350
|
-
--wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.12);
|
|
1351
|
-
--wds-primary-border: oklch(0.7695 0.1177 255.22 / 0.4);
|
|
1352
|
-
--wds-bg: oklch(1 0 0);
|
|
1353
|
-
--wds-fg: oklch(0.145 0 0);
|
|
1354
|
-
--wds-muted: oklch(0.556 0 0);
|
|
1355
|
-
--wds-muted-bg: oklch(0.97 0 0);
|
|
1356
|
-
--wds-border: oklch(0.922 0 0);
|
|
1357
|
-
}
|
|
1358
|
-
|
|
1359
|
-
@media (prefers-color-scheme: dark) {
|
|
1360
|
-
:root {
|
|
1361
|
-
--wds-bg: oklch(0.145 0 0);
|
|
1362
|
-
--wds-fg: oklch(0.985 0 0);
|
|
1363
|
-
--wds-muted: oklch(0.708 0 0);
|
|
1364
|
-
--wds-muted-bg: oklch(0.205 0 0);
|
|
1365
|
-
--wds-border: oklch(1 0 0 / 10%);
|
|
1366
|
-
--wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.15);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
1504
|
[data-wds-root] * {
|
|
1371
1505
|
box-sizing: border-box;
|
|
1372
1506
|
text-align: left;
|