Commit ccbcd94d by Ari Rizzitano

goodbye docs, hello storybook!

parent ca16f6cd
......@@ -6,5 +6,6 @@
}
}],
"babel-preset-react"
]
],
"plugins": ["transform-object-rest-spread"]
}
......@@ -2,5 +2,3 @@
.eslintcache
node_modules
npm-debug.log
/docs
......@@ -2,5 +2,3 @@
.eslintcache
node_modules
npm-debug.log
/docs
import { configure } from '@kadira/storybook';
function loadStories() {
require('../stories');
}
configure(loadStories, module);
// you can use this file to add your custom webpack plugins, loaders and anything you like.
// This is just the basic way to add addional webpack configurations.
// For more information refer the docs: https://getstorybook.io/docs/configurations/custom-webpack-config
// IMPORTANT
// When you add this file, we won't add the default configurations which is similar
// to "React Create App". This only has babel loader to load JavaScript.
module.exports = {
plugins: [
// your custom plugins
],
module: {
loaders: [
// add your custom loaders.
],
},
};
......@@ -7,11 +7,11 @@
"license": "MIT",
"scripts": {
"build": "NODE_ENV=production webpack",
"build-docs": "NODE_ENV=docs && install-self-peers && webpack",
"build-storybook": "build-storybook",
"lint": "eslint .",
"prestart": "install-self-peers",
"poststop": "yarn install",
"start": "BABEL_ENV=webpack webpack-dev-server --watch"
"start": "start-storybook -p 6006"
},
"dependencies": {
"classnames": "^2.2.5",
......@@ -19,9 +19,11 @@
"reactstrap": "^4.5.0"
},
"devDependencies": {
"@kadira/storybook": "^2.21.0",
"@team-griffin/install-self-peers": "^1.0.0",
"babel-cli": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-plugin-transform-object-rest-spread": "^6.23.0",
"babel-preset-babili": "^0.0.12",
"babel-preset-env": "^1.4.0",
"babel-preset-react": "^6.24.1",
......
......@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Input, Label } from 'reactstrap';
import PropTypes from 'prop-types';
import { newId } from './utils';
import newId from './utils/newId';
class SelectInput extends React.Component {
constructor(props) {
......
import React, { Component } from 'react';
import { Input, Label, FormGroup, FormFeedback, FormText } from 'reactstrap';
import PropTypes from 'prop-types';
import { newId } from './utils';
class TextInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.state = {
uuid: newId('textInput'),
value: this.props.value,
isValid: true,
validationMessage: ''
};
}
getDescriptionElements() {
let descriptionElements = {},
descriptionId,
descriptionMessages = [];
if (this.props.description) {
descriptionId = `description-${this.state.uuid}`;
descriptionMessages.push(
<FormText id={descriptionId} key="0">
{this.props.description}
</FormText>
);
}
if (!this.state.isValid) {
const errorId = `error-${this.state.uuid}`;
descriptionId = `${errorId} ${descriptionId}`
descriptionMessages = [(
<FormFeedback id={errorId} key="1">
{this.state.validationMessage}
</FormFeedback>),
...descriptionMessages
];
}
descriptionElements = {
descriptionId,
description: descriptionMessages
}
return descriptionElements;
}
handleChange(event) {
this.setState({value: event.target.value});
this.props.onChange(event.target.value, this.props.name);
}
handleBlur(event) {
if (this.props.validator) {
this.setState(this.props.validator);
}
}
render() {
const { descriptionId, description } = this.getDescriptionElements(),
inputState = (!this.state.isValid) ? 'warning' : '';
return (
<div className={this.props.className}>
<FormGroup color={inputState}>
<Label for={this.state.uuid}>{this.props.label}</Label>
<Input
id={this.state.uuid}
type="text"
name={this.props.name}
value={this.state.value}
placeholder={this.props.placeholder}
aria-describedby={descriptionId}
onChange={this.handleChange}
onBlur={this.handleBlur}
aria-invalid={!this.state.isValid}
state={inputState}
/>
{description}
</FormGroup>
</div>
);
}
import React from 'react';
import { Input } from 'reactstrap';
import asInput from './utils/asInput';
function TextField (props) {
return (
<Input
id={props.id}
type="text"
name={props.name}
value={props.value}
placeholder={props.placeholder}
aria-describedby={props.describedBy}
onChange={props.onChange}
onBlur={props.onBlur}
aria-invalid={!props.isValid}
required={props.required}
state={props.inputState}
/>
);
}
TextInput.propTypes = {
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.string,
PropTypes.element
]),
disabled: PropTypes.bool,
onChange: PropTypes.func
};
const TextInput = asInput(TextField);
TextInput.defaultProps = {
onChange: () => {}
onChange: () => {},
value: ''
};
export default TextInput;
import React from 'react';
import PropTypes from 'prop-types';
import { Label, FormGroup, FormFeedback, FormText } from 'reactstrap';
import newId from './newId';
const getDisplayName = WrappedComponent => {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
};
const asInput = WrappedComponent => {
class NewComponent extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleBlur = this.handleBlur.bind(this);
const id = newId('textInput');
this.state = {
id: id,
value: this.props.value,
isValid: true,
describedBy: [],
errorId: `error-${id}`,
descriptionId: `description-${id}`,
};
}
handleChange(event) {
this.setState({value: event.target.value});
this.props.onChange(event.target.value, this.props.name);
}
handleBlur(event) {
if (this.props.validator) {
this.setState(this.props.validator);
}
}
getDescriptions() {
// possible future work: multiple feedback msgs?
const errorId = `error-${this.state.id}`,
descriptionId = `description-${this.state.id}`;
let desc = {};
if (!this.state.isValid) {
desc.error = (
<FormFeedback id={errorId} key="0">
{this.state.validationMessage}
</FormFeedback>
);
desc.describedBy = errorId;
}
if (this.props.description) {
desc.description = (
<FormText id={descriptionId} key="1">
{this.props.description}
</FormText>
);
desc.describedBy = `${desc.describedBy} ${descriptionId}`.trim();
}
return desc;
}
render() {
const { description, error, describedBy } = this.getDescriptions();
return (
<FormGroup>
<Label for={this.state.id}>{this.props.label}</Label>
<WrappedComponent
{...this.props}
{...this.state}
describedBy={describedBy}
onChange={this.handleChange}
onBlur={this.handleBlur}
/>
{error}
{description}
</FormGroup>
);
}
}
NewComponent.displayName = `asInput(${getDisplayName(WrappedComponent)})`;
NewComponent.propTypes = {
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.string,
PropTypes.element
]),
disabled: PropTypes.bool,
required: PropTypes.bool,
onChange: PropTypes.func
};
return NewComponent;
};
export default asInput;
let lastId = 0;
export const newId = (prefix = 'id') => {
const newId = (prefix = 'id') => {
lastId += 1;
return `${prefix}${lastId}`;
};
export default newId;
import React from 'react';
const styles = {
main: {
margin: 15,
maxWidth: 600,
lineHeight: 1.4,
fontFamily: '"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif',
},
logo: {
width: 200,
},
link: {
color: '#1474f3',
textDecoration: 'none',
borderBottom: '1px solid #1474f3',
paddingBottom: 2,
},
code: {
fontSize: 15,
fontWeight: 600,
padding: "2px 5px",
border: "1px solid #eae9e9",
borderRadius: 4,
backgroundColor: '#f3f2f2',
color: '#3a3a3a',
},
note: {
opacity: 0.5,
}
};
export default class Welcome extends React.Component {
showApp(e) {
e.preventDefault();
if(this.props.showApp) this.props.showApp();
}
render() {
return (
<div style={styles.main}>
<h1>Welcome to STORYBOOK</h1>
<p>
This is a UI component dev environment for your app.
</p>
<p>
We've added some basic stories inside the <code style={styles.code}>src/stories</code> directory.
<br/>
A story is a single state of one or more UI components. You can have as many stories as you want.
<br/>
(Basically a story is like a visual test case.)
</p>
<p>
See these sample <a style={styles.link} href='#' onClick={this.showApp.bind(this)}>stories</a> for a component called <code style={styles.code}>Button</code>.
</p>
<p>
Just like that, you can add your own components as stories.
<br />
You can also edit those components and see changes right away.
<br />
(Try editing the <code style={styles.code}>Button</code> component
located at <code style={styles.code}>src/stories/Button.js</code>.)
</p>
<p>
This is just one thing you can do with Storybook.
<br/>
Have a look at the <a style={styles.link} href="https://github.com/kadirahq/react-storybook" target="_blank">React Storybook</a> repo for more information.
</p>
<p style={styles.note}>
<b>NOTE:</b>
<br/>
Have a look at the <code style={styles.code}>.storybook/webpack.config.js</code> to add webpack
loaders and plugins you are using in this project.
</p>
</div>
);
}
}
import React from 'react';
import { storiesOf, action, linkTo } from '@kadira/storybook';
import TextInput from '../src/TextInput';
import SelectInput from '../src/SelectInput';
import Welcome from './Welcome';
storiesOf('Welcome', module)
.add('to Storybook', () => (
<Welcome showApp={linkTo('Button')}/>
));
storiesOf('TextInput', module)
.add('minimal usage', () => (
<TextInput
name="name"
label="First Name"
value="Foo Bar"
/>
))
.add('validation', () => (
<TextInput
name="username"
label="Username"
description="The unique name that identifies you throughout the site."
validate={(value) => {
let feedback = { isValid: true };
if (value.length < 3) {
feedback = {
isValid: false,
validationMessage: 'Username must be at least 3 characters in length.'
}
}
return feedback;
}}
/>
));
storiesOf('SelectInput', module)
.add('basic usage', () => (
<SelectInput
name="fruits"
label="Fruits"
value="strawberry"
options={[
'apple',
'orange',
'strawberry',
'banana'
]}
/>
))
.add('separate labels and values', () => (
<SelectInput
name="new-england-states"
label="New England States"
value="RI"
options={[
{label: 'Connecticut', value: 'CN'},
{label: 'Maine', value: 'ME'},
{label: 'Massachusetts', value: 'MA'},
{label: 'New Hampshire', value: 'NH'},
{label: 'Rhode Island', value: 'RI'},
{label: 'Vermont', value: 'VT'},
]}
/>
))
.add('separate option groups', () => (
<SelectInput
name="northeast-states"
label="Northeast States"
value="MD"
options={[
{
label: 'New England States',
options: [
{label: 'Connecticut', value: 'CN'},
{label: 'Maine', value: 'ME'},
{label: 'Massachusetts', value: 'MA'},
{label: 'New Hampshire', value: 'NH'},
{label: 'Rhode Island', value: 'RI'},
{label: 'Vermont', value: 'VT'},
],
},
{
label: 'Mid Atlantic States',
options: [
{label: 'Delaware', value: 'DE'},
{label: 'Maryland', value: 'MD'},
{label: 'New Jersey', value: 'NJ'},
{label: 'New York', value: 'NY'},
{label: 'Pennsylvania', value: 'PA'},
{label: 'Virginia', value: 'VA'},
{label: 'Washington, DC', value: 'DC'},
{label: 'West Virginia', value: 'WV'},
],
},
]}
/>
));
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment