@webority/chat-react 0.88.0 → 0.89.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/dist/chat-react.js +1 -1
- package/dist/guidance.json +214 -0
- package/dist/types/ChatMarkdown.meta.d.ts +31 -0
- package/dist/types/components/ActionCard.meta.d.ts +89 -0
- package/dist/types/components/ChatComposer.d.ts +3 -3
- package/dist/types/components/ChatComposer.meta.d.ts +40 -0
- package/dist/types/components/ChatConversationList.d.ts +1 -1
- package/dist/types/components/ChatConversationList.meta.d.ts +37 -0
- package/dist/types/components/ChatLauncher.d.ts +6 -6
- package/dist/types/components/ChatLauncher.meta.d.ts +50 -0
- package/dist/types/components/ChatMessage.meta.d.ts +153 -0
- package/dist/types/components/ChatPanel.d.ts +9 -10
- package/dist/types/components/ChatPanel.meta.d.ts +208 -0
- package/dist/types/components/ChatThread.d.ts +1 -1
- package/dist/types/components/ChatThread.meta.d.ts +131 -0
- package/dist/types/components/CitationChip.d.ts +2 -2
- package/dist/types/components/CitationChip.meta.d.ts +48 -0
- package/dist/types/components/ConfirmCard.d.ts +2 -2
- package/dist/types/components/ConfirmCard.meta.d.ts +43 -0
- package/dist/types/components/ReplyRating.d.ts +2 -2
- package/dist/types/components/ReplyRating.meta.d.ts +34 -0
- package/package.json +9 -7
package/dist/chat-react.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ChatApiError as e,DEFAULT_CHAT_LABELS as t,createChatClient as n,createSseParser as r,linkRoute as i,mergeLabels as a,parseBlocks as o,parseInline as s}from"@webority/ui-elements/chat-core";import{AppActionIcon as c,AppAlert as l,AppButton as u,AppCard as d,AppChip as f,AppConfirmDialog as p,AppDataTable as m,AppEmptyState as h,AppIcon as g,AppLink as _,AppSidebarMenu as v,AppSkeleton as y,AppSpinner as b,AppTextarea as x,useFloatingStack as S}from"@webority/ui-react";import{Fragment as C,memo as w,startTransition as T,useCallback as E,useEffect as D,useId as O,useMemo as k,useRef as A,useState as j}from"react";import{Fragment as M,jsx as N,jsxs as P}from"react/jsx-runtime";import{createPortal as F}from"react-dom";function I(e,t){return e.kind===`Reply`?t.actionReply(e.ticketNumber):e.kind===`Reopen`?t.actionReopen(e.ticketNumber):t.actionRaiseTicket}function ee(e,t,n){return e===`Reply`?n.actionDoneReply(t):e===`Reopen`?n.actionDoneReopen(t):n.actionDoneRaiseTicket(t)}function L({action:e,confirmAction:t,onViewTicket:n,labels:r}){let i=a(r),[o,s]=j(`ready`),[c,f]=j(null),[p,m]=j(``);if(o===`dismissed`)return N(`p`,{className:`wui-text-sm text-body-secondary mb-0`,children:i.actionDismissed});if(o===`done`)return N(l,{variant:`success`,role:`status`,size:`sm`,action:n?N(u,{size:`sm`,variant:`ghost`,onClick:()=>n(c),children:i.viewTicket}):void 0,children:ee(e.kind,c.number,i)});async function h(){s(`sending`),m(``);try{f(await t(e.token)),s(`done`)}catch(e){m(e?.message||i.actionFailed),s(`ready`)}}let g=o===`sending`,_=new Date(e.expiresDateTimeUtc).getTime()<=Date.now(),v=e.kind===`RaiseTicket`?[e.category,e.subject].filter(Boolean).join(` · `):``;return N(d,{padding:`sm`,className:`border`,title:I(e,i),subtitle:v||void 0,children:P(`div`,{className:`d-flex flex-column gap-2`,children:[e.kind!==`Reopen`&&e.body&&N(`p`,{className:`wui-text-sm mb-0`,style:{whiteSpace:`pre-wrap`,overflowWrap:`anywhere`},children:e.body}),_?N(`p`,{className:`wui-text-sm text-body-secondary mb-0`,children:i.actionExpired}):P(M,{children:[N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,children:i.actionNote}),p&&N(l,{size:`sm`,variant:`danger`,children:p}),P(`div`,{className:`d-flex flex-wrap gap-2`,children:[N(u,{size:`sm`,loading:g,onClick:h,children:i.actionConfirm}),N(u,{size:`sm`,variant:`secondary`,disabled:g,onClick:()=>s(`dismissed`),children:i.actionDismiss})]})]})]})})}function R({onSubmit:e,busy:t=!1,disabled:n=!1,maxLength:r=4e3,inputRef:i,labels:o}){let s=a(o),c=O(),[l,d]=j(``),f=t||n||!l.trim();function p(){f||(e(l.trim()),d(``))}return P(`form`,{className:`wui-chat-composer d-flex align-items-end gap-2`,"aria-label":s.composer,onSubmit:e=>{e.preventDefault(),p()},children:[N(x,{id:`${c}-message`,"aria-label":s.composer,"aria-describedby":`${c}-hint`,placeholder:s.placeholder,rows:1,autoGrow:!0,maxLength:r,value:l,disabled:n,ref:i,fieldClassName:`flex-grow-1 mb-0`,onChange:e=>d(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),p())}}),N(`span`,{id:`${c}-hint`,className:`visually-hidden`,children:s.composerHint}),N(u,{type:`submit`,leftIcon:`send`,disabled:f,children:N(`span`,{className:`visually-hidden`,children:s.send})})]})}var z=new Intl.DateTimeFormat(`en-IN`,{day:`2-digit`,month:`numeric`,year:`numeric`,hour:`numeric`,minute:`2-digit`,hour12:!0,timeZoneName:`short`}),B=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`];function V(e){if(!e)return`-`;let t=new Date(e);if(Number.isNaN(t.getTime()))return`-`;let n=Object.fromEntries(z.formatToParts(t).map(e=>[e.type,e.value]));return`${n.day} ${B[Number(n.month)-1]} ${n.year}, ${n.hour}:${n.minute} ${n.dayPeriod.toLowerCase()} ${n.timeZoneName}`}function H({client:e,onOpen:t,onDeleted:n,pageSize:r=20,labels:i}){let o=a(i),[s,f]=j([]),[m,g]=j(!0),[_,v]=j(``),[b,x]=j(!1),[S,C]=j(0),[w,T]=j(null),[O,k]=j(!1),[A,M]=j(``),F=E(async t=>{g(!0),v(``);try{let n=await e.listConversations({skip:t,take:r});f(e=>t===0?n:[...e,...n]),x(n.length===r)}catch(e){v(e?.message||o.loadFailed)}finally{g(!1)}},[e,r,o.loadFailed]);D(()=>{F(0)},[F,S]);async function I(){k(!0),M(``);try{await e.deleteConversation(w.publicId),f(e=>e.filter(e=>e.publicId!==w.publicId)),n?.(w.publicId),T(null)}catch(e){M(e?.message||o.deleteFailed)}finally{k(!1)}}return!m&&!_&&s.length===0?N(h,{icon:`chat`,size:`sm`,title:o.conversationsEmptyTitle,text:o.conversationsEmptyText}):P(`div`,{className:`d-flex flex-column gap-3`,children:[_&&N(l,{variant:`danger`,action:N(u,{size:`sm`,variant:`secondary`,onClick:()=>C(e=>e+1),children:o.retry}),children:_}),s.length>0&&N(`ul`,{className:`list-unstyled d-flex flex-column gap-2 mb-0`,"aria-label":o.conversations,children:s.map(e=>N(`li`,{children:P(d,{padding:`sm`,className:`border`,bodyClassName:`d-flex align-items-center gap-2`,children:[N(u,{variant:`ghost`,className:`flex-grow-1 text-start`,style:{minWidth:0},onClick:()=>t(e),children:P(`span`,{className:`d-flex flex-column`,style:{minWidth:0},children:[N(`span`,{className:`text-truncate fw-semibold`,children:e.title||o.untitled}),N(`time`,{dateTime:e.lastMessageDateTimeUtc,className:`wui-text-xs text-body-secondary`,children:V(e.lastMessageDateTimeUtc)})]})}),N(c,{icon:`trash-2`,danger:!0,label:o.deleteConversation,onClick:()=>{M(``),T(e)}})]})},e.publicId))}),m&&P(`div`,{className:`d-flex flex-column gap-2`,"aria-hidden":`true`,children:[N(y,{height:44}),N(y,{height:44}),N(y,{height:44})]}),!m&&b&&N(u,{variant:`secondary`,className:`align-self-center`,onClick:()=>F(s.length),children:o.loadMore}),N(p,{open:w!==null,title:o.deleteConfirmTitle,message:A?N(l,{variant:`danger`,children:A}):o.deleteConfirmMessage,confirmLabel:o.deleteConfirm,cancelLabel:o.cancel,danger:!0,loading:O,onConfirm:I,onClose:()=>{O||T(null)}})]})}var U={zIndex:`var(--wui-z-fixed)`,bottom:`var(--wui-consent-banner-block, 0px)`},W={end:{insetInlineEnd:0},start:{insetInlineStart:0}};function G({onClick:e,open:t=!1,position:n=`end`,icon:r=`sparkles`,compact:i=!1,className:o,style:s,labels:c}){let l=a(c);return i?N(K,{onClick:e,open:t,position:n,icon:r,className:o,style:s,label:l.launcher}):N(`span`,{"data-support-capture":`exclude`,className:[`position-fixed m-3`,o].filter(Boolean).join(` `),style:{...U,...W[n],...s},children:N(u,{leftIcon:r,className:`rounded-pill`,onClick:e,"aria-haspopup":`dialog`,"aria-expanded":t,children:l.launcher})})}function K({onClick:e,open:t,position:n,icon:r,className:i,style:a,label:o}){let s=S(n);return s?F(N(`span`,{className:[`wui-floating-stack-item wui-floating-stack-item--primary`,i].filter(Boolean).join(` `),style:a,children:N(u,{className:`wui-floating-btn`,onClick:e,"aria-label":o,"aria-haspopup":`dialog`,"aria-expanded":t,tooltip:o,tooltipPlacement:n===`start`?`end`:`start`,children:N(g,{name:r,size:24})})}),s):null}function q({tokens:e,resolveLink:t,linkComponent:n}){return e.map(e=>{switch(e.type){case`code`:return N(`code`,{children:e.text},e.key);case`strong`:return N(`strong`,{children:N(q,{tokens:e.children,resolveLink:t,linkComponent:n})},e.key);case`em`:return N(`em`,{children:N(q,{tokens:e.children,resolveLink:t,linkComponent:n})},e.key);case`link`:{let r=N(q,{tokens:e.children,resolveLink:t,linkComponent:n}),a=i(e.href,t);return a?N(_,{href:a,linkComponent:n,animation:`static`,children:r},e.key):N(`span`,{children:r},e.key)}default:return N(C,{children:e.text},e.key)}})}function J({text:e,resolveLink:t,linkComponent:n}){return N(q,{tokens:s(e),resolveLink:t,linkComponent:n})}function te({block:e,resolveLink:t,linkComponent:n}){let r=e=>N(J,{text:e,resolveLink:t,linkComponent:n}),i=k(()=>e.type===`table`?{columns:e.header.map((e,r)=>({key:`c${r}`,label:N(J,{text:e,resolveLink:t,linkComponent:n}),render:e=>N(J,{text:e.cells[r]??``,resolveLink:t,linkComponent:n})})),rows:e.rows.map((e,t)=>({id:t,cells:e}))}:null,[e,t,n]);switch(e.type){case`heading`:return N(`p`,{className:`fw-semibold mb-2`,children:r(e.text)});case`rule`:return N(`hr`,{className:`my-2`});case`code`:return N(`pre`,{className:`wui-text-sm mb-2`,children:N(`code`,{children:e.text})});case`list`:{let t=e.items.map((e,t)=>N(`li`,{children:r(e)},t));return e.ordered?N(`ol`,{className:`mb-2 ps-4`,start:e.start===1?void 0:e.start,children:t}):N(`ul`,{className:`mb-2 ps-4`,children:t})}case`table`:return N(m,{columns:i.columns,rows:i.rows,density:`compact`,empty:null,wrapperClassName:`mb-2`});default:return N(`p`,{className:`mb-2`,children:e.lines.map((e,t)=>P(`span`,{children:[t>0&&N(`br`,{}),r(e)]},t))})}}function Y({text:e,resolveLink:t,linkComponent:n,className:r}){let i=k(()=>o(e),[e]);return N(`div`,{className:[`wui-text-sm text-break`,r].filter(Boolean).join(` `),children:i.map(e=>N(te,{block:e,resolveLink:t,linkComponent:n},e.key))})}function X({rating:e=null,onRate:t,noteMaxLength:n=1e3,labels:r}){let i=a(r),o=O(),[s,c]=j(!1),[d,f]=j(!1),[p,m]=j(``),[h,g]=j(``),[_,v]=j(!1);async function y(e,n){c(!0),g(``);try{await t(e,n),f(e===`Down`&&n===void 0),v(e===`Up`||n!==void 0),n!==void 0&&m(``)}catch{g(i.ratingFailed)}finally{c(!1)}}return P(`div`,{className:`d-flex flex-column gap-2`,children:[P(`div`,{className:`d-flex flex-wrap align-items-center gap-1`,children:[N(u,{size:`sm`,variant:e===`Up`?`neutral`:`ghost`,leftIcon:`check`,"aria-pressed":e===`Up`,disabled:s,onClick:()=>y(`Up`),children:i.rateUp}),N(u,{size:`sm`,variant:e===`Down`?`neutral`:`ghost`,leftIcon:`x`,"aria-pressed":e===`Down`,disabled:s,onClick:()=>y(`Down`),children:i.rateDown}),_&&!d&&N(`span`,{className:`wui-text-xs text-body-secondary`,role:`status`,children:i.rated})]}),h&&N(l,{size:`sm`,variant:`danger`,children:h}),d&&P(`form`,{className:`d-flex flex-column gap-2`,onSubmit:e=>{e.preventDefault(),y(`Down`,p)},children:[N(x,{id:`${o}-note`,label:i.ratingNote,hint:i.ratingNoteHint,rows:2,maxLength:n,value:p,onChange:e=>m(e.target.value)}),P(`div`,{className:`d-flex gap-2`,children:[N(u,{type:`submit`,size:`sm`,loading:s,children:i.ratingNoteSend}),N(u,{size:`sm`,variant:`secondary`,disabled:s,onClick:()=>{f(!1),v(!0)},children:i.ratingNoteSkip})]})]})]})}var ne={maxWidth:`85%`,whiteSpace:`pre-wrap`,overflowWrap:`anywhere`};function re({turn:e,onRate:t,resolveLink:n,linkComponent:r,confirmAction:i,onViewTicket:o,renderReply:s,labels:c}){let u=a(c),f=e.streaming&&!e.answer;return P(`li`,{className:`d-flex flex-column gap-2`,children:[e.question&&P(`div`,{className:`align-self-end`,style:ne,children:[P(`span`,{className:`visually-hidden`,children:[u.you,`: `]}),N(d,{padding:`sm`,variant:`muted`,className:`wui-text-sm`,children:e.question})]}),P(`div`,{className:`d-flex flex-column gap-2`,style:{minWidth:0},children:[P(`span`,{className:`visually-hidden`,children:[u.assistant,`: `]}),N(`div`,{"aria-live":`polite`,"aria-busy":e.streaming,children:f?P(`span`,{className:`d-inline-flex align-items-center gap-2 wui-text-sm text-body-secondary`,children:[N(b,{size:`sm`,label:u.thinking}),N(`span`,{"aria-hidden":`true`,children:u.thinking})]}):e.answer&&(s?s(e,{streaming:!!e.streaming}):N(Y,{text:e.answer,resolveLink:n,linkComponent:r}))}),e.error&&N(l,{size:`sm`,variant:`danger`,children:e.error.message}),i&&!e.streaming&&e.actions.map(e=>N(L,{action:e,confirmAction:i,onViewTicket:o,labels:c},e.token)),t&&e.messageId&&!e.streaming&&N(X,{rating:e.rating,onRate:(n,r)=>t(e.id,n,r),labels:c})]})]})}var Z=w(re);function ie(e){for(let t=e?.parentElement;t&&t!==document.body;t=t.parentElement){let{overflowY:e}=getComputedStyle(t);if((e===`auto`||e===`scroll`)&&t.scrollHeight>t.clientHeight)return t}return null}function Q({turns:e,empty:t,onRate:n,resolveLink:r,linkComponent:i,confirmAction:o,onViewTicket:s,renderReply:c,labels:l}){let u=a(l),d=A(null),f=e[e.length-1];return D(()=>{let e=ie(d.current);e&&(e.scrollTop=e.scrollHeight)},[e.length,f?.answer,f?.error,f?.actions]),e.length===0?t??N(h,{icon:`sparkles`,size:`sm`,title:u.emptyTitle,text:u.emptyText}):P(M,{children:[N(`ol`,{className:`list-unstyled d-flex flex-column gap-3 mb-0`,"aria-label":u.thread,children:e.map(e=>N(Z,{turn:e,onRate:n,resolveLink:r,linkComponent:i,confirmAction:o,onViewTicket:s,renderReply:c,labels:l},e.id))}),N(`div`,{ref:d})]})}function ae({chat:e,open:t,onClose:n,title:r,titleIcon:i=`sparkles`,headerActions:o,empty:s,disclaimer:u,maxLength:d=4e3,allowanceThreshold:f=10,width:p=`440px`,resolveLink:m,linkComponent:h,confirmAction:_,onViewTicket:y,rating:x=!0,renderReply:S,labels:C}){let w=a(C),T=A(null),{refreshAllowance:E}=e;D(()=>{t&&E().catch(()=>{})},[t,E]);let O=e.messagesLeftToday,k=r??w.panelTitle;return N(v,{show:t,onHide:n,side:`right`,width:p,header:P(`div`,{className:`drawer-header`,children:[P(`div`,{className:`drawer-title`,children:[i&&N(`span`,{className:`drawer-title-ic`,children:N(g,{name:i,size:18})}),k]}),P(`div`,{className:`d-flex align-items-center gap-1`,children:[o,N(c,{icon:`plus`,label:w.newChat,onClick:e.newConversation,disabled:e.turns.length===0&&!e.loading}),N(c,{icon:`x`,label:w.close,onClick:n})]})]}),footer:P(`div`,{className:`d-flex flex-column gap-2`,children:[O!==null&&O<=f&&N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,role:`status`,children:w.allowance(O)}),N(R,{onSubmit:e.submit,busy:e.streaming||e.loading,disabled:O===0,maxLength:d,inputRef:T,labels:C}),N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,children:u??w.disclaimer})]}),ariaLabel:typeof k==`string`?k:w.panelTitle,onEntered:()=>T.current?.focus(),children:e.loading?N(`div`,{className:`d-flex justify-content-center py-4`,children:N(b,{label:w.loadingConversation})}):e.loadError?N(l,{variant:`danger`,children:e.loadError.message}):N(Q,{turns:e.turns,empty:s,onRate:x?e.rate:void 0,resolveLink:m,linkComponent:h,confirmAction:_,onViewTicket:y,renderReply:S,labels:C})})}var oe=/\[([^[\]]*)\](?!\()/g;function se(e,t){let n=[],r=0;for(let i of e.matchAll(oe)){let a=i[1];a===``||!t(a)||(i.index>r&&n.push({text:e.slice(r,i.index)}),n.push({citation:a}),r=i.index+i[0].length)}return r<e.length&&n.push({text:e.slice(r)}),n}function ce({citation:e,label:t,ariaLabel:n,onOpen:r}){return N(f,{label:t??e,size:`sm`,tone:`primary`,variant:`outline`,leadingIcon:`book-1`,"aria-label":n??e,onClick:()=>r(e)})}function le({title:e,subtitle:t,lines:n,note:r,onConfirm:i,labels:o}){let s=a(o),[c,f]=j(`ready`),[p,m]=j(null),[h,g]=j(``);if(c===`dismissed`)return N(`p`,{className:`wui-text-sm text-body-secondary mb-0`,children:s.actionDismissed});if(c===`done`)return N(l,{variant:`success`,role:`status`,size:`sm`,children:p?.message||s.actionDone});async function _(){f(`sending`),g(``);try{let e=await i();m(e??null),f(`done`)}catch(e){g(e?.message||s.actionFailed),f(`ready`)}}let v=c===`sending`;return N(d,{padding:`sm`,className:`border`,title:e,subtitle:t||void 0,children:P(`div`,{className:`d-flex flex-column gap-2`,children:[(n??[]).map((e,t)=>N(`p`,{className:`wui-text-sm mb-0`,style:{whiteSpace:`pre-wrap`,overflowWrap:`anywhere`},children:e},t)),N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,children:r??s.actionNote}),h&&N(l,{size:`sm`,variant:`danger`,children:h}),P(`div`,{className:`d-flex flex-wrap gap-2`,children:[N(u,{size:`sm`,loading:v,onClick:_,children:s.actionConfirm}),N(u,{size:`sm`,variant:`secondary`,disabled:v,onClick:()=>f(`dismissed`),children:s.actionDismiss})]})]})})}function $(e){return{code:e?.code||`unknown`,message:e?.message||`Something went wrong. Please try again.`,resetsAtUtc:e?.resetsAtUtc??null}}function ue(e){if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?t:[]}function de(e){let t=[];for(let n of e??[]){if(n.role===`User`){t.push({id:n.publicId,question:n.content,answer:``,streaming:!1,step:null,error:null,actions:[],messageId:null,rating:null,ratingNote:null});continue}let e=t[t.length-1],r={answer:n.content,actions:ue(n.actionsJson),messageId:n.publicId,rating:n.rating??null,ratingNote:n.ratingNote??null};e&&e.messageId===null&&e.answer===``?Object.assign(e,r):t.push({id:n.publicId,question:``,streaming:!1,step:null,error:null,...r})}return t}function fe({client:e,pageContext:t}){let[n,r]=j([]),[i,a]=j(null),[o,s]=j(null),[c,l]=j(!1),[u,d]=j(null),f=A(null),p=A(0),m=A(0),h=A(t);h.current=t;let g=A(null);g.current=i;let _=A(n);_.current=n;let v=A(new Map),y=A(0),b=A(!1),x=E(()=>{let e=v.current;e.size!==0&&(v.current=new Map,T(()=>{r(t=>t.map(t=>e.has(t.id)?{...t,answer:t.answer+e.get(t.id),step:null}:t))}))},[]),S=E((e,t)=>{v.current.set(e,(v.current.get(e)??``)+t),!b.current&&(b.current=!0,y.current=requestAnimationFrame(()=>{b.current=!1,x()}))},[x]),C=E(()=>{x(),p.current+=1,f.current?.abort(),f.current=null},[x]);D(()=>C,[C]),D(()=>()=>{cancelAnimationFrame(y.current),b.current=!1},[]);let w=E((e,t)=>{r(n=>n.map(n=>n.id===e?{...n,...typeof t==`function`?t(n):t}:n))},[]),O=E(async t=>{let n=typeof t==`string`?t.trim():``;if(!n||f.current)return;let i=p.current,o=new AbortController;f.current=o,m.current+=1;let c=`turn-${m.current}`;r(e=>[...e,{id:c,question:n,answer:``,streaming:!0,step:null,error:null,actions:[],messageId:null,rating:null,ratingNote:null}]);let l=()=>i===p.current&&!o.signal.aborted;try{let t=await e.sendMessage({message:n,conversationId:g.current,pageContext:h.current},{signal:o.signal,onEvent:(e,t)=>{if(l()){if(e===`delta`){S(c,t?.text??``);return}x(),e===`reset`?w(c,{answer:``,step:null}):e===`tool`?w(c,{step:typeof t?.toolName==`string`&&t.toolName?t.toolName:null}):e===`actions`&&w(c,{actions:Array.isArray(t?.actions)?t.actions:[]})}}});if(x(),!l())return;w(c,{answer:t.reply,messageId:t.messageId??null,streaming:!1,step:null}),g.current=t.conversationId,a(t.conversationId),s(t.messagesLeftToday??null)}catch(e){if(x(),!l())return;w(c,{answer:``,actions:[],streaming:!1,step:null,error:$(e)}),e?.code===`daily_limit`&&s(0),e?.code===`conversation_not_found`&&(g.current=null,a(null))}finally{f.current===o&&(f.current=null)}},[e,w,x,S]),k=E(async t=>{C();let n=p.current;r([]),a(null),d(null),l(!0);try{let i=await e.getConversation(t);if(n!==p.current)return;r(de(i.messages)),a(i.publicId)}catch(e){if(n!==p.current)return;d($(e))}finally{n===p.current&&l(!1)}},[C,e]),M=E(()=>{C(),r([]),a(null),d(null),l(!1)},[C]),N=E(()=>{C(),r([]),a(null),s(null),d(null),l(!1)},[C]),P=E(async()=>{let t=p.current,n=await e.getAllowance();t===p.current&&s(n?.messagesLeftToday??null)},[e]),F=E(async(t,n,r)=>{let i=_.current.find(e=>e.id===t),a=g.current;if(!i?.messageId||!a)throw Error(`Only a stored reply can be rated.`);let o={rating:i.rating,ratingNote:i.ratingNote},s=typeof r==`string`&&r.trim()?r.trim():null;w(t,{rating:n,ratingNote:s});try{await e.rateMessage(a,i.messageId,{rating:n,note:s})}catch(e){throw w(t,o),e}},[e,w]);return{turns:n,conversationId:i,messagesLeftToday:o,streaming:n.some(e=>e.streaming),loading:c,loadError:u,submit:O,openConversation:k,newConversation:M,rate:F,refreshAllowance:P,reset:N}}export{L as ActionCard,e as ChatApiError,R as ChatComposer,H as ChatConversationList,G as ChatLauncher,Y as ChatMarkdown,Z as ChatMessage,ae as ChatPanel,Q as ChatThread,ce as CitationChip,le as ConfirmCard,t as DEFAULT_CHAT_LABELS,X as ReplyRating,n as createChatClient,r as createSseParser,se as splitCitations,fe as useChat};
|
|
1
|
+
import{ChatApiError as e,DEFAULT_CHAT_LABELS as t,createChatClient as n,createSseParser as r,linkRoute as i,mergeLabels as a,parseBlocks as o,parseInline as s}from"@webority/ui-elements/chat-core";import{AppActionIcon as c,AppAlert as l,AppButton as u,AppCard as d,AppChip as f,AppConfirmDialog as p,AppDataTable as m,AppEmptyState as h,AppIcon as g,AppLink as _,AppSidebarMenu as v,AppSkeleton as y,AppSpinner as b,AppTextarea as x,useFloatingStack as S}from"@webority/ui-react";import{Fragment as C,memo as w,startTransition as T,useCallback as E,useEffect as D,useId as O,useMemo as k,useRef as A,useState as j}from"react";import{Fragment as M,jsx as N,jsxs as P}from"react/jsx-runtime";import{createPortal as F}from"react-dom";function I(e,t){return e.kind===`Reply`?t.actionReply(e.ticketNumber):e.kind===`Reopen`?t.actionReopen(e.ticketNumber):t.actionRaiseTicket}function ee(e,t,n){return e===`Reply`?n.actionDoneReply(t):e===`Reopen`?n.actionDoneReopen(t):n.actionDoneRaiseTicket(t)}function L({action:e,confirmAction:t,onViewTicket:n,labels:r}){let i=a(r),[o,s]=j(`ready`),[c,f]=j(null),[p,m]=j(``);if(o===`dismissed`)return N(`p`,{className:`wui-text-sm text-body-secondary mb-0`,children:i.actionDismissed});if(o===`done`)return N(l,{variant:`success`,role:`status`,size:`sm`,action:n?N(u,{size:`sm`,variant:`ghost`,onClick:()=>n(c),children:i.viewTicket}):void 0,children:ee(e.kind,c.number,i)});async function h(){s(`sending`),m(``);try{f(await t(e.token)),s(`done`)}catch(e){m(e?.message||i.actionFailed),s(`ready`)}}let g=o===`sending`,_=new Date(e.expiresDateTimeUtc).getTime()<=Date.now(),v=e.kind===`RaiseTicket`?[e.category,e.subject].filter(Boolean).join(` · `):``;return N(d,{padding:`sm`,className:`border`,title:I(e,i),subtitle:v||void 0,children:P(`div`,{className:`d-flex flex-column gap-2`,children:[e.kind!==`Reopen`&&e.body&&N(`p`,{className:`wui-text-sm mb-0`,style:{whiteSpace:`pre-wrap`,overflowWrap:`anywhere`},children:e.body}),_?N(`p`,{className:`wui-text-sm text-body-secondary mb-0`,children:i.actionExpired}):P(M,{children:[N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,children:i.actionNote}),p&&N(l,{size:`sm`,variant:`danger`,children:p}),P(`div`,{className:`d-flex flex-wrap gap-2`,children:[N(u,{size:`sm`,loading:g,onClick:h,children:i.actionConfirm}),N(u,{size:`sm`,variant:`secondary`,disabled:g,onClick:()=>s(`dismissed`),children:i.actionDismiss})]})]})]})})}function R({onSubmit:e,busy:t=!1,disabled:n=!1,maxLength:r=4e3,inputRef:i,labels:o}){let s=a(o),c=O(),[l,d]=j(``),f=t||n||!l.trim();function p(){f||(e(l.trim()),d(``))}return P(`form`,{className:`wui-chat-composer d-flex align-items-end gap-2`,"aria-label":s.composer,onSubmit:e=>{e.preventDefault(),p()},children:[N(x,{id:`${c}-message`,"aria-label":s.composer,"aria-describedby":`${c}-hint`,placeholder:s.placeholder,rows:1,autoGrow:!0,maxLength:r,value:l,disabled:n,ref:i,fieldClassName:`flex-grow-1 mb-0`,onChange:e=>d(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),p())}}),N(`span`,{id:`${c}-hint`,className:`visually-hidden`,children:s.composerHint}),N(u,{type:`submit`,leftIcon:`send`,disabled:f,children:N(`span`,{className:`visually-hidden`,children:s.send})})]})}var z=new Intl.DateTimeFormat(`en-IN`,{day:`2-digit`,month:`numeric`,year:`numeric`,hour:`numeric`,minute:`2-digit`,hour12:!0,timeZoneName:`short`}),B=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`];function V(e){if(!e)return`-`;let t=new Date(e);if(Number.isNaN(t.getTime()))return`-`;let n=Object.fromEntries(z.formatToParts(t).map(e=>[e.type,e.value]));return`${n.day} ${B[Number(n.month)-1]} ${n.year}, ${n.hour}:${n.minute} ${n.dayPeriod.toLowerCase()} ${n.timeZoneName}`}function H({client:e,onOpen:t,onDeleted:n,pageSize:r=20,labels:i}){let o=a(i),[s,f]=j([]),[m,g]=j(!0),[_,v]=j(``),[b,x]=j(!1),[S,C]=j(0),[w,T]=j(null),[O,k]=j(!1),[A,M]=j(``),F=E(async t=>{g(!0),v(``);try{let n=await e.listConversations({skip:t,take:r});f(e=>t===0?n:[...e,...n]),x(n.length===r)}catch(e){v(e?.message||o.loadFailed)}finally{g(!1)}},[e,r,o.loadFailed]);D(()=>{F(0)},[F,S]);async function I(){k(!0),M(``);try{await e.deleteConversation(w.publicId),f(e=>e.filter(e=>e.publicId!==w.publicId)),n?.(w.publicId),T(null)}catch(e){M(e?.message||o.deleteFailed)}finally{k(!1)}}return!m&&!_&&s.length===0?N(h,{icon:`chat`,size:`sm`,title:o.conversationsEmptyTitle,text:o.conversationsEmptyText}):P(`div`,{className:`d-flex flex-column gap-3`,children:[_&&N(l,{variant:`danger`,action:N(u,{size:`sm`,variant:`secondary`,onClick:()=>C(e=>e+1),children:o.retry}),children:_}),s.length>0&&N(`ul`,{className:`list-unstyled d-flex flex-column gap-2 mb-0`,"aria-label":o.conversations,children:s.map(e=>N(`li`,{children:P(d,{padding:`sm`,className:`border`,bodyClassName:`d-flex align-items-center gap-2`,children:[N(u,{variant:`ghost`,className:`flex-grow-1 text-start`,style:{minWidth:0},onClick:()=>t(e),children:P(`span`,{className:`d-flex flex-column`,style:{minWidth:0},children:[N(`span`,{className:`text-truncate fw-semibold`,children:e.title||o.untitled}),N(`time`,{dateTime:e.lastMessageDateTimeUtc,className:`wui-text-xs text-body-secondary`,children:V(e.lastMessageDateTimeUtc)})]})}),N(c,{icon:`trash-2`,danger:!0,label:o.deleteConversation,onClick:()=>{M(``),T(e)}})]})},e.publicId))}),m&&P(`div`,{className:`d-flex flex-column gap-2`,"aria-hidden":`true`,children:[N(y,{height:44}),N(y,{height:44}),N(y,{height:44})]}),!m&&b&&N(u,{variant:`secondary`,className:`align-self-center`,onClick:()=>F(s.length),children:o.loadMore}),N(p,{open:w!==null,title:o.deleteConfirmTitle,message:A?N(l,{variant:`danger`,children:A}):o.deleteConfirmMessage,confirmLabel:o.deleteConfirm,cancelLabel:o.cancel,danger:!0,loading:O,onConfirm:I,onClose:()=>{O||T(null)}})]})}var U={zIndex:`var(--wui-z-fixed)`,bottom:`var(--wui-consent-banner-block, 0px)`},W={end:{insetInlineEnd:0},start:{insetInlineStart:0}};function G({onClick:e,open:t=!1,position:n=`end`,icon:r=`sparkles`,compact:i=!1,className:o,style:s,labels:c}){let l=a(c);return i?N(K,{onClick:e,open:t,position:n,icon:r,className:o,style:s,label:l.launcher}):N(`span`,{"data-support-capture":`exclude`,className:[`position-fixed m-3`,o].filter(Boolean).join(` `),style:{...U,...W[n],...s},children:N(u,{leftIcon:r,className:`rounded-pill`,onClick:e,"aria-haspopup":`dialog`,"aria-expanded":t,children:l.launcher})})}function K({onClick:e,open:t,position:n,icon:r,className:i,style:a,label:o}){let s=S(n);return s?F(N(`span`,{className:[`wui-floating-stack-item wui-floating-stack-item--primary`,i].filter(Boolean).join(` `),style:a,children:N(u,{className:`wui-floating-btn`,onClick:e,"aria-label":o,"aria-haspopup":`dialog`,"aria-expanded":t,tooltip:o,tooltipPlacement:n===`start`?`end`:`start`,children:N(g,{name:r,size:24})})}),s):null}function q({tokens:e,resolveLink:t,linkComponent:n}){return e.map(e=>{switch(e.type){case`code`:return N(`code`,{children:e.text},e.key);case`strong`:return N(`strong`,{children:N(q,{tokens:e.children,resolveLink:t,linkComponent:n})},e.key);case`em`:return N(`em`,{children:N(q,{tokens:e.children,resolveLink:t,linkComponent:n})},e.key);case`link`:{let r=N(q,{tokens:e.children,resolveLink:t,linkComponent:n}),a=i(e.href,t);return a?N(_,{href:a,linkComponent:n,animation:`static`,children:r},e.key):N(`span`,{children:r},e.key)}default:return N(C,{children:e.text},e.key)}})}function J({text:e,resolveLink:t,linkComponent:n}){return N(q,{tokens:s(e),resolveLink:t,linkComponent:n})}function te({block:e,resolveLink:t,linkComponent:n}){let r=e=>N(J,{text:e,resolveLink:t,linkComponent:n}),i=k(()=>e.type===`table`?{columns:e.header.map((e,r)=>({key:`c${r}`,label:N(J,{text:e,resolveLink:t,linkComponent:n}),render:e=>N(J,{text:e.cells[r]??``,resolveLink:t,linkComponent:n})})),rows:e.rows.map((e,t)=>({id:t,cells:e}))}:null,[e,t,n]);switch(e.type){case`heading`:return N(`p`,{className:`fw-semibold mb-2`,children:r(e.text)});case`rule`:return N(`hr`,{className:`my-2`});case`code`:return N(`pre`,{className:`wui-text-sm mb-2`,children:N(`code`,{children:e.text})});case`list`:{let t=e.items.map((e,t)=>N(`li`,{children:r(e)},t));return e.ordered?N(`ol`,{className:`mb-2 ps-4`,start:e.start===1?void 0:e.start,children:t}):N(`ul`,{className:`mb-2 ps-4`,children:t})}case`table`:return N(m,{columns:i.columns,rows:i.rows,density:`compact`,empty:null,wrapperClassName:`mb-2`});default:return N(`p`,{className:`mb-2`,children:e.lines.map((e,t)=>P(`span`,{children:[t>0&&N(`br`,{}),r(e)]},t))})}}function Y({text:e,resolveLink:t,linkComponent:n,className:r}){let i=k(()=>o(e),[e]);return N(`div`,{className:[`wui-text-sm text-break`,r].filter(Boolean).join(` `),children:i.map(e=>N(te,{block:e,resolveLink:t,linkComponent:n},e.key))})}function X({rating:e,onRate:t,noteMaxLength:n=1e3,labels:r}){let i=a(r),o=O(),[s,c]=j(!1),[d,f]=j(!1),[p,m]=j(``),[h,g]=j(``),[_,v]=j(!1);async function y(e,n){c(!0),g(``);try{await t(e,n),f(e===`Down`&&n===void 0),v(e===`Up`||n!==void 0),n!==void 0&&m(``)}catch{g(i.ratingFailed)}finally{c(!1)}}return P(`div`,{className:`d-flex flex-column gap-2`,children:[P(`div`,{className:`d-flex flex-wrap align-items-center gap-1`,children:[N(u,{size:`sm`,variant:e===`Up`?`neutral`:`ghost`,leftIcon:`check`,"aria-pressed":e===`Up`,disabled:s,onClick:()=>y(`Up`),children:i.rateUp}),N(u,{size:`sm`,variant:e===`Down`?`neutral`:`ghost`,leftIcon:`x`,"aria-pressed":e===`Down`,disabled:s,onClick:()=>y(`Down`),children:i.rateDown}),_&&!d&&N(`span`,{className:`wui-text-xs text-body-secondary`,role:`status`,children:i.rated})]}),h&&N(l,{size:`sm`,variant:`danger`,children:h}),d&&P(`form`,{className:`d-flex flex-column gap-2`,onSubmit:e=>{e.preventDefault(),y(`Down`,p)},children:[N(x,{id:`${o}-note`,label:i.ratingNote,hint:i.ratingNoteHint,rows:2,maxLength:n,value:p,onChange:e=>m(e.target.value)}),P(`div`,{className:`d-flex gap-2`,children:[N(u,{type:`submit`,size:`sm`,loading:s,children:i.ratingNoteSend}),N(u,{size:`sm`,variant:`secondary`,disabled:s,onClick:()=>{f(!1),v(!0)},children:i.ratingNoteSkip})]})]})]})}var ne={maxWidth:`85%`,whiteSpace:`pre-wrap`,overflowWrap:`anywhere`};function re({turn:e,onRate:t,resolveLink:n,linkComponent:r,confirmAction:i,onViewTicket:o,renderReply:s,labels:c}){let u=a(c),f=e.streaming&&!e.answer;return P(`li`,{className:`d-flex flex-column gap-2`,children:[e.question&&P(`div`,{className:`align-self-end`,style:ne,children:[P(`span`,{className:`visually-hidden`,children:[u.you,`: `]}),N(d,{padding:`sm`,variant:`muted`,className:`wui-text-sm`,children:e.question})]}),P(`div`,{className:`d-flex flex-column gap-2`,style:{minWidth:0},children:[P(`span`,{className:`visually-hidden`,children:[u.assistant,`: `]}),N(`div`,{"aria-live":`polite`,"aria-busy":e.streaming,children:f?P(`span`,{className:`d-inline-flex align-items-center gap-2 wui-text-sm text-body-secondary`,children:[N(b,{size:`sm`,label:u.thinking}),N(`span`,{"aria-hidden":`true`,children:u.thinking})]}):e.answer&&(s?s(e,{streaming:!!e.streaming}):N(Y,{text:e.answer,resolveLink:n,linkComponent:r}))}),e.error&&N(l,{size:`sm`,variant:`danger`,children:e.error.message}),i&&!e.streaming&&e.actions.map(e=>N(L,{action:e,confirmAction:i,onViewTicket:o,labels:c},e.token)),t&&e.messageId&&!e.streaming&&N(X,{rating:e.rating,onRate:(n,r)=>t(e.id,n,r),labels:c})]})]})}var Z=w(re);function ie(e){for(let t=e?.parentElement;t&&t!==document.body;t=t.parentElement){let{overflowY:e}=getComputedStyle(t);if((e===`auto`||e===`scroll`)&&t.scrollHeight>t.clientHeight)return t}return null}function Q({turns:e,empty:t,onRate:n,resolveLink:r,linkComponent:i,confirmAction:o,onViewTicket:s,renderReply:c,labels:l}){let u=a(l),d=A(null),f=e[e.length-1];return D(()=>{let e=ie(d.current);e&&(e.scrollTop=e.scrollHeight)},[e.length,f?.answer,f?.error,f?.actions]),e.length===0?t??N(h,{icon:`sparkles`,size:`sm`,title:u.emptyTitle,text:u.emptyText}):P(M,{children:[N(`ol`,{className:`list-unstyled d-flex flex-column gap-3 mb-0`,"aria-label":u.thread,children:e.map(e=>N(Z,{turn:e,onRate:n,resolveLink:r,linkComponent:i,confirmAction:o,onViewTicket:s,renderReply:c,labels:l},e.id))}),N(`div`,{ref:d})]})}function ae({chat:e,open:t,onClose:n,title:r,titleIcon:i=`sparkles`,headerActions:o,empty:s,disclaimer:u,maxLength:d=4e3,allowanceThreshold:f=10,width:p=`440px`,resolveLink:m,linkComponent:h,confirmAction:_,onViewTicket:y,rating:x=!0,renderReply:S,labels:C}){let w=a(C),T=A(null),{refreshAllowance:E}=e;D(()=>{t&&E().catch(()=>{})},[t,E]);let O=e.messagesLeftToday,k=r??w.panelTitle;return N(v,{show:t,onHide:n,side:`right`,width:p,header:P(`div`,{className:`drawer-header`,children:[P(`div`,{className:`drawer-title`,children:[i&&N(`span`,{className:`drawer-title-ic`,children:N(g,{name:i,size:18})}),k]}),P(`div`,{className:`d-flex align-items-center gap-1`,children:[o,N(c,{icon:`plus`,label:w.newChat,onClick:e.newConversation,disabled:e.turns.length===0&&!e.loading}),N(c,{icon:`x`,label:w.close,onClick:n})]})]}),footer:P(`div`,{className:`d-flex flex-column gap-2`,children:[O!==null&&O<=f&&N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,role:`status`,children:w.allowance(O)}),N(R,{onSubmit:e.submit,busy:e.streaming||e.loading,disabled:O===0,maxLength:d,inputRef:T,labels:C}),N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,children:u??w.disclaimer})]}),ariaLabel:typeof k==`string`?k:w.panelTitle,onEntered:()=>T.current?.focus(),children:e.loading?N(`div`,{className:`d-flex justify-content-center py-4`,children:N(b,{label:w.loadingConversation})}):e.loadError?N(l,{variant:`danger`,children:e.loadError.message}):N(Q,{turns:e.turns,empty:s,onRate:x?e.rate:void 0,resolveLink:m,linkComponent:h,confirmAction:_,onViewTicket:y,renderReply:S,labels:C})})}var oe=/\[([^[\]]*)\](?!\()/g;function se(e,t){let n=[],r=0;for(let i of e.matchAll(oe)){let a=i[1];a===``||!t(a)||(i.index>r&&n.push({text:e.slice(r,i.index)}),n.push({citation:a}),r=i.index+i[0].length)}return r<e.length&&n.push({text:e.slice(r)}),n}function ce({citation:e,label:t,ariaLabel:n,onOpen:r}){return N(f,{label:t??e,size:`sm`,tone:`primary`,variant:`outline`,leadingIcon:`book-1`,"aria-label":n??e,onClick:()=>r(e)})}function le({title:e,subtitle:t,lines:n,note:r,onConfirm:i,labels:o}){let s=a(o),[c,f]=j(`ready`),[p,m]=j(null),[h,g]=j(``);if(c===`dismissed`)return N(`p`,{className:`wui-text-sm text-body-secondary mb-0`,children:s.actionDismissed});if(c===`done`)return N(l,{variant:`success`,role:`status`,size:`sm`,children:p?.message||s.actionDone});async function _(){f(`sending`),g(``);try{let e=await i();m(e??null),f(`done`)}catch(e){g(e?.message||s.actionFailed),f(`ready`)}}let v=c===`sending`;return N(d,{padding:`sm`,className:`border`,title:e,subtitle:t||void 0,children:P(`div`,{className:`d-flex flex-column gap-2`,children:[(n??[]).map((e,t)=>N(`p`,{className:`wui-text-sm mb-0`,style:{whiteSpace:`pre-wrap`,overflowWrap:`anywhere`},children:e},t)),N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,children:r??s.actionNote}),h&&N(l,{size:`sm`,variant:`danger`,children:h}),P(`div`,{className:`d-flex flex-wrap gap-2`,children:[N(u,{size:`sm`,loading:v,onClick:_,children:s.actionConfirm}),N(u,{size:`sm`,variant:`secondary`,disabled:v,onClick:()=>f(`dismissed`),children:s.actionDismiss})]})]})})}function $(e){return{code:e?.code||`unknown`,message:e?.message||`Something went wrong. Please try again.`,resetsAtUtc:e?.resetsAtUtc??null}}function ue(e){if(!e)return[];let t=JSON.parse(e);return Array.isArray(t)?t:[]}function de(e){let t=[];for(let n of e??[]){if(n.role===`User`){t.push({id:n.publicId,question:n.content,answer:``,streaming:!1,step:null,error:null,actions:[],messageId:null,rating:null,ratingNote:null});continue}let e=t[t.length-1],r={answer:n.content,actions:ue(n.actionsJson),messageId:n.publicId,rating:n.rating??null,ratingNote:n.ratingNote??null};e&&e.messageId===null&&e.answer===``?Object.assign(e,r):t.push({id:n.publicId,question:``,streaming:!1,step:null,error:null,...r})}return t}function fe({client:e,pageContext:t}){let[n,r]=j([]),[i,a]=j(null),[o,s]=j(null),[c,l]=j(!1),[u,d]=j(null),f=A(null),p=A(0),m=A(0),h=A(t);h.current=t;let g=A(null);g.current=i;let _=A(n);_.current=n;let v=A(new Map),y=A(0),b=A(!1),x=E(()=>{let e=v.current;e.size!==0&&(v.current=new Map,T(()=>{r(t=>t.map(t=>e.has(t.id)?{...t,answer:t.answer+e.get(t.id),step:null}:t))}))},[]),S=E((e,t)=>{v.current.set(e,(v.current.get(e)??``)+t),!b.current&&(b.current=!0,y.current=requestAnimationFrame(()=>{b.current=!1,x()}))},[x]),C=E(()=>{x(),p.current+=1,f.current?.abort(),f.current=null},[x]);D(()=>C,[C]),D(()=>()=>{cancelAnimationFrame(y.current),b.current=!1},[]);let w=E((e,t)=>{r(n=>n.map(n=>n.id===e?{...n,...typeof t==`function`?t(n):t}:n))},[]),O=E(async t=>{let n=typeof t==`string`?t.trim():``;if(!n||f.current)return;let i=p.current,o=new AbortController;f.current=o,m.current+=1;let c=`turn-${m.current}`;r(e=>[...e,{id:c,question:n,answer:``,streaming:!0,step:null,error:null,actions:[],messageId:null,rating:null,ratingNote:null}]);let l=()=>i===p.current&&!o.signal.aborted;try{let t=await e.sendMessage({message:n,conversationId:g.current,pageContext:h.current},{signal:o.signal,onEvent:(e,t)=>{if(l()){if(e===`delta`){S(c,t?.text??``);return}x(),e===`reset`?w(c,{answer:``,step:null}):e===`tool`?w(c,{step:typeof t?.toolName==`string`&&t.toolName?t.toolName:null}):e===`actions`&&w(c,{actions:Array.isArray(t?.actions)?t.actions:[]})}}});if(x(),!l())return;w(c,{answer:t.reply,messageId:t.messageId??null,streaming:!1,step:null}),g.current=t.conversationId,a(t.conversationId),s(t.messagesLeftToday??null)}catch(e){if(x(),!l())return;w(c,{answer:``,actions:[],streaming:!1,step:null,error:$(e)}),e?.code===`daily_limit`&&s(0),e?.code===`conversation_not_found`&&(g.current=null,a(null))}finally{f.current===o&&(f.current=null)}},[e,w,x,S]),k=E(async t=>{C();let n=p.current;r([]),a(null),d(null),l(!0);try{let i=await e.getConversation(t);if(n!==p.current)return;r(de(i.messages)),a(i.publicId)}catch(e){if(n!==p.current)return;d($(e))}finally{n===p.current&&l(!1)}},[C,e]),M=E(()=>{C(),r([]),a(null),d(null),l(!1)},[C]),N=E(()=>{C(),r([]),a(null),s(null),d(null),l(!1)},[C]),P=E(async()=>{let t=p.current,n=await e.getAllowance();t===p.current&&s(n?.messagesLeftToday??null)},[e]),F=E(async(t,n,r)=>{let i=_.current.find(e=>e.id===t),a=g.current;if(!i?.messageId||!a)throw Error(`Only a stored reply can be rated.`);let o={rating:i.rating,ratingNote:i.ratingNote},s=typeof r==`string`&&r.trim()?r.trim():null;w(t,{rating:n,ratingNote:s});try{await e.rateMessage(a,i.messageId,{rating:n,note:s})}catch(e){throw w(t,o),e}},[e,w]);return{turns:n,conversationId:i,messagesLeftToday:o,streaming:n.some(e=>e.streaming),loading:c,loadError:u,submit:O,openConversation:k,newConversation:M,rate:F,refreshAllowance:P,reset:N}}export{L as ActionCard,e as ChatApiError,R as ChatComposer,H as ChatConversationList,G as ChatLauncher,Y as ChatMarkdown,Z as ChatMessage,ae as ChatPanel,Q as ChatThread,ce as CitationChip,le as ConfirmCard,t as DEFAULT_CHAT_LABELS,X as ReplyRating,n as createChatClient,r as createSseParser,se as splitCitations,fe as useChat};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": "webority-guidance/1",
|
|
3
|
+
"package": {
|
|
4
|
+
"name": "@webority/chat-react",
|
|
5
|
+
"version": "0.89.0"
|
|
6
|
+
},
|
|
7
|
+
"components": [
|
|
8
|
+
{
|
|
9
|
+
"name": "ActionCard",
|
|
10
|
+
"usage": {
|
|
11
|
+
"when": [
|
|
12
|
+
"One support action the assistant prepared, shown under its reply for the person to confirm before anything reaches support."
|
|
13
|
+
],
|
|
14
|
+
"whenNot": [],
|
|
15
|
+
"do": [],
|
|
16
|
+
"dont": [],
|
|
17
|
+
"a11y": [
|
|
18
|
+
"The done message is an alert with role status, so it is announced when the ticket is raised.",
|
|
19
|
+
"Confirm and Not now are native buttons with text labels, and Not now is disabled while the request is sending.",
|
|
20
|
+
"A failed confirm shows its message in a danger alert and puts the card back to ready so the person can try again."
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "ChatComposer",
|
|
26
|
+
"usage": {
|
|
27
|
+
"when": [
|
|
28
|
+
"The question box where the person types a question for the assistant: Enter sends it and Shift and Enter starts a new line."
|
|
29
|
+
],
|
|
30
|
+
"whenNot": [],
|
|
31
|
+
"do": [],
|
|
32
|
+
"dont": [],
|
|
33
|
+
"a11y": [
|
|
34
|
+
"The form and its text box are both named by the composer label.",
|
|
35
|
+
"The text box is described by a visually hidden hint, so the Enter and Shift and Enter keys are announced.",
|
|
36
|
+
"Send is a submit button whose only text is the visually hidden send label next to a send icon, and it is disabled while busy, disabled or empty."
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "ChatConversationList",
|
|
42
|
+
"usage": {
|
|
43
|
+
"when": [
|
|
44
|
+
"The person's past chats, newest first, for a past-chats page or a panel."
|
|
45
|
+
],
|
|
46
|
+
"whenNot": [],
|
|
47
|
+
"do": [],
|
|
48
|
+
"dont": [],
|
|
49
|
+
"a11y": [
|
|
50
|
+
"The chats are a list named by the conversations label.",
|
|
51
|
+
"Each chat is a button showing its title and a time element that carries the date, and the delete icon button is named by the delete label.",
|
|
52
|
+
"Deleting asks for confirmation in a dialog first, and the loading skeleton is hidden from assistive technology."
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "ChatLauncher",
|
|
58
|
+
"usage": {
|
|
59
|
+
"when": [
|
|
60
|
+
"The floating pill that opens the assistant, pinned to a bottom corner."
|
|
61
|
+
],
|
|
62
|
+
"whenNot": [],
|
|
63
|
+
"do": [],
|
|
64
|
+
"dont": [],
|
|
65
|
+
"a11y": [
|
|
66
|
+
"The button announces that it opens a dialog (aria-haspopup) and whether it is open (aria-expanded).",
|
|
67
|
+
"The default pill shows the launcher label as its button text.",
|
|
68
|
+
"The compact circle takes the launcher label as its accessible name and as its tooltip."
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "ChatMarkdown",
|
|
74
|
+
"usage": {
|
|
75
|
+
"when": [
|
|
76
|
+
"A chat reply is written in Markdown and must render as text, never as HTML.",
|
|
77
|
+
"A reply may point at in-app records, and the host decides which links become routes."
|
|
78
|
+
],
|
|
79
|
+
"whenNot": [],
|
|
80
|
+
"do": [],
|
|
81
|
+
"dont": [],
|
|
82
|
+
"a11y": [
|
|
83
|
+
"Lists render as real ordered and unordered lists, and tables render through AppDataTable.",
|
|
84
|
+
"A link renders only when the host maps it to a route; any other link shows its label as plain text.",
|
|
85
|
+
"Headings render as bold lines, not heading elements, so a reply does not change the page outline."
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "ChatMessage",
|
|
91
|
+
"usage": {
|
|
92
|
+
"when": [
|
|
93
|
+
"Show one question and its answer inside a chat thread.",
|
|
94
|
+
"Draw a single stored or streaming turn on its own, such as in a history view."
|
|
95
|
+
],
|
|
96
|
+
"whenNot": [
|
|
97
|
+
{
|
|
98
|
+
"text": "Showing the whole conversation, oldest turn first, with the newest text kept in view.",
|
|
99
|
+
"instead": "ChatThread"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"do": [],
|
|
103
|
+
"dont": [],
|
|
104
|
+
"a11y": [
|
|
105
|
+
"The answer sits in a polite live region, so a screen reader reads it once it settles; it is marked busy while it streams.",
|
|
106
|
+
"Visually hidden labels name who is speaking, taken from the You and Assistant labels.",
|
|
107
|
+
"While the first text is awaited, a spinner carries the Thinking label."
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "ChatPanel",
|
|
113
|
+
"usage": {
|
|
114
|
+
"when": [
|
|
115
|
+
"Offer the assistant as a drawer that opens from a launcher.",
|
|
116
|
+
"Show the conversation, the question box, the questions left today and the footnote in one place."
|
|
117
|
+
],
|
|
118
|
+
"whenNot": [
|
|
119
|
+
{
|
|
120
|
+
"text": "Showing only the conversation inside a page.",
|
|
121
|
+
"instead": "ChatThread"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
"do": [],
|
|
125
|
+
"dont": [],
|
|
126
|
+
"a11y": [
|
|
127
|
+
"Focus stays inside the drawer while it is open, Escape closes it, and the question box takes focus when it opens.",
|
|
128
|
+
"The drawer is named by its title.",
|
|
129
|
+
"The questions left note is a status region."
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "ChatThread",
|
|
135
|
+
"usage": {
|
|
136
|
+
"when": [
|
|
137
|
+
"Show a whole conversation, oldest turn first, in a panel or a page.",
|
|
138
|
+
"Let the thread follow the newest text as an answer streams."
|
|
139
|
+
],
|
|
140
|
+
"whenNot": [
|
|
141
|
+
{
|
|
142
|
+
"text": "Showing one turn on its own.",
|
|
143
|
+
"instead": "ChatMessage"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"text": "Showing the full assistant drawer with its header and question box.",
|
|
147
|
+
"instead": "ChatPanel"
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
"do": [],
|
|
151
|
+
"dont": [],
|
|
152
|
+
"a11y": [
|
|
153
|
+
"The turns are an ordered list named by the thread label.",
|
|
154
|
+
"Each answer is a polite live region; see ChatMessage.",
|
|
155
|
+
"Only the nearest box that scrolls on its own follows the newest text, so the page itself never jumps."
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"name": "CitationChip",
|
|
161
|
+
"usage": {
|
|
162
|
+
"when": [
|
|
163
|
+
"Show a source the assistant named in a reply as a small chip the person can select to open it.",
|
|
164
|
+
"Pair it with splitCitations to turn [source] runs in reply text into chips."
|
|
165
|
+
],
|
|
166
|
+
"whenNot": [
|
|
167
|
+
{
|
|
168
|
+
"text": "Showing a general label or removable token that is not a source.",
|
|
169
|
+
"instead": "AppChip"
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
"do": [],
|
|
173
|
+
"dont": [],
|
|
174
|
+
"a11y": [
|
|
175
|
+
"The chip is a button named by ariaLabel, or by the citation when none is given.",
|
|
176
|
+
"Selecting it by pointer or keyboard calls onOpen with the citation."
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"name": "ConfirmCard",
|
|
182
|
+
"usage": {
|
|
183
|
+
"when": [
|
|
184
|
+
"The assistant has prepared an action and nothing should happen until the person says yes.",
|
|
185
|
+
"The action is one step the person can send now or decline."
|
|
186
|
+
],
|
|
187
|
+
"whenNot": [],
|
|
188
|
+
"do": [],
|
|
189
|
+
"dont": [],
|
|
190
|
+
"a11y": [
|
|
191
|
+
"Confirm and Not now are native buttons, and Confirm shows its loading state while the action is sent.",
|
|
192
|
+
"The done message is a status message.",
|
|
193
|
+
"A failed confirm shows its message in an alert above the buttons and returns the card to ready."
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"name": "ReplyRating",
|
|
199
|
+
"usage": {
|
|
200
|
+
"when": [
|
|
201
|
+
"A reply can be rated helpful or not helpful, with an optional note after a not helpful rating."
|
|
202
|
+
],
|
|
203
|
+
"whenNot": [],
|
|
204
|
+
"do": [],
|
|
205
|
+
"dont": [],
|
|
206
|
+
"a11y": [
|
|
207
|
+
"Both rating buttons are native buttons that expose their state through aria-pressed.",
|
|
208
|
+
"The thank you line is a status message.",
|
|
209
|
+
"The note field has a visible label and a hint, and the person can send the note or skip it."
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const meta: {
|
|
2
|
+
readonly name: "ChatMarkdown";
|
|
3
|
+
readonly marker: any;
|
|
4
|
+
readonly platforms: readonly ["web"];
|
|
5
|
+
readonly acceptsChildren: false;
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly text: {
|
|
8
|
+
readonly type: "string";
|
|
9
|
+
readonly required: true;
|
|
10
|
+
readonly description: "The reply text, written in the supported Markdown subset. It always renders as text, never as HTML.";
|
|
11
|
+
};
|
|
12
|
+
readonly className: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly description: "Extra classes on the wrapper around the rendered reply.";
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
readonly examples: readonly [{
|
|
18
|
+
readonly id: "ChatMarkdown";
|
|
19
|
+
readonly title: "Default";
|
|
20
|
+
readonly props: {
|
|
21
|
+
readonly text: "See [your ticket](ticket:support/42) or [this site](https://evil.example).";
|
|
22
|
+
};
|
|
23
|
+
}];
|
|
24
|
+
readonly usage: {
|
|
25
|
+
readonly when: readonly ["A chat reply is written in Markdown and must render as text, never as HTML.", "A reply may point at in-app records, and the host decides which links become routes."];
|
|
26
|
+
readonly whenNot: readonly [];
|
|
27
|
+
readonly do: readonly [];
|
|
28
|
+
readonly dont: readonly [];
|
|
29
|
+
readonly a11y: readonly ["Lists render as real ordered and unordered lists, and tables render through AppDataTable.", "A link renders only when the host maps it to a route; any other link shows its label as plain text.", "Headings render as bold lines, not heading elements, so a reply does not change the page outline."];
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export declare const meta: {
|
|
2
|
+
readonly name: "ActionCard";
|
|
3
|
+
readonly marker: any;
|
|
4
|
+
readonly platforms: readonly ["web"];
|
|
5
|
+
readonly acceptsChildren: false;
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly action: {
|
|
8
|
+
readonly type: "object";
|
|
9
|
+
readonly required: true;
|
|
10
|
+
readonly description: "The support action to show: its kind, its text and when it expires.";
|
|
11
|
+
readonly fields: {
|
|
12
|
+
readonly token: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly required: true;
|
|
15
|
+
readonly description: "Sent back by the confirm button; nothing happens without it.";
|
|
16
|
+
};
|
|
17
|
+
readonly kind: {
|
|
18
|
+
readonly type: "enum";
|
|
19
|
+
readonly values: readonly ["RaiseTicket", "Reply", "Reopen"];
|
|
20
|
+
readonly required: true;
|
|
21
|
+
readonly description: "What the action does: raise a new ticket, reply on one, or reopen one.";
|
|
22
|
+
};
|
|
23
|
+
readonly ticketId: {
|
|
24
|
+
readonly type: "string";
|
|
25
|
+
readonly required: true;
|
|
26
|
+
readonly nullable: true;
|
|
27
|
+
readonly description: "The ticket the action is about. It is null when the action raises a new ticket.";
|
|
28
|
+
};
|
|
29
|
+
readonly ticketNumber: {
|
|
30
|
+
readonly type: "string";
|
|
31
|
+
readonly required: true;
|
|
32
|
+
readonly nullable: true;
|
|
33
|
+
readonly description: "The number of that ticket, shown in the title of a reply or reopen. It is null when the action raises a new ticket.";
|
|
34
|
+
};
|
|
35
|
+
readonly category: {
|
|
36
|
+
readonly type: "string";
|
|
37
|
+
readonly required: true;
|
|
38
|
+
readonly nullable: true;
|
|
39
|
+
readonly description: "The category of a new ticket, shown under the title. It is null for a reply or reopen.";
|
|
40
|
+
};
|
|
41
|
+
readonly subject: {
|
|
42
|
+
readonly type: "string";
|
|
43
|
+
readonly required: true;
|
|
44
|
+
readonly nullable: true;
|
|
45
|
+
readonly description: "The subject of a new ticket, shown under the title. It is null for a reply or reopen.";
|
|
46
|
+
};
|
|
47
|
+
readonly body: {
|
|
48
|
+
readonly type: "string";
|
|
49
|
+
readonly required: true;
|
|
50
|
+
readonly nullable: true;
|
|
51
|
+
readonly description: "The text the assistant prepared, shown in the card. A reopen shows none.";
|
|
52
|
+
};
|
|
53
|
+
readonly expiresDateTimeUtc: {
|
|
54
|
+
readonly type: "string";
|
|
55
|
+
readonly required: true;
|
|
56
|
+
readonly description: "When the action stops being confirmable, as a UTC date and time. After it the card shows what was offered without a Confirm button.";
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
readonly labels: {
|
|
61
|
+
readonly type: "object";
|
|
62
|
+
readonly description: "Overrides for the component's text, keyed by label name. A key left out keeps its default.";
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
readonly omit: readonly [];
|
|
66
|
+
readonly examples: readonly [{
|
|
67
|
+
readonly id: "ActionCard";
|
|
68
|
+
readonly title: "Default";
|
|
69
|
+
readonly props: {
|
|
70
|
+
readonly action: {
|
|
71
|
+
readonly token: "example-token";
|
|
72
|
+
readonly kind: "RaiseTicket";
|
|
73
|
+
readonly ticketId: any;
|
|
74
|
+
readonly ticketNumber: any;
|
|
75
|
+
readonly category: "Billing";
|
|
76
|
+
readonly subject: "Invoice address is wrong";
|
|
77
|
+
readonly body: "Please change the address on invoice 12.";
|
|
78
|
+
readonly expiresDateTimeUtc: "2099-12-31T23:59:59Z";
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
}];
|
|
82
|
+
readonly usage: {
|
|
83
|
+
readonly when: readonly ["One support action the assistant prepared, shown under its reply for the person to confirm before anything reaches support."];
|
|
84
|
+
readonly whenNot: readonly [];
|
|
85
|
+
readonly do: readonly [];
|
|
86
|
+
readonly dont: readonly [];
|
|
87
|
+
readonly a11y: readonly ["The done message is an alert with role status, so it is announced when the ticket is raised.", "Confirm and Not now are native buttons with text labels, and Not now is disabled while the request is sending.", "A failed confirm shows its message in a danger alert and puts the card back to ready so the person can try again."];
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @param {object} props
|
|
6
6
|
* @param {(message: string) => unknown} props.onSubmit Called with the trimmed question.
|
|
7
|
-
* @param {boolean} [props.busy
|
|
8
|
-
* @param {boolean} [props.disabled
|
|
9
|
-
* @param {number} [props.maxLength
|
|
7
|
+
* @param {boolean} [props.busy]
|
|
8
|
+
* @param {boolean} [props.disabled]
|
|
9
|
+
* @param {number} [props.maxLength]
|
|
10
10
|
* @param {import('react').Ref<HTMLTextAreaElement>} [props.inputRef] The question box, for focusing it.
|
|
11
11
|
* @param {Partial<typeof import('@webority/ui-elements/chat-core').DEFAULT_CHAT_LABELS>} [props.labels]
|
|
12
12
|
*/
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const meta: {
|
|
2
|
+
readonly name: "ChatComposer";
|
|
3
|
+
readonly marker: any;
|
|
4
|
+
readonly platforms: readonly ["web"];
|
|
5
|
+
readonly acceptsChildren: false;
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly busy: {
|
|
8
|
+
readonly type: "boolean";
|
|
9
|
+
readonly default: false;
|
|
10
|
+
readonly description: "An answer is still arriving, so Send is held.";
|
|
11
|
+
};
|
|
12
|
+
readonly disabled: {
|
|
13
|
+
readonly type: "boolean";
|
|
14
|
+
readonly default: false;
|
|
15
|
+
readonly description: "Nothing can be asked, for example when no questions are left today.";
|
|
16
|
+
};
|
|
17
|
+
readonly maxLength: {
|
|
18
|
+
readonly type: "number";
|
|
19
|
+
readonly default: 4000;
|
|
20
|
+
readonly description: "The longest question the box accepts, matching the server's message limit.";
|
|
21
|
+
};
|
|
22
|
+
readonly labels: {
|
|
23
|
+
readonly type: "object";
|
|
24
|
+
readonly description: "Overrides for the component's text, keyed by label name. A key left out keeps its default.";
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
readonly omit: readonly ["inputRef"];
|
|
28
|
+
readonly examples: readonly [{
|
|
29
|
+
readonly id: "ChatComposer";
|
|
30
|
+
readonly title: "Default";
|
|
31
|
+
readonly props: {};
|
|
32
|
+
}];
|
|
33
|
+
readonly usage: {
|
|
34
|
+
readonly when: readonly ["The question box where the person types a question for the assistant: Enter sends it and Shift and Enter starts a new line."];
|
|
35
|
+
readonly whenNot: readonly [];
|
|
36
|
+
readonly do: readonly [];
|
|
37
|
+
readonly dont: readonly [];
|
|
38
|
+
readonly a11y: readonly ["The form and its text box are both named by the composer label.", "The text box is described by a visually hidden hint, so the Enter and Shift and Enter keys are announced.", "Send is a submit button whose only text is the visually hidden send label next to a send icon, and it is disabled while busy, disabled or empty."];
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* E.g. open the panel and call `chat.openConversation(conversation.publicId)`.
|
|
9
9
|
* @param {(id: string) => void} [props.onDeleted] Called after a chat is deleted, e.g. to start a
|
|
10
10
|
* new chat when the open one was deleted.
|
|
11
|
-
* @param {number} [props.pageSize
|
|
11
|
+
* @param {number} [props.pageSize]
|
|
12
12
|
* @param {Partial<typeof import('@webority/ui-elements/chat-core').DEFAULT_CHAT_LABELS>} [props.labels]
|
|
13
13
|
*/
|
|
14
14
|
export default function ChatConversationList({ client, onOpen, onDeleted, pageSize, labels: labelOverrides }: {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare const meta: {
|
|
2
|
+
readonly name: "ChatConversationList";
|
|
3
|
+
readonly marker: any;
|
|
4
|
+
readonly platforms: readonly ["web"];
|
|
5
|
+
readonly acceptsChildren: false;
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly client: {
|
|
8
|
+
readonly type: "object";
|
|
9
|
+
readonly required: true;
|
|
10
|
+
readonly description: "The chat client the list loads and deletes chats through.";
|
|
11
|
+
};
|
|
12
|
+
readonly pageSize: {
|
|
13
|
+
readonly type: "number";
|
|
14
|
+
readonly default: 20;
|
|
15
|
+
readonly description: "How many chats each load fetches. Show more loads the next page.";
|
|
16
|
+
};
|
|
17
|
+
readonly labels: {
|
|
18
|
+
readonly type: "object";
|
|
19
|
+
readonly description: "Overrides for the component's text, keyed by label name. A key left out keeps its default.";
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
readonly omit: readonly [];
|
|
23
|
+
readonly examples: readonly [{
|
|
24
|
+
readonly id: "ChatConversationList";
|
|
25
|
+
readonly title: "Default";
|
|
26
|
+
readonly props: {
|
|
27
|
+
client: {};
|
|
28
|
+
};
|
|
29
|
+
}];
|
|
30
|
+
readonly usage: {
|
|
31
|
+
readonly when: readonly ["The person's past chats, newest first, for a past-chats page or a panel."];
|
|
32
|
+
readonly whenNot: readonly [];
|
|
33
|
+
readonly do: readonly [];
|
|
34
|
+
readonly dont: readonly [];
|
|
35
|
+
readonly a11y: readonly ["The chats are a list named by the conversations label.", "Each chat is a button showing its title and a time element that carries the date, and the delete icon button is named by the delete label.", "Deleting asks for confirmation in a dialog first, and the loading skeleton is hidden from assistive technology."];
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @param {object} props
|
|
13
13
|
* @param {() => void} props.onClick Opens the panel.
|
|
14
|
-
* @param {boolean} [props.open
|
|
15
|
-
* @param {"end"|"start"} [props.position
|
|
16
|
-
* @param {string} [props.icon
|
|
17
|
-
* @param {boolean} [props.compact
|
|
18
|
-
* @param {string} [props.className]
|
|
14
|
+
* @param {boolean} [props.open]
|
|
15
|
+
* @param {"end"|"start"} [props.position]
|
|
16
|
+
* @param {string} [props.icon]
|
|
17
|
+
* @param {boolean} [props.compact]
|
|
18
|
+
* @param {string} [props.className]
|
|
19
19
|
* @param {import('react').CSSProperties} [props.style] Merged over the wrapper's own style.
|
|
20
|
-
* @param {Partial<typeof import('@webority/ui-elements/chat-core').DEFAULT_CHAT_LABELS>} [props.labels]
|
|
20
|
+
* @param {Partial<typeof import('@webority/ui-elements/chat-core').DEFAULT_CHAT_LABELS>} [props.labels]
|
|
21
21
|
*/
|
|
22
22
|
export default function ChatLauncher({ onClick, open, position, icon, compact, className, style, labels: labelOverrides, }: {
|
|
23
23
|
onClick: () => void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export declare const meta: {
|
|
2
|
+
readonly name: "ChatLauncher";
|
|
3
|
+
readonly marker: any;
|
|
4
|
+
readonly platforms: readonly ["web"];
|
|
5
|
+
readonly acceptsChildren: false;
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly open: {
|
|
8
|
+
readonly type: "boolean";
|
|
9
|
+
readonly default: false;
|
|
10
|
+
readonly description: "Whether the panel is open. It is announced on the button.";
|
|
11
|
+
};
|
|
12
|
+
readonly position: {
|
|
13
|
+
readonly type: "enum";
|
|
14
|
+
readonly values: readonly ["end", "start"];
|
|
15
|
+
readonly default: "end";
|
|
16
|
+
readonly description: "The bottom corner the launcher sits in.";
|
|
17
|
+
};
|
|
18
|
+
readonly icon: {
|
|
19
|
+
readonly type: "string";
|
|
20
|
+
readonly default: "sparkles";
|
|
21
|
+
readonly description: "A library icon name.";
|
|
22
|
+
};
|
|
23
|
+
readonly compact: {
|
|
24
|
+
readonly type: "boolean";
|
|
25
|
+
readonly default: false;
|
|
26
|
+
readonly description: "Shows an icon-only circle stacked in the shared floating corner container, with the label as its tooltip.";
|
|
27
|
+
};
|
|
28
|
+
readonly className: {
|
|
29
|
+
readonly type: "string";
|
|
30
|
+
readonly description: "Added to the floating wrapper.";
|
|
31
|
+
};
|
|
32
|
+
readonly labels: {
|
|
33
|
+
readonly type: "object";
|
|
34
|
+
readonly description: "Overrides for the component's text, keyed by label name. The launcher key is the button text. A key left out keeps its default.";
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
readonly omit: readonly ["style"];
|
|
38
|
+
readonly examples: readonly [{
|
|
39
|
+
readonly id: "ChatLauncher";
|
|
40
|
+
readonly title: "Default";
|
|
41
|
+
readonly props: {};
|
|
42
|
+
}];
|
|
43
|
+
readonly usage: {
|
|
44
|
+
readonly when: readonly ["The floating pill that opens the assistant, pinned to a bottom corner."];
|
|
45
|
+
readonly whenNot: readonly [];
|
|
46
|
+
readonly do: readonly [];
|
|
47
|
+
readonly dont: readonly [];
|
|
48
|
+
readonly a11y: readonly ["The button announces that it opens a dialog (aria-haspopup) and whether it is open (aria-expanded).", "The default pill shows the launcher label as its button text.", "The compact circle takes the launcher label as its accessible name and as its tooltip."];
|
|
49
|
+
};
|
|
50
|
+
};
|