Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion website/build/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions website/lib/mdx-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BlockQuote } from "@/components/mdx/block-quote";
import { CodeBlock } from "@/components/mdx/code-block";
import {
Code,
ExampleCode,
ExampleTabs,
Implementation,
Schema,
Expand All @@ -26,6 +27,7 @@ const mdxComponents = {
blockquote: BlockQuote,
ExampleTabs,
Code,
ExampleCode,
Implementation,
Schema,
PackageInstallation,
Expand All @@ -47,6 +49,7 @@ const mdxComponents = {
// tag names per the HTML spec, so <Video> becomes <video>, etc.
video: Video,
exampletabs: ExampleTabs,
examplecode: ExampleCode,
implementation: Implementation,
schema: Schema,
packageinstallation: PackageInstallation,
Expand Down
16 changes: 15 additions & 1 deletion website/lib/mdx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,18 @@ function replaceDottedComponents(source: string): string {
return result;
}

// Rename <Code> to <ExampleCode> to avoid conflict with the HTML <code> element.
// When using format:"md" with rehype-raw, tag names are lowercased per the HTML spec,
// so <Code> becomes <code>. Since <code> is a standard inline HTML element, the parser
// cannot nest block content inside it, causing tab content to spill out.
function renameCodeComponent(source: string): string {
return source
.replaceAll("<Code>", "<ExampleCode>")
.replaceAll("</Code>", "</ExampleCode>")
.replaceAll("<Code ", "<ExampleCode ")
.replaceAll("<Code/>", "<ExampleCode/>");
}

export function extractHeadings(
source: string
): Array<{ depth: number; value: string }> {
Expand Down Expand Up @@ -373,7 +385,9 @@ function resolveImagePaths(source: string, originPath: string): string {
export async function compileMdxContent(source: string, originPath = "") {
const cleaned = resolveImagePaths(
fixJsxAttributes(
expandSelfClosingTags(replaceDottedComponents(stripImports(source)))
expandSelfClosingTags(
renameCodeComponent(replaceDottedComponents(stripImports(source)))
)
),
originPath
);
Expand Down
41 changes: 36 additions & 5 deletions website/src/components/mdx/example-tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
import React, { FC } from "react";
"use client";

import { List, Panel, Tab, Tabs } from "./tabs";
import React, { FC, useEffect } from "react";
import { usePathname } from "next/navigation";

import { List, Panel, Tab, Tabs, useTabs } from "./tabs";

/**
* Resets the active tab to the default if the current tab is not in the
* allowed set (e.g. "schema" tab hidden on v16 but stored in localStorage).
*/
const ResetDisallowedTab: FC<{ allowed: string[] }> = ({ allowed }) => {
const { activeTab, setActiveTab } = useTabs();

useEffect(() => {
if (!allowed.includes(activeTab)) {
setActiveTab(allowed[0]);
}
}, [activeTab, allowed, setActiveTab]);

return null;
};

export const ExampleTabs: FC = ({ children }) => {
const pathname = usePathname();
const showSchema = !pathname?.includes("/v16/");

return (
<Tabs defaultValue={"implementation"} groupId="code-style">
{!showSchema && (
<ResetDisallowedTab allowed={["implementation", "code"]} />
)}
<List>
<Tab value="implementation">Implementation-first</Tab>
<Tab value="code">Code-first</Tab>
<Tab value="schema">Schema-first</Tab>
{showSchema && <Tab value="schema">Schema-first</Tab>}
</List>
{children}
</Tabs>
Expand All @@ -23,6 +48,12 @@ export const Code: FC = ({ children }) => (
<Panel value="code">{children}</Panel>
);

export const Schema: FC = ({ children }) => (
<Panel value="schema">{children}</Panel>
export const ExampleCode: FC = ({ children }) => (
<Panel value="code">{children}</Panel>
);

export const Schema: FC = ({ children }) => {
const pathname = usePathname();
if (pathname?.includes("/v16/")) return null;
return <Panel value="schema">{children}</Panel>;
};
Loading