observablehq / feedback

Customer submitted bugs and feature requests
42 stars 3 forks source link

Width and height of notebook view is ignored in React environment #348

Closed alexpreynolds closed 2 years ago

alexpreynolds commented 2 years ago

Describe the bug

When a notebook is imported into a React project, any custom width and height dimensions of elements that are set in the notebook are ignored in the React application. Instead, the notebook view is rendered at the full width of the browser viewport. Additionally, the browser viewport height is ignored, leading to layout calculation errors.

To Reproduce

Steps to reproduce the behavior:

  1. Go to 'https://observablehq.com/d/b9d92c5544a72ac9'
  2. Click on '... > Export > Download Code' and right-click to get the download URL
  3. Create a new React application and install the notebook via:
npx create-react-app genome-space
cd genome-space
yarn add @observablehq/runtime@4
yarn install "https://api.observablehq.com/d/b9d92c5544a72ac9@3406.tgz?v=3"
  1. Replace src/App.js with the following:
import React, {Component} from "react";
import {Runtime, Inspector} from "@observablehq/runtime";
import notebook from "b9d92c5544a72ac9";

class App extends Component {

  constructor(props) {
    super(props);
    this.genomeSpaceRef = React.createRef();
    this.viewportWidth = {};
    this.viewportHeight = {};
  }

  componentDidMount() {
    const genomeSpace = this.genomeSpaceRef.current;
    const runtime = new Runtime();
    const main = runtime.module(notebook, name => {
      if (name === "viewof genomeSpace") {
        return new Inspector(genomeSpace);
      }
      if (name === "mutable viewportWidth") {
        return {fulfilled: (value) => {
          this.viewportWidth = value;
          console.log(`viewportWidth ${JSON.stringify(this.viewportWidth)}`);
        }};
      }
      if (name === "mutable viewportHeight") {
        return {fulfilled: (value) => {
          this.viewportHeight = value;
          console.log(`viewportHeight ${JSON.stringify(this.viewportHeight)}`);
        }};
      }
    });
  }

  render() {
    return (
      <div id="parent" className="parent">
        <div ref={this.genomeSpaceRef} className="genomeSpace"></div>
      </div>
    );
  }
}

export default App;
  1. Start the application:
yarn start

Expected behavior

In the notebook, there are two variables mutable viewportWidth and mutable viewportHeight, which are set to values of 800 and 599, respectively. The data visualization at the top of the notebook is rendered at these preset dimensions in the Observable site.

In the React application, however, they are rendered with the width of the browser viewport — as if the notebook view is fullscreen — and the values of mutable viewportWidth and mutable viewportHeight are ignored.

I would expect that the React component will respect any specified width and height parameters specified in the notebook. I would also expect to be able to dynamically resize the React component and draw the notebook view with any dimensions I choose before, at, and during runtime, so that I can integrate it in a larger layout with other components.

Screenshots

NA

Desktop (please complete the following information):

Additional context

I used the Notebook Visualizer on the notebook at https://observablehq.com/d/b9d92c5544a72ac9 with built-ins enabled. The resulting graph for this notebook shows no apparent use of the width event handler. (It is not clear, therefore, what code is used to allow the React component to render the notebook view as a fullscreen application.)

mbostock commented 2 years ago

Is there a reason that you need viewportHeight and viewportWidth to be mutable here? I don’t see any assignments to those values, and in general, I recommend avoiding mutable.

alexpreynolds commented 2 years ago

I'd like to be able to fit a notebook view into a larger React application, which requires control over layout and presentation. These variables are mutable so that I can test setting them to new values in React. In fact, I am unable to change these values from within React, even though they are mutable and I should be able to change them.

mbostock commented 2 years ago

If you just want to set the variables from React, you don’t need to use mutable; you can use module.redefine on the main module. You can find an example of this in React here: https://github.com/observablehq/examples/tree/main/react-dataflow

alexpreynolds commented 2 years ago

Thanks; using that pattern seems to work. I don't know why hooks work here, but class components do not, however — but at least I can move forwards!