// Towbook Android styleguide — iframe mount. // Reads ?page=… from the URL and renders just that section. The Rails app's // sidebar/theme chrome wraps the iframe, so the design no longer needs its own. const { useEffect: useEffectM } = React; const PAGE_COMPONENTS = { foundations: () => , components: () => , patterns: () => , screens: () => , }; function ScreensPageWithState() { const [checkedIn, setCheckedIn] = React.useState(true); return ; } function MountedPage() { // Auto-report scrollHeight to parent so the iframe can size itself. useEffectM(() => { const report = () => { const h = document.documentElement.scrollHeight; window.parent?.postMessage({ type: 'tb-android:height', height: h }, '*'); }; report(); const ro = new ResizeObserver(report); ro.observe(document.documentElement); const interval = setInterval(report, 500); return () => { ro.disconnect(); clearInterval(interval); }; }, []); // Listen for theme updates from the parent window. useEffectM(() => { const onMessage = (e) => { if (e.data?.type === 'tb-android:theme') { document.documentElement.setAttribute('data-theme', e.data.value); } }; window.addEventListener('message', onMessage); // Ask parent for the current theme on first mount. window.parent?.postMessage({ type: 'tb-android:ready' }, '*'); return () => window.removeEventListener('message', onMessage); }, []); const params = new URLSearchParams(window.location.search); const page = params.get('page') || 'components'; const render = PAGE_COMPONENTS[page]; if (!render) { return (
Unknown page: {page}. Try ?page=components, ?page=patterns, or ?page=screens.
); } return render(); } ReactDOM.createRoot(document.getElementById('root')).render();