Skip to content

Commit 2632ba6

Browse files
authored
Improve input and implement popup (#19)
1 parent 4cee713 commit 2632ba6

File tree

14 files changed

+1728
-631
lines changed

14 files changed

+1728
-631
lines changed

apps/react/demo/src/app/page.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
useConfigureSuggestions,
1010
} from "@copilotkitnext/react";
1111
import { z } from "zod";
12+
import { useMemo } from "react";
1213

1314
// Disable static optimization for this page
1415
export const dynamic = "force-dynamic";
@@ -74,5 +75,34 @@ function Chat() {
7475
return `Hello ${name}`;
7576
},
7677
});
77-
return <CopilotChat />;
78+
const toolsMenu = useMemo(
79+
() => [
80+
{
81+
label: "Say hi to CopilotKit",
82+
action: () => {
83+
const textarea = document.querySelector<HTMLTextAreaElement>("textarea[placeholder='Type a message...']");
84+
if (!textarea) {
85+
return;
86+
}
87+
88+
const greeting = "Hello Copilot! 👋 Could you help me with something?";
89+
90+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value")?.set;
91+
nativeInputValueSetter?.call(textarea, greeting);
92+
textarea.dispatchEvent(new Event("input", { bubbles: true }));
93+
textarea.focus();
94+
},
95+
},
96+
"-",
97+
{
98+
label: "Open CopilotKit Docs",
99+
action: () => {
100+
window.open("https://docs.copilotkit.ai", "_blank", "noopener,noreferrer");
101+
},
102+
},
103+
],
104+
[],
105+
);
106+
107+
return <CopilotChat inputProps={{ toolsMenu }} />;
78108
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
"use client";
2+
3+
import {
4+
CopilotKitProvider,
5+
CopilotPopup,
6+
defineToolCallRenderer,
7+
useConfigureSuggestions,
8+
useFrontendTool,
9+
} from "@copilotkitnext/react";
10+
import { z } from "zod";
11+
12+
export const dynamic = "force-dynamic";
13+
14+
export default function PopupDemoPage() {
15+
const wildcardRenderer = defineToolCallRenderer({
16+
name: "*",
17+
render: ({ name, args, status }) => (
18+
<div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-700 shadow-sm">
19+
<strong className="block text-slate-900">Unknown Tool: {name}</strong>
20+
<pre className="mt-2 whitespace-pre-wrap text-xs text-slate-600">
21+
Status: {status}
22+
{args && "\nArguments: " + JSON.stringify(args, null, 2)}
23+
</pre>
24+
</div>
25+
),
26+
});
27+
28+
return (
29+
<CopilotKitProvider runtimeUrl="/api/copilotkit" renderToolCalls={[wildcardRenderer]} showDevConsole="auto">
30+
<PopupLayout />
31+
</CopilotKitProvider>
32+
);
33+
}
34+
35+
function PopupLayout() {
36+
return (
37+
<div className="relative min-h-screen bg-gradient-to-br from-slate-100 via-white to-slate-200">
38+
<main className="mx-auto flex w-full max-w-5xl flex-col gap-10 px-6 py-12 pb-40">
39+
<section className="space-y-4">
40+
<span className="inline-flex items-center rounded-full bg-slate-900/10 px-3 py-1 text-xs font-medium text-slate-700">
41+
Overlay Chat Demo
42+
</span>
43+
<h1 className="text-3xl font-semibold tracking-tight text-slate-900">Copilot Popup Demo</h1>
44+
<p className="max-w-2xl text-slate-600">
45+
This page mounts the chat as a floating popup anchored to the bottom-right corner. The popup animates in and
46+
out, and leaves the rest of the interface interactive. Try clicking outside the popup or using the toggle
47+
button to open and close the assistant.
48+
</p>
49+
</section>
50+
51+
<section className="grid gap-6 md:grid-cols-2">
52+
{Array.from({ length: 6 }).map((_, index) => (
53+
<article
54+
key={index}
55+
className="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm transition hover:shadow-md"
56+
>
57+
<h2 className="text-lg font-medium text-slate-900">In-Flow Task {index + 1}</h2>
58+
<p className="mt-2 text-sm text-slate-600">
59+
Use the popup assistant to draft updates, summarize status, or trigger custom tools without losing
60+
context.
61+
</p>
62+
</article>
63+
))}
64+
</section>
65+
66+
<section className="rounded-2xl border border-dashed border-slate-300 bg-white/70 p-6 shadow-inner">
67+
<h3 className="text-base font-semibold text-slate-900">How the popup behaves</h3>
68+
<ul className="mt-3 space-y-2 text-sm text-slate-600">
69+
<li>• Appears with a bottom-right scale and translate animation.</li>
70+
<li>• Leaves the page scrollable and interactive—no backdrop overlay.</li>
71+
<li>• Supports closing when you click outside (enabled in this demo).</li>
72+
<li>• Reuses all chat slots, tools, and suggestion hooks from the core chat.</li>
73+
</ul>
74+
</section>
75+
</main>
76+
77+
<PopupChat />
78+
</div>
79+
);
80+
}
81+
82+
function PopupChat() {
83+
useConfigureSuggestions({
84+
instructions: "Suggest short summaries or next actions based on the dashboard content",
85+
});
86+
87+
useFrontendTool({
88+
name: "notify",
89+
parameters: z.object({
90+
message: z.string(),
91+
}),
92+
handler: async ({ message }) => {
93+
alert(`Notification: ${message}`);
94+
return `Displayed notification: ${message}`;
95+
},
96+
});
97+
98+
return <CopilotPopup defaultOpen={true} clickOutsideToClose={true} />;
99+
}

0 commit comments

Comments
 (0)