UNPKG

@tamagui/react-native-web-lite

Version:
200 lines (199 loc) 9.18 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: !0 }); }, __copyProps = (to, from, except, desc) => { if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod); var ViewabilityHelper_exports = {}; __export(ViewabilityHelper_exports, { default: () => ViewabilityHelper_default }); module.exports = __toCommonJS(ViewabilityHelper_exports); var import_react_native_web_internals = require("@tamagui/react-native-web-internals"); function _class_call_check(instance, Constructor) { if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); } } function _create_class(Constructor, protoProps, staticProps) { return protoProps && _defineProperties(Constructor.prototype, protoProps), staticProps && _defineProperties(Constructor, staticProps), Constructor; } function _define_property(obj, key, value) { return key in obj ? Object.defineProperty(obj, key, { value, enumerable: !0, configurable: !0, writable: !0 }) : obj[key] = value, obj; } var ViewabilityHelper = /* @__PURE__ */ function() { "use strict"; function ViewabilityHelper2() { var config = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : { viewAreaCoveragePercentThreshold: 0 }; _class_call_check(this, ViewabilityHelper2), _define_property(this, "_config", void 0), _define_property(this, "_hasInteracted", !1), _define_property(this, "_timers", /* @__PURE__ */ new Set()), _define_property(this, "_viewableIndices", []), _define_property(this, "_viewableItems", /* @__PURE__ */ new Map()), this._config = config; } return _create_class(ViewabilityHelper2, [ { /** * Cleanup, e.g. on unmount. Clears any pending timers. */ key: "dispose", value: function() { this._timers.forEach(clearTimeout); } }, { /** * Determines which items are viewable based on the current metrics and config. */ key: "computeViewableItems", value: function(props, scrollOffset, viewportHeight, getFrameMetrics, renderRange) { var itemCount = props.getItemCount(props.data), { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = this._config, viewAreaMode = viewAreaCoveragePercentThreshold != null, viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold; (0, import_react_native_web_internals.invariant)(viewablePercentThreshold != null && itemVisiblePercentThreshold != null != (viewAreaCoveragePercentThreshold != null), "Must set exactly one of itemVisiblePercentThreshold or viewAreaCoveragePercentThreshold"); var viewableIndices = []; if (itemCount === 0) return viewableIndices; var firstVisible = -1, { first, last } = renderRange || { first: 0, last: itemCount - 1 }; if (last >= itemCount) return console.warn("Invalid render range computing viewability " + JSON.stringify({ renderRange, itemCount })), []; for (var idx = first; idx <= last; idx++) { var metrics = getFrameMetrics(idx, props); if (metrics) { var top = metrics.offset - scrollOffset, bottom = top + metrics.length; if (top < viewportHeight && bottom > 0) firstVisible = idx, _isViewable(viewAreaMode, viewablePercentThreshold, top, bottom, viewportHeight, metrics.length) && viewableIndices.push(idx); else if (firstVisible >= 0) break; } } return viewableIndices; } }, { /** * Figures out which items are viewable and how that has changed from before and calls * `onViewableItemsChanged` as appropriate. */ key: "onUpdate", value: function(props, scrollOffset, viewportHeight, getFrameMetrics, createViewToken, onViewableItemsChanged, renderRange) { var _this = this, itemCount = props.getItemCount(props.data); if (!(this._config.waitForInteraction && !this._hasInteracted || itemCount === 0 || !getFrameMetrics(0, props))) { var viewableIndices = []; if (itemCount && (viewableIndices = this.computeViewableItems(props, scrollOffset, viewportHeight, getFrameMetrics, renderRange)), !(this._viewableIndices.length === viewableIndices.length && this._viewableIndices.every(function(v, ii) { return v === viewableIndices[ii]; }))) if (this._viewableIndices = viewableIndices, this._config.minimumViewTime) { var handle = setTimeout(function() { _this._timers.delete(handle), _this._onUpdateSync(props, viewableIndices, onViewableItemsChanged, createViewToken); }, this._config.minimumViewTime); this._timers.add(handle); } else this._onUpdateSync(props, viewableIndices, onViewableItemsChanged, createViewToken); } } }, { key: "resetViewableIndices", value: function() { this._viewableIndices = []; } }, { key: "recordInteraction", value: function() { this._hasInteracted = !0; } }, { key: "_onUpdateSync", value: function(props, viewableIndicesToCheck, onViewableItemsChanged, createViewToken) { var _this = this; viewableIndicesToCheck = viewableIndicesToCheck.filter(function(ii) { return _this._viewableIndices.includes(ii); }); var prevItems = this._viewableItems, nextItems = new Map(viewableIndicesToCheck.map(function(ii) { var viewable2 = createViewToken(ii, !0, props); return [ viewable2.key, viewable2 ]; })), changed = [], _iteratorNormalCompletion = !0, _didIteratorError = !1, _iteratorError = void 0; try { for (var _iterator = nextItems[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = !0) { var [key, viewable] = _step.value; prevItems.has(key) || changed.push(viewable); } } catch (err) { _didIteratorError = !0, _iteratorError = err; } finally { try { !_iteratorNormalCompletion && _iterator.return != null && _iterator.return(); } finally { if (_didIteratorError) throw _iteratorError; } } var _iteratorNormalCompletion1 = !0, _didIteratorError1 = !1, _iteratorError1 = void 0; try { for (var _iterator1 = prevItems[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = !0) { var [key1, viewable1] = _step1.value; nextItems.has(key1) || changed.push({ ...viewable1, isViewable: !1 }); } } catch (err) { _didIteratorError1 = !0, _iteratorError1 = err; } finally { try { !_iteratorNormalCompletion1 && _iterator1.return != null && _iterator1.return(); } finally { if (_didIteratorError1) throw _iteratorError1; } } changed.length > 0 && (this._viewableItems = nextItems, onViewableItemsChanged({ viewableItems: Array.from(nextItems.values()), changed })); } } ]), ViewabilityHelper2; }(); function _isViewable(viewAreaMode, viewablePercentThreshold, top, bottom, viewportHeight, itemLength) { if (_isEntirelyVisible(top, bottom, viewportHeight)) return !0; var pixels = _getPixelsVisible(top, bottom, viewportHeight), percent = 100 * (viewAreaMode ? pixels / viewportHeight : pixels / itemLength); return percent >= viewablePercentThreshold; } function _getPixelsVisible(top, bottom, viewportHeight) { var visibleHeight = Math.min(bottom, viewportHeight) - Math.max(top, 0); return Math.max(0, visibleHeight); } function _isEntirelyVisible(top, bottom, viewportHeight) { return top >= 0 && bottom <= viewportHeight && bottom > top; } var ViewabilityHelper_default = ViewabilityHelper; //# sourceMappingURL=ViewabilityHelper.js.map