@getnexorai/sdk 0.1.5 → 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.cjs CHANGED
@@ -712,6 +712,40 @@ var widgetCss = (accent, accentText) => `
712
712
  }
713
713
  .nexor-chat__msg--bot .nexor-chat__msg-time { text-align: left; }
714
714
 
715
+ /* File Library attachment: the image itself is the bubble (no padding/bg). */
716
+ .nexor-chat__msg--media {
717
+ padding: 0;
718
+ background: transparent;
719
+ border: none;
720
+ box-shadow: none;
721
+ overflow: hidden;
722
+ }
723
+ .nexor-chat__media-img {
724
+ display: block;
725
+ max-width: 100%;
726
+ max-height: 260px;
727
+ width: auto;
728
+ height: auto;
729
+ border-radius: 14px;
730
+ border-bottom-left-radius: 4px;
731
+ object-fit: cover;
732
+ }
733
+ .nexor-chat__media-doc {
734
+ display: inline-flex;
735
+ align-items: center;
736
+ gap: 6px;
737
+ padding: 8px 12px;
738
+ border-radius: 14px;
739
+ border-bottom-left-radius: 4px;
740
+ background: #fff;
741
+ border: 1px solid rgba(0,0,0,0.06);
742
+ color: ${accent};
743
+ text-decoration: none;
744
+ font-size: 13px;
745
+ font-weight: 500;
746
+ }
747
+ .nexor-chat__media-doc::before { content: "\\1F4CE"; }
748
+
715
749
  @keyframes nexor-msg-in {
716
750
  from { transform: translateY(8px) scale(0.96); opacity: 0; }
717
751
  to { transform: translateY(0) scale(1); opacity: 1; }
@@ -851,7 +885,8 @@ var widgetCss = (accent, accentText) => `
851
885
  transition: border-color 140ms ease, box-shadow 140ms ease;
852
886
  }
