@anker-in/campaign-ui 0.4.0 → 0.4.2

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.
Files changed (57) hide show
  1. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js +1 -1
  2. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js.map +2 -2
  3. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js +1 -1
  4. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
  5. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
  6. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
  7. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
  8. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
  9. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
  10. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
  11. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
  12. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
  13. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  14. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
  15. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
  16. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
  17. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js +1 -1
  18. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js.map +3 -3
  19. package/dist/cjs/stories/CartCard.stories.d.ts +33 -0
  20. package/dist/cjs/stories/CartCard.stories.js +21 -0
  21. package/dist/cjs/stories/CartCard.stories.js.map +7 -0
  22. package/dist/cjs/stories/LiveChatWidget.stories.js +2 -2
  23. package/dist/cjs/stories/LiveChatWidget.stories.js.map +2 -2
  24. package/dist/esm/components/LiveChatWidget/components/ChatInput.js +1 -1
  25. package/dist/esm/components/LiveChatWidget/components/ChatInput.js.map +2 -2
  26. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js +2 -2
  27. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
  28. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
  29. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
  30. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
  31. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
  32. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
  33. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
  34. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
  35. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
  36. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  37. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
  38. package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
  39. package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
  40. package/dist/esm/components/LiveChatWidget/utils/fetcher.js +1 -1
  41. package/dist/esm/components/LiveChatWidget/utils/fetcher.js.map +3 -3
  42. package/dist/esm/stories/CartCard.stories.d.ts +33 -0
  43. package/dist/esm/stories/CartCard.stories.js +21 -0
  44. package/dist/esm/stories/CartCard.stories.js.map +7 -0
  45. package/dist/esm/stories/LiveChatWidget.stories.js +1 -1
  46. package/dist/esm/stories/LiveChatWidget.stories.js.map +2 -2
  47. package/package.json +1 -1
  48. package/src/components/LiveChatWidget/components/ChatInput.tsx +2 -2
  49. package/src/components/LiveChatWidget/components/ChatMessage.tsx +1 -1
  50. package/src/components/LiveChatWidget/components/MessageContent/CartCard.tsx +7 -7
  51. package/src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx +2 -2
  52. package/src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx +1 -1
  53. package/src/components/LiveChatWidget/components/MessageContent/ProductList.tsx +2 -2
  54. package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +2 -2
  55. package/src/components/LiveChatWidget/components/MessageContent/ThinkingBlock.tsx +3 -3
  56. package/src/components/LiveChatWidget/utils/fetcher.ts +12 -3
  57. package/src/stories/LiveChatWidget.stories.tsx +2 -2
@@ -1,5 +1,5 @@
1
- import{jsx as s,jsxs as C}from"react/jsx-runtime";import{MessageContent as d}from"./MessageContent";import u from"classnames";function v(t){const r=new Date(t),o=r.getHours().toString().padStart(2,"0"),i=r.getMinutes().toString().padStart(2,"0");return`${o}:${i}`}const $=({message:t,rendererRegistry:r,defaultRenderer:o,showTimestamp:i=!0,className:c="",onAddToCart:p})=>{const n=t.role==="user",R=t.role==="assistant",y=t.role==="system",g=t.role==="tool";if(y)return s("div",{className:`flex justify-center py-2 ${c}`,children:s("div",{className:"",children:t.content.map((e,a)=>s(d,{content:e,isUser:!1,isSystem:!0,rendererRegistry:r,defaultRenderer:o},a))})});if(g)return null;const f=["product_list","product_comparison","faq_list","promotion_list","cart"],l=t.content.filter(e=>!f.includes(e.type)),x=t.content.filter(e=>f.includes(e.type)),m=l.some(e=>e.type==="product_card");return s("div",{className:`flex ${n?"justify-end":"justify-start"} py-2 ${c}`,children:C("div",{className:"flex w-fit max-w-full flex-col gap-2",children:[l.length>0&&s("div",{className:u("w-fit min-w-0 overflow-hidden rounded-2xl ",n?"text-white":"text-[#1D1D1F]",m?"p-4":"p-3"),style:{backgroundColor:n?"#005D8E":"#F5F6F7"},children:s("div",{className:u("flex w-full min-w-0 flex-col",m?"gap-0":"gap-2"),children:l.map((e,a)=>s(d,{content:e,isUser:n,isSystem:!1,rendererRegistry:r,defaultRenderer:o,onAddToCart:p},a))})}),x.map((e,a)=>s("div",{className:"w-full",children:s(d,{content:e,isUser:n,isSystem:!1,rendererRegistry:r,defaultRenderer:o,onAddToCart:p})},`standalone-${a}`)),i&&s("span",{className:`
1
+ import{jsx as s,jsxs as b}from"react/jsx-runtime";import{MessageContent as d}from"./MessageContent";import m from"classnames";function x(t){const r=new Date(t),o=r.getHours().toString().padStart(2,"0"),i=r.getMinutes().toString().padStart(2,"0");return`${o}:${i}`}const $=({message:t,rendererRegistry:r,defaultRenderer:o,showTimestamp:i=!0,className:c="",onAddToCart:p})=>{const n=t.role==="user",C=t.role==="assistant",y=t.role==="system",g=t.role==="tool";if(y)return s("div",{className:`flex justify-center py-2 ${c}`,children:s("div",{className:"",children:t.content.map((e,a)=>s(d,{content:e,isUser:!1,isSystem:!0,rendererRegistry:r,defaultRenderer:o},a))})});if(g)return null;const u=["product_list","product_comparison","faq_list","promotion_list","cart"],l=t.content.filter(e=>!u.includes(e.type)),v=t.content.filter(e=>u.includes(e.type)),f=l.some(e=>e.type==="product_card");return s("div",{className:`flex ${n?"justify-end":"justify-start"} py-2 ${c}`,children:b("div",{className:"flex w-fit max-w-full flex-col gap-2",children:[l.length>0&&s("div",{className:m("w-fit min-w-0 overflow-hidden rounded-2xl ",n?"livechat-bubble-user text-white":"livechat-bubble-bot text-[#1D1D1F]",f?"p-4":"p-3"),style:{backgroundColor:n?"#005D8E":"#F5F6F7"},children:s("div",{className:m("flex w-full min-w-0 flex-col",f?"gap-0":"gap-2"),children:l.map((e,a)=>s(d,{content:e,isUser:n,isSystem:!1,rendererRegistry:r,defaultRenderer:o,onAddToCart:p},a))})}),v.map((e,a)=>s("div",{className:"w-full",children:s(d,{content:e,isUser:n,isSystem:!1,rendererRegistry:r,defaultRenderer:o,onAddToCart:p})},`standalone-${a}`)),i&&s("span",{className:`
2
2
  px-2 text-xs text-gray-400
3
3
  ${n?"text-right":"text-left"}
4
- `,children:v(t.timestamp)})]})})};export{$ as ChatMessage};
4
+ `,children:x(t.timestamp)})]})})};export{$ as ChatMessage};
5
5
  //# sourceMappingURL=ChatMessage.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/components/LiveChatWidget/components/ChatMessage.tsx"],
