@anker-in/campaign-ui 0.2.11-beta.36 → 0.2.11-beta.38
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/cjs/components/LiveChatWidget/components/ChatInput.d.ts +1 -1
- package/dist/cjs/components/LiveChatWidget/components/ChatInput.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/ChatInput.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/ChatWindow.d.ts +1 -1
- package/dist/cjs/components/LiveChatWidget/components/ChatWindow.js.map +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js +1 -1
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/types.d.ts +1 -1
- package/dist/cjs/components/LiveChatWidget/types.js.map +1 -1
- package/dist/esm/components/LiveChatWidget/components/ChatInput.d.ts +1 -1
- package/dist/esm/components/LiveChatWidget/components/ChatInput.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/ChatInput.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/ChatWindow.d.ts +1 -1
- package/dist/esm/components/LiveChatWidget/components/ChatWindow.js.map +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.js +1 -1
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/types.d.ts +1 -1
- package/package.json +4 -3
- package/src/components/LiveChatWidget/components/ChatInput.tsx +7 -5
- package/src/components/LiveChatWidget/components/ChatWindow.tsx +1 -1
- package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +21 -0
- package/src/components/LiveChatWidget/hooks/useChatState.ts +4 -12
- package/src/components/LiveChatWidget/types.ts +1 -1
- package/src/styles/livechat.css +3 -3
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var h=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var R=(e,n)=>{for(var s in n)h(e,s,{get:n[s],enumerable:!0})},N=(e,n,s,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of v(n))!F.call(e,o)&&o!==s&&h(e,o,{get:()=>n[o],enumerable:!(i=E(n,o))||i.enumerable});return e};var A=e=>N(h({},"__esModule",{value:!0}),e);var M={};R(M,{ChatInput:()=>H});module.exports=A(M);var t=require("react/jsx-runtime"),r=require("react");const D=()=>(0,t.jsxs)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[(0,t.jsx)("path",{d:"M10.2069 15.6997V4.69971",stroke:"white","stroke-width":"2","stroke-linecap":"round"}),(0,t.jsx)("path",{d:"M15.3995 8.50341L10.9506 4.05446C10.534 3.6379 9.85866 3.63791 9.4421 4.05446L5.00005 8.49651",stroke:"white","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"})]}),H=({value:e,onChange:n,onSend:s,placeholder:i="",disabled:o=!1,autoFocus:x=!1,maxLength:l=5e3,bottomTips:p,className:f=""})=>{const u=(0,r.useRef)(null),c=(0,r.useRef)(!1);(0,r.useEffect)(()=>{const a=u.current;if(!a)return;a.style.height="auto";const k=Math.min(a.scrollHeight,120);a.style.height=`${k}px`},[e]);const m=()=>{c.current=!0},b=()=>{c.current=!1},w=a=>{if(a.key==="Enter"&&!a.shiftKey){if(c.current)return;a.preventDefault(),e.trim()&&!o&&s()}},C=a=>{const g=a.target.value;g.length<=l&&n(g)},y=()=>{e.trim()&&!o&&s()},d=e.trim().length>0&&!o;return(0,t.jsxs)("div",{className:`flex flex-col gap-2 bg-white px-4 py-4 ${f}`,children:[(0,t.jsx)("div",{className:"flex items-center gap-2 rounded-2xl",style:{background:"linear-gradient(to right, #7687F3, #7687F3, #4DA8F5, #A3DFCE)",padding:"2px"},children:(0,t.jsxs)("div",{className:"flex flex-1 items-center gap-2 bg-white px-3 py-2",style:{borderRadius:"14px"},children:[(0,t.jsx)("textarea",{ref:u,value:e,onChange:C,onKeyDown:w,onCompositionStart:m,onCompositionEnd:b,placeholder:i,disabled:o,autoFocus:x,rows:1,className:"flex-1 resize-none bg-transparent font-bold text-sm text-gray-900 outline-none placeholder:text-gray-400 disabled:cursor-not-allowed disabled:opacity-50",style:{resize:"none"}}),e.length>l*.8&&(0,t.jsxs)("span",{className:"text-xs text-gray-400",children:[e.length,"/",l]}),(0,t.jsx)("button",{type:"button",onClick:y,disabled:!d,className:`shrink-0 rounded-full p-2 transition-all ${d?" active:scale-95":"cursor-not-allowed "}`,style:d?{background:"linear-gradient(to bottom, #A3DFCE, #4DA8F5, #7687F3)"}:{background:"#BEBEBE"},"aria-label":"Send message",children:(0,t.jsx)(D,{})})]})}),p&&(0,t.jsx)("p",{className:"px-3 font-bold text-[12px] text-[#767880] tracking-tight leading-[1.4]",children:p})]})};
|
|
2
2
|
//# sourceMappingURL=ChatInput.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/LiveChatWidget/components/ChatInput.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u804A\u5929\u8F93\u5165\u6846\u7EC4\u4EF6\n * \u63D0\u4F9B\u6587\u672C\u8F93\u5165\u548C\u53D1\u9001\u6309\u94AE\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u8F93\u5165\u6846\u8BBE\u8BA1\n */\n\nimport React, { useRef, useEffect } from 'react'\n\nexport interface ChatInputProps {\n /**\n * \u8F93\u5165\u6846\u5F53\u524D\u503C\n */\n value: string\n\n /**\n * \u503C\u53D8\u5316\u56DE\u8C03\n */\n onChange: (value: string) => void\n\n /**\n * \u53D1\u9001\u6D88\u606F\u56DE\u8C03\n */\n onSend: () => void\n\n /**\n * \u5360\u4F4D\u7B26\u6587\u672C\n * @default \"\u8F93\u5165\u6D88\u606F...\"\n */\n placeholder?: string\n\n /**\n * \u662F\u5426\u7981\u7528\u8F93\u5165\n * @default false\n */\n disabled?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u805A\u7126\n * @default false\n */\n autoFocus?: boolean\n\n /**\n * \u6700\u5927\u5B57\u7B26\u6570\n * @default 5000\n */\n maxLength?: number\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5E95\u90E8\u63D0\u793A\u6587\u672C\n *
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,GAgEE,IAAAI,EAAA,6BA1DFC,EAAyC,iBAyDzC,MAAMC,EAAqB,OACzB,QAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,MAAM,6BAChE,oBAAC,QAAK,EAAE,2BAA2B,OAAO,QAAQ,eAAa,IAAI,iBAAe,QAAQ,KAC1F,OAAC,QACC,EAAE,gGACF,OAAO,QACP,eAAa,IACb,iBAAe,QACf,kBAAgB,QAClB,GACF,EA4BWJ,EAAsC,CAAC,CAClD,MAAAK,EACA,SAAAC,EACA,OAAAC,EACA,YAAAC,EAAc,GACd,SAAAC,EAAW,GACX,UAAAC,EAAY,GACZ,UAAAC,EAAY,IACZ,WAAAC,
|
|
4
|
+
"sourcesContent": ["/**\n * \u804A\u5929\u8F93\u5165\u6846\u7EC4\u4EF6\n * \u63D0\u4F9B\u6587\u672C\u8F93\u5165\u548C\u53D1\u9001\u6309\u94AE\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u8F93\u5165\u6846\u8BBE\u8BA1\n */\n\nimport React, { useRef, useEffect } from 'react'\n\nexport interface ChatInputProps {\n /**\n * \u8F93\u5165\u6846\u5F53\u524D\u503C\n */\n value: string\n\n /**\n * \u503C\u53D8\u5316\u56DE\u8C03\n */\n onChange: (value: string) => void\n\n /**\n * \u53D1\u9001\u6D88\u606F\u56DE\u8C03\n */\n onSend: () => void\n\n /**\n * \u5360\u4F4D\u7B26\u6587\u672C\n * @default \"\u8F93\u5165\u6D88\u606F...\"\n */\n placeholder?: string\n\n /**\n * \u662F\u5426\u7981\u7528\u8F93\u5165\n * @default false\n */\n disabled?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u805A\u7126\n * @default false\n */\n autoFocus?: boolean\n\n /**\n * \u6700\u5927\u5B57\u7B26\u6570\n * @default 5000\n */\n maxLength?: number\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5E95\u90E8\u63D0\u793A\u6587\u672C\n * \u4E0D\u4F20\u5165\u5219\u4E0D\u663E\u793A\n */\n bottomTips?: string\n}\n\n/**\n * \u53D1\u9001\u56FE\u6807 (\u5411\u4E0A\u7BAD\u5934)\n */\nconst SendIcon: React.FC = () => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10.2069 15.6997V4.69971\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" />\n <path\n d=\"M15.3995 8.50341L10.9506 4.05446C10.534 3.6379 9.85866 3.63791 9.4421 4.05446L5.00005 8.49651\"\n stroke=\"white\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n)\n\n/**\n * \u804A\u5929\u8F93\u5165\u6846\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u591A\u884C\u6587\u672C\u8F93\u5165\uFF08\u81EA\u52A8\u589E\u957F\uFF09\n * - Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\n * - \u5B57\u7B26\u6570\u9650\u5236\uFF085000\uFF09\n * - \u7981\u7528\u72B6\u6001\uFF08\u53D1\u9001\u4E2D\uFF09\n * - \u53D1\u9001\u6309\u94AE\uFF08\u7A7A\u5185\u5BB9\u65F6\u7981\u7528\uFF09\n *\n * \u6837\u5F0F\uFF1A\n * - \u56FA\u5B9A\u5E95\u90E8\n * - \u8FB9\u6846\u5206\u9694\u4E0A\u65B9\u5185\u5BB9\n * - \u81EA\u9002\u5E94\u9AD8\u5EA6\uFF081-5 \u884C\uFF09\n *\n * @example\n * ```tsx\n * <ChatInput\n * value={inputValue}\n * onChange={setInputValue}\n * onSend={handleSend}\n * disabled={isStreaming}\n * />\n * ```\n */\nexport const ChatInput: React.FC<ChatInputProps> = ({\n value,\n onChange,\n onSend,\n placeholder = '',\n disabled = false,\n autoFocus = false,\n maxLength = 5000,\n bottomTips,\n className = '',\n}) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n // \u8DDF\u8E2A\u8F93\u5165\u6CD5\u72B6\u6001\uFF08\u662F\u5426\u6B63\u5728\u4F7F\u7528\u62FC\u97F3\u8F93\u5165\u7B49\uFF09\n const isComposingRef = useRef(false)\n\n /**\n * \u81EA\u52A8\u8C03\u6574 textarea \u9AD8\u5EA6\n */\n useEffect(() => {\n const textarea = textareaRef.current\n if (!textarea) return\n\n // \u91CD\u7F6E\u9AD8\u5EA6\u4EE5\u83B7\u53D6\u6B63\u786E\u7684 scrollHeight\n textarea.style.height = 'auto'\n\n // \u8BBE\u7F6E\u9AD8\u5EA6\uFF0C\u6700\u5927 5 \u884C\uFF08\u7EA6 120px\uFF09\n const maxHeight = 120\n const newHeight = Math.min(textarea.scrollHeight, maxHeight)\n textarea.style.height = `${newHeight}px`\n }, [value])\n\n /**\n * \u5904\u7406\u8F93\u5165\u6CD5\u5F00\u59CB\n */\n const handleCompositionStart = () => {\n isComposingRef.current = true\n }\n\n /**\n * \u5904\u7406\u8F93\u5165\u6CD5\u7ED3\u675F\n */\n const handleCompositionEnd = () => {\n isComposingRef.current = false\n }\n\n /**\n * \u5904\u7406\u952E\u76D8\u4E8B\u4EF6\n * Enter \u53D1\u9001\uFF0CShift+Enter \u6362\u884C\n * \u6CE8\u610F\uFF1A\u8F93\u5165\u6CD5\u6FC0\u6D3B\u65F6\uFF08\u5982\u62FC\u97F3\u8F93\u5165\u4E2D\uFF09\uFF0C\u56DE\u8F66\u952E\u4E0D\u5E94\u53D1\u9001\u6D88\u606F\n */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n // \u5982\u679C\u6B63\u5728\u4F7F\u7528\u8F93\u5165\u6CD5\uFF08\u5982\u62FC\u97F3\u8F93\u5165\uFF09\uFF0C\u5219\u4E0D\u53D1\u9001\u6D88\u606F\n // \u8BA9\u8F93\u5165\u6CD5\u5148\u5B8C\u6210\u5B57\u7B26\u9009\u62E9\n if (isComposingRef.current) {\n return\n }\n\n event.preventDefault()\n if (value.trim() && !disabled) {\n onSend()\n }\n }\n }\n\n /**\n * \u5904\u7406\u8F93\u5165\u53D8\u5316\n */\n const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n const newValue = event.target.value\n\n // \u5B57\u7B26\u6570\u9650\u5236\n if (newValue.length <= maxLength) {\n onChange(newValue)\n }\n }\n\n /**\n * \u5904\u7406\u53D1\u9001\u6309\u94AE\u70B9\u51FB\n */\n const handleSendClick = () => {\n if (value.trim() && !disabled) {\n onSend()\n }\n }\n\n const canSend = value.trim().length > 0 && !disabled\n\n return (\n <div className={`flex flex-col gap-2 bg-white px-4 py-4 ${className}`}>\n {/* \u8F93\u5165\u6846\u5BB9\u5668 - \u5E26\u6E10\u53D8\u8FB9\u6846 */}\n <div\n className=\"flex items-center gap-2 rounded-2xl\"\n style={{\n background: 'linear-gradient(to right, #7687F3, #7687F3, #4DA8F5, #A3DFCE)',\n padding: '2px',\n }}\n >\n {/* \u5185\u90E8\u767D\u8272\u80CC\u666F */}\n <div className=\"flex flex-1 items-center gap-2 bg-white px-3 py-2\" style={{ borderRadius: '14px' }}>\n {/* \u6587\u672C\u8F93\u5165\u6846 */}\n <textarea\n ref={textareaRef}\n value={value}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n placeholder={placeholder}\n disabled={disabled}\n autoFocus={autoFocus}\n rows={1}\n className=\"flex-1 resize-none bg-transparent font-bold text-sm text-gray-900 outline-none placeholder:text-gray-400 disabled:cursor-not-allowed disabled:opacity-50\"\n style={{\n resize: 'none',\n }}\n />\n\n {/* \u5B57\u7B26\u6570\u63D0\u793A (\u63A5\u8FD1\u4E0A\u9650\u65F6\u663E\u793A) */}\n {value.length > maxLength * 0.8 && (\n <span className=\"text-xs text-gray-400\">\n {value.length}/{maxLength}\n </span>\n )}\n\n {/* \u53D1\u9001\u6309\u94AE */}\n <button\n type=\"button\"\n onClick={handleSendClick}\n disabled={!canSend}\n className={`shrink-0 rounded-full p-2 transition-all ${canSend ? ' active:scale-95' : 'cursor-not-allowed '}`}\n style={\n canSend\n ? {\n background: 'linear-gradient(to bottom, #A3DFCE, #4DA8F5, #7687F3)',\n }\n : { background: '#BEBEBE' }\n }\n aria-label=\"Send message\"\n >\n <SendIcon />\n </button>\n </div>\n </div>\n {bottomTips && (\n <p className=\"px-3 font-bold text-[12px] text-[#767880] tracking-tight leading-[1.4]\">\n {bottomTips}\n </p>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,GAgEE,IAAAI,EAAA,6BA1DFC,EAAyC,iBAyDzC,MAAMC,EAAqB,OACzB,QAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,MAAM,6BAChE,oBAAC,QAAK,EAAE,2BAA2B,OAAO,QAAQ,eAAa,IAAI,iBAAe,QAAQ,KAC1F,OAAC,QACC,EAAE,gGACF,OAAO,QACP,eAAa,IACb,iBAAe,QACf,kBAAgB,QAClB,GACF,EA4BWJ,EAAsC,CAAC,CAClD,MAAAK,EACA,SAAAC,EACA,OAAAC,EACA,YAAAC,EAAc,GACd,SAAAC,EAAW,GACX,UAAAC,EAAY,GACZ,UAAAC,EAAY,IACZ,WAAAC,EACA,UAAAC,EAAY,EACd,IAAM,CACJ,MAAMC,KAAc,UAA4B,IAAI,EAE9CC,KAAiB,UAAO,EAAK,KAKnC,aAAU,IAAM,CACd,MAAMC,EAAWF,EAAY,QAC7B,GAAI,CAACE,EAAU,OAGfA,EAAS,MAAM,OAAS,OAIxB,MAAMC,EAAY,KAAK,IAAID,EAAS,aADlB,GACyC,EAC3DA,EAAS,MAAM,OAAS,GAAGC,CAAS,IACtC,EAAG,CAACZ,CAAK,CAAC,EAKV,MAAMa,EAAyB,IAAM,CACnCH,EAAe,QAAU,EAC3B,EAKMI,EAAuB,IAAM,CACjCJ,EAAe,QAAU,EAC3B,EAOMK,EAAiBC,GAAoD,CACzE,GAAIA,EAAM,MAAQ,SAAW,CAACA,EAAM,SAAU,CAG5C,GAAIN,EAAe,QACjB,OAGFM,EAAM,eAAe,EACjBhB,EAAM,KAAK,GAAK,CAACI,GACnBF,EAAO,CAEX,CACF,EAKMe,EAAgBD,GAAkD,CACtE,MAAME,EAAWF,EAAM,OAAO,MAG1BE,EAAS,QAAUZ,GACrBL,EAASiB,CAAQ,CAErB,EAKMC,EAAkB,IAAM,CACxBnB,EAAM,KAAK,GAAK,CAACI,GACnBF,EAAO,CAEX,EAEMkB,EAAUpB,EAAM,KAAK,EAAE,OAAS,GAAK,CAACI,EAE5C,SACE,QAAC,OAAI,UAAW,0CAA0CI,CAAS,GAEjE,oBAAC,OACC,UAAU,sCACV,MAAO,CACL,WAAY,gEACZ,QAAS,KACX,EAGA,oBAAC,OAAI,UAAU,oDAAoD,MAAO,CAAE,aAAc,MAAO,EAE/F,oBAAC,YACC,IAAKC,EACL,MAAOT,EACP,SAAUiB,EACV,UAAWF,EACX,mBAAoBF,EACpB,iBAAkBC,EAClB,YAAaX,EACb,SAAUC,EACV,UAAWC,EACX,KAAM,EACN,UAAU,2JACV,MAAO,CACL,OAAQ,MACV,EACF,EAGCL,EAAM,OAASM,EAAY,OAC1B,QAAC,QAAK,UAAU,wBACb,UAAAN,EAAM,OAAO,IAAEM,GAClB,KAIF,OAAC,UACC,KAAK,SACL,QAASa,EACT,SAAU,CAACC,EACX,UAAW,4CAA4CA,EAAU,mBAAqB,qBAAqB,GAC3G,MACEA,EACI,CACE,WAAY,uDACd,EACA,CAAE,WAAY,SAAU,EAE9B,aAAW,eAEX,mBAACrB,EAAA,EAAS,EACZ,GACF,EACF,EACCQ,MACC,OAAC,KAAE,UAAU,yEACV,SAAAA,EACH,GAEJ,CAEJ",
|
|
6
6
|
"names": ["ChatInput_exports", "__export", "ChatInput", "__toCommonJS", "import_jsx_runtime", "import_react", "SendIcon", "value", "onChange", "onSend", "placeholder", "disabled", "autoFocus", "maxLength", "bottomTips", "className", "textareaRef", "isComposingRef", "textarea", "newHeight", "handleCompositionStart", "handleCompositionEnd", "handleKeyDown", "event", "handleChange", "newValue", "handleSendClick", "canSend"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/LiveChatWidget/components/ChatWindow.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u804A\u5929\u7A97\u53E3\u5BB9\u5668\u7EC4\u4EF6\n * \u5305\u542B\u5934\u90E8\u3001\u6D88\u606F\u5217\u8868\u3001\u8F93\u5165\u6846\u7684\u5B8C\u6574\u804A\u5929\u754C\u9762\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u7A97\u53E3\u8BBE\u8BA1\n */\n\nimport React, { useState, useRef, useEffect, useCallback } from 'react'\nimport type { Message, MessageRenderer } from '../types'\nimport { ChatHeader } from './ChatHeader'\nimport { MessageList } from './MessageList'\nimport { ChatInput } from './ChatInput'\nimport { MessageRendererRegistry } from '../utils/messageRenderers'\n\nexport interface ChatWindowProps {\n /**\n * \u6D88\u606F\u5217\u8868\n */\n messages: Message[]\n\n /**\n * \u8F93\u5165\u6846\u5F53\u524D\u503C\n */\n inputValue: string\n\n /**\n * \u8F93\u5165\u6846\u503C\u53D8\u5316\u56DE\u8C03\n */\n onInputChange: (value: string) => void\n\n /**\n * \u53D1\u9001\u6D88\u606F\u56DE\u8C03\n */\n onSend: () => void\n\n /**\n * \u5173\u95ED\u7A97\u53E3\u56DE\u8C03\n */\n onClose?: () => void\n\n /**\n * \u65B0\u4F1A\u8BDD\u56DE\u8C03\n */\n onNewSession?: () => void\n\n /**\n * \u5934\u90E8\u6807\u9898\n */\n title?: string\n\n /**\n * Logo URL\n */\n logoUrl?: string\n\n /**\n * \u662F\u5426\u6B63\u5728\u53D1\u9001\u6D88\u606F\n * @default false\n */\n isSending?: boolean\n\n /**\n * \u662F\u5426\u6B63\u5728\u52A0\u8F7D\u5386\u53F2\u6D88\u606F\n * @default false\n */\n isLoadingHistory?: boolean\n\n /**\n * \u662F\u5426\u663E\u793A\u65F6\u95F4\u6233\n * @default true\n */\n showTimestamp?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u6EDA\u52A8\n * @default true\n */\n autoScroll?: boolean\n\n /**\n * \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u6CE8\u518C\u8868\n */\n rendererRegistry?: MessageRendererRegistry\n\n /**\n * \u9ED8\u8BA4\u6E32\u67D3\u5668\n */\n defaultRenderer?: MessageRenderer\n\n /**\n * \u8F93\u5165\u6846\u5360\u4F4D\u7B26\n */\n inputPlaceholder?: string\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5546\u54C1\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: any) => void\n\n /**\n * \u662F\u5426\u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n * @default true\n */\n showNewSessionButton?: boolean\n\n /**\n * \u8F93\u5165\u6846\u5E95\u90E8\u63D0\u793A\u6587\u672C\n * @default \"The above content is provided by AI, for reference.\"\n */\n bottomTips?: string\n}\n\n/**\n * \u804A\u5929\u7A97\u53E3\u5BB9\u5668\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u7EC4\u5408\u5934\u90E8\u3001\u6D88\u606F\u5217\u8868\u3001\u8F93\u5165\u6846\n * - \u54CD\u5E94\u5F0F\u5E03\u5C40\uFF08\u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\uFF09\n * - \u52A8\u753B\u8FDB\u5165/\u9000\u51FA\u6548\u679C\n *\n * \u5E03\u5C40\u7ED3\u6784\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 ChatHeader \u2502 (\u56FA\u5B9A\u9876\u90E8)\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 MessageList \u2502 (\u53EF\u6EDA\u52A8\u533A\u57DF)\n * \u2502 (flex-1) \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 ChatInput \u2502 (\u56FA\u5B9A\u5E95\u90E8)\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n *\n * \u54CD\u5E94\u5F0F\u8BBE\u8BA1\uFF1A\n * - \u79FB\u52A8\u7AEF (< 768px): \u5168\u5C4F\u663E\u793A\n * - \u5E73\u677F\u53CA\u4EE5\u4E0A (>= 768px): \u56FA\u5B9A\u5C3A\u5BF8\u5F39\u7A97\n *\n * @example\n * ```tsx\n * <ChatWindow\n * messages={messages}\n * inputValue={inputValue}\n * onInputChange={setInputValue}\n * onSend={handleSend}\n * onClose={() => setIsOpen(false)}\n * onNewSession={handleNewSession}\n * isSending={isStreaming}\n * title=\"AI \u52A9\u624B\"\n * logoUrl=\"/logo.png\"\n * />\n * ```\n */\nexport const ChatWindow: React.FC<ChatWindowProps> = ({\n messages,\n inputValue,\n onInputChange,\n onSend,\n onClose,\n onNewSession,\n title,\n logoUrl,\n isSending = false,\n isLoadingHistory = false,\n showTimestamp = true,\n autoScroll = true,\n rendererRegistry,\n defaultRenderer,\n inputPlaceholder,\n className = '',\n onAddToCart,\n showNewSessionButton = true,\n bottomTips,\n}) => {\n // \u5E38\u91CF\uFF1A\u9AD8\u5EA6\u9650\u5236\u6BD4\u4F8B\n const MIN_HEIGHT_RATIO = 0.4 // \u6700\u5C0F40%\n const MAX_HEIGHT_RATIO = 0.8 // \u6700\u592780%\n const DEFAULT_HEIGHT = 680 // \u9ED8\u8BA4680px\n\n // \u83B7\u53D6\u5F53\u524D\u5141\u8BB8\u7684\u9AD8\u5EA6\u8303\u56F4\n const getHeightConstraints = useCallback(() => {\n if (typeof window === 'undefined') {\n return { minHeight: DEFAULT_HEIGHT, maxHeight: DEFAULT_HEIGHT }\n }\n return {\n minHeight: window.innerHeight * MIN_HEIGHT_RATIO,\n maxHeight: window.innerHeight * MAX_HEIGHT_RATIO,\n }\n }, [MIN_HEIGHT_RATIO, MAX_HEIGHT_RATIO, DEFAULT_HEIGHT])\n\n // \u5C06\u9AD8\u5EA6\u9650\u5236\u5728\u5141\u8BB8\u8303\u56F4\u5185\n const clampHeight = useCallback(\n (height: number) => {\n const { minHeight, maxHeight } = getHeightConstraints()\n return Math.max(minHeight, Math.min(maxHeight, height))\n },\n [getHeightConstraints]\n )\n\n // \u8BA1\u7B97\u521D\u59CB\u9AD8\u5EA6\uFF1A\u9ED8\u8BA4680px\uFF0C\u4F46\u9700\u8981\u572830%-80%\u8303\u56F4\u5185\n const getInitialHeight = () => {\n if (typeof window === 'undefined') return DEFAULT_HEIGHT\n return clampHeight(DEFAULT_HEIGHT)\n }\n\n // \u79FB\u52A8\u7AEF\u9AD8\u5EA6\u8C03\u8282\u72B6\u6001\uFF08\u9ED8\u8BA4680px\u6216\u5C4F\u5E5580%\uFF0C\u53D6\u8F83\u5C0F\u503C\uFF09\n const [mobileHeight, setMobileHeight] = useState(getInitialHeight)\n const [isDragging, setIsDragging] = useState(false)\n const dragStartY = useRef(0)\n const dragStartHeight = useRef(getInitialHeight())\n const windowRef = useRef<HTMLDivElement>(null)\n\n // \u66F4\u65B0\u9AD8\u5EA6\u5E76\u540C\u6B65CSS\u53D8\u91CF\n const updateHeight = useCallback(\n (newHeight: number) => {\n const clampedHeight = clampHeight(newHeight)\n setMobileHeight(clampedHeight)\n // \u540C\u6B65\u66F4\u65B0CSS\u53D8\u91CF\uFF0C\u4F9B livechat.css \u4F7F\u7528\n if (windowRef.current) {\n windowRef.current.style.setProperty('--livechat-mobile-height', `${clampedHeight}px`)\n }\n return clampedHeight\n },\n [clampHeight]\n )\n\n // \u68C0\u6D4B\u662F\u5426\u4E3A\u79FB\u52A8\u7AEF\uFF08\u521D\u59CB\u5316\u65F6\u7ACB\u5373\u68C0\u6D4B\uFF09\n const [isMobile, setIsMobile] = useState(() => {\n if (typeof window !== 'undefined') {\n return window.innerWidth < 768\n }\n return false\n })\n\n useEffect(() => {\n const handleResize = () => {\n const newIsMobile = window.innerWidth < 768\n setIsMobile(newIsMobile)\n\n // \u5982\u679C\u662F\u79FB\u52A8\u7AEF\uFF0C\u68C0\u67E5\u5F53\u524D\u9AD8\u5EA6\u662F\u5426\u5728\u5141\u8BB8\u8303\u56F4\u5185\n if (newIsMobile) {\n const clampedHeight = clampHeight(mobileHeight)\n if (clampedHeight !== mobileHeight) {\n updateHeight(clampedHeight)\n }\n }\n }\n\n window.addEventListener('resize', handleResize)\n return () => window.removeEventListener('resize', handleResize)\n }, [mobileHeight, clampHeight, updateHeight])\n\n // \u62D6\u62FD\u5F00\u59CB\n const handleDragStart = (e: React.MouseEvent | React.TouchEvent) => {\n if (!isMobile) return\n\n setIsDragging(true)\n const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY\n dragStartY.current = clientY\n dragStartHeight.current = mobileHeight\n\n // \u963B\u6B62\u9ED8\u8BA4\u884C\u4E3A\n e.preventDefault()\n }\n\n // \u62D6\u62FD\u4E2D\n useEffect(() => {\n if (!isDragging) return\n\n const handleDragMove = (e: MouseEvent | TouchEvent) => {\n const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY\n const deltaY = dragStartY.current - clientY // \u5411\u4E0A\u62D6\u52A8\u4E3A\u6B63\u503C\n const newHeight = dragStartHeight.current + deltaY\n\n updateHeight(newHeight)\n }\n\n const handleDragEnd = () => {\n setIsDragging(false)\n }\n\n document.addEventListener('mousemove', handleDragMove)\n document.addEventListener('mouseup', handleDragEnd)\n document.addEventListener('touchmove', handleDragMove, { passive: false })\n document.addEventListener('touchend', handleDragEnd)\n\n return () => {\n document.removeEventListener('mousemove', handleDragMove)\n document.removeEventListener('mouseup', handleDragEnd)\n document.removeEventListener('touchmove', handleDragMove)\n document.removeEventListener('touchend', handleDragEnd)\n }\n }, [isDragging, updateHeight])\n\n return (\n <div\n ref={windowRef}\n className={`livechat-window flex flex-col overflow-hidden bg-white ${className}`}\n style={\n {\n borderRadius: '16px',\n borderBottomLeftRadius: isMobile && '0px',\n borderBottomRightRadius: isMobile && '0px',\n '--livechat-mobile-height': `${mobileHeight}px`,\n } as React.CSSProperties\n }\n >\n {/* \u79FB\u52A8\u7AEF\u62D6\u62FD\u624B\u67C4 */}\n {isMobile && (\n <div\n className=\"flex cursor-ns-resize items-center justify-center py-2\"\n style={{\n touchAction: 'none',\n backgroundColor: '#ffffff',\n }}\n onMouseDown={handleDragStart}\n onTouchStart={handleDragStart}\n >\n <div\n style={{\n width: '48px',\n height: '6px',\n borderRadius: '999px',\n backgroundColor: '#DADCE0',\n }}\n />\n </div>\n )}\n\n {/* \u5934\u90E8 */}\n <ChatHeader\n title={title}\n logoUrl={logoUrl}\n onClose={onClose}\n onNewSession={onNewSession}\n showNewSessionButton={showNewSessionButton}\n />\n\n {/* \u6D88\u606F\u5217\u8868\uFF08\u53EF\u6EDA\u52A8\u533A\u57DF\uFF09 */}\n <MessageList\n messages={messages}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n showTimestamp={showTimestamp}\n autoScroll={autoScroll}\n isLoadingHistory={isLoadingHistory}\n onAddToCart={onAddToCart}\n />\n\n {/* \u8F93\u5165\u6846 */}\n <ChatInput\n value={inputValue}\n onChange={onInputChange}\n onSend={onSend}\n placeholder={inputPlaceholder}\n disabled={isSending}\n bottomTips={bottomTips}\n />\n </div>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * \u804A\u5929\u7A97\u53E3\u5BB9\u5668\u7EC4\u4EF6\n * \u5305\u542B\u5934\u90E8\u3001\u6D88\u606F\u5217\u8868\u3001\u8F93\u5165\u6846\u7684\u5B8C\u6574\u804A\u5929\u754C\u9762\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u7A97\u53E3\u8BBE\u8BA1\n */\n\nimport React, { useState, useRef, useEffect, useCallback } from 'react'\nimport type { Message, MessageRenderer } from '../types'\nimport { ChatHeader } from './ChatHeader'\nimport { MessageList } from './MessageList'\nimport { ChatInput } from './ChatInput'\nimport { MessageRendererRegistry } from '../utils/messageRenderers'\n\nexport interface ChatWindowProps {\n /**\n * \u6D88\u606F\u5217\u8868\n */\n messages: Message[]\n\n /**\n * \u8F93\u5165\u6846\u5F53\u524D\u503C\n */\n inputValue: string\n\n /**\n * \u8F93\u5165\u6846\u503C\u53D8\u5316\u56DE\u8C03\n */\n onInputChange: (value: string) => void\n\n /**\n * \u53D1\u9001\u6D88\u606F\u56DE\u8C03\n */\n onSend: () => void\n\n /**\n * \u5173\u95ED\u7A97\u53E3\u56DE\u8C03\n */\n onClose?: () => void\n\n /**\n * \u65B0\u4F1A\u8BDD\u56DE\u8C03\n */\n onNewSession?: () => void\n\n /**\n * \u5934\u90E8\u6807\u9898\n */\n title?: string\n\n /**\n * Logo URL\n */\n logoUrl?: string\n\n /**\n * \u662F\u5426\u6B63\u5728\u53D1\u9001\u6D88\u606F\n * @default false\n */\n isSending?: boolean\n\n /**\n * \u662F\u5426\u6B63\u5728\u52A0\u8F7D\u5386\u53F2\u6D88\u606F\n * @default false\n */\n isLoadingHistory?: boolean\n\n /**\n * \u662F\u5426\u663E\u793A\u65F6\u95F4\u6233\n * @default true\n */\n showTimestamp?: boolean\n\n /**\n * \u662F\u5426\u81EA\u52A8\u6EDA\u52A8\n * @default true\n */\n autoScroll?: boolean\n\n /**\n * \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u6CE8\u518C\u8868\n */\n rendererRegistry?: MessageRendererRegistry\n\n /**\n * \u9ED8\u8BA4\u6E32\u67D3\u5668\n */\n defaultRenderer?: MessageRenderer\n\n /**\n * \u8F93\u5165\u6846\u5360\u4F4D\u7B26\n */\n inputPlaceholder?: string\n\n /**\n * \u81EA\u5B9A\u4E49\u6837\u5F0F\u7C7B\u540D\n */\n className?: string\n\n /**\n * \u5546\u54C1\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: any) => void\n\n /**\n * \u662F\u5426\u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n * @default true\n */\n showNewSessionButton?: boolean\n\n /**\n * \u8F93\u5165\u6846\u5E95\u90E8\u63D0\u793A\u6587\u672C\n * \u4E0D\u4F20\u5165\u5219\u4E0D\u663E\u793A\n */\n bottomTips?: string\n}\n\n/**\n * \u804A\u5929\u7A97\u53E3\u5BB9\u5668\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u7EC4\u5408\u5934\u90E8\u3001\u6D88\u606F\u5217\u8868\u3001\u8F93\u5165\u6846\n * - \u54CD\u5E94\u5F0F\u5E03\u5C40\uFF08\u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\uFF09\n * - \u52A8\u753B\u8FDB\u5165/\u9000\u51FA\u6548\u679C\n *\n * \u5E03\u5C40\u7ED3\u6784\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 ChatHeader \u2502 (\u56FA\u5B9A\u9876\u90E8)\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 MessageList \u2502 (\u53EF\u6EDA\u52A8\u533A\u57DF)\n * \u2502 (flex-1) \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 ChatInput \u2502 (\u56FA\u5B9A\u5E95\u90E8)\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n *\n * \u54CD\u5E94\u5F0F\u8BBE\u8BA1\uFF1A\n * - \u79FB\u52A8\u7AEF (< 768px): \u5168\u5C4F\u663E\u793A\n * - \u5E73\u677F\u53CA\u4EE5\u4E0A (>= 768px): \u56FA\u5B9A\u5C3A\u5BF8\u5F39\u7A97\n *\n * @example\n * ```tsx\n * <ChatWindow\n * messages={messages}\n * inputValue={inputValue}\n * onInputChange={setInputValue}\n * onSend={handleSend}\n * onClose={() => setIsOpen(false)}\n * onNewSession={handleNewSession}\n * isSending={isStreaming}\n * title=\"AI \u52A9\u624B\"\n * logoUrl=\"/logo.png\"\n * />\n * ```\n */\nexport const ChatWindow: React.FC<ChatWindowProps> = ({\n messages,\n inputValue,\n onInputChange,\n onSend,\n onClose,\n onNewSession,\n title,\n logoUrl,\n isSending = false,\n isLoadingHistory = false,\n showTimestamp = true,\n autoScroll = true,\n rendererRegistry,\n defaultRenderer,\n inputPlaceholder,\n className = '',\n onAddToCart,\n showNewSessionButton = true,\n bottomTips,\n}) => {\n // \u5E38\u91CF\uFF1A\u9AD8\u5EA6\u9650\u5236\u6BD4\u4F8B\n const MIN_HEIGHT_RATIO = 0.4 // \u6700\u5C0F40%\n const MAX_HEIGHT_RATIO = 0.8 // \u6700\u592780%\n const DEFAULT_HEIGHT = 680 // \u9ED8\u8BA4680px\n\n // \u83B7\u53D6\u5F53\u524D\u5141\u8BB8\u7684\u9AD8\u5EA6\u8303\u56F4\n const getHeightConstraints = useCallback(() => {\n if (typeof window === 'undefined') {\n return { minHeight: DEFAULT_HEIGHT, maxHeight: DEFAULT_HEIGHT }\n }\n return {\n minHeight: window.innerHeight * MIN_HEIGHT_RATIO,\n maxHeight: window.innerHeight * MAX_HEIGHT_RATIO,\n }\n }, [MIN_HEIGHT_RATIO, MAX_HEIGHT_RATIO, DEFAULT_HEIGHT])\n\n // \u5C06\u9AD8\u5EA6\u9650\u5236\u5728\u5141\u8BB8\u8303\u56F4\u5185\n const clampHeight = useCallback(\n (height: number) => {\n const { minHeight, maxHeight } = getHeightConstraints()\n return Math.max(minHeight, Math.min(maxHeight, height))\n },\n [getHeightConstraints]\n )\n\n // \u8BA1\u7B97\u521D\u59CB\u9AD8\u5EA6\uFF1A\u9ED8\u8BA4680px\uFF0C\u4F46\u9700\u8981\u572830%-80%\u8303\u56F4\u5185\n const getInitialHeight = () => {\n if (typeof window === 'undefined') return DEFAULT_HEIGHT\n return clampHeight(DEFAULT_HEIGHT)\n }\n\n // \u79FB\u52A8\u7AEF\u9AD8\u5EA6\u8C03\u8282\u72B6\u6001\uFF08\u9ED8\u8BA4680px\u6216\u5C4F\u5E5580%\uFF0C\u53D6\u8F83\u5C0F\u503C\uFF09\n const [mobileHeight, setMobileHeight] = useState(getInitialHeight)\n const [isDragging, setIsDragging] = useState(false)\n const dragStartY = useRef(0)\n const dragStartHeight = useRef(getInitialHeight())\n const windowRef = useRef<HTMLDivElement>(null)\n\n // \u66F4\u65B0\u9AD8\u5EA6\u5E76\u540C\u6B65CSS\u53D8\u91CF\n const updateHeight = useCallback(\n (newHeight: number) => {\n const clampedHeight = clampHeight(newHeight)\n setMobileHeight(clampedHeight)\n // \u540C\u6B65\u66F4\u65B0CSS\u53D8\u91CF\uFF0C\u4F9B livechat.css \u4F7F\u7528\n if (windowRef.current) {\n windowRef.current.style.setProperty('--livechat-mobile-height', `${clampedHeight}px`)\n }\n return clampedHeight\n },\n [clampHeight]\n )\n\n // \u68C0\u6D4B\u662F\u5426\u4E3A\u79FB\u52A8\u7AEF\uFF08\u521D\u59CB\u5316\u65F6\u7ACB\u5373\u68C0\u6D4B\uFF09\n const [isMobile, setIsMobile] = useState(() => {\n if (typeof window !== 'undefined') {\n return window.innerWidth < 768\n }\n return false\n })\n\n useEffect(() => {\n const handleResize = () => {\n const newIsMobile = window.innerWidth < 768\n setIsMobile(newIsMobile)\n\n // \u5982\u679C\u662F\u79FB\u52A8\u7AEF\uFF0C\u68C0\u67E5\u5F53\u524D\u9AD8\u5EA6\u662F\u5426\u5728\u5141\u8BB8\u8303\u56F4\u5185\n if (newIsMobile) {\n const clampedHeight = clampHeight(mobileHeight)\n if (clampedHeight !== mobileHeight) {\n updateHeight(clampedHeight)\n }\n }\n }\n\n window.addEventListener('resize', handleResize)\n return () => window.removeEventListener('resize', handleResize)\n }, [mobileHeight, clampHeight, updateHeight])\n\n // \u62D6\u62FD\u5F00\u59CB\n const handleDragStart = (e: React.MouseEvent | React.TouchEvent) => {\n if (!isMobile) return\n\n setIsDragging(true)\n const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY\n dragStartY.current = clientY\n dragStartHeight.current = mobileHeight\n\n // \u963B\u6B62\u9ED8\u8BA4\u884C\u4E3A\n e.preventDefault()\n }\n\n // \u62D6\u62FD\u4E2D\n useEffect(() => {\n if (!isDragging) return\n\n const handleDragMove = (e: MouseEvent | TouchEvent) => {\n const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY\n const deltaY = dragStartY.current - clientY // \u5411\u4E0A\u62D6\u52A8\u4E3A\u6B63\u503C\n const newHeight = dragStartHeight.current + deltaY\n\n updateHeight(newHeight)\n }\n\n const handleDragEnd = () => {\n setIsDragging(false)\n }\n\n document.addEventListener('mousemove', handleDragMove)\n document.addEventListener('mouseup', handleDragEnd)\n document.addEventListener('touchmove', handleDragMove, { passive: false })\n document.addEventListener('touchend', handleDragEnd)\n\n return () => {\n document.removeEventListener('mousemove', handleDragMove)\n document.removeEventListener('mouseup', handleDragEnd)\n document.removeEventListener('touchmove', handleDragMove)\n document.removeEventListener('touchend', handleDragEnd)\n }\n }, [isDragging, updateHeight])\n\n return (\n <div\n ref={windowRef}\n className={`livechat-window flex flex-col overflow-hidden bg-white ${className}`}\n style={\n {\n borderRadius: '16px',\n borderBottomLeftRadius: isMobile && '0px',\n borderBottomRightRadius: isMobile && '0px',\n '--livechat-mobile-height': `${mobileHeight}px`,\n } as React.CSSProperties\n }\n >\n {/* \u79FB\u52A8\u7AEF\u62D6\u62FD\u624B\u67C4 */}\n {isMobile && (\n <div\n className=\"flex cursor-ns-resize items-center justify-center py-2\"\n style={{\n touchAction: 'none',\n backgroundColor: '#ffffff',\n }}\n onMouseDown={handleDragStart}\n onTouchStart={handleDragStart}\n >\n <div\n style={{\n width: '48px',\n height: '6px',\n borderRadius: '999px',\n backgroundColor: '#DADCE0',\n }}\n />\n </div>\n )}\n\n {/* \u5934\u90E8 */}\n <ChatHeader\n title={title}\n logoUrl={logoUrl}\n onClose={onClose}\n onNewSession={onNewSession}\n showNewSessionButton={showNewSessionButton}\n />\n\n {/* \u6D88\u606F\u5217\u8868\uFF08\u53EF\u6EDA\u52A8\u533A\u57DF\uFF09 */}\n <MessageList\n messages={messages}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n showTimestamp={showTimestamp}\n autoScroll={autoScroll}\n isLoadingHistory={isLoadingHistory}\n onAddToCart={onAddToCart}\n />\n\n {/* \u8F93\u5165\u6846 */}\n <ChatInput\n value={inputValue}\n onChange={onInputChange}\n onSend={onSend}\n placeholder={inputPlaceholder}\n disabled={isSending}\n bottomTips={bottomTips}\n />\n </div>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["ChatWindow_exports", "__export", "ChatWindow", "__toCommonJS", "import_jsx_runtime", "import_react", "import_ChatHeader", "import_MessageList", "import_ChatInput", "messages", "inputValue", "onInputChange", "onSend", "onClose", "onNewSession", "title", "logoUrl", "isSending", "isLoadingHistory", "showTimestamp", "autoScroll", "rendererRegistry", "defaultRenderer", "inputPlaceholder", "className", "onAddToCart", "showNewSessionButton", "bottomTips", "getHeightConstraints", "clampHeight", "height", "minHeight", "maxHeight", "getInitialHeight", "mobileHeight", "setMobileHeight", "isDragging", "setIsDragging", "dragStartY", "dragStartHeight", "windowRef", "updateHeight", "newHeight", "clampedHeight", "isMobile", "setIsMobile", "handleResize", "newIsMobile", "handleDragStart", "clientY", "handleDragMove", "e", "deltaY", "handleDragEnd"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var x=Object.create;var n=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var f=(a,r)=>{for(var l in r)n(a,l,{get:r[l],enumerable:!0})},s=(a,r,l,d)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of g(r))!N.call(a,t)&&t!==l&&n(a,t,{get:()=>r[t],enumerable:!(d=i(r,t))||d.enumerable});return a};var m=(a,r,l)=>(l=a!=null?x(y(a)):{},s(r||!a||!a.__esModule?n(l,"default",{value:a,enumerable:!0}):l,a)),p=a=>s(n({},"__esModule",{value:!0}),a);var u={};f(u,{TextBlock:()=>h});module.exports=p(u);var o=require("react/jsx-runtime"),b=m(require("react-markdown")),c=m(require("remark-gfm"));const h={render:(a,r,l)=>{const d=a;return d.text?(0,o.jsx)("div",{className:"livechat-markdown text-base md:text-sm",children:(0,o.jsx)(b.default,{remarkPlugins:[c.default],components:{a:({node:t,...e})=>(0,o.jsx)("a",{...e,className:`underline ${r?"text-blue-200 hover:text-blue-100":"text-blue-600 hover:text-blue-700"}`,target:"_blank",rel:"noopener noreferrer"}),code:({node:t,...e})=>e.inline?(0,o.jsx)("code",{...e,className:`rounded px-1.5 py-0.5 font-mono text-xs ${r?"bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}):(0,o.jsx)("code",{...e,className:`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${r?"bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}),p:({node:t,...e})=>(0,o.jsx)("p",{...e,className:"last:mb-0"}),ul:({node:t,...e})=>(0,o.jsx)("ul",{...e,className:"ml-4 list-disc"}),ol:({node:t,...e})=>(0,o.jsx)("ol",{...e,className:"mb-2 ml-4 list-decimal"}),li:({node:t,...e})=>(0,o.jsx)("li",{...e,className:"mb-1"}),h1:({node:t,...e})=>(0,o.jsx)("h1",{...e,className:"mb-2 text-lg font-bold"}),h2:({node:t,...e})=>(0,o.jsx)("h2",{...e,className:"mb-2 text-base font-bold"}),h3:({node:t,...e})=>(0,o.jsx)("h3",{...e,className:"mb-1 text-sm font-bold"}),strong:({node:t,...e})=>(0,o.jsx)("strong",{...e,className:"font-bold"}),em:({node:t,...e})=>(0,o.jsx)("em",{...e,className:"italic"}),table:({node:t,...e})=>(0,o.jsx)("div",{className:"my-2 overflow-x-auto",children:(0,o.jsx)("table",{...e,className:"min-w-full border-collapse border border-gray-300 text-base md:text-sm"})}),thead:({node:t,...e})=>(0,o.jsx)("thead",{...e,className:"bg-gray-100"}),tbody:({node:t,...e})=>(0,o.jsx)("tbody",{...e}),tr:({node:t,...e})=>(0,o.jsx)("tr",{...e,className:"border-b border-gray-300"}),th:({node:t,...e})=>(0,o.jsx)("th",{...e,className:"border border-gray-300 px-3 py-2 text-left font-semibold"}),td:({node:t,...e})=>(0,o.jsx)("td",{...e,className:"border border-gray-300 px-3 py-2"})},children:d.text})}):null}};
|
|
2
2
|
//# sourceMappingURL=TextBlock.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u6587\u672C\u6D88\u606F\u5185\u5BB9\u6E32\u67D3\u5668\n * \u652F\u6301 Markdown \u683C\u5F0F\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6587\u672C\u6D88\u606F\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport type { MessageRenderer, TextContent } from '../../types'\n\n/**\n * \u6587\u672C\u6D88\u606F\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u652F\u6301 Markdown \u8BED\u6CD5\uFF08\u7C97\u4F53\u3001\u659C\u4F53\u3001\u94FE\u63A5\u3001\u5217\u8868\u7B49\uFF09\n * - \u5B89\u5168\u6E32\u67D3\uFF08React Markdown \u81EA\u52A8\u9632\u62A4 XSS\uFF09\n * - \u54CD\u5E94\u5F0F\u6587\u672C\u6837\u5F0F\n *\n * Markdown \u652F\u6301\uFF1A\n * - \u7C97\u4F53\uFF1A**text** \u6216 __text__\n * - \u659C\u4F53\uFF1A*text* \u6216 _text_\n * - \u94FE\u63A5\uFF1A[text](url)\n * - \u5217\u8868\uFF1A- item \u6216 1. item\n * - \u4EE3\u7801\uFF1A`code` \u6216 ```code block```\n *\n * @example\n * ```tsx\n * const content: TextContent = {\n * type: 'text',\n * text: '\u60A8\u597D\uFF01**\u8FD9\u662F\u7C97\u4F53**\uFF0C*\u8FD9\u662F\u659C\u4F53*\u3002'\n * }\n * <TextBlock.render(content, false, false) />\n * ```\n */\nexport const TextBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const textContent = content as TextContent\n\n if (!textContent.text) {\n return null\n }\n\n return (\n <div className=\"livechat-markdown text-base md:text-sm\">\n <ReactMarkdown\n components={{\n // \u81EA\u5B9A\u4E49\u94FE\u63A5\u6837\u5F0F\n a: ({ node, ...props }) => (\n <a\n {...props}\n className={`underline ${isUser ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700'}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n />\n ),\n // \u81EA\u5B9A\u4E49\u4EE3\u7801\u5757\u6837\u5F0F\n code: ({ node, ...props }: any) =>\n props.inline ? (\n <code\n {...props}\n className={`rounded px-1.5 py-0.5 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}\n />\n ) : (\n <code\n {...props}\n className={`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}\n />\n ),\n // \u81EA\u5B9A\u4E49\u6BB5\u843D\u6837\u5F0F\n p: ({ node, ...props }) => <p {...props} className=\"last:mb-0\" />,\n // \u81EA\u5B9A\u4E49\u5217\u8868\u6837\u5F0F\n ul: ({ node, ...props }) => <ul {...props} className=\"ml-4 list-disc\" />,\n ol: ({ node, ...props }) => <ol {...props} className=\"mb-2 ml-4 list-decimal\" />,\n li: ({ node, ...props }) => <li {...props} className=\"mb-1\" />,\n // \u81EA\u5B9A\u4E49\u6807\u9898\u6837\u5F0F\n h1: ({ node, ...props }) => <h1 {...props} className=\"mb-2 text-lg font-bold\" />,\n h2: ({ node, ...props }) => <h2 {...props} className=\"mb-2 text-base font-bold\" />,\n h3: ({ node, ...props }) => <h3 {...props} className=\"mb-1 text-sm font-bold\" />,\n // \u81EA\u5B9A\u4E49\u5F3A\u8C03\u6837\u5F0F\n strong: ({ node, ...props }) => <strong {...props} className=\"font-bold\" />,\n em: ({ node, ...props }) => <em {...props} className=\"italic\" />,\n }}\n >\n {textContent.text}\n </ReactMarkdown>\n </div>\n )\n },\n}\n"],
|
|
5
|
-
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,
|
|
6
|
-
"names": ["TextBlock_exports", "__export", "TextBlock", "__toCommonJS", "import_jsx_runtime", "import_react_markdown", "content", "isUser", "isSystem", "textContent", "ReactMarkdown", "node", "props"]
|
|
4
|
+
"sourcesContent": ["/**\n * \u6587\u672C\u6D88\u606F\u5185\u5BB9\u6E32\u67D3\u5668\n * \u652F\u6301 Markdown \u683C\u5F0F\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6587\u672C\u6D88\u606F\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport type { MessageRenderer, TextContent } from '../../types'\n\n/**\n * \u6587\u672C\u6D88\u606F\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u652F\u6301 Markdown \u8BED\u6CD5\uFF08\u7C97\u4F53\u3001\u659C\u4F53\u3001\u94FE\u63A5\u3001\u5217\u8868\u7B49\uFF09\n * - \u5B89\u5168\u6E32\u67D3\uFF08React Markdown \u81EA\u52A8\u9632\u62A4 XSS\uFF09\n * - \u54CD\u5E94\u5F0F\u6587\u672C\u6837\u5F0F\n *\n * Markdown \u652F\u6301\uFF1A\n * - \u7C97\u4F53\uFF1A**text** \u6216 __text__\n * - \u659C\u4F53\uFF1A*text* \u6216 _text_\n * - \u94FE\u63A5\uFF1A[text](url)\n * - \u5217\u8868\uFF1A- item \u6216 1. item\n * - \u4EE3\u7801\uFF1A`code` \u6216 ```code block```\n *\n * @example\n * ```tsx\n * const content: TextContent = {\n * type: 'text',\n * text: '\u60A8\u597D\uFF01**\u8FD9\u662F\u7C97\u4F53**\uFF0C*\u8FD9\u662F\u659C\u4F53*\u3002'\n * }\n * <TextBlock.render(content, false, false) />\n * ```\n */\nexport const TextBlock: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const textContent = content as TextContent\n\n if (!textContent.text) {\n return null\n }\n\n return (\n <div className=\"livechat-markdown text-base md:text-sm\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n // \u81EA\u5B9A\u4E49\u94FE\u63A5\u6837\u5F0F\n a: ({ node, ...props }) => (\n <a\n {...props}\n className={`underline ${isUser ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700'}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n />\n ),\n // \u81EA\u5B9A\u4E49\u4EE3\u7801\u5757\u6837\u5F0F\n code: ({ node, ...props }: any) =>\n props.inline ? (\n <code\n {...props}\n className={`rounded px-1.5 py-0.5 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}\n />\n ) : (\n <code\n {...props}\n className={`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}\n />\n ),\n // \u81EA\u5B9A\u4E49\u6BB5\u843D\u6837\u5F0F\n p: ({ node, ...props }) => <p {...props} className=\"last:mb-0\" />,\n // \u81EA\u5B9A\u4E49\u5217\u8868\u6837\u5F0F\n ul: ({ node, ...props }) => <ul {...props} className=\"ml-4 list-disc\" />,\n ol: ({ node, ...props }) => <ol {...props} className=\"mb-2 ml-4 list-decimal\" />,\n li: ({ node, ...props }) => <li {...props} className=\"mb-1\" />,\n // \u81EA\u5B9A\u4E49\u6807\u9898\u6837\u5F0F\n h1: ({ node, ...props }) => <h1 {...props} className=\"mb-2 text-lg font-bold\" />,\n h2: ({ node, ...props }) => <h2 {...props} className=\"mb-2 text-base font-bold\" />,\n h3: ({ node, ...props }) => <h3 {...props} className=\"mb-1 text-sm font-bold\" />,\n // \u81EA\u5B9A\u4E49\u5F3A\u8C03\u6837\u5F0F\n strong: ({ node, ...props }) => <strong {...props} className=\"font-bold\" />,\n em: ({ node, ...props }) => <em {...props} className=\"italic\" />,\n // \u8868\u683C\u6837\u5F0F\n table: ({ node, ...props }) => (\n <div className=\"my-2 overflow-x-auto\">\n <table {...props} className=\"min-w-full border-collapse border border-gray-300 text-base md:text-sm\" />\n </div>\n ),\n thead: ({ node, ...props }) => (\n <thead {...props} className=\"bg-gray-100\" />\n ),\n tbody: ({ node, ...props }) => <tbody {...props} />,\n tr: ({ node, ...props }) => (\n <tr {...props} className=\"border-b border-gray-300\" />\n ),\n th: ({ node, ...props }) => (\n <th {...props} className=\"border border-gray-300 px-3 py-2 text-left font-semibold\" />\n ),\n td: ({ node, ...props }) => (\n <td {...props} className=\"border border-gray-300 px-3 py-2\" />\n ),\n }}\n >\n {textContent.text}\n </ReactMarkdown>\n </div>\n )\n },\n}\n"],
|
|
5
|
+
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,GAkDc,IAAAI,EAAA,6BA3CdC,EAA0B,6BAC1BC,EAAsB,yBA2Bf,MAAMJ,EAA6B,CACxC,OAAQ,CAACK,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAcH,EAEpB,OAAKG,EAAY,QAKf,OAAC,OAAI,UAAU,yCACb,mBAAC,EAAAC,QAAA,CACC,cAAe,CAAC,EAAAC,OAAS,EACzB,WAAY,CAEV,EAAG,CAAC,CAAE,KAAAC,EAAM,GAAGC,CAAM,OACnB,OAAC,KACE,GAAGA,EACJ,UAAW,aAAaN,EAAS,oCAAsC,mCAAmC,GAC1G,OAAO,SACP,IAAI,sBACN,EAGF,KAAM,CAAC,CAAE,KAAAK,EAAM,GAAGC,CAAM,IACtBA,EAAM,UACJ,OAAC,QACE,GAAGA,EACJ,UAAW,2CAA2CN,EAAS,0BAA4B,2BAA2B,GACxH,KAEA,OAAC,QACE,GAAGM,EACJ,UAAW,6DAA6DN,EAAS,0BAA4B,2BAA2B,GAC1I,EAGJ,EAAG,CAAC,CAAE,KAAAK,EAAM,GAAGC,CAAM,OAAM,OAAC,KAAG,GAAGA,EAAO,UAAU,YAAY,EAE/D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,yBAAyB,EAC9E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,OAAO,EAE5D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,yBAAyB,EAC9E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,2BAA2B,EAChF,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,yBAAyB,EAE9E,OAAQ,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,UAAQ,GAAGA,EAAO,UAAU,YAAY,EACzE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,MAAI,GAAGA,EAAO,UAAU,SAAS,EAE9D,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACvB,OAAC,OAAI,UAAU,uBACb,mBAAC,SAAO,GAAGA,EAAO,UAAU,yEAAyE,EACvG,EAEF,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACvB,OAAC,SAAO,GAAGA,EAAO,UAAU,cAAc,EAE5C,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OAAM,OAAC,SAAO,GAAGA,EAAO,EACjD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACpB,OAAC,MAAI,GAAGA,EAAO,UAAU,2BAA2B,EAEtD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACpB,OAAC,MAAI,GAAGA,EAAO,UAAU,2DAA2D,EAEtF,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,OACpB,OAAC,MAAI,GAAGA,EAAO,UAAU,mCAAmC,CAEhE,EAEC,SAAAJ,EAAY,KACf,EACF,EAlEO,IAoEX,CACF",
|
|
6
|
+
"names": ["TextBlock_exports", "__export", "TextBlock", "__toCommonJS", "import_jsx_runtime", "import_react_markdown", "import_remark_gfm", "content", "isUser", "isSystem", "textContent", "ReactMarkdown", "remarkGfm", "node", "props"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var F=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var it=Object.getOwnPropertyNames;var
|
|
1
|
+
"use strict";var F=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var it=Object.getOwnPropertyNames;var dt=Object.prototype.hasOwnProperty;var ut=(t,d)=>{for(var f in d)F(t,f,{get:d[f],enumerable:!0})},lt=(t,d,f,x)=>{if(d&&typeof d=="object"||typeof d=="function")for(let p of it(d))!dt.call(t,p)&&p!==f&&F(t,p,{get:()=>d[p],enumerable:!(x=ct(d,p))||x.enumerable});return t};var pt=t=>lt(F({},"__esModule",{value:!0}),t);var yt={};ut(yt,{useChatState:()=>mt});module.exports=pt(yt);var u=require("react"),j=require("../utils/userId"),G=require("./useSession"),H=require("../utils/productTransformers"),J=require("../utils/cartTransformers");function gt(t,d,f,x,p){const r=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let S=0,i,h=!1;for(;(i=g.exec(t))!==null;){h=!0;const a=t.slice(S,i.index);a&&r.push({type:"text",text:a});const l=i[1].trim(),M=d.get(l),T=f.get(l);M?(console.log("[useChatState] \u{1F3AF} \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1:",l,"\u2192",M.title),r.push({type:"product_card",data:{product:M,rawProduct:T,onAddToCart:x,productCardRender:p}})):console.warn("[useChatState] \u26A0\uFE0F \u5B9E\u65F6\u89E3\u6790\u672A\u627E\u5230\u4EA7\u54C1\uFF0C\u5DF2\u9690\u85CF:",l),S=g.lastIndex}if(h){const a=t.slice(S);return{contents:r,remainingBuffer:a}}else{const a=t.match(/\{\{[^}]*$/);if(a){const l=t.slice(0,a.index);return l&&r.push({type:"text",text:l}),{contents:r,remainingBuffer:a[0]}}else return t&&r.push({type:"text",text:t}),{contents:r,remainingBuffer:""}}}function ft(t,d,f,x,p){const r=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let S=0,i;for(;(i=g.exec(t))!==null;){const a=t.slice(S,i.index).trim(),l=i[1].trim();a&&r.push({type:"text",text:a});const M=d.get(l),T=f.get(l);M?(console.log(`[useChatState] \u2705 \u627E\u5230\u4EA7\u54C1\u5339\u914D: ${l} \u2192 ${M.title}`),r.push({type:"product_card",data:{product:M,rawProduct:T,onAddToCart:x,productCardRender:p}})):console.warn(`[useChatState] \u274C Product not found for ID: "${l}"\uFF0C\u5DF2\u9690\u85CF`),S=g.lastIndex}const h=t.slice(S).trim();return h&&r.push({type:"text",text:h}),r}function ht(t,d,f,x,p){const r=[];for(const g of t)if(g.type==="text"){const i=ft(g.text,d,f,x,p);r.push(...i)}else{if(g.type==="product_list")continue;r.push(g)}return r}function Ct(t,d,f){if(!t.content.some(i=>i.type==="product_list")||!t.content.some(i=>i.type==="text"&&/\{\{(?:product:)?[^}]+\}\}/.test(i.text)))return t;console.log("[useChatState] \u68C0\u6D4B\u5230\u5386\u53F2\u6D88\u606F\u9700\u8981\u91CD\u7EC4, \u6D88\u606FID:",t.id);const r=new Map,g=new Map;t.structured_content&&t.structured_content.forEach(i=>{i.type==="product_list"&&Array.isArray(i.data)&&i.data.forEach(h=>{if(h&&h.shopify_product_id){const a=h.shopify_product_id;g.set(a,h);const l=a.match(/\d+$/)?.[0];l&&g.set(l,h),console.log("[useChatState] \u4ECE structured_content \u63D0\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E:",{fullId:a,numericId:l,title:h.title})}})}),t.content.forEach(i=>{i.type==="product_list"&&i.data.products.forEach(a=>{if(a&&a.shopifyId){r.set(a.shopifyId,a);const l=a.shopifyId.match(/\d+$/)?.[0];l&&r.set(l,a)}})});const S=ht(t.content,r,g,d,f);return{...t,content:S}}function mt(t={}){const{welcomeMessage:d,site:f,open:x,onOpenChange:p,onOpen:r,onClose:g,onMessageSend:S,onError:i,onTextMessage:h,onProductList:a,onPromotionList:l,onAddToCart:M,onCart:T,productCardRender:O}=t,{sessionId:L,saveSession:B,clearSession:U}=(0,G.useSession)(),[K,Q]=(0,u.useState)("");(0,u.useEffect)(()=>{(0,j.getUserId)().then(y=>Q(y))},[]);const[X,D]=(0,u.useState)(()=>d?[{id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:d}],timestamp:Date.now()}]:[]),[Y,N]=(0,u.useState)(!1),_=x!==void 0,q=_?x:Y,[Z,tt]=(0,u.useState)(""),[et,$]=(0,u.useState)(!1),e=(0,u.useRef)(null),z=(0,u.useRef)(!1),E=(0,u.useRef)(new Map),P=(0,u.useRef)(new Map),I=(0,u.useRef)(""),k=(0,u.useRef)([]),nt=(0,u.useCallback)(()=>{_||N(!0),p?.(!0),r?.()},[_,p,r]),st=(0,u.useCallback)(()=>{_||N(!1),p?.(!1),g?.()},[_,p,g]),ot=(0,u.useCallback)(()=>{const y=!q;_||N(y),p?.(y),y?r?.():g?.()},[_,q,p,r,g]),A=(0,u.useCallback)(y=>{if(!y){console.warn("[useChatState] Attempted to add null/undefined message");return}D(R=>[...R,y])},[]),rt=(0,u.useCallback)(y=>{const R=y.filter(s=>s!=null);R.length!==y.length&&console.warn("[useChatState] Filtered out null/undefined messages from batch set");const v=R.map(s=>Ct(s,M,O));D(v)},[M,O]),V=(0,u.useCallback)(()=>{D([])},[]),at=(0,u.useCallback)(y=>{const{event:R,data:v}=y;switch(R){case"message_start":{$(!0),z.current=!1,I.current="",k.current=[];const s=v;s.sessionId&&s.sessionId!==L&&B(s.sessionId),D(o=>{const n=o[o.length-1];if(n&&n.role==="assistant"&&n.content.length===1&&n.content[0].type==="thinking")return e.current=n,o;{const w=`msg-${Date.now()}`;return e.current={id:w,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()},[...o,e.current]}});break}case"content_delta":{const s=v,o=s.delta||s.text||"";if(e.current&&o){z.current||(z.current=!0,h?.()),e.current.content.some(c=>c.type==="thinking")&&(e.current.content=e.current.content.filter(c=>c.type!=="thinking")),I.current+=o;const{contents:C,remainingBuffer:w}=gt(I.current,E.current,P.current,M,O);I.current=w,C.length>0&&(C.forEach(c=>{const m=e.current.content[e.current.content.length-1];c.type==="text"&&m&&m.type==="text"?m.text+=c.text:e.current.content.push(c)}),D(c=>{if(!e.current)return c;const m=[...c],b=m.findIndex(W=>W&&W.id===e.current.id);return b>=0?m[b]={...e.current}:m.push({...e.current}),m}))}break}case"content_block":{const s=v;if(e.current){const o=s.type||s.data?.type,n=s.data;if(!o||!n){console.warn("[useChatState] Invalid content_block:",s);break}let C;if(o==="product_list"&&Array.isArray(n)){a?.(),n.forEach(c=>{if(c&&c.shopify_product_id){const m=c.shopify_product_id;P.current.set(m,c);const b=m.match(/\d+$/)?.[0];b&&P.current.set(b,c)}}),(0,H.transformProducts)(n,f).forEach(c=>{if(c&&c.shopifyId){E.current.set(c.shopifyId,c);const m=c.shopifyId.match(/\d+$/)?.[0];m&&E.current.set(m,c),console.log("[useChatState] \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04:",{fullId:c.shopifyId,numericId:m,title:c.title})}}),console.log("[useChatState] \u2705 \u4EA7\u54C1\u5217\u8868\u5DF2\u7F13\u5B58\uFF0C\u4E0D\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF08\u907F\u514D\u95EA\u70C1\uFF09");break}else o==="product_comparison"&&n.products?C={type:"product_comparison",data:{products:(0,H.transformProducts)(n.products,f),dimensions:n.dimensions||{}}}:o==="faq_list"&&n.found!==void 0?C={type:"faq_list",data:n}:o==="quick_replies"&&n.replies?C={type:"quick_replies",data:{replies:n.replies}}:o==="policy"&&n.title&&n.content?C={type:"policy",data:{title:n.title,content:n.content}}:o==="promotion_list"&&n.found!==void 0?(l?.(),C={type:"promotion_list",data:n}):o==="cart"&&n.id!==void 0?C={type:"cart",data:{...(0,J.transformCartData)(n),onCart:T}}:C={type:o,data:n};console.log("[useChatState] \u2705 \u5361\u7247\u5DF2\u7F13\u5B58\uFF0C\u7B49\u5F85\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A:",o),k.current.push(C)}break}case"tool_start":case"tool_end":break;case"message_end":{if($(!1),e.current&&I.current){console.log("[useChatState] \u5904\u7406\u5269\u4F59\u7F13\u51B2\u533A:",I.current);const s=e.current.content[e.current.content.length-1];s&&s.type==="text"?s.text+=I.current:e.current.content.push({type:"text",text:I.current})}e.current&&k.current.length>0&&(console.log("[useChatState] \u{1F4CB} \u6587\u672C\u5DF2\u5B8C\u6210\uFF0C\u73B0\u5728\u6DFB\u52A0",k.current.length,"\u4E2A\u7F13\u5B58\u7684\u5361\u7247"),e.current.content.push(...k.current)),e.current&&e.current.content.some(o=>o.type==="thinking")&&(console.log("[useChatState] \u26A0\uFE0F message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u7ACB\u5373\u79FB\u9664\uFF08\u89C6\u4E3A\u8D85\u65F6\uFF09"),e.current.content=e.current.content.filter(o=>o.type!=="thinking"),e.current.content.length===0&&e.current.content.push({type:"text",text:"Response timed out, please try again."})),e.current&&D(s=>{if(!e.current)return s;const o=[...s],n=o.findIndex(C=>C&&C.id===e.current.id);return n>=0&&(o[n]={...e.current}),o}),I.current="",k.current=[],E.current.clear(),P.current.clear(),e.current=null;break}case"status":{v.type==="session_expired"&&(V(),U(),d&&A({id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:d}],timestamp:Date.now()}));break}case"error":{const s=v;$(!1),I.current="",k.current=[],E.current.clear(),P.current.clear(),e.current=null,A({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:s.message,code:s.code}}],timestamp:Date.now()}),i?.(new Error(s.message));break}case"done":{$(!1),I.current="",k.current=[],E.current.clear(),P.current.clear(),e.current=null;break}default:break}},[d,f,A,V,U,B,L,i,h,a,l,M,T]);return{messages:X,isOpen:q,userId:K,sessionId:L,inputValue:Z,isStreaming:et,openChat:nt,closeChat:st,toggleChat:ot,setInputValue:tt,addMessage:A,setMessages:rt,clearMessages:V,handleSSEEvent:at,saveSession:B,clearSession:U}}
|
|
2
2
|
//# sourceMappingURL=useChatState.js.map
|