@findify/react-components
Version:
Findify react UI components
143 lines (122 loc) • 4.36 kB
JavaScript
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { List, Map } from 'immutable';
import { useItems } from '@findify/react-connect';
import { emit } from "./emmiter";
var hasRange = function hasRange(ranges, offset) {
return !!ranges.find(function (r) {
return r.get('from') === offset;
});
};
var createRange = function createRange(meta) {
return Map({
from: meta.get('offset'),
to: meta.get('offset') + meta.get('limit')
});
};
var updateItems = function updateItems(_ref, nextItems, meta) {
var ranges = _ref.ranges,
items = _ref.items;
var append = ranges.find(function (r) {
return r.get('from') < meta.get('offset');
});
var newRange = createRange(meta);
var _items = nextItems.filter(function (i) {
return !items.includes(i);
});
return {
ranges: append ? ranges.push(newRange) : ranges.insert(0, newRange),
items: append ? items.concat(_items) : _items.concat(items),
meta: meta
};
};
var initialState = {
items: List(),
ranges: List(),
meta: Map()
};
export default (function () {
var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 300;
var _useItems = useItems(),
items = _useItems.items,
meta = _useItems.meta,
update = _useItems.update,
config = _useItems.config;
var container = useRef(null);
var pending = useRef(true);
var state = useRef(initialState);
var autoLoad = useRef(config.getIn(['pagination', 'autoLoadTimes']) || 0);
var onLoadNext = useCallback(function (e) {
e.preventDefault();
pending.current = true;
return update('offset', state.current.ranges.last().get('to'));
}, [meta]);
var onLoadPrev = useCallback(function (e) {
e.preventDefault();
pending.current = true;
return update('offset', state.current.ranges.first().get('from') - meta.get('limit'));
}, [meta]);
var trackPosition = function trackPosition() {
if (pending.current || !autoLoad.current || !state.current.items.size || state.current.ranges.last().get('to') >= state.current.meta.get('total')) return;
Promise.resolve().then(function () {
var _container$current;
if (!container.current || ((_container$current = container.current) === null || _container$current === void 0 ? void 0 : _container$current.clientHeight) === 0) return;
var _container$current$ge = container.current.getBoundingClientRect(),
bottom = _container$current$ge.bottom;
var height = window.innerHeight || document.documentElement.clientHeight;
var inView = bottom - height <= offset;
if (!inView) return;
autoLoad.current -= 1;
pending.current = true;
update('offset', state.current.ranges.last().get('to'));
});
};
useEffect(function () {
if (container.current === null) return;
window.addEventListener('scroll', trackPosition, true);
pending.current = false;
return function () {
return window.removeEventListener('scroll', trackPosition);
};
}, [container]);
/**
* Handle items change
*/
var getUpdate = function getUpdate() {
/**
* Reset refs if update has come from outside of this component
*/
if (!pending.current) {
var _update = updateItems(initialState, items, meta);
autoLoad.current = config.getIn(['pagination', 'autoLoadTimes']) || 0;
pending.current = true;
/** Scroll to top on query change */
emit('scrollTop');
pending.current = false;
state.current = _update;
return _update;
}
/**
* Check the new ranges and if there is difference update state
*/
if (!hasRange(state.current.ranges, meta.get('offset'))) {
var _update2 = updateItems(state.current, items, meta);
pending.current = false;
state.current = _update2;
return _update2;
}
return state.current;
};
return useMemo(function () {
var update = getUpdate();
var firstRange = update.ranges.first();
var lastRange = update.ranges.last();
return {
container: container,
onLoadNext: onLoadNext,
onLoadPrev: onLoadPrev,
items: update.items,
displayPrevButton: firstRange && firstRange.get('from') > 0,
displayNextButton: lastRange && lastRange.get('to') < meta.get('total') && !autoLoad.current
};
}, [items]);
});