Move JSDoc examples to type-checked .examples.ts files

Extract inline code examples from JSDoc comments into companion
`.examples.ts`/`.examples.tsx` files. Examples are now:

- Type-checked by wrapping them in functions
- Referenced via `{@includeCode ./file.examples.ts#regionName}` tags
- Organized using `//#region` and `//#endregion` markers

This keeps the main source files cleaner while ensuring examples
compile correctly. Updated TypeDoc config with `exampleTag: false`
to support title text on `@example` tags.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jonathan Hefner 2026-01-18 15:11:00 -06:00
commit ad04e89745
10 changed files with 1661 additions and 838 deletions

View file

@ -0,0 +1,26 @@
/**
* Type-checked examples for the React module overview.
*
* @module
*/
import { useApp } from "./index.js";
/**
* Example: Basic React App from module overview.
*/
function index_basicReactApp() {
//#region index_basicReactApp
function MyApp() {
const { app, isConnected, error } = useApp({
appInfo: { name: "MyApp", version: "1.0.0" },
capabilities: {},
});
if (error) return <div>Error: {error.message}</div>;
if (!isConnected) return <div>Connecting...</div>;
return <div>Connected!</div>;
}
//#endregion index_basicReactApp
}

View file

@ -17,21 +17,7 @@
* @module @modelcontextprotocol/ext-apps/react
*
* @example Basic React App
* ```tsx
* import { useApp } from '@modelcontextprotocol/ext-apps/react';
*
* function MyApp() {
* const { app, isConnected, error } = useApp({
* appInfo: { name: "MyApp", version: "1.0.0" },
* capabilities: {}
* });
*
* if (error) return <div>Error: {error.message}</div>;
* if (!isConnected) return <div>Connecting...</div>;
*
* return <div>Connected!</div>;
* }
* ```
* {@includeCode ./index.examples.tsx#index_basicReactApp}
*/
export * from "./useApp";
export * from "./useAutoResize";

View file

@ -0,0 +1,54 @@
/**
* Type-checked examples for the useApp hook.
*
* @module
*/
import { useApp, McpUiToolInputNotificationSchema } from "./index.js";
/**
* Example: Register a notification handler in onAppCreated.
*/
function useApp_registerHandler() {
//#region useApp_registerHandler
useApp({
appInfo: { name: "MyApp", version: "1.0.0" },
capabilities: {},
onAppCreated: (app) => {
app.setNotificationHandler(
McpUiToolInputNotificationSchema,
(notification) => {
console.log("Tool input:", notification.params.arguments);
},
);
},
});
//#endregion useApp_registerHandler
}
/**
* Example: Basic usage of useApp hook.
*/
function useApp_basicUsage() {
//#region useApp_basicUsage
function MyApp() {
const { app, isConnected, error } = useApp({
appInfo: { name: "MyApp", version: "1.0.0" },
capabilities: {},
onAppCreated: (app) => {
// Register handlers before connection
app.setNotificationHandler(
McpUiToolInputNotificationSchema,
(notification) => {
console.log("Tool input:", notification.params.arguments);
},
);
},
});
if (error) return <div>Error: {error.message}</div>;
if (!isConnected) return <div>Connecting...</div>;
return <div>Connected!</div>;
}
//#endregion useApp_basicUsage
}

View file

@ -30,18 +30,7 @@ export interface UseAppOptions {
* @param app - The newly created `App` instance
*
* @example Register a notification handler
* ```typescript
* import { McpUiToolInputNotificationSchema } from '@modelcontextprotocol/ext-apps/react';
*
* onAppCreated: (app) => {
* app.setNotificationHandler(
* McpUiToolInputNotificationSchema,
* (notification) => {
* console.log("Tool input:", notification.params.arguments);
* }
* );
* }
* ```
* {@includeCode ./useApp.examples.tsx#useApp_registerHandler}
*/
onAppCreated?: (app: App) => void;
}
@ -81,29 +70,7 @@ export interface AppState {
* timeouts, initialization handshake failures, or transport errors).
*
* @example Basic usage
* ```typescript
* import { useApp, McpUiToolInputNotificationSchema } from '@modelcontextprotocol/ext-apps/react';
*
* function MyApp() {
* const { app, isConnected, error } = useApp({
* appInfo: { name: "MyApp", version: "1.0.0" },
* capabilities: {},
* onAppCreated: (app) => {
* // Register handlers before connection
* app.setNotificationHandler(
* McpUiToolInputNotificationSchema,
* (notification) => {
* console.log("Tool input:", notification.params.arguments);
* }
* );
* },
* });
*
* if (error) return <div>Error: {error.message}</div>;
* if (!isConnected) return <div>Connecting...</div>;
* return <div>Connected!</div>;
* }
* ```
* {@includeCode ./useApp.examples.tsx#useApp_basicUsage}
*
* @see {@link App.connect} for the underlying connection method
* @see {@link useAutoResize} for manual auto-resize control when using custom App options

View file

@ -0,0 +1,42 @@
/**
* Type-checked examples for the useAutoResize hook.
*
* @module
*/
import { useState, useEffect } from "react";
import { App, PostMessageTransport } from "./index.js";
import { useAutoResize } from "./useAutoResize.js";
/**
* Example: Manual App creation with custom auto-resize control.
*/
function useAutoResize_manualApp() {
//#region useAutoResize_manualApp
function MyComponent() {
// For custom App options, create App manually instead of using useApp
const [app, setApp] = useState<App | null>(null);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const myApp = new App(
{ name: "MyApp", version: "1.0.0" },
{}, // capabilities
{ autoResize: false }, // Disable default auto-resize
);
const transport = new PostMessageTransport(window.parent, window.parent);
myApp
.connect(transport)
.then(() => setApp(myApp))
.catch((err) => setError(err));
}, []);
// Add manual auto-resize control
useAutoResize(app);
if (error) return <div>Connection failed: {error.message}</div>;
return <div>My content</div>;
}
//#endregion useAutoResize_manualApp
}

View file

@ -20,32 +20,7 @@ import { App } from "../app";
* cause unnecessary effect re-runs; omit this parameter.
*
* @example Manual App creation with custom auto-resize control
* ```tsx
* function MyComponent() {
* // For custom App options, create App manually instead of using useApp
* const [app, setApp] = useState<App | null>(null);
* const [error, setError] = useState<Error | null>(null);
*
* useEffect(() => {
* const myApp = new App(
* { name: "MyApp", version: "1.0.0" },
* {}, // capabilities
* { autoResize: false } // Disable default auto-resize
* );
*
* const transport = new PostMessageTransport(window.parent, window.parent);
* myApp.connect(transport)
* .then(() => setApp(myApp))
* .catch((err) => setError(err));
* }, []);
*
* // Add manual auto-resize control
* useAutoResize(app);
*
* if (error) return <div>Connection failed: {error.message}</div>;
* return <div>My content</div>;
* }
* ```
* {@includeCode ./useAutoResize.examples.tsx#useAutoResize_manualApp}
*
* @see {@link App.setupSizeChangedNotifications} for the underlying implementation
* @see {@link useApp} which enables auto-resize by default

View file

@ -0,0 +1,46 @@
/**
* Type-checked examples for the useDocumentTheme hook.
*
* @module
*/
import { useDocumentTheme } from "./useDocumentTheme.js";
// Stub components for examples
declare function DarkIcon(): React.JSX.Element;
declare function LightIcon(): React.JSX.Element;
/**
* Example: Conditionally render based on theme.
*/
function useDocumentTheme_conditionalRender() {
//#region useDocumentTheme_conditionalRender
function MyApp() {
const theme = useDocumentTheme();
return <div>{theme === "dark" ? <DarkIcon /> : <LightIcon />}</div>;
}
//#endregion useDocumentTheme_conditionalRender
}
/**
* Example: Use with theme-aware styling.
*/
function useDocumentTheme_themedButton() {
//#region useDocumentTheme_themedButton
function ThemedButton() {
const theme = useDocumentTheme();
return (
<button
style={{
background: theme === "dark" ? "#333" : "#fff",
color: theme === "dark" ? "#fff" : "#333",
}}
>
Click me
</button>
);
}
//#endregion useDocumentTheme_themedButton
}

View file

@ -15,35 +15,10 @@ import { McpUiTheme } from "../types";
* @returns The current theme ("light" or "dark")
*
* @example Conditionally render based on theme
* ```tsx
* import { useDocumentTheme } from '@modelcontextprotocol/ext-apps/react';
*
* function MyApp() {
* const theme = useDocumentTheme();
*
* return (
* <div>
* {theme === 'dark' ? <DarkIcon /> : <LightIcon />}
* </div>
* );
* }
* ```
* {@includeCode ./useDocumentTheme.examples.tsx#useDocumentTheme_conditionalRender}
*
* @example Use with theme-aware styling
* ```tsx
* function ThemedButton() {
* const theme = useDocumentTheme();
*
* return (
* <button style={{
* background: theme === 'dark' ? '#333' : '#fff',
* color: theme === 'dark' ? '#fff' : '#333',
* }}>
* Click me
* </button>
* );
* }
* ```
* {@includeCode ./useDocumentTheme.examples.tsx#useDocumentTheme_themedButton}
*
* @see {@link getDocumentTheme} for the underlying function
* @see {@link applyDocumentTheme} to set the theme

View file

@ -0,0 +1,87 @@
/**
* Type-checked examples for the useHostStyles hooks.
*
* @module
*/
import { useState } from "react";
import {
useApp,
useHostStyleVariables,
useHostFonts,
useHostStyles,
App,
} from "./index.js";
import type { McpUiHostContext } from "../types.js";
/**
* Example: Basic usage of useHostStyleVariables.
*/
function useHostStyleVariables_basicUsage() {
//#region useHostStyleVariables_basicUsage
function MyApp() {
const { app, isConnected } = useApp({
appInfo: { name: "MyApp", version: "1.0.0" },
capabilities: {},
});
// Apply host styles - pass initial context to apply styles from connect() immediately
useHostStyleVariables(app, app?.getHostContext());
return (
<div style={{ background: "var(--color-background-primary)" }}>
Hello!
</div>
);
}
//#endregion useHostStyleVariables_basicUsage
}
/**
* Example: Basic usage of useHostFonts with useApp.
*/
function useHostFonts_basicUsage() {
//#region useHostFonts_basicUsage
function MyApp() {
const { app, isConnected } = useApp({
appInfo: { name: "MyApp", version: "1.0.0" },
capabilities: {},
});
// Automatically apply host fonts
useHostFonts(app);
return <div style={{ fontFamily: "var(--font-sans)" }}>Hello!</div>;
}
//#endregion useHostFonts_basicUsage
}
/**
* Example: useHostFonts with initial context.
*/
function useHostFonts_withInitialContext(app: App) {
//#region useHostFonts_withInitialContext
const [hostContext, setHostContext] = useState<McpUiHostContext | null>(null);
// ... get initial context from app.connect() result
useHostFonts(app, hostContext);
//#endregion useHostFonts_withInitialContext
}
/**
* Example: Basic usage of useHostStyles.
*/
function useHostStyles_basicUsage() {
const appInfo = { name: "MyApp", version: "1.0.0" };
//#region useHostStyles_basicUsage
function MyApp() {
const { app } = useApp({ appInfo, capabilities: {} });
useHostStyles(app, app?.getHostContext());
return (
<div style={{ background: "var(--color-background-primary)" }}>...</div>
);
}
//#endregion useHostStyles_basicUsage
}

View file

@ -26,25 +26,7 @@ import { McpUiHostContext } from "../types";
* If provided, styles and theme will be applied immediately on mount.
*
* @example
* ```tsx
* import { useApp, useHostStyleVariables } from '@modelcontextprotocol/ext-apps/react';
*
* function MyApp() {
* const { app, isConnected } = useApp({
* appInfo: { name: "MyApp", version: "1.0.0" },
* capabilities: {},
* });
*
* // Apply host styles - pass initial context to apply styles from connect() immediately
* useHostStyleVariables(app, app?.getHostContext());
*
* return (
* <div style={{ background: 'var(--color-background-primary)' }}>
* Hello!
* </div>
* );
* }
* ```
* {@includeCode ./useHostStyles.examples.tsx#useHostStyleVariables_basicUsage}
*
* @see {@link applyHostStyleVariables} for the underlying styles function
* @see {@link applyDocumentTheme} for the underlying theme function
@ -107,35 +89,10 @@ export function useHostStyleVariables(
* If provided, fonts will be applied immediately on mount.
*
* @example Basic usage with useApp
* ```tsx
* import { useApp } from '@modelcontextprotocol/ext-apps/react';
* import { useHostFonts } from '@modelcontextprotocol/ext-apps/react';
*
* function MyApp() {
* const { app, isConnected } = useApp({
* appInfo: { name: "MyApp", version: "1.0.0" },
* capabilities: {},
* });
*
* // Automatically apply host fonts
* useHostFonts(app);
*
* return (
* <div style={{ fontFamily: 'var(--font-sans)' }}>
* Hello!
* </div>
* );
* }
* ```
* {@includeCode ./useHostStyles.examples.tsx#useHostFonts_basicUsage}
*
* @example With initial context
* ```tsx
* const [hostContext, setHostContext] = useState<McpUiHostContext | null>(null);
*
* // ... get initial context from app.connect() result
*
* useHostFonts(app, hostContext);
* ```
* {@includeCode ./useHostStyles.examples.tsx#useHostFonts_withInitialContext}
*
* @see {@link applyHostFonts} for the underlying fonts function
* @see {@link useHostStyleVariables} for applying style variables and theme
@ -182,14 +139,7 @@ export function useHostFonts(
* Pass `app?.getHostContext()` to apply styles immediately on mount.
*
* @example
* ```tsx
* function MyApp() {
* const { app } = useApp({ appInfo, capabilities: {} });
* useHostStyles(app, app?.getHostContext());
*
* return <div style={{ background: 'var(--color-background-primary)' }}>...</div>;
* }
* ```
* {@includeCode ./useHostStyles.examples.tsx#useHostStyles_basicUsage}
*
* @see {@link useHostStyleVariables} for style variables and theme only
* @see {@link useHostFonts} for fonts only