@useknest/widget-react 0.1.0-beta.1 → 0.1.0-beta.11

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 CHANGED
@@ -22,7 +22,7 @@ import { ChatWidget } from '@useknest/widget-react';
22
22
  function App() {
23
23
  return (
24
24
  <div>
25
- <ChatWidget publishableApiKey="pk_your_key_here" />
25
+ <ChatWidget publishableApiKey="pk_your_public_key_here" />
26
26
  </div>
27
27
  );
28
28
  }
@@ -34,9 +34,11 @@ function App() {
34
34
 
35
35
  ### ChatWidget
36
36
 
37
- | Prop | Type | Required | Description |
38
- | ------------------- | -------- | -------- | ---------------------------------- |
39
- | `publishableApiKey` | `string` | Yes | Your project's publishable API key |
37
+ | Prop | Type | Required | Default | Description |
38
+ | ------------------- | ---------------------- | -------- | ---------- | ---------------------------------------------------------- |
39
+ | `publishableApiKey` | `string` | Yes | - | Your project's publishable API key |
40
+ | `mode` | `'inline' \| 'bubble'` | No | `'inline'` | Display mode: inline or floating bubble button |
41
+ | `defaultOpen` | `boolean` | No | `false` | Whether the chat starts open (only applies to bubble mode) |
40
42
 
41
43
  ## Features
42
44
 
@@ -44,7 +46,7 @@ function App() {
44
46
  - ✅ **Streaming Support** - Real-time message streaming via Server-Sent Events (SSE)
45
47
  - ✅ **TypeScript** - Full TypeScript support with exported types
46
48
  - ✅ **Customizable** - Fetches branding (avatar, colors, welcome message) from your project config
47
- - ✅ **Lightweight** - ~28KB minified (~8.5KB gzipped)
49
+ - ✅ **Lightweight** - ~17KB minified (~4.4KB gzipped)
48
50
  - ✅ **Framework-Agnostic Core** - Shares business logic with other platform packages
49
51
 
50
52
  ## TypeScript
@@ -57,7 +59,7 @@ import { ChatWidget, type ChatWidgetProps, type Message } from '@useknest/widget
57
59
 
58
60
  ## Customization
59
61
 
60
- The widget automatically loads customization from your project's configuration:
62
+ The widget automatically loads customization from your project's configuration at useknest.com:
61
63
 
62
64
  - Avatar image
63
65
  - Brand color
@@ -89,12 +91,11 @@ This package uses `@useknest/widget-core` for all business logic (API calls, str
89
91
 
90
92
  ```tsx
91
93
  import { ChatWidget } from '@useknest/widget-react';
92
- import '@useknest/widget-react/dist/widget-react.css';
93
94
 
94
95
  function FullPageChat() {
95
96
  return (
96
97
  <div style={{ height: '100vh', width: '100vw' }}>
97
- <ChatWidget publishableApiKey="pk_your_key_here" />
98
+ <ChatWidget publishableApiKey="pk_your_public_key_here" />
98
99
  </div>
99
100
  );
100
101
  }
@@ -104,35 +105,40 @@ function FullPageChat() {
104
105
 
105
106
  ```tsx
106
107
  import { ChatWidget } from '@useknest/widget-react';
107
- import '@useknest/widget-react/dist/widget-react.css';
108
108
 
109
109
  function ChatContainer() {
110
110
  return (
111
111
  <div style={{ maxWidth: '900px', height: '600px', margin: '0 auto' }}>
112
- <ChatWidget publishableApiKey="pk_your_key_here" />
112
+ <ChatWidget publishableApiKey="pk_your_public_key_here" />
113
113
  </div>
114
114
  );
115
115
  }
116
116
  ```
117
117
 
118
- ## Troubleshooting
118
+ ### Floating Bubble Mode
119
119
 
120
- ### Streaming not working
120
+ ```tsx
121
+ import { ChatWidget } from '@useknest/widget-react';
121
122
 
122
- **Solution:** Check that your backend API is running and accessible. The widget defaults to `http://localhost:5173/api/v1` for local development.
123
+ function App() {
124
+ return <ChatWidget publishableApiKey="pk_your_public_key_here" mode="bubble" />;
125
+ }
126
+ ```
123
127
 
124
- ### TypeScript errors
128
+ ### Bubble Mode (Auto-Open)
125
129
 
126
- **Solution:** Make sure you have React types installed:
130
+ ```tsx
131
+ import { ChatWidget } from '@useknest/widget-react';
127
132
 
128
- ```bash
129
- npm install --save-dev @types/react @types/react-dom
133
+ function App() {
134
+ return <ChatWidget publishableApiKey="pk_your_public_key_here" mode="bubble" defaultOpen />;
135
+ }
130
136
  ```
131
137
 
132
138
  ## License
133
139
 
134
- MIT
140
+ Proprietary - All rights reserved. This software is for use by authorized Knest customers only.
135
141
 
136
142
  ## Support
137
143
 
138
- For issues and questions, please visit [GitHub Issues](https://github.com/your-repo/issues).
144
+ For issues and questions, please email us at useknest@gmail.com
@@ -1 +1 @@
1
- {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../src/ChatMessage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAC3B,OAAO,EACP,SAAiB,EACjB,SAAiC,EACjC,UAAsB,EACtB,UAAiB,EACjB,EAAE,gBAAgB,2CAoFlB"}
1
+ {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../src/ChatMessage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAC3B,OAAO,EACP,SAAiB,EACjB,SAAiC,EACjC,UAAgC,EAChC,UAAiB,EACjB,EAAE,gBAAgB,2CAkFlB"}
@@ -1,7 +1,18 @@
1
+ import { WidgetMode } from '@useknest/widget-core';
2
+ /** Internal config for testing/development - not part of the public API. */
3
+ export interface InternalConfig {
4
+ baseUrl?: string;
5
+ supabaseUrl?: string;
6
+ supabaseAnonKey?: string;
7
+ }
1
8
  export interface ChatWidgetProps {
2
9
  publishableApiKey: string;
3
- /** Base URL for the API. Defaults to https://useknest.com. Pass empty string for relative paths. */
4
- baseUrl?: string;
10
+ /** Display mode: 'inline' renders in place, 'bubble' shows floating button. Defaults to 'inline'. */
11
+ mode?: WidgetMode;
12
+ /** Whether to auto-open the chat in bubble mode. Defaults to false. */
13
+ defaultOpen?: boolean;
14
+ /** Internal config for testing/development - not part of the public API. */
15
+ _internal?: InternalConfig;
5
16
  }
6
- export declare function ChatWidget({ publishableApiKey, baseUrl }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function ChatWidget({ publishableApiKey, mode, defaultOpen, _internal }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
7
18
  //# sourceMappingURL=ChatWidget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../src/ChatWidget.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,eAAe;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,EAAE,iBAAiB,EAAE,OAAO,EAAE,EAAE,eAAe,2CA+RzE"}
1
+ {"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../src/ChatWidget.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAKX,UAAU,EACV,MAAM,uBAAuB,CAAC;AAK/B,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qGAAqG;IACrG,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,wBAAgB,UAAU,CAAC,EAC1B,iBAAiB,EACjB,IAAe,EACf,WAAmB,EACnB,SAAS,EACT,EAAE,eAAe,2CA2ajB"}
package/dist/index.js CHANGED
@@ -1,39 +1,39 @@
1
- (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(".knest-chat-card{display:flex;flex-direction:column;height:100%;background:#fff;border-radius:1rem;box-shadow:0 10px 15px -3px #0000001a;overflow:hidden;font-family:system-ui,-apple-system,sans-serif}.knest-loading-container{display:flex;align-items:center;justify-content:center;height:100%;background:linear-gradient(135deg,#fdfbf7,#fff)}.knest-loading-content{display:flex;flex-direction:column;align-items:center;gap:1.5rem}.knest-spinner-ring{width:3rem;height:3rem;border:3px solid #f3f4f6;border-top-color:#0d7a7f;border-radius:50%;animation:knest-spin .8s linear infinite}@keyframes knest-spin{to{transform:rotate(360deg)}}.knest-loading-text{font-size:.875rem;font-weight:500;color:#6b7280;margin:0}.knest-error-container{display:flex;align-items:center;justify-content:center;height:100%;background:linear-gradient(135deg,#fef2f2,#fff);padding:2rem}.knest-error-content{text-align:center;max-width:300px}.knest-error-text{font-size:.875rem;color:#991b1b;margin:0;line-height:1.5}.knest-header{border-bottom:1px solid #f3f4f6;padding:1rem}.knest-header-content{display:flex;align-items:center;gap:.75rem}.knest-avatar-img{width:2rem;height:2rem;object-fit:cover;border-radius:.25rem}.knest-header h2{font-size:1.125rem;font-weight:600;color:#111827;margin:0 0 .25rem}.knest-badge{display:inline-block;padding:.25rem .5rem;border-radius:9999px;font-size:.75rem;font-weight:500;color:#fff}.knest-messages-container{flex:1;overflow-y:auto}.knest-separator{margin:0 1.5rem;border-bottom:1px solid #e5e7eb}.knest-message-wrapper{display:flex;flex-direction:column}.knest-message{display:flex;gap:1rem;padding:1.25rem 1.5rem;align-items:flex-start}.knest-message-avatar{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0}.knest-message-avatar .knest-avatar-img{width:100%;height:100%;border-radius:.25rem;object-fit:cover}.knest-user-avatar{width:2rem;height:2rem;border-radius:.25rem;display:flex;align-items:center;justify-content:center;color:#fff;font-size:.875rem;font-weight:500}.knest-message-content{flex:1;min-width:0}.knest-message-content p{margin:0 0 .5rem;font-size:.875rem;line-height:1.625;color:#374151;word-wrap:break-word}.knest-message-content p:last-child{margin-bottom:0}.knest-message-content code{background-color:#f3f4f6;padding:.125rem .375rem;border-radius:.25rem;font-family:ui-monospace,monospace;font-size:.8125rem;color:#ef4444}.knest-message-content pre{background-color:#1f2937;color:#f9fafb;padding:12px;border-radius:6px;overflow-x:auto;margin:8px 0}.knest-message-content pre code{background-color:transparent;padding:0;color:inherit}.knest-message-content a{color:#374151;text-decoration:underline}.knest-message-content ul,.knest-message-content ol{margin:8px 0;padding-left:24px}.knest-message-content li{margin:4px 0}.knest-message-content strong{font-weight:600;color:#111827}.knest-message-content em{font-style:italic}.knest-loading{display:flex;gap:.25rem;align-items:center}.knest-dot{width:.5rem;height:.5rem;background:#9ca3af;border-radius:50%;animation:knest-bounce 1.4s infinite ease-in-out both}.knest-dot:nth-child(2){animation-delay:.16s}.knest-dot:nth-child(3){animation-delay:.32s}@keyframes knest-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.knest-sources{margin-top:.75rem}.knest-sources-label{font-size:.75rem;font-weight:500;color:#6b7280;margin-bottom:.5rem}.knest-source-item{display:flex;gap:.5rem;padding:.5rem .75rem;margin-bottom:.25rem;border:1px solid #e5e7eb;border-radius:.375rem;background:#f9fafb;text-decoration:none;transition:all .15s}.knest-source-item:hover{border-color:#d1d5db;background:#f3f4f6}.knest-source-icon{width:1rem;height:1rem;color:#6b7280;flex-shrink:0}.knest-source-text{flex:1;min-width:0}.knest-source-breadcrumb{font-size:.75rem;color:#6b7280;margin-bottom:.125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.knest-source-title{font-size:.875rem;font-weight:500;color:#374151;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.knest-examples{border-top:1px solid #e5e7eb;padding:1.25rem 1.5rem}.knest-examples h3{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:#6b7280;margin:0 0 1rem}.knest-example-btn{width:100%;padding:.75rem;margin-bottom:.75rem;border:1px solid #e5e7eb;border-radius:.5rem;background:#fff;text-align:left;font-size:.875rem;color:#374151;cursor:pointer;transition:background .15s}.knest-example-btn:hover{background:#f9fafb}.knest-input-section{border-top:1px solid #f3f4f6;padding:1rem}.knest-input-wrapper{display:flex;align-items:center;gap:.5rem}.knest-input-field{flex:1;padding:.75rem 1rem;border:1px solid #e5e7eb;border-radius:.5rem;background:#f9fafb;font-size:.875rem;color:#374151;outline:none}.knest-input-field:focus{background:#fff;border-color:#d1d5db}.knest-input-field:disabled{opacity:.5}.knest-send-btn{width:2.5rem;height:2.5rem;display:flex;align-items:center;justify-content:center;border:none;border-radius:.5rem;background:#e5e7eb;color:#6b7280;cursor:pointer;transition:background .15s}.knest-send-btn:hover:not(:disabled){background:#d1d5db}.knest-send-btn:disabled{opacity:.5;cursor:not-allowed}.knest-send-icon{width:1rem;height:1rem}.knest-footer{margin-top:.75rem;display:flex;justify-content:center}.knest-powered-by{display:flex;align-items:center;gap:.125rem;font-size:.75rem;color:#6b7280;text-decoration:none;transition:color .15s}.knest-powered-by:hover{color:#374151}")),document.head.appendChild(e)}}catch(t){console.error("vite-plugin-css-injected-by-js",t)}})();
2
- import { jsx as e, jsxs as s } from "react/jsx-runtime";
3
- import { useState as c, useRef as D, useEffect as _ } from "react";
4
- import { formatContent as O, DEFAULT_AVATAR_URL as j, DEFAULT_EXAMPLE_QUESTIONS as B, DEFAULT_BRAND_COLOR as F, initWidgetSentry as P, AUTH_ERROR_MESSAGE as Q, fetchWidgetConfig as K, initWidgetAuth as z, DEFAULT_WELCOME_MESSAGE as G, streamChatMessage as H, captureWidgetException as V } from "@useknest/widget-core";
5
- function X({
6
- message: r,
7
- isLoading: d = !1,
8
- avatarUrl: m = "/default-avatar.svg",
9
- brandColor: g = "#0d7a7f",
1
+ (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(".knest-chat-card{display:flex;flex-direction:column;height:100%;background:#fff;color:#374151;border-radius:1rem;box-shadow:0 10px 15px -3px #0000001a;overflow:hidden;font-family:system-ui,-apple-system,sans-serif}.knest-loading-container{display:flex;align-items:center;justify-content:center;height:100%;background:linear-gradient(135deg,#fdfbf7,#fff)}.knest-loading-content{display:flex;flex-direction:column;align-items:center;gap:1.5rem}.knest-spinner-ring{width:3rem;height:3rem;border:3px solid #f3f4f6;border-top-color:#3b82f6;border-radius:50%;animation:knest-spin .8s linear infinite}@keyframes knest-spin{to{transform:rotate(360deg)}}.knest-loading-text{font-size:.875rem;font-weight:500;color:#6b7280;margin:0}.knest-error-container{display:flex;align-items:center;justify-content:center;height:100%;background:linear-gradient(135deg,#fef2f2,#fff);padding:2rem}.knest-error-content{text-align:center;max-width:300px}.knest-error-text{font-size:.875rem;color:#991b1b;margin:0;line-height:1.5}.knest-header{border-bottom:1px solid #f3f4f6;padding:1rem}.knest-header-content{display:flex;align-items:center;gap:.75rem}.knest-avatar-img{width:2rem;height:2rem;object-fit:cover;border-radius:.25rem}.knest-header h2{font-size:1.125rem;font-weight:600;color:#111827;margin:0 0 .25rem}.knest-badge{display:inline-block;padding:.25rem .5rem;border-radius:9999px;font-size:.75rem;font-weight:500;color:#fff}.knest-messages-container{flex:1;overflow-y:auto}.knest-separator{margin:0 1.5rem;border-bottom:1px solid #e5e7eb}.knest-message-wrapper{display:flex;flex-direction:column}.knest-message{display:flex;gap:1rem;padding:1.25rem 1.5rem;align-items:center}.knest-message-avatar{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0}.knest-message-avatar .knest-avatar-img{width:100%;height:100%;border-radius:.25rem;object-fit:cover}.knest-user-avatar{width:2rem;height:2rem;border-radius:.25rem;display:flex;align-items:center;justify-content:center;color:#fff;font-size:.875rem;font-weight:500}.knest-message-content{flex:1;min-width:0}.knest-message-content p{margin:0 0 .5rem;font-size:.875rem;line-height:1.625;color:inherit;word-wrap:break-word}.knest-message-content p:last-child{margin-bottom:0}.knest-message-content code{background-color:#f3f4f6;padding:.125rem .375rem;border-radius:.25rem;font-family:ui-monospace,monospace;font-size:.8125rem;color:#ef4444}.knest-message-content pre{background-color:#1f2937;color:#f9fafb;padding:12px;border-radius:6px;overflow-x:auto;margin:8px 0}.knest-message-content pre code{background-color:transparent;padding:0;color:inherit;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.8125rem;line-height:1.5}.knest-message-content .token.keyword,.knest-message-content .token.builtin,.knest-message-content .token.tag{color:#ff7b72}.knest-message-content .token.string,.knest-message-content .token.attr-value{color:#a5d6ff}.knest-message-content .token.number,.knest-message-content .token.boolean{color:#79c0ff}.knest-message-content .token.function,.knest-message-content .token.class-name{color:#d2a8ff}.knest-message-content .token.comment{color:#8b949e;font-style:italic}.knest-message-content .token.variable,.knest-message-content .token.property{color:#ffa657}.knest-message-content .token.operator,.knest-message-content .token.punctuation{color:#c9d1d9}.knest-message-content a{color:inherit;text-decoration:underline}.knest-message-content ul,.knest-message-content ol{margin:8px 0;padding-left:24px}.knest-message-content li{margin:4px 0;color:inherit}.knest-message-content strong{font-weight:600;color:inherit}.knest-message-content em{font-style:italic}.knest-loading{display:flex;gap:.25rem;align-items:center}.knest-dot{width:.5rem;height:.5rem;background:#9ca3af;border-radius:50%;animation:knest-bounce 1.4s infinite ease-in-out both}.knest-dot:nth-child(2){animation-delay:.16s}.knest-dot:nth-child(3){animation-delay:.32s}@keyframes knest-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.knest-sources{margin-top:.75rem}.knest-sources-label{font-size:.75rem;font-weight:500;color:#6b7280;margin-bottom:.5rem}.knest-source-item{display:flex;gap:.5rem;padding:.5rem .75rem;margin-bottom:.25rem;border:1px solid #e5e7eb;border-radius:.375rem;background:#f9fafb;text-decoration:none;transition:all .15s}.knest-source-item:hover{border-color:#d1d5db;background:#f3f4f6}.knest-source-icon{width:1rem;height:1rem;color:#6b7280;flex-shrink:0}.knest-source-text{flex:1;min-width:0}.knest-source-breadcrumb{font-size:.75rem;color:#6b7280;margin-bottom:.125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.knest-source-title{font-size:.875rem;font-weight:500;color:#374151;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.knest-examples{border-top:1px solid #e5e7eb;padding:1.25rem 1.5rem}.knest-examples h3{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:#6b7280;margin:0 0 1rem}.knest-example-btn{width:100%;padding:.75rem;margin-bottom:.75rem;border:1px solid #e5e7eb;border-radius:.5rem;background:#fff;text-align:left;font-size:.875rem;color:#374151;cursor:pointer;transition:background .15s}.knest-example-btn:hover{background:#f9fafb}.knest-input-section{border-top:1px solid #f3f4f6;padding:1rem}.knest-input-wrapper{display:flex;align-items:center;gap:.5rem}.knest-input-field{flex:1;padding:.75rem 1rem;border:1px solid #e5e7eb;border-radius:.5rem;background:#f9fafb;font-size:.875rem;color:#374151;outline:none}.knest-input-field:focus{background:#fff;border-color:#d1d5db}.knest-input-field:disabled{opacity:.5}.knest-send-btn{width:2.5rem;height:2.5rem;display:flex;align-items:center;justify-content:center;border:none;border-radius:.5rem;background:#e5e7eb;color:#6b7280;cursor:pointer;transition:background .15s}.knest-send-btn:hover:not(:disabled){background:#d1d5db}.knest-send-btn:disabled{opacity:.5;cursor:not-allowed}.knest-send-icon{width:1rem;height:1rem}.knest-reset-row{display:flex;justify-content:center;margin-top:.5rem}.knest-reset-btn{background:none;border:none;padding:0;font-size:.75rem;color:#9ca3af;cursor:pointer;transition:color .15s}.knest-reset-btn:hover{color:#6b7280}.knest-footer{margin-top:.75rem;display:flex;justify-content:center}.knest-powered-by{display:flex;align-items:center;gap:.125rem;font-size:.75rem;color:#6b7280;text-decoration:none;transition:color .15s}.knest-powered-by:hover{color:#374151;text-decoration:underline}.knest-bubble-container{position:fixed;bottom:24px;right:24px;z-index:9999;display:flex;flex-direction:column;align-items:flex-end;gap:16px;font-family:system-ui,-apple-system,sans-serif}.knest-bubble-button{width:56px;height:56px;border-radius:50%;border:none;color:#fff;cursor:pointer;box-shadow:0 4px 12px #00000026;display:flex;align-items:center;justify-content:center;transition:transform .2s,box-shadow .2s}.knest-bubble-button:hover{transform:scale(1.05);box-shadow:0 6px 16px #0003}.knest-bubble-spinner{animation:knest-spin 1s linear infinite}.knest-bubble-panel{width:380px;height:520px;max-width:calc(100vw - 48px);max-height:calc(100vh - 100px);border-radius:1rem;border:1px solid rgba(0,0,0,.1);box-shadow:0 10px 15px -3px #0000001a;overflow:hidden}.knest-bubble-panel .knest-chat-card{height:100%}@media (max-width: 440px){.knest-bubble-container{bottom:16px;right:16px}.knest-bubble-panel{width:calc(100vw - 32px);height:calc(100vh - 100px)}}")),document.head.appendChild(e)}}catch(t){console.error("vite-plugin-css-injected-by-js",t)}})();
2
+ import { jsx as e, jsxs as r } from "react/jsx-runtime";
3
+ import { useState as d, useRef as q, useEffect as E } from "react";
4
+ import { formatContent as K, DEFAULT_BRAND_COLOR as O, DEFAULT_AVATAR_URL as X, DEFAULT_EXAMPLE_QUESTIONS as Y, initWidgetSentry as T, PUBLIC_SUPABASE_URL as $, PUBLIC_SUPABASE_ANON_KEY as J, initWidgetAuth as Z, saveChatStateDebounced as ee, subscribeToThread as te, AUTH_ERROR_MESSAGE as ne, fetchWidgetConfig as se, loadChatState as re, DEFAULT_WELCOME_MESSAGE as R, streamChatMessage as ae, captureWidgetException as oe, clearChatState as ce } from "@useknest/widget-core";
5
+ function le({
6
+ message: a,
7
+ isLoading: M = !1,
8
+ avatarUrl: y = "/default-avatar.svg",
9
+ brandColor: h = O,
10
10
  showAvatar: v = !0
11
11
  }) {
12
- const [p, x] = c(!1), E = () => {
13
- x(!0);
14
- }, f = r.content ? O(r.content) : [];
15
- return /* @__PURE__ */ e("div", { className: "knest-message-wrapper", children: /* @__PURE__ */ s("div", { className: "knest-message", children: [
16
- v && /* @__PURE__ */ e("div", { className: "knest-message-avatar", children: r.role === "assistant" ? p ? /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: g }, children: "AI" }) : /* @__PURE__ */ e(
12
+ const [L, k] = d(!1), x = () => {
13
+ k(!0);
14
+ }, A = a.content ? K(a.content) : "";
15
+ return /* @__PURE__ */ e("div", { className: "knest-message-wrapper", children: /* @__PURE__ */ r("div", { className: "knest-message", children: [
16
+ v && /* @__PURE__ */ e("div", { className: "knest-message-avatar", children: a.role === "assistant" ? L ? /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: h }, children: "AI" }) : /* @__PURE__ */ e(
17
17
  "img",
18
18
  {
19
- src: m,
19
+ src: y,
20
20
  alt: "Avatar",
21
21
  className: "knest-avatar-img",
22
- onError: E
22
+ onError: x
23
23
  }
24
- ) : /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: g }, children: "U" }) }),
25
- /* @__PURE__ */ s("div", { className: "knest-message-content", children: [
26
- !r.content && d && r.role === "assistant" ? /* @__PURE__ */ s("div", { className: "knest-loading", children: [
24
+ ) : /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: h }, children: "U" }) }),
25
+ /* @__PURE__ */ r("div", { className: "knest-message-content", children: [
26
+ !a.content && M && a.role === "assistant" ? /* @__PURE__ */ r("div", { className: "knest-loading", children: [
27
27
  /* @__PURE__ */ e("div", { className: "knest-dot" }),
28
28
  /* @__PURE__ */ e("div", { className: "knest-dot" }),
29
29
  /* @__PURE__ */ e("div", { className: "knest-dot" })
30
- ] }) : f.map((i, o) => /* @__PURE__ */ e("p", { dangerouslySetInnerHTML: { __html: i.html } }, o)),
31
- r.sources && r.sources.length > 0 && /* @__PURE__ */ s("div", { className: "knest-sources", children: [
30
+ ] }) : /* @__PURE__ */ e("div", { dangerouslySetInnerHTML: { __html: A } }),
31
+ a.sources && a.sources.length > 0 && /* @__PURE__ */ r("div", { className: "knest-sources", children: [
32
32
  /* @__PURE__ */ e("div", { className: "knest-sources-label", children: "Sources" }),
33
- r.sources.slice(0, 1).map((i, o) => /* @__PURE__ */ s(
33
+ a.sources.slice(0, 1).map((C, f) => /* @__PURE__ */ r(
34
34
  "a",
35
35
  {
36
- href: i.url,
36
+ href: C.url,
37
37
  target: "_blank",
38
38
  rel: "noopener noreferrer",
39
39
  className: "knest-source-item",
@@ -56,146 +56,176 @@ function X({
56
56
  )
57
57
  }
58
58
  ),
59
- /* @__PURE__ */ s("div", { className: "knest-source-text", children: [
60
- i.breadcrumb && /* @__PURE__ */ e("div", { className: "knest-source-breadcrumb", children: i.breadcrumb }),
61
- /* @__PURE__ */ e("div", { className: "knest-source-title", children: i.title })
59
+ /* @__PURE__ */ r("div", { className: "knest-source-text", children: [
60
+ C.breadcrumb && /* @__PURE__ */ e("div", { className: "knest-source-breadcrumb", children: C.breadcrumb }),
61
+ /* @__PURE__ */ e("div", { className: "knest-source-title", children: C.title })
62
62
  ] })
63
63
  ]
64
64
  },
65
- o
65
+ f
66
66
  ))
67
67
  ] })
68
68
  ] })
69
69
  ] }) });
70
70
  }
71
- function Z({ publishableApiKey: r, baseUrl: d }) {
72
- const [m, g] = c(null), [v, p] = c(!0), [x, E] = c(null), [f, i] = c(!1), [o, u] = c([]), [C, A] = c(""), [N, M] = c(!1), [y, S] = c(void 0), L = D(null), I = m?.avatarUrl || j, R = m?.exampleQuestions || B, b = m?.brandColor || F;
73
- _(() => {
74
- P(), (async () => {
75
- const n = await K(r, d);
71
+ function ue({
72
+ publishableApiKey: a,
73
+ mode: M = "inline",
74
+ defaultOpen: y = !1,
75
+ _internal: h
76
+ }) {
77
+ const [v, L] = d(null), [k, x] = d(!0), [A, C] = d(null), [f, D] = d(!1), [l, i] = d([]), [g, b] = d(""), [p, B] = d(!1), [m, U] = d(void 0), [w, P] = d(y), S = q(null), j = v?.avatarUrl || X, F = v?.exampleQuestions || Y, W = v?.brandColor || O;
78
+ E(() => {
79
+ typeof requestIdleCallback < "u" ? requestIdleCallback(() => T()) : setTimeout(() => T(), 0);
80
+ const t = h?.supabaseUrl || $, s = h?.supabaseAnonKey || J, u = Z(t, s);
81
+ (async () => {
82
+ const n = await se(
83
+ a,
84
+ h?.baseUrl,
85
+ (V) => {
86
+ L(V);
87
+ }
88
+ );
76
89
  if (n.error) {
77
- E(n.error), p(!1);
90
+ C(n.error), x(!1);
78
91
  return;
79
92
  }
80
- if (g(n.config), n.config) {
81
- const h = await z(
82
- n.config.supabaseUrl,
83
- n.config.supabaseAnonKey
84
- );
85
- h || console.warn("Widget auth initialization failed"), i(h);
86
- }
87
- p(!1), u([
93
+ L(n.config), x(!1);
94
+ const o = re(a);
95
+ o && o.messages.length > 0 ? (i(o.messages), U(o.threadId), b(o.input)) : i([
88
96
  {
89
97
  role: "assistant",
90
- content: n.config?.welcomeMessage || G
98
+ content: n.config?.welcomeMessage || R
91
99
  }
92
100
  ]);
101
+ const c = await u;
102
+ c || console.warn("Widget auth initialization failed"), D(c);
93
103
  })();
94
- }, [r, d]), _(() => {
95
- o.length > 0 && L.current && L.current.scrollIntoView({ behavior: "smooth" });
96
- }, [o]);
97
- const w = async () => {
98
- if (!C.trim() || N || !f) return;
99
- const t = C.trim();
100
- A(""), M(!0), u((a) => [...a, { role: "user", content: t }]);
101
- const n = o.length + 1;
102
- u((a) => [...a, { role: "assistant", content: "" }]);
103
- let h = "", W = [];
104
- await H({
105
- publishableApiKey: r,
104
+ }, [a, h]), E(() => {
105
+ l.length > 0 && S.current && S.current.scrollIntoView({ behavior: "smooth" });
106
+ }, [l]), E(() => {
107
+ l.length <= 1 && !g || ee(a, {
108
+ threadId: m,
109
+ messages: l,
110
+ input: g,
111
+ savedAt: Date.now()
112
+ });
113
+ }, [l, m, g, a]), E(() => !m || !f ? void 0 : te(m, (s) => {
114
+ s.role === "human" && i(
115
+ (u) => u.some((N) => N.id === s.id) ? u : [...u, { id: s.id, role: "assistant", content: s.content }]
116
+ );
117
+ }), [m, f]);
118
+ const I = async () => {
119
+ if (!g.trim() || p || !f) return;
120
+ const t = g.trim();
121
+ b(""), B(!0), i((n) => [...n, { role: "user", content: t }]);
122
+ const s = l.length + 1;
123
+ i((n) => [...n, { role: "assistant", content: "" }]);
124
+ let u = "", N = [];
125
+ await ae({
126
+ publishableApiKey: a,
106
127
  content: t,
107
- threadId: y,
108
- baseUrl: d,
128
+ threadId: m,
129
+ baseUrl: h?.baseUrl,
109
130
  callbacks: {
110
- onInit: (a) => {
111
- y || S(a);
131
+ onInit: (n) => {
132
+ m || U(n);
112
133
  },
113
- onContent: (a) => {
114
- h += a, u((k) => {
115
- const l = [...k];
116
- return l[n] = {
134
+ onContent: (n) => {
135
+ u += n, i((o) => {
136
+ const c = [...o];
137
+ return c[s] = {
117
138
  role: "assistant",
118
- content: h
119
- }, l;
139
+ content: u
140
+ }, c;
120
141
  });
121
142
  },
122
- onComplete: (a) => {
123
- W = a, u((k) => {
124
- const l = [...k];
125
- return l[n] = {
143
+ onComplete: (n) => {
144
+ N = n, i((o) => {
145
+ const c = [...o];
146
+ return c[s] = {
126
147
  role: "assistant",
127
- content: h,
128
- sources: W
129
- }, l;
148
+ content: u,
149
+ sources: N
150
+ }, c;
130
151
  });
131
152
  },
132
- onError: (a) => {
133
- V(a, { userMessage: t, threadId: y, baseUrl: d }), u((k) => {
134
- const l = [...k];
135
- return l[n] = {
153
+ onDone: ({ humanTakeover: n }) => {
154
+ n && i((o) => [
155
+ ...o.slice(0, s),
156
+ ...o.slice(s + 1)
157
+ ]);
158
+ },
159
+ onError: (n) => {
160
+ oe(n, { userMessage: t, threadId: m, baseUrl: h?.baseUrl }), i((o) => {
161
+ const c = [...o];
162
+ return c[s] = {
136
163
  role: "assistant",
137
- content: `Error: ${a}`
138
- }, l;
164
+ content: `Error: ${n}`
165
+ }, c;
139
166
  });
140
167
  }
141
168
  }
142
- }), M(!1);
143
- }, T = (t) => {
144
- t.key === "Enter" && !t.shiftKey && (t.preventDefault(), w());
145
- }, U = async (t) => {
146
- A(t), setTimeout(() => w(), 0);
147
- };
148
- return v ? /* @__PURE__ */ e("div", { className: "knest-chat-card", children: /* @__PURE__ */ e("div", { className: "knest-loading-container", children: /* @__PURE__ */ s("div", { className: "knest-loading-content", children: [
169
+ }), B(!1);
170
+ }, Q = () => {
171
+ ce(a), U(void 0), i([
172
+ { role: "assistant", content: v?.welcomeMessage || R }
173
+ ]), b("");
174
+ }, z = (t) => {
175
+ t.key === "Enter" && !t.shiftKey && (t.preventDefault(), I());
176
+ }, G = async (t) => {
177
+ b(t), setTimeout(() => I(), 0);
178
+ }, _ = k ? /* @__PURE__ */ e("div", { className: "knest-chat-card", children: /* @__PURE__ */ e("div", { className: "knest-loading-container", children: /* @__PURE__ */ r("div", { className: "knest-loading-content", children: [
149
179
  /* @__PURE__ */ e("div", { className: "knest-spinner-ring" }),
150
180
  /* @__PURE__ */ e("p", { className: "knest-loading-text", children: "Loading chat..." })
151
- ] }) }) }) : x === "auth" ? /* @__PURE__ */ e("div", { className: "knest-chat-card", children: /* @__PURE__ */ e("div", { className: "knest-error-container", children: /* @__PURE__ */ e("div", { className: "knest-error-content", children: /* @__PURE__ */ e("p", { className: "knest-error-text", children: Q }) }) }) }) : /* @__PURE__ */ s("div", { className: "knest-chat-card", children: [
152
- /* @__PURE__ */ s("div", { className: "knest-messages-container", children: [
153
- o.map((t, n) => /* @__PURE__ */ s("div", { children: [
181
+ ] }) }) }) : A === "auth" ? /* @__PURE__ */ e("div", { className: "knest-chat-card", children: /* @__PURE__ */ e("div", { className: "knest-error-container", children: /* @__PURE__ */ e("div", { className: "knest-error-content", children: /* @__PURE__ */ e("p", { className: "knest-error-text", children: ne }) }) }) }) : /* @__PURE__ */ r("div", { className: "knest-chat-card", children: [
182
+ /* @__PURE__ */ r("div", { className: "knest-messages-container", children: [
183
+ l.map((t, s) => /* @__PURE__ */ r("div", { children: [
154
184
  /* @__PURE__ */ e(
155
- X,
185
+ le,
156
186
  {
157
187
  message: t,
158
- isLoading: !t.content && N && t.role === "assistant",
159
- avatarUrl: I,
160
- brandColor: b
188
+ isLoading: !t.content && p && t.role === "assistant",
189
+ avatarUrl: j,
190
+ brandColor: W
161
191
  }
162
192
  ),
163
- n < o.length - 1 && /* @__PURE__ */ e("div", { className: "knest-separator" })
164
- ] }, n)),
165
- o.length === 1 && !v && /* @__PURE__ */ s("div", { className: "knest-examples", children: [
193
+ s < l.length - 1 && /* @__PURE__ */ e("div", { className: "knest-separator" })
194
+ ] }, s)),
195
+ l.length === 1 && !k && /* @__PURE__ */ r("div", { className: "knest-examples", children: [
166
196
  /* @__PURE__ */ e("h3", { children: "Example Questions" }),
167
- R.map((t, n) => /* @__PURE__ */ e(
197
+ F.map((t, s) => /* @__PURE__ */ e(
168
198
  "button",
169
199
  {
170
- onClick: () => U(t),
200
+ onClick: () => G(t),
171
201
  className: "knest-example-btn",
172
- style: n === 0 ? { borderColor: b, borderWidth: "2px" } : {},
202
+ style: s === 0 ? { borderColor: W, borderWidth: "2px" } : {},
173
203
  children: t
174
204
  },
175
- n
205
+ s
176
206
  ))
177
207
  ] }),
178
- /* @__PURE__ */ e("div", { ref: L })
208
+ /* @__PURE__ */ e("div", { ref: S })
179
209
  ] }),
180
- /* @__PURE__ */ s("div", { className: "knest-input-section", children: [
181
- /* @__PURE__ */ s("div", { className: "knest-input-wrapper", children: [
210
+ /* @__PURE__ */ r("div", { className: "knest-input-section", children: [
211
+ /* @__PURE__ */ r("div", { className: "knest-input-wrapper", children: [
182
212
  /* @__PURE__ */ e(
183
213
  "input",
184
214
  {
185
215
  type: "text",
186
- value: C,
187
- onChange: (t) => A(t.target.value),
188
- onKeyPress: T,
216
+ value: g,
217
+ onChange: (t) => b(t.target.value),
218
+ onKeyPress: z,
189
219
  placeholder: "Ask me anything...",
190
- disabled: N || !f,
220
+ disabled: p || !f,
191
221
  className: "knest-input-field"
192
222
  }
193
223
  ),
194
224
  /* @__PURE__ */ e(
195
225
  "button",
196
226
  {
197
- onClick: w,
198
- disabled: N || !C.trim() || !f,
227
+ onClick: I,
228
+ disabled: p || !g.trim() || !f,
199
229
  className: "knest-send-btn",
200
230
  "aria-label": "Send message",
201
231
  children: /* @__PURE__ */ e("svg", { className: "knest-send-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e(
@@ -210,7 +240,8 @@ function Z({ publishableApiKey: r, baseUrl: d }) {
210
240
  }
211
241
  )
212
242
  ] }),
213
- /* @__PURE__ */ e("div", { className: "knest-footer", children: /* @__PURE__ */ s(
243
+ l.length > 1 && !p && /* @__PURE__ */ e("div", { className: "knest-reset-row", children: /* @__PURE__ */ e("button", { onClick: Q, className: "knest-reset-btn", children: "Clear chat" }) }),
244
+ /* @__PURE__ */ e("div", { className: "knest-footer", children: /* @__PURE__ */ r(
214
245
  "a",
215
246
  {
216
247
  href: "https://useknest.com",
@@ -219,7 +250,7 @@ function Z({ publishableApiKey: r, baseUrl: d }) {
219
250
  className: "knest-powered-by",
220
251
  children: [
221
252
  /* @__PURE__ */ e("span", { children: "Powered by" }),
222
- /* @__PURE__ */ s(
253
+ /* @__PURE__ */ r(
223
254
  "svg",
224
255
  {
225
256
  width: "14",
@@ -286,8 +317,86 @@ function Z({ publishableApiKey: r, baseUrl: d }) {
286
317
  ) })
287
318
  ] })
288
319
  ] });
320
+ if (M === "inline")
321
+ return _;
322
+ const H = k ? "#9ca3af" : W;
323
+ return /* @__PURE__ */ r("div", { className: "knest-bubble-container", children: [
324
+ w && /* @__PURE__ */ e("div", { className: "knest-bubble-panel", children: _ }),
325
+ /* @__PURE__ */ e(
326
+ "button",
327
+ {
328
+ className: ["knest-bubble-button", k && "knest-bubble-loading"].filter(Boolean).join(" "),
329
+ onClick: () => P(!w),
330
+ "aria-label": k ? "Loading chat" : w ? "Close chat" : "Open chat",
331
+ style: { backgroundColor: H },
332
+ children: k ? /* @__PURE__ */ r(
333
+ "svg",
334
+ {
335
+ width: "24",
336
+ height: "24",
337
+ viewBox: "0 0 24 24",
338
+ fill: "none",
339
+ className: "knest-bubble-spinner",
340
+ children: [
341
+ /* @__PURE__ */ e(
342
+ "circle",
343
+ {
344
+ cx: "12",
345
+ cy: "12",
346
+ r: "9",
347
+ stroke: "currentColor",
348
+ strokeOpacity: "0.25",
349
+ strokeWidth: "3",
350
+ fill: "none"
351
+ }
352
+ ),
353
+ /* @__PURE__ */ e(
354
+ "path",
355
+ {
356
+ d: "M12 3a9 9 0 0 1 9 9",
357
+ stroke: "currentColor",
358
+ strokeWidth: "3",
359
+ strokeLinecap: "round",
360
+ fill: "none"
361
+ }
362
+ )
363
+ ]
364
+ }
365
+ ) : w ? /* @__PURE__ */ e(
366
+ "svg",
367
+ {
368
+ width: "24",
369
+ height: "24",
370
+ viewBox: "0 0 24 24",
371
+ fill: "none",
372
+ stroke: "currentColor",
373
+ strokeWidth: "2",
374
+ children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
375
+ }
376
+ ) : /* @__PURE__ */ e(
377
+ "svg",
378
+ {
379
+ width: "24",
380
+ height: "24",
381
+ viewBox: "0 0 24 24",
382
+ fill: "none",
383
+ stroke: "currentColor",
384
+ strokeWidth: "2",
385
+ children: /* @__PURE__ */ e(
386
+ "path",
387
+ {
388
+ strokeLinecap: "round",
389
+ strokeLinejoin: "round",
390
+ d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
391
+ }
392
+ )
393
+ }
394
+ )
395
+ }
396
+ )
397
+ ] });
289
398
  }
290
399
  export {
291
- X as ChatMessage,
292
- Z as ChatWidget
400
+ le as ChatMessage,
401
+ ue as ChatWidget
293
402
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useknest/widget-react",
3
- "version": "0.1.0-beta.1",
3
+ "version": "0.1.0-beta.11",
4
4
  "type": "module",
5
5
  "description": "Native React component for Knest chat widget",
6
6
  "files": [
@@ -22,7 +22,7 @@
22
22
  "react-dom": "^18.0.0 || ^19.0.0"
23
23
  },
24
24
  "dependencies": {
25
- "@useknest/widget-core": "0.1.0-beta.1"
25
+ "@useknest/widget-core": "0.1.0-beta.11"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/react": "^18.3.3",