Add iframe auto-resize via postMessage
Embeds now report content height to the parent frame using a ResizeObserver on document.body. The EmbedDialog snippet includes a listener script that adjusts the iframe height on each resize event. Documented the spicebook-resize protocol in llms.txt.
This commit is contained in:
parent
bfab38e954
commit
00fa420743
@ -598,6 +598,26 @@ iframe.contentWindow.postMessage(
|
|||||||
|
|
||||||
Accepted values for `theme`: `"dark"`, `"light"`. Other messages are ignored.
|
Accepted values for `theme`: `"dark"`, `"light"`. Other messages are ignored.
|
||||||
|
|
||||||
|
### Auto-resize via postMessage
|
||||||
|
|
||||||
|
The embed reports its content height to the parent page whenever the layout changes (initial render, simulation results, expanded cells). The parent listens for `spicebook-resize` messages and updates the iframe height:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
window.addEventListener('message', function(e) {
|
||||||
|
if (e.data && e.data.type === 'spicebook-resize') {
|
||||||
|
document.getElementById('spicebook-{notebook_id}').style.height = e.data.height + 'px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The message payload:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "type": "spicebook-resize", "height": 1842 }
|
||||||
|
```
|
||||||
|
|
||||||
|
`height` is `document.documentElement.scrollHeight` in pixels. The embed sends this message on every `ResizeObserver` callback, deduplicated to only fire when height actually changes. The **Embed** button's generated snippet includes this listener automatically.
|
||||||
|
|
||||||
### Discovering the embed snippet
|
### Discovering the embed snippet
|
||||||
|
|
||||||
In the notebook editor UI, the **Embed** button in the toolbar opens a popover with a ready-to-copy iframe snippet and a theme toggle.
|
In the notebook editor UI, the **Embed** button in the toolbar opens a popover with a ready-to-copy iframe snippet (including auto-resize listener) and a theme toggle.
|
||||||
|
|||||||
@ -38,6 +38,26 @@ export default function EmbedViewer({ notebookId, initialTheme }: EmbedViewerPro
|
|||||||
return () => window.removeEventListener('message', handleMessage);
|
return () => window.removeEventListener('message', handleMessage);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Report content height to parent frame for auto-resize
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window === 'undefined' || window.parent === window) return;
|
||||||
|
|
||||||
|
let lastHeight = 0;
|
||||||
|
function reportHeight() {
|
||||||
|
const height = document.documentElement.scrollHeight;
|
||||||
|
if (height !== lastHeight) {
|
||||||
|
lastHeight = height;
|
||||||
|
window.parent.postMessage({ type: 'spicebook-resize', height }, '*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const observer = new ResizeObserver(reportHeight);
|
||||||
|
observer.observe(document.body);
|
||||||
|
reportHeight();
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Keep a ref to notebook for use inside handleRun to avoid stale closures
|
// Keep a ref to notebook for use inside handleRun to avoid stale closures
|
||||||
const notebookRef = useRef(notebook);
|
const notebookRef = useRef(notebook);
|
||||||
notebookRef.current = notebook;
|
notebookRef.current = notebook;
|
||||||
|
|||||||
@ -14,12 +14,23 @@ export function EmbedDialog() {
|
|||||||
|
|
||||||
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
||||||
|
|
||||||
|
const iframeId = `spicebook-${notebookId}`;
|
||||||
|
|
||||||
const snippet = `<iframe
|
const snippet = `<iframe
|
||||||
|
id="${iframeId}"
|
||||||
src="${origin}/embed/${notebookId}?theme=${theme}"
|
src="${origin}/embed/${notebookId}?theme=${theme}"
|
||||||
width="100%" height="600"
|
width="100%" height="600"
|
||||||
style="border: 1px solid #334155; border-radius: 8px;"
|
style="border: 1px solid #334155; border-radius: 8px;"
|
||||||
allow="clipboard-write"
|
allow="clipboard-write"
|
||||||
></iframe>`;
|
></iframe>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('message', function(e) {
|
||||||
|
if (e.data && e.data.type === 'spicebook-resize') {
|
||||||
|
var f = document.getElementById('${iframeId}');
|
||||||
|
if (f) f.style.height = e.data.height + 'px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>`;
|
||||||
|
|
||||||
function handleCopy() {
|
function handleCopy() {
|
||||||
navigator.clipboard.writeText(snippet).then(() => {
|
navigator.clipboard.writeText(snippet).then(() => {
|
||||||
@ -72,7 +83,7 @@ export function EmbedDialog() {
|
|||||||
<textarea
|
<textarea
|
||||||
readOnly
|
readOnly
|
||||||
value={snippet}
|
value={snippet}
|
||||||
rows={5}
|
rows={12}
|
||||||
className="w-full resize-none rounded-md border border-slate-600 bg-slate-800 p-2 font-mono text-[11px] text-slate-300 focus:outline-none focus:border-blue-500"
|
className="w-full resize-none rounded-md border border-slate-600 bg-slate-800 p-2 font-mono text-[11px] text-slate-300 focus:outline-none focus:border-blue-500"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user