Skip to content

Commit

Permalink
Add CRNA support
Browse files Browse the repository at this point in the history
1. detect CRNA projects
2. simplify RN and CRNA templates by consolidating app into single
`index.js` instead of `index.ios.js` and `index.android.js`
3. notify user of extra setup steps in CLI
4. document CRNA idiosyncrasies in README
  • Loading branch information
shilman committed May 24, 2017
1 parent f908535 commit 3e2673b
Show file tree
Hide file tree
Showing 15 changed files with 197 additions and 8 deletions.
41 changes: 36 additions & 5 deletions app/react-native/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,53 @@ npm -g i @storybook/cli
getstorybook
```

## Start the Storybook
After you have installed, there are additional steps for `create-react-native-app` apps. See the section for details, otherwise skip to [Start Storybook](#start-storybook)
to see the next step.

## Create React Native App (CRNA)

If you run `getstorybook` inside a CRNA app, you'll be notified that there is an extra step required to use Storybook.

The easiest way to use Storybook inside CRNA is to simply replace your App with the Storybook UI, which is possible by replacing `App.js` with a single line of code:

```js
export default from './storybook';
```

This will get you up and running quickly, but then you lose your app!
There are multiple options here. for example, you can export conditionally:

```js
import StorybookUI from './storybook';
module.exports = __DEV__ ? StorybookUI : App;
```

Alternatively, `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.

## Start Storybook

After initial setup start the storybook server with the storybook npm script.

```shell
npm run storybook
```

also start your mobile app with the `react-native` command.
Now, you can open <http://localhost:7007> to view your storybook menus in the browser.

## Start App

To see your Storybook stories on the device, you should start your mobile app for the `<platform>` of your choice (typically `ios` or `android`).

For CRNA apps:
```
npm run <platform>
```
For RN apps:
```
react-native run-ios
react-native run-android
react-native run-<platform>
```

Now, you can open <http://localhost:7007> to view your storybook.
Once your app is started, changing the selected story in web browser will update the story displayed within your mobile app.

## Learn More

Expand Down
21 changes: 21 additions & 0 deletions lib/cli/bin/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ const end = () => {
logger.log();
};

const CRNA_DISCUSSION =
'https://github.com/storybooks/storybook/blob/master/app/react-native/docs/manual-setup.md';