4
- "sourcesContent": ["/**\n * \u5355\u6761\u804A\u5929\u6D88\u606F\u7EC4\u4EF6\n * \u663E\u793A\u6D88\u606F\u6C14\u6CE1\u3001\u53D1\u9001\u8005\u3001\u65F6\u95F4\u6233\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6D88\u606F\u5C55\u793A\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport type { Message, MessageRenderer } from '../types'\nimport { MessageContent } from './MessageContent'\nimport { MessageRendererRegistry } from '../utils/messageRenderers'\nimport cn from 'classnames'\nexport interface ChatMessageProps {\n /**\n * \u6D88\u606F\u6570\u636E\n */\n message: Message\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 * \u662F\u5426\u663E\u793A\u65F6\u95F4\u6233\n * @default true\n */\n showTimestamp?: boolean\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/**\n * \u683C\u5F0F\u5316\u65F6\u95F4\u6233\u4E3A\u53EF\u8BFB\u683C\u5F0F\n * @param timestamp Unix \u65F6\u95F4\u6233\uFF08\u6BEB\u79D2\uFF09\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u65F6\u95F4\u5B57\u7B26\u4E32 (\u5982 \"14:30\")\n */\nfunction formatTimestamp(timestamp: number): string {\n const date = new Date(timestamp)\n const hours = date.getHours().toString().padStart(2, '0')\n const minutes = date.getMinutes().toString().padStart(2, '0')\n return `${hours}:${minutes}`\n}\n\n/**\n * \u5355\u6761\u804A\u5929\u6D88\u606F\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u6D88\u606F\u6C14\u6CE1\uFF08\u7528\u6237 vs AI \u52A9\u624B\u4E0D\u540C\u6837\u5F0F\uFF09\n * - \u652F\u6301\u591A\u4E2A content \u5757\uFF08\u4E00\u6761\u6D88\u606F\u53EF\u5305\u542B\u591A\u79CD\u5185\u5BB9\u7C7B\u578B\uFF09\n * - \u663E\u793A\u65F6\u95F4\u6233\n * - \u7CFB\u7EDF\u6D88\u606F\u5C45\u4E2D\u663E\u793A\n *\n * \u6837\u5F0F\u89C4\u5219\uFF1A\n * - \u7528\u6237\u6D88\u606F\uFF1A\u53F3\u5BF9\u9F50\uFF0C\u7070\u8272\u80CC\u666F\n * - AI \u52A9\u624B\u6D88\u606F\uFF1A\u5DE6\u5BF9\u9F50\uFF0C\u767D\u8272\u80CC\u666F\n * - \u7CFB\u7EDF\u6D88\u606F\uFF1A\u5C45\u4E2D\uFF0C\u9EC4\u8272\u80CC\u666F\n *\n * @example\n * ```tsx\n * <ChatMessage\n * message={message}\n * rendererRegistry={customRegistry}\n * showTimestamp={true}\n * />\n * ```\n */\nexport const ChatMessage: React.FC<ChatMessageProps> = ({\n message,\n rendererRegistry,\n defaultRenderer,\n showTimestamp = true,\n className = '',\n onAddToCart,\n}) => {\n const isUser = message.role === 'user'\n const isAssistant = message.role === 'assistant'\n const isSystem = message.role === 'system'\n const isTool = message.role === 'tool'\n\n // \u7CFB\u7EDF\u6D88\u606F\u7279\u6B8A\u5904\u7406\uFF08\u5C45\u4E2D\u663E\u793A\uFF09\n if (isSystem) {\n return (\n <div className={`flex justify-center py-2 ${className}`}>\n <div className=\"\">\n {message.content.map((content, index) => (\n <MessageContent\n key={index}\n content={content}\n isUser={false}\n isSystem={true}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n />\n ))}\n </div>\n </div>\n )\n }\n\n // \u5DE5\u5177\u6D88\u606F\uFF08\u901A\u5E38\u4E0D\u663E\u793A\uFF0C\u6216\u663E\u793A\u4E3A\u7CFB\u7EDF\u6D88\u606F\uFF09\n if (isTool) {\n return null\n }\n\n // \u5206\u79BB\u5185\u5BB9\u7C7B\u578B\uFF1A\u9700\u8981\u72EC\u7ACB\u6E32\u67D3\u7684\u7ED3\u6784\u5316\u5185\u5BB9\n // \u6CE8\u610F\uFF1Aproduct_card \u4E0D\u5728\u6B64\u5217\u8868\u4E2D\uFF0C\u5B83\u4F1A\u5728\u6C14\u6CE1\u5185\u6E32\u67D3\n const structuredContentTypes = ['product_list', 'product_comparison', 'faq_list', 'promotion_list', 'cart']\n\n // \u5C06\u5185\u5BB9\u5206\u4E3A\u4E24\u7EC4\uFF1A\u6C14\u6CE1\u5185\u5BB9 \u548C \u72EC\u7ACB\u5185\u5BB9\n const bubbleContent = message.content.filter(c => !structuredContentTypes.includes(c.type))\n const standaloneContent = message.content.filter(c => structuredContentTypes.includes(c.type))\n const isBubbleProductCard = bubbleContent.some(c => c.type === 'product_card')\n // \u7528\u6237/\u52A9\u624B\u6D88\u606F\n return (\n <div className={`flex ${isUser ? 'justify-end' : 'justify-start'} py-2 ${className}`}>\n <div className=\"flex w-fit max-w-full flex-col gap-2\">\n {/* \u6D88\u606F\u6C14\u6CE1\uFF08\u5305\u542B\u6587\u672C\u548C\u4EA7\u54C1\u5361\u7247\uFF0C\u6309\u539F\u59CB\u987A\u5E8F\uFF09 */}\n {bubbleContent.length > 0 && (\n <div\n className={cn(\n 'w-fit min-w-0 overflow-hidden rounded-2xl ',\n isUser ? 'text-white' : 'text-[#1D1D1F]',\n isBubbleProductCard ? 'p-4' : 'p-3'\n )}\n style={{\n backgroundColor: isUser ? '#005D8E' : '#F5F6F7',\n }}\n >\n {/* \u6309\u539F\u59CB\u987A\u5E8F\u6E32\u67D3\u6C14\u6CE1\u5185\u7684\u6240\u6709\u5185\u5BB9\uFF08text \u548C product_card \u4EA4\u66FF\uFF09 */}\n <div className={cn(\n 'flex w-full min-w-0 flex-col',\n isBubbleProductCard ?'gap-0':'gap-2'\n )}>\n {bubbleContent.map((content, index) => (\n <MessageContent\n key={index}\n content={content}\n isUser={isUser}\n isSystem={false}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n onAddToCart={onAddToCart}\n />\n ))}\n </div>\n </div>\n )}\n\n {/* \u72EC\u7ACB\u6E32\u67D3\u7684\u7ED3\u6784\u5316\u5185\u5BB9\uFF08\u4E0D\u5728\u6C14\u6CE1\u5185\uFF09 */}\n {standaloneContent.map((content, index) => (\n <div key={`standalone-${index}`} className=\"w-full\">\n <MessageContent\n content={content}\n isUser={isUser}\n isSystem={false}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n onAddToCart={onAddToCart}\n />\n </div>\n ))}\n\n {/* \u65F6\u95F4\u6233 */}\n {showTimestamp && (\n <span\n className={`\n px-2 text-xs text-gray-400\n ${isUser ? 'text-right' : 'text-left'}\n `}\n >\n {formatTimestamp(message.timestamp)}\n </span>\n )}\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "AAkGY,cAAAA,EA8BN,QAAAC,MA9BM,oBA1FZ,OAAS,kBAAAC,MAAsB,mBAE/B,OAAOC,MAAQ,aAuCf,SAASC,EAAgBC,EAA2B,CAClD,MAAMC,EAAO,IAAI,KAAKD,CAAS,EACzBE,EAAQD,EAAK,SAAS,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,EAClDE,EAAUF,EAAK,WAAW,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,EAC5D,MAAO,GAAGC,CAAK,IAAIC,CAAO,EAC5B,CAyBO,MAAMC,EAA0C,CAAC,CACtD,QAAAC,EACA,iBAAAC,EACA,gBAAAC,EACA,cAAAC,EAAgB,GAChB,UAAAC,EAAY,GACZ,YAAAC,CACF,IAAM,CACJ,MAAMC,EAASN,EAAQ,OAAS,OAC1BO,EAAcP,EAAQ,OAAS,YAC/BQ,EAAWR,EAAQ,OAAS,SAC5BS,EAAST,EAAQ,OAAS,OAGhC,GAAIQ,EACF,OACElB,EAAC,OAAI,UAAW,4BAA4Bc,CAAS,GACnD,SAAAd,EAAC,OAAI,UAAU,GACZ,SAAAU,EAAQ,QAAQ,IAAI,CAACU,EAASC,IAC7BrB,EAACE,EAAA,CAEC,QAASkB,EACT,OAAQ,GACR,SAAU,GACV,iBAAkBT,EAClB,gBAAiBC,GALZS,CAMP,CACD,EACH,EACF,EAKJ,GAAIF,EACF,OAAO,KAKT,MAAMG,EAAyB,CAAC,eAAgB,qBAAsB,WAAY,iBAAkB,MAAM,EAGpGC,EAAgBb,EAAQ,QAAQ,OAAOc,GAAK,CAACF,EAAuB,SAASE,EAAE,IAAI,CAAC,EACpFC,EAAoBf,EAAQ,QAAQ,OAAOc,GAAKF,EAAuB,SAASE,EAAE,IAAI,CAAC,EACvFE,EAAsBH,EAAc,KAAKC,GAAKA,EAAE,OAAS,cAAc,EAE7E,OACExB,EAAC,OAAI,UAAW,QAAQgB,EAAS,cAAgB,eAAe,SAASF,CAAS,GAChF,SAAAb,EAAC,OAAI,UAAU,uCAEZ,UAAAsB,EAAc,OAAS,GACtBvB,EAAC,OACC,UAAWG,EACT,6CACAa,EAAS,aAAe,iBACxBU,EAAsB,MAAQ,KAChC,EACA,MAAO,CACL,gBAAiBV,EAAS,UAAY,SACxC,EAGA,SAAAhB,EAAC,OAAI,UAAWG,EACd,+BACAuB,EAAqB,QAAQ,OAC/B,EACG,SAAAH,EAAc,IAAI,CAACH,EAASC,IAC3BrB,EAACE,EAAA,CAEC,QAASkB,EACT,OAAQJ,EACR,SAAU,GACV,iBAAkBL,EAClB,gBAAiBC,EACjB,YAAaG,GANRM,CAOP,CACD,EACH,EACF,EAIDI,EAAkB,IAAI,CAACL,EAASC,IAC/BrB,EAAC,OAAgC,UAAU,SACzC,SAAAA,EAACE,EAAA,CACC,QAASkB,EACT,OAAQJ,EACR,SAAU,GACV,iBAAkBL,EAClB,gBAAiBC,EACjB,YAAaG,EACf,GARQ,cAAcM,CAAK,EAS7B,CACD,EAGAR,GACCb,EAAC,QACC,UAAW;AAAA;AAAA,gBAEPgB,EAAS,aAAe,WAAW;AAAA,cAGtC,SAAAZ,EAAgBM,EAAQ,SAAS,EACpC,GAEJ,EACF,CAEJ",
4
+ "sourcesContent": ["/**\n * \u5355\u6761\u804A\u5929\u6D88\u606F\u7EC4\u4EF6\n * \u663E\u793A\u6D88\u606F\u6C14\u6CE1\u3001\u53D1\u9001\u8005\u3001\u65F6\u95F4\u6233\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u6D88\u606F\u5C55\u793A\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport type { Message, MessageRenderer } from '../types'\nimport { MessageContent } from './MessageContent'\nimport { MessageRendererRegistry } from '../utils/messageRenderers'\nimport cn from 'classnames'\nexport interface ChatMessageProps {\n /**\n * \u6D88\u606F\u6570\u636E\n */\n message: Message\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 * \u662F\u5426\u663E\u793A\u65F6\u95F4\u6233\n * @default true\n */\n showTimestamp?: boolean\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/**\n * \u683C\u5F0F\u5316\u65F6\u95F4\u6233\u4E3A\u53EF\u8BFB\u683C\u5F0F\n * @param timestamp Unix \u65F6\u95F4\u6233\uFF08\u6BEB\u79D2\uFF09\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u65F6\u95F4\u5B57\u7B26\u4E32 (\u5982 \"14:30\")\n */\nfunction formatTimestamp(timestamp: number): string {\n const date = new Date(timestamp)\n const hours = date.getHours().toString().padStart(2, '0')\n const minutes = date.getMinutes().toString().padStart(2, '0')\n return `${hours}:${minutes}`\n}\n\n/**\n * \u5355\u6761\u804A\u5929\u6D88\u606F\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u6D88\u606F\u6C14\u6CE1\uFF08\u7528\u6237 vs AI \u52A9\u624B\u4E0D\u540C\u6837\u5F0F\uFF09\n * - \u652F\u6301\u591A\u4E2A content \u5757\uFF08\u4E00\u6761\u6D88\u606F\u53EF\u5305\u542B\u591A\u79CD\u5185\u5BB9\u7C7B\u578B\uFF09\n * - \u663E\u793A\u65F6\u95F4\u6233\n * - \u7CFB\u7EDF\u6D88\u606F\u5C45\u4E2D\u663E\u793A\n *\n * \u6837\u5F0F\u89C4\u5219\uFF1A\n * - \u7528\u6237\u6D88\u606F\uFF1A\u53F3\u5BF9\u9F50\uFF0C\u7070\u8272\u80CC\u666F\n * - AI \u52A9\u624B\u6D88\u606F\uFF1A\u5DE6\u5BF9\u9F50\uFF0C\u767D\u8272\u80CC\u666F\n * - \u7CFB\u7EDF\u6D88\u606F\uFF1A\u5C45\u4E2D\uFF0C\u9EC4\u8272\u80CC\u666F\n *\n * @example\n * ```tsx\n * <ChatMessage\n * message={message}\n * rendererRegistry={customRegistry}\n * showTimestamp={true}\n * />\n * ```\n */\nexport const ChatMessage: React.FC<ChatMessageProps> = ({\n message,\n rendererRegistry,\n defaultRenderer,\n showTimestamp = true,\n className = '',\n onAddToCart,\n}) => {\n const isUser = message.role === 'user'\n const isAssistant = message.role === 'assistant'\n const isSystem = message.role === 'system'\n const isTool = message.role === 'tool'\n\n // \u7CFB\u7EDF\u6D88\u606F\u7279\u6B8A\u5904\u7406\uFF08\u5C45\u4E2D\u663E\u793A\uFF09\n if (isSystem) {\n return (\n <div className={`flex justify-center py-2 ${className}`}>\n <div className=\"\">\n {message.content.map((content, index) => (\n <MessageContent\n key={index}\n content={content}\n isUser={false}\n isSystem={true}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n />\n ))}\n </div>\n </div>\n )\n }\n\n // \u5DE5\u5177\u6D88\u606F\uFF08\u901A\u5E38\u4E0D\u663E\u793A\uFF0C\u6216\u663E\u793A\u4E3A\u7CFB\u7EDF\u6D88\u606F\uFF09\n if (isTool) {\n return null\n }\n\n // \u5206\u79BB\u5185\u5BB9\u7C7B\u578B\uFF1A\u9700\u8981\u72EC\u7ACB\u6E32\u67D3\u7684\u7ED3\u6784\u5316\u5185\u5BB9\n // \u6CE8\u610F\uFF1Aproduct_card \u4E0D\u5728\u6B64\u5217\u8868\u4E2D\uFF0C\u5B83\u4F1A\u5728\u6C14\u6CE1\u5185\u6E32\u67D3\n const structuredContentTypes = ['product_list', 'product_comparison', 'faq_list', 'promotion_list', 'cart']\n\n // \u5C06\u5185\u5BB9\u5206\u4E3A\u4E24\u7EC4\uFF1A\u6C14\u6CE1\u5185\u5BB9 \u548C \u72EC\u7ACB\u5185\u5BB9\n const bubbleContent = message.content.filter(c => !structuredContentTypes.includes(c.type))\n const standaloneContent = message.content.filter(c => structuredContentTypes.includes(c.type))\n const isBubbleProductCard = bubbleContent.some(c => c.type === 'product_card')\n // \u7528\u6237/\u52A9\u624B\u6D88\u606F\n return (\n <div className={`flex ${isUser ? 'justify-end' : 'justify-start'} py-2 ${className}`}>\n <div className=\"flex w-fit max-w-full flex-col gap-2\">\n {/* \u6D88\u606F\u6C14\u6CE1\uFF08\u5305\u542B\u6587\u672C\u548C\u4EA7\u54C1\u5361\u7247\uFF0C\u6309\u539F\u59CB\u987A\u5E8F\uFF09 */}\n {bubbleContent.length > 0 && (\n <div\n className={cn(\n 'w-fit min-w-0 overflow-hidden rounded-2xl ',\n isUser ? 'livechat-bubble-user text-white' : 'livechat-bubble-bot text-[#1D1D1F]',\n isBubbleProductCard ? 'p-4' : 'p-3'\n )}\n style={{\n backgroundColor: isUser ? '#005D8E' : '#F5F6F7',\n }}\n >\n {/* \u6309\u539F\u59CB\u987A\u5E8F\u6E32\u67D3\u6C14\u6CE1\u5185\u7684\u6240\u6709\u5185\u5BB9\uFF08text \u548C product_card \u4EA4\u66FF\uFF09 */}\n <div className={cn(\n 'flex w-full min-w-0 flex-col',\n isBubbleProductCard ?'gap-0':'gap-2'\n )}>\n {bubbleContent.map((content, index) => (\n <MessageContent\n key={index}\n content={content}\n isUser={isUser}\n isSystem={false}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n onAddToCart={onAddToCart}\n />\n ))}\n </div>\n </div>\n )}\n\n {/* \u72EC\u7ACB\u6E32\u67D3\u7684\u7ED3\u6784\u5316\u5185\u5BB9\uFF08\u4E0D\u5728\u6C14\u6CE1\u5185\uFF09 */}\n {standaloneContent.map((content, index) => (\n <div key={`standalone-${index}`} className=\"w-full\">\n <MessageContent\n content={content}\n isUser={isUser}\n isSystem={false}\n rendererRegistry={rendererRegistry}\n defaultRenderer={defaultRenderer}\n onAddToCart={onAddToCart}\n />\n </div>\n ))}\n\n {/* \u65F6\u95F4\u6233 */}\n {showTimestamp && (\n <span\n className={`\n px-2 text-xs text-gray-400\n ${isUser ? 'text-right' : 'text-left'}\n `}\n >\n {formatTimestamp(message.timestamp)}\n </span>\n )}\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "AAkGY,cAAAA,EA8BN,QAAAC,MA9BM,oBA1FZ,OAAS,kBAAAC,MAAsB,mBAE/B,OAAOC,MAAQ,aAuCf,SAASC,EAAgBC,EAA2B,CAClD,MAAMC,EAAO,IAAI,KAAKD,CAAS,EACzBE,EAAQD,EAAK,SAAS,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,EAClDE,EAAUF,EAAK,WAAW,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,EAC5D,MAAO,GAAGC,CAAK,IAAIC,CAAO,EAC5B,CAyBO,MAAMC,EAA0C,CAAC,CACtD,QAAAC,EACA,iBAAAC,EACA,gBAAAC,EACA,cAAAC,EAAgB,GAChB,UAAAC,EAAY,GACZ,YAAAC,CACF,IAAM,CACJ,MAAMC,EAASN,EAAQ,OAAS,OAC1BO,EAAcP,EAAQ,OAAS,YAC/BQ,EAAWR,EAAQ,OAAS,SAC5BS,EAAST,EAAQ,OAAS,OAGhC,GAAIQ,EACF,OACElB,EAAC,OAAI,UAAW,4BAA4Bc,CAAS,GACnD,SAAAd,EAAC,OAAI,UAAU,GACZ,SAAAU,EAAQ,QAAQ,IAAI,CAACU,EAASC,IAC7BrB,EAACE,EAAA,CAEC,QAASkB,EACT,OAAQ,GACR,SAAU,GACV,iBAAkBT,EAClB,gBAAiBC,GALZS,CAMP,CACD,EACH,EACF,EAKJ,GAAIF,EACF,OAAO,KAKT,MAAMG,EAAyB,CAAC,eAAgB,qBAAsB,WAAY,iBAAkB,MAAM,EAGpGC,EAAgBb,EAAQ,QAAQ,OAAOc,GAAK,CAACF,EAAuB,SAASE,EAAE,IAAI,CAAC,EACpFC,EAAoBf,EAAQ,QAAQ,OAAOc,GAAKF,EAAuB,SAASE,EAAE,IAAI,CAAC,EACvFE,EAAsBH,EAAc,KAAKC,GAAKA,EAAE,OAAS,cAAc,EAE7E,OACExB,EAAC,OAAI,UAAW,QAAQgB,EAAS,cAAgB,eAAe,SAASF,CAAS,GAChF,SAAAb,EAAC,OAAI,UAAU,uCAEZ,UAAAsB,EAAc,OAAS,GACtBvB,EAAC,OACC,UAAWG,EACT,6CACAa,EAAS,kCAAoC,qCAC7CU,EAAsB,MAAQ,KAChC,EACA,MAAO,CACL,gBAAiBV,EAAS,UAAY,SACxC,EAGA,SAAAhB,EAAC,OAAI,UAAWG,EACd,+BACAuB,EAAqB,QAAQ,OAC/B,EACG,SAAAH,EAAc,IAAI,CAACH,EAASC,IAC3BrB,EAACE,EAAA,CAEC,QAASkB,EACT,OAAQJ,EACR,SAAU,GACV,iBAAkBL,EAClB,gBAAiBC,EACjB,YAAaG,GANRM,CAOP,CACD,EACH,EACF,EAIDI,EAAkB,IAAI,CAACL,EAASC,IAC/BrB,EAAC,OAAgC,UAAU,SACzC,SAAAA,EAACE,EAAA,CACC,QAASkB,EACT,OAAQJ,EACR,SAAU,GACV,iBAAkBL,EAClB,gBAAiBC,EACjB,YAAaG,EACf,GARQ,cAAcM,CAAK,EAS7B,CACD,EAGAR,GACCb,EAAC,QACC,UAAW;AAAA;AAAA,gBAEPgB,EAAS,aAAe,WAAW;AAAA,cAGtC,SAAAZ,EAAgBM,EAAQ,SAAS,EACpC,GAEJ,EACF,CAEJ",
6
6
  "names": ["jsx", "jsxs", "MessageContent", "cn", "formatTimestamp", "timestamp", "date", "hours", "minutes", "ChatMessage", "message", "rendererRegistry", "defaultRenderer", "showTimestamp", "className", "onAddToCart", "isUser", "isAssistant", "isSystem", "isTool", "content", "index", "structuredContentTypes", "bubbleContent", "c", "standaloneContent", "isBubbleProductCard"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{jsx as t,jsxs as n}from"react/jsx-runtime";import{CURRENCY_SYMBOLS as f,DEFAULT_COMMON_TEXT as v}from"../../constants.js";function c(o){const{amount:l,currencyCode:s}=o,e=f[s]||s,a=parseFloat(l);return`${e}${a.toFixed(2)}`}const b=({line:o})=>{const{quantity:l,merchandise:s,cost:e}=o,{product:a,title:d,image:r}=s,i=r?.url||"",m=parseFloat(e.totalAmount.amount)<parseFloat(e.subtotalAmount.amount)&&e.totalAmount.currencyCode===e.subtotalAmount.currencyCode;return n("div",{className:"flex gap-4",children:[t("div",{className:"shrink-0 overflow-hidden rounded-md",style:{width:"72px",height:"72px"},children:t("img",{src:i,alt:a.title,className:"size-full object-cover",loading:"lazy"})}),n("div",{className:"flex flex-1 flex-col",children:[t("h4",{className:"line-clamp-2 text-sm tablet:text-[16px] font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:a.title}),n("div",{className:"flex items-end justify-between gap-2",children:[n("div",{className:"flex-1",children:[d&&t("p",{className:"mt-0.5 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]",children:d}),n("p",{className:"mt-1 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:["\xD7",l]})]}),n("div",{className:"flex gap-1 text-right",children:[t("div",{className:"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-gray-900",children:c(e.totalAmount)}),m&&t("div",{className:"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56] line-through",children:c(e.subtotalAmount)})]})]})]})]})},C=({total:o,totalText:l})=>t("div",{className:"border-t border-gray-200 p-4",children:n("div",{className:"flex items-center justify-between",children:[t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-gray-900",children:l}),t("span",{className:"text-base tablet:text-[18px] font-bold leading-[1.4] tracking-[-0.02em] text-gray-900",children:c(o)})]})}),A={render:o=>{const l=o,{data:s}=l;if(!s)return null;const{isEmpty:e,lines:a,cost:d,checkoutUrl:r,onCart:i,cartId:m,commonText:p}=s,u={...v,...p},g=()=>{i?i(m,r):r&&window.open(r,"_blank","noopener,noreferrer")};return e||!a||a.length===0?null:n("div",{className:"w-full max-w-md overflow-hidden rounded-2xl shadow-sm",style:{backgroundColor:"#F5F6F7"},children:[t("div",{className:"flex flex-col gap-6 overflow-y-auto p-4",children:a.map(x=>t(b,{line:x},x.id))}),t(C,{total:d.totalAmount,totalText:u.total}),(r||i)&&t("div",{className:"px-4 pb-4",children:t("button",{type:"button",onClick:g,className:"w-full rounded-full py-[10px] text-center text-sm font-bold leading-[1.4] tracking-[-0.02em] text-white",style:{backgroundColor:"#1D1D1F"},children:u.viewMore})})]})}};export{A as CartCard};
1
+ import{jsx as t,jsxs as s}from"react/jsx-runtime";import{CURRENCY_SYMBOLS as f,DEFAULT_COMMON_TEXT as v}from"../../constants.js";function c(n){const{amount:o,currencyCode:l}=n,e=f[l]||l,a=parseFloat(o);return`${e}${a.toFixed(2)}`}const b=({line:n})=>{const{quantity:o,merchandise:l,cost:e}=n,{product:a,title:d,image:r}=l,i=r?.url||"",m=parseFloat(e.totalAmount.amount)<parseFloat(e.subtotalAmount.amount)&&e.totalAmount.currencyCode===e.subtotalAmount.currencyCode;return s("div",{className:"flex gap-4",children:[t("div",{className:"shrink-0 overflow-hidden rounded-md",style:{width:"72px",height:"72px"},children:t("img",{src:i,alt:a.title,className:"size-full object-cover",loading:"lazy"})}),s("div",{className:"flex flex-1 flex-col",children:[t("h4",{className:"line-clamp-2 text-sm tablet:text-[16px] font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:a.title}),d&&t("p",{className:"mt-0.5 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]",children:d}),s("div",{className:"flex items-end justify-between gap-2 mt-1",children:[t("div",{className:"flex-1",children:s("p",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:["\xD7",o]})}),s("div",{className:"flex gap-1 text-right",children:[t("div",{className:"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-gray-900",children:c(e.totalAmount)}),m&&t("div",{className:"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56] line-through",children:c(e.subtotalAmount)})]})]})]})]})},C=({total:n,totalText:o})=>t("div",{className:"border-t border-gray-200 p-4",children:s("div",{className:"flex items-center justify-between",children:[t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-gray-900",children:o}),t("span",{className:"text-base tablet:text-[18px] font-bold leading-[1.4] tracking-[-0.02em] text-gray-900",children:c(n)})]})}),A={render:n=>{const o=n,{data:l}=o;if(!l)return null;const{isEmpty:e,lines:a,cost:d,checkoutUrl:r,onCart:i,cartId:m,commonText:p}=l,u={...v,...p},g=()=>{i?i(m,r):r&&window.open(r,"_blank","noopener,noreferrer")};return e||!a||a.length===0?null:s("div",{className:"w-full max-w-md overflow-hidden rounded-2xl shadow-sm",style:{backgroundColor:"#F5F6F7"},children:[t("div",{className:"flex flex-col gap-6 overflow-y-auto p-4",children:a.map(x=>t(b,{line:x},x.id))}),t(C,{total:d.totalAmount,totalText:u.total}),(r||i)&&t("div",{className:"px-4 pb-4",children:t("button",{type:"button",onClick:g,className:"livechat-btn-primary w-full rounded-full py-[10px] text-center text-sm font-bold leading-[1.4] tracking-[-0.02em] text-white",style:{backgroundColor:"#1D1D1F"},children:u.viewMore})})]})}};export{A as CartCard};
2
2
  //# sourceMappingURL=CartCard.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/CartCard.tsx"],
4
- "sourcesContent": ["/**\n * \u8D2D\u7269\u8F66\u5361\u7247\u6E32\u67D3\u5668\n * \u663E\u793A\u8D2D\u7269\u8F66\u5185\u5BB9\u3001\u4EF7\u683C\u6C47\u603B\u548C\u7ED3\u8D26\u6309\u94AE\n * \u57FA\u4E8E\u540E\u7AEF\u8FD4\u56DE\u7684\u8D2D\u7269\u8F66\u6570\u636E\u7ED3\u6784\n */\n\nimport React from 'react'\nimport type { MessageRenderer, CartContent, CartLine, CartAmount } from '../../types'\nimport { CURRENCY_SYMBOLS, DEFAULT_COMMON_TEXT } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u91D1\u989D\n * @param amount \u91D1\u989D\u5BF9\u8C61\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u91D1\u989D\u5B57\u7B26\u4E32\uFF08\u5982 \"$99.99\"\uFF09\n */\nfunction formatAmount(amount: CartAmount): string {\n const { amount: value, currencyCode } = amount\n\n const symbol = CURRENCY_SYMBOLS[currencyCode] || currencyCode\n const numValue = parseFloat(value)\n\n return `${symbol}${numValue.toFixed(2)}`\n}\n\n/**\n * \u8D2D\u7269\u8F66\u5546\u54C1\u884C\u7EC4\u4EF6\n */\nconst CartLineItem: React.FC<{\n line: CartLine\n}> = ({ line }) => {\n const { quantity, merchandise, cost } = line\n const { product, title: variantTitle, image } = merchandise\n\n // \u5546\u54C1\u56FE\u7247 URL\n const imageUrl = image?.url || ''\n\n // \u5224\u65AD\u662F\u5426\u6709\u6298\u6263\uFF08\u603B\u4EF7 < \u539F\u4EF7\uFF09\n const hasDiscount =\n parseFloat(cost.totalAmount.amount) < parseFloat(cost.subtotalAmount.amount) &&\n cost.totalAmount.currencyCode === cost.subtotalAmount.currencyCode\n\n return (\n <div className=\"flex gap-4\">\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\"shrink-0 overflow-hidden rounded-md\" style={{ width: '72px', height: '72px' }}>\n <img src={imageUrl} alt={product.title} className=\"size-full object-cover\" loading=\"lazy\" />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-1 flex-col\">\n <h4 className=\"line-clamp-2 text-sm tablet:text-[16px] font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {product.title}\n </h4>\n <div className=\"flex items-end justify-between gap-2\">\n {/* \u5DE6\u4FA7\uFF1A\u6807\u9898\u3001\u53D8\u4F53\u3001\u6570\u91CF */}\n <div className=\"flex-1\">\n {variantTitle && (\n <p className=\"mt-0.5 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]\">{variantTitle}</p>\n )}\n <p className=\"mt-1 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\u00D7{quantity}</p>\n </div>\n\n {/* \u53F3\u4FA7\uFF1A\u4EF7\u683C */}\n <div className=\"flex gap-1 text-right\">\n <div className=\"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-gray-900\">\n {formatAmount(cost.totalAmount)}\n </div>\n {hasDiscount && (\n <div className=\"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56] line-through\">\n {formatAmount(cost.subtotalAmount)}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * \u4EF7\u683C\u6C47\u603B\u7EC4\u4EF6\uFF08\u7B80\u5316\u7248\uFF09\n */\nconst CartSummary: React.FC<{\n total: CartAmount\n totalText: string\n}> = ({ total, totalText }) => {\n return (\n <div className=\"border-t border-gray-200 p-4\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-gray-900\">{totalText}</span>\n <span className=\"text-base tablet:text-[18px] font-bold leading-[1.4] tracking-[-0.02em] text-gray-900\">\n {formatAmount(total)}\n </span>\n </div>\n </div>\n )\n}\n\n/**\n * \u8D2D\u7269\u8F66\u5361\u7247\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u8D2D\u7269\u8F66\u5546\u54C1\u5217\u8868\n * - \u663E\u793A\u4EF7\u683C\u6C47\u603B\uFF08\u5C0F\u8BA1\u3001\u6298\u6263\u3001\u603B\u8BA1\uFF09\n * - \u663E\u793A\u6298\u6263\u7801\n * - \u63D0\u4F9B Checkout \u6309\u94AE\n * - \u7A7A\u8D2D\u7269\u8F66\u72B6\u6001\n *\n * \u5E03\u5C40\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 \u8D2D\u7269\u8F66 (3 \u4EF6\u5546\u54C1) \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 [\u56FE] \u5546\u54C11 \u2502\n * \u2502 \u53D8\u4F53: Black \u2502\n * \u2502 \u6570\u91CF: 2 $199.98 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 [\u56FE] \u5546\u54C12 \u2502\n * \u2502 \u53D8\u4F53: White \u2502\n * \u2502 \u6570\u91CF: 1 $99.99 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u5C0F\u8BA1 $299.97 \u2502\n * \u2502 \u6298\u6263 [SPRING20] -$30.00 \u2502\n * \u2502 \u603B\u8BA1 $269.97 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 [Checkout \u6309\u94AE] \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * @example\n * ```tsx\n * const content: CartContent = {\n * type: 'cart',\n * data: {\n * isEmpty: false,\n * cartId: \"gid://...\",\n * totalQuantity: 3,\n * lines: [...],\n * cost: {...},\n * checkoutUrl: \"https://...\"\n * }\n * }\n * <CartCard.render(content, false, false) />\n * ```\n */\nexport const CartCard: MessageRenderer = {\n render: content => {\n const cartContent = content as CartContent\n const { data } = cartContent\n\n if (!data) {\n return null\n }\n\n const { isEmpty, lines, cost, checkoutUrl, onCart, cartId, commonText } = data\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n // \u5904\u7406\u8D2D\u7269\u8F66\u6309\u94AE\u70B9\u51FB\n const handleCart = () => {\n if (onCart) {\n onCart(cartId, checkoutUrl)\n } else if (checkoutUrl) {\n window.open(checkoutUrl, '_blank', 'noopener,noreferrer')\n }\n }\n\n // \u7A7A\u8D2D\u7269\u8F66\u72B6\u6001 - \u4E0D\u5C55\u793A\u7EC4\u4EF6\n if (isEmpty || !lines || lines.length === 0) {\n return null\n }\n\n return (\n <div className=\"w-full max-w-md overflow-hidden rounded-2xl shadow-sm\" style={{ backgroundColor: '#F5F6F7' }}>\n {/* \u5546\u54C1\u5217\u8868 */}\n <div className=\"flex flex-col gap-6 overflow-y-auto p-4\">\n {lines.map(line => (\n <CartLineItem key={line.id} line={line} />\n ))}\n </div>\n\n {/* \u4EF7\u683C\u6C47\u603B */}\n <CartSummary total={cost.totalAmount} totalText={mergedText.total} />\n\n {/* Checkout \u6309\u94AE */}\n {(checkoutUrl || onCart) && (\n <div className=\"px-4 pb-4\">\n <button\n type=\"button\"\n onClick={handleCart}\n className=\"w-full rounded-full py-[10px] text-center text-sm font-bold leading-[1.4] tracking-[-0.02em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {mergedText.viewMore}\n </button>\n </div>\n )}\n </div>\n )\n },\n}\n"],
5
- "mappings": "AA6CQ,cAAAA,EAcI,QAAAC,MAdJ,oBArCR,OAAS,oBAAAC,EAAkB,uBAAAC,MAA2B,qBAOtD,SAASC,EAAaC,EAA4B,CAChD,KAAM,CAAE,OAAQC,EAAO,aAAAC,CAAa,EAAIF,EAElCG,EAASN,EAAiBK,CAAY,GAAKA,EAC3CE,EAAW,WAAWH,CAAK,EAEjC,MAAO,GAAGE,CAAM,GAAGC,EAAS,QAAQ,CAAC,CAAC,EACxC,CAKA,MAAMC,EAED,CAAC,CAAE,KAAAC,CAAK,IAAM,CACjB,KAAM,CAAE,SAAAC,EAAU,YAAAC,EAAa,KAAAC,CAAK,EAAIH,EAClC,CAAE,QAAAI,EAAS,MAAOC,EAAc,MAAAC,CAAM,EAAIJ,EAG1CK,EAAWD,GAAO,KAAO,GAGzBE,EACJ,WAAWL,EAAK,YAAY,MAAM,EAAI,WAAWA,EAAK,eAAe,MAAM,GAC3EA,EAAK,YAAY,eAAiBA,EAAK,eAAe,aAExD,OACEb,EAAC,OAAI,UAAU,aAEb,UAAAD,EAAC,OAAI,UAAU,sCAAsC,MAAO,CAAE,MAAO,OAAQ,OAAQ,MAAO,EAC1F,SAAAA,EAAC,OAAI,IAAKkB,EAAU,IAAKH,EAAQ,MAAO,UAAU,yBAAyB,QAAQ,OAAO,EAC5F,EAGAd,EAAC,OAAI,UAAU,uBACb,UAAAD,EAAC,MAAG,UAAU,oGACX,SAAAe,EAAQ,MACX,EACAd,EAAC,OAAI,UAAU,uCAEb,UAAAA,EAAC,OAAI,UAAU,SACZ,UAAAe,GACChB,EAAC,KAAE,UAAU,2EAA4E,SAAAgB,EAAa,EAExGf,EAAC,KAAE,UAAU,yEAAyE,iBAAEW,GAAS,GACnG,EAGAX,EAAC,OAAI,UAAU,wBACb,UAAAD,EAAC,OAAI,UAAU,sFACZ,SAAAI,EAAaU,EAAK,WAAW,EAChC,EACCK,GACCnB,EAAC,OAAI,UAAU,oGACZ,SAAAI,EAAaU,EAAK,cAAc,EACnC,GAEJ,GACF,GACF,GACF,CAEJ,EAKMM,EAGD,CAAC,CAAE,MAAAC,EAAO,UAAAC,CAAU,IAErBtB,EAAC,OAAI,UAAU,+BACb,SAAAC,EAAC,OAAI,UAAU,oCACb,UAAAD,EAAC,QAAK,UAAU,qEAAsE,SAAAsB,EAAU,EAChGtB,EAAC,QAAK,UAAU,wFACb,SAAAI,EAAaiB,CAAK,EACrB,GACF,EACF,EAmDSE,EAA4B,CACvC,OAAQC,GAAW,CACjB,MAAMC,EAAcD,EACd,CAAE,KAAAE,CAAK,EAAID,EAEjB,GAAI,CAACC,EACH,OAAO,KAGT,KAAM,CAAE,QAAAC,EAAS,MAAAC,EAAO,KAAAd,EAAM,YAAAe,EAAa,OAAAC,EAAQ,OAAAC,EAAQ,WAAAC,CAAW,EAAIN,EAGpEO,EAAa,CAAE,GAAG9B,EAAqB,GAAG6B,CAAW,EAGrDE,EAAa,IAAM,CACnBJ,EACFA,EAAOC,EAAQF,CAAW,EACjBA,GACT,OAAO,KAAKA,EAAa,SAAU,qBAAqB,CAE5D,EAGA,OAAIF,GAAW,CAACC,GAASA,EAAM,SAAW,EACjC,KAIP3B,EAAC,OAAI,UAAU,wDAAwD,MAAO,CAAE,gBAAiB,SAAU,EAEzG,UAAAD,EAAC,OAAI,UAAU,0CACZ,SAAA4B,EAAM,IAAIjB,GACTX,EAACU,EAAA,CAA2B,KAAMC,GAAfA,EAAK,EAAgB,CACzC,EACH,EAGAX,EAACoB,EAAA,CAAY,MAAON,EAAK,YAAa,UAAWmB,EAAW,MAAO,GAGjEJ,GAAeC,IACf9B,EAAC,OAAI,UAAU,YACb,SAAAA,EAAC,UACC,KAAK,SACL,QAASkC,EACT,UAAU,0GACV,MAAO,CAAE,gBAAiB,SAAU,EAEnC,SAAAD,EAAW,SACd,EACF,GAEJ,CAEJ,CACF",
4
+ "sourcesContent": ["/**\n * \u8D2D\u7269\u8F66\u5361\u7247\u6E32\u67D3\u5668\n * \u663E\u793A\u8D2D\u7269\u8F66\u5185\u5BB9\u3001\u4EF7\u683C\u6C47\u603B\u548C\u7ED3\u8D26\u6309\u94AE\n * \u57FA\u4E8E\u540E\u7AEF\u8FD4\u56DE\u7684\u8D2D\u7269\u8F66\u6570\u636E\u7ED3\u6784\n */\n\nimport React from 'react'\nimport type { MessageRenderer, CartContent, CartLine, CartAmount } from '../../types'\nimport { CURRENCY_SYMBOLS, DEFAULT_COMMON_TEXT } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u91D1\u989D\n * @param amount \u91D1\u989D\u5BF9\u8C61\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u91D1\u989D\u5B57\u7B26\u4E32\uFF08\u5982 \"$99.99\"\uFF09\n */\nfunction formatAmount(amount: CartAmount): string {\n const { amount: value, currencyCode } = amount\n\n const symbol = CURRENCY_SYMBOLS[currencyCode] || currencyCode\n const numValue = parseFloat(value)\n\n return `${symbol}${numValue.toFixed(2)}`\n}\n\n/**\n * \u8D2D\u7269\u8F66\u5546\u54C1\u884C\u7EC4\u4EF6\n */\nconst CartLineItem: React.FC<{\n line: CartLine\n}> = ({ line }) => {\n const { quantity, merchandise, cost } = line\n const { product, title: variantTitle, image } = merchandise\n\n // \u5546\u54C1\u56FE\u7247 URL\n const imageUrl = image?.url || ''\n\n // \u5224\u65AD\u662F\u5426\u6709\u6298\u6263\uFF08\u603B\u4EF7 < \u539F\u4EF7\uFF09\n const hasDiscount =\n parseFloat(cost.totalAmount.amount) < parseFloat(cost.subtotalAmount.amount) &&\n cost.totalAmount.currencyCode === cost.subtotalAmount.currencyCode\n\n return (\n <div className=\"flex gap-4\">\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\"shrink-0 overflow-hidden rounded-md\" style={{ width: '72px', height: '72px' }}>\n <img src={imageUrl} alt={product.title} className=\"size-full object-cover\" loading=\"lazy\" />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-1 flex-col\">\n <h4 className=\"line-clamp-2 text-sm tablet:text-[16px] font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {product.title}\n </h4>\n {variantTitle && (\n <p className=\"mt-0.5 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]\">{variantTitle}</p>\n )}\n <div className=\"flex items-end justify-between gap-2 mt-1\">\n {/* \u5DE6\u4FA7\uFF1A\u6570\u91CF */}\n <div className=\"flex-1\">\n <p className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\u00D7{quantity}</p>\n </div>\n\n {/* \u53F3\u4FA7\uFF1A\u4EF7\u683C */}\n <div className=\"flex gap-1 text-right\">\n <div className=\"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-gray-900\">\n {formatAmount(cost.totalAmount)}\n </div>\n {hasDiscount && (\n <div className=\"tablet:text-[16px] text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56] line-through\">\n {formatAmount(cost.subtotalAmount)}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * \u4EF7\u683C\u6C47\u603B\u7EC4\u4EF6\uFF08\u7B80\u5316\u7248\uFF09\n */\nconst CartSummary: React.FC<{\n total: CartAmount\n totalText: string\n}> = ({ total, totalText }) => {\n return (\n <div className=\"border-t border-gray-200 p-4\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-gray-900\">{totalText}</span>\n <span className=\"text-base tablet:text-[18px] font-bold leading-[1.4] tracking-[-0.02em] text-gray-900\">\n {formatAmount(total)}\n </span>\n </div>\n </div>\n )\n}\n\n/**\n * \u8D2D\u7269\u8F66\u5361\u7247\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u663E\u793A\u8D2D\u7269\u8F66\u5546\u54C1\u5217\u8868\n * - \u663E\u793A\u4EF7\u683C\u6C47\u603B\uFF08\u5C0F\u8BA1\u3001\u6298\u6263\u3001\u603B\u8BA1\uFF09\n * - \u663E\u793A\u6298\u6263\u7801\n * - \u63D0\u4F9B Checkout \u6309\u94AE\n * - \u7A7A\u8D2D\u7269\u8F66\u72B6\u6001\n *\n * \u5E03\u5C40\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 \u8D2D\u7269\u8F66 (3 \u4EF6\u5546\u54C1) \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 [\u56FE] \u5546\u54C11 \u2502\n * \u2502 \u53D8\u4F53: Black \u2502\n * \u2502 \u6570\u91CF: 2 $199.98 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 [\u56FE] \u5546\u54C12 \u2502\n * \u2502 \u53D8\u4F53: White \u2502\n * \u2502 \u6570\u91CF: 1 $99.99 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u5C0F\u8BA1 $299.97 \u2502\n * \u2502 \u6298\u6263 [SPRING20] -$30.00 \u2502\n * \u2502 \u603B\u8BA1 $269.97 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 [Checkout \u6309\u94AE] \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * @example\n * ```tsx\n * const content: CartContent = {\n * type: 'cart',\n * data: {\n * isEmpty: false,\n * cartId: \"gid://...\",\n * totalQuantity: 3,\n * lines: [...],\n * cost: {...},\n * checkoutUrl: \"https://...\"\n * }\n * }\n * <CartCard.render(content, false, false) />\n * ```\n */\nexport const CartCard: MessageRenderer = {\n render: content => {\n const cartContent = content as CartContent\n const { data } = cartContent\n\n if (!data) {\n return null\n }\n\n const { isEmpty, lines, cost, checkoutUrl, onCart, cartId, commonText } = data\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n // \u5904\u7406\u8D2D\u7269\u8F66\u6309\u94AE\u70B9\u51FB\n const handleCart = () => {\n if (onCart) {\n onCart(cartId, checkoutUrl)\n } else if (checkoutUrl) {\n window.open(checkoutUrl, '_blank', 'noopener,noreferrer')\n }\n }\n\n // \u7A7A\u8D2D\u7269\u8F66\u72B6\u6001 - \u4E0D\u5C55\u793A\u7EC4\u4EF6\n if (isEmpty || !lines || lines.length === 0) {\n return null\n }\n\n return (\n <div className=\"w-full max-w-md overflow-hidden rounded-2xl shadow-sm\" style={{ backgroundColor: '#F5F6F7' }}>\n {/* \u5546\u54C1\u5217\u8868 */}\n <div className=\"flex flex-col gap-6 overflow-y-auto p-4\">\n {lines.map(line => (\n <CartLineItem key={line.id} line={line} />\n ))}\n </div>\n\n {/* \u4EF7\u683C\u6C47\u603B */}\n <CartSummary total={cost.totalAmount} totalText={mergedText.total} />\n\n {/* Checkout \u6309\u94AE */}\n {(checkoutUrl || onCart) && (\n <div className=\"px-4 pb-4\">\n <button\n type=\"button\"\n onClick={handleCart}\n className=\"livechat-btn-primary w-full rounded-full py-[10px] text-center text-sm font-bold leading-[1.4] tracking-[-0.02em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {mergedText.viewMore}\n </button>\n </div>\n )}\n </div>\n )\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["jsx", "jsxs", "CURRENCY_SYMBOLS", "DEFAULT_COMMON_TEXT", "formatAmount", "amount", "value", "currencyCode", "symbol", "numValue", "CartLineItem", "line", "quantity", "merchandise", "cost", "product", "variantTitle", "image", "imageUrl", "hasDiscount", "CartSummary", "total", "totalText", "CartCard", "content", "cartContent", "data", "isEmpty", "lines", "checkoutUrl", "onCart", "cartId", "commonText", "mergedText", "handleCart"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{Fragment as F,jsx as e,jsxs as c}from"react/jsx-runtime";import{CURRENCY_SYMBOLS as y,DEFAULT_COMMON_TEXT as p}from"../../constants.js";function C(t){const{amount:o,currency:n}=t;return`${y[n]||n}${o.toFixed(2)}`}function k(t,o,n=p.off){if(!t.discount_type||t.discount_value===void 0)return"";const r=typeof t.discount_value=="string"?parseFloat(t.discount_value):t.discount_value;return isNaN(r)?"":t.discount_type==="percentage"?`${Math.round(r)}% ${n}`:t.discount_type==="fixed_amount"?`${y[o]||o}${Math.round(r)} ${n}`:""}const w=({product:t,onAddToCart:o,addToCartText:n=p.addToCart,offText:r=p.off})=>{const{title:a,description:i,price:s,imageUrl:l,stockStatus:d,averageRating:f,variants:h}=t,N=d==="out_of_stock",u=h?.[0],m=u?.discount?.has_discount,g=m?u?.discount?.discount_price:null,x=u?.discount,P=g?{amount:g,currency:s.currency}:s,v=x&&m?k(x,s.currency,r):"",_=b=>{b.preventDefault(),b.stopPropagation(),o&&o(t)};return e("div",{className:"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow mb-[32px]",children:e("div",{className:"block",children:c("div",{className:"flex gap-2 p-4 bg-white",children:[e("div",{className:" flex shrink-0 items-center overflow-hidden rounded-md ",style:{width:"40%"},children:e("img",{src:l,alt:a,className:`h-auto w-full object-cover ${N?"opacity-50":""}`,loading:"lazy"})}),c("div",{className:"flex flex-1 flex-col justify-center",children:[v&&e("div",{className:"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white",style:{backgroundColor:"#005D8E",paddingTop:"6px",paddingBottom:"4px"},children:v}),e("h4",{className:"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:a}),c("div",{className:"mt-4 flex items-center gap-2",children:[c("div",{className:"flex items-center gap-1",children:[e("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:C(P)}),m&&e("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through",children:C(s)})]}),f!==void 0&&c("div",{className:"flex items-center gap-0.5 text-xs text-gray-600",children:[e("span",{className:"text-yellow-500",children:"\u2B50"}),e("span",{children:f.toFixed(1)})]})]}),e("button",{type:"button",onClick:_,className:"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:n})]})]})})})},M={render:(t,o,n)=>{const r=t,{product:a,rawProduct:i,productHandle:s,onAddToCart:l,productCardRender:d}=r.data;return console.log("[ProductCard] \u6E32\u67D3\u4EA7\u54C1\u5361\u7247:",{productHandle:s,hasProduct:!!a,hasRawProduct:!!i,hasCustomRender:!!d}),d?(console.log("[ProductCard] \u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3, productHandle:",s),e(F,{children:d(i||a,s)})):a?e(w,{product:a,onAddToCart:l}):null}};export{M as ProductCard};
1
+ import{Fragment as F,jsx as e,jsxs as c}from"react/jsx-runtime";import{CURRENCY_SYMBOLS as y,DEFAULT_COMMON_TEXT as m}from"../../constants.js";function C(t){const{amount:o,currency:n}=t;return`${y[n]||n}${o.toFixed(2)}`}function k(t,o,n=m.off){if(!t.discount_type||t.discount_value===void 0)return"";const a=typeof t.discount_value=="string"?parseFloat(t.discount_value):t.discount_value;return isNaN(a)?"":t.discount_type==="percentage"?`${Math.round(a)}% ${n}`:t.discount_type==="fixed_amount"?`${y[o]||o}${Math.round(a)} ${n}`:""}const w=({product:t,onAddToCart:o,addToCartText:n=m.addToCart,offText:a=m.off})=>{const{title:r,description:i,price:s,imageUrl:l,stockStatus:d,averageRating:f,variants:h}=t,N=d==="out_of_stock",u=h?.[0],p=u?.discount?.has_discount,g=p?u?.discount?.discount_price:null,x=u?.discount,P=g?{amount:g,currency:s.currency}:s,v=x&&p?k(x,s.currency,a):"",_=b=>{b.preventDefault(),b.stopPropagation(),o&&o(t)};return e("div",{className:"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow mb-[32px]",children:e("div",{className:"block",children:c("div",{className:"flex gap-2 p-4 bg-white",children:[e("div",{className:" flex shrink-0 items-center overflow-hidden rounded-md ",style:{width:"40%"},children:e("img",{src:l,alt:r,className:`h-auto w-full object-cover ${N?"opacity-50":""}`,loading:"lazy"})}),c("div",{className:"flex flex-1 flex-col justify-center",children:[v&&e("div",{className:"livechat-tag-product mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white",style:{backgroundColor:"#005D8E",paddingTop:"6px",paddingBottom:"4px"},children:v}),e("h4",{className:"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:r}),c("div",{className:"mt-4 flex items-center gap-2",children:[c("div",{className:"flex items-center gap-1",children:[e("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:C(P)}),p&&e("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through",children:C(s)})]}),f!==void 0&&c("div",{className:"flex items-center gap-0.5 text-xs text-gray-600",children:[e("span",{className:"text-yellow-500",children:"\u2B50"}),e("span",{children:f.toFixed(1)})]})]}),e("button",{type:"button",onClick:_,className:"livechat-btn-primary mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:n})]})]})})})},M={render:(t,o,n)=>{const a=t,{product:r,rawProduct:i,productHandle:s,onAddToCart:l,productCardRender:d}=a.data;return console.log("[ProductCard] \u6E32\u67D3\u4EA7\u54C1\u5361\u7247:",{productHandle:s,hasProduct:!!r,hasRawProduct:!!i,hasCustomRender:!!d}),d?(console.log("[ProductCard] \u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3, productHandle:",s),e(F,{children:d(i||r,s)})):r?e(w,{product:r,onAddToCart:l}):null}};export{M as ProductCard};
2
2
  //# sourceMappingURL=ProductCard.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx"],
4
- "sourcesContent": ["/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668 - \u7D27\u51D1\u578B\n * \u663E\u793A\u5355\u4E2A\u5546\u54C1\u7684\u8BE6\u7EC6\u4FE1\u606F\uFF08\u6A2A\u5411\u5E03\u5C40\uFF09\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React from 'react'\nimport type { MessageRenderer, ProductCardContent, Product, CommonText } from '../../types'\nimport { CURRENCY_SYMBOLS, DEFAULT_COMMON_TEXT } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\n */\nfunction formatPrice(price: Product['price']): string {\n const { amount, currency } = price\n\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount.toFixed(2)}`\n}\n\n/**\n * \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\u6587\u672C\n * @param discount \u6298\u6263\u5BF9\u8C61\n * @param currency \u8D27\u5E01\u4EE3\u7801\n * @param offText \"OFF\" \u6587\u6848\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u6298\u6263\u6587\u672C\uFF08\u5982 \"$10 OFF\" \u6216 \"20% OFF\"\uFF09\n */\nfunction formatDiscountLabel(\n discount: { discount_type?: string; discount_value?: string | number },\n currency: string,\n offText: string = DEFAULT_COMMON_TEXT.off\n): string {\n if (!discount.discount_type || discount.discount_value === undefined) {\n return ''\n }\n\n // \u5C06 discount_value \u8F6C\u6362\u4E3A\u6570\u5B57\n const value =\n typeof discount.discount_value === 'string' ? parseFloat(discount.discount_value) : discount.discount_value\n\n if (isNaN(value)) {\n return ''\n }\n\n if (discount.discount_type === 'percentage') {\n return `${Math.round(value)}% ${offText}`\n }\n\n if (discount.discount_type === 'fixed_amount') {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${Math.round(value)} ${offText}`\n }\n\n return ''\n}\n\n/**\n * \u7D27\u51D1\u578B\u5546\u54C1\u5361\u7247\u7EC4\u4EF6\uFF08\u6A2A\u5411\u5E03\u5C40\uFF09\n */\nconst CompactProductCard: React.FC<{\n product: Product\n onAddToCart?: (product: Product) => void\n addToCartText?: string\n offText?: string\n}> = ({ product, onAddToCart, addToCartText = DEFAULT_COMMON_TEXT.addToCart, offText = DEFAULT_COMMON_TEXT.off }) => {\n const { title, description, price, imageUrl, stockStatus, averageRating, variants } = product\n\n const isOutOfStock = stockStatus === 'out_of_stock'\n\n // \u83B7\u53D6\u7B2C\u4E00\u4E2A\u53D8\u4F53\u7684\u6298\u6263\u4FE1\u606F\n const firstVariant = variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n const discount = firstVariant?.discount\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice ? { amount: discountPrice, currency: price.currency } : price\n\n // \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\n const discountLabel = discount && hasDiscount ? formatDiscountLabel(discount, price.currency, offText) : ''\n\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div className=\"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow mb-[32px]\">\n <div className=\"block\">\n <div className=\"flex gap-2 p-4 bg-white\">\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\" flex shrink-0 items-center overflow-hidden rounded-md \" style={{ width: '40%' }}>\n <img\n src={imageUrl}\n alt={title}\n className={`h-auto w-full object-cover ${isOutOfStock ? 'opacity-50' : ''}`}\n loading=\"lazy\"\n />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-1 flex-col justify-center\">\n {/* \u6298\u6263\u6807\u7B7E */}\n {discountLabel && (\n <div\n className=\"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#005D8E', paddingTop: '6px', paddingBottom: '4px' }}\n >\n {discountLabel}\n </div>\n )}\n\n {/* \u6807\u9898 */}\n <h4 className=\"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {title}\n </h4>\n\n {/* \u63CF\u8FF0\uFF08\u53EF\u9009\uFF09 */}\n {/* {description && (\n <p className=\"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {description}\n </p>\n )} */}\n\n {/* \u4EF7\u683C\u548C\u8BC4\u5206 */}\n <div className=\"mt-4 flex items-center gap-2\">\n <div className=\"flex items-center gap-1\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice)}\n </span>\n {/* \u539F\u4EF7\uFF08\u5212\u7EBF\u4EF7\uFF09- \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && (\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through\">\n {formatPrice(price)}\n </span>\n )}\n </div>\n {/* \u8BC4\u5206\uFF08\u53EF\u9009\uFF09 */}\n {averageRating !== undefined && (\n <div className=\"flex items-center gap-0.5 text-xs text-gray-600\">\n <span className=\"text-yellow-500\">\u2B50</span>\n <span>{averageRating.toFixed(1)}</span>\n </div>\n )}\n </div>\n\n {/* Add to Cart \u6309\u94AE - \u5728\u4EF7\u683C\u4E0B\u65B9 */}\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {addToCartText}\n </button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u7D27\u51D1\u578B\u6A2A\u5411\u5E03\u5C40\uFF08\u56FE\u7247\u5728\u5DE6\uFF0C\u4FE1\u606F\u5728\u53F3\uFF09\n * - \u663E\u793A\u6298\u6263\u6807\u7B7E\u3001\u4EF7\u683C\u3001\u8BC4\u5206\n * - \u652F\u6301 Add to Cart \u6309\u94AE\n * - \u72EC\u7ACB\u6210\u6BB5\u5C55\u793A\n * - \u652F\u6301\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\n *\n * \u5E03\u5C40\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE\u7247] \u6298\u6263\u6807\u7B7E \u2502\n * \u2502 \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 (\u539F\u4EF7) \u2502\n * \u2502 \u2B50 4.5 \u2502\n * \u2502 [Add to Cart] \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * @example\n * ```tsx\n * const content: ProductCardContent = {\n * type: 'product_card',\n * data: {\n * product: { ... },\n * onAddToCart: (product) => { ... },\n * productCardRender: (product, productHandle) => <CustomCard product={product} handle={productHandle} />\n * }\n * }\n * <ProductCard.render(content, false, false) />\n * ```\n */\nexport const ProductCard: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const productContent = content as ProductCardContent\n const { product, rawProduct, productHandle, onAddToCart, productCardRender } = productContent.data\n\n console.log('[ProductCard] \u6E32\u67D3\u4EA7\u54C1\u5361\u7247:', {\n productHandle,\n hasProduct: !!product,\n hasRawProduct: !!rawProduct,\n hasCustomRender: !!productCardRender,\n })\n\n // \u5982\u679C\u63D0\u4F9B\u4E86\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\uFF08\u4F20\u5165\u539F\u59CB\u540E\u7AEF\u6570\u636E\u548C productHandle\uFF09\n // \u5373\u4F7F product \u4E3A\u7A7A\uFF0C\u4E5F\u8C03\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u8BA9\u5E94\u7528\u5C42\u53EF\u4EE5\u7528 productHandle \u67E5\u8BE2\u4EA7\u54C1\n if (productCardRender) {\n console.log('[ProductCard] \u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3, productHandle:', productHandle)\n return <>{productCardRender(rawProduct || product, productHandle)}</>\n }\n\n // \u9ED8\u8BA4\u6E32\u67D3\uFF1A\u5982\u679C\u6CA1\u6709\u4EA7\u54C1\u6570\u636E\u5219\u4E0D\u6E32\u67D3\n if (!product) {\n return null\n }\n\n return <CompactProductCard product={product} onAddToCart={onAddToCart} />\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668 - \u7D27\u51D1\u578B\n * \u663E\u793A\u5355\u4E2A\u5546\u54C1\u7684\u8BE6\u7EC6\u4FE1\u606F\uFF08\u6A2A\u5411\u5E03\u5C40\uFF09\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React from 'react'\nimport type { MessageRenderer, ProductCardContent, Product, CommonText } from '../../types'\nimport { CURRENCY_SYMBOLS, DEFAULT_COMMON_TEXT } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\n */\nfunction formatPrice(price: Product['price']): string {\n const { amount, currency } = price\n\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount.toFixed(2)}`\n}\n\n/**\n * \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\u6587\u672C\n * @param discount \u6298\u6263\u5BF9\u8C61\n * @param currency \u8D27\u5E01\u4EE3\u7801\n * @param offText \"OFF\" \u6587\u6848\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u6298\u6263\u6587\u672C\uFF08\u5982 \"$10 OFF\" \u6216 \"20% OFF\"\uFF09\n */\nfunction formatDiscountLabel(\n discount: { discount_type?: string; discount_value?: string | number },\n currency: string,\n offText: string = DEFAULT_COMMON_TEXT.off\n): string {\n if (!discount.discount_type || discount.discount_value === undefined) {\n return ''\n }\n\n // \u5C06 discount_value \u8F6C\u6362\u4E3A\u6570\u5B57\n const value =\n typeof discount.discount_value === 'string' ? parseFloat(discount.discount_value) : discount.discount_value\n\n if (isNaN(value)) {\n return ''\n }\n\n if (discount.discount_type === 'percentage') {\n return `${Math.round(value)}% ${offText}`\n }\n\n if (discount.discount_type === 'fixed_amount') {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${Math.round(value)} ${offText}`\n }\n\n return ''\n}\n\n/**\n * \u7D27\u51D1\u578B\u5546\u54C1\u5361\u7247\u7EC4\u4EF6\uFF08\u6A2A\u5411\u5E03\u5C40\uFF09\n */\nconst CompactProductCard: React.FC<{\n product: Product\n onAddToCart?: (product: Product) => void\n addToCartText?: string\n offText?: string\n}> = ({ product, onAddToCart, addToCartText = DEFAULT_COMMON_TEXT.addToCart, offText = DEFAULT_COMMON_TEXT.off }) => {\n const { title, description, price, imageUrl, stockStatus, averageRating, variants } = product\n\n const isOutOfStock = stockStatus === 'out_of_stock'\n\n // \u83B7\u53D6\u7B2C\u4E00\u4E2A\u53D8\u4F53\u7684\u6298\u6263\u4FE1\u606F\n const firstVariant = variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n const discount = firstVariant?.discount\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice ? { amount: discountPrice, currency: price.currency } : price\n\n // \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\n const discountLabel = discount && hasDiscount ? formatDiscountLabel(discount, price.currency, offText) : ''\n\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div className=\"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow mb-[32px]\">\n <div className=\"block\">\n <div className=\"flex gap-2 p-4 bg-white\">\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\" flex shrink-0 items-center overflow-hidden rounded-md \" style={{ width: '40%' }}>\n <img\n src={imageUrl}\n alt={title}\n className={`h-auto w-full object-cover ${isOutOfStock ? 'opacity-50' : ''}`}\n loading=\"lazy\"\n />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-1 flex-col justify-center\">\n {/* \u6298\u6263\u6807\u7B7E */}\n {discountLabel && (\n <div\n className=\"livechat-tag-product mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#005D8E', paddingTop: '6px', paddingBottom: '4px' }}\n >\n {discountLabel}\n </div>\n )}\n\n {/* \u6807\u9898 */}\n <h4 className=\"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {title}\n </h4>\n\n {/* \u63CF\u8FF0\uFF08\u53EF\u9009\uFF09 */}\n {/* {description && (\n <p className=\"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {description}\n </p>\n )} */}\n\n {/* \u4EF7\u683C\u548C\u8BC4\u5206 */}\n <div className=\"mt-4 flex items-center gap-2\">\n <div className=\"flex items-center gap-1\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice)}\n </span>\n {/* \u539F\u4EF7\uFF08\u5212\u7EBF\u4EF7\uFF09- \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && (\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through\">\n {formatPrice(price)}\n </span>\n )}\n </div>\n {/* \u8BC4\u5206\uFF08\u53EF\u9009\uFF09 */}\n {averageRating !== undefined && (\n <div className=\"flex items-center gap-0.5 text-xs text-gray-600\">\n <span className=\"text-yellow-500\">\u2B50</span>\n <span>{averageRating.toFixed(1)}</span>\n </div>\n )}\n </div>\n\n {/* Add to Cart \u6309\u94AE - \u5728\u4EF7\u683C\u4E0B\u65B9 */}\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"livechat-btn-primary mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {addToCartText}\n </button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * \u5546\u54C1\u5361\u7247\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u7D27\u51D1\u578B\u6A2A\u5411\u5E03\u5C40\uFF08\u56FE\u7247\u5728\u5DE6\uFF0C\u4FE1\u606F\u5728\u53F3\uFF09\n * - \u663E\u793A\u6298\u6263\u6807\u7B7E\u3001\u4EF7\u683C\u3001\u8BC4\u5206\n * - \u652F\u6301 Add to Cart \u6309\u94AE\n * - \u72EC\u7ACB\u6210\u6BB5\u5C55\u793A\n * - \u652F\u6301\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\n *\n * \u5E03\u5C40\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE\u7247] \u6298\u6263\u6807\u7B7E \u2502\n * \u2502 \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 (\u539F\u4EF7) \u2502\n * \u2502 \u2B50 4.5 \u2502\n * \u2502 [Add to Cart] \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * @example\n * ```tsx\n * const content: ProductCardContent = {\n * type: 'product_card',\n * data: {\n * product: { ... },\n * onAddToCart: (product) => { ... },\n * productCardRender: (product, productHandle) => <CustomCard product={product} handle={productHandle} />\n * }\n * }\n * <ProductCard.render(content, false, false) />\n * ```\n */\nexport const ProductCard: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n const productContent = content as ProductCardContent\n const { product, rawProduct, productHandle, onAddToCart, productCardRender } = productContent.data\n\n console.log('[ProductCard] \u6E32\u67D3\u4EA7\u54C1\u5361\u7247:', {\n productHandle,\n hasProduct: !!product,\n hasRawProduct: !!rawProduct,\n hasCustomRender: !!productCardRender,\n })\n\n // \u5982\u679C\u63D0\u4F9B\u4E86\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\uFF08\u4F20\u5165\u539F\u59CB\u540E\u7AEF\u6570\u636E\u548C productHandle\uFF09\n // \u5373\u4F7F product \u4E3A\u7A7A\uFF0C\u4E5F\u8C03\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u8BA9\u5E94\u7528\u5C42\u53EF\u4EE5\u7528 productHandle \u67E5\u8BE2\u4EA7\u54C1\n if (productCardRender) {\n console.log('[ProductCard] \u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3, productHandle:', productHandle)\n return <>{productCardRender(rawProduct || product, productHandle)}</>\n }\n\n // \u9ED8\u8BA4\u6E32\u67D3\uFF1A\u5982\u679C\u6CA1\u6709\u4EA7\u54C1\u6570\u636E\u5219\u4E0D\u6E32\u67D3\n if (!product) {\n return null\n }\n\n return <CompactProductCard product={product} onAddToCart={onAddToCart} />\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["Fragment", "jsx", "jsxs", "CURRENCY_SYMBOLS", "DEFAULT_COMMON_TEXT", "formatPrice", "price", "amount", "currency", "formatDiscountLabel", "discount", "offText", "value", "CompactProductCard", "product", "onAddToCart", "addToCartText", "title", "description", "imageUrl", "stockStatus", "averageRating", "variants", "isOutOfStock", "firstVariant", "hasDiscount", "discountPrice", "currentPrice", "discountLabel", "handleAddToCart", "e", "ProductCard", "content", "isUser", "isSystem", "productContent", "rawProduct", "productHandle", "productCardRender"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{Fragment as A,jsx as t,jsxs as c}from"react/jsx-runtime";import{useState as T}from"react";import{DEFAULT_COMMON_TEXT as _,CURRENCY_SYMBOLS as I}from"../../constants";const d=(l,a="USD")=>`${I[a]||a}${l}`,M=({data:l,onAddToCart:a,commonText:m})=>{const{products:i,dimensions:g}=l,y={..._,...m},p=i?.filter(e=>e&&e.shopifyId)||[],f=2,D=p.slice(0,f),[x,h]=T(D);if(p.length===0)return null;const N=(e,n)=>{const r=p.find(o=>o.shopifyId===n);if(r){const o=[...x];o[e]=r,h(o)}},C=x.slice(0,f),b=(e,n)=>!e||!e.values||!Array.isArray(e.values)?null:e.values.find(r=>r&&r.product_id===n),k=(e,n)=>n?c("div",{className:"border-b border-[#DADCE0] pb-2",children:[t("div",{className:"mb-1",children:t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:e==="price"?"has member price":e})}),t("div",{className:"flex gap-4",style:{gap:"36px"},children:C.map((r,o)=>{if(!r||!r.shopifyId)return null;const u=b(n,r.shopifyId);return t("div",{className:"flex-1",children:P(u,n.label)},`comparison-${o}`)})})]}):null,P=(e,n)=>{if(!e)return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:"-"});if(n.toLowerCase().includes("price")){const r=e?.has_member_price,o=e?.available?e.min===e.max?d(e.min,e.currency):`${d(e.min,e.currency)} - ${d(e.max,e.currency)}`:"-";return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:r?"Yes":"No"})}if(n.toLowerCase().includes("variant"))return c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:[e.count||0," ",e.count===1?"variant":"variants"]});if(n.toLowerCase().includes("review")){const r=e.rating||0,o=e.count||0;return c("div",{className:"flex items-center gap-1",children:[c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:["\u2B50 ",r.toFixed(1)]}),c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:["(",o,")"]})]})}return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:e.display||e.value||"-"})};return c("div",{className:"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]",children:[t("div",{className:"flex p-4",style:{gap:"36px",paddingBottom:"0px"},children:C.map((e,n)=>{if(!e||!e.shopifyId)return null;const r=g.price?b(g.price,e.shopifyId):null,o=e.variants?.[0],u=o?.discount?.has_discount,v=u?o?.discount?.discount_price:null,w=v||r?.min||e.price.amount,F=e.price.amount,R=s=>{s.preventDefault(),s.stopPropagation(),a&&a(e)};return c("div",{className:"flex flex-1 flex-col items-center",children:[t("div",{className:"mb-4 w-full",children:t("select",{value:e.shopifyId,onChange:s=>N(n,s.target.value),className:"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",style:{appearance:"none",backgroundImage:`url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 12px center",paddingRight:"32px"},children:p.map(s=>t("option",{value:s.shopifyId,children:s.title.length>30?`${s.title.slice(0,30)}...`:s.title},s.shopifyId))})}),t("a",{href:e.productUrl,target:"_blank",rel:"noopener noreferrer",className:"mb-4 block w-full max-w-[160px]",children:t("div",{className:"aspect-square w-full overflow-hidden rounded-lg",children:e.imageUrl?t("img",{src:e.imageUrl,alt:e.title,className:"size-full object-contain",loading:"lazy"}):t("div",{className:"flex size-full items-center justify-center text-gray-400",children:t("svg",{className:"size-12",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:t("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"})})})})}),t("div",{className:"mb-4 flex flex-col items-center gap-1",children:c("div",{className:"flex items-center gap-2",children:[t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]",children:d(w,r?.currency||e.price.currency)}),u&&v&&t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through",children:d(F,e.price.currency)})]})}),a&&t("button",{type:"button",onClick:R,className:"mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:y.addToCart})]},`product-column-${n}`)})}),t("div",{className:"flex flex-col gap-4 p-4",children:Object.entries(g).map(([e,n])=>n?t("div",{children:k(n.label,n)},e):null)})]})},U={render:(l,a,m)=>{if(l.type!=="product_comparison"||!l.data)return null;const i=l.data;return i.productComparisonRender?t(A,{children:i.productComparisonRender(i)}):t(M,{data:i,isUser:a,isSystem:m,onAddToCart:i.onAddToCart,commonText:i.commonText})}};export{M as ProductComparison,U as ProductComparisonRenderer};
1
+ import{Fragment as A,jsx as t,jsxs as c}from"react/jsx-runtime";import{useState as T}from"react";import{DEFAULT_COMMON_TEXT as _,CURRENCY_SYMBOLS as I}from"../../constants";const d=(l,a="USD")=>`${I[a]||a}${l}`,M=({data:l,onAddToCart:a,commonText:m})=>{const{products:i,dimensions:g}=l,y={..._,...m},p=i?.filter(e=>e&&e.shopifyId)||[],f=2,D=p.slice(0,f),[x,h]=T(D);if(p.length===0)return null;const N=(e,n)=>{const r=p.find(o=>o.shopifyId===n);if(r){const o=[...x];o[e]=r,h(o)}},C=x.slice(0,f),b=(e,n)=>!e||!e.values||!Array.isArray(e.values)?null:e.values.find(r=>r&&r.product_id===n),k=(e,n)=>n?c("div",{className:"border-b border-[#DADCE0] pb-2",children:[t("div",{className:"mb-1",children:t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:e==="price"?"has member price":e})}),t("div",{className:"flex gap-4",style:{gap:"36px"},children:C.map((r,o)=>{if(!r||!r.shopifyId)return null;const u=b(n,r.shopifyId);return t("div",{className:"flex-1",children:P(u,n.label)},`comparison-${o}`)})})]}):null,P=(e,n)=>{if(!e)return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:"-"});if(n.toLowerCase().includes("price")){const r=e?.has_member_price,o=e?.available?e.min===e.max?d(e.min,e.currency):`${d(e.min,e.currency)} - ${d(e.max,e.currency)}`:"-";return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:r?"Yes":"No"})}if(n.toLowerCase().includes("variant"))return c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:[e.count||0," ",e.count===1?"variant":"variants"]});if(n.toLowerCase().includes("review")){const r=e.rating||0,o=e.count||0;return c("div",{className:"flex items-center gap-1",children:[c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:["\u2B50 ",r.toFixed(1)]}),c("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]",children:["(",o,")"]})]})}return t("span",{className:"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:e.display||e.value||"-"})};return c("div",{className:"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]",children:[t("div",{className:"flex p-4",style:{gap:"36px",paddingBottom:"0px"},children:C.map((e,n)=>{if(!e||!e.shopifyId)return null;const r=g.price?b(g.price,e.shopifyId):null,o=e.variants?.[0],u=o?.discount?.has_discount,v=u?o?.discount?.discount_price:null,w=v||r?.min||e.price.amount,F=e.price.amount,R=s=>{s.preventDefault(),s.stopPropagation(),a&&a(e)};return c("div",{className:"flex flex-1 flex-col items-center",children:[t("div",{className:"mb-4 w-full",children:t("select",{value:e.shopifyId,onChange:s=>N(n,s.target.value),className:"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",style:{appearance:"none",backgroundImage:`url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 12px center",paddingRight:"32px"},children:p.map(s=>t("option",{value:s.shopifyId,children:s.title.length>30?`${s.title.slice(0,30)}...`:s.title},s.shopifyId))})}),t("a",{href:e.productUrl,target:"_blank",rel:"noopener noreferrer",className:"mb-4 block w-full max-w-[160px]",children:t("div",{className:"aspect-square w-full overflow-hidden rounded-lg",children:e.imageUrl?t("img",{src:e.imageUrl,alt:e.title,className:"size-full object-contain",loading:"lazy"}):t("div",{className:"flex size-full items-center justify-center text-gray-400",children:t("svg",{className:"size-12",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:t("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"})})})})}),t("div",{className:"mb-4 flex flex-col items-center gap-1",children:c("div",{className:"flex items-center gap-2",children:[t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]",children:d(w,r?.currency||e.price.currency)}),u&&v&&t("span",{className:"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through",children:d(F,e.price.currency)})]})}),a&&t("button",{type:"button",onClick:R,className:"livechat-btn-primary mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:y.addToCart})]},`product-column-${n}`)})}),t("div",{className:"flex flex-col gap-4 p-4",children:Object.entries(g).map(([e,n])=>n?t("div",{children:k(n.label,n)},e):null)})]})},U={render:(l,a,m)=>{if(l.type!=="product_comparison"||!l.data)return null;const i=l.data;return i.productComparisonRender?t(A,{children:i.productComparisonRender(i)}):t(M,{data:i,isUser:a,isSystem:m,onAddToCart:i.onAddToCart,commonText:i.commonText})}};export{M as ProductComparison,U as ProductComparisonRenderer};
2
2
  //# sourceMappingURL=ProductComparison.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx"],
