storybook-router icon indicating copy to clipboard operation
storybook-router copied to clipboard

reach-router support

Open travi opened this issue 6 years ago • 6 comments

Feature Request:

Are you using storybook-router with a react based project or a vue one?

React (Gatsby)

Context for the request

I've been using storybook-router with components that use gatsby-link because it previously wrapped react-router's Link component.

However, that switched to using Reach Router. I haven't used react router yet to give much insight into what might be different, but it would be great to be able to continue using storybook-router the same way.

thanks for continued efforts with this package. it has been a great addition to storybook!

travi avatar Aug 07 '18 03:08 travi

Hi @travi, thank you for the suggestion. I'll have a look but unfortunately I will not be able before September.

gvaldambrini avatar Aug 13 '18 08:08 gvaldambrini

not a problem. mostly wanted to get it on your radar for when it makes sense

travi avatar Aug 14 '18 02:08 travi

Would this thread be helpful? https://spectrum.chat/reach/questions/using-reach-router-in-storybook~d6ed6f77-dad7-4c5a-8ad3-c7784a594d7b?authed=true

In the thread @mikebarkmin suggested to @theinterned to use, for inspiration, his (MIT licensed) @reach/router proxy for react-cosmos as seen at this mirror: https://github.com/openpatch/ui-core/blob/master/src/proxies/ReachRouterProxy.js

JelaMiraj avatar Jan 30 '19 04:01 JelaMiraj

Btw, sorry in advance if I don't notice my notification of this thread being updated... Guess I need to change the settings on a mobile app to make important GitHub notifications more obtrusive...

JelaMiraj avatar Jan 30 '19 04:01 JelaMiraj

I was able to add memory source support in Reach Router and Storyboard with the following decorator:

import {
  LocationProvider,
  createMemorySource,
  createHistory
} from "@reach/router";
import React from "react";
import { makeDecorator } from "@storybook/addons";

export const withRouter = makeDecorator({
  name: "router",
  parameterName: "router",
  skipIfNoParametersOrOptions: true,

  wrapper: (getStory, context, { parameters = "/" }) => {
    const source = createMemorySource(parameters);
    const history = createHistory(source);
    history.listen(() => console.log('message arrived at router', source.location));
    return <LocationProvider history={history}>{getStory(context)}</LocationProvider>;
  }
});

which I then include in all stories (though you don't have to) with:

import { withRouter } from "./addons/router";

addDecorator(withRouter);

In a story that I want to add Reach Router component rendering, I add a router param with the initial path:

storiesOf(storyName(base))
  .add("default app state", () => {
    return <App />
  }, { router: "/" });

The url of your app won't update as you navigate around, but it does tie into Reach Router in what looks like the desired approach. This does not attempt to tie into Storybook's <Link>s.

jonknapp avatar Apr 07 '19 15:04 jonknapp

I ran into a snag having the router work properly after changing any context (ex: changing "knob" value) and the issue seemed to stem from calling createHistory multiple times. If I kept a reference to the first history object I could make navigate calls, but otherwise they would trigger my listener but do nothing in the router.

Here's my current iteration of the code that memoizes the history object, but resets the router location when a story with the router parameter is encountered:

import {
  LocationProvider,
  createMemorySource,
  createHistory as createRouterHistory
} from "@reach/router";
import React from "react";
import { makeDecorator } from "@storybook/addons";

let firstHistoryObject = null;
function createHistory(initialPath) {
  if (firstHistoryObject) {
    firstHistoryObject.navigate(initialPath);
    return firstHistoryObject;
  }

  const source = createMemorySource(initialPath);
  firstHistoryObject = createRouterHistory(source);
  firstHistoryObject.listen(() =>
    console.log("message arrived at router", source.location)
  );
  return firstHistoryObject;
}

export const withRouter = makeDecorator({
  name: "router",
  parameterName: "router",
  skipIfNoParametersOrOptions: true,

  wrapper: (getStory, context, { parameters = "/" }) => {
    return (
      <LocationProvider history={createHistory(parameters)}>
        {getStory(context)}
      </LocationProvider>
    );
  }
});

jonknapp avatar Apr 18 '19 22:04 jonknapp