├── .eslintrc
├── .gitignore
├── .npmignore
├── README.md
├── example
├── basic.jsx
├── example.config.js
├── index.html
└── server.config.js
├── mocha.opts
├── package.json
├── src
├── head.jsx
├── rows.jsx
├── table.jsx
└── uniqueId.js
└── tests
├── head.jsx
├── setup.js
└── table.jsx
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "es6": true
5 | },
6 | "ecmaFeatures": {
7 | "blockBindings": true,
8 | "forOf": true,
9 | "jsx": true,
10 | "modules": true
11 | },
12 | "rules": {
13 | "indent": [2, 2],
14 | "max-len": 0,
15 | "semi": 0,
16 | "quotes": 0,
17 | "no-console": 0,
18 | "no-trailing-spaces": 0,
19 | "curly": 0,
20 | "camelcase": 0,
21 | "react/jsx-boolean-value": 1,
22 | "react/jsx-quotes": 1,
23 | "react/jsx-no-undef": 1,
24 | "react/jsx-uses-react": 1,
25 | "react/jsx-uses-vars": 1,
26 | "react/no-did-mount-set-state": 1,
27 | "react/no-did-update-set-state": 1,
28 | "react/no-multi-comp": 1,
29 | "react/no-unknown-property": 1,
30 | "react/prop-types": 1,
31 | "react/react-in-jsx-scope": 1,
32 | "react/self-closing-comp": 1,
33 | "react/sort-comp": 1,
34 | "react/wrap-multilines": 1,
35 | "new-cap": [1, {newIsCap: true, capIsNew: false}],
36 | },
37 | "plugins": [
38 | "react"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | rethinkdb_data
3 | npm-debug.log
4 | example/main.js
5 | .DS_Store
6 | lib
7 | # Ignore all vim swap files
8 | *.swp
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | tests
3 | .eslintrc
4 | mocha.opts
5 | circle.yml
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##Install
2 | `npm install react-legit-table`
3 |
4 | ##Another Table Component....
5 |
6 | I know what you're thinking... Yet another one of these things, right? I was using Facebook's Fixed Data Table until I realized how big of a library it is. All I needed was a simple html table. It's as simple as it can be, and works great with bootstrap:
7 |
8 | ###Importing and setup
9 | ~~~js
10 | import Table from 'react-legit-table'
11 |
12 | let rows = [
13 | {
14 | id: 1,
15 | name: 'Zach',
16 | job: 'coding'
17 | },
18 | {
19 | id: 2,
20 | name: 'Jed',
21 | job: 'Being a boss'
22 | }
23 | ]
24 | ~~~
25 |
26 | ###Rendering
27 |
28 | ~~~js
29 | render(){
30 | return (
31 |
32 | )
33 | }
34 | ~~~
35 |
36 | The component expects simple, regular ol' javascript objects inside of an array.
37 |
38 | ###Options
39 |
40 | `modify` accepts an object with keys equal to those in your rows object and the values are callbacks that will be called on rendering a row.
41 | Optionally, use `modifyAll` to change every item.
42 |
43 | **Example:**
44 |
45 | ~~~js
46 |
47 | modifyId({hidden, value, key, row}){
48 | return {value}
49 | }
50 |
51 | render() {
52 | return (
53 |
58 | );
59 | }
60 |
61 | //optionally modifyAll rows:
62 |
63 |
67 | ~~~
68 |
69 | `capitalize` Optionally, turn off capitalization of header row. True by default.
70 |
71 | ~~~js
72 |
73 | ~~~
74 |
75 | ##Requests?
76 |
77 | I want to keep this simple and it has been perfect for my use case so far, but I'd love to hear suggestions.
78 |
--------------------------------------------------------------------------------
/example/basic.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Table from '../src/table';
3 |
4 | var rows = [
5 | {
6 | id: 1,
7 | name: 'Zach',
8 | job: 'coding'
9 | },
10 | {
11 | id: 2,
12 | name: 'Jed',
13 | job: 'Being a boss'
14 | }
15 | ];
16 |
17 | export default class Basic extends React.Component {
18 | modifyId(id){
19 | return `the user's is ${id}`
20 | }
21 | render() {
22 | return (
23 |
29 | );
30 | }
31 | }
32 |
33 | React.render(, document.getElementById('react'));
34 |
--------------------------------------------------------------------------------
/example/example.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 |
4 | module.exports = {
5 | entry: './example/basic.jsx',
6 | output: {
7 | path: __dirname,
8 | filename: "[name].js"
9 | },
10 | resolve: {
11 | extensions: ['', '.js', '.jsx', '.es6'],
12 | modulesDirectories: ['node_modules']
13 | },
14 | module: {
15 | loaders: [
16 | { test: /\.jsx$|\.es6$|\.js$/, loaders: ['babel-loader?stage=0'], exclude: /node_modules/ },
17 | ]
18 | },
19 | plugins: [
20 | new webpack.NoErrorsPlugin()
21 | ],
22 | devtool: "eval-source-map"
23 | };
24 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Basic Example
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/example/server.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 |
4 | module.exports = {
5 | entry: {
6 | 'basic': [
7 | 'webpack-dev-server/client?http://localhost:8881/',
8 | 'webpack/hot/only-dev-server',
9 | './example/basic.jsx'
10 | ]
11 | },
12 | output: {
13 | path: __dirname,
14 | filename: "[name].js",
15 | publicPath: 'http://localhost:8881/',
16 | chunkFilename: '[id].chunk.js',
17 | sourceMapFilename: '[name].map'
18 | },
19 | resolve: {
20 | extensions: ['', '.js', '.jsx', '.es6'],
21 | modulesDirectories: ['node_modules']
22 | },
23 | module: {
24 | loaders: [
25 | { test: /\.jsx$|\.es6$|\.js$/, loaders: ['react-hot', 'babel-loader?stage=0'], exclude: /node_modules/ },
26 | { test: /\.scss$|\.css$/, loader: 'style-loader!style!css!sass' },
27 | { test: /\.(jpe?g|png|gif)$/i, loader: 'url?limit=10000!img?progressive=true' }
28 | ]
29 | },
30 | plugins: [
31 | new webpack.NoErrorsPlugin()
32 | ],
33 | devtool: "eval-source-map"
34 | };
35 |
--------------------------------------------------------------------------------
/mocha.opts:
--------------------------------------------------------------------------------
1 | --require ./tests/setup
2 | --full-trace
3 | --compilers js:babel/register
4 | --recursive ./tests/**/*.jsx
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-legit-table",
3 | "version": "0.5.0",
4 | "description": "the simplest table component out there",
5 | "main": "lib/table.js",
6 | "scripts": {
7 | "compile": "babel src --stage 0 --out-dir lib;",
8 | "prepublish": "babel src --stage 0 --out-dir lib;",
9 | "dev-server": "webpack-dev-server --config ./example/server.config.js --hot --port 8881",
10 | "example": "webpack --config ./example/example.config.js",
11 | "test": "mocha --opts ./mocha.opts; eslint ./src/ --ext .jsx,.js --global require,exports:true"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+ssh://git@github.com/legitcode/table.git"
16 | },
17 | "keywords": [
18 | "react-component",
19 | "react",
20 | "table",
21 | "react-table",
22 | "bootstrap"
23 | ],
24 | "author": "Zach Silveira",
25 | "license": "ISC",
26 | "bugs": {
27 | "url": "https://github.com/legitcode/table/issues"
28 | },
29 | "homepage": "https://github.com/legitcode/table#readme",
30 | "devDependencies": {
31 | "babel": "^5.8.23",
32 | "babel-core": "^5.8.23",
33 | "babel-eslint": "^4.1.1",
34 | "babel-loader": "^5.3.2",
35 | "chai": "^3.2.0",
36 | "eslint": "^0.24.1",
37 | "eslint-plugin-react": "^2.7.0",
38 | "expect": "^1.8.0",
39 | "legit-tests": "^0.6.0",
40 | "mocha": "^2.2.5",
41 | "mocha-babel": "^3.0.0",
42 | "react-hot-loader": "^1.3.0",
43 | "webpack": "^1.12.1",
44 | "webpack-dev-server": "^1.10.1"
45 | },
46 | "dependencies": {
47 | "react": "^0.14.0"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/head.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import uniqueId from './uniqueId'
3 |
4 | export default class Head extends React.Component{
5 | static propTypes = {
6 | row: React.PropTypes.object.isRequired,
7 | hide: React.PropTypes.array,
8 | capitalize: React.PropTypes.bool
9 | }
10 |
11 | static defaultProps = {
12 | capitalize: true
13 | }
14 |
15 | headings() {
16 | let row = Object.assign({}, this.props.row)
17 | return Object.keys(row).map((name) => {
18 | return {this.props.capitalize ? this.titleize(name) : name} |
19 | })
20 | }
21 |
22 | titleize(str) {
23 | let words = str.replace(/([A-Z])/g, ' $1').replace(/_/g, ' ').split(' ')
24 |
25 | let array = words.map((word) => {
26 | return `${word.charAt(0).toUpperCase()}${word.substring(1)}`
27 | })
28 |
29 | return array.join(' ').trim()
30 | }
31 |
32 | render() {
33 | return (
34 |
35 |
36 | {this.headings()}
37 |
38 |
39 | )
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/rows.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import uniqueId from './uniqueId'
3 |
4 | export default class Rows extends React.Component{
5 |
6 | static propTypes = {
7 | rows: React.PropTypes.array,
8 | modify: React.PropTypes.object,
9 | hide: React.PropTypes.array,
10 | modifyAll: React.PropTypes.func
11 | }
12 |
13 | rows(){
14 | let rows = [];
15 |
16 | for(let row of this.props.rows){
17 | let rowList = []
18 | let id = row[Object.keys(row)[0]]
19 |
20 | for(let item in row){
21 | let value = row[item]
22 | let params = {
23 | value: row[item],
24 | key: item,
25 | row
26 | }
27 | if(this.props.modifyAll) value = this.props.modifyAll(params)
28 | else if(this.props.modify[item]) value = this.props.modify[item](params)
29 |
30 | rowList.push({value} | )
31 | }
32 |
33 | rows.push({rowList}
)
34 | }
35 |
36 | return rows;
37 | }
38 |
39 | render(){
40 | return (
41 |
42 | {this.rows()}
43 |
44 | )
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/table.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from './head'
3 | import Rows from './rows'
4 |
5 | export default class Table extends React.Component{
6 | static propTypes = {
7 | rows: React.PropTypes.array.isRequired,
8 | capitalize: React.PropTypes.bool,
9 | modify: React.PropTypes.object
10 |
11 | }
12 |
13 | render() {
14 | if (this.props.rows.length === 0) return null
15 |
16 | let {
17 | rows,
18 | capitalize,
19 | modify,
20 | ...attributes
21 | } = this.props
22 |
23 | return (
24 |
26 |
27 |
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/uniqueId.js:
--------------------------------------------------------------------------------
1 | var number = 0
2 | export default function uniqueId(id){
3 | number++
4 | return number + '-' + id
5 | }
6 |
--------------------------------------------------------------------------------
/tests/head.jsx:
--------------------------------------------------------------------------------
1 | import Test from 'legit-tests'
2 | import Head from '../src/head'
3 | import { expect } from 'chai'
4 |
5 | /* globals describe, it */
6 |
7 | describe('Head component', () => {
8 | describe('initialize', () => {
9 | it('should default capitalize to true', () => {
10 | Test()
11 | .test(({instance}) => {
12 | expect(instance.props.capitalize).to.be.true
13 | })
14 | })
15 |
16 | it('should set capitalize to false if it is passed in', () => {
17 | Test(
)
18 | .test(({instance}) => {
19 | expect(instance.props.capitalize).to.be.false
20 | })
21 | })
22 | })
23 |
24 | describe('#headings', () => {
25 | var head = new Head({ row: { foo: "bar" } })
26 |
27 | it('should return an array of header columns', () => {
28 | let headings = head.headings()
29 |
30 | expect(headings.length).to.equal(1)
31 | expect(headings[0].type).to.equal('th')
32 | expect(headings[0].key).to.equal('3-foo')
33 | })
34 | })
35 |
36 | describe('#titleize', () => {
37 | var head = new Head()
38 |
39 | it('should titleize a string properly', () => {
40 | expect(head.titleize('foo bar')).to.equal('Foo Bar')
41 | })
42 |
43 | it('should titleize a snake case string properly', () => {
44 | expect(head.titleize('foo_bar')).to.equal('Foo Bar')
45 | })
46 |
47 | it('should titleize a camel cased string properly', () => {
48 | expect(head.titleize('fooBar')).to.equal('Foo Bar')
49 | })
50 |
51 | it('should titleize a constantized string properly', () => {
52 | expect(head.titleize('FooBar')).to.equal('Foo Bar')
53 | })
54 | })
55 | })
56 |
--------------------------------------------------------------------------------
/tests/setup.js:
--------------------------------------------------------------------------------
1 | require("babel/register")({
2 | stage: 0
3 | });
4 |
--------------------------------------------------------------------------------
/tests/table.jsx:
--------------------------------------------------------------------------------
1 | import Test from 'legit-tests'
2 | import Table from '../src/table'
3 | import Head from '../src/head'
4 | import Rows from '../src/rows'
5 | import { expect } from 'chai'
6 |
7 | /* globals describe, it */
8 |
9 | describe('Table component', () => {
10 | var table = new Table({ rows: [] })
11 |
12 | describe('#render', () => {
13 | it('should not render the component if the rows are empty', () => {
14 | Test(