@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
425 lines (424 loc) • 15.6 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.InfinityLoadButton = InfinityLoadButton;
exports.default = InfinityScroller;
var _push = _interopRequireDefault(require("core-js-pure/stable/instance/push.js"));
var _react = _interopRequireWildcard(require("react"));
var _useMountEffect = _interopRequireDefault(require("../../shared/helpers/useMountEffect.js"));
var _componentHelper = require("../../shared/component-helper.js");
var _withComponentMarkers = _interopRequireDefault(require("../../shared/helpers/withComponentMarkers.js"));
var _Context = _interopRequireDefault(require("../../shared/Context.js"));
var _Button = _interopRequireDefault(require("../button/Button.js"));
var _PaginationHelpers = require("./PaginationHelpers.js");
var _PaginationContext = _interopRequireDefault(require("./PaginationContext.js"));
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function InfinityScroller({
children = null
}) {
const {
pagination
} = (0, _react.useContext)(_PaginationContext.default);
const hideIndicator = pagination.hideProgressIndicator;
const useLoadButton = pagination.useLoadButton;
const paginationRef = (0, _react.useRef)(pagination);
paginationRef.current = pagination;
const callOnUnmountRef = (0, _react.useRef)([]);
const startupTimeoutRef = (0, _react.useRef)(null);
const bufferTimeoutRef = (0, _react.useRef)(null);
const callbackBufferRef = (0, _react.useRef)([]);
const lastCallRef = (0, _react.useRef)(0);
(0, _react.useEffect)(() => {
return () => {
clearTimeout(startupTimeoutRef.current);
clearTimeout(bufferTimeoutRef.current);
callOnUnmountRef.current.forEach(f => typeof f === 'function' && f());
};
}, []);
const callBuffer = (minTime = paginationRef.current.minTime) => {
if (callbackBufferRef.current.length === 0) {
return;
}
const diff = lastCallRef.current > 0 ? new Date().getTime() - lastCallRef.current : 0;
const waitTime = diff < minTime ? minTime : 0;
const nextTick = () => {
if (callbackBufferRef.current.length > 0) {
lastCallRef.current = new Date().getTime();
const {
fn,
params
} = callbackBufferRef.current.shift();
fn(params);
callBuffer(params.preventWaitForDelay ? -1 : minTime);
}
};
if (minTime > 0) {
clearTimeout(bufferTimeoutRef.current);
bufferTimeoutRef.current = setTimeout(nextTick, waitTime);
} else {
nextTick();
}
};
const waitForReachedTime = (fn, params) => {
var _context;
(0, _push.default)(_context = callbackBufferRef.current).call(_context, {
fn,
params
});
callBuffer(params.preventWaitForDelay ? -1 : paginationRef.current.minTime);
};
const callEventHandler = (pageNumber, {
callStartupEvent = false,
preventWaitForDelay = false,
callOnEnd = false,
onDispatch = null
} = {}) => {
waitForReachedTime(({
pageNumber: pn,
callStartupEvent: isStartup
}) => {
const ctx = paginationRef.current;
let resolvedPageNumber = pn;
const createEvent = eventName => {
if (isNaN(resolvedPageNumber)) {
resolvedPageNumber = 1;
}
const ret = (0, _componentHelper.dispatchCustomElementEvent)(ctx, eventName, {
pageNumber: resolvedPageNumber,
...ctx
});
if (typeof onDispatch === 'function') {
onDispatch();
}
if (typeof ret === 'function') {
var _context2;
(0, _push.default)(_context2 = callOnUnmountRef.current).call(_context2, ret);
}
};
if (callOnEnd) {
createEvent('onEnd');
} else {
if (isStartup) {
createEvent('onStartup');
} else {
createEvent('onChange');
}
createEvent('onLoad');
}
}, {
pageNumber,
callStartupEvent,
preventWaitForDelay
});
};
const getNewContent = (newPageNo, props = {}, {
callStartupEvent = false,
preventWaitForDelay = false
} = {}) => {
const {
pageCountInternal,
endInfinity
} = paginationRef.current;
if (newPageNo > pageCountInternal) {
return endInfinity();
}
const exists = paginationRef.current.items.findIndex(obj => obj.pageNumber === newPageNo) > -1;
if (exists) {
return;
}
const items = paginationRef.current.prefillItems(newPageNo, props);
paginationRef.current.setItems(items, () => {
callEventHandler(newPageNo, {
callStartupEvent,
preventWaitForDelay
});
});
};
const startup = () => {
const {
startupPage,
startupCount
} = paginationRef.current;
const usedStartupCount = parseFloat(startupCount);
for (let i = 0; i < usedStartupCount; ++i) {
const newPageNo = startupPage + i;
const skipObserver = newPageNo < usedStartupCount;
const callStartupEvent = i === 0;
const preventWaitForDelay = i <= usedStartupCount - 1;
getNewContent(newPageNo, {
position: 'after',
skipObserver
}, {
callStartupEvent,
preventWaitForDelay
});
}
};
const handleInfinityMarker = () => {
const {
lowerPage,
upperPage,
pageCountInternal,
hasEndedInfinity,
parallelLoadCount,
currentPage,
fallbackElement,
markerElement,
indicatorElement
} = paginationRef.current;
const Marker = () => (0, _jsxRuntime.jsx)(InteractionMarker, {
pageNumber: upperPage,
markerElement: markerElement || fallbackElement,
onVisible: pageNumber => {
let newPageNo;
for (let i = 0; i < parallelLoadCount; ++i) {
newPageNo = pageNumber + 1 + i;
paginationRef.current.onPageUpdate(() => {
paginationRef.current.setState({
upperPage: newPageNo,
skipObserver: i + 1 < parallelLoadCount
});
});
callEventHandler(newPageNo);
}
}
});
const LoadButton = () => (0, _jsxRuntime.jsx)(InfinityLoadButton, {
icon: "arrow_up",
element: fallbackElement,
pressedElement: (0, _jsxRuntime.jsx)(_PaginationHelpers.PaginationIndicator, {
indicatorElement: indicatorElement || fallbackElement
}),
onClick: () => {
const newPageNo = lowerPage - 1;
paginationRef.current.onPageUpdate(() => {
paginationRef.current.setState({
lowerPage: newPageNo
});
});
callEventHandler(newPageNo);
}
});
return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [parseFloat(currentPage) > 0 && lowerPage > 1 && (0, _jsxRuntime.jsx)(LoadButton, {}), children, !hasEndedInfinity && parseFloat(currentPage) > 0 && (typeof pageCountInternal === 'undefined' || upperPage < pageCountInternal) && (0, _jsxRuntime.jsx)(Marker, {}), !hasEndedInfinity && !hideIndicator && (typeof pageCountInternal === 'undefined' || upperPage < pageCountInternal) && (0, _jsxRuntime.jsx)(_PaginationHelpers.PaginationIndicator, {
indicatorElement: indicatorElement || fallbackElement
})]
});
};
const {
items,
pageCountInternal,
startupPage,
hasEndedInfinity,
parallelLoadCount,
placeMakerBeforeContent,
pageElement,
fallbackElement,
markerElement,
indicatorElement,
loadButton
} = pagination;
if (!(items && items.length > 0)) {
clearTimeout(startupTimeoutRef.current);
startupTimeoutRef.current = setTimeout(startup, 1);
return null;
}
if (pagination.useMarkerOnly) {
return handleInfinityMarker();
}
const Element = (0, _PaginationHelpers.preparePageElement)(pageElement || _react.default.Fragment);
return items.map(({
pageNumber,
hasContent,
content,
ref,
skipObserver,
ScrollElement
}, idx) => {
const isLastItem = idx === items.length - 1;
const Elem = hasContent && ScrollElement || Element;
const isFragment = Elem === _react.default.Fragment;
const marker = hasContent && !useLoadButton && !skipObserver && !hasEndedInfinity && (typeof pageCountInternal === 'undefined' || pageNumber <= pageCountInternal) && (0, _jsxRuntime.jsx)(InteractionMarker, {
pageNumber: pageNumber,
markerElement: markerElement || fallbackElement,
onVisible: pageNumber => {
let newPageNo;
for (let i = 0; i < parallelLoadCount; ++i) {
newPageNo = pageNumber + 1 + i;
getNewContent(newPageNo, {
position: 'after',
skipObserver: i + 1 < parallelLoadCount
});
}
}
});
const showIndicator = (parallelLoadCount > 1 && idx > 0 ? isLastItem : true) && !hasContent && !hideIndicator;
return (0, _jsxRuntime.jsxs)(Elem, {
...(!isFragment && {
ref
}),
children: [hasContent && startupPage > 1 && pageNumber > 1 && pageNumber <= startupPage && (0, _jsxRuntime.jsx)(InfinityLoadButton, {
element: typeof loadButton === 'function' ? loadButton : fallbackElement,
icon: "arrow_up",
text: loadButton === null || loadButton === void 0 ? void 0 : loadButton.text,
iconPosition: loadButton === null || loadButton === void 0 ? void 0 : loadButton.iconPosition,
onClick: event => getNewContent(pageNumber - 1, {
position: 'before',
skipObserver: true,
event
})
}), placeMakerBeforeContent && marker, content, !placeMakerBeforeContent && marker, showIndicator && (0, _jsxRuntime.jsx)(_PaginationHelpers.PaginationIndicator, {
indicatorElement: indicatorElement || fallbackElement
}), hasContent && useLoadButton && isLastItem && (typeof pageCountInternal === 'undefined' || pageNumber < pageCountInternal) && (0, _jsxRuntime.jsx)(InfinityLoadButton, {
element: typeof loadButton === 'function' ? loadButton : fallbackElement,
text: loadButton === null || loadButton === void 0 ? void 0 : loadButton.text,
iconPosition: loadButton === null || loadButton === void 0 ? void 0 : loadButton.iconPosition,
icon: "arrow_down",
onClick: event => getNewContent(pageNumber + 1, {
position: 'after',
skipObserver: true,
ScrollElement: props => hasContent && (0, _jsxRuntime.jsx)(ScrollToElement, {
pageElement: pageElement,
...props
}),
event
})
})]
}, pageNumber);
});
}
function InteractionMarker({
pageNumber,
markerElement = null,
onVisible
}) {
const [isConnected, setIsConnected] = (0, _react.useState)(false);
const markerRef = (0, _react.useRef)(null);
const observerRef = (0, _react.useRef)(null);
const hasObserverSupport = (0, _react.useRef)(typeof IntersectionObserver !== 'undefined');
const isMountedRef = (0, _react.useRef)(false);
const readyTimeoutRef = (0, _react.useRef)(null);
(0, _useMountEffect.default)(() => {
if (typeof markerElement === 'function') {
(0, _componentHelper.warn)('Pagination: Please use a string or React element e.g. markerElement="tr"');
}
if (hasObserverSupport.current) {
observerRef.current = new IntersectionObserver(entries => {
const [{
isIntersecting
}] = entries;
if (isIntersecting) {
callReady();
}
});
} else {
(0, _componentHelper.warn)('Pagination is missing IntersectionObserver supported!');
}
isMountedRef.current = true;
if (markerRef.current) {
var _observerRef$current;
(_observerRef$current = observerRef.current) === null || _observerRef$current === void 0 || _observerRef$current.observe(markerRef.current);
}
return () => {
var _observerRef$current2;
isMountedRef.current = false;
clearTimeout(readyTimeoutRef.current);
(_observerRef$current2 = observerRef.current) === null || _observerRef$current2 === void 0 || _observerRef$current2.disconnect();
};
});
const callReady = () => {
var _observerRef$current3;
(_observerRef$current3 = observerRef.current) === null || _observerRef$current3 === void 0 || _observerRef$current3.disconnect();
observerRef.current = null;
clearTimeout(readyTimeoutRef.current);
readyTimeoutRef.current = setTimeout(() => {
if (isMountedRef.current) {
setIsConnected(true);
}
onVisible(pageNumber);
}, 1);
};
if (isConnected || !hasObserverSupport.current) {
return null;
}
const Element = markerElement && (0, _PaginationHelpers.isTrElement)(markerElement) ? 'tr' : 'div';
const ElementChild = markerElement && (0, _PaginationHelpers.isTrElement)(markerElement) ? 'td' : 'div';
return (0, _jsxRuntime.jsx)(Element, {
className: "dnb-pagination__marker dnb-table--ignore",
children: (0, _jsxRuntime.jsx)(ElementChild, {
className: "dnb-pagination__marker__inner",
ref: markerRef
})
});
}
function InfinityLoadButton({
element = 'div',
pressedElement = null,
icon = 'arrow_down',
text = null,
iconPosition = 'left',
onClick
}) {
const context = _react.default.useContext(_Context.default);
const [isPressed, setIsPressed] = _react.default.useState(false);
const handleClick = e => {
setIsPressed(true);
if (typeof onClick === 'function') {
onClick(e);
}
};
const Element = element;
const ElementChild = (0, _PaginationHelpers.isTrElement)(Element) ? 'td' : 'div';
if (isPressed) {
return (0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
children: pressedElement
});
}
return (0, _jsxRuntime.jsx)(Element, {
children: (0, _jsxRuntime.jsx)(ElementChild, {
className: "dnb-pagination__loadbar",
children: (0, _jsxRuntime.jsx)(_Button.default, {
size: "medium",
icon: icon,
iconPosition: iconPosition,
text: text || context.translation.Pagination.loadButtonText,
variant: "secondary",
onClick: handleClick
})
})
});
}
function ScrollToElement({
pageElement = null,
...props
}) {
const elementRef = _react.default.useRef(null);
(0, _useMountEffect.default)(() => {
const elem = elementRef.current;
if (elem && typeof elem.scrollIntoView === 'function') {
elem.scrollIntoView({
block: 'nearest',
behavior: 'smooth'
});
}
});
const Element = (0, _PaginationHelpers.preparePageElement)(pageElement || _react.default.Fragment);
if (Element === _react.default.Fragment) {
return (0, _jsxRuntime.jsx)("div", {
ref: elementRef,
...props
});
}
return (0, _jsxRuntime.jsx)(Element, {
ref: elementRef,
...props
});
}
(0, _withComponentMarkers.default)(InfinityScroller, {
_supportsSpacingProps: true
});
//# sourceMappingURL=PaginationInfinity.js.map