switch (projectType) {
case types.ALREADY_HAS_STORYBOOK:
logger.log();
Expand All @@ -83,6 +86,24 @@ switch (projectType) {
.then(end);
break;

case types.REACT_NATIVE_SCRIPTS:
require('../generators/REACT_NATIVE_SCRIPTS')
.then(commandLog('Adding storybook support to your "Create React Native App" app'))
.then(end)
.then(() => {
logger.log(chalk.red('NOTE: CRNA app installation is not 100% automated.'));
logger.log(
'To quickly run storybook, replace contents of',
chalk.bold('\'./App.js\''),
'with:\n'
);
codeLog(["export default from './storybook';"]);
logger.log('\nFor a more complete discussion of options, see:\n');
logger.log(chalk.cyan(CRNA_DISCUSSION));
logger.log();
});
break;

case types.REACT_NATIVE:
require('../generators/REACT_NATIVE')
.then(commandLog('Adding storybook support to your "React Native" app'))
Expand Down
3 changes: 1 addition & 2 deletions lib/cli/generators/REACT_NATIVE/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ module.exports = latestVersion('@storybook/react-native').then(version => {
const projectName =
dirname && dirname.slice('ios/'.length, dirname.length - '.xcodeproj'.length - 1);
if (projectName) {
shell.sed('-i', '%APP_NAME%', projectName, 'storybook/index.ios.js');
shell.sed('-i', '%APP_NAME%', projectName, 'storybook/index.android.js');
shell.sed('-i', '%APP_NAME%', projectName, 'storybook/index.js');
}

const packageJson = helpers.getPackageJson();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ configure(() => {

const StorybookUI = getStorybookUI({ port: 7007, host: 'localhost' });
AppRegistry.registerComponent('%APP_NAME%', () => StorybookUI);
export default StorybookUI;
26 changes: 26 additions & 0 deletions lib/cli/generators/REACT_NATIVE_SCRIPTS/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const mergeDirs = require('merge-dirs').default;
const helpers = require('../../lib/helpers');
const path = require('path');
const shell = require('shelljs');
const latestVersion = require('latest-version');

module.exports = latestVersion('@storybook/react-native').then(version => {
// copy all files from the template directory to project directory
mergeDirs(path.resolve(__dirname, 'template/'), '.', 'overwrite');

const packageJson = helpers.getPackageJson();

packageJson.dependencies = packageJson.dependencies || {};
packageJson.devDependencies = packageJson.devDependencies || {};

packageJson.devDependencies['@storybook/react-native'] = `^${version}`;

if (!packageJson.dependencies['react-dom'] && !packageJson.devDependencies['react-dom']) {
packageJson.devDependencies['react-dom'] = '^15.5.4';
}

packageJson.scripts = packageJson.scripts || {};
packageJson.scripts['storybook'] = 'storybook start -p 7007';

helpers.writePackageJson(packageJson);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ configure(() => {
}, module);

const StorybookUI = getStorybookUI({ port: 7007, host: 'localhost' });
AppRegistry.registerComponent('%APP_NAME%', () => StorybookUI);
export default StorybookUI;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { TouchableNativeFeedback } from 'react-native';

export default function Button(props) {
return (
<TouchableNativeFeedback onPress={props.onPress || Function()}>
{props.children}
</TouchableNativeFeedback>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { TouchableHighlight } from 'react-native';

export default function Button(props) {
return (
<TouchableHighlight onPress={props.onPress || Function()}>
{props.children}
</TouchableHighlight>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { View } from 'react-native';
import style from './style';

export default function CenterView(props) {
return (
<View style={style.main}>
{props.children}
</View>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default {
main: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import { View, Text } from 'react-native';

export default class Welcome extends React.Component {
styles = {
wrapper: {
flex: 1,
padding: 24,
justifyContent: 'center',
},
header: {
fontSize: 18,
marginBottom: 18,
},
content: {
fontSize: 12,
marginBottom: 10,
lineHeight: 18,
},
};

showApp(e) {
e.preventDefault();
if (this.props.showApp) this.props.showApp();
}

render() {
return (
<View style={this.styles.wrapper}>
<Text style={this.styles.header}>Welcome to React Native Storybook</Text>
<Text style={this.styles.content}>
This is a UI Component development environment for your React Native app. Here you can display and interact with your UI components as stories. A story is a single state of one or more UI components. You can have as many stories as you want. In other words a story is like a visual test case.
</Text>
<Text style={this.styles.content}>
We have added some stories inside the "storybook/stories" directory for examples. Try editing the "storybook/stories/Welcome.js" file to edit this message.
</Text>
</View>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { Text } from 'react-native';

import { storiesOf } from '@storybook/react-native';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';

import Button from './Button';
import CenterView from './CenterView';
import Welcome from './Welcome';

storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);

storiesOf('Button', module)
.addDecorator(getStory => <CenterView>{getStory()}</CenterView>)
.add('with text', () => (
<Button onPress={action('clicked-text')}>
<Text>Hello Button</Text>
</Button>
))
.add('with some emoji', () => (
<Button onPress={action('clicked-emoji')}>
<Text>😀 😎 👍 💯</Text>
</Button>
));
4 changes: 4 additions & 0 deletions lib/cli/lib/detect.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ module.exports = function detect(options) {
return types.REACT_PROJECT;
}

if (packageJson.dependencies && packageJson.devDependencies['react-native-scripts']) {
return types.REACT_NATIVE_SCRIPTS;
}

if (packageJson.dependencies && packageJson.dependencies['react-native']) {
return types.REACT_NATIVE;
}
Expand Down
1 change: 1 addition & 0 deletions lib/cli/lib/project_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
METEOR: 'METEOR',
REACT: 'REACT',
REACT_NATIVE: 'REACT_NATIVE',
REACT_NATIVE_SCRIPTS: 'REACT_NATIVE_SCRIPTS',
REACT_PROJECT: 'REACT_PROJECT',
WEBPACK_REACT: 'WEBPACK_REACT',
ALREADY_HAS_STORYBOOK: 'ALREADY_HAS_STORYBOOK',
Expand Down

0 comments on commit 3e2673b

Please sign in to comment.