@zhin.js/adapter-sandbox 1.0.30 → 1.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import{jsx as t,jsxs as i}from"react/jsx-runtime";import{cn as he,addPage as Ae}from"@zhin.js/client";import{MessageSquare as Y,Wifi as Ie,WifiOff as $e,Trash2 as Le,Bot as De,User as se,Smile as Fe,Image as Me,X as Ue,Search as me,Check as fe,Send as Be,Info as Pe,Hash as je,Users as _e,Terminal as He}from"lucide-react";import ye,{forwardRef as Oe,useRef as B,useImperativeHandle as We,useState as f,useEffect as Q}from"react";import{Card as X,Box as v,Flex as p,Heading as xe,Badge as C,Button as k,Text as b,TextField as J,Grid as qe,Tabs as V}from"@radix-ui/themes";const ve=Oe(({placeholder:K="输入消息...",onSend:L,onChange:S,onAtTrigger:w,minHeight:G="44px",maxHeight:Z="200px"},m)=>{const u=B(null),x=B(null),E=()=>{if(!u.current)return{text:"",segments:[]};let s="";const a=[],o=Array.from(u.current.childNodes);for(const l of o)if(l.nodeType===Node.TEXT_NODE){const c=l.textContent||"";c&&(s+=c,a.push({type:"text",data:{text:c}}))}else if(l.nodeType===Node.ELEMENT_NODE){const c=l;if(c.classList.contains("editor-face")){const g=c.dataset.id;s+=`[face:${g}]`,a.push({type:"face",data:{id:Number(g)}})}else if(c.classList.contains("editor-image")){const g=c.dataset.url;s+=`[image:${g}]`,a.push({type:"image",data:{url:g}})}else if(c.classList.contains("editor-at")){const g=c.dataset.name,z=c.dataset.id;s+=`[@${g}]`,a.push({type:"at",data:{name:g,qq:z}})}else c.tagName==="BR"&&(s+=`
2
- `)}return{text:s,segments:a}},D=s=>{if(!u.current)return;const a=document.createElement("img");a.src=`https://face.viki.moe/apng/${s}.png`,a.alt=`[face:${s}]`,a.dataset.type="face",a.dataset.id=String(s),a.className="editor-face",M(a),T()},ee=s=>{if(!u.current||!s.trim())return;const a=document.createElement("img");a.src=s.trim(),a.alt=`[image:${s.trim()}]`,a.dataset.type="image",a.dataset.url=s.trim(),a.className="editor-image",M(a),T()},F=(s,a)=>{if(!u.current||!s.trim())return;const o=document.createElement("span");o.dataset.type="at",o.dataset.name=s,a&&(o.dataset.id=a),o.className="editor-at",o.contentEditable="false";const l=document.createElement("span");l.textContent="@",l.className="editor-at-symbol";const c=document.createElement("span");c.textContent=s,c.className="editor-at-name",o.appendChild(l),o.appendChild(c),M(o),T()},M=s=>{if(!u.current)return;u.current.focus();const a=window.getSelection();if(a&&a.rangeCount>0){const o=a.getRangeAt(0);if(u.current.contains(o.commonAncestorContainer))o.deleteContents(),o.insertNode(s),o.collapse(false),a.removeAllRanges(),a.addRange(o);else{u.current.appendChild(s);const c=document.createRange();c.setStartAfter(s),c.collapse(true),a.removeAllRanges(),a.addRange(c)}}else{u.current.appendChild(s);const o=window.getSelection();if(o){const l=document.createRange();l.setStartAfter(s),l.collapse(true),o.removeAllRanges(),o.addRange(l)}}},P=()=>{u.current&&(u.current.innerHTML="",T())},j=()=>{u.current?.focus()},_=()=>E(),H=()=>{if(!u.current||!w)return;const s=window.getSelection();if(!s||s.rangeCount===0){w(false,""),x.current=null;return}const a=s.getRangeAt(0);if(!u.current.contains(a.commonAncestorContainer)){w(false,""),x.current=null;return}const o=a.startContainer;if(o.nodeType!==Node.TEXT_NODE){w(false,""),x.current=null;return}const l=o,c=l.textContent?.substring(0,a.startOffset)||"",g=c.lastIndexOf("@");if(g!==-1){const z=c.substring(g+1);if(z.includes(" ")||z.includes(`
3
- `)){w(false,""),x.current=null;return}x.current=l;const R=document.createRange();R.setStart(l,g),R.setEnd(l,g+1);const A=R.getBoundingClientRect(),N=u.current.getBoundingClientRect();w(true,z,{top:A.bottom-N.top,left:A.left-N.left})}else w(false,""),x.current=null},T=()=>{if(H(),S){const{text:s,segments:a}=E();S(s,a)}},te=(s,a)=>{if(!x.current)return;const o=x.current,l=o.textContent||"",c=l.lastIndexOf("@");if(c!==-1){const g=l.substring(c+1),z=c+1+g.split(/[\s\n]/)[0].length,R=l.substring(0,c),A=l.substring(z);o.textContent=R+A;const N=window.getSelection();if(N){const W=document.createRange();W.setStart(o,c),W.collapse(true),N.removeAllRanges(),N.addRange(W)}}x.current=null,F(s,a)},O=s=>{if(s.key==="Enter"&&!s.shiftKey&&(s.preventDefault(),L)){const{text:a,segments:o}=E();L(a,o)}};return We(m,()=>({focus:j,clear:P,insertFace:D,insertImage:ee,insertAt:F,replaceAtTrigger:te,getContent:_})),t("div",{ref:u,contentEditable:true,suppressContentEditableWarning:true,onInput:T,onKeyDown:O,"data-placeholder":K,className:"rich-text-editor",style:{width:"100%",minHeight:G,maxHeight:Z,padding:"0.5rem 0.75rem",border:"1px solid var(--gray-6)",borderRadius:"6px",backgroundColor:"var(--gray-1)",fontSize:"var(--font-size-2)",outline:"none",overflowY:"auto",lineHeight:"1.5",wordWrap:"break-word",color:"var(--gray-12)"}})});ve.displayName="RichTextEditor";function Ke(){const[K,L]=f([]),[S,w]=f([{id:"user_1001",name:"测试用户",type:"private",unread:0},{id:"group_2001",name:"测试群组",type:"group",unread:0},{id:"channel_3001",name:"测试频道",type:"channel",unread:0}]),[G,Z]=f([]),[m,u]=f(S[0]),[x,E]=f(""),[D,ee]=f("ProcessBot"),[F,M]=f(false),[P,j]=f(false),[_,H]=f(false),[T,te]=f(false),[O,s]=f(null),[a,o]=f(""),[l,c]=f(""),[g,z]=f(""),[R,A]=f(""),[N]=f([{id:"10001",name:"张三"},{id:"10002",name:"李四"},{id:"10003",name:"王五"},{id:"10004",name:"赵六"},{id:"10005",name:"测试用户"},{id:"10086",name:"Admin"},{id:"10010",name:"Test User"}]),[W,q]=f([]),[ne,re]=f(false),oe=B(null),U=B(null);B(null);const I=B(null),be=async()=>{try{const r=await(await fetch("https://face.viki.moe/metadata.json")).json();Z(r)}catch(e){console.error("[ProcessSandbox] Failed to fetch face list:",e)}};Q(()=>{be()},[]),Q(()=>{const e=window.location.protocol==="https:"?"wss:":"ws:";return U.current=new WebSocket(`${e}//${window.location.host}/sandbox`),U.current.onopen=()=>{M(true)},U.current.onmessage=r=>{try{const n=JSON.parse(r.data);let h=[];typeof n.content=="string"?h=ae(n.content):Array.isArray(n.content)?h=n.content:h=ae(String(n.content));let d=S.find($=>$.id===n.id);if(!d){const $=n.type==="private"?`私聊-${n.bot||D}`:n.type==="group"?`群组-${n.id}`:`频道-${n.id}`;d={id:n.id,name:$,type:n.type,unread:0},w(Te=>[...Te,d]),u(d)}const y={id:`bot_${n.timestamp}`,type:"received",channelType:n.type,channelId:n.id,channelName:d.name,senderId:"bot",senderName:n.bot||D,content:h,timestamp:n.timestamp};L($=>[...$,y])}catch(n){console.error("[Sandbox] Failed to parse message:",n)}},U.current.onclose=()=>{M(false)},()=>{U.current?.close()}},[D,S]),Q(()=>{oe.current?.scrollIntoView({behavior:"smooth"})},[K]),Q(()=>{if(x.trim()){const e=ae(x);q(e)}else q([])},[x]);const ae=e=>{const r=[],n=/\[@([^\]]+)\]|\[face:(\d+)\]|\[image:([^\]]+)\]/g;let h=0,d;for(;(d=n.exec(e))!==null;){if(d.index>h){const y=e.substring(h,d.index);y&&r.push({type:"text",data:{text:y}})}d[1]?r.push({type:"at",data:{qq:d[1],name:d[1]}}):d[2]?r.push({type:"face",data:{id:parseInt(d[2])}}):d[3]&&r.push({type:"image",data:{url:d[3]}}),h=n.lastIndex}if(h<e.length){const y=e.substring(h);y&&r.push({type:"text",data:{text:y}})}return r.length>0?r:[{type:"text",data:{text:e}}]},we=e=>e.map((r,n)=>{if(typeof r=="string"){const h=r.split(`
4
- `);return t("span",{children:h.map((d,y)=>i(ye.Fragment,{children:[d,y<h.length-1&&t("br",{})]},y))},n)}switch(r.type){case"text":const h=r.data.text.split(`
5
- `);return t("span",{children:h.map((d,y)=>i(ye.Fragment,{children:[d,y<h.length-1&&t("br",{})]},y))},n);case"at":return i(C,{color:"blue",variant:"soft",style:{margin:"0 2px"},children:["@",r.data.name||r.data.qq]},n);case"face":return t("img",{src:`https://face.viki.moe/apng/${r.data.id}.png`,alt:`表情${r.data.id}`,style:{width:"24px",height:"24px",display:"inline-block",verticalAlign:"middle",margin:"0 2px"}},n);case"image":return t("img",{src:r.data.url,alt:"图片",style:{maxWidth:"300px",borderRadius:"8px",margin:"4px 0",display:"block"},onError:d=>{d.currentTarget.style.display="none"}},n);case"video":return t(C,{variant:"outline",style:{margin:"0 2px"},children:"📹 视频"},n);case"audio":return t(C,{variant:"outline",style:{margin:"0 2px"},children:"🎵 语音"},n);case"file":return i(C,{variant:"outline",style:{margin:"0 2px"},children:["📎 ",r.data.name||"文件"]},n);default:return t("span",{children:"[未知消息类型]"},n)}}),ce=(e,r)=>{if(!e.trim()||r.length===0)return;const n={id:`msg_${Date.now()}`,type:"sent",channelType:m.type,channelId:m.id,channelName:m.name,senderId:"test_user",senderName:"测试用户",content:r,timestamp:Date.now()};L(h=>[...h,n]),E(""),q([]),I.current?.clear(),U.current?.send(JSON.stringify({type:m.type,id:m.id,content:r,timestamp:Date.now()}))},Ce=()=>{confirm("确定清空所有消息记录?")&&L([])},ze=e=>{u(e),w(r=>r.map(n=>n.id===e.id?{...n,unread:0}:n)),window.innerWidth<768&&re(false)},Re=()=>{const e=["private","group","channel"],r={private:"私聊",group:"群聊",guild:"频道"},n=e[Math.floor(Math.random()*e.length)],h=`${n}_${Date.now()}`,d=prompt(`请输入${r[n]}名称:`);if(d){const y={id:h,name:d,type:n,unread:0};w($=>[...$,y]),u(y)}},le=e=>{switch(e){case"private":return t(se,{size:16});case"group":return t(_e,{size:16});case"channel":return t(je,{size:16});default:return t(Y,{size:16})}},Ne=e=>{I.current?.insertFace(e),j(false)},de=()=>{g.trim()&&(I.current?.insertImage(g.trim()),z(""),H(false))},pe=()=>{R.trim()&&(I.current?.insertAt(R.trim()),A(""),te(false))},ke=e=>{I.current?.replaceAtTrigger(e.name,e.id),s(null),o("")},Se=(e,r,n)=>{if(m.type==="private"){s(null),o("");return}e&&n?(s(n),o(r)):(s(null),o(""))},ue=N.filter(e=>{if(!a.trim())return true;const r=a.toLowerCase();return e.name.toLowerCase().includes(r)||e.id.toLowerCase().includes(r)}),Ee=(e,r)=>{E(e),q(r)},ge=G.filter(e=>e.name.toLowerCase().includes(l.toLowerCase())||e.describe.toLowerCase().includes(l.toLowerCase())),ie=K.filter(e=>e.channelId===m.id);return i("div",{className:"sandbox-container",children:[i("button",{className:"mobile-channel-toggle md:hidden",onClick:()=>re(!ne),children:[t(Y,{size:20}),"频道列表"]}),i(X,{className:he("channel-sidebar",ne&&"show"),children:[t(v,{p:"3",style:{borderBottom:"1px solid var(--gray-6)"},children:i(p,{justify:"between",align:"center",mb:"2",children:[i(p,{align:"center",gap:"2",children:[t(v,{p:"1",style:{borderRadius:"8px",backgroundColor:"var(--purple-3)"},children:t(Y,{size:16,color:"var(--purple-9)"})}),t(xe,{size:"4",children:"频道列表"})]}),t(C,{color:F?"green":"gray",children:i(p,{align:"center",gap:"1",children:[F?t(Ie,{size:12}):t($e,{size:12}),F?"已连接":"未连接"]})})]})}),t(v,{style:{flex:1,overflowY:"auto"},p:"3",children:t(p,{direction:"column",gap:"2",children:S.map(e=>{const r=m.id===e.id;return i("div",{className:he("channel-item",r&&"active"),onClick:()=>ze(e),children:[t("div",{className:"icon",children:le(e.type)}),i("div",{className:"text",children:[t("div",{className:"title",children:e.name}),i("div",{className:"subtitle",children:[e.type==="private"&&"私聊",e.type==="group"&&"群聊",e.type==="channel"&&"频道"]})]}),e.unread>0&&t(C,{color:"red",size:"1",className:"badge",children:e.unread}),r&&t("div",{className:"indicator"})]},e.id)})})}),t(v,{p:"2",style:{borderTop:"1px solid var(--gray-6)"},children:t(k,{variant:"outline",onClick:Re,style:{width:"100%"},children:"+ 添加频道"})})]}),ne&&t("div",{className:"channel-overlay md:hidden",onClick:()=>re(false)}),i("div",{className:"chat-area",children:[t(X,{children:i(p,{justify:"between",align:"center",p:"3",children:[i(p,{align:"center",gap:"3",children:[t(v,{p:"2",style:{borderRadius:"12px",backgroundColor:"var(--blue-3)"},children:le(m.type)}),i(v,{children:[t(xe,{size:"5",children:m.name}),i(p,{align:"center",gap:"2",children:[t(b,{size:"1",color:"gray",children:m.id}),t(C,{variant:"outline",size:"1",children:ie.length}),t(b,{size:"1",color:"gray",children:"条消息"})]})]}),i(C,{color:m.type==="private"?"blue":m.type==="group"?"green":"purple",children:[m.type==="private"&&"私聊",m.type==="group"&&"群聊",m.type==="channel"&&"频道"]})]}),i(p,{align:"center",gap:"2",children:[t(J.Root,{value:D,onChange:e=>ee(e.target.value),placeholder:"机器人名称",style:{width:"120px"}}),i(k,{variant:"soft",onClick:Ce,children:[t(Le,{size:16}),"清空"]})]})]})}),t(X,{style:{flex:1,display:"flex",flexDirection:"column"},children:t(v,{style:{flex:1,overflowY:"auto"},p:"4",children:ie.length===0?i(p,{direction:"column",align:"center",justify:"center",style:{height:"100%"},children:[t(Y,{size:64,color:"var(--gray-6)"}),t(b,{color:"gray",mt:"3",children:"暂无消息,开始对话吧!"})]}):i(p,{direction:"column",gap:"2",children:[ie.map(e=>t(p,{justify:e.type==="sent"?"end":"start",children:i(v,{style:{maxWidth:"70%",padding:"12px",borderRadius:"16px",backgroundColor:e.type==="sent"?"var(--blue-9)":"var(--gray-3)",color:e.type==="sent"?"white":"var(--gray-12)"},children:[i(p,{align:"center",gap:"2",mb:"1",children:[e.type==="received"&&t(De,{size:14}),e.type==="sent"&&t(se,{size:14}),t(b,{size:"1",weight:"medium",style:{opacity:.9},children:e.senderName}),t(b,{size:"1",style:{opacity:.7},children:new Date(e.timestamp).toLocaleTimeString()})]}),t(b,{size:"2",children:we(e.content)})]})},e.id)),t("div",{ref:oe})]})})}),t(X,{children:i(p,{direction:"column",gap:"3",p:"3",children:[i(p,{gap:"2",align:"center",children:[t(k,{variant:P?"solid":"outline",size:"2",onClick:()=>{j(!P),H(false)},title:"插入表情",children:t(Fe,{size:16})}),t(k,{variant:_?"solid":"outline",size:"2",onClick:()=>{H(!_),j(false)},title:"插入图片",children:t(Me,{size:16})}),t(v,{style:{flex:1}}),x&&t(k,{variant:"ghost",size:"2",onClick:()=>{E(""),q([])},title:"清空",children:t(Ue,{size:16})})]}),P&&i(v,{p:"3",style:{border:"1px solid var(--gray-6)",borderRadius:"8px",backgroundColor:"var(--gray-1)",maxHeight:"256px",overflowY:"auto"},children:[t(J.Root,{value:l,onChange:e=>c(e.target.value),placeholder:"搜索表情...",style:{marginBottom:"8px"}}),t(qe,{columns:"8",gap:"2",children:ge.slice(0,80).map(e=>t("button",{onClick:()=>Ne(e.id),style:{width:"40px",height:"40px",borderRadius:"8px",border:"1px solid var(--gray-6)",backgroundColor:"transparent",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"},title:e.name,children:t("img",{src:`https://face.viki.moe/apng/${e.id}.png`,alt:e.name,style:{width:"32px",height:"32px"}})},e.id))}),ge.length===0&&i(p,{direction:"column",align:"center",gap:"2",py:"4",children:[t(me,{size:32,color:"var(--gray-6)"}),t(b,{size:"2",color:"gray",children:"未找到匹配的表情"})]})]}),_&&t(v,{p:"3",style:{border:"1px solid var(--gray-6)",borderRadius:"8px",backgroundColor:"var(--gray-1)"},children:i(V.Root,{defaultValue:"url",children:[i(V.List,{children:[t(V.Trigger,{value:"url",children:"图片链接"}),t(V.Trigger,{value:"upload",children:"本地上传"})]}),t(v,{pt:"3",children:i(p,{direction:"column",gap:"2",children:[t(J.Root,{value:g,onChange:e=>z(e.target.value),placeholder:"输入图片 URL...",onKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),de())}}),i(k,{onClick:de,disabled:!g.trim(),children:[t(fe,{size:16}),"插入"]})]})})]})}),T&&t(v,{p:"3",style:{border:"1px solid var(--gray-6)",borderRadius:"8px",backgroundColor:"var(--gray-1)"},children:i(p,{direction:"column",gap:"2",children:[t(J.Root,{value:R,onChange:e=>A(e.target.value),placeholder:"输入用户名...",onKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),pe())}}),i(k,{onClick:pe,disabled:!R.trim(),children:[t(fe,{size:16}),"插入"]})]})}),i(p,{gap:"2",align:"start",children:[i(v,{style:{flex:1,position:"relative"},children:[t(ve,{ref:I,placeholder:`向 ${m.name} 发送消息...`,onSend:ce,onChange:Ee,onAtTrigger:Se,minHeight:"44px",maxHeight:"200px"}),O&&t(v,{style:{position:"absolute",top:`${O.top}px`,left:`${O.left}px`,zIndex:1e3,backgroundColor:"var(--gray-1)",border:"1px solid var(--gray-6)",borderRadius:"8px",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15)",minWidth:"240px",maxHeight:"280px",overflowY:"auto",padding:"4px"},children:ue.length>0?ue.map(e=>i(p,{align:"center",gap:"2",p:"2",onClick:()=>ke(e),style:{cursor:"pointer",borderRadius:"6px",transition:"background-color 0.2s"},onMouseEnter:r=>{r.currentTarget.style.backgroundColor="var(--blue-a3)"},onMouseLeave:r=>{r.currentTarget.style.backgroundColor="transparent"},children:[t(se,{size:16,color:"var(--blue-9)"}),i(p,{direction:"column",gap:"0",style:{flex:1},children:[t(b,{size:"2",weight:"medium",children:e.name}),i(b,{size:"1",color:"gray",children:["ID: ",e.id]})]})]},e.id)):i(p,{align:"center",justify:"center",p:"4",direction:"column",gap:"2",children:[t(me,{size:20,color:"var(--gray-8)"}),t(b,{size:"1",color:"gray",children:"未找到匹配的用户"})]})})]}),i(k,{onClick:()=>{const e=I.current?.getContent();e&&ce(e.text,e.segments)},disabled:!x.trim()||W.length===0,size:"3",title:"发送消息 (Enter)",children:[t(Be,{size:16}),"发送"]})]}),i(p,{align:"center",gap:"2",wrap:"wrap",children:[t(Pe,{size:12,color:"var(--gray-9)"}),t(b,{size:"1",color:"gray",children:"快捷操作:"}),t(C,{variant:"outline",size:"1",children:"Enter"}),t(b,{size:"1",color:"gray",children:"发送"}),t(C,{variant:"outline",size:"1",children:"Shift+Enter"}),t(b,{size:"1",color:"gray",children:"换行"}),t(C,{variant:"outline",size:"1",children:"[@名称]"}),t(b,{size:"1",color:"gray",children:"@某人"})]})]})})]})]})}Ae({key:"process-sandbox",path:"/sandbox",title:"沙盒",icon:t(He,{className:"w-5 h-5"}),element:t(Ke,{})});
1
+ import{jsx as t,jsxs as i}from"react/jsx-runtime";import{cn as C,addPage as be}from"@zhin.js/client";import{MessageSquare as B,Wifi as Ne,WifiOff as ve,Trash2 as we,Bot as Ce,User as G,Smile as Se,Image as ke,X as Re,Search as ie,Check as Ee,Send as Ae,Info as Ie,Hash as ze,Users as Te,Terminal as $e}from"lucide-react";import ce,{forwardRef as Le,useRef as _,useImperativeHandle as je,useState as f,useEffect as H}from"react";const oe=Le(({placeholder:O="输入消息...",onSend:S,onChange:N,onAtTrigger:x,minHeight:W="44px",maxHeight:K="200px"},h)=>{const m=_(null),g=_(null),v=()=>{if(!m.current)return{text:"",segments:[]};let a="";const r=[],c=Array.from(m.current.childNodes);for(const d of c)if(d.nodeType===Node.TEXT_NODE){const o=d.textContent||"";o&&(a+=o,r.push({type:"text",data:{text:o}}))}else if(d.nodeType===Node.ELEMENT_NODE){const o=d;if(o.classList.contains("editor-face")){const u=o.dataset.id;a+=`[face:${u}]`,r.push({type:"face",data:{id:Number(u)}})}else if(o.classList.contains("editor-image")){const u=o.dataset.url;a+=`[image:${u}]`,r.push({type:"image",data:{url:u}})}else if(o.classList.contains("editor-at")){const u=o.dataset.name,y=o.dataset.id;a+=`[@${u}]`,r.push({type:"at",data:{name:u,qq:y}})}else o.tagName==="BR"&&(a+=`
2
+ `)}return{text:a,segments:r}},k=a=>{if(!m.current)return;const r=document.createElement("img");r.src=`https://face.viki.moe/apng/${a}.png`,r.alt=`[face:${a}]`,r.dataset.type="face",r.dataset.id=String(a),r.className="editor-face",E(r),A()},Q=a=>{if(!m.current||!a.trim())return;const r=document.createElement("img");r.src=a.trim(),r.alt=`[image:${a.trim()}]`,r.dataset.type="image",r.dataset.url=a.trim(),r.className="editor-image",E(r),A()},R=(a,r)=>{if(!m.current||!a.trim())return;const c=document.createElement("span");c.dataset.type="at",c.dataset.name=a,r&&(c.dataset.id=r),c.className="editor-at",c.contentEditable="false";const d=document.createElement("span");d.textContent="@",d.className="editor-at-symbol";const o=document.createElement("span");o.textContent=a,o.className="editor-at-name",c.appendChild(d),c.appendChild(o),E(c),A()},E=a=>{if(!m.current)return;m.current.focus();const r=window.getSelection();if(r&&r.rangeCount>0){const c=r.getRangeAt(0);if(m.current.contains(c.commonAncestorContainer))c.deleteContents(),c.insertNode(a),c.collapse(false),r.removeAllRanges(),r.addRange(c);else{m.current.appendChild(a);const o=document.createRange();o.setStartAfter(a),o.collapse(true),r.removeAllRanges(),r.addRange(o)}}else{m.current.appendChild(a);const c=window.getSelection();if(c){const d=document.createRange();d.setStartAfter(a),d.collapse(true),c.removeAllRanges(),c.addRange(d)}}},$=()=>{m.current&&(m.current.innerHTML="",A())},L=()=>{m.current?.focus()},j=()=>v(),D=()=>{if(!m.current||!x)return;const a=window.getSelection();if(!a||a.rangeCount===0){x(false,""),g.current=null;return}const r=a.getRangeAt(0);if(!m.current.contains(r.commonAncestorContainer)){x(false,""),g.current=null;return}const c=r.startContainer;if(c.nodeType!==Node.TEXT_NODE){x(false,""),g.current=null;return}const d=c,o=d.textContent?.substring(0,r.startOffset)||"",u=o.lastIndexOf("@");if(u!==-1){const y=o.substring(u+1);if(y.includes(" ")||y.includes(`
3
+ `)){x(false,""),g.current=null;return}g.current=d;const I=document.createRange();I.setStart(d,u),I.setEnd(d,u+1);const U=I.getBoundingClientRect(),b=m.current.getBoundingClientRect();x(true,y,{top:U.bottom-b.top,left:U.left-b.left})}else x(false,""),g.current=null},A=()=>{if(D(),N){const{text:a,segments:r}=v();N(a,r)}},Z=(a,r)=>{if(!g.current)return;const c=g.current,d=c.textContent||"",o=d.lastIndexOf("@");if(o!==-1){const u=d.substring(o+1),y=o+1+u.split(/[\s\n]/)[0].length,I=d.substring(0,o),U=d.substring(y);c.textContent=I+U;const b=window.getSelection();if(b){const M=document.createRange();M.setStart(c,o),M.collapse(true),b.removeAllRanges(),b.addRange(M)}}g.current=null,R(a,r)},F=a=>{if(a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),S)){const{text:r,segments:c}=v();S(r,c)}};return je(h,()=>({focus:L,clear:$,insertFace:k,insertImage:Q,insertAt:R,replaceAtTrigger:Z,getContent:j})),t("div",{ref:m,contentEditable:true,suppressContentEditableWarning:true,onInput:A,onKeyDown:F,"data-placeholder":O,className:"rich-text-editor",style:{width:"100%",minHeight:W,maxHeight:K,padding:"0.5rem 0.75rem",border:"1px solid var(--gray-6)",borderRadius:"6px",backgroundColor:"var(--gray-1)",fontSize:"var(--font-size-2)",outline:"none",overflowY:"auto",lineHeight:"1.5",wordWrap:"break-word",color:"var(--gray-12)"}})});oe.displayName="RichTextEditor";function De(){const[O,S]=f([]),[N,x]=f([{id:"user_1001",name:"测试用户",type:"private",unread:0},{id:"group_2001",name:"测试群组",type:"group",unread:0},{id:"channel_3001",name:"测试频道",type:"channel",unread:0}]),[W,K]=f([]),[h,m]=f(N[0]),[g,v]=f(""),[k,Q]=f("ProcessBot"),[R,E]=f(false),[$,L]=f(false),[j,D]=f(false),[A,Z]=f(false),[F,a]=f(null),[r,c]=f(""),[d,o]=f(""),[u,y]=f(""),[I,U]=f(""),[b]=f([{id:"10001",name:"张三"},{id:"10002",name:"李四"},{id:"10003",name:"王五"},{id:"10004",name:"赵六"},{id:"10005",name:"测试用户"},{id:"10086",name:"Admin"},{id:"10010",name:"Test User"}]),[M,q]=f([]),[X,J]=f(false),ee=_(null),z=_(null),T=_(null),de=async()=>{try{const e=await fetch("https://face.viki.moe/metadata.json");K(await e.json())}catch(e){console.error("[Sandbox] Failed to fetch face list:",e)}};H(()=>{de()},[]),H(()=>{const e=window.location.protocol==="https:"?"wss:":"ws:";return z.current=new WebSocket(`${e}//${window.location.host}/sandbox`),z.current.onopen=()=>E(true),z.current.onmessage=s=>{try{const n=JSON.parse(s.data);let p=typeof n.content=="string"?V(n.content):Array.isArray(n.content)?n.content:V(String(n.content)),l=N.find(P=>P.id===n.id);if(!l){const P=n.type==="private"?`私聊-${n.bot||k}`:n.type==="group"?`群组-${n.id}`:`频道-${n.id}`;l={id:n.id,name:P,type:n.type,unread:0},x(ye=>[...ye,l]),m(l)}const w={id:`bot_${n.timestamp}`,type:"received",channelType:n.type,channelId:n.id,channelName:l.name,senderId:"bot",senderName:n.bot||k,content:p,timestamp:n.timestamp};S(P=>[...P,w])}catch(n){console.error("[Sandbox] Failed to parse message:",n)}},z.current.onclose=()=>E(false),()=>{z.current?.close()}},[k,N]),H(()=>{ee.current?.scrollIntoView({behavior:"smooth"})},[O]),H(()=>{q(g.trim()?V(g):[])},[g]);const V=e=>{const s=[],n=/\[@([^\]]+)\]|\[face:(\d+)\]|\[image:([^\]]+)\]/g;let p=0,l;for(;(l=n.exec(e))!==null;){if(l.index>p){const w=e.substring(p,l.index);w&&s.push({type:"text",data:{text:w}})}l[1]?s.push({type:"at",data:{qq:l[1],name:l[1]}}):l[2]?s.push({type:"face",data:{id:parseInt(l[2])}}):l[3]&&s.push({type:"image",data:{url:l[3]}}),p=n.lastIndex}if(p<e.length){const w=e.substring(p);w&&s.push({type:"text",data:{text:w}})}return s.length>0?s:[{type:"text",data:{text:e}}]},le=e=>e.map((s,n)=>{if(typeof s=="string")return t("span",{children:s.split(`
4
+ `).map((p,l)=>i(ce.Fragment,{children:[p,l<s.split(`
5
+ `).length-1&&t("br",{})]},l))},n);switch(s.type){case"text":return t("span",{children:s.data.text.split(`
6
+ `).map((p,l)=>i(ce.Fragment,{children:[p,l<s.data.text.split(`
7
+ `).length-1&&t("br",{})]},l))},n);case"at":return i("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded bg-accent text-accent-foreground text-xs mx-0.5",children:["@",s.data.name||s.data.qq]},n);case"face":return t("img",{src:`https://face.viki.moe/apng/${s.data.id}.png`,alt:`face${s.data.id}`,className:"w-6 h-6 inline-block align-middle mx-0.5"},n);case"image":return t("img",{src:s.data.url,alt:"image",className:"max-w-[300px] rounded-lg my-1 block",onError:p=>{p.currentTarget.style.display="none"}},n);case"video":return t("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-xs mx-0.5",children:"📹 视频"},n);case"audio":return t("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-xs mx-0.5",children:"🎵 语音"},n);case"file":return i("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-xs mx-0.5",children:["📎 ",s.data.name||"文件"]},n);default:return t("span",{children:"[未知消息类型]"},n)}}),te=(e,s)=>{if(!e.trim()||s.length===0)return;const n={id:`msg_${Date.now()}`,type:"sent",channelType:h.type,channelId:h.id,channelName:h.name,senderId:"test_user",senderName:"测试用户",content:s,timestamp:Date.now()};S(p=>[...p,n]),v(""),q([]),T.current?.clear(),z.current?.send(JSON.stringify({type:h.type,id:h.id,content:s,timestamp:Date.now()}))},me=()=>{confirm("确定清空所有消息记录?")&&S([])},ue=e=>{m(e),x(s=>s.map(n=>n.id===e.id?{...n,unread:0}:n)),window.innerWidth<768&&J(false)},pe=()=>{const e=["private","group","channel"],s=e[Math.floor(Math.random()*e.length)],n=prompt("请输入频道名称:");if(n){const p={id:`${s}_${Date.now()}`,name:n,type:s,unread:0};x(l=>[...l,p]),m(p)}},ne=e=>{switch(e){case"private":return t(G,{size:16});case"group":return t(Te,{size:16});case"channel":return t(ze,{size:16});default:return t(B,{size:16})}},fe=e=>{T.current?.insertFace(e),L(false)},re=()=>{u.trim()&&(T.current?.insertImage(u.trim()),y(""),D(false))},he=e=>{T.current?.replaceAtTrigger(e.name,e.id),a(null),c("")},ge=(e,s,n)=>{if(h.type==="private"){a(null),c("");return}e&&n?(a(n),c(s)):(a(null),c(""))},ae=b.filter(e=>{if(!r.trim())return true;const s=r.toLowerCase();return e.name.toLowerCase().includes(s)||e.id.toLowerCase().includes(s)}),xe=(e,s)=>{v(e),q(s)},se=W.filter(e=>e.name.toLowerCase().includes(d.toLowerCase())||e.describe.toLowerCase().includes(d.toLowerCase())),Y=O.filter(e=>e.channelId===h.id);return i("div",{className:"sandbox-container",children:[i("button",{className:"mobile-channel-toggle md:hidden",onClick:()=>J(!X),children:[t(B,{size:20})," 频道列表"]}),i("div",{className:C("channel-sidebar rounded-lg border bg-card",X&&"show"),children:[t("div",{className:"p-3 border-b",children:i("div",{className:"flex justify-between items-center",children:[i("div",{className:"flex items-center gap-2",children:[t("div",{className:"p-1 rounded-md bg-secondary",children:t(B,{size:16,className:"text-muted-foreground"})}),t("h3",{className:"font-semibold",children:"频道列表"})]}),i("span",{className:C("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border",R?"bg-emerald-100 text-emerald-800 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800":"bg-muted text-muted-foreground"),children:[R?t(Ne,{size:12}):t(ve,{size:12}),R?"已连接":"未连接"]})]})}),t("div",{className:"flex-1 overflow-y-auto p-2 space-y-1",children:N.map(e=>{const s=h.id===e.id;return i("div",{className:C("menu-item",s&&"active"),onClick:()=>ue(e),children:[t("span",{className:"shrink-0",children:ne(e.type)}),i("div",{className:"flex-1 min-w-0",children:[t("div",{className:"text-sm font-medium truncate",children:e.name}),t("div",{className:"text-xs text-muted-foreground",children:e.type==="private"?"私聊":e.type==="group"?"群聊":"频道"})]}),e.unread>0&&t("span",{className:"inline-flex items-center justify-center h-5 min-w-5 rounded-full bg-destructive text-destructive-foreground text-[10px] font-medium px-1",children:e.unread})]},e.id)})}),t("div",{className:"p-2 border-t",children:t("button",{className:"w-full py-2 px-3 rounded-md border border-dashed text-sm text-muted-foreground hover:bg-accent transition-colors",onClick:pe,children:"+ 添加频道"})})]}),X&&t("div",{className:"channel-overlay md:hidden",onClick:()=>J(false)}),i("div",{className:"chat-area",children:[t("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0",children:i("div",{className:"flex justify-between items-center flex-wrap gap-2",children:[i("div",{className:"flex items-center gap-3",children:[t("div",{className:"p-2 rounded-lg bg-secondary",children:ne(h.type)}),i("div",{children:[t("h2",{className:"text-lg font-bold",children:h.name}),i("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[t("span",{children:h.id}),t("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-[10px]",children:Y.length}),t("span",{children:"条消息"})]})]}),t("span",{className:"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-secondary text-secondary-foreground",children:h.type==="private"?"私聊":h.type==="group"?"群聊":"频道"})]}),i("div",{className:"flex items-center gap-2",children:[t("input",{value:k,onChange:e=>Q(e.target.value),placeholder:"机器人名称",className:"h-8 w-28 rounded-md border bg-transparent px-2 text-sm"}),i("button",{className:"inline-flex items-center gap-1 h-8 px-3 rounded-md bg-secondary text-secondary-foreground text-sm hover:bg-secondary/80",onClick:me,children:[t(we,{size:14})," 清空"]})]})]})}),t("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0",children:t("div",{className:"flex-1 overflow-y-auto p-4",children:Y.length===0?i("div",{className:"flex flex-col items-center justify-center h-full gap-3",children:[t(B,{size:64,className:"text-muted-foreground/20"}),t("span",{className:"text-muted-foreground",children:"暂无消息,开始对话吧!"})]}):i("div",{className:"space-y-2",children:[Y.map(e=>t("div",{className:C("flex",e.type==="sent"?"justify-end":"justify-start"),children:i("div",{className:C("max-w-[70%] p-3 rounded-2xl",e.type==="sent"?"bg-primary text-primary-foreground":"bg-muted"),children:[i("div",{className:"flex items-center gap-2 mb-1",children:[e.type==="received"&&t(Ce,{size:14}),e.type==="sent"&&t(G,{size:14}),t("span",{className:"text-xs font-medium opacity-90",children:e.senderName}),t("span",{className:"text-xs opacity-70",children:new Date(e.timestamp).toLocaleTimeString()})]}),t("div",{className:"text-sm",children:le(e.content)})]})},e.id)),t("div",{ref:ee})]})})}),i("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0 space-y-3",children:[i("div",{className:"flex gap-2 items-center",children:[t("button",{className:C("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",$?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{L(!$),D(false)},title:"插入表情",children:t(Se,{size:16})}),t("button",{className:C("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",j?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{D(!j),L(false)},title:"插入图片",children:t(ke,{size:16})}),t("div",{className:"flex-1"}),g&&t("button",{className:"h-8 w-8 rounded-md flex items-center justify-center hover:bg-accent transition-colors",onClick:()=>{v(""),q([])},children:t(Re,{size:16})})]}),$&&i("div",{className:"p-3 rounded-md border bg-muted/30 max-h-64 overflow-y-auto space-y-2",children:[t("input",{value:d,onChange:e=>o(e.target.value),placeholder:"搜索表情...",className:"w-full h-8 rounded-md border bg-transparent px-2 text-sm"}),t("div",{className:"grid grid-cols-8 gap-1",children:se.slice(0,80).map(e=>t("button",{onClick:()=>fe(e.id),title:e.name,className:"w-10 h-10 rounded-md border flex items-center justify-center hover:bg-accent transition-colors",children:t("img",{src:`https://face.viki.moe/apng/${e.id}.png`,alt:e.name,className:"w-8 h-8"})},e.id))}),se.length===0&&i("div",{className:"flex flex-col items-center gap-2 py-4",children:[t(ie,{size:32,className:"text-muted-foreground/30"}),t("span",{className:"text-sm text-muted-foreground",children:"未找到匹配的表情"})]})]}),j&&i("div",{className:"p-3 rounded-md border bg-muted/30 space-y-2",children:[t("input",{value:u,onChange:e=>y(e.target.value),placeholder:"输入图片 URL...",className:"w-full h-8 rounded-md border bg-transparent px-2 text-sm",onKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),re())}}),i("button",{className:"inline-flex items-center gap-1 h-8 px-3 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50",onClick:re,disabled:!u.trim(),children:[t(Ee,{size:14})," 插入"]})]}),i("div",{className:"flex gap-2 items-start",children:[i("div",{className:"flex-1 relative",children:[t(oe,{ref:T,placeholder:`向 ${h.name} 发送消息...`,onSend:te,onChange:xe,onAtTrigger:ge,minHeight:"44px",maxHeight:"200px"}),F&&t("div",{className:"absolute z-50 rounded-lg border bg-popover shadow-md min-w-60 max-h-72 overflow-y-auto p-1",style:{top:`${F.top}px`,left:`${F.left}px`},children:ae.length>0?ae.map(e=>i("div",{className:"flex items-center gap-2 p-2 rounded-md cursor-pointer hover:bg-accent transition-colors",onClick:()=>he(e),children:[t(G,{size:16,className:"text-muted-foreground"}),i("div",{className:"flex-1",children:[t("div",{className:"text-sm font-medium",children:e.name}),i("div",{className:"text-xs text-muted-foreground",children:["ID: ",e.id]})]})]},e.id)):i("div",{className:"flex flex-col items-center gap-2 p-4",children:[t(ie,{size:20,className:"text-muted-foreground/50"}),t("span",{className:"text-xs text-muted-foreground",children:"未找到匹配的用户"})]})})]}),i("button",{className:"inline-flex items-center gap-1.5 h-10 px-4 rounded-md bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50 transition-colors hover:bg-primary/90",onClick:()=>{const e=T.current?.getContent();e&&te(e.text,e.segments)},disabled:!g.trim()||M.length===0,children:[t(Ae,{size:16})," 发送"]})]}),i("div",{className:"flex items-center gap-2 flex-wrap text-xs text-muted-foreground",children:[t(Ie,{size:12})," 快捷操作:",t("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Enter"})," 发送",t("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Shift+Enter"})," 换行",t("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[@名称]"})," @某人"]})]})]})]})}be({key:"process-sandbox",path:"/sandbox",title:"沙盒",icon:t($e,{className:"w-5 h-5"}),element:t(De,{})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-sandbox",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "description": "Zhin.js adapter for local testing and development",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -44,17 +44,16 @@
44
44
  "@types/react": "^19.2.2",
45
45
  "@types/react-dom": "^19.2.1",
46
46
  "radix-ui": "^1.4.3",
47
- "@radix-ui/themes": "^3.2.1",
48
47
  "lucide-react": "^0.469.0",
49
48
  "typescript": "^5.3.0",
50
- "zhin.js": "1.0.25"
49
+ "zhin.js": "1.0.27"
51
50
  },
52
51
  "peerDependencies": {
53
- "@zhin.js/core": "1.0.25",
54
- "@zhin.js/client": "1.0.8",
55
- "@zhin.js/http": "1.0.16",
56
- "@zhin.js/console": "1.0.21",
57
- "zhin.js": "1.0.25"
52
+ "@zhin.js/core": "1.0.27",
53
+ "@zhin.js/client": "1.0.9",
54
+ "@zhin.js/http": "1.0.18",
55
+ "@zhin.js/console": "1.0.23",
56
+ "zhin.js": "1.0.27"
58
57
  },
59
58
  "peerDependenciesMeta": {
60
59
  "@zhin.js/http": {
@@ -73,6 +72,6 @@
73
72
  },
74
73
  "scripts": {
75
74
  "build": "tsc && (test -f ../../services/console/lib/bin.js && node ../../services/console/lib/bin.js build || echo 'Skipping client build: console not built yet')",
76
- "clean": "rm -rf lib"
75
+ "clean": "rimraf lib"
77
76
  }
78
77
  }