UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

425 lines (424 loc) 15.6 kB
"use strict"; "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