@emblemvault/hustle-react 1.2.0 → 1.4.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.
@@ -1609,7 +1609,7 @@ var screenshotExecutor = async (args2) => {
1609
1609
  if (!window.html2canvas) {
1610
1610
  await new Promise((resolve, reject) => {
1611
1611
  const script = document.createElement("script");
1612
- script.src = "https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js";
1612
+ script.src = "https://cdn.jsdelivr.net/npm/html2canvas-pro@1.5.0/dist/html2canvas-pro.min.js";
1613
1613
  script.onload = () => resolve();
1614
1614
  script.onerror = () => reject(new Error("Failed to load html2canvas"));
1615
1615
  document.head.appendChild(script);
@@ -2664,6 +2664,14 @@ var animations = `
2664
2664
  text-shadow: 0 0 8px ${defaults.colors.accentPrimary};
2665
2665
  }
2666
2666
  }
2667
+ /* Hide scrollbar while maintaining scroll functionality */
2668
+ .hustle-hide-scrollbar {
2669
+ -ms-overflow-style: none; /* IE and Edge */
2670
+ scrollbar-width: none; /* Firefox */
2671
+ }
2672
+ .hustle-hide-scrollbar::-webkit-scrollbar {
2673
+ display: none; /* Chrome, Safari, Opera */
2674
+ }
2667
2675
  `;
2668
2676
  hljs__default.default.registerLanguage("javascript", javascript__default.default);
2669
2677
  hljs__default.default.registerLanguage("js", javascript__default.default);
@@ -3307,7 +3315,11 @@ var styles = {
3307
3315
  border: "none",
3308
3316
  borderRadius: 0,
3309
3317
  color: tokens.colors.textTertiary,
3310
- flexShrink: 0
3318
+ flexShrink: 0,
3319
+ display: "flex",
3320
+ alignItems: "center",
3321
+ justifyContent: "center",
3322
+ cursor: "pointer"
3311
3323
  },
3312
3324
  inputWrapper: {
3313
3325
  flex: 1
@@ -3516,6 +3528,7 @@ function HustleChat({
3516
3528
  placeholder = "Type a message...",
3517
3529
  showSettings = false,
3518
3530
  showDebug = false,
3531
+ hideHeader = false,
3519
3532
  initialSystemPrompt = "",
3520
3533
  onMessage,
3521
3534
  onToolCall,
@@ -3528,6 +3541,7 @@ function HustleChat({
3528
3541
  isLoading,
3529
3542
  error: error2,
3530
3543
  models,
3544
+ client,
3531
3545
  chatStream,
3532
3546
  uploadFile,
3533
3547
  selectedModel,
@@ -3554,6 +3568,7 @@ function HustleChat({
3554
3568
  const [showSettingsPanel, setShowSettingsPanel] = react.useState(false);
3555
3569
  const messagesEndRef = react.useRef(null);
3556
3570
  const fileInputRef = react.useRef(null);
3571
+ const messagesRef = react.useRef(messages);
3557
3572
  react.useEffect(() => {
3558
3573
  if (initialSystemPrompt && !systemPrompt) {
3559
3574
  setSystemPrompt(initialSystemPrompt);
@@ -3562,6 +3577,9 @@ function HustleChat({
3562
3577
  react.useEffect(() => {
3563
3578
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
3564
3579
  }, [messages]);
3580
+ react.useEffect(() => {
3581
+ messagesRef.current = messages;
3582
+ }, [messages]);
3565
3583
  const handleFileSelect = react.useCallback(
3566
3584
  async (e) => {
3567
3585
  const files = e.target.files;
@@ -3583,6 +3601,96 @@ function HustleChat({
3583
3601
  const removeAttachment = react.useCallback((index) => {
3584
3602
  setAttachments((prev) => prev.filter((_, i) => i !== index));
3585
3603
  }, []);
3604
+ const sendContinue = react.useCallback(async () => {
3605
+ if (isStreaming || !isReady) return;
3606
+ console.log("[AUTO_CONTINUE] Sending continue message...");
3607
+ const userMessage = {
3608
+ id: generateId(),
3609
+ role: "user",
3610
+ content: "continue"
3611
+ };
3612
+ setMessages((prev) => [...prev, userMessage]);
3613
+ onMessage?.(userMessage);
3614
+ const assistantMessage = {
3615
+ id: generateId(),
3616
+ role: "assistant",
3617
+ content: "",
3618
+ isStreaming: true,
3619
+ toolCalls: []
3620
+ };
3621
+ setMessages((prev) => [...prev, assistantMessage]);
3622
+ setIsStreaming(true);
3623
+ setCurrentToolCalls([]);
3624
+ try {
3625
+ const chatMessages = messagesRef.current.filter((m) => !m.isStreaming).map((m) => ({ role: m.role, content: m.content }));
3626
+ chatMessages.push({ role: "user", content: "continue" });
3627
+ const stream = chatStream({
3628
+ messages: chatMessages,
3629
+ processChunks: true
3630
+ });
3631
+ let fullContent = "";
3632
+ const toolCallsAccumulated = [];
3633
+ for await (const chunk of stream) {
3634
+ if (chunk.type === "text") {
3635
+ fullContent += chunk.value;
3636
+ setMessages(
3637
+ (prev) => prev.map(
3638
+ (m) => m.id === assistantMessage.id ? { ...m, content: fullContent } : m
3639
+ )
3640
+ );
3641
+ } else if (chunk.type === "tool_call") {
3642
+ const toolCall = chunk.value;
3643
+ toolCallsAccumulated.push(toolCall);
3644
+ setCurrentToolCalls([...toolCallsAccumulated]);
3645
+ setMessages(
3646
+ (prev) => prev.map(
3647
+ (m) => m.id === assistantMessage.id ? { ...m, toolCalls: [...toolCallsAccumulated] } : m
3648
+ )
3649
+ );
3650
+ onToolCall?.(toolCall);
3651
+ } else if (chunk.type === "error") {
3652
+ console.error("Stream error:", chunk.value);
3653
+ }
3654
+ }
3655
+ const processedResponse = await stream.response;
3656
+ const finalContent = processedResponse?.content || fullContent || "(No response)";
3657
+ setMessages(
3658
+ (prev) => prev.map(
3659
+ (m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: finalContent } : m
3660
+ )
3661
+ );
3662
+ onResponse?.(finalContent);
3663
+ } catch (err) {
3664
+ console.error("Continue error:", err);
3665
+ setMessages(
3666
+ (prev) => prev.map(
3667
+ (m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: `Error: ${err instanceof Error ? err.message : "Unknown error"}` } : m
3668
+ )
3669
+ );
3670
+ } finally {
3671
+ setIsStreaming(false);
3672
+ setCurrentToolCalls([]);
3673
+ }
3674
+ }, [isStreaming, isReady, chatStream, onMessage, onToolCall, onResponse]);
3675
+ react.useEffect(() => {
3676
+ if (!client) return;
3677
+ const unsubMaxTools = client.on("max_tools_reached", (event) => {
3678
+ console.log(`[AUTO_CONTINUE] Max tools reached (${event.toolsExecuted}/${event.maxSteps}), auto-continuing...`);
3679
+ setTimeout(() => {
3680
+ sendContinue();
3681
+ }, 100);
3682
+ });
3683
+ const unsubTimeout = client.on("timeout", (event) => {
3684
+ console.log(`[AUTO_CONTINUE] Timeout: ${event.message}, auto-continuing...`);
3685
+ setTimeout(() => {
3686
+ sendContinue();
3687
+ }, 100);
3688
+ });
3689
+ return () => {
3690
+ unsubMaxTools();
3691
+ unsubTimeout();
3692
+ };
3693
+ }, [client, sendContinue]);
3586
3694
  const sendMessage = react.useCallback(async () => {
3587
3695
  const content = inputValue.trim();
3588
3696
  if (!content || isStreaming || !isReady) return;
@@ -3679,7 +3787,7 @@ function HustleChat({
3679
3787
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3680
3788
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: animations }),
3681
3789
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: styles.container, children: [
3682
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.header, children: [
3790
+ !hideHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.header, children: [
3683
3791
  /* @__PURE__ */ jsxRuntime.jsx("h2", { style: styles.headerTitle, children: "Chat" }),
3684
3792
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.headerActions, children: [
3685
3793
  selectedModel && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: tokens.typography.fontSizeSm, color: tokens.colors.textSecondary }, children: selectedModel.split("/").pop() }),
@@ -3854,7 +3962,7 @@ function HustleChat({
3854
3962
  ] })
3855
3963
  ] })
3856
3964
  ] }) }),
3857
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.messagesArea, children: [
3965
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hustle-hide-scrollbar", style: styles.messagesArea, children: [
3858
3966
  messages.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.messagesEmpty, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: getPlaceholderMessage() }) }),
3859
3967
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.messagesContainer, children: messages.map((message) => /* @__PURE__ */ jsxRuntime.jsx(
3860
3968
  MessageBubble,
@@ -3981,8 +4089,346 @@ function SettingsIcon() {
3981
4089
  function AttachIcon() {
3982
4090
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) });
3983
4091
  }
4092
+ var sizeConfigs = {
4093
+ sm: { width: "320px", height: "400px" },
4094
+ md: { width: "380px", height: "520px" },
4095
+ lg: { width: "420px", height: "600px" },
4096
+ xl: { width: "480px", height: "700px" },
4097
+ full: { width: "100vw", height: "100vh" }
4098
+ };
4099
+ var widgetStyles = {
4100
+ // Container for absolute positioning
4101
+ container: {
4102
+ position: "fixed",
4103
+ zIndex: 9999,
4104
+ fontFamily: tokens.typography.fontFamily
4105
+ },
4106
+ // Launcher button
4107
+ launcher: {
4108
+ width: "56px",
4109
+ height: "56px",
4110
+ borderRadius: tokens.radius.full,
4111
+ background: `linear-gradient(135deg, ${tokens.colors.accentPrimary} 0%, #2d7dd2 100%)`,
4112
+ border: "none",
4113
+ cursor: "pointer",
4114
+ display: "flex",
4115
+ alignItems: "center",
4116
+ justifyContent: "center",
4117
+ boxShadow: `0 4px 20px rgba(76, 154, 255, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3)`,
4118
+ transition: `all ${tokens.transitions.normal}`,
4119
+ color: tokens.colors.textInverse
4120
+ },
4121
+ launcherHover: {
4122
+ transform: "scale(1.05)",
4123
+ boxShadow: `0 6px 24px rgba(76, 154, 255, 0.5), 0 4px 12px rgba(0, 0, 0, 0.4)`
4124
+ },
4125
+ // Badge
4126
+ badge: {
4127
+ position: "absolute",
4128
+ top: "-4px",
4129
+ right: "-4px",
4130
+ minWidth: "20px",
4131
+ height: "20px",
4132
+ borderRadius: tokens.radius.pill,
4133
+ background: tokens.colors.accentError,
4134
+ color: tokens.colors.textInverse,
4135
+ fontSize: tokens.typography.fontSizeXs,
4136
+ fontWeight: tokens.typography.fontWeightSemibold,
4137
+ display: "flex",
4138
+ alignItems: "center",
4139
+ justifyContent: "center",
4140
+ padding: "0 6px",
4141
+ border: `2px solid ${tokens.colors.bgPrimary}`
4142
+ },
4143
+ // Chat panel
4144
+ panel: {
4145
+ position: "absolute",
4146
+ borderRadius: tokens.radius.xl,
4147
+ background: tokens.colors.bgSecondary,
4148
+ border: `1px solid ${tokens.colors.borderPrimary}`,
4149
+ boxShadow: `0 16px 48px rgba(0, 0, 0, 0.5)`,
4150
+ overflow: "hidden",
4151
+ display: "flex",
4152
+ flexDirection: "column",
4153
+ transition: `all ${tokens.transitions.slow}`
4154
+ },
4155
+ panelHidden: {
4156
+ opacity: 0,
4157
+ transform: "scale(0.95) translateY(10px)",
4158
+ pointerEvents: "none"
4159
+ },
4160
+ panelVisible: {
4161
+ opacity: 1,
4162
+ transform: "scale(1) translateY(0)"
4163
+ },
4164
+ // Full screen mode overrides
4165
+ panelFull: {
4166
+ position: "fixed",
4167
+ top: 0,
4168
+ left: 0,
4169
+ right: 0,
4170
+ bottom: 0,
4171
+ borderRadius: 0,
4172
+ width: "100vw",
4173
+ height: "100vh"
4174
+ },
4175
+ // Close button in panel header
4176
+ closeBtn: {
4177
+ width: "32px",
4178
+ height: "32px",
4179
+ borderRadius: tokens.radius.md,
4180
+ background: "transparent",
4181
+ border: "none",
4182
+ color: tokens.colors.textTertiary,
4183
+ cursor: "pointer",
4184
+ display: "flex",
4185
+ alignItems: "center",
4186
+ justifyContent: "center",
4187
+ transition: `all ${tokens.transitions.fast}`
4188
+ },
4189
+ closeBtnHover: {
4190
+ background: tokens.colors.bgTertiary,
4191
+ color: tokens.colors.textPrimary
4192
+ }
4193
+ };
4194
+ function ChatIcon() {
4195
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
4196
+ }
4197
+ function CloseIcon() {
4198
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4199
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4200
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4201
+ ] });
4202
+ }
4203
+ function MinimizeIcon() {
4204
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4205
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "4 14 10 14 10 20" }),
4206
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 10 14 10 14 4" }),
4207
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
4208
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4209
+ ] });
4210
+ }
4211
+ function HustleChatWidget({
4212
+ config = {},
4213
+ ...chatProps
4214
+ }) {
4215
+ const {
4216
+ position = "bottom-right",
4217
+ size = "md",
4218
+ title = "Chat",
4219
+ defaultOpen = false,
4220
+ launcherIcon,
4221
+ offset = { x: 24, y: 24 },
4222
+ zIndex = 9999,
4223
+ showBadge = false,
4224
+ badgeContent,
4225
+ launcherStyle,
4226
+ panelStyle,
4227
+ onOpen,
4228
+ onClose,
4229
+ storageKey = "hustle-widget-open"
4230
+ } = config;
4231
+ const [isOpen, setIsOpen] = react.useState(false);
4232
+ const [isHovered, setIsHovered] = react.useState(false);
4233
+ const [closeHovered, setCloseHovered] = react.useState(false);
4234
+ const [mounted, setMounted] = react.useState(false);
4235
+ react.useEffect(() => {
4236
+ setMounted(true);
4237
+ if (storageKey && typeof window !== "undefined") {
4238
+ const stored = localStorage.getItem(storageKey);
4239
+ if (stored !== null) {
4240
+ setIsOpen(stored === "true");
4241
+ } else {
4242
+ setIsOpen(defaultOpen);
4243
+ }
4244
+ } else {
4245
+ setIsOpen(defaultOpen);
4246
+ }
4247
+ }, [defaultOpen, storageKey]);
4248
+ react.useEffect(() => {
4249
+ if (!mounted) return;
4250
+ if (storageKey && typeof window !== "undefined") {
4251
+ localStorage.setItem(storageKey, String(isOpen));
4252
+ }
4253
+ }, [isOpen, storageKey, mounted]);
4254
+ const toggle = react.useCallback(() => {
4255
+ setIsOpen((prev) => {
4256
+ const next = !prev;
4257
+ if (next) {
4258
+ onOpen?.();
4259
+ } else {
4260
+ onClose?.();
4261
+ }
4262
+ return next;
4263
+ });
4264
+ }, [onOpen, onClose]);
4265
+ const positionStyles = getPositionStyles(position, offset);
4266
+ const sizeConfig = sizeConfigs[size];
4267
+ if (!mounted) {
4268
+ return null;
4269
+ }
4270
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4271
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: animations }),
4272
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
4273
+ @keyframes hustle-widget-bounce {
4274
+ 0%, 100% { transform: translateY(0); }
4275
+ 50% { transform: translateY(-4px); }
4276
+ }
4277
+ ` }),
4278
+ /* @__PURE__ */ jsxRuntime.jsxs(
4279
+ "div",
4280
+ {
4281
+ style: {
4282
+ ...widgetStyles.container,
4283
+ ...positionStyles.container,
4284
+ zIndex
4285
+ },
4286
+ children: [
4287
+ /* @__PURE__ */ jsxRuntime.jsxs(
4288
+ "div",
4289
+ {
4290
+ style: {
4291
+ ...widgetStyles.panel,
4292
+ ...positionStyles.panel,
4293
+ ...size === "full" ? widgetStyles.panelFull : {
4294
+ width: sizeConfig.width,
4295
+ height: sizeConfig.height
4296
+ },
4297
+ ...isOpen ? widgetStyles.panelVisible : widgetStyles.panelHidden,
4298
+ ...panelStyle
4299
+ },
4300
+ children: [
4301
+ /* @__PURE__ */ jsxRuntime.jsxs(
4302
+ "div",
4303
+ {
4304
+ style: {
4305
+ display: "flex",
4306
+ alignItems: "center",
4307
+ justifyContent: "space-between",
4308
+ padding: `${tokens.spacing.md} ${tokens.spacing.lg}`,
4309
+ background: tokens.colors.bgPrimary,
4310
+ borderBottom: `1px solid ${tokens.colors.borderPrimary}`,
4311
+ borderRadius: `${tokens.radius.xl} ${tokens.radius.xl} 0 0`,
4312
+ flexShrink: 0
4313
+ },
4314
+ children: [
4315
+ /* @__PURE__ */ jsxRuntime.jsx(
4316
+ "span",
4317
+ {
4318
+ style: {
4319
+ fontWeight: tokens.typography.fontWeightSemibold,
4320
+ color: tokens.colors.textPrimary,
4321
+ fontSize: tokens.typography.fontSizeMd
4322
+ },
4323
+ children: title
4324
+ }
4325
+ ),
4326
+ /* @__PURE__ */ jsxRuntime.jsx(
4327
+ "button",
4328
+ {
4329
+ onClick: toggle,
4330
+ onMouseEnter: () => setCloseHovered(true),
4331
+ onMouseLeave: () => setCloseHovered(false),
4332
+ style: {
4333
+ ...widgetStyles.closeBtn,
4334
+ ...closeHovered ? widgetStyles.closeBtnHover : {}
4335
+ },
4336
+ title: "Close chat",
4337
+ children: size === "full" ? /* @__PURE__ */ jsxRuntime.jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
4338
+ }
4339
+ )
4340
+ ]
4341
+ }
4342
+ ),
4343
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(HustleChatInner, { ...chatProps }) })
4344
+ ]
4345
+ }
4346
+ ),
4347
+ (size !== "full" || !isOpen) && /* @__PURE__ */ jsxRuntime.jsxs(
4348
+ "button",
4349
+ {
4350
+ onClick: toggle,
4351
+ onMouseEnter: () => setIsHovered(true),
4352
+ onMouseLeave: () => setIsHovered(false),
4353
+ style: {
4354
+ ...widgetStyles.launcher,
4355
+ ...isHovered ? widgetStyles.launcherHover : {},
4356
+ ...positionStyles.launcher,
4357
+ ...launcherStyle,
4358
+ ...isOpen ? { opacity: 0, pointerEvents: "none" } : {}
4359
+ },
4360
+ title: isOpen ? "Close chat" : "Open chat",
4361
+ "aria-label": isOpen ? "Close chat" : "Open chat",
4362
+ children: [
4363
+ launcherIcon || /* @__PURE__ */ jsxRuntime.jsx(ChatIcon, {}),
4364
+ showBadge && badgeContent && !isOpen && /* @__PURE__ */ jsxRuntime.jsx("span", { style: widgetStyles.badge, children: badgeContent })
4365
+ ]
4366
+ }
4367
+ )
4368
+ ]
4369
+ }
4370
+ )
4371
+ ] });
4372
+ }
4373
+ function HustleChatInner(props) {
4374
+ return /* @__PURE__ */ jsxRuntime.jsx(HustleChat, { ...props, hideHeader: true });
4375
+ }
4376
+ function getPositionStyles(position, offset, isOpen, size) {
4377
+ const panelGap = 16;
4378
+ switch (position) {
4379
+ case "bottom-right":
4380
+ return {
4381
+ container: {
4382
+ bottom: `${offset.y}px`,
4383
+ right: `${offset.x}px`
4384
+ },
4385
+ launcher: {},
4386
+ panel: {
4387
+ bottom: `${56 + panelGap}px`,
4388
+ right: 0
4389
+ }
4390
+ };
4391
+ case "bottom-left":
4392
+ return {
4393
+ container: {
4394
+ bottom: `${offset.y}px`,
4395
+ left: `${offset.x}px`
4396
+ },
4397
+ launcher: {},
4398
+ panel: {
4399
+ bottom: `${56 + panelGap}px`,
4400
+ left: 0
4401
+ }
4402
+ };
4403
+ case "top-right":
4404
+ return {
4405
+ container: {
4406
+ top: `${offset.y}px`,
4407
+ right: `${offset.x}px`
4408
+ },
4409
+ launcher: {},
4410
+ panel: {
4411
+ top: `${56 + panelGap}px`,
4412
+ right: 0
4413
+ }
4414
+ };
4415
+ case "top-left":
4416
+ return {
4417
+ container: {
4418
+ top: `${offset.y}px`,
4419
+ left: `${offset.x}px`
4420
+ },
4421
+ launcher: {},
4422
+ panel: {
4423
+ top: `${56 + panelGap}px`,
4424
+ left: 0
4425
+ }
4426
+ };
4427
+ }
4428
+ }
3984
4429
 
3985
4430
  exports.HustleChat = HustleChat;
4431
+ exports.HustleChatWidget = HustleChatWidget;
3986
4432
  exports.MarkdownContent = MarkdownContent;
3987
4433
  //# sourceMappingURL=index.cjs.map
3988
4434
  //# sourceMappingURL=index.cjs.map