Add safeAreaInsets support to all example apps (#202)
Apply host-provided safe area insets as padding on main containers across all examples. This ensures content doesn't render under system UI elements like phone notches. React apps use `useState` + `onhostcontextchanged` handler with initial fetch via `getHostContext()` in `useEffect`. Vanilla JS apps apply padding in the handler and invoke it after `connect()`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
97990b6b28
commit
79670b4dcd
2 changed files with 267 additions and 48 deletions
|
|
@ -7,7 +7,7 @@
|
|||
import type { App, McpUiHostContext } from "@modelcontextprotocol/ext-apps";
|
||||
import { useApp } from "@modelcontextprotocol/ext-apps/react";
|
||||
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { StrictMode, useState, useCallback } from "react";
|
||||
import { StrictMode, useState, useCallback, useEffect } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import ThreeJSApp from "./threejs-app.tsx";
|
||||
import "./global.css";
|
||||
|
|
@ -67,11 +67,21 @@ function McpAppWrapper() {
|
|||
};
|
||||
// Host context changes (theme, dimensions, etc.)
|
||||
app.onhostcontextchanged = (params) => {
|
||||
setHostContext(params);
|
||||
setHostContext((prev) => ({ ...prev, ...params }));
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Get initial host context after connection
|
||||
useEffect(() => {
|
||||
if (app) {
|
||||
const ctx = app.getHostContext();
|
||||
if (ctx) {
|
||||
setHostContext(ctx);
|
||||
}
|
||||
}
|
||||
}, [app]);
|
||||
|
||||
// Memoized callbacks that forward to app methods
|
||||
const callServerTool = useCallback<App["callServerTool"]>(
|
||||
(params, options) => app!.callServerTool(params, options),
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export default function ThreeJSApp({
|
|||
toolInputs,
|
||||
toolInputsPartial,
|
||||
toolResult: _toolResult,
|
||||
hostContext: _hostContext,
|
||||
hostContext,
|
||||
callServerTool: _callServerTool,
|
||||
sendMessage: _sendMessage,
|
||||
openLink: _openLink,
|
||||
|
|
@ -155,6 +155,14 @@ export default function ThreeJSApp({
|
|||
const partialCode = toolInputsPartial?.code;
|
||||
const isStreaming = !toolInputs && !!toolInputsPartial;
|
||||
|
||||
const safeAreaInsets = hostContext?.safeAreaInsets;
|
||||
const containerStyle = {
|
||||
paddingTop: safeAreaInsets?.top,
|
||||
paddingRight: safeAreaInsets?.right,
|
||||
paddingBottom: safeAreaInsets?.bottom,
|
||||
paddingLeft: safeAreaInsets?.left,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!code || !canvasRef.current || !containerRef.current) return;
|
||||
|
||||
|
|
@ -166,11 +174,19 @@ export default function ThreeJSApp({
|
|||
}, [code, height]);
|
||||
|
||||
if (isStreaming || !code) {
|
||||
return <LoadingShimmer height={height} code={partialCode} />;
|
||||
return (
|
||||
<div style={containerStyle}>
|
||||
<LoadingShimmer height={height} code={partialCode} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="threejs-container">
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="threejs-container"
|
||||
style={containerStyle}
|
||||
>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
style={{
|
||||
|
|
|
|||
Loading…
Reference in a new issue