Storybook: CRNA storybook: provide simple integration HOC

Created on 8 Jun 2017  路  8Comments  路  Source: storybookjs/storybook

As discussed with @shilman on Slack

Currently the advised way to integrate Storybook in our app is to build a custom view inside our app, or something simple like:

import StorybookUI from './storybook';

import App from './app';

module.exports = __DEV__ ? StorybookUI : App;

I think Storybook should provide a simple interaction HOC to wrap the main app, and trigger the display of the storybook on a given interaction.

The HOC would only be active on dev env.

Something like

const ProvideStorybook = Component => class StorybookProvider extends Component {
  state = { storybook: false };
  componentDidMount() {
    if ( dev ) registerInteractionListener();
  }
  onInteraction = () => {
    this.setState({storybook: !this.state.storybook});
  }
  registerInteractionListener = () => { 
    // TODO
  }
  render() {
    if (this.state.storybook) {
      return <Storybook/>;
    } else {
      return <Component {...this.props}/>;
    }
  }
}

And the client would become:

class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Open up App.js to start working on your app!</Text>
        <Text>Changes you make will automatically reload.</Text>
        <Text>Shake your phone to open the developer menu.</Text>
      </View>
    );
  }
}
export default provideStorybook(App);

I'm a RN newbie so don't know if this hoc is good enough or which kind of interaction could be appropriate for showing the storybook. Shaking the phone could be nice but already taken by Expo

react-native feature request inactive

Most helpful comment

For the record, I'm using this in my app and it works fine.

It just adds a little top-bar with a button to open storybook.
It's not perfect as it pollutes a bit the dev UI with an always-visible button but it's a good start.

I can remove dependencies and make a PR

import React from "react";
import PropTypes from "prop-types";
import { Button } from "react-native";
import { getStorybookUI, configure } from "@storybook/react-native";
import glamorous, { View, Text } from "glamorous-native";

const doProvideStorybook = (Comp, config) => {
  const StorybookUI = getStorybookUI(config);

  configure(() => {
    require("./stories");
  }, module);

  const StorybookButtonView = ({ text, onPress, children }) =>
    <View display="flex" flexDirection="column" width="100%" height="100%">
      <View>
        <Button title={text} onPress={onPress} />
      </View>
      <View flex={1} width="100%">
        {children}
      </View>
    </View>;
  StorybookButtonView.propTypes = {
    children: PropTypes.node.isRequired,
    text: PropTypes.string.isRequired,
    onPress: PropTypes.func.isRequired,
  };

  return class StorybookProvider extends React.Component {
    state = {
      storybook: false,
    };

    render () {
      if (this.state.storybook) {
        return (
          <StorybookButtonView
            text="Close storybook"
            onPress={() => {
              this.setState({ storybook: false });
            }}
          >
            <StorybookUI />
          </StorybookButtonView>
        );
      } else {
        return (
          <StorybookButtonView
            text="Open storybook"
            onPress={() => {
              this.setState({ storybook: true });
            }}
          >
            <Comp />
          </StorybookButtonView>
        );
      }
    }
  };
};

export const provideStorybook = (Comp, config) => {
  if (__DEV__) {
    return doProvideStorybook(Comp, config);
  } else {
    return Comp;
  }
};

All 8 comments

Could we add something to the Expo debug menu? That'd be pretty awesome

@tmeasday haha asked the same thing last night. please upvote!

https://medium.com/@shilman/awesome-addition-a1c375b2b6e5

That's exactly what I wanted to investigate :)

Yeah, I think this is a good pattern, if you're using storybooks it's pretty likely that you're gonna want something like as your root component. You definitely don't want that showing in production, feels like a good starting place for people 馃憤

It's a bit weird that you'd end up shipping the whole of storybooks with your app, but chances are people are already doing that.

For the record, I'm using this in my app and it works fine.

It just adds a little top-bar with a button to open storybook.
It's not perfect as it pollutes a bit the dev UI with an always-visible button but it's a good start.

I can remove dependencies and make a PR

import React from "react";
import PropTypes from "prop-types";
import { Button } from "react-native";
import { getStorybookUI, configure } from "@storybook/react-native";
import glamorous, { View, Text } from "glamorous-native";

const doProvideStorybook = (Comp, config) => {
  const StorybookUI = getStorybookUI(config);

  configure(() => {
    require("./stories");
  }, module);

  const StorybookButtonView = ({ text, onPress, children }) =>
    <View display="flex" flexDirection="column" width="100%" height="100%">
      <View>
        <Button title={text} onPress={onPress} />
      </View>
      <View flex={1} width="100%">
        {children}
      </View>
    </View>;
  StorybookButtonView.propTypes = {
    children: PropTypes.node.isRequired,
    text: PropTypes.string.isRequired,
    onPress: PropTypes.func.isRequired,
  };

  return class StorybookProvider extends React.Component {
    state = {
      storybook: false,
    };

    render () {
      if (this.state.storybook) {
        return (
          <StorybookButtonView
            text="Close storybook"
            onPress={() => {
              this.setState({ storybook: false });
            }}
          >
            <StorybookUI />
          </StorybookButtonView>
        );
      } else {
        return (
          <StorybookButtonView
            text="Open storybook"
            onPress={() => {
              this.setState({ storybook: true });
            }}
          >
            <Comp />
          </StorybookButtonView>
        );
      }
    }
  };
};

export const provideStorybook = (Comp, config) => {
  if (__DEV__) {
    return doProvideStorybook(Comp, config);
  } else {
    return Comp;
  }
};

@slorber that's really slick. not sure we want to take the dep on glamorous-native yet, but aside from that i think this would be an awesome contribution! Also might call it withStorybook?

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. We do try to do some housekeeping every once in a while so inactive issues will get closed after 90 days. Thanks!

Hey there, it's me again! I am going to help our maintainers close this issue so they can focus on development efforts instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

arunoda picture arunoda  路  3Comments

wahengchang picture wahengchang  路  3Comments

tomitrescak picture tomitrescak  路  3Comments

rpersaud picture rpersaud  路  3Comments

zvictor picture zvictor  路  3Comments