├── .gitignore
├── package.json
├── LICENSE
├── gulpfile.js
├── rjt.js
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-json-table",
3 | "version": "0.1.1",
4 | "description": "A simple but reactive table react component to display JSON data.",
5 | "main": "rjt.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/arqex/react-json-table.git"
12 | },
13 | "keywords": [
14 | "react",
15 | "table",
16 | "json"
17 | ],
18 | "author": "Javier Marquez",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/arqex/react-json-table/issues"
22 | },
23 | "homepage": "https://github.com/arqex/react-json-table",
24 | "devDependencies": {
25 | "gulp": "^3.9.0",
26 | "gulp-insert": "^0.4.0",
27 | "gulp-uglify": "^1.2.0",
28 | "gulp-webpack": "^1.4.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | uglify = require('gulp-uglify'),
3 | insert = require('gulp-insert'),
4 | webpack = require('gulp-webpack')
5 | ;
6 |
7 | var packageName = 'react-json-table';
8 | var pack = require( './package.json' );
9 |
10 | var getWPConfig = function( filename ){
11 | return {
12 | externals: {
13 | react: {
14 | root: 'React'
15 | }
16 | },
17 | output: {
18 | libraryTarget: 'umd',
19 | library: 'JsonTable',
20 | filename: filename + '.js'
21 | }
22 | };
23 | };
24 |
25 | var cr = ('/*\n%%name%% v%%version%%\n%%homepage%%\n%%license%%: https://github.com/arqex/' + packageName + '/raw/master/LICENSE\n*/\n')
26 | .replace( '%%name%%', pack.name)
27 | .replace( '%%version%%', pack.version)
28 | .replace( '%%license%%', pack.license)
29 | .replace( '%%homepage%%', pack.homepage)
30 | ;
31 |
32 | function build( config, minify ){
33 | var stream = gulp.src('./rjt.js')
34 | .pipe( webpack( config ) )
35 | ;
36 |
37 | if( minify ){
38 | stream.pipe( uglify() );
39 | }
40 |
41 | return stream.pipe( insert.prepend( cr ) )
42 | .pipe( gulp.dest('build/') )
43 | ;
44 | }
45 |
46 | gulp.task("build", function( callback ) {
47 | build( getWPConfig( packageName ) );
48 | return build( getWPConfig( packageName + '.min' ), true );
49 | });
50 |
51 | gulp.task( 'default', ['build'] );
52 |
--------------------------------------------------------------------------------
/rjt.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var $ = React.DOM;
4 |
5 | // Some shared attrs for JsonTable and JsonRow
6 | var defaultSettings = {
7 | header: true,
8 | noRowsMessage: 'No items',
9 | classPrefix: 'json'
10 | },
11 | getSetting = function( name ){
12 | var settings = this.props.settings;
13 |
14 | if( !settings || typeof settings[ name ] == 'undefined' )
15 | return defaultSettings[ name ];
16 |
17 | return settings[ name ];
18 | }
19 | ;
20 |
21 | var JsonTable = React.createClass({
22 | getSetting: getSetting,
23 |
24 | render: function(){
25 | var cols = this.normalizeColumns(),
26 | contents = [this.renderRows( cols )]
27 | ;
28 |
29 | if( this.getSetting('header') )
30 | contents.unshift( this.renderHeader( cols ) );
31 |
32 | var tableClass = this.props.className || this.getSetting( 'classPrefix' ) + 'Table';
33 |
34 | return $.table({ className: tableClass }, contents );
35 | },
36 |
37 | renderHeader: function( cols ){
38 | var me = this,
39 | prefix = this.getSetting( 'classPrefix' ),
40 | headerClass = this.getSetting( 'headerClass' ),
41 | cells = cols.map( function(col){
42 | var className = prefix + 'Column';
43 | if( headerClass )
44 | className = headerClass( className, col.key );
45 |
46 | return $.th(
47 | { className: className, key: col.key, onClick: me.onClickHeader, "data-key": col.key },
48 | col.label
49 | );
50 | })
51 | ;
52 |
53 | return $.thead({ key: 'th' },
54 | $.tr({ className: prefix + 'Header' }, cells )
55 | );
56 | },
57 |
58 | renderRows: function( cols ){
59 | var me = this,
60 | items = this.props.rows,
61 | settings = this.props.settings || {},
62 | i = 1
63 | ;
64 |
65 | if( !items || !items.length )
66 | return $.tbody({key:'body'}, [$.tr({key:'row'}, $.td({key:'column'}, this.getSetting('noRowsMessage') ))]);
67 |
68 | var rows = items.map( function( item ){
69 | var key = me.getKey( item, i );
70 | return React.createElement(Row, {
71 | key: key,
72 | reactKey: key,
73 | item: item,
74 | settings: settings,
75 | columns: cols,
76 | i: i++,
77 | onClickRow: me.onClickRow,
78 | onClickCell: me.onClickCell
79 | });
80 | });
81 |
82 | return $.tbody({key:'body'}, rows);
83 | },
84 |
85 | getItemField: function( item, field ){
86 | return item[ field ];
87 | },
88 |
89 | normalizeColumns: function(){
90 | var getItemField = this.props.cellRenderer || this.getItemField,
91 | cols = this.props.columns,
92 | items = this.props.rows
93 | ;
94 |
95 | if( !cols ){
96 | if( !items || !items.length )
97 | return [];
98 |
99 | return Object.keys( items[0] ).map( function( key ){
100 | return { key: key, label: key, cell: getItemField };
101 | });
102 | }
103 |
104 | return cols.map( function( col ){
105 | var key;
106 | if( typeof col == 'string' ){
107 | return {
108 | key: col,
109 | label: col,
110 | cell: getItemField
111 | };
112 | }
113 |
114 | if( typeof col == 'object' ){
115 | key = col.key || col.label;
116 |
117 | // This is about get default column definition
118 | // we use label as key if not defined
119 | // we use key as label if not defined
120 | // we use getItemField as cell function if not defined
121 | return {
122 | key: key,
123 | label: col.label || key,
124 | cell: col.cell || getItemField
125 | };
126 | }
127 |
128 | return {
129 | key: 'unknown',
130 | name:'unknown',
131 | cell: 'Unknown'
132 | };
133 | });
134 | },
135 |
136 | getKey: function( item, i ){
137 | var field = this.props.settings && this.props.settings.keyField;
138 | if( field && item[ field ] )
139 | return item[ field ];
140 |
141 | if( item.id )
142 | return item.id;
143 |
144 | if( item._id )
145 | return item._id;
146 |
147 | return i;
148 | },
149 |
150 | shouldComponentUpdate: function(){
151 | return true;
152 | },
153 |
154 | onClickRow: function( e, item ){
155 | if( this.props.onClickRow ){
156 | this.props.onClickRow( e, item );
157 | }
158 | },
159 |
160 | onClickHeader: function( e ){
161 | if( this.props.onClickHeader ){
162 | this.props.onClickHeader( e, e.target.dataset.key );
163 | }
164 | },
165 |
166 | onClickCell: function( e, key, item ){
167 | if( this.props.onClickCell ){
168 | this.props.onClickCell( e, key, item );
169 | }
170 | }
171 | });
172 |
173 | var Row = React.createClass({
174 | getSetting: getSetting,
175 |
176 | render: function() {
177 | var me = this,
178 | props = this.props,
179 | cellClass = this.getSetting('cellClass'),
180 | rowClass = this.getSetting('rowClass'),
181 | prefix = this.getSetting('classPrefix'),
182 | cells = props.columns.map( function( col ){
183 | var content = col.cell,
184 | key = col.key,
185 | className = prefix + 'Cell ' + prefix + 'Cell_' + key
186 | ;
187 |
188 | if( cellClass )
189 | className = cellClass( className, key, props.item );
190 |
191 | if( typeof content == 'function' )
192 | content = content( props.item, key );
193 |
194 | return $.td( {
195 | className: className,
196 | key: key,
197 | "data-key": key,
198 | onClick: me.onClickCell
199 | }, content );
200 | })
201 | ;
202 |
203 | var className = prefix + 'Row ' + prefix +
204 | (props.i % 2 ? 'Odd' : 'Even')
205 | ;
206 |
207 | if( props.reactKey )
208 | className += ' ' + prefix + 'Row_' + props.reactKey;
209 |
210 | if( rowClass )
211 | className = rowClass( className, props.item );
212 |
213 | return $.tr({
214 | className: className,
215 | onClick: me.onClickRow,
216 | key: this.props.reactKey
217 | }, cells );
218 | },
219 |
220 | onClickCell: function( e ){
221 | this.props.onClickCell( e, e.target.dataset.key, this.props.item );
222 | },
223 |
224 | onClickRow: function( e ){
225 | this.props.onClickRow( e, this.props.item );
226 | }
227 | });
228 |
229 | module.exports = JsonTable;
230 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-json-table
2 | A simple but flexible table react component to display JSON data.
3 |
4 | As simple as feeding it with an array of objects.
5 | ```js
6 | var items = [
7 | { name: 'Louise', age: 27, color: 'red' },
8 | { name: 'Margaret', age: 15, color: 'blue'},
9 | { name: 'Lisa', age:34, color: 'yellow'}
10 | ];
11 |
12 | React.render(