@emblemvault/hustle-react 1.5.0 → 1.5.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.
@@ -13,6 +13,10 @@ interface HustleChatProps {
13
13
  placeholder?: string;
14
14
  /** Show settings button (opens modal with model selector, prompts, etc.) */
15
15
  showSettings?: boolean;
16
+ /** Controlled mode: external control of settings panel visibility */
17
+ settingsPanelOpen?: boolean;
18
+ /** Controlled mode: callback when settings panel visibility changes */
19
+ onSettingsPanelOpenChange?: (open: boolean) => void;
16
20
  /** Show debug info */
17
21
  showDebug?: boolean;
18
22
  /** Hide the header (useful when embedding in a widget with its own header) */
@@ -45,7 +49,7 @@ interface HustleChatProps {
45
49
  * />
46
50
  * ```
47
51
  */
48
- declare function HustleChat({ className, placeholder, showSettings, showDebug, hideHeader, initialSystemPrompt, enableSpeechToText, onMessage, onToolCall, onResponse, }: HustleChatProps): react_jsx_runtime.JSX.Element;
52
+ declare function HustleChat({ className, placeholder, showSettings, settingsPanelOpen: controlledSettingsPanelOpen, onSettingsPanelOpenChange, showDebug, hideHeader, initialSystemPrompt, enableSpeechToText, onMessage, onToolCall, onResponse, }: HustleChatProps): react_jsx_runtime.JSX.Element;
49
53
 
50
54
  /**
51
55
  * Position options for the widget
@@ -13,6 +13,10 @@ interface HustleChatProps {
13
13
  placeholder?: string;
14
14
  /** Show settings button (opens modal with model selector, prompts, etc.) */
15
15
  showSettings?: boolean;
16
+ /** Controlled mode: external control of settings panel visibility */
17
+ settingsPanelOpen?: boolean;
18
+ /** Controlled mode: callback when settings panel visibility changes */
19
+ onSettingsPanelOpenChange?: (open: boolean) => void;
16
20
  /** Show debug info */
17
21
  showDebug?: boolean;
18
22
  /** Hide the header (useful when embedding in a widget with its own header) */
@@ -45,7 +49,7 @@ interface HustleChatProps {
45
49
  * />
46
50
  * ```
47
51
  */
48
- declare function HustleChat({ className, placeholder, showSettings, showDebug, hideHeader, initialSystemPrompt, enableSpeechToText, onMessage, onToolCall, onResponse, }: HustleChatProps): react_jsx_runtime.JSX.Element;
52
+ declare function HustleChat({ className, placeholder, showSettings, settingsPanelOpen: controlledSettingsPanelOpen, onSettingsPanelOpenChange, showDebug, hideHeader, initialSystemPrompt, enableSpeechToText, onMessage, onToolCall, onResponse, }: HustleChatProps): react_jsx_runtime.JSX.Element;
49
53
 
50
54
  /**
51
55
  * Position options for the widget
@@ -3660,6 +3660,8 @@ function HustleChat({
3660
3660
  className = "",
3661
3661
  placeholder = "Type a message...",
3662
3662
  showSettings = false,
3663
+ settingsPanelOpen: controlledSettingsPanelOpen,
3664
+ onSettingsPanelOpenChange,
3663
3665
  showDebug = false,
3664
3666
  hideHeader = false,
3665
3667
  initialSystemPrompt = "",
@@ -3699,7 +3701,17 @@ function HustleChat({
3699
3701
  const [isStreaming, setIsStreaming] = useState(false);
3700
3702
  const [attachments, setAttachments] = useState([]);
3701
3703
  const [currentToolCalls, setCurrentToolCalls] = useState([]);
3702
- const [showSettingsPanel, setShowSettingsPanel] = useState(false);
3704
+ const [internalShowSettingsPanel, setInternalShowSettingsPanel] = useState(false);
3705
+ const isSettingsControlled = controlledSettingsPanelOpen !== void 0;
3706
+ const showSettingsPanel = isSettingsControlled ? controlledSettingsPanelOpen : internalShowSettingsPanel;
3707
+ const setShowSettingsPanel = (open) => {
3708
+ const newValue = typeof open === "function" ? open(showSettingsPanel) : open;
3709
+ if (isSettingsControlled) {
3710
+ onSettingsPanelOpenChange?.(newValue);
3711
+ } else {
3712
+ setInternalShowSettingsPanel(newValue);
3713
+ }
3714
+ };
3703
3715
  const [speechToTextEnabled, setSpeechToTextEnabled] = useState(() => {
3704
3716
  if (typeof window !== "undefined") {
3705
3717
  const stored = localStorage.getItem(`hustle-stt-enabled-${instanceId}`);
@@ -4572,6 +4584,12 @@ function CloseIcon() {
4572
4584
  /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4573
4585
  ] });
4574
4586
  }
4587
+ function SettingsIcon2() {
4588
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
4589
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" }),
4590
+ /* @__PURE__ */ jsx("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" })
4591
+ ] });
4592
+ }
4575
4593
  function ExpandIcon() {
4576
4594
  return /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4577
4595
  /* @__PURE__ */ jsx("polyline", { points: "15 3 21 3 21 9" }),
@@ -4620,6 +4638,8 @@ function HustleChatWidget({
4620
4638
  const [isHovered, setIsHovered] = useState(false);
4621
4639
  const [closeHovered, setCloseHovered] = useState(false);
4622
4640
  const [mounted, setMounted] = useState(false);
4641
+ const [settingsOpen, setSettingsOpen] = useState(false);
4642
+ const { showSettings, ...restChatProps } = chatProps;
4623
4643
  useEffect(() => {
4624
4644
  setMounted(true);
4625
4645
  if (storageKey && typeof window !== "undefined") {
@@ -4729,6 +4749,18 @@ function HustleChatWidget({
4729
4749
  ] })
4730
4750
  ] }),
4731
4751
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: tokens.spacing.xs }, children: [
4752
+ showSettings && /* @__PURE__ */ jsx(
4753
+ "button",
4754
+ {
4755
+ onClick: () => setSettingsOpen(!settingsOpen),
4756
+ style: {
4757
+ ...widgetStyles.closeBtn,
4758
+ ...settingsOpen ? { background: tokens.colors.bgSecondary } : {}
4759
+ },
4760
+ title: "Settings",
4761
+ children: /* @__PURE__ */ jsx(SettingsIcon2, {})
4762
+ }
4763
+ ),
4732
4764
  size === "sideDock" && /* @__PURE__ */ jsx(
4733
4765
  "button",
4734
4766
  {
@@ -4763,7 +4795,15 @@ function HustleChatWidget({
4763
4795
  ]
4764
4796
  }
4765
4797
  ),
4766
- /* @__PURE__ */ jsx("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsx(HustleChatInner, { ...chatProps }) })
4798
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsx(
4799
+ HustleChatInner,
4800
+ {
4801
+ ...restChatProps,
4802
+ showSettings,
4803
+ settingsPanelOpen: settingsOpen,
4804
+ onSettingsPanelOpenChange: setSettingsOpen
4805
+ }
4806
+ ) })
4767
4807
  ]
4768
4808
  }
4769
4809
  ),