@botonic/react 0.54.0 → 0.55.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/lib/cjs/components/index-types.d.ts +0 -2
- package/lib/cjs/components/message/index.js +2 -4
- package/lib/cjs/components/message/index.js.map +1 -1
- package/lib/cjs/components/message/message-footer.d.ts +1 -4
- package/lib/cjs/components/message/message-footer.js +2 -3
- package/lib/cjs/components/message/message-footer.js.map +1 -1
- package/lib/cjs/components/system-debug-trace/debug-message.js +0 -2
- package/lib/cjs/components/system-debug-trace/debug-message.js.map +1 -1
- package/lib/cjs/components/system-debug-trace/events/ai-agent/ai-agent.d.ts +1 -1
- package/lib/cjs/components/system-debug-trace/events/ai-agent/ai-agent.js +6 -2
- package/lib/cjs/components/system-debug-trace/events/ai-agent/ai-agent.js.map +1 -1
- package/lib/cjs/components/system-debug-trace/events/ai-agent/rehydrate-ai-agent-event.d.ts +6 -0
- package/lib/cjs/components/system-debug-trace/events/ai-agent/rehydrate-ai-agent-event.js +55 -0
- package/lib/cjs/components/system-debug-trace/events/ai-agent/rehydrate-ai-agent-event.js.map +1 -0
- package/lib/cjs/components/system-debug-trace/events/ai-agent/types.d.ts +2 -0
- package/lib/cjs/components/system-debug-trace/events/ai-agent/use-rehydrated-ai-agent-event.d.ts +8 -0
- package/lib/cjs/components/system-debug-trace/events/ai-agent/use-rehydrated-ai-agent-event.js +41 -0
- package/lib/cjs/components/system-debug-trace/events/ai-agent/use-rehydrated-ai-agent-event.js.map +1 -0
- package/lib/cjs/components/system-debug-trace/events/constants.d.ts +0 -2
- package/lib/cjs/components/system-debug-trace/events/constants.js +0 -2
- package/lib/cjs/components/system-debug-trace/events/constants.js.map +1 -1
- package/lib/cjs/components/system-debug-trace/events/index.d.ts +0 -1
- package/lib/cjs/components/system-debug-trace/events/index.js +0 -1
- package/lib/cjs/components/system-debug-trace/events/index.js.map +1 -1
- package/lib/cjs/components/system-debug-trace/hooks/use-knowledge-base-info.d.ts +1 -4
- package/lib/cjs/components/system-debug-trace/hooks/use-knowledge-base-info.js +1 -23
- package/lib/cjs/components/system-debug-trace/hooks/use-knowledge-base-info.js.map +1 -1
- package/lib/cjs/components/system-debug-trace/types.d.ts +2 -2
- package/lib/cjs/components/text.js +0 -2
- package/lib/cjs/components/text.js.map +1 -1
- package/lib/cjs/debug-system-messages.d.ts +0 -22
- package/lib/cjs/debug-system-messages.js +0 -22
- package/lib/cjs/debug-system-messages.js.map +1 -1
- package/lib/cjs/dev-app.d.ts +0 -22
- package/lib/cjs/index-types.d.ts +5 -1
- package/lib/cjs/index-types.js.map +1 -1
- package/lib/cjs/webchat/input-panel/index.js +7 -17
- package/lib/cjs/webchat/input-panel/index.js.map +1 -1
- package/lib/cjs/webchat/input-panel/textarea.d.ts +3 -2
- package/lib/cjs/webchat/input-panel/textarea.js +16 -46
- package/lib/cjs/webchat/input-panel/textarea.js.map +1 -1
- package/lib/cjs/webchat/input-panel/typing-network-sender.d.ts +52 -0
- package/lib/cjs/webchat/input-panel/typing-network-sender.js +122 -0
- package/lib/cjs/webchat/input-panel/typing-network-sender.js.map +1 -0
- package/lib/cjs/webchat/input-panel/use-typing-chat-event-sender.d.ts +16 -0
- package/lib/cjs/webchat/input-panel/use-typing-chat-event-sender.js +45 -0
- package/lib/cjs/webchat/input-panel/use-typing-chat-event-sender.js.map +1 -0
- package/lib/cjs/webchat/input-panel/use-typing-session.d.ts +15 -0
- package/lib/cjs/webchat/input-panel/use-typing-session.js +98 -0
- package/lib/cjs/webchat/input-panel/use-typing-session.js.map +1 -0
- package/lib/cjs/webchat/tracking.d.ts +0 -10
- package/lib/cjs/webchat/tracking.js +1 -32
- package/lib/cjs/webchat/tracking.js.map +1 -1
- package/lib/esm/components/index-types.d.ts +0 -2
- package/lib/esm/components/message/index.js +2 -4
- package/lib/esm/components/message/index.js.map +1 -1
- package/lib/esm/components/message/message-footer.d.ts +1 -4
- package/lib/esm/components/message/message-footer.js +2 -3
- package/lib/esm/components/message/message-footer.js.map +1 -1
- package/lib/esm/components/system-debug-trace/debug-message.js +0 -2
- package/lib/esm/components/system-debug-trace/debug-message.js.map +1 -1
- package/lib/esm/components/system-debug-trace/events/ai-agent/ai-agent.d.ts +1 -1
- package/lib/esm/components/system-debug-trace/events/ai-agent/ai-agent.js +6 -2
- package/lib/esm/components/system-debug-trace/events/ai-agent/ai-agent.js.map +1 -1
- package/lib/esm/components/system-debug-trace/events/ai-agent/rehydrate-ai-agent-event.d.ts +6 -0
- package/lib/esm/components/system-debug-trace/events/ai-agent/rehydrate-ai-agent-event.js +55 -0
- package/lib/esm/components/system-debug-trace/events/ai-agent/rehydrate-ai-agent-event.js.map +1 -0
- package/lib/esm/components/system-debug-trace/events/ai-agent/types.d.ts +2 -0
- package/lib/esm/components/system-debug-trace/events/ai-agent/use-rehydrated-ai-agent-event.d.ts +8 -0
- package/lib/esm/components/system-debug-trace/events/ai-agent/use-rehydrated-ai-agent-event.js +41 -0
- package/lib/esm/components/system-debug-trace/events/ai-agent/use-rehydrated-ai-agent-event.js.map +1 -0
- package/lib/esm/components/system-debug-trace/events/constants.d.ts +0 -2
- package/lib/esm/components/system-debug-trace/events/constants.js +0 -2
- package/lib/esm/components/system-debug-trace/events/constants.js.map +1 -1
- package/lib/esm/components/system-debug-trace/events/index.d.ts +0 -1
- package/lib/esm/components/system-debug-trace/events/index.js +0 -1
- package/lib/esm/components/system-debug-trace/events/index.js.map +1 -1
- package/lib/esm/components/system-debug-trace/hooks/use-knowledge-base-info.d.ts +1 -4
- package/lib/esm/components/system-debug-trace/hooks/use-knowledge-base-info.js +1 -23
- package/lib/esm/components/system-debug-trace/hooks/use-knowledge-base-info.js.map +1 -1
- package/lib/esm/components/system-debug-trace/types.d.ts +2 -2
- package/lib/esm/components/text.js +0 -2
- package/lib/esm/components/text.js.map +1 -1
- package/lib/esm/debug-system-messages.d.ts +0 -22
- package/lib/esm/debug-system-messages.js +0 -22
- package/lib/esm/debug-system-messages.js.map +1 -1
- package/lib/esm/dev-app.d.ts +0 -22
- package/lib/esm/index-types.d.ts +5 -1
- package/lib/esm/index-types.js.map +1 -1
- package/lib/esm/webchat/input-panel/index.js +7 -17
- package/lib/esm/webchat/input-panel/index.js.map +1 -1
- package/lib/esm/webchat/input-panel/textarea.d.ts +3 -2
- package/lib/esm/webchat/input-panel/textarea.js +16 -46
- package/lib/esm/webchat/input-panel/textarea.js.map +1 -1
- package/lib/esm/webchat/input-panel/typing-network-sender.d.ts +52 -0
- package/lib/esm/webchat/input-panel/typing-network-sender.js +122 -0
- package/lib/esm/webchat/input-panel/typing-network-sender.js.map +1 -0
- package/lib/esm/webchat/input-panel/use-typing-chat-event-sender.d.ts +16 -0
- package/lib/esm/webchat/input-panel/use-typing-chat-event-sender.js +45 -0
- package/lib/esm/webchat/input-panel/use-typing-chat-event-sender.js.map +1 -0
- package/lib/esm/webchat/input-panel/use-typing-session.d.ts +15 -0
- package/lib/esm/webchat/input-panel/use-typing-session.js +98 -0
- package/lib/esm/webchat/input-panel/use-typing-session.js.map +1 -0
- package/lib/esm/webchat/tracking.d.ts +0 -10
- package/lib/esm/webchat/tracking.js +1 -32
- package/lib/esm/webchat/tracking.js.map +1 -1
- package/package.json +2 -2
- package/src/components/index-types.ts +0 -2
- package/src/components/message/index.jsx +1 -8
- package/src/components/message/message-footer.tsx +0 -14
- package/src/components/system-debug-trace/debug-message.tsx +0 -3
- package/src/components/system-debug-trace/events/ai-agent/ai-agent.tsx +22 -10
- package/src/components/system-debug-trace/events/ai-agent/rehydrate-ai-agent-event.ts +70 -0
- package/src/components/system-debug-trace/events/ai-agent/types.ts +2 -0
- package/src/components/system-debug-trace/events/ai-agent/use-rehydrated-ai-agent-event.ts +67 -0
- package/src/components/system-debug-trace/events/constants.ts +0 -2
- package/src/components/system-debug-trace/events/index.ts +0 -1
- package/src/components/system-debug-trace/hooks/use-knowledge-base-info.tsx +1 -27
- package/src/components/system-debug-trace/types.ts +0 -2
- package/src/components/text.tsx +0 -2
- package/src/debug-system-messages.ts +0 -25
- package/src/index-types.ts +9 -1
- package/src/webchat/input-panel/index.tsx +7 -17
- package/src/webchat/input-panel/textarea.tsx +20 -60
- package/src/webchat/input-panel/typing-network-sender.ts +168 -0
- package/src/webchat/input-panel/use-typing-chat-event-sender.ts +67 -0
- package/src/webchat/input-panel/use-typing-session.ts +124 -0
- package/src/webchat/tracking.ts +2 -56
- package/lib/cjs/components/message/message-feedback.d.ts +0 -7
- package/lib/cjs/components/message/message-feedback.js +0 -55
- package/lib/cjs/components/message/message-feedback.js.map +0 -1
- package/lib/cjs/components/system-debug-trace/events/knowledge-base.d.ts +0 -17
- package/lib/cjs/components/system-debug-trace/events/knowledge-base.js +0 -42
- package/lib/cjs/components/system-debug-trace/events/knowledge-base.js.map +0 -1
- package/lib/esm/components/message/message-feedback.d.ts +0 -7
- package/lib/esm/components/message/message-feedback.js +0 -55
- package/lib/esm/components/message/message-feedback.js.map +0 -1
- package/lib/esm/components/system-debug-trace/events/knowledge-base.d.ts +0 -17
- package/lib/esm/components/system-debug-trace/events/knowledge-base.js +0 -42
- package/lib/esm/components/system-debug-trace/events/knowledge-base.js.map +0 -1
- package/src/components/message/message-feedback.tsx +0 -90
- package/src/components/system-debug-trace/events/knowledge-base.tsx +0 -115
package/lib/cjs/dev-app.d.ts
CHANGED
|
@@ -56,28 +56,6 @@ export class DevApp extends WebchatApp {
|
|
|
56
56
|
action: import("@botonic/core").EventAction.BotAction;
|
|
57
57
|
payload: string;
|
|
58
58
|
};
|
|
59
|
-
knowledgeBase: {
|
|
60
|
-
action: import("@botonic/core").EventAction.Knowledgebase;
|
|
61
|
-
flow_id: string;
|
|
62
|
-
flow_node_id: string;
|
|
63
|
-
knowledgebase_inference_id: string;
|
|
64
|
-
knowledgebase_fail_reason: string;
|
|
65
|
-
knowledgebase_sources_ids: string[];
|
|
66
|
-
knowledgebase_chunks_ids: string[];
|
|
67
|
-
user_input: string;
|
|
68
|
-
knowledge_base_chunks_with_sources: import("./index-types").ChunkIdsGroupedBySourceData[];
|
|
69
|
-
};
|
|
70
|
-
knowledgeBaseFailed: {
|
|
71
|
-
action: import("@botonic/core").EventAction.Knowledgebase;
|
|
72
|
-
flow_id: string;
|
|
73
|
-
flow_node_id: string;
|
|
74
|
-
knowledgebase_inference_id: string;
|
|
75
|
-
knowledgebase_fail_reason: string;
|
|
76
|
-
knowledgebase_sources_ids: never[];
|
|
77
|
-
knowledgebase_chunks_ids: never[];
|
|
78
|
-
user_input: string;
|
|
79
|
-
knowledge_base_chunks_with_sources: never[];
|
|
80
|
-
};
|
|
81
59
|
conditionalChannel: {
|
|
82
60
|
action: import("@botonic/core").EventAction.ConditionalChannel;
|
|
83
61
|
channel: string;
|
package/lib/cjs/index-types.d.ts
CHANGED
|
@@ -57,15 +57,19 @@ export interface MinimalHubtypeMessage {
|
|
|
57
57
|
type: string;
|
|
58
58
|
action: string;
|
|
59
59
|
text: string;
|
|
60
|
+
event_data?: Record<string, unknown> | null;
|
|
60
61
|
}
|
|
61
62
|
export interface WebchatLocaleContents {
|
|
62
63
|
inputPlaceholder: string;
|
|
63
64
|
}
|
|
65
|
+
export interface GetMessageByIdOptions {
|
|
66
|
+
includeDebugEvents?: boolean;
|
|
67
|
+
}
|
|
64
68
|
export interface PreviewUtils {
|
|
65
69
|
getChunkIdsGroupedBySource: (chunkIds: string[]) => Promise<ChunkIdsGroupedBySourceData[]>;
|
|
66
70
|
onClickOpenChunks: (chunkIdsGroupedBySource: ChunkIdsGroupedBySourceData[]) => void;
|
|
67
71
|
onClickOpenToolResults: (toolExecution: ToolExecution) => void;
|
|
68
|
-
getMessageById: (messageId: string) => Promise<MinimalHubtypeMessage>;
|
|
72
|
+
getMessageById: (messageId: string, options?: GetMessageByIdOptions) => Promise<MinimalHubtypeMessage>;
|
|
69
73
|
trackPreviewEventOpened: (eventProperties: Record<string, unknown>) => void;
|
|
70
74
|
}
|
|
71
75
|
export interface WebchatArgs {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-types.js","sourceRoot":"","sources":["../../src/index-types.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index-types.js","sourceRoot":"","sources":["../../src/index-types.ts"],"names":[],"mappings":";;;AA8KA,IAAY,OAKX;AALD,WAAY,OAAO;IACjB,sBAAW,CAAA;IACX,wBAAa,CAAA;IACb,0BAAe,CAAA;IACf,4BAAiB,CAAA;AACnB,CAAC,EALW,OAAO,uBAAP,OAAO,QAKlB;AAED,IAAY,MAGX;AAHD,WAAY,MAAM;IAChB,0BAAgB,CAAA;IAChB,4BAAkB,CAAA;AACpB,CAAC,EAHW,MAAM,sBAAN,MAAM,QAGjB"}
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InputPanel = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
-
const core_1 = require("@botonic/core");
|
|
6
5
|
const react_1 = require("react");
|
|
7
|
-
const uuid_1 = require("uuid");
|
|
8
6
|
const constants_1 = require("../../constants");
|
|
9
7
|
const message_utils_1 = require("../../message-utils");
|
|
10
8
|
const context_1 = require("../../webchat/context");
|
|
@@ -16,6 +14,7 @@ const persistent_menu_1 = require("./persistent-menu");
|
|
|
16
14
|
const send_button_1 = require("./send-button");
|
|
17
15
|
const styles_1 = require("./styles");
|
|
18
16
|
const textarea_1 = require("./textarea");
|
|
17
|
+
const use_typing_chat_event_sender_1 = require("./use-typing-chat-event-sender");
|
|
19
18
|
const InputPanel = ({ handleAttachment, textareaRef, host, onUserInput, }) => {
|
|
20
19
|
const { getThemeProperty, sendText, togglePersistentMenu, toggleEmojiPicker, webchatState, inputPanelRef, } = (0, react_1.useContext)(context_1.WebchatContext);
|
|
21
20
|
const handleSelectedEmoji = event => {
|
|
@@ -38,21 +37,12 @@ const InputPanel = ({ handleAttachment, textareaRef, host, onUserInput, }) => {
|
|
|
38
37
|
await sendText(textareaRef.current?.value);
|
|
39
38
|
textareaRef.current.value = '';
|
|
40
39
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (onUserInput) {
|
|
48
|
-
onUserInput({
|
|
49
|
-
user: webchatState.session.user,
|
|
50
|
-
input: chatEventInput,
|
|
51
|
-
session: webchatState.session,
|
|
52
|
-
lastRoutePath: webchatState.lastRoutePath,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
};
|
|
40
|
+
// Network layer: deduplicates typing_on/off before they reach onUserInput.
|
|
41
|
+
const sendChatEvent = (0, use_typing_chat_event_sender_1.useTypingChatEventSender)({
|
|
42
|
+
onUserInput,
|
|
43
|
+
session: webchatState.session,
|
|
44
|
+
lastRoutePath: webchatState.lastRoutePath,
|
|
45
|
+
});
|
|
56
46
|
return ((0, jsx_runtime_1.jsxs)(styles_1.UserInputContainer, { id: constants_2.BotonicContainerId.InputPanel, ref: inputPanelRef, style: {
|
|
57
47
|
...getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.userInputStyle),
|
|
58
48
|
}, className: 'user-input-container', children: [webchatState.isEmojiPickerOpen && ((0, jsx_runtime_1.jsx)(opened_emoji_picker_1.OpenedEmojiPicker, { onEmojiClick: handleSelectedEmoji, onClick: handleEmojiClick })), (0, jsx_runtime_1.jsx)(persistent_menu_1.PersistentMenu, { onClick: handleMenu }), (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { host: host, textareaRef: textareaRef, sendChatEvent: sendChatEvent, sendTextAreaText: sendTextAreaText }), (0, jsx_runtime_1.jsx)(emoji_picker_1.EmojiPicker, { onClick: handleEmojiClick }), (0, jsx_runtime_1.jsx)(attachment_1.Attachment, { onChange: handleAttachment, accept: (0, message_utils_1.getFullMimeWhitelist)().join(',') }), (0, jsx_runtime_1.jsx)(send_button_1.SendButton, { onClick: sendTextAreaText })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/webchat/input-panel/index.tsx"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/webchat/input-panel/index.tsx"],"names":[],"mappings":";;;;AACA,iCAAkC;AAElC,+CAAyC;AACzC,uDAA0D;AAC1D,mDAAsD;AACtD,4CAAiD;AACjD,6CAAyC;AACzC,iDAA4C;AAC5C,+DAAyD;AACzD,uDAAkD;AAClD,+CAA0C;AAC1C,qCAA6C;AAC7C,yCAAqC;AACrC,iFAAyE;AASlE,MAAM,UAAU,GAAG,CAAC,EACzB,gBAAgB,EAChB,WAAW,EACX,IAAI,EACJ,WAAW,GACK,EAAE,EAAE;IACpB,MAAM,EACJ,gBAAgB,EAChB,QAAQ,EACR,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,aAAa,GACd,GAAG,IAAA,kBAAU,EAAC,wBAAc,CAAC,CAAA;IAE9B,MAAM,mBAAmB,GAAG,KAAK,CAAC,EAAE;QAClC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,OAAM;QACR,CAAC;QAED,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAA;QACxC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IAC7B,CAAC,CAAA;IAED,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,iBAAiB,CAAC,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAA;IACpD,CAAC,CAAA;IAED,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,oBAAoB,CAAC,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAA;IAC1D,CAAC,CAAA;IAED,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;QAClC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC1C,WAAW,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAA;IAChC,CAAC,CAAA;IAED,2EAA2E;IAC3E,MAAM,aAAa,GAAG,IAAA,uDAAwB,EAAC;QAC7C,WAAW;QACX,OAAO,EAAE,YAAY,CAAC,OAAO;QAC7B,aAAa,EAAE,YAAY,CAAC,aAAa;KAC1C,CAAC,CAAA;IAEF,OAAO,CACL,wBAAC,2BAAkB,IACjB,EAAE,EAAE,8BAAkB,CAAC,UAAU,EACjC,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE;YACL,GAAG,gBAAgB,CAAC,mBAAO,CAAC,iBAAiB,CAAC,cAAc,CAAC;SAC9D,EACD,SAAS,EAAC,sBAAsB,aAE/B,YAAY,CAAC,iBAAiB,IAAI,CACjC,uBAAC,uCAAiB,IAChB,YAAY,EAAE,mBAAmB,EACjC,OAAO,EAAE,gBAAgB,GACzB,CACH,EAED,uBAAC,gCAAc,IAAC,OAAO,EAAE,UAAU,GAAI,EAEvC,uBAAC,mBAAQ,IACP,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,gBAAgB,GAClC,EAEF,uBAAC,0BAAW,IAAC,OAAO,EAAE,gBAAgB,GAAI,EAE1C,uBAAC,uBAAU,IACT,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,IAAA,oCAAoB,GAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GACxC,EAEF,uBAAC,wBAAU,IAAC,OAAO,EAAE,gBAAgB,GAAI,IACtB,CACtB,CAAA;AACH,CAAC,CAAA;AAnFY,QAAA,UAAU,cAmFtB"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import type { TypingChatEvent } from './typing-network-sender';
|
|
2
3
|
interface TextareaProps {
|
|
3
4
|
host: HTMLElement;
|
|
4
5
|
textareaRef: React.MutableRefObject<HTMLTextAreaElement | undefined>;
|
|
5
|
-
sendChatEvent: (event:
|
|
6
|
+
sendChatEvent: (event: TypingChatEvent) => Promise<boolean>;
|
|
6
7
|
sendTextAreaText: () => Promise<void>;
|
|
7
8
|
}
|
|
9
|
+
export { TYPING_IDLE_MS } from './use-typing-session';
|
|
8
10
|
export declare const Textarea: ({ host, textareaRef, sendChatEvent, sendTextAreaText, }: TextareaProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export {};
|
|
@@ -1,69 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Textarea = void 0;
|
|
3
|
+
exports.Textarea = exports.TYPING_IDLE_MS = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const react_textarea_autosize_1 = tslib_1.__importDefault(require("react-textarea-autosize"));
|
|
8
|
-
const index_types_1 = require("../../index-types");
|
|
9
8
|
const context_1 = require("../../webchat/context");
|
|
10
9
|
const hooks_1 = require("../hooks");
|
|
11
10
|
const styles_1 = require("./styles");
|
|
11
|
+
const use_typing_session_1 = require("./use-typing-session");
|
|
12
|
+
var use_typing_session_2 = require("./use-typing-session");
|
|
13
|
+
Object.defineProperty(exports, "TYPING_IDLE_MS", { enumerable: true, get: function () { return use_typing_session_2.TYPING_IDLE_MS; } });
|
|
12
14
|
const Textarea = ({ host, textareaRef, sendChatEvent, sendTextAreaText, }) => {
|
|
13
15
|
const { webchatState, setIsInputFocused } = (0, react_1.useContext)(context_1.WebchatContext);
|
|
16
|
+
// UI layer: decides when the user is typing. Network dedup lives in sendChatEvent.
|
|
17
|
+
const { stopTyping, onTextChange } = (0, use_typing_session_1.useTypingSession)(sendChatEvent);
|
|
14
18
|
(0, hooks_1.useDeviceAdapter)(host, webchatState.isWebchatOpen);
|
|
15
|
-
let isTyping = false;
|
|
16
|
-
let typingTimeout = null;
|
|
17
19
|
const persistentMenuOptions = webchatState.theme.userInput?.persistentMenu;
|
|
18
20
|
const placeholder = webchatState.theme.userInput?.box?.placeholder;
|
|
19
21
|
const userInputBoxStyle = webchatState.theme.userInput?.box?.style;
|
|
20
|
-
const onKeyDown = event => {
|
|
21
|
-
if (event.
|
|
22
|
+
const onKeyDown = async (event) => {
|
|
23
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
22
24
|
event.preventDefault();
|
|
23
|
-
sendTextAreaText
|
|
24
|
-
stopTyping();
|
|
25
|
+
// Run in parallel: stop typing must not wait for sendTextAreaText to finish.
|
|
26
|
+
await Promise.all([stopTyping(), sendTextAreaText()]);
|
|
25
27
|
}
|
|
26
28
|
};
|
|
27
|
-
const onKeyUp = () => {
|
|
28
|
-
if (!textareaRef.current) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (textareaRef.current.value === '') {
|
|
32
|
-
stopTyping();
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (!isTyping) {
|
|
36
|
-
startTyping();
|
|
37
|
-
}
|
|
38
|
-
clearTimeoutWithReset(true);
|
|
39
|
-
};
|
|
40
|
-
const clearTimeoutWithReset = (reset) => {
|
|
41
|
-
const waitTime = 20 * 1000;
|
|
42
|
-
if (typingTimeout) {
|
|
43
|
-
clearTimeout(typingTimeout);
|
|
44
|
-
}
|
|
45
|
-
if (reset) {
|
|
46
|
-
typingTimeout = setTimeout(stopTyping, waitTime);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
const startTyping = () => {
|
|
50
|
-
isTyping = true;
|
|
51
|
-
sendChatEvent(index_types_1.Typing.On);
|
|
52
|
-
};
|
|
53
|
-
const stopTyping = () => {
|
|
54
|
-
clearTimeoutWithReset(false);
|
|
55
|
-
isTyping = false;
|
|
56
|
-
sendChatEvent(index_types_1.Typing.Off);
|
|
57
|
-
};
|
|
58
|
-
const handleFocus = () => {
|
|
59
|
-
setIsInputFocused(true);
|
|
60
|
-
};
|
|
61
|
-
const handleBlur = () => {
|
|
62
|
-
setIsInputFocused(false);
|
|
63
|
-
};
|
|
64
29
|
return ((0, jsx_runtime_1.jsx)(styles_1.TextAreaContainer, { children: (0, jsx_runtime_1.jsx)(react_textarea_autosize_1.default, { ref: (ref) => {
|
|
65
30
|
textareaRef.current = ref;
|
|
66
|
-
}, onFocus:
|
|
31
|
+
}, onFocus: () => setIsInputFocused(true), onBlur: async () => {
|
|
32
|
+
setIsInputFocused(false);
|
|
33
|
+
await stopTyping();
|
|
34
|
+
}, onChange: async (event) => {
|
|
35
|
+
await onTextChange(event.target.value);
|
|
36
|
+
}, name: 'text', maxRows: 4, wrap: 'soft', maxLength: 1000, placeholder: placeholder, autoFocus: false, onKeyDown: onKeyDown, style: {
|
|
67
37
|
display: 'flex',
|
|
68
38
|
fontSize: 16,
|
|
69
39
|
width: '100%',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../../../src/webchat/input-panel/textarea.tsx"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../../../src/webchat/input-panel/textarea.tsx"],"names":[],"mappings":";;;;;AACA,iCAAkC;AAClC,8FAAsD;AAEtD,mDAAsD;AACtD,oCAA2C;AAC3C,qCAA4C;AAE5C,6DAAuD;AASvD,2DAAqD;AAA5C,oHAAA,cAAc,OAAA;AAEhB,MAAM,QAAQ,GAAG,CAAC,EACvB,IAAI,EACJ,WAAW,EACX,aAAa,EACb,gBAAgB,GACF,EAAE,EAAE;IAClB,MAAM,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,IAAA,kBAAU,EAAC,wBAAc,CAAC,CAAA;IACtE,mFAAmF;IACnF,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,IAAA,qCAAgB,EAAC,aAAa,CAAC,CAAA;IAEpE,IAAA,wBAAgB,EAAC,IAAI,EAAE,YAAY,CAAC,aAAa,CAAC,CAAA;IAElD,MAAM,qBAAqB,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,cAAc,CAAA;IAC1E,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,WAAW,CAAA;IAClE,MAAM,iBAAiB,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAA;IAElE,MAAM,SAAS,GAAG,KAAK,EAAC,KAAK,EAAC,EAAE;QAC9B,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC7C,KAAK,CAAC,cAAc,EAAE,CAAA;YACtB,6EAA6E;YAC7E,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAA;QACvD,CAAC;IACH,CAAC,CAAA;IAED,OAAO,CACL,uBAAC,0BAAiB,cAChB,uBAAC,iCAAgB,IACf,GAAG,EAAE,CAAC,GAAwB,EAAE,EAAE;gBAChC,WAAW,CAAC,OAAO,GAAG,GAAG,CAAA;YAC3B,CAAC,EACD,OAAO,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,EACtC,MAAM,EAAE,KAAK,IAAI,EAAE;gBACjB,iBAAiB,CAAC,KAAK,CAAC,CAAA;gBACxB,MAAM,UAAU,EAAE,CAAA;YACpB,CAAC,EACD,QAAQ,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE;gBACtB,MAAM,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACxC,CAAC,EACD,IAAI,EAAC,MAAM,EACX,OAAO,EAAE,CAAC,EACV,IAAI,EAAC,MAAM,EACX,SAAS,EAAE,IAAI,EACf,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,KAAK,EAChB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE;gBACL,OAAO,EAAE,MAAM;gBACf,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,MAAM;gBACd,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,MAAM;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;gBAC3C,UAAU,EAAE,SAAS;gBACrB,GAAG,iBAAiB;aACrB,GACD,GACgB,CACrB,CAAA;AACH,CAAC,CAAA;AA9DY,QAAA,QAAQ,YA8DpB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Session as CoreSession } from '@botonic/core';
|
|
2
|
+
import { INPUT } from '@botonic/core';
|
|
3
|
+
import { Typing } from '../../index-types';
|
|
4
|
+
/** Network debounce before `typing_off` is sent after a stop signal. */
|
|
5
|
+
export declare const TYPING_OFF_DEBOUNCE_MS = 2000;
|
|
6
|
+
export type TypingChatEvent = Typing.On | Typing.Off;
|
|
7
|
+
/** `true` when `typing_on` was delivered to the server. */
|
|
8
|
+
export type TypingOnSendResult = boolean;
|
|
9
|
+
/** `true` when `typing_off` was scheduled; delivery happens after debounce. */
|
|
10
|
+
export type TypingOffSendResult = boolean;
|
|
11
|
+
export interface ChatEventContext {
|
|
12
|
+
session: Partial<CoreSession>;
|
|
13
|
+
lastRoutePath?: string;
|
|
14
|
+
}
|
|
15
|
+
export type SendToServer = (chatEvent: TypingChatEvent, context: ChatEventContext) => Promise<boolean>;
|
|
16
|
+
export declare function buildChatEventPayload(chatEvent: TypingChatEvent, { session, lastRoutePath }: ChatEventContext): {
|
|
17
|
+
user: import("@botonic/core").SessionUser<any> | undefined;
|
|
18
|
+
input: {
|
|
19
|
+
id: string;
|
|
20
|
+
type: INPUT;
|
|
21
|
+
data: TypingChatEvent;
|
|
22
|
+
};
|
|
23
|
+
session: Partial<CoreSession<any>>;
|
|
24
|
+
lastRoutePath: string | undefined;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Network-layer sender for typing_on / typing_off.
|
|
28
|
+
*
|
|
29
|
+
* Guarantees at most one typing_on per session, debounced typing_off,
|
|
30
|
+
* and matching session context between on/off pairs.
|
|
31
|
+
*/
|
|
32
|
+
export declare class TypingNetworkSender {
|
|
33
|
+
private readonly getContext;
|
|
34
|
+
private readonly sendToServer;
|
|
35
|
+
private disposed;
|
|
36
|
+
private isTypingOnServer;
|
|
37
|
+
private activeContext;
|
|
38
|
+
private pendingOffTimer;
|
|
39
|
+
private pendingTypingOn;
|
|
40
|
+
constructor(getContext: () => ChatEventContext, sendToServer: SendToServer);
|
|
41
|
+
/**
|
|
42
|
+
* For `Typing.On`, returns whether the event was delivered.
|
|
43
|
+
* For `Typing.Off`, returns whether the stop was scheduled.
|
|
44
|
+
*/
|
|
45
|
+
send(chatEvent: TypingChatEvent): Promise<TypingOnSendResult | TypingOffSendResult>;
|
|
46
|
+
private sendTypingOffBestEffort;
|
|
47
|
+
dispose(): void;
|
|
48
|
+
private userStartedTyping;
|
|
49
|
+
private userStoppedTyping;
|
|
50
|
+
private resetTypingState;
|
|
51
|
+
private cancelPendingOff;
|
|
52
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypingNetworkSender = exports.TYPING_OFF_DEBOUNCE_MS = void 0;
|
|
4
|
+
exports.buildChatEventPayload = buildChatEventPayload;
|
|
5
|
+
const core_1 = require("@botonic/core");
|
|
6
|
+
const uuid_1 = require("uuid");
|
|
7
|
+
const index_types_1 = require("../../index-types");
|
|
8
|
+
/** Network debounce before `typing_off` is sent after a stop signal. */
|
|
9
|
+
exports.TYPING_OFF_DEBOUNCE_MS = 2000;
|
|
10
|
+
function buildChatEventPayload(chatEvent, { session, lastRoutePath }) {
|
|
11
|
+
return {
|
|
12
|
+
user: session.user,
|
|
13
|
+
input: {
|
|
14
|
+
id: (0, uuid_1.v7)(),
|
|
15
|
+
type: core_1.INPUT.CHAT_EVENT,
|
|
16
|
+
data: chatEvent,
|
|
17
|
+
},
|
|
18
|
+
session,
|
|
19
|
+
lastRoutePath,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Network-layer sender for typing_on / typing_off.
|
|
24
|
+
*
|
|
25
|
+
* Guarantees at most one typing_on per session, debounced typing_off,
|
|
26
|
+
* and matching session context between on/off pairs.
|
|
27
|
+
*/
|
|
28
|
+
class TypingNetworkSender {
|
|
29
|
+
constructor(getContext, sendToServer) {
|
|
30
|
+
this.getContext = getContext;
|
|
31
|
+
this.sendToServer = sendToServer;
|
|
32
|
+
this.disposed = false;
|
|
33
|
+
this.isTypingOnServer = false;
|
|
34
|
+
// Snapshot of session/route captured when typing_on was delivered.
|
|
35
|
+
this.activeContext = null;
|
|
36
|
+
this.pendingOffTimer = null;
|
|
37
|
+
this.pendingTypingOn = null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* For `Typing.On`, returns whether the event was delivered.
|
|
41
|
+
* For `Typing.Off`, returns whether the stop was scheduled.
|
|
42
|
+
*/
|
|
43
|
+
async send(chatEvent) {
|
|
44
|
+
if (chatEvent === index_types_1.Typing.On) {
|
|
45
|
+
return this.userStartedTyping();
|
|
46
|
+
}
|
|
47
|
+
return this.userStoppedTyping();
|
|
48
|
+
}
|
|
49
|
+
sendTypingOffBestEffort(context) {
|
|
50
|
+
return this.sendToServer(index_types_1.Typing.Off, context).catch(() => { });
|
|
51
|
+
}
|
|
52
|
+
dispose() {
|
|
53
|
+
this.disposed = true;
|
|
54
|
+
this.cancelPendingOff();
|
|
55
|
+
if (!this.isTypingOnServer || !this.activeContext) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Unmount should not leave the server thinking the user is still typing.
|
|
59
|
+
const context = this.activeContext;
|
|
60
|
+
this.resetTypingState();
|
|
61
|
+
this.sendTypingOffBestEffort(context);
|
|
62
|
+
}
|
|
63
|
+
async userStartedTyping() {
|
|
64
|
+
if (this.pendingTypingOn) {
|
|
65
|
+
return this.pendingTypingOn;
|
|
66
|
+
}
|
|
67
|
+
// User resumed typing before the debounced typing_off was sent.
|
|
68
|
+
this.cancelPendingOff();
|
|
69
|
+
if (this.isTypingOnServer) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
this.pendingTypingOn = (async () => {
|
|
73
|
+
const context = this.getContext();
|
|
74
|
+
try {
|
|
75
|
+
const delivered = await this.sendToServer(index_types_1.Typing.On, context);
|
|
76
|
+
if (this.disposed) {
|
|
77
|
+
// typing_on resolved after unmount: immediately balance with typing_off.
|
|
78
|
+
if (delivered) {
|
|
79
|
+
this.sendTypingOffBestEffort(context);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
if (delivered) {
|
|
84
|
+
this.isTypingOnServer = true;
|
|
85
|
+
this.activeContext = context;
|
|
86
|
+
}
|
|
87
|
+
return delivered;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
this.pendingTypingOn = null;
|
|
91
|
+
}
|
|
92
|
+
})();
|
|
93
|
+
return this.pendingTypingOn;
|
|
94
|
+
}
|
|
95
|
+
userStoppedTyping() {
|
|
96
|
+
if (!this.isTypingOnServer || !this.activeContext) {
|
|
97
|
+
return Promise.resolve(false);
|
|
98
|
+
}
|
|
99
|
+
this.cancelPendingOff();
|
|
100
|
+
const context = this.activeContext;
|
|
101
|
+
// Coalesce blur + clear + send into a single typing_off.
|
|
102
|
+
this.pendingOffTimer = setTimeout(() => {
|
|
103
|
+
this.pendingOffTimer = null;
|
|
104
|
+
this.resetTypingState();
|
|
105
|
+
this.sendTypingOffBestEffort(context);
|
|
106
|
+
}, exports.TYPING_OFF_DEBOUNCE_MS);
|
|
107
|
+
return Promise.resolve(true);
|
|
108
|
+
}
|
|
109
|
+
resetTypingState() {
|
|
110
|
+
this.isTypingOnServer = false;
|
|
111
|
+
this.activeContext = null;
|
|
112
|
+
}
|
|
113
|
+
cancelPendingOff() {
|
|
114
|
+
if (!this.pendingOffTimer) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
clearTimeout(this.pendingOffTimer);
|
|
118
|
+
this.pendingOffTimer = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.TypingNetworkSender = TypingNetworkSender;
|
|
122
|
+
//# sourceMappingURL=typing-network-sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typing-network-sender.js","sourceRoot":"","sources":["../../../../src/webchat/input-panel/typing-network-sender.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Session as CoreSession } from '@botonic/core';
|
|
2
|
+
import { buildChatEventPayload, type TypingChatEvent } from './typing-network-sender';
|
|
3
|
+
export type TypingChatEventPayload = ReturnType<typeof buildChatEventPayload>;
|
|
4
|
+
interface UseTypingChatEventSenderArgs {
|
|
5
|
+
onUserInput?: (args: TypingChatEventPayload) => Promise<void>;
|
|
6
|
+
session: Partial<CoreSession>;
|
|
7
|
+
lastRoutePath?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* React bridge from Textarea to TypingNetworkSender.
|
|
11
|
+
*
|
|
12
|
+
* Keeps one sender instance per input panel and forwards typing events
|
|
13
|
+
* to onUserInput with the current session context.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useTypingChatEventSender({ onUserInput, session, lastRoutePath, }: UseTypingChatEventSenderArgs): (chatEvent: TypingChatEvent) => Promise<boolean>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useTypingChatEventSender = useTypingChatEventSender;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const typing_network_sender_1 = require("./typing-network-sender");
|
|
6
|
+
/**
|
|
7
|
+
* React bridge from Textarea to TypingNetworkSender.
|
|
8
|
+
*
|
|
9
|
+
* Keeps one sender instance per input panel and forwards typing events
|
|
10
|
+
* to onUserInput with the current session context.
|
|
11
|
+
*/
|
|
12
|
+
function useTypingChatEventSender({ onUserInput, session, lastRoutePath, }) {
|
|
13
|
+
// Always read the latest handler/session without recreating the sender.
|
|
14
|
+
const contextRef = (0, react_1.useRef)({ onUserInput, session, lastRoutePath });
|
|
15
|
+
const typingSenderRef = (0, react_1.useRef)(null);
|
|
16
|
+
contextRef.current = { onUserInput, session, lastRoutePath };
|
|
17
|
+
if (!typingSenderRef.current) {
|
|
18
|
+
typingSenderRef.current = new typing_network_sender_1.TypingNetworkSender(() => ({
|
|
19
|
+
session: contextRef.current.session,
|
|
20
|
+
lastRoutePath: contextRef.current.lastRoutePath,
|
|
21
|
+
}), async (chatEvent, context) => {
|
|
22
|
+
const handler = contextRef.current.onUserInput;
|
|
23
|
+
if (!handler) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
await handler((0, typing_network_sender_1.buildChatEventPayload)(chatEvent, context));
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Let the UI retry on the next keystroke.
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
(0, react_1.useEffect)(() => {
|
|
37
|
+
return () => {
|
|
38
|
+
typingSenderRef.current?.dispose();
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
return (0, react_1.useCallback)(async (chatEvent) => {
|
|
42
|
+
return (await typingSenderRef.current?.send(chatEvent)) ?? false;
|
|
43
|
+
}, []);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=use-typing-chat-event-sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-typing-chat-event-sender.js","sourceRoot":"","sources":["../../../../src/webchat/input-panel/use-typing-chat-event-sender.ts"],"names":[],"mappings":";;AAsBA,4DA4CC;AAjED,iCAAsD;AACtD,mEAIgC;AAUhC;;;;;GAKG;AACH,SAAgB,wBAAwB,CAAC,EACvC,WAAW,EACX,OAAO,EACP,aAAa,GACgB;IAC7B,wEAAwE;IACxE,MAAM,UAAU,GAAG,IAAA,cAAM,EAAC,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAA;IAClE,MAAM,eAAe,GAAG,IAAA,cAAM,EAA6B,IAAI,CAAC,CAAA;IAEhE,UAAU,CAAC,OAAO,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,CAAA;IAE5D,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC;QAC7B,eAAe,CAAC,OAAO,GAAG,IAAI,2CAAmB,CAC/C,GAAG,EAAE,CAAC,CAAC;YACL,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO;YACnC,aAAa,EAAE,UAAU,CAAC,OAAO,CAAC,aAAa;SAChD,CAAC,EACF,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;YAC3B,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,CAAA;YAE9C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,KAAK,CAAA;YACd,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,IAAA,6CAAqB,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;gBACxD,OAAO,IAAI,CAAA;YACb,CAAC;YAAC,MAAM,CAAC;gBACP,0CAA0C;gBAC1C,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC,CACF,CAAA;IACH,CAAC;IAED,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,OAAO,GAAG,EAAE;YACV,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,CAAA;QACpC,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,IAAA,mBAAW,EAAC,KAAK,EAAE,SAA0B,EAAoB,EAAE;QACxE,OAAO,CAAC,MAAM,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,KAAK,CAAA;IAClE,CAAC,EAAE,EAAE,CAAC,CAAA;AACR,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TypingChatEvent } from './typing-network-sender';
|
|
2
|
+
/** Local UI inactivity before the textarea stops emitting typing events. */
|
|
3
|
+
export declare const TYPING_IDLE_MS: number;
|
|
4
|
+
type SendTypingEvent = (event: TypingChatEvent) => Promise<boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* UI-layer typing session for the textarea.
|
|
7
|
+
*
|
|
8
|
+
* Decides *when* the user is typing and requests typing_on / typing_off.
|
|
9
|
+
* Deduplication and network debouncing live in TypingNetworkSender instead.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useTypingSession(sendChatEvent: SendTypingEvent): {
|
|
12
|
+
stopTyping: () => Promise<void>;
|
|
13
|
+
onTextChange: (value: string) => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TYPING_IDLE_MS = void 0;
|
|
4
|
+
exports.useTypingSession = useTypingSession;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const index_types_1 = require("../../index-types");
|
|
7
|
+
/** Local UI inactivity before the textarea stops emitting typing events. */
|
|
8
|
+
exports.TYPING_IDLE_MS = 10 * 1000;
|
|
9
|
+
/**
|
|
10
|
+
* UI-layer typing session for the textarea.
|
|
11
|
+
*
|
|
12
|
+
* Decides *when* the user is typing and requests typing_on / typing_off.
|
|
13
|
+
* Deduplication and network debouncing live in TypingNetworkSender instead.
|
|
14
|
+
*/
|
|
15
|
+
function useTypingSession(sendChatEvent) {
|
|
16
|
+
const isTyping = (0, react_1.useRef)(false);
|
|
17
|
+
// Bumps on each start/stop so stale async stopTyping() calls can be ignored.
|
|
18
|
+
const startOrStopTypingCount = (0, react_1.useRef)(0);
|
|
19
|
+
const idleTimer = (0, react_1.useRef)(null);
|
|
20
|
+
// Shares one in-flight typing_on while delivery is still pending.
|
|
21
|
+
const pendingTypingOn = (0, react_1.useRef)(null);
|
|
22
|
+
const stopTyping = (0, react_1.useCallback)(async () => {
|
|
23
|
+
const countWhenStopWasRequested = ++startOrStopTypingCount.current;
|
|
24
|
+
if (idleTimer.current) {
|
|
25
|
+
clearTimeout(idleTimer.current);
|
|
26
|
+
idleTimer.current = null;
|
|
27
|
+
}
|
|
28
|
+
// Wait for typing_on to settle before deciding whether to send typing_off.
|
|
29
|
+
if (pendingTypingOn.current) {
|
|
30
|
+
await pendingTypingOn.current;
|
|
31
|
+
}
|
|
32
|
+
// Let same-turn input events (e.g. Enter then type next message) bump the counter first.
|
|
33
|
+
await Promise.resolve();
|
|
34
|
+
if (countWhenStopWasRequested !== startOrStopTypingCount.current) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!isTyping.current) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
isTyping.current = false;
|
|
41
|
+
await sendChatEvent(index_types_1.Typing.Off);
|
|
42
|
+
}, [sendChatEvent]);
|
|
43
|
+
const startTyping = (0, react_1.useCallback)(async () => {
|
|
44
|
+
if (isTyping.current) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (pendingTypingOn.current) {
|
|
48
|
+
return pendingTypingOn.current;
|
|
49
|
+
}
|
|
50
|
+
pendingTypingOn.current = (async () => {
|
|
51
|
+
try {
|
|
52
|
+
const accepted = await sendChatEvent(index_types_1.Typing.On);
|
|
53
|
+
// Only mark active after the network layer confirms delivery.
|
|
54
|
+
if (accepted) {
|
|
55
|
+
isTyping.current = true;
|
|
56
|
+
}
|
|
57
|
+
return accepted;
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
pendingTypingOn.current = null;
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
return pendingTypingOn.current;
|
|
64
|
+
}, [sendChatEvent]);
|
|
65
|
+
const onTextChange = (0, react_1.useCallback)(async (value) => {
|
|
66
|
+
if (value === '') {
|
|
67
|
+
await stopTyping();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const countWhenUserTyped = ++startOrStopTypingCount.current;
|
|
71
|
+
await startTyping();
|
|
72
|
+
if (countWhenUserTyped !== startOrStopTypingCount.current) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!isTyping.current) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Reset the idle timer on every keystroke.
|
|
79
|
+
if (idleTimer.current) {
|
|
80
|
+
clearTimeout(idleTimer.current);
|
|
81
|
+
}
|
|
82
|
+
idleTimer.current = setTimeout(() => {
|
|
83
|
+
stopTyping().catch(() => { });
|
|
84
|
+
}, exports.TYPING_IDLE_MS);
|
|
85
|
+
}, [startTyping, stopTyping]);
|
|
86
|
+
const stopTypingRef = (0, react_1.useRef)(stopTyping);
|
|
87
|
+
stopTypingRef.current = stopTyping;
|
|
88
|
+
(0, react_1.useEffect)(() => {
|
|
89
|
+
return () => {
|
|
90
|
+
if (idleTimer.current) {
|
|
91
|
+
clearTimeout(idleTimer.current);
|
|
92
|
+
}
|
|
93
|
+
stopTypingRef.current().catch(() => { });
|
|
94
|
+
};
|
|
95
|
+
}, []);
|
|
96
|
+
return { stopTyping, onTextChange };
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=use-typing-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-typing-session.js","sourceRoot":"","sources":["../../../../src/webchat/input-panel/use-typing-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
import type { EventCustom, EventFeedback } from '@botonic/core';
|
|
2
|
-
export declare enum EventAction {
|
|
3
|
-
FeedbackKnowledgebase = "feedback_knowledgebase"
|
|
4
|
-
}
|
|
5
|
-
interface TrackKnowledgebaseFeedbackArgs {
|
|
6
|
-
messageId: string;
|
|
7
|
-
isUseful: boolean;
|
|
8
|
-
botInteractionId?: string;
|
|
9
|
-
inferenceId?: string;
|
|
10
|
-
}
|
|
11
2
|
interface UseTracking {
|
|
12
|
-
trackKnowledgebaseFeedback: ({ messageId, isUseful, botInteractionId, inferenceId, }: TrackKnowledgebaseFeedbackArgs) => Promise<void>;
|
|
13
3
|
trackCustomEvent: (event: EventCustom) => Promise<void>;
|
|
14
4
|
trackFeedbackEvent: (event: EventFeedback) => Promise<void>;
|
|
15
5
|
}
|