@pocketping/widget 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,321 @@
1
+ # @pocketping/widget
2
+
3
+ Embeddable chat widget for PocketPing. Drop-in customer support chat that connects to your backend and notifies you via Telegram, Discord, or Slack.
4
+
5
+ ## Installation
6
+
7
+ ### Via CDN (Recommended)
8
+
9
+ ```html
10
+ <script src="https://cdn.jsdelivr.net/npm/@pocketping/widget/dist/index.global.js"></script>
11
+ <script>
12
+ PocketPing.init({
13
+ endpoint: 'https://yoursite.com/pocketping'
14
+ });
15
+ </script>
16
+ ```
17
+
18
+ ### Via npm
19
+
20
+ ```bash
21
+ npm install @pocketping/widget
22
+ ```
23
+
24
+ ```javascript
25
+ import { init } from '@pocketping/widget';
26
+
27
+ init({
28
+ endpoint: 'https://yoursite.com/pocketping'
29
+ });
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Configuration Options
35
+
36
+ ### Required
37
+
38
+ | Option | Type | Description |
39
+ |--------|------|-------------|
40
+ | `endpoint` | `string` | Your backend endpoint (e.g., `"https://yoursite.com/pocketping"`) |
41
+
42
+ ---
43
+
44
+ ### Branding
45
+
46
+ Customize the widget's branding to match your company identity.
47
+
48
+ | Option | Type | Default | Description |
49
+ |--------|------|---------|-------------|
50
+ | `operatorName` | `string` | - | Company/operator name displayed in header |
51
+ | `operatorAvatar` | `string` | - | Operator/company avatar URL (displayed in header) |
52
+ | `logoUrl` | `string` | - | Company logo URL (alternative to avatar) |
53
+ | `headerTitle` | `string` | `operatorName` | Header title text |
54
+ | `headerSubtitle` | `string` | - | Header subtitle (e.g., "We usually reply within minutes") |
55
+ | `welcomeMessage` | `string` | - | Welcome message shown when chat opens |
56
+ | `placeholder` | `string` | `"Type a message..."` | Placeholder text for message input |
57
+
58
+ **Example:**
59
+
60
+ ```javascript
61
+ PocketPing.init({
62
+ endpoint: 'https://yoursite.com/pocketping',
63
+ operatorName: 'Acme Support',
64
+ operatorAvatar: 'https://yoursite.com/avatar.png',
65
+ headerTitle: 'Chat with us',
66
+ headerSubtitle: 'We usually reply within 5 minutes',
67
+ welcomeMessage: 'Hi there! How can we help you today?',
68
+ placeholder: 'Ask us anything...'
69
+ });
70
+ ```
71
+
72
+ ---
73
+
74
+ ### Appearance
75
+
76
+ Control the visual appearance of the widget.
77
+
78
+ | Option | Type | Default | Description |
79
+ |--------|------|---------|-------------|
80
+ | `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Color theme (`'auto'` follows system preference) |
81
+ | `primaryColor` | `string` | `'#6366f1'` | Primary brand color (hex format) |
82
+ | `primaryTextColor` | `string` | `'#ffffff'` | Text color on primary background |
83
+ | `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Widget position on screen |
84
+ | `offset` | `number` | `20` | Distance from edge in pixels |
85
+ | `borderRadius` | `number` | `16` | Border radius in pixels |
86
+ | `fontFamily` | `string` | System font stack | Custom font family |
87
+ | `zIndex` | `number` | `9999` | Z-index for widget layering |
88
+ | `toggleIcon` | `'chat' \| 'message' \| 'help' \| string` | `'chat'` | Toggle button icon (or custom SVG) |
89
+ | `customCSS` | `string` | - | Custom CSS to inject |
90
+
91
+ **Example:**
92
+
93
+ ```javascript
94
+ PocketPing.init({
95
+ endpoint: 'https://yoursite.com/pocketping',
96
+ theme: 'dark',
97
+ primaryColor: '#10b981',
98
+ primaryTextColor: '#ffffff',
99
+ position: 'bottom-left',
100
+ offset: 24,
101
+ borderRadius: 12,
102
+ fontFamily: '"Inter", sans-serif',
103
+ zIndex: 10000,
104
+ toggleIcon: 'help'
105
+ });
106
+ ```
107
+
108
+ **Custom Icon Example:**
109
+
110
+ ```javascript
111
+ PocketPing.init({
112
+ endpoint: 'https://yoursite.com/pocketping',
113
+ toggleIcon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></svg>'
114
+ });
115
+ ```
116
+
117
+ **Custom CSS Example:**
118
+
119
+ ```javascript
120
+ PocketPing.init({
121
+ endpoint: 'https://yoursite.com/pocketping',
122
+ customCSS: `
123
+ .pocketping-header {
124
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
125
+ }
126
+ .pocketping-message--visitor {
127
+ background: #e0e7ff;
128
+ }
129
+ `
130
+ });
131
+ ```
132
+
133
+ ---
134
+
135
+ ### Behavior
136
+
137
+ Control when and how the widget behaves.
138
+
139
+ | Option | Type | Default | Description |
140
+ |--------|------|---------|-------------|
141
+ | `showOnPages` | `string[]` | - | Only show on pages matching these regex patterns |
142
+ | `hideOnPages` | `string[]` | - | Hide on pages matching these regex patterns |
143
+ | `showDelay` | `number` | `0` | Delay before showing widget (ms) |
144
+ | `autoOpenDelay` | `number` | `0` | Auto-open chat after delay (ms, `0` = disabled) |
145
+ | `soundEnabled` | `boolean` | `true` | Play sound on new message |
146
+ | `showUnreadBadge` | `boolean` | `true` | Show unread badge on toggle button |
147
+ | `persistOpenState` | `boolean` | `false` | Persist chat open/closed state in localStorage |
148
+
149
+ **Example:**
150
+
151
+ ```javascript
152
+ PocketPing.init({
153
+ endpoint: 'https://yoursite.com/pocketping',
154
+ showOnPages: ['^/pricing', '^/contact', '^/help'],
155
+ hideOnPages: ['^/admin', '^/checkout'],
156
+ showDelay: 3000,
157
+ autoOpenDelay: 10000,
158
+ soundEnabled: true,
159
+ showUnreadBadge: true,
160
+ persistOpenState: true
161
+ });
162
+ ```
163
+
164
+ ---
165
+
166
+ ### Callbacks
167
+
168
+ React to widget events in your application.
169
+
170
+ | Option | Type | Description |
171
+ |--------|------|-------------|
172
+ | `onOpen` | `() => void` | Called when chat window opens |
173
+ | `onClose` | `() => void` | Called when chat window closes |
174
+ | `onMessage` | `(message: Message) => void` | Called when a message is received |
175
+ | `onConnect` | `(sessionId: string) => void` | Called when connected to backend |
176
+ | `onError` | `(error: Error) => void` | Called when connection fails |
177
+
178
+ **Example:**
179
+
180
+ ```javascript
181
+ PocketPing.init({
182
+ endpoint: 'https://yoursite.com/pocketping',
183
+ onOpen: () => {
184
+ console.log('Chat opened');
185
+ analytics.track('chat_opened');
186
+ },
187
+ onClose: () => {
188
+ console.log('Chat closed');
189
+ },
190
+ onMessage: (message) => {
191
+ console.log('New message:', message.content);
192
+ },
193
+ onConnect: (sessionId) => {
194
+ console.log('Connected with session:', sessionId);
195
+ },
196
+ onError: (error) => {
197
+ console.error('Chat error:', error.message);
198
+ }
199
+ });
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Complete Example
205
+
206
+ ```javascript
207
+ PocketPing.init({
208
+ // Required
209
+ endpoint: 'https://api.yoursite.com/pocketping',
210
+
211
+ // Branding
212
+ operatorName: 'Acme Inc.',
213
+ operatorAvatar: 'https://yoursite.com/logo-small.png',
214
+ headerTitle: 'Chat with Acme Support',
215
+ headerSubtitle: 'We typically reply within 5 minutes',
216
+ welcomeMessage: 'Welcome! How can we help you today?',
217
+ placeholder: 'Type your question...',
218
+
219
+ // Appearance
220
+ theme: 'auto',
221
+ primaryColor: '#2563eb',
222
+ primaryTextColor: '#ffffff',
223
+ position: 'bottom-right',
224
+ offset: 20,
225
+ borderRadius: 16,
226
+ fontFamily: '"Inter", system-ui, sans-serif',
227
+ zIndex: 9999,
228
+ toggleIcon: 'chat',
229
+
230
+ // Behavior
231
+ showOnPages: ['^/pricing', '^/features', '^/contact'],
232
+ hideOnPages: ['^/admin'],
233
+ showDelay: 2000,
234
+ autoOpenDelay: 0,
235
+ soundEnabled: true,
236
+ showUnreadBadge: true,
237
+ persistOpenState: true,
238
+
239
+ // Callbacks
240
+ onOpen: () => analytics.track('chat_opened'),
241
+ onClose: () => analytics.track('chat_closed'),
242
+ onConnect: (sessionId) => console.log('Session:', sessionId),
243
+ onError: (error) => console.error('Error:', error)
244
+ });
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Programmatic Control
250
+
251
+ After initialization, you can control the widget programmatically:
252
+
253
+ ```javascript
254
+ // Open the chat
255
+ PocketPing.open();
256
+
257
+ // Close the chat
258
+ PocketPing.close();
259
+
260
+ // Toggle the chat
261
+ PocketPing.toggle();
262
+
263
+ // Destroy the widget
264
+ PocketPing.destroy();
265
+ ```
266
+
267
+ ---
268
+
269
+ ## TypeScript Support
270
+
271
+ Full TypeScript definitions are included:
272
+
273
+ ```typescript
274
+ import { init, PocketPingConfig, Message } from '@pocketping/widget';
275
+
276
+ const config: PocketPingConfig = {
277
+ endpoint: 'https://yoursite.com/pocketping',
278
+ onMessage: (message: Message) => {
279
+ console.log(message.content);
280
+ }
281
+ };
282
+
283
+ init(config);
284
+ ```
285
+
286
+ ---
287
+
288
+ ## CSS Classes
289
+
290
+ For advanced customization, you can target these CSS classes:
291
+
292
+ | Class | Element |
293
+ |-------|---------|
294
+ | `.pocketping-container` | Main container |
295
+ | `.pocketping-toggle` | Toggle button |
296
+ | `.pocketping-toggle--unread` | Toggle with unread badge |
297
+ | `.pocketping-window` | Chat window |
298
+ | `.pocketping-header` | Chat header |
299
+ | `.pocketping-messages` | Messages container |
300
+ | `.pocketping-message` | Individual message |
301
+ | `.pocketping-message--visitor` | Visitor message |
302
+ | `.pocketping-message--operator` | Operator message |
303
+ | `.pocketping-message--ai` | AI message |
304
+ | `.pocketping-input` | Input container |
305
+ | `.pocketping-input__field` | Text input |
306
+ | `.pocketping-input__send` | Send button |
307
+
308
+ ---
309
+
310
+ ## Browser Support
311
+
312
+ - Chrome 60+
313
+ - Firefox 55+
314
+ - Safari 12+
315
+ - Edge 79+
316
+
317
+ ---
318
+
319
+ ## License
320
+
321
+ MIT
@@ -0,0 +1,145 @@
1
+ interface PocketPingConfig {
2
+ /** Your backend endpoint (e.g., "https://yoursite.com/pocketping") */
3
+ endpoint: string;
4
+ /** Company/operator name displayed in header */
5
+ operatorName?: string;
6
+ /** Operator/company avatar URL (displayed in header) */
7
+ operatorAvatar?: string;
8
+ /** Company logo URL (displayed in header, alternative to avatar) */
9
+ logoUrl?: string;
10
+ /** Header title (defaults to operatorName) */
11
+ headerTitle?: string;
12
+ /** Header subtitle (e.g., "We usually reply within minutes") */
13
+ headerSubtitle?: string;
14
+ /** Welcome message shown when chat opens */
15
+ welcomeMessage?: string;
16
+ /** Placeholder text for message input */
17
+ placeholder?: string;
18
+ /** Color theme */
19
+ theme?: 'light' | 'dark' | 'auto';
20
+ /** Primary brand color (hex, e.g., "#6366f1") */
21
+ primaryColor?: string;
22
+ /** Text color on primary background (defaults to white) */
23
+ primaryTextColor?: string;
24
+ /** Widget position */
25
+ position?: 'bottom-right' | 'bottom-left';
26
+ /** Distance from edge in pixels (default: 20) */
27
+ offset?: number;
28
+ /** Border radius in pixels (default: 16) */
29
+ borderRadius?: number;
30
+ /** Font family (defaults to system font stack) */
31
+ fontFamily?: string;
32
+ /** Z-index for widget (default: 9999) */
33
+ zIndex?: number;
34
+ /** Toggle button icon: 'chat' | 'message' | 'help' | custom SVG string */
35
+ toggleIcon?: 'chat' | 'message' | 'help' | string;
36
+ /** Custom CSS to inject (for advanced customization) */
37
+ customCSS?: string;
38
+ /** Only show on certain pages (regex patterns) */
39
+ showOnPages?: string[];
40
+ /** Hide on certain pages (regex patterns) */
41
+ hideOnPages?: string[];
42
+ /** Delay before showing widget in ms (default: 0) */
43
+ showDelay?: number;
44
+ /** Auto-open chat after delay in ms (0 = disabled) */
45
+ autoOpenDelay?: number;
46
+ /** Play sound on new message */
47
+ soundEnabled?: boolean;
48
+ /** Show unread badge on toggle button */
49
+ showUnreadBadge?: boolean;
50
+ /** Persist chat open/closed state in localStorage */
51
+ persistOpenState?: boolean;
52
+ /** Called when chat window opens */
53
+ onOpen?: () => void;
54
+ /** Called when chat window closes */
55
+ onClose?: () => void;
56
+ /** Called when a message is received */
57
+ onMessage?: (message: Message) => void;
58
+ /** Called when connected to backend */
59
+ onConnect?: (sessionId: string) => void;
60
+ /** Called when connection fails */
61
+ onError?: (error: Error) => void;
62
+ }
63
+ type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read';
64
+ interface Message {
65
+ id: string;
66
+ sessionId: string;
67
+ content: string;
68
+ sender: 'visitor' | 'operator' | 'ai';
69
+ timestamp: string;
70
+ replyTo?: string;
71
+ metadata?: Record<string, unknown>;
72
+ status?: MessageStatus;
73
+ deliveredAt?: string;
74
+ readAt?: string;
75
+ }
76
+ interface Session {
77
+ sessionId: string;
78
+ visitorId: string;
79
+ operatorOnline: boolean;
80
+ messages: Message[];
81
+ }
82
+ interface PresenceResponse {
83
+ online: boolean;
84
+ operators?: Array<{
85
+ id: string;
86
+ name: string;
87
+ avatar?: string;
88
+ }>;
89
+ aiEnabled?: boolean;
90
+ aiActiveAfter?: number;
91
+ }
92
+
93
+ type Listener<T> = (data: T) => void;
94
+ declare class PocketPingClient {
95
+ private config;
96
+ private session;
97
+ private ws;
98
+ private isOpen;
99
+ private listeners;
100
+ private reconnectAttempts;
101
+ private maxReconnectAttempts;
102
+ private reconnectTimeout;
103
+ constructor(config: PocketPingConfig);
104
+ connect(): Promise<Session>;
105
+ disconnect(): void;
106
+ sendMessage(content: string): Promise<Message>;
107
+ fetchMessages(after?: string): Promise<Message[]>;
108
+ sendTyping(isTyping?: boolean): Promise<void>;
109
+ sendReadStatus(messageIds: string[], status: MessageStatus): Promise<void>;
110
+ getPresence(): Promise<PresenceResponse>;
111
+ getSession(): Session | null;
112
+ getMessages(): Message[];
113
+ isConnected(): boolean;
114
+ isWidgetOpen(): boolean;
115
+ setOpen(open: boolean): void;
116
+ toggleOpen(): void;
117
+ on<T>(event: string, listener: Listener<T>): () => void;
118
+ private emit;
119
+ private connectWebSocket;
120
+ private handleWebSocketEvent;
121
+ private scheduleReconnect;
122
+ private startPolling;
123
+ private fetch;
124
+ private getOrCreateVisitorId;
125
+ private getStoredSessionId;
126
+ private storeSessionId;
127
+ private generateId;
128
+ }
129
+
130
+ declare function init(config: PocketPingConfig): PocketPingClient;
131
+ declare function destroy(): void;
132
+ declare function open(): void;
133
+ declare function close(): void;
134
+ declare function toggle(): void;
135
+ declare function sendMessage(content: string): Promise<Message>;
136
+ declare const _default: {
137
+ init: typeof init;
138
+ destroy: typeof destroy;
139
+ open: typeof open;
140
+ close: typeof close;
141
+ toggle: typeof toggle;
142
+ sendMessage: typeof sendMessage;
143
+ };
144
+
145
+ export { type Message, type PocketPingConfig, close, _default as default, destroy, init, open, sendMessage, toggle };
@@ -0,0 +1,145 @@
1
+ interface PocketPingConfig {
2
+ /** Your backend endpoint (e.g., "https://yoursite.com/pocketping") */
3
+ endpoint: string;
4
+ /** Company/operator name displayed in header */
5
+ operatorName?: string;
6
+ /** Operator/company avatar URL (displayed in header) */
7
+ operatorAvatar?: string;
8
+ /** Company logo URL (displayed in header, alternative to avatar) */
9
+ logoUrl?: string;
10
+ /** Header title (defaults to operatorName) */
11
+ headerTitle?: string;
12
+ /** Header subtitle (e.g., "We usually reply within minutes") */
13
+ headerSubtitle?: string;
14
+ /** Welcome message shown when chat opens */
15
+ welcomeMessage?: string;
16
+ /** Placeholder text for message input */
17
+ placeholder?: string;
18
+ /** Color theme */
19
+ theme?: 'light' | 'dark' | 'auto';
20
+ /** Primary brand color (hex, e.g., "#6366f1") */
21
+ primaryColor?: string;
22
+ /** Text color on primary background (defaults to white) */
23
+ primaryTextColor?: string;
24
+ /** Widget position */
25
+ position?: 'bottom-right' | 'bottom-left';
26
+ /** Distance from edge in pixels (default: 20) */
27
+ offset?: number;
28
+ /** Border radius in pixels (default: 16) */
29
+ borderRadius?: number;
30
+ /** Font family (defaults to system font stack) */
31
+ fontFamily?: string;
32
+ /** Z-index for widget (default: 9999) */
33
+ zIndex?: number;
34
+ /** Toggle button icon: 'chat' | 'message' | 'help' | custom SVG string */
35
+ toggleIcon?: 'chat' | 'message' | 'help' | string;
36
+ /** Custom CSS to inject (for advanced customization) */
37
+ customCSS?: string;
38
+ /** Only show on certain pages (regex patterns) */
39
+ showOnPages?: string[];
40
+ /** Hide on certain pages (regex patterns) */
41
+ hideOnPages?: string[];
42
+ /** Delay before showing widget in ms (default: 0) */
43
+ showDelay?: number;
44
+ /** Auto-open chat after delay in ms (0 = disabled) */
45
+ autoOpenDelay?: number;
46
+ /** Play sound on new message */
47
+ soundEnabled?: boolean;
48
+ /** Show unread badge on toggle button */
49
+ showUnreadBadge?: boolean;
50
+ /** Persist chat open/closed state in localStorage */
51
+ persistOpenState?: boolean;
52
+ /** Called when chat window opens */
53
+ onOpen?: () => void;
54
+ /** Called when chat window closes */
55
+ onClose?: () => void;
56
+ /** Called when a message is received */
57
+ onMessage?: (message: Message) => void;
58
+ /** Called when connected to backend */
59
+ onConnect?: (sessionId: string) => void;
60
+ /** Called when connection fails */
61
+ onError?: (error: Error) => void;
62
+ }
63
+ type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read';
64
+ interface Message {
65
+ id: string;
66
+ sessionId: string;
67
+ content: string;
68
+ sender: 'visitor' | 'operator' | 'ai';
69
+ timestamp: string;
70
+ replyTo?: string;
71
+ metadata?: Record<string, unknown>;
72
+ status?: MessageStatus;
73
+ deliveredAt?: string;
74
+ readAt?: string;
75
+ }
76
+ interface Session {
77
+ sessionId: string;
78
+ visitorId: string;
79
+ operatorOnline: boolean;
80
+ messages: Message[];
81
+ }
82
+ interface PresenceResponse {
83
+ online: boolean;
84
+ operators?: Array<{
85
+ id: string;
86
+ name: string;
87
+ avatar?: string;
88
+ }>;
89
+ aiEnabled?: boolean;
90
+ aiActiveAfter?: number;
91
+ }
92
+
93
+ type Listener<T> = (data: T) => void;
94
+ declare class PocketPingClient {
95
+ private config;
96
+ private session;
97
+ private ws;
98
+ private isOpen;
99
+ private listeners;
100
+ private reconnectAttempts;
101
+ private maxReconnectAttempts;
102
+ private reconnectTimeout;
103
+ constructor(config: PocketPingConfig);
104
+ connect(): Promise<Session>;
105
+ disconnect(): void;
106
+ sendMessage(content: string): Promise<Message>;
107
+ fetchMessages(after?: string): Promise<Message[]>;
108
+ sendTyping(isTyping?: boolean): Promise<void>;
109
+ sendReadStatus(messageIds: string[], status: MessageStatus): Promise<void>;
110
+ getPresence(): Promise<PresenceResponse>;
111
+ getSession(): Session | null;
112
+ getMessages(): Message[];
113
+ isConnected(): boolean;
114
+ isWidgetOpen(): boolean;
115
+ setOpen(open: boolean): void;
116
+ toggleOpen(): void;
117
+ on<T>(event: string, listener: Listener<T>): () => void;
118
+ private emit;
119
+ private connectWebSocket;
120
+ private handleWebSocketEvent;
121
+ private scheduleReconnect;
122
+ private startPolling;
123
+ private fetch;
124
+ private getOrCreateVisitorId;
125
+ private getStoredSessionId;
126
+ private storeSessionId;
127
+ private generateId;
128
+ }
129
+
130
+ declare function init(config: PocketPingConfig): PocketPingClient;
131
+ declare function destroy(): void;
132
+ declare function open(): void;
133
+ declare function close(): void;
134
+ declare function toggle(): void;
135
+ declare function sendMessage(content: string): Promise<Message>;
136
+ declare const _default: {
137
+ init: typeof init;
138
+ destroy: typeof destroy;
139
+ open: typeof open;
140
+ close: typeof close;
141
+ toggle: typeof toggle;
142
+ sendMessage: typeof sendMessage;
143
+ };
144
+
145
+ export { type Message, type PocketPingConfig, close, _default as default, destroy, init, open, sendMessage, toggle };