@wallavi/widget 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -111,8 +111,16 @@ interface BubbleWidgetProps extends ChatWidgetConfig {
111
111
  bubbleSize?: number;
112
112
  /** className applied to the chat panel */
113
113
  panelClassName?: string;
114
+ /**
115
+ * Auto-fetch the agent's configuration from the Wallavi public API and apply it
116
+ * as defaults (profilePicture, chatIcon, colors, messages, autoOpen, keyboardShortcut…).
117
+ * The client only needs to pass `agentId` — everything else self-configures.
118
+ * Pass `autoConfig={false}` if you are providing all props manually.
119
+ * @default true
120
+ */
121
+ autoConfig?: boolean;
114
122
  }
115
- declare function BubbleWidget({ position, width, height, expandedWidth, expandedHeight, keyboardShortcut, shortcutKey, autoOpen, bubbleIconUrl, bubbleSize, panelClassName, ...chatProps }: BubbleWidgetProps): react_jsx_runtime.JSX.Element;
123
+ declare function BubbleWidget({ position: positionProp, width, height, expandedWidth, expandedHeight, keyboardShortcut: keyboardShortcutProp, shortcutKey, autoOpen: autoOpenProp, bubbleIconUrl: bubbleIconUrlProp, bubbleSize, panelClassName, autoConfig, ...chatProps }: BubbleWidgetProps): react_jsx_runtime.JSX.Element;
116
124
 
117
125
  declare function ChatWidget({ agentId, workspaceId, agentName, displayName, profilePicture, userMessageColor, initialMessages, suggestedMessages, messagePlaceholder, watermark, watermarkLogoUrl, footer, theme, showThinking, regenerateMessage, persist, onNavigate, hideCloseButton, source, userContext, playgroundOverrides, className, onClose, onReset, }: ChatWidgetProps): react_jsx_runtime.JSX.Element;
118
126
 
package/dist/index.d.ts CHANGED
@@ -111,8 +111,16 @@ interface BubbleWidgetProps extends ChatWidgetConfig {
111
111
  bubbleSize?: number;
112
112
  /** className applied to the chat panel */
113
113
  panelClassName?: string;
114
+ /**
115
+ * Auto-fetch the agent's configuration from the Wallavi public API and apply it
116
+ * as defaults (profilePicture, chatIcon, colors, messages, autoOpen, keyboardShortcut…).
117
+ * The client only needs to pass `agentId` — everything else self-configures.
118
+ * Pass `autoConfig={false}` if you are providing all props manually.
119
+ * @default true
120
+ */
121
+ autoConfig?: boolean;
114
122
  }
115
- declare function BubbleWidget({ position, width, height, expandedWidth, expandedHeight, keyboardShortcut, shortcutKey, autoOpen, bubbleIconUrl, bubbleSize, panelClassName, ...chatProps }: BubbleWidgetProps): react_jsx_runtime.JSX.Element;
123
+ declare function BubbleWidget({ position: positionProp, width, height, expandedWidth, expandedHeight, keyboardShortcut: keyboardShortcutProp, shortcutKey, autoOpen: autoOpenProp, bubbleIconUrl: bubbleIconUrlProp, bubbleSize, panelClassName, autoConfig, ...chatProps }: BubbleWidgetProps): react_jsx_runtime.JSX.Element;
116
124
 
117
125
  declare function ChatWidget({ agentId, workspaceId, agentName, displayName, profilePicture, userMessageColor, initialMessages, suggestedMessages, messagePlaceholder, watermark, watermarkLogoUrl, footer, theme, showThinking, regenerateMessage, persist, onNavigate, hideCloseButton, source, userContext, playgroundOverrides, className, onClose, onReset, }: ChatWidgetProps): react_jsx_runtime.JSX.Element;
118
126
 
package/dist/index.js CHANGED
@@ -710,6 +710,7 @@ function ChatWidget({
710
710
  );
711
711
  }
