@iloveagents/foundry-web-ui 0.1.0 → 0.1.2

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.
@@ -39,6 +39,18 @@ function Trigger() {
39
39
  );
40
40
  }
41
41
 
42
+ function PreserveNavigationTrigger() {
43
+ const handleNewConversation = useNewConversation({
44
+ navigateToChat: false,
45
+ preserveNavigation: true,
46
+ });
47
+ return (
48
+ <button type="button" onClick={handleNewConversation}>
49
+ New Bubble Thread
50
+ </button>
51
+ );
52
+ }
53
+
42
54
  describe("useNewConversation", () => {
43
55
  let container: HTMLDivElement;
44
56
  let root: Root;
@@ -121,4 +133,30 @@ describe("useNewConversation", () => {
121
133
  expect(citationStore.getState().results).toEqual([]);
122
134
  expect(citationStore.getState().handler).toBeNull();
123
135
  });
136
+
137
+ it("can reset the thread without leaving the current page", async () => {
138
+ await act(async () => {
139
+ root.render(
140
+ <MemoryRouter initialEntries={["/spaces/demo"]}>
141
+ <PreserveNavigationTrigger />
142
+ <LocationProbe />
143
+ </MemoryRouter>,
144
+ );
145
+ });
146
+
147
+ const button = container.querySelector("button");
148
+ expect(button).toBeTruthy();
149
+
150
+ await act(async () => {
151
+ button?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
152
+ });
153
+
154
+ expect(container.querySelector('[data-testid="location"]')?.textContent).toBe("/spaces/demo");
155
+ expect(switchToNewThread).toHaveBeenCalledTimes(1);
156
+ expect(resetThread).toHaveBeenCalledTimes(1);
157
+ expect(useAppStore.getState().currentPage).toBe("/spaces/demo");
158
+ expect(useAppStore.getState().navContext.label).toBe("Demo");
159
+ expect(useAppStore.getState().threadActive).toBe(false);
160
+ expect(useAppStore.getState().contextItems).toEqual([]);
161
+ });
124
162
  });
@@ -12,7 +12,7 @@ import { useSidebarStore } from "./sidebar-store.ts";
12
12
  * Shared hook for starting a new conversation.
13
13
  * Used by ChatHeader and Sidebar to keep behavior in sync.
14
14
  */
15
- export function useNewConversation() {
15
+ export function useNewConversation(options?: { navigateToChat?: boolean; preserveNavigation?: boolean }) {
16
16
  const aui = useAui();
17
17
  const { resetThread } = useAGUIAdapter();
18
18
  const navigate = useNavigate();
@@ -22,12 +22,33 @@ export function useNewConversation() {
22
22
  const clearCitations = useStore(citationStore, (s) => s.clear);
23
23
 
24
24
  return useCallback(() => {
25
+ const preserved = options?.preserveNavigation
26
+ ? {
27
+ currentPage: useAppStore.getState().currentPage,
28
+ navContext: useAppStore.getState().navContext,
29
+ }
30
+ : null;
25
31
  closePanel();
26
32
  resetApp();
33
+ if (preserved) {
34
+ useAppStore.setState(preserved);
35
+ }
27
36
  closeMobile();
28
37
  clearCitations();
29
38
  resetThread();
30
39
  aui.threads().switchToNewThread();
31
- navigate("/");
32
- }, [closePanel, resetApp, closeMobile, clearCitations, resetThread, aui, navigate]);
40
+ if (options?.navigateToChat ?? true) {
41
+ navigate("/");
42
+ }
43
+ }, [
44
+ closePanel,
45
+ resetApp,
46
+ options?.preserveNavigation,
47
+ closeMobile,
48
+ clearCitations,
49
+ resetThread,
50
+ aui,
51
+ options?.navigateToChat,
52
+ navigate,
53
+ ]);
33
54
  }
@@ -36,7 +36,11 @@ export const DropdownMenuItem = forwardRef<
36
36
  <DropdownMenuPrimitive.Item
37
37
  ref={ref}
38
38
  className={cn(
39
- "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
39
+ // ``gap-2`` is the same icon-to-text spacing the framework's
40
+ // Button primitive uses, so a ``<lucide-icon /> Label`` pattern
41
+ // inside any menu item renders consistently everywhere without
42
+ // the consumer needing to remember the override.
43
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
40
44
  "transition-colors focus:bg-accent focus:text-accent-foreground",
41
45
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
42
46
  className,