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
92 lines (85 loc) · 3.26 KB
/
Copy pathframework-tabs.tsx
File metadata and controls
92 lines (85 loc) · 3.26 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
// <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 className="shell-docs-radius-surface my-4 mb-5 overflow-hidden border border-[var(--border)] bg-[var(--bg-surface)]">
<div
role="tablist"
className="flex flex-wrap gap-1 border-b border-[var(--border)] bg-[var(--bg-elevated)] px-2 pt-1.5"
>
{frameworks.map((fw) => {
const isActive = fw === active;
return (
<button
key={fw}
role="tab"
aria-selected={isActive}
onClick={() => setActive(fw)}
className={[
"cursor-pointer border-0 border-b-2 px-3.5 py-2 text-[0.8125rem] [border-radius:var(--shell-docs-radius-control)_var(--shell-docs-radius-control)_0_0]",
isActive
? "border-[var(--accent)] bg-[var(--bg-surface)] font-semibold text-[var(--text)]"
: "border-transparent bg-transparent font-medium text-[var(--text-muted)] hover:bg-[var(--accent-dim)] hover:text-[var(--accent)]",
].join(" ")}
>
{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>
);
}