@wallavi/widget 1.1.0 → 1.2.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 +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +214 -5
- package/dist/index.mjs +214 -6
- package/package.json +10 -20
package/dist/index.d.mts
CHANGED
|
@@ -62,6 +62,12 @@ interface ChatWidgetConfig {
|
|
|
62
62
|
*/
|
|
63
63
|
persist?: boolean;
|
|
64
64
|
onNavigate?: (path: string) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Hide the close (X) button in the widget header.
|
|
67
|
+
* Useful when the integrator controls open/close from an outer bubble wrapper
|
|
68
|
+
* and wants to avoid showing two close buttons.
|
|
69
|
+
*/
|
|
70
|
+
hideCloseButton?: boolean;
|
|
65
71
|
source?: string;
|
|
66
72
|
userContext?: UserContext;
|
|
67
73
|
/** Per-session tool overrides used by Playground (not persisted) */
|
|
@@ -79,7 +85,36 @@ interface ChatWidgetProps extends ChatWidgetConfig {
|
|
|
79
85
|
declare function getContrastColor(hex: string): string;
|
|
80
86
|
declare function formatToolName(name: string): string;
|
|
81
87
|
|
|
82
|
-
|
|
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
|
+
|
|
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;
|
|
83
118
|
|
|
84
119
|
interface UseChatOptions {
|
|
85
120
|
agentId: string;
|
|
@@ -106,4 +141,4 @@ interface UseChatReturn {
|
|
|
106
141
|
}
|
|
107
142
|
declare function useChat({ agentId, workspaceId, source, userContext, persist, onNavigate, playgroundOverrides, }: UseChatOptions): UseChatReturn;
|
|
108
143
|
|
|
109
|
-
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
|
@@ -62,6 +62,12 @@ interface ChatWidgetConfig {
|
|
|
62
62
|
*/
|
|
63
63
|
persist?: boolean;
|
|
64
64
|
onNavigate?: (path: string) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Hide the close (X) button in the widget header.
|
|
67
|
+
* Useful when the integrator controls open/close from an outer bubble wrapper
|
|
68
|
+
* and wants to avoid showing two close buttons.
|
|
69
|
+
*/
|
|
70
|
+
hideCloseButton?: boolean;
|
|
65
71
|
source?: string;
|
|
66
72
|
userContext?: UserContext;
|
|
67
73
|
/** Per-session tool overrides used by Playground (not persisted) */
|
|
@@ -79,7 +85,36 @@ interface ChatWidgetProps extends ChatWidgetConfig {
|
|
|
79
85
|
declare function getContrastColor(hex: string): string;
|
|
80
86
|
declare function formatToolName(name: string): string;
|
|
81
87
|
|
|
82
|
-
|
|
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
|
+
|
|
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;
|
|
83
118
|
|
|
84
119
|
interface UseChatOptions {
|
|
85
120
|
agentId: string;
|
|
@@ -106,4 +141,4 @@ interface UseChatReturn {
|
|
|
106
141
|
}
|
|
107
142
|
declare function useChat({ agentId, workspaceId, source, userContext, persist, onNavigate, playgroundOverrides, }: UseChatOptions): UseChatReturn;
|
|
108
143
|
|
|
109
|
-
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/
|
|
36
|
+
// src/bubble-widget.tsx
|
|
37
37
|
|
|
38
38
|
// src/types.ts
|
|
39
39
|
function getContrastColor(hex) {
|
|
@@ -615,13 +615,14 @@ function ChatWidget({
|
|
|
615
615
|
suggestedMessages = [],
|
|
616
616
|
messagePlaceholder,
|
|
617
617
|
watermark = true,
|
|
618
|
-
watermarkLogoUrl = "https://wallavi.com/wallavi.svg",
|
|
618
|
+
watermarkLogoUrl = "https://app.wallavi.com/wallavi.svg",
|
|
619
619
|
footer,
|
|
620
620
|
theme,
|
|
621
621
|
showThinking = false,
|
|
622
622
|
regenerateMessage = false,
|
|
623
623
|
persist = false,
|
|
624
624
|
onNavigate,
|
|
625
|
+
hideCloseButton = false,
|
|
625
626
|
source = "playground",
|
|
626
627
|
userContext,
|
|
627
628
|
playgroundOverrides,
|
|
@@ -642,7 +643,7 @@ function ChatWidget({
|
|
|
642
643
|
"div",
|
|
643
644
|
{
|
|
644
645
|
className: cn3(
|
|
645
|
-
"flex flex-col overflow-hidden rounded-2xl border shadow-xl bg-background",
|
|
646
|
+
"flex flex-col overflow-hidden rounded-2xl border shadow-xl bg-background h-full",
|
|
646
647
|
className
|
|
647
648
|
),
|
|
648
649
|
style: { colorScheme: theme },
|
|
@@ -655,7 +656,7 @@ function ChatWidget({
|
|
|
655
656
|
headerBg,
|
|
656
657
|
headerText,
|
|
657
658
|
onReset: handleReset,
|
|
658
|
-
onClose
|
|
659
|
+
onClose: hideCloseButton ? void 0 : onClose
|
|
659
660
|
}
|
|
660
661
|
),
|
|
661
662
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -708,7 +709,215 @@ function ChatWidget({
|
|
|
708
709
|
}
|
|
709
710
|
);
|
|
710
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 dismissed = sessionStorage.getItem("wallavi_bubble_dismissed");
|
|
756
|
+
if (!dismissed) {
|
|
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
|
+
sessionStorage.setItem("wallavi_bubble_dismissed", "1");
|
|
782
|
+
};
|
|
783
|
+
const toggleExpanded = () => setExpanded((v) => !v);
|
|
784
|
+
const isLeft = position === "bottom-left";
|
|
785
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
786
|
+
"div",
|
|
787
|
+
{
|
|
788
|
+
style: {
|
|
789
|
+
position: "fixed",
|
|
790
|
+
bottom: 20,
|
|
791
|
+
[isLeft ? "left" : "right"]: 20,
|
|
792
|
+
zIndex: 9999,
|
|
793
|
+
display: "flex",
|
|
794
|
+
flexDirection: "column",
|
|
795
|
+
alignItems: isLeft ? "flex-start" : "flex-end",
|
|
796
|
+
gap: 12
|
|
797
|
+
},
|
|
798
|
+
children: [
|
|
799
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
800
|
+
"div",
|
|
801
|
+
{
|
|
802
|
+
ref: panelRef,
|
|
803
|
+
"aria-hidden": !open,
|
|
804
|
+
style: { display: open ? "block" : "none", position: "relative" },
|
|
805
|
+
children: [
|
|
806
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
807
|
+
"div",
|
|
808
|
+
{
|
|
809
|
+
style: {
|
|
810
|
+
position: "absolute",
|
|
811
|
+
top: -12,
|
|
812
|
+
[isLeft ? "left" : "right"]: -12,
|
|
813
|
+
zIndex: 10,
|
|
814
|
+
display: "flex",
|
|
815
|
+
alignItems: "center",
|
|
816
|
+
gap: 4
|
|
817
|
+
},
|
|
818
|
+
children: [
|
|
819
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
820
|
+
"button",
|
|
821
|
+
{
|
|
822
|
+
onClick: toggleExpanded,
|
|
823
|
+
title: expanded ? "Minimize" : "Expand",
|
|
824
|
+
style: {
|
|
825
|
+
width: 24,
|
|
826
|
+
height: 24,
|
|
827
|
+
borderRadius: "50%",
|
|
828
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
829
|
+
background: "var(--background, #fff)",
|
|
830
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
|
|
831
|
+
display: "flex",
|
|
832
|
+
alignItems: "center",
|
|
833
|
+
justifyContent: "center",
|
|
834
|
+
cursor: "pointer",
|
|
835
|
+
color: "var(--muted-foreground, #888)"
|
|
836
|
+
},
|
|
837
|
+
children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ExpandIcon, {})
|
|
838
|
+
}
|
|
839
|
+
),
|
|
840
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
841
|
+
"button",
|
|
842
|
+
{
|
|
843
|
+
onClick: handleClose,
|
|
844
|
+
title: "Close",
|
|
845
|
+
style: {
|
|
846
|
+
width: 24,
|
|
847
|
+
height: 24,
|
|
848
|
+
borderRadius: "50%",
|
|
849
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
850
|
+
background: "var(--background, #fff)",
|
|
851
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
|
|
852
|
+
display: "flex",
|
|
853
|
+
alignItems: "center",
|
|
854
|
+
justifyContent: "center",
|
|
855
|
+
cursor: "pointer",
|
|
856
|
+
color: "var(--muted-foreground, #888)"
|
|
857
|
+
},
|
|
858
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
|
|
859
|
+
}
|
|
860
|
+
)
|
|
861
|
+
]
|
|
862
|
+
}
|
|
863
|
+
),
|
|
864
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
865
|
+
"div",
|
|
866
|
+
{
|
|
867
|
+
style: {
|
|
868
|
+
width: expanded ? Math.min(expandedWidth, typeof window !== "undefined" ? window.innerWidth - 40 : expandedWidth) : width,
|
|
869
|
+
height: expanded ? expandedHeight : height,
|
|
870
|
+
transition: "width 0.3s ease, height 0.3s ease"
|
|
871
|
+
},
|
|
872
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
873
|
+
ChatWidget,
|
|
874
|
+
{
|
|
875
|
+
...chatProps,
|
|
876
|
+
hideCloseButton: true,
|
|
877
|
+
className: cn4("shadow-2xl h-full", panelClassName)
|
|
878
|
+
}
|
|
879
|
+
)
|
|
880
|
+
}
|
|
881
|
+
)
|
|
882
|
+
]
|
|
883
|
+
}
|
|
884
|
+
),
|
|
885
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
886
|
+
"button",
|
|
887
|
+
{
|
|
888
|
+
onClick: () => setOpen((v) => !v),
|
|
889
|
+
title: open ? "Close chat" : "Open chat",
|
|
890
|
+
style: {
|
|
891
|
+
width: bubbleSize,
|
|
892
|
+
height: bubbleSize,
|
|
893
|
+
borderRadius: "50%",
|
|
894
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
895
|
+
boxShadow: "0 4px 16px rgba(0,0,0,0.16)",
|
|
896
|
+
cursor: "pointer",
|
|
897
|
+
overflow: "hidden",
|
|
898
|
+
display: "flex",
|
|
899
|
+
alignItems: "center",
|
|
900
|
+
justifyContent: "center",
|
|
901
|
+
transition: "transform 0.2s ease, box-shadow 0.2s ease",
|
|
902
|
+
background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
|
|
903
|
+
color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
|
|
904
|
+
},
|
|
905
|
+
children: open ? /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
906
|
+
"img",
|
|
907
|
+
{
|
|
908
|
+
src: bubbleIconUrl,
|
|
909
|
+
alt: "Open chat",
|
|
910
|
+
style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
|
|
911
|
+
}
|
|
912
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(DefaultIcon, {})
|
|
913
|
+
}
|
|
914
|
+
)
|
|
915
|
+
]
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
}
|
|
711
919
|
|
|
920
|
+
exports.BubbleWidget = BubbleWidget;
|
|
712
921
|
exports.ChatWidget = ChatWidget;
|
|
713
922
|
exports.formatToolName = formatToolName;
|
|
714
923
|
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/
|
|
10
|
+
// src/bubble-widget.tsx
|
|
11
11
|
|
|
12
12
|
// src/types.ts
|
|
13
13
|
function getContrastColor(hex) {
|
|
@@ -589,13 +589,14 @@ function ChatWidget({
|
|
|
589
589
|
suggestedMessages = [],
|
|
590
590
|
messagePlaceholder,
|
|
591
591
|
watermark = true,
|
|
592
|
-
watermarkLogoUrl = "https://wallavi.com/wallavi.svg",
|
|
592
|
+
watermarkLogoUrl = "https://app.wallavi.com/wallavi.svg",
|
|
593
593
|
footer,
|
|
594
594
|
theme,
|
|
595
595
|
showThinking = false,
|
|
596
596
|
regenerateMessage = false,
|
|
597
597
|
persist = false,
|
|
598
598
|
onNavigate,
|
|
599
|
+
hideCloseButton = false,
|
|
599
600
|
source = "playground",
|
|
600
601
|
userContext,
|
|
601
602
|
playgroundOverrides,
|
|
@@ -616,7 +617,7 @@ function ChatWidget({
|
|
|
616
617
|
"div",
|
|
617
618
|
{
|
|
618
619
|
className: cn3(
|
|
619
|
-
"flex flex-col overflow-hidden rounded-2xl border shadow-xl bg-background",
|
|
620
|
+
"flex flex-col overflow-hidden rounded-2xl border shadow-xl bg-background h-full",
|
|
620
621
|
className
|
|
621
622
|
),
|
|
622
623
|
style: { colorScheme: theme },
|
|
@@ -629,7 +630,7 @@ function ChatWidget({
|
|
|
629
630
|
headerBg,
|
|
630
631
|
headerText,
|
|
631
632
|
onReset: handleReset,
|
|
632
|
-
onClose
|
|
633
|
+
onClose: hideCloseButton ? void 0 : onClose
|
|
633
634
|
}
|
|
634
635
|
),
|
|
635
636
|
/* @__PURE__ */ jsx(
|
|
@@ -682,5 +683,212 @@ function ChatWidget({
|
|
|
682
683
|
}
|
|
683
684
|
);
|
|
684
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 dismissed = sessionStorage.getItem("wallavi_bubble_dismissed");
|
|
730
|
+
if (!dismissed) {
|
|
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
|
+
sessionStorage.setItem("wallavi_bubble_dismissed", "1");
|
|
756
|
+
};
|
|
757
|
+
const toggleExpanded = () => setExpanded((v) => !v);
|
|
758
|
+
const isLeft = position === "bottom-left";
|
|
759
|
+
return /* @__PURE__ */ jsxs(
|
|
760
|
+
"div",
|
|
761
|
+
{
|
|
762
|
+
style: {
|
|
763
|
+
position: "fixed",
|
|
764
|
+
bottom: 20,
|
|
765
|
+
[isLeft ? "left" : "right"]: 20,
|
|
766
|
+
zIndex: 9999,
|
|
767
|
+
display: "flex",
|
|
768
|
+
flexDirection: "column",
|
|
769
|
+
alignItems: isLeft ? "flex-start" : "flex-end",
|
|
770
|
+
gap: 12
|
|
771
|
+
},
|
|
772
|
+
children: [
|
|
773
|
+
/* @__PURE__ */ jsxs(
|
|
774
|
+
"div",
|
|
775
|
+
{
|
|
776
|
+
ref: panelRef,
|
|
777
|
+
"aria-hidden": !open,
|
|
778
|
+
style: { display: open ? "block" : "none", position: "relative" },
|
|
779
|
+
children: [
|
|
780
|
+
/* @__PURE__ */ jsxs(
|
|
781
|
+
"div",
|
|
782
|
+
{
|
|
783
|
+
style: {
|
|
784
|
+
position: "absolute",
|
|
785
|
+
top: -12,
|
|
786
|
+
[isLeft ? "left" : "right"]: -12,
|
|
787
|
+
zIndex: 10,
|
|
788
|
+
display: "flex",
|
|
789
|
+
alignItems: "center",
|
|
790
|
+
gap: 4
|
|
791
|
+
},
|
|
792
|
+
children: [
|
|
793
|
+
/* @__PURE__ */ jsx(
|
|
794
|
+
"button",
|
|
795
|
+
{
|
|
796
|
+
onClick: toggleExpanded,
|
|
797
|
+
title: expanded ? "Minimize" : "Expand",
|
|
798
|
+
style: {
|
|
799
|
+
width: 24,
|
|
800
|
+
height: 24,
|
|
801
|
+
borderRadius: "50%",
|
|
802
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
803
|
+
background: "var(--background, #fff)",
|
|
804
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
|
|
805
|
+
display: "flex",
|
|
806
|
+
alignItems: "center",
|
|
807
|
+
justifyContent: "center",
|
|
808
|
+
cursor: "pointer",
|
|
809
|
+
color: "var(--muted-foreground, #888)"
|
|
810
|
+
},
|
|
811
|
+
children: expanded ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(ExpandIcon, {})
|
|
812
|
+
}
|
|
813
|
+
),
|
|
814
|
+
/* @__PURE__ */ jsx(
|
|
815
|
+
"button",
|
|
816
|
+
{
|
|
817
|
+
onClick: handleClose,
|
|
818
|
+
title: "Close",
|
|
819
|
+
style: {
|
|
820
|
+
width: 24,
|
|
821
|
+
height: 24,
|
|
822
|
+
borderRadius: "50%",
|
|
823
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
824
|
+
background: "var(--background, #fff)",
|
|
825
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.12)",
|
|
826
|
+
display: "flex",
|
|
827
|
+
alignItems: "center",
|
|
828
|
+
justifyContent: "center",
|
|
829
|
+
cursor: "pointer",
|
|
830
|
+
color: "var(--muted-foreground, #888)"
|
|
831
|
+
},
|
|
832
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
833
|
+
}
|
|
834
|
+
)
|
|
835
|
+
]
|
|
836
|
+
}
|
|
837
|
+
),
|
|
838
|
+
/* @__PURE__ */ jsx(
|
|
839
|
+
"div",
|
|
840
|
+
{
|
|
841
|
+
style: {
|
|
842
|
+
width: expanded ? Math.min(expandedWidth, typeof window !== "undefined" ? window.innerWidth - 40 : expandedWidth) : width,
|
|
843
|
+
height: expanded ? expandedHeight : height,
|
|
844
|
+
transition: "width 0.3s ease, height 0.3s ease"
|
|
845
|
+
},
|
|
846
|
+
children: /* @__PURE__ */ jsx(
|
|
847
|
+
ChatWidget,
|
|
848
|
+
{
|
|
849
|
+
...chatProps,
|
|
850
|
+
hideCloseButton: true,
|
|
851
|
+
className: cn4("shadow-2xl h-full", panelClassName)
|
|
852
|
+
}
|
|
853
|
+
)
|
|
854
|
+
}
|
|
855
|
+
)
|
|
856
|
+
]
|
|
857
|
+
}
|
|
858
|
+
),
|
|
859
|
+
/* @__PURE__ */ jsx(
|
|
860
|
+
"button",
|
|
861
|
+
{
|
|
862
|
+
onClick: () => setOpen((v) => !v),
|
|
863
|
+
title: open ? "Close chat" : "Open chat",
|
|
864
|
+
style: {
|
|
865
|
+
width: bubbleSize,
|
|
866
|
+
height: bubbleSize,
|
|
867
|
+
borderRadius: "50%",
|
|
868
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
869
|
+
boxShadow: "0 4px 16px rgba(0,0,0,0.16)",
|
|
870
|
+
cursor: "pointer",
|
|
871
|
+
overflow: "hidden",
|
|
872
|
+
display: "flex",
|
|
873
|
+
alignItems: "center",
|
|
874
|
+
justifyContent: "center",
|
|
875
|
+
transition: "transform 0.2s ease, box-shadow 0.2s ease",
|
|
876
|
+
background: open ? "var(--foreground, #19191c)" : "var(--background, #fff)",
|
|
877
|
+
color: open ? "var(--background, #fff)" : "var(--foreground, #19191c)"
|
|
878
|
+
},
|
|
879
|
+
children: open ? /* @__PURE__ */ jsx(CloseIcon, {}) : bubbleIconUrl ? /* @__PURE__ */ jsx(
|
|
880
|
+
"img",
|
|
881
|
+
{
|
|
882
|
+
src: bubbleIconUrl,
|
|
883
|
+
alt: "Open chat",
|
|
884
|
+
style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
|
|
885
|
+
}
|
|
886
|
+
) : /* @__PURE__ */ jsx(DefaultIcon, {})
|
|
887
|
+
}
|
|
888
|
+
)
|
|
889
|
+
]
|
|
890
|
+
}
|
|
891
|
+
);
|
|
892
|
+
}
|
|
685
893
|
|
|
686
|
-
export { ChatWidget, formatToolName, getContrastColor, useChat };
|
|
894
|
+
export { BubbleWidget, ChatWidget, formatToolName, getContrastColor, useChat };
|
package/package.json
CHANGED
|
@@ -11,42 +11,32 @@
|
|
|
11
11
|
"@types/node": "^22.10.7",
|
|
12
12
|
"@types/react": "^19.1.0",
|
|
13
13
|
"@types/react-dom": "^19.1.0",
|
|
14
|
-
"@wallavi/typescript-config": "workspace:*",
|
|
15
14
|
"tsup": "^8.3.5",
|
|
16
|
-
"typescript": "^5.7.3"
|
|
15
|
+
"typescript": "^5.7.3",
|
|
16
|
+
"@wallavi/typescript-config": "0.0.1"
|
|
17
17
|
},
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
20
|
+
"import": "./dist/index.mjs",
|
|
21
|
+
"require": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts"
|
|
22
23
|
}
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
25
26
|
"dist"
|
|
26
27
|
],
|
|
27
|
-
"main": "./
|
|
28
|
+
"main": "./dist/index.js",
|
|
28
29
|
"name": "@wallavi/widget",
|
|
29
30
|
"peerDependencies": {
|
|
30
31
|
"react": "^18.0.0 || ^19.0.0",
|
|
31
32
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
32
33
|
},
|
|
33
34
|
"private": false,
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
".": {
|
|
37
|
-
"import": "./dist/index.mjs",
|
|
38
|
-
"require": "./dist/index.js",
|
|
39
|
-
"types": "./dist/index.d.ts"
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
"main": "./dist/index.js",
|
|
43
|
-
"module": "./dist/index.mjs",
|
|
44
|
-
"types": "./dist/index.d.ts"
|
|
45
|
-
},
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"version": "1.2.0",
|
|
46
37
|
"scripts": {
|
|
47
38
|
"build": "tsup",
|
|
48
39
|
"typecheck": "tsc --noEmit"
|
|
49
40
|
},
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
}
|
|
41
|
+
"module": "./dist/index.mjs"
|
|
42
|
+
}
|