statelyai / inspect

Inspect state transitions and actor communication
https://stately.ai/docs/inspector
MIT License
43 stars 5 forks source link

Issue Attaching XState Inspector to iframe #36

Open tamjeedhur opened 2 weeks ago

tamjeedhur commented 2 weeks ago

I'm encountering an issue while trying to render the XState machine UI inside an iframe using the @statelyai/inspect library. The inspector is supposed to be attached to the iframe after it has been rendered, but it seems like the state machine is initialized before the inspector is fully set up. This results in the state machine not being able to use the inspector for visualization.

Current Behavior:

I create an iframe in the DOM and reference it using useRef. I use createBrowserInspector to create an inspector and attach it to the iframe once the iframe is rendered (useEffect). The state machine is initialized using a custom hook useMachineAdvance, which expects the inspector to be available. The inspector doesn't seem to attach properly to the iframe, possibly because the state machine is initialized before the inspector setup is complete. Expected Behavior: The XState machine UI should be rendered inside the iframe, with the inspector properly attached and synchronized with the state machine from the moment the component mounts.

Code Example:

import React, { useEffect, useState, useRef } from 'react';
import './App.css';
import { useMachine } from '@xstate/react';
import { trafficLightMachine } from './counterMachine';
import { createBrowserInspector } from "@statelyai/inspect";

function App() {
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
  const [inspect, setInspect] = useState<any | null>(null);

  useEffect(() => {
    if (iframeRef.current) {
      const inspector = createBrowserInspector({ iframe: iframeRef.current });
      setInspect(inspector);
    }
  }, []);

  const [state, send] = useMachine(trafficLightMachine, { inspect });

  return (
    <section id="app">
      <output>{state.value}</output>
      <iframe
        id="inspector-iframe"
        ref={iframeRef}
        title="Traffic Light State Inspector"
        style={{ height: "500px", width: "500px" }}
      ></iframe>
      <button onClick={() => send({ type: 'TIMER' })}>Count</button>
    </section>
  );
}

export default App;

Steps to Reproduce:

Create a React component that renders an iframe. Use createBrowserInspector from @statelyai/inspect to attach the inspector to the iframe after it renders. Initialize a state machine using a useMachine hook, passing the inspector as a parameter. Observe that the inspector is not fully functional.

but getting this as output

Screenshot 2024-08-27 at 4 47 44 AM

can you guide me on it ?

davidkpiano commented 2 weeks ago

Can you please try with an externally created inspector? Outside of the component

tamjeedhur commented 2 weeks ago
import React, { useEffect, useState, useRef } from 'react';
import './App.css';
import { useMachine } from '@xstate/react';
import { trafficLightMachine } from './counterMachine';
import { createBrowserInspector } from "@statelyai/inspect";

const inspector = createBrowserInspector({ iframe: document.getElementById("inspector-iframe") });

function App() {
  const [inspect, setInspect] = useState<any | null>(inspector.inspect);

  const [state, send] = useMachine(trafficLightMachine, { inspect });

  return (
    <section id="app">
      <output>{state.value}</output>
      <iframe
        id="inspector-iframe"
        title="Traffic Light State Inspector"
        style={{ height: "500px", width: "500px" }}
      ></iframe>
      <button onClick={() => send({ type: 'TIMER' })}>Count</button>
    </section>
  );
}

export default App;

hi @davidkpiano creating inspector outside the component will open the inspector in new tab , in that way we will not be able to reference iframe using ref as going outside the component react does not support to call any hook . I want it to be in iframe .