Skip to content

Commit 4b058a8

Browse files
committed
fix(Map): sync with ChatGPT displayMode for automatic collapse
Fixes display mode synchronization bug where clicking ChatGPT's X button didn't collapse the Map component back to compact view. Changes: - Add useDisplayMode() hook to listen to ChatGPT's display mode changes - Sync internal fullscreen state when ChatGPT displayMode changes - Only sync in uncontrolled mode (respects external state management) - Update Storybook docs to document display mode sync behavior Implementation: - Uses useEffect to detect displayMode changes from 'fullscreen' to 'inline' - Automatically updates internalIsFullscreen state to match - Two-way sync: widget responds to both internal and external display mode changes Result: - Clicking ChatGPT's X button now properly collapses map to compact view - No manual reset needed - Follows Album component pattern for ChatGPT Apps SDK integration
1 parent 6bc4fe4 commit 4b058a8

File tree

3 files changed

+32
-2
lines changed

3 files changed

+32
-2
lines changed

packages/ui/src/components/Map/Map.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { CompactMap, type CompactMapProps } from './CompactMap';
33
import { FullscreenMap, type FullscreenMapProps } from './FullscreenMap';
44
import type { MapViewProps } from './MapView';
5+
import { useDisplayMode } from '../../hooks/openai';
56

67
export interface MapProps extends Omit<MapViewProps, 'className' | 'style'> {
78
/**
@@ -80,10 +81,23 @@ export const Map: React.FC<MapProps> = ({
8081
}) => {
8182
const [internalIsFullscreen, setInternalIsFullscreen] = React.useState(false);
8283

84+
// Listen to ChatGPT's displayMode changes
85+
const displayMode = useDisplayMode();
86+
8387
// Use controlled state if provided, otherwise use internal state
8488
const isControlled = controlledIsFullscreen !== undefined;
8589
const isFullscreen = isControlled ? controlledIsFullscreen : internalIsFullscreen;
8690

91+
// Sync internal state with ChatGPT's displayMode when not controlled
92+
React.useEffect(() => {
93+
if (!isControlled && displayMode) {
94+
const shouldBeFullscreen = displayMode === 'fullscreen';
95+
if (shouldBeFullscreen !== internalIsFullscreen) {
96+
setInternalIsFullscreen(shouldBeFullscreen);
97+
}
98+
}
99+
}, [displayMode, isControlled, internalIsFullscreen]);
100+
87101
const handleExpand = async () => {
88102
// Request fullscreen mode from ChatGPT host
89103
if (window.openai?.requestDisplayMode) {

packages/ui/src/components/Map/Maps.stories.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,12 +491,19 @@ const MapSystemComponent: React.FC = () => {
491491
Use controlled mode to let ChatGPT manage the iframe expansion based on user
492492
interaction.
493493
</p>
494-
<p style={{ margin: 0 }}>
494+
<p style={{ margin: '0 0 12px 0' }}>
495495
When user clicks expand button → Map calls <code>onToggleFullscreen(true)</code> → Your
496496
app expands the iframe → User sees FullscreenMap. When user clicks collapse → Map calls{' '}
497497
<code>onToggleFullscreen(false)</code> → Your app collapses iframe → User sees
498498
CompactMap.
499499
</p>
500+
<p style={{ margin: 0 }}>
501+
<strong>🔄 Display Mode Sync:</strong> The Map component automatically listens to ChatGPT's{' '}
502+
<code>displayMode</code> changes using the <code>useDisplayMode()</code> hook. This means
503+
clicking ChatGPT's close button (X) will automatically collapse the map back to compact view
504+
without requiring manual interaction. Two-way sync ensures your map stays in sync with
505+
ChatGPT's UI state.
506+
</p>
500507
</div>
501508

502509
<div style={codeBlockStyles.primary}>
@@ -552,6 +559,10 @@ const handleMapToggle = (fullscreen: boolean) => {
552559
<li>CompactMap height: 478px (standard ChatGPT Apps size)</li>
553560
<li>Expand/collapse buttons automatically shown in both views</li>
554561
<li>Buttons automatically disabled if callbacks not provided</li>
562+
<li>
563+
<strong>Automatic sync with ChatGPT's display mode</strong> - clicking ChatGPT's X button
564+
automatically collapses the map
565+
</li>
555566
<li>Responsive design works on all device sizes</li>
556567
</ul>
557568
</div>

packages/ui/src/gallery/examples/Maps.stories.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,8 @@ const MapsComponent: React.FC = () => {
420420
}}
421421
>
422422
The Map component is designed specifically for ChatGPT Apps SDK integration. Use the controlled mode pattern
423-
shown below to let ChatGPT manage the iframe expansion when users click the expand button.
423+
shown below to let ChatGPT manage the iframe expansion when users click the expand button. The component
424+
automatically syncs with ChatGPT's display mode changes, so clicking ChatGPT's X button will collapse the map.
424425
</p>
425426

426427
<div style={codeBlockStyles.primary}>
@@ -479,6 +480,10 @@ function MyMapApp() {
479480
<strong>isFullscreen + onToggleFullscreen:</strong> Map calls your callback when user clicks expand/collapse
480481
button
481482
</li>
483+
<li>
484+
<strong>Automatic Display Mode Sync:</strong> Map listens to ChatGPT's display mode changes - clicking
485+
ChatGPT's X button automatically collapses the map
486+
</li>
482487
<li>
483488
<strong>Default Size:</strong> CompactMap uses 478px height (ChatGPT Apps SDK standard)
484489
</li>

0 commit comments

Comments
 (0)