UNPKG

wix-style-react

Version:
631 lines (533 loc) • 24.3 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataTableHeader = undefined; var _class2, _temp2; 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; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _DataTable = require('./DataTable.scss'); var _DataTable2 = _interopRequireDefault(_DataTable); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _InfiniteScroll = require('../utils/InfiniteScroll'); var _InfiniteScroll2 = _interopRequireDefault(_InfiniteScroll); var _SortByArrowUp = require('../new-icons/system/SortByArrowUp'); var _SortByArrowUp2 = _interopRequireDefault(_SortByArrowUp); var _SortByArrowDown = require('../new-icons/system/SortByArrowDown'); var _SortByArrowDown2 = _interopRequireDefault(_SortByArrowDown); var _wixAnimations = require('wix-animations'); var _InfoCircle = require('wix-ui-icons-common/InfoCircle'); var _InfoCircle2 = _interopRequireDefault(_InfoCircle); var _Tooltip = require('../Tooltip/Tooltip'); var _Tooltip2 = _interopRequireDefault(_Tooltip); var _InfoIcon = require('../common/InfoIcon'); var _InfoIcon2 = _interopRequireDefault(_InfoIcon); var _deprecationLog = require('../utils/deprecationLog'); var _deprecationLog2 = _interopRequireDefault(_deprecationLog); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var DataTableHeader = exports.DataTableHeader = function DataTableHeader(props) { var dataHook = props.dataHook; return _react2.default.createElement( 'div', { 'data-hook': dataHook }, _react2.default.createElement( 'table', { style: { width: props.width }, className: _DataTable2.default.table }, _react2.default.createElement(TableHeader, props) ) ); }; DataTableHeader.propTypes = { width: _propTypes2.default.string }; var DataTable = function (_React$Component) { _inherits(DataTable, _React$Component); function DataTable(props) { _classCallCheck(this, DataTable); var _this = _possibleConstructorReturn(this, (DataTable.__proto__ || Object.getPrototypeOf(DataTable)).call(this, props)); _this.wrapWithInfiniteScroll = function (table) { return _react2.default.createElement( _InfiniteScroll2.default, { pageStart: 0, loadMore: _this.loadMore, hasMore: _this.state.currentPage < _this.state.lastPage || _this.props.hasMore, loader: _this.props.loader, useWindow: _this.props.useWindow, scrollElement: _this.props.scrollElement }, table ); }; _this.renderTable = function (rowsToRender) { var dataHook = _this.props.dataHook; var style = { width: _this.props.width }; return _react2.default.createElement( 'div', { 'data-hook': dataHook }, _react2.default.createElement( 'table', { id: _this.props.id, style: style, className: (0, _classnames2.default)(_this.style.table, _defineProperty({}, _this.style.showLastRowDivider, _this.props.showLastRowDivider)) }, !_this.props.hideHeader && _react2.default.createElement(TableHeader, _this.props), _this.renderBody(rowsToRender) ) ); }; _this.renderBody = function (rows) { return _react2.default.createElement( 'tbody', null, rows.map(_this.renderRow) ); }; _this.onRowClick = function (rowData, rowNum) { var _this$props = _this.props, onRowClick = _this$props.onRowClick, rowDetails = _this$props.rowDetails; onRowClick && onRowClick(rowData, rowNum); rowDetails && _this.toggleRowDetails(rowNum); }; _this.renderRow = function (rowData, rowNum) { var _this$props2 = _this.props, onRowClick = _this$props2.onRowClick, onMouseEnterRow = _this$props2.onMouseEnterRow, onMouseLeaveRow = _this$props2.onMouseLeaveRow, rowDataHook = _this$props2.rowDataHook, dynamicRowClass = _this$props2.dynamicRowClass, rowDetails = _this$props2.rowDetails; var rowClasses = [_this.props.rowClass]; var optionalRowProps = {}; var handlers = [{ rowEventHandler: _this.onRowClick, eventHandler: 'onClick' }, { rowEventHandler: onMouseEnterRow, eventHandler: 'onMouseEnter' }, { rowEventHandler: onMouseLeaveRow, eventHandler: 'onMouseLeave' }]; handlers.forEach(function (_ref) { var rowEventHandler = _ref.rowEventHandler, eventHandler = _ref.eventHandler; if (rowEventHandler) { optionalRowProps[eventHandler] = function (event) { if (event.isDefaultPrevented()) { return; } rowEventHandler(rowData, rowNum); }; } }); if (onRowClick) { rowClasses.push(_this.style.clickableDataRow); } if (rowDetails) { rowClasses.push(_this.style.animatedDataRow); } if (rowDataHook) { if (typeof rowDataHook === 'string') { optionalRowProps['data-hook'] = rowDataHook; } else { optionalRowProps['data-hook'] = rowDataHook(rowData, rowNum); } } if (dynamicRowClass) { rowClasses.push(dynamicRowClass(rowData, rowNum)); } optionalRowProps.className = (0, _classnames2.default)(rowClasses); var key = rowData.id === undefined ? rowNum : rowData.id; var rowsToRender = [_react2.default.createElement( 'tr', _extends({ 'data-table-row': 'dataTableRow', key: key }, optionalRowProps), _this.props.columns.map(function (column, colNum) { return _this.renderCell(rowData, column, rowNum, colNum); }) )]; if (rowDetails) { var showDetails = !!_this.state.selectedRows[rowNum]; rowsToRender.push(_react2.default.createElement( 'tr', { key: key + '_details', className: (0, _classnames2.default)(_this.style.rowDetails) }, _react2.default.createElement( 'td', { 'data-hook': rowNum + '_details', className: (0, _classnames2.default)(_this.style.details, showDetails ? _this.style.active : ''), colSpan: _this.props.columns.length }, _react2.default.createElement( 'div', { className: (0, _classnames2.default)(_this.style.rowDetailsInner) }, _react2.default.createElement( _wixAnimations.Animator, { show: showDetails, height: true }, rowDetails(rowData, rowNum) ) ) ) )); } return rowsToRender; }; _this.renderCell = function (rowData, column, rowNum, colNum) { var _classNames2; var classes = (0, _classnames2.default)((_classNames2 = {}, _defineProperty(_classNames2, _this.style.important, column.important), _defineProperty(_classNames2, _this.style.largeVerticalPadding, _this.props.rowVerticalPadding === 'large'), _defineProperty(_classNames2, _this.style.mediumVerticalPadding, _this.props.rowVerticalPadding !== 'large'), _defineProperty(_classNames2, _this.style.alignStart, column.align === 'start'), _defineProperty(_classNames2, _this.style.alignCenter, column.align === 'center'), _defineProperty(_classNames2, _this.style.alignEnd, column.align === 'end'), _classNames2)); var width = rowNum === 0 && _this.props.hideHeader ? column.width : undefined; return _react2.default.createElement( 'td', { style: column.style, width: width, className: classes, key: colNum }, column.render && column.render(rowData, rowNum) ); }; _this.calcLastPage = function (_ref2) { var data = _ref2.data, itemsPerPage = _ref2.itemsPerPage; return Math.ceil(data.length / itemsPerPage) - 1; }; _this.loadMore = function () { if (_this.state.currentPage < _this.state.lastPage) { _this.setState({ currentPage: _this.state.currentPage + 1 }); } else { _this.props.loadMore && _this.props.loadMore(); } }; _this.toggleRowDetails = function (selectedRow) { var selectedRows = _defineProperty({}, selectedRow, !_this.state.selectedRows[selectedRow]); if (_this.props.allowMultiDetailsExpansion) { selectedRows = Object.assign({}, _this.state.selectedRows, _defineProperty({}, selectedRow, !_this.state.selectedRows[selectedRow])); } _this.setState({ selectedRows: selectedRows }); }; var state = { selectedRows: {} }; if (props.infiniteScroll) { state = _extends({}, state, _this.createInitialScrollingState(props)); } _this.state = state; return _this; } _createClass(DataTable, [{ key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { var isLoadingMore = false; if (this.props.infiniteScroll && nextProps.data !== this.props.data) { if (nextProps.data instanceof Array && this.props.data instanceof Array) { if (this.props.data.every(function (elem, index) { return nextProps.data.length > index && nextProps.data[index] === elem; })) { isLoadingMore = true; var lastPage = this.calcLastPage(nextProps); var currentPage = this.state.currentPage < lastPage ? this.state.currentPage + 1 : this.state.currentPage; this.setState({ lastPage: lastPage, currentPage: currentPage }); } } if (!isLoadingMore) { this.setState(this.createInitialScrollingState(nextProps)); } } } }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate() { // DataTable extends WixComponent which is a PureComponent, but DataTable is not pure. // returning true, disables the PureComponent optimization. return true; } }, { key: 'createInitialScrollingState', value: function createInitialScrollingState(props) { return { currentPage: 0, lastPage: this.calcLastPage(props) }; } }, { key: 'render', value: function render() { var _props = this.props, data = _props.data, showHeaderWhenEmpty = _props.showHeaderWhenEmpty, infiniteScroll = _props.infiniteScroll, itemsPerPage = _props.itemsPerPage; if (!data.length && !showHeaderWhenEmpty) { return null; } var rowsToRender = infiniteScroll ? data.slice(0, (this.state.currentPage + 1) * itemsPerPage) : data; var table = this.renderTable(rowsToRender); if (infiniteScroll) { return this.wrapWithInfiniteScroll(table); } return table; } }, { key: 'style', get: function get() { return _DataTable2.default; } }]); return DataTable; }(_react2.default.Component); var TableHeader = (_temp2 = _class2 = function (_Component) { _inherits(TableHeader, _Component); function TableHeader() { var _ref3; var _temp, _this2, _ret; _classCallCheck(this, TableHeader); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this2 = _possibleConstructorReturn(this, (_ref3 = TableHeader.__proto__ || Object.getPrototypeOf(TableHeader)).call.apply(_ref3, [this].concat(args))), _this2), _this2.renderSortingArrow = function (sortDescending, colNum) { if (sortDescending === undefined) { return null; } if (_this2.props.newDesign) { var Arrow = sortDescending ? _SortByArrowUp2.default : _SortByArrowDown2.default; return _react2.default.createElement( 'span', { 'data-hook': colNum + '_title', className: _this2.style.sortArrow }, _react2.default.createElement(Arrow, { height: 12, 'data-hook': sortDescending ? 'sort_arrow_dec' : 'sort_arrow_asc' }) ); } var sortDirectionClassName = sortDescending ? _this2.style.sortArrowAsc : _this2.style.sortArrowDesc; return _react2.default.createElement( 'span', { 'data-hook': colNum + '_title', className: sortDirectionClassName }, _react2.default.createElement(_SortByArrowUp2.default, null) ); }, _this2.renderInfoTooltip = function (tooltipProps, colNum) { if (tooltipProps === undefined) { return null; } if (_this2.props.newDesign) { return _react2.default.createElement(_InfoIcon2.default, { tooltipProps: tooltipProps, dataHook: colNum + '_info_tooltip', className: _this2.style.infoTooltipWrapper }); } else { var _tooltipProps = Object.assign({ theme: 'dark' }, tooltipProps, { dataHook: colNum + '_info_tooltip', moveBy: { x: 2.5, y: -7 } }); return _react2.default.createElement( _Tooltip2.default, _tooltipProps, _react2.default.createElement( 'span', { className: _this2.style.infoTooltipWrapper }, _react2.default.createElement(_InfoCircle2.default, { className: _this2.style.infoIcon, size: 24 }) ) ); } }, _this2.renderHeaderCell = function (column, colNum) { var _classNames4; var infoTooltipProps = column.infoTooltipProps; // Deprecate `infoTooltip` in favor of `infoTooltipProps` if (!infoTooltipProps && column.infoTooltip) { infoTooltipProps = column.infoTooltip; (0, _deprecationLog2.default)("Property `infoTooltip` of Table's `columns` prop is deprecated; use `infoTooltipProps` instead."); } var style = { width: column.width, padding: _this2.props.thPadding, height: _this2.props.thHeight, fontSize: _this2.props.thFontSize, border: _this2.props.thBorder, boxShadow: _this2.props.thBoxShadow, color: _this2.props.thColor, opacity: _this2.props.thOpacity, letterSpacing: _this2.props.thLetterSpacing, cursor: column.sortable === undefined ? 'arrow' : 'pointer' }; var thClasses = (0, _classnames2.default)(_defineProperty({}, _this2.style.thText, _this2.props.newDesign)); var optionalHeaderCellProps = {}; if (column.sortable) { optionalHeaderCellProps.onClick = function () { return _this2.props.onSortClick && _this2.props.onSortClick(column, colNum); }; } return _react2.default.createElement( 'th', _extends({ style: style, key: colNum, className: thClasses }, optionalHeaderCellProps), _react2.default.createElement( 'div', { className: (0, _classnames2.default)(_this2.style.thContainer, (_classNames4 = {}, _defineProperty(_classNames4, _this2.style.alignStart, !column.align || column.align === 'start'), _defineProperty(_classNames4, _this2.style.alignCenter, column.align === 'center'), _defineProperty(_classNames4, _this2.style.alignEnd, column.align === 'end'), _classNames4)) }, column.title, _this2.renderSortingArrow(column.sortDescending, colNum), _this2.renderInfoTooltip(infoTooltipProps, colNum) ) ); }, _temp), _possibleConstructorReturn(_this2, _ret); } _createClass(TableHeader, [{ key: 'render', value: function render() { return _react2.default.createElement( 'thead', null, _react2.default.createElement( 'tr', null, this.props.columns.map(this.renderHeaderCell) ) ); } }, { key: 'style', get: function get() { return _DataTable2.default; } }]); return TableHeader; }(_react.Component), _class2.propTypes = { onSortClick: _propTypes2.default.func, thPadding: _propTypes2.default.string, thHeight: _propTypes2.default.string, thFontSize: _propTypes2.default.string, thBorder: _propTypes2.default.string, thColor: _propTypes2.default.string, thOpacity: _propTypes2.default.string, thLetterSpacing: _propTypes2.default.string, thBoxShadow: _propTypes2.default.string, columns: _propTypes2.default.array, newDesign: _propTypes2.default.bool }, _temp2); function validateData(props, propName) { if (props[propName]) { if (props[propName].constructor && props[propName].constructor.name && props[propName].constructor.name.toLowerCase().indexOf('array') > -1) { return null; } else { return Error('Data element must be an array type'); } } return null; } DataTable.defaultProps = { data: [], columns: [], showHeaderWhenEmpty: false, infiniteScroll: false, itemsPerPage: 20, width: '100%', loadMore: null, hasMore: false, loader: _react2.default.createElement( 'div', { className: 'loader' }, 'Loading ...' ), scrollElement: null, useWindow: true, rowVerticalPadding: 'medium', showLastRowDivider: true }; /* eslint-disable no-unused-vars */ var _Tooltip$propTypes = _Tooltip2.default.propTypes, moveBy = _Tooltip$propTypes.moveBy, dataHook = _Tooltip$propTypes.dataHook, infoTooltipProps = _objectWithoutProperties(_Tooltip$propTypes, ['moveBy', 'dataHook']); DataTable.propTypes = { dataHook: _propTypes2.default.string, /** An id to pass to the table */ id: _propTypes2.default.string, /** The data to display. (If data.id exists then it will be used as the React key value for each row, otherwise, the rowIndex will be used) */ data: validateData, /** Configuration of the table's columns. See table below */ columns: _propTypes2.default.arrayOf(_propTypes2.default.shape({ title: _propTypes2.default.oneOfType([_propTypes2.default.node, _propTypes2.default.string]).isRequired, render: _propTypes2.default.func.isRequired, sortable: _propTypes2.default.bool, infoTooltipProps: _propTypes2.default.shape(infoTooltipProps), sortDescending: _propTypes2.default.bool, align: _propTypes2.default.oneOf(['start', 'center', 'end']) })).isRequired, /** Should the table show the header when data is empty */ showHeaderWhenEmpty: _propTypes2.default.bool, /** A string data-hook to apply to all table body rows. or a func which calculates the data-hook for each row - Signature: `(rowData, rowNum) => string` */ rowDataHook: _propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.string]), /** A class to apply to all table body rows */ rowClass: _propTypes2.default.string, /** A func that gets row data and returns a class(es) to apply to that specific row */ dynamicRowClass: _propTypes2.default.func, /** A callback method to be called on row click. Signature: `onRowClick(rowData, rowNum)` */ onRowClick: _propTypes2.default.func, /** A callback method to be called on row mouse enter. Signature: `onMouseEnterRow(rowData, rowNum)` */ onMouseEnterRow: _propTypes2.default.func, /** A callback method to be called on row mouse leave. Signature: `onMouseLeaveRow(rowData, rowNum)` */ onMouseLeaveRow: _propTypes2.default.func, /** If true, table will not render all data to begin with, but will gradually render the data as the user scrolls */ infiniteScroll: _propTypes2.default.bool, /** If infiniteScroll is on, this prop will determine how many rows will be rendered on each load */ itemsPerPage: _propTypes2.default.number, /** The width of the fixed table. Can be in percentages or pixels. */ width: _propTypes2.default.string, /** A callback when more items are requested by the user. */ loadMore: _propTypes2.default.func, /** Whether there are more items to be loaded. Event listeners are removed if false. */ hasMore: _propTypes2.default.bool, /** The loader to show when loading more items. */ loader: _propTypes2.default.node, /** Add scroll listeners to the window, or else, the component's parentNode. */ useWindow: _propTypes2.default.bool, /** Add scroll listeners to specified DOM Object. */ scrollElement: _propTypes2.default.object, /** Table cell vertical padding. should be 'medium' or 'large' */ rowVerticalPadding: _propTypes2.default.oneOf(['medium', 'large']), /** this prop is deprecated and should not be used * @deprecated */ thPadding: _propTypes2.default.string, /** this prop is deprecated and should not be used * @deprecated */ thHeight: _propTypes2.default.string, /** this prop is deprecated and should not be used * @deprecated */ thFontSize: _propTypes2.default.string, /** this prop is deprecated and should not be used * @deprecated */ thBorder: _propTypes2.default.string, /** this prop is deprecated and should not be used * @deprecated */ thColor: _propTypes2.default.string, /** this prop is deprecated and should not be used * @deprecated */ thOpacity: _propTypes2.default.string, /** this prop is deprecated and should not be used * @deprecated */ thBoxShadow: _propTypes2.default.string, /** this prop is deprecated and should not be used * @deprecated */ thLetterSpacing: _propTypes2.default.string, /** Function that returns React component that will be rendered in row details section. Example: `rowDetails={(row, rowNum) => <MyRowDetailsComponent {...row} />}` */ rowDetails: _propTypes2.default.func, /** Allows to open multiple row details */ allowMultiDetailsExpansion: _propTypes2.default.bool, /** Should we hide the header of the table. */ hideHeader: _propTypes2.default.bool, /** A flag specifying weather to show a divider after the last row */ showLastRowDivider: _propTypes2.default.bool, newDesign: _propTypes2.default.bool }; DataTable.displayName = 'DataTable'; exports.default = DataTable;