Integrate storybook

This commit is contained in:
Rodrigo Nascimento 2017-08-17 16:31:27 -03:00
parent c11141aa3b
commit e64e34ef7e
16 changed files with 7737 additions and 32 deletions

View File

@ -69,3 +69,24 @@ Follow the [React Native Getting Started Guide](https://facebook.github.io/react
- Start emulator - Start emulator
- Start react packager: `$ react-native start` - Start react packager: `$ react-native start`
- Run in emulator: `$ react-native run-android` - Run in emulator: `$ react-native run-android`
# Storybook
- General requirements
- Install storybook
```bash
$ npm i -g @storybook/cli
```
- Running storybook
- Run storybook application
```bash
$ npm run storybook
```
- Run application in other shell
```bash
$ react-native run-ios
```
- Running storybook on browser to help stories navigation
```
open http://localhost:7007/
```

View File

@ -8,10 +8,10 @@ import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, // flex: 1,
flexDirection: 'row', flexDirection: 'row',
paddingLeft: 16, paddingLeft: 16,
paddingRight: 56, paddingRight: 16,
height: 56, height: 56,
alignItems: 'center' alignItems: 'center'
}, },
@ -23,15 +23,15 @@ const styles = StyleSheet.create({
textAlign: 'center', textAlign: 'center',
overflow: 'hidden', overflow: 'hidden',
fontSize: 14, fontSize: 14,
right: 16, paddingLeft: 5,
marginLeft: 16, paddingRight: 5
position: 'absolute'
}, },
roomName: { roomName: {
flexGrow: 1, flex: 1,
fontSize: 16, fontSize: 16,
color: '#444', color: '#444',
marginLeft: 16 marginLeft: 16,
marginRight: 4
}, },
iconContainer: { iconContainer: {
height: 40, height: 40,
@ -52,36 +52,39 @@ const styles = StyleSheet.create({
borderRadius: 20 borderRadius: 20
}, },
avatarInitials: { avatarInitials: {
fontSize: 22, fontSize: 20,
color: '#ffffff' color: '#ffffff'
} }
}); });
export default class RoomItem extends React.PureComponent { export default class RoomItem extends React.PureComponent {
static propTypes = { static propTypes = {
item: PropTypes.object.isRequired, type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
unread: PropTypes.number,
baseUrl: PropTypes.string baseUrl: PropTypes.string
} }
get icon() { get icon() {
const { type, name, baseUrl } = this.props;
const icon = { const icon = {
d: 'at', d: 'at',
c: 'pound', c: 'pound',
p: 'lock', p: 'lock',
l: 'account' l: 'account'
}[this.props.item.t]; }[type];
if (!icon) { if (!icon) {
return null; return null;
} }
const { name } = this.props.item; if (type === 'd') {
if (this.props.item.t === 'd') {
const { initials, color } = avatarInitialsAndColor(name); const { initials, color } = avatarInitialsAndColor(name);
return ( return (
<View style={[styles.iconContainer, { backgroundColor: color }]}> <View style={[styles.iconContainer, { backgroundColor: color }]}>
<Text style={styles.avatarInitials}>{initials}</Text> <Text style={styles.avatarInitials}>{initials}</Text>
<CachedImage style={styles.avatar} source={{ uri: `${ this.props.baseUrl }/avatar/${ name }` }} /> <CachedImage style={styles.avatar} source={{ uri: `${ baseUrl }/avatar/${ name }` }} />
</View> </View>
); );
} }
@ -95,26 +98,30 @@ export default class RoomItem extends React.PureComponent {
); );
} }
renderNumber = (item) => { renderNumber = (unread) => {
if (item.unread) { if (!unread || unread <= 0) {
return ( return;
<Text style={styles.number}>
{ item.unread }
</Text>
);
} }
if (unread >= 1000) {
unread = '999+';
}
return (
<Text style={styles.number}>
{ unread }
</Text>
);
} }
render() { render() {
let extraSpace = {}; const { unread, name } = this.props;
if (this.props.item.unread) {
extraSpace = { paddingRight: 92 };
}
return ( return (
<View style={[styles.container, extraSpace]}> <View style={styles.container}>
{this.icon} {this.icon}
<Text style={styles.roomName} ellipsizeMode='tail' numberOfLines={1}>{ this.props.item.name }</Text> <Text style={styles.roomName} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
{this.renderNumber(this.props.item)} {this.renderNumber(unread)}
</View> </View>
); );
} }

View File

@ -84,7 +84,9 @@ class RoomsListItem extends React.PureComponent {
<TouchableOpacity key={item._id} onPress={() => this.props.onPress(item._id, item)}> <TouchableOpacity key={item._id} onPress={() => this.props.onPress(item._id, item)}>
<RoomItem <RoomItem
id={item._id} id={item._id}
item={item} type={item.t}
name={item.name}
unread={item.unread}
baseUrl={this.props.baseUrl} baseUrl={this.props.baseUrl}
/> />
</TouchableOpacity> </TouchableOpacity>

View File

@ -8,7 +8,8 @@
"lint": "eslint .", "lint": "eslint .",
"ios": "react-native run-ios", "ios": "react-native run-ios",
"log-android": "react-native log-android", "log-android": "react-native log-android",
"android": "react-native run-android" "android": "react-native run-android",
"storybook": "storybook start -p 7007"
}, },
"dependencies": { "dependencies": {
"babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-decorators-legacy": "^1.3.4",
@ -56,7 +57,9 @@
"eslint-plugin-react": "^7.1.0", "eslint-plugin-react": "^7.1.0",
"eslint-plugin-react-native": "^3.0.1", "eslint-plugin-react-native": "^3.0.1",
"jest": "20.0.4", "jest": "20.0.4",
"react-test-renderer": "16.0.0-alpha.12" "react-test-renderer": "16.0.0-alpha.12",
"@storybook/react-native": "^3.2.4",
"react-dom": "16.0.0-alpha.12"
}, },
"jest": { "jest": {
"preset": "react-native" "preset": "react-native"

4
storybook/addons.js Normal file
View File

@ -0,0 +1,4 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';

View File

@ -0,0 +1,3 @@
import StorybookUI from './storybook';
export default StorybookUI;

3
storybook/index.ios.js Normal file
View File

@ -0,0 +1,3 @@
import StorybookUI from './storybook';
export default StorybookUI;

View File

@ -0,0 +1,22 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React, { PropTypes } from 'react';
import { TouchableNativeFeedback } from 'react-native';
export default function Button(props) {
return (
<TouchableNativeFeedback onPress={props.onPress}>
{props.children}
</TouchableNativeFeedback>
);
}
Button.defaultProps = {
children: null,
onPress: () => {},
};
Button.propTypes = {
children: PropTypes.node,
onPress: PropTypes.func,
};

View File

@ -0,0 +1,22 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React, { PropTypes } from 'react';
import { TouchableHighlight } from 'react-native';
export default function Button(props) {
return (
<TouchableHighlight onPress={props.onPress}>
{props.children}
</TouchableHighlight>
);
}
Button.defaultProps = {
children: null,
onPress: () => {},
};
Button.propTypes = {
children: PropTypes.node,
onPress: PropTypes.func,
};

View File

@ -0,0 +1,21 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React, { PropTypes } from 'react';
import { View } from 'react-native';
import style from './style';
export default function CenterView(props) {
return (
<View style={style.main}>
{props.children}
</View>
);
}
CenterView.defaultProps = {
children: null,
};
CenterView.propTypes = {
children: PropTypes.node,
};

View File

@ -0,0 +1,8 @@
export default {
main: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
};

View File

@ -0,0 +1,65 @@
import React from 'react';
import { ScrollView } from 'react-native';
import RoomItem from '../../../app/components/RoomItem';
export default (
<ScrollView>
<RoomItem
type='d'
name='rocket.cat'
baseUrl='https://demo.rocket.chat'
/>
<RoomItem
type='d'
unread={0}
name='rocket.cat'
baseUrl='https://demo.rocket.chat'
/>
<RoomItem
type='d'
unread={1}
name='rocket.cat'
baseUrl='https://demo.rocket.chat'
/>
<RoomItem
type='d'
unread={9}
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
baseUrl='https://demo.rocket.chat'
/>
<RoomItem
type='d'
unread={99}
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
baseUrl='https://demo.rocket.chat'
/>
<RoomItem
type='d'
unread={100}
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
baseUrl='https://demo.rocket.chat'
/>
<RoomItem
type='d'
unread={100000}
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
baseUrl='https://demo.rocket.chat'
/>
<RoomItem
type='d'
name='W'
unread={-100}
/>
<RoomItem
type='d'
name='WW'
unread={-100}
/>
<RoomItem
type='d'
name=''
unread={-100}
/>
</ScrollView>
);

View File

@ -0,0 +1,54 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React, { PropTypes } from 'react';
import { View, Text, Button } 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(event) {
event.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>
);
}
}
Welcome.defaultProps = {
showApp: null
};
Welcome.propTypes = {
showApp: PropTypes.func
};

View File

@ -0,0 +1,25 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
// import React from 'react';
import { storiesOf } from '@storybook/react-native';
// import { action } from '@storybook/addon-actions';
// import { linkTo } from '@storybook/addon-links';
import DirectMessage from './Channels/DirectMessage';
storiesOf('Channel Cell', module).add('Direct Messages', () => DirectMessage);
// 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>
// ))

25
storybook/storybook.js Normal file
View File

@ -0,0 +1,25 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, global-require */
import { Navigation } from 'react-native-navigation';
import { getStorybookUI, configure } from '@storybook/react-native';
// import stories
configure(() => {
require('./stories');
}, module);
// This assumes that storybook is running on the same host as your RN packager,
// to set manually use, e.g. host: 'localhost' option
const StorybookUI = getStorybookUI({ port: 7007, onDeviceUI: true });
Navigation.registerComponent('storybook.UI', () => StorybookUI);
Navigation.startSingleScreenApp({
screen: {
screen: 'storybook.UI',
title: 'Storybook',
navigatorStyle: {
navBarHidden: true
}
}
});
export default StorybookUI;

7420
yarn.lock Normal file

File diff suppressed because it is too large Load Diff