@brainfish-ai/components 0.13.7 → 0.13.9

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.
@@ -25,10 +25,12 @@ interface ChatSearchContextProps {
25
25
  setLoadError: React.Dispatch<React.SetStateAction<string>>;
26
26
  showMobileCloseWidgetButton: boolean;
27
27
  setShowMobileCloseWidgetButton: React.Dispatch<React.SetStateAction<boolean>>;
28
+ contentTypeEndpoint?: string;
28
29
  }
29
30
  export declare const ChatSearchProvider: React.FC<{
30
31
  children: ReactNode;
31
32
  searchPath?: string;
33
+ contentTypeEndpoint?: string;
32
34
  }>;
33
35
  export declare const useChatSearch: () => ChatSearchContextProps;
34
36
  export {};
@@ -1,5 +1,6 @@
1
1
  import { RefObject } from 'react';
2
- export declare const useScrollManager: (answerRefs: RefObject<(HTMLDivElement | null)[]>, containerRef: RefObject<HTMLDivElement | null>) => {
2
+ export declare const useScrollManager: (answerRefs: RefObject<(HTMLDivElement | null)[]>, containerRef: RefObject<HTMLDivElement | null>, bottomRef?: RefObject<HTMLDivElement | null>) => {
3
3
  scrollToLastAnswer: () => void;
4
4
  scrollToAnswer: (index: number) => void;
5
+ scrollToBottom: () => void;
5
6
  };
@@ -160,6 +160,7 @@ export interface ChatSearchProps {
160
160
  loadConversationEndpoint?: string;
161
161
  followUpQuestionsEndpoint?: string;
162
162
  autocompleteEndpoint?: string;
163
+ contentTypeEndpoint?: string;
163
164
  disableFollowUpQuestions?: boolean;
164
165
  disableImageAttachment?: boolean;
165
166
  disableFeedback?: boolean;
@@ -8,7 +8,7 @@ export interface Props {
8
8
  message: Message;
9
9
  isStreaming?: boolean;
10
10
  redirectRules?: RedirectRule[];
11
- apiUrl?: string;
11
+ contentTypeEndpoint?: string;
12
12
  }
13
13
  export declare const FormattedMessage: FC<Props>;
14
14
  export {};
@@ -1,9 +1,9 @@
1
- import React__default, { Fragment, useState, useCallback, useMemo, createContext, useContext, useRef, useEffect, forwardRef, useImperativeHandle } from 'react';
1
+ import React__default, { useState, useCallback, useMemo, createContext, useContext, Fragment, useRef, useEffect, forwardRef, useImperativeHandle } from 'react';
2
2
  import { motion, AnimatePresence } from 'framer-motion';
3
3
  import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '../components/ui/tooltip.js';
4
4
  import { Button } from '../components/ui/button.js';
5
5
  import { XCircle, Check, Copy, CaretDown, ArrowSquareOut, CaretRight, ArrowsVertical, ArrowDown, MagnifyingGlass, X, CheckCircle, Circle, Image, ArrowRight, ArrowLeft, ArrowsInSimple, ArrowsOutSimple } from '@phosphor-icons/react';
6
- import { g as getDefaultExportFromCjs, F as FormattedMessage, c as addPopupWidgetUtm } from './FormattedMessage.CpTetIzd.js';
6
+ import { g as getDefaultExportFromCjs, F as FormattedMessage, c as addPopupWidgetUtm } from './FormattedMessage.Ci8jirX2.js';
7
7
  import { appendErrors, useForm, Controller } from 'react-hook-form';
8
8
  import { validateFieldsNatively, toNestErrors } from '@hookform/resolvers';
9
9
  import require$$0 from 'ajv';
@@ -14,13 +14,13 @@ import { S as SimpleSelect } from './simpleSelect.BfAgKOea.js';
14
14
  import { c as cn, i as isAnswerUncertain } from './utils.DaMF_LVC.js';
15
15
  import { D as DatePicker } from './date-picker.DqcdwXZS.js';
16
16
  import { createId } from '@paralleldrive/cuid2';
17
+ import { useImmerReducer } from 'use-immer';
18
+ import { useSearchParam, useEffectOnce } from 'react-use';
17
19
  import { MemoizedIcon } from '../components/ui/icon.js';
18
20
  import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '../components/ui/collapsible.js';
19
21
  import { F as Feedback } from './feedback.NWn6_mYe.js';
20
22
  import { G as GeneratingStar } from './generating-star.B0RUXRff.js';
21
23
  import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '../components/ui/dropdown-menu.js';
22
- import { useImmerReducer } from 'use-immer';
23
- import { useSearchParam, useEffectOnce } from 'react-use';
24
24
  import { ScrollArea } from '../components/ui/scroll-area.js';
25
25
 
26
26
  import '../ChatSearch.css';function Suggestions({ suggestions, onQuestionClick, title = "Suggested questions" }) {
@@ -3450,36 +3450,6 @@ function ActionButtonsBlock({ block: _block }) {
3450
3450
  return null;
3451
3451
  }
3452
3452
 
3453
- function MarkdownTextBlock({ block, redirectRules, state }) {
3454
- if (!block.text || block.text.trim() === "") {
3455
- return /* @__PURE__ */ React__default.createElement("div", { className: "w-full py-4" }, /* @__PURE__ */ React__default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React__default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React__default.createElement("div", { className: "h-4 rounded w-3/4 shimmer" }), /* @__PURE__ */ React__default.createElement("div", { className: "h-4 rounded w-full shimmer" }), /* @__PURE__ */ React__default.createElement("div", { className: "h-4 rounded w-5/6 shimmer" }))));
3456
- }
3457
- const { text } = block;
3458
- return /* @__PURE__ */ React__default.createElement("div", { className: "w-full" }, /* @__PURE__ */ React__default.createElement("div", { className: "prose prose-sm max-w-none text-foreground" }, /* @__PURE__ */ React__default.createElement(
3459
- FormattedMessage,
3460
- {
3461
- message: {
3462
- content: text
3463
- },
3464
- redirectRules,
3465
- isStreaming: state === "streaming"
3466
- }
3467
- )));
3468
- }
3469
-
3470
- function AnswerBlock({ block, redirectRules, state }) {
3471
- switch (block.type) {
3472
- case "markdown-text":
3473
- return /* @__PURE__ */ React__default.createElement(MarkdownTextBlock, { block, redirectRules, state });
3474
- case "action-buttons":
3475
- return /* @__PURE__ */ React__default.createElement(ActionButtonsBlock, { block });
3476
- case "action-input-form":
3477
- return /* @__PURE__ */ React__default.createElement(ActionInputFormBlock, { block });
3478
- default:
3479
- return null;
3480
- }
3481
- }
3482
-
3483
3453
  const markdownTextBlock = ({ text = "" } = {}) => ({
3484
3454
  id: createId(),
3485
3455
  type: "markdown-text",
@@ -3512,196 +3482,6 @@ const isActionInputFormBlock = (block) => {
3512
3482
  return block.type === "action-input-form";
3513
3483
  };
3514
3484
 
3515
- const MotionButton$1 = motion(Button);
3516
- const NextBestActions = ({ nextBestActions, onActionClick }) => {
3517
- if (!nextBestActions.length) return null;
3518
- return /* @__PURE__ */ React__default.createElement(
3519
- motion.div,
3520
- {
3521
- initial: { opacity: 0, y: 20 },
3522
- animate: { opacity: 1, y: 0 },
3523
- exit: { opacity: 0, y: -20 },
3524
- className: "w-full"
3525
- },
3526
- /* @__PURE__ */ React__default.createElement("div", { className: "rounded-lg overflow-hidden bg-card border divide-y divide-dark-300" }, nextBestActions.map((action, index) => {
3527
- const handleClick = () => {
3528
- onActionClick(action);
3529
- };
3530
- const className = "w-full h-12 py-2 px-4 inline-flex items-center justify-center gap-2 whitespace-nowrap text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-6 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground";
3531
- const key = `${action.label}-${index}`.replace(/\s+/g, "-");
3532
- switch (action.type) {
3533
- case "email":
3534
- return /* @__PURE__ */ React__default.createElement(
3535
- motion.a,
3536
- {
3537
- key,
3538
- initial: { opacity: 0, x: -20 },
3539
- animate: { opacity: 1, x: 0 },
3540
- transition: { delay: index * 0.1 },
3541
- href: `mailto:${action.value}`,
3542
- target: "_blank",
3543
- rel: "noopener noreferrer",
3544
- className,
3545
- onClick: () => handleClick()
3546
- },
3547
- action.icon && /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: action.icon }),
3548
- /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3549
- /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3550
- );
3551
- case "link":
3552
- return /* @__PURE__ */ React__default.createElement(
3553
- motion.a,
3554
- {
3555
- key,
3556
- initial: { opacity: 0, x: -20 },
3557
- animate: { opacity: 1, x: 0 },
3558
- transition: { delay: index * 0.1 },
3559
- href: addPopupWidgetUtm(action.value),
3560
- target: "_blank",
3561
- rel: "noopener noreferrer",
3562
- className,
3563
- onClick: () => handleClick()
3564
- },
3565
- action.icon && /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: action.icon }),
3566
- /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3567
- /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3568
- );
3569
- case "phone":
3570
- return /* @__PURE__ */ React__default.createElement(
3571
- motion.a,
3572
- {
3573
- key,
3574
- initial: { opacity: 0, x: -20 },
3575
- animate: { opacity: 1, x: 0 },
3576
- transition: { delay: index * 0.1 },
3577
- href: `tel:${action.value}`,
3578
- target: "_blank",
3579
- rel: "noopener noreferrer",
3580
- className,
3581
- onClick: () => handleClick()
3582
- },
3583
- action.icon && /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: action.icon }),
3584
- /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3585
- /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3586
- );
3587
- default:
3588
- return /* @__PURE__ */ React__default.createElement(Fragment, { key }, /* @__PURE__ */ React__default.createElement(
3589
- MotionButton$1,
3590
- {
3591
- initial: { opacity: 0, x: -20 },
3592
- animate: { opacity: 1, x: 0 },
3593
- transition: { delay: index * 0.1 },
3594
- className: "w-full text-left h-12 rounded-none [&_svg]:pointer-events-none [&_svg]:size-6 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground text-base font-medium",
3595
- variant: "ghost",
3596
- onClick: () => handleClick()
3597
- },
3598
- /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowCircleRight" }),
3599
- /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3600
- /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3601
- ));
3602
- }
3603
- }))
3604
- );
3605
- };
3606
-
3607
- var ActionType = /* @__PURE__ */ ((ActionType2) => {
3608
- ActionType2["CallPhone"] = "call_phone";
3609
- ActionType2["OpenUrl"] = "open_url";
3610
- ActionType2["SendEmail"] = "send_email";
3611
- ActionType2["RunCallback"] = "run_callback";
3612
- return ActionType2;
3613
- })(ActionType || {});
3614
- var NextBestActionType = /* @__PURE__ */ ((NextBestActionType2) => {
3615
- NextBestActionType2["Link"] = "link";
3616
- NextBestActionType2["Email"] = "email";
3617
- NextBestActionType2["Phone"] = "phone";
3618
- NextBestActionType2["Callback"] = "callback";
3619
- NextBestActionType2["Function"] = "function";
3620
- return NextBestActionType2;
3621
- })(NextBestActionType || {});
3622
-
3623
- const getActionMapping = (action) => {
3624
- const actionMapping = {
3625
- [ActionType.CallPhone]: {
3626
- type: NextBestActionType.Phone,
3627
- icon: "Phone",
3628
- getValue: (a) => a.action?.options?.phoneNumber || a.id,
3629
- getLabel: (a) => a.action?.options?.title || a.type
3630
- },
3631
- [ActionType.SendEmail]: {
3632
- type: NextBestActionType.Email,
3633
- icon: "EnvelopeSimple",
3634
- getValue: (a) => a.action?.options?.to || a.id,
3635
- getLabel: (a) => a.action?.options?.title || a.type
3636
- },
3637
- [ActionType.OpenUrl]: {
3638
- type: NextBestActionType.Link,
3639
- icon: "Link",
3640
- getValue: (a) => a.action?.options?.url || a.id,
3641
- getLabel: (a) => a.action?.options?.title || a.type
3642
- }
3643
- };
3644
- const mapping = actionMapping[action.type] || {
3645
- type: NextBestActionType.Link,
3646
- icon: "Link",
3647
- getValue: (a) => a.action?.options?.url || a.id,
3648
- getLabel: (a) => a.action?.options?.title || a.type
3649
- };
3650
- return mapping;
3651
- };
3652
-
3653
- const AnswerActions = ({
3654
- actions,
3655
- nextBestActions,
3656
- isLastAnswer,
3657
- handleActionClick,
3658
- searchQueryId,
3659
- question,
3660
- answer
3661
- }) => {
3662
- const hasActions = actions && actions.length > 0;
3663
- const hasNextBestActions = nextBestActions && isLastAnswer && nextBestActions.length > 0;
3664
- const [showAnswerActions] = useState(hasActions || hasNextBestActions);
3665
- if (!showAnswerActions) {
3666
- return null;
3667
- }
3668
- let mappedActions = [];
3669
- if (hasActions) {
3670
- mappedActions = actions.map((action) => {
3671
- const mapping = getActionMapping(action);
3672
- return {
3673
- id: action.id,
3674
- label: mapping.getLabel(action),
3675
- type: mapping.type,
3676
- icon: mapping.icon,
3677
- value: mapping.getValue(action)
3678
- };
3679
- });
3680
- }
3681
- if (hasNextBestActions) {
3682
- const filteredNextBestActions = nextBestActions.filter(
3683
- (action) => !mappedActions.some((mappedAction) => mappedAction.type === action.type)
3684
- );
3685
- mappedActions = mappedActions.concat(filteredNextBestActions);
3686
- }
3687
- return /* @__PURE__ */ React__default.createElement("div", { className: "p-4" }, /* @__PURE__ */ React__default.createElement(
3688
- NextBestActions,
3689
- {
3690
- nextBestActions: mappedActions,
3691
- onActionClick: (action) => {
3692
- if (action) {
3693
- handleActionClick?.({
3694
- action,
3695
- searchQueryId: searchQueryId || "",
3696
- query: question,
3697
- answer
3698
- });
3699
- }
3700
- }
3701
- }
3702
- ));
3703
- };
3704
-
3705
3485
  const AnswersActions = {
3706
3486
  SET_ANSWERS: "answers/set_answers",
3707
3487
  CLEAR_ALL: "answers/clear_all",
@@ -4030,10 +3810,7 @@ const useConversationId = (searchPath) => {
4030
3810
  };
4031
3811
 
4032
3812
  const ChatSearchContext = createContext(void 0);
4033
- const ChatSearchProvider = ({
4034
- children,
4035
- searchPath
4036
- }) => {
3813
+ const ChatSearchProvider = ({ children, searchPath, contentTypeEndpoint }) => {
4037
3814
  const [query, setQuery] = useState("");
4038
3815
  const [queryId, setQueryId] = useState("");
4039
3816
  const [followUpQuery, setFollowUpQuery] = useState("");
@@ -4069,7 +3846,8 @@ const ChatSearchProvider = ({
4069
3846
  loadError,
4070
3847
  setLoadError,
4071
3848
  showMobileCloseWidgetButton,
4072
- setShowMobileCloseWidgetButton
3849
+ setShowMobileCloseWidgetButton,
3850
+ contentTypeEndpoint
4073
3851
  }),
4074
3852
  [
4075
3853
  query,
@@ -4085,7 +3863,8 @@ const ChatSearchProvider = ({
4085
3863
  clearConversationId,
4086
3864
  isLoadingConversation,
4087
3865
  loadError,
4088
- showMobileCloseWidgetButton
3866
+ showMobileCloseWidgetButton,
3867
+ contentTypeEndpoint
4089
3868
  ]
4090
3869
  );
4091
3870
  return /* @__PURE__ */ React__default.createElement(ChatSearchContext.Provider, { value: contextValue }, children);
@@ -4098,13 +3877,235 @@ const useChatSearch = () => {
4098
3877
  return context;
4099
3878
  };
4100
3879
 
3880
+ function MarkdownTextBlock({ block, redirectRules, state }) {
3881
+ const { contentTypeEndpoint } = useChatSearch();
3882
+ if (!block.text || block.text.trim() === "") {
3883
+ return /* @__PURE__ */ React__default.createElement("div", { className: "w-full py-4" }, /* @__PURE__ */ React__default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React__default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React__default.createElement("div", { className: "h-4 rounded w-3/4 shimmer" }), /* @__PURE__ */ React__default.createElement("div", { className: "h-4 rounded w-full shimmer" }), /* @__PURE__ */ React__default.createElement("div", { className: "h-4 rounded w-5/6 shimmer" }))));
3884
+ }
3885
+ const { text } = block;
3886
+ return /* @__PURE__ */ React__default.createElement("div", { className: "w-full" }, /* @__PURE__ */ React__default.createElement("div", { className: "prose prose-sm max-w-none text-foreground" }, /* @__PURE__ */ React__default.createElement(
3887
+ FormattedMessage,
3888
+ {
3889
+ message: {
3890
+ content: text
3891
+ },
3892
+ redirectRules,
3893
+ isStreaming: state === "streaming",
3894
+ contentTypeEndpoint
3895
+ }
3896
+ )));
3897
+ }
3898
+
3899
+ function AnswerBlock({ block, redirectRules, state }) {
3900
+ switch (block.type) {
3901
+ case "markdown-text":
3902
+ return /* @__PURE__ */ React__default.createElement(MarkdownTextBlock, { block, redirectRules, state });
3903
+ case "action-buttons":
3904
+ return /* @__PURE__ */ React__default.createElement(ActionButtonsBlock, { block });
3905
+ case "action-input-form":
3906
+ return /* @__PURE__ */ React__default.createElement(ActionInputFormBlock, { block });
3907
+ default:
3908
+ return null;
3909
+ }
3910
+ }
3911
+
3912
+ const MotionButton$1 = motion(Button);
3913
+ const NextBestActions = ({ nextBestActions, onActionClick }) => {
3914
+ if (!nextBestActions.length) return null;
3915
+ return /* @__PURE__ */ React__default.createElement(
3916
+ motion.div,
3917
+ {
3918
+ initial: { opacity: 0, y: 20 },
3919
+ animate: { opacity: 1, y: 0 },
3920
+ exit: { opacity: 0, y: -20 },
3921
+ className: "w-full"
3922
+ },
3923
+ /* @__PURE__ */ React__default.createElement("div", { className: "rounded-lg overflow-hidden bg-card border divide-y divide-dark-300" }, nextBestActions.map((action, index) => {
3924
+ const handleClick = () => {
3925
+ onActionClick(action);
3926
+ };
3927
+ const className = "w-full h-12 py-2 px-4 inline-flex items-center justify-center gap-2 whitespace-nowrap text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-6 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground";
3928
+ const key = `${action.label}-${index}`.replace(/\s+/g, "-");
3929
+ switch (action.type) {
3930
+ case "email":
3931
+ return /* @__PURE__ */ React__default.createElement(
3932
+ motion.a,
3933
+ {
3934
+ key,
3935
+ initial: { opacity: 0, x: -20 },
3936
+ animate: { opacity: 1, x: 0 },
3937
+ transition: { delay: index * 0.1 },
3938
+ href: `mailto:${action.value}`,
3939
+ target: "_blank",
3940
+ rel: "noopener noreferrer",
3941
+ className,
3942
+ onClick: () => handleClick()
3943
+ },
3944
+ action.icon && /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: action.icon }),
3945
+ /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3946
+ /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3947
+ );
3948
+ case "link":
3949
+ return /* @__PURE__ */ React__default.createElement(
3950
+ motion.a,
3951
+ {
3952
+ key,
3953
+ initial: { opacity: 0, x: -20 },
3954
+ animate: { opacity: 1, x: 0 },
3955
+ transition: { delay: index * 0.1 },
3956
+ href: addPopupWidgetUtm(action.value),
3957
+ target: "_blank",
3958
+ rel: "noopener noreferrer",
3959
+ className,
3960
+ onClick: () => handleClick()
3961
+ },
3962
+ action.icon && /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: action.icon }),
3963
+ /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3964
+ /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3965
+ );
3966
+ case "phone":
3967
+ return /* @__PURE__ */ React__default.createElement(
3968
+ motion.a,
3969
+ {
3970
+ key,
3971
+ initial: { opacity: 0, x: -20 },
3972
+ animate: { opacity: 1, x: 0 },
3973
+ transition: { delay: index * 0.1 },
3974
+ href: `tel:${action.value}`,
3975
+ target: "_blank",
3976
+ rel: "noopener noreferrer",
3977
+ className,
3978
+ onClick: () => handleClick()
3979
+ },
3980
+ action.icon && /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: action.icon }),
3981
+ /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3982
+ /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3983
+ );
3984
+ default:
3985
+ return /* @__PURE__ */ React__default.createElement(Fragment, { key }, /* @__PURE__ */ React__default.createElement(
3986
+ MotionButton$1,
3987
+ {
3988
+ initial: { opacity: 0, x: -20 },
3989
+ animate: { opacity: 1, x: 0 },
3990
+ transition: { delay: index * 0.1 },
3991
+ className: "w-full text-left h-12 rounded-none [&_svg]:pointer-events-none [&_svg]:size-6 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground text-base font-medium",
3992
+ variant: "ghost",
3993
+ onClick: () => handleClick()
3994
+ },
3995
+ /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowCircleRight" }),
3996
+ /* @__PURE__ */ React__default.createElement("span", { className: "flex-grow" }, action.label),
3997
+ /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "ArrowSquareOut" })
3998
+ ));
3999
+ }
4000
+ }))
4001
+ );
4002
+ };
4003
+
4004
+ var ActionType = /* @__PURE__ */ ((ActionType2) => {
4005
+ ActionType2["CallPhone"] = "call_phone";
4006
+ ActionType2["OpenUrl"] = "open_url";
4007
+ ActionType2["SendEmail"] = "send_email";
4008
+ ActionType2["RunCallback"] = "run_callback";
4009
+ return ActionType2;
4010
+ })(ActionType || {});
4011
+ var NextBestActionType = /* @__PURE__ */ ((NextBestActionType2) => {
4012
+ NextBestActionType2["Link"] = "link";
4013
+ NextBestActionType2["Email"] = "email";
4014
+ NextBestActionType2["Phone"] = "phone";
4015
+ NextBestActionType2["Callback"] = "callback";
4016
+ NextBestActionType2["Function"] = "function";
4017
+ return NextBestActionType2;
4018
+ })(NextBestActionType || {});
4019
+
4020
+ const getActionMapping = (action) => {
4021
+ const actionMapping = {
4022
+ [ActionType.CallPhone]: {
4023
+ type: NextBestActionType.Phone,
4024
+ icon: "Phone",
4025
+ getValue: (a) => a.action?.options?.phoneNumber || a.id,
4026
+ getLabel: (a) => a.action?.options?.title || a.type
4027
+ },
4028
+ [ActionType.SendEmail]: {
4029
+ type: NextBestActionType.Email,
4030
+ icon: "EnvelopeSimple",
4031
+ getValue: (a) => a.action?.options?.to || a.id,
4032
+ getLabel: (a) => a.action?.options?.title || a.type
4033
+ },
4034
+ [ActionType.OpenUrl]: {
4035
+ type: NextBestActionType.Link,
4036
+ icon: "Link",
4037
+ getValue: (a) => a.action?.options?.url || a.id,
4038
+ getLabel: (a) => a.action?.options?.title || a.type
4039
+ }
4040
+ };
4041
+ const mapping = actionMapping[action.type] || {
4042
+ type: NextBestActionType.Link,
4043
+ icon: "Link",
4044
+ getValue: (a) => a.action?.options?.url || a.id,
4045
+ getLabel: (a) => a.action?.options?.title || a.type
4046
+ };
4047
+ return mapping;
4048
+ };
4049
+
4050
+ const AnswerActions = ({
4051
+ actions,
4052
+ nextBestActions,
4053
+ isLastAnswer,
4054
+ handleActionClick,
4055
+ searchQueryId,
4056
+ question,
4057
+ answer
4058
+ }) => {
4059
+ const hasActions = actions && actions.length > 0;
4060
+ const hasNextBestActions = nextBestActions && isLastAnswer && nextBestActions.length > 0;
4061
+ const [showAnswerActions] = useState(hasActions || hasNextBestActions);
4062
+ if (!showAnswerActions) {
4063
+ return null;
4064
+ }
4065
+ let mappedActions = [];
4066
+ if (hasActions) {
4067
+ mappedActions = actions.map((action) => {
4068
+ const mapping = getActionMapping(action);
4069
+ return {
4070
+ id: action.id,
4071
+ label: mapping.getLabel(action),
4072
+ type: mapping.type,
4073
+ icon: mapping.icon,
4074
+ value: mapping.getValue(action)
4075
+ };
4076
+ });
4077
+ }
4078
+ if (hasNextBestActions) {
4079
+ const filteredNextBestActions = nextBestActions.filter(
4080
+ (action) => !mappedActions.some((mappedAction) => mappedAction.type === action.type)
4081
+ );
4082
+ mappedActions = mappedActions.concat(filteredNextBestActions);
4083
+ }
4084
+ return /* @__PURE__ */ React__default.createElement("div", { className: "p-4" }, /* @__PURE__ */ React__default.createElement(
4085
+ NextBestActions,
4086
+ {
4087
+ nextBestActions: mappedActions,
4088
+ onActionClick: (action) => {
4089
+ if (action) {
4090
+ handleActionClick?.({
4091
+ action,
4092
+ searchQueryId: searchQueryId || "",
4093
+ query: question,
4094
+ answer
4095
+ });
4096
+ }
4097
+ }
4098
+ }
4099
+ ));
4100
+ };
4101
+
4101
4102
  const useIsChatSearchDirty = () => {
4102
4103
  const { showResults, answers } = useChatSearch();
4103
4104
  const isDirty = Boolean(showResults || answers.length > 0);
4104
4105
  return isDirty;
4105
4106
  };