4
- "sourcesContent": ["/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n * \u663E\u793A\u591A\u4E2A\u4EA7\u54C1\u7684\u5BF9\u6BD4\u4FE1\u606F\uFF0C\u91C7\u7528\u8868\u683C\u5E03\u5C40\u5C55\u793A\u5404\u7EF4\u5EA6\u5DEE\u5F02\n * \u57FA\u4E8E\u53C2\u8003\u8BBE\u8BA1\uFF1A\u9876\u90E8\u4EA7\u54C1\u5C55\u793A + \u5E95\u90E8\u5BF9\u6BD4\u8868\u683C\n */\n\nimport React, { useState } from 'react'\nimport type { Product, MessageRenderer, CommonText } from '../../types'\nimport { DEFAULT_COMMON_TEXT, CURRENCY_SYMBOLS } from '../../constants'\n\n/**\n * \u5BF9\u6BD4\u7EF4\u5EA6\u6570\u636E\u7ED3\u6784\n */\ninterface ComparisonDimension {\n label: string\n values: Array<{\n product_id: string\n [key: string]: any\n }>\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\u7ED3\u6784\n */\nexport interface ProductComparisonData {\n products: Product[]\n dimensions: {\n price?: ComparisonDimension\n variants?: ComparisonDimension\n member_price?: ComparisonDimension\n discount?: ComparisonDimension\n reviews?: ComparisonDimension\n [key: string]: ComparisonDimension | undefined\n }\n commonText?: CommonText\n productComparisonRender?: (data: ProductComparisonData) => React.ReactNode\n}\n\nexport interface ProductComparisonProps {\n /**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\n */\n data: ProductComparisonData\n\n /**\n * \u662F\u5426\u4E3A\u7528\u6237\u6D88\u606F\n */\n isUser?: boolean\n\n /**\n * \u662F\u5426\u4E3A\u7CFB\u7EDF\u6D88\u606F\n */\n isSystem?: boolean\n\n /**\n * \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: Product) => void\n\n /**\n * \u901A\u7528\u6587\u6848\u914D\u7F6E\n */\n commonText?: CommonText\n}\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\u663E\u793A\n */\nconst formatPrice = (amount: number, currency: string = 'USD'): string => {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount}`\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n *\n * \u5E03\u5C40\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u4EA7\u54C11\u56FE\u7247] [\u4EA7\u54C12\u56FE\u7247] \u2502\n * \u2502 \u4EF7\u683C1 \u4EF7\u683C2 \u2502\n * \u2502 \u989C\u8272\u9009\u9879 \u989C\u8272\u9009\u9879 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u7EF4\u5EA61 \u2502 \u503C1-1 \u2502 \u503C1-2 \u2502\n * \u2502 \u7EF4\u5EA62 \u2502 \u503C2-1 \u2502 \u503C2-2 \u2502\n * \u2502 \u7EF4\u5EA63 \u2502 \u503C3-1 \u2502 \u503C3-2 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n */\nexport const ProductComparison: React.FC<ProductComparisonProps> = ({ data, onAddToCart, commonText }) => {\n const { products: rawProducts, dimensions } = data\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const allProducts = rawProducts?.filter(p => p && p.shopifyId) || []\n\n // \u5BF9\u6BD4\u5217\u6570\uFF08\u56FA\u5B9A\u4E3A2\u5217\uFF09\n const COMPARISON_COLUMNS = 2\n\n // \u521D\u59CB\u5316\u6BCF\u4E2A\u5BF9\u6BD4\u4F4D\u7F6E\u7684\u9009\u4E2D\u4EA7\u54C1\uFF08\u9ED8\u8BA4\u53D6\u524D\u4E24\u4E2A\u4EA7\u54C1\uFF09\n const initialSelectedProducts = allProducts.slice(0, COMPARISON_COLUMNS)\n const [selectedProducts, setSelectedProducts] = useState<Product[]>(initialSelectedProducts)\n\n // Early return \u5FC5\u987B\u5728\u6240\u6709 hooks \u4E4B\u540E\n if (allProducts.length === 0) {\n return null\n }\n\n // \u5904\u7406\u4EA7\u54C1\u9009\u62E9\u53D8\u66F4\n const handleProductChange = (index: number, productId: string) => {\n const newProduct = allProducts.find(p => p.shopifyId === productId)\n if (newProduct) {\n const newSelectedProducts = [...selectedProducts]\n newSelectedProducts[index] = newProduct\n setSelectedProducts(newSelectedProducts)\n }\n }\n\n // \u5F53\u524D\u663E\u793A\u7684\u4EA7\u54C1\uFF08\u786E\u4FDD\u53EA\u663E\u793A\u6307\u5B9A\u5217\u6570\uFF09\n const products = selectedProducts.slice(0, COMPARISON_COLUMNS)\n\n /**\n * \u83B7\u53D6\u6307\u5B9A\u4EA7\u54C1\u5728\u67D0\u4E2A\u7EF4\u5EA6\u7684\u503C\n */\n const getDimensionValue = (dimension: ComparisonDimension, productId: string): any => {\n if (!dimension || !dimension.values || !Array.isArray(dimension.values)) {\n return null\n }\n return dimension.values.find(v => v && v.product_id === productId)\n }\n\n /**\n * \u6E32\u67D3\u901A\u7528\u5BF9\u6BD4\u884C\n */\n const renderComparisonRow = (label: string, dimension: ComparisonDimension | undefined) => {\n if (!dimension) return null\n\n return (\n <div className=\"border-b border-[#DADCE0] pb-2\">\n {/* \u7EF4\u5EA6\u6807\u7B7E\uFF08\u6807\u9898\uFF09 */}\n <div className=\"mb-1\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]\">{label==='price'?'has member price':label}</span>\n </div>\n\n {/* \u4EA7\u54C1\u503C\u5217\u8868\uFF08\u6A2A\u5411\u6392\u5217\uFF09 */}\n <div className=\"flex gap-4\" style={{ gap: '36px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n const value = getDimensionValue(dimension, product.shopifyId)\n\n return (\n <div key={`comparison-${index}`} className=\"flex-1\">\n {renderDimensionValue(value, dimension.label)}\n </div>\n )\n })}\n </div>\n </div>\n )\n }\n\n /**\n * \u6E32\u67D3\u7EF4\u5EA6\u503C\n */\n const renderDimensionValue = (value: any, dimensionLabel: string) => {\n if (!value) {\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">-</span>\n }\n\n // \u6839\u636E\u4E0D\u540C\u7EF4\u5EA6\u7C7B\u578B\u6E32\u67D3\u4E0D\u540C\u683C\u5F0F\n if (dimensionLabel.toLowerCase().includes('price')) {\n const hasMemberPrice = value?.has_member_price\n // \u4EF7\u683C\u7EF4\u5EA6\n const priceDisplay = value?.available?\n value.min === value.max\n ? formatPrice(value.min, value.currency)\n : `${formatPrice(value.min, value.currency)} - ${formatPrice(value.max, value.currency)}`:'-'\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">{hasMemberPrice?'Yes':'No'}</span>\n }\n\n if (dimensionLabel.toLowerCase().includes('variant')) {\n // \u53D8\u4F53\u6570\u91CF\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.count || 0} {value.count === 1 ? 'variant' : 'variants'}\n </span>\n )\n }\n\n if (dimensionLabel.toLowerCase().includes('review')) {\n // \u8BC4\u8BBA\u7EF4\u5EA6\uFF1A\u663E\u793A\u8BC4\u5206\u548C\u6570\u91CF\n const rating = value.rating || 0\n const count = value.count || 0\n return (\n <div className=\"flex items-center gap-1\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n \u2B50 {rating.toFixed(1)}\n </span>\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]\">\n ({count})\n </span>\n </div>\n )\n }\n\n // \u9ED8\u8BA4\u663E\u793A\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.display || value.value || '-'}\n </span>\n )\n }\n\n return (\n <div className=\"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]\">\n {/* \u9876\u90E8\u4EA7\u54C1\u5C55\u793A\u533A\u57DF */}\n <div className=\"flex p-4\" style={{ gap: '36px', paddingBottom: '0px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n\n // \u83B7\u53D6\u4EF7\u683C\u4FE1\u606F\n const priceInfo = dimensions.price ? getDimensionValue(dimensions.price, product.shopifyId) : null\n\n // \u83B7\u53D6\u6298\u6263\u4FE1\u606F\n const firstVariant = product.variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice || priceInfo?.min || product.price.amount\n const originalPrice = product.price.amount\n\n // Add to Cart \u6309\u94AE\u70B9\u51FB\u5904\u7406\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div key={`product-column-${index}`} className=\"flex flex-1 flex-col items-center\">\n {/* \u4EA7\u54C1\u9009\u62E9\u4E0B\u62C9\u6846 */}\n <div className=\"mb-4 w-full\">\n <select\n value={product.shopifyId}\n onChange={e => handleProductChange(index, e.target.value)}\n className=\"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\"\n style={{\n appearance: 'none',\n backgroundImage:\n \"url(\\\"data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\\\")\",\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'right 12px center',\n paddingRight: '32px',\n }}\n >\n {allProducts.map(p => (\n <option key={p.shopifyId} value={p.shopifyId}>\n {p.title.length > 30 ? `${p.title.slice(0, 30)}...` : p.title}\n </option>\n ))}\n </select>\n </div>\n\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n <a\n href={product.productUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mb-4 block w-full max-w-[160px]\"\n >\n <div className=\"aspect-square w-full overflow-hidden rounded-lg\">\n {product.imageUrl ? (\n <img\n src={product.imageUrl}\n alt={product.title}\n className=\"size-full object-contain\"\n loading=\"lazy\"\n />\n ) : (\n <div className=\"flex size-full items-center justify-center text-gray-400\">\n <svg className=\"size-12\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n </div>\n )}\n </div>\n </a>\n\n {/* \u4EF7\u683C\u5C55\u793A\uFF08\u5E26\u5212\u7EBF\u4EF7\uFF09 */}\n <div className=\"mb-4 flex flex-col items-center gap-1\">\n <div className=\"flex items-center gap-2\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6298\u6263\u4EF7\u6216\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice, priceInfo?.currency || product.price.currency)}\n </span>\n {/* \u5212\u7EBF\u4EF7 - \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && discountPrice && (\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through\">\n {formatPrice(originalPrice, product.price.currency)}\n </span>\n )}\n </div>\n </div>\n\n {/* Add to Cart \u6309\u94AE */}\n {onAddToCart && (\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {mergedText.addToCart}\n </button>\n )}\n\n </div>\n )\n })}\n </div>\n\n {/* \u5BF9\u6BD4\u8868\u683C\u533A\u57DF */}\n <div className=\"flex flex-col gap-4 p-4\">\n {/* \u904D\u5386\u6240\u6709\u7EF4\u5EA6\u5E76\u6E32\u67D3 */}\n {Object.entries(dimensions).map(([key, dimension]) => {\n if (!dimension) return null // price \u5DF2\u5728\u9876\u90E8\u663E\u793A\n return <div key={key}>{renderComparisonRow(dimension.label, dimension)}</div>\n })}\n </div>\n </div>\n )\n}\n\n/**\n * \u521B\u5EFA\u4EA7\u54C1\u5BF9\u6BD4\u6E32\u67D3\u5668\n */\nexport const ProductComparisonRenderer: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n if (content.type !== 'product_comparison' || !content.data) {\n return null\n }\n\n const comparisonData = content.data as ProductComparisonData & { onAddToCart?: (product: Product) => void }\n\n // \u5982\u679C\u63D0\u4F9B\u4E86\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\n if (comparisonData.productComparisonRender) {\n return <>{comparisonData.productComparisonRender(comparisonData)}</>\n }\n\n return (\n <ProductComparison\n data={comparisonData}\n isUser={isUser}\n isSystem={isSystem}\n onAddToCart={comparisonData.onAddToCart}\n commonText={comparisonData.commonText}\n />\n )\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n * \u663E\u793A\u591A\u4E2A\u4EA7\u54C1\u7684\u5BF9\u6BD4\u4FE1\u606F\uFF0C\u91C7\u7528\u8868\u683C\u5E03\u5C40\u5C55\u793A\u5404\u7EF4\u5EA6\u5DEE\u5F02\n * \u57FA\u4E8E\u53C2\u8003\u8BBE\u8BA1\uFF1A\u9876\u90E8\u4EA7\u54C1\u5C55\u793A + \u5E95\u90E8\u5BF9\u6BD4\u8868\u683C\n */\n\nimport React, { useState } from 'react'\nimport type { Product, MessageRenderer, CommonText } from '../../types'\nimport { DEFAULT_COMMON_TEXT, CURRENCY_SYMBOLS } from '../../constants'\n\n/**\n * \u5BF9\u6BD4\u7EF4\u5EA6\u6570\u636E\u7ED3\u6784\n */\ninterface ComparisonDimension {\n label: string\n values: Array<{\n product_id: string\n [key: string]: any\n }>\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\u7ED3\u6784\n */\nexport interface ProductComparisonData {\n products: Product[]\n dimensions: {\n price?: ComparisonDimension\n variants?: ComparisonDimension\n member_price?: ComparisonDimension\n discount?: ComparisonDimension\n reviews?: ComparisonDimension\n [key: string]: ComparisonDimension | undefined\n }\n commonText?: CommonText\n productComparisonRender?: (data: ProductComparisonData) => React.ReactNode\n}\n\nexport interface ProductComparisonProps {\n /**\n * \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\n */\n data: ProductComparisonData\n\n /**\n * \u662F\u5426\u4E3A\u7528\u6237\u6D88\u606F\n */\n isUser?: boolean\n\n /**\n * \u662F\u5426\u4E3A\u7CFB\u7EDF\u6D88\u606F\n */\n isSystem?: boolean\n\n /**\n * \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: Product) => void\n\n /**\n * \u901A\u7528\u6587\u6848\u914D\u7F6E\n */\n commonText?: CommonText\n}\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\u663E\u793A\n */\nconst formatPrice = (amount: number, currency: string = 'USD'): string => {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount}`\n}\n\n/**\n * \u4EA7\u54C1\u5BF9\u6BD4\u7EC4\u4EF6\n *\n * \u5E03\u5C40\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u4EA7\u54C11\u56FE\u7247] [\u4EA7\u54C12\u56FE\u7247] \u2502\n * \u2502 \u4EF7\u683C1 \u4EF7\u683C2 \u2502\n * \u2502 \u989C\u8272\u9009\u9879 \u989C\u8272\u9009\u9879 \u2502\n * \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n * \u2502 \u7EF4\u5EA61 \u2502 \u503C1-1 \u2502 \u503C1-2 \u2502\n * \u2502 \u7EF4\u5EA62 \u2502 \u503C2-1 \u2502 \u503C2-2 \u2502\n * \u2502 \u7EF4\u5EA63 \u2502 \u503C3-1 \u2502 \u503C3-2 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n */\nexport const ProductComparison: React.FC<ProductComparisonProps> = ({ data, onAddToCart, commonText }) => {\n const { products: rawProducts, dimensions } = data\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const allProducts = rawProducts?.filter(p => p && p.shopifyId) || []\n\n // \u5BF9\u6BD4\u5217\u6570\uFF08\u56FA\u5B9A\u4E3A2\u5217\uFF09\n const COMPARISON_COLUMNS = 2\n\n // \u521D\u59CB\u5316\u6BCF\u4E2A\u5BF9\u6BD4\u4F4D\u7F6E\u7684\u9009\u4E2D\u4EA7\u54C1\uFF08\u9ED8\u8BA4\u53D6\u524D\u4E24\u4E2A\u4EA7\u54C1\uFF09\n const initialSelectedProducts = allProducts.slice(0, COMPARISON_COLUMNS)\n const [selectedProducts, setSelectedProducts] = useState<Product[]>(initialSelectedProducts)\n\n // Early return \u5FC5\u987B\u5728\u6240\u6709 hooks \u4E4B\u540E\n if (allProducts.length === 0) {\n return null\n }\n\n // \u5904\u7406\u4EA7\u54C1\u9009\u62E9\u53D8\u66F4\n const handleProductChange = (index: number, productId: string) => {\n const newProduct = allProducts.find(p => p.shopifyId === productId)\n if (newProduct) {\n const newSelectedProducts = [...selectedProducts]\n newSelectedProducts[index] = newProduct\n setSelectedProducts(newSelectedProducts)\n }\n }\n\n // \u5F53\u524D\u663E\u793A\u7684\u4EA7\u54C1\uFF08\u786E\u4FDD\u53EA\u663E\u793A\u6307\u5B9A\u5217\u6570\uFF09\n const products = selectedProducts.slice(0, COMPARISON_COLUMNS)\n\n /**\n * \u83B7\u53D6\u6307\u5B9A\u4EA7\u54C1\u5728\u67D0\u4E2A\u7EF4\u5EA6\u7684\u503C\n */\n const getDimensionValue = (dimension: ComparisonDimension, productId: string): any => {\n if (!dimension || !dimension.values || !Array.isArray(dimension.values)) {\n return null\n }\n return dimension.values.find(v => v && v.product_id === productId)\n }\n\n /**\n * \u6E32\u67D3\u901A\u7528\u5BF9\u6BD4\u884C\n */\n const renderComparisonRow = (label: string, dimension: ComparisonDimension | undefined) => {\n if (!dimension) return null\n\n return (\n <div className=\"border-b border-[#DADCE0] pb-2\">\n {/* \u7EF4\u5EA6\u6807\u7B7E\uFF08\u6807\u9898\uFF09 */}\n <div className=\"mb-1\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]\">{label==='price'?'has member price':label}</span>\n </div>\n\n {/* \u4EA7\u54C1\u503C\u5217\u8868\uFF08\u6A2A\u5411\u6392\u5217\uFF09 */}\n <div className=\"flex gap-4\" style={{ gap: '36px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n const value = getDimensionValue(dimension, product.shopifyId)\n\n return (\n <div key={`comparison-${index}`} className=\"flex-1\">\n {renderDimensionValue(value, dimension.label)}\n </div>\n )\n })}\n </div>\n </div>\n )\n }\n\n /**\n * \u6E32\u67D3\u7EF4\u5EA6\u503C\n */\n const renderDimensionValue = (value: any, dimensionLabel: string) => {\n if (!value) {\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">-</span>\n }\n\n // \u6839\u636E\u4E0D\u540C\u7EF4\u5EA6\u7C7B\u578B\u6E32\u67D3\u4E0D\u540C\u683C\u5F0F\n if (dimensionLabel.toLowerCase().includes('price')) {\n const hasMemberPrice = value?.has_member_price\n // \u4EF7\u683C\u7EF4\u5EA6\n const priceDisplay = value?.available?\n value.min === value.max\n ? formatPrice(value.min, value.currency)\n : `${formatPrice(value.min, value.currency)} - ${formatPrice(value.max, value.currency)}`:'-'\n return <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">{hasMemberPrice?'Yes':'No'}</span>\n }\n\n if (dimensionLabel.toLowerCase().includes('variant')) {\n // \u53D8\u4F53\u6570\u91CF\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.count || 0} {value.count === 1 ? 'variant' : 'variants'}\n </span>\n )\n }\n\n if (dimensionLabel.toLowerCase().includes('review')) {\n // \u8BC4\u8BBA\u7EF4\u5EA6\uFF1A\u663E\u793A\u8BC4\u5206\u548C\u6570\u91CF\n const rating = value.rating || 0\n const count = value.count || 0\n return (\n <div className=\"flex items-center gap-1\">\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n \u2B50 {rating.toFixed(1)}\n </span>\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#86868C]\">\n ({count})\n </span>\n </div>\n )\n }\n\n // \u9ED8\u8BA4\u663E\u793A\n return (\n <span className=\"text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {value.display || value.value || '-'}\n </span>\n )\n }\n\n return (\n <div className=\"w-full overflow-hidden rounded-2xl bg-[#F5F6F7]\">\n {/* \u9876\u90E8\u4EA7\u54C1\u5C55\u793A\u533A\u57DF */}\n <div className=\"flex p-4\" style={{ gap: '36px', paddingBottom: '0px' }}>\n {products.map((product, index) => {\n if (!product || !product.shopifyId) return null\n\n // \u83B7\u53D6\u4EF7\u683C\u4FE1\u606F\n const priceInfo = dimensions.price ? getDimensionValue(dimensions.price, product.shopifyId) : null\n\n // \u83B7\u53D6\u6298\u6263\u4FE1\u606F\n const firstVariant = product.variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice || priceInfo?.min || product.price.amount\n const originalPrice = product.price.amount\n\n // Add to Cart \u6309\u94AE\u70B9\u51FB\u5904\u7406\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div key={`product-column-${index}`} className=\"flex flex-1 flex-col items-center\">\n {/* \u4EA7\u54C1\u9009\u62E9\u4E0B\u62C9\u6846 */}\n <div className=\"mb-4 w-full\">\n <select\n value={product.shopifyId}\n onChange={e => handleProductChange(index, e.target.value)}\n className=\"w-full rounded-lg border border-[#DADCE0] bg-[#F5F6F7] px-3 py-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\"\n style={{\n appearance: 'none',\n backgroundImage:\n \"url(\\\"data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%231D1D1F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\\\")\",\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'right 12px center',\n paddingRight: '32px',\n }}\n >\n {allProducts.map(p => (\n <option key={p.shopifyId} value={p.shopifyId}>\n {p.title.length > 30 ? `${p.title.slice(0, 30)}...` : p.title}\n </option>\n ))}\n </select>\n </div>\n\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n <a\n href={product.productUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mb-4 block w-full max-w-[160px]\"\n >\n <div className=\"aspect-square w-full overflow-hidden rounded-lg\">\n {product.imageUrl ? (\n <img\n src={product.imageUrl}\n alt={product.title}\n className=\"size-full object-contain\"\n loading=\"lazy\"\n />\n ) : (\n <div className=\"flex size-full items-center justify-center text-gray-400\">\n <svg className=\"size-12\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n </div>\n )}\n </div>\n </a>\n\n {/* \u4EF7\u683C\u5C55\u793A\uFF08\u5E26\u5212\u7EBF\u4EF7\uFF09 */}\n <div className=\"mb-4 flex flex-col items-center gap-1\">\n <div className=\"flex items-center gap-2\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6298\u6263\u4EF7\u6216\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice, priceInfo?.currency || product.price.currency)}\n </span>\n {/* \u5212\u7EBF\u4EF7 - \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && discountPrice && (\n <span className=\"text-base font-bold leading-[1.2] tracking-[-0.02em] text-[#4A4C56] line-through\">\n {formatPrice(originalPrice, product.price.currency)}\n </span>\n )}\n </div>\n </div>\n\n {/* Add to Cart \u6309\u94AE */}\n {onAddToCart && (\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"livechat-btn-primary mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {mergedText.addToCart}\n </button>\n )}\n\n </div>\n )\n })}\n </div>\n\n {/* \u5BF9\u6BD4\u8868\u683C\u533A\u57DF */}\n <div className=\"flex flex-col gap-4 p-4\">\n {/* \u904D\u5386\u6240\u6709\u7EF4\u5EA6\u5E76\u6E32\u67D3 */}\n {Object.entries(dimensions).map(([key, dimension]) => {\n if (!dimension) return null // price \u5DF2\u5728\u9876\u90E8\u663E\u793A\n return <div key={key}>{renderComparisonRow(dimension.label, dimension)}</div>\n })}\n </div>\n </div>\n )\n}\n\n/**\n * \u521B\u5EFA\u4EA7\u54C1\u5BF9\u6BD4\u6E32\u67D3\u5668\n */\nexport const ProductComparisonRenderer: MessageRenderer = {\n render: (content, isUser, isSystem) => {\n if (content.type !== 'product_comparison' || !content.data) {\n return null\n }\n\n const comparisonData = content.data as ProductComparisonData & { onAddToCart?: (product: Product) => void }\n\n // \u5982\u679C\u63D0\u4F9B\u4E86\u81EA\u5B9A\u4E49\u6E32\u67D3\u51FD\u6570\uFF0C\u4F7F\u7528\u81EA\u5B9A\u4E49\u6E32\u67D3\n if (comparisonData.productComparisonRender) {\n return <>{comparisonData.productComparisonRender(comparisonData)}</>\n }\n\n return (\n <ProductComparison\n data={comparisonData}\n isUser={isUser}\n isSystem={isSystem}\n onAddToCart={comparisonData.onAddToCart}\n commonText={comparisonData.commonText}\n />\n )\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["Fragment", "jsx", "jsxs", "useState", "DEFAULT_COMMON_TEXT", "CURRENCY_SYMBOLS", "formatPrice", "amount", "currency", "ProductComparison", "data", "onAddToCart", "commonText", "rawProducts", "dimensions", "mergedText", "allProducts", "p", "COMPARISON_COLUMNS", "initialSelectedProducts", "selectedProducts", "setSelectedProducts", "handleProductChange", "index", "productId", "newProduct", "newSelectedProducts", "products", "getDimensionValue", "dimension", "v", "renderComparisonRow", "label", "product", "value", "renderDimensionValue", "dimensionLabel", "hasMemberPrice", "priceDisplay", "rating", "count", "priceInfo", "firstVariant", "hasDiscount", "discountPrice", "currentPrice", "originalPrice", "handleAddToCart", "e", "key", "ProductComparisonRenderer", "content", "isUser", "isSystem", "comparisonData"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{jsx as t,jsxs as c}from"react/jsx-runtime";import{useState as P}from"react";import{CURRENCY_SYMBOLS as C,DEFAULT_COMMON_TEXT as p}from"../../constants.js";function N(e){const{amount:o,currency:s}=e;return`${C[s]||s}${o.toFixed(2)}`}function _(e,o,s=p.off){if(!e.discount_type||e.discount_value===void 0)return"";const a=typeof e.discount_value=="string"?parseFloat(e.discount_value):e.discount_value;return isNaN(a)?"":e.discount_type==="percentage"?`${Math.round(a)}% ${s}`:e.discount_type==="fixed_amount"?`${C[o]||o}${Math.round(a)} ${s}`:""}const w=({product:e,onAddToCart:o,addToCartText:s=p.addToCart,offText:a=p.off})=>{const{title:r,description:l,price:n,imageUrl:d,stockStatus:u,averageRating:m,variants:f}=e,i=u==="out_of_stock",x=f?.[0],g=x?.discount?.has_discount,v=g?x?.discount?.discount_price:null,y=x?.discount,T=v?{amount:v,currency:n.currency}:n,h=y&&g?_(y,n.currency,a):"",k=b=>{b.preventDefault(),b.stopPropagation(),o&&o(e)};return t("div",{className:"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow",children:t("div",{className:"block",children:c("div",{className:"flex gap-2 p-4",children:[t("div",{className:" flex shrink-0 items-center overflow-hidden rounded-md ",style:{width:"40%"},children:t("img",{src:d,alt:r,className:`h-auto w-full object-cover ${i?"opacity-50":""}`,loading:"lazy"})}),c("div",{className:"flex flex-1 flex-col justify-center",children:[h&&t("div",{className:"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white",style:{backgroundColor:"#005D8E",paddingTop:"6px",paddingBottom:"4px"},children:h}),t("h4",{className:"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:r}),l&&t("p",{className:"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:l}),c("div",{className:"mt-4 flex items-center gap-2",children:[c("div",{className:"flex items-center gap-1",children:[t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:N(T)}),g&&t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through",children:N(n)})]}),m!==void 0&&c("div",{className:"flex items-center gap-0.5 text-xs text-gray-600",children:[t("span",{className:"text-yellow-500",children:"\u2B50"}),t("span",{children:m.toFixed(1)})]})]}),t("button",{type:"button",onClick:k,className:"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:s})]})]})})})},F=({products:e,title:o,onAddToCart:s,commonText:a})=>{const[r,l]=P(!1),n={...p,...a},d=e.filter(i=>i&&i.shopifyId),u=3,m=d.length>u,f=r?d:d.slice(0,u);return c("div",{className:"flex w-full flex-col gap-2",children:[o&&t("h3",{className:"text-sm font-semibold text-gray-900",children:o}),t("div",{className:"flex flex-col gap-1.5",children:f.map(i=>!i||!i.shopifyId?null:t(w,{product:i,onAddToCart:s,addToCartText:n.addToCart,offText:n.off},i.shopifyId))}),m&&c("button",{type:"button",onClick:()=>l(!r),className:"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]",children:[t("span",{children:r?n.showLess:n.learnMore}),t("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:`transition-transform ${r?"rotate-180":""}`,children:t("polyline",{points:"6 9 12 15 18 9"})})]})]})},M={render:e=>{const o=e,{products:s,title:a,onAddToCart:r,commonText:l}=o.data,n=s?.filter(d=>d&&d.shopifyId)||[];return n.length===0?null:t(F,{products:n,title:a,onAddToCart:r,commonText:l})}};export{M as ProductList};
1
+ import{jsx as t,jsxs as c}from"react/jsx-runtime";import{useState as P}from"react";import{CURRENCY_SYMBOLS as C,DEFAULT_COMMON_TEXT as p}from"../../constants.js";function N(e){const{amount:o,currency:s}=e;return`${C[s]||s}${o.toFixed(2)}`}function _(e,o,s=p.off){if(!e.discount_type||e.discount_value===void 0)return"";const a=typeof e.discount_value=="string"?parseFloat(e.discount_value):e.discount_value;return isNaN(a)?"":e.discount_type==="percentage"?`${Math.round(a)}% ${s}`:e.discount_type==="fixed_amount"?`${C[o]||o}${Math.round(a)} ${s}`:""}const w=({product:e,onAddToCart:o,addToCartText:s=p.addToCart,offText:a=p.off})=>{const{title:r,description:l,price:n,imageUrl:d,stockStatus:u,averageRating:m,variants:f}=e,i=u==="out_of_stock",x=f?.[0],g=x?.discount?.has_discount,v=g?x?.discount?.discount_price:null,y=x?.discount,T=v?{amount:v,currency:n.currency}:n,h=y&&g?_(y,n.currency,a):"",k=b=>{b.preventDefault(),b.stopPropagation(),o&&o(e)};return t("div",{className:"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow",children:t("div",{className:"block",children:c("div",{className:"flex gap-2 p-4",children:[t("div",{className:" flex shrink-0 items-center overflow-hidden rounded-md ",style:{width:"40%"},children:t("img",{src:d,alt:r,className:`h-auto w-full object-cover ${i?"opacity-50":""}`,loading:"lazy"})}),c("div",{className:"flex flex-1 flex-col justify-center",children:[h&&t("div",{className:"livechat-tag-product mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white",style:{backgroundColor:"#005D8E",paddingTop:"6px",paddingBottom:"4px"},children:h}),t("h4",{className:"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]",children:r}),l&&t("p",{className:"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:l}),c("div",{className:"mt-4 flex items-center gap-2",children:[c("div",{className:"flex items-center gap-1",children:[t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]",children:N(T)}),g&&t("span",{className:"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through",children:N(n)})]}),m!==void 0&&c("div",{className:"flex items-center gap-0.5 text-xs text-gray-600",children:[t("span",{className:"text-yellow-500",children:"\u2B50"}),t("span",{children:m.toFixed(1)})]})]}),t("button",{type:"button",onClick:k,className:"livechat-btn-primary mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white",style:{backgroundColor:"#1D1D1F"},children:s})]})]})})})},F=({products:e,title:o,onAddToCart:s,commonText:a})=>{const[r,l]=P(!1),n={...p,...a},d=e.filter(i=>i&&i.shopifyId),u=3,m=d.length>u,f=r?d:d.slice(0,u);return c("div",{className:"flex w-full flex-col gap-2",children:[o&&t("h3",{className:"text-sm font-semibold text-gray-900",children:o}),t("div",{className:"flex flex-col gap-1.5",children:f.map(i=>!i||!i.shopifyId?null:t(w,{product:i,onAddToCart:s,addToCartText:n.addToCart,offText:n.off},i.shopifyId))}),m&&c("button",{type:"button",onClick:()=>l(!r),className:"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]",children:[t("span",{children:r?n.showLess:n.learnMore}),t("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:`transition-transform ${r?"rotate-180":""}`,children:t("polyline",{points:"6 9 12 15 18 9"})})]})]})},M={render:e=>{const o=e,{products:s,title:a,onAddToCart:r,commonText:l}=o.data,n=s?.filter(d=>d&&d.shopifyId)||[];return n.length===0?null:t(F,{products:n,title:a,onAddToCart:r,commonText:l})}};export{M as ProductList};
2
2
  //# sourceMappingURL=ProductList.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/LiveChatWidget/components/MessageContent/ProductList.tsx"],
4
- "sourcesContent": ["/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n * \u663E\u793A\u591A\u4E2A\u5546\u54C1\u7684\u7EB5\u5411\u5217\u8868\uFF0C\u652F\u6301\u5C55\u5F00/\u6536\u8D77\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React, { useState } from 'react'\nimport type { MessageRenderer, ProductListContent, Product, CommonText } from '../../types'\nimport { CURRENCY_SYMBOLS, DEFAULT_COMMON_TEXT } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\n */\nfunction formatPrice(price: Product['price']): string {\n const { amount, currency } = price\n\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount.toFixed(2)}`\n}\n\n/**\n * \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\u6587\u672C\n * @param discount \u6298\u6263\u5BF9\u8C61\n * @param currency \u8D27\u5E01\u4EE3\u7801\n * @param offText \"OFF\" \u6587\u6848\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u6298\u6263\u6587\u672C\uFF08\u5982 \"$10 OFF\" \u6216 \"20% OFF\"\uFF09\n */\nfunction formatDiscountLabel(\n discount: { discount_type?: string; discount_value?: string | number },\n currency: string,\n offText: string = DEFAULT_COMMON_TEXT.off\n): string {\n if (!discount.discount_type || discount.discount_value === undefined) {\n return ''\n }\n\n // \u5C06 discount_value \u8F6C\u6362\u4E3A\u6570\u5B57\n const value =\n typeof discount.discount_value === 'string' ? parseFloat(discount.discount_value) : discount.discount_value\n\n if (isNaN(value)) {\n return ''\n }\n\n if (discount.discount_type === 'percentage') {\n return `${Math.round(value)}% ${offText}`\n }\n\n if (discount.discount_type === 'fixed_amount') {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${Math.round(value)} ${offText}`\n }\n\n return ''\n}\n\n/**\n * \u7D27\u51D1\u578B\u5546\u54C1\u5361\u7247\uFF08\u7528\u4E8E\u7EB5\u5411\u5217\u8868\uFF09\n */\nconst CompactProductCard: React.FC<{\n product: Product\n onAddToCart?: (product: Product) => void\n addToCartText?: string\n offText?: string\n}> = ({ product, onAddToCart, addToCartText = DEFAULT_COMMON_TEXT.addToCart, offText = DEFAULT_COMMON_TEXT.off }) => {\n const { title, description, price, imageUrl, stockStatus, averageRating, variants } = product\n\n const isOutOfStock = stockStatus === 'out_of_stock'\n\n // \u83B7\u53D6\u7B2C\u4E00\u4E2A\u53D8\u4F53\u7684\u6298\u6263\u4FE1\u606F\n const firstVariant = variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n const discount = firstVariant?.discount\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice ? { amount: discountPrice, currency: price.currency } : price\n\n // \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\n const discountLabel = discount && hasDiscount ? formatDiscountLabel(discount, price.currency, offText) : ''\n\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div className=\"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow\">\n <div className=\"block\">\n <div className=\"flex gap-2 p-4\">\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\" flex shrink-0 items-center overflow-hidden rounded-md \" style={{ width: '40%' }}>\n <img\n src={imageUrl}\n alt={title}\n className={`h-auto w-full object-cover ${isOutOfStock ? 'opacity-50' : ''}`}\n loading=\"lazy\"\n />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-1 flex-col justify-center\">\n {/* \u6298\u6263\u6807\u7B7E */}\n {discountLabel && (\n <div\n className=\"mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#005D8E', paddingTop: '6px', paddingBottom: '4px' }}\n >\n {discountLabel}\n </div>\n )}\n\n {/* \u6807\u9898 */}\n <h4 className=\"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {title}\n </h4>\n\n {/* \u63CF\u8FF0\uFF08\u53EF\u9009\uFF09 */}\n {description && (\n <p className=\"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {description}\n </p>\n )}\n\n {/* \u4EF7\u683C\u548C\u8BC4\u5206 */}\n <div className=\"mt-4 flex items-center gap-2\">\n <div className=\"flex items-center gap-1\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice)}\n </span>\n {/* \u539F\u4EF7\uFF08\u5212\u7EBF\u4EF7\uFF09- \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && (\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through\">\n {formatPrice(price)}\n </span>\n )}\n </div>\n {/* \u8BC4\u5206\uFF08\u53EF\u9009\uFF09 */}\n {averageRating !== undefined && (\n <div className=\"flex items-center gap-0.5 text-xs text-gray-600\">\n <span className=\"text-yellow-500\">\u2B50</span>\n <span>{averageRating.toFixed(1)}</span>\n </div>\n )}\n </div>\n\n {/* Add to Cart \u6309\u94AE - \u5728\u4EF7\u683C\u4E0B\u65B9 */}\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {addToCartText}\n </button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * \u5546\u54C1\u5217\u8868\u5185\u90E8\u7EC4\u4EF6\uFF08\u652F\u6301\u5C55\u5F00/\u6536\u8D77\uFF09\n */\nconst ProductListComponent: React.FC<{\n products: Product[]\n title?: string\n onAddToCart?: (product: Product) => void\n commonText?: CommonText\n}> = ({ products, title, onAddToCart, commonText }) => {\n const [isExpanded, setIsExpanded] = useState(false)\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const validProducts = products.filter(p => p && p.shopifyId)\n\n // \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n const INITIAL_DISPLAY_COUNT = 3\n const hasMore = validProducts.length > INITIAL_DISPLAY_COUNT\n const displayedProducts = isExpanded ? validProducts : validProducts.slice(0, INITIAL_DISPLAY_COUNT)\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n {/* \u5217\u8868\u6807\u9898\uFF08\u53EF\u9009\uFF09 */}\n {title && <h3 className=\"text-sm font-semibold text-gray-900\">{title}</h3>}\n\n {/* \u7EB5\u5411\u6392\u5217\u7684\u5546\u54C1\u5217\u8868 */}\n <div className=\"flex flex-col gap-1.5\">\n {displayedProducts.map(product => {\n if (!product || !product.shopifyId) return null\n return (\n <CompactProductCard\n key={product.shopifyId}\n product={product}\n onAddToCart={onAddToCart}\n addToCartText={mergedText.addToCart}\n offText={mergedText.off}\n />\n )\n })}\n </div>\n\n {/* Learn More \u6309\u94AE */}\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setIsExpanded(!isExpanded)}\n className=\"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]\"\n >\n <span>{isExpanded ? mergedText.showLess : mergedText.learnMore}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={`transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n )}\n </div>\n )\n}\n\n/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u7EB5\u5411\u5C55\u793A\u591A\u4E2A\u5546\u54C1\n * - \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n * - \u652F\u6301\u5C55\u5F00/\u6536\u8D77\u67E5\u770B\u5168\u90E8\n * - \u7D27\u51D1\u578B\u5361\u7247\u8BBE\u8BA1\n * - \u53EF\u9009\u6807\u9898\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u6807\u9898\uFF08\u53EF\u9009\uFF09\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $39.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $49.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * [ Learn More \u2193 ]\n * ```\n *\n * @example\n * ```tsx\n * const content: ProductListContent = {\n * type: 'product_list',\n * data: {\n * title: '\u76F8\u5173\u5546\u54C1\u63A8\u8350',\n * products: [product1, product2, product3, product4, product5]\n * }\n * }\n * <ProductList.render(content, false, false) />\n * ```\n */\nexport const ProductList: MessageRenderer = {\n render: content => {\n const productListContent = content as ProductListContent\n const { products, title, onAddToCart, commonText } = productListContent.data\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const validProducts = products?.filter(p => p && p.shopifyId) || []\n\n if (validProducts.length === 0) {\n return null\n }\n\n return (\n <ProductListComponent products={validProducts} title={title} onAddToCart={onAddToCart} commonText={commonText} />\n )\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n * \u663E\u793A\u591A\u4E2A\u5546\u54C1\u7684\u7EB5\u5411\u5217\u8868\uFF0C\u652F\u6301\u5C55\u5F00/\u6536\u8D77\n * \u57FA\u4E8E specs/livechat-widget/data-model.md \u7684\u5546\u54C1\u6570\u636E\u6A21\u578B\n */\n\nimport React, { useState } from 'react'\nimport type { MessageRenderer, ProductListContent, Product, CommonText } from '../../types'\nimport { CURRENCY_SYMBOLS, DEFAULT_COMMON_TEXT } from '../../constants.js'\n\n/**\n * \u683C\u5F0F\u5316\u4EF7\u683C\n */\nfunction formatPrice(price: Product['price']): string {\n const { amount, currency } = price\n\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${amount.toFixed(2)}`\n}\n\n/**\n * \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\u6587\u672C\n * @param discount \u6298\u6263\u5BF9\u8C61\n * @param currency \u8D27\u5E01\u4EE3\u7801\n * @param offText \"OFF\" \u6587\u6848\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u6298\u6263\u6587\u672C\uFF08\u5982 \"$10 OFF\" \u6216 \"20% OFF\"\uFF09\n */\nfunction formatDiscountLabel(\n discount: { discount_type?: string; discount_value?: string | number },\n currency: string,\n offText: string = DEFAULT_COMMON_TEXT.off\n): string {\n if (!discount.discount_type || discount.discount_value === undefined) {\n return ''\n }\n\n // \u5C06 discount_value \u8F6C\u6362\u4E3A\u6570\u5B57\n const value =\n typeof discount.discount_value === 'string' ? parseFloat(discount.discount_value) : discount.discount_value\n\n if (isNaN(value)) {\n return ''\n }\n\n if (discount.discount_type === 'percentage') {\n return `${Math.round(value)}% ${offText}`\n }\n\n if (discount.discount_type === 'fixed_amount') {\n const symbol = CURRENCY_SYMBOLS[currency] || currency\n return `${symbol}${Math.round(value)} ${offText}`\n }\n\n return ''\n}\n\n/**\n * \u7D27\u51D1\u578B\u5546\u54C1\u5361\u7247\uFF08\u7528\u4E8E\u7EB5\u5411\u5217\u8868\uFF09\n */\nconst CompactProductCard: React.FC<{\n product: Product\n onAddToCart?: (product: Product) => void\n addToCartText?: string\n offText?: string\n}> = ({ product, onAddToCart, addToCartText = DEFAULT_COMMON_TEXT.addToCart, offText = DEFAULT_COMMON_TEXT.off }) => {\n const { title, description, price, imageUrl, stockStatus, averageRating, variants } = product\n\n const isOutOfStock = stockStatus === 'out_of_stock'\n\n // \u83B7\u53D6\u7B2C\u4E00\u4E2A\u53D8\u4F53\u7684\u6298\u6263\u4FE1\u606F\n const firstVariant = variants?.[0]\n const hasDiscount = firstVariant?.discount?.has_discount\n const discountPrice = hasDiscount ? firstVariant?.discount?.discount_price : null\n const discount = firstVariant?.discount\n\n // \u5F53\u524D\u663E\u793A\u4EF7\u683C\uFF1A\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\n const currentPrice = discountPrice ? { amount: discountPrice, currency: price.currency } : price\n\n // \u683C\u5F0F\u5316\u6298\u6263\u6807\u7B7E\n const discountLabel = discount && hasDiscount ? formatDiscountLabel(discount, price.currency, offText) : ''\n\n const handleAddToCart = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (onAddToCart) {\n onAddToCart(product)\n }\n }\n\n return (\n <div className=\"block w-full overflow-hidden rounded-2xl bg-[#F5F6F7] transition-shadow\">\n <div className=\"block\">\n <div className=\"flex gap-2 p-4\">\n {/* \u5546\u54C1\u56FE\u7247 */}\n <div className=\" flex shrink-0 items-center overflow-hidden rounded-md \" style={{ width: '40%' }}>\n <img\n src={imageUrl}\n alt={title}\n className={`h-auto w-full object-cover ${isOutOfStock ? 'opacity-50' : ''}`}\n loading=\"lazy\"\n />\n </div>\n\n {/* \u5546\u54C1\u4FE1\u606F */}\n <div className=\"flex flex-1 flex-col justify-center\">\n {/* \u6298\u6263\u6807\u7B7E */}\n {discountLabel && (\n <div\n className=\"livechat-tag-product mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#005D8E', paddingTop: '6px', paddingBottom: '4px' }}\n >\n {discountLabel}\n </div>\n )}\n\n {/* \u6807\u9898 */}\n <h4 className=\"line-clamp-2 text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]\">\n {title}\n </h4>\n\n {/* \u63CF\u8FF0\uFF08\u53EF\u9009\uFF09 */}\n {description && (\n <p className=\"line-clamp-2 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {description}\n </p>\n )}\n\n {/* \u4EF7\u683C\u548C\u8BC4\u5206 */}\n <div className=\"mt-4 flex items-center gap-2\">\n <div className=\"flex items-center gap-1\">\n {/* \u5F53\u524D\u4EF7\u683C\uFF08\u6709\u6298\u6263\u65F6\u663E\u793A\u6298\u6263\u4EF7\uFF0C\u5426\u5219\u663E\u793A\u539F\u4EF7\uFF09 */}\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#1D1D1F]\">\n {formatPrice(currentPrice)}\n </span>\n {/* \u539F\u4EF7\uFF08\u5212\u7EBF\u4EF7\uFF09- \u4EC5\u5728\u6709\u6298\u6263\u65F6\u663E\u793A */}\n {hasDiscount && (\n <span className=\"text-base font-bold leading-[1.4] tracking-[-0.02em] text-[#6D6D6F] line-through\">\n {formatPrice(price)}\n </span>\n )}\n </div>\n {/* \u8BC4\u5206\uFF08\u53EF\u9009\uFF09 */}\n {averageRating !== undefined && (\n <div className=\"flex items-center gap-0.5 text-xs text-gray-600\">\n <span className=\"text-yellow-500\">\u2B50</span>\n <span>{averageRating.toFixed(1)}</span>\n </div>\n )}\n </div>\n\n {/* Add to Cart \u6309\u94AE - \u5728\u4EF7\u683C\u4E0B\u65B9 */}\n <button\n type=\"button\"\n onClick={handleAddToCart}\n className=\"livechat-btn-primary mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white\"\n style={{ backgroundColor: '#1D1D1F' }}\n >\n {addToCartText}\n </button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * \u5546\u54C1\u5217\u8868\u5185\u90E8\u7EC4\u4EF6\uFF08\u652F\u6301\u5C55\u5F00/\u6536\u8D77\uFF09\n */\nconst ProductListComponent: React.FC<{\n products: Product[]\n title?: string\n onAddToCart?: (product: Product) => void\n commonText?: CommonText\n}> = ({ products, title, onAddToCart, commonText }) => {\n const [isExpanded, setIsExpanded] = useState(false)\n\n // \u5408\u5E76\u9ED8\u8BA4\u6587\u6848\u548C\u81EA\u5B9A\u4E49\u6587\u6848\n const mergedText = { ...DEFAULT_COMMON_TEXT, ...commonText }\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const validProducts = products.filter(p => p && p.shopifyId)\n\n // \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n const INITIAL_DISPLAY_COUNT = 3\n const hasMore = validProducts.length > INITIAL_DISPLAY_COUNT\n const displayedProducts = isExpanded ? validProducts : validProducts.slice(0, INITIAL_DISPLAY_COUNT)\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n {/* \u5217\u8868\u6807\u9898\uFF08\u53EF\u9009\uFF09 */}\n {title && <h3 className=\"text-sm font-semibold text-gray-900\">{title}</h3>}\n\n {/* \u7EB5\u5411\u6392\u5217\u7684\u5546\u54C1\u5217\u8868 */}\n <div className=\"flex flex-col gap-1.5\">\n {displayedProducts.map(product => {\n if (!product || !product.shopifyId) return null\n return (\n <CompactProductCard\n key={product.shopifyId}\n product={product}\n onAddToCart={onAddToCart}\n addToCartText={mergedText.addToCart}\n offText={mergedText.off}\n />\n )\n })}\n </div>\n\n {/* Learn More \u6309\u94AE */}\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setIsExpanded(!isExpanded)}\n className=\"flex items-center justify-center gap-1.5 px-3 py-2 text-[14px] font-bold leading-[1.2] tracking-tighter text-[#080A0F]\"\n >\n <span>{isExpanded ? mergedText.showLess : mergedText.learnMore}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={`transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n )}\n </div>\n )\n}\n\n/**\n * \u5546\u54C1\u5217\u8868\u6E32\u67D3\u5668\n *\n * \u529F\u80FD\uFF1A\n * - \u7EB5\u5411\u5C55\u793A\u591A\u4E2A\u5546\u54C1\n * - \u9ED8\u8BA4\u663E\u793A\u524D3\u4E2A\u4EA7\u54C1\n * - \u652F\u6301\u5C55\u5F00/\u6536\u8D77\u67E5\u770B\u5168\u90E8\n * - \u7D27\u51D1\u578B\u5361\u7247\u8BBE\u8BA1\n * - \u53EF\u9009\u6807\u9898\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u6807\u9898\uFF08\u53EF\u9009\uFF09\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $29.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $39.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 [\u56FE] \u5546\u54C1\u6807\u9898 \u2502\n * \u2502 $49.99 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * [ Learn More \u2193 ]\n * ```\n *\n * @example\n * ```tsx\n * const content: ProductListContent = {\n * type: 'product_list',\n * data: {\n * title: '\u76F8\u5173\u5546\u54C1\u63A8\u8350',\n * products: [product1, product2, product3, product4, product5]\n * }\n * }\n * <ProductList.render(content, false, false) />\n * ```\n */\nexport const ProductList: MessageRenderer = {\n render: content => {\n const productListContent = content as ProductListContent\n const { products, title, onAddToCart, commonText } = productListContent.data\n\n // \u8FC7\u6EE4\u6389 null \u6216\u65E0\u6548\u7684\u4EA7\u54C1\n const validProducts = products?.filter(p => p && p.shopifyId) || []\n\n if (validProducts.length === 0) {\n return null\n }\n\n return (\n <ProductListComponent products={validProducts} title={title} onAddToCart={onAddToCart} commonText={commonText} />\n )\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["jsx", "jsxs", "useState", "CURRENCY_SYMBOLS", "DEFAULT_COMMON_TEXT", "formatPrice", "price", "amount", "currency", "formatDiscountLabel", "discount", "offText", "value", "CompactProductCard", "product", "onAddToCart", "addToCartText", "title", "description", "imageUrl", "stockStatus", "averageRating", "variants", "isOutOfStock", "firstVariant", "hasDiscount", "discountPrice", "currentPrice", "discountLabel", "handleAddToCart", "e", "ProductListComponent", "products", "commonText", "isExpanded", "setIsExpanded", "mergedText", "validProducts", "p", "INITIAL_DISPLAY_COUNT", "hasMore", "displayedProducts", "ProductList", "content", "productListContent"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{jsx as t}from"react/jsx-runtime";import d from"react-markdown";import n from"remark-gfm";const i={render:(l,a,s)=>{const r=l;return r.text?t("div",{className:"livechat-markdown text-base md:text-sm",children:t(d,{remarkPlugins:[n],components:{a:({node:o,...e})=>t("a",{...e,className:`underline ${a?"text-blue-200 hover:text-blue-100":"text-blue-600 hover:text-blue-700"}`,target:"_blank",rel:"noopener noreferrer"}),code:({node:o,...e})=>e.inline?t("code",{...e,className:`rounded px-1.5 py-0.5 font-mono text-xs ${a?"bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}):t("code",{...e,className:`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${a?"bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}),p:({node:o,...e})=>t("p",{...e,className:"last:mb-0"}),ul:({node:o,...e})=>t("ul",{...e,className:"ml-4 list-disc"}),ol:({node:o,...e})=>t("ol",{...e,className:"mb-2 ml-4 list-decimal"}),li:({node:o,...e})=>t("li",{...e,className:"mb-1"}),h1:({node:o,...e})=>t("h1",{...e,className:"mb-2 font-bold"}),h2:({node:o,...e})=>t("h2",{...e,className:"mb-2 font-bold"}),h3:({node:o,...e})=>t("h3",{...e,className:"mb-1 font-bold"}),strong:({node:o,...e})=>t("strong",{...e,className:"font-bold"}),em:({node:o,...e})=>t("em",{...e,className:"italic"}),table:({node:o,...e})=>t("div",{className:"my-2 overflow-x-auto",children:t("table",{...e,className:"min-w-full border-collapse border border-gray-300 text-base md:text-sm"})}),thead:({node:o,...e})=>t("thead",{...e,className:"bg-gray-100"}),tbody:({node:o,...e})=>t("tbody",{...e}),tr:({node:o,...e})=>t("tr",{...e,className:"border-b border-gray-300"}),th:({node:o,...e})=>t("th",{...e,className:"border border-gray-300 px-3 py-2 text-left font-semibold"}),td:({node:o,...e})=>t("td",{...e,className:"border border-gray-300 px-3 py-2"})},children:r.text})}):null}};export{i as TextBlock};
1
+ import{jsx as t}from"react/jsx-runtime";import d from"react-markdown";import n from"remark-gfm";const i={render:(l,a,s)=>{const r=l;return r.text?t("div",{className:"livechat-markdown text-base md:text-sm",children:t(d,{remarkPlugins:[n],components:{a:({node:o,...e})=>t("a",{...e,className:`underline ${a?"text-blue-200 hover:text-blue-100":"text-blue-600 hover:text-blue-700"}`,target:"_blank",rel:"noopener noreferrer"}),code:({node:o,...e})=>e.inline?t("code",{...e,className:`rounded px-1.5 py-0.5 font-mono text-xs ${a?"livechat-code-user bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}):t("code",{...e,className:`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${a?"livechat-code-user bg-[#004A6E] text-white":"bg-gray-200 text-gray-800"}`}),p:({node:o,...e})=>t("p",{...e,className:"last:mb-0"}),ul:({node:o,...e})=>t("ul",{...e,className:"ml-4 list-disc"}),ol:({node:o,...e})=>t("ol",{...e,className:"mb-2 ml-4 list-decimal"}),li:({node:o,...e})=>t("li",{...e,className:"mb-1"}),h1:({node:o,...e})=>t("h1",{...e,className:"mb-2 font-bold"}),h2:({node:o,...e})=>t("h2",{...e,className:"mb-2 font-bold"}),h3:({node:o,...e})=>t("h3",{...e,className:"mb-1 font-bold"}),strong:({node:o,...e})=>t("strong",{...e,className:"font-bold"}),em:({node:o,...e})=>t("em",{...e,className:"italic"}),table:({node:o,...e})=>t("div",{className:"my-2 overflow-x-auto",children:t("table",{...e,className:"min-w-full border-collapse border border-gray-300 text-base md:text-sm"})}),thead:({node:o,...e})=>t("thead",{...e,className:"bg-gray-100"}),tbody:({node:o,...e})=>t("tbody",{...e}),tr:({node:o,...e})=>t("tr",{...e,className:"border-b border-gray-300"}),th:({node:o,...e})=>t("th",{...e,className:"border border-gray-300 px-3 py-2 text-left font-semibold"}),td:({node:o,...e})=>t("td",{...e,className:"border border-gray-300 px-3 py-2"})},children:r.text})}):null}};export{i as TextBlock};
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 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 font-bold\" />,\n h2: ({ node, ...props }) => <h2 {...props} className=\"mb-2 font-bold\" />,\n h3: ({ node, ...props }) => <h3 {...props} className=\"mb-1 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": "AAkDc,cAAAA,MAAA,oBA3Cd,OAAOC,MAAmB,iBAC1B,OAAOC,MAAe,aA2Bf,MAAMC,EAA6B,CACxC,OAAQ,CAACC,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAcH,EAEpB,OAAKG,EAAY,KAKfP,EAAC,OAAI,UAAU,yCACb,SAAAA,EAACC,EAAA,CACC,cAAe,CAACC,CAAS,EACzB,WAAY,CAEV,EAAG,CAAC,CAAE,KAAAM,EAAM,GAAGC,CAAM,IACnBT,EAAC,KACE,GAAGS,EACJ,UAAW,aAAaJ,EAAS,oCAAsC,mCAAmC,GAC1G,OAAO,SACP,IAAI,sBACN,EAGF,KAAM,CAAC,CAAE,KAAAG,EAAM,GAAGC,CAAM,IACtBA,EAAM,OACJT,EAAC,QACE,GAAGS,EACJ,UAAW,2CAA2CJ,EAAS,0BAA4B,2BAA2B,GACxH,EAEAL,EAAC,QACE,GAAGS,EACJ,UAAW,6DAA6DJ,EAAS,0BAA4B,2BAA2B,GAC1I,EAGJ,EAAG,CAAC,CAAE,KAAAG,EAAM,GAAGC,CAAM,IAAMT,EAAC,KAAG,GAAGS,EAAO,UAAU,YAAY,EAE/D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,yBAAyB,EAC9E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,OAAO,EAE5D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EAEtE,OAAQ,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,UAAQ,GAAGS,EAAO,UAAU,YAAY,EACzE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,SAAS,EAE9D,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACvBT,EAAC,OAAI,UAAU,uBACb,SAAAA,EAAC,SAAO,GAAGS,EAAO,UAAU,yEAAyE,EACvG,EAEF,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACvBT,EAAC,SAAO,GAAGS,EAAO,UAAU,cAAc,EAE5C,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,SAAO,GAAGS,EAAO,EACjD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACpBT,EAAC,MAAI,GAAGS,EAAO,UAAU,2BAA2B,EAEtD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACpBT,EAAC,MAAI,GAAGS,EAAO,UAAU,2DAA2D,EAEtF,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACpBT,EAAC,MAAI,GAAGS,EAAO,UAAU,mCAAmC,CAEhE,EAEC,SAAAF,EAAY,KACf,EACF,EAlEO,IAoEX,CACF",
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 ? 'livechat-code-user 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 ? 'livechat-code-user 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 font-bold\" />,\n h2: ({ node, ...props }) => <h2 {...props} className=\"mb-2 font-bold\" />,\n h3: ({ node, ...props }) => <h3 {...props} className=\"mb-1 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": "AAkDc,cAAAA,MAAA,oBA3Cd,OAAOC,MAAmB,iBAC1B,OAAOC,MAAe,aA2Bf,MAAMC,EAA6B,CACxC,OAAQ,CAACC,EAASC,EAAQC,IAAa,CACrC,MAAMC,EAAcH,EAEpB,OAAKG,EAAY,KAKfP,EAAC,OAAI,UAAU,yCACb,SAAAA,EAACC,EAAA,CACC,cAAe,CAACC,CAAS,EACzB,WAAY,CAEV,EAAG,CAAC,CAAE,KAAAM,EAAM,GAAGC,CAAM,IACnBT,EAAC,KACE,GAAGS,EACJ,UAAW,aAAaJ,EAAS,oCAAsC,mCAAmC,GAC1G,OAAO,SACP,IAAI,sBACN,EAGF,KAAM,CAAC,CAAE,KAAAG,EAAM,GAAGC,CAAM,IACtBA,EAAM,OACJT,EAAC,QACE,GAAGS,EACJ,UAAW,2CAA2CJ,EAAS,6CAA+C,2BAA2B,GAC3I,EAEAL,EAAC,QACE,GAAGS,EACJ,UAAW,6DAA6DJ,EAAS,6CAA+C,2BAA2B,GAC7J,EAGJ,EAAG,CAAC,CAAE,KAAAG,EAAM,GAAGC,CAAM,IAAMT,EAAC,KAAG,GAAGS,EAAO,UAAU,YAAY,EAE/D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,yBAAyB,EAC9E,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,OAAO,EAE5D,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EACtE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,iBAAiB,EAEtE,OAAQ,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,UAAQ,GAAGS,EAAO,UAAU,YAAY,EACzE,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,MAAI,GAAGS,EAAO,UAAU,SAAS,EAE9D,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACvBT,EAAC,OAAI,UAAU,uBACb,SAAAA,EAAC,SAAO,GAAGS,EAAO,UAAU,yEAAyE,EACvG,EAEF,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACvBT,EAAC,SAAO,GAAGS,EAAO,UAAU,cAAc,EAE5C,MAAO,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IAAMT,EAAC,SAAO,GAAGS,EAAO,EACjD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACpBT,EAAC,MAAI,GAAGS,EAAO,UAAU,2BAA2B,EAEtD,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACpBT,EAAC,MAAI,GAAGS,EAAO,UAAU,2DAA2D,EAEtF,GAAI,CAAC,CAAE,KAAAD,EAAM,GAAGC,CAAM,IACpBT,EAAC,MAAI,GAAGS,EAAO,UAAU,mCAAmC,CAEhE,EAEC,SAAAF,EAAY,KACf,EACF,EAlEO,IAoEX,CACF",
6
6
  "names": ["jsx", "ReactMarkdown", "remarkGfm", "TextBlock", "content", "isUser", "isSystem", "textContent", "node", "props"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{jsx as e,jsxs as n}from"react/jsx-runtime";const d={render:(s,t,a)=>{const r=s.data.status||"";return e("div",{className:"flex items-center gap-2 py-1",children:n("div",{className:"livechat-thinking-dots flex gap-1",children:[e("span",{className:"size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 1)"}}),e("span",{className:"size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 0.6)"}}),e("span",{className:"size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 0.2)"}})]})})}};export{d as ThinkingBlock};
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";const d={render:(n,s,a)=>{const i=n.data.status||"";return e("div",{className:"flex items-center gap-2 py-1",children:t("div",{className:"livechat-thinking-dots flex gap-1",children:[e("span",{className:"livechat-loading-dot size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 1)"}}),e("span",{className:"livechat-loading-dot size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 0.6)"}}),e("span",{className:"livechat-loading-dot size-2 rounded-full",style:{backgroundColor:"rgba(0, 93, 142, 0.2)"}})]})})}};export{d as ThinkingBlock};
2
2
  //# sourceMappingURL=ThinkingBlock.js.map