UNPKG

@tamagui/react-native-web-lite

Version:
181 lines (179 loc) 7.98 kB
import { invariant } from "@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; 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; export { ViewabilityHelper_default as default }; //# sourceMappingURL=ViewabilityHelper.native.js.map