@getnexorai/sdk 0.1.4 → 0.1.7

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/dist/chat.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { N as NexorClient, d as ChatInitOptions, c as ChatHandle } from './config-C39P5Aax.cjs';
2
- export { a as ChatChannelKey, b as ChatChannels, e as ChatLeadCapture } from './config-C39P5Aax.cjs';
1
+ import { N as NexorClient, d as ChatInitOptions, c as ChatHandle } from './config-DBEY3q4Q.cjs';
2
+ export { a as ChatChannelKey, b as ChatChannels, e as ChatLeadCapture } from './config-DBEY3q4Q.cjs';
3
3
 
4
4
  /**
5
5
  * Chat widget orchestrator.
package/dist/chat.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { N as NexorClient, d as ChatInitOptions, c as ChatHandle } from './config-C39P5Aax.js';
2
- export { a as ChatChannelKey, b as ChatChannels, e as ChatLeadCapture } from './config-C39P5Aax.js';
1
+ import { N as NexorClient, d as ChatInitOptions, c as ChatHandle } from './config-DBEY3q4Q.js';
2
+ export { a as ChatChannelKey, b as ChatChannels, e as ChatLeadCapture } from './config-DBEY3q4Q.js';
3
3
 
4
4
  /**
5
5
  * Chat widget orchestrator.
package/dist/chat.js CHANGED
@@ -1,3 +1,3 @@
1
- export { initChat } from './chunk-WUUXZIQN.js';
1
+ export { initChat } from './chunk-DSKP6MXM.js';
2
2
  //# sourceMappingURL=chat.js.map
3
3
  //# sourceMappingURL=chat.js.map
@@ -235,10 +235,21 @@ function randomHex(bytes) {
235
235
  }
236
236
 
237
237
  // src/chat/validate.ts
238
+ var EMAIL_RE = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
238
239
  function isValidEmail(value) {
239
240
  const s = (value || "").trim();
240
241
  if (s.length < 6 || s.length > 254) return false;
241
- return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(s);
242
+ const at = s.lastIndexOf("@");
243
+ if (at < 1) return false;
244
+ const local = s.slice(0, at);
245
+ const domain = s.slice(at + 1);
246
+ if (local.length > 64) return false;
247
+ if (local.startsWith(".") || local.endsWith(".") || local.includes("..")) {
248
+ return false;
249
+ }
250
+ if (domain.includes("..")) return false;
251
+ if (!/\.[a-zA-Z]{2,}$/.test(domain)) return false;
252
+ return EMAIL_RE.test(s);
242
253
  }
243
254
 
244
255
  // src/chat/template.ts
@@ -699,6 +710,40 @@ var widgetCss = (accent, accentText) => `
699
710
  }
700
711
  .nexor-chat__msg--bot .nexor-chat__msg-time { text-align: left; }
701
712
 
713
+ /* File Library attachment: the image itself is the bubble (no padding/bg). */
714
+ .nexor-chat__msg--media {
715
+ padding: 0;
716
+ background: transparent;
717
+ border: none;
718
+ box-shadow: none;
719
+ overflow: hidden;
720
+ }
721
+ .nexor-chat__media-img {
722
+ display: block;
723
+ max-width: 100%;
724
+ max-height: 260px;
725
+ width: auto;
726
+ height: auto;
727
+ border-radius: 14px;
728
+ border-bottom-left-radius: 4px;
729
+ object-fit: cover;
730
+ }
731
+ .nexor-chat__media-doc {
732
+ display: inline-flex;
733
+ align-items: center;
734
+ gap: 6px;
735
+ padding: 8px 12px;
736
+ border-radius: 14px;
737
+ border-bottom-left-radius: 4px;
738
+ background: #fff;
739
+ border: 1px solid rgba(0,0,0,0.06);
740
+ color: ${accent};
741
+ text-decoration: none;
742
+ font-size: 13px;
743
+ font-weight: 500;
744
+ }
745
+ .nexor-chat__media-doc::before { content: "\\1F4CE"; }
746
+
702
747
  @keyframes nexor-msg-in {
703
748
  from { transform: translateY(8px) scale(0.96); opacity: 0; }
704
749
  to { transform: translateY(0) scale(1); opacity: 1; }
@@ -838,7 +883,8 @@ var widgetCss = (accent, accentText) => `
838
883
  transition: border-color 140ms ease, box-shadow 140ms ease;
839
884
  }
840
885
  /* Composer textarea: auto-grows (height managed in JS) up to ~4 lines, then
841
- scrolls. resize:none disables the manual drag handle. */
886
+ scrolls. resize:none disables the manual drag handle. Filled style: neutral
887
+ pill at rest that "lights up" white on focus \u2014 calmer than a glowing ring. */
842
888
  textarea.nexor-chat__input {
843
889
  display: block;
844
890
  resize: none;
@@ -847,11 +893,22 @@ textarea.nexor-chat__input {
847
893
  max-height: 98px; /* 4 lines (20\xD74) + 16 padding + 2 border */
848
894
  white-space: pre-wrap;
849
895
  word-break: break-word;
896
+ background: #f3f4f6;
897
+ border-color: transparent;
898
+ border-radius: 19px;
899
+ padding: 8px 14px;
900
+ transition: background 140ms ease, border-color 140ms ease, box-shadow 140ms ease;
850
901
  }
902
+ textarea.nexor-chat__input::placeholder { color: #9ca3af; }
851
903
  .nexor-chat__input:focus,
852
904
  .nexor-chat__capture input:focus {
853
905
  border-color: ${accent};
854
- box-shadow: 0 0 0 3px ${accent}33;
906
+ box-shadow: 0 0 0 2px ${accent}1f;
907
+ }
908
+ textarea.nexor-chat__input:focus {
909
+ background: #fff;
910
+ border-color: ${accent}99;
911
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06);
855
912
  }
856
913
  .nexor-chat__input--error,
857
914
  .nexor-chat__capture input.nexor-chat__input--error {
@@ -992,21 +1049,26 @@ textarea.nexor-chat__input {
992
1049
  background: ${accent};
993
1050
  color: ${accentText};
994
1051
  border: none;
995
- border-radius: 8px;
996
- padding: 0 14px;
1052
+ border-radius: 9999px; /* circle, matches the pill composer */
1053
+ padding: 0;
997
1054
  font: inherit;
998
1055
  font-weight: 600;
999
1056
  cursor: pointer;
1000
- min-width: 44px;
1057
+ width: 38px;
1001
1058
  height: 38px; /* matches the one-line textarea height */
1002
1059
  flex: none;
1003
1060
  display: flex;
1004
1061
  align-items: center;
1005
1062
  justify-content: center;
1006
- transition: transform 140ms ease, filter 140ms ease;
1063
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12);
1064
+ transition: transform 140ms ease, filter 140ms ease, box-shadow 140ms ease;
1065
+ }
1066
+ .nexor-chat__send:hover {
1067
+ filter: brightness(1.08);
1068
+ box-shadow: 0 2px 6px rgba(0,0,0,0.18);
1069
+ transform: translateY(-1px);
1007
1070
  }
1008
- .nexor-chat__send:hover { filter: brightness(1.08); }
1009
- .nexor-chat__send:active { transform: scale(0.95); }
1071
+ .nexor-chat__send:active { transform: scale(0.93); }
1010
1072
  .nexor-chat__send[disabled] {
1011
1073
  opacity: 0.6;
1012
1074
  cursor: not-allowed;
@@ -1017,7 +1079,7 @@ textarea.nexor-chat__input {
1017
1079
  height: 18px;
1018
1080
  transition: transform 200ms ease;
1019
1081
  }
1020
- .nexor-chat__send:not([disabled]):hover svg { transform: translateX(2px); }
1082
+ .nexor-chat__send:not([disabled]):hover svg { transform: translateY(-1.5px); }
1021
1083
 
1022
1084
  /* Small spinner inside the send button while a turn is in flight */
1023
1085
  .nexor-chat__send--loading svg { display: none; }
@@ -1170,11 +1232,13 @@ textarea.nexor-chat__input {
1170
1232
  // src/chat/dom.ts
1171
1233
  var STYLE_ATTR = "data-nexor-chat-styles";
1172
1234
  function injectStyles(accent, accentText) {
1173
- if (document.querySelector(`style[${STYLE_ATTR}]`)) return;
1174
- const style = document.createElement("style");
1175
- style.setAttribute(STYLE_ATTR, "1");
1235
+ let style = document.querySelector(`style[${STYLE_ATTR}]`);
1236
+ if (!style) {
1237
+ style = document.createElement("style");
1238
+ style.setAttribute(STYLE_ATTR, "1");
1239
+ document.head.appendChild(style);
1240
+ }
1176
1241
  style.textContent = widgetCss(accent, accentText);
1177
- document.head.appendChild(style);
1178
1242
  }
1179
1243
  var CHAT_ICON = `
1180
1244
  <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
@@ -1537,8 +1601,8 @@ function buildComposer(cfg) {
1537
1601
  send.setAttribute("aria-label", "Send message");
1538
1602
  send.innerHTML = `
1539
1603
  <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1540
- <path d="M3.4 11.2 20.5 4.3c.7-.3 1.4.4 1.1 1.1l-6.9 17.1c-.3.8-1.4.8-1.8 0L10 14l-7.5-3c-.8-.3-.8-1.5 0-1.8Z"
1541
- stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" fill="currentColor"/>
1604
+ <path d="M12 19V5.8M5.8 12 12 5.8 18.2 12"
1605
+ stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>
1542
1606
  </svg>
1543
1607
  `;
1544
1608
  form.appendChild(input);
@@ -1580,6 +1644,28 @@ function buildMessage(role, text, ts, locale) {
1580
1644
  }
1581
1645
  return el;
1582
1646
  }
1647
+ function buildMediaMessage(item) {
1648
+ const el = document.createElement("div");
1649
+ el.className = "nexor-chat__msg nexor-chat__msg--bot nexor-chat__msg--media";
1650
+ if (item.type === "image") {
1651
+ const img = document.createElement("img");
1652
+ img.className = "nexor-chat__media-img";
1653
+ img.src = item.url;
1654
+ img.alt = item.filename || "";
1655
+ img.loading = "lazy";
1656
+ img.addEventListener("error", () => el.remove());
1657
+ el.appendChild(img);
1658
+ } else {
1659
+ const a = document.createElement("a");
1660
+ a.className = "nexor-chat__media-doc";
1661
+ a.href = item.url;
1662
+ a.target = "_blank";
1663
+ a.rel = "noopener noreferrer";
1664
+ a.textContent = item.filename || "Descargar archivo";
1665
+ el.appendChild(a);
1666
+ }
1667
+ return el;
1668
+ }
1583
1669
  function formatRelativeTime(ts, locale, now = Date.now()) {
1584
1670
  try {
1585
1671
  const diff = Math.max(0, now - ts);
@@ -1757,7 +1843,8 @@ function initChat(client, options) {
1757
1843
  setView("chat");
1758
1844
  renderResumeBanner();
1759
1845
  for (const m of persisted.history) {
1760
- appendBubble(m.role === "user" ? "user" : "bot", m.text, m.ts);
1846
+ if (m.media) appendNode(buildMediaMessage(m.media));
1847
+ else appendBubble(m.role === "user" ? "user" : "bot", m.text, m.ts);
1761
1848
  }
1762
1849
  scrollToBottom();
1763
1850
  }
@@ -2290,9 +2377,12 @@ function initChat(client, options) {
2290
2377
  renderResumeBanner(true);
2291
2378
  }
2292
2379
  const reply = (res.reply ?? "").trim();
2380
+ const hasMedia = Array.isArray(res.media) && res.media.length > 0;
2293
2381
  hideTyping();
2294
2382
  if (reply) {
2295
- appendBotReply(reply);
2383
+ appendBotReply(reply, hasMedia ? () => appendBotMedia(res.media) : void 0);
2384
+ } else if (hasMedia) {
2385
+ appendBotMedia(res.media);
2296
2386
  } else {
2297
2387
  appendSystem(cfg.errorText);
2298
2388
  cfg.onError?.(new Error("Nexor SDK: empty reply from server"));
@@ -2327,10 +2417,21 @@ function initChat(client, options) {
2327
2417
  if (!state.isOpen) bumpUnread();
2328
2418
  cfg.onMessage?.({ role: "bot", text });
2329
2419
  }
2330
- function appendBotReply(text) {
2420
+ function appendBotMedia(items) {
2421
+ if (!Array.isArray(items) || items.length === 0) return;
2422
+ for (const item of items) {
2423
+ if (!item || typeof item.url !== "string" || !item.url) continue;
2424
+ appendNode(buildMediaMessage(item));
2425
+ state.history.push({ role: "bot", text: "", ts: Date.now(), media: item });
2426
+ }
2427
+ saveHistory();
2428
+ if (!state.isOpen) bumpUnread();
2429
+ }
2430
+ function appendBotReply(text, after) {
2331
2431
  const parts = cfg.splitReplies ? splitReply(text) : [text];
2332
2432
  if (parts.length <= 1) {
2333
2433
  appendBot(text);
2434
+ after?.();
2334
2435
  return;
2335
2436
  }
2336
2437
  const [first, ...rest] = parts;
@@ -2338,7 +2439,10 @@ function initChat(client, options) {
2338
2439
  let i = 0;
2339
2440
  const sendNext = () => {
2340
2441
  const part = rest[i];
2341
- if (part === void 0) return;
2442
+ if (part === void 0) {
2443
+ after?.();
2444
+ return;
2445
+ }
2342
2446
  const isLast = i === rest.length - 1;
2343
2447
  i++;
2344
2448
  showTyping();
@@ -2479,5 +2583,5 @@ function readCaptureFields(panel) {
2479
2583
  }
2480
2584
 
2481
2585
  export { initChat };
2482
- //# sourceMappingURL=chunk-WUUXZIQN.js.map
2483
- //# sourceMappingURL=chunk-WUUXZIQN.js.map
2586
+ //# sourceMappingURL=chunk-DSKP6MXM.js.map
2587
+ //# sourceMappingURL=chunk-DSKP6MXM.js.map