@aslaluroba/help-center-react 3.0.3 → 3.0.5

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.
Files changed (57) hide show
  1. package/README.md +28 -33
  2. package/dist/components/shared/Button/button.d.ts +1 -2
  3. package/dist/components/ui/agent-response/agent-response.d.ts +1 -2
  4. package/dist/components/ui/header.d.ts +1 -2
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +1 -2
  7. package/dist/index.esm.js +36039 -11175
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +35997 -11135
  10. package/dist/index.js.map +1 -1
  11. package/dist/ui/chatbot-popup/chat-window-screen/footer.d.ts +0 -2
  12. package/dist/ui/chatbot-popup/chat-window-screen/header.d.ts +1 -1
  13. package/dist/ui/chatbot-popup/chat-window-screen/index.d.ts +1 -1
  14. package/dist/ui/chatbot-popup/error-screen/index.d.ts +0 -1
  15. package/dist/ui/chatbot-popup/home-screen/card.d.ts +0 -1
  16. package/dist/ui/chatbot-popup/home-screen/chat-now-card.d.ts +0 -1
  17. package/dist/ui/chatbot-popup/home-screen/index.d.ts +0 -1
  18. package/dist/ui/chatbot-popup/loading-screen/index.d.ts +0 -1
  19. package/dist/ui/chatbot-popup/options-list-screen/expanded-option.d.ts +0 -1
  20. package/dist/ui/chatbot-popup/options-list-screen/header.d.ts +0 -1
  21. package/dist/ui/chatbot-popup/options-list-screen/index.d.ts +0 -1
  22. package/dist/ui/chatbot-popup/options-list-screen/option-card.d.ts +0 -1
  23. package/dist/ui/confirmation-modal/index.d.ts +1 -2
  24. package/dist/ui/floating-message.d.ts +1 -2
  25. package/dist/ui/help-button.d.ts +1 -2
  26. package/dist/ui/help-center.d.ts +1 -2
  27. package/dist/ui/help-popup.d.ts +1 -2
  28. package/dist/ui/review-dialog/index.d.ts +0 -1
  29. package/package.json +25 -25
  30. package/src/components/shared/Button/button.tsx +0 -1
  31. package/src/components/ui/agent-response/agent-response.tsx +0 -1
  32. package/src/components/ui/header.tsx +0 -1
  33. package/src/globals.css +1 -1
  34. package/src/index.ts +1 -3
  35. package/src/types/svg.d.ts +4 -4
  36. package/src/ui/chatbot-popup/chat-window-screen/footer.tsx +1 -3
  37. package/src/ui/chatbot-popup/chat-window-screen/header.tsx +42 -26
  38. package/src/ui/chatbot-popup/chat-window-screen/index.tsx +96 -99
  39. package/src/ui/chatbot-popup/error-screen/index.tsx +0 -1
  40. package/src/ui/chatbot-popup/home-screen/card.tsx +25 -25
  41. package/src/ui/chatbot-popup/home-screen/chat-now-card.tsx +0 -2
  42. package/src/ui/chatbot-popup/home-screen/index.tsx +0 -1
  43. package/src/ui/chatbot-popup/loading-screen/index.tsx +0 -2
  44. package/src/ui/chatbot-popup/options-list-screen/expanded-option.tsx +0 -1
  45. package/src/ui/chatbot-popup/options-list-screen/header.tsx +14 -12
  46. package/src/ui/chatbot-popup/options-list-screen/index.tsx +0 -1
  47. package/src/ui/chatbot-popup/options-list-screen/option-card.tsx +26 -19
  48. package/src/ui/confirmation-modal/index.tsx +0 -1
  49. package/src/ui/floating-message.tsx +0 -1
  50. package/src/ui/help-button.tsx +0 -1
  51. package/src/ui/help-center.tsx +29 -67
  52. package/src/ui/help-popup.tsx +4 -4
  53. package/src/ui/review-dialog/index.tsx +4 -4
  54. package/src/useLocalTranslation.ts +5 -5
  55. package/tsconfig.json +19 -8
  56. package/src/.DS_Store +0 -0
  57. package/src/styles/tailwind.css +0 -4
