@agentforge-io/chat-sdk 2.4.0-dev.0 → 2.4.0-dev.1
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/react.js +36 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -385,6 +385,28 @@ function ChatWidget(props) {
|
|
|
385
385
|
hasInteractedRef.current = true;
|
|
386
386
|
setDraft('');
|
|
387
387
|
void session.send(text);
|
|
388
|
+
// Mobile UX: when the send button disables (sendDisabled flips
|
|
389
|
+
// true the moment status goes to 'sending'), focus jumps to
|
|
390
|
+
// <body> and the on-screen keyboard collapses. Re-anchor focus
|
|
391
|
+
// on the textarea synchronously so the visitor keeps typing
|
|
392
|
+
// their next message without re-tapping. We schedule one rAF
|
|
393
|
+
// to win the race against React's status flip + button disable
|
|
394
|
+
// (a single tick is enough — mobile browsers haven't decided
|
|
395
|
+
// to dismiss the keyboard yet).
|
|
396
|
+
if (typeof window !== 'undefined') {
|
|
397
|
+
const el = inputRef.current;
|
|
398
|
+
if (el) {
|
|
399
|
+
el.focus({ preventScroll: true });
|
|
400
|
+
// Belt-and-braces: re-focus in the next frame in case
|
|
401
|
+
// React's render happens AFTER our synchronous focus call
|
|
402
|
+
// and steals it via the button-disable side effect.
|
|
403
|
+
window.requestAnimationFrame(() => {
|
|
404
|
+
if (document.activeElement !== el) {
|
|
405
|
+
el.focus({ preventScroll: true });
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
388
410
|
}, [session, draft]);
|
|
389
411
|
const onKeyDown = (0, react_1.useCallback)((e) => {
|
|
390
412
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
@@ -531,7 +553,20 @@ function ChatWidget(props) {
|
|
|
531
553
|
onShortcutClick(text, i);
|
|
532
554
|
else
|
|
533
555
|
setDraft(text);
|
|
534
|
-
}, children: text }, `${i}-${text}`))) })), (0, jsx_runtime_1.jsxs)("div", { className: "af-input-row", children: [composerLeftSlot && ((0, jsx_runtime_1.jsx)("div", { className: "af-input-left", children: composerLeftSlot })), (0, jsx_runtime_1.jsx)("textarea", { ref: inputRef, className: "af-input", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: onKeyDown, placeholder: inputPlaceholder ?? 'Type a message…', rows: 1,
|
|
556
|
+
}, children: text }, `${i}-${text}`))) })), (0, jsx_runtime_1.jsxs)("div", { className: "af-input-row", children: [composerLeftSlot && ((0, jsx_runtime_1.jsx)("div", { className: "af-input-left", children: composerLeftSlot })), (0, jsx_runtime_1.jsx)("textarea", { ref: inputRef, className: "af-input", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: onKeyDown, placeholder: inputPlaceholder ?? 'Type a message…', rows: 1,
|
|
557
|
+
// The textarea stays editable while the agent is
|
|
558
|
+
// streaming so the visitor can compose their next
|
|
559
|
+
// message without waiting. Only block when the
|
|
560
|
+
// conversation has actually ended OR before the
|
|
561
|
+
// session is ready at all.
|
|
562
|
+
disabled: status === 'ended' || status === 'loading' || status === 'idle' }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "af-send",
|
|
563
|
+
// `onMouseDown preventDefault` prevents the button from
|
|
564
|
+
// stealing focus from the textarea when the visitor
|
|
565
|
+
// taps Send. Without this, the focus shifts to the
|
|
566
|
+
// button just before `handleSend` runs, the button
|
|
567
|
+
// then disables (sendDisabled flips true), focus jumps
|
|
568
|
+
// to <body>, and on mobile the keyboard collapses.
|
|
569
|
+
onMouseDown: (e) => e.preventDefault(), onClick: handleSend, disabled: sendDisabled, "aria-label": "Send message", children: (0, jsx_runtime_1.jsx)(SendIcon, {}) })] }), !bare && (0, jsx_runtime_1.jsx)("div", { className: "af-footer", children: "Powered by AgentForge" })] })] }));
|
|
535
570
|
}
|
|
536
571
|
function MessageBubble({ message, session, readOnly, onDecision, onContinue, bare = false, showAvatar = false, avatarTheme, avatarName, avatarAgentId, speakerLabel, }) {
|
|
537
572
|
const kind = message.metadata?.kind;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge-io/chat-sdk",
|
|
3
|
-
"version": "2.4.0-dev.
|
|
3
|
+
"version": "2.4.0-dev.1",
|
|
4
4
|
"description": "Framework-free chat session SDK for AgentForge public chat tokens. Headless — no DOM. Drop into any frontend (React, Vue, Svelte, vanilla) and listen for events.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|