forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathframework-tabs.tsx
More file actions
114 lines (107 loc) · 3.56 KB
/
Copy pathframework-tabs.tsx
File metadata and controls
114 lines (107 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// <FrameworkTabs> — tabbed view of the same region rendered against
// multiple integration frameworks' cells.
//
// Usage:
// <FrameworkTabs
// frameworks={["langgraph-python", "mastra", "crewai-crews"]}
// cell="agentic-chat"
// region="provider-setup"
// />
//
// Each tab runs <Snippet framework=... cell=... region=...>. When a
// framework is missing that region/cell the Snippet's built-in warning
// box surfaces inline, so authors get a clear signal to tag the missing
// region in the corresponding cell.
//
// FrameworkTabs is intentionally **client-side** (uses useState for the
// active tab). The inner <Snippet> is a server component — Next.js will
// transport its rendered HTML across the boundary, which keeps syntax
// highlighting sharp and avoids duplicating the highlight.js dependency
// in the client bundle.
"use client";
import React, { useState } from "react";
interface FrameworkTabsProps {
frameworks: string[];
cell: string;
region: string;
/** Render an alternative label for each framework (e.g. pretty names). */
labels?: Record<string, string>;
/** Pre-rendered <Snippet> content, keyed by framework slug. Populated by
* the parent MDX renderer which walks the `frameworks` list and emits
* a Snippet per framework on the server side. */
children: React.ReactNode;
}
export function FrameworkTabs({
frameworks,
labels,
children,
}: FrameworkTabsProps) {
const [active, setActive] = useState<string>(frameworks[0] ?? "");
// children should be an array of <div data-framework="..."> wrappers.
// We filter + render the active one. This keeps all snippets rendered
// on the server (good: syntax highlighting) and client only swaps.
const wrapped = React.Children.toArray(children);
const displayLabel = (slug: string) =>
labels?.[slug] ??
slug
.split("-")
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
.join(" ");
return (
<div
style={{
margin: "1rem 0 1.25rem 0",
borderRadius: "0.5rem",
border: "1px solid var(--border)",
overflow: "hidden",
background: "var(--bg-surface)",
}}
>
<div
role="tablist"
style={{
display: "flex",
borderBottom: "1px solid var(--border)",
background: "var(--bg-elevated)",
padding: "0.375rem 0.5rem 0 0.5rem",
gap: "0.25rem",
flexWrap: "wrap",
}}
>
{frameworks.map((fw) => {
const isActive = fw === active;
return (
<button
key={fw}
role="tab"
aria-selected={isActive}
onClick={() => setActive(fw)}
style={{
padding: "0.5rem 0.875rem",
fontSize: "0.8125rem",
fontWeight: isActive ? 600 : 500,
color: isActive ? "var(--text)" : "var(--text-muted)",
background: isActive ? "var(--bg-surface)" : "transparent",
borderRadius: "0.375rem 0.375rem 0 0",
border: "none",
borderBottom: isActive
? "2px solid var(--accent)"
: "2px solid transparent",
cursor: "pointer",
}}
>
{displayLabel(fw)}
</button>
);
})}
</div>
<div>
{wrapped.map((child, i) => {
const fw = frameworks[i];
if (fw !== active) return null;
return <React.Fragment key={fw}>{child}</React.Fragment>;
})}
</div>
</div>
);
}