Complete "Entering / exiting fullscreen" pattern documentation
Add `App_onhostcontextchanged_respondToDisplayMode` example showing how to listen for display mode changes and update UI with `classList.toggle()`. Update `App_requestDisplayMode_fullscreen` to `App_requestDisplayMode_toggle` to show the common toggle pattern checking `availableDisplayModes` first. Refactor full examples (pdf-server, shadertoy-server) to use `classList.toggle(class, condition)` instead of add/remove branches. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
566ac58ab7
commit
dce143e92e
6 changed files with 43 additions and 47 deletions
|
|
@ -43,9 +43,15 @@ Use the SDK's style helpers to apply host styling, then reference them in your C
|
||||||
|
|
||||||
{@includeCode ./patterns.tsx#hostStylingReact}
|
{@includeCode ./patterns.tsx#hostStylingReact}
|
||||||
|
|
||||||
## [TODO] Support fullscreen / exit fullscreen
|
## Entering / Exiting fullscreen
|
||||||
|
|
||||||
{@includeCode ./patterns.tsx#fullscreen}
|
Toggle fullscreen mode by calling {@link app!App.requestDisplayMode requestDisplayMode}:
|
||||||
|
|
||||||
|
{@includeCode ../src/app.examples.ts#App_requestDisplayMode_toggle}
|
||||||
|
|
||||||
|
Listen for display mode changes via {@link app!App.onhostcontextchanged onhostcontextchanged} to update your UI:
|
||||||
|
|
||||||
|
{@includeCode ../src/app.examples.ts#App_onhostcontextchanged_respondToDisplayMode}
|
||||||
|
|
||||||
## [TODO] Persist data (incl. widget state)
|
## [TODO] Persist data (incl. widget state)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,15 +97,6 @@ function hostStylingReact() {
|
||||||
//#endregion hostStylingReact
|
//#endregion hostStylingReact
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Example: Support fullscreen / exit fullscreen
|
|
||||||
*/
|
|
||||||
function fullscreen() {
|
|
||||||
//#region fullscreen
|
|
||||||
// TODO: Implement fullscreen support
|
|
||||||
//#endregion fullscreen
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example: Persist data (incl. widget state)
|
* Example: Persist data (incl. widget state)
|
||||||
*/
|
*/
|
||||||
|
|
@ -155,7 +146,6 @@ void authenticatedCalls;
|
||||||
void errorsToModel;
|
void errorsToModel;
|
||||||
void hostStylingVanillaJs;
|
void hostStylingVanillaJs;
|
||||||
void hostStylingReact;
|
void hostStylingReact;
|
||||||
void fullscreen;
|
|
||||||
void persistData;
|
void persistData;
|
||||||
void lowerPerceivedLatency;
|
void lowerPerceivedLatency;
|
||||||
void iframeAndMcpApps;
|
void iframeAndMcpApps;
|
||||||
|
|
|
||||||
|
|
@ -769,16 +769,12 @@ function handleHostContextChanged(ctx: McpUiHostContext) {
|
||||||
if (ctx.displayMode) {
|
if (ctx.displayMode) {
|
||||||
const wasFullscreen = currentDisplayMode === "fullscreen";
|
const wasFullscreen = currentDisplayMode === "fullscreen";
|
||||||
currentDisplayMode = ctx.displayMode as "inline" | "fullscreen";
|
currentDisplayMode = ctx.displayMode as "inline" | "fullscreen";
|
||||||
if (ctx.displayMode === "fullscreen") {
|
const isFullscreen = currentDisplayMode === "fullscreen";
|
||||||
mainEl.classList.add("fullscreen");
|
mainEl.classList.toggle("fullscreen", isFullscreen);
|
||||||
log.info("Fullscreen mode enabled");
|
log.info(isFullscreen ? "Fullscreen mode enabled" : "Inline mode");
|
||||||
} else {
|
// When exiting fullscreen, request resize to fit content
|
||||||
mainEl.classList.remove("fullscreen");
|
if (wasFullscreen && !isFullscreen && pdfDocument) {
|
||||||
log.info("Inline mode");
|
requestFitToContent();
|
||||||
// When exiting fullscreen, request resize to fit content
|
|
||||||
if (wasFullscreen && pdfDocument) {
|
|
||||||
requestFitToContent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
updateFullscreenButton();
|
updateFullscreenButton();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,21 +65,14 @@ function handleHostContextChanged(ctx: McpUiHostContext) {
|
||||||
|
|
||||||
// Show fullscreen button if available (only update if field is present)
|
// Show fullscreen button if available (only update if field is present)
|
||||||
if (ctx.availableDisplayModes !== undefined) {
|
if (ctx.availableDisplayModes !== undefined) {
|
||||||
if (ctx.availableDisplayModes.includes("fullscreen")) {
|
const canFullscreen = ctx.availableDisplayModes.includes("fullscreen");
|
||||||
fullscreenBtn.classList.add("available");
|
fullscreenBtn.classList.toggle("available", canFullscreen);
|
||||||
} else {
|
|
||||||
fullscreenBtn.classList.remove("available");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update display mode state and UI
|
// Update display mode state and UI
|
||||||
if (ctx.displayMode) {
|
if (ctx.displayMode) {
|
||||||
currentDisplayMode = ctx.displayMode as "inline" | "fullscreen";
|
currentDisplayMode = ctx.displayMode as "inline" | "fullscreen";
|
||||||
if (currentDisplayMode === "fullscreen") {
|
mainEl.classList.toggle("fullscreen", currentDisplayMode === "fullscreen");
|
||||||
mainEl.classList.add("fullscreen");
|
|
||||||
} else {
|
|
||||||
mainEl.classList.remove("fullscreen");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,11 +89,7 @@ async function toggleFullscreen() {
|
||||||
try {
|
try {
|
||||||
const result = await app.requestDisplayMode({ mode: newMode });
|
const result = await app.requestDisplayMode({ mode: newMode });
|
||||||
currentDisplayMode = result.mode as "inline" | "fullscreen";
|
currentDisplayMode = result.mode as "inline" | "fullscreen";
|
||||||
if (currentDisplayMode === "fullscreen") {
|
mainEl.classList.toggle("fullscreen", currentDisplayMode === "fullscreen");
|
||||||
mainEl.classList.add("fullscreen");
|
|
||||||
} else {
|
|
||||||
mainEl.classList.remove("fullscreen");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Failed to change display mode:", err);
|
log.error("Failed to change display mode:", err);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,20 @@ function App_onhostcontextchanged_respondToTheme(app: App) {
|
||||||
//#endregion App_onhostcontextchanged_respondToTheme
|
//#endregion App_onhostcontextchanged_respondToTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example: Respond to display mode changes using onhostcontextchanged.
|
||||||
|
*/
|
||||||
|
function App_onhostcontextchanged_respondToDisplayMode(app: App) {
|
||||||
|
//#region App_onhostcontextchanged_respondToDisplayMode
|
||||||
|
app.onhostcontextchanged = (params) => {
|
||||||
|
if (params.displayMode) {
|
||||||
|
const isFullscreen = params.displayMode === "fullscreen";
|
||||||
|
document.body.classList.toggle("fullscreen", isFullscreen);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//#endregion App_onhostcontextchanged_respondToDisplayMode
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example: Perform cleanup before teardown.
|
* Example: Perform cleanup before teardown.
|
||||||
*/
|
*/
|
||||||
|
|
@ -344,16 +358,17 @@ async function App_openLink_documentation(app: App) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example: Request fullscreen mode.
|
* Example: Toggle between inline and fullscreen display modes.
|
||||||
*/
|
*/
|
||||||
async function App_requestDisplayMode_fullscreen(app: App) {
|
async function App_requestDisplayMode_toggle(app: App) {
|
||||||
//#region App_requestDisplayMode_fullscreen
|
//#region App_requestDisplayMode_toggle
|
||||||
const context = app.getHostContext();
|
const ctx = app.getHostContext();
|
||||||
if (context?.availableDisplayModes?.includes("fullscreen")) {
|
if (ctx?.availableDisplayModes?.includes("fullscreen")) {
|
||||||
const result = await app.requestDisplayMode({ mode: "fullscreen" });
|
const target = ctx.displayMode === "fullscreen" ? "inline" : "fullscreen";
|
||||||
console.log("Display mode set to:", result.mode);
|
const result = await app.requestDisplayMode({ mode: target });
|
||||||
|
console.log("Now in:", result.mode);
|
||||||
}
|
}
|
||||||
//#endregion App_requestDisplayMode_fullscreen
|
//#endregion App_requestDisplayMode_toggle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -729,8 +729,8 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
||||||
* @param options - Request options (timeout, etc.)
|
* @param options - Request options (timeout, etc.)
|
||||||
* @returns Result containing the actual display mode that was set
|
* @returns Result containing the actual display mode that was set
|
||||||
*
|
*
|
||||||
* @example Request fullscreen mode
|
* @example Toggle display mode
|
||||||
* {@includeCode ./app.examples.ts#App_requestDisplayMode_fullscreen}
|
* {@includeCode ./app.examples.ts#App_requestDisplayMode_toggle}
|
||||||
*
|
*
|
||||||
* @see {@link McpUiRequestDisplayModeRequest} for request structure
|
* @see {@link McpUiRequestDisplayModeRequest} for request structure
|
||||||
* @see {@link McpUiHostContext} for checking availableDisplayModes
|
* @see {@link McpUiHostContext} for checking availableDisplayModes
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue