From 95a3a3d92291c3964927aad897fdf70f6d8105c6 Mon Sep 17 00:00:00 2001 From: John Knox Date: Tue, 6 Dec 2022 09:38:11 -0800 Subject: [PATCH] Fix style guide internally Summary: The site loads the style guide in an iframe so that it's css is isolated from the main sites styles. But it doesn't know how big to render the iframe, because it doesn't know the size of its contents. Previously, the js running inside the iframe measured itself and then accessed itself using the parents frame and modified it's own size to match. That doesn't work anymore because the iframe isn't allowed to interact directly with its parent. So instead, i'm using message passing. Also changing MutationObserver to ResizeObserver because the former does not always fire when new css gets loaded and applied. Reviewed By: aigoncharov Differential Revision: D41735809 fbshipit-source-id: 9e84a9b20741f5470012e25f240fb6a2b494f7e3 --- website/src/components/StyleGuide.js | 42 +++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/website/src/components/StyleGuide.js b/website/src/components/StyleGuide.js index e805b21ba..46d787a96 100644 --- a/website/src/components/StyleGuide.js +++ b/website/src/components/StyleGuide.js @@ -7,7 +7,7 @@ * @format */ -import React, {useState, useLayoutEffect} from 'react'; +import React, {useLayoutEffect, useEffect, useRef} from 'react'; import { Typography, Button, @@ -33,6 +33,7 @@ import { import {css} from '@emotion/css'; import reactElementToJSXString from 'react-element-to-jsx-string'; import {IFrame} from './IFrame'; +import useBaseUrl from '@docusaurus/useBaseUrl'; const {Title, Text, Link} = Typography; @@ -550,29 +551,25 @@ const DesignComponentDemos = () => ( ); function SandyDesignSystem() { - const [root, setRoot] = useState(null); + const root = useRef(null); + // Whenever layout happens, or if the size of root changes, measure it and send a message to the parent frame. useLayoutEffect(() => { - if (root) { - const iframe = window.parent.document.getElementById('styleguide'); - iframe.style.height = `${root.scrollHeight}px`; + if (root.current) { + const sendUpdate = () => window.postMessage({name: 'setStyleGuideHeight', value: `${root.current.scrollHeight}px`}, '*'); + const observer = new ResizeObserver(() => { + sendUpdate(); + }); + observer.observe(root.current); - const observer = new MutationObserver(() => { - iframe.style.height = `${root.scrollHeight}px`; - }); - observer.observe(root, { - subtree: true, - childList: true, - attributes: true, - characterData: true, - }); + sendUpdate(); return () => observer.disconnect(); } - }, [root]); + }, [root.current]); return ( - +

Welcome to the Flipper Design System. The Flipper design system is @@ -694,9 +691,20 @@ function SandyDesignSystem() { } export default function DesignSystemFramed() { + // We're displaying the style guide in an iframe to isolate it's styles. + // But we don't know how big it is, so don't know how high to make the iframe to avoid a double scroll bar. + // So lets get the js inside the frame measure itself and post a message to this frame, where we'll then + // adjust the size of the iframe to match. + useEffect(() => { + window.addEventListener("message", (event) => { + if (event.data.name === 'setStyleGuideHeight') { + document.getElementById('styleguide').style.height = event.data.value; + } + }) + }, []) return (