@nickle/chatbot-react 0.1.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/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # @nickle/chatbot-react
2
+
3
+ Customizable chatbot bubble + chat panel for React apps.
4
+
5
+ ## Install (npm)
6
+
7
+ ```bash
8
+ npm install @nickle/chatbot-react
9
+ ```
10
+
11
+ Do not install from `github:schvffler/chatbot-react`. That installs monorepo source and internal playground files.
12
+
13
+ ## Quick Start
14
+
15
+ ```tsx
16
+ import "@nickle/chatbot-react/styles.css";
17
+ import { ChatbotProvider, ChatbotWidget } from "@nickle/chatbot-react";
18
+
19
+ export function SiteChat() {
20
+ return (
21
+ <ChatbotProvider
22
+ webhookUrl={process.env.NEXT_PUBLIC_CHATBOT_WEBHOOK_URL || ""}
23
+ agentName="Assistant"
24
+ assistantNote="Here to help"
25
+ >
26
+ <ChatbotWidget />
27
+ </ChatbotProvider>
28
+ );
29
+ }
30
+ ```
31
+
32
+ ## How It Works
33
+
34
+ ### Provider runtime
35
+
36
+ `ChatbotProvider` manages:
37
+
38
+ - session id and chat history in `sessionStorage`
39
+ - locale fallback copy for agent/welcome/disclaimer text
40
+ - delayed welcome message when opened with an empty conversation
41
+ - merged global config + latest `ChatbotPageConfig` override
42
+
43
+ ### Send/receive flow
44
+
45
+ When `sendMessage` is called, the widget:
46
+
47
+ 1. Appends the user message.
48
+ 2. Adds a streaming assistant placeholder.
49
+ 3. Builds the request via adapter (`buildRequest`).
50
+ 4. Sends webhook payload including metadata (`sessionId`, `pageUrl`, `locale`, `agentName`, history).
51
+ 5. Parses non-streaming or streaming response and updates assistant message state.
52
+
53
+ ### Streaming behavior
54
+
55
+ `streamingMode` options:
56
+
57
+ - `auto`: stream when response looks stream-compatible
58
+ - `on`: force stream parsing
59
+ - `off`: parse as non-streaming response
60
+
61
+ Stream formats supported:
62
+
63
+ - `text/event-stream` (SSE)
64
+ - line-delimited JSON/text
65
+ - `application/x-ndjson`
66
+
67
+ ## Webhook Contract
68
+
69
+ ### Request payload (JSON mode)
70
+
71
+ ```json
72
+ {
73
+ "message": "User message text",
74
+ "sessionId": "uuid-or-generated-id",
75
+ "metadata": {
76
+ "sessionId": "...",
77
+ "pageUrl": "https://client-site/path",
78
+ "timestamp": "2026-03-02T18:00:00.000Z",
79
+ "agentName": "Assistant",
80
+ "locale": "en",
81
+ "history": [
82
+ {
83
+ "id": "msg_1",
84
+ "role": "assistant",
85
+ "content": "Hi, how can I help you?",
86
+ "createdAt": "2026-03-02T17:59:00.000Z"
87
+ }
88
+ ]
89
+ }
90
+ }
91
+ ```
92
+
93
+ When uploads are enabled and files are attached, the adapter sends `multipart/form-data` with:
94
+
95
+ - `message`
96
+ - `sessionId`
97
+ - `metadata` (JSON string)
98
+ - `files[]`
99
+
100
+ ### Accepted response shapes (default adapter)
101
+
102
+ Non-streaming JSON can return any of these fields:
103
+
104
+ - `message`
105
+ - `text`
106
+ - `output`
107
+ - `response`
108
+ - `answer`
109
+ - `content`
110
+
111
+ Streaming chunks can return:
112
+
113
+ ```json
114
+ { "delta": "partial text" }
115
+ { "delta": "partial text", "done": true }
116
+ ```
117
+
118
+ SSE `[DONE]` is also supported.
119
+
120
+ ## API Highlights
121
+
122
+ ### Components
123
+
124
+ - `ChatbotProvider`
125
+ - `ChatbotWidget`
126
+ - `ChatbotPageConfig`
127
+
128
+ ### Hooks
129
+
130
+ - `useChatbot`
131
+ - `useChatbotSession`
132
+
133
+ ### Common provider props
134
+
135
+ - `webhookUrl: string`
136
+ - `streamingMode?: "auto" | "on" | "off"`
137
+ - `enableUploads?: boolean`
138
+ - `agentName?: string`
139
+ - `assistantNote?: string`
140
+ - `headers?: Record<string, string>`
141
+ - `theme?: Partial<ChatbotThemeTokens>`
142
+ - `icons?: Partial<ChatbotIcons>`
143
+ - `adapter?: ChatbotAdapter`
144
+ - `events?: Partial<ChatbotEventHandlers>`
145
+
146
+ ### Per-page overrides (`ChatbotPageConfig`)
147
+
148
+ - `enabled?: boolean`
149
+ - `agentName?: string`
150
+ - `assistantNote?: string`
151
+ - `enableUploads?: boolean`
152
+ - `theme?: Partial<ChatbotThemeTokens>`
153
+
154
+ ## Tailwind Notes
155
+
156
+ The package ships compiled `styles.css` for the widget UI.
157
+
158
+ If you want Tailwind to see package class strings (for custom overrides), add one of these globs:
159
+
160
+ ```js
161
+ "./node_modules/@nickle/chatbot-react/src/**/*.{ts,tsx}",
162
+ "./node_modules/@nickle/chatbot-react/dist/**/*.{js,cjs}"
163
+ ```
164
+
165
+ ## Build
166
+
167
+ ```bash
168
+ npm run build --workspace @nickle/chatbot-react
169
+ ```
170
+
171
+ ## Troubleshooting
172
+
173
+ ### Install fails from npm
174
+
175
+ - Confirm package name is exactly `@nickle/chatbot-react`
176
+ - Check your npm auth only if your environment requires it
177
+ - Ensure your npm client can access the latest published version
178
+
179
+ ### Webhook returns but UI shows empty assistant response
180
+
181
+ - Confirm response body includes recognized text fields (`message`, `text`, `output`, `response`, `answer`, `content`)
182
+ - If using custom format, provide an `adapter.parseJsonResponse`
183
+
184
+ ### Streaming response not updating incrementally
185
+
186
+ - Set `streamingMode="on"` while debugging
187
+ - Ensure server returns SSE/line-delimited chunks compatible with adapter parsing
188
+
189
+ ### Browser blocks webhook requests
190
+
191
+ - Verify CORS policy on your webhook endpoint allows the client origin and headers
@@ -0,0 +1,169 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ComponentType, ReactNode } from 'react';
3
+
4
+ type ChatRole = "user" | "assistant" | "system";
5
+ type MessageStatus = "pending" | "streaming" | "complete" | "error";
6
+ interface ChatAttachment {
7
+ id: string;
8
+ name: string;
9
+ size: number;
10
+ type: string;
11
+ file?: File;
12
+ }
13
+ interface ChatMessage {
14
+ id: string;
15
+ role: ChatRole;
16
+ content: string;
17
+ createdAt: string;
18
+ status?: MessageStatus;
19
+ attachments?: ChatAttachment[];
20
+ }
21
+ interface NormalizedAssistantChunk {
22
+ delta?: string;
23
+ done?: boolean;
24
+ message?: string;
25
+ }
26
+ interface ChatbotAdapterRequestInput {
27
+ webhookUrl: string;
28
+ message: string;
29
+ sessionId: string;
30
+ agentName: string;
31
+ files: File[];
32
+ metadata: Record<string, unknown>;
33
+ headers?: Record<string, string>;
34
+ }
35
+ interface ChatbotAdapter {
36
+ buildRequest?: (input: ChatbotAdapterRequestInput) => RequestInit & {
37
+ url?: string;
38
+ };
39
+ parseJsonResponse?: (raw: unknown) => NormalizedAssistantChunk;
40
+ parseStreamChunk?: (chunk: string) => NormalizedAssistantChunk;
41
+ }
42
+ interface ChatbotThemeTokens {
43
+ primary: string;
44
+ primaryForeground: string;
45
+ background: string;
46
+ surface: string;
47
+ surfaceForeground: string;
48
+ muted: string;
49
+ mutedForeground: string;
50
+ border: string;
51
+ ring: string;
52
+ userBubble: string;
53
+ userText: string;
54
+ assistantBubble: string;
55
+ assistantText: string;
56
+ radius: string;
57
+ fontFamily: string;
58
+ shadowBubble: string;
59
+ shadowPanel: string;
60
+ }
61
+ interface ChatbotIconProps {
62
+ size?: string | number;
63
+ className?: string;
64
+ strokeWidth?: string | number;
65
+ }
66
+ interface ChatbotIcons {
67
+ /**
68
+ * Legacy alias. If provided, it maps to launcherClosed when launcherClosed is not set.
69
+ */
70
+ launcher?: ComponentType<ChatbotIconProps>;
71
+ launcherClosed: ComponentType<ChatbotIconProps>;
72
+ launcherOpen: ComponentType<ChatbotIconProps>;
73
+ close: ComponentType<ChatbotIconProps>;
74
+ send: ComponentType<ChatbotIconProps>;
75
+ attach: ComponentType<ChatbotIconProps>;
76
+ bot: ComponentType<ChatbotIconProps>;
77
+ menu: ComponentType<ChatbotIconProps>;
78
+ expand: ComponentType<ChatbotIconProps>;
79
+ download: ComponentType<ChatbotIconProps>;
80
+ }
81
+ interface ChatbotEventHandlers {
82
+ onOpen: () => void;
83
+ onClose: () => void;
84
+ onMessageSent: (message: ChatMessage) => void;
85
+ onChunkReceived: (chunk: string) => void;
86
+ onResponseComplete: (message: ChatMessage) => void;
87
+ onError: (error: Error) => void;
88
+ onAttachmentAdded: (attachments: ChatAttachment[]) => void;
89
+ }
90
+ interface ChatbotClassNames {
91
+ root: string;
92
+ bubble: string;
93
+ panel: string;
94
+ header: string;
95
+ headerMeta: string;
96
+ menu: string;
97
+ menuItem: string;
98
+ body: string;
99
+ footer: string;
100
+ composer: string;
101
+ input: string;
102
+ sendButton: string;
103
+ }
104
+ interface PageConfigOverrides {
105
+ enabled?: boolean;
106
+ agentName?: string;
107
+ assistantNote?: string;
108
+ enableUploads?: boolean;
109
+ theme?: Partial<ChatbotThemeTokens>;
110
+ }
111
+ interface ChatbotProviderProps {
112
+ webhookUrl: string;
113
+ children: ReactNode;
114
+ locale?: string;
115
+ agentName?: string;
116
+ assistantNote?: string;
117
+ enableUploads?: boolean;
118
+ streamingMode?: "auto" | "on" | "off";
119
+ headers?: Record<string, string>;
120
+ theme?: Partial<ChatbotThemeTokens>;
121
+ icons?: Partial<ChatbotIcons>;
122
+ adapter?: ChatbotAdapter;
123
+ events?: Partial<ChatbotEventHandlers>;
124
+ initialOpen?: boolean;
125
+ position?: "bottom-right" | "bottom-left";
126
+ classNames?: Partial<ChatbotClassNames>;
127
+ }
128
+ interface SendMessageInput {
129
+ text: string;
130
+ files?: File[];
131
+ }
132
+ interface ChatbotContextValue {
133
+ isOpen: boolean;
134
+ isAwaiting: boolean;
135
+ messages: ChatMessage[];
136
+ sessionId: string;
137
+ uploadEnabled: boolean;
138
+ agentName: string;
139
+ assistantNote: string;
140
+ disclaimerText: string;
141
+ position: "bottom-right" | "bottom-left";
142
+ themeVars: Record<string, string>;
143
+ icons: ChatbotIcons;
144
+ classNames: Partial<ChatbotClassNames>;
145
+ open: () => void;
146
+ close: () => void;
147
+ toggle: () => void;
148
+ sendMessage: (input: SendMessageInput) => Promise<void>;
149
+ clearConversation: () => void;
150
+ registerPageConfig: (id: string, config: PageConfigOverrides) => void;
151
+ unregisterPageConfig: (id: string) => void;
152
+ widgetEnabled: boolean;
153
+ resetSession: () => void;
154
+ }
155
+
156
+ declare function ChatbotProvider({ children, webhookUrl, locale, agentName, assistantNote, enableUploads, streamingMode, headers, theme, icons, adapter, events, initialOpen, position, classNames, }: ChatbotProviderProps): react_jsx_runtime.JSX.Element;
157
+
158
+ declare function ChatbotWidget(): react_jsx_runtime.JSX.Element | null;
159
+
160
+ declare function ChatbotPageConfig(props: PageConfigOverrides): null;
161
+
162
+ declare function useChatbot(): ChatbotContextValue;
163
+
164
+ declare function useChatbotSession(): {
165
+ sessionId: string;
166
+ resetSession: () => void;
167
+ };
168
+
169
+ export { type ChatAttachment, type ChatMessage, type ChatbotAdapter, type ChatbotAdapterRequestInput, type ChatbotClassNames, type ChatbotContextValue, type ChatbotEventHandlers, type ChatbotIcons, ChatbotPageConfig, ChatbotProvider, type ChatbotProviderProps, type ChatbotThemeTokens, ChatbotWidget, type NormalizedAssistantChunk, type PageConfigOverrides, type SendMessageInput, useChatbot, useChatbotSession };
@@ -0,0 +1,169 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ComponentType, ReactNode } from 'react';
3
+
4
+ type ChatRole = "user" | "assistant" | "system";
5
+ type MessageStatus = "pending" | "streaming" | "complete" | "error";
6
+ interface ChatAttachment {
7
+ id: string;
8
+ name: string;
9
+ size: number;
10
+ type: string;
11
+ file?: File;
12
+ }
13
+ interface ChatMessage {
14
+ id: string;
15
+ role: ChatRole;
16
+ content: string;
17
+ createdAt: string;
18
+ status?: MessageStatus;
19
+ attachments?: ChatAttachment[];
20
+ }
21
+ interface NormalizedAssistantChunk {
22
+ delta?: string;
23
+ done?: boolean;
24
+ message?: string;
25
+ }
26
+ interface ChatbotAdapterRequestInput {
27
+ webhookUrl: string;
28
+ message: string;
29
+ sessionId: string;
30
+ agentName: string;
31
+ files: File[];
32
+ metadata: Record<string, unknown>;
33
+ headers?: Record<string, string>;
34
+ }
35
+ interface ChatbotAdapter {
36
+ buildRequest?: (input: ChatbotAdapterRequestInput) => RequestInit & {
37
+ url?: string;
38
+ };
39
+ parseJsonResponse?: (raw: unknown) => NormalizedAssistantChunk;
40
+ parseStreamChunk?: (chunk: string) => NormalizedAssistantChunk;
41
+ }
42
+ interface ChatbotThemeTokens {
43
+ primary: string;
44
+ primaryForeground: string;
45
+ background: string;
46
+ surface: string;
47
+ surfaceForeground: string;
48
+ muted: string;
49
+ mutedForeground: string;
50
+ border: string;
51
+ ring: string;
52
+ userBubble: string;
53
+ userText: string;
54
+ assistantBubble: string;
55
+ assistantText: string;
56
+ radius: string;
57
+ fontFamily: string;
58
+ shadowBubble: string;
59
+ shadowPanel: string;
60
+ }
61
+ interface ChatbotIconProps {
62
+ size?: string | number;
63
+ className?: string;
64
+ strokeWidth?: string | number;
65
+ }
66
+ interface ChatbotIcons {
67
+ /**
68
+ * Legacy alias. If provided, it maps to launcherClosed when launcherClosed is not set.
69
+ */
70
+ launcher?: ComponentType<ChatbotIconProps>;
71
+ launcherClosed: ComponentType<ChatbotIconProps>;
72
+ launcherOpen: ComponentType<ChatbotIconProps>;
73
+ close: ComponentType<ChatbotIconProps>;
74
+ send: ComponentType<ChatbotIconProps>;
75
+ attach: ComponentType<ChatbotIconProps>;
76
+ bot: ComponentType<ChatbotIconProps>;
77
+ menu: ComponentType<ChatbotIconProps>;
78
+ expand: ComponentType<ChatbotIconProps>;
79
+ download: ComponentType<ChatbotIconProps>;
80
+ }
81
+ interface ChatbotEventHandlers {
82
+ onOpen: () => void;
83
+ onClose: () => void;
84
+ onMessageSent: (message: ChatMessage) => void;
85
+ onChunkReceived: (chunk: string) => void;
86
+ onResponseComplete: (message: ChatMessage) => void;
87
+ onError: (error: Error) => void;
88
+ onAttachmentAdded: (attachments: ChatAttachment[]) => void;
89
+ }
90
+ interface ChatbotClassNames {
91
+ root: string;
92
+ bubble: string;
93
+ panel: string;
94
+ header: string;
95
+ headerMeta: string;
96
+ menu: string;
97
+ menuItem: string;
98
+ body: string;
99
+ footer: string;
100
+ composer: string;
101
+ input: string;
102
+ sendButton: string;
103
+ }
104
+ interface PageConfigOverrides {
105
+ enabled?: boolean;
106
+ agentName?: string;
107
+ assistantNote?: string;
108
+ enableUploads?: boolean;
109
+ theme?: Partial<ChatbotThemeTokens>;
110
+ }
111
+ interface ChatbotProviderProps {
112
+ webhookUrl: string;
113
+ children: ReactNode;
114
+ locale?: string;
115
+ agentName?: string;
116
+ assistantNote?: string;
117
+ enableUploads?: boolean;
118
+ streamingMode?: "auto" | "on" | "off";
119
+ headers?: Record<string, string>;
120
+ theme?: Partial<ChatbotThemeTokens>;
121
+ icons?: Partial<ChatbotIcons>;
122
+ adapter?: ChatbotAdapter;
123
+ events?: Partial<ChatbotEventHandlers>;
124
+ initialOpen?: boolean;
125
+ position?: "bottom-right" | "bottom-left";
126
+ classNames?: Partial<ChatbotClassNames>;
127
+ }
128
+ interface SendMessageInput {
129
+ text: string;
130
+ files?: File[];
131
+ }
132
+ interface ChatbotContextValue {
133
+ isOpen: boolean;
134
+ isAwaiting: boolean;
135
+ messages: ChatMessage[];
136
+ sessionId: string;
137
+ uploadEnabled: boolean;
138
+ agentName: string;
139
+ assistantNote: string;
140
+ disclaimerText: string;
141
+ position: "bottom-right" | "bottom-left";
142
+ themeVars: Record<string, string>;
143
+ icons: ChatbotIcons;
144
+ classNames: Partial<ChatbotClassNames>;
145
+ open: () => void;
146
+ close: () => void;
147
+ toggle: () => void;
148
+ sendMessage: (input: SendMessageInput) => Promise<void>;
149
+ clearConversation: () => void;
150
+ registerPageConfig: (id: string, config: PageConfigOverrides) => void;
151
+ unregisterPageConfig: (id: string) => void;
152
+ widgetEnabled: boolean;
153
+ resetSession: () => void;
154
+ }
155
+
156
+ declare function ChatbotProvider({ children, webhookUrl, locale, agentName, assistantNote, enableUploads, streamingMode, headers, theme, icons, adapter, events, initialOpen, position, classNames, }: ChatbotProviderProps): react_jsx_runtime.JSX.Element;
157
+
158
+ declare function ChatbotWidget(): react_jsx_runtime.JSX.Element | null;
159
+
160
+ declare function ChatbotPageConfig(props: PageConfigOverrides): null;
161
+
162
+ declare function useChatbot(): ChatbotContextValue;
163
+
164
+ declare function useChatbotSession(): {
165
+ sessionId: string;
166
+ resetSession: () => void;
167
+ };
168
+
169
+ export { type ChatAttachment, type ChatMessage, type ChatbotAdapter, type ChatbotAdapterRequestInput, type ChatbotClassNames, type ChatbotContextValue, type ChatbotEventHandlers, type ChatbotIcons, ChatbotPageConfig, ChatbotProvider, type ChatbotProviderProps, type ChatbotThemeTokens, ChatbotWidget, type NormalizedAssistantChunk, type PageConfigOverrides, type SendMessageInput, useChatbot, useChatbotSession };