Skip to content

Commit 28a803a

Browse files
committed
Add support for fe_/be_ language prefixes in CodeSnippet
- Add 'fe' and 'be' to SDKType union for frontend/backend code blocks - Update stripSdkType() to handle fe_ and be_ prefixes - Add findCodeElement helper to handle array children (fixes code extraction when pre element has multiple children) - Add showFixedLanguageLabel to display read-only language indicator when code block is controlled by external selector (fixed=true) These changes support dual language selection in documentation, allowing separate client and agent language selectors for AI Transport guides.
1 parent 2a3d121 commit 28a803a

File tree

2 files changed

+69
-14
lines changed

2 files changed

+69
-14
lines changed

src/core/CodeSnippet.tsx

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import CopyButton from "./CodeSnippet/CopyButton";
1818
import SegmentedControl from "./SegmentedControl";
1919

2020
// Define SDK type
21-
export type SDKType = "realtime" | "rest" | null;
21+
export type SDKType = "realtime" | "rest" | "fe" | "be" | null;
2222

2323
// Define API key types
2424
export type ApiKeysItem = {
@@ -169,6 +169,21 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
169169
[],
170170
);
171171

172+
// Helper to find the code element within pre's children (handles both single element and array)
173+
const findCodeElement = useCallback(
174+
(preChildren: React.ReactNode): React.ReactElement | null => {
175+
if (isValidElement(preChildren)) {
176+
return preChildren;
177+
}
178+
if (Array.isArray(preChildren)) {
179+
const codeEl = preChildren.find((c) => isValidElement(c));
180+
return codeEl && isValidElement(codeEl) ? codeEl : null;
181+
}
182+
return null;
183+
},
184+
[],
185+
);
186+
172187
const { codeData, languages, sdkTypes, isSinglePlainCommand } =
173188
useMemo(() => {
174189
const childrenArray = Children.toArray(children);
@@ -178,20 +193,17 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
178193

179194
const isSinglePlainCommand =
180195
childrenArray.length === 1 &&
181-
["language-shell", "language-text"].some(
182-
(lang) =>
183-
isValidElement(childrenArray[0]) &&
184-
isValidElement(childrenArray[0].props.children) &&
185-
childrenArray[0].props.children.props.className?.includes(lang),
186-
);
196+
["language-shell", "language-text"].some((lang) => {
197+
if (!isValidElement(childrenArray[0])) return false;
198+
const codeEl = findCodeElement(childrenArray[0].props.children);
199+
return codeEl?.props.className?.includes(lang);
200+
});
187201

188202
childrenArray.forEach((child) => {
189203
if (!isValidElement(child)) return;
190204

191205
const preElement = child;
192-
const codeElement = isValidElement(preElement.props.children)
193-
? preElement.props.children
194-
: null;
206+
const codeElement = findCodeElement(preElement.props.children);
195207

196208
if (!codeElement) return;
197209

@@ -203,6 +215,10 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
203215
sdkTypes.add("realtime");
204216
} else if (codeLanguage.startsWith("rest_")) {
205217
sdkTypes.add("rest");
218+
} else if (codeLanguage.startsWith("fe_")) {
219+
sdkTypes.add("fe");
220+
} else if (codeLanguage.startsWith("be_")) {
221+
sdkTypes.add("be");
206222
}
207223

208224
if (!languages.includes(codeLanguage)) {
@@ -219,7 +235,7 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
219235
sdkTypes,
220236
isSinglePlainCommand,
221237
};
222-
}, [children, extractLanguageFromCode]);
238+
}, [children, extractLanguageFromCode, findCodeElement]);
223239

224240
const resolvedSdk: SDKType = useMemo(() => {
225241
if (sdkTypes.size === 1 && sdk && !sdkTypes.has(sdk)) {
@@ -228,7 +244,8 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
228244
return sdk ?? null;
229245
}, [sdk, sdkTypes]);
230246

231-
const showSDKSelector = sdkTypes.size > 0;
247+
// Only show SDK selector for realtime/rest types, not for fe/be (which are controlled by page-level selector)
248+
const showSDKSelector = sdkTypes.has("realtime") || sdkTypes.has("rest");
232249

233250
const filteredLanguages = useMemo(() => {
234251
const filtered =
@@ -256,6 +273,19 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
256273
}, [resolvedSdk, showSDKSelector, languages, languageOrdering]);
257274

258275
const activeLanguage = useMemo(() => {
276+
// For fe/be SDK types (controlled by page-level selector), construct the full language
277+
if (resolvedSdk === "fe" || resolvedSdk === "be") {
278+
const fullLang = `${resolvedSdk}_${lang}`;
279+
// Verify this language exists in available languages
280+
if (languages.includes(fullLang)) {
281+
return fullLang;
282+
}
283+
// Fall back to first language with this prefix
284+
const prefixMatch = languages.find((l) => l.startsWith(`${resolvedSdk}_`));
285+
if (prefixMatch) return prefixMatch;
286+
}
287+
288+
// For realtime/rest SDK types
259289
if (resolvedSdk && sdkTypes.has(resolvedSdk)) {
260290
return `${resolvedSdk}_${lang}`;
261291
}
@@ -399,6 +429,8 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
399429

400430
const showLanguageSelector = !fixed && filteredLanguages.length > 0;
401431
const showFullSelector = filteredLanguages.length > 1;
432+
// Show a read-only language label when fixed (controlled by external selector)
433+
const showFixedLanguageLabel = fixed && activeLanguage;
402434

403435
const renderContent = useMemo(() => {
404436
if (!activeLanguage) return null;
@@ -501,6 +533,26 @@ const CodeSnippet: React.FC<CodeSnippetProps> = ({
501533
</div>
502534
)}
503535

536+
{showFixedLanguageLabel && (
537+
<div
538+
className={cn(
539+
"border-b border-neutral-300 dark:border-neutral-1000 h-[2.125rem] inline-flex items-center px-3 w-full",
540+
{ "rounded-t-lg": !headerRow },
541+
)}
542+
>
543+
<div className="inline-flex items-center">
544+
<Icon
545+
name={getLanguageInfo(activeLanguage).icon}
546+
size="16px"
547+
additionalCSS="mr-2"
548+
/>
549+
<span className="ui-text-label4 font-semibold text-neutral-800 dark:text-neutral-500 select-none">
550+
{getLanguageInfo(activeLanguage).label}
551+
</span>
552+
</div>
553+
</div>
554+
)}
555+
504556
{showLanguageSelector &&
505557
(showFullSelector ? (
506558
<LanguageSelector

src/core/CodeSnippet/languages.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,11 @@ const languages: LanguageMap = {
133133
};
134134

135135
export const stripSdkType = (lang: string) => {
136-
if (lang.startsWith("realtime_") || lang.startsWith("rest_")) {
137-
return lang.split("_").slice(1).join("_");
136+
const prefixes = ["realtime_", "rest_", "fe_", "be_"];
137+
for (const prefix of prefixes) {
138+
if (lang.startsWith(prefix)) {
139+
return lang.slice(prefix.length);
140+
}
138141
}
139142
return lang;
140143
};

0 commit comments

Comments
 (0)