@ihoomanai/react-chat 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@ihoomanai/react-chat",
3
+ "version": "2.0.0",
4
+ "type": "module",
5
+ "description": "React components and hooks for Ihooman Chat Widget - secure Widget ID based initialization",
6
+ "main": "dist/index.cjs.js",
7
+ "module": "dist/index.esm.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.esm.js",
13
+ "require": "./dist/index.cjs.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "src"
20
+ ],
21
+ "sideEffects": false,
22
+ "scripts": {
23
+ "build": "rollup -c",
24
+ "build:types": "tsc --emitDeclarationOnly",
25
+ "dev": "rollup -c -w",
26
+ "clean": "rm -rf dist",
27
+ "prebuild": "npm run clean",
28
+ "lint": "eslint src/ --ext .ts,.tsx",
29
+ "typecheck": "tsc --noEmit",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "prepublishOnly": "npm run build"
33
+ },
34
+ "keywords": [
35
+ "react",
36
+ "chat",
37
+ "widget",
38
+ "support",
39
+ "customer-service",
40
+ "live-chat",
41
+ "chatbot",
42
+ "ai",
43
+ "rag",
44
+ "ihooman",
45
+ "hooks",
46
+ "components"
47
+ ],
48
+ "author": "Ihooman AI",
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/ihooman/chat-widget"
53
+ },
54
+ "homepage": "https://ihooman.ai",
55
+ "bugs": {
56
+ "url": "https://github.com/ihooman/chat-widget/issues"
57
+ },
58
+ "peerDependencies": {
59
+ "react": ">=17.0.0",
60
+ "react-dom": ">=17.0.0"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "react-dom": {
64
+ "optional": true
65
+ }
66
+ },
67
+ "dependencies": {
68
+ "@ihoomanai/chat-widget": "^2.0.0"
69
+ },
70
+ "devDependencies": {
71
+ "@rollup/plugin-commonjs": "^25.0.7",
72
+ "@rollup/plugin-node-resolve": "^15.2.3",
73
+ "@rollup/plugin-terser": "^0.4.4",
74
+ "@rollup/plugin-typescript": "^11.1.6",
75
+ "@testing-library/react": "^14.1.0",
76
+ "@types/node": "^20.10.0",
77
+ "@types/react": "^18.2.0",
78
+ "@types/react-dom": "^18.2.0",
79
+ "react": "^18.2.0",
80
+ "react-dom": "^18.2.0",
81
+ "rollup": "^4.9.0",
82
+ "tslib": "^2.6.2",
83
+ "typescript": "^5.3.3",
84
+ "vitest": "^1.1.0"
85
+ },
86
+ "engines": {
87
+ "node": ">=16.0.0"
88
+ }
89
+ }
@@ -0,0 +1,232 @@
1
+ /**
2
+ * ChatWidget React Component
3
+ *
4
+ * A React wrapper for the Ihooman Chat Widget that handles
5
+ * initialization, lifecycle management, and SSR compatibility.
6
+ *
7
+ * @module @ihooman/react-chat
8
+ */
9
+
10
+ import React, { useEffect, useRef, useCallback } from 'react';
11
+ import type { IhoomanChatAPI, WidgetConfig } from '@ihooman/chat-widget';
12
+ import { useChatWidgetContext } from './context';
13
+ import type { ChatWidgetProps } from './types';
14
+
15
+ /**
16
+ * ChatWidget Component
17
+ *
18
+ * Renders the Ihooman Chat Widget with React lifecycle management.
19
+ * Supports SSR by deferring initialization to useEffect.
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * import { ChatWidget } from '@ihooman/react-chat';
24
+ *
25
+ * function App() {
26
+ * return (
27
+ * <ChatWidget
28
+ * widgetId="wgt_abc123def456"
29
+ * position="bottom-right"
30
+ * onReady={() => console.log('Widget ready!')}
31
+ * />
32
+ * );
33
+ * }
34
+ * ```
35
+ *
36
+ * @example With user information
37
+ * ```tsx
38
+ * <ChatWidget
39
+ * widgetId="wgt_abc123def456"
40
+ * user={{ name: 'John Doe', email: 'john@example.com' }}
41
+ * />
42
+ * ```
43
+ */
44
+ export function ChatWidget({
45
+ widgetId,
46
+ serverUrl,
47
+ theme,
48
+ position,
49
+ startOpen,
50
+ user,
51
+ title,
52
+ subtitle,
53
+ welcomeMessage,
54
+ placeholder,
55
+ primaryColor,
56
+ gradientFrom,
57
+ gradientTo,
58
+ showTimestamps,
59
+ showTypingIndicator,
60
+ enableSounds,
61
+ enableFileUpload,
62
+ persistSession,
63
+ zIndex,
64
+ width,
65
+ height,
66
+ buttonSize,
67
+ borderRadius,
68
+ fontFamily,
69
+ avatarUrl,
70
+ poweredBy,
71
+ onReady,
72
+ onOpen,
73
+ onClose,
74
+ onMessage,
75
+ onError,
76
+ }: ChatWidgetProps): React.ReactElement | null {
77
+ const widgetInstanceRef = useRef<IhoomanChatAPI | null>(null);
78
+ const isInitializedRef = useRef(false);
79
+ const context = useChatWidgetContext();
80
+
81
+ // Memoize callbacks to prevent unnecessary re-initialization
82
+ const handleReady = useCallback(() => {
83
+ context.setIsReady(true);
84
+ onReady?.();
85
+ }, [context, onReady]);
86
+
87
+ const handleOpen = useCallback(() => {
88
+ context.setIsOpen(true);
89
+ onOpen?.();
90
+ }, [context, onOpen]);
91
+
92
+ const handleClose = useCallback(() => {
93
+ context.setIsOpen(false);
94
+ onClose?.();
95
+ }, [context, onClose]);
96
+
97
+ const handleMessage = useCallback(
98
+ (message: unknown) => {
99
+ // Update messages in context
100
+ if (widgetInstanceRef.current) {
101
+ const state = widgetInstanceRef.current.getState();
102
+ context.setMessages(state.messages);
103
+ context.setUnreadCount(state.unreadCount);
104
+ }
105
+ onMessage?.(message as import('@ihooman/chat-widget').Message);
106
+ },
107
+ [context, onMessage]
108
+ );
109
+
110
+ const handleError = useCallback(
111
+ (error: unknown) => {
112
+ onError?.(error as Error);
113
+ },
114
+ [onError]
115
+ );
116
+
117
+ // Initialize widget on mount (client-side only for SSR compatibility)
118
+ useEffect(() => {
119
+ // Skip if already initialized or if we're in SSR
120
+ if (isInitializedRef.current || typeof window === 'undefined') {
121
+ return;
122
+ }
123
+
124
+ let isMounted = true;
125
+
126
+ const initWidget = async () => {
127
+ try {
128
+ // Dynamic import to support SSR
129
+ const { IhoomanChat } = await import('@ihooman/chat-widget');
130
+
131
+ if (!isMounted) return;
132
+
133
+ // Build configuration
134
+ const config: WidgetConfig = {
135
+ widgetId,
136
+ serverUrl,
137
+ theme,
138
+ position,
139
+ startOpen,
140
+ title,
141
+ subtitle,
142
+ welcomeMessage,
143
+ placeholder,
144
+ primaryColor,
145
+ gradientFrom,
146
+ gradientTo,
147
+ showTimestamps,
148
+ showTypingIndicator,
149
+ enableSounds,
150
+ enableFileUpload,
151
+ persistSession,
152
+ zIndex,
153
+ width,
154
+ height,
155
+ buttonSize,
156
+ borderRadius,
157
+ fontFamily,
158
+ avatarUrl,
159
+ poweredBy,
160
+ onReady: handleReady,
161
+ onOpen: handleOpen,
162
+ onClose: handleClose,
163
+ onMessage: handleMessage,
164
+ onError: handleError,
165
+ };
166
+
167
+ // Initialize the widget
168
+ const instance = await IhoomanChat.init(config);
169
+
170
+ if (!isMounted) {
171
+ // Component unmounted during initialization, clean up
172
+ instance?.destroy();
173
+ return;
174
+ }
175
+
176
+ if (instance) {
177
+ widgetInstanceRef.current = instance;
178
+ context.setWidgetRef(instance);
179
+ isInitializedRef.current = true;
180
+
181
+ // Set user info if provided
182
+ if (user) {
183
+ instance.setUser(user);
184
+ }
185
+
186
+ // Sync initial state
187
+ const state = instance.getState();
188
+ context.setIsOpen(state.isOpen);
189
+ context.setIsConnected(state.isConnected);
190
+ context.setMessages(state.messages);
191
+ context.setUnreadCount(state.unreadCount);
192
+ }
193
+ } catch (error) {
194
+ console.error('Failed to initialize Ihooman Chat Widget:', error);
195
+ handleError(error);
196
+ }
197
+ };
198
+
199
+ initWidget();
200
+
201
+ // Cleanup on unmount
202
+ return () => {
203
+ isMounted = false;
204
+ if (widgetInstanceRef.current) {
205
+ widgetInstanceRef.current.destroy();
206
+ widgetInstanceRef.current = null;
207
+ context.setWidgetRef(null);
208
+ context.setIsReady(false);
209
+ context.setIsOpen(false);
210
+ context.setIsConnected(false);
211
+ context.setMessages([]);
212
+ context.setUnreadCount(0);
213
+ isInitializedRef.current = false;
214
+ }
215
+ };
216
+ // Note: We intentionally only run this effect once on mount
217
+ // eslint-disable-next-line react-hooks/exhaustive-deps
218
+ }, [widgetId]);
219
+
220
+ // Update user info when it changes
221
+ useEffect(() => {
222
+ if (widgetInstanceRef.current && user) {
223
+ widgetInstanceRef.current.setUser(user);
224
+ }
225
+ }, [user]);
226
+
227
+ // This component doesn't render any DOM elements
228
+ // The widget injects its own DOM elements
229
+ return null;
230
+ }
231
+
232
+ export default ChatWidget;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * ChatWidgetProvider Component
3
+ *
4
+ * Provides global widget state and controls to all child components.
5
+ * Wrap your app with this provider to use the useChatWidget hook.
6
+ */
7
+
8
+ import React, { useState, useMemo, useCallback } from 'react';
9
+ import type { IhoomanChatAPI, Message } from '@ihooman/chat-widget';
10
+ import { ChatWidgetContext, type ChatWidgetContextValue } from './context';
11
+ import type { ChatWidgetProviderProps } from './types';
12
+
13
+ /**
14
+ * Provider component for the Chat Widget context
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * import { ChatWidgetProvider, ChatWidget } from '@ihooman/react-chat';
19
+ *
20
+ * function App() {
21
+ * return (
22
+ * <ChatWidgetProvider>
23
+ * <ChatWidget widgetId="wgt_abc123def456" />
24
+ * <YourApp />
25
+ * </ChatWidgetProvider>
26
+ * );
27
+ * }
28
+ * ```
29
+ */
30
+ export function ChatWidgetProvider({ children }: ChatWidgetProviderProps): React.ReactElement {
31
+ const [widgetRef, setWidgetRefState] = useState<IhoomanChatAPI | null>(null);
32
+ const [isReady, setIsReady] = useState(false);
33
+ const [isOpen, setIsOpen] = useState(false);
34
+ const [isConnected, setIsConnected] = useState(false);
35
+ const [messages, setMessages] = useState<Message[]>([]);
36
+ const [unreadCount, setUnreadCount] = useState(0);
37
+
38
+ const setWidgetRef = useCallback((widget: IhoomanChatAPI | null) => {
39
+ setWidgetRefState(widget);
40
+ }, []);
41
+
42
+ const contextValue = useMemo<ChatWidgetContextValue>(
43
+ () => ({
44
+ widgetRef,
45
+ setWidgetRef,
46
+ isReady,
47
+ setIsReady,
48
+ isOpen,
49
+ setIsOpen,
50
+ isConnected,
51
+ setIsConnected,
52
+ messages,
53
+ setMessages,
54
+ unreadCount,
55
+ setUnreadCount,
56
+ }),
57
+ [widgetRef, setWidgetRef, isReady, isOpen, isConnected, messages, unreadCount]
58
+ );
59
+
60
+ return (
61
+ <ChatWidgetContext.Provider value={contextValue}>
62
+ {children}
63
+ </ChatWidgetContext.Provider>
64
+ );
65
+ }
66
+
67
+ export default ChatWidgetProvider;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * React Context for Ihooman Chat Widget
3
+ *
4
+ * Provides global access to widget state and controls
5
+ * throughout the React component tree.
6
+ */
7
+
8
+ import { createContext, useContext } from 'react';
9
+ import type { IhoomanChatAPI, Message, UserInfo } from '@ihooman/chat-widget';
10
+
11
+ /**
12
+ * Internal context value type
13
+ */
14
+ export interface ChatWidgetContextValue {
15
+ /** Reference to the widget API instance */
16
+ widgetRef: IhoomanChatAPI | null;
17
+ /** Set the widget API reference */
18
+ setWidgetRef: (widget: IhoomanChatAPI | null) => void;
19
+ /** Whether the widget is initialized and ready */
20
+ isReady: boolean;
21
+ /** Set the ready state */
22
+ setIsReady: (ready: boolean) => void;
23
+ /** Whether the widget window is open */
24
+ isOpen: boolean;
25
+ /** Set the open state */
26
+ setIsOpen: (open: boolean) => void;
27
+ /** Whether connected to the server */
28
+ isConnected: boolean;
29
+ /** Set the connected state */
30
+ setIsConnected: (connected: boolean) => void;
31
+ /** Current chat messages */
32
+ messages: Message[];
33
+ /** Set the messages */
34
+ setMessages: (messages: Message[]) => void;
35
+ /** Number of unread messages */
36
+ unreadCount: number;
37
+ /** Set the unread count */
38
+ setUnreadCount: (count: number) => void;
39
+ }
40
+
41
+ /**
42
+ * Default context value (used when no provider is present)
43
+ */
44
+ const defaultContextValue: ChatWidgetContextValue = {
45
+ widgetRef: null,
46
+ setWidgetRef: () => {
47
+ console.warn('ChatWidgetProvider not found. Wrap your app with <ChatWidgetProvider>.');
48
+ },
49
+ isReady: false,
50
+ setIsReady: () => {},
51
+ isOpen: false,
52
+ setIsOpen: () => {},
53
+ isConnected: false,
54
+ setIsConnected: () => {},
55
+ messages: [],
56
+ setMessages: () => {},
57
+ unreadCount: 0,
58
+ setUnreadCount: () => {},
59
+ };
60
+
61
+ /**
62
+ * React Context for the Chat Widget
63
+ */
64
+ export const ChatWidgetContext = createContext<ChatWidgetContextValue>(defaultContextValue);
65
+
66
+ /**
67
+ * Hook to access the ChatWidget context
68
+ * @internal
69
+ */
70
+ export function useChatWidgetContext(): ChatWidgetContextValue {
71
+ return useContext(ChatWidgetContext);
72
+ }
73
+
74
+ /**
75
+ * Type guard to check if widget is available
76
+ */
77
+ export function isWidgetAvailable(widget: IhoomanChatAPI | null): widget is IhoomanChatAPI {
78
+ return widget !== null;
79
+ }
package/src/index.ts ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @ihooman/react-chat
3
+ *
4
+ * React components and hooks for the Ihooman Chat Widget.
5
+ * Provides native React integration with proper lifecycle management
6
+ * and SSR compatibility.
7
+ *
8
+ * @packageDocumentation
9
+ * @module @ihooman/react-chat
10
+ *
11
+ * @example Basic usage
12
+ * ```tsx
13
+ * import { ChatWidget } from '@ihooman/react-chat';
14
+ *
15
+ * function App() {
16
+ * return (
17
+ * <ChatWidget
18
+ * widgetId="wgt_abc123def456"
19
+ * position="bottom-right"
20
+ * />
21
+ * );
22
+ * }
23
+ * ```
24
+ *
25
+ * @example With provider and hook
26
+ * ```tsx
27
+ * import { ChatWidgetProvider, ChatWidget, useChatWidget } from '@ihooman/react-chat';
28
+ *
29
+ * function SupportButton() {
30
+ * const { open, isReady } = useChatWidget();
31
+ * return (
32
+ * <button onClick={open} disabled={!isReady}>
33
+ * Need Help?
34
+ * </button>
35
+ * );
36
+ * }
37
+ *
38
+ * function App() {
39
+ * return (
40
+ * <ChatWidgetProvider>
41
+ * <ChatWidget widgetId="wgt_abc123def456" />
42
+ * <SupportButton />
43
+ * </ChatWidgetProvider>
44
+ * );
45
+ * }
46
+ * ```
47
+ */
48
+
49
+ // Components
50
+ export { ChatWidget } from './ChatWidget';
51
+ export { ChatWidgetProvider } from './ChatWidgetProvider';
52
+
53
+ // Hooks
54
+ export { useChatWidget } from './useChatWidget';
55
+
56
+ // Context (for advanced usage)
57
+ export { ChatWidgetContext, useChatWidgetContext } from './context';
58
+
59
+ // Types
60
+ export type {
61
+ // React-specific types
62
+ ChatWidgetProps,
63
+ UseChatWidgetReturn,
64
+ ChatWidgetProviderProps,
65
+ // Re-exported core types
66
+ WidgetConfig,
67
+ UserInfo,
68
+ Message,
69
+ WidgetState,
70
+ WidgetEvent,
71
+ EventCallback,
72
+ ThemeConfig,
73
+ BehaviorConfig,
74
+ BrandingConfig,
75
+ IhoomanChatAPI,
76
+ } from './types';
77
+
78
+ // Re-export context value type for advanced usage
79
+ export type { ChatWidgetContextValue } from './context';