message: Handle iOS Safari iframe postmessage behaviour
diff: @@ -29,6 +29,7 @@ function getSrcDocWithScript(script, parentOrigin) {
  };
  window.parent.postMessage('ready', '${parentOrigin}');
  + window.__READY_TO_RUN = true;
  </script>
  `;
  }
  @@ -36,25 +37,29 @@ function getSrcDocWithScript(script, parentOrigin) {
  const Chart = props => {
  const { script } = props;
  const { origin } = window;
  + const { version } = useDocsVersion();
  const srcDoc = getSrcDocWithScript(script, origin);
  const ref = React.useRef();
  - const { version } = useDocsVersion();
  -
  + /**
  + * iOS Safari seems to run scripts iwthin the iframe in a differnet order
  + * compared to desktop Chrome, Safari, etc.
  + *
  + * On the desktop browsers the React effect will run first, so the 'ready'
  + * event listener is added before the iframe script calls postMessage.
  + *
  + * On iOS Safari the iframe script runs before the React effect, so the
  + * 'ready' event listener hasn't been added yet!
  + *
  + * We use the __READY_TO_RUN flag to handle this case. If __READY_TO_RUN
  + * is true then we know that the inner window's run function can be
  + * called immediately and we don't need to register a event listener.
  + */
  React.useEffect(() => {
  const lightweightChartsImportPromise = importLightweightChartsVersion(version);
  -
  - const readyMessageListener = event => {
  - if (event.origin !== origin || event.source !== ref.current.contentWindow) {
  - return;
  - }
  -
  - if (event.data === 'ready') {
  - window.removeEventListener('message', readyMessageListener, false);
  -
  + const injectCreateChartAndRun = contentWindow => {
  lightweightChartsImportPromise.then(mod => {
  const createChart = mod.createChart;
  - const contentWindow = event.source;
  contentWindow.createChart = (container, options) => {
  const chart = createChart(container, options);
  @@ -68,8 +73,23 @@ const Chart = props => {
  return chart;
  };
  - event.source.run();
  + contentWindow.run();
  });
  + };
  +
  + if (ref.current.contentWindow.__READY_TO_RUN) {
  + injectCreateChartAndRun(ref.current.contentWindow);
  + return;
  + }
  +
  + const readyMessageListener = event => {
  + if (event.origin !== origin || event.source !== ref.current.contentWindow) {
  + return;
  + }
  +
  + if (event.data === 'ready') {
  + injectCreateChartAndRun(event.source);
  + window.removeEventListener('message', readyMessageListener, false);
  }
  };
  