Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[onDeviceUI] Add ability to render addons in React Native #4381

Merged
merged 103 commits into from
Oct 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
8bf63f5
Reducing the size of the ui.
Gongreg Jul 19, 2018
2a6fe0f
Addon scrollview with addon names
Gongreg Jul 19, 2018
233f369
Updated style, shows addons list with loaded addons.
Gongreg Jul 20, 2018
f745fdb
Updated status bar, so content would not be drawn below it on android.
Gongreg Jul 20, 2018
676c110
Added some addons to example.
Gongreg Jul 20, 2018
dc3b8a4
Moved out of state
Gongreg Jul 20, 2018
07b502d
Fixed event on android.
Gongreg Jul 20, 2018
a8af427
Temporary disabled yellow box.
Gongreg Jul 20, 2018
e5ca681
Adding two options for storybook ui:
Gongreg Aug 2, 2018
8d31f83
Creating rn-addons.js file inside generators.
Gongreg Aug 2, 2018
838748e
Removed separate addon store.
Gongreg Aug 2, 2018
d62e440
Using active prop.
Gongreg Aug 2, 2018
cd0f98a
Rewrote addons wrapper without using modal.
Gongreg Aug 2, 2018
20969ec
Fixing yellow box warnings.
Gongreg Aug 2, 2018
21d19c2
Addon window by default is scrollable.
Gongreg Aug 3, 2018
6215c8e
Removed yellow box disabling, cleared up example index.
Gongreg Aug 3, 2018
33c99ab
Reverted accidentally deleted line.
Gongreg Aug 3, 2018
40007cf
Updated dependencies.
Gongreg Aug 3, 2018
5a9e6ff
Dependency bump
Gongreg Aug 3, 2018
15f48af
Updated UI. Removed modal, displaying menus as panels appearing from …
Gongreg Aug 17, 2018
ab3cacd
Clearing up the style a little bit.
Gongreg Aug 20, 2018
882cf00
fixed merge conflict
Gongreg Aug 30, 2018
1fca1dc
Temporary disabling some examples
Gongreg Aug 30, 2018
e383470
Updating the readmes.
Gongreg Aug 30, 2018
05c96f0
Updating the readme.
Gongreg Aug 30, 2018
cd957da
Added notes addon that support rn
Gongreg Aug 30, 2018
b1d1d5f
Updated addon documentation regarding setTimeout.
Gongreg Aug 30, 2018
ff66452
Fixed proptypes issue, properly set initial tab from the props.
Gongreg Aug 30, 2018
9722c17
Reduced the amount of rerenders, if you use onDeviceUI it only listen…
Gongreg Aug 31, 2018
dd1fc34
Adding more addons.
Gongreg Aug 31, 2018
066801d
OnDeviceUI is now set to true by default.
Gongreg Aug 31, 2018
f59a64f
Updated the notes addon so it renders markdown properly.
Gongreg Aug 31, 2018
a8db10a
Fixes endless cycle when initially rendering when both onDeviceUI and…
Gongreg Aug 31, 2018
94f7df1
Selection prop is not required ( it is not set when not using onDevic…
Gongreg Aug 31, 2018
02057e6
Renamed rn-notes to ondevice-notes addon.
Gongreg Aug 31, 2018
68fe8a9
Added option to use channels as async.
Gongreg Sep 1, 2018
409de89
Using async channel if onDeviceUI is set to true.
Gongreg Sep 1, 2018
c0fac41
Updated notes documentation/tests.
Gongreg Sep 1, 2018
ce55c96
Adding backgrounds addon.
Gongreg Sep 1, 2018
ab8dc32
Updated notes readme.
Gongreg Sep 1, 2018
2d8dfec
Adding ondevice knobs addon.
Gongreg Sep 1, 2018
5dd635c
Updated example
Gongreg Sep 1, 2018
119b3d1
Merge remote-tracking branch 'origin/master' into rn-storybook-new-ui
Gongreg Sep 1, 2018
080e86c
Reverted accidental merge issue.
Gongreg Sep 1, 2018
7400136
Updating documentation.
Gongreg Sep 1, 2018
3cb9eea
Fixed knobs entry file.
Gongreg Sep 3, 2018
ac8628b
Updating documentation.
Gongreg Sep 3, 2018
8ea2c5e
Updating documentation.
Gongreg Sep 3, 2018
bc33f26
Removed packager completely.
Gongreg Sep 3, 2018
50d2a95
Updated cli.
Gongreg Sep 3, 2018
5bd522f
Added missing dependency.
Gongreg Sep 3, 2018
75ac400
Websocket doesn't throw red screen on connection fail anymore.
Gongreg Sep 4, 2018
53df36c
Takes children from props instead out of state..
Gongreg Sep 4, 2018
42d23f8
Fixed bug where selecting story didn't actually select it.
Gongreg Sep 4, 2018
828c80f
Removed ondeviceUI in example.
Gongreg Sep 4, 2018
d0fb7e6
If it fails to connect it selects initial story.
Gongreg Sep 4, 2018
c692813
Knobs are properly reset on change.
Gongreg Sep 4, 2018
708347f
Proper import in example
Gongreg Sep 4, 2018
2677250
Reverts to localhost if no host is defined.
Gongreg Sep 13, 2018
65063d8
Ui doesnt jump when hiding bottom bar, should handle keyboard correct…
Gongreg Sep 13, 2018
495670f
Updated background addon to unregister on unmount.
Gongreg Sep 24, 2018
8aa8e72
Properly handles animations on android.
Gongreg Oct 7, 2018
69f8448
Creates channel as soon as getStorybookUI is called instead of during…
Gongreg Oct 7, 2018
7e98e1d
Displays message if no addons are loaded.
Gongreg Oct 7, 2018
5ab26de
setOptions called without timeout.
Gongreg Oct 7, 2018
19b5091
Sets initial story if connection to websocket server fail.
Gongreg Oct 7, 2018
11bf337
Updating style.
Gongreg Oct 7, 2018
1aeccd0
Removed margin bottom.
Gongreg Oct 7, 2018
2eccce4
Added swiping on the nav bar, touching preview maximizes it.
Gongreg Oct 7, 2018
08b2df5
Fixed keyboard aware view.
Gongreg Oct 7, 2018
bd57fe7
Fixed background panel so it doesn't lose color immediately.
Gongreg Oct 7, 2018
8e210ca
Uses preview width for panels.
Gongreg Oct 7, 2018
54b377c
Merge master.
Gongreg Oct 8, 2018
2fbd755
Moving class inside preview.
Gongreg Oct 8, 2018
ceee056
All react native installations receive same template.
Gongreg Oct 8, 2018
e8c8d83
Removed react_native fixture.
Gongreg Oct 8, 2018
4a2b64d
Fixing lint.
Gongreg Oct 8, 2018
c0ff8fe
Lint fix.
Gongreg Oct 8, 2018
44bb6cb
Improving performance dramatically.
Gongreg Oct 8, 2018
8e255f8
Merge remote-tracking branch 'origin/master' into rn-storybook-new-ui
Gongreg Oct 9, 2018
11e8f87
Merge branch 'addons-async-option' into rn-storybook-new-ui
Gongreg Oct 9, 2018
048b2b4
Adding on device addons.
Gongreg Oct 9, 2018
4012044
Merge branch 'on-device-addons' into rn-storybook-new-ui
Gongreg Oct 9, 2018
edfaa09
Merge branch 'addons-async-option' into on-device-ui-all-prs
Gongreg Oct 9, 2018
6db1f75
Merge branch 'react-native-cli-template' into on-device-ui-all-prs
Gongreg Oct 9, 2018
7d98112
Merge branch 'react-native-cli-template' into rn-storybook-new-ui
Gongreg Oct 9, 2018
fb68670
Reverted back fixtures change.
Gongreg Oct 9, 2018
75cabdf
Reverting file change
Gongreg Oct 9, 2018
667785a
Merge branch 'on-device-ui-all-prs' into rn-storybook-new-ui
Gongreg Oct 9, 2018
f622a08
Updating readmes.
Gongreg Oct 9, 2018
30d0fd2
Updated readme about server.
Gongreg Oct 9, 2018
afe1b5f
Reverted yarn.lock
Gongreg Oct 9, 2018
85e8742
Fixing propTypes.
Gongreg Oct 9, 2018
8eba6b2
Splitting out onDeviceUI/index to smaller components.
Gongreg Oct 9, 2018
748a9c9
Splitting up onDeviceUI.
Gongreg Oct 9, 2018
2adbce8
Removed unused dependency.
Gongreg Oct 9, 2018
755f552
Properly uses whole screen for preview.
Gongreg Oct 9, 2018
36bd66d
Updated visibility button.
Gongreg Oct 9, 2018
18fccca
Few code review fixes
Gongreg Oct 10, 2018
d32952d
Merge pull request #3903 from storybooks/rn-storybook-new-ui
ndelangen Oct 11, 2018
4499cb5
Fixed where width is taken from.
Gongreg Oct 12, 2018
d5387d9
Merge pull request #4379 from storybooks/rn-storybook-new-ui
Gongreg Oct 12, 2018
90f2d48
Merge master
Gongreg Oct 12, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 21 additions & 19 deletions ADDONS_SUPPORT.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
## Addon / Framework Support Table

| | [React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)| [Svelte](app/svelte)| [Riot](app/riot)| [Ember](app/ember)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| |+|+|+|+|+|+| | |+|
|[actions](addons/actions) |+|+|+|+|+|+|+|+|+|+|+|
|[backgrounds](addons/backgrounds)|+| |+|+|+|+|+|+|+|+|+|
|[centered](addons/centered) |+| |+|+| |+|+| |+| |+|
|[events](addons/events) |+| |+|+|+|+|+|+| | |+|
|[graphql](addons/graphql) |+| | | | | | | | | | |
|[info](addons/info) |+| | | | | | | | | | |
|[jest](addons/jest) |+| | |+| | |+| | | | |
|[knobs](addons/knobs) |+|+|+|+|+|+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|+| |+|+|+|
|[notes](addons/notes) |+| |+|+|+|+|+| |+|+|+|
|[options](addons/options) |+|+|+|+|+|+|+| |+|+|+|
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |+|+| |
|[storysource](addons/storysource)|+| |+|+|+|+|+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|+|+|+|
## Addon / Framework Support Table

| | [React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)| [Svelte](app/svelte)| [Riot](app/riot)| [Ember](app/ember)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| |+|+|+|+|+|+| | |+|
|[actions](addons/actions) |+|+|+|+|+|+|+|+|+|+|+|
|[backgrounds](addons/backgrounds)|+|*|+|+|+|+|+|+|+|+|+|
|[centered](addons/centered) |+| |+|+| |+|+| |+| |+|
|[events](addons/events) |+| |+|+|+|+|+|+| | |+|
|[graphql](addons/graphql) |+| | | | | | | | | | |
|[info](addons/info) |+| | | | | | | | | | |
|[jest](addons/jest) |+| | |+| | |+| | | | |
|[knobs](addons/knobs) |+|+*|+|+|+|+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|+| |+|+|+|
|[notes](addons/notes) |+|+*|+|+|+|+|+| |+|+|+|
|[options](addons/options) |+|+|+|+|+|+|+| |+|+|+|
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |+|+| |
|[storysource](addons/storysource)|+| |+|+|+|+|+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|+|+|+|

`*` - React Native on device addon (addons/onDevice-\<name>)
50 changes: 50 additions & 0 deletions app/react-native/docs/addons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Addons

Storybook supports addons. You can read more about them [here](https://storybook.js.org/addons/introduction/)

There is one big difference in React Native is that it has two types of addons: Addons that work in the browser
and addons that work on the app itself (on device addons).

## Browser addons
Browser addons are default addons to storybook. You create a file called addons.js inside storybook and it is
automatically added inside your browser.

## On device addons
On device addons are addons that are displayed in your app in addons panel.
To use them you have to create a file called `rn-addons.js` next to your storybook entry.
Because React Native does not dynamically resolve imports, you also have to manually import them.
Example:
**storybook/index.js**
```
import { getStorybookUI, configure } from '@storybook/react-native';
import './rn-addons';
// import stories
configure(() => {
require($PATH_TO_STORIES);
}, module);

const StorybookUI = getStorybookUI();
export default StorybookUI;

**storybook/rn-addons.js**
```
import '@storybook/addon-ondevice-knobs/register';
import '@storybook/addon-ondevice-notes/register';
...
```

This step is done automatically when you install Storybook for the first time and also described in [Manual Setup](https://github.com/storybooks/storybook/blob/master/app/react-native/docs/manual-setup.md)

## Compatibility
Addon compatibilty can be found [here](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

## Performance of on device addons
Because on device addons are inside the app, they are also rerendered on every change. This can reduce performance a lot.

## Writing the on device addons
On device addons use same addon store and api as web addons. The only difference in api is that you don't have `api` prop
and have to rely on channel for everything.

The main difference between browser and app addons is that the render has to be supported by React Native (View, Text).
For more info about writing addons read [writing addons](https://storybook.js.org/addons/writing-addons/) section in
storybook documentation.
55 changes: 40 additions & 15 deletions app/react-native/docs/manual-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,38 @@ First, install the `@storybook/react-native` module
npm install @storybook/react-native
```

Create a new directory called `storybook` in your project root and create an entry file (index.ios.js or index.android.js) as given below. (Don't forget to replace "MyApplicationName" with your app name).
Create a new directory called `storybook` in your project root and create an entry file (index.js) as given below.
(Don't forget to replace "MyApplicationName" with your app name).

**storybook/index.js**
```js
import { AppRegistry } from 'react-native';
import { getStorybookUI, configure } from '@storybook/react-native';
import './addons';
import './rn-addons';

// import your stories
configure(function() {
// import stories
configure(() => {
// eslint-disable-next-line global-require
require('./stories');
}, module);

const StorybookUI = getStorybookUI({
port: 7007,
host: 'localhost',
});
AppRegistry.registerComponent('MyApplicationName', () => StorybookUI);
const StorybookUIRoot = getStorybookUI();

AppRegistry.registerComponent('MyApplicationName', () => StorybookUIRoot);
export default StorybookUIRoot;
```

Create a file named `addons.js` file in `storybook` directory to use addons. Here is a list of default addons:
Create a file called `rn-addons.js`
In this file you can import on device addons.

```js
import '@storybook/addon-actions';
import '@storybook/addon-links';
**storybook/rn-addons.js**
```
import '@storybook/addon-ondevice-knobs/register';
import '@storybook/addon-ondevice-notes/register';
...
```


Then write your first story in the `stories` directory like this:

```js
Expand All @@ -58,12 +64,31 @@ storiesOf('CenteredView')
));
```

Then add following NPM script into your `package.json` file:
Finally replace your app entry with
```js
import './storybook';
```
If you cannot replace your entry point just make sure that the component exported from `./storybook` is displayed
somewhere in your app. `StorybookUI` is simply a RN `View` component that can be embedded anywhere in your
RN application, e.g. on a tab or within an admin screen.

## Server support

If you want to support having a storybook server running add following NPM script into your `package.json` file:

```json
{
"scripts": {
"storybook": "storybook start -p 7007"
"storybook": "storybook start"
}
}
```

If you want to have addons inside browser, create a file named `addons.js` file in `storybook`. Here is a list of default addons:

**storybook/addons.js**
```js
import '@storybook/addon-actions';
import '@storybook/addon-links';
```

24 changes: 24 additions & 0 deletions app/react-native/docs/server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Storybook server
The default usage of React Native Storybook till version 4 involved starting Storybook server.
Starting from v4 we do not expect user to start the server since in most cases it is not really necessary.

In case you still want to run Storybook server simply call `npm run storybook` or `npx storybook start`.

## Benefits of storybook server

* ### Websockets connection
The main benefit you get from running storybook server is that your app will be listening for websockets connection.
That means that you can create your own tools that integrate with your storybook app.

* ### IDE Plugins
Having server running allows you to control your storybook view from inside web page or your ide.

There is a plugin for [JetBrains IDEs](https://plugins.jetbrains.com/plugin/9910-storybook) and there is one
for [VS Code](https://github.com/orta/vscode-react-native-storybooks).


* ### Web addons
There are Storybook addons that work with React Native but do not have on device implementations.



4 changes: 2 additions & 2 deletions app/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.24",
"@storybook/channels": "4.0.0-alpha.24",
"@storybook/channel-websocket": "4.0.0-alpha.24",
"@storybook/core": "4.0.0-alpha.24",
"@storybook/core-events": "4.0.0-alpha.24",
Expand Down Expand Up @@ -57,8 +58,7 @@
"prop-types": "^15.6.2",
"raw-loader": "^0.5.1",
"react-dev-utils": "6.0.4",
"react-native-compat": "^1.0.0",
"react-native-iphone-x-helper": "^1.2.0",
"react-native-swipe-gestures": "^1.0.2",
"shelljs": "^0.8.2",
"universal-dotenv": "^1.9.1",
"url-parse": "^1.4.3",
Expand Down
8 changes: 6 additions & 2 deletions app/react-native/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ You can pass these parameters to getStorybookUI call in your storybook entry poi

```
{
onDeviceUI: Boolean (false)
-- display stories list on the device
onDeviceUI: Boolean (true)
-- display navigator and addons on the device
disableWebsockets: Boolean (false)
-- allows to display stories without running storybook server. Should be used with onDeviceUI
secured: Boolean (false)
Expand All @@ -116,6 +116,10 @@ You can pass these parameters to getStorybookUI call in your storybook entry poi
-- port to use
query: String ("")
-- additional query string to pass to websockets
isUIHidden: Boolean (false)
-- should the ui be closed initialy.
tabOpen: Number (0)
-- which tab should be open. -1 Navigator, 0 Preview, 1 Addons
}
```

Expand Down
6 changes: 3 additions & 3 deletions app/react-native/src/bin/storybook-start.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import program from 'commander';
import Server from '../server';

program
.option('-h, --host <host>', 'host to listen on')
.option('-p, --port <port>', 'port to listen on')
.option('-h, --host <host>', 'host to listen on', 'localhost')
.option('-p, --port <port>', 'port to listen on', 7007)
.option('-s, --secured', 'whether server is running on https')
.option('-c, --config-dir [dir-name]', 'storybook config directory')
.option('-e, --environment [environment]', 'DEVELOPMENT/PRODUCTION environment for webpack')
Expand All @@ -33,7 +33,7 @@ server.listen(...listenAddr, err => {
if (err) {
throw err;
}
const address = `http://${program.host || 'localhost'}:${program.port}/`;
const address = `http://${program.host}:${program.port}/`;
console.info(`\nReact Native Storybook started on => ${address}\n`);
if (program.smokeTest) {
process.exit(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { Platform, Keyboard, Dimensions, View } from 'react-native';

import style from './style';

// Android changes screen size when keyboard opens.
// To avoid issues we use absolute positioned element with predefined screen size
export default class AbsolutePositionedKeyboardAwareView extends PureComponent {
componentWillMount() {
this.keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
this.keyboardDidShowHandler
);
this.keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
this.keyboardDidHideHandler
);
Dimensions.addEventListener('change', this.removeKeyboardOnOrientationChange);
}

componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
Dimensions.removeEventListener('change', this.removeKeyboardOnOrientationChange);
}

keyboardDidShowHandler = e => {
if (Platform.OS === 'android') {
const { previewWidth } = this.props;
// There is bug in RN android that keyboardDidShow event is called simply when you go from portrait to landscape.
// To make sure that this is keyboard event we check screen width
if (previewWidth === e.endCoordinates.width) {
this.keyboardOpen = true;
}
}
};

// When rotating screen from portrait to landscape with keyboard open on android it calls keyboardDidShow, but doesn't call
// keyboardDidHide. To avoid issues we set keyboardOpen to false immediately on keyboardChange.
removeKeyboardOnOrientationChange = () => {
if (Platform.OS === 'android') {
this.keyboardOpen = false;
}
};

keyboardDidHideHandler = () => {
if (this.keyboardOpen) {
this.keyboardOpen = false;
}
};

onLayoutHandler = ({ nativeEvent }) => {
if (!this.keyboardOpen) {
const { width, height } = nativeEvent.layout;
const { onLayout } = this.props;

onLayout({
previewHeight: height,
previewWidth: width,
});
}
};

render() {
const { children, previewWidth, previewHeight } = this.props;

return (
<View style={style.flex} onLayout={this.onLayoutHandler}>
<View
style={
previewWidth === 0
? style.flex
: { position: 'absolute', width: previewWidth, height: previewHeight }
}
>
{children}
</View>
</View>
);
}
}

AbsolutePositionedKeyboardAwareView.propTypes = {
children: PropTypes.node.isRequired,
previewWidth: PropTypes.number.isRequired,
previewHeight: PropTypes.number.isRequired,
onLayout: PropTypes.func.isRequired,
};