UNPKG

amit-fixed-data-table

Version:

A React table component designed to allow presenting thousands of rows of data.

1,329 lines (1,110 loc) 342 kB
/** * FixedDataTable v1.0.2 * * Copyright Schrodinger, LLC * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("react"), require("react-dom")); else if(typeof define === 'function' && define.amd) define(["react", "react-dom"], factory); else if(typeof exports === 'object') exports["FixedDataTable"] = factory(require("react"), require("react-dom")); else root["FixedDataTable"] = factory(root["React"], root["ReactDOM"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_30__, __WEBPACK_EXTERNAL_MODULE_60__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { __webpack_require__(1); __webpack_require__(5); __webpack_require__(7); __webpack_require__(9); __webpack_require__(11); __webpack_require__(13); __webpack_require__(15); __webpack_require__(17); __webpack_require__(19); __webpack_require__(21); __webpack_require__(23); __webpack_require__(25); module.exports = __webpack_require__(27); /***/ }), /* 1 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 2 */, /* 3 */, /* 4 */, /* 5 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 6 */, /* 7 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 8 */, /* 9 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 10 */, /* 11 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 12 */, /* 13 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 14 */, /* 15 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 16 */, /* 17 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 18 */, /* 19 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 20 */, /* 21 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 22 */, /* 23 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 24 */, /* 25 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 26 */, /* 27 */ /***/ (function(module, exports, __webpack_require__) { /** * Copyright Schrodinger, LLC * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule FixedDataTableRoot */ 'use strict'; var _FixedDataTable = __webpack_require__(28); var _FixedDataTable2 = _interopRequireDefault(_FixedDataTable); var _FixedDataTableCellDefault = __webpack_require__(81); var _FixedDataTableCellDefault2 = _interopRequireDefault(_FixedDataTableCellDefault); var _FixedDataTableColumn = __webpack_require__(79); var _FixedDataTableColumn2 = _interopRequireDefault(_FixedDataTableColumn); var _FixedDataTableColumnGroup = __webpack_require__(78); var _FixedDataTableColumnGroup2 = _interopRequireDefault(_FixedDataTableColumnGroup); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var FixedDataTableRoot = { Cell: _FixedDataTableCellDefault2.default, Column: _FixedDataTableColumn2.default, ColumnGroup: _FixedDataTableColumnGroup2.default, Table: _FixedDataTable2.default }; FixedDataTableRoot.version = '0.7.17'; module.exports = FixedDataTableRoot; /***/ }), /* 28 */ /***/ (function(module, exports, __webpack_require__) { 'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * Copyright Schrodinger, LLC * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule FixedDataTable * @typechecks * @noflow */ /*eslint no-bitwise:1*/ var _React = __webpack_require__(29); var _React2 = _interopRequireDefault(_React); var _createReactClass = __webpack_require__(31); var _createReactClass2 = _interopRequireDefault(_createReactClass); var _propTypes = __webpack_require__(39); var _propTypes2 = _interopRequireDefault(_propTypes); var _ReactComponentWithPureRenderMixin = __webpack_require__(44); var _ReactComponentWithPureRenderMixin2 = _interopRequireDefault(_ReactComponentWithPureRenderMixin); var _ReactWheelHandler = __webpack_require__(45); var _ReactWheelHandler2 = _interopRequireDefault(_ReactWheelHandler); var _ReactTouchHandler = __webpack_require__(53); var _ReactTouchHandler2 = _interopRequireDefault(_ReactTouchHandler); var _Scrollbar = __webpack_require__(54); var _Scrollbar2 = _interopRequireDefault(_Scrollbar); var _FixedDataTableBufferedRows = __webpack_require__(69); var _FixedDataTableBufferedRows2 = _interopRequireDefault(_FixedDataTableBufferedRows); var _FixedDataTableColumnResizeHandle = __webpack_require__(85); var _FixedDataTableColumnResizeHandle2 = _interopRequireDefault(_FixedDataTableColumnResizeHandle); var _FixedDataTableRow = __webpack_require__(74); var _FixedDataTableRow2 = _interopRequireDefault(_FixedDataTableRow); var _FixedDataTableScrollHelper = __webpack_require__(86); var _FixedDataTableScrollHelper2 = _interopRequireDefault(_FixedDataTableScrollHelper); var _FixedDataTableWidthHelper = __webpack_require__(88); var _FixedDataTableWidthHelper2 = _interopRequireDefault(_FixedDataTableWidthHelper); var _cx = __webpack_require__(62); var _cx2 = _interopRequireDefault(_cx); var _debounceCore = __webpack_require__(89); var _debounceCore2 = _interopRequireDefault(_debounceCore); var _emptyFunction = __webpack_require__(46); var _emptyFunction2 = _interopRequireDefault(_emptyFunction); var _invariant = __webpack_require__(68); var _invariant2 = _interopRequireDefault(_invariant); var _joinClasses = __webpack_require__(82); var _joinClasses2 = _interopRequireDefault(_joinClasses); var _shallowEqual = __webpack_require__(84); var _shallowEqual2 = _interopRequireDefault(_shallowEqual); var _FixedDataTableTranslateDOMPosition = __webpack_require__(63); var _FixedDataTableTranslateDOMPosition2 = _interopRequireDefault(_FixedDataTableTranslateDOMPosition); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } var ReactChildren = _React2.default.Children; var EMPTY_OBJECT = {}; var BORDER_HEIGHT = 1; var HEADER = 'header'; var FOOTER = 'footer'; var CELL = 'cell'; var DRAG_SCROLL_SPEED = 15; var DRAG_SCROLL_BUFFER = 100; /** * Data grid component with fixed or scrollable header and columns. * * The layout of the data table is as follows: * * ``` * +---------------------------------------------------+ * | Fixed Column Group | Scrollable Column Group | * | Header | Header | * | | | * +---------------------------------------------------+ * | | | * | Fixed Header Columns | Scrollable Header Columns | * | | | * +-----------------------+---------------------------+ * | | | * | Fixed Body Columns | Scrollable Body Columns | * | | | * +-----------------------+---------------------------+ * | | | * | Fixed Footer Columns | Scrollable Footer Columns | * | | | * +-----------------------+---------------------------+ * ``` * * - Fixed Column Group Header: These are the headers for a group * of columns if included in the table that do not scroll * vertically or horizontally. * * - Scrollable Column Group Header: The header for a group of columns * that do not move while scrolling vertically, but move horizontally * with the horizontal scrolling. * * - Fixed Header Columns: The header columns that do not move while scrolling * vertically or horizontally. * * - Scrollable Header Columns: The header columns that do not move * while scrolling vertically, but move horizontally with the horizontal * scrolling. * * - Fixed Body Columns: The body columns that do not move while scrolling * horizontally, but move vertically with the vertical scrolling. * * - Scrollable Body Columns: The body columns that move while scrolling * vertically or horizontally. */ var FixedDataTable = (0, _createReactClass2.default)({ displayName: 'FixedDataTable', propTypes: { /** * Pixel width of table. If all columns do not fit, * a horizontal scrollbar will appear. */ width: _propTypes2.default.number.isRequired, /** * Pixel height of table. If all rows do not fit, * a vertical scrollbar will appear. * * Either `height` or `maxHeight` must be specified. */ height: _propTypes2.default.number, /** * Class name to be passed into parent container */ className: _propTypes2.default.string, /** * Maximum pixel height of table. If all rows do not fit, * a vertical scrollbar will appear. * * Either `height` or `maxHeight` must be specified. */ maxHeight: _propTypes2.default.number, /** * Pixel height of table's owner, this is used in a managed scrolling * situation when you want to slide the table up from below the fold * without having to constantly update the height on every scroll tick. * Instead, vary this property on scroll. By using `ownerHeight`, we * over-render the table while making sure the footer and horizontal * scrollbar of the table are visible when the current space for the table * in view is smaller than the final, over-flowing height of table. It * allows us to avoid resizing and reflowing table when it is moving in the * view. * * This is used if `ownerHeight < height` (or `maxHeight`). */ ownerHeight: _propTypes2.default.number, overflowX: _propTypes2.default.oneOf(['hidden', 'auto']), overflowY: _propTypes2.default.oneOf(['hidden', 'auto']), /** * Boolean flag indicating of touch scrolling should be enabled * This feature is current in beta and may have bugs */ touchScrollEnabled: _propTypes2.default.bool, /** * Hide the scrollbar but still enable scroll functionality */ showScrollbarX: _propTypes2.default.bool, showScrollbarY: _propTypes2.default.bool, /** * Callback when horizontally scrolling the grid. * * Return false to stop propagation. */ onHorizontalScroll: _propTypes2.default.func, /** * Callback when vertically scrolling the grid. * * Return false to stop propagation. */ onVerticalScroll: _propTypes2.default.func, /** * Number of rows in the table. */ rowsCount: _propTypes2.default.number.isRequired, /** * Pixel height of rows unless `rowHeightGetter` is specified and returns * different value. */ rowHeight: _propTypes2.default.number.isRequired, /** * If specified, `rowHeightGetter(index)` is called for each row and the * returned value overrides `rowHeight` for particular row. */ rowHeightGetter: _propTypes2.default.func, /** * To get any additional CSS classes that should be added to a row, * `rowClassNameGetter(index)` is called. */ rowClassNameGetter: _propTypes2.default.func, /** * If specified, `rowKeyGetter(index)` is called for each row and the * returned value overrides `key` for the particular row. */ rowKeyGetter: _propTypes2.default.func, /** * Pixel height of the column group header. */ groupHeaderHeight: _propTypes2.default.number, /** * Pixel height of header. */ headerHeight: _propTypes2.default.number.isRequired, /** * Pixel height of footer. */ footerHeight: _propTypes2.default.number, /** * Value of horizontal scroll. */ scrollLeft: _propTypes2.default.number, /** * Index of column to scroll to. */ scrollToColumn: _propTypes2.default.number, /** * Value of vertical scroll. */ scrollTop: _propTypes2.default.number, /** * Index of row to scroll to. */ scrollToRow: _propTypes2.default.number, /** * Callback that is called when scrolling starts with current horizontal * and vertical scroll values. */ onScrollStart: _propTypes2.default.func, /** * Callback that is called when scrolling ends or stops with new horizontal * and vertical scroll values. */ onScrollEnd: _propTypes2.default.func, /** * If enabled scroll events will not be propagated outside of the table. */ stopScrollPropagation: _propTypes2.default.bool, /** * Callback that is called when `rowHeightGetter` returns a different height * for a row than the `rowHeight` prop. This is necessary because initially * table estimates heights of some parts of the content. */ onContentHeightChange: _propTypes2.default.func, /** * Callback that is called when a row is clicked. */ onRowClick: _propTypes2.default.func, /** * Callback that is called when a row is double clicked. */ onRowDoubleClick: _propTypes2.default.func, /** * Callback that is called when a mouse-down event happens on a row. */ onRowMouseDown: _propTypes2.default.func, /** * Callback that is called when a mouse-enter event happens on a row. */ onRowMouseEnter: _propTypes2.default.func, /** * Callback that is called when a mouse-leave event happens on a row. */ onRowMouseLeave: _propTypes2.default.func, /** * Callback that is called when resizer has been released * and column needs to be updated. * * Required if the isResizable property is true on any column. * * ``` * function( * newColumnWidth: number, * columnKey: string, * ) * ``` */ onColumnResizeEndCallback: _propTypes2.default.func, /** * Callback that is called when reordering has been completed * and columns need to be updated. * * ``` * function( * event { * columnBefore: string|undefined, // the column before the new location of this one * columnAfter: string|undefined, // the column after the new location of this one * reorderColumn: string, // the column key that was just reordered * } * ) * ``` */ onColumnReorderEndCallback: _propTypes2.default.func, /** * Whether a column is currently being resized. */ isColumnResizing: _propTypes2.default.bool, /** * Whether columns are currently being reordered. */ isColumnReordering: _propTypes2.default.bool, /** * The number of rows outside the viewport to prerender. Defaults to roughly * half of the number of visible rows. */ bufferRowCount: _propTypes2.default.number }, getDefaultProps: function getDefaultProps() /*object*/{ return { footerHeight: 0, groupHeaderHeight: 0, headerHeight: 0, showScrollbarX: true, showScrollbarY: true, touchScrollEnabled: false, stopScrollPropagation: false }; }, componentWillMount: function componentWillMount() { var props = this.props; var viewportHeight = (props.height === undefined ? props.maxHeight : props.height) - (props.headerHeight || 0) - (props.footerHeight || 0) - (props.groupHeaderHeight || 0); this._scrollHelper = new _FixedDataTableScrollHelper2.default(props.rowsCount, props.rowHeight, viewportHeight, props.rowHeightGetter); this._didScrollStop = (0, _debounceCore2.default)(this._didScrollStop, 200, this); this._wheelHandler = new _ReactWheelHandler2.default(this._onScroll, this._shouldHandleWheelX, this._shouldHandleWheelY, props.stopScrollPropagation); this._touchHandler = new _ReactTouchHandler2.default(this._onScroll, this._shouldHandleTouchX, this._shouldHandleTouchY, props.stopScrollPropagation); this.setState(this._calculateState(props)); }, componentWillUnmount: function componentWillUnmount() { this._wheelHandler = null; this._touchHandler = null; }, _shouldHandleTouchX: function _shouldHandleTouchX( /*number*/delta) /*boolean*/{ return this.props.touchScrollEnabled && this._shouldHandleWheelX(delta); }, _shouldHandleTouchY: function _shouldHandleTouchY( /*number*/delta) /*boolean*/{ return this.props.touchScrollEnabled && this._shouldHandleWheelY(delta); }, _shouldHandleWheelX: function _shouldHandleWheelX( /*number*/delta) /*boolean*/{ if (this.props.overflowX === 'hidden') { return false; } delta = Math.round(delta); if (delta === 0) { return false; } return delta < 0 && this.state.scrollX > 0 || delta >= 0 && this.state.scrollX < this.state.maxScrollX; }, _shouldHandleWheelY: function _shouldHandleWheelY( /*number*/delta) /*boolean*/{ if (this.props.overflowY === 'hidden' || delta === 0) { return false; } delta = Math.round(delta); if (delta === 0) { return false; } return delta < 0 && this.state.scrollY > 0 || delta >= 0 && this.state.scrollY < this.state.maxScrollY; }, _reportContentHeight: function _reportContentHeight() { var scrollContentHeight = this.state.scrollContentHeight; var reservedHeight = this.state.reservedHeight; var requiredHeight = scrollContentHeight + reservedHeight; var contentHeight; var useMaxHeight = this.props.height === undefined; if (useMaxHeight && this.props.maxHeight > requiredHeight) { contentHeight = requiredHeight; } else if (this.state.height > requiredHeight && this.props.ownerHeight) { contentHeight = Math.max(requiredHeight, this.props.ownerHeight); } else { contentHeight = this.state.height + this.state.maxScrollY; } if (contentHeight !== this._contentHeight && this.props.onContentHeightChange) { this.props.onContentHeightChange(contentHeight); } this._contentHeight = contentHeight; }, componentDidMount: function componentDidMount() { this._reportContentHeight(); }, componentWillReceiveProps: function componentWillReceiveProps( /*object*/nextProps) { var newOverflowX = nextProps.overflowX; var newOverflowY = nextProps.overflowY; // In the case of controlled scrolling, notify. if (this.props.ownerHeight !== nextProps.ownerHeight || this.props.scrollTop !== nextProps.scrollTop || this.props.scrollLeft !== nextProps.scrollLeft) { this._didScrollStart(); } this._didScrollStop(); this.setState(this._calculateState(nextProps, this.state)); }, componentDidUpdate: function componentDidUpdate() { this._reportContentHeight(); }, render: function render() /*object*/{ var state = this.state; var props = this.props; var onColumnReorder = props.onColumnReorderEndCallback ? this._onColumnReorder : null; var groupHeader; if (state.useGroupHeader) { groupHeader = _React2.default.createElement(_FixedDataTableRow2.default, { key: 'group_header', isScrolling: this._isScrolling, className: (0, _joinClasses2.default)((0, _cx2.default)('fixedDataTableLayout/header'), (0, _cx2.default)('public/fixedDataTable/header')), width: state.width, height: state.groupHeaderHeight, index: 0, zIndex: 1, offsetTop: 0, scrollLeft: state.scrollX, fixedColumns: state.groupHeaderFixedColumns, scrollableColumns: state.groupHeaderScrollableColumns, onColumnResize: this._onColumnResize, onColumnReorder: onColumnReorder, onColumnReorderMove: this._onColumnReorderMove }); } var maxScrollY = this.state.maxScrollY; var showScrollbarX = state.maxScrollX > 0 && state.overflowX !== 'hidden' && state.showScrollbarX !== false; var showScrollbarY = maxScrollY > 0 && state.overflowY !== 'hidden' && state.showScrollbarY !== false; var scrollbarXHeight = showScrollbarX ? _Scrollbar2.default.SIZE : 0; var scrollbarYHeight = state.height - scrollbarXHeight - 2 * BORDER_HEIGHT - state.footerHeight; var headerOffsetTop = state.useGroupHeader ? state.groupHeaderHeight : 0; var bodyOffsetTop = headerOffsetTop + state.headerHeight; scrollbarYHeight -= bodyOffsetTop; var bottomSectionOffset = 0; var footOffsetTop = props.maxHeight != null ? bodyOffsetTop + state.bodyHeight : bodyOffsetTop + scrollbarYHeight; var rowsContainerHeight = footOffsetTop + state.footerHeight; if (props.ownerHeight !== undefined && props.ownerHeight < state.height) { bottomSectionOffset = props.ownerHeight - state.height; footOffsetTop = Math.min(footOffsetTop, props.ownerHeight - state.footerHeight - scrollbarXHeight); scrollbarYHeight = Math.max(0, footOffsetTop - bodyOffsetTop); } var verticalScrollbar; if (showScrollbarY) { verticalScrollbar = _React2.default.createElement(_Scrollbar2.default, { size: scrollbarYHeight, contentSize: scrollbarYHeight + maxScrollY, onScroll: this._onVerticalScroll, verticalTop: bodyOffsetTop, position: state.scrollY }); } var horizontalScrollbar; if (showScrollbarX) { var scrollbarXWidth = state.width; horizontalScrollbar = _React2.default.createElement(HorizontalScrollbar, { contentSize: scrollbarXWidth + state.maxScrollX, offset: bottomSectionOffset, onScroll: this._onHorizontalScroll, position: state.scrollX, size: scrollbarXWidth }); } var dragKnob = _React2.default.createElement(_FixedDataTableColumnResizeHandle2.default, { height: state.height, initialWidth: state.columnResizingData.width || 0, minWidth: state.columnResizingData.minWidth || 0, maxWidth: state.columnResizingData.maxWidth || Number.MAX_VALUE, visible: !!state.isColumnResizing, leftOffset: state.columnResizingData.left || 0, knobHeight: state.headerHeight, initialEvent: state.columnResizingData.initialEvent, onColumnResizeEnd: props.onColumnResizeEndCallback, columnKey: state.columnResizingData.key }); var footer = null; if (state.footerHeight) { footer = _React2.default.createElement(_FixedDataTableRow2.default, { key: 'footer', isScrolling: this._isScrolling, className: (0, _joinClasses2.default)((0, _cx2.default)('fixedDataTableLayout/footer'), (0, _cx2.default)('public/fixedDataTable/footer')), width: state.width, height: state.footerHeight, index: -1, zIndex: 1, offsetTop: footOffsetTop, fixedColumns: state.footFixedColumns, scrollableColumns: state.footScrollableColumns, scrollLeft: state.scrollX }); } var rows = this._renderRows(bodyOffsetTop); var header = _React2.default.createElement(_FixedDataTableRow2.default, { key: 'header', isScrolling: this._isScrolling, className: (0, _joinClasses2.default)((0, _cx2.default)('fixedDataTableLayout/header'), (0, _cx2.default)('public/fixedDataTable/header')), width: state.width, height: state.headerHeight, index: -1, zIndex: 1, offsetTop: headerOffsetTop, scrollLeft: state.scrollX, fixedColumns: state.headFixedColumns, scrollableColumns: state.headScrollableColumns, onColumnResize: this._onColumnResize, onColumnReorder: onColumnReorder, onColumnReorderMove: this._onColumnReorderMove, onColumnReorderEnd: this._onColumnReorderEnd, isColumnReordering: !!state.isColumnReordering, columnReorderingData: state.columnReorderingData }); var topShadow; var bottomShadow; if (state.scrollY) { topShadow = _React2.default.createElement('div', { className: (0, _joinClasses2.default)((0, _cx2.default)('fixedDataTableLayout/topShadow'), (0, _cx2.default)('public/fixedDataTable/topShadow')), style: { top: bodyOffsetTop } }); } if (state.ownerHeight != null && state.ownerHeight < state.height && state.scrollContentHeight + state.reservedHeight > state.ownerHeight || state.scrollY < maxScrollY) { bottomShadow = _React2.default.createElement('div', { className: (0, _joinClasses2.default)((0, _cx2.default)('fixedDataTableLayout/bottomShadow'), (0, _cx2.default)('public/fixedDataTable/bottomShadow')), style: { top: footOffsetTop } }); } return _React2.default.createElement( 'div', { className: (0, _joinClasses2.default)(this.state.className, (0, _cx2.default)('fixedDataTableLayout/main'), (0, _cx2.default)('public/fixedDataTable/main')), onWheel: this._wheelHandler.onWheel, onTouchStart: this._touchHandler.onTouchStart, onTouchEnd: this._touchHandler.onTouchEnd, onTouchMove: this._touchHandler.onTouchMove, onTouchCancel: this._touchHandler.onTouchCancel, style: { height: state.height, width: state.width } }, _React2.default.createElement( 'div', { className: (0, _cx2.default)('fixedDataTableLayout/rowsContainer'), style: { height: rowsContainerHeight, width: state.width } }, dragKnob, groupHeader, header, rows, footer, topShadow, bottomShadow ), verticalScrollbar, horizontalScrollbar ); }, _renderRows: function _renderRows( /*number*/offsetTop) /*object*/{ var state = this.state; return _React2.default.createElement(_FixedDataTableBufferedRows2.default, { isScrolling: this._isScrolling, defaultRowHeight: state.rowHeight, firstRowIndex: state.firstRowIndex, firstRowOffset: state.firstRowOffset, fixedColumns: state.bodyFixedColumns, height: state.bodyHeight, offsetTop: offsetTop, onRowClick: state.onRowClick, onRowDoubleClick: state.onRowDoubleClick, onRowMouseDown: state.onRowMouseDown, onRowMouseEnter: state.onRowMouseEnter, onRowMouseLeave: state.onRowMouseLeave, rowClassNameGetter: state.rowClassNameGetter, rowsCount: state.rowsCount, rowGetter: state.rowGetter, rowHeightGetter: state.rowHeightGetter, rowKeyGetter: state.rowKeyGetter, scrollLeft: state.scrollX, scrollableColumns: state.bodyScrollableColumns, showLastRowBorder: true, width: state.width, rowPositionGetter: this._scrollHelper.getRowPosition, bufferRowCount: this.state.bufferRowCount }); }, /** * This is called when a cell that is in the header of a column has its * resizer knob clicked on. It displays the resizer and puts in the correct * location on the table. */ _onColumnResize: function _onColumnResize( /*number*/combinedWidth, /*number*/leftOffset, /*number*/cellWidth, /*?number*/cellMinWidth, /*?number*/cellMaxWidth, /*number|string*/columnKey, /*object*/event) { this.setState({ isColumnResizing: true, columnResizingData: { left: leftOffset + combinedWidth - cellWidth, width: cellWidth, minWidth: cellMinWidth, maxWidth: cellMaxWidth, initialEvent: { clientX: event.clientX, clientY: event.clientY, preventDefault: _emptyFunction2.default }, key: columnKey } }); }, _onColumnReorder: function _onColumnReorder( /*string*/columnKey, /*number*/width, /*number*/left, /*object*/event) { // No native support in IE11 for find, findIndex, or includes, so using some. var isFixed = this.state.headFixedColumns.some(function (column) { return column.props.columnKey === columnKey; }); this.setState({ isColumnReordering: true, columnReorderingData: { dragDistance: 0, isFixed: isFixed, scrollStart: this.state.scrollX, columnKey: columnKey, columnWidth: width, originalLeft: left, columnsBefore: [], columnsAfter: [] } }); }, _onColumnReorderMove: function _onColumnReorderMove( /*number*/deltaX) { //NOTE Need to clone this object when use pureRendering var reorderingData = _extends({}, this.state.columnReorderingData); reorderingData.dragDistance = deltaX; reorderingData.columnBefore = undefined; reorderingData.columnAfter = undefined; var isFixedColumn = this.state.columnReorderingData.isFixed; var scrollX = this.state.scrollX; if (!isFixedColumn) { //Relative dragX position on scroll var dragX = reorderingData.originalLeft - reorderingData.scrollStart + reorderingData.dragDistance; var fixedColumnsWidth = this.state.bodyFixedColumns.reduce(function (sum, column) { return sum + column.props.width; }, 0); var relativeWidth = this.props.width - fixedColumnsWidth; //Scroll the table left or right if we drag near the edges of the table if (dragX > relativeWidth - DRAG_SCROLL_BUFFER) { scrollX = Math.min(scrollX + DRAG_SCROLL_SPEED, this.state.maxScrollX); } else if (dragX <= DRAG_SCROLL_BUFFER) { scrollX = Math.max(scrollX - DRAG_SCROLL_SPEED, 0); } reorderingData.dragDistance += this.state.scrollX - reorderingData.scrollStart; } this.setState({ scrollX: scrollX, columnReorderingData: reorderingData }); }, _onColumnReorderEnd: function _onColumnReorderEnd( /*object*/props, /*object*/event) { var columnBefore = this.state.columnReorderingData.columnBefore; var columnAfter = this.state.columnReorderingData.columnAfter; var reorderColumn = this.state.columnReorderingData.columnKey; var cancelReorder = this.state.columnReorderingData.cancelReorder; this.setState({ isColumnReordering: false, columnReorderingData: {} }); if (cancelReorder) { return; } this.props.onColumnReorderEndCallback({ columnBefore: columnBefore, columnAfter: columnAfter, reorderColumn: reorderColumn }); var onHorizontalScroll = this.props.onHorizontalScroll; if (this.state.columnReorderingData.scrollStart !== this.state.scrollX && onHorizontalScroll) { onHorizontalScroll(this.state.scrollX); }; }, _areColumnSettingsIdentical: function _areColumnSettingsIdentical(oldColumns, newColumns) { if (oldColumns.length !== newColumns.length) { return false; } for (var index = 0; index < oldColumns.length; ++index) { if (!(0, _shallowEqual2.default)(oldColumns[index].props, newColumns[index].props)) { return false; } } return true; }, _populateColumnsAndColumnData: function _populateColumnsAndColumnData(columns, columnGroups, oldState) { var canReuseColumnSettings = false; var canReuseColumnGroupSettings = false; if (oldState && oldState.columns) { canReuseColumnSettings = this._areColumnSettingsIdentical(columns, oldState.columns); } if (oldState && oldState.columnGroups && columnGroups) { canReuseColumnGroupSettings = this._areColumnSettingsIdentical(columnGroups, oldState.columnGroups); } var columnInfo = {}; if (canReuseColumnSettings) { columnInfo.bodyFixedColumns = oldState.bodyFixedColumns; columnInfo.bodyScrollableColumns = oldState.bodyScrollableColumns; columnInfo.headFixedColumns = oldState.headFixedColumns; columnInfo.headScrollableColumns = oldState.headScrollableColumns; columnInfo.footFixedColumns = oldState.footFixedColumns; columnInfo.footScrollableColumns = oldState.footScrollableColumns; } else { var bodyColumnTypes = this._splitColumnTypes(columns); columnInfo.bodyFixedColumns = bodyColumnTypes.fixed; columnInfo.bodyScrollableColumns = bodyColumnTypes.scrollable; var headColumnTypes = this._splitColumnTypes(this._selectColumnElement(HEADER, columns)); columnInfo.headFixedColumns = headColumnTypes.fixed; columnInfo.headScrollableColumns = headColumnTypes.scrollable; var footColumnTypes = this._splitColumnTypes(this._selectColumnElement(FOOTER, columns)); columnInfo.footFixedColumns = footColumnTypes.fixed; columnInfo.footScrollableColumns = footColumnTypes.scrollable; } if (canReuseColumnGroupSettings) { columnInfo.groupHeaderFixedColumns = oldState.groupHeaderFixedColumns; columnInfo.groupHeaderScrollableColumns = oldState.groupHeaderScrollableColumns; } else { if (columnGroups) { var groupHeaderColumnTypes = this._splitColumnTypes(this._selectColumnElement(HEADER, columnGroups)); columnInfo.groupHeaderFixedColumns = groupHeaderColumnTypes.fixed; columnInfo.groupHeaderScrollableColumns = groupHeaderColumnTypes.scrollable; } } return columnInfo; }, _calculateState: function _calculateState( /*object*/props, /*?object*/oldState) /*object*/{ var _this = this; (0, _invariant2.default)(props.height !== undefined || props.maxHeight !== undefined, 'You must set either a height or a maxHeight'); var children = []; ReactChildren.forEach(props.children, function (child, index) { if (child == null) { return; } (0, _invariant2.default)(child.type.__TableColumnGroup__ || child.type.__TableColumn__, 'child type should be <FixedDataTableColumn /> or ' + '<FixedDataTableColumnGroup />'); children.push(child); }); var useGroupHeader = false; if (children.length && children[0].type.__TableColumnGroup__) { useGroupHeader = true; } var scrollState; var firstRowIndex = oldState && oldState.firstRowIndex || 0; var firstRowOffset = oldState && oldState.firstRowOffset || 0; var scrollY = oldState ? oldState.scrollY : 0; var scrollX = oldState ? oldState.scrollX : 0; var lastScrollLeft = oldState ? oldState.scrollLeft : 0; if (props.scrollLeft !== undefined && props.scrollLeft !== lastScrollLeft) { scrollX = props.scrollLeft; } var groupHeaderHeight = useGroupHeader ? props.groupHeaderHeight : 0; if (oldState && (props.rowsCount !== oldState.rowsCount || props.rowHeight !== oldState.rowHeight || props.height !== oldState.height)) { // Number of rows changed, try to scroll to the row from before the // change var viewportHeight = (props.height === undefined ? props.maxHeight : props.height) - (props.headerHeight || 0) - (props.footerHeight || 0) - (props.groupHeaderHeight || 0); var oldViewportHeight = this._scrollHelper._viewportHeight; this._scrollHelper = new _FixedDataTableScrollHelper2.default(props.rowsCount, props.rowHeight, viewportHeight, props.rowHeightGetter); scrollState = this._scrollHelper.scrollToRow(firstRowIndex, firstRowOffset); firstRowIndex = scrollState.index; firstRowOffset = scrollState.offset; scrollY = scrollState.position; } else if (oldState && props.rowHeightGetter !== oldState.rowHeightGetter) { this._scrollHelper.setRowHeightGetter(props.rowHeightGetter); } var lastScrollToRow = oldState ? oldState.scrollToRow : undefined; if (props.scrollToRow != null && (props.scrollToRow !== lastScrollToRow || viewportHeight !== oldViewportHeight)) { scrollState = this._scrollHelper.scrollRowIntoView(props.scrollToRow); firstRowIndex = scrollState.index; firstRowOffset = scrollState.offset; scrollY = scrollState.position; } var lastScrollTop = oldState ? oldState.scrollTop : undefined; if (props.scrollTop != null && props.scrollTop !== lastScrollTop) { scrollState = this._scrollHelper.scrollTo(props.scrollTop); firstRowIndex = scrollState.index; firstRowOffset = scrollState.offset; scrollY = scrollState.position; } // update row heights [].concat(_toConsumableArray(Array(props.rowsCount).keys())).forEach(function (index) { _this._scrollHelper._updateRowHeight(index); }); var columnResizingData; if (props.isColumnResizing) { columnResizingData = oldState && oldState.columnResizingData; } else { columnResizingData = EMPTY_OBJECT; } var columns; var columnGroups; if (useGroupHeader) { var columnGroupSettings = _FixedDataTableWidthHelper2.default.adjustColumnGroupWidths(children, props.width); columns = columnGroupSettings.columns; columnGroups = columnGroupSettings.columnGroups; } else { columns = _FixedDataTableWidthHelper2.default.adjustColumnWidths(children, props.width); } var columnInfo = this._populateColumnsAndColumnData(columns, columnGroups, oldState); var lastScrollToColumn = oldState ? oldState.scrollToColumn : undefined; if (props.scrollToColumn !== null && props.scrollToColumn !== lastScrollToColumn) { // If selected column is a fixed column, don't scroll var fixedColumnsCount = columnInfo.bodyFixedColumns.length; if (props.scrollToColumn >= fixedColumnsCount) { var totalFixedColumnsWidth = 0; var i, column; for (i = 0; i < columnInfo.bodyFixedColumns.length; ++i) { column = columnInfo.bodyFixedColumns[i]; totalFixedColumnsWidth += column.props.width; } var scrollableColumnIndex = Math.min(props.scrollToColumn - fixedColumnsCount, columnInfo.bodyScrollableColumns.length - 1); var previousColumnsWidth = 0; for (i = 0; i < scrollableColumnIndex; ++i) { column = columnInfo.bodyScrollableColumns[i]; previousColumnsWidth += column.props.width; } var availableScrollWidth = props.width - totalFixedColumnsWidth; var selectedColumnWidth = columnInfo.bodyScrollableColumns[scrollableColumnIndex].props.width; var minAcceptableScrollPosition = previousColumnsWidth + selectedColumnWidth - availableScrollWidth; if (scrollX < minAcceptableScrollPosition) { scrollX = minAcceptableScrollPosition; } if (scrollX > previousColumnsWidth) { scrollX = previousColumnsWidth; } } } var useMaxHeight = props.height === undefined; var height = Math.round(useMaxHeight ? props.maxHeight : props.height); var totalHeightReserved = props.footerHeight + props.headerHeight + groupHeaderHeight + 2 * BORDER_HEIGHT; var bodyHeight = height - totalHeightReserved; var scrollContentHeight = this._scrollHelper.getContentHeight(); var totalHeightNeeded = scrollContentHeight + totalHeightReserved; var scrollContentWidth = _FixedDataTableWidthHelper2.default.getTotalWidth(columns); var horizontalScrollbarVisible = scrollContentWidth > props.width && props.overflowX !== 'hidden' && props.showScrollbarX !== false; if (horizontalScrollbarVisible) { bodyHeight -= _Scrollbar2.default.SIZE; totalHeightNeeded += _Scrollbar2.default.SIZE; totalHeightReserved += _Scrollbar2.default.SIZE; } var maxScrollX = Math.max(0, scrollContentWidth - props.width); var maxScrollY = Math.max(0, scrollContentHeight - bodyHeight); scrollX = Math.min(scrollX, maxScrollX); scrollY = Math.min(scrollY, maxScrollY); if (!maxScrollY) { // no vertical scrollbar necessary, use the totals we tracked so we // can shrink-to-fit vertically if (useMaxHeight) { height = totalHeightNeeded; } bodyHeight = totalHeightNeeded - totalHeightReserved; } this._scrollHelper.setViewportHeight(bodyHeight); // This calculation is synonymous to Element.scrollTop var scrollTop = Math.abs(firstRowOffset - this._scrollHelper.getRowPosition(firstRowIndex)); // This case can happen when the user is completely scrolled down and resizes the viewport to be taller vertically. // This is because we set the viewport height after having calculated the rows if (scrollTop !== scrollY) { scrollTop = maxScrollY; scrollState = this._scrollHelper.scrollTo(scrollTop); firstRowIndex = scrollState.index; firstRowOffset = scrollState.offset; scrollY = scrollState.position; } // The order of elements in this object metters and bringing bodyHeight, // height or useGroupHeader to the top can break various features var newState = _extends({ isColumnResizing: oldState && oldState.isColumnResizing }, columnInfo, props, { columns: columns, columnGroups: columnGroups, columnResizingData: columnResizingData, firstRowIndex: firstRowIndex, firstRowOffset: firstRowOffset, horizontalScrollbarVisible: horizontalScrollbarVisible, maxScrollX: maxScrollX, maxScrollY: maxScrollY, reservedHeight: totalHeightReserved, scrollContentHeight: scrollContentHeight, scrollX: scrollX, scrollY: scrollY, // These properties may overwrite properties defined in // columnInfo and props bodyHeight: bodyHeight, height: height, groupHeaderHeight: groupHeaderHeight, useGroupHeader: useGroupHeader }); return newState; }, _selectColumnElement: function _selectColumnElement( /*string*/type, /*array*/columns) /*array*/{ var newColumns = []; for (var i = 0; i < columns.length; ++i) { var column = columns[i]; newColumns.push(_React2.default.cloneElement(column, { cell: type ? column.props[type] : column.props[CELL] })); } return newColumns; }, _splitColumnTypes: function _splitColumnTypes( /*array*/columns) /*object*/{ var fixedColumns = []; var scrollableColumns = []; for (var i = 0; i < columns.length; ++i) { if (columns[i].props.fixed) { fixedColumns.push(columns[i]); } else { scrollableColumns.push(columns[i]); } } return { fixed: fixedColumns, scrollable: scrollableColumns }; }, _onScroll: function _onScroll( /*number*/deltaX, /*number*/deltaY) { if (!this._isScrolling) { this._didScrollStart(); } var x = this.state.scrollX; if (Math.abs(deltaY) > Math.abs(deltaX) && this.props.overflowY !== 'hidden') { var scrollState = this._scrollHelper.scrollBy(Math.round(deltaY)); var onVerticalScroll = this.props.onVerticalScroll; if (onVerticalScroll ? onVerticalScroll(scrollState.position) : true) { var maxScrollY = Math.max(0, scrollState.contentHeight - this.state.bodyHeight); this.setState({ firstRowIndex: scrollState.index, firstRowOffset: scrollState.offset, scrollY: scrollState.position, scrollContentHeight: scrollState.contentHeight, maxScrollY: maxScrollY }); } } else if (deltaX && this.props.overflowX !== 'hidden') { x += deltaX; x = x < 0 ? 0 : x; x = x > this.state.maxScrollX ? this.state.maxScrollX : x; //NOTE (asif) This is a hacky workaround to prevent FDT from setting its internal state var onHorizontalScroll = this.props.onHorizontalScroll; if (onHorizontalScroll ? onHorizontalScroll(x) : true) { this.setState({ scrollX: x }); } } this._didScrollStop(); }, _onHorizontalScroll: function _onHorizontalScroll( /*number*/scrollPos) { if (scrollPos === this.state.scrollX) { return; } if (!this._isScrolling)