react-recycled-list
Version:
A React library for efficiently rendering large list with expensive component
1,217 lines (1,024 loc) • 46.5 kB
JavaScript
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = _interopDefault(require('react'));
var reactResizeDetector = require('react-resize-detector');
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function calculateRowPositions(rowHeights) {
var prev = 0;
var rowPositions = [];
var rowCount = rowHeights.length;
for (var i = 0; i < rowCount; i++) {
if (i === 0) rowPositions[i] = 0;else rowPositions[i] = prev;
prev += rowHeights[i];
}
return rowPositions;
}
function mapRowIndexToDataIndex(rowColumns, totalNumOfData) {
var rowCount = rowColumns.length;
var prevEndDataIndex = 0;
var map = {};
for (var i = 0; i < rowCount; i++) {
var newEndDataIndex = Math.min(prevEndDataIndex + rowColumns[i], totalNumOfData);
map[i] = [prevEndDataIndex, newEndDataIndex];
prevEndDataIndex = newEndDataIndex;
}
return map;
}
function validateScrollTo(result) {
if (result === -1 || result === undefined) {
throw Error('Invalid input to ScrollTo, make sure your input data index or row is correct');
}
}
function sortedLastIndex(array, target) {
var start = 0;
var end = array.length - 1;
while (start <= end) {
var mid = Math.floor((start + end) / 2);
if (array[mid] <= target) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return start;
}
function sortedFirstIndex(array, target) {
var start = 0;
var end = array.length - 1;
while (start <= end) {
var mid = Math.floor((start + end) / 2);
if (array[mid] < target) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return start;
}
var noRowRenderInfo = {
firstRenderedRowIndex: -1,
firstRenderedDataIndex: -1,
lastRenderedRowIndex: -1,
lastRenderedDataIndex: -1,
lastRowIndex: -1
};
var noRowVisibilityInfo = {
firstVisibleRowIndex: -1,
firstVisibleDataIndex: -1,
lastVisibleRowIndex: -1,
lastVisibleDataIndex: -1,
lastRowIndex: -1
};
var General = /*#__PURE__*/function (_React$PureComponent) {
_inheritsLoose(General, _React$PureComponent);
function General(props) {
var _this;
_this = _React$PureComponent.call(this, props) || this;
_this.onListWillRecycle = function (newRenderedRowIndex, newScrollState, newTopRenderedRowRelativeIndex) {
var _this$props = _this.props,
useScrollIndicator = _this$props.useScrollIndicator,
onRenderedRowChange = _this$props.onRenderedRowChange;
if (useScrollIndicator) {
_this.setState({
scrollState: newScrollState
});
_this._debounceScrollState();
}
if (onRenderedRowChange) {
if (_this.totalNumOfRenderedRows === 0) {
onRenderedRowChange(noRowRenderInfo);
return;
}
var lastRenderedRowIndex = newRenderedRowIndex[_this.mod(newTopRenderedRowRelativeIndex - 1)];
if (lastRenderedRowIndex === _this.prevLastRenderedRow) return;
var topRowIndex = newRenderedRowIndex[newTopRenderedRowRelativeIndex];
onRenderedRowChange({
firstRenderedRowIndex: topRowIndex,
firstRenderedDataIndex: _this.rowToDataIndexMap[topRowIndex][0],
lastRenderedRowIndex: lastRenderedRowIndex,
lastRenderedDataIndex: _this.rowToDataIndexMap[lastRenderedRowIndex][1] - 1,
lastRowIndex: _this.totalRows - 1
});
_this.prevLastRenderedRow = lastRenderedRowIndex;
}
};
_this.onScrollChange = function (scrollTop) {
var onVisibleRowChange = _this.props.onVisibleRowChange;
if (!onVisibleRowChange) return;
if (_this.totalNumOfRenderedRows === 0) {
onVisibleRowChange(noRowVisibilityInfo);
_this.prevLastVisibleRow = -1;
return;
}
var lastVisibleRowIndex = _this.getBottomViewportRowIndex(scrollTop + _this.windowHeight);
if (_this.fullHeight < _this.windowHeight) {
lastVisibleRowIndex = _this.getBottomViewportRowIndex(scrollTop + _this.fullHeight);
}
if (lastVisibleRowIndex === _this.prevLastVisibleRow) return;
var firstVisibleRowIndex = _this.getTopViewportRowIndex(scrollTop);
var firstVisibleDataIndex = _this.rowToDataIndexMap[firstVisibleRowIndex][0];
var lastVisibleDataIndex = _this.rowToDataIndexMap[lastVisibleRowIndex][1] - 1;
onVisibleRowChange({
firstVisibleRowIndex: firstVisibleRowIndex,
firstVisibleDataIndex: firstVisibleDataIndex,
lastVisibleRowIndex: lastVisibleRowIndex,
lastVisibleDataIndex: lastVisibleDataIndex,
lastRowIndex: _this.totalRows - 1
});
_this.prevLastVisibleRow = lastVisibleRowIndex;
};
_this.recycle = function (scrollTop) {
var _this$state = _this.state,
renderedRowIndex = _this$state.renderedRowIndex,
topRenderedRowRelativeIndex = _this$state.topRenderedRowRelativeIndex,
scrollState = _this$state.scrollState;
var topScroll = scrollTop - _this.prevScroll > 0 ? false : true;
_this.prevScroll = scrollTop;
_this.onScrollChange(scrollTop);
var rowsToRecycle = 0;
if (topScroll) {
var topRenderedRowIndex = renderedRowIndex[topRenderedRowRelativeIndex];
var newTopRenderedRowIndex = Math.max(_this.getTopViewportRowIndex(scrollTop) - _this.numOfInvisibleRowOnEachDirection, 0);
rowsToRecycle = topRenderedRowIndex - newTopRenderedRowIndex;
} else {
var bottomRenderedRowIndex = renderedRowIndex[_this.mod(topRenderedRowRelativeIndex - 1)];
var viewportBottom = scrollTop + _this.windowHeight;
var newBottomRenderedRowIndex = Math.min(_this.getBottomViewportRowIndex(viewportBottom) + _this.numOfInvisibleRowOnEachDirection, _this.totalRows - 1);
rowsToRecycle = newBottomRenderedRowIndex - bottomRenderedRowIndex;
}
if (rowsToRecycle > 0) {
var newRenderedRowIndex = [].concat(renderedRowIndex);
var newScrollState = [].concat(scrollState);
var cycle = 0;
while (cycle < rowsToRecycle) {
var _newTopRenderedRowRelativeIndex = _this.mod(topRenderedRowRelativeIndex + (topScroll ? -cycle - 1 : cycle));
newRenderedRowIndex[_newTopRenderedRowRelativeIndex] += topScroll ? -_this.totalNumOfRenderedRows : _this.totalNumOfRenderedRows;
newScrollState[_newTopRenderedRowRelativeIndex] = true;
cycle++;
}
var newTopRenderedRowRelativeIndex = _this.mod(topRenderedRowRelativeIndex + (topScroll ? -rowsToRecycle : rowsToRecycle));
_this.onListWillRecycle(newRenderedRowIndex, newScrollState, newTopRenderedRowRelativeIndex);
_this.setState({
renderedRowIndex: newRenderedRowIndex,
topRenderedRowRelativeIndex: newTopRenderedRowRelativeIndex
});
}
};
_this.resetList = function () {
var bottomRenderedRowIndex = _this.totalNumOfRenderedRows - 1;
var viewportBottom = _this.getResetViewportBottom();
var newBottomRenderedRowIndex = Math.min(_this.getBottomViewportRowIndex(viewportBottom) + _this.numOfInvisibleRowOnEachDirection, _this.totalRows - 1);
var rowsToRecycle = newBottomRenderedRowIndex - bottomRenderedRowIndex;
var newRenderedRowIndex = _this.initialArrayTemplate.map(function (_, index) {
return index;
});
var newScrollState = _this.initialArrayTemplate.map(function () {
return false;
});
var newTopRenderedRowRelativeIndex = 0;
if (rowsToRecycle > 0) {
var cycle = 0;
while (cycle < rowsToRecycle) {
var _newTopRenderedRowRelativeIndex2 = _this.mod(cycle);
newRenderedRowIndex[_newTopRenderedRowRelativeIndex2] += _this.totalNumOfRenderedRows;
newScrollState[_newTopRenderedRowRelativeIndex2] = true;
cycle++;
}
newTopRenderedRowRelativeIndex = _this.mod(rowsToRecycle);
}
_this.onListWillRecycle(newRenderedRowIndex, newScrollState, newTopRenderedRowRelativeIndex);
_this.onScrollChange(_this.prevScroll);
_this.setState({
renderedRowIndex: newRenderedRowIndex,
topRenderedRowRelativeIndex: newTopRenderedRowRelativeIndex
});
};
_this.onScroll = function (event) {
_this.recycle(event.currentTarget.scrollTop);
};
_this.scrollToDataIndex = function (targetIndex) {
if (targetIndex === -1) {
_this.manualScroll(targetIndex);
return;
}
var targetRow = Object.values(_this.rowToDataIndexMap).findIndex(function (value) {
return targetIndex >= value[0] && targetIndex < value[1];
});
validateScrollTo(targetRow);
var targetPosition = _this.rowPositions[targetRow];
_this.manualScroll(targetPosition);
};
_this.scrollToRow = function (targetRow) {
if (targetRow === -1) {
_this.manualScroll(targetRow);
return;
}
var targetPosition = _this.rowPositions[targetRow];
validateScrollTo(targetPosition);
_this.manualScroll(targetPosition);
};
_this.scrollTo = function (scrollTop) {
_this.manualScroll(scrollTop);
};
_this.manualScroll = function (targetPosition) {
if (_this.listWindowRef.current) {
if (targetPosition === -1) _this.listWindowRef.current.scrollTop = _this.fullHeight;else _this.listWindowRef.current.scrollTop = targetPosition;
}
};
_this.mod = function (n, m) {
if (m === void 0) {
m = _this.totalNumOfRenderedRows;
}
return (n % m + m) % m;
};
_this.getResetViewportBottom = function () {
return _this.prevScroll + _this.windowHeight;
};
_this._debounceScrollState = function () {
clearTimeout(_this.timeOut);
_this.timeOut = setTimeout(function () {
_this.setState({
scrollState: _this.initialArrayTemplate.map(function () {
return false;
})
});
}, _this.props.scrollInterval || 250);
};
_this.prevScroll = 0;
_this.prevLastVisibleRow = -1;
_this.prevLastRenderedRow = -1;
return _this;
}
var _proto = General.prototype;
_proto.componentDidMount = function componentDidMount() {
var initialScrollTop = this.props.initialScrollTop;
if (initialScrollTop) {
this.manualScroll(initialScrollTop);
}
};
_proto.componentWillUnmount = function componentWillUnmount() {
var onUnmount = this.props.onUnmount;
if (onUnmount) onUnmount(this.prevScroll);
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
if (this.shouldResetList(prevProps)) {
var _this$initializePrope = this.initializeProperties(),
rowToDataIndexMap = _this$initializePrope.rowToDataIndexMap,
rowPositions = _this$initializePrope.rowPositions,
totalRows = _this$initializePrope.totalRows,
initialArrayTemplate = _this$initializePrope.initialArrayTemplate,
fullHeight = _this$initializePrope.fullHeight,
totalNumOfRenderedRows = _this$initializePrope.totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection = _this$initializePrope.numOfInvisibleRowOnEachDirection,
windowHeight = _this$initializePrope.windowHeight,
rowHeights = _this$initializePrope.rowHeights;
this.rowToDataIndexMap = rowToDataIndexMap;
this.rowPositions = rowPositions;
this.totalRows = totalRows;
this.initialArrayTemplate = initialArrayTemplate;
this.fullHeight = fullHeight;
this.totalNumOfRenderedRows = totalNumOfRenderedRows;
this.numOfInvisibleRowOnEachDirection = numOfInvisibleRowOnEachDirection;
this.rowHeights = rowHeights;
this.windowHeight = windowHeight;
this.resetList();
}
};
_proto.render = function render() {
var _this2 = this;
var _this$props2 = this.props,
listTagName = _this$props2.listTagName,
_this$props2$listProp = _this$props2.listProps,
listProps = _this$props2$listProp === void 0 ? {} : _this$props2$listProp,
_this$props2$listWind = _this$props2.listWindowProps,
listWindowProps = _this$props2$listWind === void 0 ? {} : _this$props2$listWind,
listWindowTagName = _this$props2.listWindowTagName,
data = _this$props2.data,
width = _this$props2.width,
rowComponent = _this$props2.rowComponent;
var _this$state2 = this.state,
renderedRowIndex = _this$state2.renderedRowIndex,
scrollState = _this$state2.scrollState;
var ListTag = listTagName || 'div';
var WindowTag = listWindowTagName || 'div';
var RowComponent = rowComponent;
return React.createElement(WindowTag, Object.assign({}, listWindowProps, {
style: {
height: this.windowHeight,
overflowY: 'auto',
width: width || '100%'
},
onScroll: this.onScroll,
ref: this.listWindowRef
}), React.createElement(ListTag, Object.assign({}, listProps, {
style: {
height: this.fullHeight,
position: 'relative'
}
}), renderedRowIndex.map(function (absoluteRowIndex, index) {
var dataIndexInfo = _this2.rowToDataIndexMap[absoluteRowIndex];
var startDataIndex = dataIndexInfo[0];
var endDataIndex = dataIndexInfo[1];
return React.createElement(RowComponent, {
key: index,
data: data,
dataIndex: startDataIndex,
dataEndIndex: endDataIndex,
row: absoluteRowIndex,
column: endDataIndex - startDataIndex,
isScrolling: scrollState[index],
top: _this2.rowPositions[absoluteRowIndex],
height: _this2.rowHeights[absoluteRowIndex]
});
})));
};
return General;
}(React.PureComponent);
var FixedList = /*#__PURE__*/function (_GeneralList) {
_inheritsLoose(FixedList, _GeneralList);
function FixedList(props) {
var _this;
_this = _GeneralList.call(this, props) || this;
_this.initializeProperties = function () {
var _this$props = _this.props,
rowHeight = _this$props.rowHeight,
column = _this$props.column,
rowColumns = _this$props.rowColumns,
data = _this$props.data,
height = _this$props.height,
offScreenRow = _this$props.offScreenRow;
if (rowColumns) {
if (rowColumns.reduce(function (acc, current) {
return acc + current;
}, 0) !== data.length) {
throw Error('The total number of data item calculated from rowColumns does not match the length of your input data');
}
}
var calculatedRowColumns = rowColumns ? rowColumns : column ? Array(Math.ceil(data.length / column)).fill(column) : Array(data.length).fill(1);
var rowHeights = calculatedRowColumns.map(function () {
return rowHeight;
});
var rowToDataIndexMap = mapRowIndexToDataIndex(calculatedRowColumns, data.length);
var rowPositions = calculateRowPositions(rowHeights);
var totalRows = rowHeights.length;
var numOfVisibleRow = Math.ceil(height / rowHeight);
var numOfInvisibleRowOnEachDirection = offScreenRow || 1;
var totalNumOfRenderedRows = numOfVisibleRow + numOfInvisibleRowOnEachDirection * 2;
if (totalNumOfRenderedRows > totalRows) totalNumOfRenderedRows = totalRows;
var initialArrayTemplate = Array(totalNumOfRenderedRows).fill(null);
var fullHeight = rowHeights.reduce(function (acc, current) {
return acc + current;
}, 0);
var windowHeight = height;
return {
rowToDataIndexMap: rowToDataIndexMap,
rowPositions: rowPositions,
totalRows: totalRows,
initialArrayTemplate: initialArrayTemplate,
fullHeight: fullHeight,
totalNumOfRenderedRows: totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection: numOfInvisibleRowOnEachDirection,
rowHeights: rowHeights,
windowHeight: windowHeight
};
};
_this.shouldResetList = function (prevProps) {
var currentProp = _this.props;
if (prevProps === currentProp) return false;
var rowHeight = currentProp.rowHeight,
column = currentProp.column,
rowColumns = currentProp.rowColumns,
height = currentProp.height,
data = currentProp.data,
offScreenRow = currentProp.offScreenRow;
return prevProps.rowHeight !== rowHeight || prevProps.column !== column || prevProps.rowColumns !== rowColumns || prevProps.height !== height || prevProps.data !== data || prevProps.offScreenRow !== offScreenRow;
};
_this.getTopViewportRowIndex = function (scrollTop) {
return Math.floor(scrollTop / _this.props.rowHeight);
};
_this.getBottomViewportRowIndex = function (viewportBottom) {
var viewportBottomRow = viewportBottom / _this.props.rowHeight;
if (Number.isInteger(viewportBottomRow)) viewportBottomRow -= 1;else viewportBottomRow = Math.floor(viewportBottomRow);
return viewportBottomRow;
};
var _this$initializePrope = _this.initializeProperties(),
rowToDataIndexMap = _this$initializePrope.rowToDataIndexMap,
rowPositions = _this$initializePrope.rowPositions,
totalRows = _this$initializePrope.totalRows,
initialArrayTemplate = _this$initializePrope.initialArrayTemplate,
fullHeight = _this$initializePrope.fullHeight,
totalNumOfRenderedRows = _this$initializePrope.totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection = _this$initializePrope.numOfInvisibleRowOnEachDirection,
rowHeights = _this$initializePrope.rowHeights,
windowHeight = _this$initializePrope.windowHeight;
_this.rowToDataIndexMap = rowToDataIndexMap;
_this.rowPositions = rowPositions;
_this.totalRows = totalRows;
_this.initialArrayTemplate = initialArrayTemplate;
_this.fullHeight = fullHeight;
_this.totalNumOfRenderedRows = totalNumOfRenderedRows;
_this.numOfInvisibleRowOnEachDirection = numOfInvisibleRowOnEachDirection;
_this.rowHeights = rowHeights;
_this.windowHeight = windowHeight;
_this.listWindowRef = React.createRef();
var initialRenderedRowIndex = _this.initialArrayTemplate.map(function (_, index) {
return index;
});
var initialScrollState = _this.initialArrayTemplate.map(function () {
return false;
});
if (!props.initialScrollTop) {
_this.onListWillRecycle(initialRenderedRowIndex, initialScrollState, 0);
_this.onScrollChange(0);
}
_this.state = {
renderedRowIndex: initialRenderedRowIndex,
scrollState: initialScrollState,
topRenderedRowRelativeIndex: 0
};
return _this;
}
return FixedList;
}(General);
var VariableList = /*#__PURE__*/function (_GeneralList) {
_inheritsLoose(VariableList, _GeneralList);
function VariableList(props) {
var _this;
_this = _GeneralList.call(this, props) || this;
_this.initializeProperties = function () {
var _this$props = _this.props,
rowHeight = _this$props.rowHeight,
rowHeights = _this$props.rowHeights,
column = _this$props.column,
rowColumns = _this$props.rowColumns,
data = _this$props.data,
height = _this$props.height,
offScreenRow = _this$props.offScreenRow;
if (rowColumns) {
if (rowColumns.reduce(function (acc, current) {
return acc + current;
}, 0) !== data.length) {
throw Error('The total number of data item calculated from rowColumns does not match the length of your input data');
}
if (rowColumns.length !== rowHeights.length) {
throw Error('The number of rows provided from rowHeights does not match the number of rows provided from rowColumns');
}
} else if (column) {
var rows = Math.ceil(data.length / column);
if (rows !== rowHeights.length) {
throw Error('The number of rows provided from rowHeights does not match the number of rows calculated from column');
}
} else if (rowHeights.length !== data.length) {
throw Error('The number of rows provided from rowHeights does not match the number of rows calculated from your input data');
}
var calculatedRowColumns = rowColumns ? rowColumns : column ? Array(rowHeights.length).fill(column) : Array(rowHeights.length).fill(1);
var rowToDataIndexMap = mapRowIndexToDataIndex(calculatedRowColumns, data.length);
var rowPositions = calculateRowPositions(rowHeights);
var totalRows = rowHeights.length;
var numOfVisibleRow = Math.ceil(height / rowHeight);
var numOfInvisibleRowOnEachDirection = offScreenRow || 1;
var totalNumOfRenderedRows = numOfVisibleRow + numOfInvisibleRowOnEachDirection * 2;
if (totalNumOfRenderedRows > totalRows) totalNumOfRenderedRows = totalRows;
var initialArrayTemplate = Array(totalNumOfRenderedRows).fill(null);
var fullHeight = rowHeights.reduce(function (acc, current) {
return acc + current;
}, 0);
var windowHeight = height;
return {
rowToDataIndexMap: rowToDataIndexMap,
rowPositions: rowPositions,
totalRows: totalRows,
initialArrayTemplate: initialArrayTemplate,
fullHeight: fullHeight,
totalNumOfRenderedRows: totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection: numOfInvisibleRowOnEachDirection,
rowHeights: rowHeights,
windowHeight: windowHeight
};
};
_this.shouldResetList = function (prevProps) {
var currentProp = _this.props;
if (prevProps === currentProp) return false;
var rowHeight = currentProp.rowHeight,
rowHeights = currentProp.rowHeights,
column = currentProp.column,
rowColumns = currentProp.rowColumns,
height = currentProp.height,
data = currentProp.data,
offScreenRow = currentProp.offScreenRow;
return prevProps.rowHeight !== rowHeight || prevProps.rowHeights !== rowHeights || prevProps.column !== column || prevProps.rowColumns !== rowColumns || prevProps.height !== height || prevProps.data !== data || prevProps.offScreenRow !== offScreenRow;
};
_this.getTopViewportRowIndex = function (scrollTop) {
return sortedLastIndex(_this.rowPositions, scrollTop) - 1;
};
_this.getBottomViewportRowIndex = function (viewportBottom) {
return sortedFirstIndex(_this.rowPositions, viewportBottom) - 1;
};
var _this$initializePrope = _this.initializeProperties(),
rowToDataIndexMap = _this$initializePrope.rowToDataIndexMap,
rowPositions = _this$initializePrope.rowPositions,
totalRows = _this$initializePrope.totalRows,
initialArrayTemplate = _this$initializePrope.initialArrayTemplate,
fullHeight = _this$initializePrope.fullHeight,
totalNumOfRenderedRows = _this$initializePrope.totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection = _this$initializePrope.numOfInvisibleRowOnEachDirection,
rowHeights = _this$initializePrope.rowHeights,
windowHeight = _this$initializePrope.windowHeight;
_this.rowToDataIndexMap = rowToDataIndexMap;
_this.rowPositions = rowPositions;
_this.totalRows = totalRows;
_this.initialArrayTemplate = initialArrayTemplate;
_this.fullHeight = fullHeight;
_this.totalNumOfRenderedRows = totalNumOfRenderedRows;
_this.numOfInvisibleRowOnEachDirection = numOfInvisibleRowOnEachDirection;
_this.rowHeights = rowHeights;
_this.windowHeight = windowHeight;
_this.listWindowRef = React.createRef();
var initialRenderedRowIndex = _this.initialArrayTemplate.map(function (_, index) {
return index;
});
var initialScrollState = _this.initialArrayTemplate.map(function () {
return false;
});
_this.onListWillRecycle(initialRenderedRowIndex, initialScrollState, 0);
_this.onScrollChange(0);
_this.state = {
renderedRowIndex: initialRenderedRowIndex,
scrollState: initialScrollState,
topRenderedRowRelativeIndex: 0
};
return _this;
}
return VariableList;
}(General);
var FullWindowFixedList = /*#__PURE__*/function (_GeneralList) {
_inheritsLoose(FullWindowFixedList, _GeneralList);
function FullWindowFixedList(props) {
var _this;
_this = _GeneralList.call(this, props) || this;
_this.initializeProperties = function (constructor) {
if (constructor === void 0) {
constructor = false;
}
var _this$props = _this.props,
rowHeight = _this$props.rowHeight,
column = _this$props.column,
rowColumns = _this$props.rowColumns,
data = _this$props.data,
offScreenRow = _this$props.offScreenRow,
serverSideHeight = _this$props.serverSideHeight,
scrollRef = _this$props.scrollRef,
_this$props$rootMargi = _this$props.rootMarginTop,
rootMarginTop = _this$props$rootMargi === void 0 ? 0 : _this$props$rootMargi,
_this$props$rootMargi2 = _this$props.rootMarginBottom,
rootMarginBottom = _this$props$rootMargi2 === void 0 ? 0 : _this$props$rootMargi2;
if (rowColumns) {
if (rowColumns.reduce(function (acc, current) {
return acc + current;
}, 0) !== data.length) {
throw Error('The total number of data item calculated from rowColumns does not match the length of your input data');
}
}
var calculatedWindowHeight = 0;
var scrollListener;
if (constructor && serverSideHeight !== undefined) {
calculatedWindowHeight = serverSideHeight;
} else if ('scrollRef' in _this.props) {
if (scrollRef !== null && scrollRef !== void 0 && scrollRef.current) {
calculatedWindowHeight = parseInt(window.getComputedStyle(scrollRef.current).height);
scrollListener = scrollRef.current;
} else calculatedWindowHeight = 0;
} else {
calculatedWindowHeight = window.innerHeight;
scrollListener = window;
}
calculatedWindowHeight = Math.max(0, calculatedWindowHeight - rootMarginTop - rootMarginBottom);
var calculatedRowColumns = rowColumns ? rowColumns : column ? Array(Math.ceil(data.length / column)).fill(column) : Array(data.length).fill(1);
var rowHeights = calculatedRowColumns.map(function () {
return rowHeight;
});
var rowToDataIndexMap = mapRowIndexToDataIndex(calculatedRowColumns, data.length);
var rowPositions = calculateRowPositions(rowHeights);
var totalRows = rowHeights.length;
var numOfVisibleRow = Math.ceil(calculatedWindowHeight / rowHeight);
var numOfInvisibleRowOnEachDirection = offScreenRow || numOfVisibleRow ? 1 : 0;
var totalNumOfRenderedRows = numOfVisibleRow + numOfInvisibleRowOnEachDirection * 2;
if (totalNumOfRenderedRows > totalRows) totalNumOfRenderedRows = totalRows;
var initialArrayTemplate = Array(totalNumOfRenderedRows).fill(null);
var fullHeight = rowHeights.reduce(function (acc, current) {
return acc + current;
}, 0);
return {
rowToDataIndexMap: rowToDataIndexMap,
rowPositions: rowPositions,
totalRows: totalRows,
initialArrayTemplate: initialArrayTemplate,
fullHeight: fullHeight,
totalNumOfRenderedRows: totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection: numOfInvisibleRowOnEachDirection,
rowHeights: rowHeights,
windowHeight: calculatedWindowHeight,
scrollListener: scrollListener
};
};
_this.attachScrollListener = function () {
if (_this.scrollListener) {
_this.scrollListener.removeEventListener('scroll', _this.onScroll);
_this.scrollListener.addEventListener('scroll', _this.onScroll);
}
};
_this.getScrollTop = function () {
var _this$props$rootMargi3 = _this.props.rootMarginTop,
rootMarginTop = _this$props$rootMargi3 === void 0 ? 0 : _this$props$rootMargi3;
var recycledList = _this.fullListRef.current;
if (!recycledList) return window.scrollY;
var distanceBetweenScrollContainerAndWindow = _this.scrollListener === window ? 0 : _this.scrollListener.getBoundingClientRect().top;
return -(recycledList.getBoundingClientRect().top - distanceBetweenScrollContainerAndWindow - rootMarginTop);
};
_this.onScroll = function () {
if (_this.fullListRef) {
var scrollTop = _this.getScrollTop();
_this.recycle(scrollTop);
}
};
_this.manualScroll = function (targetPosition) {
var parsedTargetPosition = targetPosition;
if (targetPosition === -1) {
var _this$props2 = _this.props,
_this$props2$rootMarg = _this$props2.rootMarginBottom,
rootMarginBottom = _this$props2$rootMarg === void 0 ? 0 : _this$props2$rootMarg,
_this$props2$rootMarg2 = _this$props2.rootMarginTop,
_rootMarginTop = _this$props2$rootMarg2 === void 0 ? 0 : _this$props2$rootMarg2;
var fullWindowHeight = _this.windowHeight + _rootMarginTop + rootMarginBottom;
parsedTargetPosition = _this.fullHeight + rootMarginBottom + _rootMarginTop - fullWindowHeight;
}
var _this$props$rootMargi4 = _this.props.rootMarginTop,
rootMarginTop = _this$props$rootMargi4 === void 0 ? 0 : _this$props$rootMargi4;
if (_this.scrollListener) {
var recycledList = _this.fullListRef.current;
if (_this.scrollListener === window) {
var distanceToWindowTopFromTopOfList = recycledList.getBoundingClientRect().top + window.scrollY;
window.scrollTo({
top: distanceToWindowTopFromTopOfList + parsedTargetPosition - rootMarginTop
});
} else {
var customElement = _this.scrollListener;
var distanceToElementTopFromTopOfList = recycledList.getBoundingClientRect().top - customElement.getBoundingClientRect().top;
customElement.scrollTop = distanceToElementTopFromTopOfList + parsedTargetPosition - rootMarginTop;
}
}
};
_this.shouldResetList = function (prevProps) {
var _this$props3 = _this.props,
rowHeight = _this$props3.rowHeight,
column = _this$props3.column,
rowColumns = _this$props3.rowColumns,
windowHeight = _this$props3.windowHeight,
data = _this$props3.data,
offScreenRow = _this$props3.offScreenRow,
scrollRef = _this$props3.scrollRef,
rootMarginBottom = _this$props3.rootMarginBottom,
rootMarginTop = _this$props3.rootMarginTop;
return prevProps.data !== data || prevProps.windowHeight !== windowHeight || scrollRef && scrollRef.current !== _this.scrollListener || prevProps.rowHeight !== rowHeight || prevProps.column !== column || prevProps.rowColumns !== rowColumns || prevProps.offScreenRow !== offScreenRow || prevProps.rootMarginBottom !== rootMarginBottom || prevProps.rootMarginTop !== rootMarginTop;
};
_this.resetListAndRef = function () {
var _this$initializePrope = _this.initializeProperties(),
rowToDataIndexMap = _this$initializePrope.rowToDataIndexMap,
rowPositions = _this$initializePrope.rowPositions,
totalRows = _this$initializePrope.totalRows,
initialArrayTemplate = _this$initializePrope.initialArrayTemplate,
fullHeight = _this$initializePrope.fullHeight,
totalNumOfRenderedRows = _this$initializePrope.totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection = _this$initializePrope.numOfInvisibleRowOnEachDirection,
rowHeights = _this$initializePrope.rowHeights,
windowHeight = _this$initializePrope.windowHeight,
scrollListener = _this$initializePrope.scrollListener;
var scrollRef = _this.props.scrollRef;
_this.rowToDataIndexMap = rowToDataIndexMap;
_this.rowPositions = rowPositions;
_this.totalRows = totalRows;
_this.initialArrayTemplate = initialArrayTemplate;
_this.fullHeight = fullHeight;
_this.totalNumOfRenderedRows = totalNumOfRenderedRows;
_this.numOfInvisibleRowOnEachDirection = numOfInvisibleRowOnEachDirection;
_this.rowHeights = rowHeights;
_this.windowHeight = windowHeight;
if (scrollRef && scrollRef.current !== _this.scrollListener) {
_this.scrollListener = scrollListener;
_this.attachScrollListener();
}
_this.resetList();
};
_this.setCustomScrollRef = function () {
_this.resetListAndRef();
};
_this.getTopViewportRowIndex = function (scrollTop) {
return Math.max(Math.floor(scrollTop / _this.props.rowHeight), 0);
};
_this.getBottomViewportRowIndex = function (viewportBottom) {
var viewportBottomRow = viewportBottom / _this.props.rowHeight;
if (Number.isInteger(viewportBottomRow)) viewportBottomRow -= 1;else viewportBottomRow = Math.floor(viewportBottomRow);
return Math.min(viewportBottomRow, _this.totalRows - 1);
};
_this.getResetViewportBottom = function () {
var _this$props4 = _this.props,
_this$props4$rootMarg = _this$props4.rootMarginBottom,
rootMarginBottom = _this$props4$rootMarg === void 0 ? 0 : _this$props4$rootMarg,
_this$props4$rootMarg2 = _this$props4.rootMarginTop,
rootMarginTop = _this$props4$rootMarg2 === void 0 ? 0 : _this$props4$rootMarg2;
var scrollTop = _this.getScrollTop();
var fullWindowHeight = _this.windowHeight + rootMarginTop + rootMarginBottom;
return scrollTop + fullWindowHeight - rootMarginBottom;
};
var _this$initializePrope2 = _this.initializeProperties(true),
rowToDataIndexMap = _this$initializePrope2.rowToDataIndexMap,
rowPositions = _this$initializePrope2.rowPositions,
totalRows = _this$initializePrope2.totalRows,
initialArrayTemplate = _this$initializePrope2.initialArrayTemplate,
fullHeight = _this$initializePrope2.fullHeight,
totalNumOfRenderedRows = _this$initializePrope2.totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection = _this$initializePrope2.numOfInvisibleRowOnEachDirection,
rowHeights = _this$initializePrope2.rowHeights,
windowHeight = _this$initializePrope2.windowHeight,
scrollListener = _this$initializePrope2.scrollListener;
_this.fullListRef = React.createRef();
_this.listWindowRef = null;
_this.rowToDataIndexMap = rowToDataIndexMap;
_this.rowPositions = rowPositions;
_this.totalRows = totalRows;
_this.initialArrayTemplate = initialArrayTemplate;
_this.fullHeight = fullHeight;
_this.totalNumOfRenderedRows = totalNumOfRenderedRows;
_this.numOfInvisibleRowOnEachDirection = numOfInvisibleRowOnEachDirection;
_this.rowHeights = rowHeights;
_this.windowHeight = windowHeight;
_this.scrollListener = scrollListener;
_this.initialScrolling = false;
var initialRenderedRowIndex = _this.initialArrayTemplate.map(function (_, index) {
return index;
});
var initialScrollState = _this.initialArrayTemplate.map(function () {
return false;
});
if (!props.initialScrollTop && _this.scrollListener) {
_this.onListWillRecycle(initialRenderedRowIndex, initialScrollState, 0);
_this.onScrollChange(0);
}
_this.state = {
renderedRowIndex: initialRenderedRowIndex,
scrollState: initialScrollState,
topRenderedRowRelativeIndex: 0
};
return _this;
}
var _proto = FullWindowFixedList.prototype;
_proto.componentDidMount = function componentDidMount() {
this.attachScrollListener();
var initialScrollTop = this.props.initialScrollTop;
if (initialScrollTop) {
this.manualScroll(initialScrollTop);
}
};
_proto.componentWillUnmount = function componentWillUnmount() {
if (this.scrollListener) {
this.scrollListener.removeEventListener('scroll', this.onScroll);
}
var onUnmount = this.props.onUnmount;
if (onUnmount) onUnmount(this.prevScroll);
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
if (this.shouldResetList(prevProps)) {
this.resetListAndRef();
}
};
_proto.render = function render() {
var _this2 = this;
var _this$props5 = this.props,
listTagName = _this$props5.listTagName,
_this$props5$listProp = _this$props5.listProps,
listProps = _this$props5$listProp === void 0 ? {} : _this$props5$listProp,
data = _this$props5.data,
width = _this$props5.width,
rowComponent = _this$props5.rowComponent;
var _this$state = this.state,
renderedRowIndex = _this$state.renderedRowIndex,
scrollState = _this$state.scrollState;
console.log('render');
var ListTag = listTagName || 'div';
var RowComponent = rowComponent;
return React.createElement(ListTag, Object.assign({}, listProps, {
style: {
height: this.fullHeight,
position: 'relative',
width: width
},
ref: this.fullListRef
}), renderedRowIndex.map(function (absoluteRowIndex, index) {
var dataIndexInfo = _this2.rowToDataIndexMap[absoluteRowIndex];
var startDataIndex = dataIndexInfo[0];
var endDataIndex = dataIndexInfo[1];
return React.createElement(RowComponent, {
key: index,
data: data,
dataIndex: startDataIndex,
dataEndIndex: endDataIndex,
row: absoluteRowIndex,
column: endDataIndex - startDataIndex,
isScrolling: scrollState[index],
top: _this2.rowPositions[absoluteRowIndex],
height: _this2.rowHeights[absoluteRowIndex]
});
}));
};
return FullWindowFixedList;
}(General);
var FullWindowVariableList = /*#__PURE__*/function (_FullWindowFixedList) {
_inheritsLoose(FullWindowVariableList, _FullWindowFixedList);
function FullWindowVariableList(props) {
var _this;
_this = _FullWindowFixedList.call(this, props) || this;
_this.initializeProperties = function (constructor) {
if (constructor === void 0) {
constructor = false;
}
var _this$props = _this.props,
rowHeight = _this$props.rowHeight,
rowHeights = _this$props.rowHeights,
column = _this$props.column,
rowColumns = _this$props.rowColumns,
data = _this$props.data,
offScreenRow = _this$props.offScreenRow,
serverSideHeight = _this$props.serverSideHeight,
scrollRef = _this$props.scrollRef,
_this$props$rootMargi = _this$props.rootMarginTop,
rootMarginTop = _this$props$rootMargi === void 0 ? 0 : _this$props$rootMargi,
_this$props$rootMargi2 = _this$props.rootMarginBottom,
rootMarginBottom = _this$props$rootMargi2 === void 0 ? 0 : _this$props$rootMargi2;
if (rowColumns) {
if (rowColumns.reduce(function (acc, current) {
return acc + current;
}, 0) !== data.length) {
throw Error('The total number of data item calculated from rowColumns does not match the length of your input data');
}
if (rowColumns.length !== rowHeights.length) {
throw Error('The number of rows provided from rowHeights does not match the number of rows provided from rowColumns');
}
} else if (column) {
var rows = Math.ceil(data.length / column);
if (rows !== rowHeights.length) {
throw Error('The number of rows provided from rowHeights does not match the number of rows calculated from column');
}
} else if (rowHeights.length !== data.length) {
throw Error('The number of rows provided from rowHeights does not match the number of rows calculated from your input data');
}
var calculatedWindowHeight = 0;
var scrollListener;
if (constructor && serverSideHeight !== undefined) {
calculatedWindowHeight = serverSideHeight;
} else if ('scrollRef' in _this.props) {
if (scrollRef !== null && scrollRef !== void 0 && scrollRef.current) {
calculatedWindowHeight = parseInt(window.getComputedStyle(scrollRef.current).height);
scrollListener = scrollRef;
} else calculatedWindowHeight = 0;
} else {
calculatedWindowHeight = window.innerHeight;
scrollListener = window;
}
calculatedWindowHeight = Math.max(0, calculatedWindowHeight - rootMarginTop - rootMarginBottom);
var calculatedRowColumns = rowColumns ? rowColumns : column ? Array(rowHeights.length).fill(column) : Array(rowHeights.length).fill(1);
var rowToDataIndexMap = mapRowIndexToDataIndex(calculatedRowColumns, data.length);
var rowPositions = calculateRowPositions(rowHeights);
var totalRows = rowHeights.length;
var numOfVisibleRow = Math.ceil(calculatedWindowHeight / rowHeight);
var numOfInvisibleRowOnEachDirection = offScreenRow || numOfVisibleRow ? 1 : 0;
var totalNumOfRenderedRows = numOfVisibleRow + numOfInvisibleRowOnEachDirection * 2;
if (totalNumOfRenderedRows > totalRows) totalNumOfRenderedRows = totalRows;
var initialArrayTemplate = Array(totalNumOfRenderedRows).fill(null);
var fullHeight = rowHeights.reduce(function (acc, current) {
return acc + current;
}, 0);
return {
rowToDataIndexMap: rowToDataIndexMap,
rowPositions: rowPositions,
totalRows: totalRows,
initialArrayTemplate: initialArrayTemplate,
fullHeight: fullHeight,
totalNumOfRenderedRows: totalNumOfRenderedRows,
numOfInvisibleRowOnEachDirection: numOfInvisibleRowOnEachDirection,
rowHeights: rowHeights,
windowHeight: calculatedWindowHeight,
scrollListener: scrollListener
};
};
_this.getTopViewportRowIndex = function (scrollTop) {
return sortedLastIndex(_this.rowPositions, scrollTop) - 1;
};
_this.getBottomViewportRowIndex = function (viewportBottom) {
return sortedFirstIndex(_this.rowPositions, viewportBottom) - 1;
};
_this.shouldResetList = function (prevProps) {
var _this$props2 = _this.props,
rowHeight = _this$props2.rowHeight,
rowHeights = _this$props2.rowHeights,
column = _this$props2.column,
rowColumns = _this$props2.rowColumns,
windowHeight = _this$props2.windowHeight,
data = _this$props2.data,
offScreenRow = _this$props2.offScreenRow,
scrollRef = _this$props2.scrollRef,
rootMarginBottom = _this$props2.rootMarginBottom,
rootMarginTop = _this$props2.rootMarginTop;
return prevProps.data !== data || prevProps.windowHeight !== windowHeight || scrollRef && scrollRef.current !== _this.scrollListener || prevProps.rowHeight !== rowHeight || prevProps.rowHeights !== rowHeights || prevProps.column !== column || prevProps.rowColumns !== rowColumns || prevProps.offScreenRow !== offScreenRow || prevProps.rootMarginBottom !== rootMarginBottom || prevProps.rootMarginTop !== rootMarginTop;
};
return _this;
}
return FullWindowVariableList;
}(FullWindowFixedList);
function ResponsiveContainer(props) {
var render = props.render,
debounceResize = props.debounceResize,
debounceInterval = props.debounceInterval,
serverSideHeight = props.serverSideHeight;
var _useResizeDetector = reactResizeDetector.useResizeDetector({
refreshMode: debounceResize ? 'debounce' : undefined,
refreshRate: debounceInterval ? debounceInterval : 100
}),
width = _useResizeDetector.width,
height = _useResizeDetector.height,
ref = _useResizeDetector.ref;
var _React$useState = React.useState(false),
hasMounted = _React$useState[0],
setHasMounted = _React$useState[1];
React.useLayoutEffect(function () {
if (serverSideHeight !== undefined) {
setHasMounted(true);
}
}, []);
return React.createElement("div", {
ref: ref,
style: {
height: '100%',
width: '100%'
}
}, render({
width: width || 0,
height: height || !hasMounted && serverSideHeight || 0
}));
}
function ResponsiveWindowContainer(props) {
var render = props.render,
debounceResize = props.debounceResize,
debounceInterval = props.debounceInterval,
serverSideHeight = props.serverSideHeight,
scrollRef = props.scrollRef;
var targetRef = React.useRef();
var _useResizeDetector = reactResizeDetector.useResizeDetector({
refreshMode: debounceResize ? 'debounce' : undefined,
refreshRate: debounceInterval ? debounceInterval : 100,
targetRef: 'scrollRef' in props ? scrollRef : targetRef
}),
width = _useResizeDetector.width,
height = _useResizeDetector.height;
var _React$useState = React.useState(false),
hasMounted = _React$useState[0],
setHasMounted = _React$useState[1];
var _React$useState2 = React.useState(true),
reRender = _React$useState2[0],
forceRerender = _React$useState2[1];
React.useLayoutEffect(function () {
if (serverSideHeight !== undefined) {
setHasMounted(!hasMounted);
}
}, []);
React.useLayoutEffect(function () {
forceRerender(!reRender);
}, [scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current, scrollRef]);
return React.createElement(React.Fragment, null, render({
width: width || 0,
height: height || !hasMounted && serverSideHeight || 0
}), React.createElement("div", {
ref: targetRef,
style: {
position: 'fixed',
height: '100vh',
width: '100vw'
}
}));
}
exports.FixedList = FixedList;
exports.FullWindowFixedList = FullWindowFixedList;
exports.FullWindowVariableList = FullWindowVariableList;
exports.ResponsiveContainer = ResponsiveContainer;
exports.ResponsiveWindowContainer = ResponsiveWindowContainer;
exports.VariableList = VariableList;
//# sourceMappingURL=index.js.map