4106
4107
 
4107
- const useScrollManager = (answerRefs, containerRef) => {
4108
+ const useScrollManager = (answerRefs, containerRef, bottomRef) => {
4108
4109
  const scrollToLastAnswer = () => {
4109
4110
  requestAnimationFrame(() => {
4110
4111
  const lastAnswer = answerRefs.current?.[answerRefs.current.length - 1];
@@ -4129,7 +4130,14 @@ const useScrollManager = (answerRefs, containerRef) => {
4129
4130
  }
4130
4131
  });
4131
4132
  };
4132
- return { scrollToLastAnswer, scrollToAnswer };
4133
+ const scrollToBottom = () => {
4134
+ setTimeout(() => {
4135
+ if (bottomRef?.current && containerRef.current) {
4136
+ bottomRef.current.scrollIntoView({ behavior: "smooth", block: "end" });
4137
+ }
4138
+ }, 200);
4139
+ };
4140
+ return { scrollToLastAnswer, scrollToAnswer, scrollToBottom };
4133
4141
  };
4134
4142
 
4135
4143
  const defaultRetryOptions = {
@@ -4524,7 +4532,7 @@ function Answer({
4524
4532
  return /* @__PURE__ */ React__default.createElement(
4525
4533
  "div",
4526
4534
  {
4527
- className: "rounded-lg relative mx-auto overflow-hidden bg-card border border-primary mb-4",
4535
+ className: "rounded-lg relative mx-auto overflow-hidden bg-card border border-primary",
4528
4536
  "data-name": "SearchResults",
4529
4537
  "data-index": index
4530
4538
  },
@@ -5352,6 +5360,7 @@ const ChatSearchComponent = forwardRef(
5352
5360
  const fileInputRef = useRef(null);
5353
5361
  const primarySearchRef = useRef(null);
5354
5362
  const followUpSearchRef = useRef(null);
5363
+ const bottomRef = useRef(null);
5355
5364
  const { suggestions: autocompleteSuggestions } = useAutocomplete({
5356
5365
  query,
5357
5366
  endpoint: autocompleteEndpoint || "",
@@ -5366,7 +5375,11 @@ const ChatSearchComponent = forwardRef(
5366
5375
  headers,
5367
5376
  mergedTextConfig
5368
5377
  });
5369
- const { scrollToLastAnswer, scrollToAnswer } = useScrollManager(answerRefs, containerRef);
5378
+ const { scrollToLastAnswer, scrollToAnswer, scrollToBottom } = useScrollManager(
5379
+ answerRefs,
5380
+ containerRef,
5381
+ bottomRef
5382
+ );
5370
5383
  const { subscribeToStateChanges } = useSubscriptionManager();
5371
5384
  const loadFollowUpQuestions = async (searchQueryId, conversationId) => {
5372
5385
  if (!followUpQuestionsEndpoint || disableFollowUpQuestions) {
@@ -5403,6 +5416,7 @@ const ChatSearchComponent = forwardRef(
5403
5416
  for (const line of lines) {
5404
5417
  try {
5405
5418
  if (line === "[DONE]") {
5419
+ scrollToBottom();
5406
5420
  continue;
5407
5421
  }
5408
5422
  const event = JSON.parse(line);
@@ -5413,6 +5427,7 @@ const ChatSearchComponent = forwardRef(
5413
5427
  text: event.content
5414
5428
  })
5415
5429
  );
5430
+ scrollToBottom();
5416
5431
  const uncertaintyCheck = isAnswerUncertain(accumulatedAnswer);
5417
5432
  isUncertain = uncertaintyCheck.uncertain;
5418
5433
  if (isUncertain) {
@@ -5944,7 +5959,8 @@ const ChatSearchComponent = forwardRef(
5944
5959
  ref: (el) => answerRefs.current[i] = el,
5945
5960
  initial: { opacity: 0, y: 20 },
5946
5961
  animate: { opacity: 1, y: 0 },
5947
- transition: { duration: 0.5, delay: i * 0.1 }
5962
+ transition: { duration: 0.5, delay: i * 0.1 },
5963
+ className: "space-y-4 last:!mb-8"
5948
5964
  },
5949
5965
  /* @__PURE__ */ React__default.createElement(
5950
5966
  Answer,
@@ -5967,13 +5983,13 @@ const ChatSearchComponent = forwardRef(
5967
5983
  onFeedbackReasonSubmit: (reason) => void handleFeedbackReasonSubmit(reason, answer.searchQueryId)
5968
5984
  }
5969
5985
  ),
5970
- i === answers.length - 1 && !disableFollowUpQuestions && answer.followUpQuestions && answer.state === "completed" && /* @__PURE__ */ React__default.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React__default.createElement(
5986
+ i === answers.length - 1 && !disableFollowUpQuestions && answer.followUpQuestions && answer.state === "completed" && /* @__PURE__ */ React__default.createElement(
5971
5987
  FollowUpQuestions,
5972
5988
  {
5973
5989
  questions: answer.followUpQuestions,
5974
5990
  onQuestionClick: handleFollowUpQuestionClick
5975
5991
  }
5976
- ))
5992
+ )
5977
5993
  ))
5978
5994
  ))), showResults && answers.length > 1 && /* @__PURE__ */ React__default.createElement("div", { className: "hidden lg:block" }, /* @__PURE__ */ React__default.createElement(
5979
5995
  TimelineNavigation,
@@ -5986,7 +6002,7 @@ const ChatSearchComponent = forwardRef(
5986
6002
  },
5987
6003
  offset
5988
6004
  }
5989
- )), disclaimer && isWidgetMode && !(showResults && showFollowUp) && /* @__PURE__ */ React__default.createElement("div", { className: "mt-2 px-3 @3xl:px-0 text-xs text-dark-500 flex items-center gap-1 absolute bottom-12 justify-center text-center w-full" }, /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "Info", className: "size-4" }), disclaimer)),
6005
+ )), disclaimer && isWidgetMode && !(showResults && showFollowUp) && /* @__PURE__ */ React__default.createElement("div", { className: "mt-2 px-3 @3xl:px-0 text-xs text-dark-500 flex items-center gap-1 absolute bottom-12 justify-center text-center w-full" }, /* @__PURE__ */ React__default.createElement(MemoizedIcon, { iconName: "Info", className: "size-4" }), disclaimer), /* @__PURE__ */ React__default.createElement("div", { ref: bottomRef })),
5990
6006
  showResults && showFollowUp && /* @__PURE__ */ React__default.createElement(
5991
6007
  FollowUpSearchBar,
5992
6008
  {
@@ -6003,8 +6019,8 @@ const ChatSearchComponent = forwardRef(
6003
6019
  }
6004
6020
  );
6005
6021
  ChatSearchComponent.displayName = "ChatSearch";
6006
- const ChatSearch = forwardRef(({ featureFlags, ...props }, ref) => /* @__PURE__ */ React__default.createElement(FeatureFlagProvider, { flags: featureFlags }, /* @__PURE__ */ React__default.createElement(ChatSearchProvider, { searchPath: props.searchPath }, /* @__PURE__ */ React__default.createElement(ChatSearchComponent, { ...props, ref }))));
6022
+ const ChatSearch = forwardRef(({ featureFlags, ...props }, ref) => /* @__PURE__ */ React__default.createElement(FeatureFlagProvider, { flags: featureFlags }, /* @__PURE__ */ React__default.createElement(ChatSearchProvider, { searchPath: props.searchPath, contentTypeEndpoint: props.contentTypeEndpoint }, /* @__PURE__ */ React__default.createElement(ChatSearchComponent, { ...props, ref }))));
6007
6023
  ChatSearch.displayName = "ChatSearch";
6008
6024
 
6009
6025
  export { ChatSearch as C, ChatSearchProvider as a, useIsChatSearchDirty as b, useChatSearch as u };
6010
- //# sourceMappingURL=ChatSearch.CxwRDkGx.js.map
6026
+ //# sourceMappingURL=ChatSearch.CNtUt5oJ.js.map