@zhin.js/adapter-sandbox 1.0.30 → 1.0.31

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.31",
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.26"
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.26",
53
+ "@zhin.js/client": "1.0.9",
54
+ "@zhin.js/http": "1.0.17",
55
+ "@zhin.js/console": "1.0.22",
56
+ "zhin.js": "1.0.26"
58
57
  },
59
58
  "peerDependenciesMeta": {
60
59
  "@zhin.js/http": {