UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

480 lines (479 loc) 18.3 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.InfinityLoadButton = void 0; var _push = _interopRequireDefault(require("core-js-pure/stable/instance/push.js")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _componentHelper = require("../../shared/component-helper.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")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } class InfinityScroller extends _react.default.PureComponent { constructor(_props, context) { super(_props); _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", (newPageNo, props = {}, { callStartupEvent = false, preventWaitForDelay = false } = {}) => { 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 = (0, _componentHelper.isTrue)(context.pagination.hide_progress_indicator); this.useLoadButton = (0, _componentHelper.isTrue)(context.pagination.use_load_button); this.lastElement = _react.default.createRef(); this.callOnUnmount = []; } componentWillUnmount() { clearTimeout(this._startupTimeout); clearTimeout(this._bufferTimeout); this.callOnUnmount.forEach(f => typeof f === 'function' && f()); } waitForReachedTime(fn, params) { var _context; this.callbackBuffer = this.callbackBuffer || []; (0, _push.default)(_context = this.callbackBuffer).call(_context, { fn, params }); this.callBuffer({ minTime: params.preventWaitForDelay ? -1 : this.context.pagination.minTime }); } callBuffer({ minTime = this.context.pagination.minTime } = {}) { 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, { callStartupEvent = false, preventWaitForDelay = false, callOnEnd = false, onDispatch = null } = {}) { this.waitForReachedTime(({ pageNumber, callStartupEvent }) => { const context = this.context.pagination; const createEvent = eventName => { if (isNaN(pageNumber)) { pageNumber = 1; } const ret = (0, _componentHelper.dispatchCustomElementEvent)(context, eventName, { pageNumber, ...context }); if (typeof onDispatch === 'function') { onDispatch(); } if (typeof ret === 'function') { var _context2; (0, _push.default)(_context2 = this.callOnUnmount).call(_context2, 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.default.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.default.createElement(InfinityLoadButton, { icon: "arrow_up", element: fallback_element, pressed_element: _react.default.createElement(_PaginationHelpers.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.default.createElement(_react.default.Fragment, null, parseFloat(current_page) > 0 && lowerPage > 1 && _react.default.createElement(LoadButton, null), children, !hasEndedInfinity && parseFloat(current_page) > 0 && (typeof pageCount === 'undefined' || upperPage < pageCount) && _react.default.createElement(Marker, null), !hasEndedInfinity && !this.hideIndicator && (typeof pageCount === 'undefined' || upperPage < pageCount) && _react.default.createElement(_PaginationHelpers.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 = (0, _PaginationHelpers.preparePageElement)(page_element || _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 marker = hasContent && !this.useLoadButton && !skipObserver && !hasEndedInfinity && (typeof pageCount === 'undefined' || pageNumber <= pageCount) && _react.default.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.default.createElement(Elem, { key: pageNumber, ref: ref }, hasContent && startupPage > 1 && pageNumber > 1 && pageNumber <= startupPage && _react.default.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.default.createElement(_PaginationHelpers.PaginationIndicator, { indicator_element: indicator_element || fallback_element }), hasContent && this.useLoadButton && isLastItem && (typeof pageCount === 'undefined' || pageNumber < pageCount) && _react.default.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.default.createElement(ScrollToElement, _extends({ page_element: page_element }, props)), event }) })); }); } } exports.default = InfinityScroller; _defineProperty(InfinityScroller, "contextType", _PaginationContext.default); _defineProperty(InfinityScroller, "defaultProps", { children: null }); process.env.NODE_ENV !== "production" ? InfinityScroller.propTypes = { children: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]) } : void 0; class InteractionMarker extends _react.default.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 || _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') { (0, _componentHelper.warn)('Pagination: Please use a string or React element e.g. marker_element="tr"'); } this._ref = _react.default.createRef(); if (typeof IntersectionObserver !== 'undefined') { this.intersectionObserver = new IntersectionObserver(entries => { const [{ isIntersecting }] = entries; if (isIntersecting) { this.callReady(); } }); } else { (0, _componentHelper.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 || _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 = (0, _componentHelper.getClosestParent)('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 && (0, _PaginationHelpers.isTrElement)(markerElement) ? 'tr' : 'div'; const ElementChild = markerElement && (0, _PaginationHelpers.isTrElement)(markerElement) ? 'td' : 'div'; return _react.default.createElement(Element, { className: "dnb-pagination__marker dnb-table--ignore" }, _react.default.createElement(ElementChild, { className: "dnb-pagination__marker__inner", ref: this._ref })); } } _defineProperty(InteractionMarker, "defaultProps", { markerElement: null }); process.env.NODE_ENV !== "production" ? InteractionMarker.propTypes = { pageNumber: _propTypes.default.number.isRequired, onVisible: _propTypes.default.func.isRequired, markerElement: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.node, _propTypes.default.func, _propTypes.default.string]) } : void 0; class InfinityLoadButton extends _react.default.PureComponent { constructor(...args) { super(...args); _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 = (0, _PaginationHelpers.isTrElement)(Element) ? 'td' : 'div'; return this.state.isPressed ? this.props.pressed_element : _react.default.createElement(Element, null, _react.default.createElement(ElementChild, { className: "dnb-pagination__loadbar" }, _react.default.createElement(_Button.default, { size: "medium", icon: icon, icon_position: icon_position, text: text || this.context.translation.Pagination.load_button_text, variant: "secondary", on_click: this.onClickHandler }))); } } exports.InfinityLoadButton = InfinityLoadButton; _defineProperty(InfinityLoadButton, "contextType", _Context.default); _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.default.oneOfType([_propTypes.default.object, _propTypes.default.node, _propTypes.default.func, _propTypes.default.string]), pressed_element: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.node, _propTypes.default.func]), icon: _propTypes.default.string.isRequired, on_click: _propTypes.default.func.isRequired, text: _propTypes.default.string, icon_position: _propTypes.default.string } : void 0; class ScrollToElement extends _react.default.PureComponent { constructor(props) { super(props); this._elementRef = _react.default.createRef(); } componentDidMount() { const elem = this._elementRef.current; this.scrollToPage(elem); } scrollToPage(element) { if (element && typeof element.scrollIntoView === 'function') { element.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); } } render() { const { page_element, ...props } = this.props; const Element = (0, _PaginationHelpers.preparePageElement)(page_element || _react.default.Fragment); if (Element === _react.default.Fragment) { return _react.default.createElement("div", _extends({ ref: this._elementRef }, props)); } return _react.default.createElement(Element, _extends({ ref: this._elementRef }, props)); } } _defineProperty(ScrollToElement, "defaultProps", { page_element: null }); process.env.NODE_ENV !== "production" ? ScrollToElement.propTypes = { page_element: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.node, _propTypes.default.func, _propTypes.default.string]) } : void 0; InfinityScroller._supportsSpacingProps = true; //# sourceMappingURL=PaginationInfinity.js.map