@xinghunm/ai-chat 1.1.0 → 1.1.2
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/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +243 -74
- package/dist/index.mjs +244 -75
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -68,6 +68,7 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
68
68
|
sendButton: "Send",
|
|
69
69
|
stopButton: "Stop",
|
|
70
70
|
retryButton: "Retry",
|
|
71
|
+
scrollToLatest: "Jump to latest",
|
|
71
72
|
placeholder: "Ask something...",
|
|
72
73
|
modeLabelAsk: "Ask",
|
|
73
74
|
modeLabelPlan: "Plan",
|
|
@@ -2338,11 +2339,11 @@ var TextInput = import_styled4.default.input`
|
|
|
2338
2339
|
color: rgba(255, 255, 255, 0.34);
|
|
2339
2340
|
}
|
|
2340
2341
|
`;
|
|
2341
|
-
var InlineOtherInput = (0, import_styled4.default)(import_compass_ui.
|
|
2342
|
+
var InlineOtherInput = (0, import_styled4.default)(import_compass_ui.Input)`
|
|
2342
2343
|
width: 100%;
|
|
2343
2344
|
margin-top: 0;
|
|
2344
2345
|
|
|
2345
|
-
.compass-input-
|
|
2346
|
+
.compass-input-wrapper {
|
|
2346
2347
|
min-height: 30px;
|
|
2347
2348
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
2348
2349
|
border-radius: 10px;
|
|
@@ -2351,22 +2352,22 @@ var InlineOtherInput = (0, import_styled4.default)(import_compass_ui.InputField)
|
|
|
2351
2352
|
padding: 2px 9px;
|
|
2352
2353
|
}
|
|
2353
2354
|
|
|
2354
|
-
.compass-input-
|
|
2355
|
+
.compass-input-wrapper:hover {
|
|
2355
2356
|
border-color: rgba(126, 160, 255, 0.28);
|
|
2356
2357
|
}
|
|
2357
2358
|
|
|
2358
|
-
.compass-input-
|
|
2359
|
+
.compass-input-wrapper:focus-within {
|
|
2359
2360
|
border-color: rgba(126, 160, 255, 0.42);
|
|
2360
2361
|
box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.14);
|
|
2361
2362
|
}
|
|
2362
2363
|
|
|
2363
|
-
.compass-input-
|
|
2364
|
+
.compass-input-input {
|
|
2364
2365
|
color: rgba(255, 255, 255, 0.92);
|
|
2365
2366
|
font-size: 13px;
|
|
2366
2367
|
line-height: 1.2;
|
|
2367
2368
|
}
|
|
2368
2369
|
|
|
2369
|
-
.compass-input-
|
|
2370
|
+
.compass-input-input::placeholder {
|
|
2370
2371
|
color: rgba(255, 255, 255, 0.34);
|
|
2371
2372
|
}
|
|
2372
2373
|
`;
|
|
@@ -3360,6 +3361,8 @@ var HeroSubtitle = import_styled8.default.p`
|
|
|
3360
3361
|
|
|
3361
3362
|
// src/components/chat-thread/index.tsx
|
|
3362
3363
|
var import_jsx_runtime10 = require("@emotion/react/jsx-runtime");
|
|
3364
|
+
var CHAT_THREAD_PINNED_THRESHOLD_PX = 32;
|
|
3365
|
+
var isThreadPinnedToBottom = (container) => container.scrollHeight - container.clientHeight - container.scrollTop <= CHAT_THREAD_PINNED_THRESHOLD_PX;
|
|
3363
3366
|
var renderChatMessage = ({
|
|
3364
3367
|
message,
|
|
3365
3368
|
mode,
|
|
@@ -3433,6 +3436,7 @@ var ChatThreadView = ({
|
|
|
3433
3436
|
streamingMessage,
|
|
3434
3437
|
error,
|
|
3435
3438
|
retryButtonLabel,
|
|
3439
|
+
scrollToLatestLabel,
|
|
3436
3440
|
onRetry,
|
|
3437
3441
|
onConfirmationSubmit,
|
|
3438
3442
|
onQuestionnaireSubmit,
|
|
@@ -3446,9 +3450,15 @@ var ChatThreadView = ({
|
|
|
3446
3450
|
const latestTurn = conversationTurns[conversationTurns.length - 1];
|
|
3447
3451
|
const previousTurns = conversationTurns.slice(0, -1);
|
|
3448
3452
|
const latestUserMessageId = latestTurn?.userMessage?.id;
|
|
3449
|
-
const
|
|
3453
|
+
const latestHistoryMessage = historyMessages[historyMessages.length - 1];
|
|
3454
|
+
const latestTurnRef = (0, import_react11.useRef)(null);
|
|
3450
3455
|
const reservedSpaceFrameRef = (0, import_react11.useRef)(null);
|
|
3456
|
+
const isPinnedRef = (0, import_react11.useRef)(true);
|
|
3457
|
+
const lastHistoryMessageIdRef = (0, import_react11.useRef)(latestHistoryMessage?.id);
|
|
3458
|
+
const lastStreamingMessageIdRef = (0, import_react11.useRef)(streamingMessage?.id);
|
|
3451
3459
|
const [latestTurnMinHeight, setLatestTurnMinHeight] = (0, import_react11.useState)(0);
|
|
3460
|
+
const [isDetached, setIsDetached] = (0, import_react11.useState)(false);
|
|
3461
|
+
const [pendingNewMessageCount, setPendingNewMessageCount] = (0, import_react11.useState)(0);
|
|
3452
3462
|
const measureLatestTurnMinHeight = (0, import_react11.useCallback)(() => {
|
|
3453
3463
|
const container = containerRef.current;
|
|
3454
3464
|
if (!container)
|
|
@@ -3459,26 +3469,86 @@ var ChatThreadView = ({
|
|
|
3459
3469
|
const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
|
|
3460
3470
|
setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
|
|
3461
3471
|
}, []);
|
|
3462
|
-
const
|
|
3472
|
+
const scrollToBottom = (0, import_react11.useCallback)((force = false) => {
|
|
3463
3473
|
const container = containerRef.current;
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
const
|
|
3469
|
-
|
|
3470
|
-
0,
|
|
3471
|
-
container.scrollTop + (targetRect.top - containerRect.top) - CHAT_THREAD_SCROLL_TOP_GAP
|
|
3472
|
-
);
|
|
3474
|
+
if (!container)
|
|
3475
|
+
return false;
|
|
3476
|
+
if (!force && !isPinnedRef.current)
|
|
3477
|
+
return false;
|
|
3478
|
+
const nextScrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
|
|
3479
|
+
container.scrollTop = nextScrollTop;
|
|
3473
3480
|
if (typeof container.scrollTo === "function") {
|
|
3474
3481
|
container.scrollTo({
|
|
3475
3482
|
top: nextScrollTop,
|
|
3476
3483
|
behavior: "auto"
|
|
3477
3484
|
});
|
|
3485
|
+
}
|
|
3486
|
+
return true;
|
|
3487
|
+
}, []);
|
|
3488
|
+
const markThreadPinned = (0, import_react11.useCallback)(() => {
|
|
3489
|
+
isPinnedRef.current = true;
|
|
3490
|
+
setIsDetached(false);
|
|
3491
|
+
setPendingNewMessageCount(0);
|
|
3492
|
+
}, []);
|
|
3493
|
+
const scrollToBottomAndPin = (0, import_react11.useCallback)(
|
|
3494
|
+
(force = false) => {
|
|
3495
|
+
const didScroll = scrollToBottom(force);
|
|
3496
|
+
if (!didScroll)
|
|
3497
|
+
return;
|
|
3498
|
+
markThreadPinned();
|
|
3499
|
+
},
|
|
3500
|
+
[markThreadPinned, scrollToBottom]
|
|
3501
|
+
);
|
|
3502
|
+
const handleContainerScroll = (0, import_react11.useCallback)(() => {
|
|
3503
|
+
const container = containerRef.current;
|
|
3504
|
+
if (!container)
|
|
3478
3505
|
return;
|
|
3506
|
+
const nextPinned = isThreadPinnedToBottom(container);
|
|
3507
|
+
isPinnedRef.current = nextPinned;
|
|
3508
|
+
setIsDetached(!nextPinned);
|
|
3509
|
+
if (nextPinned) {
|
|
3510
|
+
setPendingNewMessageCount(0);
|
|
3479
3511
|
}
|
|
3480
|
-
container.scrollTop = nextScrollTop;
|
|
3481
3512
|
}, []);
|
|
3513
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3514
|
+
const nextHistoryMessageId = latestHistoryMessage?.id;
|
|
3515
|
+
if (lastHistoryMessageIdRef.current === nextHistoryMessageId) {
|
|
3516
|
+
return;
|
|
3517
|
+
}
|
|
3518
|
+
lastHistoryMessageIdRef.current = nextHistoryMessageId;
|
|
3519
|
+
if (!latestHistoryMessage) {
|
|
3520
|
+
return;
|
|
3521
|
+
}
|
|
3522
|
+
if (latestHistoryMessage.role === "user") {
|
|
3523
|
+
window.requestAnimationFrame(() => {
|
|
3524
|
+
if (!scrollToBottom(true)) {
|
|
3525
|
+
return;
|
|
3526
|
+
}
|
|
3527
|
+
markThreadPinned();
|
|
3528
|
+
});
|
|
3529
|
+
return;
|
|
3530
|
+
}
|
|
3531
|
+
if (!isPinnedRef.current && latestHistoryMessage.role === "assistant" && latestHistoryMessage.id !== lastStreamingMessageIdRef.current) {
|
|
3532
|
+
window.requestAnimationFrame(() => {
|
|
3533
|
+
setPendingNewMessageCount((current) => current + 1);
|
|
3534
|
+
});
|
|
3535
|
+
}
|
|
3536
|
+
}, [latestHistoryMessage, markThreadPinned, scrollToBottom]);
|
|
3537
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3538
|
+
const nextStreamingMessageId = streamingMessage?.id;
|
|
3539
|
+
if (lastStreamingMessageIdRef.current === nextStreamingMessageId) {
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
lastStreamingMessageIdRef.current = nextStreamingMessageId;
|
|
3543
|
+
if (!streamingMessage || streamingMessage.role !== "assistant") {
|
|
3544
|
+
return;
|
|
3545
|
+
}
|
|
3546
|
+
if (!isPinnedRef.current) {
|
|
3547
|
+
window.requestAnimationFrame(() => {
|
|
3548
|
+
setPendingNewMessageCount((current) => current + 1);
|
|
3549
|
+
});
|
|
3550
|
+
}
|
|
3551
|
+
}, [streamingMessage]);
|
|
3482
3552
|
(0, import_react11.useLayoutEffect)(() => {
|
|
3483
3553
|
if (reservedSpaceFrameRef.current !== null) {
|
|
3484
3554
|
window.cancelAnimationFrame(reservedSpaceFrameRef.current);
|
|
@@ -3488,6 +3558,7 @@ var ChatThreadView = ({
|
|
|
3488
3558
|
reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
|
|
3489
3559
|
reservedSpaceFrameRef.current = null;
|
|
3490
3560
|
setLatestTurnMinHeight((current) => current === 0 ? current : 0);
|
|
3561
|
+
scrollToBottom();
|
|
3491
3562
|
});
|
|
3492
3563
|
return () => {
|
|
3493
3564
|
if (reservedSpaceFrameRef.current !== null) {
|
|
@@ -3499,7 +3570,7 @@ var ChatThreadView = ({
|
|
|
3499
3570
|
reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
|
|
3500
3571
|
reservedSpaceFrameRef.current = null;
|
|
3501
3572
|
measureLatestTurnMinHeight();
|
|
3502
|
-
|
|
3573
|
+
scrollToBottom();
|
|
3503
3574
|
});
|
|
3504
3575
|
return () => {
|
|
3505
3576
|
if (reservedSpaceFrameRef.current !== null) {
|
|
@@ -3507,13 +3578,18 @@ var ChatThreadView = ({
|
|
|
3507
3578
|
reservedSpaceFrameRef.current = null;
|
|
3508
3579
|
}
|
|
3509
3580
|
};
|
|
3510
|
-
}, [latestUserMessageId, measureLatestTurnMinHeight,
|
|
3581
|
+
}, [latestTurn, latestUserMessageId, error, measureLatestTurnMinHeight, scrollToBottom]);
|
|
3511
3582
|
(0, import_react11.useLayoutEffect)(() => {
|
|
3512
|
-
if (!
|
|
3583
|
+
if (!latestTurn)
|
|
3513
3584
|
return;
|
|
3514
3585
|
const handleResize = () => {
|
|
3586
|
+
if (!latestUserMessageId) {
|
|
3587
|
+
setLatestTurnMinHeight((current) => current === 0 ? current : 0);
|
|
3588
|
+
scrollToBottom();
|
|
3589
|
+
return;
|
|
3590
|
+
}
|
|
3515
3591
|
measureLatestTurnMinHeight();
|
|
3516
|
-
|
|
3592
|
+
scrollToBottom();
|
|
3517
3593
|
};
|
|
3518
3594
|
const container = containerRef.current;
|
|
3519
3595
|
let resizeObserver = null;
|
|
@@ -3528,57 +3604,101 @@ var ChatThreadView = ({
|
|
|
3528
3604
|
resizeObserver?.disconnect();
|
|
3529
3605
|
window.removeEventListener("resize", handleResize);
|
|
3530
3606
|
};
|
|
3531
|
-
}, [latestUserMessageId, measureLatestTurnMinHeight,
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3607
|
+
}, [latestTurn, latestUserMessageId, measureLatestTurnMinHeight, scrollToBottom]);
|
|
3608
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3609
|
+
const latestTurnElement = latestTurnRef.current;
|
|
3610
|
+
if (!latestTurnElement || typeof ResizeObserver === "undefined") {
|
|
3611
|
+
return;
|
|
3612
|
+
}
|
|
3613
|
+
const observer = new ResizeObserver(() => {
|
|
3614
|
+
scrollToBottom();
|
|
3615
|
+
});
|
|
3616
|
+
observer.observe(latestTurnElement);
|
|
3617
|
+
return () => {
|
|
3618
|
+
observer.disconnect();
|
|
3619
|
+
};
|
|
3620
|
+
}, [latestTurn, scrollToBottom]);
|
|
3621
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3622
|
+
const latestTurnElement = latestTurnRef.current;
|
|
3623
|
+
if (!latestTurnElement || typeof MutationObserver === "undefined") {
|
|
3624
|
+
return;
|
|
3625
|
+
}
|
|
3626
|
+
const observer = new MutationObserver(() => {
|
|
3627
|
+
scrollToBottom();
|
|
3628
|
+
});
|
|
3629
|
+
observer.observe(latestTurnElement, {
|
|
3630
|
+
childList: true,
|
|
3631
|
+
subtree: true,
|
|
3632
|
+
characterData: true
|
|
3633
|
+
});
|
|
3634
|
+
return () => {
|
|
3635
|
+
observer.disconnect();
|
|
3636
|
+
};
|
|
3637
|
+
}, [latestTurn, scrollToBottom]);
|
|
3638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ThreadViewport, { children: [
|
|
3639
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Container, { ref: containerRef, "data-testid": "chat-thread", onScroll: handleContainerScroll, children: [
|
|
3640
|
+
previousTurns.map((turn) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ConversationTurn, { "data-testid": "chat-thread-turn", children: [
|
|
3641
|
+
turn.userMessage ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3642
|
+
message: turn.userMessage,
|
|
3643
|
+
mode: activeSessionMode,
|
|
3644
|
+
onConfirmationSubmit,
|
|
3645
|
+
onQuestionnaireSubmit,
|
|
3646
|
+
renderMessageBlock
|
|
3647
|
+
}) }) : null,
|
|
3648
|
+
turn.responseMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3649
|
+
message,
|
|
3650
|
+
mode: activeSessionMode,
|
|
3651
|
+
onConfirmationSubmit,
|
|
3652
|
+
onQuestionnaireSubmit,
|
|
3653
|
+
renderMessageBlock
|
|
3654
|
+
}) }, message.id))
|
|
3655
|
+
] }, turn.id)),
|
|
3656
|
+
latestTurn ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
3657
|
+
ConversationTurn,
|
|
3658
|
+
{
|
|
3659
|
+
ref: latestTurnRef,
|
|
3660
|
+
"data-testid": "chat-thread-latest-turn",
|
|
3661
|
+
style: latestTurnMinHeight > 0 ? { minHeight: `${latestTurnMinHeight}px` } : void 0,
|
|
3662
|
+
children: [
|
|
3663
|
+
latestTurn.userMessage ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3664
|
+
MessageSlot,
|
|
3665
|
+
{
|
|
3666
|
+
"data-testid": "chat-latest-user-anchor",
|
|
3667
|
+
style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
|
|
3668
|
+
children: renderChatMessage({
|
|
3669
|
+
message: latestTurn.userMessage,
|
|
3670
|
+
mode: activeSessionMode,
|
|
3671
|
+
onConfirmationSubmit,
|
|
3672
|
+
onQuestionnaireSubmit,
|
|
3673
|
+
renderMessageBlock
|
|
3674
|
+
})
|
|
3675
|
+
}
|
|
3676
|
+
) : null,
|
|
3677
|
+
latestTurn.responseMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3678
|
+
message,
|
|
3679
|
+
mode: activeSessionMode,
|
|
3680
|
+
onConfirmationSubmit,
|
|
3681
|
+
onQuestionnaireSubmit,
|
|
3682
|
+
renderMessageBlock
|
|
3683
|
+
}) }, message.id)),
|
|
3684
|
+
error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3685
|
+
]
|
|
3686
|
+
}
|
|
3687
|
+
) : null,
|
|
3688
|
+
!latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3689
|
+
] }),
|
|
3690
|
+
isDetached ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScrollToLatestOverlay, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
3691
|
+
ScrollToLatestButton,
|
|
3551
3692
|
{
|
|
3552
|
-
|
|
3553
|
-
|
|
3693
|
+
type: "button",
|
|
3694
|
+
"data-testid": "chat-thread-scroll-to-latest",
|
|
3695
|
+
onClick: () => scrollToBottomAndPin(true),
|
|
3554
3696
|
children: [
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
{
|
|
3558
|
-
ref: latestUserMessageRef,
|
|
3559
|
-
"data-testid": "chat-latest-user-anchor",
|
|
3560
|
-
style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
|
|
3561
|
-
children: renderChatMessage({
|
|
3562
|
-
message: latestTurn.userMessage,
|
|
3563
|
-
mode: activeSessionMode,
|
|
3564
|
-
onConfirmationSubmit,
|
|
3565
|
-
onQuestionnaireSubmit,
|
|
3566
|
-
renderMessageBlock
|
|
3567
|
-
})
|
|
3568
|
-
}
|
|
3569
|
-
) : null,
|
|
3570
|
-
latestTurn.responseMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3571
|
-
message,
|
|
3572
|
-
mode: activeSessionMode,
|
|
3573
|
-
onConfirmationSubmit,
|
|
3574
|
-
onQuestionnaireSubmit,
|
|
3575
|
-
renderMessageBlock
|
|
3576
|
-
}) }, message.id)),
|
|
3577
|
-
error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3697
|
+
scrollToLatestLabel,
|
|
3698
|
+
pendingNewMessageCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScrollToLatestBadge, { "data-testid": "chat-thread-scroll-to-latest-count", children: pendingNewMessageCount }) : null
|
|
3578
3699
|
]
|
|
3579
3700
|
}
|
|
3580
|
-
) : null
|
|
3581
|
-
!latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3701
|
+
) }) : null
|
|
3582
3702
|
] });
|
|
3583
3703
|
};
|
|
3584
3704
|
var EMPTY_MESSAGES = [];
|
|
@@ -3666,13 +3786,21 @@ var ChatThread = () => {
|
|
|
3666
3786
|
streamingMessage,
|
|
3667
3787
|
error,
|
|
3668
3788
|
retryButtonLabel: labels.retryButton,
|
|
3789
|
+
scrollToLatestLabel: labels.scrollToLatest,
|
|
3669
3790
|
onRetry: handleRetry,
|
|
3670
3791
|
onConfirmationSubmit: handleConfirmation,
|
|
3671
3792
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
3672
3793
|
renderMessageBlock
|
|
3673
|
-
}
|
|
3794
|
+
},
|
|
3795
|
+
activeSessionId ?? "chat-thread-empty"
|
|
3674
3796
|
);
|
|
3675
3797
|
};
|
|
3798
|
+
var ThreadViewport = import_styled9.default.div`
|
|
3799
|
+
position: relative;
|
|
3800
|
+
display: flex;
|
|
3801
|
+
flex: 1;
|
|
3802
|
+
min-height: 0;
|
|
3803
|
+
`;
|
|
3676
3804
|
var Container = import_styled9.default.div`
|
|
3677
3805
|
display: flex;
|
|
3678
3806
|
flex: 1;
|
|
@@ -3680,8 +3808,7 @@ var Container = import_styled9.default.div`
|
|
|
3680
3808
|
gap: 18px;
|
|
3681
3809
|
min-height: 0;
|
|
3682
3810
|
overflow: auto;
|
|
3683
|
-
padding: 24px;
|
|
3684
|
-
margin-bottom: 24px;
|
|
3811
|
+
padding: 24px 24px 88px;
|
|
3685
3812
|
overscroll-behavior: contain;
|
|
3686
3813
|
|
|
3687
3814
|
&::-webkit-scrollbar {
|
|
@@ -3733,6 +3860,48 @@ var RetryButton = import_styled9.default.button`
|
|
|
3733
3860
|
background: rgba(255, 255, 255, 0.08);
|
|
3734
3861
|
}
|
|
3735
3862
|
`;
|
|
3863
|
+
var ScrollToLatestOverlay = import_styled9.default.div`
|
|
3864
|
+
position: absolute;
|
|
3865
|
+
right: 24px;
|
|
3866
|
+
bottom: 24px;
|
|
3867
|
+
left: 24px;
|
|
3868
|
+
display: flex;
|
|
3869
|
+
justify-content: center;
|
|
3870
|
+
pointer-events: none;
|
|
3871
|
+
`;
|
|
3872
|
+
var ScrollToLatestButton = import_styled9.default.button`
|
|
3873
|
+
display: inline-flex;
|
|
3874
|
+
align-items: center;
|
|
3875
|
+
gap: 8px;
|
|
3876
|
+
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
3877
|
+
border-radius: 999px;
|
|
3878
|
+
background: rgba(17, 18, 21, 0.92);
|
|
3879
|
+
color: rgba(255, 255, 255, 0.9);
|
|
3880
|
+
font-size: 12px;
|
|
3881
|
+
line-height: 1;
|
|
3882
|
+
padding: 10px 14px;
|
|
3883
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
|
|
3884
|
+
cursor: pointer;
|
|
3885
|
+
z-index: 1;
|
|
3886
|
+
pointer-events: auto;
|
|
3887
|
+
|
|
3888
|
+
&:hover {
|
|
3889
|
+
background: rgba(28, 30, 36, 0.96);
|
|
3890
|
+
}
|
|
3891
|
+
`;
|
|
3892
|
+
var ScrollToLatestBadge = import_styled9.default.span`
|
|
3893
|
+
display: inline-flex;
|
|
3894
|
+
min-width: 18px;
|
|
3895
|
+
height: 18px;
|
|
3896
|
+
align-items: center;
|
|
3897
|
+
justify-content: center;
|
|
3898
|
+
padding: 0 6px;
|
|
3899
|
+
border-radius: 999px;
|
|
3900
|
+
background: rgba(109, 170, 255, 0.2);
|
|
3901
|
+
color: #9ac0ff;
|
|
3902
|
+
font-size: 11px;
|
|
3903
|
+
font-weight: 600;
|
|
3904
|
+
`;
|
|
3736
3905
|
|
|
3737
3906
|
// src/components/chat-composer/index.tsx
|
|
3738
3907
|
var import_react15 = require("react");
|
|
@@ -4940,7 +5109,7 @@ var ChatComposerView = ({
|
|
|
4940
5109
|
}
|
|
4941
5110
|
) : null,
|
|
4942
5111
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4943
|
-
|
|
5112
|
+
Input2,
|
|
4944
5113
|
{
|
|
4945
5114
|
ref: inputRef,
|
|
4946
5115
|
"data-testid": "chat-composer-input",
|
|
@@ -5084,7 +5253,7 @@ var InputArea = import_styled14.default.div`
|
|
|
5084
5253
|
grid-area: input;
|
|
5085
5254
|
position: relative;
|
|
5086
5255
|
`;
|
|
5087
|
-
var
|
|
5256
|
+
var Input2 = import_styled14.default.textarea`
|
|
5088
5257
|
--textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
|
|
5089
5258
|
--textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
|
|
5090
5259
|
--textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
|
package/dist/index.mjs
CHANGED
|
@@ -21,6 +21,7 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
21
21
|
sendButton: "Send",
|
|
22
22
|
stopButton: "Stop",
|
|
23
23
|
retryButton: "Retry",
|
|
24
|
+
scrollToLatest: "Jump to latest",
|
|
24
25
|
placeholder: "Ask something...",
|
|
25
26
|
modeLabelAsk: "Ask",
|
|
26
27
|
modeLabelPlan: "Plan",
|
|
@@ -1494,7 +1495,7 @@ import {
|
|
|
1494
1495
|
useState as useState2
|
|
1495
1496
|
} from "react";
|
|
1496
1497
|
import styled4 from "@emotion/styled";
|
|
1497
|
-
import {
|
|
1498
|
+
import { Input } from "@xinghunm/compass-ui";
|
|
1498
1499
|
|
|
1499
1500
|
// src/components/chat-thread/components/questionnaire-card-helpers.ts
|
|
1500
1501
|
var OTHER_OPTION_VALUE = "__other__";
|
|
@@ -2295,11 +2296,11 @@ var TextInput = styled4.input`
|
|
|
2295
2296
|
color: rgba(255, 255, 255, 0.34);
|
|
2296
2297
|
}
|
|
2297
2298
|
`;
|
|
2298
|
-
var InlineOtherInput = styled4(
|
|
2299
|
+
var InlineOtherInput = styled4(Input)`
|
|
2299
2300
|
width: 100%;
|
|
2300
2301
|
margin-top: 0;
|
|
2301
2302
|
|
|
2302
|
-
.compass-input-
|
|
2303
|
+
.compass-input-wrapper {
|
|
2303
2304
|
min-height: 30px;
|
|
2304
2305
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
2305
2306
|
border-radius: 10px;
|
|
@@ -2308,22 +2309,22 @@ var InlineOtherInput = styled4(InputField)`
|
|
|
2308
2309
|
padding: 2px 9px;
|
|
2309
2310
|
}
|
|
2310
2311
|
|
|
2311
|
-
.compass-input-
|
|
2312
|
+
.compass-input-wrapper:hover {
|
|
2312
2313
|
border-color: rgba(126, 160, 255, 0.28);
|
|
2313
2314
|
}
|
|
2314
2315
|
|
|
2315
|
-
.compass-input-
|
|
2316
|
+
.compass-input-wrapper:focus-within {
|
|
2316
2317
|
border-color: rgba(126, 160, 255, 0.42);
|
|
2317
2318
|
box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.14);
|
|
2318
2319
|
}
|
|
2319
2320
|
|
|
2320
|
-
.compass-input-
|
|
2321
|
+
.compass-input-input {
|
|
2321
2322
|
color: rgba(255, 255, 255, 0.92);
|
|
2322
2323
|
font-size: 13px;
|
|
2323
2324
|
line-height: 1.2;
|
|
2324
2325
|
}
|
|
2325
2326
|
|
|
2326
|
-
.compass-input-
|
|
2327
|
+
.compass-input-input::placeholder {
|
|
2327
2328
|
color: rgba(255, 255, 255, 0.34);
|
|
2328
2329
|
}
|
|
2329
2330
|
`;
|
|
@@ -3317,6 +3318,8 @@ var HeroSubtitle = styled8.p`
|
|
|
3317
3318
|
|
|
3318
3319
|
// src/components/chat-thread/index.tsx
|
|
3319
3320
|
import { jsx as jsx10, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
|
|
3321
|
+
var CHAT_THREAD_PINNED_THRESHOLD_PX = 32;
|
|
3322
|
+
var isThreadPinnedToBottom = (container) => container.scrollHeight - container.clientHeight - container.scrollTop <= CHAT_THREAD_PINNED_THRESHOLD_PX;
|
|
3320
3323
|
var renderChatMessage = ({
|
|
3321
3324
|
message,
|
|
3322
3325
|
mode,
|
|
@@ -3390,6 +3393,7 @@ var ChatThreadView = ({
|
|
|
3390
3393
|
streamingMessage,
|
|
3391
3394
|
error,
|
|
3392
3395
|
retryButtonLabel,
|
|
3396
|
+
scrollToLatestLabel,
|
|
3393
3397
|
onRetry,
|
|
3394
3398
|
onConfirmationSubmit,
|
|
3395
3399
|
onQuestionnaireSubmit,
|
|
@@ -3403,9 +3407,15 @@ var ChatThreadView = ({
|
|
|
3403
3407
|
const latestTurn = conversationTurns[conversationTurns.length - 1];
|
|
3404
3408
|
const previousTurns = conversationTurns.slice(0, -1);
|
|
3405
3409
|
const latestUserMessageId = latestTurn?.userMessage?.id;
|
|
3406
|
-
const
|
|
3410
|
+
const latestHistoryMessage = historyMessages[historyMessages.length - 1];
|
|
3411
|
+
const latestTurnRef = useRef5(null);
|
|
3407
3412
|
const reservedSpaceFrameRef = useRef5(null);
|
|
3413
|
+
const isPinnedRef = useRef5(true);
|
|
3414
|
+
const lastHistoryMessageIdRef = useRef5(latestHistoryMessage?.id);
|
|
3415
|
+
const lastStreamingMessageIdRef = useRef5(streamingMessage?.id);
|
|
3408
3416
|
const [latestTurnMinHeight, setLatestTurnMinHeight] = useState4(0);
|
|
3417
|
+
const [isDetached, setIsDetached] = useState4(false);
|
|
3418
|
+
const [pendingNewMessageCount, setPendingNewMessageCount] = useState4(0);
|
|
3409
3419
|
const measureLatestTurnMinHeight = useCallback3(() => {
|
|
3410
3420
|
const container = containerRef.current;
|
|
3411
3421
|
if (!container)
|
|
@@ -3416,26 +3426,86 @@ var ChatThreadView = ({
|
|
|
3416
3426
|
const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
|
|
3417
3427
|
setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
|
|
3418
3428
|
}, []);
|
|
3419
|
-
const
|
|
3429
|
+
const scrollToBottom = useCallback3((force = false) => {
|
|
3420
3430
|
const container = containerRef.current;
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
const
|
|
3426
|
-
|
|
3427
|
-
0,
|
|
3428
|
-
container.scrollTop + (targetRect.top - containerRect.top) - CHAT_THREAD_SCROLL_TOP_GAP
|
|
3429
|
-
);
|
|
3431
|
+
if (!container)
|
|
3432
|
+
return false;
|
|
3433
|
+
if (!force && !isPinnedRef.current)
|
|
3434
|
+
return false;
|
|
3435
|
+
const nextScrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
|
|
3436
|
+
container.scrollTop = nextScrollTop;
|
|
3430
3437
|
if (typeof container.scrollTo === "function") {
|
|
3431
3438
|
container.scrollTo({
|
|
3432
3439
|
top: nextScrollTop,
|
|
3433
3440
|
behavior: "auto"
|
|
3434
3441
|
});
|
|
3442
|
+
}
|
|
3443
|
+
return true;
|
|
3444
|
+
}, []);
|
|
3445
|
+
const markThreadPinned = useCallback3(() => {
|
|
3446
|
+
isPinnedRef.current = true;
|
|
3447
|
+
setIsDetached(false);
|
|
3448
|
+
setPendingNewMessageCount(0);
|
|
3449
|
+
}, []);
|
|
3450
|
+
const scrollToBottomAndPin = useCallback3(
|
|
3451
|
+
(force = false) => {
|
|
3452
|
+
const didScroll = scrollToBottom(force);
|
|
3453
|
+
if (!didScroll)
|
|
3454
|
+
return;
|
|
3455
|
+
markThreadPinned();
|
|
3456
|
+
},
|
|
3457
|
+
[markThreadPinned, scrollToBottom]
|
|
3458
|
+
);
|
|
3459
|
+
const handleContainerScroll = useCallback3(() => {
|
|
3460
|
+
const container = containerRef.current;
|
|
3461
|
+
if (!container)
|
|
3435
3462
|
return;
|
|
3463
|
+
const nextPinned = isThreadPinnedToBottom(container);
|
|
3464
|
+
isPinnedRef.current = nextPinned;
|
|
3465
|
+
setIsDetached(!nextPinned);
|
|
3466
|
+
if (nextPinned) {
|
|
3467
|
+
setPendingNewMessageCount(0);
|
|
3436
3468
|
}
|
|
3437
|
-
container.scrollTop = nextScrollTop;
|
|
3438
3469
|
}, []);
|
|
3470
|
+
useLayoutEffect2(() => {
|
|
3471
|
+
const nextHistoryMessageId = latestHistoryMessage?.id;
|
|
3472
|
+
if (lastHistoryMessageIdRef.current === nextHistoryMessageId) {
|
|
3473
|
+
return;
|
|
3474
|
+
}
|
|
3475
|
+
lastHistoryMessageIdRef.current = nextHistoryMessageId;
|
|
3476
|
+
if (!latestHistoryMessage) {
|
|
3477
|
+
return;
|
|
3478
|
+
}
|
|
3479
|
+
if (latestHistoryMessage.role === "user") {
|
|
3480
|
+
window.requestAnimationFrame(() => {
|
|
3481
|
+
if (!scrollToBottom(true)) {
|
|
3482
|
+
return;
|
|
3483
|
+
}
|
|
3484
|
+
markThreadPinned();
|
|
3485
|
+
});
|
|
3486
|
+
return;
|
|
3487
|
+
}
|
|
3488
|
+
if (!isPinnedRef.current && latestHistoryMessage.role === "assistant" && latestHistoryMessage.id !== lastStreamingMessageIdRef.current) {
|
|
3489
|
+
window.requestAnimationFrame(() => {
|
|
3490
|
+
setPendingNewMessageCount((current) => current + 1);
|
|
3491
|
+
});
|
|
3492
|
+
}
|
|
3493
|
+
}, [latestHistoryMessage, markThreadPinned, scrollToBottom]);
|
|
3494
|
+
useLayoutEffect2(() => {
|
|
3495
|
+
const nextStreamingMessageId = streamingMessage?.id;
|
|
3496
|
+
if (lastStreamingMessageIdRef.current === nextStreamingMessageId) {
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
lastStreamingMessageIdRef.current = nextStreamingMessageId;
|
|
3500
|
+
if (!streamingMessage || streamingMessage.role !== "assistant") {
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
if (!isPinnedRef.current) {
|
|
3504
|
+
window.requestAnimationFrame(() => {
|
|
3505
|
+
setPendingNewMessageCount((current) => current + 1);
|
|
3506
|
+
});
|
|
3507
|
+
}
|
|
3508
|
+
}, [streamingMessage]);
|
|
3439
3509
|
useLayoutEffect2(() => {
|
|
3440
3510
|
if (reservedSpaceFrameRef.current !== null) {
|
|
3441
3511
|
window.cancelAnimationFrame(reservedSpaceFrameRef.current);
|
|
@@ -3445,6 +3515,7 @@ var ChatThreadView = ({
|
|
|
3445
3515
|
reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
|
|
3446
3516
|
reservedSpaceFrameRef.current = null;
|
|
3447
3517
|
setLatestTurnMinHeight((current) => current === 0 ? current : 0);
|
|
3518
|
+
scrollToBottom();
|
|
3448
3519
|
});
|
|
3449
3520
|
return () => {
|
|
3450
3521
|
if (reservedSpaceFrameRef.current !== null) {
|
|
@@ -3456,7 +3527,7 @@ var ChatThreadView = ({
|
|
|
3456
3527
|
reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
|
|
3457
3528
|
reservedSpaceFrameRef.current = null;
|
|
3458
3529
|
measureLatestTurnMinHeight();
|
|
3459
|
-
|
|
3530
|
+
scrollToBottom();
|
|
3460
3531
|
});
|
|
3461
3532
|
return () => {
|
|
3462
3533
|
if (reservedSpaceFrameRef.current !== null) {
|
|
@@ -3464,13 +3535,18 @@ var ChatThreadView = ({
|
|
|
3464
3535
|
reservedSpaceFrameRef.current = null;
|
|
3465
3536
|
}
|
|
3466
3537
|
};
|
|
3467
|
-
}, [latestUserMessageId, measureLatestTurnMinHeight,
|
|
3538
|
+
}, [latestTurn, latestUserMessageId, error, measureLatestTurnMinHeight, scrollToBottom]);
|
|
3468
3539
|
useLayoutEffect2(() => {
|
|
3469
|
-
if (!
|
|
3540
|
+
if (!latestTurn)
|
|
3470
3541
|
return;
|
|
3471
3542
|
const handleResize = () => {
|
|
3543
|
+
if (!latestUserMessageId) {
|
|
3544
|
+
setLatestTurnMinHeight((current) => current === 0 ? current : 0);
|
|
3545
|
+
scrollToBottom();
|
|
3546
|
+
return;
|
|
3547
|
+
}
|
|
3472
3548
|
measureLatestTurnMinHeight();
|
|
3473
|
-
|
|
3549
|
+
scrollToBottom();
|
|
3474
3550
|
};
|
|
3475
3551
|
const container = containerRef.current;
|
|
3476
3552
|
let resizeObserver = null;
|
|
@@ -3485,57 +3561,101 @@ var ChatThreadView = ({
|
|
|
3485
3561
|
resizeObserver?.disconnect();
|
|
3486
3562
|
window.removeEventListener("resize", handleResize);
|
|
3487
3563
|
};
|
|
3488
|
-
}, [latestUserMessageId, measureLatestTurnMinHeight,
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3564
|
+
}, [latestTurn, latestUserMessageId, measureLatestTurnMinHeight, scrollToBottom]);
|
|
3565
|
+
useLayoutEffect2(() => {
|
|
3566
|
+
const latestTurnElement = latestTurnRef.current;
|
|
3567
|
+
if (!latestTurnElement || typeof ResizeObserver === "undefined") {
|
|
3568
|
+
return;
|
|
3569
|
+
}
|
|
3570
|
+
const observer = new ResizeObserver(() => {
|
|
3571
|
+
scrollToBottom();
|
|
3572
|
+
});
|
|
3573
|
+
observer.observe(latestTurnElement);
|
|
3574
|
+
return () => {
|
|
3575
|
+
observer.disconnect();
|
|
3576
|
+
};
|
|
3577
|
+
}, [latestTurn, scrollToBottom]);
|
|
3578
|
+
useLayoutEffect2(() => {
|
|
3579
|
+
const latestTurnElement = latestTurnRef.current;
|
|
3580
|
+
if (!latestTurnElement || typeof MutationObserver === "undefined") {
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3583
|
+
const observer = new MutationObserver(() => {
|
|
3584
|
+
scrollToBottom();
|
|
3585
|
+
});
|
|
3586
|
+
observer.observe(latestTurnElement, {
|
|
3587
|
+
childList: true,
|
|
3588
|
+
subtree: true,
|
|
3589
|
+
characterData: true
|
|
3590
|
+
});
|
|
3591
|
+
return () => {
|
|
3592
|
+
observer.disconnect();
|
|
3593
|
+
};
|
|
3594
|
+
}, [latestTurn, scrollToBottom]);
|
|
3595
|
+
return /* @__PURE__ */ jsxs7(ThreadViewport, { children: [
|
|
3596
|
+
/* @__PURE__ */ jsxs7(Container, { ref: containerRef, "data-testid": "chat-thread", onScroll: handleContainerScroll, children: [
|
|
3597
|
+
previousTurns.map((turn) => /* @__PURE__ */ jsxs7(ConversationTurn, { "data-testid": "chat-thread-turn", children: [
|
|
3598
|
+
turn.userMessage ? /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
|
|
3599
|
+
message: turn.userMessage,
|
|
3600
|
+
mode: activeSessionMode,
|
|
3601
|
+
onConfirmationSubmit,
|
|
3602
|
+
onQuestionnaireSubmit,
|
|
3603
|
+
renderMessageBlock
|
|
3604
|
+
}) }) : null,
|
|
3605
|
+
turn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
|
|
3606
|
+
message,
|
|
3607
|
+
mode: activeSessionMode,
|
|
3608
|
+
onConfirmationSubmit,
|
|
3609
|
+
onQuestionnaireSubmit,
|
|
3610
|
+
renderMessageBlock
|
|
3611
|
+
}) }, message.id))
|
|
3612
|
+
] }, turn.id)),
|
|
3613
|
+
latestTurn ? /* @__PURE__ */ jsxs7(
|
|
3614
|
+
ConversationTurn,
|
|
3615
|
+
{
|
|
3616
|
+
ref: latestTurnRef,
|
|
3617
|
+
"data-testid": "chat-thread-latest-turn",
|
|
3618
|
+
style: latestTurnMinHeight > 0 ? { minHeight: `${latestTurnMinHeight}px` } : void 0,
|
|
3619
|
+
children: [
|
|
3620
|
+
latestTurn.userMessage ? /* @__PURE__ */ jsx10(
|
|
3621
|
+
MessageSlot,
|
|
3622
|
+
{
|
|
3623
|
+
"data-testid": "chat-latest-user-anchor",
|
|
3624
|
+
style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
|
|
3625
|
+
children: renderChatMessage({
|
|
3626
|
+
message: latestTurn.userMessage,
|
|
3627
|
+
mode: activeSessionMode,
|
|
3628
|
+
onConfirmationSubmit,
|
|
3629
|
+
onQuestionnaireSubmit,
|
|
3630
|
+
renderMessageBlock
|
|
3631
|
+
})
|
|
3632
|
+
}
|
|
3633
|
+
) : null,
|
|
3634
|
+
latestTurn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
|
|
3635
|
+
message,
|
|
3636
|
+
mode: activeSessionMode,
|
|
3637
|
+
onConfirmationSubmit,
|
|
3638
|
+
onQuestionnaireSubmit,
|
|
3639
|
+
renderMessageBlock
|
|
3640
|
+
}) }, message.id)),
|
|
3641
|
+
error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3642
|
+
]
|
|
3643
|
+
}
|
|
3644
|
+
) : null,
|
|
3645
|
+
!latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3646
|
+
] }),
|
|
3647
|
+
isDetached ? /* @__PURE__ */ jsx10(ScrollToLatestOverlay, { children: /* @__PURE__ */ jsxs7(
|
|
3648
|
+
ScrollToLatestButton,
|
|
3508
3649
|
{
|
|
3509
|
-
|
|
3510
|
-
|
|
3650
|
+
type: "button",
|
|
3651
|
+
"data-testid": "chat-thread-scroll-to-latest",
|
|
3652
|
+
onClick: () => scrollToBottomAndPin(true),
|
|
3511
3653
|
children: [
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
{
|
|
3515
|
-
ref: latestUserMessageRef,
|
|
3516
|
-
"data-testid": "chat-latest-user-anchor",
|
|
3517
|
-
style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
|
|
3518
|
-
children: renderChatMessage({
|
|
3519
|
-
message: latestTurn.userMessage,
|
|
3520
|
-
mode: activeSessionMode,
|
|
3521
|
-
onConfirmationSubmit,
|
|
3522
|
-
onQuestionnaireSubmit,
|
|
3523
|
-
renderMessageBlock
|
|
3524
|
-
})
|
|
3525
|
-
}
|
|
3526
|
-
) : null,
|
|
3527
|
-
latestTurn.responseMessages.map((message) => /* @__PURE__ */ jsx10(MessageSlot, { children: renderChatMessage({
|
|
3528
|
-
message,
|
|
3529
|
-
mode: activeSessionMode,
|
|
3530
|
-
onConfirmationSubmit,
|
|
3531
|
-
onQuestionnaireSubmit,
|
|
3532
|
-
renderMessageBlock
|
|
3533
|
-
}) }, message.id)),
|
|
3534
|
-
error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3654
|
+
scrollToLatestLabel,
|
|
3655
|
+
pendingNewMessageCount > 0 ? /* @__PURE__ */ jsx10(ScrollToLatestBadge, { "data-testid": "chat-thread-scroll-to-latest-count", children: pendingNewMessageCount }) : null
|
|
3535
3656
|
]
|
|
3536
3657
|
}
|
|
3537
|
-
) : null
|
|
3538
|
-
!latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3658
|
+
) }) : null
|
|
3539
3659
|
] });
|
|
3540
3660
|
};
|
|
3541
3661
|
var EMPTY_MESSAGES = [];
|
|
@@ -3623,13 +3743,21 @@ var ChatThread = () => {
|
|
|
3623
3743
|
streamingMessage,
|
|
3624
3744
|
error,
|
|
3625
3745
|
retryButtonLabel: labels.retryButton,
|
|
3746
|
+
scrollToLatestLabel: labels.scrollToLatest,
|
|
3626
3747
|
onRetry: handleRetry,
|
|
3627
3748
|
onConfirmationSubmit: handleConfirmation,
|
|
3628
3749
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
3629
3750
|
renderMessageBlock
|
|
3630
|
-
}
|
|
3751
|
+
},
|
|
3752
|
+
activeSessionId ?? "chat-thread-empty"
|
|
3631
3753
|
);
|
|
3632
3754
|
};
|
|
3755
|
+
var ThreadViewport = styled9.div`
|
|
3756
|
+
position: relative;
|
|
3757
|
+
display: flex;
|
|
3758
|
+
flex: 1;
|
|
3759
|
+
min-height: 0;
|
|
3760
|
+
`;
|
|
3633
3761
|
var Container = styled9.div`
|
|
3634
3762
|
display: flex;
|
|
3635
3763
|
flex: 1;
|
|
@@ -3637,8 +3765,7 @@ var Container = styled9.div`
|
|
|
3637
3765
|
gap: 18px;
|
|
3638
3766
|
min-height: 0;
|
|
3639
3767
|
overflow: auto;
|
|
3640
|
-
padding: 24px;
|
|
3641
|
-
margin-bottom: 24px;
|
|
3768
|
+
padding: 24px 24px 88px;
|
|
3642
3769
|
overscroll-behavior: contain;
|
|
3643
3770
|
|
|
3644
3771
|
&::-webkit-scrollbar {
|
|
@@ -3690,6 +3817,48 @@ var RetryButton = styled9.button`
|
|
|
3690
3817
|
background: rgba(255, 255, 255, 0.08);
|
|
3691
3818
|
}
|
|
3692
3819
|
`;
|
|
3820
|
+
var ScrollToLatestOverlay = styled9.div`
|
|
3821
|
+
position: absolute;
|
|
3822
|
+
right: 24px;
|
|
3823
|
+
bottom: 24px;
|
|
3824
|
+
left: 24px;
|
|
3825
|
+
display: flex;
|
|
3826
|
+
justify-content: center;
|
|
3827
|
+
pointer-events: none;
|
|
3828
|
+
`;
|
|
3829
|
+
var ScrollToLatestButton = styled9.button`
|
|
3830
|
+
display: inline-flex;
|
|
3831
|
+
align-items: center;
|
|
3832
|
+
gap: 8px;
|
|
3833
|
+
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
3834
|
+
border-radius: 999px;
|
|
3835
|
+
background: rgba(17, 18, 21, 0.92);
|
|
3836
|
+
color: rgba(255, 255, 255, 0.9);
|
|
3837
|
+
font-size: 12px;
|
|
3838
|
+
line-height: 1;
|
|
3839
|
+
padding: 10px 14px;
|
|
3840
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
|
|
3841
|
+
cursor: pointer;
|
|
3842
|
+
z-index: 1;
|
|
3843
|
+
pointer-events: auto;
|
|
3844
|
+
|
|
3845
|
+
&:hover {
|
|
3846
|
+
background: rgba(28, 30, 36, 0.96);
|
|
3847
|
+
}
|
|
3848
|
+
`;
|
|
3849
|
+
var ScrollToLatestBadge = styled9.span`
|
|
3850
|
+
display: inline-flex;
|
|
3851
|
+
min-width: 18px;
|
|
3852
|
+
height: 18px;
|
|
3853
|
+
align-items: center;
|
|
3854
|
+
justify-content: center;
|
|
3855
|
+
padding: 0 6px;
|
|
3856
|
+
border-radius: 999px;
|
|
3857
|
+
background: rgba(109, 170, 255, 0.2);
|
|
3858
|
+
color: #9ac0ff;
|
|
3859
|
+
font-size: 11px;
|
|
3860
|
+
font-weight: 600;
|
|
3861
|
+
`;
|
|
3693
3862
|
|
|
3694
3863
|
// src/components/chat-composer/index.tsx
|
|
3695
3864
|
import { useEffect as useEffect7, useLayoutEffect as useLayoutEffect3, useRef as useRef8, useState as useState8 } from "react";
|
|
@@ -4897,7 +5066,7 @@ var ChatComposerView = ({
|
|
|
4897
5066
|
}
|
|
4898
5067
|
) : null,
|
|
4899
5068
|
/* @__PURE__ */ jsx15(
|
|
4900
|
-
|
|
5069
|
+
Input2,
|
|
4901
5070
|
{
|
|
4902
5071
|
ref: inputRef,
|
|
4903
5072
|
"data-testid": "chat-composer-input",
|
|
@@ -5041,7 +5210,7 @@ var InputArea = styled14.div`
|
|
|
5041
5210
|
grid-area: input;
|
|
5042
5211
|
position: relative;
|
|
5043
5212
|
`;
|
|
5044
|
-
var
|
|
5213
|
+
var Input2 = styled14.textarea`
|
|
5045
5214
|
--textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
|
|
5046
5215
|
--textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
|
|
5047
5216
|
--textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xinghunm/ai-chat",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "AI chat React component library",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@emotion/react": ">=11",
|
|
21
21
|
"@emotion/styled": ">=11",
|
|
22
|
-
"@xinghunm/compass-ui": ">=0.
|
|
22
|
+
"@xinghunm/compass-ui": ">=0.9.0",
|
|
23
23
|
"axios": ">=1.0",
|
|
24
24
|
"react": ">=18",
|
|
25
25
|
"react-dom": ">=18",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"tsup": "^8.0.0",
|
|
54
54
|
"typescript": "^5.2.2",
|
|
55
55
|
"zustand": "^5.0.0",
|
|
56
|
-
"@xinghunm/compass-ui": "^0.
|
|
56
|
+
"@xinghunm/compass-ui": "^0.9.0"
|
|
57
57
|
},
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public"
|