Commit f0784f3f by Ari Rizzitano

add some legitimately working components

parent dbbdce6e
...@@ -4,3 +4,4 @@ node_modules ...@@ -4,3 +4,4 @@ node_modules
npm-debug.log npm-debug.log
/dist /dist
/docs
.DS_Store
.eslintcache
node_modules
npm-debug.log
/docs
...@@ -7,21 +7,22 @@ ...@@ -7,21 +7,22 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build": "webpack", "build": "webpack",
"build-docs": "NODE_ENV=doc webpack", "build-docs": "install-self-peers && webpack --config ./webpack.docs.config.js",
"lint": "eslint .", "lint": "eslint .",
"prestart": "install-self-peers", "prestart": "install-self-peers",
"poststop": "yarn install",
"start": "BABEL_ENV=webpack webpack-dev-server --config ./webpack.dev.config.js --watch" "start": "BABEL_ENV=webpack webpack-dev-server --config ./webpack.dev.config.js --watch"
}, },
"dependencies": { "dependencies": {
"classnames": "^2.2.5", "classnames": "^2.2.5",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
"react-router-dom": "^4.1.1",
"reactstrap": "^4.5.0" "reactstrap": "^4.5.0"
}, },
"devDependencies": { "devDependencies": {
"@team-griffin/install-self-peers": "^1.0.0", "@team-griffin/install-self-peers": "^1.0.0",
"babel-cli": "^6.24.1", "babel-cli": "^6.24.1",
"babel-loader": "^7.0.0", "babel-loader": "^7.0.0",
"babel-preset-babili": "^0.0.12",
"babel-preset-env": "^1.4.0", "babel-preset-env": "^1.4.0",
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"eslint": "^3.19.0", "eslint": "^3.19.0",
...@@ -29,6 +30,8 @@ ...@@ -29,6 +30,8 @@
"eslint-config-edx": "^2.0.1", "eslint-config-edx": "^2.0.1",
"eslint-plugin-jsx-a11y": "^4.0.0", "eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-react": "^6.10.3", "eslint-plugin-react": "^6.10.3",
"react-router-dom": "^4.1.1",
"static-site-generator-webpack-plugin": "^3.4.1",
"webpack": "^2.4.1", "webpack": "^2.4.1",
"webpack-dev-server": "^2.4.4" "webpack-dev-server": "^2.4.4"
}, },
......
import React, { Component } from 'react';
import { Input, Label } from 'reactstrap';
import PropTypes from 'prop-types';
import { newId } from './utils';
class SelectInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
uuid: newId('textInput'),
value: this.props.value
};
}
getDescriptionElements() {
let descriptionElements = {};
if (this.props.description) {
const descriptionId = `description-${this.state.uuid}"`;
descriptionElements = {
descriptionId,
description: (
<span className="input-description" id={descriptionId}>
{this.props.description}
</span>
)
}
}
return descriptionElements;
}
handleChange(event) {
this.setState({value: event.target.value});
this.props.onChange(event.target.value);
}
getOptions() {
return this.props.options.map(option => {
return (
<option>{option}</option>
);
});
}
render() {
const { descriptionId, description } = this.getDescriptionElements(),
options = this.getOptions();
return (
<div className={this.props.className}>
<Label for={this.state.uuid}>{this.props.label}</Label>
<Input
id={this.state.uuid}
type="select"
name={this.props.name}
value={this.props.value}
aria-describedby={descriptionId}
onChange={this.handleChange}
>
{options}
</Input>
{description}
</div>
);
}
}
SelectInput.propTypes = {
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.string,
PropTypes.element
]),
options: PropTypes.array.isRequired,
disabled: PropTypes.bool,
onChange: PropTypes.func
};
SelectInput.defaultProps = {
onChange: () => {}
};
export default SelectInput;
import React, { Component } from 'react';
import { TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { newId } from './utils';
class TabInterface extends React.Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
activeTab: 0,
uuid: newId('tabInterface')
};
}
toggle(tab) {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
});
}
}
genLabelId(index) {
return `tab-label-${this.state.uuid}-${index}`;
}
genPanelId(index) {
return `tab-panel-${this.state.uuid}-${index}`;
}
buildLabels() {
return this.props.tabLabels.map((label, i) => {
const selected = this.state.activeTab === i;
return (
<NavItem
aria-selected={selected}
aria-controls={this.genPanelId(i)}
id={this.genLabelId(i)}
key={i}
role="tab"
tabIndex={selected ? 0 : -1}
>
<NavLink
className={classnames({ active: selected })}
onClick={() => { this.toggle(i); }}
>
{label}
</NavLink>
</NavItem>
);
});
}
buildPanels() {
return this.props.panels.map((panel, i) => {
const selected = this.state.activeTab === i;
return (
<TabPane
aria-hidden={!selected}
aria-labelledby={this.genLabelId(i)}
id={this.genPanelId(i)}
key={i}
role="tabpanel"
tabId={i}
>
{panel}
</TabPane>
);
});
}
render() {
const labels = this.buildLabels(),
panels = this.buildPanels();
return (
<div className={this.props.className}>
<Nav tabs role="tablist">
{labels}
</Nav>
<TabContent activeTab={this.state.activeTab}>
{panels}
</TabContent>
</div>
);
}
}
// TODO: custom validator that ensures tabLabels and panels are the same length
TabInterface.propTypes = {
tabLabels: PropTypes.array.isRequired,
panels: PropTypes.array.isRequired
};
export default TabInterface;
import React, { Component } from 'react';
import { Input, Label } 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.state = {
uuid: newId('textInput'),
value: this.props.value
};
}
getDescriptionElements() {
let descriptionElements = {};
if (this.props.description) {
const descriptionId = `description-${this.state.uuid}"`;
descriptionElements = {
descriptionId,
description: (
<span className="input-description" id={descriptionId}>
{this.props.description}
</span>
)
}
}
return descriptionElements;
}
handleChange(event) {
this.setState({value: event.target.value});
this.props.onChange(event.target.value);
}
render() {
const { descriptionId, description } = this.getDescriptionElements();
return (
<div className={this.props.className}>
<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}
/>
{description}
</div>
);
}
}
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
};
TextInput.defaultProps = {
onChange: () => {}
};
export default TextInput;
import Button from './Button'; import SelectInput from './SelectInput';
import TabInterface from './TabInterface';
import TextInput from './TextInput';
export { export {
Button SelectInput,
TabInterface,
TextInput
}; };
let lastId = 0;
export const newId = (prefix='id') => {
lastId++;
return `${prefix}${lastId}`;
};
...@@ -31,6 +31,14 @@ module.exports = { ...@@ -31,6 +31,14 @@ module.exports = {
amd: 'react-addons-transition-group', amd: 'react-addons-transition-group',
root: ['React', 'addons', 'TransitionGroup'], root: ['React', 'addons', 'TransitionGroup'],
}, },
},
{
'react-addons-css-transition-group': {
commonjs: 'react-addons-css-transition-group',
commonjs2: 'react-addons-css-transition-group',
amd: 'react-addons-css-transition-group',
root: ['React', 'addons', 'CSSTransitionGroup'],
},
}], }],
module: { module: {
rules: [ rules: [
...@@ -40,7 +48,7 @@ module.exports = { ...@@ -40,7 +48,7 @@ module.exports = {
use: { use: {
loader: 'babel-loader', loader: 'babel-loader',
options: { options: {
presets: ['env'], presets: ['env', 'babili'],
}, },
}, },
}, },
......
...@@ -3,60 +3,32 @@ const path = require('path'); ...@@ -3,60 +3,32 @@ const path = require('path');
module.exports = { module.exports = {
devtool: 'source-map', devtool: 'source-map',
devServer: { devServer: {
contentBase: path.resolve('./doc'), contentBase: path.resolve('./docs'),
historyApiFallback: true, historyApiFallback: true,
stats: { stats: {
chunks: false chunks: false
} }
}, },
entry: { entry: {
main: './doc/App.js' main: './docs/App.js'
}, },
node: { node: {
fs: 'empty' fs: 'empty'
}, },
output: { output: {
filename: 'bundle.js', filename: 'bundle.js',
path: path.resolve('./doc'), path: path.resolve('./docs'),
libraryTarget: 'umd' libraryTarget: 'umd'
}, },
// plugins: [
// new CleanWebpackPlugin(['build']),
// new CopyWebpackPlugin([{ from: './docs/static', to: 'assets' }]),
// new webpack.DefinePlugin({
// 'process.env.NODE_ENV': JSON.stringify(env)
// }),
// new webpack.optimize.OccurenceOrderPlugin(),
// new StaticSiteGeneratorPlugin('main', paths, {}),
// new webpack.NoErrorsPlugin(),
// new ExtractTextPlugin("/assets/style.css")
// ],
module: { module: {
loaders: [ loaders: [
// {
// test: /\.json$/,
// loaders: [
// 'json-loader?cacheDirectory'
// ]
// },
{ {
test: /\.(js|jsx)$/, test: /\.(js|jsx)$/,
exclude: /node_modules/, exclude: /node_modules/,
loaders: [ loaders: [
'babel-loader?cacheDirectory' 'babel-loader?cacheDirectory',
] ],
}, },
// { ],
// test: /\.css$/,
// loader: ExtractTextPlugin.extract("style-loader", "css-loader")
// },
]
}, },
// resolve: {
// extensions: ['', '.js', '.json'],
// alias: {
// 'bootstrap-css': path.join(__dirname,'node_modules/bootstrap/dist/css/bootstrap.css'),
// reactstrap: path.resolve('./src')
// }
// }
}; };
const path = require('path');
const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
module.exports = {
entry: {
main: path.resolve('./docs/App.js'),
},
output: {
path: path.resolve('./docs'),
filename: 'bundle.js',
libraryTarget: 'umd',
},
plugins: [
new StaticSiteGeneratorPlugin('main', [
'/',
'/header/',
'/inputs/',
], {}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env'],
},
},
},
],
},
};
\ No newline at end of file
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