@@ -1,11 +1,9 @@
1
- import React from 'react';
2
1
  interface ChatWindowFooterProps {
3
2
  inputMessage: string;
4
3
  setInputMessage: (e: string) => void;
5
4
  handleKeyDown: (e: React.KeyboardEvent) => void;
6
5
  handleSendMessage: () => void;
7
6
  isLoading: boolean;
8
- isAblyConnected: boolean;
9
7
  }
10
8
  declare const ChatWindowFooter: React.FC<ChatWindowFooterProps>;
11
9
  export default ChatWindowFooter;
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  interface ChatWindowHeaderProps {
3
3
  isShowList: boolean;
4
4
  setIsShowList?: (isShowList: boolean) => void;
@@ -7,5 +7,5 @@ interface ChatWindowProps {
7
7
  needsAgent: boolean;
8
8
  isAblyConnected: boolean;
9
9
  }
10
- export declare const ChatWindow: React.MemoExoticComponent<({ onSendMessage, messages, assistantStatus, isAblyConnected }: ChatWindowProps) => React.JSX.Element>;
10
+ export declare const ChatWindow: React.MemoExoticComponent<({ onSendMessage, messages, assistantStatus }: ChatWindowProps) => import("react/jsx-runtime").JSX.Element>;
11
11
  export {};
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface ChatBotErrorScreenProps {
3
2
  onClose: () => void;
4
3
  error: string;
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface CardProps {
3
2
  text: string;
4
3
  handleClick: () => void;
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface ChatNowCardProps {
3
2
  setIsShowList: (isShowList: boolean) => void;
4
3
  }
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface HomeScreenProps {
3
2
  setIsShowList: (isShowList: boolean) => void;
4
3
  onClose: () => void;
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface ChatBotLoadingScreenProps {
3
2
  isShowList: boolean;
4
3
  onClose: () => void;
@@ -1,5 +1,4 @@
1
1
  import { Option } from '@/lib/types';
2
- import React from 'react';
3
2
  interface ExpandedOptionProps {
4
3
  option: Option;
5
4
  handleStartChat: (option: Option) => void;
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface OptionsListHeaderProps {
3
2
  handleBack: () => void;
4
3
  showHelpScreen: boolean;
@@ -1,5 +1,4 @@
1
1
  import { HelpScreenData, Option } from '@/lib/types';
2
- import React from 'react';
3
2
  interface OptionsListScreenProps {
4
3
  helpScreen: HelpScreenData | null;
5
4
  expandedOption: Option | null;
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface OptionCardProps {
3
2
  title: string;
4
3
  }
@@ -1,9 +1,8 @@
1
- import React from "react";
2
1
  interface ConfirmationModalProps {
3
2
  title: string;
4
3
  message: string;
5
4
  onCancel: () => void;
6
5
  onConfirm: () => void;
7
6
  }
8
- declare const ConfirmationModal: ({ title, message, onCancel, onConfirm, }: ConfirmationModalProps) => React.JSX.Element;
7
+ declare const ConfirmationModal: ({ title, message, onCancel, onConfirm, }: ConfirmationModalProps) => import("react/jsx-runtime").JSX.Element;
9
8
  export default ConfirmationModal;
@@ -1,7 +1,6 @@
1
- import React from 'react';
2
1
  interface FloatingMessageProps {
3
2
  message: string;
4
3
  onClose: () => void;
5
4
  }
6
- export declare function FloatingMessage({ message, onClose }: FloatingMessageProps): React.JSX.Element;
5
+ export declare function FloatingMessage({ message, onClose }: FloatingMessageProps): import("react/jsx-runtime").JSX.Element;
7
6
  export {};
@@ -1,6 +1,5 @@
1
- import React from 'react';
2
1
  interface HelpButtonProps {
3
2
  onClick: () => void;
4
3
  }
5
- export declare function HelpButton({ onClick }: HelpButtonProps): React.JSX.Element;
4
+ export declare function HelpButton({ onClick }: HelpButtonProps): import("react/jsx-runtime").JSX.Element;
6
5
  export {};
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import '../globals.css';
3
2
  interface HelpCenterProps {
4
3
  helpScreenId: string;
@@ -13,5 +12,5 @@ interface HelpCenterProps {
13
12
  messageLabel?: string | null;
14
13
  showHelpScreen?: boolean;
15
14
  }
16
- export declare function HelpCenter({ helpScreenId, user, showArrow, language, messageLabel, showHelpScreen, }: HelpCenterProps): React.JSX.Element;
15
+ export declare function HelpCenter({ helpScreenId, user, showArrow, language, messageLabel, showHelpScreen, }: HelpCenterProps): import("react/jsx-runtime").JSX.Element;
17
16
  export {};
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import { HelpScreenData, Message, Option } from '@/lib/types';
3
2
  type HelpPopupProps = {
4
3
  isOpen: boolean;
@@ -20,5 +19,5 @@ type HelpPopupProps = {
20
19
  setSelectedOption: (option: Option | null) => void;
21
20
  showHelpScreen: boolean;
22
21
  };
23
- export declare function HelpPopup({ onClose, helpScreen, status, error, onStartChat, onSendMessage, onEndChat, messages, assistantStatus, needsAgent, sessionId, selectedOption, setSelectedOption, showHelpScreen, isAblyConnected, }: HelpPopupProps): React.JSX.Element;
22
+ export declare function HelpPopup({ onClose, helpScreen, status, error, onStartChat, onSendMessage, onEndChat, messages, assistantStatus, needsAgent, sessionId, selectedOption, setSelectedOption, showHelpScreen, isAblyConnected, }: HelpPopupProps): import("react/jsx-runtime").JSX.Element;
24
23
  export {};
@@ -1,5 +1,4 @@
1
1
  import { ReviewProps } from '@/lib/types';
2
- import React from 'react';
3
2
  interface ReviewDialogProps {
4
3
  handleSubmit: ({ comment, rating }: ReviewProps) => void;
5
4
  onClose: () => void;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "main": "dist/index.js",
4
4
  "module": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
- "version": "3.0.3",
6
+ "version": "3.0.5",
7
7
  "description": "BabylAI Help Center Widget for React and Next.js",
8
8
  "private": false,
9
9
  "exports": {
@@ -12,15 +12,12 @@
12
12
  "require": "./dist/index.js",
13
13
  "types": "./dist/index.d.ts"
14
14
  },
15
- "./react": {
16
- "import": "./dist/react.esm.js",
17
- "require": "./dist/react.js",
18
- "types": "./dist/react.d.ts"
15
+ "./style.css": {
16
+ "default": "./dist/index.css"
19
17
  }
20
18
  },
21
19
  "scripts": {
22
20
  "build": "rollup -c",
23
- "build:prod": "production rollup -c",
24
21
  "dev": "rollup --watch --config rollup.dev.config.js",
25
22
  "test": "jest",
26
23
  "clean": "rimraf dist",
@@ -51,26 +48,29 @@
51
48
  ],
52
49
  "author": "BabylAI",
53
50
  "license": "MIT",
51
+ "sideEffects": [
52
+ "dist/index.css"
53
+ ],
54
54
  "peerDependencies": {
55
- "@tabler/icons-react": "^3.34.0",
56
- "clsx": "^2.0.0",
57
55
  "i18next": "^23.0.0 || ^25.0.0",
58
- "react": ">=16.8.0",
59
- "react-dom": ">=16.8.0",
60
- "react-i18next": "^13.0.0 || ^15.0.0",
61
- "react-markdown": "^10.0.0",
62
- "tailwind-merge": "^3.0.0"
56
+ "react": "^18 || ^19",
57
+ "react-dom": "^18 || ^19",
58
+ "react-i18next": "^13.0.0 || ^15.0.0"
63
59
  },
64
60
  "dependencies": {
65
61
  "@ably/chat": "^0.8.0",
66
62
  "@microsoft/signalr": "^7.0.14",
67
- "ably": "^2.9.0",
68
- "axios": "^1.10.0",
63
+ "@tabler/icons-react": "^3.34.1",
64
+ "clsx": "^2.1.1",
65
+ "tailwind-merge": "^3.3.1",
66
+ "react-markdown": "^10.1.0",
67
+ "ably": "^2.12.0",
68
+ "axios": "^1.11.0",
69
69
  "class-variance-authority": "^0.7.1"
70
70
  },
71
71
  "devDependencies": {
72
- "@babel/core": "^7.27.4",
73
- "@babel/preset-env": "^7.27.2",
72
+ "@babel/core": "^7.28.3",
73
+ "@babel/preset-env": "^7.28.3",
74
74
  "@babel/preset-react": "^7.27.1",
75
75
  "@rollup/plugin-alias": "^5.1.1",
76
76
  "@rollup/plugin-babel": "^6.0.4",
@@ -81,28 +81,28 @@
81
81
  "@rollup/plugin-typescript": "^8.5.0",
82
82
  "@rollup/plugin-url": "^8.0.2",
83
83
  "@svgr/rollup": "^8.1.0",
84
- "@tabler/icons-react": "^3.34.0",
84
+ "@tabler/icons-react": "^3.34.1",
85
85
  "@types/hast": "^3.0.4",
86
86
  "@types/node": "^16.18.126",
87
- "@types/react": "^17.0.83",
87
+ "@types/react": "^18.3.0",
88
+ "@types/react-dom": "^18.3.0",
88
89
  "autoprefixer": "^10.4.21",
89
90
  "babel-loader": "^10.0.0",
90
91
  "clsx": "^2.1.1",
91
- "concurrently": "^9.1.2",
92
- "i18next": "^25.2.1",
92
+ "concurrently": "^9.2.0",
93
+ "i18next": "^25.4.2",
93
94
  "postcss": "^8.5.6",
94
- "react-i18next": "^15.5.3",
95
+ "react-i18next": "^15.7.2",
95
96
  "react-markdown": "^10.1.0",
96
97
  "rimraf": "^6.0.1",
97
98
  "rollup": "^2.79.2",
98
99
  "rollup-plugin-postcss": "^4.0.2",
99
- "tailwind-merge": "^3.3.1",
100
100
  "tailwindcss": "^3.3.2",
101
101
  "tailwindcss-animate": "^1.0.7",
102
102
  "tailwindcss-rtl": "^0.9.0",
103
103
  "tslib": "^2.8.1",
104
- "typescript": "^5.8.3",
105
- "webpack": "^5.99.9"
104
+ "typescript": "^5.9.2",
105
+ "webpack": "^5.101.3"
106
106
  },
107
107
  "publishConfig": {
108
108
  "access": "public"
@@ -1,5 +1,4 @@
1
1
  import { cn } from '../../../lib'
2
- import React from 'react'
3
2
  import { cva, type VariantProps } from 'class-variance-authority'
4
3
 
5
4
  const buttonVariants = cva(
@@ -1,5 +1,4 @@
1
1
  import { useTypewriter } from '@/lib/custom-hooks/useTypewriter';
2
- import React from 'react';
3
2
  import Markdown from 'react-markdown';
4
3
  import type { Element } from 'hast';
5
4
 
@@ -1,4 +1,3 @@
1
- import React from 'react'
2
1
  import CloseCircle from '../../assets/icons/closeCircle.svg'
3
2
  import Logo from '../../assets/logo.svg'
4
3
 
package/src/globals.css CHANGED
@@ -1,4 +1,4 @@
1
- @tailwind base;
1
+ /* @tailwind base; */
2
2
  @tailwind components;
3
3
  @tailwind utilities;
4
4
 
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { configService } from './lib/config';
2
- import { HelpCenter } from './ui/help-center';
3
2
  import { TokenResponse } from './lib/types';
4
3
 
5
4
  export type HelpCenterConfig = {
@@ -12,11 +11,10 @@ export function initializeHelpCenter(config: HelpCenterConfig) {
12
11
  configService.initialize(config);
13
12
  }
14
13
 
15
- export { HelpCenter };
14
+ export { HelpCenter } from './ui/help-center';
16
15
 
17
16
  export * from './lib/types';
18
17
  export * from './core/ApiService';
19
18
  export * from './core/AblyService';
20
- // export * from './globals.css'
21
19
 
22
20
  export { TokenService } from './core/token-service';
@@ -1,5 +1,5 @@
1
- declare module '*.svg' {
2
- import React from 'react'
3
- const SVG: React.FC<React.SVGProps<SVGSVGElement>>
4
- export default SVG
1
+ declare module "*.svg" {
2
+ import type { FC, SVGProps } from "react";
3
+ const SVG: FC<SVGProps<SVGSVGElement> & { title?: string }>;
4
+ export default SVG;
5
5
  }
@@ -1,5 +1,4 @@
1
1
  import { Button } from '@/components';
2
- import React from 'react';
3
2
  import EnvelopeIcon from './../../../assets/icons/envelope.svg';
4
3
  import { useLocalTranslation } from '../../../useLocalTranslation';
5
4
 
@@ -9,7 +8,6 @@ interface ChatWindowFooterProps {
9
8
  handleKeyDown: (e: React.KeyboardEvent) => void;
10
9
  handleSendMessage: () => void;
11
10
  isLoading: boolean;
12
- isAblyConnected: boolean;
13
11
  }
14
12
 
15
13
  const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
@@ -28,7 +26,7 @@ const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
28
26
  variant='default'
29
27
  size='icon'
30
28
  onClick={props.handleSendMessage}
31
- disabled={props?.isLoading || !props.isAblyConnected}
29
+ disabled={props?.isLoading}
32
30
  className='babylai-rounded-full babylai-bg-purple-500 babylai-hover:babylai-bg-purple-600 babylai-w-8 babylai-h-8 babylai-disabled:babylai-opacity-50'
33
31
  >
34
32
  <EnvelopeIcon className={`babylai-w-4 babylai-h-4 ${dir === 'rtl' ? 'babylai-rotate-270' : ''}`} />
@@ -1,48 +1,64 @@
1
- import Logo from '../../../assets/logo_ai.svg'
2
- import { Button } from '@/components'
3
- import React, { useState } from 'react'
4
- import ArrowRight from './../../../assets/icons/arrowRight.svg'
5
- import ThreeDots from './../../../assets/icons/threeDots.svg'
6
- import { useLocalTranslation } from '../../../useLocalTranslation'
1
+ import Logo from "../../../assets/logo_ai.svg";
2
+ import { Button } from "@/components";
3
+ import React, { useState } from "react";
4
+ import ArrowRight from "./../../../assets/icons/arrowRight.svg";
5
+ import ThreeDots from "./../../../assets/icons/threeDots.svg";
6
+ import { useLocalTranslation } from "../../../useLocalTranslation";
7
7
 
8
8
  interface ChatWindowHeaderProps {
9
- isShowList: boolean
10
- setIsShowList?: (isShowList: boolean) => void
11
- showChat: boolean
12
- onClose: () => void
13
- handleBack: () => void
14
- handleEndChat: () => void
9
+ isShowList: boolean;
10
+ setIsShowList?: (isShowList: boolean) => void;
11
+ showChat: boolean;
12
+ onClose: () => void;
13
+ handleBack: () => void;
14
+ handleEndChat: () => void;
15
15
  }
16
16
 
17
17
  const ChatWindowHeader: React.FC<ChatWindowHeaderProps> = (props) => {
18
- const [showMenu, setShowMenu] = useState(false)
19
- const { t, i18n } = useLocalTranslation()
20
- const isRTL = i18n.dir() === 'rtl'
18
+ const [showMenu, setShowMenu] = useState(false);
19
+ const { t, dir } = useLocalTranslation();
20
+ const isRTL = dir === "rtl";
21
21
 
22
22
  return (
23
23
  <header className="babylai-flex babylai-w-full babylai-items-center babylai-py-[18px] babylai-px-[18px] babylai-justify-between babylai-relative babylai-bg-black-white-50 dark:!babylai-bg-storm-dust-900 babylai-rounded-t-3xl">
24
24
  <div className="babylai-flex babylai-items-center babylai-gap-2">
25
- <Button variant="rounded-icon" size="icon" className="babylai-bg-primary-500/10 dark:babylai-bg-storm-dust-950" onClick={props.handleBack}>
26
- <ArrowRight className={`!babylai-w-[12px] babylai-h-[12px] ${isRTL ? '' : 'babylai-rotate-180'} babylai-text-primary-500 dark:babylai-text-white`} />{' '}
25
+ <Button
26
+ variant="rounded-icon"
27
+ size="icon"
28
+ className="babylai-bg-primary-500/10 dark:babylai-bg-storm-dust-950"
29
+ onClick={props.handleBack}
30
+ >
31
+ <ArrowRight
32
+ className={`!babylai-w-[12px] babylai-h-[12px] ${isRTL ? "" : "babylai-rotate-180"} babylai-text-primary-500 dark:babylai-text-white`}
33
+ />{" "}
27
34
  </Button>
28
35
  <div className="babylai-relative babylai-mr-2">
29
- <Button variant="rounded-icon" size="icon" className="babylai-bg-primary-500/10 dark:babylai-bg-storm-dust-950" onClick={() => setShowMenu(!showMenu)}>
36
+ <Button
37
+ variant="rounded-icon"
38
+ size="icon"
39
+ className="babylai-bg-primary-500/10 dark:babylai-bg-storm-dust-950"
40
+ onClick={() => setShowMenu(!showMenu)}
41
+ >
30
42
  <ThreeDots className="babylai-w-[14px] babylai-h-[4px] babylai-text-primary-500 dark:babylai-text-white" />
31
43
  </Button>
32
44
 
33
45
  {showMenu && (
34
46
  <div className="babylai-absolute babylai-top-10 babylai-start-0 babylai-w-48 babylai-rounded-md babylai-shadow-lg babylai-bg-white dark:!babylai-bg-storm-dust-950 babylai-ring-1 babylai-ring-black babylai-ring-opacity-5 babylai-z-10">
35
- <div className="babylai-py-1" role="menu" aria-orientation="vertical">
47
+ <div
48
+ className="babylai-py-1"
49
+ role="menu"
50
+ aria-orientation="vertical"
51
+ >
36
52
  <button
37
53
  className="babylai-block babylai-px-4 babylai-py-2 babylai-text-sm babylai-text-gray-700 dark:babylai-text-white babylai-hover:babylai-bg-gray-100 babylai-w-full babylai-text-left"
38
54
  role="menuitem"
39
55
  onClick={(e) => {
40
- e.stopPropagation()
41
- props.handleEndChat()
42
- setShowMenu(false)
56
+ e.stopPropagation();
57
+ props.handleEndChat();
58
+ setShowMenu(false);
43
59
  }}
44
60
  >
45
- {t('homeSdk.endChat')}
61
+ {t("homeSdk.endChat")}
46
62
  </button>
47
63
  </div>
48
64
  </div>
@@ -53,6 +69,6 @@ const ChatWindowHeader: React.FC<ChatWindowHeaderProps> = (props) => {
53
69
  <Logo className="babylai-w-[124px] babylai-h-auto dark:babylai-text-white" />
54
70
  </div>
55
71
  </header>
56
- )
57
- }
58
- export default ChatWindowHeader
72
+ );
73
+ };
74
+ export default ChatWindowHeader;
@@ -93,114 +93,111 @@ const TypingIndicator = React.memo(({ firstHumanAgentIndex }: { firstHumanAgentI
93
93
 
94
94
  TypingIndicator.displayName = 'TypingIndicator';
95
95
 
96
- export const ChatWindow = React.memo(
97
- ({ onSendMessage, messages, assistantStatus = 'loading', isAblyConnected }: ChatWindowProps) => {
98
- const [inputMessage, setInputMessage] = useState('');
99
- const messagesEndRef = useRef<HTMLDivElement>(null);
100
- const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
101
- const lastMessageCountRef = useRef(messages.length);
102
-
103
- // Debounced scroll to bottom function
104
- const scrollToBottom = useCallback(() => {
96
+ export const ChatWindow = React.memo(({ onSendMessage, messages, assistantStatus = 'loading' }: ChatWindowProps) => {
97
+ const [inputMessage, setInputMessage] = useState('');
98
+ const messagesEndRef = useRef<HTMLDivElement>(null);
99
+ const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
100
+ const lastMessageCountRef = useRef(messages.length);
101
+
102
+ // Debounced scroll to bottom function
103
+ const scrollToBottom = useCallback(() => {
104
+ if (scrollTimeoutRef.current) {
105
+ clearTimeout(scrollTimeoutRef.current);
106
+ }
107
+
108
+ scrollTimeoutRef.current = setTimeout(() => {
109
+ messagesEndRef.current?.scrollIntoView({
110
+ behavior: 'smooth',
111
+ block: 'end',
112
+ });
113
+ }, 100);
114
+ }, []);
115
+
116
+ // Only scroll when new messages are added or status changes
117
+ useEffect(() => {
118
+ if (messages.length !== lastMessageCountRef.current || assistantStatus === 'typing') {
119
+ lastMessageCountRef.current = messages.length;
120
+ scrollToBottom();
121
+ }
122
+ }, [messages.length, assistantStatus, scrollToBottom]);
123
+
124
+ // Cleanup timeout on unmount
125
+ useEffect(() => {
126
+ return () => {
105
127
  if (scrollTimeoutRef.current) {
106
128
  clearTimeout(scrollTimeoutRef.current);
107
129
  }
108
-
109
- scrollTimeoutRef.current = setTimeout(() => {
110
- messagesEndRef.current?.scrollIntoView({
111
- behavior: 'smooth',
112
- block: 'end',
113
- });
114
- }, 100);
115
- }, []);
116
-
117
- // Only scroll when new messages are added or status changes
118
- useEffect(() => {
119
- if (messages.length !== lastMessageCountRef.current || assistantStatus === 'typing') {
120
- lastMessageCountRef.current = messages.length;
121
- scrollToBottom();
122
- }
123
- }, [messages.length, assistantStatus, scrollToBottom]);
124
-
125
- // Cleanup timeout on unmount
126
- useEffect(() => {
127
- return () => {
128
- if (scrollTimeoutRef.current) {
129
- clearTimeout(scrollTimeoutRef.current);
130
+ };
131
+ }, []);
132
+
133
+ const handleSendMessage = useCallback(() => {
134
+ if (inputMessage.trim()) {
135
+ onSendMessage(inputMessage);
136
+ setInputMessage('');
137
+ }
138
+ }, [inputMessage, onSendMessage]);
139
+
140
+ const handleKeyDown = useCallback(
141
+ (e: React.KeyboardEvent) => {
142
+ if (e.key === 'Enter' && !e.shiftKey) {
143
+ e.preventDefault();
144
+ if (inputMessage.trim() && assistantStatus !== 'typing') {
145
+ onSendMessage(inputMessage);
146
+ setInputMessage('');
130
147
  }
131
- };
132
- }, []);
133
-
134
- const handleSendMessage = useCallback(() => {
135
- if (inputMessage.trim()) {
136
- onSendMessage(inputMessage);
137
- setInputMessage('');
138
148
  }
139
- }, [inputMessage, onSendMessage]);
140
-
141
- const handleKeyDown = useCallback(
142
- (e: React.KeyboardEvent) => {
143
- if (e.key === 'Enter' && !e.shiftKey && isAblyConnected) {
144
- e.preventDefault();
145
- if (inputMessage.trim() && assistantStatus !== 'typing') {
146
- onSendMessage(inputMessage);
147
- setInputMessage('');
148
- }
149
- }
150
- },
151
- [inputMessage, onSendMessage, assistantStatus, isAblyConnected]
152
- );
153
-
154
- // Memoize the first human agent index calculation
155
- const firstHumanAgentIndex = useMemo(() => {
156
- return messages.findIndex((message) => message.senderType === 2);
157
- }, [messages]);
158
-
159
- // Memoize the message list to prevent unnecessary re-renders
160
- const messagesList = useMemo(() => {
161
- return messages.map((message, index) => (
162
- <MessageComponent
163
- key={`${message.id}-${index}`}
164
- message={message}
165
- index={index}
166
- messages={messages}
167
- firstHumanAgentIndex={firstHumanAgentIndex}
168
- onType={scrollToBottom}
169
- />
170
- ));
171
- }, [messages, firstHumanAgentIndex, scrollToBottom]);
172
-
173
- // Memoize loading state check
174
- const isLoading = useMemo(() => {
175
- return (
176
- assistantStatus === 'typing' ||
177
- assistantStatus === 'loading' ||
178
- assistantStatus === 'error' ||
179
- inputMessage.trim() === ''
180
- );
181
- }, [assistantStatus, inputMessage]);
149
+ },
150
+ [inputMessage, onSendMessage, assistantStatus]
151
+ );
182
152
 
153
+ // Memoize the first human agent index calculation
154
+ const firstHumanAgentIndex = useMemo(() => {
155
+ return messages.findIndex((message) => message.senderType === 2);
156
+ }, [messages]);
157
+
158
+ // Memoize the message list to prevent unnecessary re-renders
159
+ const messagesList = useMemo(() => {
160
+ return messages.map((message, index) => (
161
+ <MessageComponent
162
+ key={`${message.id}-${index}`}
163
+ message={message}
164
+ index={index}
165
+ messages={messages}
166
+ firstHumanAgentIndex={firstHumanAgentIndex}
167
+ onType={scrollToBottom}
168
+ />
169
+ ));
170
+ }, [messages, firstHumanAgentIndex, scrollToBottom]);
171
+
172
+ // Memoize loading state check
173
+ const isLoading = useMemo(() => {
183
174
  return (
184
- <>
185
- <div className='babylai-flex-1 babylai-overflow-y-auto babylai-p-4 babylai-h-full'>
186
- {messagesList}
175
+ assistantStatus === 'typing' ||
176
+ assistantStatus === 'loading' ||
177
+ assistantStatus === 'error' ||
178
+ inputMessage.trim() === ''
179
+ );
180
+ }, [assistantStatus, inputMessage]);
187
181
 
188
- {assistantStatus === 'typing' && <TypingIndicator firstHumanAgentIndex={firstHumanAgentIndex} />}
182
+ return (
183
+ <>
184
+ <div className='babylai-flex-1 babylai-overflow-y-auto babylai-p-4 babylai-h-full'>
185
+ {messagesList}
189
186
 
190
- <div ref={messagesEndRef} />
191
- </div>
187
+ {assistantStatus === 'typing' && <TypingIndicator firstHumanAgentIndex={firstHumanAgentIndex} />}
192
188
 
193
- <ChatWindowFooter
194
- inputMessage={inputMessage}
195
- handleKeyDown={handleKeyDown}
196
- handleSendMessage={handleSendMessage}
197
- setInputMessage={setInputMessage}
198
- isLoading={isLoading}
199
- isAblyConnected={isAblyConnected}
200
- />
201
- </>
202
- );
203
- }
204
- );
189
+ <div ref={messagesEndRef} />
190
+ </div>
191
+
192
+ <ChatWindowFooter
193
+ inputMessage={inputMessage}
194
+ handleKeyDown={handleKeyDown}
195
+ handleSendMessage={handleSendMessage}
196
+ setInputMessage={setInputMessage}
197
+ isLoading={isLoading}
198
+ />
199
+ </>
200
+ );
201
+ });
205
202
 
206
203
  ChatWindow.displayName = 'ChatWindow';