ffr-components
Version:
Fiori styled UI components
551 lines (460 loc) • 19.2 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import classnames from 'classnames';
import React from 'react';
import TableContext from './TableContext';
import HeaderTable from './HeaderTable';
import BodyTable from './BodyTable';
import { TableProvider } from './TableContext';
import { throttle, KeyCode } from '../utils';
import { REF_TYPE } from './constant';
import Loading from '../loading';
import "./style.css";
/**
*
* withFixedHeader: bool, fixed header when scroll
* childName : attribute namre of children collection
* selectionColumn : {
* onSelect : (record, selected, selectedRows) => {}
* onSelectAll : (selected, selectedRows, changeRows)=>{}
* }
* columns : {
* fixed: string, 'left' or 'right'
* width: width of cloumn,
* key: key for react, if "attribute" is unique string, could skip this arrtibute
* attribute: is the acctribute name of data
* title: title of the column displayed in header
* sorter: boolean || {
* sortFunction: ( value1, value2, sortKey ) => {}
* sortDirections:[{key: 'ascend', text:'Ascend' , sapIcon :''}, {key:'descend', text: 'Descend'}]
* }
* filterable: bool
*
*
* }
*
*/
import "../theme/theme.css";
var Table =
/*#__PURE__*/
function (_React$Component) {
_inherits(Table, _React$Component);
function Table(props) {
var _this;
_classCallCheck(this, Table);
_this = _possibleConstructorReturn(this, _getPrototypeOf(Table).call(this, props));
_this.renderFixTable = function () {
var leftColumns = _this.tableContext.getLeftFixedColumns();
var rightColumns = _this.tableContext.getRightFixedColumns();
return React.createElement(React.Fragment, null, leftColumns.length > 0 && _this.renderRealTable({
fixed: 'left',
columns: leftColumns,
lastLine: _this.tableContext.getLeftLastLine()
}), rightColumns.length > 0 && _this.renderRealTable({
fixed: 'right',
columns: rightColumns,
lastLine: _this.tableContext.getRightLastLine()
}));
};
_this.updateEmptyText = function () {
if (_this.state.isEmpty) {
_this.forceUpdate();
}
};
_this.emptyDataHook = function (attr, data) {
var isEmpty = _this.state.isEmpty;
if (data.length === 0 && !isEmpty) {
_this.setState({
isEmpty: true
});
} else if (data.length > 0 && isEmpty) {
_this.setState({
isEmpty: false
});
}
};
_this.renderEmptyText = function () {
var emptyText = _this.props.emptyText;
var isEmpty = _this.state.isEmpty;
var top = _this.tableContext.getHeaderHeight();
return isEmpty ? React.createElement("div", {
className: "ffr-table-empty",
style: {
top: top
}
}, React.createElement("span", null, emptyText)) : null;
};
_this.renderLoading = function () {
var loading = _this.props.loading;
var top = _this.tableContext.getHeaderHeight();
return loading ? React.createElement(Loading, {
className: "ffr-table-empty",
style: {
top: top
}
}) : null;
};
_this.getNextFocusElementRef = function (dataIndex, keyCode) {
if (!dataIndex) {
console.error('failed to find attribtue data-index');
return null;
}
var _dataIndex$split = dataIndex.split('-'),
_dataIndex$split2 = _slicedToArray(_dataIndex$split, 4),
type = _dataIndex$split2[0],
fixed = _dataIndex$split2[1],
rowIndex = _dataIndex$split2[2],
colIndex = _dataIndex$split2[3];
var nextRefName = undefined;
var nextRef = null;
if ([KeyCode.RIGHT, KeyCode.LEFT].indexOf(keyCode) >= 0) {
if (keyCode === KeyCode.RIGHT) {
nextRefName = fixed === 'left' ? 'center' : !fixed || fixed === 'center' ? 'right' : undefined;
} else if (keyCode === KeyCode.LEFT) {
nextRefName = fixed === 'right' ? 'center' : !fixed || fixed === 'center' ? 'left' : undefined;
}
nextRef = !nextRefName ? null : type === REF_TYPE.body ? _this["".concat(nextRefName, "BodyRef")] : _this["".concat(nextRefName, "HeaderRef")];
if (nextRef && nextRef.current) {
var rowNode = nextRef.current.childNodes[rowIndex];
if (rowNode) {
return rowNode.childNodes[keyCode === KeyCode.RIGHT ? 0 : rowNode.childNodes.length - 1];
}
}
} else if ([KeyCode.UP, KeyCode.DOWN].indexOf(keyCode) >= 0) {
if (keyCode === KeyCode.UP) {
nextRefName = type === REF_TYPE.body ? 'Header' : undefined;
} else if (keyCode === KeyCode.DOWN) {
nextRefName = type === REF_TYPE.header ? 'Body' : undefined;
}
nextRef = !nextRefName ? null : _this["".concat(!fixed || fixed === 'center' ? 'center' : fixed).concat(nextRefName, "Ref")];
if (nextRef && nextRef.current) {
var _rowNode = nextRef.current.childNodes[keyCode === KeyCode.DOWN ? 0 : nextRef.current.childNodes.length - 1];
if (_rowNode) {
return _rowNode.childNodes[colIndex];
}
}
}
return null;
};
_this.handleMoveFocus = function (e) {
var target = e.target,
keyCode = e.keyCode;
if ([KeyCode.RIGHT, KeyCode.LEFT, KeyCode.UP, KeyCode.DOWN].indexOf(keyCode) < 0) return;
var indexAttr = target.getAttribute('data-index');
if (!indexAttr) return;
var next = null;
var reserveTabIndex = false;
if ([KeyCode.RIGHT, KeyCode.LEFT].indexOf(keyCode) >= 0) {
next = keyCode === KeyCode.RIGHT ? target.nextElementSibling : target.previousElementSibling;
next = next || _this.getNextFocusElementRef(indexAttr, keyCode);
if (next) {
var lastFocus = indexAttr.indexOf(REF_TYPE.body) === 0 ? _this.tableContext.getHeaderFocusIndex() : _this.tableContext.getBodyFocusIndex();
if (lastFocus) {
var _lastFocus$split = lastFocus.split('-'),
_lastFocus$split2 = _slicedToArray(_lastFocus$split, 4),
type = _lastFocus$split2[0],
fixed = _lastFocus$split2[1],
rowIndex = _lastFocus$split2[2],
colIndex = _lastFocus$split2[3];
var _next$getAttribute$sp = next.getAttribute('data-index').split('-'),
_next$getAttribute$sp2 = _slicedToArray(_next$getAttribute$sp, 4),
currentFixed = _next$getAttribute$sp2[1],
currentColIndex = _next$getAttribute$sp2[3];
var ref = _this["".concat(fixed).concat(type === REF_TYPE.body ? 'Body' : 'Header', "Ref")];
var currentRef = _this["".concat(currentFixed).concat(type === REF_TYPE.body ? 'Body' : 'Header', "Ref")];
var lastRow = ref.current.childNodes[rowIndex];
if (lastRow) {
lastRow.childNodes[colIndex].tabIndex = '-1';
}
var currentRow = currentRef.current.childNodes[rowIndex];
if (currentRow) {
var currentEle = currentRow.childNodes[currentColIndex];
currentEle.tabIndex = '0';
type === REF_TYPE.body ? _this.tableContext.updateBodyFocusIndex(currentEle.getAttribute('data-index')) : _this.tableContext.updateHeaderFocusIndex(currentEle.getAttribute('data-index'));
}
}
}
} else if ([KeyCode.UP, KeyCode.DOWN].indexOf(keyCode) >= 0) {
var rowEle = target.parentNode;
var getNextVisible = function getNextVisible(ele) {
var nextEle = ele.nextElementSibling;
return nextEle ? nextEle.style.display !== 'none' ? nextEle : getNextVisible(nextEle) : null;
};
var getPrevioueEle = function getPrevioueEle(ele) {
var preEle = ele.previousElementSibling;
return preEle ? preEle.style.display !== 'none' ? preEle : getPrevioueEle(preEle) : null;
};
var _indexAttr$split = indexAttr.split('-'),
_indexAttr$split2 = _slicedToArray(_indexAttr$split, 4),
_colIndex = _indexAttr$split2[3];
next = keyCode === KeyCode.DOWN ? getNextVisible(rowEle) : getPrevioueEle(rowEle);
if (next) {
next = next.childNodes[_colIndex];
} else {
e.preventDefault();
reserveTabIndex = true;
next = _this.getNextFocusElementRef(indexAttr, keyCode);
}
}
if (next) {
if (!reserveTabIndex) {
target.tabIndex = '-1';
}
if (indexAttr.indexOf(REF_TYPE.body) === 0) {
_this.tableContext.updateBodyFocusIndex(indexAttr);
} else {
_this.tableContext.updateHeaderFocusIndex(indexAttr);
}
next.tabIndex = 0;
next.focus();
}
};
_this.handleScrollTop = function (e) {
var target = e.target;
if (e.currentTarget !== target) {
return;
}
var scrollTop = target.scrollTop;
if (_this.lastScrollTop === scrollTop) return;
[_this.leftTableRef, _this.centerTableRef, _this.rightTableRef].filter(function (ref) {
return ref.current !== target && ref.current;
}).forEach(function (ref) {
ref.current.scrollTop = scrollTop;
});
_this.lastScrollTop = scrollTop;
};
_this.handleScrollLeft = function (e) {
var target = e.target;
if (e.currentTarget !== target || target !== _this.centerTableRef.current) {
return;
}
var scrollLeft = target.scrollLeft,
scrollTop = target.scrollTop;
/**
* scroll top will set scroll left to 0, this make table header blink when scrool vertically if
* sroll left is not 0. so check scroll top first , if not same, means this is
* vertical scroll, just return
* */
if (_this.lastScrollLeft === scrollLeft || scrollTop !== _this.lastScrollTop) return;
if (_this.scrollableHeaderRef.current) {
_this.scrollableHeaderRef.current.scrollLeft = scrollLeft;
_this.lastScrollLeft = scrollLeft;
}
};
_this.handleScroll = function (e) {
_this.handleScrollLeft(e);
_this.handleScrollTop(e);
};
_this.handleWindowResize = function (e) {
var currentCenter = _this.centerTableRef.current;
var currentOuter = _this.outerTableRef.current;
if (currentCenter) {
_this.tableContext.updateShouldAlignHorizentalScrollbar(currentCenter.scrollWidth > currentCenter.clientWidth);
_this.tableContext.updateShouldAlignVerticalScrollbar(currentCenter.scrollHeight > currentCenter.clientHeight);
}
if (currentOuter) {
var clientHeight = currentOuter.clientHeight;
if (Math.abs(clientHeight - _this.lastOuterTableHeight) > 10) {
_this.lastOuterTableHeight = clientHeight;
_this.tableContext.updateOuterTableHeight(clientHeight);
}
}
};
_this.renderScrollTable = function () {
var scrollable = false;
var table = _this.renderRealTable();
return scrollable ? React.createElement("div", {
className: "ffr-table-scroll"
}, table) : table;
};
_this.renderToolBar = function () {
return React.createElement("div", {
className: "ffr-table-toolbar"
});
};
_this.__getExpandTableClass = function (fixed) {
var childName = _this.props.childName;
var klass = '';
if (childName) {
if (fixed === 'left' && _this.tableContext.hasLeftFixedContentTable()) {
klass = 'ffr-expandable-table ffr-expandable-fix-width';
} else if (!_this.tableContext.hasLeftFixedTable() && fixed === undefined) {
klass = 'ffr-expandable-table';
}
return klass;
}
return klass;
};
_this.renderRealTable = function () {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _this$props = _this.props,
withFixedHeader = _this$props.withFixedHeader,
childName = _this$props.childName,
defaultExpandAll = _this$props.defaultExpandAll,
expandedDataKeys = _this$props.expandedDataKeys,
data = _this$props.data;
var columns = options.columns,
fixed = options.fixed,
lastLine = options.lastLine;
columns = columns || _this.tableContext.getCenterColumns();
lastLine = lastLine || _this.tableContext.getCenterLastLine();
var tableClass = fixed !== undefined ? "ffr-table-fixed ffr-table-fixed-".concat(fixed) : '';
var classnames = _this.__getExpandTableClass(fixed);
var innerProps = {};
if (!fixed) {
innerProps.innerRef = _this.scrollableHeaderRef;
}
return React.createElement("div", {
className: "ffr-real-table ".concat(tableClass)
}, withFixedHeader && React.createElement(HeaderTable, _extends({
columns: columns,
fixed: fixed
}, innerProps, {
innerHeaderRef: fixed === undefined ? _this.centerHeaderRef : _this["".concat(fixed, "HeaderRef")],
handleMoveFocus: _this.handleMoveFocus,
className: classnames,
lastLine: lastLine
})), React.createElement(BodyTable, {
columns: columns,
withFixedHeader: withFixedHeader,
fixed: fixed,
innerRef: fixed === undefined ? _this.centerTableRef : _this["".concat(fixed, "TableRef")],
innerHeaderRef: fixed === undefined ? _this.centerHeaderRef : _this["".concat(fixed, "HeaderRef")],
innerBodyRef: fixed === undefined ? _this.centerBodyRef : _this["".concat(fixed, "BodyRef")],
handleScroll: _this.handleScroll,
childName: childName,
defaultExpandAll: defaultExpandAll,
className: classnames,
lastLine: lastLine,
handleMoveFocus: _this.handleMoveFocus,
expandedDataKeys: expandedDataKeys
}), !withFixedHeader && data.length > 0 && _this.renderLoading());
};
_this.assignOutterTableRef = function (ref) {
_this.outerTableRef.current = ref;
var innerRef = _this.props.innerRef;
if (!innerRef) return;
if (typeof innerRef === 'function') {
innerRef(ref);
} else {
innerRef.current = ref;
}
};
var _data = props.data,
sorter = props.sorter,
datakey = props.datakey;
_this.outerTableRef = React.createRef();
_this.tableContext = new TableContext(props);
_this.leftTableRef = React.createRef();
_this.rightTableRef = React.createRef();
_this.centerTableRef = React.createRef();
_this.leftHeaderRef = React.createRef();
_this.rightHeaderRef = React.createRef();
_this.centerHeaderRef = React.createRef();
_this.leftBodyRef = React.createRef();
_this.rightBodyRef = React.createRef();
_this.centerBodyRef = React.createRef();
_this.scrollableHeaderRef = React.createRef();
_this.lastScrollTop = 0;
_this.lastScrollLeft = 0;
_this.lastOuterTableHeight = -1;
_this.state = {
isEmpty: _data.length === 0
};
_this.tableContext.subscribe('data', _this.emptyDataHook);
_this.tableContext.subscribe('headerHeight', _this.updateEmptyText);
if (sorter && datakey === undefined) {
throw new Error('sorted table must supply dataKey used to identify each row');
}
return _this;
}
_createClass(Table, [{
key: "componentDidMount",
value: function componentDidMount() {
var withFixedHeader = this.props.withFixedHeader;
if (withFixedHeader) {
var clientHeight = this.outerTableRef.current.clientHeight;
this.tableContext.updateOuterTableHeight(clientHeight);
this.throttleResizeHandler = throttle(this.handleWindowResize, 200);
window.addEventListener('resize', this.throttleResizeHandler);
} // caculate minwidth to avoid two fixed table overlap
if (this.tableContext.hasLeftFixedTable() && this.tableContext.hasRightFixedTable()) {
var leftRef = this.leftTableRef.current;
var rightRef = this.rightTableRef.current;
var outRef = this.outerTableRef.current;
var minWidth = Math.max(leftRef.clientWidth, leftRef.offsetWidth) + Math.max(rightRef.clientWidth, rightRef.offsetWidth) + 16;
outRef.style.minWidth = "".concat(minWidth, "px");
}
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(preProps) {
var lastData = preProps.data;
var data = this.props.data;
if (data !== lastData) {
this.tableContext.updateData(data);
this.tableContext.updatOriginData(data);
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
if (this.throttleResizeHandler) {
window.removeEventListener('resize', this.throttleResizeHandler);
}
this.tableContext.unsubscribe('data', this.emptyDataHook);
this.tableContext.unsubscribe('headerHeight', this.updateEmptyText);
}
}, {
key: "render",
value: function render() {
var _this$props2 = this.props,
style = _this$props2.style,
id = _this$props2.id,
className = _this$props2.className,
compact = _this$props2.compact,
withBorder = _this$props2.withBorder,
withFixedHeader = _this$props2.withFixedHeader,
_this$props2$data = _this$props2.data,
data = _this$props2$data === void 0 ? [] : _this$props2$data;
var tableClasses = classnames('ffr-table-wrapper', {
'ffr-table-bordered': withBorder
}, className);
var contentClass = classnames('ffr-table-content', {
'ffr-table-compact': compact
});
return React.createElement(TableProvider, {
value: {
tableContext: this.tableContext
}
}, React.createElement("div", {
ref: this.assignOutterTableRef,
className: tableClasses,
style: style,
id: id
}, this.renderToolBar(), React.createElement("div", {
className: contentClass
}, this.renderFixTable(), this.renderScrollTable(), this.renderEmptyText(), (withFixedHeader || data.length === 0) && this.renderLoading())));
}
}]);
return Table;
}(React.Component);
Table.defaultProps = {
columns: [],
data: [],
showHeader: true,
withFixedHeader: false,
emptyText: '',
loading: false,
withBorder: false,
defaultExpandAll: false,
compact: false,
headerAlignment: 'left'
};
Table.displayName = 'Table';
export default Table;