@xto/chat 1.0.0

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/es/style.css ADDED
@@ -0,0 +1 @@
1
+ .x-markdown-renderer{font-size:14px;line-height:1.6}.x-markdown-renderer h1,.x-markdown-renderer h2,.x-markdown-renderer h3,.x-markdown-renderer h4,.x-markdown-renderer h5,.x-markdown-renderer h6{margin:12px 0 6px;font-weight:600}.x-markdown-renderer h1{font-size:1.5em}.x-markdown-renderer h2{font-size:1.3em}.x-markdown-renderer h3{font-size:1.1em}.x-markdown-renderer p{margin:6px 0}.x-markdown-renderer ul,.x-markdown-renderer ol{padding-left:20px;margin:6px 0}.x-markdown-renderer code{background:#f0f0f0;padding:2px 4px;border-radius:2px;font-family:Monaco,Consolas,monospace;font-size:.9em}.x-markdown-renderer pre{margin:8px 0;border-radius:4px;overflow:hidden}.x-markdown-renderer pre code{display:block;padding:8px 12px;background:#1e1e1e;color:#d4d4d4}.x-markdown-renderer blockquote{border-left:3px solid #d0d0d0;padding-left:12px;margin:8px 0;color:#666}.x-markdown-renderer table{border-collapse:collapse;margin:8px 0}.x-markdown-renderer table th,.x-markdown-renderer table td{border:1px solid #d0d0d0;padding:6px 10px}.x-markdown-renderer table th{background:#f5f5f5}.x-markdown-renderer a{color:#155eef;text-decoration:none}.x-markdown-renderer a:hover{text-decoration:underline}.x-markdown-renderer img{max-width:100%;border-radius:4px}.x-markdown-renderer hr{border:none;border-top:1px solid #e0e0e0;margin:12px 0}.x-thinking-chain{background:#fafafa;border:1px solid #e8e8e8;border-radius:4px;margin-bottom:8px;font-size:12px}.x-thinking-chain__header{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none}.x-thinking-chain__icon{font-size:14px}.x-thinking-chain__title{font-weight:600;color:#666}.x-thinking-chain__toggle{margin-left:auto;color:#999}.x-thinking-chain__steps{padding:0 10px 8px}.x-thinking-chain__step{border-left:2px solid #d0d0d0;padding-left:8px;margin-bottom:6px}.x-thinking-chain__step:last-child{margin-bottom:0}.x-thinking-chain__field{display:flex;gap:4px;margin-bottom:2px}.x-thinking-chain__label{color:#999;font-weight:600;flex-shrink:0}.x-thinking-chain__value{color:#333;word-break:break-word}.x-thinking-chain__value--action{color:#155eef;font-weight:500}.x-tool-call-display{background:#f9f9f9;border:1px solid #e8e8e8;border-radius:4px;margin-bottom:8px;font-size:12px}.x-tool-call-display__item{border-bottom:1px solid #f0f0f0}.x-tool-call-display__item:last-child{border-bottom:none}.x-tool-call-display__header{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none}.x-tool-call-display__icon{font-size:12px}.x-tool-call-display__name{font-weight:600;color:#333}.x-tool-call-display__status{font-size:11px;padding:1px 6px;border-radius:2px}.x-tool-call-display__status--success{background:#d1fae5;color:#10b981}.x-tool-call-display__status--failed{background:#fee2e2;color:#ef4444}.x-tool-call-display__time{color:#999;font-size:11px}.x-tool-call-display__toggle{margin-left:auto;color:#999}.x-tool-call-display__body{padding:8px 10px;background:#fafafa}.x-tool-call-display__section{margin-bottom:6px}.x-tool-call-display__label{color:#999;margin-bottom:2px}.x-tool-call-display__code{background:#1e1e1e;color:#d4d4d4;padding:6px;border-radius:2px;font-size:11px;overflow-x:auto;margin:0}.x-tool-call-display__error{color:#ef4444;background:#fef2f2;padding:4px 6px;border-radius:2px}.x-feedback-buttons{display:flex;gap:4px;margin-top:4px}.x-feedback-buttons__btn{background:none;border:1px solid transparent;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:14px}.x-feedback-buttons__btn:hover{background:#f5f5f5}.x-feedback-buttons__btn--active{background:#f0f7ff;border-color:#155eef}.x-message-item{display:flex;gap:12px}.x-message-item--user{flex-direction:row-reverse}.x-message-item__avatar{width:32px;height:32px;border-radius:50%;background:#155eef;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;flex-shrink:0}.x-message-item--user .x-message-item__avatar{background:#10b981}.x-message-item__body{flex:1;max-width:80%}.x-message-item--user .x-message-item__body{text-align:right}.x-message-item__meta{font-size:11px;color:#999;margin-bottom:4px;display:flex;gap:8px}.x-message-item__content{background:#f5f5f5;padding:12px 16px;border-radius:8px;font-size:14px;line-height:1.6;text-align:left;word-break:break-word}.x-message-item--user .x-message-item__content{background:#155eef;color:#fff}.x-message-item__cursor{animation:blink 1s infinite;font-weight:700}@keyframes blink{0%,50%{opacity:1}51%,to{opacity:0}}.x-message-list{display:flex;flex-direction:column;gap:16px}.x-message-list__loading{display:flex;gap:4px;align-items:center;padding:8px}.x-message-list__dot{width:8px;height:8px;background:#999;border-radius:50%;animation:bounce 1.4s infinite ease-in-out}.x-message-list__dot:nth-child(1){animation-delay:-.32s}.x-message-list__dot:nth-child(2){animation-delay:-.16s}@keyframes bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.x-message-input__attachments{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px}.x-message-input__attachment{display:flex;align-items:center;gap:4px;padding:4px 8px;background:#f5f5f5;border-radius:4px;font-size:12px}.x-message-input__attachment-remove{background:none;border:none;cursor:pointer;color:#999}.x-message-input__row{display:flex;gap:8px;align-items:flex-end}.x-message-input__upload{cursor:pointer;padding:8px;background:#f5f5f5;border-radius:4px}.x-message-input__upload input{display:none}.x-message-input__textarea{flex:1;padding:10px 12px;border:1px solid #d0d0d0;border-radius:8px;resize:none;font-size:14px;line-height:1.5;font-family:inherit;max-height:200px;overflow-y:auto}.x-message-input__textarea:focus{outline:none;border-color:#155eef}.x-message-input__textarea:disabled{background:#f5f5f5;cursor:not-allowed}.x-message-input__actions{display:flex;flex-direction:column;align-items:flex-end;gap:4px}.x-message-input__count{font-size:11px;color:#999}.x-message-input__btn{padding:8px 16px;border:none;border-radius:6px;cursor:pointer;font-size:13px}.x-message-input__btn--send{background:#155eef;color:#fff}.x-message-input__btn--send:disabled{background:#ccc;cursor:not-allowed}.x-message-input__btn--stop{background:#ef4444;color:#fff}.x-suggested-questions__label{font-size:11px;color:#999;margin-bottom:4px}.x-suggested-questions__list{display:flex;flex-wrap:wrap;gap:6px}.x-suggested-questions__item{padding:4px 10px;border:1px solid #d0d0d0;border-radius:12px;background:#fff;color:#155eef;cursor:pointer;font-size:12px;transition:all .2s}.x-suggested-questions__item:hover{background:#155eef;color:#fff;border-color:#155eef}.x-chat-container{display:flex;flex-direction:column;height:100%;background:#fff}.x-chat-container__messages{flex:1;overflow-y:auto;padding:16px}.x-chat-container__suggested{padding:8px 16px;border-top:1px solid #f0f0f0}.x-chat-container__input{border-top:1px solid #e0e0e0;padding:12px 16px}.x-code-block{border-radius:4px;overflow:hidden;margin:8px 0}.x-code-block__header{display:flex;justify-content:space-between;align-items:center;background:#2d2d2d;color:#ccc;padding:4px 8px;font-size:11px}.x-code-block__language{text-transform:uppercase}.x-code-block__copy{background:none;border:1px solid #555;color:#ccc;padding:2px 8px;border-radius:2px;cursor:pointer;font-size:11px}.x-code-block__copy:hover{background:#444}.x-code-block__pre{background:#1e1e1e;color:#d4d4d4;padding:8px 12px;margin:0;overflow-x:auto;font-family:Monaco,Consolas,monospace;font-size:12px;line-height:1.5}.x-file-upload__dropzone{border:2px dashed #d0d0d0;border-radius:6px;padding:16px;text-align:center;cursor:pointer;transition:all .2s;position:relative}.x-file-upload__dropzone:hover,.x-file-upload__dropzone--active{border-color:#155eef;background:#f0f7ff}.x-file-upload__dropzone input[type=file]{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0;cursor:pointer}.x-file-upload__hint{font-size:13px;color:#666}.x-file-upload__hint span{display:block}.x-file-upload__max{font-size:11px;color:#999;margin-top:4px}.x-file-upload__list{margin-top:8px;display:flex;flex-direction:column;gap:4px}.x-file-upload__item{display:flex;align-items:center;gap:8px;padding:6px 10px;background:#f5f5f5;border-radius:4px;font-size:12px}.x-file-upload__name{flex:1;color:#333}.x-file-upload__size{color:#999}.x-file-upload__remove{background:none;border:none;cursor:pointer;color:#ef4444;font-size:16px}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * 聊天类型定义。
3
+ */
4
+ export type MessageRole = 'user' | 'assistant' | 'system' | 'tool';
5
+ export type MessageStatus = 'pending' | 'streaming' | 'completed' | 'failed';
6
+ export interface Message {
7
+ id?: string;
8
+ role: MessageRole;
9
+ content: string;
10
+ status?: MessageStatus;
11
+ thinkingChain?: ThinkingStep[];
12
+ toolCalls?: ToolCall[];
13
+ tokenUsage?: number;
14
+ latency?: number;
15
+ attachments?: MessageAttachment[];
16
+ feedback?: 'like' | 'dislike' | null;
17
+ timestamp?: number;
18
+ toolCallId?: string;
19
+ toolName?: string;
20
+ }
21
+ export interface MessageAttachment {
22
+ referenceId: string;
23
+ fileName: string;
24
+ mimeType: string;
25
+ size: number;
26
+ }
27
+ export interface ChatSession {
28
+ id: string;
29
+ title: string;
30
+ messages: Message[];
31
+ variables?: Record<string, unknown>;
32
+ summary?: string;
33
+ status: 'active' | 'archived';
34
+ createdAt: number;
35
+ updatedAt: number;
36
+ }
37
+ export interface ChatEvent {
38
+ type: 'message_started' | 'message_chunk' | 'message_completed' | 'message_failed' | 'thinking_step' | 'tool_call_started' | 'tool_call_completed';
39
+ message?: Message;
40
+ chunk?: string;
41
+ thinkingStep?: ThinkingStep;
42
+ toolCall?: ToolCall;
43
+ error?: string;
44
+ }
45
+ export interface ThinkingStep {
46
+ thought?: string;
47
+ action?: string;
48
+ actionInput?: string;
49
+ observation?: string;
50
+ timestamp?: number;
51
+ }
52
+ export interface ToolCall {
53
+ id?: string;
54
+ name: string;
55
+ arguments?: Record<string, unknown>;
56
+ result?: unknown;
57
+ elapsedMs?: number;
58
+ success?: boolean;
59
+ errorMessage?: string;
60
+ }
@@ -0,0 +1,37 @@
1
+ import { Message } from '../types';
2
+ /**
3
+ * 消息格式化工具。
4
+ */
5
+ export declare const messageFormatter: {
6
+ /**
7
+ * 格式化时间戳为本地时间字符串。
8
+ */
9
+ formatTime(timestamp: number): string;
10
+ /**
11
+ * 格式化耗时为人类可读字符串。
12
+ */
13
+ formatLatency(ms: number): string;
14
+ /**
15
+ * 粗略估算 token 数(中文按字数 / 英文按单词数 * 1.3)。
16
+ */
17
+ estimateTokens(text: string): number;
18
+ /**
19
+ * 提取消息中的代码块。
20
+ */
21
+ extractCodeBlocks(content: string): Array<{
22
+ language: string;
23
+ code: string;
24
+ }>;
25
+ /**
26
+ * 截断长消息。
27
+ */
28
+ truncate(message: Message, maxLength: number): Message;
29
+ };
30
+ /**
31
+ * Token 计数器。
32
+ */
33
+ export declare const tokenCounter: {
34
+ count(text: string): number;
35
+ countMessage(message: Message): number;
36
+ countMessages(messages: Message[]): number;
37
+ };
package/lib/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),L=require("markdown-it"),$=require("highlight.js"),w=require("dompurify"),A=require("dayjs"),z=["innerHTML"],x=e.defineComponent({name:"XMarkdownRenderer",__name:"index",props:{content:{default:""},enableHighlight:{type:Boolean,default:!0}},setup(t){const l=t,o=e.computed(()=>{const s=new L({html:!1,linkify:!0,breaks:!0,highlight(a,n){if(n&&l.enableHighlight&&$.getLanguage(n))try{return`<pre class="hljs"><code>${$.highlight(a,{language:n}).value}</code></pre>`}catch{}return`<pre class="hljs"><code>${s.utils.escapeHtml(a)}</code></pre>`}});return s}),c=e.computed(()=>{if(!l.content)return"";const s=o.value.render(l.content);return w.sanitize(s,{ADD_ATTR:["target"],ALLOWED_TAGS:w.config.ALLOWED_TAGS})});return e.watch(c,()=>{}),(s,a)=>(e.openBlock(),e.createElementBlock("div",{class:"x-markdown-renderer",innerHTML:c.value},null,8,z))}}),I={class:"x-thinking-chain"},U={class:"x-thinking-chain__title"},q={class:"x-thinking-chain__toggle"},H={key:0,class:"x-thinking-chain__steps"},X={key:0,class:"x-thinking-chain__field"},O={class:"x-thinking-chain__value"},Q={key:1,class:"x-thinking-chain__field"},j={class:"x-thinking-chain__value x-thinking-chain__value--action"},R={key:2,class:"x-thinking-chain__field"},K={class:"x-thinking-chain__value"},G={key:3,class:"x-thinking-chain__field"},J={class:"x-thinking-chain__value"},B=e.defineComponent({name:"XThinkingChain",__name:"index",props:{steps:{default:()=>[]},collapsed:{type:Boolean,default:!1}},setup(t){const l=t,o=e.ref(l.collapsed),c=()=>{o.value=!o.value},s=e.computed(()=>l.steps.length);return(a,n)=>(e.openBlock(),e.createElementBlock("div",I,[e.createElementVNode("div",{class:"x-thinking-chain__header",onClick:c},[n[0]||(n[0]=e.createElementVNode("span",{class:"x-thinking-chain__icon"},"🧠",-1)),e.createElementVNode("span",U,"思维链 ("+e.toDisplayString(s.value)+" 步)",1),e.createElementVNode("span",q,e.toDisplayString(o.value?"▶":"▼"),1)]),o.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",H,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.steps,(i,m)=>(e.openBlock(),e.createElementBlock("div",{key:m,class:"x-thinking-chain__step"},[i.thought?(e.openBlock(),e.createElementBlock("div",X,[n[1]||(n[1]=e.createElementVNode("span",{class:"x-thinking-chain__label"},"Thought:",-1)),e.createElementVNode("span",O,e.toDisplayString(i.thought),1)])):e.createCommentVNode("",!0),i.action?(e.openBlock(),e.createElementBlock("div",Q,[n[2]||(n[2]=e.createElementVNode("span",{class:"x-thinking-chain__label"},"Action:",-1)),e.createElementVNode("span",j,e.toDisplayString(i.action),1)])):e.createCommentVNode("",!0),i.actionInput?(e.openBlock(),e.createElementBlock("div",R,[n[3]||(n[3]=e.createElementVNode("span",{class:"x-thinking-chain__label"},"Action Input:",-1)),e.createElementVNode("span",K,e.toDisplayString(i.actionInput),1)])):e.createCommentVNode("",!0),i.observation?(e.openBlock(),e.createElementBlock("div",G,[n[4]||(n[4]=e.createElementVNode("span",{class:"x-thinking-chain__label"},"Observation:",-1)),e.createElementVNode("span",J,e.toDisplayString(i.observation),1)])):e.createCommentVNode("",!0)]))),128))]))]))}}),P={key:0,class:"x-tool-call-display"},W=["onClick"],Y={class:"x-tool-call-display__name"},Z={key:0,class:"x-tool-call-display__time"},ee={class:"x-tool-call-display__toggle"},te={key:0,class:"x-tool-call-display__body"},ne={key:0,class:"x-tool-call-display__section"},se={class:"x-tool-call-display__code"},ae={key:1,class:"x-tool-call-display__section"},le={class:"x-tool-call-display__code"},oe={key:2,class:"x-tool-call-display__error"},y=e.defineComponent({name:"XToolCallDisplay",__name:"index",props:{toolCalls:{default:()=>[]}},setup(t){const l=e.ref(new Set),o=s=>{l.value.has(s)?l.value.delete(s):l.value.add(s)},c=s=>l.value.has(s);return(s,a)=>t.toolCalls.length?(e.openBlock(),e.createElementBlock("div",P,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.toolCalls,(n,i)=>(e.openBlock(),e.createElementBlock("div",{key:i,class:"x-tool-call-display__item"},[e.createElementVNode("div",{class:"x-tool-call-display__header",onClick:m=>o(i)},[a[0]||(a[0]=e.createElementVNode("span",{class:"x-tool-call-display__icon"},"🔧",-1)),e.createElementVNode("span",Y,e.toDisplayString(n.name),1),e.createElementVNode("span",{class:e.normalizeClass(["x-tool-call-display__status",`x-tool-call-display__status--${n.success?"success":"failed"}`])},e.toDisplayString(n.success===!1?"失败":"成功"),3),n.elapsedMs?(e.openBlock(),e.createElementBlock("span",Z,e.toDisplayString(n.elapsedMs)+"ms",1)):e.createCommentVNode("",!0),e.createElementVNode("span",ee,e.toDisplayString(c(i)?"▼":"▶"),1)],8,W),c(i)?(e.openBlock(),e.createElementBlock("div",te,[n.arguments?(e.openBlock(),e.createElementBlock("div",ne,[a[1]||(a[1]=e.createElementVNode("div",{class:"x-tool-call-display__label"},"参数:",-1)),e.createElementVNode("pre",se,e.toDisplayString(JSON.stringify(n.arguments,null,2)),1)])):e.createCommentVNode("",!0),n.result!==void 0?(e.openBlock(),e.createElementBlock("div",ae,[a[2]||(a[2]=e.createElementVNode("div",{class:"x-tool-call-display__label"},"结果:",-1)),e.createElementVNode("pre",le,e.toDisplayString(typeof n.result=="string"?n.result:JSON.stringify(n.result,null,2)),1)])):e.createCommentVNode("",!0),n.errorMessage?(e.openBlock(),e.createElementBlock("div",oe,e.toDisplayString(n.errorMessage),1)):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0)]))),128))])):e.createCommentVNode("",!0)}}),ce={class:"x-feedback-buttons"},E=e.defineComponent({name:"XFeedbackButtons",__name:"index",props:{current:{default:null}},emits:["feedback"],setup(t,{emit:l}){const o=l;return(c,s)=>(e.openBlock(),e.createElementBlock("div",ce,[e.createElementVNode("button",{class:e.normalizeClass(["x-feedback-buttons__btn",{"x-feedback-buttons__btn--active":t.current==="like"}]),onClick:s[0]||(s[0]=a=>o("feedback","like"))},"👍",2),e.createElementVNode("button",{class:e.normalizeClass(["x-feedback-buttons__btn",{"x-feedback-buttons__btn--active":t.current==="dislike"}]),onClick:s[1]||(s[1]=a=>o("feedback","dislike"))},"👎",2)]))}}),ie={key:0,class:"x-message-item__avatar"},re={key:0},de={key:1},ue={key:2},me={class:"x-message-item__body"},ge={key:0,class:"x-message-item__meta"},pe={class:"x-message-item__time"},he={key:0,class:"x-message-item__latency"},ke={key:1,class:"x-message-item__tokens"},_e={class:"x-message-item__content"},fe={key:3,class:"x-message-item__cursor"},b=e.defineComponent({name:"XMessageItem",__name:"index",props:{message:{},showAvatar:{type:Boolean,default:!0},showTimestamp:{type:Boolean,default:!0},showFeedback:{type:Boolean,default:!0}},emits:["feedback"],setup(t,{emit:l}){const o=t,c=l,s=e.computed(()=>o.message.role==="user"),a=e.computed(()=>o.message.role==="assistant"),n=e.computed(()=>o.message.timestamp?A(o.message.timestamp).format("HH:mm:ss"):""),i=m=>{o.message.id&&c("feedback",o.message.id,m)};return(m,d)=>{var p,h;return e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["x-message-item",`x-message-item--${t.message.role}`])},[t.showAvatar?(e.openBlock(),e.createElementBlock("div",ie,[s.value?(e.openBlock(),e.createElementBlock("span",re,"U")):a.value?(e.openBlock(),e.createElementBlock("span",de,"AI")):(e.openBlock(),e.createElementBlock("span",ue,"S"))])):e.createCommentVNode("",!0),e.createElementVNode("div",me,[t.showTimestamp?(e.openBlock(),e.createElementBlock("div",ge,[e.createElementVNode("span",pe,e.toDisplayString(n.value),1),t.message.latency?(e.openBlock(),e.createElementBlock("span",he,e.toDisplayString((t.message.latency/1e3).toFixed(2))+"s",1)):e.createCommentVNode("",!0),t.message.tokenUsage?(e.openBlock(),e.createElementBlock("span",ke,e.toDisplayString(t.message.tokenUsage)+" tokens",1)):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),e.createElementVNode("div",_e,[(p=t.message.thinkingChain)!=null&&p.length?(e.openBlock(),e.createBlock(B,{key:0,steps:t.message.thinkingChain},null,8,["steps"])):e.createCommentVNode("",!0),(h=t.message.toolCalls)!=null&&h.length?(e.openBlock(),e.createBlock(y,{key:1,"tool-calls":t.message.toolCalls},null,8,["tool-calls"])):e.createCommentVNode("",!0),t.message.content?(e.openBlock(),e.createBlock(x,{key:2,content:t.message.content},null,8,["content"])):e.createCommentVNode("",!0),t.message.status==="streaming"?(e.openBlock(),e.createElementBlock("span",fe,"|")):e.createCommentVNode("",!0)]),t.showFeedback&&a.value&&t.message.status==="completed"?(e.openBlock(),e.createBlock(E,{key:1,current:t.message.feedback||null,onFeedback:i},null,8,["current"])):e.createCommentVNode("",!0)])],2)}}}),ve={class:"x-message-list"},xe={key:0,class:"x-message-list__loading"},C=e.defineComponent({name:"XMessageList",__name:"index",props:{messages:{default:()=>[]},loading:{type:Boolean,default:!1},showAvatar:{type:Boolean,default:!0},showTimestamp:{type:Boolean,default:!0},showFeedback:{type:Boolean,default:!0}},emits:["feedback"],setup(t,{emit:l}){const o=l,c=(s,a)=>o("feedback",s,a);return(s,a)=>(e.openBlock(),e.createElementBlock("div",ve,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.messages,n=>(e.openBlock(),e.createBlock(b,{key:n.id||n.timestamp,message:n,"show-avatar":t.showAvatar,"show-timestamp":t.showTimestamp,"show-feedback":t.showFeedback,onFeedback:c},null,8,["message","show-avatar","show-timestamp","show-feedback"]))),128)),t.loading?(e.openBlock(),e.createElementBlock("div",xe,[...a[0]||(a[0]=[e.createElementVNode("span",{class:"x-message-list__dot"},null,-1),e.createElementVNode("span",{class:"x-message-list__dot"},null,-1),e.createElementVNode("span",{class:"x-message-list__dot"},null,-1)])])):e.createCommentVNode("",!0)]))}}),Be={class:"x-message-input"},ye={key:0,class:"x-message-input__attachments"},Ee={class:"x-message-input__attachment-name"},be=["onClick"],Ce={class:"x-message-input__row"},Ne={key:0,class:"x-message-input__upload"},Ve=["placeholder","disabled","maxlength"],$e={class:"x-message-input__actions"},we={class:"x-message-input__count"},Se=["disabled"],N=e.defineComponent({name:"XMessageInput",__name:"index",props:{placeholder:{default:"请输入消息..."},maxLength:{default:4e3},disabled:{type:Boolean,default:!1},loading:{type:Boolean,default:!1},enableFileUpload:{type:Boolean,default:!1}},emits:["send","stop","regenerate"],setup(t,{emit:l}){const o=t,c=l,s=e.ref(""),a=e.ref(null),n=e.ref([]),i=e.computed(()=>s.value.length),m=e.computed(()=>s.value.trim().length>0&&!o.disabled),d=()=>{a.value&&(a.value.style.height="auto",a.value.style.height=Math.min(a.value.scrollHeight,200)+"px")},p=()=>{d(),s.value.length>o.maxLength&&(s.value=s.value.substring(0,o.maxLength))},h=()=>{m.value&&(c("send",s.value.trim(),n.value.length?n.value:void 0),s.value="",n.value=[],e.nextTick(()=>d()))},_=r=>{r.key==="Enter"&&!r.shiftKey&&(r.preventDefault(),h())},f=r=>{const u=r.target;u.files&&(n.value=[...n.value,...Array.from(u.files)])},g=r=>{n.value.splice(r,1)};return(r,u)=>(e.openBlock(),e.createElementBlock("div",Be,[n.value.length?(e.openBlock(),e.createElementBlock("div",ye,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(n.value,(k,v)=>(e.openBlock(),e.createElementBlock("div",{key:v,class:"x-message-input__attachment"},[e.createElementVNode("span",Ee,e.toDisplayString(k.name),1),e.createElementVNode("button",{class:"x-message-input__attachment-remove",onClick:T=>g(v)},"×",8,be)]))),128))])):e.createCommentVNode("",!0),e.createElementVNode("div",Ce,[t.enableFileUpload?(e.openBlock(),e.createElementBlock("label",Ne,[e.createElementVNode("input",{type:"file",multiple:"",onChange:f},null,32),u[2]||(u[2]=e.createElementVNode("span",null,"📎",-1))])):e.createCommentVNode("",!0),e.withDirectives(e.createElementVNode("textarea",{ref_key:"textareaRef",ref:a,"onUpdate:modelValue":u[0]||(u[0]=k=>s.value=k),placeholder:t.placeholder,disabled:t.disabled,maxlength:t.maxLength,class:"x-message-input__textarea",rows:"1",onInput:p,onKeydown:_},null,40,Ve),[[e.vModelText,s.value]]),e.createElementVNode("div",$e,[e.createElementVNode("span",we,e.toDisplayString(i.value)+"/"+e.toDisplayString(t.maxLength),1),t.loading?(e.openBlock(),e.createElementBlock("button",{key:0,class:"x-message-input__btn x-message-input__btn--stop",onClick:u[1]||(u[1]=k=>c("stop"))},"停止")):(e.openBlock(),e.createElementBlock("button",{key:1,class:"x-message-input__btn x-message-input__btn--send",disabled:!m.value,onClick:h},"发送",8,Se))])])]))}}),De={key:0,class:"x-suggested-questions"},Me={class:"x-suggested-questions__list"},Fe=["onClick"],V=e.defineComponent({name:"XSuggestedQuestions",__name:"index",props:{questions:{default:()=>[]}},emits:["select"],setup(t,{emit:l}){const o=l,c=s=>o("select",s);return(s,a)=>t.questions.length?(e.openBlock(),e.createElementBlock("div",De,[a[0]||(a[0]=e.createElementVNode("div",{class:"x-suggested-questions__label"},"推荐问题:",-1)),e.createElementVNode("div",Me,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.questions,(n,i)=>(e.openBlock(),e.createElementBlock("button",{key:i,class:"x-suggested-questions__item",onClick:m=>c(n)},e.toDisplayString(n),9,Fe))),128))])])):e.createCommentVNode("",!0)}});function S(t){const l=e.ref(!0);let o=0;const c=()=>{if(!t.value)return;const{scrollTop:n,scrollHeight:i,clientHeight:m}=t.value,d=i-n-m<50;n<o&&!d?l.value=!1:d&&(l.value=!0),o=n},s=()=>{e.nextTick(()=>{t.value&&(t.value.scrollTop=t.value.scrollHeight)})},a=()=>{l.value=!0,s()};return t.value&&t.value.addEventListener("scroll",c),e.watch(t,(n,i,m)=>{n&&(n.addEventListener("scroll",c),m(()=>n.removeEventListener("scroll",c)))}),{autoScroll:l,scrollToBottom:s,enableAutoScroll:a}}const Te={class:"x-chat-container__messages"},Le={key:0,class:"x-chat-container__suggested"},Ae={class:"x-chat-container__input"},D=e.defineComponent({name:"XChatContainer",__name:"index",props:{messages:{default:()=>[]},loading:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1},showAvatar:{type:Boolean,default:!0},showTimestamp:{type:Boolean,default:!0},showFeedback:{type:Boolean,default:!0},suggestedQuestions:{default:()=>[]},placeholder:{default:"请输入消息..."},maxLength:{default:4e3},enableFileUpload:{type:Boolean,default:!1}},emits:["send","stop","regenerate","feedback","selectQuestion"],setup(t,{expose:l,emit:o}){const c=t,s=o,a=e.ref(null),{autoScroll:n,scrollToBottom:i}=S(a),m=e.computed(()=>c.messages),d=(g,r)=>s("send",g,r),p=()=>s("stop"),h=()=>s("regenerate"),_=(g,r)=>s("feedback",g,r),f=g=>s("selectQuestion",g);return e.watch(()=>c.messages.length,()=>{n.value&&e.nextTick(()=>i())}),l({clearMessages:()=>s("send","__clear__"),scrollToBottom:i,appendMessage:g=>{c.messages.push(g)},updateLastMessage:g=>{c.messages.length>0&&(c.messages[c.messages.length-1]=g)}}),(g,r)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"containerRef",ref:a,class:"x-chat-container"},[e.createElementVNode("div",Te,[e.createVNode(C,{messages:m.value,loading:t.loading,"show-avatar":t.showAvatar,"show-timestamp":t.showTimestamp,"show-feedback":t.showFeedback,onFeedback:_},null,8,["messages","loading","show-avatar","show-timestamp","show-feedback"])]),t.suggestedQuestions.length?(e.openBlock(),e.createElementBlock("div",Le,[e.createVNode(V,{questions:t.suggestedQuestions,onSelect:f},null,8,["questions"])])):e.createCommentVNode("",!0),e.createElementVNode("div",Ae,[e.createVNode(N,{placeholder:t.placeholder,"max-length":t.maxLength,disabled:t.loading||t.readonly,"enable-file-upload":t.enableFileUpload,onSend:d,onStop:p,onRegenerate:h,loading:t.loading},null,8,["placeholder","max-length","disabled","enable-file-upload","loading"])])],512))}}),ze={class:"x-code-block"},Ie={class:"x-code-block__header"},Ue={class:"x-code-block__language"},qe={class:"x-code-block__pre"},M=e.defineComponent({name:"XCodeBlock",__name:"index",props:{code:{},language:{default:"plaintext"},showCopy:{type:Boolean,default:!0}},setup(t){const l=t,o=e.ref(!1),c=async()=>{try{await navigator.clipboard.writeText(l.code),o.value=!0,setTimeout(()=>{o.value=!1},2e3)}catch{}};return(s,a)=>(e.openBlock(),e.createElementBlock("div",ze,[e.createElementVNode("div",Ie,[e.createElementVNode("span",Ue,e.toDisplayString(t.language),1),t.showCopy?(e.openBlock(),e.createElementBlock("button",{key:0,class:"x-code-block__copy",onClick:c},e.toDisplayString(o.value?"已复制":"复制"),1)):e.createCommentVNode("",!0)]),e.createElementVNode("pre",qe,[e.createElementVNode("code",{class:e.normalizeClass(`language-${t.language}`)},e.toDisplayString(t.code),3)])]))}}),He={class:"x-file-upload"},Xe=["accept","multiple"],Oe={class:"x-file-upload__hint"},Qe={class:"x-file-upload__max"},je={key:0,class:"x-file-upload__list"},Re={class:"x-file-upload__name"},Ke={class:"x-file-upload__size"},Ge=["onClick"],F=e.defineComponent({name:"XFileUpload",__name:"index",props:{accept:{default:""},multiple:{type:Boolean,default:!0},maxSize:{default:50}},emits:["change","exceed"],setup(t,{expose:l,emit:o}){const c=t,s=o,a=e.ref([]),n=e.ref(!1),i=r=>r<1024?r+"B":r<1024*1024?(r/1024).toFixed(1)+"KB":(r/1024/1024).toFixed(1)+"MB",m=r=>{if(!r)return;const u=[];for(const k of Array.from(r)){if(k.size>c.maxSize*1024*1024){s("exceed",k);continue}u.push(k)}c.multiple?a.value=[...a.value,...u]:a.value=u,s("change",a.value)},d=r=>{const u=r.target;m(u.files)},p=r=>{var u;n.value=!1,(u=r.dataTransfer)!=null&&u.files&&m(r.dataTransfer.files)},h=()=>{n.value=!0},_=()=>{n.value=!1},f=r=>{a.value.splice(r,1),s("change",a.value)};return l({files:a,clear:()=>{a.value=[],s("change",a.value)}}),(r,u)=>(e.openBlock(),e.createElementBlock("div",He,[e.createElementVNode("div",{class:e.normalizeClass(["x-file-upload__dropzone",{"x-file-upload__dropzone--active":n.value}]),onDrop:e.withModifiers(p,["prevent"]),onDragover:e.withModifiers(h,["prevent"]),onDragleave:e.withModifiers(_,["prevent"])},[e.createElementVNode("input",{type:"file",accept:t.accept,multiple:t.multiple,onChange:d},null,40,Xe),e.createElementVNode("div",Oe,[u[0]||(u[0]=e.createElementVNode("span",null,"📎 拖拽文件到此处,或点击选择",-1)),e.createElementVNode("span",Qe,"最大 "+e.toDisplayString(t.maxSize)+"MB",1)])],34),a.value.length?(e.openBlock(),e.createElementBlock("div",je,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.value,(k,v)=>(e.openBlock(),e.createElementBlock("div",{key:v,class:"x-file-upload__item"},[e.createElementVNode("span",Re,e.toDisplayString(k.name),1),e.createElementVNode("span",Ke,e.toDisplayString(i(k.size)),1),e.createElementVNode("button",{class:"x-file-upload__remove",onClick:T=>f(v)},"×",8,Ge)]))),128))])):e.createCommentVNode("",!0)]))}});function Je(t){const l=e.ref([]),o=e.ref(!1),c=e.ref(null);return{messages:l,loading:o,error:c,send:async i=>{if(!i.trim()||o.value)return;const m={id:`user-${Date.now()}`,role:"user",content:i,status:"completed",timestamp:Date.now()};l.value.push(m);const d={id:`assistant-${Date.now()}`,role:"assistant",content:"",status:"pending",timestamp:Date.now()};l.value.push(d),o.value=!0,c.value=null;try{if(t!=null&&t.sendMessage){const p=await t.sendMessage(i);if(p instanceof ReadableStream){const h=p.getReader();let _="";for(;;){const{done:f,value:g}=await h.read();if(f)break;g&&(_+=g.content||"",d.content=_,d.status="streaming")}d.status="completed"}else Object.assign(d,p),d.status="completed"}else d.content="No sendMessage handler configured.",d.status="failed"}catch(p){d.status="failed",d.content=`Error: ${p.message||"Unknown error"}`,c.value=p.message}finally{o.value=!1}},stop:()=>{o.value=!1;const i=l.value[l.value.length-1];i&&i.status==="streaming"&&(i.status="completed")},clear:()=>{l.value=[],c.value=null}}}function Pe(){const t=e.ref(!1);let l=null;const o=(s,a,n)=>{c(),l=new EventSource(s),t.value=!0,l.onmessage=i=>{a(i.data)},l.onerror=i=>{t.value=!1,n==null||n(i)},l.onopen=()=>{t.value=!0}},c=()=>{l&&(l.close(),l=null,t.value=!1)};return e.onBeforeUnmount(()=>{c()}),{isConnected:t,connect:o,disconnect:c}}const We={ChatContainer:D,MessageList:C,MessageItem:b,MessageInput:N,ThinkingChain:B,ToolCallDisplay:y,MarkdownRenderer:x,CodeBlock:M,SuggestedQuestions:V,FileUpload:F,FeedbackButtons:E},Ye={install(t){Object.entries(We).forEach(([l,o])=>{t.component(l,o)})}};exports.ChatContainer=D;exports.CodeBlock=M;exports.FeedbackButtons=E;exports.FileUpload=F;exports.MarkdownRenderer=x;exports.MessageInput=N;exports.MessageItem=b;exports.MessageList=C;exports.SuggestedQuestions=V;exports.ThinkingChain=B;exports.ToolCallDisplay=y;exports.default=Ye;exports.useAutoScroll=S;exports.useChat=Je;exports.useSSE=Pe;
package/lib/style.css ADDED
@@ -0,0 +1 @@
1
+ .x-markdown-renderer{font-size:14px;line-height:1.6}.x-markdown-renderer h1,.x-markdown-renderer h2,.x-markdown-renderer h3,.x-markdown-renderer h4,.x-markdown-renderer h5,.x-markdown-renderer h6{margin:12px 0 6px;font-weight:600}.x-markdown-renderer h1{font-size:1.5em}.x-markdown-renderer h2{font-size:1.3em}.x-markdown-renderer h3{font-size:1.1em}.x-markdown-renderer p{margin:6px 0}.x-markdown-renderer ul,.x-markdown-renderer ol{padding-left:20px;margin:6px 0}.x-markdown-renderer code{background:#f0f0f0;padding:2px 4px;border-radius:2px;font-family:Monaco,Consolas,monospace;font-size:.9em}.x-markdown-renderer pre{margin:8px 0;border-radius:4px;overflow:hidden}.x-markdown-renderer pre code{display:block;padding:8px 12px;background:#1e1e1e;color:#d4d4d4}.x-markdown-renderer blockquote{border-left:3px solid #d0d0d0;padding-left:12px;margin:8px 0;color:#666}.x-markdown-renderer table{border-collapse:collapse;margin:8px 0}.x-markdown-renderer table th,.x-markdown-renderer table td{border:1px solid #d0d0d0;padding:6px 10px}.x-markdown-renderer table th{background:#f5f5f5}.x-markdown-renderer a{color:#155eef;text-decoration:none}.x-markdown-renderer a:hover{text-decoration:underline}.x-markdown-renderer img{max-width:100%;border-radius:4px}.x-markdown-renderer hr{border:none;border-top:1px solid #e0e0e0;margin:12px 0}.x-thinking-chain{background:#fafafa;border:1px solid #e8e8e8;border-radius:4px;margin-bottom:8px;font-size:12px}.x-thinking-chain__header{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none}.x-thinking-chain__icon{font-size:14px}.x-thinking-chain__title{font-weight:600;color:#666}.x-thinking-chain__toggle{margin-left:auto;color:#999}.x-thinking-chain__steps{padding:0 10px 8px}.x-thinking-chain__step{border-left:2px solid #d0d0d0;padding-left:8px;margin-bottom:6px}.x-thinking-chain__step:last-child{margin-bottom:0}.x-thinking-chain__field{display:flex;gap:4px;margin-bottom:2px}.x-thinking-chain__label{color:#999;font-weight:600;flex-shrink:0}.x-thinking-chain__value{color:#333;word-break:break-word}.x-thinking-chain__value--action{color:#155eef;font-weight:500}.x-tool-call-display{background:#f9f9f9;border:1px solid #e8e8e8;border-radius:4px;margin-bottom:8px;font-size:12px}.x-tool-call-display__item{border-bottom:1px solid #f0f0f0}.x-tool-call-display__item:last-child{border-bottom:none}.x-tool-call-display__header{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none}.x-tool-call-display__icon{font-size:12px}.x-tool-call-display__name{font-weight:600;color:#333}.x-tool-call-display__status{font-size:11px;padding:1px 6px;border-radius:2px}.x-tool-call-display__status--success{background:#d1fae5;color:#10b981}.x-tool-call-display__status--failed{background:#fee2e2;color:#ef4444}.x-tool-call-display__time{color:#999;font-size:11px}.x-tool-call-display__toggle{margin-left:auto;color:#999}.x-tool-call-display__body{padding:8px 10px;background:#fafafa}.x-tool-call-display__section{margin-bottom:6px}.x-tool-call-display__label{color:#999;margin-bottom:2px}.x-tool-call-display__code{background:#1e1e1e;color:#d4d4d4;padding:6px;border-radius:2px;font-size:11px;overflow-x:auto;margin:0}.x-tool-call-display__error{color:#ef4444;background:#fef2f2;padding:4px 6px;border-radius:2px}.x-feedback-buttons{display:flex;gap:4px;margin-top:4px}.x-feedback-buttons__btn{background:none;border:1px solid transparent;padding:4px 8px;border-radius:4px;cursor:pointer;font-size:14px}.x-feedback-buttons__btn:hover{background:#f5f5f5}.x-feedback-buttons__btn--active{background:#f0f7ff;border-color:#155eef}.x-message-item{display:flex;gap:12px}.x-message-item--user{flex-direction:row-reverse}.x-message-item__avatar{width:32px;height:32px;border-radius:50%;background:#155eef;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;flex-shrink:0}.x-message-item--user .x-message-item__avatar{background:#10b981}.x-message-item__body{flex:1;max-width:80%}.x-message-item--user .x-message-item__body{text-align:right}.x-message-item__meta{font-size:11px;color:#999;margin-bottom:4px;display:flex;gap:8px}.x-message-item__content{background:#f5f5f5;padding:12px 16px;border-radius:8px;font-size:14px;line-height:1.6;text-align:left;word-break:break-word}.x-message-item--user .x-message-item__content{background:#155eef;color:#fff}.x-message-item__cursor{animation:blink 1s infinite;font-weight:700}@keyframes blink{0%,50%{opacity:1}51%,to{opacity:0}}.x-message-list{display:flex;flex-direction:column;gap:16px}.x-message-list__loading{display:flex;gap:4px;align-items:center;padding:8px}.x-message-list__dot{width:8px;height:8px;background:#999;border-radius:50%;animation:bounce 1.4s infinite ease-in-out}.x-message-list__dot:nth-child(1){animation-delay:-.32s}.x-message-list__dot:nth-child(2){animation-delay:-.16s}@keyframes bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.x-message-input__attachments{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px}.x-message-input__attachment{display:flex;align-items:center;gap:4px;padding:4px 8px;background:#f5f5f5;border-radius:4px;font-size:12px}.x-message-input__attachment-remove{background:none;border:none;cursor:pointer;color:#999}.x-message-input__row{display:flex;gap:8px;align-items:flex-end}.x-message-input__upload{cursor:pointer;padding:8px;background:#f5f5f5;border-radius:4px}.x-message-input__upload input{display:none}.x-message-input__textarea{flex:1;padding:10px 12px;border:1px solid #d0d0d0;border-radius:8px;resize:none;font-size:14px;line-height:1.5;font-family:inherit;max-height:200px;overflow-y:auto}.x-message-input__textarea:focus{outline:none;border-color:#155eef}.x-message-input__textarea:disabled{background:#f5f5f5;cursor:not-allowed}.x-message-input__actions{display:flex;flex-direction:column;align-items:flex-end;gap:4px}.x-message-input__count{font-size:11px;color:#999}.x-message-input__btn{padding:8px 16px;border:none;border-radius:6px;cursor:pointer;font-size:13px}.x-message-input__btn--send{background:#155eef;color:#fff}.x-message-input__btn--send:disabled{background:#ccc;cursor:not-allowed}.x-message-input__btn--stop{background:#ef4444;color:#fff}.x-suggested-questions__label{font-size:11px;color:#999;margin-bottom:4px}.x-suggested-questions__list{display:flex;flex-wrap:wrap;gap:6px}.x-suggested-questions__item{padding:4px 10px;border:1px solid #d0d0d0;border-radius:12px;background:#fff;color:#155eef;cursor:pointer;font-size:12px;transition:all .2s}.x-suggested-questions__item:hover{background:#155eef;color:#fff;border-color:#155eef}.x-chat-container{display:flex;flex-direction:column;height:100%;background:#fff}.x-chat-container__messages{flex:1;overflow-y:auto;padding:16px}.x-chat-container__suggested{padding:8px 16px;border-top:1px solid #f0f0f0}.x-chat-container__input{border-top:1px solid #e0e0e0;padding:12px 16px}.x-code-block{border-radius:4px;overflow:hidden;margin:8px 0}.x-code-block__header{display:flex;justify-content:space-between;align-items:center;background:#2d2d2d;color:#ccc;padding:4px 8px;font-size:11px}.x-code-block__language{text-transform:uppercase}.x-code-block__copy{background:none;border:1px solid #555;color:#ccc;padding:2px 8px;border-radius:2px;cursor:pointer;font-size:11px}.x-code-block__copy:hover{background:#444}.x-code-block__pre{background:#1e1e1e;color:#d4d4d4;padding:8px 12px;margin:0;overflow-x:auto;font-family:Monaco,Consolas,monospace;font-size:12px;line-height:1.5}.x-file-upload__dropzone{border:2px dashed #d0d0d0;border-radius:6px;padding:16px;text-align:center;cursor:pointer;transition:all .2s;position:relative}.x-file-upload__dropzone:hover,.x-file-upload__dropzone--active{border-color:#155eef;background:#f0f7ff}.x-file-upload__dropzone input[type=file]{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0;cursor:pointer}.x-file-upload__hint{font-size:13px;color:#666}.x-file-upload__hint span{display:block}.x-file-upload__max{font-size:11px;color:#999;margin-top:4px}.x-file-upload__list{margin-top:8px;display:flex;flex-direction:column;gap:4px}.x-file-upload__item{display:flex;align-items:center;gap:8px;padding:6px 10px;background:#f5f5f5;border-radius:4px;font-size:12px}.x-file-upload__name{flex:1;color:#333}.x-file-upload__size{color:#999}.x-file-upload__remove{background:none;border:none;cursor:pointer;color:#ef4444;font-size:16px}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@xto/chat",
3
+ "version": "1.0.0",
4
+ "description": "Xto Chat - AI Chat Interface Components (message list, streaming, thinking chain, tool calls)",
5
+ "homepage": "https://jinguchu.github.io/xto-ui/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/jinguchu/xto-ui.git",
9
+ "directory": "packages/chat"
10
+ },
11
+ "main": "./lib/index.cjs",
12
+ "module": "./es/index.mjs",
13
+ "types": "./es/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": "./es/index.mjs",
17
+ "require": "./lib/index.cjs",
18
+ "types": "./es/index.d.ts"
19
+ },
20
+ "./es/style.css": "./es/style.css",
21
+ "./lib/style.css": "./lib/style.css"
22
+ },
23
+ "files": [
24
+ "es",
25
+ "lib"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "vite build",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest"
34
+ },
35
+ "dependencies": {
36
+ "@vueuse/core": "^11.0.0",
37
+ "markdown-it": "^14.1.0",
38
+ "highlight.js": "^11.10.0",
39
+ "dompurify": "^3.1.6",
40
+ "dayjs": "^1.11.13",
41
+ "@xto/base": "^1.4.1",
42
+ "@xto/core": "^1.2.4",
43
+ "@xto/form": "^1.4.1",
44
+ "@xto/feedback": "^1.2.6",
45
+ "@xto/data": "^1.2.2"
46
+ },
47
+ "peerDependencies": {
48
+ "vue": "^3.4.0"
49
+ },
50
+ "devDependencies": {
51
+ "@vitejs/plugin-vue": "^5.0.4",
52
+ "@vitejs/plugin-vue-jsx": "^3.1.0",
53
+ "@xto/build": "workspace:*",
54
+ "typescript": "^5.4.2",
55
+ "vite": "^5.2.0",
56
+ "vite-plugin-dts": "^4.5.4",
57
+ "vitest": "^1.4.0",
58
+ "vue": "^3.4.21"
59
+ }
60
+ }