storybookjs / native

📱 Storybook for Native: iOS, Android, Flutter
MIT License
184 stars 29 forks source link

Storybook OnDeviceUI integration #66

Closed toddpi314 closed 1 year ago

toddpi314 commented 2 years ago

Hey folks! There is an exciting opportunity here to bridge the Storybook/Native solution with the pre-existing OnDeviceUI. I didn't see this publicly documented anywhere, and thought it would be worth sharing so folks can get a picture of how the pieces could potentially fit together.

Native Side

  1. Create a standard React-Native project
  2. Mount in the Storybook React-Native bits: npx -p @storybook/cli sb init --type react_native

    Note: Don't install @storybook/react-native-server. This is the older way of controlling the React-Native UI from the web via sockets.

  3. Extend the native apps to support Deep Linking (https://github.com/storybookjs/native/blob/master/APP-CONFIG.md#1-deep-linking)
  4. Extend the native code to support DeepLink forwarding into the React-Native DeviceEventManager
    
    // Java example
    package com.storybook;

import android.content.Intent; import android.net.Uri; import android.os.Bundle; import com.facebook.react.ReactActivity; import com.facebook.react.modules.core.DeviceEventManagerModule;

public class MainActivity extends ReactActivity {

/**

Web Side

  1. Install Storybook/native, including the Dev-middleware
  2. Build a story factory that helps facade the story across platform (will run on web and native using platform extension as strategy):
    
    // @flow
    import {storiesOf} from '@storybook/react-native';
    import UnimoduleStoryRenderer from '../UnimoduleStoryRenderer';
    import {toId} from '@storybook/csf';

export default ({ kind, story, component, }: { kind: string, story: string, component: any, }) => { storiesOf(kind, module).add(story, () => UnimoduleStoryRenderer({ component, deepLinkPath: toId(kind, story), }), ); };

> Note: the usage of `toId` to assure the deep-link is marshaled correctly
3. Create a fancy platform specific implementation of the actual renderer:

// index.native.js // @flow import {Platform} from 'react-native';

export default ({component}: {component: any}) => { return component; };

// index.web.js // @flow import React from 'react'; import {Platform, View} from 'react-native'; import {DeepLinkRenderer} from '@storybook/native-components';

export default ({ extraParams, component, deepLinkPath, }: { deepLinkPath: string, component: any, extraParams: any, }) => { const isOsx = process.platform === 'darwin'; const platforms = ['android']; if (isOsx) { platforms.push('ios'); } return (

{component} {platforms.map(platform => { const [visible, setVisible] = React.useState(true); return ( ); })}

); };

4. Make sure to generate your stories using `react-native-storybook-loader` or the fancy new build tool from `https://github.com/storybookjs/native`
5. Write your story:

UnimoduleStory({ kind: 'Alert', story: 'default', component: (

shilman commented 2 years ago

Cc @dannyhw

dannyhw commented 2 years ago

@toddpi314 Hey this sounds really cool! Could you maybe demo this or provide a video/images? Would love to see what it looks like.

Just a note in the 6.0 alpha we've added support for CSF and the new config style used in web so the integration here might become quite different. Also with 6.0 there is a command for getting all the stories based on the main.js config so the loader won't be necessary.

That being said I'd love to bring this functionality directly into the react native package. Or at least facilitate this. Maybe we can collaborate to make this happen, what do you think?

dannyhw commented 2 years ago

@toddpi314 Do you think this could fully replace the server? Currently the server is outdated and not working with 6.0 alpha. I've been thinking a lot about a new way of doing the server and this seems like it could have potential. I'm not sure exactly how the native package works though so I'm interested in knowing more about this.

toddpi314 commented 2 years ago

@dannyhw While I am not sure what the full range of use-cases are for server, I personally believe storybook/native is going to be a game changer. I have used server to speed up story dev, even to drive screenshots with cypress (over detox scaffolding); aside being an accelerator, it didn't ever make it to design system artifacts.

The major advantage I see of storybook/native is the web-first funnel. The idea that a legacy storybook web team, which is a majority of setup's i've encountered professionally, can drop in React components to interop with connected devices and appetize.io makes this huge. This also would avoid native-only silo'd design systems, when they can just extend web-based.

There are gaps:

Here's what I expect to see as a consumer:

A combined story facade would be a huge commitment on the storybook/react-native team to keep compatible with core-web add-ons, and to support a deep-link format across. That seems like a huge risk. Basically, the expectations for add-ons so far (ex. @storybook/addon-ondevice-actions) are probably lower, since those storybook instances are silo'd. Add this to web project, start combining the story facade, and the native add-ons offerings will really be limiting compared to the web ecosystem.

If this general plan sounds ballpark, I can just submit PRs to the respective repositories after getting caught up on the v6.0 setup.

dannyhw commented 2 years ago

I think that a lot of the pain with "glue" could be solved by using CSF to do things behind the scenes.

I think with web support that could be easier than it seems considering the new addon I've been working on (addon-react-native-web) in which I've had success in using react-native-web with the modern storybook features. Though I'm not sure how much overlap there would be here.

Also big part of 6.0 for stoybook/react-native is the support for the main features like controls, args and CSF which helps to bring things closer to the web.

I'm not sure I understand fully about the combined story facade that you mention, the thing with the react-native addons is that it's always been limited by having to reimplement addons. I'm not sure if its viable to suggest that all addons would be supported however similar to the current solution probably the core ones can be supported.

I think I'd like to see a gradual introduction of these features/documentation and see if people like the idea. From what I can tell nothing with this approach would be breaking right? For example exporting the preview could be a change made to the stable version to make it available already without much fuss.

Probably providing content around this approach would also be good to get some feedback on the idea. Have you written about this somewhere?

toddpi314 commented 2 years ago

Same experience with web-native-web mounted in custom webconfig for storybook-web historically. Works like a charm.

100% agree on the simplicity of CSF being supported on storybook/react-native side. I think the "Story Facade" idea is really just a byproduct of CSF 3.0 no being portable on storybook/react-native@v5.

Since it sounds like a good idea, I'll get a PR up in this repo/examples folder to showcase how it could potentially work on storybook/react-native@v6. Basing it on CSF on both sides (web, native) would simplify it greatly. We can let folks beat up the approach on the PR.