@waysdrop/chat 1.0.1 โ†’ 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -208,14 +208,15 @@ var useChat = (config) => {
208
208
  [config, visitorInfo]
209
209
  );
210
210
  const sendFile = (0, import_react.useCallback)(
211
- async (file, info) => {
211
+ async (file, content, info) => {
212
212
  var _a, _b;
213
213
  const url = await uploadFile(file, config);
214
214
  const socket2 = getSocket(config);
215
- const dto = __spreadValues({
216
- file: url,
215
+ const dto = __spreadValues(__spreadProps(__spreadValues({
216
+ file: url
217
+ }, content ? { content } : {}), {
217
218
  externalId: `file-${Date.now()}`
218
- }, (info != null ? info : visitorInfo) ? {
219
+ }), (info != null ? info : visitorInfo) ? {
219
220
  email: (info != null ? info : visitorInfo).email,
220
221
  name: (_a = info != null ? info : visitorInfo) == null ? void 0 : _a.name,
221
222
  phone: (_b = info != null ? info : visitorInfo) == null ? void 0 : _b.phone
@@ -734,7 +735,7 @@ var MessageBubble = ({ message }) => {
734
735
  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
736
  isBot && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: styles4.botLabel, children: "Ways AI" }),
736
737
  /* @__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" }),
738
+ 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
739
  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
740
  ] }),
740
741
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: styles4.time, children: formatTime(message.createdAt) })
@@ -777,12 +778,13 @@ var styles4 = {
777
778
  white-space: pre-wrap;
778
779
  text-align: left;
779
780
  `,
780
- fileLink: import_css5.css`
781
+ fileLink: (hasContent) => import_css5.css`
781
782
  font-size: 0.875rem;
782
783
  color: inherit;
783
784
  text-decoration: underline;
784
785
  display: block;
785
786
  text-align: left;
787
+ ${hasContent ? "margin-bottom: 6px;" : ""}
786
788
  `,
787
789
  time: import_css5.css`
788
790
  font-size: 10px;
@@ -815,13 +817,13 @@ var ChatInput = ({ onSendText, onSendFile, disabled, isThinking }) => {
815
817
  if (!trimmed && !pendingFile || disabled || uploading) return;
816
818
  if (pendingFile) {
817
819
  setUploading(true);
818
- onSendFile(pendingFile).finally(() => {
820
+ onSendFile(pendingFile, trimmed || void 0).finally(() => {
819
821
  setUploading(false);
820
822
  setPendingFile(null);
821
823
  setPendingPreview(null);
824
+ setValue("");
822
825
  });
823
- }
824
- if (trimmed) {
826
+ } else if (trimmed) {
825
827
  onSendText(trimmed);
826
828
  setValue("");
827
829
  }
@@ -1102,35 +1104,102 @@ var ChatScreen = ({
1102
1104
  };
1103
1105
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.wrapper, children: [
1104
1106
  /* @__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)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 18 9 12 15 6" }) }) }),
1107
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.iconBtn, onClick: onBack, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1108
+ "svg",
1109
+ {
1110
+ width: "18",
1111
+ height: "18",
1112
+ viewBox: "0 0 24 24",
1113
+ fill: "none",
1114
+ stroke: "currentColor",
1115
+ strokeWidth: "2",
1116
+ strokeLinecap: "round",
1117
+ strokeLinejoin: "round",
1118
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 18 9 12 15 6" })
1119
+ }
1120
+ ) }),
1106
1121
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.headerCenter, children: [
1107
1122
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: styles6.headerTitle, children: "Support" }),
1108
1123
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: styles6.statusDot(connected) }),
1109
1124
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: styles6.statusLabel, children: connected ? "Online" : "Connecting..." })
1110
1125
  ] }),
1111
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.expandBtn, onClick: onExpand, children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1112
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "4 14 10 14 10 20" }),
1113
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "20 10 14 10 14 4" }),
1114
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "10", y1: "14", x2: "3", y2: "21" }),
1115
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" })
1116
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1117
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 3 21 3 21 9" }),
1118
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "9 21 3 21 3 15" }),
1119
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
1120
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
1121
- ] }) })
1126
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.expandBtn, onClick: onExpand, children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1127
+ "svg",
1128
+ {
1129
+ width: "16",
1130
+ height: "16",
1131
+ viewBox: "0 0 24 24",
1132
+ fill: "none",
1133
+ stroke: "currentColor",
1134
+ strokeWidth: "2",
1135
+ strokeLinecap: "round",
1136
+ strokeLinejoin: "round",
1137
+ children: [
1138
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "4 14 10 14 10 20" }),
1139
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "20 10 14 10 14 4" }),
1140
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "10", y1: "14", x2: "3", y2: "21" }),
1141
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" })
1142
+ ]
1143
+ }
1144
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1145
+ "svg",
1146
+ {
1147
+ width: "16",
1148
+ height: "16",
1149
+ viewBox: "0 0 24 24",
1150
+ fill: "none",
1151
+ stroke: "currentColor",
1152
+ strokeWidth: "2",
1153
+ strokeLinecap: "round",
1154
+ strokeLinejoin: "round",
1155
+ children: [
1156
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 3 21 3 21 9" }),
1157
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "9 21 3 21 3 15" }),
1158
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
1159
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
1160
+ ]
1161
+ }
1162
+ ) })
1122
1163
  ] }),
1123
1164
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.messagesWrap, children: [
1124
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: styles6.messages, ref: scrollRef, onScroll: handleScroll, children: [
1125
- error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: styles6.errorBanner, children: error.message }),
1126
- 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." }) }),
1127
- messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageBubble, { message: msg }, msg.id)),
1128
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: bottomRef })
1129
- ] }),
1130
- showScrollBtn && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: styles6.scrollBtn, onClick: () => {
1131
- var _a;
1132
- return (_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
1133
- }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "6 9 12 15 18 9" }) }) })
1165
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1166
+ "div",
1167
+ {
1168
+ className: styles6.messages,
1169
+ ref: scrollRef,
1170
+ onScroll: handleScroll,
1171
+ children: [
1172
+ error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: styles6.errorBanner, children: error.message }),
1173
+ 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." }) }),
1174
+ messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageBubble, { message: msg }, msg.id)),
1175
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: bottomRef })
1176
+ ]
1177
+ }
1178
+ ),
1179
+ showScrollBtn && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1180
+ "button",
1181
+ {
1182
+ className: styles6.scrollBtn,
1183
+ onClick: () => {
1184
+ var _a;
1185
+ return (_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
1186
+ },
1187
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1188
+ "svg",
1189
+ {
1190
+ width: "14",
1191
+ height: "14",
1192
+ viewBox: "0 0 24 24",
1193
+ fill: "none",
1194
+ stroke: "currentColor",
1195
+ strokeWidth: "2.5",
1196
+ strokeLinecap: "round",
1197
+ strokeLinejoin: "round",
1198
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "6 9 12 15 18 9" })
1199
+ }
1200
+ )
1201
+ }
1202
+ )
1134
1203
  ] }),
1135
1204
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1136
1205
  ChatInput,
@@ -1196,7 +1265,9 @@ var styles6 = {
1196
1265
  align-items: center;
1197
1266
  justify-content: center;
1198
1267
  flex-shrink: 0;
1199
- transition: color 0.15s, background 0.15s;
1268
+ transition:
1269
+ color 0.15s,
1270
+ background 0.15s;
1200
1271
  &:hover {
1201
1272
  color: var(--wds-fg);
1202
1273
  background: var(--wds-muted-bg);
@@ -1213,7 +1284,9 @@ var styles6 = {
1213
1284
  align-items: center;
1214
1285
  justify-content: center;
1215
1286
  flex-shrink: 0;
1216
- transition: color 0.15s, background 0.15s;
1287
+ transition:
1288
+ color 0.15s,
1289
+ background 0.15s;
1217
1290
  &:hover {
1218
1291
  color: var(--wds-fg);
1219
1292
  background: var(--wds-muted-bg);
@@ -1270,8 +1343,10 @@ var styles6 = {
1270
1343
  align-items: center;
1271
1344
  justify-content: center;
1272
1345
  cursor: pointer;
1273
- box-shadow: 0 2px 8px rgba(0,0,0,0.12);
1274
- transition: color 0.15s, border-color 0.15s;
1346
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
1347
+ transition:
1348
+ color 0.15s,
1349
+ border-color 0.15s;
1275
1350
  &:hover {
1276
1351
  color: var(--wds-primary);
1277
1352
  border-color: var(--wds-primary);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/ChatWidget.tsx","../src/lib/upload.ts","../src/hooks/useChat.ts","../src/lib/socket.ts","../src/store/chatStore.ts","../src/components/FloatingButton.tsx","../src/components/ChatPanel.tsx","../src/components/HomeScreen.tsx","../src/components/ChatScreen.tsx","../src/components/MessageBubble.tsx","../src/components/MarkdownRenderer.tsx","../src/components/ChatInput.tsx"],"sourcesContent":["export { ChatWidget } from './components/ChatWidget'\nexport type { ChatWidgetProps } from './components/ChatWidget'\nexport { useChat } from './hooks/useChat'\nexport { useChatStore } from './store/chatStore'\nexport { loadVisitorId, saveVisitorId, clearVisitorId } from './lib/upload'\nexport * from './types'","import React, { useEffect, useState } from 'react'\nimport { injectGlobal } from '@emotion/css'\nimport { ChatConfig } from '../types'\nimport { loadVisitorId } from '../lib/upload'\nimport { useChat } from '../hooks/useChat'\nimport { useChatStore } from '../store/chatStore'\nimport { FloatingButton } from './FloatingButton'\nimport { ChatPanel } from './ChatPanel'\nimport { HomeScreen } from './HomeScreen'\nimport { ChatScreen } from './ChatScreen'\n\nexport type ChatWidgetProps = {\n config: ChatConfig\n}\n\ntype View = 'home' | 'chat'\n\nexport const ChatWidget: React.FC<ChatWidgetProps> = ({ config }) => {\n const [isOpen, setIsOpen] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n const [view, setView] = useState<View>('home')\n\n const reset = useChatStore((s) => s.reset)\n\n const resolvedConfig: ChatConfig = {\n ...config,\n visitorId: config.visitorId ?? loadVisitorId() ?? undefined,\n }\n\n const hasHistory = !!resolvedConfig.visitorId\n\n const { status, messages, error, sendMessage, sendFile } = useChat(resolvedConfig)\n\n const handleNewConversation = () => {\n reset()\n setView('chat')\n }\n\n useEffect(() => {\n const isMobile = window.innerWidth <= 480\n if (isMobile) {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n }\n return () => {\n document.body.style.overflow = ''\n }\n }, [isOpen])\n\n return (\n <>\n <FloatingButton\n isOpen={isOpen}\n onToggle={() => setIsOpen((p) => !p)}\n />\n\n <ChatPanel\n isOpen={isOpen}\n isExpanded={isExpanded}\n >\n {view === 'home' ? (\n <HomeScreen\n onStartChat={handleNewConversation}\n onContinueChat={() => setView('chat')}\n hasHistory={hasHistory}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n />\n ) : (\n <ChatScreen\n messages={messages}\n onSendText={sendMessage}\n onSendFile={sendFile}\n onBack={() => setView('home')}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n status={status}\n error={error}\n />\n )}\n </ChatPanel>\n </>\n )\n}\n\ninjectGlobal`\n :root {\n --wds-primary: oklch(0.5811 0.2268 259.15);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.12);\n --wds-primary-border: oklch(0.7695 0.1177 255.22 / 0.4);\n --wds-bg: oklch(1 0 0);\n --wds-fg: oklch(0.145 0 0);\n --wds-muted: oklch(0.556 0 0);\n --wds-muted-bg: oklch(0.97 0 0);\n --wds-border: oklch(0.922 0 0);\n }\n\n @media (prefers-color-scheme: dark) {\n :root {\n --wds-bg: oklch(0.145 0 0);\n --wds-fg: oklch(0.985 0 0);\n --wds-muted: oklch(0.708 0 0);\n --wds-muted-bg: oklch(0.205 0 0);\n --wds-border: oklch(1 0 0 / 10%);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.15);\n }\n }\n\n [data-wds-root] * {\n box-sizing: border-box;\n text-align: left;\n }\n`","import type { ChatConfig } from \"../types\";\n\nconst VISITOR_ID_KEY = \"waysdrop_visitor_id\";\n\nexport const saveVisitorId = (id: string): void => {\n localStorage.setItem(VISITOR_ID_KEY, id);\n};\n\nexport const loadVisitorId = (): string | null => {\n return localStorage.getItem(VISITOR_ID_KEY);\n};\n\nexport const clearVisitorId = (): void => {\n localStorage.removeItem(VISITOR_ID_KEY);\n};\n\nexport const uploadFile = async (\n file: File,\n config: ChatConfig,\n): Promise<string> => {\n const formData = new FormData();\n formData.append(\"files\", file);\n\n const headers: HeadersInit = {};\n if (config.token) headers[\"Authorization\"] = `Bearer ${config.token}`;\n\n const res = await fetch(`${config.apiUrl}/file/bulk-upload`, {\n method: \"POST\",\n headers,\n body: formData,\n });\n\n if (!res.ok) {\n throw new Error(\"File upload failed\");\n }\n\n const json = await res.json();\n\n if (!json.success || !json.data?.urls?.length) {\n throw new Error(json.message || \"File upload failed\");\n }\n\n const first = json.data.urls[0];\n if (typeof first !== \"string\") {\n throw new Error(first?.error || \"File upload failed\");\n }\n\n return first;\n};","import { useEffect, useCallback } from 'react'\nimport { getSocket, destroySocket } from '../lib/socket'\nimport { saveVisitorId, uploadFile } from '../lib/upload'\nimport { useChatStore } from '../store/chatStore'\nimport type {\n ChatConfig,\n ConnectedPayload,\n SupportMessageSentPayload,\n SupportNewMessagePayload,\n SocketError,\n SupportSendMessageDTO,\n VisitorInfo,\n} from '../types'\n\nexport const useChat = (config: ChatConfig) => {\n const {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setStatus,\n setRole,\n setVisitorId,\n setChatId,\n addMessage,\n setError,\n setVisitorInfo,\n reset,\n } = useChatStore()\n\n // โ”€โ”€โ”€ Connect โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n useEffect(() => {\n const socket = getSocket(config)\n\n setStatus('connecting')\n socket.connect()\n\n socket.on('connected', (payload: ConnectedPayload) => {\n setStatus('connected')\n setRole(payload.role)\n\n if (payload.role === 'VISITOR') {\n saveVisitorId(payload.visitorId)\n setVisitorId(payload.visitorId)\n }\n })\n\n socket.on('support-message-sent', (payload: SupportMessageSentPayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('support-new-message', (payload: SupportNewMessagePayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('error', (err: SocketError) => {\n setError(err)\n setStatus('error')\n })\n\n return () => {\n destroySocket()\n reset()\n }\n }, [])\n\n // โ”€โ”€โ”€ Send text message โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n const sendMessage = useCallback(\n (content: string, info?: VisitorInfo) => {\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n content,\n externalId: `msg-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n // โ”€โ”€โ”€ Send file โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n const sendFile = useCallback(\n async (file: File, info?: VisitorInfo) => {\n const url = await uploadFile(file, config)\n\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n file: url,\n externalId: `file-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n return {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setVisitorInfo,\n sendMessage,\n sendFile,\n }\n}","import { io, Socket } from 'socket.io-client'\nimport type { ChatConfig } from '../types'\n\nlet socket: Socket | null = null\n\nexport const getSocket = (config: ChatConfig): Socket => {\n if (socket) return socket\n\n const { serverUrl, token, visitorId } = config\n\n socket = io(serverUrl, {\n transports: ['websocket', 'polling'],\n auth: {\n ...(token ? { token } : {}),\n ...(visitorId ? { visitorId } : {}),\n },\n autoConnect: false,\n })\n\n return socket\n}\n\nexport const destroySocket = (): void => {\n if (socket) {\n socket.disconnect()\n socket = null\n }\n}","import { create } from 'zustand'\nimport type {\n ChatState,\n ChatMessage,\n UserRole,\n SocketError,\n VisitorInfo,\n ConnectionStatus,\n} from '../types'\n\ntype ChatActions = {\n setStatus: (status: ConnectionStatus) => void\n setRole: (role: UserRole) => void\n setVisitorId: (id: string) => void\n setChatId: (id: string) => void\n addMessage: (message: ChatMessage) => void\n setError: (error: SocketError | null) => void\n setVisitorInfo: (info: VisitorInfo) => void\n reset: () => void\n}\n\nconst initialState: ChatState = {\n status: 'idle',\n role: null,\n visitorId: null,\n chatId: null,\n messages: [],\n error: null,\n visitorInfo: null,\n}\n\nexport const useChatStore = create<ChatState & ChatActions>((set) => ({\n ...initialState,\n\n setStatus: (status) => set({ status }),\n setRole: (role) => set({ role }),\n setVisitorId: (id) => set({ visitorId: id }),\n setChatId: (id) => set({ chatId: id }),\n addMessage: (message) =>\n set((state) => ({\n messages: [...state.messages, message],\n })),\n setError: (error) => set({ error }),\n setVisitorInfo: (info) => set({ visitorInfo: info }),\n reset: () => set(initialState),\n}))","import React, { useEffect, useState } from \"react\";\nimport { css } from \"@emotion/css\";\n\nconst BUTTON_SIZE = 56;\n\ninterface Props {\n isOpen: boolean;\n onToggle: () => void;\n}\n\nexport const FloatingButton: React.FC<Props> = ({ isOpen, onToggle }) => {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const check = () => setIsMobile(window.innerWidth <= 480);\n check();\n window.addEventListener(\"resize\", check);\n return () => window.removeEventListener(\"resize\", check);\n }, []);\n\n if (isMobile && isOpen) {\n return (\n <button\n className={styles.mobileCloseBtn}\n onClick={onToggle}\n type=\"button\"\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n );\n }\n\n return (\n <button className={styles.btn} onClick={onToggle} type=\"button\">\n <span className={styles.icon(!isOpen)}>\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z\" />\n </svg>\n </span>\n <span className={styles.icon(isOpen)}>\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </span>\n </button>\n );\n};\n\nconst styles = {\n btn: css`\n position: fixed;\n right: 30px;\n bottom: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n -webkit-user-select: none;\n &:hover {\n opacity: 0.92;\n }\n `,\n mobileCloseBtn: css`\n position: fixed;\n top: 16px;\n right: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n `,\n icon: (visible: boolean) => css`\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n transition:\n opacity 0.2s,\n transform 0.2s;\n opacity: ${visible ? 1 : 0};\n transform: ${visible ? \"scale(1)\" : \"scale(0.6) rotate(30deg)\"};\n pointer-events: ${visible ? \"auto\" : \"none\"};\n `,\n};\n","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n isOpen: boolean\n isExpanded: boolean\n children: React.ReactNode\n}\n\nexport const ChatPanel: React.FC<Props> = ({ isOpen, isExpanded, children }) => {\n return (\n <div data-wds-root className={styles.panel(isOpen, isExpanded)}>\n <div className={styles.inner}>{children}</div>\n </div>\n )\n}\n\nconst styles = {\n panel: (isOpen: boolean, isExpanded: boolean) => css`\n position: fixed;\n bottom: 86px;\n z-index: 999998;\n transition: opacity 0.2s, transform 0.25s cubic-bezier(0.34, 1.2, 0.64, 1);\n opacity: ${isOpen ? 1 : 0};\n pointer-events: ${isOpen ? 'auto' : 'none'};\n\n ${isExpanded\n ? `\n width: min(760px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 120px));\n border-radius: 20px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.1);\n left: 50%;\n right: auto;\n translate: -50% 0;\n transform: ${isOpen ? 'scale(1)' : 'scale(0.95)'};\n transform-origin: bottom center;\n `\n : `\n width: 400px;\n height: 620px;\n border-radius: 20px;\n box-shadow: 0 12px 48px rgba(0,0,0,0.16), 0 2px 8px rgba(0,0,0,0.08);\n right: 22px;\n transform: ${isOpen ? 'translateY(0) scale(1)' : 'translateY(16px) scale(0.97)'};\n `}\n\n overflow: hidden;\n\n @media (max-width: 480px) {\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n width: 100% !important;\n height: 100% !important;\n border-radius: 0 !important;\n translate: none !important;\n }\n `,\n inner: css`\n width: 100%;\n height: 100%;\n overflow: hidden;\n border-radius: inherit;\n `,\n}","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n onStartChat: () => void\n onContinueChat: () => void\n hasHistory: boolean\n onExpand: () => void\n isExpanded: boolean\n}\n\nexport const HomeScreen: React.FC<Props> = ({\n onStartChat,\n onContinueChat,\n hasHistory,\n onExpand,\n isExpanded,\n}) => {\n return (\n <div className={styles.wrapper}>\n <div className={styles.topBar}>\n <div className={styles.logoMark}>\n <img\n src=\"https://cdn.waysdrop.com/bulk/horizon_20260411202129966_d25edae2.png\"\n alt=\"Waysdrop\"\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n />\n </div>\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/>\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/>\n </svg>\n ) : (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/>\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.hero}>\n <h2 className={styles.heroTitle}>Hi there! ๐Ÿ‘‹</h2>\n <p className={styles.heroSub}>We're here to help. Ask us anything or share your feedback.</p>\n </div>\n\n <div className={styles.section}>\n <p className={styles.sectionLabel}>Conversations</p>\n {hasHistory ? (\n <button className={styles.conversationCard} onClick={onContinueChat}>\n <div className={styles.cardIcon}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n </div>\n <div className={styles.cardBody}>\n <span className={styles.cardTitle}>Continue conversation</span>\n <span className={styles.cardSub}>Tap to resume your last chat</span>\n </div>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n ) : (\n <div className={styles.emptyHistory}>\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ opacity: 0.25 }}>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n <p>No previous conversations</p>\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button className={styles.startBtn} onClick={onStartChat}>\n New conversation\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n <p className={styles.poweredBy}>Powered by Waysdrop</p>\n </div>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n text-align: left;\n `,\n topBar: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 18px 18px 0;\n flex-shrink: 0;\n `,\n logoMark: css`\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n hero: css`\n padding: 20px 20px 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n `,\n heroTitle: css`\n font-size: 1.375rem;\n font-weight: 700;\n color: var(--wds-fg);\n margin: 0;\n line-height: 1.2;\n text-align: left;\n `,\n heroSub: css`\n font-size: 0.9375rem;\n color: var(--wds-muted);\n margin: 0;\n line-height: 1.6;\n text-align: left;\n `,\n section: css`\n flex: 1;\n padding: 4px 18px 0;\n overflow-y: auto;\n `,\n sectionLabel: css`\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.07em;\n text-transform: uppercase;\n color: var(--wds-muted);\n margin: 0 0 12px 2px;\n text-align: left;\n `,\n conversationCard: css`\n display: flex;\n align-items: center;\n gap: 14px;\n width: 100%;\n padding: 14px 16px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n cursor: pointer;\n text-align: left;\n transition: border-color 0.15s, background 0.15s;\n color: var(--wds-fg);\n &:hover {\n border-color: var(--wds-primary);\n background: var(--wds-primary-soft);\n }\n `,\n cardIcon: css`\n width: 38px;\n height: 38px;\n border-radius: 10px;\n background: var(--wds-primary-soft);\n color: var(--wds-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n `,\n cardBody: css`\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 3px;\n `,\n cardTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n text-align: left;\n `,\n cardSub: css`\n font-size: 12px;\n color: var(--wds-muted);\n text-align: left;\n `,\n emptyHistory: css`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n padding: 40px 0;\n color: var(--wds-muted);\n font-size: 12px;\n `,\n footer: css`\n padding: 18px 18px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n flex-shrink: 0;\n border-top: 1px solid var(--wds-border);\n `,\n startBtn: css`\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n width: 100%;\n padding: 13px 16px;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n border-radius: 14px;\n font-size: 0.9375rem;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.15s;\n font-family: inherit;\n &:hover { opacity: 0.88; }\n `,\n poweredBy: css`\n font-size: 11px;\n color: var(--wds-muted);\n margin: 0;\n opacity: 0.7;\n `,\n}","import React, { useEffect, useRef, useState } from 'react'\nimport { css, keyframes } from '@emotion/css'\nimport { ChatMessage } from '../types'\nimport { MessageBubble } from './MessageBubble'\nimport { ChatInput } from './ChatInput'\n\ninterface Props {\n messages: ChatMessage[]\n onSendText: (content: string) => void\n onSendFile: (file: File) => Promise<void>\n onBack: () => void\n onExpand: () => void\n isExpanded: boolean\n status: string\n error: { code: number; message: string } | null\n}\n\nexport const ChatScreen: React.FC<Props> = ({\n messages,\n onSendText,\n onSendFile,\n onBack,\n onExpand,\n isExpanded,\n status,\n error,\n}) => {\n const bottomRef = useRef<HTMLDivElement>(null)\n const scrollRef = useRef<HTMLDivElement>(null)\n const connected = status === 'connected'\n const [showScrollBtn, setShowScrollBtn] = useState(false)\n\n const lastMsg = messages[messages.length - 1]\n const isThinking = connected && lastMsg?.direction === 'INBOUND'\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' })\n }, [messages])\n\n const handleScroll = () => {\n const el = scrollRef.current\n if (!el) return\n setShowScrollBtn(el.scrollHeight - el.scrollTop - el.clientHeight > 80)\n }\n\n return (\n <div className={styles.wrapper}>\n <div className={styles.header}>\n <button className={styles.iconBtn} onClick={onBack}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\"/>\n </svg>\n </button>\n\n <div className={styles.headerCenter}>\n <span className={styles.headerTitle}>Support</span>\n <span className={styles.statusDot(connected)} />\n <span className={styles.statusLabel}>{connected ? 'Online' : 'Connecting...'}</span>\n </div>\n\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/>\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/>\n </svg>\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/>\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.messagesWrap}>\n <div className={styles.messages} ref={scrollRef} onScroll={handleScroll}>\n {error && <div className={styles.errorBanner}>{error.message}</div>}\n {messages.length === 0 && connected && (\n <div className={styles.emptyState}>\n <p>Send a message to start the conversation.</p>\n </div>\n )}\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n <div ref={bottomRef} />\n </div>\n\n {showScrollBtn && (\n <button className={styles.scrollBtn} onClick={() => bottomRef.current?.scrollIntoView({ behavior: 'smooth' })}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"/>\n </svg>\n </button>\n )}\n </div>\n\n <ChatInput\n onSendText={onSendText}\n onSendFile={onSendFile}\n disabled={!connected}\n isThinking={isThinking}\n />\n </div>\n )\n}\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n`\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n `,\n header: css`\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n border-bottom: 1px solid var(--wds-border);\n flex-shrink: 0;\n `,\n headerCenter: css`\n flex: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n `,\n headerTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n `,\n statusDot: (connected: boolean) => css`\n width: 7px;\n height: 7px;\n border-radius: 50%;\n flex-shrink: 0;\n background: ${connected ? '#22c55e' : '#f59e0b'};\n animation: ${connected ? 'none' : `${pulse} 1.2s ease-in-out infinite`};\n `,\n statusLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n iconBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n messagesWrap: css`\n flex: 1;\n position: relative;\n overflow: hidden;\n `,\n messages: css`\n position: absolute;\n inset: 0;\n overflow-y: auto;\n padding: 16px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n `,\n errorBanner: css`\n background: oklch(0.9705 0.0129 17.04);\n color: oklch(0.5054 0.1905 27.51);\n border: 1px solid oklch(0.8845 0.0592 18.27);\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 12px;\n text-align: center;\n `,\n emptyState: css`\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--wds-muted);\n font-size: 13px;\n text-align: center;\n padding: 40px 20px;\n `,\n scrollBtn: css`\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: var(--wds-bg);\n border: 1px solid var(--wds-border);\n color: var(--wds-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n transition: color 0.15s, border-color 0.15s;\n &:hover {\n color: var(--wds-primary);\n border-color: var(--wds-primary);\n }\n `,\n}","import React from 'react'\nimport { css } from '@emotion/css'\nimport { ChatMessage } from '../types'\nimport { MarkdownRenderer } from './MarkdownRenderer'\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\ninterface Props {\n message: ChatMessage\n}\n\nexport const MessageBubble: React.FC<Props> = ({ message }) => {\n const isCustomer = message.direction === 'OUTBOUND'\n const isBot = message.senderRole === 'BOT'\n\n return (\n <div className={styles.row(isCustomer)}>\n <div className={styles.group(isCustomer)}>\n {isBot && <span className={styles.botLabel}>Ways AI</span>}\n <div className={styles.bubble(isCustomer)}>\n {message.file && (\n <a href={message.file} target=\"_blank\" rel=\"noreferrer\" className={styles.fileLink}>\n ๐Ÿ“Ž View attachment\n </a>\n )}\n {message.content && (\n isBot\n ? <MarkdownRenderer content={message.content} />\n : <p className={styles.text}>{message.content}</p>\n )}\n </div>\n <span className={styles.time}>{formatTime(message.createdAt)}</span>\n </div>\n </div>\n )\n}\n\nconst styles = {\n row: (isCustomer: boolean) => css`\n display: flex;\n width: 100%;\n justify-content: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n group: (isCustomer: boolean) => css`\n display: flex;\n flex-direction: column;\n max-width: 78%;\n gap: 4px;\n align-items: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n botLabel: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n font-weight: 500;\n letter-spacing: 0.03em;\n `,\n bubble: (isCustomer: boolean) => css`\n border-radius: 18px;\n padding: 10px 14px;\n word-break: break-word;\n text-align: left;\n border-top-left-radius: ${isCustomer ? '4px' : '18px'};\n border-top-right-radius: ${isCustomer ? '18px' : '4px'};\n background: ${isCustomer ? 'var(--wds-muted-bg)' : 'var(--wds-primary)'};\n color: ${isCustomer ? 'var(--wds-fg)' : '#fff'};\n `,\n text: css`\n font-size: 0.875rem;\n line-height: 1.5;\n margin: 0;\n white-space: pre-wrap;\n text-align: left;\n `,\n fileLink: css`\n font-size: 0.875rem;\n color: inherit;\n text-decoration: underline;\n display: block;\n text-align: left;\n `,\n time: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n `,\n}","import React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport { css } from '@emotion/css'\n\nconst markdownStyle = css`\n font-size: 0.875rem;\n line-height: 1.6;\n color: inherit;\n text-align: left;\n\n p {\n margin: 0 0 0.6rem 0;\n text-align: left;\n }\n p:last-child {\n margin-bottom: 0;\n }\n strong { font-weight: 600; }\n em { font-style: italic; }\n\n ul, ol {\n margin: 0.4rem 0 0.6rem 0;\n padding-left: 1.4rem;\n text-align: left;\n }\n ul { list-style-type: disc; }\n ol { list-style-type: decimal; }\n li {\n margin-bottom: 0.3rem;\n }\n li > ul, li > ol {\n margin: 0.25rem 0 0.25rem 0;\n padding-left: 1.2rem;\n }\n li:last-child { margin-bottom: 0; }\n\n hr {\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.25);\n margin: 0.75rem 0;\n }\n\n code {\n font-family: monospace;\n font-size: 0.8rem;\n background: rgba(255,255,255,0.15);\n border-radius: 4px;\n padding: 0.1rem 0.35rem;\n }\n pre {\n background: rgba(255,255,255,0.1);\n border-radius: 8px;\n padding: 0.75rem 1rem;\n overflow-x: auto;\n margin: 0.5rem 0;\n }\n pre code {\n background: none;\n padding: 0;\n font-size: 0.78rem;\n }\n blockquote {\n border-left: 3px solid rgba(255,255,255,0.25);\n margin: 0.5rem 0;\n padding-left: 0.75rem;\n opacity: 0.8;\n }\n a {\n color: rgba(255,255,255,0.85);\n text-decoration: underline;\n }\n h1, h2, h3 {\n font-weight: 600;\n margin: 0.6rem 0 0.3rem;\n line-height: 1.3;\n text-align: left;\n }\n h1 { font-size: 1rem; }\n h2 { font-size: 0.95rem; }\n h3 { font-size: 0.875rem; }\n`\n\ninterface Props {\n content: string\n}\n\nexport const MarkdownRenderer: React.FC<Props> = ({ content }) => {\n return (\n <div className={markdownStyle}>\n <ReactMarkdown>{content}</ReactMarkdown>\n </div>\n )\n}","import React, { useState, useRef, useCallback, KeyboardEvent } from 'react'\nimport { css, keyframes } from '@emotion/css'\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 0.4; transform: scaleY(0.6); }\n 50% { opacity: 1; transform: scaleY(1); }\n`\n\ninterface Props {\n onSendText: (content: string) => void\n onSendFile: (file: File) => Promise<void>\n disabled?: boolean\n isThinking?: boolean\n}\n\nexport const ChatInput: React.FC<Props> = ({ onSendText, onSendFile, disabled, isThinking }) => {\n const [value, setValue] = useState('')\n const [uploading, setUploading] = useState(false)\n const [pendingFile, setPendingFile] = useState<File | null>(null)\n const [pendingPreview, setPendingPreview] = useState<string | null>(null)\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n const handleSend = useCallback(() => {\n const trimmed = value.trim()\n if ((!trimmed && !pendingFile) || disabled || uploading) return\n\n if (pendingFile) {\n setUploading(true)\n onSendFile(pendingFile).finally(() => {\n setUploading(false)\n setPendingFile(null)\n setPendingPreview(null)\n })\n }\n\n if (trimmed) {\n onSendText(trimmed)\n setValue('')\n }\n\n textareaRef.current?.focus()\n }, [value, pendingFile, disabled, uploading, onSendText, onSendFile])\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSend()\n }\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file) return\n if (!file.type.startsWith('image/')) return\n setPendingFile(file)\n const reader = new FileReader()\n reader.onload = (ev) => setPendingPreview(ev.target?.result as string)\n reader.readAsDataURL(file)\n e.target.value = ''\n }\n\n const canSend = (value.trim() || pendingFile) && !disabled && !uploading\n\n return (\n <div className={styles.wrapper}>\n {isThinking && (\n <div className={styles.thinkingBar}>\n <div className={styles.thinkingDots}>\n <span className={styles.dot(0)} />\n <span className={styles.dot(1)} />\n <span className={styles.dot(2)} />\n </div>\n <span className={styles.thinkingLabel}>Ways AI is typing...</span>\n </div>\n )}\n\n {pendingPreview && (\n <div className={styles.imagePreview}>\n <img src={pendingPreview} alt=\"attachment\" className={styles.previewImg} />\n <button className={styles.removeFile} onClick={() => { setPendingFile(null); setPendingPreview(null) }}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n )}\n\n <div className={styles.inputRow}>\n <button\n className={styles.attachBtn}\n onClick={() => fileInputRef.current?.click()}\n disabled={disabled || uploading}\n type=\"button\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"3\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/>\n </svg>\n </button>\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className={styles.hiddenInput}\n onChange={handleFileChange}\n />\n\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a message...\"\n disabled={disabled || uploading}\n rows={1}\n />\n\n <button className={styles.sendBtn} onClick={handleSend} disabled={!canSend} type=\"button\">\n {uploading ? (\n <span className={styles.spinner} />\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"5\"/><polyline points=\"5 12 12 5 19 12\"/>\n </svg>\n )}\n </button>\n </div>\n\n <p className={styles.hint}>Enter to send ยท Shift+Enter for new line</p>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n padding: 8px 12px 10px;\n border-top: 1px solid var(--wds-border);\n display: flex;\n flex-direction: column;\n gap: 6px;\n background: var(--wds-bg);\n flex-shrink: 0;\n `,\n thinkingBar: css`\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 2px 2px;\n `,\n thinkingDots: css`\n display: flex;\n align-items: center;\n gap: 3px;\n `,\n dot: (i: number) => css`\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--wds-primary);\n animation: ${pulse} 1.2s ease-in-out infinite;\n animation-delay: ${i * 0.18}s;\n display: inline-block;\n `,\n thinkingLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n imagePreview: css`\n position: relative;\n width: fit-content;\n margin: 0 2px;\n `,\n previewImg: css`\n width: 72px;\n height: 72px;\n object-fit: cover;\n border-radius: 10px;\n border: 1px solid var(--wds-border);\n display: block;\n `,\n removeFile: css`\n position: absolute;\n top: -6px;\n right: -6px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--wds-fg);\n color: var(--wds-bg);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n `,\n inputRow: css`\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n padding: 4px 4px 4px 8px;\n transition: border-color 0.15s;\n &:focus-within {\n border-color: var(--wds-primary);\n background: var(--wds-bg);\n }\n `,\n attachBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 5px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s;\n &:hover:not(:disabled) {\n color: var(--wds-primary);\n }\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n `,\n hiddenInput: css`\n display: none;\n `,\n textarea: css`\n flex: 1;\n resize: none;\n border: none;\n padding: 6px 0;\n font-size: 0.875rem;\n font-family: inherit;\n line-height: 1.5;\n background: transparent;\n color: var(--wds-fg);\n outline: none;\n max-height: 120px;\n overflow-y: auto;\n &::placeholder { color: var(--wds-muted); }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n `,\n sendBtn: css`\n background: var(--wds-primary);\n border: none;\n border-radius: 10px;\n width: 34px;\n height: 34px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n color: #fff;\n flex-shrink: 0;\n transition: opacity 0.15s;\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n &:hover:not(:disabled) { opacity: 0.85; }\n `,\n spinner: css`\n width: 14px;\n height: 14px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: ${spin} 0.7s linear infinite;\n display: block;\n `,\n hint: css`\n font-size: 10px;\n color: var(--wds-muted);\n margin: 0;\n text-align: center;\n opacity: 0.7;\n text-align: center;\n `,\n}"],"mappings":"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","names":["import_react","import_css","socket","import_react","import_css","import_jsx_runtime","styles","import_css","import_jsx_runtime","styles","import_react","import_css","import_css","import_css","import_jsx_runtime","ReactMarkdown","import_jsx_runtime","styles","import_react","import_css","import_jsx_runtime","_a","styles","import_jsx_runtime","styles","pulse","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/ChatWidget.tsx","../src/lib/upload.ts","../src/hooks/useChat.ts","../src/lib/socket.ts","../src/store/chatStore.ts","../src/components/FloatingButton.tsx","../src/components/ChatPanel.tsx","../src/components/HomeScreen.tsx","../src/components/ChatScreen.tsx","../src/components/MessageBubble.tsx","../src/components/MarkdownRenderer.tsx","../src/components/ChatInput.tsx"],"sourcesContent":["export { ChatWidget } from './components/ChatWidget'\nexport type { ChatWidgetProps } from './components/ChatWidget'\nexport { useChat } from './hooks/useChat'\nexport { useChatStore } from './store/chatStore'\nexport { loadVisitorId, saveVisitorId, clearVisitorId } from './lib/upload'\nexport * from './types'","import React, { useEffect, useState } from 'react'\nimport { injectGlobal } from '@emotion/css'\nimport { ChatConfig } from '../types'\nimport { loadVisitorId } from '../lib/upload'\nimport { useChat } from '../hooks/useChat'\nimport { useChatStore } from '../store/chatStore'\nimport { FloatingButton } from './FloatingButton'\nimport { ChatPanel } from './ChatPanel'\nimport { HomeScreen } from './HomeScreen'\nimport { ChatScreen } from './ChatScreen'\n\nexport type ChatWidgetProps = {\n config: ChatConfig\n}\n\ntype View = 'home' | 'chat'\n\nexport const ChatWidget: React.FC<ChatWidgetProps> = ({ config }) => {\n const [isOpen, setIsOpen] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n const [view, setView] = useState<View>('home')\n\n const reset = useChatStore((s) => s.reset)\n\n const resolvedConfig: ChatConfig = {\n ...config,\n visitorId: config.visitorId ?? loadVisitorId() ?? undefined,\n }\n\n const hasHistory = !!resolvedConfig.visitorId\n\n const { status, messages, error, sendMessage, sendFile } = useChat(resolvedConfig)\n\n const handleNewConversation = () => {\n reset()\n setView('chat')\n }\n\n useEffect(() => {\n const isMobile = window.innerWidth <= 480\n if (isMobile) {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n }\n return () => {\n document.body.style.overflow = ''\n }\n }, [isOpen])\n\n return (\n <>\n <FloatingButton\n isOpen={isOpen}\n onToggle={() => setIsOpen((p) => !p)}\n />\n\n <ChatPanel\n isOpen={isOpen}\n isExpanded={isExpanded}\n >\n {view === 'home' ? (\n <HomeScreen\n onStartChat={handleNewConversation}\n onContinueChat={() => setView('chat')}\n hasHistory={hasHistory}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n />\n ) : (\n <ChatScreen\n messages={messages}\n onSendText={sendMessage}\n onSendFile={sendFile}\n onBack={() => setView('home')}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n status={status}\n error={error}\n />\n )}\n </ChatPanel>\n </>\n )\n}\n\ninjectGlobal`\n :root {\n --wds-primary: oklch(0.5811 0.2268 259.15);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.12);\n --wds-primary-border: oklch(0.7695 0.1177 255.22 / 0.4);\n --wds-bg: oklch(1 0 0);\n --wds-fg: oklch(0.145 0 0);\n --wds-muted: oklch(0.556 0 0);\n --wds-muted-bg: oklch(0.97 0 0);\n --wds-border: oklch(0.922 0 0);\n }\n\n @media (prefers-color-scheme: dark) {\n :root {\n --wds-bg: oklch(0.145 0 0);\n --wds-fg: oklch(0.985 0 0);\n --wds-muted: oklch(0.708 0 0);\n --wds-muted-bg: oklch(0.205 0 0);\n --wds-border: oklch(1 0 0 / 10%);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.15);\n }\n }\n\n [data-wds-root] * {\n box-sizing: border-box;\n text-align: left;\n }\n`","import type { ChatConfig } from \"../types\";\n\nconst VISITOR_ID_KEY = \"waysdrop_visitor_id\";\n\nexport const saveVisitorId = (id: string): void => {\n localStorage.setItem(VISITOR_ID_KEY, id);\n};\n\nexport const loadVisitorId = (): string | null => {\n return localStorage.getItem(VISITOR_ID_KEY);\n};\n\nexport const clearVisitorId = (): void => {\n localStorage.removeItem(VISITOR_ID_KEY);\n};\n\nexport const uploadFile = async (\n file: File,\n config: ChatConfig,\n): Promise<string> => {\n const formData = new FormData();\n formData.append(\"files\", file);\n\n const headers: HeadersInit = {};\n if (config.token) headers[\"Authorization\"] = `Bearer ${config.token}`;\n\n const res = await fetch(`${config.apiUrl}/file/bulk-upload`, {\n method: \"POST\",\n headers,\n body: formData,\n });\n\n if (!res.ok) {\n throw new Error(\"File upload failed\");\n }\n\n const json = await res.json();\n\n if (!json.success || !json.data?.urls?.length) {\n throw new Error(json.message || \"File upload failed\");\n }\n\n const first = json.data.urls[0];\n if (typeof first !== \"string\") {\n throw new Error(first?.error || \"File upload failed\");\n }\n\n return first;\n};","import { useEffect, useCallback } from 'react'\nimport { getSocket, destroySocket } from '../lib/socket'\nimport { saveVisitorId, uploadFile } from '../lib/upload'\nimport { useChatStore } from '../store/chatStore'\nimport type {\n ChatConfig,\n ConnectedPayload,\n SupportMessageSentPayload,\n SupportNewMessagePayload,\n SocketError,\n SupportSendMessageDTO,\n VisitorInfo,\n} from '../types'\n\nexport const useChat = (config: ChatConfig) => {\n const {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setStatus,\n setRole,\n setVisitorId,\n setChatId,\n addMessage,\n setError,\n setVisitorInfo,\n reset,\n } = useChatStore()\n\n\n useEffect(() => {\n const socket = getSocket(config)\n\n setStatus('connecting')\n socket.connect()\n\n socket.on('connected', (payload: ConnectedPayload) => {\n setStatus('connected')\n setRole(payload.role)\n\n if (payload.role === 'VISITOR') {\n saveVisitorId(payload.visitorId)\n setVisitorId(payload.visitorId)\n }\n })\n\n socket.on('support-message-sent', (payload: SupportMessageSentPayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('support-new-message', (payload: SupportNewMessagePayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('error', (err: SocketError) => {\n setError(err)\n setStatus('error')\n })\n\n return () => {\n destroySocket()\n reset()\n }\n }, [])\n\n\n const sendMessage = useCallback(\n (content: string, info?: VisitorInfo) => {\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n content,\n externalId: `msg-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n\n const sendFile = useCallback(\n async (file: File, content?: string, info?: VisitorInfo) => {\n const url = await uploadFile(file, config)\n\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n file: url,\n ...(content ? { content } : {}),\n externalId: `file-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n return {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setVisitorInfo,\n sendMessage,\n sendFile,\n }\n}","import { io, Socket } from 'socket.io-client'\nimport type { ChatConfig } from '../types'\n\nlet socket: Socket | null = null\n\nexport const getSocket = (config: ChatConfig): Socket => {\n if (socket) return socket\n\n const { serverUrl, token, visitorId } = config\n\n socket = io(serverUrl, {\n transports: ['websocket', 'polling'],\n auth: {\n ...(token ? { token } : {}),\n ...(visitorId ? { visitorId } : {}),\n },\n autoConnect: false,\n })\n\n return socket\n}\n\nexport const destroySocket = (): void => {\n if (socket) {\n socket.disconnect()\n socket = null\n }\n}","import { create } from 'zustand'\nimport type {\n ChatState,\n ChatMessage,\n UserRole,\n SocketError,\n VisitorInfo,\n ConnectionStatus,\n} from '../types'\n\ntype ChatActions = {\n setStatus: (status: ConnectionStatus) => void\n setRole: (role: UserRole) => void\n setVisitorId: (id: string) => void\n setChatId: (id: string) => void\n addMessage: (message: ChatMessage) => void\n setError: (error: SocketError | null) => void\n setVisitorInfo: (info: VisitorInfo) => void\n reset: () => void\n}\n\nconst initialState: ChatState = {\n status: 'idle',\n role: null,\n visitorId: null,\n chatId: null,\n messages: [],\n error: null,\n visitorInfo: null,\n}\n\nexport const useChatStore = create<ChatState & ChatActions>((set) => ({\n ...initialState,\n\n setStatus: (status) => set({ status }),\n setRole: (role) => set({ role }),\n setVisitorId: (id) => set({ visitorId: id }),\n setChatId: (id) => set({ chatId: id }),\n addMessage: (message) =>\n set((state) => ({\n messages: [...state.messages, message],\n })),\n setError: (error) => set({ error }),\n setVisitorInfo: (info) => set({ visitorInfo: info }),\n reset: () => set(initialState),\n}))","import React, { useEffect, useState } from \"react\";\nimport { css } from \"@emotion/css\";\n\nconst BUTTON_SIZE = 56;\n\ninterface Props {\n isOpen: boolean;\n onToggle: () => void;\n}\n\nexport const FloatingButton: React.FC<Props> = ({ isOpen, onToggle }) => {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const check = () => setIsMobile(window.innerWidth <= 480);\n check();\n window.addEventListener(\"resize\", check);\n return () => window.removeEventListener(\"resize\", check);\n }, []);\n\n if (isMobile && isOpen) {\n return (\n <button\n className={styles.mobileCloseBtn}\n onClick={onToggle}\n type=\"button\"\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n );\n }\n\n return (\n <button className={styles.btn} onClick={onToggle} type=\"button\">\n <span className={styles.icon(!isOpen)}>\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z\" />\n </svg>\n </span>\n <span className={styles.icon(isOpen)}>\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </span>\n </button>\n );\n};\n\nconst styles = {\n btn: css`\n position: fixed;\n right: 30px;\n bottom: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n -webkit-user-select: none;\n &:hover {\n opacity: 0.92;\n }\n `,\n mobileCloseBtn: css`\n position: fixed;\n top: 16px;\n right: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n `,\n icon: (visible: boolean) => css`\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n transition:\n opacity 0.2s,\n transform 0.2s;\n opacity: ${visible ? 1 : 0};\n transform: ${visible ? \"scale(1)\" : \"scale(0.6) rotate(30deg)\"};\n pointer-events: ${visible ? \"auto\" : \"none\"};\n `,\n};\n","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n isOpen: boolean\n isExpanded: boolean\n children: React.ReactNode\n}\n\nexport const ChatPanel: React.FC<Props> = ({ isOpen, isExpanded, children }) => {\n return (\n <div data-wds-root className={styles.panel(isOpen, isExpanded)}>\n <div className={styles.inner}>{children}</div>\n </div>\n )\n}\n\nconst styles = {\n panel: (isOpen: boolean, isExpanded: boolean) => css`\n position: fixed;\n bottom: 86px;\n z-index: 999998;\n transition: opacity 0.2s, transform 0.25s cubic-bezier(0.34, 1.2, 0.64, 1);\n opacity: ${isOpen ? 1 : 0};\n pointer-events: ${isOpen ? 'auto' : 'none'};\n\n ${isExpanded\n ? `\n width: min(760px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 120px));\n border-radius: 20px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.1);\n left: 50%;\n right: auto;\n translate: -50% 0;\n transform: ${isOpen ? 'scale(1)' : 'scale(0.95)'};\n transform-origin: bottom center;\n `\n : `\n width: 400px;\n height: 620px;\n border-radius: 20px;\n box-shadow: 0 12px 48px rgba(0,0,0,0.16), 0 2px 8px rgba(0,0,0,0.08);\n right: 22px;\n transform: ${isOpen ? 'translateY(0) scale(1)' : 'translateY(16px) scale(0.97)'};\n `}\n\n overflow: hidden;\n\n @media (max-width: 480px) {\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n width: 100% !important;\n height: 100% !important;\n border-radius: 0 !important;\n translate: none !important;\n }\n `,\n inner: css`\n width: 100%;\n height: 100%;\n overflow: hidden;\n border-radius: inherit;\n `,\n}","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n onStartChat: () => void\n onContinueChat: () => void\n hasHistory: boolean\n onExpand: () => void\n isExpanded: boolean\n}\n\nexport const HomeScreen: React.FC<Props> = ({\n onStartChat,\n onContinueChat,\n hasHistory,\n onExpand,\n isExpanded,\n}) => {\n return (\n <div className={styles.wrapper}>\n <div className={styles.topBar}>\n <div className={styles.logoMark}>\n <img\n src=\"https://cdn.waysdrop.com/bulk/horizon_20260411202129966_d25edae2.png\"\n alt=\"Waysdrop\"\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n />\n </div>\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/>\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/>\n </svg>\n ) : (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/>\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.hero}>\n <h2 className={styles.heroTitle}>Hi there! ๐Ÿ‘‹</h2>\n <p className={styles.heroSub}>We're here to help. Ask us anything or share your feedback.</p>\n </div>\n\n <div className={styles.section}>\n <p className={styles.sectionLabel}>Conversations</p>\n {hasHistory ? (\n <button className={styles.conversationCard} onClick={onContinueChat}>\n <div className={styles.cardIcon}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n </div>\n <div className={styles.cardBody}>\n <span className={styles.cardTitle}>Continue conversation</span>\n <span className={styles.cardSub}>Tap to resume your last chat</span>\n </div>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n ) : (\n <div className={styles.emptyHistory}>\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ opacity: 0.25 }}>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n <p>No previous conversations</p>\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button className={styles.startBtn} onClick={onStartChat}>\n New conversation\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n <p className={styles.poweredBy}>Powered by Waysdrop</p>\n </div>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n text-align: left;\n `,\n topBar: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 18px 18px 0;\n flex-shrink: 0;\n `,\n logoMark: css`\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n hero: css`\n padding: 20px 20px 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n `,\n heroTitle: css`\n font-size: 1.375rem;\n font-weight: 700;\n color: var(--wds-fg);\n margin: 0;\n line-height: 1.2;\n text-align: left;\n `,\n heroSub: css`\n font-size: 0.9375rem;\n color: var(--wds-muted);\n margin: 0;\n line-height: 1.6;\n text-align: left;\n `,\n section: css`\n flex: 1;\n padding: 4px 18px 0;\n overflow-y: auto;\n `,\n sectionLabel: css`\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.07em;\n text-transform: uppercase;\n color: var(--wds-muted);\n margin: 0 0 12px 2px;\n text-align: left;\n `,\n conversationCard: css`\n display: flex;\n align-items: center;\n gap: 14px;\n width: 100%;\n padding: 14px 16px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n cursor: pointer;\n text-align: left;\n transition: border-color 0.15s, background 0.15s;\n color: var(--wds-fg);\n &:hover {\n border-color: var(--wds-primary);\n background: var(--wds-primary-soft);\n }\n `,\n cardIcon: css`\n width: 38px;\n height: 38px;\n border-radius: 10px;\n background: var(--wds-primary-soft);\n color: var(--wds-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n `,\n cardBody: css`\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 3px;\n `,\n cardTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n text-align: left;\n `,\n cardSub: css`\n font-size: 12px;\n color: var(--wds-muted);\n text-align: left;\n `,\n emptyHistory: css`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n padding: 40px 0;\n color: var(--wds-muted);\n font-size: 12px;\n `,\n footer: css`\n padding: 18px 18px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n flex-shrink: 0;\n border-top: 1px solid var(--wds-border);\n `,\n startBtn: css`\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n width: 100%;\n padding: 13px 16px;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n border-radius: 14px;\n font-size: 0.9375rem;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.15s;\n font-family: inherit;\n &:hover { opacity: 0.88; }\n `,\n poweredBy: css`\n font-size: 11px;\n color: var(--wds-muted);\n margin: 0;\n opacity: 0.7;\n `,\n}","import React, { useEffect, useRef, useState } from \"react\";\nimport { css, keyframes } from \"@emotion/css\";\nimport { ChatMessage } from \"../types\";\nimport { MessageBubble } from \"./MessageBubble\";\nimport { ChatInput } from \"./ChatInput\";\n\ninterface Props {\n messages: ChatMessage[];\n onSendText: (content: string) => void;\n onSendFile: (file: File, content?: string) => Promise<void>;\n onBack: () => void;\n onExpand: () => void;\n isExpanded: boolean;\n status: string;\n error: { code: number; message: string } | null;\n}\n\nexport const ChatScreen: React.FC<Props> = ({\n messages,\n onSendText,\n onSendFile,\n onBack,\n onExpand,\n isExpanded,\n status,\n error,\n}) => {\n const bottomRef = useRef<HTMLDivElement>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const connected = status === \"connected\";\n const [showScrollBtn, setShowScrollBtn] = useState(false);\n\n const lastMsg = messages[messages.length - 1];\n const isThinking = connected && lastMsg?.direction === \"INBOUND\";\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n const handleScroll = () => {\n const el = scrollRef.current;\n if (!el) return;\n setShowScrollBtn(el.scrollHeight - el.scrollTop - el.clientHeight > 80);\n };\n\n return (\n <div className={styles.wrapper}>\n <div className={styles.header}>\n <button className={styles.iconBtn} onClick={onBack}>\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n\n <div className={styles.headerCenter}>\n <span className={styles.headerTitle}>Support</span>\n <span className={styles.statusDot(connected)} />\n <span className={styles.statusLabel}>\n {connected ? \"Online\" : \"Connecting...\"}\n </span>\n </div>\n\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"4 14 10 14 10 20\" />\n <polyline points=\"20 10 14 10 14 4\" />\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n </svg>\n ) : (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.messagesWrap}>\n <div\n className={styles.messages}\n ref={scrollRef}\n onScroll={handleScroll}\n >\n {error && <div className={styles.errorBanner}>{error.message}</div>}\n {messages.length === 0 && connected && (\n <div className={styles.emptyState}>\n <p>Send a message to start the conversation.</p>\n </div>\n )}\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n <div ref={bottomRef} />\n </div>\n\n {showScrollBtn && (\n <button\n className={styles.scrollBtn}\n onClick={() =>\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" })\n }\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n )}\n </div>\n\n <ChatInput\n onSendText={onSendText}\n onSendFile={onSendFile}\n disabled={!connected}\n isThinking={isThinking}\n />\n </div>\n );\n};\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n`;\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n `,\n header: css`\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n border-bottom: 1px solid var(--wds-border);\n flex-shrink: 0;\n `,\n headerCenter: css`\n flex: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n `,\n headerTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n `,\n statusDot: (connected: boolean) => css`\n width: 7px;\n height: 7px;\n border-radius: 50%;\n flex-shrink: 0;\n background: ${connected ? \"#22c55e\" : \"#f59e0b\"};\n animation: ${connected ? \"none\" : `${pulse} 1.2s ease-in-out infinite`};\n `,\n statusLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n iconBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition:\n color 0.15s,\n background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition:\n color 0.15s,\n background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n messagesWrap: css`\n flex: 1;\n position: relative;\n overflow: hidden;\n `,\n messages: css`\n position: absolute;\n inset: 0;\n overflow-y: auto;\n padding: 16px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n `,\n errorBanner: css`\n background: oklch(0.9705 0.0129 17.04);\n color: oklch(0.5054 0.1905 27.51);\n border: 1px solid oklch(0.8845 0.0592 18.27);\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 12px;\n text-align: center;\n `,\n emptyState: css`\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--wds-muted);\n font-size: 13px;\n text-align: center;\n padding: 40px 20px;\n `,\n scrollBtn: css`\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: var(--wds-bg);\n border: 1px solid var(--wds-border);\n color: var(--wds-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n transition:\n color 0.15s,\n border-color 0.15s;\n &:hover {\n color: var(--wds-primary);\n border-color: var(--wds-primary);\n }\n `,\n};\n","import React from 'react'\nimport { css } from '@emotion/css'\nimport { ChatMessage } from '../types'\nimport { MarkdownRenderer } from './MarkdownRenderer'\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\ninterface Props {\n message: ChatMessage\n}\n\nexport const MessageBubble: React.FC<Props> = ({ message }) => {\n const isCustomer = message.direction === 'OUTBOUND'\n const isBot = message.senderRole === 'BOT'\n\n return (\n <div className={styles.row(isCustomer)}>\n <div className={styles.group(isCustomer)}>\n {isBot && <span className={styles.botLabel}>Ways AI</span>}\n <div className={styles.bubble(isCustomer)}>\n {message.file && (\n <a href={message.file} target=\"_blank\" rel=\"noreferrer\" className={styles.fileLink(!!message.content)}>\n ๐Ÿ“Ž View attachment\n </a>\n )}\n {message.content && (\n isBot\n ? <MarkdownRenderer content={message.content} />\n : <p className={styles.text}>{message.content}</p>\n )}\n </div>\n <span className={styles.time}>{formatTime(message.createdAt)}</span>\n </div>\n </div>\n )\n}\n\nconst styles = {\n row: (isCustomer: boolean) => css`\n display: flex;\n width: 100%;\n justify-content: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n group: (isCustomer: boolean) => css`\n display: flex;\n flex-direction: column;\n max-width: 78%;\n gap: 4px;\n align-items: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n botLabel: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n font-weight: 500;\n letter-spacing: 0.03em;\n `,\n bubble: (isCustomer: boolean) => css`\n border-radius: 18px;\n padding: 10px 14px;\n word-break: break-word;\n text-align: left;\n border-top-left-radius: ${isCustomer ? '4px' : '18px'};\n border-top-right-radius: ${isCustomer ? '18px' : '4px'};\n background: ${isCustomer ? 'var(--wds-muted-bg)' : 'var(--wds-primary)'};\n color: ${isCustomer ? 'var(--wds-fg)' : '#fff'};\n `,\n text: css`\n font-size: 0.875rem;\n line-height: 1.5;\n margin: 0;\n white-space: pre-wrap;\n text-align: left;\n `,\n fileLink: (hasContent: boolean) => css`\n font-size: 0.875rem;\n color: inherit;\n text-decoration: underline;\n display: block;\n text-align: left;\n ${hasContent ? 'margin-bottom: 6px;' : ''}\n `,\n time: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n `,\n}","import React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport { css } from '@emotion/css'\n\nconst markdownStyle = css`\n font-size: 0.875rem;\n line-height: 1.6;\n color: inherit;\n text-align: left;\n\n p {\n margin: 0 0 0.6rem 0;\n text-align: left;\n }\n p:last-child {\n margin-bottom: 0;\n }\n strong { font-weight: 600; }\n em { font-style: italic; }\n\n ul, ol {\n margin: 0.4rem 0 0.6rem 0;\n padding-left: 1.4rem;\n text-align: left;\n }\n ul { list-style-type: disc; }\n ol { list-style-type: decimal; }\n li {\n margin-bottom: 0.3rem;\n }\n li > ul, li > ol {\n margin: 0.25rem 0 0.25rem 0;\n padding-left: 1.2rem;\n }\n li:last-child { margin-bottom: 0; }\n\n hr {\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.25);\n margin: 0.75rem 0;\n }\n\n code {\n font-family: monospace;\n font-size: 0.8rem;\n background: rgba(255,255,255,0.15);\n border-radius: 4px;\n padding: 0.1rem 0.35rem;\n }\n pre {\n background: rgba(255,255,255,0.1);\n border-radius: 8px;\n padding: 0.75rem 1rem;\n overflow-x: auto;\n margin: 0.5rem 0;\n }\n pre code {\n background: none;\n padding: 0;\n font-size: 0.78rem;\n }\n blockquote {\n border-left: 3px solid rgba(255,255,255,0.25);\n margin: 0.5rem 0;\n padding-left: 0.75rem;\n opacity: 0.8;\n }\n a {\n color: rgba(255,255,255,0.85);\n text-decoration: underline;\n }\n h1, h2, h3 {\n font-weight: 600;\n margin: 0.6rem 0 0.3rem;\n line-height: 1.3;\n text-align: left;\n }\n h1 { font-size: 1rem; }\n h2 { font-size: 0.95rem; }\n h3 { font-size: 0.875rem; }\n`\n\ninterface Props {\n content: string\n}\n\nexport const MarkdownRenderer: React.FC<Props> = ({ content }) => {\n return (\n <div className={markdownStyle}>\n <ReactMarkdown>{content}</ReactMarkdown>\n </div>\n )\n}","import React, { useState, useRef, useCallback, KeyboardEvent } from 'react'\nimport { css, keyframes } from '@emotion/css'\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 0.4; transform: scaleY(0.6); }\n 50% { opacity: 1; transform: scaleY(1); }\n`\n\ninterface Props {\n onSendText: (content: string) => void\n onSendFile: (file: File, content?: string) => Promise<void>\n disabled?: boolean\n isThinking?: boolean\n}\n\nexport const ChatInput: React.FC<Props> = ({ onSendText, onSendFile, disabled, isThinking }) => {\n const [value, setValue] = useState('')\n const [uploading, setUploading] = useState(false)\n const [pendingFile, setPendingFile] = useState<File | null>(null)\n const [pendingPreview, setPendingPreview] = useState<string | null>(null)\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n const handleSend = useCallback(() => {\n const trimmed = value.trim()\n if ((!trimmed && !pendingFile) || disabled || uploading) return\n\n if (pendingFile) {\n setUploading(true)\n onSendFile(pendingFile, trimmed || undefined).finally(() => {\n setUploading(false)\n setPendingFile(null)\n setPendingPreview(null)\n setValue('')\n })\n } else if (trimmed) {\n onSendText(trimmed)\n setValue('')\n }\n\n textareaRef.current?.focus()\n }, [value, pendingFile, disabled, uploading, onSendText, onSendFile])\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSend()\n }\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file) return\n if (!file.type.startsWith('image/')) return\n setPendingFile(file)\n const reader = new FileReader()\n reader.onload = (ev) => setPendingPreview(ev.target?.result as string)\n reader.readAsDataURL(file)\n e.target.value = ''\n }\n\n const canSend = (value.trim() || pendingFile) && !disabled && !uploading\n\n return (\n <div className={styles.wrapper}>\n {isThinking && (\n <div className={styles.thinkingBar}>\n <div className={styles.thinkingDots}>\n <span className={styles.dot(0)} />\n <span className={styles.dot(1)} />\n <span className={styles.dot(2)} />\n </div>\n <span className={styles.thinkingLabel}>Ways AI is typing...</span>\n </div>\n )}\n\n {pendingPreview && (\n <div className={styles.imagePreview}>\n <img src={pendingPreview} alt=\"attachment\" className={styles.previewImg} />\n <button className={styles.removeFile} onClick={() => { setPendingFile(null); setPendingPreview(null) }}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n )}\n\n <div className={styles.inputRow}>\n <button\n className={styles.attachBtn}\n onClick={() => fileInputRef.current?.click()}\n disabled={disabled || uploading}\n type=\"button\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"3\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/>\n </svg>\n </button>\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className={styles.hiddenInput}\n onChange={handleFileChange}\n />\n\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a message...\"\n disabled={disabled || uploading}\n rows={1}\n />\n\n <button className={styles.sendBtn} onClick={handleSend} disabled={!canSend} type=\"button\">\n {uploading ? (\n <span className={styles.spinner} />\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"5\"/><polyline points=\"5 12 12 5 19 12\"/>\n </svg>\n )}\n </button>\n </div>\n\n <p className={styles.hint}>Enter to send ยท Shift+Enter for new line</p>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n padding: 8px 12px 10px;\n border-top: 1px solid var(--wds-border);\n display: flex;\n flex-direction: column;\n gap: 6px;\n background: var(--wds-bg);\n flex-shrink: 0;\n `,\n thinkingBar: css`\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 2px 2px;\n `,\n thinkingDots: css`\n display: flex;\n align-items: center;\n gap: 3px;\n `,\n dot: (i: number) => css`\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--wds-primary);\n animation: ${pulse} 1.2s ease-in-out infinite;\n animation-delay: ${i * 0.18}s;\n display: inline-block;\n `,\n thinkingLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n imagePreview: css`\n position: relative;\n width: fit-content;\n margin: 0 2px;\n `,\n previewImg: css`\n width: 72px;\n height: 72px;\n object-fit: cover;\n border-radius: 10px;\n border: 1px solid var(--wds-border);\n display: block;\n `,\n removeFile: css`\n position: absolute;\n top: -6px;\n right: -6px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--wds-fg);\n color: var(--wds-bg);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n `,\n inputRow: css`\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n padding: 4px 4px 4px 8px;\n transition: border-color 0.15s;\n &:focus-within {\n border-color: var(--wds-primary);\n background: var(--wds-bg);\n }\n `,\n attachBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 5px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s;\n &:hover:not(:disabled) {\n color: var(--wds-primary);\n }\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n `,\n hiddenInput: css`\n display: none;\n `,\n textarea: css`\n flex: 1;\n resize: none;\n border: none;\n padding: 6px 0;\n font-size: 0.875rem;\n font-family: inherit;\n line-height: 1.5;\n background: transparent;\n color: var(--wds-fg);\n outline: none;\n max-height: 120px;\n overflow-y: auto;\n &::placeholder { color: var(--wds-muted); }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n `,\n sendBtn: css`\n background: var(--wds-primary);\n border: none;\n border-radius: 10px;\n width: 34px;\n height: 34px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n color: #fff;\n flex-shrink: 0;\n transition: opacity 0.15s;\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n &:hover:not(:disabled) { opacity: 0.85; }\n `,\n spinner: css`\n width: 14px;\n height: 14px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: ${spin} 0.7s linear infinite;\n display: block;\n `,\n hint: css`\n font-size: 10px;\n color: var(--wds-muted);\n margin: 0;\n text-align: center;\n opacity: 0.7;\n text-align: center;\n `,\n}"],"mappings":"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","names":["import_react","import_css","socket","import_react","import_css","import_jsx_runtime","styles","import_css","import_jsx_runtime","styles","import_react","import_css","import_css","import_css","import_jsx_runtime","ReactMarkdown","import_jsx_runtime","styles","import_react","import_css","import_jsx_runtime","_a","styles","import_jsx_runtime","styles","pulse","import_jsx_runtime"]}
package/dist/index.d.cts CHANGED
@@ -88,7 +88,7 @@ declare const useChat: (config: ChatConfig) => {
88
88
  visitorInfo: VisitorInfo | null;
89
89
  setVisitorInfo: (info: VisitorInfo) => void;
90
90
  sendMessage: (content: string, info?: VisitorInfo) => void;
91
- sendFile: (file: File, info?: VisitorInfo) => Promise<void>;
91
+ sendFile: (file: File, content?: string, info?: VisitorInfo) => Promise<void>;
92
92
  };
93
93
 
94
94
  type ChatActions = {
package/dist/index.d.ts CHANGED
@@ -88,7 +88,7 @@ declare const useChat: (config: ChatConfig) => {
88
88
  visitorInfo: VisitorInfo | null;
89
89
  setVisitorInfo: (info: VisitorInfo) => void;
90
90
  sendMessage: (content: string, info?: VisitorInfo) => void;
91
- sendFile: (file: File, info?: VisitorInfo) => Promise<void>;
91
+ sendFile: (file: File, content?: string, info?: VisitorInfo) => Promise<void>;
92
92
  };
93
93
 
94
94
  type ChatActions = {
package/dist/index.js CHANGED
@@ -170,14 +170,15 @@ var useChat = (config) => {
170
170
  [config, visitorInfo]
171
171
  );
172
172
  const sendFile = useCallback(
173
- async (file, info) => {
173
+ async (file, content, info) => {
174
174
  var _a, _b;
175
175
  const url = await uploadFile(file, config);
176
176
  const socket2 = getSocket(config);
177
- const dto = __spreadValues({
178
- file: url,
177
+ const dto = __spreadValues(__spreadProps(__spreadValues({
178
+ file: url
179
+ }, content ? { content } : {}), {
179
180
  externalId: `file-${Date.now()}`
180
- }, (info != null ? info : visitorInfo) ? {
181
+ }), (info != null ? info : visitorInfo) ? {
181
182
  email: (info != null ? info : visitorInfo).email,
182
183
  name: (_a = info != null ? info : visitorInfo) == null ? void 0 : _a.name,
183
184
  phone: (_b = info != null ? info : visitorInfo) == null ? void 0 : _b.phone
@@ -696,7 +697,7 @@ var MessageBubble = ({ message }) => {
696
697
  return /* @__PURE__ */ jsx5("div", { className: styles4.row(isCustomer), children: /* @__PURE__ */ jsxs3("div", { className: styles4.group(isCustomer), children: [
697
698
  isBot && /* @__PURE__ */ jsx5("span", { className: styles4.botLabel, children: "Ways AI" }),
698
699
  /* @__PURE__ */ jsxs3("div", { className: styles4.bubble(isCustomer), children: [
699
- message.file && /* @__PURE__ */ jsx5("a", { href: message.file, target: "_blank", rel: "noreferrer", className: styles4.fileLink, children: "\u{1F4CE} View attachment" }),
700
+ message.file && /* @__PURE__ */ jsx5("a", { href: message.file, target: "_blank", rel: "noreferrer", className: styles4.fileLink(!!message.content), children: "\u{1F4CE} View attachment" }),
700
701
  message.content && (isBot ? /* @__PURE__ */ jsx5(MarkdownRenderer, { content: message.content }) : /* @__PURE__ */ jsx5("p", { className: styles4.text, children: message.content }))
701
702
  ] }),
702
703
  /* @__PURE__ */ jsx5("span", { className: styles4.time, children: formatTime(message.createdAt) })
@@ -739,12 +740,13 @@ var styles4 = {
739
740
  white-space: pre-wrap;
740
741
  text-align: left;
741
742
  `,
742
- fileLink: css5`
743
+ fileLink: (hasContent) => css5`
743
744
  font-size: 0.875rem;
744
745
  color: inherit;
745
746
  text-decoration: underline;
746
747
  display: block;
747
748
  text-align: left;
749
+ ${hasContent ? "margin-bottom: 6px;" : ""}
748
750
  `,
749
751
  time: css5`
750
752
  font-size: 10px;
@@ -777,13 +779,13 @@ var ChatInput = ({ onSendText, onSendFile, disabled, isThinking }) => {
777
779
  if (!trimmed && !pendingFile || disabled || uploading) return;
778
780
  if (pendingFile) {
779
781
  setUploading(true);
780
- onSendFile(pendingFile).finally(() => {
782
+ onSendFile(pendingFile, trimmed || void 0).finally(() => {
781
783
  setUploading(false);
782
784
  setPendingFile(null);
783
785
  setPendingPreview(null);
786
+ setValue("");
784
787
  });
785
- }
786
- if (trimmed) {
788
+ } else if (trimmed) {
787
789
  onSendText(trimmed);
788
790
  setValue("");
789
791
  }
@@ -1064,35 +1066,102 @@ var ChatScreen = ({
1064
1066
  };
1065
1067
  return /* @__PURE__ */ jsxs5("div", { className: styles6.wrapper, children: [
1066
1068
  /* @__PURE__ */ jsxs5("div", { className: styles6.header, children: [
1067
- /* @__PURE__ */ jsx7("button", { className: styles6.iconBtn, onClick: onBack, children: /* @__PURE__ */ jsx7("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("polyline", { points: "15 18 9 12 15 6" }) }) }),
1069
+ /* @__PURE__ */ jsx7("button", { className: styles6.iconBtn, onClick: onBack, children: /* @__PURE__ */ jsx7(
1070
+ "svg",
1071
+ {
1072
+ width: "18",
1073
+ height: "18",
1074
+ viewBox: "0 0 24 24",
1075
+ fill: "none",
1076
+ stroke: "currentColor",
1077
+ strokeWidth: "2",
1078
+ strokeLinecap: "round",
1079
+ strokeLinejoin: "round",
1080
+ children: /* @__PURE__ */ jsx7("polyline", { points: "15 18 9 12 15 6" })
1081
+ }
1082
+ ) }),
1068
1083
  /* @__PURE__ */ jsxs5("div", { className: styles6.headerCenter, children: [
1069
1084
  /* @__PURE__ */ jsx7("span", { className: styles6.headerTitle, children: "Support" }),
1070
1085
  /* @__PURE__ */ jsx7("span", { className: styles6.statusDot(connected) }),
1071
1086
  /* @__PURE__ */ jsx7("span", { className: styles6.statusLabel, children: connected ? "Online" : "Connecting..." })
1072
1087
  ] }),
1073
- /* @__PURE__ */ jsx7("button", { className: styles6.expandBtn, onClick: onExpand, children: isExpanded ? /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1074
- /* @__PURE__ */ jsx7("polyline", { points: "4 14 10 14 10 20" }),
1075
- /* @__PURE__ */ jsx7("polyline", { points: "20 10 14 10 14 4" }),
1076
- /* @__PURE__ */ jsx7("line", { x1: "10", y1: "14", x2: "3", y2: "21" }),
1077
- /* @__PURE__ */ jsx7("line", { x1: "21", y1: "3", x2: "14", y2: "10" })
1078
- ] }) : /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1079
- /* @__PURE__ */ jsx7("polyline", { points: "15 3 21 3 21 9" }),
1080
- /* @__PURE__ */ jsx7("polyline", { points: "9 21 3 21 3 15" }),
1081
- /* @__PURE__ */ jsx7("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
1082
- /* @__PURE__ */ jsx7("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
1083
- ] }) })
1088
+ /* @__PURE__ */ jsx7("button", { className: styles6.expandBtn, onClick: onExpand, children: isExpanded ? /* @__PURE__ */ jsxs5(
1089
+ "svg",
1090
+ {
1091
+ width: "16",
1092
+ height: "16",
1093
+ viewBox: "0 0 24 24",
1094
+ fill: "none",
1095
+ stroke: "currentColor",
1096
+ strokeWidth: "2",
1097
+ strokeLinecap: "round",
1098
+ strokeLinejoin: "round",
1099
+ children: [
1100
+ /* @__PURE__ */ jsx7("polyline", { points: "4 14 10 14 10 20" }),
1101
+ /* @__PURE__ */ jsx7("polyline", { points: "20 10 14 10 14 4" }),
1102
+ /* @__PURE__ */ jsx7("line", { x1: "10", y1: "14", x2: "3", y2: "21" }),
1103
+ /* @__PURE__ */ jsx7("line", { x1: "21", y1: "3", x2: "14", y2: "10" })
1104
+ ]
1105
+ }
1106
+ ) : /* @__PURE__ */ jsxs5(
1107
+ "svg",
1108
+ {
1109
+ width: "16",
1110
+ height: "16",
1111
+ viewBox: "0 0 24 24",
1112
+ fill: "none",
1113
+ stroke: "currentColor",
1114
+ strokeWidth: "2",
1115
+ strokeLinecap: "round",
1116
+ strokeLinejoin: "round",
1117
+ children: [
1118
+ /* @__PURE__ */ jsx7("polyline", { points: "15 3 21 3 21 9" }),
1119
+ /* @__PURE__ */ jsx7("polyline", { points: "9 21 3 21 3 15" }),
1120
+ /* @__PURE__ */ jsx7("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
1121
+ /* @__PURE__ */ jsx7("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
1122
+ ]
1123
+ }
1124
+ ) })
1084
1125
  ] }),
1085
1126
  /* @__PURE__ */ jsxs5("div", { className: styles6.messagesWrap, children: [
1086
- /* @__PURE__ */ jsxs5("div", { className: styles6.messages, ref: scrollRef, onScroll: handleScroll, children: [
1087
- error && /* @__PURE__ */ jsx7("div", { className: styles6.errorBanner, children: error.message }),
1088
- messages.length === 0 && connected && /* @__PURE__ */ jsx7("div", { className: styles6.emptyState, children: /* @__PURE__ */ jsx7("p", { children: "Send a message to start the conversation." }) }),
1089
- messages.map((msg) => /* @__PURE__ */ jsx7(MessageBubble, { message: msg }, msg.id)),
1090
- /* @__PURE__ */ jsx7("div", { ref: bottomRef })
1091
- ] }),
1092
- showScrollBtn && /* @__PURE__ */ jsx7("button", { className: styles6.scrollBtn, onClick: () => {
1093
- var _a;
1094
- return (_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
1095
- }, children: /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx7("polyline", { points: "6 9 12 15 18 9" }) }) })
1127
+ /* @__PURE__ */ jsxs5(
1128
+ "div",
1129
+ {
1130
+ className: styles6.messages,
1131
+ ref: scrollRef,
1132
+ onScroll: handleScroll,
1133
+ children: [
1134
+ error && /* @__PURE__ */ jsx7("div", { className: styles6.errorBanner, children: error.message }),
1135
+ messages.length === 0 && connected && /* @__PURE__ */ jsx7("div", { className: styles6.emptyState, children: /* @__PURE__ */ jsx7("p", { children: "Send a message to start the conversation." }) }),
1136
+ messages.map((msg) => /* @__PURE__ */ jsx7(MessageBubble, { message: msg }, msg.id)),
1137
+ /* @__PURE__ */ jsx7("div", { ref: bottomRef })
1138
+ ]
1139
+ }
1140
+ ),
1141
+ showScrollBtn && /* @__PURE__ */ jsx7(
1142
+ "button",
1143
+ {
1144
+ className: styles6.scrollBtn,
1145
+ onClick: () => {
1146
+ var _a;
1147
+ return (_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
1148
+ },
1149
+ children: /* @__PURE__ */ jsx7(
1150
+ "svg",
1151
+ {
1152
+ width: "14",
1153
+ height: "14",
1154
+ viewBox: "0 0 24 24",
1155
+ fill: "none",
1156
+ stroke: "currentColor",
1157
+ strokeWidth: "2.5",
1158
+ strokeLinecap: "round",
1159
+ strokeLinejoin: "round",
1160
+ children: /* @__PURE__ */ jsx7("polyline", { points: "6 9 12 15 18 9" })
1161
+ }
1162
+ )
1163
+ }
1164
+ )
1096
1165
  ] }),
1097
1166
  /* @__PURE__ */ jsx7(
1098
1167
  ChatInput,
@@ -1158,7 +1227,9 @@ var styles6 = {
1158
1227
  align-items: center;
1159
1228
  justify-content: center;
1160
1229
  flex-shrink: 0;
1161
- transition: color 0.15s, background 0.15s;
1230
+ transition:
1231
+ color 0.15s,
1232
+ background 0.15s;
1162
1233
  &:hover {
1163
1234
  color: var(--wds-fg);
1164
1235
  background: var(--wds-muted-bg);
@@ -1175,7 +1246,9 @@ var styles6 = {
1175
1246
  align-items: center;
1176
1247
  justify-content: center;
1177
1248
  flex-shrink: 0;
1178
- transition: color 0.15s, background 0.15s;
1249
+ transition:
1250
+ color 0.15s,
1251
+ background 0.15s;
1179
1252
  &:hover {
1180
1253
  color: var(--wds-fg);
1181
1254
  background: var(--wds-muted-bg);
@@ -1232,8 +1305,10 @@ var styles6 = {
1232
1305
  align-items: center;
1233
1306
  justify-content: center;
1234
1307
  cursor: pointer;
1235
- box-shadow: 0 2px 8px rgba(0,0,0,0.12);
1236
- transition: color 0.15s, border-color 0.15s;
1308
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
1309
+ transition:
1310
+ color 0.15s,
1311
+ border-color 0.15s;
1237
1312
  &:hover {
1238
1313
  color: var(--wds-primary);
1239
1314
  border-color: var(--wds-primary);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ChatWidget.tsx","../src/lib/upload.ts","../src/hooks/useChat.ts","../src/lib/socket.ts","../src/store/chatStore.ts","../src/components/FloatingButton.tsx","../src/components/ChatPanel.tsx","../src/components/HomeScreen.tsx","../src/components/ChatScreen.tsx","../src/components/MessageBubble.tsx","../src/components/MarkdownRenderer.tsx","../src/components/ChatInput.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { injectGlobal } from '@emotion/css'\nimport { ChatConfig } from '../types'\nimport { loadVisitorId } from '../lib/upload'\nimport { useChat } from '../hooks/useChat'\nimport { useChatStore } from '../store/chatStore'\nimport { FloatingButton } from './FloatingButton'\nimport { ChatPanel } from './ChatPanel'\nimport { HomeScreen } from './HomeScreen'\nimport { ChatScreen } from './ChatScreen'\n\nexport type ChatWidgetProps = {\n config: ChatConfig\n}\n\ntype View = 'home' | 'chat'\n\nexport const ChatWidget: React.FC<ChatWidgetProps> = ({ config }) => {\n const [isOpen, setIsOpen] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n const [view, setView] = useState<View>('home')\n\n const reset = useChatStore((s) => s.reset)\n\n const resolvedConfig: ChatConfig = {\n ...config,\n visitorId: config.visitorId ?? loadVisitorId() ?? undefined,\n }\n\n const hasHistory = !!resolvedConfig.visitorId\n\n const { status, messages, error, sendMessage, sendFile } = useChat(resolvedConfig)\n\n const handleNewConversation = () => {\n reset()\n setView('chat')\n }\n\n useEffect(() => {\n const isMobile = window.innerWidth <= 480\n if (isMobile) {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n }\n return () => {\n document.body.style.overflow = ''\n }\n }, [isOpen])\n\n return (\n <>\n <FloatingButton\n isOpen={isOpen}\n onToggle={() => setIsOpen((p) => !p)}\n />\n\n <ChatPanel\n isOpen={isOpen}\n isExpanded={isExpanded}\n >\n {view === 'home' ? (\n <HomeScreen\n onStartChat={handleNewConversation}\n onContinueChat={() => setView('chat')}\n hasHistory={hasHistory}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n />\n ) : (\n <ChatScreen\n messages={messages}\n onSendText={sendMessage}\n onSendFile={sendFile}\n onBack={() => setView('home')}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n status={status}\n error={error}\n />\n )}\n </ChatPanel>\n </>\n )\n}\n\ninjectGlobal`\n :root {\n --wds-primary: oklch(0.5811 0.2268 259.15);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.12);\n --wds-primary-border: oklch(0.7695 0.1177 255.22 / 0.4);\n --wds-bg: oklch(1 0 0);\n --wds-fg: oklch(0.145 0 0);\n --wds-muted: oklch(0.556 0 0);\n --wds-muted-bg: oklch(0.97 0 0);\n --wds-border: oklch(0.922 0 0);\n }\n\n @media (prefers-color-scheme: dark) {\n :root {\n --wds-bg: oklch(0.145 0 0);\n --wds-fg: oklch(0.985 0 0);\n --wds-muted: oklch(0.708 0 0);\n --wds-muted-bg: oklch(0.205 0 0);\n --wds-border: oklch(1 0 0 / 10%);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.15);\n }\n }\n\n [data-wds-root] * {\n box-sizing: border-box;\n text-align: left;\n }\n`","import type { ChatConfig } from \"../types\";\n\nconst VISITOR_ID_KEY = \"waysdrop_visitor_id\";\n\nexport const saveVisitorId = (id: string): void => {\n localStorage.setItem(VISITOR_ID_KEY, id);\n};\n\nexport const loadVisitorId = (): string | null => {\n return localStorage.getItem(VISITOR_ID_KEY);\n};\n\nexport const clearVisitorId = (): void => {\n localStorage.removeItem(VISITOR_ID_KEY);\n};\n\nexport const uploadFile = async (\n file: File,\n config: ChatConfig,\n): Promise<string> => {\n const formData = new FormData();\n formData.append(\"files\", file);\n\n const headers: HeadersInit = {};\n if (config.token) headers[\"Authorization\"] = `Bearer ${config.token}`;\n\n const res = await fetch(`${config.apiUrl}/file/bulk-upload`, {\n method: \"POST\",\n headers,\n body: formData,\n });\n\n if (!res.ok) {\n throw new Error(\"File upload failed\");\n }\n\n const json = await res.json();\n\n if (!json.success || !json.data?.urls?.length) {\n throw new Error(json.message || \"File upload failed\");\n }\n\n const first = json.data.urls[0];\n if (typeof first !== \"string\") {\n throw new Error(first?.error || \"File upload failed\");\n }\n\n return first;\n};","import { useEffect, useCallback } from 'react'\nimport { getSocket, destroySocket } from '../lib/socket'\nimport { saveVisitorId, uploadFile } from '../lib/upload'\nimport { useChatStore } from '../store/chatStore'\nimport type {\n ChatConfig,\n ConnectedPayload,\n SupportMessageSentPayload,\n SupportNewMessagePayload,\n SocketError,\n SupportSendMessageDTO,\n VisitorInfo,\n} from '../types'\n\nexport const useChat = (config: ChatConfig) => {\n const {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setStatus,\n setRole,\n setVisitorId,\n setChatId,\n addMessage,\n setError,\n setVisitorInfo,\n reset,\n } = useChatStore()\n\n // โ”€โ”€โ”€ Connect โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n useEffect(() => {\n const socket = getSocket(config)\n\n setStatus('connecting')\n socket.connect()\n\n socket.on('connected', (payload: ConnectedPayload) => {\n setStatus('connected')\n setRole(payload.role)\n\n if (payload.role === 'VISITOR') {\n saveVisitorId(payload.visitorId)\n setVisitorId(payload.visitorId)\n }\n })\n\n socket.on('support-message-sent', (payload: SupportMessageSentPayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('support-new-message', (payload: SupportNewMessagePayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('error', (err: SocketError) => {\n setError(err)\n setStatus('error')\n })\n\n return () => {\n destroySocket()\n reset()\n }\n }, [])\n\n // โ”€โ”€โ”€ Send text message โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n const sendMessage = useCallback(\n (content: string, info?: VisitorInfo) => {\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n content,\n externalId: `msg-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n // โ”€โ”€โ”€ Send file โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n const sendFile = useCallback(\n async (file: File, info?: VisitorInfo) => {\n const url = await uploadFile(file, config)\n\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n file: url,\n externalId: `file-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n return {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setVisitorInfo,\n sendMessage,\n sendFile,\n }\n}","import { io, Socket } from 'socket.io-client'\nimport type { ChatConfig } from '../types'\n\nlet socket: Socket | null = null\n\nexport const getSocket = (config: ChatConfig): Socket => {\n if (socket) return socket\n\n const { serverUrl, token, visitorId } = config\n\n socket = io(serverUrl, {\n transports: ['websocket', 'polling'],\n auth: {\n ...(token ? { token } : {}),\n ...(visitorId ? { visitorId } : {}),\n },\n autoConnect: false,\n })\n\n return socket\n}\n\nexport const destroySocket = (): void => {\n if (socket) {\n socket.disconnect()\n socket = null\n }\n}","import { create } from 'zustand'\nimport type {\n ChatState,\n ChatMessage,\n UserRole,\n SocketError,\n VisitorInfo,\n ConnectionStatus,\n} from '../types'\n\ntype ChatActions = {\n setStatus: (status: ConnectionStatus) => void\n setRole: (role: UserRole) => void\n setVisitorId: (id: string) => void\n setChatId: (id: string) => void\n addMessage: (message: ChatMessage) => void\n setError: (error: SocketError | null) => void\n setVisitorInfo: (info: VisitorInfo) => void\n reset: () => void\n}\n\nconst initialState: ChatState = {\n status: 'idle',\n role: null,\n visitorId: null,\n chatId: null,\n messages: [],\n error: null,\n visitorInfo: null,\n}\n\nexport const useChatStore = create<ChatState & ChatActions>((set) => ({\n ...initialState,\n\n setStatus: (status) => set({ status }),\n setRole: (role) => set({ role }),\n setVisitorId: (id) => set({ visitorId: id }),\n setChatId: (id) => set({ chatId: id }),\n addMessage: (message) =>\n set((state) => ({\n messages: [...state.messages, message],\n })),\n setError: (error) => set({ error }),\n setVisitorInfo: (info) => set({ visitorInfo: info }),\n reset: () => set(initialState),\n}))","import React, { useEffect, useState } from \"react\";\nimport { css } from \"@emotion/css\";\n\nconst BUTTON_SIZE = 56;\n\ninterface Props {\n isOpen: boolean;\n onToggle: () => void;\n}\n\nexport const FloatingButton: React.FC<Props> = ({ isOpen, onToggle }) => {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const check = () => setIsMobile(window.innerWidth <= 480);\n check();\n window.addEventListener(\"resize\", check);\n return () => window.removeEventListener(\"resize\", check);\n }, []);\n\n if (isMobile && isOpen) {\n return (\n <button\n className={styles.mobileCloseBtn}\n onClick={onToggle}\n type=\"button\"\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n );\n }\n\n return (\n <button className={styles.btn} onClick={onToggle} type=\"button\">\n <span className={styles.icon(!isOpen)}>\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z\" />\n </svg>\n </span>\n <span className={styles.icon(isOpen)}>\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </span>\n </button>\n );\n};\n\nconst styles = {\n btn: css`\n position: fixed;\n right: 30px;\n bottom: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n -webkit-user-select: none;\n &:hover {\n opacity: 0.92;\n }\n `,\n mobileCloseBtn: css`\n position: fixed;\n top: 16px;\n right: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n `,\n icon: (visible: boolean) => css`\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n transition:\n opacity 0.2s,\n transform 0.2s;\n opacity: ${visible ? 1 : 0};\n transform: ${visible ? \"scale(1)\" : \"scale(0.6) rotate(30deg)\"};\n pointer-events: ${visible ? \"auto\" : \"none\"};\n `,\n};\n","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n isOpen: boolean\n isExpanded: boolean\n children: React.ReactNode\n}\n\nexport const ChatPanel: React.FC<Props> = ({ isOpen, isExpanded, children }) => {\n return (\n <div data-wds-root className={styles.panel(isOpen, isExpanded)}>\n <div className={styles.inner}>{children}</div>\n </div>\n )\n}\n\nconst styles = {\n panel: (isOpen: boolean, isExpanded: boolean) => css`\n position: fixed;\n bottom: 86px;\n z-index: 999998;\n transition: opacity 0.2s, transform 0.25s cubic-bezier(0.34, 1.2, 0.64, 1);\n opacity: ${isOpen ? 1 : 0};\n pointer-events: ${isOpen ? 'auto' : 'none'};\n\n ${isExpanded\n ? `\n width: min(760px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 120px));\n border-radius: 20px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.1);\n left: 50%;\n right: auto;\n translate: -50% 0;\n transform: ${isOpen ? 'scale(1)' : 'scale(0.95)'};\n transform-origin: bottom center;\n `\n : `\n width: 400px;\n height: 620px;\n border-radius: 20px;\n box-shadow: 0 12px 48px rgba(0,0,0,0.16), 0 2px 8px rgba(0,0,0,0.08);\n right: 22px;\n transform: ${isOpen ? 'translateY(0) scale(1)' : 'translateY(16px) scale(0.97)'};\n `}\n\n overflow: hidden;\n\n @media (max-width: 480px) {\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n width: 100% !important;\n height: 100% !important;\n border-radius: 0 !important;\n translate: none !important;\n }\n `,\n inner: css`\n width: 100%;\n height: 100%;\n overflow: hidden;\n border-radius: inherit;\n `,\n}","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n onStartChat: () => void\n onContinueChat: () => void\n hasHistory: boolean\n onExpand: () => void\n isExpanded: boolean\n}\n\nexport const HomeScreen: React.FC<Props> = ({\n onStartChat,\n onContinueChat,\n hasHistory,\n onExpand,\n isExpanded,\n}) => {\n return (\n <div className={styles.wrapper}>\n <div className={styles.topBar}>\n <div className={styles.logoMark}>\n <img\n src=\"https://cdn.waysdrop.com/bulk/horizon_20260411202129966_d25edae2.png\"\n alt=\"Waysdrop\"\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n />\n </div>\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/>\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/>\n </svg>\n ) : (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/>\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.hero}>\n <h2 className={styles.heroTitle}>Hi there! ๐Ÿ‘‹</h2>\n <p className={styles.heroSub}>We're here to help. Ask us anything or share your feedback.</p>\n </div>\n\n <div className={styles.section}>\n <p className={styles.sectionLabel}>Conversations</p>\n {hasHistory ? (\n <button className={styles.conversationCard} onClick={onContinueChat}>\n <div className={styles.cardIcon}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n </div>\n <div className={styles.cardBody}>\n <span className={styles.cardTitle}>Continue conversation</span>\n <span className={styles.cardSub}>Tap to resume your last chat</span>\n </div>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n ) : (\n <div className={styles.emptyHistory}>\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ opacity: 0.25 }}>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n <p>No previous conversations</p>\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button className={styles.startBtn} onClick={onStartChat}>\n New conversation\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n <p className={styles.poweredBy}>Powered by Waysdrop</p>\n </div>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n text-align: left;\n `,\n topBar: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 18px 18px 0;\n flex-shrink: 0;\n `,\n logoMark: css`\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n hero: css`\n padding: 20px 20px 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n `,\n heroTitle: css`\n font-size: 1.375rem;\n font-weight: 700;\n color: var(--wds-fg);\n margin: 0;\n line-height: 1.2;\n text-align: left;\n `,\n heroSub: css`\n font-size: 0.9375rem;\n color: var(--wds-muted);\n margin: 0;\n line-height: 1.6;\n text-align: left;\n `,\n section: css`\n flex: 1;\n padding: 4px 18px 0;\n overflow-y: auto;\n `,\n sectionLabel: css`\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.07em;\n text-transform: uppercase;\n color: var(--wds-muted);\n margin: 0 0 12px 2px;\n text-align: left;\n `,\n conversationCard: css`\n display: flex;\n align-items: center;\n gap: 14px;\n width: 100%;\n padding: 14px 16px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n cursor: pointer;\n text-align: left;\n transition: border-color 0.15s, background 0.15s;\n color: var(--wds-fg);\n &:hover {\n border-color: var(--wds-primary);\n background: var(--wds-primary-soft);\n }\n `,\n cardIcon: css`\n width: 38px;\n height: 38px;\n border-radius: 10px;\n background: var(--wds-primary-soft);\n color: var(--wds-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n `,\n cardBody: css`\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 3px;\n `,\n cardTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n text-align: left;\n `,\n cardSub: css`\n font-size: 12px;\n color: var(--wds-muted);\n text-align: left;\n `,\n emptyHistory: css`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n padding: 40px 0;\n color: var(--wds-muted);\n font-size: 12px;\n `,\n footer: css`\n padding: 18px 18px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n flex-shrink: 0;\n border-top: 1px solid var(--wds-border);\n `,\n startBtn: css`\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n width: 100%;\n padding: 13px 16px;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n border-radius: 14px;\n font-size: 0.9375rem;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.15s;\n font-family: inherit;\n &:hover { opacity: 0.88; }\n `,\n poweredBy: css`\n font-size: 11px;\n color: var(--wds-muted);\n margin: 0;\n opacity: 0.7;\n `,\n}","import React, { useEffect, useRef, useState } from 'react'\nimport { css, keyframes } from '@emotion/css'\nimport { ChatMessage } from '../types'\nimport { MessageBubble } from './MessageBubble'\nimport { ChatInput } from './ChatInput'\n\ninterface Props {\n messages: ChatMessage[]\n onSendText: (content: string) => void\n onSendFile: (file: File) => Promise<void>\n onBack: () => void\n onExpand: () => void\n isExpanded: boolean\n status: string\n error: { code: number; message: string } | null\n}\n\nexport const ChatScreen: React.FC<Props> = ({\n messages,\n onSendText,\n onSendFile,\n onBack,\n onExpand,\n isExpanded,\n status,\n error,\n}) => {\n const bottomRef = useRef<HTMLDivElement>(null)\n const scrollRef = useRef<HTMLDivElement>(null)\n const connected = status === 'connected'\n const [showScrollBtn, setShowScrollBtn] = useState(false)\n\n const lastMsg = messages[messages.length - 1]\n const isThinking = connected && lastMsg?.direction === 'INBOUND'\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' })\n }, [messages])\n\n const handleScroll = () => {\n const el = scrollRef.current\n if (!el) return\n setShowScrollBtn(el.scrollHeight - el.scrollTop - el.clientHeight > 80)\n }\n\n return (\n <div className={styles.wrapper}>\n <div className={styles.header}>\n <button className={styles.iconBtn} onClick={onBack}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\"/>\n </svg>\n </button>\n\n <div className={styles.headerCenter}>\n <span className={styles.headerTitle}>Support</span>\n <span className={styles.statusDot(connected)} />\n <span className={styles.statusLabel}>{connected ? 'Online' : 'Connecting...'}</span>\n </div>\n\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/>\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/>\n </svg>\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/>\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.messagesWrap}>\n <div className={styles.messages} ref={scrollRef} onScroll={handleScroll}>\n {error && <div className={styles.errorBanner}>{error.message}</div>}\n {messages.length === 0 && connected && (\n <div className={styles.emptyState}>\n <p>Send a message to start the conversation.</p>\n </div>\n )}\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n <div ref={bottomRef} />\n </div>\n\n {showScrollBtn && (\n <button className={styles.scrollBtn} onClick={() => bottomRef.current?.scrollIntoView({ behavior: 'smooth' })}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"/>\n </svg>\n </button>\n )}\n </div>\n\n <ChatInput\n onSendText={onSendText}\n onSendFile={onSendFile}\n disabled={!connected}\n isThinking={isThinking}\n />\n </div>\n )\n}\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n`\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n `,\n header: css`\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n border-bottom: 1px solid var(--wds-border);\n flex-shrink: 0;\n `,\n headerCenter: css`\n flex: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n `,\n headerTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n `,\n statusDot: (connected: boolean) => css`\n width: 7px;\n height: 7px;\n border-radius: 50%;\n flex-shrink: 0;\n background: ${connected ? '#22c55e' : '#f59e0b'};\n animation: ${connected ? 'none' : `${pulse} 1.2s ease-in-out infinite`};\n `,\n statusLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n iconBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n messagesWrap: css`\n flex: 1;\n position: relative;\n overflow: hidden;\n `,\n messages: css`\n position: absolute;\n inset: 0;\n overflow-y: auto;\n padding: 16px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n `,\n errorBanner: css`\n background: oklch(0.9705 0.0129 17.04);\n color: oklch(0.5054 0.1905 27.51);\n border: 1px solid oklch(0.8845 0.0592 18.27);\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 12px;\n text-align: center;\n `,\n emptyState: css`\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--wds-muted);\n font-size: 13px;\n text-align: center;\n padding: 40px 20px;\n `,\n scrollBtn: css`\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: var(--wds-bg);\n border: 1px solid var(--wds-border);\n color: var(--wds-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n transition: color 0.15s, border-color 0.15s;\n &:hover {\n color: var(--wds-primary);\n border-color: var(--wds-primary);\n }\n `,\n}","import React from 'react'\nimport { css } from '@emotion/css'\nimport { ChatMessage } from '../types'\nimport { MarkdownRenderer } from './MarkdownRenderer'\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\ninterface Props {\n message: ChatMessage\n}\n\nexport const MessageBubble: React.FC<Props> = ({ message }) => {\n const isCustomer = message.direction === 'OUTBOUND'\n const isBot = message.senderRole === 'BOT'\n\n return (\n <div className={styles.row(isCustomer)}>\n <div className={styles.group(isCustomer)}>\n {isBot && <span className={styles.botLabel}>Ways AI</span>}\n <div className={styles.bubble(isCustomer)}>\n {message.file && (\n <a href={message.file} target=\"_blank\" rel=\"noreferrer\" className={styles.fileLink}>\n ๐Ÿ“Ž View attachment\n </a>\n )}\n {message.content && (\n isBot\n ? <MarkdownRenderer content={message.content} />\n : <p className={styles.text}>{message.content}</p>\n )}\n </div>\n <span className={styles.time}>{formatTime(message.createdAt)}</span>\n </div>\n </div>\n )\n}\n\nconst styles = {\n row: (isCustomer: boolean) => css`\n display: flex;\n width: 100%;\n justify-content: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n group: (isCustomer: boolean) => css`\n display: flex;\n flex-direction: column;\n max-width: 78%;\n gap: 4px;\n align-items: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n botLabel: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n font-weight: 500;\n letter-spacing: 0.03em;\n `,\n bubble: (isCustomer: boolean) => css`\n border-radius: 18px;\n padding: 10px 14px;\n word-break: break-word;\n text-align: left;\n border-top-left-radius: ${isCustomer ? '4px' : '18px'};\n border-top-right-radius: ${isCustomer ? '18px' : '4px'};\n background: ${isCustomer ? 'var(--wds-muted-bg)' : 'var(--wds-primary)'};\n color: ${isCustomer ? 'var(--wds-fg)' : '#fff'};\n `,\n text: css`\n font-size: 0.875rem;\n line-height: 1.5;\n margin: 0;\n white-space: pre-wrap;\n text-align: left;\n `,\n fileLink: css`\n font-size: 0.875rem;\n color: inherit;\n text-decoration: underline;\n display: block;\n text-align: left;\n `,\n time: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n `,\n}","import React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport { css } from '@emotion/css'\n\nconst markdownStyle = css`\n font-size: 0.875rem;\n line-height: 1.6;\n color: inherit;\n text-align: left;\n\n p {\n margin: 0 0 0.6rem 0;\n text-align: left;\n }\n p:last-child {\n margin-bottom: 0;\n }\n strong { font-weight: 600; }\n em { font-style: italic; }\n\n ul, ol {\n margin: 0.4rem 0 0.6rem 0;\n padding-left: 1.4rem;\n text-align: left;\n }\n ul { list-style-type: disc; }\n ol { list-style-type: decimal; }\n li {\n margin-bottom: 0.3rem;\n }\n li > ul, li > ol {\n margin: 0.25rem 0 0.25rem 0;\n padding-left: 1.2rem;\n }\n li:last-child { margin-bottom: 0; }\n\n hr {\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.25);\n margin: 0.75rem 0;\n }\n\n code {\n font-family: monospace;\n font-size: 0.8rem;\n background: rgba(255,255,255,0.15);\n border-radius: 4px;\n padding: 0.1rem 0.35rem;\n }\n pre {\n background: rgba(255,255,255,0.1);\n border-radius: 8px;\n padding: 0.75rem 1rem;\n overflow-x: auto;\n margin: 0.5rem 0;\n }\n pre code {\n background: none;\n padding: 0;\n font-size: 0.78rem;\n }\n blockquote {\n border-left: 3px solid rgba(255,255,255,0.25);\n margin: 0.5rem 0;\n padding-left: 0.75rem;\n opacity: 0.8;\n }\n a {\n color: rgba(255,255,255,0.85);\n text-decoration: underline;\n }\n h1, h2, h3 {\n font-weight: 600;\n margin: 0.6rem 0 0.3rem;\n line-height: 1.3;\n text-align: left;\n }\n h1 { font-size: 1rem; }\n h2 { font-size: 0.95rem; }\n h3 { font-size: 0.875rem; }\n`\n\ninterface Props {\n content: string\n}\n\nexport const MarkdownRenderer: React.FC<Props> = ({ content }) => {\n return (\n <div className={markdownStyle}>\n <ReactMarkdown>{content}</ReactMarkdown>\n </div>\n )\n}","import React, { useState, useRef, useCallback, KeyboardEvent } from 'react'\nimport { css, keyframes } from '@emotion/css'\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 0.4; transform: scaleY(0.6); }\n 50% { opacity: 1; transform: scaleY(1); }\n`\n\ninterface Props {\n onSendText: (content: string) => void\n onSendFile: (file: File) => Promise<void>\n disabled?: boolean\n isThinking?: boolean\n}\n\nexport const ChatInput: React.FC<Props> = ({ onSendText, onSendFile, disabled, isThinking }) => {\n const [value, setValue] = useState('')\n const [uploading, setUploading] = useState(false)\n const [pendingFile, setPendingFile] = useState<File | null>(null)\n const [pendingPreview, setPendingPreview] = useState<string | null>(null)\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n const handleSend = useCallback(() => {\n const trimmed = value.trim()\n if ((!trimmed && !pendingFile) || disabled || uploading) return\n\n if (pendingFile) {\n setUploading(true)\n onSendFile(pendingFile).finally(() => {\n setUploading(false)\n setPendingFile(null)\n setPendingPreview(null)\n })\n }\n\n if (trimmed) {\n onSendText(trimmed)\n setValue('')\n }\n\n textareaRef.current?.focus()\n }, [value, pendingFile, disabled, uploading, onSendText, onSendFile])\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSend()\n }\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file) return\n if (!file.type.startsWith('image/')) return\n setPendingFile(file)\n const reader = new FileReader()\n reader.onload = (ev) => setPendingPreview(ev.target?.result as string)\n reader.readAsDataURL(file)\n e.target.value = ''\n }\n\n const canSend = (value.trim() || pendingFile) && !disabled && !uploading\n\n return (\n <div className={styles.wrapper}>\n {isThinking && (\n <div className={styles.thinkingBar}>\n <div className={styles.thinkingDots}>\n <span className={styles.dot(0)} />\n <span className={styles.dot(1)} />\n <span className={styles.dot(2)} />\n </div>\n <span className={styles.thinkingLabel}>Ways AI is typing...</span>\n </div>\n )}\n\n {pendingPreview && (\n <div className={styles.imagePreview}>\n <img src={pendingPreview} alt=\"attachment\" className={styles.previewImg} />\n <button className={styles.removeFile} onClick={() => { setPendingFile(null); setPendingPreview(null) }}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n )}\n\n <div className={styles.inputRow}>\n <button\n className={styles.attachBtn}\n onClick={() => fileInputRef.current?.click()}\n disabled={disabled || uploading}\n type=\"button\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"3\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/>\n </svg>\n </button>\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className={styles.hiddenInput}\n onChange={handleFileChange}\n />\n\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a message...\"\n disabled={disabled || uploading}\n rows={1}\n />\n\n <button className={styles.sendBtn} onClick={handleSend} disabled={!canSend} type=\"button\">\n {uploading ? (\n <span className={styles.spinner} />\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"5\"/><polyline points=\"5 12 12 5 19 12\"/>\n </svg>\n )}\n </button>\n </div>\n\n <p className={styles.hint}>Enter to send ยท Shift+Enter for new line</p>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n padding: 8px 12px 10px;\n border-top: 1px solid var(--wds-border);\n display: flex;\n flex-direction: column;\n gap: 6px;\n background: var(--wds-bg);\n flex-shrink: 0;\n `,\n thinkingBar: css`\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 2px 2px;\n `,\n thinkingDots: css`\n display: flex;\n align-items: center;\n gap: 3px;\n `,\n dot: (i: number) => css`\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--wds-primary);\n animation: ${pulse} 1.2s ease-in-out infinite;\n animation-delay: ${i * 0.18}s;\n display: inline-block;\n `,\n thinkingLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n imagePreview: css`\n position: relative;\n width: fit-content;\n margin: 0 2px;\n `,\n previewImg: css`\n width: 72px;\n height: 72px;\n object-fit: cover;\n border-radius: 10px;\n border: 1px solid var(--wds-border);\n display: block;\n `,\n removeFile: css`\n position: absolute;\n top: -6px;\n right: -6px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--wds-fg);\n color: var(--wds-bg);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n `,\n inputRow: css`\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n padding: 4px 4px 4px 8px;\n transition: border-color 0.15s;\n &:focus-within {\n border-color: var(--wds-primary);\n background: var(--wds-bg);\n }\n `,\n attachBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 5px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s;\n &:hover:not(:disabled) {\n color: var(--wds-primary);\n }\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n `,\n hiddenInput: css`\n display: none;\n `,\n textarea: css`\n flex: 1;\n resize: none;\n border: none;\n padding: 6px 0;\n font-size: 0.875rem;\n font-family: inherit;\n line-height: 1.5;\n background: transparent;\n color: var(--wds-fg);\n outline: none;\n max-height: 120px;\n overflow-y: auto;\n &::placeholder { color: var(--wds-muted); }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n `,\n sendBtn: css`\n background: var(--wds-primary);\n border: none;\n border-radius: 10px;\n width: 34px;\n height: 34px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n color: #fff;\n flex-shrink: 0;\n transition: opacity 0.15s;\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n &:hover:not(:disabled) { opacity: 0.85; }\n `,\n spinner: css`\n width: 14px;\n height: 14px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: ${spin} 0.7s linear infinite;\n display: block;\n `,\n hint: css`\n font-size: 10px;\n color: var(--wds-muted);\n margin: 0;\n text-align: center;\n opacity: 0.7;\n text-align: center;\n `,\n}"],"mappings":"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","names":["useEffect","useState","socket","useEffect","css","jsx","styles","css","jsx","jsxs","styles","useEffect","useRef","useState","css","keyframes","css","css","jsx","jsx","jsxs","styles","css","useState","useCallback","css","jsx","jsxs","_a","styles","jsx","jsxs","useRef","useState","useEffect","styles","pulse","keyframes","css","jsx","jsxs","useState","useEffect"]}
1
+ {"version":3,"sources":["../src/components/ChatWidget.tsx","../src/lib/upload.ts","../src/hooks/useChat.ts","../src/lib/socket.ts","../src/store/chatStore.ts","../src/components/FloatingButton.tsx","../src/components/ChatPanel.tsx","../src/components/HomeScreen.tsx","../src/components/ChatScreen.tsx","../src/components/MessageBubble.tsx","../src/components/MarkdownRenderer.tsx","../src/components/ChatInput.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { injectGlobal } from '@emotion/css'\nimport { ChatConfig } from '../types'\nimport { loadVisitorId } from '../lib/upload'\nimport { useChat } from '../hooks/useChat'\nimport { useChatStore } from '../store/chatStore'\nimport { FloatingButton } from './FloatingButton'\nimport { ChatPanel } from './ChatPanel'\nimport { HomeScreen } from './HomeScreen'\nimport { ChatScreen } from './ChatScreen'\n\nexport type ChatWidgetProps = {\n config: ChatConfig\n}\n\ntype View = 'home' | 'chat'\n\nexport const ChatWidget: React.FC<ChatWidgetProps> = ({ config }) => {\n const [isOpen, setIsOpen] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n const [view, setView] = useState<View>('home')\n\n const reset = useChatStore((s) => s.reset)\n\n const resolvedConfig: ChatConfig = {\n ...config,\n visitorId: config.visitorId ?? loadVisitorId() ?? undefined,\n }\n\n const hasHistory = !!resolvedConfig.visitorId\n\n const { status, messages, error, sendMessage, sendFile } = useChat(resolvedConfig)\n\n const handleNewConversation = () => {\n reset()\n setView('chat')\n }\n\n useEffect(() => {\n const isMobile = window.innerWidth <= 480\n if (isMobile) {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n }\n return () => {\n document.body.style.overflow = ''\n }\n }, [isOpen])\n\n return (\n <>\n <FloatingButton\n isOpen={isOpen}\n onToggle={() => setIsOpen((p) => !p)}\n />\n\n <ChatPanel\n isOpen={isOpen}\n isExpanded={isExpanded}\n >\n {view === 'home' ? (\n <HomeScreen\n onStartChat={handleNewConversation}\n onContinueChat={() => setView('chat')}\n hasHistory={hasHistory}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n />\n ) : (\n <ChatScreen\n messages={messages}\n onSendText={sendMessage}\n onSendFile={sendFile}\n onBack={() => setView('home')}\n onExpand={() => setIsExpanded((p) => !p)}\n isExpanded={isExpanded}\n status={status}\n error={error}\n />\n )}\n </ChatPanel>\n </>\n )\n}\n\ninjectGlobal`\n :root {\n --wds-primary: oklch(0.5811 0.2268 259.15);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.12);\n --wds-primary-border: oklch(0.7695 0.1177 255.22 / 0.4);\n --wds-bg: oklch(1 0 0);\n --wds-fg: oklch(0.145 0 0);\n --wds-muted: oklch(0.556 0 0);\n --wds-muted-bg: oklch(0.97 0 0);\n --wds-border: oklch(0.922 0 0);\n }\n\n @media (prefers-color-scheme: dark) {\n :root {\n --wds-bg: oklch(0.145 0 0);\n --wds-fg: oklch(0.985 0 0);\n --wds-muted: oklch(0.708 0 0);\n --wds-muted-bg: oklch(0.205 0 0);\n --wds-border: oklch(1 0 0 / 10%);\n --wds-primary-soft: oklch(0.5811 0.2268 259.15 / 0.15);\n }\n }\n\n [data-wds-root] * {\n box-sizing: border-box;\n text-align: left;\n }\n`","import type { ChatConfig } from \"../types\";\n\nconst VISITOR_ID_KEY = \"waysdrop_visitor_id\";\n\nexport const saveVisitorId = (id: string): void => {\n localStorage.setItem(VISITOR_ID_KEY, id);\n};\n\nexport const loadVisitorId = (): string | null => {\n return localStorage.getItem(VISITOR_ID_KEY);\n};\n\nexport const clearVisitorId = (): void => {\n localStorage.removeItem(VISITOR_ID_KEY);\n};\n\nexport const uploadFile = async (\n file: File,\n config: ChatConfig,\n): Promise<string> => {\n const formData = new FormData();\n formData.append(\"files\", file);\n\n const headers: HeadersInit = {};\n if (config.token) headers[\"Authorization\"] = `Bearer ${config.token}`;\n\n const res = await fetch(`${config.apiUrl}/file/bulk-upload`, {\n method: \"POST\",\n headers,\n body: formData,\n });\n\n if (!res.ok) {\n throw new Error(\"File upload failed\");\n }\n\n const json = await res.json();\n\n if (!json.success || !json.data?.urls?.length) {\n throw new Error(json.message || \"File upload failed\");\n }\n\n const first = json.data.urls[0];\n if (typeof first !== \"string\") {\n throw new Error(first?.error || \"File upload failed\");\n }\n\n return first;\n};","import { useEffect, useCallback } from 'react'\nimport { getSocket, destroySocket } from '../lib/socket'\nimport { saveVisitorId, uploadFile } from '../lib/upload'\nimport { useChatStore } from '../store/chatStore'\nimport type {\n ChatConfig,\n ConnectedPayload,\n SupportMessageSentPayload,\n SupportNewMessagePayload,\n SocketError,\n SupportSendMessageDTO,\n VisitorInfo,\n} from '../types'\n\nexport const useChat = (config: ChatConfig) => {\n const {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setStatus,\n setRole,\n setVisitorId,\n setChatId,\n addMessage,\n setError,\n setVisitorInfo,\n reset,\n } = useChatStore()\n\n\n useEffect(() => {\n const socket = getSocket(config)\n\n setStatus('connecting')\n socket.connect()\n\n socket.on('connected', (payload: ConnectedPayload) => {\n setStatus('connected')\n setRole(payload.role)\n\n if (payload.role === 'VISITOR') {\n saveVisitorId(payload.visitorId)\n setVisitorId(payload.visitorId)\n }\n })\n\n socket.on('support-message-sent', (payload: SupportMessageSentPayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('support-new-message', (payload: SupportNewMessagePayload) => {\n setChatId(payload.chatId)\n addMessage(payload.message)\n })\n\n socket.on('error', (err: SocketError) => {\n setError(err)\n setStatus('error')\n })\n\n return () => {\n destroySocket()\n reset()\n }\n }, [])\n\n\n const sendMessage = useCallback(\n (content: string, info?: VisitorInfo) => {\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n content,\n externalId: `msg-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n\n const sendFile = useCallback(\n async (file: File, content?: string, info?: VisitorInfo) => {\n const url = await uploadFile(file, config)\n\n const socket = getSocket(config)\n\n const dto: SupportSendMessageDTO = {\n file: url,\n ...(content ? { content } : {}),\n externalId: `file-${Date.now()}`,\n ...(info ?? visitorInfo\n ? {\n email: (info ?? visitorInfo)!.email,\n name: (info ?? visitorInfo)?.name,\n phone: (info ?? visitorInfo)?.phone,\n }\n : {}),\n }\n\n socket.emit('support-send-message', dto)\n },\n [config, visitorInfo]\n )\n\n return {\n status,\n role,\n visitorId,\n chatId,\n messages,\n error,\n visitorInfo,\n setVisitorInfo,\n sendMessage,\n sendFile,\n }\n}","import { io, Socket } from 'socket.io-client'\nimport type { ChatConfig } from '../types'\n\nlet socket: Socket | null = null\n\nexport const getSocket = (config: ChatConfig): Socket => {\n if (socket) return socket\n\n const { serverUrl, token, visitorId } = config\n\n socket = io(serverUrl, {\n transports: ['websocket', 'polling'],\n auth: {\n ...(token ? { token } : {}),\n ...(visitorId ? { visitorId } : {}),\n },\n autoConnect: false,\n })\n\n return socket\n}\n\nexport const destroySocket = (): void => {\n if (socket) {\n socket.disconnect()\n socket = null\n }\n}","import { create } from 'zustand'\nimport type {\n ChatState,\n ChatMessage,\n UserRole,\n SocketError,\n VisitorInfo,\n ConnectionStatus,\n} from '../types'\n\ntype ChatActions = {\n setStatus: (status: ConnectionStatus) => void\n setRole: (role: UserRole) => void\n setVisitorId: (id: string) => void\n setChatId: (id: string) => void\n addMessage: (message: ChatMessage) => void\n setError: (error: SocketError | null) => void\n setVisitorInfo: (info: VisitorInfo) => void\n reset: () => void\n}\n\nconst initialState: ChatState = {\n status: 'idle',\n role: null,\n visitorId: null,\n chatId: null,\n messages: [],\n error: null,\n visitorInfo: null,\n}\n\nexport const useChatStore = create<ChatState & ChatActions>((set) => ({\n ...initialState,\n\n setStatus: (status) => set({ status }),\n setRole: (role) => set({ role }),\n setVisitorId: (id) => set({ visitorId: id }),\n setChatId: (id) => set({ chatId: id }),\n addMessage: (message) =>\n set((state) => ({\n messages: [...state.messages, message],\n })),\n setError: (error) => set({ error }),\n setVisitorInfo: (info) => set({ visitorInfo: info }),\n reset: () => set(initialState),\n}))","import React, { useEffect, useState } from \"react\";\nimport { css } from \"@emotion/css\";\n\nconst BUTTON_SIZE = 56;\n\ninterface Props {\n isOpen: boolean;\n onToggle: () => void;\n}\n\nexport const FloatingButton: React.FC<Props> = ({ isOpen, onToggle }) => {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const check = () => setIsMobile(window.innerWidth <= 480);\n check();\n window.addEventListener(\"resize\", check);\n return () => window.removeEventListener(\"resize\", check);\n }, []);\n\n if (isMobile && isOpen) {\n return (\n <button\n className={styles.mobileCloseBtn}\n onClick={onToggle}\n type=\"button\"\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n );\n }\n\n return (\n <button className={styles.btn} onClick={onToggle} type=\"button\">\n <span className={styles.icon(!isOpen)}>\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z\" />\n </svg>\n </span>\n <span className={styles.icon(isOpen)}>\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </span>\n </button>\n );\n};\n\nconst styles = {\n btn: css`\n position: fixed;\n right: 30px;\n bottom: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n -webkit-user-select: none;\n &:hover {\n opacity: 0.92;\n }\n `,\n mobileCloseBtn: css`\n position: fixed;\n top: 16px;\n right: 20px;\n width: ${BUTTON_SIZE}px;\n height: ${BUTTON_SIZE}px;\n border-radius: 50%;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n `,\n icon: (visible: boolean) => css`\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n transition:\n opacity 0.2s,\n transform 0.2s;\n opacity: ${visible ? 1 : 0};\n transform: ${visible ? \"scale(1)\" : \"scale(0.6) rotate(30deg)\"};\n pointer-events: ${visible ? \"auto\" : \"none\"};\n `,\n};\n","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n isOpen: boolean\n isExpanded: boolean\n children: React.ReactNode\n}\n\nexport const ChatPanel: React.FC<Props> = ({ isOpen, isExpanded, children }) => {\n return (\n <div data-wds-root className={styles.panel(isOpen, isExpanded)}>\n <div className={styles.inner}>{children}</div>\n </div>\n )\n}\n\nconst styles = {\n panel: (isOpen: boolean, isExpanded: boolean) => css`\n position: fixed;\n bottom: 86px;\n z-index: 999998;\n transition: opacity 0.2s, transform 0.25s cubic-bezier(0.34, 1.2, 0.64, 1);\n opacity: ${isOpen ? 1 : 0};\n pointer-events: ${isOpen ? 'auto' : 'none'};\n\n ${isExpanded\n ? `\n width: min(760px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 120px));\n border-radius: 20px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.1);\n left: 50%;\n right: auto;\n translate: -50% 0;\n transform: ${isOpen ? 'scale(1)' : 'scale(0.95)'};\n transform-origin: bottom center;\n `\n : `\n width: 400px;\n height: 620px;\n border-radius: 20px;\n box-shadow: 0 12px 48px rgba(0,0,0,0.16), 0 2px 8px rgba(0,0,0,0.08);\n right: 22px;\n transform: ${isOpen ? 'translateY(0) scale(1)' : 'translateY(16px) scale(0.97)'};\n `}\n\n overflow: hidden;\n\n @media (max-width: 480px) {\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n width: 100% !important;\n height: 100% !important;\n border-radius: 0 !important;\n translate: none !important;\n }\n `,\n inner: css`\n width: 100%;\n height: 100%;\n overflow: hidden;\n border-radius: inherit;\n `,\n}","import React from 'react'\nimport { css } from '@emotion/css'\n\ninterface Props {\n onStartChat: () => void\n onContinueChat: () => void\n hasHistory: boolean\n onExpand: () => void\n isExpanded: boolean\n}\n\nexport const HomeScreen: React.FC<Props> = ({\n onStartChat,\n onContinueChat,\n hasHistory,\n onExpand,\n isExpanded,\n}) => {\n return (\n <div className={styles.wrapper}>\n <div className={styles.topBar}>\n <div className={styles.logoMark}>\n <img\n src=\"https://cdn.waysdrop.com/bulk/horizon_20260411202129966_d25edae2.png\"\n alt=\"Waysdrop\"\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n />\n </div>\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/>\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/>\n </svg>\n ) : (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/>\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.hero}>\n <h2 className={styles.heroTitle}>Hi there! ๐Ÿ‘‹</h2>\n <p className={styles.heroSub}>We're here to help. Ask us anything or share your feedback.</p>\n </div>\n\n <div className={styles.section}>\n <p className={styles.sectionLabel}>Conversations</p>\n {hasHistory ? (\n <button className={styles.conversationCard} onClick={onContinueChat}>\n <div className={styles.cardIcon}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n </div>\n <div className={styles.cardBody}>\n <span className={styles.cardTitle}>Continue conversation</span>\n <span className={styles.cardSub}>Tap to resume your last chat</span>\n </div>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n ) : (\n <div className={styles.emptyHistory}>\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ opacity: 0.25 }}>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n <p>No previous conversations</p>\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button className={styles.startBtn} onClick={onStartChat}>\n New conversation\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\"/>\n </svg>\n </button>\n <p className={styles.poweredBy}>Powered by Waysdrop</p>\n </div>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n text-align: left;\n `,\n topBar: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 18px 18px 0;\n flex-shrink: 0;\n `,\n logoMark: css`\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n hero: css`\n padding: 20px 20px 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n flex-shrink: 0;\n `,\n heroTitle: css`\n font-size: 1.375rem;\n font-weight: 700;\n color: var(--wds-fg);\n margin: 0;\n line-height: 1.2;\n text-align: left;\n `,\n heroSub: css`\n font-size: 0.9375rem;\n color: var(--wds-muted);\n margin: 0;\n line-height: 1.6;\n text-align: left;\n `,\n section: css`\n flex: 1;\n padding: 4px 18px 0;\n overflow-y: auto;\n `,\n sectionLabel: css`\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.07em;\n text-transform: uppercase;\n color: var(--wds-muted);\n margin: 0 0 12px 2px;\n text-align: left;\n `,\n conversationCard: css`\n display: flex;\n align-items: center;\n gap: 14px;\n width: 100%;\n padding: 14px 16px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n cursor: pointer;\n text-align: left;\n transition: border-color 0.15s, background 0.15s;\n color: var(--wds-fg);\n &:hover {\n border-color: var(--wds-primary);\n background: var(--wds-primary-soft);\n }\n `,\n cardIcon: css`\n width: 38px;\n height: 38px;\n border-radius: 10px;\n background: var(--wds-primary-soft);\n color: var(--wds-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n `,\n cardBody: css`\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 3px;\n `,\n cardTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n text-align: left;\n `,\n cardSub: css`\n font-size: 12px;\n color: var(--wds-muted);\n text-align: left;\n `,\n emptyHistory: css`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n padding: 40px 0;\n color: var(--wds-muted);\n font-size: 12px;\n `,\n footer: css`\n padding: 18px 18px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n flex-shrink: 0;\n border-top: 1px solid var(--wds-border);\n `,\n startBtn: css`\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n width: 100%;\n padding: 13px 16px;\n background: var(--wds-primary);\n color: #fff;\n border: none;\n border-radius: 14px;\n font-size: 0.9375rem;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.15s;\n font-family: inherit;\n &:hover { opacity: 0.88; }\n `,\n poweredBy: css`\n font-size: 11px;\n color: var(--wds-muted);\n margin: 0;\n opacity: 0.7;\n `,\n}","import React, { useEffect, useRef, useState } from \"react\";\nimport { css, keyframes } from \"@emotion/css\";\nimport { ChatMessage } from \"../types\";\nimport { MessageBubble } from \"./MessageBubble\";\nimport { ChatInput } from \"./ChatInput\";\n\ninterface Props {\n messages: ChatMessage[];\n onSendText: (content: string) => void;\n onSendFile: (file: File, content?: string) => Promise<void>;\n onBack: () => void;\n onExpand: () => void;\n isExpanded: boolean;\n status: string;\n error: { code: number; message: string } | null;\n}\n\nexport const ChatScreen: React.FC<Props> = ({\n messages,\n onSendText,\n onSendFile,\n onBack,\n onExpand,\n isExpanded,\n status,\n error,\n}) => {\n const bottomRef = useRef<HTMLDivElement>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const connected = status === \"connected\";\n const [showScrollBtn, setShowScrollBtn] = useState(false);\n\n const lastMsg = messages[messages.length - 1];\n const isThinking = connected && lastMsg?.direction === \"INBOUND\";\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n const handleScroll = () => {\n const el = scrollRef.current;\n if (!el) return;\n setShowScrollBtn(el.scrollHeight - el.scrollTop - el.clientHeight > 80);\n };\n\n return (\n <div className={styles.wrapper}>\n <div className={styles.header}>\n <button className={styles.iconBtn} onClick={onBack}>\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n\n <div className={styles.headerCenter}>\n <span className={styles.headerTitle}>Support</span>\n <span className={styles.statusDot(connected)} />\n <span className={styles.statusLabel}>\n {connected ? \"Online\" : \"Connecting...\"}\n </span>\n </div>\n\n <button className={styles.expandBtn} onClick={onExpand}>\n {isExpanded ? (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"4 14 10 14 10 20\" />\n <polyline points=\"20 10 14 10 14 4\" />\n <line x1=\"10\" y1=\"14\" x2=\"3\" y2=\"21\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n </svg>\n ) : (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </svg>\n )}\n </button>\n </div>\n\n <div className={styles.messagesWrap}>\n <div\n className={styles.messages}\n ref={scrollRef}\n onScroll={handleScroll}\n >\n {error && <div className={styles.errorBanner}>{error.message}</div>}\n {messages.length === 0 && connected && (\n <div className={styles.emptyState}>\n <p>Send a message to start the conversation.</p>\n </div>\n )}\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n <div ref={bottomRef} />\n </div>\n\n {showScrollBtn && (\n <button\n className={styles.scrollBtn}\n onClick={() =>\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" })\n }\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n )}\n </div>\n\n <ChatInput\n onSendText={onSendText}\n onSendFile={onSendFile}\n disabled={!connected}\n isThinking={isThinking}\n />\n </div>\n );\n};\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n`;\n\nconst styles = {\n wrapper: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--wds-bg);\n `,\n header: css`\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n border-bottom: 1px solid var(--wds-border);\n flex-shrink: 0;\n `,\n headerCenter: css`\n flex: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n `,\n headerTitle: css`\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--wds-fg);\n `,\n statusDot: (connected: boolean) => css`\n width: 7px;\n height: 7px;\n border-radius: 50%;\n flex-shrink: 0;\n background: ${connected ? \"#22c55e\" : \"#f59e0b\"};\n animation: ${connected ? \"none\" : `${pulse} 1.2s ease-in-out infinite`};\n `,\n statusLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n iconBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition:\n color 0.15s,\n background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n `,\n expandBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 6px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition:\n color 0.15s,\n background 0.15s;\n &:hover {\n color: var(--wds-fg);\n background: var(--wds-muted-bg);\n }\n @media (max-width: 480px) {\n display: none;\n }\n `,\n messagesWrap: css`\n flex: 1;\n position: relative;\n overflow: hidden;\n `,\n messages: css`\n position: absolute;\n inset: 0;\n overflow-y: auto;\n padding: 16px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n `,\n errorBanner: css`\n background: oklch(0.9705 0.0129 17.04);\n color: oklch(0.5054 0.1905 27.51);\n border: 1px solid oklch(0.8845 0.0592 18.27);\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 12px;\n text-align: center;\n `,\n emptyState: css`\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--wds-muted);\n font-size: 13px;\n text-align: center;\n padding: 40px 20px;\n `,\n scrollBtn: css`\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: var(--wds-bg);\n border: 1px solid var(--wds-border);\n color: var(--wds-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n transition:\n color 0.15s,\n border-color 0.15s;\n &:hover {\n color: var(--wds-primary);\n border-color: var(--wds-primary);\n }\n `,\n};\n","import React from 'react'\nimport { css } from '@emotion/css'\nimport { ChatMessage } from '../types'\nimport { MarkdownRenderer } from './MarkdownRenderer'\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\ninterface Props {\n message: ChatMessage\n}\n\nexport const MessageBubble: React.FC<Props> = ({ message }) => {\n const isCustomer = message.direction === 'OUTBOUND'\n const isBot = message.senderRole === 'BOT'\n\n return (\n <div className={styles.row(isCustomer)}>\n <div className={styles.group(isCustomer)}>\n {isBot && <span className={styles.botLabel}>Ways AI</span>}\n <div className={styles.bubble(isCustomer)}>\n {message.file && (\n <a href={message.file} target=\"_blank\" rel=\"noreferrer\" className={styles.fileLink(!!message.content)}>\n ๐Ÿ“Ž View attachment\n </a>\n )}\n {message.content && (\n isBot\n ? <MarkdownRenderer content={message.content} />\n : <p className={styles.text}>{message.content}</p>\n )}\n </div>\n <span className={styles.time}>{formatTime(message.createdAt)}</span>\n </div>\n </div>\n )\n}\n\nconst styles = {\n row: (isCustomer: boolean) => css`\n display: flex;\n width: 100%;\n justify-content: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n group: (isCustomer: boolean) => css`\n display: flex;\n flex-direction: column;\n max-width: 78%;\n gap: 4px;\n align-items: ${isCustomer ? 'flex-start' : 'flex-end'};\n `,\n botLabel: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n font-weight: 500;\n letter-spacing: 0.03em;\n `,\n bubble: (isCustomer: boolean) => css`\n border-radius: 18px;\n padding: 10px 14px;\n word-break: break-word;\n text-align: left;\n border-top-left-radius: ${isCustomer ? '4px' : '18px'};\n border-top-right-radius: ${isCustomer ? '18px' : '4px'};\n background: ${isCustomer ? 'var(--wds-muted-bg)' : 'var(--wds-primary)'};\n color: ${isCustomer ? 'var(--wds-fg)' : '#fff'};\n `,\n text: css`\n font-size: 0.875rem;\n line-height: 1.5;\n margin: 0;\n white-space: pre-wrap;\n text-align: left;\n `,\n fileLink: (hasContent: boolean) => css`\n font-size: 0.875rem;\n color: inherit;\n text-decoration: underline;\n display: block;\n text-align: left;\n ${hasContent ? 'margin-bottom: 6px;' : ''}\n `,\n time: css`\n font-size: 10px;\n color: var(--wds-muted);\n padding: 0 4px;\n `,\n}","import React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport { css } from '@emotion/css'\n\nconst markdownStyle = css`\n font-size: 0.875rem;\n line-height: 1.6;\n color: inherit;\n text-align: left;\n\n p {\n margin: 0 0 0.6rem 0;\n text-align: left;\n }\n p:last-child {\n margin-bottom: 0;\n }\n strong { font-weight: 600; }\n em { font-style: italic; }\n\n ul, ol {\n margin: 0.4rem 0 0.6rem 0;\n padding-left: 1.4rem;\n text-align: left;\n }\n ul { list-style-type: disc; }\n ol { list-style-type: decimal; }\n li {\n margin-bottom: 0.3rem;\n }\n li > ul, li > ol {\n margin: 0.25rem 0 0.25rem 0;\n padding-left: 1.2rem;\n }\n li:last-child { margin-bottom: 0; }\n\n hr {\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.25);\n margin: 0.75rem 0;\n }\n\n code {\n font-family: monospace;\n font-size: 0.8rem;\n background: rgba(255,255,255,0.15);\n border-radius: 4px;\n padding: 0.1rem 0.35rem;\n }\n pre {\n background: rgba(255,255,255,0.1);\n border-radius: 8px;\n padding: 0.75rem 1rem;\n overflow-x: auto;\n margin: 0.5rem 0;\n }\n pre code {\n background: none;\n padding: 0;\n font-size: 0.78rem;\n }\n blockquote {\n border-left: 3px solid rgba(255,255,255,0.25);\n margin: 0.5rem 0;\n padding-left: 0.75rem;\n opacity: 0.8;\n }\n a {\n color: rgba(255,255,255,0.85);\n text-decoration: underline;\n }\n h1, h2, h3 {\n font-weight: 600;\n margin: 0.6rem 0 0.3rem;\n line-height: 1.3;\n text-align: left;\n }\n h1 { font-size: 1rem; }\n h2 { font-size: 0.95rem; }\n h3 { font-size: 0.875rem; }\n`\n\ninterface Props {\n content: string\n}\n\nexport const MarkdownRenderer: React.FC<Props> = ({ content }) => {\n return (\n <div className={markdownStyle}>\n <ReactMarkdown>{content}</ReactMarkdown>\n </div>\n )\n}","import React, { useState, useRef, useCallback, KeyboardEvent } from 'react'\nimport { css, keyframes } from '@emotion/css'\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst pulse = keyframes`\n 0%, 100% { opacity: 0.4; transform: scaleY(0.6); }\n 50% { opacity: 1; transform: scaleY(1); }\n`\n\ninterface Props {\n onSendText: (content: string) => void\n onSendFile: (file: File, content?: string) => Promise<void>\n disabled?: boolean\n isThinking?: boolean\n}\n\nexport const ChatInput: React.FC<Props> = ({ onSendText, onSendFile, disabled, isThinking }) => {\n const [value, setValue] = useState('')\n const [uploading, setUploading] = useState(false)\n const [pendingFile, setPendingFile] = useState<File | null>(null)\n const [pendingPreview, setPendingPreview] = useState<string | null>(null)\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n const handleSend = useCallback(() => {\n const trimmed = value.trim()\n if ((!trimmed && !pendingFile) || disabled || uploading) return\n\n if (pendingFile) {\n setUploading(true)\n onSendFile(pendingFile, trimmed || undefined).finally(() => {\n setUploading(false)\n setPendingFile(null)\n setPendingPreview(null)\n setValue('')\n })\n } else if (trimmed) {\n onSendText(trimmed)\n setValue('')\n }\n\n textareaRef.current?.focus()\n }, [value, pendingFile, disabled, uploading, onSendText, onSendFile])\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSend()\n }\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file) return\n if (!file.type.startsWith('image/')) return\n setPendingFile(file)\n const reader = new FileReader()\n reader.onload = (ev) => setPendingPreview(ev.target?.result as string)\n reader.readAsDataURL(file)\n e.target.value = ''\n }\n\n const canSend = (value.trim() || pendingFile) && !disabled && !uploading\n\n return (\n <div className={styles.wrapper}>\n {isThinking && (\n <div className={styles.thinkingBar}>\n <div className={styles.thinkingDots}>\n <span className={styles.dot(0)} />\n <span className={styles.dot(1)} />\n <span className={styles.dot(2)} />\n </div>\n <span className={styles.thinkingLabel}>Ways AI is typing...</span>\n </div>\n )}\n\n {pendingPreview && (\n <div className={styles.imagePreview}>\n <img src={pendingPreview} alt=\"attachment\" className={styles.previewImg} />\n <button className={styles.removeFile} onClick={() => { setPendingFile(null); setPendingPreview(null) }}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n )}\n\n <div className={styles.inputRow}>\n <button\n className={styles.attachBtn}\n onClick={() => fileInputRef.current?.click()}\n disabled={disabled || uploading}\n type=\"button\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"3\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/>\n </svg>\n </button>\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className={styles.hiddenInput}\n onChange={handleFileChange}\n />\n\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a message...\"\n disabled={disabled || uploading}\n rows={1}\n />\n\n <button className={styles.sendBtn} onClick={handleSend} disabled={!canSend} type=\"button\">\n {uploading ? (\n <span className={styles.spinner} />\n ) : (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"5\"/><polyline points=\"5 12 12 5 19 12\"/>\n </svg>\n )}\n </button>\n </div>\n\n <p className={styles.hint}>Enter to send ยท Shift+Enter for new line</p>\n </div>\n )\n}\n\nconst styles = {\n wrapper: css`\n padding: 8px 12px 10px;\n border-top: 1px solid var(--wds-border);\n display: flex;\n flex-direction: column;\n gap: 6px;\n background: var(--wds-bg);\n flex-shrink: 0;\n `,\n thinkingBar: css`\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 2px 2px;\n `,\n thinkingDots: css`\n display: flex;\n align-items: center;\n gap: 3px;\n `,\n dot: (i: number) => css`\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--wds-primary);\n animation: ${pulse} 1.2s ease-in-out infinite;\n animation-delay: ${i * 0.18}s;\n display: inline-block;\n `,\n thinkingLabel: css`\n font-size: 11px;\n color: var(--wds-muted);\n `,\n imagePreview: css`\n position: relative;\n width: fit-content;\n margin: 0 2px;\n `,\n previewImg: css`\n width: 72px;\n height: 72px;\n object-fit: cover;\n border-radius: 10px;\n border: 1px solid var(--wds-border);\n display: block;\n `,\n removeFile: css`\n position: absolute;\n top: -6px;\n right: -6px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--wds-fg);\n color: var(--wds-bg);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n `,\n inputRow: css`\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--wds-muted-bg);\n border: 1px solid var(--wds-border);\n border-radius: 14px;\n padding: 4px 4px 4px 8px;\n transition: border-color 0.15s;\n &:focus-within {\n border-color: var(--wds-primary);\n background: var(--wds-bg);\n }\n `,\n attachBtn: css`\n background: none;\n border: none;\n cursor: pointer;\n color: var(--wds-muted);\n padding: 5px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: color 0.15s;\n &:hover:not(:disabled) {\n color: var(--wds-primary);\n }\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n `,\n hiddenInput: css`\n display: none;\n `,\n textarea: css`\n flex: 1;\n resize: none;\n border: none;\n padding: 6px 0;\n font-size: 0.875rem;\n font-family: inherit;\n line-height: 1.5;\n background: transparent;\n color: var(--wds-fg);\n outline: none;\n max-height: 120px;\n overflow-y: auto;\n &::placeholder { color: var(--wds-muted); }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n `,\n sendBtn: css`\n background: var(--wds-primary);\n border: none;\n border-radius: 10px;\n width: 34px;\n height: 34px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n color: #fff;\n flex-shrink: 0;\n transition: opacity 0.15s;\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n &:hover:not(:disabled) { opacity: 0.85; }\n `,\n spinner: css`\n width: 14px;\n height: 14px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: ${spin} 0.7s linear infinite;\n display: block;\n `,\n hint: css`\n font-size: 10px;\n color: var(--wds-muted);\n margin: 0;\n text-align: center;\n opacity: 0.7;\n text-align: center;\n `,\n}"],"mappings":"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","names":["useEffect","useState","socket","useEffect","css","jsx","styles","css","jsx","jsxs","styles","useEffect","useRef","useState","css","keyframes","css","css","jsx","jsx","jsxs","styles","css","useState","useCallback","css","jsx","jsxs","_a","styles","jsx","jsxs","useRef","useState","useEffect","styles","pulse","keyframes","css","jsx","jsxs","useState","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waysdrop/chat",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Floating support chat widget for React apps",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://waysdrop.com",
@@ -8,14 +8,19 @@
8
8
  "main": "./dist/index.cjs",
9
9
  "module": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
11
- "sideEffects": ["./dist/index.js", "./dist/index.cjs"],
11
+ "sideEffects": [
12
+ "./dist/index.js",
13
+ "./dist/index.cjs"
14
+ ],
12
15
  "exports": {
13
16
  ".": {
14
17
  "import": "./dist/index.js",
15
18
  "require": "./dist/index.cjs"
16
19
  }
17
20
  },
18
- "files": ["dist"],
21
+ "files": [
22
+ "dist"
23
+ ],
19
24
  "scripts": {
20
25
  "build": "tsup",
21
26
  "dev": "tsup --watch",
@@ -38,4 +43,4 @@
38
43
  "typescript": "^6.0.2",
39
44
  "tsup": "^8.5.1"
40
45
  }
41
- }
46
+ }