diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..a1f0b7a --- /dev/null +++ b/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": ["react", "es2015", "stage-1"], + "env": { + "umd": { + "plugins": [ + "add-module-exports", + "transform-es2015-modules-umd" + ] + } + } +} \ No newline at end of file diff --git a/.npmignore b/.npmignore index c0b28bf..40fe4ce 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,6 @@ test src example +webpack.config.js +.babelrc .module-cache \ No newline at end of file diff --git a/README.md b/README.md index 4bc6055..12e6c40 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,29 @@ -[![npm version](https://badge.fury.io/js/responsive-fixed-data-table.svg)](http://badge.fury.io/js/responsive-fixed-data-table) # responsive-fixed-data-table +[![npm version](https://badge.fury.io/js/responsive-fixed-data-table.svg)](http://badge.fury.io/js/responsive-fixed-data-table) Responsive wrapper for [Facebook's Fixed-Data-Table](https://github.com/facebook/fixed-data-table) grids ## Installation This module is available as an npm package. - npm install [--save] responsive-fixed-data-table + npm install [--save] responsive-fixed-data-table ## Usage +This module includes minified and non minified UMD builds as well as an ES6 build. You choose! + ```js -var React = require('react'); -var Column = require('fixed-data-table').Column; -var ResponsiveFixedDataTable = require('responsive-fixed-data-table'); - -var ResponsiveTable = React.createClass({ - render: function() { - return ( - - - - ); - } -}); - -module.exports = ResponsiveTable; +import React from 'react'; +import ResponsiveFixedDataTable from 'responsive-fixed-data-table'; +import { Column } from 'fixed-data-table'; + +export default class ResponsiveTable extends React.Component { + render() { + return ( + + + + ); + } +} ``` All passed props will be passed to the underlying FixedDataTable component. Please check [FixedDataTable docs](http://facebook.github.io/fixed-data-table/api-table.html) for a list of available options. @@ -32,3 +32,6 @@ Width and height will be overriden to take all the available space of its parent ### Additional configuration **containerStyle** *{Object}*: Additional styles to be set on the container div. **refreshRate** *{Number}*: Time in milliseconds to debounce the resize handler. + +### React 0.13 compatibility +If you want to use this module with old versions of React and FixedDataTable please check the **v1.5.0-deprecated** branch. \ No newline at end of file diff --git a/example/.babelrc b/example/.babelrc new file mode 100644 index 0000000..014a6aa --- /dev/null +++ b/example/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["react", "es2015", "stage-1"] +} \ No newline at end of file diff --git a/example/gulpfile.js b/example/gulpfile.js index 9c682e0..4d2c312 100644 --- a/example/gulpfile.js +++ b/example/gulpfile.js @@ -3,10 +3,6 @@ var gulp = require('gulp'), rimraf = require('rimraf'), runSequence = require('run-sequence'), - source = require('vinyl-source-stream'), - buffer = require('vinyl-buffer'), - browserify = require('browserify'), - reactify = require('reactify'), modRewrite = require('connect-modrewrite'), connect = require('gulp-connect'); @@ -24,19 +20,6 @@ var buildPaths = { css: './build/assets/css/' }; -// BUNDLER -// - - - - - - - - - - - - - - - -var bundler = browserify({ - entries: [paths.mainJs], // Only need initial file, browserify finds the deps - transform: [ - reactify // We want to convert JSX to normal javascript - ], - debug: true, // Gives us sourcemapping - cache: {}, - packageCache: {}, - fullPaths: true -}); - // TASKS // - - - - - - - - - - - - - - - // Cleans the build directory. @@ -44,15 +27,6 @@ gulp.task('clean', function(cb) { rimraf(buildPaths.main, cb); }); -// Bundle files and minify for prod. -gulp.task('bundle', function() { - return bundler - .bundle() - .pipe(source('bundle.js')) - .pipe(buffer()) - .pipe(gulp.dest(buildPaths.js)); -}); - // Copies html file gulp.task('copy-html-css', function() { gulp.src(paths.mainHtml) @@ -65,6 +39,7 @@ gulp.task('copy-html-css', function() { gulp.task('server:start', function() { return connect.server({ root: './build', + port: 8000, middleware: function() { return [ modRewrite(['^[^\\.]*$ /index.html [L]']) @@ -75,7 +50,7 @@ gulp.task('server:start', function() { // Builds the app prod ready. gulp.task('build', function() { - runSequence('clean', ['bundle'], 'copy-html-css', function() { + runSequence('clean', 'copy-html-css', function() { console.log('Successfully built.'); }); }); diff --git a/example/package.json b/example/package.json index 45e5089..7adef5a 100644 --- a/example/package.json +++ b/example/package.json @@ -21,22 +21,27 @@ ], "license": "MIT", "scripts": { - "start": "gulp" + "build": "./node_modules/.bin/gulp build && ./node_modules/.bin/webpack", + "start": "npm run build && ./node_modules/.bin/gulp server:start" }, "dependencies": { - "fixed-data-table": "^0.3.0", - "react": "^0.13.3", - "responsive-fixed-data-table": "^1.5.0" + "fixed-data-table": "^0.6.0", + "react": "^0.14.7", + "react-dom": "^0.14.7", + "responsive-fixed-data-table": "^2.0.0" }, "devDependencies": { - "browserify": "^10.2.4", + "babel-core": "^6.5.2", + "babel-loader": "^6.2.2", + "babel-preset-es2015": "^6.5.0", + "babel-preset-react": "^6.5.0", + "babel-preset-stage-1": "^6.5.0", "connect-modrewrite": "^0.8.1", "gulp": "^3.9.0", "gulp-connect": "^2.2.0", - "reactify": "^1.1.1", "rimraf": "^2.4.0", "run-sequence": "^1.1.0", - "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0" + "source-map-loader": "^0.1.5", + "webpack": "^1.12.13" } } diff --git a/example/src/index.html b/example/src/index.html index c36ba43..1dc4ff8 100644 --- a/example/src/index.html +++ b/example/src/index.html @@ -4,10 +4,11 @@ +
\ No newline at end of file diff --git a/example/src/responsive-table-example.js b/example/src/responsive-table-example.js index 095d5a4..293091e 100644 --- a/example/src/responsive-table-example.js +++ b/example/src/responsive-table-example.js @@ -1,30 +1,43 @@ -'use-strict'; +'use strict'; -var React = require('react'); -var FixedDataTable = require('fixed-data-table'); -var ResponsiveFixedDataTable = require('responsive-fixed-data-table'); +import React from 'react'; +import { render } from 'react-dom'; +import { Column, Cell } from 'fixed-data-table'; +import ResponsiveFixedDataTable from 'responsive-fixed-data-table'; -var Column = FixedDataTable.Column; - -var data = [ - ['a1', 'b1', 'c1'], - ['a2', 'b3', 'c2'], - ['a3', 'b3', 'c3'] +const data = [ + { name: 'Olivia Dunham', email: 'odunham@fbi.gov' }, + { name: 'Walter Bishop', email: 'drbishop@harvard.edu' }, + { name: 'Peter Bishop', email: 'peterbishop@fbi.gov' }, + { name: 'Astrid Farnsworth', email: 'afarnsworth@fbi.gov' } ]; -function rowGetter(rowIndex) { - return data[rowIndex]; +class MyCell extends React.Component { + render() { + const { rowIndex, data, field, ...props } = this.props; + return ( + + {data[rowIndex][field]} + + ); + } } -React.render( +render( - - - -, document.body); + rowHeight={40} + rowsCount={data.length} + width={500} + height={200} + headerHeight={60} > + Name} + cell={} + width={200} /> + Email} + cell={} + width={400} + flexGrow={1} /> + +, document.getElementById('example-container')); \ No newline at end of file diff --git a/example/webpack.config.js b/example/webpack.config.js new file mode 100644 index 0000000..9f80fa4 --- /dev/null +++ b/example/webpack.config.js @@ -0,0 +1,26 @@ +'use strict'; + +var webpack = require('webpack'); +var path = require('path'); + +module.exports = { + context: __dirname, + entry: path.resolve(__dirname, 'src', 'responsive-table-example.js'), + output: { + path: path.resolve(__dirname, 'build', 'assets', 'js'), + sourceMapFileName: '[file].map', + filename: 'bundle.js', + }, + devtool: 'source-map', + resolve: { + extensions: ['', '.js'] + }, + module: { + preLoaders: [ + { test: /\.js$/, include: /responsive-fixed-data-table/, loader: 'source-map' } + ], + loaders: [ + { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel' } + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json index 6f95628..dda16d6 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,14 @@ { "name": "responsive-fixed-data-table", - "version": "1.5.0", + "version": "2.0.0", "author": "Viky Guerra ", "description": "Responsive utility wrapper for Facebook's Fixed-Data-Table", - "main": "./lib/responsive-fixed-data-table.js", + "main": "lib/responsive-fixed-data-table.js", + "jsnext:main": "lib/responsive-fixed-data-table.es.js", + "files": [ + "lib", + "src" + ], "repository": { "type": "git", "url": "https://github.com/vaiRk/responsive-fixed-data-table" @@ -21,24 +26,42 @@ ], "license": "MIT", "dependencies": { - "debounce": "^1.0.0" + "lodash": "^4.3.0" }, "peerDependencies": { - "fixed-data-table": ">=0.2.0", - "react": ">=0.13" + "fixed-data-table": ">=0.6.0", + "react": ">=0.14", + "react-dom": ">=0.14" }, "devDependencies": { - "jsx-loader": "^0.13.2", - "karma": "^0.12.36", - "karma-chrome-launcher": "^0.1.12", - "karma-jasmine": "^0.3.5", - "karma-webpack": "^1.5.1", - "react-tools": "^0.13.3", - "webpack": "^1.9.11" + "babel-core": "^6.5.2", + "babel-loader": "^6.2.2", + "babel-plugin-add-module-exports": "^0.1.2", + "babel-plugin-transform-es2015-modules-umd": "^6.5.0", + "babel-preset-es2015": "^6.5.0", + "babel-preset-react": "^6.5.0", + "babel-preset-stage-1": "^6.5.0", + "cross-env": "^1.0.7", + "fixed-data-table": "^0.6.0", + "jasmine-core": "^2.4.1", + "karma": "^0.13.21", + "karma-chrome-launcher": "^0.2.2", + "karma-jasmine": "^0.3.7", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "^1.7.0", + "ncp": "^2.0.0", + "react": "^0.14.7", + "react-addons-test-utils": "^0.14.7", + "react-dom": "^0.14.7", + "rimraf": "^2.5.1", + "webpack": "^1.12.13" }, "scripts": { - "prebuild": "rm -rf lib", - "build": "./node_modules/.bin/jsx --no-cache-dir ./src ./lib", + "prebuild": "rimraf lib", + "build": "npm run build:umd && npm run build:umd:min && npm run build:es", + "build:umd": "cross-env BABEL_ENV=umd webpack", + "build:umd:min": "cross-env BABEL_ENV=umd NODE_ENV=production webpack", + "build:es": "ncp src/responsive-fixed-data-table.js lib/responsive-fixed-data-table.es.js", "prepublish": "npm run build", "test": "./node_modules/karma/bin/karma start test/karma.conf.js", "test:debug": "./node_modules/karma/bin/karma start test/karma.conf.js --no-single-run --auto-watch --log-level debug" diff --git a/src/responsive-fixed-data-table.js b/src/responsive-fixed-data-table.js index 3512924..04680b3 100644 --- a/src/responsive-fixed-data-table.js +++ b/src/responsive-fixed-data-table.js @@ -1,85 +1,88 @@ -'use-strict'; +'use strict'; -var React = require('react/addons'); -var PureRenderMixin = React.addons.PureRenderMixin; -var Table = require('fixed-data-table').Table; -var debounce = require('debounce'); -var assign = require('react/lib/Object.assign'); +import React from 'react'; +import { findDOMNode } from 'react-dom'; +import { Table } from 'fixed-data-table'; +import debounce from 'lodash/debounce'; +import assign from 'lodash/assign'; +import isEqual from 'lodash/isEqual'; -var ResponsiveFixedDataTable = React.createClass({ - mixins: [ PureRenderMixin ], +export default class ResponsiveFixedDataTable extends React.Component { + constructor(props, context) { + super(props, context); + } - propTypes: { + static propTypes = { containerStyle: React.PropTypes.object, refreshRate: React.PropTypes.number - }, + }; - getDefaultProps: function() { - return { - containerStyle: {}, - refreshRate: 250 // ms - }; - }, + static defaultProps = { + containerStyle: {}, + refreshRate: 250 // ms + }; - getInitialState: function() { - return { - gridWidth: 1, - gridHeight: 1 - }; - }, + state = { + gridWidth: 1, + gridHeight: 1 + }; - componentDidMount: function() { + shouldComponentUpdate(nextProps, nextState) { + return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState); + } + + componentDidMount() { + this.__isMounted = true; this._setDimensionsOnState(); this._attachResizeEvent(); - }, + } - componentWillMount: function() { - this._setDimensionsOnState = debounce(this._setDimensionsOnState, this.props.refreshRate); - }, + componentWillMount() { + const { refreshRate } = this.props; + this._setDimensionsOnState = debounce(this._setDimensionsOnState, refreshRate); + } - componentWillUnmount: function() { + componentWillUnmount() { + this.__isMounted = false; window.removeEventListener('resize', this._setDimensionsOnState); - }, - - _attachResizeEvent: function() { - var win = window; + } - if (win.addEventListener) { - win.addEventListener('resize', this._setDimensionsOnState, false); - } else if (win.attachEvent) { - win.attachEvent('resize', this._setDimensionsOnState); + _attachResizeEvent() { + if (window.addEventListener) { + window.addEventListener('resize', this._setDimensionsOnState, false); + } else if (window.attachEvent) { + window.attachEvent('resize', this._setDimensionsOnState); } else { - win.onresize = this._setDimensionsOnState; + window.onresize = this._setDimensionsOnState; } - }, + } + + _setDimensionsOnState = () => { + if (this.__isMounted) { + const { offsetWidth, offsetHeight } = findDOMNode(this); - _setDimensionsOnState: function() { - if (this.isMounted()) { - var tableWrapperNode = this.getDOMNode(); this.setState({ - gridWidth: tableWrapperNode.offsetWidth, - gridHeight: tableWrapperNode.offsetHeight + gridWidth: offsetWidth, + gridHeight: offsetHeight }); } - }, + } - _getStyle: function() { - return assign(this.props.containerStyle, { + _getStyle() { + return { + ...this.props.containerStyle, width: '100%', height: '100%' - }); - }, + }; + } + + render() { + const { gridWidth, gridHeight } = this.state; - /** - * @return {ReactDOMNode} - */ - render: function() { return (
- +
); } -}); - -module.exports = ResponsiveFixedDataTable; +}; \ No newline at end of file diff --git a/test/karma.conf.js b/test/karma.conf.js index 2d77dea..e988ab9 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -1,5 +1,7 @@ 'use strict'; +var webpackConfig = require('../webpack.config.js'); + module.exports = function(karma) { karma.set({ @@ -22,7 +24,7 @@ module.exports = function(karma) { // Preprocess matching files before serving them to the browser. preprocessors: { - 'test/specs/*.js': [ 'webpack' ] + 'test/specs/*.js': [ 'webpack', 'sourcemap' ] }, // Start this browsers @@ -45,15 +47,9 @@ module.exports = function(karma) { port: 9876, webpack: { - module: { - loaders: [ - { - exclude: /node_modules/, - test: /\.js$/, - loader: 'jsx-loader' - } - ] - } + devtool: 'cheap-eval-source-map', + module: webpackConfig.module, + resolve: webpackConfig.resolve }, // Prevent webpack from logging stuff to the console. @@ -73,6 +69,7 @@ module.exports = function(karma) { plugins: [ 'karma-jasmine', 'karma-webpack', + 'karma-sourcemap-loader', 'karma-chrome-launcher' ] }); diff --git a/test/specs/responsive-fixed-data-table.js b/test/specs/responsive-fixed-data-table.js index d47faff..4089e90 100644 --- a/test/specs/responsive-fixed-data-table.js +++ b/test/specs/responsive-fixed-data-table.js @@ -1,47 +1,61 @@ -'use-strict'; +'use strict'; -var React = require('react/addons'); -var TestUtils = React.addons.TestUtils; +import React from 'react'; +import ReactDOM from 'react-dom'; +import TestUtils from 'react-addons-test-utils'; +import ResponsiveFixedDataTable from './../../src/responsive-fixed-data-table'; describe('responsive-fixed-data-table', function() { - var table; - var ResponsiveFixedDataTable = require('../../src/responsive-fixed-data-table'); - var container = document.createElement('div'); + let table; + const container = document.createElement('div'); container.style.width = '500px'; container.style.height = '500px'; beforeEach(function() { - var props = { + const props = { foo: 'bar', containerStyle: { width: '20%', position: 'absolute' }, - rowGetter: function() {}, rowHeight: 1, rowsCount: 1, headerHeight: 1 }; - table = React.render(, container); + table = ReactDOM.render(, container); }); afterEach(function() { - React.unmountComponentAtNode(container); + ReactDOM.unmountComponentAtNode(container); table = null; }); // _____TESTS_________________________________________________________________ // it('should have 100% width and height', function() { - var tableNode = table.getDOMNode(); + const tableNode = ReactDOM.findDOMNode(table); expect(tableNode.style.width).toBe('100%'); expect(tableNode.style.height).toBe('100%'); }); it('should accept additional styles', function() { - var tableNode = table.getDOMNode(); + const tableNode = ReactDOM.findDOMNode(table); expect(tableNode.style.position).toBe('absolute'); }); + it('should not update', function() { + const newProps = { ...table.props }; + const newState = { ...table.state }; + expect(table.shouldComponentUpdate(newProps, newState)).toBe(false); + }); + + it('should update', function() { + const newProps = { ...table.props, headerHeight: 100 }; + const newState = { ...table.state, gridWidth: 100 }; + expect(table.shouldComponentUpdate(newProps, newState)).toBe(true); + expect(table.shouldComponentUpdate(newProps, { ...table.state })).toBe(true); + expect(table.shouldComponentUpdate({ ...table.props }, newState)).toBe(true); + }); + it('should transfer props and add width and height', function() { - var tableState = table.state; - var fixedDataTable = table.refs.table + const tableState = table.state; + const fixedDataTable = table.refs.table; expect(fixedDataTable.props.foo).toBe('bar'); expect(fixedDataTable.props.width).toBe(tableState.gridWidth); expect(fixedDataTable.props.height).toBe(tableState.gridHeight); diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..9acc771 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,64 @@ +'use strict'; + +var webpack = require('webpack'); +var path = require('path'); + +var minify = process.env.NODE_ENV === 'production'; +var plugins = [ + new webpack.optimize.OccurenceOrderPlugin() +]; + +if (minify) { + plugins.push( + new webpack.optimize.UglifyJsPlugin({ + comments: false, + compress: { + warnings: false, + screw_ie8: true, + dead_code: true, + drop_debugger: true, + drop_console: true + } + }) + ); +} + +module.exports = { + context: __dirname, + entry: path.resolve(__dirname, 'src', 'responsive-fixed-data-table.js'), + output: { + path: path.resolve(__dirname, 'lib'), + filename: 'responsive-fixed-data-table' + (minify ? '.min.js' : '.js'), + library: 'ResponsiveFixedDataTable', + libraryTarget: 'umd' + }, + externals: { + react: { + root: 'React', + commonjs2: 'react', + commonjs: 'react', + amd: 'react' + }, + 'react-dom': { + root: 'ReactDOM', + commonjs2: 'react-dom', + commonjs: 'react-dom', + amd: 'react-dom' + }, + 'fixed-data-table': { + root: 'FixedDataTable', + commonjs2: 'fixed-data-table', + commonjs: 'fixed-data-table', + amd: 'fixed-data-table' + } + }, + resolve: { + extensions: ['', '.js'] + }, + module: { + loaders: [ + { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel' } + ] + }, + plugins: plugins +} \ No newline at end of file