853
887
  /* Composer textarea: auto-grows (height managed in JS) up to ~4 lines, then
854
- scrolls. resize:none disables the manual drag handle. */
888
+ scrolls. resize:none disables the manual drag handle. Filled style: neutral
889
+ pill at rest that "lights up" white on focus \u2014 calmer than a glowing ring. */
855
890
  textarea.nexor-chat__input {
856
891
  display: block;
857
892
  resize: none;
@@ -860,11 +895,22 @@ textarea.nexor-chat__input {
860
895
  max-height: 98px; /* 4 lines (20\xD74) + 16 padding + 2 border */
861
896
  white-space: pre-wrap;
862
897
  word-break: break-word;
898
+ background: #f3f4f6;
899
+ border-color: transparent;
900
+ border-radius: 19px;
901
+ padding: 8px 14px;
902
+ transition: background 140ms ease, border-color 140ms ease, box-shadow 140ms ease;
863
903
  }
904
+ textarea.nexor-chat__input::placeholder { color: #9ca3af; }
864
905
  .nexor-chat__input:focus,
865
906
  .nexor-chat__capture input:focus {
866
907
  border-color: ${accent};
867
- box-shadow: 0 0 0 3px ${accent}33;
908
+ box-shadow: 0 0 0 2px ${accent}1f;
909
+ }
910
+ textarea.nexor-chat__input:focus {
911
+ background: #fff;
912
+ border-color: ${accent}99;
913
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06);
868
914
  }
869
915
  .nexor-chat__input--error,
870
916
  .nexor-chat__capture input.nexor-chat__input--error {
@@ -1005,21 +1051,26 @@ textarea.nexor-chat__input {
1005
1051
  background: ${accent};
1006
1052
  color: ${accentText};
1007
1053
  border: none;
1008
- border-radius: 8px;
1009
- padding: 0 14px;
1054
+ border-radius: 9999px; /* circle, matches the pill composer */
1055
+ padding: 0;
1010
1056
  font: inherit;
1011
1057
  font-weight: 600;
1012
1058
  cursor: pointer;
1013
- min-width: 44px;
1059
+ width: 38px;
1014
1060
  height: 38px; /* matches the one-line textarea height */
1015
1061
  flex: none;
1016
1062
  display: flex;
1017
1063
  align-items: center;
1018
1064
  justify-content: center;
1019
- transition: transform 140ms ease, filter 140ms ease;
1065
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12);
1066
+ transition: transform 140ms ease, filter 140ms ease, box-shadow 140ms ease;
1067
+ }
1068
+ .nexor-chat__send:hover {
1069
+ filter: brightness(1.08);
1070
+ box-shadow: 0 2px 6px rgba(0,0,0,0.18);
1071
+ transform: translateY(-1px);
1020
1072
  }
1021
- .nexor-chat__send:hover { filter: brightness(1.08); }
1022
- .nexor-chat__send:active { transform: scale(0.95); }
1073
+ .nexor-chat__send:active { transform: scale(0.93); }
1023
1074
  .nexor-chat__send[disabled] {
1024
1075
  opacity: 0.6;
1025
1076
  cursor: not-allowed;
@@ -1030,7 +1081,7 @@ textarea.nexor-chat__input {
1030
1081
  height: 18px;
1031
1082
  transition: transform 200ms ease;
1032
1083
  }
1033
- .nexor-chat__send:not([disabled]):hover svg { transform: translateX(2px); }
1084
+ .nexor-chat__send:not([disabled]):hover svg { transform: translateY(-1.5px); }
1034
1085
 
1035
1086
  /* Small spinner inside the send button while a turn is in flight */
1036
1087
  .nexor-chat__send--loading svg { display: none; }
@@ -1183,11 +1234,13 @@ textarea.nexor-chat__input {
1183
1234
  // src/chat/dom.ts
1184
1235
  var STYLE_ATTR = "data-nexor-chat-styles";
1185
1236
  function injectStyles(accent, accentText) {
1186
- if (document.querySelector(`style[${STYLE_ATTR}]`)) return;
1187
- const style = document.createElement("style");
1188
- style.setAttribute(STYLE_ATTR, "1");
1237
+ let style = document.querySelector(`style[${STYLE_ATTR}]`);
1238
+ if (!style) {
1239
+ style = document.createElement("style");
1240
+ style.setAttribute(STYLE_ATTR, "1");
1241
+ document.head.appendChild(style);
1242
+ }
1189
1243
  style.textContent = widgetCss(accent, accentText);
1190
- document.head.appendChild(style);
1191
1244
  }
1192
1245
  var CHAT_ICON = `
1193
1246
  <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
@@ -1550,8 +1603,8 @@ function buildComposer(cfg) {
1550
1603
  send.setAttribute("aria-label", "Send message");
1551
1604
  send.innerHTML = `
1552
1605
  <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1553
- <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"
1554
- stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" fill="currentColor"/>
1606
+ <path d="M12 19V5.8M5.8 12 12 5.8 18.2 12"
1607
+ stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>
1555
1608
  </svg>
1556
1609
  `;
1557
1610
  form.appendChild(input);
@@ -1593,6 +1646,28 @@ function buildMessage(role, text, ts, locale) {
1593
1646
  }
1594
1647
  return el;
1595
1648
  }
1649
+ function buildMediaMessage(item) {
1650
+ const el = document.createElement("div");
1651
+ el.className = "nexor-chat__msg nexor-chat__msg--bot nexor-chat__msg--media";
1652
+ if (item.type === "image") {
1653
+ const img = document.createElement("img");
1654
+ img.className = "nexor-chat__media-img";
1655
+ img.src = item.url;
1656
+ img.alt = item.filename || "";
1657
+ img.loading = "lazy";
1658
+ img.addEventListener("error", () => el.remove());
1659
+ el.appendChild(img);
1660
+ } else {
1661
+ const a = document.createElement("a");
1662
+ a.className = "nexor-chat__media-doc";
1663
+ a.href = item.url;
1664
+ a.target = "_blank";
1665
+ a.rel = "noopener noreferrer";
1666
+ a.textContent = item.filename || "Descargar archivo";
1667
+ el.appendChild(a);
1668
+ }
1669
+ return el;
1670
+ }
1596
1671
  function formatRelativeTime(ts, locale, now = Date.now()) {
1597
1672
  try {
1598
1673
  const diff = Math.max(0, now - ts);
@@ -1770,7 +1845,8 @@ function initChat(client, options) {
1770
1845
  setView("chat");
1771
1846
  renderResumeBanner();
1772
1847
  for (const m of persisted.history) {
1773
- appendBubble(m.role === "user" ? "user" : "bot", m.text, m.ts);
1848
+ if (m.media) appendNode(buildMediaMessage(m.media));
1849
+ else appendBubble(m.role === "user" ? "user" : "bot", m.text, m.ts);
1774
1850
  }
1775
1851
  scrollToBottom();
1776
1852
  }
@@ -2303,9 +2379,12 @@ function initChat(client, options) {
2303
2379
  renderResumeBanner(true);
2304
2380
  }
2305
2381
  const reply = (res.reply ?? "").trim();
2382
+ const hasMedia = Array.isArray(res.media) && res.media.length > 0;
2306
2383
  hideTyping();
2307
2384
  if (reply) {
2308
- appendBotReply(reply);
2385
+ appendBotReply(reply, hasMedia ? () => appendBotMedia(res.media) : void 0);
2386
+ } else if (hasMedia) {
2387
+ appendBotMedia(res.media);
2309
2388
  } else {
2310
2389
  appendSystem(cfg.errorText);
2311
2390
  cfg.onError?.(new Error("Nexor SDK: empty reply from server"));
@@ -2340,10 +2419,21 @@ function initChat(client, options) {
2340
2419
  if (!state.isOpen) bumpUnread();
2341
2420
  cfg.onMessage?.({ role: "bot", text });
2342
2421
  }
2343
- function appendBotReply(text) {
2422
+ function appendBotMedia(items) {
2423
+ if (!Array.isArray(items) || items.length === 0) return;
2424
+ for (const item of items) {
2425
+ if (!item || typeof item.url !== "string" || !item.url) continue;
2426
+ appendNode(buildMediaMessage(item));
2427
+ state.history.push({ role: "bot", text: "", ts: Date.now(), media: item });
2428
+ }
2429
+ saveHistory();
2430
+ if (!state.isOpen) bumpUnread();
2431
+ }
2432
+ function appendBotReply(text, after) {
2344
2433
  const parts = cfg.splitReplies ? splitReply(text) : [text];
2345
2434
  if (parts.length <= 1) {
2346
2435
  appendBot(text);
2436
+ after?.();
2347
2437
  return;
2348
2438
  }
2349
2439
  const [first, ...rest] = parts;
@@ -2351,7 +2441,10 @@ function initChat(client, options) {
2351
2441
  let i = 0;
2352
2442
  const sendNext = () => {
2353
2443
  const part = rest[i];
2354
- if (part === void 0) return;
2444
+ if (part === void 0) {
2445
+ after?.();
2446
+ return;
2447
+ }
2355
2448
  const isLast = i === rest.length - 1;
2356
2449
  i++;
2357
2450
  showTyping();