712
712
  var cn4 = (...inputs) => tailwindMerge.twMerge(clsx.clsx(inputs));
713
+ var WALLAVI_API = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app" : "https://wallavi-production.up.railway.app";
713
714
  function DefaultIcon() {
714
715
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 26, height: 26 }, children: [
715
716
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "12", fill: "currentColor", opacity: 0.12 }),
@@ -732,17 +733,18 @@ function MinimizeIcon() {
732
733
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 12, height: 12 }, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 14h6v6M20 10h-6V4M14 10l7-7M3 21l7-7", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) });
733
734
  }
734
735
  function BubbleWidget({
735
- position = "bottom-right",
736
+ position: positionProp,
736
737
  width = 360,
737
738
  height = 580,
738
739
  expandedWidth = 640,
739
740
  expandedHeight = "calc(100vh - 100px)",
740
- keyboardShortcut = false,
741
+ keyboardShortcut: keyboardShortcutProp = false,
741
742
  shortcutKey = "k",
742
- autoOpen = false,
743
- bubbleIconUrl,
743
+ autoOpen: autoOpenProp = false,
744
+ bubbleIconUrl: bubbleIconUrlProp,
744
745
  bubbleSize = 52,
745
746
  panelClassName,
747
+ autoConfig = true,
746
748
  // ChatWidgetConfig props
747
749
  ...chatProps
748
750
  }) {
@@ -750,16 +752,50 @@ function BubbleWidget({
750
752
  const [expanded, setExpanded] = react.useState(false);
751
753
  const panelRef = react.useRef(null);
752
754
  const autoOpenedRef = react.useRef(false);
755
+ const [remoteConfig, setRemoteConfig] = react.useState({});
756
+ const [resolvedBubbleIcon, setResolvedBubbleIcon] = react.useState(bubbleIconUrlProp);
757
+ const [resolvedAutoOpen, setResolvedAutoOpen] = react.useState(autoOpenProp);
758
+ const [resolvedKeyboardShortcut, setResolvedKeyboardShortcut] = react.useState(keyboardShortcutProp);
759
+ const [resolvedPosition, setResolvedPosition] = react.useState(positionProp ?? "bottom-right");
753
760
  react.useEffect(() => {
754
- if (!autoOpen || autoOpenedRef.current) return;
761
+ if (!autoConfig) return;
762
+ fetch(`${WALLAVI_API}/api/public/widget/${chatProps.agentId}`).then((r) => r.json()).then((body) => {
763
+ const cfg = body?.data ?? {};
764
+ const remote = {};
765
+ if (cfg.profilePicture != null) remote.profilePicture = cfg.profilePicture;
766
+ if (cfg.displayName != null) remote.displayName = cfg.displayName;
767
+ if (cfg.theme) remote.theme = cfg.theme;
768
+ if (cfg.userMessageColor) remote.userMessageColor = cfg.userMessageColor;
769
+ if (Array.isArray(cfg.initialMessages) && cfg.initialMessages.length > 0) remote.initialMessages = cfg.initialMessages;
770
+ if (Array.isArray(cfg.suggestedMessages)) remote.suggestedMessages = cfg.suggestedMessages;
771
+ if (cfg.messagePlaceholder != null) remote.messagePlaceholder = cfg.messagePlaceholder;
772
+ if (cfg.watermark != null) remote.watermark = cfg.watermark;
773
+ if (cfg.footer != null) remote.footer = cfg.footer;
774
+ if (cfg.showThinking != null) remote.showThinking = cfg.showThinking;
775
+ if (cfg.regenerateMessage != null) remote.regenerateMessage = cfg.regenerateMessage;
776
+ setRemoteConfig(remote);
777
+ if (!bubbleIconUrlProp) {
778
+ const icon = cfg.chatIcon || cfg.profilePicture;
779
+ if (icon) setResolvedBubbleIcon(icon);
780
+ }
781
+ if (!autoOpenProp && cfg.autoOpen) setResolvedAutoOpen(true);
782
+ if (!keyboardShortcutProp && cfg.keyboardShortcut) setResolvedKeyboardShortcut(true);
783
+ if (!positionProp && cfg.alignChatBubbleButton) {
784
+ setResolvedPosition(cfg.alignChatBubbleButton === "left" ? "bottom-left" : "bottom-right");
785
+ }
786
+ }).catch(() => {
787
+ });
788
+ }, [autoConfig, chatProps.agentId]);
789
+ react.useEffect(() => {
790
+ if (!resolvedAutoOpen || autoOpenedRef.current) return;
755
791
  const dismissedUntil = Number(localStorage.getItem("wallavi_bubble_dismissed") ?? 0);
756
792
  if (dismissedUntil < Date.now()) {
757
793
  autoOpenedRef.current = true;
758
794
  setOpen(true);
759
795
  }
760
- }, [autoOpen]);
796
+ }, [resolvedAutoOpen]);
761
797
  react.useEffect(() => {
762
- if (!keyboardShortcut) return;
798
+ if (!resolvedKeyboardShortcut) return;
763
799
  const handler = (e) => {
764
800
  if ((e.metaKey || e.ctrlKey) && e.key === shortcutKey) {
765
801
  e.preventDefault();
@@ -768,7 +804,7 @@ function BubbleWidget({
768
804
  };
769
805
  window.addEventListener("keydown", handler);
770
806
  return () => window.removeEventListener("keydown", handler);
771
- }, [keyboardShortcut, shortcutKey]);
807
+ }, [resolvedKeyboardShortcut, shortcutKey]);
772
808
  react.useEffect(() => {
773
809
  if (!open) return;
774
810
  const id = setTimeout(() => {
@@ -776,13 +812,23 @@ function BubbleWidget({
776
812
  }, 50);
777
813
  return () => clearTimeout(id);
778
814
  }, [open]);
815
+ const definedChatProps = Object.fromEntries(
816
+ Object.entries(chatProps).filter(([, v]) => v !== void 0)
817
+ );
818
+ const mergedConfig = {
819
+ ...remoteConfig,
820
+ ...definedChatProps,
821
+ // Required fields must always come from chatProps
822
+ agentId: chatProps.agentId,
823
+ agentName: chatProps.agentName
824
+ };
779
825
  const handleClose = () => {
780
826
  setOpen(false);
781
827
  const expires = Date.now() + 24 * 60 * 60 * 1e3;
782
828
  localStorage.setItem("wallavi_bubble_dismissed", String(expires));
783
829
  };
784
830
  const toggleExpanded = () => setExpanded((v) => !v);
785
- const isLeft = position === "bottom-left";
831
+ const isLeft = resolvedPosition === "bottom-left";
786
832
  return /* @__PURE__ */ jsxRuntime.jsxs(
787
833
  "div",
788
834
  {
@@ -873,7 +919,7 @@ function BubbleWidget({
873
919
  children: /* @__PURE__ */ jsxRuntime.jsx(
874
920
  ChatWidget,
875
921
  {
876
- ...chatProps,
922
+ ...mergedConfig,
877
923
  hideCloseButton: true,
878
924
  className: cn4("shadow-2xl h-full", panelClassName)
879
925
  }
@@ -903,10 +949,10 @@ function BubbleWidget({
903
949
  background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
904
950
  color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
905
951
  },
906
- children: open ? /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsxRuntime.jsx(
952
+ children: open ? /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) : resolvedBubbleIcon ? /* @__PURE__ */ jsxRuntime.jsx(
907
953
  "img",
908
954
  {
909
- src: bubbleIconUrl,
955
+ src: resolvedBubbleIcon,
910
956
  alt: "Open chat",
911
957
  style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
912
958
  }
package/dist/index.mjs CHANGED
@@ -684,6 +684,7 @@ function ChatWidget({
684
684
  );
685
685
  }
686
686
  var cn4 = (...inputs) => twMerge(clsx(inputs));
687
+ var WALLAVI_API = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app" : "https://wallavi-production.up.railway.app";
687
688
  function DefaultIcon() {
688
689
  return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 26, height: 26 }, children: [
689
690
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "12", fill: "currentColor", opacity: 0.12 }),
@@ -706,17 +707,18 @@ function MinimizeIcon() {
706
707
  return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 12, height: 12 }, children: /* @__PURE__ */ jsx("path", { d: "M4 14h6v6M20 10h-6V4M14 10l7-7M3 21l7-7", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) });
707
708
  }
708
709
  function BubbleWidget({
709
- position = "bottom-right",
710
+ position: positionProp,
710
711
  width = 360,
711
712
  height = 580,
712
713
  expandedWidth = 640,
713
714
  expandedHeight = "calc(100vh - 100px)",
714
- keyboardShortcut = false,
715
+ keyboardShortcut: keyboardShortcutProp = false,
715
716
  shortcutKey = "k",
716
- autoOpen = false,
717
- bubbleIconUrl,
717
+ autoOpen: autoOpenProp = false,
718
+ bubbleIconUrl: bubbleIconUrlProp,
718
719
  bubbleSize = 52,
719
720
  panelClassName,
721
+ autoConfig = true,
720
722
  // ChatWidgetConfig props
721
723
  ...chatProps
722
724
  }) {
@@ -724,16 +726,50 @@ function BubbleWidget({
724
726
  const [expanded, setExpanded] = useState(false);
725
727
  const panelRef = useRef(null);
726
728
  const autoOpenedRef = useRef(false);
729
+ const [remoteConfig, setRemoteConfig] = useState({});
730
+ const [resolvedBubbleIcon, setResolvedBubbleIcon] = useState(bubbleIconUrlProp);
731
+ const [resolvedAutoOpen, setResolvedAutoOpen] = useState(autoOpenProp);
732
+ const [resolvedKeyboardShortcut, setResolvedKeyboardShortcut] = useState(keyboardShortcutProp);
733
+ const [resolvedPosition, setResolvedPosition] = useState(positionProp ?? "bottom-right");
727
734
  useEffect(() => {
728
- if (!autoOpen || autoOpenedRef.current) return;
735
+ if (!autoConfig) return;
736
+ fetch(`${WALLAVI_API}/api/public/widget/${chatProps.agentId}`).then((r) => r.json()).then((body) => {
737
+ const cfg = body?.data ?? {};
738
+ const remote = {};
739
+ if (cfg.profilePicture != null) remote.profilePicture = cfg.profilePicture;
740
+ if (cfg.displayName != null) remote.displayName = cfg.displayName;
741
+ if (cfg.theme) remote.theme = cfg.theme;
742
+ if (cfg.userMessageColor) remote.userMessageColor = cfg.userMessageColor;
743
+ if (Array.isArray(cfg.initialMessages) && cfg.initialMessages.length > 0) remote.initialMessages = cfg.initialMessages;
744
+ if (Array.isArray(cfg.suggestedMessages)) remote.suggestedMessages = cfg.suggestedMessages;
745
+ if (cfg.messagePlaceholder != null) remote.messagePlaceholder = cfg.messagePlaceholder;
746
+ if (cfg.watermark != null) remote.watermark = cfg.watermark;
747
+ if (cfg.footer != null) remote.footer = cfg.footer;
748
+ if (cfg.showThinking != null) remote.showThinking = cfg.showThinking;
749
+ if (cfg.regenerateMessage != null) remote.regenerateMessage = cfg.regenerateMessage;
750
+ setRemoteConfig(remote);
751
+ if (!bubbleIconUrlProp) {
752
+ const icon = cfg.chatIcon || cfg.profilePicture;
753
+ if (icon) setResolvedBubbleIcon(icon);
754
+ }
755
+ if (!autoOpenProp && cfg.autoOpen) setResolvedAutoOpen(true);
756
+ if (!keyboardShortcutProp && cfg.keyboardShortcut) setResolvedKeyboardShortcut(true);
757
+ if (!positionProp && cfg.alignChatBubbleButton) {
758
+ setResolvedPosition(cfg.alignChatBubbleButton === "left" ? "bottom-left" : "bottom-right");
759
+ }
760
+ }).catch(() => {
761
+ });
762
+ }, [autoConfig, chatProps.agentId]);
763
+ useEffect(() => {
764
+ if (!resolvedAutoOpen || autoOpenedRef.current) return;
729
765
  const dismissedUntil = Number(localStorage.getItem("wallavi_bubble_dismissed") ?? 0);
730
766
  if (dismissedUntil < Date.now()) {
731
767
  autoOpenedRef.current = true;
732
768
  setOpen(true);
733
769
  }
734
- }, [autoOpen]);
770
+ }, [resolvedAutoOpen]);
735
771
  useEffect(() => {
736
- if (!keyboardShortcut) return;
772
+ if (!resolvedKeyboardShortcut) return;
737
773
  const handler = (e) => {
738
774
  if ((e.metaKey || e.ctrlKey) && e.key === shortcutKey) {
739
775
  e.preventDefault();
@@ -742,7 +778,7 @@ function BubbleWidget({
742
778
  };
743
779
  window.addEventListener("keydown", handler);
744
780
  return () => window.removeEventListener("keydown", handler);
745
- }, [keyboardShortcut, shortcutKey]);
781
+ }, [resolvedKeyboardShortcut, shortcutKey]);
746
782
  useEffect(() => {
747
783
  if (!open) return;
748
784
  const id = setTimeout(() => {
@@ -750,13 +786,23 @@ function BubbleWidget({
750
786
  }, 50);
751
787
  return () => clearTimeout(id);
752
788
  }, [open]);
789
+ const definedChatProps = Object.fromEntries(
790
+ Object.entries(chatProps).filter(([, v]) => v !== void 0)
791
+ );
792
+ const mergedConfig = {
793
+ ...remoteConfig,
794
+ ...definedChatProps,
795
+ // Required fields must always come from chatProps
796
+ agentId: chatProps.agentId,
797
+ agentName: chatProps.agentName
798
+ };
753
799
  const handleClose = () => {
754
800
  setOpen(false);
755
801
  const expires = Date.now() + 24 * 60 * 60 * 1e3;
756
802
  localStorage.setItem("wallavi_bubble_dismissed", String(expires));
757
803
  };
758
804
  const toggleExpanded = () => setExpanded((v) => !v);
759
- const isLeft = position === "bottom-left";
805
+ const isLeft = resolvedPosition === "bottom-left";
760
806
  return /* @__PURE__ */ jsxs(
761
807
  "div",
762
808
  {
@@ -847,7 +893,7 @@ function BubbleWidget({
847
893
  children: /* @__PURE__ */ jsx(
848
894
  ChatWidget,
849
895
  {
850
- ...chatProps,
896
+ ...mergedConfig,
851
897
  hideCloseButton: true,
852
898
  className: cn4("shadow-2xl h-full", panelClassName)
853
899
  }
@@ -877,10 +923,10 @@ function BubbleWidget({
877
923
  background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
878
924
  color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
879
925
  },
880
- children: open ? /* @__PURE__ */ jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsx(
926
+ children: open ? /* @__PURE__ */ jsx(CloseIcon, {}) : resolvedBubbleIcon ? /* @__PURE__ */ jsx(
881
927
  "img",
882
928
  {
883
- src: bubbleIconUrl,
929
+ src: resolvedBubbleIcon,
884
930
  alt: "Open chat",
885
931
  style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
886
932
  }
package/package.json CHANGED
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "private": false,
35
35
  "types": "./dist/index.d.ts",
36
- "version": "1.2.1",
36
+ "version": "1.3.0",
37
37
  "scripts": {
38
38
  "build": "tsup",
39
39
  "typecheck": "tsc --noEmit"