@wallavi/widget 1.2.0 → 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;
755
- const dismissed = sessionStorage.getItem("wallavi_bubble_dismissed");
756
- if (!dismissed) {
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;
791
+ const dismissedUntil = Number(localStorage.getItem("wallavi_bubble_dismissed") ?? 0);
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,12 +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
- sessionStorage.setItem("wallavi_bubble_dismissed", "1");
827
+ const expires = Date.now() + 24 * 60 * 60 * 1e3;
828
+ localStorage.setItem("wallavi_bubble_dismissed", String(expires));
782
829
  };
783
830
  const toggleExpanded = () => setExpanded((v) => !v);
784
- const isLeft = position === "bottom-left";
831
+ const isLeft = resolvedPosition === "bottom-left";
785
832
  return /* @__PURE__ */ jsxRuntime.jsxs(
786
833
  "div",
787
834
  {
@@ -872,7 +919,7 @@ function BubbleWidget({
872
919
  children: /* @__PURE__ */ jsxRuntime.jsx(
873
920
  ChatWidget,
874
921
  {
875
- ...chatProps,
922
+ ...mergedConfig,
876
923
  hideCloseButton: true,
877
924
  className: cn4("shadow-2xl h-full", panelClassName)
878
925
  }
@@ -902,10 +949,10 @@ function BubbleWidget({
902
949
  background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
903
950
  color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
904
951
  },
905
- children: open ? /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsxRuntime.jsx(
952
+ children: open ? /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) : resolvedBubbleIcon ? /* @__PURE__ */ jsxRuntime.jsx(
906
953
  "img",
907
954
  {
908
- src: bubbleIconUrl,
955
+ src: resolvedBubbleIcon,
909
956
  alt: "Open chat",
910
957
  style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
911
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;
729
- const dismissed = sessionStorage.getItem("wallavi_bubble_dismissed");
730
- if (!dismissed) {
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;
765
+ const dismissedUntil = Number(localStorage.getItem("wallavi_bubble_dismissed") ?? 0);
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,12 +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
- sessionStorage.setItem("wallavi_bubble_dismissed", "1");
801
+ const expires = Date.now() + 24 * 60 * 60 * 1e3;
802
+ localStorage.setItem("wallavi_bubble_dismissed", String(expires));
756
803
  };
757
804
  const toggleExpanded = () => setExpanded((v) => !v);
758
- const isLeft = position === "bottom-left";
805
+ const isLeft = resolvedPosition === "bottom-left";
759
806
  return /* @__PURE__ */ jsxs(
760
807
  "div",
761
808
  {
@@ -846,7 +893,7 @@ function BubbleWidget({
846
893
  children: /* @__PURE__ */ jsx(
847
894
  ChatWidget,
848
895
  {
849
- ...chatProps,
896
+ ...mergedConfig,
850
897
  hideCloseButton: true,
851
898
  className: cn4("shadow-2xl h-full", panelClassName)
852
899
  }
@@ -876,10 +923,10 @@ function BubbleWidget({
876
923
  background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
877
924
  color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
878
925
  },
879
- children: open ? /* @__PURE__ */ jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsx(
926
+ children: open ? /* @__PURE__ */ jsx(CloseIcon, {}) : resolvedBubbleIcon ? /* @__PURE__ */ jsx(
880
927
  "img",
881
928
  {
882
- src: bubbleIconUrl,
929
+ src: resolvedBubbleIcon,
883
930
  alt: "Open chat",
884
931
  style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
885
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.0",
36
+ "version": "1.3.0",
37
37
  "scripts": {
38
38
  "build": "tsup",
39
39
  "typecheck": "tsc --noEmit"