UNPKG

ffr-components

Version:

Fiori styled UI components

551 lines (460 loc) 19.2 kB
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;