UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

470 lines (469 loc) 17.2 kB
"use client"; import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; import _extends from "@babel/runtime/helpers/esm/extends"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; const _excluded = ["page_element"]; import "core-js/modules/web.dom-collections.iterator.js"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import { warn, isTrue, dispatchCustomElementEvent, getPreviousSibling } from '../../shared/component-helper'; import Context from '../../shared/Context'; import Button from '../button/Button'; import { preparePageElement, isTrElement, PaginationIndicator } from './PaginationHelpers'; import PaginationContext from './PaginationContext'; export default class InfinityScroller extends React.PureComponent { constructor(_props, context) { var _this; super(_props); _this = this; _defineProperty(this, "startup", () => { const { startupPage, startup_count } = this.context.pagination; const startupCount = parseFloat(startup_count); let newPageNo, skipObserver, callStartupEvent, preventWaitForDelay; for (let i = 0; i < startupCount; ++i) { newPageNo = startupPage + i; skipObserver = newPageNo < startupCount; callStartupEvent = i === 0; preventWaitForDelay = i <= startupCount - 1; this.getNewContent(newPageNo, { position: 'after', skipObserver }, { callStartupEvent, preventWaitForDelay }); } }); _defineProperty(this, "getNewContent", function (newPageNo) { let props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; let { callStartupEvent = false, preventWaitForDelay = false } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; const { pageCount, endInfinity } = _this.context.pagination; if (newPageNo > pageCount) { return endInfinity(); } const exists = _this.context.pagination.items.findIndex(obj => { return obj.pageNumber === newPageNo; }) > -1; if (exists) { return; } const items = _this.context.pagination.prefillItems(newPageNo, props); _this.context.pagination.setItems(items, () => { _this.callEventHandler(newPageNo, { callStartupEvent, preventWaitForDelay }); }); }); this.hideIndicator = isTrue(context.pagination.hide_progress_indicator); this.useLoadButton = isTrue(context.pagination.use_load_button); this.lastElement = React.createRef(); this.callOnUnmount = []; } componentWillUnmount() { clearTimeout(this._startupTimeout); clearTimeout(this._bufferTimeout); this.callOnUnmount.forEach(f => typeof f === 'function' && f()); } waitForReachedTime(fn, params) { this.callbackBuffer = this.callbackBuffer || []; this.callbackBuffer.push({ fn, params }); this.callBuffer({ minTime: params.preventWaitForDelay ? -1 : this.context.pagination.minTime }); } callBuffer() { let { minTime = this.context.pagination.minTime } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (this.callbackBuffer.length === 0) { return; } const diff = this._lastCall > 0 ? new Date().getTime() - this._lastCall : 0; const waitTime = diff < minTime ? minTime : 0; const nextTick = () => { if (this.callbackBuffer.length > 0) { this._lastCall = new Date().getTime(); const { fn, params } = this.callbackBuffer.shift(); fn(params); this.callBuffer({ minTime: params.preventWaitForDelay ? -1 : minTime }); } }; if (minTime > 0) { clearTimeout(this._bufferTimeout); this._bufferTimeout = setTimeout(nextTick, waitTime); } else { nextTick(); } } callEventHandler(pageNumber) { let { callStartupEvent = false, preventWaitForDelay = false, callOnEnd = false, onDispatch = null } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; this.waitForReachedTime(_ref => { let { pageNumber, callStartupEvent } = _ref; const context = this.context.pagination; const createEvent = eventName => { if (isNaN(pageNumber)) { pageNumber = 1; } const ret = dispatchCustomElementEvent(context, eventName, _objectSpread({ pageNumber }, context)); if (typeof onDispatch === 'function') { onDispatch(); } if (typeof ret === 'function') { this.callOnUnmount.push(ret); } }; if (callOnEnd) { createEvent('on_end'); } else { if (callStartupEvent) { createEvent('on_startup'); } else { createEvent('on_change'); } createEvent('on_load'); } }, { pageNumber, callStartupEvent, preventWaitForDelay }); } handleInfinityMarker() { const { children } = this.props; const { lowerPage, upperPage, pageCount, hasEndedInfinity, parallelLoadCount, current_page, fallback_element, marker_element, indicator_element } = this.context.pagination; const Marker = () => React.createElement(InteractionMarker, { pageNumber: upperPage, markerElement: marker_element || fallback_element, onVisible: pageNumber => { let newPageNo; for (let i = 0; i < parallelLoadCount; ++i) { newPageNo = pageNumber + 1 + i; this.context.pagination.onPageUpdate(() => { this.context.pagination.setState({ upperPage: newPageNo, skipObserver: i + 1 < parallelLoadCount }); }); this.callEventHandler(newPageNo); } } }); const LoadButton = () => React.createElement(InfinityLoadButton, { icon: "arrow_up", element: fallback_element, pressed_element: React.createElement(PaginationIndicator, { indicator_element: indicator_element || fallback_element }), on_click: () => { const newPageNo = lowerPage - 1; this.context.pagination.onPageUpdate(() => { this.context.pagination.setState({ lowerPage: newPageNo }); }); this.callEventHandler(newPageNo); } }); return React.createElement(React.Fragment, null, parseFloat(current_page) > 0 && lowerPage > 1 && React.createElement(LoadButton, null), children, !hasEndedInfinity && parseFloat(current_page) > 0 && (typeof pageCount === 'undefined' || upperPage < pageCount) && React.createElement(Marker, null), !hasEndedInfinity && !this.hideIndicator && (typeof pageCount === 'undefined' || upperPage < pageCount) && React.createElement(PaginationIndicator, { indicator_element: indicator_element || fallback_element })); } render() { const { items, pageCount, startupPage, hasEndedInfinity, parallelLoadCount, placeMakerBeforeContent, page_element, fallback_element, marker_element, indicator_element, load_button_text, loadButton } = this.context.pagination; if (!(items && items.length > 0)) { clearTimeout(this._startupTimeout); this._startupTimeout = setTimeout(this.startup, 1); return null; } if (this.context.pagination.useMarkerOnly) { return this.handleInfinityMarker(); } const Element = preparePageElement(page_element || React.Fragment); return items.map((_ref2, idx) => { let { pageNumber, hasContent, content, ref, skipObserver, ScrollElement } = _ref2; const isLastItem = idx === items.length - 1; const Elem = hasContent && ScrollElement || Element; const marker = hasContent && !this.useLoadButton && !skipObserver && !hasEndedInfinity && (typeof pageCount === 'undefined' || pageNumber <= pageCount) && React.createElement(InteractionMarker, { pageNumber: pageNumber, markerElement: marker_element || fallback_element, onVisible: pageNumber => { let newPageNo; for (let i = 0; i < parallelLoadCount; ++i) { newPageNo = pageNumber + 1 + i; this.getNewContent(newPageNo, { position: 'after', skipObserver: i + 1 < parallelLoadCount }); } } }); const showIndicator = (parallelLoadCount > 1 && idx > 0 ? isLastItem : true) && !hasContent && !this.hideIndicator; return React.createElement(Elem, { key: pageNumber, ref: ref }, hasContent && startupPage > 1 && pageNumber > 1 && pageNumber <= startupPage && React.createElement(InfinityLoadButton, { element: typeof loadButton === 'function' ? loadButton : fallback_element, icon: "arrow_up", text: load_button_text !== null && load_button_text !== void 0 ? load_button_text : loadButton === null || loadButton === void 0 ? void 0 : loadButton.text, icon_position: loadButton === null || loadButton === void 0 ? void 0 : loadButton.iconPosition, on_click: event => this.getNewContent(pageNumber - 1, { position: 'before', skipObserver: true, event }) }), placeMakerBeforeContent && marker, content, !placeMakerBeforeContent && marker, showIndicator && React.createElement(PaginationIndicator, { indicator_element: indicator_element || fallback_element }), hasContent && this.useLoadButton && isLastItem && (typeof pageCount === 'undefined' || pageNumber < pageCount) && React.createElement(InfinityLoadButton, { element: typeof loadButton === 'function' ? loadButton : fallback_element, text: load_button_text !== null && load_button_text !== void 0 ? load_button_text : loadButton === null || loadButton === void 0 ? void 0 : loadButton.text, icon_position: loadButton === null || loadButton === void 0 ? void 0 : loadButton.iconPosition, icon: "arrow_down", on_click: event => this.getNewContent(pageNumber + 1, { position: 'after', skipObserver: true, ScrollElement: props => hasContent && React.createElement(ScrollToElement, _extends({ page_element: page_element }, props)), event }) })); }); } } _defineProperty(InfinityScroller, "contextType", PaginationContext); _defineProperty(InfinityScroller, "defaultProps", { children: null }); process.env.NODE_ENV !== "production" ? InfinityScroller.propTypes = { children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]) } : void 0; class InteractionMarker extends React.PureComponent { constructor(props) { super(props); _defineProperty(this, "state", { isConnected: false }); _defineProperty(this, "callReady", () => { var _this$intersectionObs; (_this$intersectionObs = this.intersectionObserver) === null || _this$intersectionObs === void 0 ? void 0 : _this$intersectionObs.disconnect(); this.intersectionObserver = null; clearTimeout(this._readyTimeout); this._readyTimeout = setTimeout(() => { if (this._isMounted) { this.setState({ isConnected: true }); } this.props.onVisible(this.props.pageNumber); }, 1); }); if (typeof props.markerElement === 'function') { warn('Pagination: Please use a string or React element e.g. marker_element="tr"'); } this._ref = React.createRef(); if (typeof IntersectionObserver !== 'undefined') { this.intersectionObserver = new IntersectionObserver(entries => { const [{ isIntersecting }] = entries; if (isIntersecting) { this.callReady(); } }); } else { warn('Pagination is missing IntersectionObserver supported!'); } } componentDidMount() { if (this._ref.current) { var _this$intersectionObs2; this._isMounted = true; (_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.observe(this._ref.current); } } componentWillUnmount() { this._isMounted = false; if (this.intersectionObserver) { clearTimeout(this._readyTimeout); this.intersectionObserver.disconnect(); } } getContentHeight() { let height = 0; try { const sibling = getPreviousSibling('dnb-table', this._ref.current); height = parseFloat(window.getComputedStyle(sibling.querySelector('tbody')).height); } catch (e) {} return height; } render() { const { markerElement } = this.props; if (this.state.isConnected || !this.intersectionObserver) { return null; } const Element = markerElement && isTrElement(markerElement) ? 'tr' : 'div'; const ElementChild = markerElement && isTrElement(markerElement) ? 'td' : 'div'; return React.createElement(Element, { className: "dnb-pagination__marker dnb-table--ignore" }, React.createElement(ElementChild, { className: "dnb-pagination__marker__inner", ref: this._ref })); } } _defineProperty(InteractionMarker, "defaultProps", { markerElement: null }); process.env.NODE_ENV !== "production" ? InteractionMarker.propTypes = { pageNumber: PropTypes.number.isRequired, onVisible: PropTypes.func.isRequired, markerElement: PropTypes.oneOfType([PropTypes.object, PropTypes.node, PropTypes.func, PropTypes.string]) } : void 0; export class InfinityLoadButton extends React.PureComponent { constructor() { super(...arguments); _defineProperty(this, "state", { isPressed: false }); _defineProperty(this, "onClickHandler", e => { this.setState({ isPressed: true }); if (typeof this.props.on_click === 'function') { this.props.on_click(e); } }); } render() { const { element, icon, text, icon_position } = this.props; const Element = element; const ElementChild = isTrElement(Element) ? 'td' : 'div'; return this.state.isPressed ? this.props.pressed_element : React.createElement(Element, null, React.createElement(ElementChild, { className: "dnb-pagination__loadbar" }, React.createElement(Button, { size: "medium", icon: icon, icon_position: icon_position, text: text || this.context.translation.Pagination.load_button_text, variant: "secondary", on_click: this.onClickHandler }))); } } _defineProperty(InfinityLoadButton, "contextType", Context); _defineProperty(InfinityLoadButton, "defaultProps", { element: 'div', pressed_element: null, icon: 'arrow_down', text: null, icon_position: 'left' }); process.env.NODE_ENV !== "production" ? InfinityLoadButton.propTypes = { element: PropTypes.oneOfType([PropTypes.object, PropTypes.node, PropTypes.func, PropTypes.string]), pressed_element: PropTypes.oneOfType([PropTypes.object, PropTypes.node, PropTypes.func]), icon: PropTypes.string.isRequired, on_click: PropTypes.func.isRequired, text: PropTypes.string, icon_position: PropTypes.string } : void 0; class ScrollToElement extends React.PureComponent { componentDidMount() { const elem = ReactDOM.findDOMNode(this); this.scrollToPage(elem); } scrollToPage(element) { if (element && typeof element.scrollIntoView === 'function') { element.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); } } render() { const _this$props = this.props, { page_element } = _this$props, props = _objectWithoutProperties(_this$props, _excluded); const Element = preparePageElement(page_element || React.Fragment); return React.createElement(Element, props); } } _defineProperty(ScrollToElement, "defaultProps", { page_element: null }); process.env.NODE_ENV !== "production" ? ScrollToElement.propTypes = { page_element: PropTypes.oneOfType([PropTypes.object, PropTypes.node, PropTypes.func, PropTypes.string]) } : void 0; InfinityScroller._supportsSpacingProps = true; //# sourceMappingURL=PaginationInfinity.js.map