@wallavi/widget 1.1.1 → 1.2.1

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
@@ -85,6 +85,35 @@ interface ChatWidgetProps extends ChatWidgetConfig {
85
85
  declare function getContrastColor(hex: string): string;
86
86
  declare function formatToolName(name: string): string;
87
87
 
88
+ interface BubbleWidgetProps extends ChatWidgetConfig {
89
+ /** Where the bubble is anchored. Default: "bottom-right" */
90
+ position?: "bottom-right" | "bottom-left";
91
+ /** Width of the chat panel in pixels. Default: 360 */
92
+ width?: number;
93
+ /** Height of the chat panel in pixels. Default: 580 */
94
+ height?: number;
95
+ /** Width of the expanded panel in pixels. Default: 640 */
96
+ expandedWidth?: number;
97
+ /** Height of the expanded panel. Default: "calc(100vh - 100px)" */
98
+ expandedHeight?: string;
99
+ /** Enable Cmd/Ctrl + shortcutKey to toggle the widget. Default: false */
100
+ keyboardShortcut?: boolean;
101
+ /** Key to use with Cmd/Ctrl. Default: "k" */
102
+ shortcutKey?: string;
103
+ /** Open the widget automatically on mount. Default: false */
104
+ autoOpen?: boolean;
105
+ /**
106
+ * Image URL to show inside the bubble button.
107
+ * Falls back to the Wallavi logo if not provided.
108
+ */
109
+ bubbleIconUrl?: string;
110
+ /** Size of the bubble toggle button in pixels. Default: 52 */
111
+ bubbleSize?: number;
112
+ /** className applied to the chat panel */
113
+ panelClassName?: string;
114
+ }
115
+ declare function BubbleWidget({ position, width, height, expandedWidth, expandedHeight, keyboardShortcut, shortcutKey, autoOpen, bubbleIconUrl, bubbleSize, panelClassName, ...chatProps }: BubbleWidgetProps): react_jsx_runtime.JSX.Element;
116
+
88
117
  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;
89
118
 
90
119
  interface UseChatOptions {
@@ -112,4 +141,4 @@ interface UseChatReturn {
112
141
  }
113
142
  declare function useChat({ agentId, workspaceId, source, userContext, persist, onNavigate, playgroundOverrides, }: UseChatOptions): UseChatReturn;
114
143
 
115
- export { ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type Message, type MessagePart, type ToolPart, type UserContext, formatToolName, getContrastColor, useChat };
144
+ export { BubbleWidget, type BubbleWidgetProps, ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type Message, type MessagePart, type PageContext, type ToolPart, type UserContext, formatToolName, getContrastColor, useChat };
package/dist/index.d.ts CHANGED
@@ -85,6 +85,35 @@ interface ChatWidgetProps extends ChatWidgetConfig {
85
85
  declare function getContrastColor(hex: string): string;
86
86
  declare function formatToolName(name: string): string;
87
87
 
88
+ interface BubbleWidgetProps extends ChatWidgetConfig {
89
+ /** Where the bubble is anchored. Default: "bottom-right" */
90
+ position?: "bottom-right" | "bottom-left";
91
+ /** Width of the chat panel in pixels. Default: 360 */
92
+ width?: number;
93
+ /** Height of the chat panel in pixels. Default: 580 */
94
+ height?: number;
95
+ /** Width of the expanded panel in pixels. Default: 640 */
96
+ expandedWidth?: number;
97
+ /** Height of the expanded panel. Default: "calc(100vh - 100px)" */
98
+ expandedHeight?: string;
99
+ /** Enable Cmd/Ctrl + shortcutKey to toggle the widget. Default: false */
100
+ keyboardShortcut?: boolean;
101
+ /** Key to use with Cmd/Ctrl. Default: "k" */
102
+ shortcutKey?: string;
103
+ /** Open the widget automatically on mount. Default: false */
104
+ autoOpen?: boolean;
105
+ /**
106
+ * Image URL to show inside the bubble button.
107
+ * Falls back to the Wallavi logo if not provided.
108
+ */
109
+ bubbleIconUrl?: string;
110
+ /** Size of the bubble toggle button in pixels. Default: 52 */
111
+ bubbleSize?: number;
112
+ /** className applied to the chat panel */
113
+ panelClassName?: string;
114
+ }
115
+ declare function BubbleWidget({ position, width, height, expandedWidth, expandedHeight, keyboardShortcut, shortcutKey, autoOpen, bubbleIconUrl, bubbleSize, panelClassName, ...chatProps }: BubbleWidgetProps): react_jsx_runtime.JSX.Element;
116
+
88
117
  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;
89
118
 
90
119
  interface UseChatOptions {
@@ -112,4 +141,4 @@ interface UseChatReturn {
112
141
  }
113
142
  declare function useChat({ agentId, workspaceId, source, userContext, persist, onNavigate, playgroundOverrides, }: UseChatOptions): UseChatReturn;
114
143
 
115
- export { ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type Message, type MessagePart, type ToolPart, type UserContext, formatToolName, getContrastColor, useChat };
144
+ export { BubbleWidget, type BubbleWidgetProps, ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type Message, type MessagePart, type PageContext, type ToolPart, type UserContext, formatToolName, getContrastColor, useChat };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var react = require('react');
3
4
  var clsx = require('clsx');
4
5
  var tailwindMerge = require('tailwind-merge');
5
- var react = require('react');
6
6
  var lucideReact = require('lucide-react');
7
7
  var AvatarPrimitive = require('@radix-ui/react-avatar');
8
8
  var jsxRuntime = require('react/jsx-runtime');
@@ -33,7 +33,7 @@ var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive)
33
33
  var ReactMarkdownLib__default = /*#__PURE__*/_interopDefault(ReactMarkdownLib);
34
34
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
35
35
 
36
- // src/chat-widget.tsx
36
+ // src/bubble-widget.tsx
37
37
 
38
38
  // src/types.ts
39
39
  function getContrastColor(hex) {
@@ -709,7 +709,216 @@ function ChatWidget({
709
709
  }
710
710
  );
711
711
  }
712
+ var cn4 = (...inputs) => tailwindMerge.twMerge(clsx.clsx(inputs));
713
+ function DefaultIcon() {
714
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 26, height: 26 }, children: [
715
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "12", fill: "currentColor", opacity: 0.12 }),
716
+ /* @__PURE__ */ jsxRuntime.jsx(
717
+ "path",
718
+ {
719
+ d: "M4 8.5C4 6.57 5.57 5 7.5 5h9C18.43 5 20 6.57 20 8.5v5c0 1.93-1.57 3.5-3.5 3.5H13l-3 2.5V17H7.5C5.57 17 4 15.43 4 13.5v-5Z",
720
+ fill: "currentColor"
721
+ }
722
+ )
723
+ ] });
724
+ }
725
+ function CloseIcon() {
726
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 20, height: 20 }, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round" }) });
727
+ }
728
+ function ExpandIcon() {
729
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 12, height: 12 }, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) });
730
+ }
731
+ function MinimizeIcon() {
732
+ 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
+ function BubbleWidget({
735
+ position = "bottom-right",
736
+ width = 360,
737
+ height = 580,
738
+ expandedWidth = 640,
739
+ expandedHeight = "calc(100vh - 100px)",
740
+ keyboardShortcut = false,
741
+ shortcutKey = "k",
742
+ autoOpen = false,
743
+ bubbleIconUrl,
744
+ bubbleSize = 52,
745
+ panelClassName,
746
+ // ChatWidgetConfig props
747
+ ...chatProps
748
+ }) {
749
+ const [open, setOpen] = react.useState(false);
750
+ const [expanded, setExpanded] = react.useState(false);
751
+ const panelRef = react.useRef(null);
752
+ const autoOpenedRef = react.useRef(false);
753
+ react.useEffect(() => {
754
+ if (!autoOpen || autoOpenedRef.current) return;
755
+ const dismissedUntil = Number(localStorage.getItem("wallavi_bubble_dismissed") ?? 0);
756
+ if (dismissedUntil < Date.now()) {
757
+ autoOpenedRef.current = true;
758
+ setOpen(true);
759
+ }
760
+ }, [autoOpen]);
761
+ react.useEffect(() => {
762
+ if (!keyboardShortcut) return;
763
+ const handler = (e) => {
764
+ if ((e.metaKey || e.ctrlKey) && e.key === shortcutKey) {
765
+ e.preventDefault();
766
+ setOpen((v) => !v);
767
+ }
768
+ };
769
+ window.addEventListener("keydown", handler);
770
+ return () => window.removeEventListener("keydown", handler);
771
+ }, [keyboardShortcut, shortcutKey]);
772
+ react.useEffect(() => {
773
+ if (!open) return;
774
+ const id = setTimeout(() => {
775
+ panelRef.current?.querySelector("textarea")?.focus();
776
+ }, 50);
777
+ return () => clearTimeout(id);
778
+ }, [open]);
779
+ const handleClose = () => {
780
+ setOpen(false);
781
+ const expires = Date.now() + 24 * 60 * 60 * 1e3;
782
+ localStorage.setItem("wallavi_bubble_dismissed", String(expires));
783
+ };
784
+ const toggleExpanded = () => setExpanded((v) => !v);
785
+ const isLeft = position === "bottom-left";
786
+ return /* @__PURE__ */ jsxRuntime.jsxs(
787
+ "div",
788
+ {
789
+ style: {
790
+ position: "fixed",
791
+ bottom: 20,
792
+ [isLeft ? "left" : "right"]: 20,
793
+ zIndex: 9999,
794
+ display: "flex",
795
+ flexDirection: "column",
796
+ alignItems: isLeft ? "flex-start" : "flex-end",
797
+ gap: 12
798
+ },
799
+ children: [
800
+ /* @__PURE__ */ jsxRuntime.jsxs(
801
+ "div",
802
+ {
803
+ ref: panelRef,
804
+ "aria-hidden": !open,
805
+ style: { display: open ? "block" : "none", position: "relative" },
806
+ children: [
807
+ /* @__PURE__ */ jsxRuntime.jsxs(
808
+ "div",
809
+ {
810
+ style: {
811
+ position: "absolute",
812
+ top: -12,
813
+ [isLeft ? "left" : "right"]: -12,
814
+ zIndex: 10,
815
+ display: "flex",
816
+ alignItems: "center",
817
+ gap: 4
818
+ },
819
+ children: [
820
+ /* @__PURE__ */ jsxRuntime.jsx(
821
+ "button",
822
+ {
823
+ onClick: toggleExpanded,
824
+ title: expanded ? "Minimize" : "Expand",
825
+ style: {
826
+ width: 24,
827
+ height: 24,
828
+ borderRadius: "50%",
829
+ border: "1px solid rgba(0,0,0,0.1)",
830
+ background: "var(--background, #fff)",
831
+ boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
832
+ display: "flex",
833
+ alignItems: "center",
834
+ justifyContent: "center",
835
+ cursor: "pointer",
836
+ color: "var(--muted-foreground, #888)"
837
+ },
838
+ children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ExpandIcon, {})
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsxRuntime.jsx(
842
+ "button",
843
+ {
844
+ onClick: handleClose,
845
+ title: "Close",
846
+ style: {
847
+ width: 24,
848
+ height: 24,
849
+ borderRadius: "50%",
850
+ border: "1px solid rgba(0,0,0,0.1)",
851
+ background: "var(--background, #fff)",
852
+ boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
853
+ display: "flex",
854
+ alignItems: "center",
855
+ justifyContent: "center",
856
+ cursor: "pointer",
857
+ color: "var(--muted-foreground, #888)"
858
+ },
859
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
860
+ }
861
+ )
862
+ ]
863
+ }
864
+ ),
865
+ /* @__PURE__ */ jsxRuntime.jsx(
866
+ "div",
867
+ {
868
+ style: {
869
+ width: expanded ? Math.min(expandedWidth, typeof window !== "undefined" ? window.innerWidth - 40 : expandedWidth) : width,
870
+ height: expanded ? expandedHeight : height,
871
+ transition: "width 0.3s ease, height 0.3s ease"
872
+ },
873
+ children: /* @__PURE__ */ jsxRuntime.jsx(
874
+ ChatWidget,
875
+ {
876
+ ...chatProps,
877
+ hideCloseButton: true,
878
+ className: cn4("shadow-2xl h-full", panelClassName)
879
+ }
880
+ )
881
+ }
882
+ )
883
+ ]
884
+ }
885
+ ),
886
+ /* @__PURE__ */ jsxRuntime.jsx(
887
+ "button",
888
+ {
889
+ onClick: () => setOpen((v) => !v),
890
+ title: open ? "Close chat" : "Open chat",
891
+ style: {
892
+ width: bubbleSize,
893
+ height: bubbleSize,
894
+ borderRadius: "50%",
895
+ border: "1px solid rgba(0,0,0,0.1)",
896
+ boxShadow: "0 4px 16px rgba(0,0,0,0.16)",
897
+ cursor: "pointer",
898
+ overflow: "hidden",
899
+ display: "flex",
900
+ alignItems: "center",
901
+ justifyContent: "center",
902
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
903
+ background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
904
+ color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
905
+ },
906
+ children: open ? /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsxRuntime.jsx(
907
+ "img",
908
+ {
909
+ src: bubbleIconUrl,
910
+ alt: "Open chat",
911
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
912
+ }
913
+ ) : /* @__PURE__ */ jsxRuntime.jsx(DefaultIcon, {})
914
+ }
915
+ )
916
+ ]
917
+ }
918
+ );
919
+ }
712
920
 
921
+ exports.BubbleWidget = BubbleWidget;
713
922
  exports.ChatWidget = ChatWidget;
714
923
  exports.formatToolName = formatToolName;
715
924
  exports.getContrastColor = getContrastColor;
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
+ import { useState, useRef, useEffect, useCallback } from 'react';
1
2
  import { clsx } from 'clsx';
2
3
  import { twMerge } from 'tailwind-merge';
3
- import { useState, useRef, useEffect, useCallback } from 'react';
4
4
  import { RotateCcw, X, Loader2, ArrowUp, Zap, ChevronDown, CheckCircle2, AlertCircle } from 'lucide-react';
5
5
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
6
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
7
  import ReactMarkdownLib from 'react-markdown';
8
8
  import remarkGfm from 'remark-gfm';
9
9
 
10
- // src/chat-widget.tsx
10
+ // src/bubble-widget.tsx
11
11
 
12
12
  // src/types.ts
13
13
  function getContrastColor(hex) {
@@ -683,5 +683,213 @@ function ChatWidget({
683
683
  }
684
684
  );
685
685
  }
686
+ var cn4 = (...inputs) => twMerge(clsx(inputs));
687
+ function DefaultIcon() {
688
+ return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 26, height: 26 }, children: [
689
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "12", fill: "currentColor", opacity: 0.12 }),
690
+ /* @__PURE__ */ jsx(
691
+ "path",
692
+ {
693
+ d: "M4 8.5C4 6.57 5.57 5 7.5 5h9C18.43 5 20 6.57 20 8.5v5c0 1.93-1.57 3.5-3.5 3.5H13l-3 2.5V17H7.5C5.57 17 4 15.43 4 13.5v-5Z",
694
+ fill: "currentColor"
695
+ }
696
+ )
697
+ ] });
698
+ }
699
+ function CloseIcon() {
700
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 20, height: 20 }, children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round" }) });
701
+ }
702
+ function ExpandIcon() {
703
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 12, height: 12 }, children: /* @__PURE__ */ jsx("path", { d: "M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) });
704
+ }
705
+ function MinimizeIcon() {
706
+ 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
+ function BubbleWidget({
709
+ position = "bottom-right",
710
+ width = 360,
711
+ height = 580,
712
+ expandedWidth = 640,
713
+ expandedHeight = "calc(100vh - 100px)",
714
+ keyboardShortcut = false,
715
+ shortcutKey = "k",
716
+ autoOpen = false,
717
+ bubbleIconUrl,
718
+ bubbleSize = 52,
719
+ panelClassName,
720
+ // ChatWidgetConfig props
721
+ ...chatProps
722
+ }) {
723
+ const [open, setOpen] = useState(false);
724
+ const [expanded, setExpanded] = useState(false);
725
+ const panelRef = useRef(null);
726
+ const autoOpenedRef = useRef(false);
727
+ useEffect(() => {
728
+ if (!autoOpen || autoOpenedRef.current) return;
729
+ const dismissedUntil = Number(localStorage.getItem("wallavi_bubble_dismissed") ?? 0);
730
+ if (dismissedUntil < Date.now()) {
731
+ autoOpenedRef.current = true;
732
+ setOpen(true);
733
+ }
734
+ }, [autoOpen]);
735
+ useEffect(() => {
736
+ if (!keyboardShortcut) return;
737
+ const handler = (e) => {
738
+ if ((e.metaKey || e.ctrlKey) && e.key === shortcutKey) {
739
+ e.preventDefault();
740
+ setOpen((v) => !v);
741
+ }
742
+ };
743
+ window.addEventListener("keydown", handler);
744
+ return () => window.removeEventListener("keydown", handler);
745
+ }, [keyboardShortcut, shortcutKey]);
746
+ useEffect(() => {
747
+ if (!open) return;
748
+ const id = setTimeout(() => {
749
+ panelRef.current?.querySelector("textarea")?.focus();
750
+ }, 50);
751
+ return () => clearTimeout(id);
752
+ }, [open]);
753
+ const handleClose = () => {
754
+ setOpen(false);
755
+ const expires = Date.now() + 24 * 60 * 60 * 1e3;
756
+ localStorage.setItem("wallavi_bubble_dismissed", String(expires));
757
+ };
758
+ const toggleExpanded = () => setExpanded((v) => !v);
759
+ const isLeft = position === "bottom-left";
760
+ return /* @__PURE__ */ jsxs(
761
+ "div",
762
+ {
763
+ style: {
764
+ position: "fixed",
765
+ bottom: 20,
766
+ [isLeft ? "left" : "right"]: 20,
767
+ zIndex: 9999,
768
+ display: "flex",
769
+ flexDirection: "column",
770
+ alignItems: isLeft ? "flex-start" : "flex-end",
771
+ gap: 12
772
+ },
773
+ children: [
774
+ /* @__PURE__ */ jsxs(
775
+ "div",
776
+ {
777
+ ref: panelRef,
778
+ "aria-hidden": !open,
779
+ style: { display: open ? "block" : "none", position: "relative" },
780
+ children: [
781
+ /* @__PURE__ */ jsxs(
782
+ "div",
783
+ {
784
+ style: {
785
+ position: "absolute",
786
+ top: -12,
787
+ [isLeft ? "left" : "right"]: -12,
788
+ zIndex: 10,
789
+ display: "flex",
790
+ alignItems: "center",
791
+ gap: 4
792
+ },
793
+ children: [
794
+ /* @__PURE__ */ jsx(
795
+ "button",
796
+ {
797
+ onClick: toggleExpanded,
798
+ title: expanded ? "Minimize" : "Expand",
799
+ style: {
800
+ width: 24,
801
+ height: 24,
802
+ borderRadius: "50%",
803
+ border: "1px solid rgba(0,0,0,0.1)",
804
+ background: "var(--background, #fff)",
805
+ boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
806
+ display: "flex",
807
+ alignItems: "center",
808
+ justifyContent: "center",
809
+ cursor: "pointer",
810
+ color: "var(--muted-foreground, #888)"
811
+ },
812
+ children: expanded ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(ExpandIcon, {})
813
+ }
814
+ ),
815
+ /* @__PURE__ */ jsx(
816
+ "button",
817
+ {
818
+ onClick: handleClose,
819
+ title: "Close",
820
+ style: {
821
+ width: 24,
822
+ height: 24,
823
+ borderRadius: "50%",
824
+ border: "1px solid rgba(0,0,0,0.1)",
825
+ background: "var(--background, #fff)",
826
+ boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
827
+ display: "flex",
828
+ alignItems: "center",
829
+ justifyContent: "center",
830
+ cursor: "pointer",
831
+ color: "var(--muted-foreground, #888)"
832
+ },
833
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
834
+ }
835
+ )
836
+ ]
837
+ }
838
+ ),
839
+ /* @__PURE__ */ jsx(
840
+ "div",
841
+ {
842
+ style: {
843
+ width: expanded ? Math.min(expandedWidth, typeof window !== "undefined" ? window.innerWidth - 40 : expandedWidth) : width,
844
+ height: expanded ? expandedHeight : height,
845
+ transition: "width 0.3s ease, height 0.3s ease"
846
+ },
847
+ children: /* @__PURE__ */ jsx(
848
+ ChatWidget,
849
+ {
850
+ ...chatProps,
851
+ hideCloseButton: true,
852
+ className: cn4("shadow-2xl h-full", panelClassName)
853
+ }
854
+ )
855
+ }
856
+ )
857
+ ]
858
+ }
859
+ ),
860
+ /* @__PURE__ */ jsx(
861
+ "button",
862
+ {
863
+ onClick: () => setOpen((v) => !v),
864
+ title: open ? "Close chat" : "Open chat",
865
+ style: {
866
+ width: bubbleSize,
867
+ height: bubbleSize,
868
+ borderRadius: "50%",
869
+ border: "1px solid rgba(0,0,0,0.1)",
870
+ boxShadow: "0 4px 16px rgba(0,0,0,0.16)",
871
+ cursor: "pointer",
872
+ overflow: "hidden",
873
+ display: "flex",
874
+ alignItems: "center",
875
+ justifyContent: "center",
876
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
877
+ background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
878
+ color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
879
+ },
880
+ children: open ? /* @__PURE__ */ jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsx(
881
+ "img",
882
+ {
883
+ src: bubbleIconUrl,
884
+ alt: "Open chat",
885
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
886
+ }
887
+ ) : /* @__PURE__ */ jsx(DefaultIcon, {})
888
+ }
889
+ )
890
+ ]
891
+ }
892
+ );
893
+ }
686
894
 
687
- export { ChatWidget, formatToolName, getContrastColor, useChat };
895
+ export { BubbleWidget, ChatWidget, formatToolName, getContrastColor, useChat };
package/package.json CHANGED
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "private": false,
35
35
  "types": "./dist/index.d.ts",
36
- "version": "1.1.1",
36
+ "version": "1.2.1",
37
37
  "scripts": {
38
38
  "build": "tsup",
39
39
  "typecheck": "tsc --noEmit"