@waniwani/sdk 0.0.7 → 0.0.8
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/chat/embed.js +150 -0
- package/dist/chat/embed.js.map +1 -0
- package/dist/chat/index.d.ts +68 -0
- package/dist/chat/index.js +44 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/mcp/react.js +1 -1
- package/dist/mcp/react.js.map +1 -1
- package/package.json +18 -2
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface ChatTheme {
|
|
4
|
+
/** Primary brand color (bubble, send button, user messages) */
|
|
5
|
+
primaryColor?: string;
|
|
6
|
+
/** Primary text color on primary background */
|
|
7
|
+
primaryForeground?: string;
|
|
8
|
+
/** Chat panel background */
|
|
9
|
+
backgroundColor?: string;
|
|
10
|
+
/** Default text color */
|
|
11
|
+
textColor?: string;
|
|
12
|
+
/** Secondary/muted text */
|
|
13
|
+
mutedColor?: string;
|
|
14
|
+
/** Border color */
|
|
15
|
+
borderColor?: string;
|
|
16
|
+
/** Assistant message bubble background */
|
|
17
|
+
assistantBubbleColor?: string;
|
|
18
|
+
/** User message bubble background */
|
|
19
|
+
userBubbleColor?: string;
|
|
20
|
+
/** Input field background */
|
|
21
|
+
inputBackgroundColor?: string;
|
|
22
|
+
/** Border radius for the panel (px) */
|
|
23
|
+
borderRadius?: number;
|
|
24
|
+
/** Border radius for message bubbles (px) */
|
|
25
|
+
messageBorderRadius?: number;
|
|
26
|
+
/** Font family */
|
|
27
|
+
fontFamily?: string;
|
|
28
|
+
}
|
|
29
|
+
interface ChatWidgetProps {
|
|
30
|
+
/** WaniWani project API key */
|
|
31
|
+
apiKey?: string;
|
|
32
|
+
/** Chat API endpoint URL. Defaults to WaniWani hosted endpoint */
|
|
33
|
+
api?: string;
|
|
34
|
+
/** Initial greeting shown before user types */
|
|
35
|
+
welcomeMessage?: string;
|
|
36
|
+
/** Header title */
|
|
37
|
+
title?: string;
|
|
38
|
+
/** Header subtitle */
|
|
39
|
+
subtitle?: string;
|
|
40
|
+
/** Theme overrides */
|
|
41
|
+
theme?: ChatTheme;
|
|
42
|
+
/** Additional headers to send with chat API requests */
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
/** Additional body fields to send with each chat request */
|
|
45
|
+
body?: Record<string, unknown>;
|
|
46
|
+
/** Chat panel width in pixels */
|
|
47
|
+
width?: number;
|
|
48
|
+
/** Chat panel height in pixels */
|
|
49
|
+
height?: number;
|
|
50
|
+
/** Callback fired when a message is sent */
|
|
51
|
+
onMessageSent?: (message: string) => void;
|
|
52
|
+
/** Callback fired when a response is received */
|
|
53
|
+
onResponseReceived?: () => void;
|
|
54
|
+
}
|
|
55
|
+
interface ChatEmbedConfig extends Omit<ChatWidgetProps, "onMessageSent" | "onResponseReceived"> {
|
|
56
|
+
/** DOM element to mount into (defaults to document.body) */
|
|
57
|
+
container?: HTMLElement;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
declare function ChatWidget(props: ChatWidgetProps & {
|
|
61
|
+
_shadowRoot?: ShadowRoot;
|
|
62
|
+
}): react_jsx_runtime.JSX.Element;
|
|
63
|
+
|
|
64
|
+
declare const DEFAULT_THEME: Required<ChatTheme>;
|
|
65
|
+
declare function mergeTheme(userTheme?: ChatTheme): Required<ChatTheme>;
|
|
66
|
+
declare function themeToCSSProperties(theme: Required<ChatTheme>): Record<string, string>;
|
|
67
|
+
|
|
68
|
+
export { type ChatEmbedConfig, type ChatTheme, ChatWidget, type ChatWidgetProps, DEFAULT_THEME, mergeTheme, themeToCSSProperties };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{useChat as xe}from"@ai-sdk/react";import{DefaultChatTransport as ve}from"ai";import{useCallback as Ce,useEffect as j,useRef as S,useState as ke}from"react";import{useCallback as f,useRef as se}from"react";function H(r){let e=se(r);e.current=r;let a=f((l,s)=>{let{apiKey:u,baseUrl:c="https://app.waniwani.ai"}=e.current;u&&fetch(`${c}/api/mcp/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${u}`},body:JSON.stringify({event:l,properties:s})}).catch(()=>{})},[]),n=f(()=>{a("tool.called",{name:"chat.opened",type:"other"})},[a]),t=f(()=>{a("tool.called",{name:"chat.message_sent",type:"other"})},[a]),i=f(()=>{a("tool.called",{name:"chat.response_received",type:"other"})},[a]);return{trackChatOpened:n,trackMessageSent:t,trackResponseReceived:i}}function B(){return`
|
|
3
|
+
/* WaniWani Chat Widget Reset & Styles */
|
|
4
|
+
*,
|
|
5
|
+
*::before,
|
|
6
|
+
*::after {
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@keyframes ww-fade-in {
|
|
13
|
+
from { opacity: 0; }
|
|
14
|
+
to { opacity: 1; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@keyframes ww-bounce {
|
|
18
|
+
0%, 60%, 100% { transform: translateY(0); }
|
|
19
|
+
30% { transform: translateY(-4px); }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@keyframes ww-pulse {
|
|
23
|
+
0%, 100% { opacity: 0.4; }
|
|
24
|
+
50% { opacity: 1; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Scrollbar */
|
|
28
|
+
.ww-scrollbar::-webkit-scrollbar {
|
|
29
|
+
width: 4px;
|
|
30
|
+
}
|
|
31
|
+
.ww-scrollbar::-webkit-scrollbar-track {
|
|
32
|
+
background: transparent;
|
|
33
|
+
}
|
|
34
|
+
.ww-scrollbar::-webkit-scrollbar-thumb {
|
|
35
|
+
background: var(--ww-border);
|
|
36
|
+
border-radius: 4px;
|
|
37
|
+
}
|
|
38
|
+
.ww-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
39
|
+
background: var(--ww-muted);
|
|
40
|
+
}
|
|
41
|
+
`.trim()}var W={primaryColor:"#6366f1",primaryForeground:"#ffffff",backgroundColor:"#ffffff",textColor:"#1f2937",mutedColor:"#6b7280",borderColor:"#e5e7eb",assistantBubbleColor:"#f3f4f6",userBubbleColor:"#6366f1",inputBackgroundColor:"#f9fafb",borderRadius:16,messageBorderRadius:12,fontFamily:"system-ui, -apple-system, 'Segoe UI', sans-serif"},oe={primaryColor:"--ww-primary",primaryForeground:"--ww-primary-fg",backgroundColor:"--ww-bg",textColor:"--ww-text",mutedColor:"--ww-muted",borderColor:"--ww-border",assistantBubbleColor:"--ww-assistant-bubble",userBubbleColor:"--ww-user-bubble",inputBackgroundColor:"--ww-input-bg",borderRadius:"--ww-radius",messageBorderRadius:"--ww-msg-radius",fontFamily:"--ww-font"};function b(r){return{...W,...r}}function y(r){let e={};for(let[a,n]of Object.entries(oe)){let t=r[a];e[n]=typeof t=="number"?`${t}px`:String(t)}return e}import{jsx as x,jsxs as ie}from"react/jsx-runtime";function L(r){let{title:e,subtitle:a}=r;return x("div",{style:{display:"flex",alignItems:"center",padding:"14px 16px",borderBottom:"1px solid var(--ww-border)",backgroundColor:"var(--ww-primary)",color:"var(--ww-primary-fg)",borderRadius:"var(--ww-radius) var(--ww-radius) 0 0"},children:ie("div",{style:{display:"flex",flexDirection:"column",gap:"2px"},children:[x("span",{style:{fontWeight:600,fontSize:"15px"},children:e}),a&&x("span",{style:{fontSize:"12px",opacity:.85},children:a})]})})}import{useCallback as le,useEffect as pe,useRef as de}from"react";import{jsx as w,jsxs as _}from"react/jsx-runtime";var A={xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor","aria-hidden":"true",role:"img"};function U(r){let e=r.size??20;return _("svg",{...A,width:e,height:e,children:[w("title",{children:"Send"}),w("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5"})]})}function F(r){let e=r.size??14;return _("svg",{...A,width:e,height:e,children:[w("title",{children:"Tool"}),w("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.048.58.024 1.194-.14 1.743"})]})}import{jsx as v,jsxs as ue}from"react/jsx-runtime";function $(r){let{value:e,onChange:a,onSend:n,disabled:t}=r,i=de(null),l=le(s=>{s.key==="Enter"&&!s.shiftKey&&(s.preventDefault(),!t&&e.trim()&&n())},[t,e,n]);return pe(()=>{let s=i.current;s&&(s.style.height="auto",s.style.height=`${Math.min(s.scrollHeight,120)}px`)},[]),ue("div",{style:{display:"flex",alignItems:"flex-end",gap:"8px",padding:"12px 16px",borderTop:"1px solid var(--ww-border)",backgroundColor:"var(--ww-bg)"},children:[v("textarea",{ref:i,value:e,onChange:s=>a(s.target.value),onKeyDown:l,disabled:t,placeholder:"Type a message...",rows:1,style:{flex:1,resize:"none",border:"1px solid var(--ww-border)",borderRadius:"8px",padding:"8px 12px",fontSize:"14px",lineHeight:1.5,fontFamily:"var(--ww-font)",backgroundColor:"var(--ww-input-bg)",color:"var(--ww-text)",outline:"none",maxHeight:"120px",transition:"border-color 0.15s"},onFocus:s=>{s.currentTarget.style.borderColor="var(--ww-primary)"},onBlur:s=>{s.currentTarget.style.borderColor="var(--ww-border)"}}),v("button",{type:"button",onClick:n,disabled:t||!e.trim(),style:{display:"flex",alignItems:"center",justifyContent:"center",width:"36px",height:"36px",borderRadius:"8px",border:"none",backgroundColor:t||!e.trim()?"var(--ww-border)":"var(--ww-primary)",color:t||!e.trim()?"var(--ww-muted)":"var(--ww-primary-fg)",cursor:t||!e.trim()?"not-allowed":"pointer",transition:"background-color 0.15s, color 0.15s",flexShrink:0},"aria-label":"Send message",children:v(U,{size:18})})]})}import{useEffect as he,useRef as be}from"react";import{Fragment as V,jsx as o}from"react/jsx-runtime";function N(r){let e=r.text.split(/\n\n+/);return o(V,{children:e.map((a,n)=>o(ce,{block:a.trim()},n))})}function ce(r){let{block:e}=r;if(e.startsWith("```")){let n=e.split(`
|
|
42
|
+
`).slice(1,-1).join(`
|
|
43
|
+
`);return o("pre",{style:{backgroundColor:"var(--ww-border)",borderRadius:"6px",padding:"8px 12px",overflowX:"auto",fontSize:"13px",lineHeight:1.5,margin:"4px 0"},children:o("code",{children:n})})}if(/^[-*]\s/.test(e)){let a=e.split(/\n/).filter(n=>/^[-*]\s/.test(n));return o("ul",{style:{paddingLeft:"20px",margin:"4px 0"},children:a.map((n,t)=>o("li",{children:o(K,{text:n.replace(/^[-*]\s/,"")})},t))})}return o("p",{style:{margin:"4px 0",lineHeight:1.5},children:o(K,{text:e})})}function K(r){let e=fe(r.text);return o(V,{children:e.map((a,n)=>o(ge,{part:a},n))})}function ge(r){let{part:e}=r;return e.type==="text"?o("span",{children:e.value}):e.type==="bold"?o("strong",{style:{fontWeight:600},children:e.value}):e.type==="italic"?o("em",{children:e.value}):e.type==="code"?o("code",{style:{backgroundColor:"var(--ww-border)",borderRadius:"3px",padding:"1px 4px",fontSize:"0.9em"},children:e.value}):e.type==="link"?o("a",{href:e.href,target:"_blank",rel:"noopener noreferrer",style:{color:"var(--ww-primary)",textDecoration:"underline"},children:e.value}):null}function fe(r){let e=[],a=/`([^`]+)`|\*\*([^*]+)\*\*|\*([^*]+)\*|\[([^\]]+)\]\(([^)]+)\)/g,n=0,t;for(t=a.exec(r);t!==null;)t.index>n&&e.push({type:"text",value:r.slice(n,t.index)}),t[1]!=null?e.push({type:"code",value:t[1]}):t[2]!=null?e.push({type:"bold",value:t[2]}):t[3]!=null?e.push({type:"italic",value:t[3]}):t[4]!=null&&t[5]!=null&&e.push({type:"link",value:t[4],href:t[5]}),n=t.index+t[0].length,t=a.exec(r);return n<r.length&&e.push({type:"text",value:r.slice(n)}),e}import{jsx as p,jsxs as me}from"react/jsx-runtime";function O(r){let{message:e}=r,a=e.role==="user";return p("div",{style:{display:"flex",justifyContent:a?"flex-end":"flex-start",marginBottom:"8px",animation:"ww-fade-in 0.2s ease-out"},children:p("div",{style:{maxWidth:"85%",padding:"10px 14px",borderRadius:a?"var(--ww-msg-radius) var(--ww-msg-radius) 4px var(--ww-msg-radius)":"var(--ww-msg-radius) var(--ww-msg-radius) var(--ww-msg-radius) 4px",backgroundColor:a?"var(--ww-user-bubble)":"var(--ww-assistant-bubble)",color:a?"var(--ww-primary-fg)":"var(--ww-text)",fontSize:"14px",lineHeight:1.5,wordBreak:"break-word"},children:e.parts.map((n,t)=>p(we,{part:n,isUser:a},t))})})}function we(r){let{part:e,isUser:a}=r;if(e.type==="text"&&e.text)return a?p("span",{children:e.text}):p(N,{text:e.text});if(e.type.startsWith("tool-")||e.type==="tool-invocation"){let n=e.toolName??e.type.replace("tool-",""),t=e.state==="input-streaming"||e.state==="input-available";return me("div",{style:{display:"flex",alignItems:"center",gap:"6px",padding:"4px 0",fontSize:"12px",color:"var(--ww-muted)",fontStyle:"italic"},children:[p(F,{size:12}),p("span",{children:t?`Using ${n}...`:`Used ${n}`}),t&&p("span",{style:{animation:"ww-pulse 1.5s ease-in-out infinite"},children:"..."})]})}return null}import{jsx as d,jsxs as q}from"react/jsx-runtime";function G(r){let{messages:e,status:a,welcomeMessage:n}=r,t=be(null);he(()=>{t.current&&(t.current.scrollTop=t.current.scrollHeight)},[]);let i=a==="submitted"||a==="streaming";return q("div",{ref:t,className:"ww-scrollbar",style:{flex:1,overflowY:"auto",padding:"16px",display:"flex",flexDirection:"column"},children:[n&&e.length===0&&d("div",{style:{display:"flex",justifyContent:"flex-start",marginBottom:"8px"},children:d("div",{style:{maxWidth:"85%",padding:"10px 14px",borderRadius:"var(--ww-msg-radius) var(--ww-msg-radius) var(--ww-msg-radius) 4px",backgroundColor:"var(--ww-assistant-bubble)",color:"var(--ww-text)",fontSize:"14px",lineHeight:1.5},children:n})}),e.map(l=>d(O,{message:l},l.id)),i&&d("div",{style:{display:"flex",justifyContent:"flex-start",marginBottom:"8px"},children:q("div",{style:{padding:"10px 14px",borderRadius:"var(--ww-msg-radius) var(--ww-msg-radius) var(--ww-msg-radius) 4px",backgroundColor:"var(--ww-assistant-bubble)",display:"flex",gap:"4px",alignItems:"center"},children:[d(C,{delay:"0s"}),d(C,{delay:"0.15s"}),d(C,{delay:"0.3s"})]})})]})}function C(r){return d("span",{style:{width:"6px",height:"6px",borderRadius:"50%",backgroundColor:"var(--ww-muted)",animation:"ww-bounce 1.2s ease-in-out infinite",animationDelay:r.delay}})}import{jsx as k,jsxs as ye}from"react/jsx-runtime";function Y(r){let{messages:e,input:a,onInputChange:n,onSend:t,status:i,title:l,subtitle:s,welcomeMessage:u,width:c,height:m}=r;return ye("div",{className:"ww-panel",style:{width:`${c}px`,height:`${m}px`,display:"flex",flexDirection:"column",backgroundColor:"var(--ww-bg)",borderRadius:"var(--ww-radius)",border:"1px solid var(--ww-border)",boxShadow:"0 20px 60px -12px rgba(0, 0, 0, 0.15), 0 8px 20px -8px rgba(0, 0, 0, 0.1)",overflow:"hidden",fontFamily:"var(--ww-font)"},children:[k(L,{title:l,subtitle:s}),k(G,{messages:e,status:i,welcomeMessage:u}),k($,{value:a,onChange:n,onSend:t,disabled:i!=="ready"})]})}import{jsx as J}from"react/jsx-runtime";var Se="https://app.waniwani.ai/api/chat";function Me(r){let{apiKey:e,api:a=Se,welcomeMessage:n,title:t="Chat",subtitle:i,theme:l,headers:s,body:u,width:c=400,height:m=600,onMessageSent:M,onResponseReceived:X,_shadowRoot:h}=r,Z=b(l),Q=y(Z),{trackChatOpened:R,trackMessageSent:T,trackResponseReceived:ee}=H({apiKey:e}),te=S(new ve({api:a,headers:{...s,...e?{"x-waniwani-api-key":e}:{}},body:u})),{messages:re,sendMessage:P,status:ae}=xe({transport:te.current,onFinish(){ee(),X?.()}}),[g,I]=ke(""),ne=Ce(()=>{g.trim()&&(P({text:g}),T(),M?.(g),I(""))},[g,P,T,M]),E=S(!1);j(()=>{if(h&&!E.current){E.current=!0;let D=document.createElement("style");D.textContent=B(),h.appendChild(D)}},[h]);let z=S(!1);return j(()=>{z.current||(z.current=!0,R())},[R]),J("div",{style:Q,"data-waniwani-chat":"",children:J(Y,{messages:re,input:g,onInputChange:I,onSend:ne,status:ae,title:t,subtitle:i,welcomeMessage:n,width:c,height:m})})}export{Me as ChatWidget,W as DEFAULT_THEME,b as mergeTheme,y as themeToCSSProperties};
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/chat/components/chat-widget.tsx","../../src/chat/hooks/use-chat-tracking.ts","../../src/chat/styles.ts","../../src/chat/theme.ts","../../src/chat/components/chat-header.tsx","../../src/chat/components/chat-input.tsx","../../src/chat/icons.tsx","../../src/chat/components/chat-messages.tsx","../../src/chat/components/chat-markdown.tsx","../../src/chat/components/chat-message.tsx","../../src/chat/components/chat-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ChatWidgetProps } from \"../@types\";\nimport { useChatTracking } from \"../hooks/use-chat-tracking\";\nimport { buildStyleSheet } from \"../styles\";\nimport { mergeTheme, themeToCSSProperties } from \"../theme\";\nimport { ChatPanel } from \"./chat-panel\";\n\nconst DEFAULT_API = \"https://app.waniwani.ai/api/chat\";\n\nexport function ChatWidget(\n\tprops: ChatWidgetProps & { _shadowRoot?: ShadowRoot },\n) {\n\tconst {\n\t\tapiKey,\n\t\tapi = DEFAULT_API,\n\t\twelcomeMessage,\n\t\ttitle = \"Chat\",\n\t\tsubtitle,\n\t\ttheme: userTheme,\n\t\theaders: userHeaders,\n\t\tbody,\n\t\twidth = 400,\n\t\theight = 600,\n\t\tonMessageSent,\n\t\tonResponseReceived,\n\t\t_shadowRoot,\n\t} = props;\n\n\tconst resolvedTheme = mergeTheme(userTheme);\n\tconst cssVars = themeToCSSProperties(resolvedTheme);\n\n\tconst { trackChatOpened, trackMessageSent, trackResponseReceived } =\n\t\tuseChatTracking({ apiKey });\n\n\tconst transportRef = useRef(\n\t\tnew DefaultChatTransport({\n\t\t\tapi,\n\t\t\theaders: {\n\t\t\t\t...userHeaders,\n\t\t\t\t...(apiKey ? { \"x-waniwani-api-key\": apiKey } : {}),\n\t\t\t},\n\t\t\tbody,\n\t\t}),\n\t);\n\n\tconst { messages, sendMessage, status } = useChat({\n\t\ttransport: transportRef.current,\n\t\tonFinish() {\n\t\t\ttrackResponseReceived();\n\t\t\tonResponseReceived?.();\n\t\t},\n\t});\n\n\tconst [input, setInput] = useState(\"\");\n\n\tconst handleSend = useCallback(() => {\n\t\tif (!input.trim()) return;\n\t\tsendMessage({ text: input });\n\t\ttrackMessageSent();\n\t\tonMessageSent?.(input);\n\t\tsetInput(\"\");\n\t}, [input, sendMessage, trackMessageSent, onMessageSent]);\n\n\t// Inject stylesheet into shadow root for embed mode\n\tconst styleInjected = useRef(false);\n\tuseEffect(() => {\n\t\tif (_shadowRoot && !styleInjected.current) {\n\t\t\tstyleInjected.current = true;\n\t\t\tconst style = document.createElement(\"style\");\n\t\t\tstyle.textContent = buildStyleSheet();\n\t\t\t_shadowRoot.appendChild(style);\n\t\t}\n\t}, [_shadowRoot]);\n\n\t// Track chat opened on mount\n\tconst tracked = useRef(false);\n\tuseEffect(() => {\n\t\tif (!tracked.current) {\n\t\t\ttracked.current = true;\n\t\t\ttrackChatOpened();\n\t\t}\n\t}, [trackChatOpened]);\n\n\treturn (\n\t\t<div style={cssVars} data-waniwani-chat=\"\">\n\t\t\t<ChatPanel\n\t\t\t\tmessages={messages}\n\t\t\t\tinput={input}\n\t\t\t\tonInputChange={setInput}\n\t\t\t\tonSend={handleSend}\n\t\t\t\tstatus={status}\n\t\t\t\ttitle={title}\n\t\t\t\tsubtitle={subtitle}\n\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t\twidth={width}\n\t\t\t\theight={height}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","import { useCallback, useRef } from \"react\";\n\ninterface TrackingConfig {\n\tapiKey?: string;\n\tbaseUrl?: string;\n}\n\n/**\n * Lightweight browser-compatible tracking hook for chat events.\n * Fires events to the WaniWani API without requiring the full tracking client\n * (which depends on process.env).\n */\nexport function useChatTracking(config: TrackingConfig) {\n\tconst configRef = useRef(config);\n\tconfigRef.current = config;\n\n\tconst trackEvent = useCallback(\n\t\t(event: string, properties?: Record<string, unknown>) => {\n\t\t\tconst { apiKey, baseUrl = \"https://app.waniwani.ai\" } = configRef.current;\n\t\t\tif (!apiKey) return;\n\n\t\t\tfetch(`${baseUrl}/api/mcp/events`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tevent,\n\t\t\t\t\tproperties,\n\t\t\t\t}),\n\t\t\t}).catch(() => {\n\t\t\t\t// Silently fail - tracking should never break the chat\n\t\t\t});\n\t\t},\n\t\t[],\n\t);\n\n\tconst trackChatOpened = useCallback(() => {\n\t\ttrackEvent(\"tool.called\", { name: \"chat.opened\", type: \"other\" });\n\t}, [trackEvent]);\n\n\tconst trackMessageSent = useCallback(() => {\n\t\ttrackEvent(\"tool.called\", { name: \"chat.message_sent\", type: \"other\" });\n\t}, [trackEvent]);\n\n\tconst trackResponseReceived = useCallback(() => {\n\t\ttrackEvent(\"tool.called\", {\n\t\t\tname: \"chat.response_received\",\n\t\t\ttype: \"other\",\n\t\t});\n\t}, [trackEvent]);\n\n\treturn { trackChatOpened, trackMessageSent, trackResponseReceived };\n}\n","export function buildStyleSheet(): string {\n\treturn `\n/* WaniWani Chat Widget Reset & Styles */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n@keyframes ww-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes ww-bounce {\n 0%, 60%, 100% { transform: translateY(0); }\n 30% { transform: translateY(-4px); }\n}\n\n@keyframes ww-pulse {\n 0%, 100% { opacity: 0.4; }\n 50% { opacity: 1; }\n}\n\n/* Scrollbar */\n.ww-scrollbar::-webkit-scrollbar {\n width: 4px;\n}\n.ww-scrollbar::-webkit-scrollbar-track {\n background: transparent;\n}\n.ww-scrollbar::-webkit-scrollbar-thumb {\n background: var(--ww-border);\n border-radius: 4px;\n}\n.ww-scrollbar::-webkit-scrollbar-thumb:hover {\n background: var(--ww-muted);\n}\n`.trim();\n}\n","import type { ChatTheme } from \"./@types\";\n\nexport const DEFAULT_THEME: Required<ChatTheme> = {\n\tprimaryColor: \"#6366f1\",\n\tprimaryForeground: \"#ffffff\",\n\tbackgroundColor: \"#ffffff\",\n\ttextColor: \"#1f2937\",\n\tmutedColor: \"#6b7280\",\n\tborderColor: \"#e5e7eb\",\n\tassistantBubbleColor: \"#f3f4f6\",\n\tuserBubbleColor: \"#6366f1\",\n\tinputBackgroundColor: \"#f9fafb\",\n\tborderRadius: 16,\n\tmessageBorderRadius: 12,\n\tfontFamily: \"system-ui, -apple-system, 'Segoe UI', sans-serif\",\n};\n\nconst CSS_VAR_MAP: Record<keyof ChatTheme, string> = {\n\tprimaryColor: \"--ww-primary\",\n\tprimaryForeground: \"--ww-primary-fg\",\n\tbackgroundColor: \"--ww-bg\",\n\ttextColor: \"--ww-text\",\n\tmutedColor: \"--ww-muted\",\n\tborderColor: \"--ww-border\",\n\tassistantBubbleColor: \"--ww-assistant-bubble\",\n\tuserBubbleColor: \"--ww-user-bubble\",\n\tinputBackgroundColor: \"--ww-input-bg\",\n\tborderRadius: \"--ww-radius\",\n\tmessageBorderRadius: \"--ww-msg-radius\",\n\tfontFamily: \"--ww-font\",\n};\n\nexport function mergeTheme(userTheme?: ChatTheme): Required<ChatTheme> {\n\treturn { ...DEFAULT_THEME, ...userTheme };\n}\n\nexport function themeToCSSProperties(\n\ttheme: Required<ChatTheme>,\n): Record<string, string> {\n\tconst vars: Record<string, string> = {};\n\tfor (const [key, cssVar] of Object.entries(CSS_VAR_MAP)) {\n\t\tconst value = theme[key as keyof ChatTheme];\n\t\tvars[cssVar] = typeof value === \"number\" ? `${value}px` : String(value);\n\t}\n\treturn vars;\n}\n","interface ChatHeaderProps {\n\ttitle: string;\n\tsubtitle?: string;\n}\n\nexport function ChatHeader(props: ChatHeaderProps) {\n\tconst { title, subtitle } = props;\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tpadding: \"14px 16px\",\n\t\t\t\tborderBottom: \"1px solid var(--ww-border)\",\n\t\t\t\tbackgroundColor: \"var(--ww-primary)\",\n\t\t\t\tcolor: \"var(--ww-primary-fg)\",\n\t\t\t\tborderRadius: \"var(--ww-radius) var(--ww-radius) 0 0\",\n\t\t\t}}\n\t\t>\n\t\t\t<div style={{ display: \"flex\", flexDirection: \"column\", gap: \"2px\" }}>\n\t\t\t\t<span style={{ fontWeight: 600, fontSize: \"15px\" }}>{title}</span>\n\t\t\t\t{subtitle && (\n\t\t\t\t\t<span style={{ fontSize: \"12px\", opacity: 0.85 }}>{subtitle}</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","import type React from \"react\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { SendIcon } from \"../icons\";\n\ninterface ChatInputProps {\n\tvalue: string;\n\tonChange: (value: string) => void;\n\tonSend: () => void;\n\tdisabled: boolean;\n}\n\nexport function ChatInput(props: ChatInputProps) {\n\tconst { value, onChange, onSend, disabled } = props;\n\tconst textareaRef = useRef<HTMLTextAreaElement>(null);\n\n\tconst handleKeyDown = useCallback(\n\t\t(e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (e.key === \"Enter\" && !e.shiftKey) {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (!disabled && value.trim()) {\n\t\t\t\t\tonSend();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[disabled, value, onSend],\n\t);\n\n\t// Auto-resize textarea\n\tuseEffect(() => {\n\t\tconst textarea = textareaRef.current;\n\t\tif (textarea) {\n\t\t\ttextarea.style.height = \"auto\";\n\t\t\ttextarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n\t\t}\n\t}, []);\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\talignItems: \"flex-end\",\n\t\t\t\tgap: \"8px\",\n\t\t\t\tpadding: \"12px 16px\",\n\t\t\t\tborderTop: \"1px solid var(--ww-border)\",\n\t\t\t\tbackgroundColor: \"var(--ww-bg)\",\n\t\t\t}}\n\t\t>\n\t\t\t<textarea\n\t\t\t\tref={textareaRef}\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => onChange(e.target.value)}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tplaceholder=\"Type a message...\"\n\t\t\t\trows={1}\n\t\t\t\tstyle={{\n\t\t\t\t\tflex: 1,\n\t\t\t\t\tresize: \"none\",\n\t\t\t\t\tborder: \"1px solid var(--ww-border)\",\n\t\t\t\t\tborderRadius: \"8px\",\n\t\t\t\t\tpadding: \"8px 12px\",\n\t\t\t\t\tfontSize: \"14px\",\n\t\t\t\t\tlineHeight: 1.5,\n\t\t\t\t\tfontFamily: \"var(--ww-font)\",\n\t\t\t\t\tbackgroundColor: \"var(--ww-input-bg)\",\n\t\t\t\t\tcolor: \"var(--ww-text)\",\n\t\t\t\t\toutline: \"none\",\n\t\t\t\t\tmaxHeight: \"120px\",\n\t\t\t\t\ttransition: \"border-color 0.15s\",\n\t\t\t\t}}\n\t\t\t\tonFocus={(e) => {\n\t\t\t\t\te.currentTarget.style.borderColor = \"var(--ww-primary)\";\n\t\t\t\t}}\n\t\t\t\tonBlur={(e) => {\n\t\t\t\t\te.currentTarget.style.borderColor = \"var(--ww-border)\";\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tonClick={onSend}\n\t\t\t\tdisabled={disabled || !value.trim()}\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\twidth: \"36px\",\n\t\t\t\t\theight: \"36px\",\n\t\t\t\t\tborderRadius: \"8px\",\n\t\t\t\t\tborder: \"none\",\n\t\t\t\t\tbackgroundColor:\n\t\t\t\t\t\tdisabled || !value.trim()\n\t\t\t\t\t\t\t? \"var(--ww-border)\"\n\t\t\t\t\t\t\t: \"var(--ww-primary)\",\n\t\t\t\t\tcolor:\n\t\t\t\t\t\tdisabled || !value.trim()\n\t\t\t\t\t\t\t? \"var(--ww-muted)\"\n\t\t\t\t\t\t\t: \"var(--ww-primary-fg)\",\n\t\t\t\t\tcursor: disabled || !value.trim() ? \"not-allowed\" : \"pointer\",\n\t\t\t\t\ttransition: \"background-color 0.15s, color 0.15s\",\n\t\t\t\t\tflexShrink: 0,\n\t\t\t\t}}\n\t\t\t\taria-label=\"Send message\"\n\t\t\t>\n\t\t\t\t<SendIcon size={18} />\n\t\t\t</button>\n\t\t</div>\n\t);\n}\n","import type React from \"react\";\n\nconst iconProps: React.SVGProps<SVGSVGElement> = {\n\txmlns: \"http://www.w3.org/2000/svg\",\n\tfill: \"none\",\n\tviewBox: \"0 0 24 24\",\n\tstrokeWidth: 1.5,\n\tstroke: \"currentColor\",\n\t\"aria-hidden\": \"true\",\n\trole: \"img\",\n};\n\nexport function SendIcon(props: { size?: number }) {\n\tconst size = props.size ?? 20;\n\treturn (\n\t\t<svg {...iconProps} width={size} height={size}>\n\t\t\t<title>Send</title>\n\t\t\t<path\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\td=\"M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5\"\n\t\t\t/>\n\t\t</svg>\n\t);\n}\n\nexport function ToolIcon(props: { size?: number }) {\n\tconst size = props.size ?? 14;\n\treturn (\n\t\t<svg {...iconProps} width={size} height={size}>\n\t\t\t<title>Tool</title>\n\t\t\t<path\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\td=\"M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.048.58.024 1.194-.14 1.743\"\n\t\t\t/>\n\t\t</svg>\n\t);\n}\n","import { useEffect, useRef } from \"react\";\nimport { ChatMessage } from \"./chat-message\";\n\ninterface MessagePart {\n\ttype: string;\n\ttext?: string;\n\t[key: string]: unknown;\n}\n\ninterface Message {\n\tid: string;\n\trole: string;\n\tparts: MessagePart[];\n}\n\ninterface ChatMessagesProps {\n\tmessages: Message[];\n\tstatus: string;\n\twelcomeMessage?: string;\n}\n\nexport function ChatMessages(props: ChatMessagesProps) {\n\tconst { messages, status, welcomeMessage } = props;\n\tconst scrollRef = useRef<HTMLDivElement>(null);\n\n\tuseEffect(() => {\n\t\tif (scrollRef.current) {\n\t\t\tscrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n\t\t}\n\t}, []);\n\n\tconst showTyping = status === \"submitted\" || status === \"streaming\";\n\n\treturn (\n\t\t<div\n\t\t\tref={scrollRef}\n\t\t\tclassName=\"ww-scrollbar\"\n\t\t\tstyle={{\n\t\t\t\tflex: 1,\n\t\t\t\toverflowY: \"auto\",\n\t\t\t\tpadding: \"16px\",\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"column\",\n\t\t\t}}\n\t\t>\n\t\t\t{welcomeMessage && messages.length === 0 && (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\tjustifyContent: \"flex-start\",\n\t\t\t\t\t\tmarginBottom: \"8px\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tmaxWidth: \"85%\",\n\t\t\t\t\t\t\tpadding: \"10px 14px\",\n\t\t\t\t\t\t\tborderRadius:\n\t\t\t\t\t\t\t\t\"var(--ww-msg-radius) var(--ww-msg-radius) var(--ww-msg-radius) 4px\",\n\t\t\t\t\t\t\tbackgroundColor: \"var(--ww-assistant-bubble)\",\n\t\t\t\t\t\t\tcolor: \"var(--ww-text)\",\n\t\t\t\t\t\t\tfontSize: \"14px\",\n\t\t\t\t\t\t\tlineHeight: 1.5,\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{welcomeMessage}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{messages.map((message) => (\n\t\t\t\t<ChatMessage key={message.id} message={message} />\n\t\t\t))}\n\n\t\t\t{showTyping && (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\tjustifyContent: \"flex-start\",\n\t\t\t\t\t\tmarginBottom: \"8px\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tpadding: \"10px 14px\",\n\t\t\t\t\t\t\tborderRadius:\n\t\t\t\t\t\t\t\t\"var(--ww-msg-radius) var(--ww-msg-radius) var(--ww-msg-radius) 4px\",\n\t\t\t\t\t\t\tbackgroundColor: \"var(--ww-assistant-bubble)\",\n\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\tgap: \"4px\",\n\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<TypingDot delay=\"0s\" />\n\t\t\t\t\t\t<TypingDot delay=\"0.15s\" />\n\t\t\t\t\t\t<TypingDot delay=\"0.3s\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction TypingDot(props: { delay: string }) {\n\treturn (\n\t\t<span\n\t\t\tstyle={{\n\t\t\t\twidth: \"6px\",\n\t\t\t\theight: \"6px\",\n\t\t\t\tborderRadius: \"50%\",\n\t\t\t\tbackgroundColor: \"var(--ww-muted)\",\n\t\t\t\tanimation: `ww-bounce 1.2s ease-in-out infinite`,\n\t\t\t\tanimationDelay: props.delay,\n\t\t\t}}\n\t\t/>\n\t);\n}\n","/**\n * Minimal markdown renderer. Handles bold, italic, inline code, code blocks,\n * links, and unordered lists. No external dependencies.\n */\nexport function ChatMarkdown(props: { text: string }) {\n\tconst blocks = props.text.split(/\\n\\n+/);\n\n\treturn (\n\t\t<>\n\t\t\t{blocks.map((block, i) => (\n\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: static parsed text blocks\n\t\t\t\t<MarkdownBlock key={i} block={block.trim()} />\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction MarkdownBlock(props: { block: string }) {\n\tconst { block } = props;\n\n\t// Code block\n\tif (block.startsWith(\"```\")) {\n\t\tconst lines = block.split(\"\\n\");\n\t\tconst code = lines.slice(1, -1).join(\"\\n\");\n\t\treturn (\n\t\t\t<pre\n\t\t\t\tstyle={{\n\t\t\t\t\tbackgroundColor: \"var(--ww-border)\",\n\t\t\t\t\tborderRadius: \"6px\",\n\t\t\t\t\tpadding: \"8px 12px\",\n\t\t\t\t\toverflowX: \"auto\",\n\t\t\t\t\tfontSize: \"13px\",\n\t\t\t\t\tlineHeight: 1.5,\n\t\t\t\t\tmargin: \"4px 0\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<code>{code}</code>\n\t\t\t</pre>\n\t\t);\n\t}\n\n\t// Unordered list\n\tif (/^[-*]\\s/.test(block)) {\n\t\tconst items = block.split(/\\n/).filter((l) => /^[-*]\\s/.test(l));\n\t\treturn (\n\t\t\t<ul style={{ paddingLeft: \"20px\", margin: \"4px 0\" }}>\n\t\t\t\t{items.map((item, i) => (\n\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: static list items\n\t\t\t\t\t<li key={i}>\n\t\t\t\t\t\t<InlineMarkdown text={item.replace(/^[-*]\\s/, \"\")} />\n\t\t\t\t\t</li>\n\t\t\t\t))}\n\t\t\t</ul>\n\t\t);\n\t}\n\n\t// Paragraph\n\treturn (\n\t\t<p style={{ margin: \"4px 0\", lineHeight: 1.5 }}>\n\t\t\t<InlineMarkdown text={block} />\n\t\t</p>\n\t);\n}\n\nfunction InlineMarkdown(props: { text: string }) {\n\tconst parts = parseInline(props.text);\n\treturn (\n\t\t<>\n\t\t\t{parts.map((part, i) => (\n\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: static inline parsed parts\n\t\t\t\t<InlinePart key={i} part={part} />\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction InlinePart(props: { part: InlinePartData }) {\n\tconst { part } = props;\n\tif (part.type === \"text\") return <span>{part.value}</span>;\n\tif (part.type === \"bold\")\n\t\treturn <strong style={{ fontWeight: 600 }}>{part.value}</strong>;\n\tif (part.type === \"italic\") return <em>{part.value}</em>;\n\tif (part.type === \"code\")\n\t\treturn (\n\t\t\t<code\n\t\t\t\tstyle={{\n\t\t\t\t\tbackgroundColor: \"var(--ww-border)\",\n\t\t\t\t\tborderRadius: \"3px\",\n\t\t\t\t\tpadding: \"1px 4px\",\n\t\t\t\t\tfontSize: \"0.9em\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{part.value}\n\t\t\t</code>\n\t\t);\n\tif (part.type === \"link\")\n\t\treturn (\n\t\t\t<a\n\t\t\t\thref={part.href}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tstyle={{\n\t\t\t\t\tcolor: \"var(--ww-primary)\",\n\t\t\t\t\ttextDecoration: \"underline\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{part.value}\n\t\t\t</a>\n\t\t);\n\treturn null;\n}\n\ntype InlinePartData =\n\t| { type: \"text\"; value: string }\n\t| { type: \"bold\"; value: string }\n\t| { type: \"italic\"; value: string }\n\t| { type: \"code\"; value: string }\n\t| { type: \"link\"; value: string; href: string };\n\nfunction parseInline(text: string): InlinePartData[] {\n\tconst parts: InlinePartData[] = [];\n\t// Match: `code`, **bold**, *italic*, [text](url)\n\tconst regex =\n\t\t/`([^`]+)`|\\*\\*([^*]+)\\*\\*|\\*([^*]+)\\*|\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n\tlet lastIndex = 0;\n\tlet match: RegExpExecArray | null;\n\n\tmatch = regex.exec(text);\n\twhile (match !== null) {\n\t\tif (match.index > lastIndex) {\n\t\t\tparts.push({ type: \"text\", value: text.slice(lastIndex, match.index) });\n\t\t}\n\n\t\tif (match[1] != null) {\n\t\t\tparts.push({ type: \"code\", value: match[1] });\n\t\t} else if (match[2] != null) {\n\t\t\tparts.push({ type: \"bold\", value: match[2] });\n\t\t} else if (match[3] != null) {\n\t\t\tparts.push({ type: \"italic\", value: match[3] });\n\t\t} else if (match[4] != null && match[5] != null) {\n\t\t\tparts.push({ type: \"link\", value: match[4], href: match[5] });\n\t\t}\n\n\t\tlastIndex = match.index + match[0].length;\n\t\tmatch = regex.exec(text);\n\t}\n\n\tif (lastIndex < text.length) {\n\t\tparts.push({ type: \"text\", value: text.slice(lastIndex) });\n\t}\n\n\treturn parts;\n}\n","import { ToolIcon } from \"../icons\";\nimport { ChatMarkdown } from \"./chat-markdown\";\n\ninterface MessagePart {\n\ttype: string;\n\ttext?: string;\n\ttoolName?: string;\n\tstate?: string;\n\t[key: string]: unknown;\n}\n\ninterface Message {\n\tid: string;\n\trole: string;\n\tparts: MessagePart[];\n}\n\nexport function ChatMessage(props: { message: Message }) {\n\tconst { message } = props;\n\tconst isUser = message.role === \"user\";\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tjustifyContent: isUser ? \"flex-end\" : \"flex-start\",\n\t\t\t\tmarginBottom: \"8px\",\n\t\t\t\tanimation: \"ww-fade-in 0.2s ease-out\",\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tmaxWidth: \"85%\",\n\t\t\t\t\tpadding: \"10px 14px\",\n\t\t\t\t\tborderRadius: isUser\n\t\t\t\t\t\t? \"var(--ww-msg-radius) var(--ww-msg-radius) 4px var(--ww-msg-radius)\"\n\t\t\t\t\t\t: \"var(--ww-msg-radius) var(--ww-msg-radius) var(--ww-msg-radius) 4px\",\n\t\t\t\t\tbackgroundColor: isUser\n\t\t\t\t\t\t? \"var(--ww-user-bubble)\"\n\t\t\t\t\t\t: \"var(--ww-assistant-bubble)\",\n\t\t\t\t\tcolor: isUser ? \"var(--ww-primary-fg)\" : \"var(--ww-text)\",\n\t\t\t\t\tfontSize: \"14px\",\n\t\t\t\t\tlineHeight: 1.5,\n\t\t\t\t\twordBreak: \"break-word\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{message.parts.map((part, i) => (\n\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: message parts are append-only\n\t\t\t\t\t<MessagePartRenderer key={i} part={part} isUser={isUser} />\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction MessagePartRenderer(props: { part: MessagePart; isUser: boolean }) {\n\tconst { part, isUser } = props;\n\n\tif (part.type === \"text\" && part.text) {\n\t\treturn isUser ? (\n\t\t\t<span>{part.text}</span>\n\t\t) : (\n\t\t\t<ChatMarkdown text={part.text} />\n\t\t);\n\t}\n\n\tif (part.type.startsWith(\"tool-\") || part.type === \"tool-invocation\") {\n\t\tconst toolName = part.toolName ?? part.type.replace(\"tool-\", \"\");\n\t\tconst isLoading =\n\t\t\tpart.state === \"input-streaming\" || part.state === \"input-available\";\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tgap: \"6px\",\n\t\t\t\t\tpadding: \"4px 0\",\n\t\t\t\t\tfontSize: \"12px\",\n\t\t\t\t\tcolor: \"var(--ww-muted)\",\n\t\t\t\t\tfontStyle: \"italic\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<ToolIcon size={12} />\n\t\t\t\t<span>{isLoading ? `Using ${toolName}...` : `Used ${toolName}`}</span>\n\t\t\t\t{isLoading && (\n\t\t\t\t\t<span style={{ animation: \"ww-pulse 1.5s ease-in-out infinite\" }}>\n\t\t\t\t\t\t...\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn null;\n}\n","import { ChatHeader } from \"./chat-header\";\nimport { ChatInput } from \"./chat-input\";\nimport { ChatMessages } from \"./chat-messages\";\n\ninterface MessagePart {\n\ttype: string;\n\ttext?: string;\n\t[key: string]: unknown;\n}\n\ninterface Message {\n\tid: string;\n\trole: string;\n\tparts: MessagePart[];\n}\n\ninterface ChatPanelProps {\n\tmessages: Message[];\n\tinput: string;\n\tonInputChange: (value: string) => void;\n\tonSend: () => void;\n\tstatus: string;\n\ttitle: string;\n\tsubtitle?: string;\n\twelcomeMessage?: string;\n\twidth: number;\n\theight: number;\n}\n\nexport function ChatPanel(props: ChatPanelProps) {\n\tconst {\n\t\tmessages,\n\t\tinput,\n\t\tonInputChange,\n\t\tonSend,\n\t\tstatus,\n\t\ttitle,\n\t\tsubtitle,\n\t\twelcomeMessage,\n\t\twidth,\n\t\theight,\n\t} = props;\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"ww-panel\"\n\t\t\tstyle={{\n\t\t\t\twidth: `${width}px`,\n\t\t\t\theight: `${height}px`,\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"column\",\n\t\t\t\tbackgroundColor: \"var(--ww-bg)\",\n\t\t\t\tborderRadius: \"var(--ww-radius)\",\n\t\t\t\tborder: \"1px solid var(--ww-border)\",\n\t\t\t\tboxShadow:\n\t\t\t\t\t\"0 20px 60px -12px rgba(0, 0, 0, 0.15), 0 8px 20px -8px rgba(0, 0, 0, 0.1)\",\n\t\t\t\toverflow: \"hidden\",\n\t\t\t\tfontFamily: \"var(--ww-font)\",\n\t\t\t}}\n\t\t>\n\t\t\t<ChatHeader title={title} subtitle={subtitle} />\n\t\t\t<ChatMessages\n\t\t\t\tmessages={messages}\n\t\t\t\tstatus={status}\n\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t/>\n\t\t\t<ChatInput\n\t\t\t\tvalue={input}\n\t\t\t\tonChange={onInputChange}\n\t\t\t\tonSend={onSend}\n\t\t\t\tdisabled={status !== \"ready\"}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"mappings":"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","names":["useChat","DefaultChatTransport","useCallback","useEffect","useRef","useState","useCallback","useRef","useChatTracking","config","configRef","trackEvent","event","properties","apiKey","baseUrl","trackChatOpened","trackMessageSent","trackResponseReceived","buildStyleSheet","DEFAULT_THEME","CSS_VAR_MAP","mergeTheme","userTheme","themeToCSSProperties","theme","vars","key","cssVar","value","jsx","jsxs","ChatHeader","props","title","subtitle","useCallback","useEffect","useRef","jsx","jsxs","iconProps","SendIcon","props","size","ToolIcon","jsx","jsxs","ChatInput","props","value","onChange","onSend","disabled","textareaRef","useRef","handleKeyDown","useCallback","e","useEffect","textarea","SendIcon","useEffect","useRef","Fragment","jsx","ChatMarkdown","props","blocks","block","i","MarkdownBlock","code","items","l","item","InlineMarkdown","parts","parseInline","part","InlinePart","text","regex","lastIndex","match","jsx","jsxs","ChatMessage","props","message","isUser","part","i","MessagePartRenderer","ChatMarkdown","toolName","isLoading","ToolIcon","jsx","jsxs","ChatMessages","props","messages","status","welcomeMessage","scrollRef","useRef","useEffect","showTyping","message","ChatMessage","TypingDot","jsx","jsxs","ChatPanel","props","messages","input","onInputChange","onSend","status","title","subtitle","welcomeMessage","width","height","ChatHeader","ChatMessages","ChatInput","jsx","DEFAULT_API","ChatWidget","props","apiKey","api","welcomeMessage","title","subtitle","userTheme","userHeaders","body","width","height","onMessageSent","onResponseReceived","_shadowRoot","resolvedTheme","mergeTheme","cssVars","themeToCSSProperties","trackChatOpened","trackMessageSent","trackResponseReceived","useChatTracking","transportRef","useRef","DefaultChatTransport","messages","sendMessage","status","useChat","input","setInput","useState","handleSend","useCallback","styleInjected","useEffect","style","buildStyleSheet","tracked","ChatPanel"]}
|
package/dist/mcp/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{a as $}from"../chunk-SCDEAZN4.js";import{b as T}from"../chunk-OVQDB7QX.js";import{Fragment as Ce,jsx as E,jsxs as Se}from"react/jsx-runtime";function Me({baseUrl:e}){return Se(Ce,{children:[E("base",{href:e}),E("script",{children:`window.innerBaseUrl = ${JSON.stringify(e)}`}),E("script",{children:'window.__isChatGptApp = typeof window.openai !== "undefined";'}),E("script",{children:"("+(()=>{let t=window.innerBaseUrl,i=document.documentElement;new MutationObserver(p=>{p.forEach(n=>{if(n.type==="attributes"&&n.target===i){let d=n.attributeName;d&&d!=="suppresshydrationwarning"&&i.removeAttribute(d)}})}).observe(i,{attributes:!0,attributeOldValue:!0});let u=history.replaceState;history.replaceState=(p,n,d)=>{let r=new URL(d??"",window.location.href),h=r.pathname+r.search+r.hash;u.call(history,n,h)};let c=history.pushState;history.pushState=(p,n,d)=>{let r=new URL(d??"",window.location.href),h=r.pathname+r.search+r.hash;c.call(history,n,h)};let g=new URL(t).origin,f=window.self!==window.top;if(window.addEventListener("click",p=>{let n=p?.target?.closest("a");if(!n||!n.href)return;let d=new URL(n.href,window.location.href);if(d.origin!==window.location.origin&&d.origin!==g)try{window.openai&&(window.openai?.openExternal({href:n.href}),p.preventDefault())}catch{console.warn("openExternal failed, likely not in OpenAI client")}},!0),f&&window.location.origin!==g){let p=window.fetch;window.fetch=(n,d)=>{let r;if(typeof n=="string"||n instanceof URL?r=new URL(n,window.location.href):r=new URL(n.url,window.location.href),r.origin===g)return typeof n=="string"||n instanceof URL?n=r.toString():n=new Request(r.toString(),n),p.call(window,n,{...d,mode:"cors"});if(r.origin===window.location.origin){let h=new URL(t);return h.pathname=r.pathname,h.search=r.search,h.hash=r.hash,r=h,typeof n=="string"||n instanceof URL?n=r.toString():n=new Request(r.toString(),n),p.call(window,n,{...d,mode:"cors"})}return p.call(window,n,d)}}}).toString()+")()"})]})}import{useCallback as w,useEffect as M,useRef as K,useState as b}from"react";var J={theme:"dark",userAgent:{device:{type:"desktop"},capabilities:{hover:!0,touch:!1}},locale:"en",maxHeight:800,displayMode:"inline",safeArea:{insets:{top:0,bottom:0,left:0,right:0}},toolInput:{},toolOutput:null,toolResponseMetadata:null,widgetState:null},N={...J};function R(e){typeof window>"u"||window.openai||(N={...J,toolOutput:e??null},window.openai={...N,requestDisplayMode:async({mode:t})=>(v("displayMode",t),{mode:t}),callTool:async(t,i)=>(console.log(`[DevMode] callTool: ${t}`,i),{result:JSON.stringify({mock:!0,tool:t,args:i})}),sendFollowUpMessage:async({prompt:t})=>{console.log(`[DevMode] sendFollowUpMessage: ${t}`)},openExternal:({href:t})=>{console.log(`[DevMode] openExternal: ${t}`),window.open(t,"_blank")},setWidgetState:async t=>{v("widgetState",t)}},window.dispatchEvent(new T({globals:N})))}function v(e,t){typeof window>"u"||!window.openai||(N[e]=t,window.openai[e]=t,window.dispatchEvent(new T({globals:{[e]:t}})))}function U(){return{...N}}function W(e){v("toolOutput",e)}function O(e){v("displayMode",e)}function A(e){v("theme",e)}import{Fragment as B,jsx as o,jsxs as s}from"react/jsx-runtime";var L=150;function q({className:e}){return s("svg",{className:e,viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Dev Controls",children:[o("rect",{x:"4",y:"4",width:"10",height:"10",rx:"2",stroke:"currentColor",strokeWidth:"1.5"}),o("rect",{x:"10",y:"10",width:"10",height:"10",rx:"2",stroke:"currentColor",strokeWidth:"1.5",fill:"currentColor",fillOpacity:"0.15"})]})}function Te({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:o("path",{d:"M18 6L6 18M6 6l12 12"})})}function Ne({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:o("rect",{x:"2",y:"4",width:"12",height:"8",rx:"1.5",stroke:"currentColor",strokeWidth:"1.25"})})}function Re({className:e}){return s("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:[o("rect",{x:"1.5",y:"3",width:"13",height:"10",rx:"1.5",stroke:"currentColor",strokeWidth:"1.25"}),o("rect",{x:"8.5",y:"7",width:"5",height:"4",rx:"0.75",fill:"currentColor"})]})}function We({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:o("path",{d:"M2 5.5V3.5C2 2.95 2.45 2.5 3 2.5H5.5M10.5 2.5H13C13.55 2.5 14 2.95 14 3.5V5.5M14 10.5V12.5C14 13.05 13.55 13.5 13 13.5H10.5M5.5 13.5H3C2.45 13.5 2 13.05 2 12.5V10.5",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round",strokeLinejoin:"round"})})}function Oe({className:e}){return s("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:[o("circle",{cx:"8",cy:"8",r:"2.5",stroke:"currentColor",strokeWidth:"1.25"}),o("path",{d:"M8 2v1.5M8 12.5V14M2 8h1.5M12.5 8H14M4.11 4.11l1.06 1.06M10.83 10.83l1.06 1.06M4.11 11.89l1.06-1.06M10.83 5.17l1.06-1.06",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round"})]})}function Ae({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:o("path",{d:"M13.5 9.5a5.5 5.5 0 01-7-7 5.5 5.5 0 107 7z",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round",strokeLinejoin:"round"})})}function De({className:e}){return s("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:[o("path",{d:"M2.5 8a5.5 5.5 0 019.37-3.9M13.5 8a5.5 5.5 0 01-9.37 3.9",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round"}),o("path",{d:"M12.5 2v3h-3M3.5 14v-3h3",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round",strokeLinejoin:"round"})]})}var Ie=`
|
|
2
|
+
import{a as $}from"../chunk-SCDEAZN4.js";import{b as T}from"../chunk-OVQDB7QX.js";import{Fragment as Ce,jsx as E,jsxs as Se}from"react/jsx-runtime";function Me({baseUrl:e}){return Se(Ce,{children:[E("base",{href:e}),E("script",{children:`window.innerBaseUrl = ${JSON.stringify(e)}`}),E("script",{children:'window.__isChatGptApp = typeof window.openai !== "undefined";'}),E("script",{children:"("+(()=>{let t=window.innerBaseUrl,i=document.documentElement;new MutationObserver(p=>{p.forEach(n=>{if(n.type==="attributes"&&n.target===i){let d=n.attributeName;d&&d!=="suppresshydrationwarning"&&d!=="class"&&d!=="style"&&i.removeAttribute(d)}})}).observe(i,{attributes:!0,attributeOldValue:!0});let u=history.replaceState;history.replaceState=(p,n,d)=>{let r=new URL(d??"",window.location.href),h=r.pathname+r.search+r.hash;u.call(history,n,h)};let c=history.pushState;history.pushState=(p,n,d)=>{let r=new URL(d??"",window.location.href),h=r.pathname+r.search+r.hash;c.call(history,n,h)};let g=new URL(t).origin,f=window.self!==window.top;if(window.addEventListener("click",p=>{let n=p?.target?.closest("a");if(!n||!n.href)return;let d=new URL(n.href,window.location.href);if(d.origin!==window.location.origin&&d.origin!==g)try{window.openai&&(window.openai?.openExternal({href:n.href}),p.preventDefault())}catch{console.warn("openExternal failed, likely not in OpenAI client")}},!0),f&&window.location.origin!==g){let p=window.fetch;window.fetch=(n,d)=>{let r;if(typeof n=="string"||n instanceof URL?r=new URL(n,window.location.href):r=new URL(n.url,window.location.href),r.origin===g)return typeof n=="string"||n instanceof URL?n=r.toString():n=new Request(r.toString(),n),p.call(window,n,{...d,mode:"cors"});if(r.origin===window.location.origin){let h=new URL(t);return h.pathname=r.pathname,h.search=r.search,h.hash=r.hash,r=h,typeof n=="string"||n instanceof URL?n=r.toString():n=new Request(r.toString(),n),p.call(window,n,{...d,mode:"cors"})}return p.call(window,n,d)}}}).toString()+")()"})]})}import{useCallback as w,useEffect as M,useRef as K,useState as b}from"react";var J={theme:"dark",userAgent:{device:{type:"desktop"},capabilities:{hover:!0,touch:!1}},locale:"en",maxHeight:800,displayMode:"inline",safeArea:{insets:{top:0,bottom:0,left:0,right:0}},toolInput:{},toolOutput:null,toolResponseMetadata:null,widgetState:null},N={...J};function R(e){typeof window>"u"||window.openai||(N={...J,toolOutput:e??null},window.openai={...N,requestDisplayMode:async({mode:t})=>(v("displayMode",t),{mode:t}),callTool:async(t,i)=>(console.log(`[DevMode] callTool: ${t}`,i),{result:JSON.stringify({mock:!0,tool:t,args:i})}),sendFollowUpMessage:async({prompt:t})=>{console.log(`[DevMode] sendFollowUpMessage: ${t}`)},openExternal:({href:t})=>{console.log(`[DevMode] openExternal: ${t}`),window.open(t,"_blank")},setWidgetState:async t=>{v("widgetState",t)}},window.dispatchEvent(new T({globals:N})))}function v(e,t){typeof window>"u"||!window.openai||(N[e]=t,window.openai[e]=t,window.dispatchEvent(new T({globals:{[e]:t}})))}function U(){return{...N}}function W(e){v("toolOutput",e)}function O(e){v("displayMode",e)}function A(e){v("theme",e)}import{Fragment as B,jsx as o,jsxs as s}from"react/jsx-runtime";var L=150;function q({className:e}){return s("svg",{className:e,viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Dev Controls",children:[o("rect",{x:"4",y:"4",width:"10",height:"10",rx:"2",stroke:"currentColor",strokeWidth:"1.5"}),o("rect",{x:"10",y:"10",width:"10",height:"10",rx:"2",stroke:"currentColor",strokeWidth:"1.5",fill:"currentColor",fillOpacity:"0.15"})]})}function Te({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:o("path",{d:"M18 6L6 18M6 6l12 12"})})}function Ne({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:o("rect",{x:"2",y:"4",width:"12",height:"8",rx:"1.5",stroke:"currentColor",strokeWidth:"1.25"})})}function Re({className:e}){return s("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:[o("rect",{x:"1.5",y:"3",width:"13",height:"10",rx:"1.5",stroke:"currentColor",strokeWidth:"1.25"}),o("rect",{x:"8.5",y:"7",width:"5",height:"4",rx:"0.75",fill:"currentColor"})]})}function We({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:o("path",{d:"M2 5.5V3.5C2 2.95 2.45 2.5 3 2.5H5.5M10.5 2.5H13C13.55 2.5 14 2.95 14 3.5V5.5M14 10.5V12.5C14 13.05 13.55 13.5 13 13.5H10.5M5.5 13.5H3C2.45 13.5 2 13.05 2 12.5V10.5",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round",strokeLinejoin:"round"})})}function Oe({className:e}){return s("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:[o("circle",{cx:"8",cy:"8",r:"2.5",stroke:"currentColor",strokeWidth:"1.25"}),o("path",{d:"M8 2v1.5M8 12.5V14M2 8h1.5M12.5 8H14M4.11 4.11l1.06 1.06M10.83 10.83l1.06 1.06M4.11 11.89l1.06-1.06M10.83 5.17l1.06-1.06",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round"})]})}function Ae({className:e}){return o("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:o("path",{d:"M13.5 9.5a5.5 5.5 0 01-7-7 5.5 5.5 0 107 7z",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round",strokeLinejoin:"round"})})}function De({className:e}){return s("svg",{"aria-hidden":"true",className:e,viewBox:"0 0 16 16",fill:"none",children:[o("path",{d:"M2.5 8a5.5 5.5 0 019.37-3.9M13.5 8a5.5 5.5 0 01-9.37 3.9",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round"}),o("path",{d:"M12.5 2v3h-3M3.5 14v-3h3",stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round",strokeLinejoin:"round"})]})}var Ie=`
|
|
3
3
|
@keyframes devPanelSlideIn {
|
|
4
4
|
0% {
|
|
5
5
|
opacity: 0;
|