@webority/mobile-chat 0.9.1 → 0.11.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/README.md +8 -3
- package/lib/commonjs/components/ChatComposer.js +1 -1
- package/lib/commonjs/components/ChatMessage.js +1 -1
- package/lib/commonjs/components/ChatScreen.js +1 -1
- package/lib/commonjs/components/ChatThread.js +1 -1
- package/lib/module/components/ChatComposer.js +1 -1
- package/lib/module/components/ChatMessage.js +1 -1
- package/lib/module/components/ChatScreen.js +1 -1
- package/lib/module/components/ChatThread.js +1 -1
- package/lib/typescript/commonjs/components/ChatComposer.d.ts +13 -2
- package/lib/typescript/commonjs/components/ChatMessage.d.ts +4 -3
- package/lib/typescript/commonjs/components/ChatScreen.d.ts +8 -3
- package/lib/typescript/commonjs/components/ChatThread.d.ts +8 -3
- package/lib/typescript/module/components/ChatComposer.d.ts +13 -2
- package/lib/typescript/module/components/ChatMessage.d.ts +4 -3
- package/lib/typescript/module/components/ChatScreen.d.ts +8 -3
- package/lib/typescript/module/components/ChatThread.d.ts +8 -3
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -120,11 +120,16 @@ package's, so a product passes one label set to both; `composerHint` is not show
|
|
|
120
120
|
`title` (default "Assistant"), `headerActions` (before New chat, e.g. "All chats"), `empty`
|
|
121
121
|
(shown before the first question), `disclaimer` (null hides it), `maxLength` (default 4000),
|
|
122
122
|
`allowanceThreshold` (show the questions left at this many or fewer, default 10), `rating`
|
|
123
|
-
(default true), `resolveLink`, `onLinkPress`, `confirmAction`, `onViewTicket`, `renderReply
|
|
123
|
+
(default true), `resolveLink`, `onLinkPress`, `confirmAction`, `onViewTicket`, `renderReply`,
|
|
124
|
+
`keyboardOffset`.
|
|
124
125
|
New chat is disabled until there is something to clear; the question box is disabled with no
|
|
125
126
|
questions left, and the thread follows the newest text while an answer streams.
|
|
126
|
-
- **`ChatThread`**, **`ChatMessage`**, **`ChatComposer`**: its parts,
|
|
127
|
-
|
|
127
|
+
- **`ChatThread`**, **`ChatMessage`**, **`ChatComposer`**: its parts, built on mobile-ui's
|
|
128
|
+
`MessageList`, `MessageBubble`, `TypingIndicator` and `Composer`, for an app that lays out its
|
|
129
|
+
own chat. The thread and the composer handle the keyboard themselves; pass
|
|
130
|
+
`keyboardAware={false}` to both inside a container that already does, and `keyboardOffset` (the
|
|
131
|
+
tab bar height) above a tab bar. The composer's return key adds a new line; only the send button
|
|
132
|
+
sends.
|
|
128
133
|
- **`ChatMarkdown`**: renders a reply from a small, safe subset of Markdown: paragraphs, bold,
|
|
129
134
|
italics, inline code, bullet and numbered lists, simple tables (scrolling sideways), headings,
|
|
130
135
|
code blocks and rules. A link shows only when its href has the form `scheme:kind/id` and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatComposer=void 0;var _mobileUi=require("@webority/mobile-ui"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatComposer=void 0;var _mobileUi=require("@webority/mobile-ui"),_labels=require("../labels.js"),_jsxRuntime=require("react/jsx-runtime");const ChatComposer=({onSubmit:e,busy:s=!1,disabled:o=!1,maxLength:r=4e3,above:a,below:t,keyboardAware:b,keyboardOffset:l,safeArea:i,labels:m,testID:d="chat-composer"})=>{const n=(0,_labels.mergeLabels)(m);return(0,_jsxRuntime.jsx)(_mobileUi.Composer,{onSend:e,busy:s,disabled:o,maxLength:r,placeholder:n.placeholder,accessibilityLabel:n.composer,sendLabel:n.send,above:a,below:t,keyboardAware:b,keyboardOffset:l,safeArea:i,testID:d})};exports.ChatComposer=ChatComposer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatMessage=ChatMessage;var _mobileUi=require("@webority/mobile-ui"),_reactNative=require("react-native"),_labels=require("../labels.js"),_ActionCard=require("./ActionCard.js"),_ChatMarkdown=require("./ChatMarkdown.js"),_ReplyRating=require("./ReplyRating.js"),_jsxRuntime=require("react/jsx-runtime");function ChatMessage({turn:e,onRate:
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatMessage=ChatMessage;var _mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_labels=require("../labels.js"),_markdownParse=require("../markdownParse.js"),_ActionCard=require("./ActionCard.js"),_ChatMarkdown=require("./ChatMarkdown.js"),_ReplyRating=require("./ReplyRating.js"),_jsxRuntime=require("react/jsx-runtime");const inlineText=e=>e.map(e=>"text"===e.type||"code"===e.type?e.text:inlineText(e.children)).join(""),spokenText=e=>(0,_markdownParse.parseBlocks)(e).map(e=>{switch(e.type){case"paragraph":return inlineText((0,_markdownParse.parseInline)(e.lines.join(" ")));case"heading":return inlineText((0,_markdownParse.parseInline)(e.text));case"list":return e.items.map(e=>inlineText((0,_markdownParse.parseInline)(e))).join(". ");case"table":return[e.header,...e.rows].map(e=>e.join(", ")).join(". ");case"code":return e.text;default:return""}}).filter(Boolean).join("\n");function ChatMessage({turn:e,onRate:t,resolveLink:i,onLinkPress:n,confirmAction:r,onViewTicket:s,renderReply:a,labels:o,testID:l="chat-message"}){const m=(0,_labels.mergeLabels)(o),u=(0,_mobileUi.useTheme)(),c=e.streaming&&!e.answer,x=(0,_react.useMemo)(()=>e.streaming?e.answer:spokenText(e.answer),[e.streaming,e.answer]),_=(0,_react.useMemo)(()=>({you:m.you}),[m.you]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{gap:u.spacing.sm},testID:l,children:[""!==e.question&&(0,_jsxRuntime.jsx)(_mobileUi.MessageBubble,{side:"mine",text:e.question,labels:_,testID:`${l}-question`}),c?(0,_jsxRuntime.jsx)(_mobileUi.TypingIndicator,{label:m.thinking,testID:`${l}-thinking`}):null,""!==e.answer?(0,_jsxRuntime.jsx)(_mobileUi.MessageBubble,{side:"theirs",author:m.assistant,text:x,streaming:e.streaming,testID:`${l}-answer`,children:a?a(e,{streaming:e.streaming}):(0,_jsxRuntime.jsx)(_ChatMarkdown.ChatMarkdown,{text:e.answer,resolveLink:i,onLinkPress:n})}):null,e.error&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:e.error.message}),r&&!e.streaming&&e.actions.map(e=>(0,_jsxRuntime.jsx)(_ActionCard.ActionCard,{action:e,confirmAction:r,onViewTicket:s,labels:o},e.token)),t&&e.messageId&&!e.streaming&&(0,_jsxRuntime.jsx)(_ReplyRating.ReplyRating,{rating:e.rating,onRate:(i,n)=>t(e.id,i,n),labels:o})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatScreen=ChatScreen;var _mobileUi=require("@webority/mobile-ui"),_reactNative=require("react-native"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatScreen=ChatScreen;var _mobileUi=require("@webority/mobile-ui"),_reactNative=require("react-native"),_labels=require("../labels.js"),_ChatComposer=require("./ChatComposer.js"),_ChatThread=require("./ChatThread.js"),_jsxRuntime=require("react/jsx-runtime");function ChatScreen({chat:e,title:t,headerActions:i,empty:s,disclaimer:r,maxLength:a=4e3,allowanceThreshold:n=10,rating:o=!0,keyboardOffset:l,testID:m="chat-screen",...c}){const d=(0,_labels.mergeLabels)(c.labels),u=(0,_mobileUi.useTheme)(),x=e.messagesLeftToday,b=void 0===r?d.disclaimer:r;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{flex:1,backgroundColor:u.colors.background.primary},testID:m,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{flexDirection:"row",alignItems:"center",gap:u.spacing.sm,paddingHorizontal:u.spacing.md,paddingVertical:u.spacing.sm,borderBottomWidth:1,borderBottomColor:u.colors.border.secondary},children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"title",accessibilityRole:"header",style:{flex:1},numberOfLines:1,children:t??d.panelTitle}),i,(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:d.newChat,size:"sm",variant:"soft",leftIcon:"add",disabled:0===e.turns.length&&!e.loading,onPress:e.newConversation,testID:`${m}-new`})]}),e.loading?(0,_jsxRuntime.jsx)(_reactNative.View,{style:{flex:1,alignItems:"center",justifyContent:"center"},children:(0,_jsxRuntime.jsx)(_mobileUi.Spinner,{message:d.loadingConversation,testID:`${m}-loading`})}):(0,_jsxRuntime.jsx)(_ChatThread.ChatThread,{turns:e.turns,style:{flex:1},keyboardOffset:l,onRate:o?e.rate:void 0,empty:s??(0,_jsxRuntime.jsx)(_mobileUi.EmptyState,{fill:!0,size:"sm",title:d.emptyTitle,description:d.emptyText,testID:`${m}-empty`}),testID:`${m}-thread`,...c}),(0,_jsxRuntime.jsx)(_ChatComposer.ChatComposer,{onSubmit:t=>{e.submit(t)},busy:e.streaming,disabled:0===x||e.loading,maxLength:a,keyboardOffset:l,labels:c.labels,testID:`${m}-composer`,above:(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[e.loadError&&(0,_jsxRuntime.jsx)(_mobileUi.Banner,{variant:"error",message:e.loadError.message,testID:`${m}-load-error`}),null!==x&&x<=n&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:0===x?"error":"secondary",accessibilityLiveRegion:"polite",testID:`${m}-allowance`,children:d.allowance(x)})]}),below:b?(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",testID:`${m}-disclaimer`,children:b}):null})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatThread=ChatThread;var _mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_labels=require("../labels.js"),_ChatMessage=require("./ChatMessage.js"),_jsxRuntime=require("react/jsx-runtime");function ChatThread({turns:e,empty:t,style:a,testID:
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatThread=ChatThread;var _mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_labels=require("../labels.js"),_ChatMessage=require("./ChatMessage.js"),_jsxRuntime=require("react/jsx-runtime");const turnKey=e=>e.id,followTurn=()=>!0,TurnGap=()=>{const e=(0,_mobileUi.useTheme)();return(0,_jsxRuntime.jsx)(_reactNative.View,{style:{height:e.spacing.lg}})};function ChatThread({turns:e,empty:t,keyboardAware:r,keyboardOffset:s,style:a,testID:i="chat-thread",...o}){const u=(0,_labels.mergeLabels)(o.labels),l=(0,_react.useMemo)(()=>[...e].reverse(),[e]);return(0,_jsxRuntime.jsx)(_mobileUi.MessageList,{messages:l,keyExtractor:turnKey,renderMessage:({item:e})=>(0,_jsxRuntime.jsx)(_ChatMessage.ChatMessage,{turn:e,testID:`${i}-${e.id}`,...o}),followNew:followTurn,empty:t,ItemSeparatorComponent:TurnGap,keyboardAware:r,keyboardOffset:s,accessibilityLabel:u.thread,style:a,testID:i})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{
|
|
1
|
+
"use strict";import{Composer}from"@webority/mobile-ui";import{mergeLabels}from"../labels.js";import{jsx as _jsx}from"react/jsx-runtime";export const ChatComposer=({onSubmit:e,busy:o=!1,disabled:s=!1,maxLength:r=4e3,above:a,below:t,keyboardAware:b,keyboardOffset:l,safeArea:m,labels:i,testID:d="chat-composer"})=>{const c=mergeLabels(i);return _jsx(Composer,{onSend:e,busy:o,disabled:s,maxLength:r,placeholder:c.placeholder,accessibilityLabel:c.composer,sendLabel:c.send,above:a,below:t,keyboardAware:b,keyboardOffset:l,safeArea:m,testID:d})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{
|
|
1
|
+
"use strict";import{MessageBubble,Text,TypingIndicator,useTheme}from"@webority/mobile-ui";import{useMemo}from"react";import{View}from"react-native";import{mergeLabels}from"../labels.js";import{parseBlocks,parseInline}from"../markdownParse.js";import{ActionCard}from"./ActionCard.js";import{ChatMarkdown}from"./ChatMarkdown.js";import{ReplyRating}from"./ReplyRating.js";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";const inlineText=e=>e.map(e=>"text"===e.type||"code"===e.type?e.text:inlineText(e.children)).join(""),spokenText=e=>parseBlocks(e).map(e=>{switch(e.type){case"paragraph":return inlineText(parseInline(e.lines.join(" ")));case"heading":return inlineText(parseInline(e.text));case"list":return e.items.map(e=>inlineText(parseInline(e))).join(". ");case"table":return[e.header,...e.rows].map(e=>e.join(", ")).join(". ");case"code":return e.text;default:return""}}).filter(Boolean).join("\n");export function ChatMessage({turn:e,onRate:t,resolveLink:s,onLinkPress:n,confirmAction:r,onViewTicket:i,renderReply:a,labels:o,testID:l="chat-message"}){const m=mergeLabels(o),c=useTheme(),p=e.streaming&&!e.answer,g=useMemo(()=>e.streaming?e.answer:spokenText(e.answer),[e.streaming,e.answer]),u=useMemo(()=>({you:m.you}),[m.you]);return _jsxs(View,{style:{gap:c.spacing.sm},testID:l,children:[""!==e.question&&_jsx(MessageBubble,{side:"mine",text:e.question,labels:u,testID:`${l}-question`}),p?_jsx(TypingIndicator,{label:m.thinking,testID:`${l}-thinking`}):null,""!==e.answer?_jsx(MessageBubble,{side:"theirs",author:m.assistant,text:g,streaming:e.streaming,testID:`${l}-answer`,children:a?a(e,{streaming:e.streaming}):_jsx(ChatMarkdown,{text:e.answer,resolveLink:s,onLinkPress:n})}):null,e.error&&_jsx(Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:e.error.message}),r&&!e.streaming&&e.actions.map(e=>_jsx(ActionCard,{action:e,confirmAction:r,onViewTicket:i,labels:o},e.token)),t&&e.messageId&&!e.streaming&&_jsx(ReplyRating,{rating:e.rating,onRate:(s,n)=>t(e.id,s,n),labels:o})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{Banner,Button,EmptyState,Spinner,Text,useTheme}from"@webority/mobile-ui";import{View}from"react-native";import{
|
|
1
|
+
"use strict";import{Banner,Button,EmptyState,Spinner,Text,useTheme}from"@webority/mobile-ui";import{View}from"react-native";import{mergeLabels}from"../labels.js";import{ChatComposer}from"./ChatComposer.js";import{ChatThread}from"./ChatThread.js";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";export function ChatScreen({chat:e,title:t,headerActions:r,empty:s,disclaimer:a,maxLength:o=4e3,allowanceThreshold:i=10,rating:n=!0,keyboardOffset:l,testID:m="chat-screen",...d}){const c=mergeLabels(d.labels),p=useTheme(),h=e.messagesLeftToday,x=void 0===a?c.disclaimer:a;return _jsxs(View,{style:{flex:1,backgroundColor:p.colors.background.primary},testID:m,children:[_jsxs(View,{style:{flexDirection:"row",alignItems:"center",gap:p.spacing.sm,paddingHorizontal:p.spacing.md,paddingVertical:p.spacing.sm,borderBottomWidth:1,borderBottomColor:p.colors.border.secondary},children:[_jsx(Text,{variant:"title",accessibilityRole:"header",style:{flex:1},numberOfLines:1,children:t??c.panelTitle}),r,_jsx(Button,{title:c.newChat,size:"sm",variant:"soft",leftIcon:"add",disabled:0===e.turns.length&&!e.loading,onPress:e.newConversation,testID:`${m}-new`})]}),e.loading?_jsx(View,{style:{flex:1,alignItems:"center",justifyContent:"center"},children:_jsx(Spinner,{message:c.loadingConversation,testID:`${m}-loading`})}):_jsx(ChatThread,{turns:e.turns,style:{flex:1},keyboardOffset:l,onRate:n?e.rate:void 0,empty:s??_jsx(EmptyState,{fill:!0,size:"sm",title:c.emptyTitle,description:c.emptyText,testID:`${m}-empty`}),testID:`${m}-thread`,...d}),_jsx(ChatComposer,{onSubmit:t=>{e.submit(t)},busy:e.streaming,disabled:0===h||e.loading,maxLength:o,keyboardOffset:l,labels:d.labels,testID:`${m}-composer`,above:_jsxs(_Fragment,{children:[e.loadError&&_jsx(Banner,{variant:"error",message:e.loadError.message,testID:`${m}-load-error`}),null!==h&&h<=i&&_jsx(Text,{variant:"caption",color:0===h?"error":"secondary",accessibilityLiveRegion:"polite",testID:`${m}-allowance`,children:c.allowance(h)})]}),below:x?_jsx(Text,{variant:"caption",color:"tertiary",testID:`${m}-disclaimer`,children:x}):null})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useTheme}from"@webority/mobile-ui";import{
|
|
1
|
+
"use strict";import{MessageList,useTheme}from"@webority/mobile-ui";import{useMemo}from"react";import{View}from"react-native";import{mergeLabels}from"../labels.js";import{ChatMessage}from"./ChatMessage.js";import{jsx as _jsx}from"react/jsx-runtime";const turnKey=e=>e.id,followTurn=()=>!0,TurnGap=()=>{const e=useTheme();return _jsx(View,{style:{height:e.spacing.lg}})};export function ChatThread({turns:e,empty:t,keyboardAware:s,keyboardOffset:r,style:a,testID:o="chat-thread",...m}){const i=mergeLabels(m.labels),n=useMemo(()=>[...e].reverse(),[e]);return _jsx(MessageList,{messages:n,keyExtractor:turnKey,renderMessage:({item:e})=>_jsx(ChatMessage,{turn:e,testID:`${o}-${e.id}`,...m}),followNew:followTurn,empty:t,ItemSeparatorComponent:TurnGap,keyboardAware:s,keyboardOffset:r,accessibilityLabel:i.thread,style:a,testID:o})}
|
|
@@ -9,12 +9,23 @@ export interface ChatComposerProps {
|
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
/** The server's message limit. Default 4000. */
|
|
11
11
|
maxLength?: number;
|
|
12
|
+
/** Inside the bar, above the question box: a banner, the questions left. */
|
|
13
|
+
above?: React.ReactNode;
|
|
14
|
+
/** Inside the bar, below the question box: the disclaimer. */
|
|
15
|
+
below?: React.ReactNode;
|
|
16
|
+
/** Rides the keyboard; see mobile-ui `Composer`. Default true. */
|
|
17
|
+
keyboardAware?: boolean;
|
|
18
|
+
/** See mobile-ui `Composer`. Default: the bottom safe-area inset. */
|
|
19
|
+
keyboardOffset?: number;
|
|
20
|
+
/** Pads for the bottom safe area. Default true. */
|
|
21
|
+
safeArea?: boolean;
|
|
12
22
|
labels?: Partial<ChatLabels>;
|
|
13
23
|
testID?: string;
|
|
14
24
|
}
|
|
15
25
|
/**
|
|
16
|
-
* The question box and its send button
|
|
17
|
-
* expect; only the button sends.
|
|
26
|
+
* The question box and its send button, on mobile-ui's `Composer`. The return
|
|
27
|
+
* key adds a new line, as phone keyboards expect; only the button sends. The
|
|
28
|
+
* bar rides the keyboard and pads for the bottom safe area by default.
|
|
18
29
|
*/
|
|
19
30
|
export declare const ChatComposer: React.FC<ChatComposerProps>;
|
|
20
31
|
//# sourceMappingURL=ChatComposer.d.ts.map
|
|
@@ -27,9 +27,10 @@ export interface ChatMessageProps<T = string> extends ChatReplyProps<T> {
|
|
|
27
27
|
testID?: string;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* One turn
|
|
31
|
-
*
|
|
32
|
-
* answer
|
|
30
|
+
* One turn on mobile-ui's chat parts: the person's question in a `MessageBubble` on the trailing
|
|
31
|
+
* side, the typing dots while the answer has not started, then the answer in a bubble on the
|
|
32
|
+
* leading side. The answer is announced once, when it finishes arriving. Support actions show
|
|
33
|
+
* under the answer, and the rating once the reply is stored.
|
|
33
34
|
*/
|
|
34
35
|
export declare function ChatMessage<T = string>({ turn, onRate, resolveLink, onLinkPress, confirmAction, onViewTicket, renderReply, labels: labelOverrides, testID }: ChatMessageProps<T>): React.ReactElement;
|
|
35
36
|
//# sourceMappingURL=ChatMessage.d.ts.map
|
|
@@ -18,13 +18,18 @@ export interface ChatScreenProps<T = string> extends Omit<ChatReplyProps<T>, 'on
|
|
|
18
18
|
allowanceThreshold?: number;
|
|
19
19
|
/** Offer ratings under stored replies. Default true. */
|
|
20
20
|
rating?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* How far below the question box the keyboard's top edge starts. Default: the bottom safe-area
|
|
23
|
+
* inset; set it to the tab bar's height when the screen sits above one.
|
|
24
|
+
*/
|
|
25
|
+
keyboardOffset?: number;
|
|
21
26
|
testID?: string;
|
|
22
27
|
}
|
|
23
28
|
/**
|
|
24
29
|
* The whole chat for one screen of the app's navigator: a header with New chat, the
|
|
25
30
|
* conversation, the questions left today, the question box and the AI disclaimer. The question
|
|
26
|
-
* box
|
|
27
|
-
* `useChat` call above the navigator, so the conversation survives leaving the screen.
|
|
31
|
+
* box rides the keyboard and the newest turn stays above it. Place it in a stack screen and keep
|
|
32
|
+
* the `useChat` call above the navigator, so the conversation survives leaving the screen.
|
|
28
33
|
*/
|
|
29
|
-
export declare function ChatScreen<T = string>({ chat, title, headerActions, empty, disclaimer, maxLength, allowanceThreshold, rating, testID, ...reply }: ChatScreenProps<T>): React.ReactElement;
|
|
34
|
+
export declare function ChatScreen<T = string>({ chat, title, headerActions, empty, disclaimer, maxLength, allowanceThreshold, rating, keyboardOffset, testID, ...reply }: ChatScreenProps<T>): React.ReactElement;
|
|
30
35
|
//# sourceMappingURL=ChatScreen.d.ts.map
|
|
@@ -6,12 +6,17 @@ export interface ChatThreadProps<T = string> extends ChatReplyProps<T> {
|
|
|
6
6
|
turns: ChatTurn[];
|
|
7
7
|
/** Shown before the first question. */
|
|
8
8
|
empty?: React.ReactNode;
|
|
9
|
+
/** Lifts the newest turn above the keyboard; see mobile-ui `MessageList`. Default true. */
|
|
10
|
+
keyboardAware?: boolean;
|
|
11
|
+
/** The composer's `keyboardOffset`. Default: the bottom safe-area inset. */
|
|
12
|
+
keyboardOffset?: number;
|
|
9
13
|
style?: StyleProp<ViewStyle>;
|
|
10
14
|
testID?: string;
|
|
11
15
|
}
|
|
12
16
|
/**
|
|
13
|
-
* The conversation
|
|
14
|
-
*
|
|
17
|
+
* The conversation on mobile-ui's `MessageList`: newest at the bottom, the
|
|
18
|
+
* streaming answer growing in place, a jump to the latest once scrolled up,
|
|
19
|
+
* and the newest turn kept above the keyboard.
|
|
15
20
|
*/
|
|
16
|
-
export declare function ChatThread<T = string>({ turns, empty, style, testID, ...reply }: ChatThreadProps<T>): React.ReactElement;
|
|
21
|
+
export declare function ChatThread<T = string>({ turns, empty, keyboardAware, keyboardOffset, style, testID, ...reply }: ChatThreadProps<T>): React.ReactElement;
|
|
17
22
|
//# sourceMappingURL=ChatThread.d.ts.map
|
|
@@ -9,12 +9,23 @@ export interface ChatComposerProps {
|
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
/** The server's message limit. Default 4000. */
|
|
11
11
|
maxLength?: number;
|
|
12
|
+
/** Inside the bar, above the question box: a banner, the questions left. */
|
|
13
|
+
above?: React.ReactNode;
|
|
14
|
+
/** Inside the bar, below the question box: the disclaimer. */
|
|
15
|
+
below?: React.ReactNode;
|
|
16
|
+
/** Rides the keyboard; see mobile-ui `Composer`. Default true. */
|
|
17
|
+
keyboardAware?: boolean;
|
|
18
|
+
/** See mobile-ui `Composer`. Default: the bottom safe-area inset. */
|
|
19
|
+
keyboardOffset?: number;
|
|
20
|
+
/** Pads for the bottom safe area. Default true. */
|
|
21
|
+
safeArea?: boolean;
|
|
12
22
|
labels?: Partial<ChatLabels>;
|
|
13
23
|
testID?: string;
|
|
14
24
|
}
|
|
15
25
|
/**
|
|
16
|
-
* The question box and its send button
|
|
17
|
-
* expect; only the button sends.
|
|
26
|
+
* The question box and its send button, on mobile-ui's `Composer`. The return
|
|
27
|
+
* key adds a new line, as phone keyboards expect; only the button sends. The
|
|
28
|
+
* bar rides the keyboard and pads for the bottom safe area by default.
|
|
18
29
|
*/
|
|
19
30
|
export declare const ChatComposer: React.FC<ChatComposerProps>;
|
|
20
31
|
//# sourceMappingURL=ChatComposer.d.ts.map
|
|
@@ -27,9 +27,10 @@ export interface ChatMessageProps<T = string> extends ChatReplyProps<T> {
|
|
|
27
27
|
testID?: string;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* One turn
|
|
31
|
-
*
|
|
32
|
-
* answer
|
|
30
|
+
* One turn on mobile-ui's chat parts: the person's question in a `MessageBubble` on the trailing
|
|
31
|
+
* side, the typing dots while the answer has not started, then the answer in a bubble on the
|
|
32
|
+
* leading side. The answer is announced once, when it finishes arriving. Support actions show
|
|
33
|
+
* under the answer, and the rating once the reply is stored.
|
|
33
34
|
*/
|
|
34
35
|
export declare function ChatMessage<T = string>({ turn, onRate, resolveLink, onLinkPress, confirmAction, onViewTicket, renderReply, labels: labelOverrides, testID }: ChatMessageProps<T>): React.ReactElement;
|
|
35
36
|
//# sourceMappingURL=ChatMessage.d.ts.map
|
|
@@ -18,13 +18,18 @@ export interface ChatScreenProps<T = string> extends Omit<ChatReplyProps<T>, 'on
|
|
|
18
18
|
allowanceThreshold?: number;
|
|
19
19
|
/** Offer ratings under stored replies. Default true. */
|
|
20
20
|
rating?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* How far below the question box the keyboard's top edge starts. Default: the bottom safe-area
|
|
23
|
+
* inset; set it to the tab bar's height when the screen sits above one.
|
|
24
|
+
*/
|
|
25
|
+
keyboardOffset?: number;
|
|
21
26
|
testID?: string;
|
|
22
27
|
}
|
|
23
28
|
/**
|
|
24
29
|
* The whole chat for one screen of the app's navigator: a header with New chat, the
|
|
25
30
|
* conversation, the questions left today, the question box and the AI disclaimer. The question
|
|
26
|
-
* box
|
|
27
|
-
* `useChat` call above the navigator, so the conversation survives leaving the screen.
|
|
31
|
+
* box rides the keyboard and the newest turn stays above it. Place it in a stack screen and keep
|
|
32
|
+
* the `useChat` call above the navigator, so the conversation survives leaving the screen.
|
|
28
33
|
*/
|
|
29
|
-
export declare function ChatScreen<T = string>({ chat, title, headerActions, empty, disclaimer, maxLength, allowanceThreshold, rating, testID, ...reply }: ChatScreenProps<T>): React.ReactElement;
|
|
34
|
+
export declare function ChatScreen<T = string>({ chat, title, headerActions, empty, disclaimer, maxLength, allowanceThreshold, rating, keyboardOffset, testID, ...reply }: ChatScreenProps<T>): React.ReactElement;
|
|
30
35
|
//# sourceMappingURL=ChatScreen.d.ts.map
|
|
@@ -6,12 +6,17 @@ export interface ChatThreadProps<T = string> extends ChatReplyProps<T> {
|
|
|
6
6
|
turns: ChatTurn[];
|
|
7
7
|
/** Shown before the first question. */
|
|
8
8
|
empty?: React.ReactNode;
|
|
9
|
+
/** Lifts the newest turn above the keyboard; see mobile-ui `MessageList`. Default true. */
|
|
10
|
+
keyboardAware?: boolean;
|
|
11
|
+
/** The composer's `keyboardOffset`. Default: the bottom safe-area inset. */
|
|
12
|
+
keyboardOffset?: number;
|
|
9
13
|
style?: StyleProp<ViewStyle>;
|
|
10
14
|
testID?: string;
|
|
11
15
|
}
|
|
12
16
|
/**
|
|
13
|
-
* The conversation
|
|
14
|
-
*
|
|
17
|
+
* The conversation on mobile-ui's `MessageList`: newest at the bottom, the
|
|
18
|
+
* streaming answer growing in place, a jump to the latest once scrolled up,
|
|
19
|
+
* and the newest turn kept above the keyboard.
|
|
15
20
|
*/
|
|
16
|
-
export declare function ChatThread<T = string>({ turns, empty, style, testID, ...reply }: ChatThreadProps<T>): React.ReactElement;
|
|
21
|
+
export declare function ChatThread<T = string>({ turns, empty, keyboardAware, keyboardOffset, style, testID, ...reply }: ChatThreadProps<T>): React.ReactElement;
|
|
17
22
|
//# sourceMappingURL=ChatThread.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/mobile-chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "AI assistant chat for Webority React Native apps: a streaming chat client, a store-agnostic chat hook, and the chat screen, thread, composer, past chats, reply rating and support action cards, built on @webority/mobile-ui.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"!**/*.map"
|
|
43
43
|
],
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@webority/mobile-core": ">=0.
|
|
46
|
-
"@webority/mobile-ui": ">=0.
|
|
45
|
+
"@webority/mobile-core": ">=0.11.0 <0.12.0",
|
|
46
|
+
"@webority/mobile-ui": ">=0.11.0 <0.12.0",
|
|
47
47
|
"react": "^19.1.0",
|
|
48
48
|
"react-native": ">=0.81.0",
|
|
49
49
|
"react-native-keyboard-controller": ">=1.21.9",
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
]
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@webority/mobile-core": "0.
|
|
85
|
-
"@webority/mobile-ui": "0.
|
|
84
|
+
"@webority/mobile-core": "0.11.0",
|
|
85
|
+
"@webority/mobile-ui": "0.11.0"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "bob build && node ../../scripts/minify-lib.mjs",
|