@useknest/widget-react 0.1.0-beta.12 → 0.1.0-beta.13

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
@@ -34,11 +34,30 @@ function App() {
34
34
 
35
35
  ### ChatWidget
36
36
 
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) |
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) |
42
+ | `user` | `WidgetUser` | No | - | Identifies the logged-in user; requires at least `id` or `email` |
43
+
44
+ #### `WidgetUser`
45
+
46
+ ```ts
47
+ interface WidgetUser {
48
+ id?: string; // Your system's user ID (cross-device dedup key)
49
+ email?: string;
50
+ fullName?: string;
51
+ metadata?: Record<string, unknown>; // Custom attributes (e.g. plan, company)
52
+ }
53
+ ```
54
+
55
+ ```tsx
56
+ <ChatWidget
57
+ publishableApiKey="pk_..."
58
+ user={{ id: currentUser.id, email: currentUser.email, fullName: currentUser.name }}
59
+ />
60
+ ```
42
61
 
43
62
  ## Features
44
63
 
@@ -1,4 +1,4 @@
1
- import { WidgetMode } from '@useknest/widget-core';
1
+ import { WidgetMode, WidgetUser } from '@useknest/widget-core';
2
2
  /** Internal config for testing/development - not part of the public API. */
3
3
  export interface InternalConfig {
4
4
  baseUrl?: string;
@@ -11,8 +11,10 @@ export interface ChatWidgetProps {
11
11
  mode?: WidgetMode;
12
12
  /** Whether to auto-open the chat in bubble mode. Defaults to false. */
13
13
  defaultOpen?: boolean;
14
+ /** Identifies the logged-in user on the customer's platform. Requires at least id or email. */
15
+ user?: WidgetUser;
14
16
  /** Internal config for testing/development - not part of the public API. */
15
17
  _internal?: InternalConfig;
16
18
  }
17
- export declare function ChatWidget({ publishableApiKey, mode, defaultOpen, _internal }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
19
+ export declare function ChatWidget({ publishableApiKey, mode, defaultOpen, user, _internal }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
18
20
  //# sourceMappingURL=ChatWidget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../src/ChatWidget.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAMX,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,2CA0iBjB"}
1
+ {"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../src/ChatWidget.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAMX,UAAU,EACV,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,+FAA+F;IAC/F,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,wBAAgB,UAAU,CAAC,EAC1B,iBAAiB,EACjB,IAAe,EACf,WAAmB,EACnB,IAAI,EACJ,SAAS,EACT,EAAE,eAAe,2CA2iBjB"}
package/dist/index.js CHANGED
@@ -1,65 +1,65 @@
1
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-attach-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;flex-shrink:0}.knest-attach-btn:hover:not(:disabled){background:#d1d5db}.knest-attach-btn:disabled{opacity:.4;cursor:not-allowed}.knest-attach-icon{width:1rem;height:1rem}.knest-file-preview{display:flex;flex-wrap:wrap;gap:.375rem;margin-bottom:.5rem}.knest-file-chip{display:inline-flex;align-items:center;gap:.25rem;padding:.25rem .5rem;background:#f3f4f6;border:1px solid #e5e7eb;border-radius:9999px;font-size:.75rem;color:#374151;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.knest-chip-remove{background:none;border:none;padding:0;font-size:1rem;line-height:1;color:#9ca3af;cursor:pointer;flex-shrink:0}.knest-chip-remove:hover{color:#374151}.knest-attach-error{font-size:.75rem;color:#dc2626;margin:0 0 .375rem}.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-attachments{display:flex;flex-direction:column;gap:.5rem;margin-top:.5rem}.knest-attachment-image-link{display:inline-block}.knest-attachment-image{max-width:240px;border-radius:.5rem;display:block}.knest-attachment-file{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .625rem;border:1px solid #e5e7eb;border-radius:9999px;background:#f9fafb;text-decoration:none;font-size:.8125rem;color:#374151;transition:background .15s}.knest-attachment-file:hover:not(.knest-attachment-disabled){background:#f3f4f6}.knest-attachment-disabled{opacity:.5;pointer-events:none}.knest-attachment-file-icon{width:.875rem;height:.875rem;color:#6b7280;flex-shrink:0}.knest-attachment-file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:160px}.knest-attachment-file-size{color:#9ca3af;flex-shrink:0}.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
2
  import { jsx as e, jsxs as l } from "react/jsx-runtime";
3
- import { useState as h, useEffect as U, useRef as Q } from "react";
4
- import { fetchSignedUrl as ae, formatContent as oe, DEFAULT_BRAND_COLOR as $, isImageType as le, formatFileSize as ce, DEFAULT_AVATAR_URL as ie, DEFAULT_EXAMPLE_QUESTIONS as de, initWidgetSentry as V, PUBLIC_SUPABASE_URL as he, PUBLIC_SUPABASE_ANON_KEY as ue, initWidgetAuth as me, saveChatStateDebounced as fe, subscribeToThread as ke, AUTH_ERROR_MESSAGE as ge, ACCEPTED_FILE_TYPES_STRING as ve, fetchWidgetConfig as pe, loadChatState as Ce, DEFAULT_WELCOME_MESSAGE as X, validateAttachment as be, MAX_ATTACHMENTS_PER_MESSAGE as Ne, uploadAttachment as Ee, captureWidgetException as Y, streamChatMessage as Le, clearChatState as we } from "@useknest/widget-core";
5
- function Me({
3
+ import { useState as d, useEffect as U, useRef as V } from "react";
4
+ import { fetchSignedUrl as oe, formatContent as le, DEFAULT_BRAND_COLOR as q, isImageType as ce, formatFileSize as ie, DEFAULT_AVATAR_URL as de, DEFAULT_EXAMPLE_QUESTIONS as he, initWidgetSentry as X, PUBLIC_SUPABASE_URL as ue, PUBLIC_SUPABASE_ANON_KEY as me, initWidgetAuth as fe, saveChatStateDebounced as ke, subscribeToThread as ge, AUTH_ERROR_MESSAGE as ve, ACCEPTED_FILE_TYPES_STRING as pe, fetchWidgetConfig as Ce, loadChatState as be, DEFAULT_WELCOME_MESSAGE as Y, validateAttachment as Ne, MAX_ATTACHMENTS_PER_MESSAGE as Ee, uploadAttachment as Le, captureWidgetException as $, streamChatMessage as we, clearChatState as Me } from "@useknest/widget-core";
5
+ function Ue({
6
6
  message: r,
7
- isLoading: P = !1,
8
- avatarUrl: T = "/default-avatar.svg",
9
- brandColor: u = $,
10
- showAvatar: L = !0,
11
- publishableApiKey: w,
12
- baseUrl: p
7
+ isLoading: T = !1,
8
+ avatarUrl: W = "/default-avatar.svg",
9
+ brandColor: y = q,
10
+ showAvatar: f = !0,
11
+ publishableApiKey: p,
12
+ baseUrl: w
13
13
  }) {
14
- const [y, W] = h(!1), [x, N] = h({});
14
+ const [C, x] = d(!1), [A, _] = d({});
15
15
  U(() => {
16
- if (!r.attachments?.length || !w) return;
17
- const s = r.attachments.filter(
18
- (o) => o.storagePath && !o.url && !x[o.storagePath]
16
+ if (!r.attachments?.length || !p) return;
17
+ const n = r.attachments.filter(
18
+ (o) => o.storagePath && !o.url && !A[o.storagePath]
19
19
  );
20
- s.length !== 0 && Promise.all(
21
- s.map(async (o) => {
22
- const c = await ae({
23
- publishableApiKey: w,
20
+ n.length !== 0 && Promise.all(
21
+ n.map(async (o) => {
22
+ const c = await oe({
23
+ publishableApiKey: p,
24
24
  storagePath: o.storagePath,
25
- baseUrl: p
25
+ baseUrl: w
26
26
  });
27
27
  return { storagePath: o.storagePath, url: c };
28
28
  })
29
29
  ).then((o) => {
30
30
  const c = {};
31
- for (const { storagePath: E, url: d } of o)
32
- d && (c[E] = d);
33
- Object.keys(c).length > 0 && N((E) => ({ ...E, ...c }));
31
+ for (const { storagePath: k, url: L } of o)
32
+ L && (c[k] = L);
33
+ Object.keys(c).length > 0 && _((k) => ({ ...k, ...c }));
34
34
  });
35
- }, [r.attachments, w, p]);
36
- const _ = (s) => s.url || (s.storagePath ? x[s.storagePath] : void 0), m = () => W(!0), f = r.content ? oe(r.content) : "";
35
+ }, [r.attachments, p, w]);
36
+ const E = (n) => n.url || (n.storagePath ? A[n.storagePath] : void 0), B = () => x(!0), u = r.content ? le(r.content) : "";
37
37
  return /* @__PURE__ */ e("div", { className: "knest-message-wrapper", children: /* @__PURE__ */ l("div", { className: "knest-message", children: [
38
- L && /* @__PURE__ */ e("div", { className: "knest-message-avatar", children: r.role === "assistant" ? y ? /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: u }, children: "AI" }) : /* @__PURE__ */ e(
38
+ f && /* @__PURE__ */ e("div", { className: "knest-message-avatar", children: r.role === "assistant" ? C ? /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: y }, children: "AI" }) : /* @__PURE__ */ e(
39
39
  "img",
40
40
  {
41
- src: T,
41
+ src: W,
42
42
  alt: "Avatar",
43
43
  className: "knest-avatar-img",
44
- onError: m
44
+ onError: B
45
45
  }
46
- ) : /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: u }, children: "U" }) }),
46
+ ) : /* @__PURE__ */ e("div", { className: "knest-user-avatar", style: { backgroundColor: y }, children: "U" }) }),
47
47
  /* @__PURE__ */ l("div", { className: "knest-message-content", children: [
48
- !r.content && P && r.role === "assistant" ? /* @__PURE__ */ l("div", { className: "knest-loading", children: [
48
+ !r.content && T && r.role === "assistant" ? /* @__PURE__ */ l("div", { className: "knest-loading", children: [
49
49
  /* @__PURE__ */ e("div", { className: "knest-dot" }),
50
50
  /* @__PURE__ */ e("div", { className: "knest-dot" }),
51
51
  /* @__PURE__ */ e("div", { className: "knest-dot" })
52
- ] }) : /* @__PURE__ */ e("div", { dangerouslySetInnerHTML: { __html: f } }),
53
- r.attachments && r.attachments.length > 0 && /* @__PURE__ */ e("div", { className: "knest-attachments", children: r.attachments.map((s, o) => {
54
- const c = _(s);
55
- return le(s.fileType) ? c ? /* @__PURE__ */ e(
52
+ ] }) : /* @__PURE__ */ e("div", { dangerouslySetInnerHTML: { __html: u } }),
53
+ r.attachments && r.attachments.length > 0 && /* @__PURE__ */ e("div", { className: "knest-attachments", children: r.attachments.map((n, o) => {
54
+ const c = E(n);
55
+ return ce(n.fileType) ? c ? /* @__PURE__ */ e(
56
56
  "a",
57
57
  {
58
58
  href: c,
59
59
  target: "_blank",
60
60
  rel: "noopener noreferrer",
61
61
  className: "knest-attachment-image-link",
62
- children: /* @__PURE__ */ e("img", { src: c, alt: s.fileName, className: "knest-attachment-image" })
62
+ children: /* @__PURE__ */ e("img", { src: c, alt: n.fileName, className: "knest-attachment-image" })
63
63
  },
64
64
  o
65
65
  ) : null : /* @__PURE__ */ l(
@@ -88,8 +88,8 @@ function Me({
88
88
  )
89
89
  }
90
90
  ),
91
- /* @__PURE__ */ e("span", { className: "knest-attachment-file-name", children: s.fileName }),
92
- /* @__PURE__ */ e("span", { className: "knest-attachment-file-size", children: ce(s.fileSize) })
91
+ /* @__PURE__ */ e("span", { className: "knest-attachment-file-name", children: n.fileName }),
92
+ /* @__PURE__ */ e("span", { className: "knest-attachment-file-size", children: ie(n.fileSize) })
93
93
  ]
94
94
  },
95
95
  o
@@ -97,10 +97,10 @@ function Me({
97
97
  }) }),
98
98
  r.sources && r.sources.length > 0 && /* @__PURE__ */ l("div", { className: "knest-sources", children: [
99
99
  /* @__PURE__ */ e("div", { className: "knest-sources-label", children: "Sources" }),
100
- r.sources.slice(0, 1).map((s, o) => /* @__PURE__ */ l(
100
+ r.sources.slice(0, 1).map((n, o) => /* @__PURE__ */ l(
101
101
  "a",
102
102
  {
103
- href: s.url,
103
+ href: n.url,
104
104
  target: "_blank",
105
105
  rel: "noopener noreferrer",
106
106
  className: "knest-source-item",
@@ -124,8 +124,8 @@ function Me({
124
124
  }
125
125
  ),
126
126
  /* @__PURE__ */ l("div", { className: "knest-source-text", children: [
127
- s.breadcrumb && /* @__PURE__ */ e("div", { className: "knest-source-breadcrumb", children: s.breadcrumb }),
128
- /* @__PURE__ */ e("div", { className: "knest-source-title", children: s.title })
127
+ n.breadcrumb && /* @__PURE__ */ e("div", { className: "knest-source-breadcrumb", children: n.breadcrumb }),
128
+ /* @__PURE__ */ e("div", { className: "knest-source-title", children: n.title })
129
129
  ] })
130
130
  ]
131
131
  },
@@ -135,249 +135,251 @@ function Me({
135
135
  ] })
136
136
  ] }) });
137
137
  }
138
- function Ae({
138
+ function Se({
139
139
  publishableApiKey: r,
140
- mode: P = "inline",
141
- defaultOpen: T = !1,
142
- _internal: u
140
+ mode: T = "inline",
141
+ defaultOpen: W = !1,
142
+ user: y,
143
+ _internal: f
143
144
  }) {
144
- const [L, w] = h(null), [p, y] = h(!0), [W, x] = h(null), [N, _] = h(!1), [m, f] = h([]), [s, o] = h(""), [c, E] = h(!1), [d, B] = h(void 0), [A, q] = h(T), [S, I] = h([]), [R, j] = h(!1), [z, M] = h(null), D = Q(null), G = Q(null), J = L?.avatarUrl || ie, Z = L?.exampleQuestions || de, O = L?.brandColor || $;
145
+ const [p, w] = d(null), [C, x] = d(!0), [A, _] = d(null), [E, B] = d(!1), [u, n] = d([]), [o, c] = d(""), [k, L] = d(!1), [h, R] = d(void 0), [S, J] = d(W), [I, P] = d([]), [j, D] = d(!1), [G, M] = d(null), O = V(null), H = V(null), Z = p?.avatarUrl || de, K = p?.exampleQuestions || he, F = p?.brandColor || q;
145
146
  U(() => {
146
- typeof requestIdleCallback < "u" ? requestIdleCallback(() => V()) : setTimeout(() => V(), 0);
147
- const t = u?.supabaseUrl || he, n = u?.supabaseAnonKey || ue, k = me(t, n);
147
+ typeof requestIdleCallback < "u" ? requestIdleCallback(() => X()) : setTimeout(() => X(), 0);
148
+ const t = f?.supabaseUrl || ue, s = f?.supabaseAnonKey || me, m = fe(t, s);
148
149
  (async () => {
149
- const g = await pe(
150
+ const g = await Ce(
150
151
  r,
151
- u?.baseUrl,
152
+ f?.baseUrl,
152
153
  (v) => {
153
154
  w(v);
154
155
  }
155
156
  );
156
157
  if (g.error) {
157
- x(g.error), y(!1);
158
+ _(g.error), x(!1);
158
159
  return;
159
160
  }
160
- w(g.config), y(!1);
161
- const C = Ce(r);
162
- C && C.messages.length > 0 ? (f(C.messages), B(C.threadId), o(C.input)) : f([
161
+ w(g.config), x(!1);
162
+ const b = be(r);
163
+ b && b.messages.length > 0 ? (n(b.messages), R(b.threadId), c(b.input)) : n([
163
164
  {
164
165
  role: "assistant",
165
- content: g.config?.welcomeMessage || X
166
+ content: g.config?.welcomeMessage || Y
166
167
  }
167
168
  ]);
168
- const a = await k;
169
- a || console.warn("Widget auth initialization failed"), _(a);
169
+ const a = await m;
170
+ a || console.warn("Widget auth initialization failed"), B(a);
170
171
  })();
171
- }, [r, u]), U(() => {
172
- m.length > 0 && D.current && D.current.scrollIntoView({ behavior: "smooth" });
173
- }, [m]), U(() => {
174
- m.length <= 1 && !s || fe(r, {
175
- threadId: d,
176
- messages: m,
177
- input: s,
172
+ }, [r, f]), U(() => {
173
+ u.length > 0 && O.current && O.current.scrollIntoView({ behavior: "smooth" });
174
+ }, [u]), U(() => {
175
+ u.length <= 1 && !o || ke(r, {
176
+ threadId: h,
177
+ messages: u,
178
+ input: o,
178
179
  savedAt: Date.now()
179
180
  });
180
- }, [m, d, s, r]), U(() => !d || !N ? void 0 : ke(d, (n) => {
181
- if (n.role !== "human") return;
182
- const k = n.metadata?.attachments ?? [];
183
- f(
184
- (i) => i.some((g) => g.id === n.id) ? i : [
181
+ }, [u, h, o, r]), U(() => !h || !E ? void 0 : ge(h, (s) => {
182
+ if (s.role !== "human") return;
183
+ const m = s.metadata?.attachments ?? [];
184
+ n(
185
+ (i) => i.some((g) => g.id === s.id) ? i : [
185
186
  ...i,
186
187
  {
187
- id: n.id,
188
+ id: s.id,
188
189
  role: "assistant",
189
- content: n.content,
190
- ...k.length > 0 ? { attachments: k } : {}
190
+ content: s.content,
191
+ ...m.length > 0 ? { attachments: m } : {}
191
192
  }
192
193
  ]
193
194
  );
194
- }), [d, N]);
195
- const K = (t) => {
196
- const n = Array.from(t.target.files || []);
195
+ }), [h, E]);
196
+ const ee = (t) => {
197
+ const s = Array.from(t.target.files || []);
197
198
  t.target.value = "", M(null);
198
- for (const k of n) {
199
- const i = be(k);
199
+ for (const m of s) {
200
+ const i = Ne(m);
200
201
  if (i) {
201
202
  M(i);
202
203
  return;
203
204
  }
204
205
  }
205
- I((k) => {
206
- const i = Ne - k.length;
207
- return [...k, ...n.slice(0, i)];
206
+ P((m) => {
207
+ const i = Ee - m.length;
208
+ return [...m, ...s.slice(0, i)];
208
209
  });
209
- }, ee = (t) => {
210
- I((n) => n.filter((k, i) => i !== t));
211
- }, F = async () => {
212
- if (!s.trim() || c || !N) return;
213
- const t = s.trim();
214
- o(""), E(!0), M(null);
215
- let n = [];
216
- if (S.length > 0 && d) {
217
- j(!0);
210
+ }, te = (t) => {
211
+ P((s) => s.filter((m, i) => i !== t));
212
+ }, z = async () => {
213
+ if (!o.trim() || k || !E) return;
214
+ const t = o.trim();
215
+ c(""), L(!0), M(null);
216
+ let s = [];
217
+ if (I.length > 0 && h) {
218
+ D(!0);
218
219
  try {
219
- n = await Promise.all(
220
- S.map(
221
- (a) => Ee({
220
+ s = await Promise.all(
221
+ I.map(
222
+ (a) => Le({
222
223
  publishableApiKey: r,
223
- threadId: d,
224
+ threadId: h,
224
225
  file: a,
225
- baseUrl: u?.baseUrl
226
+ baseUrl: f?.baseUrl
226
227
  })
227
228
  )
228
229
  );
229
230
  } catch (a) {
230
- Y(a instanceof Error ? a.message : "Upload failed", {
231
- threadId: d,
232
- baseUrl: u?.baseUrl
233
- }), M(a instanceof Error ? a.message : "Upload failed."), E(!1), j(!1);
231
+ $(a instanceof Error ? a.message : "Upload failed", {
232
+ threadId: h,
233
+ baseUrl: f?.baseUrl
234
+ }), M(a instanceof Error ? a.message : "Upload failed."), L(!1), D(!1);
234
235
  return;
235
236
  }
236
- j(!1), I([]);
237
+ D(!1), P([]);
237
238
  }
238
- const k = n.length > 0 ? { attachments: n } : void 0;
239
- f((a) => [
239
+ const m = s.length > 0 ? { attachments: s } : void 0;
240
+ n((a) => [
240
241
  ...a,
241
- { role: "user", content: t, ...n.length > 0 ? { attachments: n } : {} }
242
+ { role: "user", content: t, ...s.length > 0 ? { attachments: s } : {} }
242
243
  ]);
243
- const i = m.length + 1;
244
- f((a) => [...a, { role: "assistant", content: "" }]);
245
- let g = "", C = [];
246
- await Le({
244
+ const i = u.length + 1;
245
+ n((a) => [...a, { role: "assistant", content: "" }]);
246
+ let g = "", b = [];
247
+ await we({
247
248
  publishableApiKey: r,
248
249
  content: t,
249
- threadId: d,
250
- baseUrl: u?.baseUrl,
251
- metadata: k,
250
+ threadId: h,
251
+ baseUrl: f?.baseUrl,
252
+ metadata: m,
253
+ user: y,
252
254
  callbacks: {
253
255
  onInit: (a) => {
254
- d || B(a);
256
+ h || R(a);
255
257
  },
256
258
  onContent: (a) => {
257
- g += a, f((v) => {
258
- const b = [...v];
259
- return b[i] = {
259
+ g += a, n((v) => {
260
+ const N = [...v];
261
+ return N[i] = {
260
262
  role: "assistant",
261
263
  content: g
262
- }, b;
264
+ }, N;
263
265
  });
264
266
  },
265
267
  onComplete: (a) => {
266
- C = a, f((v) => {
267
- const b = [...v];
268
- return b[i] = {
268
+ b = a, n((v) => {
269
+ const N = [...v];
270
+ return N[i] = {
269
271
  role: "assistant",
270
272
  content: g,
271
- sources: C
272
- }, b;
273
+ sources: b
274
+ }, N;
273
275
  });
274
276
  },
275
277
  onDone: ({ humanTakeover: a }) => {
276
- a && f((v) => [
278
+ a && n((v) => [
277
279
  ...v.slice(0, i),
278
280
  ...v.slice(i + 1)
279
281
  ]);
280
282
  },
281
283
  onError: (a) => {
282
- Y(a, { userMessage: t, threadId: d, baseUrl: u?.baseUrl }), f((v) => {
283
- const b = [...v];
284
- return b[i] = {
284
+ $(a, { userMessage: t, threadId: h, baseUrl: f?.baseUrl }), n((v) => {
285
+ const N = [...v];
286
+ return N[i] = {
285
287
  role: "assistant",
286
288
  content: `Error: ${a}`
287
- }, b;
289
+ }, N;
288
290
  });
289
291
  }
290
292
  }
291
- }), E(!1);
292
- }, te = () => {
293
- we(r), B(void 0), f([
294
- { role: "assistant", content: L?.welcomeMessage || X }
295
- ]), o(""), I([]), M(null);
296
- }, ne = (t) => {
297
- t.key === "Enter" && !t.shiftKey && (t.preventDefault(), F());
298
- }, se = async (t) => {
299
- o(t), setTimeout(() => F(), 0);
300
- }, H = p ? /* @__PURE__ */ e("div", { className: "knest-chat-card", children: /* @__PURE__ */ e("div", { className: "knest-loading-container", children: /* @__PURE__ */ l("div", { className: "knest-loading-content", children: [
293
+ }), L(!1);
294
+ }, ne = () => {
295
+ Me(r), R(void 0), n([
296
+ { role: "assistant", content: p?.welcomeMessage || Y }
297
+ ]), c(""), P([]), M(null);
298
+ }, se = (t) => {
299
+ t.key === "Enter" && !t.shiftKey && (t.preventDefault(), z());
300
+ }, re = async (t) => {
301
+ c(t), setTimeout(() => z(), 0);
302
+ }, Q = C ? /* @__PURE__ */ e("div", { className: "knest-chat-card", children: /* @__PURE__ */ e("div", { className: "knest-loading-container", children: /* @__PURE__ */ l("div", { className: "knest-loading-content", children: [
301
303
  /* @__PURE__ */ e("div", { className: "knest-spinner-ring" }),
302
304
  /* @__PURE__ */ e("p", { className: "knest-loading-text", children: "Loading chat..." })
303
- ] }) }) }) : W === "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: ge }) }) }) }) : /* @__PURE__ */ l("div", { className: "knest-chat-card", children: [
305
+ ] }) }) }) : 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: ve }) }) }) }) : /* @__PURE__ */ l("div", { className: "knest-chat-card", children: [
304
306
  /* @__PURE__ */ l("div", { className: "knest-messages-container", children: [
305
- m.map((t, n) => /* @__PURE__ */ l("div", { children: [
307
+ u.map((t, s) => /* @__PURE__ */ l("div", { children: [
306
308
  /* @__PURE__ */ e(
307
- Me,
309
+ Ue,
308
310
  {
309
311
  message: t,
310
- isLoading: !t.content && c && t.role === "assistant",
311
- avatarUrl: J,
312
- brandColor: O,
312
+ isLoading: !t.content && k && t.role === "assistant",
313
+ avatarUrl: Z,
314
+ brandColor: F,
313
315
  publishableApiKey: r,
314
- baseUrl: u?.baseUrl
316
+ baseUrl: f?.baseUrl
315
317
  }
316
318
  ),
317
- n < m.length - 1 && /* @__PURE__ */ e("div", { className: "knest-separator" })
318
- ] }, n)),
319
- m.length === 1 && !p && /* @__PURE__ */ l("div", { className: "knest-examples", children: [
319
+ s < u.length - 1 && /* @__PURE__ */ e("div", { className: "knest-separator" })
320
+ ] }, s)),
321
+ u.length === 1 && !C && /* @__PURE__ */ l("div", { className: "knest-examples", children: [
320
322
  /* @__PURE__ */ e("h3", { children: "Example Questions" }),
321
- Z.map((t, n) => /* @__PURE__ */ e(
323
+ K.map((t, s) => /* @__PURE__ */ e(
322
324
  "button",
323
325
  {
324
- onClick: () => se(t),
326
+ onClick: () => re(t),
325
327
  className: "knest-example-btn",
326
- style: n === 0 ? { borderColor: O, borderWidth: "2px" } : {},
328
+ style: s === 0 ? { borderColor: F, borderWidth: "2px" } : {},
327
329
  children: t
328
330
  },
329
- n
331
+ s
330
332
  ))
331
333
  ] }),
332
- /* @__PURE__ */ e("div", { ref: D })
334
+ /* @__PURE__ */ e("div", { ref: O })
333
335
  ] }),
334
336
  /* @__PURE__ */ l("div", { className: "knest-input-section", children: [
335
337
  /* @__PURE__ */ e(
336
338
  "input",
337
339
  {
338
- ref: G,
340
+ ref: H,
339
341
  type: "file",
340
- accept: ve,
342
+ accept: pe,
341
343
  multiple: !0,
342
344
  style: { display: "none" },
343
- onChange: K
345
+ onChange: ee
344
346
  }
345
347
  ),
346
- S.length > 0 && /* @__PURE__ */ e("div", { className: "knest-file-preview", children: S.map((t, n) => /* @__PURE__ */ l("span", { className: "knest-file-chip", children: [
348
+ I.length > 0 && /* @__PURE__ */ e("div", { className: "knest-file-preview", children: I.map((t, s) => /* @__PURE__ */ l("span", { className: "knest-file-chip", children: [
347
349
  t.name,
348
350
  /* @__PURE__ */ e(
349
351
  "button",
350
352
  {
351
353
  type: "button",
352
354
  className: "knest-chip-remove",
353
- onClick: () => ee(n),
355
+ onClick: () => te(s),
354
356
  "aria-label": `Remove ${t.name}`,
355
357
  children: "×"
356
358
  }
357
359
  )
358
- ] }, n)) }),
359
- z && /* @__PURE__ */ e("p", { className: "knest-attach-error", children: z }),
360
+ ] }, s)) }),
361
+ G && /* @__PURE__ */ e("p", { className: "knest-attach-error", children: G }),
360
362
  /* @__PURE__ */ l("div", { className: "knest-input-wrapper", children: [
361
363
  /* @__PURE__ */ e(
362
364
  "input",
363
365
  {
364
366
  type: "text",
365
- value: s,
366
- onChange: (t) => o(t.target.value),
367
- onKeyDown: ne,
367
+ value: o,
368
+ onChange: (t) => c(t.target.value),
369
+ onKeyDown: se,
368
370
  placeholder: "Ask me anything...",
369
- disabled: c || R || !N,
371
+ disabled: k || j || !E,
370
372
  className: "knest-input-field"
371
373
  }
372
374
  ),
373
375
  /* @__PURE__ */ e(
374
376
  "button",
375
377
  {
376
- onClick: () => G.current?.click(),
377
- disabled: !d || c || R,
378
+ onClick: () => H.current?.click(),
379
+ disabled: !h || k || j,
378
380
  className: "knest-attach-btn",
379
381
  type: "button",
380
- title: d ? "Attach file" : "Send a message first to enable attachments",
382
+ title: h ? "Attach file" : "Send a message first to enable attachments",
381
383
  "aria-label": "Attach file",
382
384
  children: /* @__PURE__ */ e(
383
385
  "svg",
@@ -402,8 +404,8 @@ function Ae({
402
404
  /* @__PURE__ */ e(
403
405
  "button",
404
406
  {
405
- onClick: F,
406
- disabled: c || R || !s.trim() || !N,
407
+ onClick: z,
408
+ disabled: k || j || !o.trim() || !E,
407
409
  className: "knest-send-btn",
408
410
  "aria-label": "Send message",
409
411
  children: /* @__PURE__ */ e("svg", { className: "knest-send-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e(
@@ -418,7 +420,7 @@ function Ae({
418
420
  }
419
421
  )
420
422
  ] }),
421
- m.length > 1 && !c && /* @__PURE__ */ e("div", { className: "knest-reset-row", children: /* @__PURE__ */ e("button", { onClick: te, className: "knest-reset-btn", children: "Clear chat" }) }),
423
+ u.length > 1 && !k && /* @__PURE__ */ e("div", { className: "knest-reset-row", children: /* @__PURE__ */ e("button", { onClick: ne, className: "knest-reset-btn", children: "Clear chat" }) }),
422
424
  /* @__PURE__ */ e("div", { className: "knest-footer", children: /* @__PURE__ */ l(
423
425
  "a",
424
426
  {
@@ -495,19 +497,19 @@ function Ae({
495
497
  ) })
496
498
  ] })
497
499
  ] });
498
- if (P === "inline")
499
- return H;
500
- const re = p ? "#9ca3af" : O;
500
+ if (T === "inline")
501
+ return Q;
502
+ const ae = C ? "#9ca3af" : F;
501
503
  return /* @__PURE__ */ l("div", { className: "knest-bubble-container", children: [
502
- A && /* @__PURE__ */ e("div", { className: "knest-bubble-panel", children: H }),
504
+ S && /* @__PURE__ */ e("div", { className: "knest-bubble-panel", children: Q }),
503
505
  /* @__PURE__ */ e(
504
506
  "button",
505
507
  {
506
- className: ["knest-bubble-button", p && "knest-bubble-loading"].filter(Boolean).join(" "),
507
- onClick: () => q(!A),
508
- "aria-label": p ? "Loading chat" : A ? "Close chat" : "Open chat",
509
- style: { backgroundColor: re },
510
- children: p ? /* @__PURE__ */ l(
508
+ className: ["knest-bubble-button", C && "knest-bubble-loading"].filter(Boolean).join(" "),
509
+ onClick: () => J(!S),
510
+ "aria-label": C ? "Loading chat" : S ? "Close chat" : "Open chat",
511
+ style: { backgroundColor: ae },
512
+ children: C ? /* @__PURE__ */ l(
511
513
  "svg",
512
514
  {
513
515
  width: "24",
@@ -540,7 +542,7 @@ function Ae({
540
542
  )
541
543
  ]
542
544
  }
543
- ) : A ? /* @__PURE__ */ e(
545
+ ) : S ? /* @__PURE__ */ e(
544
546
  "svg",
545
547
  {
546
548
  width: "24",
@@ -575,6 +577,6 @@ function Ae({
575
577
  ] });
576
578
  }
577
579
  export {
578
- Me as ChatMessage,
579
- Ae as ChatWidget
580
+ Ue as ChatMessage,
581
+ Se as ChatWidget
580
582
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useknest/widget-react",
3
- "version": "0.1.0-beta.12",
3
+ "version": "0.1.0-beta.13",
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.12"
25
+ "@useknest/widget-core": "0.1.0-beta.13"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/react": "^18.3.3",