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

View File

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

View File

@ -8,7 +8,8 @@
"lint": "eslint .",
"ios": "react-native run-ios",
"log-android": "react-native log-android",
"android": "react-native run-android"
"android": "react-native run-android",
"storybook": "storybook start -p 7007"
},
"dependencies": {
"babel-plugin-transform-decorators-legacy": "^1.3.4",
@ -56,7 +57,9 @@
"eslint-plugin-react": "^7.1.0",
"eslint-plugin-react-native": "^3.0.1",
"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": {
"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