UNPKG

@shopify/flash-list

Version:

FlashList is a more performant FlatList replacement

107 lines 6.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var CustomError_1 = tslib_1.__importDefault(require("../errors/CustomError")); var ExceptionList_1 = tslib_1.__importDefault(require("../errors/ExceptionList")); /** * Helper class for computing viewable items based on the passed `viewabilityConfig`. * Note methods in this class will be invoked on every scroll and should be optimized for performance. */ var ViewabilityHelper = /** @class */ (function () { function ViewabilityHelper(viewabilityConfig, viewableIndicesChanged) { /** * Viewable indices regardless of the viewability config */ this.possiblyViewableIndices = []; this.hasInteracted = false; this.viewableIndices = []; this.lastReportedViewableIndices = []; this.timers = new Set(); this.viewabilityConfig = viewabilityConfig; this.viewableIndicesChanged = viewableIndicesChanged; } ViewabilityHelper.prototype.dispose = function () { // Clean up on dismount this.timers.forEach(clearTimeout); }; ViewabilityHelper.prototype.updateViewableItems = function (horizontal, scrollOffset, listSize, getLayout, viewableIndices) { var _this = this; var _a, _b, _c, _d, _e, _f, _g, _h; if (viewableIndices !== undefined) { this.possiblyViewableIndices = viewableIndices; } if (((_a = this.viewabilityConfig) === null || _a === void 0 ? void 0 : _a.itemVisiblePercentThreshold) !== null && ((_b = this.viewabilityConfig) === null || _b === void 0 ? void 0 : _b.itemVisiblePercentThreshold) !== undefined && ((_c = this.viewabilityConfig) === null || _c === void 0 ? void 0 : _c.viewAreaCoveragePercentThreshold) !== null && ((_d = this.viewabilityConfig) === null || _d === void 0 ? void 0 : _d.viewAreaCoveragePercentThreshold) !== undefined) { throw new CustomError_1.default(ExceptionList_1.default.multipleViewabilityThresholdTypesNotSupported); } if (((_f = (_e = this.viewabilityConfig) === null || _e === void 0 ? void 0 : _e.waitForInteraction) !== null && _f !== void 0 ? _f : false) && !this.hasInteracted) { return; } var newViewableIndices = this.possiblyViewableIndices.filter(function (index) { var _a, _b; return _this.isItemViewable(index, horizontal, scrollOffset, listSize, (_a = _this.viewabilityConfig) === null || _a === void 0 ? void 0 : _a.viewAreaCoveragePercentThreshold, (_b = _this.viewabilityConfig) === null || _b === void 0 ? void 0 : _b.itemVisiblePercentThreshold, getLayout); }); this.viewableIndices = newViewableIndices; var minimumViewTime = (_h = (_g = this.viewabilityConfig) === null || _g === void 0 ? void 0 : _g.minimumViewTime) !== null && _h !== void 0 ? _h : 250; // Setting default to 250. Default of 0 can impact performance when user scrolls fast. if (minimumViewTime > 0) { var timeoutId_1 = setTimeout(function () { _this.timers.delete(timeoutId_1); _this.checkViewableIndicesChanges(newViewableIndices); }, minimumViewTime); this.timers.add(timeoutId_1); } else { this.checkViewableIndicesChanges(newViewableIndices); } }; ViewabilityHelper.prototype.checkViewableIndicesChanges = function (newViewableIndices) { var _this = this; // Check if all viewable indices are still available (applicable if minimumViewTime > 0) var currentlyNewViewableIndices = newViewableIndices.filter(function (index) { return _this.viewableIndices.includes(index); }); var newlyVisibleItems = currentlyNewViewableIndices.filter(function (index) { return !_this.lastReportedViewableIndices.includes(index); }); var newlyNonvisibleItems = this.lastReportedViewableIndices.filter(function (index) { return !currentlyNewViewableIndices.includes(index); }); if (newlyVisibleItems.length > 0 || newlyNonvisibleItems.length > 0) { this.lastReportedViewableIndices = currentlyNewViewableIndices; this.viewableIndicesChanged(currentlyNewViewableIndices, newlyVisibleItems, newlyNonvisibleItems); } }; ViewabilityHelper.prototype.clearLastReportedViewableIndices = function () { this.lastReportedViewableIndices = []; }; ViewabilityHelper.prototype.isItemViewable = function (index, horizontal, scrollOffset, listSize, viewAreaCoveragePercentThreshold, itemVisiblePercentThreshold, getLayout) { var itemLayout = getLayout(index); if (itemLayout === undefined) { return false; } var itemTop = (horizontal ? itemLayout.x : itemLayout.y) - scrollOffset; var itemSize = horizontal ? itemLayout.width : itemLayout.height; var listMainSize = horizontal ? listSize.width : listSize.height; var pixelsVisible = Math.min(itemTop + itemSize, listMainSize) - Math.max(itemTop, 0); // Always consider item fully viewable if it is fully visible, regardless of the `viewAreaCoveragePercentThreshold` if (pixelsVisible === itemSize) { return true; } // Skip checking item if it's not visible at all if (pixelsVisible === 0) { return false; } var viewAreaMode = viewAreaCoveragePercentThreshold !== null && viewAreaCoveragePercentThreshold !== undefined; var percent = viewAreaMode ? pixelsVisible / listMainSize : pixelsVisible / itemSize; var viewableAreaPercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold * 0.01 : (itemVisiblePercentThreshold !== null && itemVisiblePercentThreshold !== void 0 ? itemVisiblePercentThreshold : 0) * 0.01; return percent >= viewableAreaPercentThreshold; }; return ViewabilityHelper; }()); exports.default = ViewabilityHelper; //# sourceMappingURL=ViewabilityHelper.js.map