wix-style-react
Version:
wix-style-react
631 lines (533 loc) • 24.3 kB
JavaScript
'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;