@shopify/flash-list
Version:
FlashList is a more performant FlatList replacement
579 lines • 34.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var react_1 = tslib_1.__importDefault(require("react"));
var react_native_1 = require("react-native");
var recyclerlistview_1 = require("recyclerlistview");
var sticky_1 = tslib_1.__importDefault(require("recyclerlistview/sticky"));
var AutoLayoutView_1 = tslib_1.__importDefault(require("./native/auto-layout/AutoLayoutView"));
var CellContainer_1 = tslib_1.__importDefault(require("./native/cell-container/CellContainer"));
var PureComponentWrapper_1 = require("./PureComponentWrapper");
var GridLayoutProviderWithProps_1 = tslib_1.__importDefault(require("./GridLayoutProviderWithProps"));
var CustomError_1 = tslib_1.__importDefault(require("./errors/CustomError"));
var ExceptionList_1 = tslib_1.__importDefault(require("./errors/ExceptionList"));
var Warnings_1 = tslib_1.__importDefault(require("./errors/Warnings"));
var ViewabilityManager_1 = tslib_1.__importDefault(require("./viewability/ViewabilityManager"));
var FlashListProps_1 = require("./FlashListProps");
var PlatformHelper_1 = require("./native/config/PlatformHelper");
var ContentContainerUtils_1 = require("./utils/ContentContainerUtils");
var StickyHeaderContainer = sticky_1.default;
var FlashList = /** @class */ (function (_super) {
tslib_1.__extends(FlashList, _super);
function FlashList(props) {
var _this = this;
var _a;
_this = _super.call(this, props) || this;
_this.listFixedDimensionSize = 0;
_this.transformStyle = PlatformHelper_1.PlatformConfig.invertedTransformStyle;
_this.transformStyleHorizontal = PlatformHelper_1.PlatformConfig.invertedTransformStyleHorizontal;
_this.distanceFromWindow = 0;
_this.contentStyle = {
paddingBottom: 0,
paddingTop: 0,
paddingLeft: 0,
paddingRight: 0,
};
_this.loadStartTime = 0;
_this.isListLoaded = false;
_this.windowCorrectionConfig = {
value: {
windowShift: 0,
startCorrection: 0,
endCorrection: 0,
},
applyToItemScroll: true,
applyToInitialOffset: true,
};
_this.isEmptyList = false;
_this.onEndReached = function () {
var _a, _b;
(_b = (_a = _this.props).onEndReached) === null || _b === void 0 ? void 0 : _b.call(_a);
};
_this.getRefreshControl = function () {
if (_this.props.onRefresh) {
return (react_1.default.createElement(react_native_1.RefreshControl, { refreshing: Boolean(_this.props.refreshing), progressViewOffset: _this.props.progressViewOffset, onRefresh: _this.props.onRefresh }));
}
};
_this.onScrollBeginDrag = function (event) {
var _a, _b;
_this.recordInteraction();
(_b = (_a = _this.props).onScrollBeginDrag) === null || _b === void 0 ? void 0 : _b.call(_a, event);
};
_this.onScroll = function (event) {
var _a, _b;
_this.recordInteraction();
_this.viewabilityManager.updateViewableItems();
(_b = (_a = _this.props).onScroll) === null || _b === void 0 ? void 0 : _b.call(_a, event);
};
_this.handleSizeChange = function (event) {
var _a;
_this.validateListSize(event);
var newSize = _this.props.horizontal
? event.nativeEvent.layout.height
: event.nativeEvent.layout.width;
var oldSize = _this.listFixedDimensionSize;
_this.listFixedDimensionSize = newSize;
// >0 check is to avoid rerender on mount where it would be redundant
if (oldSize > 0 && oldSize !== newSize) {
(_a = _this.rlvRef) === null || _a === void 0 ? void 0 : _a.forceRerender();
}
if (_this.props.onLayout) {
_this.props.onLayout(event);
}
};
_this.container = function (props, children) {
_this.clearPostLoadTimeout();
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(PureComponentWrapper_1.PureComponentWrapper, { enabled: _this.isListLoaded || children.length > 0 || _this.isEmptyList, contentStyle: _this.props.contentContainerStyle, horizontal: _this.props.horizontal, header: _this.props.ListHeaderComponent, extraData: _this.state.extraData, headerStyle: _this.props.ListHeaderComponentStyle, inverted: _this.props.inverted, renderer: _this.header }),
react_1.default.createElement(AutoLayoutView_1.default, tslib_1.__assign({}, props, { onBlankAreaEvent: _this.props.onBlankArea, onLayout: _this.updateDistanceFromWindow, disableAutoLayout: _this.props.disableAutoLayout }), children),
_this.isEmptyList
? _this.getValidComponent(_this.props.ListEmptyComponent)
: null,
react_1.default.createElement(PureComponentWrapper_1.PureComponentWrapper, { enabled: _this.isListLoaded || children.length > 0 || _this.isEmptyList, contentStyle: _this.props.contentContainerStyle, horizontal: _this.props.horizontal, header: _this.props.ListFooterComponent, extraData: _this.state.extraData, headerStyle: _this.props.ListFooterComponentStyle, inverted: _this.props.inverted, renderer: _this.footer }),
_this.getComponentForHeightMeasurement()));
};
_this.itemContainer = function (props, parentProps) {
var _a;
var CellRendererComponent = (_a = _this.props.CellRendererComponent) !== null && _a !== void 0 ? _a : CellContainer_1.default;
return (react_1.default.createElement(CellRendererComponent, tslib_1.__assign({}, props, { style: tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, props.style), { flexDirection: _this.props.horizontal ? "row" : "column", alignItems: "stretch" }), _this.getTransform()), (0, PlatformHelper_1.getCellContainerPlatformStyles)(_this.props.inverted, parentProps)), index: parentProps.index }),
react_1.default.createElement(PureComponentWrapper_1.PureComponentWrapper, { extendedState: parentProps.extendedState, internalSnapshot: parentProps.internalSnapshot, data: parentProps.data, arg: parentProps.index, renderer: _this.getCellContainerChild })));
};
_this.updateDistanceFromWindow = function (event) {
var newDistanceFromWindow = _this.props.horizontal
? event.nativeEvent.layout.x
: event.nativeEvent.layout.y;
if (_this.distanceFromWindow !== newDistanceFromWindow) {
_this.distanceFromWindow = newDistanceFromWindow;
_this.windowCorrectionConfig.value.windowShift = -_this.distanceFromWindow;
_this.viewabilityManager.updateViewableItems();
}
};
_this.separator = function (index) {
// Make sure we have data and don't read out of bounds
if (_this.props.data === null ||
_this.props.data === undefined ||
index + 1 >= _this.props.data.length) {
return null;
}
var leadingItem = _this.props.data[index];
var trailingItem = _this.props.data[index + 1];
var props = {
leadingItem: leadingItem,
trailingItem: trailingItem,
// TODO: Missing sections as we don't have this feature implemented yet. Implement section, leadingSection and trailingSection.
// https://github.com/facebook/react-native/blob/8bd3edec88148d0ab1f225d2119435681fbbba33/Libraries/Lists/VirtualizedSectionList.js#L285-L294
};
var Separator = _this.props.ItemSeparatorComponent;
return Separator && react_1.default.createElement(Separator, tslib_1.__assign({}, props));
};
_this.header = function () {
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(react_native_1.View, { style: {
paddingTop: _this.contentStyle.paddingTop,
paddingLeft: _this.contentStyle.paddingLeft,
} }),
react_1.default.createElement(react_native_1.View, { style: [_this.props.ListHeaderComponentStyle, _this.getTransform()] }, _this.getValidComponent(_this.props.ListHeaderComponent))));
};
_this.footer = function () {
var _a;
/** The web version of CellContainer uses a div directly which doesn't compose styles the way a View does.
* We will skip using CellContainer on web to avoid this issue. `getFooterContainer` on web will
* return a View. */
var FooterContainer = (_a = (0, PlatformHelper_1.getFooterContainer)()) !== null && _a !== void 0 ? _a : CellContainer_1.default;
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(FooterContainer, { index: -1, style: [_this.props.ListFooterComponentStyle, _this.getTransform()] }, _this.getValidComponent(_this.props.ListFooterComponent)),
react_1.default.createElement(react_native_1.View, { style: {
paddingBottom: _this.contentStyle.paddingBottom,
paddingRight: _this.contentStyle.paddingRight,
} })));
};
_this.getComponentForHeightMeasurement = function () {
return _this.props.horizontal &&
!_this.props.disableHorizontalListHeightMeasurement &&
!_this.isListLoaded &&
_this.state.dataProvider.getSize() > 0 ? (react_1.default.createElement(react_native_1.View, { style: { opacity: 0 }, pointerEvents: "none" }, _this.rowRendererWithIndex(Math.min(_this.state.dataProvider.getSize() - 1, 1), FlashListProps_1.RenderTargetOptions.Measurement))) : null;
};
_this.applyWindowCorrection = function (_, __, correctionObject) {
var _a;
correctionObject.windowShift = -_this.distanceFromWindow;
(_a = _this.stickyContentContainerRef) === null || _a === void 0 ? void 0 : _a.setEnabled(_this.isStickyEnabled);
};
_this.rowRendererSticky = function (index) {
return _this.rowRendererWithIndex(index, FlashListProps_1.RenderTargetOptions.StickyHeader);
};
_this.rowRendererWithIndex = function (index, target) {
var _a, _b, _c;
// known issue: expected to pass separators which isn't available in RLV
return (_b = (_a = _this.props).renderItem) === null || _b === void 0 ? void 0 : _b.call(_a, {
item: _this.props.data[index],
index: index,
target: target,
extraData: (_c = _this.state.extraData) === null || _c === void 0 ? void 0 : _c.value,
});
};
/**
* This will prevent render item calls unless data changes.
* Output of this method is received as children object so returning null here is no issue as long as we handle it inside our child container.
* @module getCellContainerChild acts as the new rowRenderer and is called directly from our child container.
*/
_this.emptyRowRenderer = function () {
return null;
};
_this.getCellContainerChild = function (index) {
return (react_1.default.createElement(react_1.default.Fragment, null,
_this.props.inverted ? _this.separator(index) : null,
react_1.default.createElement(react_native_1.View, { style: {
flexDirection: _this.props.horizontal || _this.props.numColumns === 1
? "column"
: "row",
} }, _this.rowRendererWithIndex(index, FlashListProps_1.RenderTargetOptions.Cell)),
_this.props.inverted ? null : _this.separator(index)));
};
_this.recyclerRef = function (ref) {
_this.rlvRef = ref;
};
_this.stickyContentRef = function (ref) {
_this.stickyContentContainerRef = ref;
};
_this.stickyOverrideRowRenderer = function (_, rowData, index, ___) {
return (react_1.default.createElement(PureComponentWrapper_1.PureComponentWrapper, { ref: _this.stickyContentRef, enabled: _this.isStickyEnabled,
// We're passing rowData to ensure that sticky headers are updated when data changes
rowData: rowData, arg: index, renderer: _this.rowRendererSticky }));
};
_this.onItemLayout = function (index) {
// Informing the layout provider about change to an item's layout. It already knows the dimensions so there's not need to pass them.
_this.state.layoutProvider.reportItemLayout(index);
_this.raiseOnLoadEventIfNeeded();
};
_this.raiseOnLoadEventIfNeeded = function () {
var _a, _b;
if (!_this.isListLoaded) {
_this.isListLoaded = true;
(_b = (_a = _this.props).onLoad) === null || _b === void 0 ? void 0 : _b.call(_a, {
elapsedTimeInMs: Date.now() - _this.loadStartTime,
});
_this.runAfterOnLoad();
}
};
_this.runAfterOnLoad = function () {
if (_this.props.estimatedItemSize === undefined) {
_this.itemSizeWarningTimeoutId = setTimeout(function () {
var averageItemSize = Math.floor(_this.state.layoutProvider.averageItemSize);
console.warn(Warnings_1.default.estimatedItemSizeMissingWarning.replace("@size", averageItemSize.toString()));
}, 1000);
}
_this.postLoadTimeoutId = setTimeout(function () {
// This force update is required to remove dummy element rendered to measure horizontal list height when the list doesn't update on its own.
// In most cases this timeout will never be triggered because list usually updates atleast once and this timeout is cleared on update.
if (_this.props.horizontal) {
_this.forceUpdate();
}
}, 500);
};
_this.clearPostLoadTimeout = function () {
if (_this.postLoadTimeoutId !== undefined) {
clearTimeout(_this.postLoadTimeoutId);
_this.postLoadTimeoutId = undefined;
}
};
_this.clearRenderSizeWarningTimeout = function () {
if (_this.renderedSizeWarningTimeoutId !== undefined) {
clearTimeout(_this.renderedSizeWarningTimeoutId);
_this.renderedSizeWarningTimeoutId = undefined;
}
};
/**
* Tells the list an interaction has occurred, which should trigger viewability calculations, e.g. if waitForInteractions is true and the user has not scrolled.
* This is typically called by taps on items or by navigation actions.
*/
_this.recordInteraction = function () {
_this.viewabilityManager.recordInteraction();
};
/**
* Retriggers viewability calculations. Useful to imperatively trigger viewability calculations.
*/
_this.recomputeViewableItems = function () {
_this.viewabilityManager.recomputeViewableItems();
};
_this.loadStartTime = Date.now();
_this.validateProps();
if (props.estimatedListSize) {
if (props.horizontal) {
_this.listFixedDimensionSize = props.estimatedListSize.height;
}
else {
_this.listFixedDimensionSize = props.estimatedListSize.width;
}
}
_this.distanceFromWindow =
(_a = props.estimatedFirstItemOffset) !== null && _a !== void 0 ? _a : ((props.ListHeaderComponent && 1) || 0);
// eslint-disable-next-line react/state-in-constructor
_this.state = FlashList.getInitialMutableState(_this);
_this.viewabilityManager = new ViewabilityManager_1.default(_this);
_this.itemAnimator = (0, PlatformHelper_1.getItemAnimator)();
return _this;
}
FlashList.prototype.validateProps = function () {
var _a, _b;
if (this.props.onRefresh && typeof this.props.refreshing !== "boolean") {
throw new CustomError_1.default(ExceptionList_1.default.refreshBooleanMissing);
}
if (Number((_a = this.props.stickyHeaderIndices) === null || _a === void 0 ? void 0 : _a.length) > 0 &&
this.props.horizontal) {
throw new CustomError_1.default(ExceptionList_1.default.stickyWhileHorizontalNotSupported);
}
if (Number(this.props.numColumns) > 1 && this.props.horizontal) {
throw new CustomError_1.default(ExceptionList_1.default.columnsWhileHorizontalNotSupported);
}
// `createAnimatedComponent` always passes a blank style object. To avoid warning while using AnimatedFlashList we've modified the check
// `style` prop can be an array. So we need to validate every object in array. Check: https://github.com/Shopify/flash-list/issues/651
if (__DEV__ &&
Object.keys(react_native_1.StyleSheet.flatten((_b = this.props.style) !== null && _b !== void 0 ? _b : {})).length > 0) {
console.warn(Warnings_1.default.styleUnsupported);
}
if ((0, ContentContainerUtils_1.hasUnsupportedKeysInContentContainerStyle)(this.props.contentContainerStyle)) {
console.warn(Warnings_1.default.styleContentContainerUnsupported);
}
};
// Some of the state variables need to update when props change
FlashList.getDerivedStateFromProps = function (nextProps, prevState) {
var _a, _b;
var newState = tslib_1.__assign({}, prevState);
if (prevState.numColumns !== nextProps.numColumns) {
newState.numColumns = nextProps.numColumns || 1;
newState.layoutProvider = FlashList.getLayoutProvider(newState.numColumns, nextProps);
}
else if (prevState.layoutProvider.updateProps(nextProps).hasExpired) {
newState.layoutProvider = FlashList.getLayoutProvider(newState.numColumns, nextProps);
}
// RLV retries to reposition the first visible item on layout provider change.
// It's not required in our case so we're disabling it
newState.layoutProvider.shouldRefreshWithAnchoring = Boolean(!((_a = prevState.layoutProvider) === null || _a === void 0 ? void 0 : _a.hasExpired));
if (nextProps.data !== prevState.data) {
newState.data = nextProps.data;
newState.dataProvider = prevState.dataProvider.cloneWithRows(nextProps.data);
if (nextProps.renderItem !== prevState.renderItem) {
newState.extraData = tslib_1.__assign({}, prevState.extraData);
}
}
if (nextProps.extraData !== ((_b = prevState.extraData) === null || _b === void 0 ? void 0 : _b.value)) {
newState.extraData = { value: nextProps.extraData };
}
newState.renderItem = nextProps.renderItem;
return newState;
};
FlashList.getInitialMutableState = function (flashList) {
var getStableId;
if (flashList.props.keyExtractor !== null &&
flashList.props.keyExtractor !== undefined) {
getStableId = function (index) {
// We assume `keyExtractor` function will never change from being `null | undefined` to defined and vice versa.
// Similarly, data should never be `null | undefined` when `getStableId` is called.
return flashList.props.keyExtractor(flashList.props.data[index], index).toString();
};
}
return {
data: null,
layoutProvider: null,
dataProvider: new recyclerlistview_1.DataProvider(function (r1, r2) {
return r1 !== r2;
}, getStableId),
numColumns: 0,
};
};
// Using only grid layout provider as it can also act as a listview, sizeProvider is a function to support future overrides
FlashList.getLayoutProvider = function (numColumns, flashListProps) {
return new GridLayoutProviderWithProps_1.default(
// max span or, total columns
numColumns, function (index, props) {
var _a;
// type of the item for given index
var type = (_a = props.getItemType) === null || _a === void 0 ? void 0 : _a.call(props, props.data[index], index, props.extraData);
return type || 0;
}, function (index, props, mutableLayout) {
var _a, _b;
// span of the item at given index, item can choose to span more than one column
(_a = props.overrideItemLayout) === null || _a === void 0 ? void 0 : _a.call(props, mutableLayout, props.data[index], index, numColumns, props.extraData);
return (_b = mutableLayout === null || mutableLayout === void 0 ? void 0 : mutableLayout.span) !== null && _b !== void 0 ? _b : 1;
}, function (index, props, mutableLayout) {
var _a;
// estimated size of the item an given index
(_a = props.overrideItemLayout) === null || _a === void 0 ? void 0 : _a.call(props, mutableLayout, props.data[index], index, numColumns, props.extraData);
return mutableLayout === null || mutableLayout === void 0 ? void 0 : mutableLayout.size;
}, flashListProps);
};
FlashList.prototype.componentDidMount = function () {
var _a;
if (((_a = this.props.data) === null || _a === void 0 ? void 0 : _a.length) === 0) {
this.raiseOnLoadEventIfNeeded();
}
};
FlashList.prototype.componentWillUnmount = function () {
this.viewabilityManager.dispose();
this.clearPostLoadTimeout();
this.clearRenderSizeWarningTimeout();
if (this.itemSizeWarningTimeoutId !== undefined) {
clearTimeout(this.itemSizeWarningTimeoutId);
}
};
FlashList.prototype.render = function () {
this.isEmptyList = this.state.dataProvider.getSize() === 0;
(0, ContentContainerUtils_1.updateContentStyle)(this.contentStyle, this.props.contentContainerStyle);
var _a = this.props, drawDistance = _a.drawDistance, removeClippedSubviews = _a.removeClippedSubviews, stickyHeaderIndices = _a.stickyHeaderIndices, horizontal = _a.horizontal, onEndReachedThreshold = _a.onEndReachedThreshold, estimatedListSize = _a.estimatedListSize, initialScrollIndex = _a.initialScrollIndex, style = _a.style, contentContainerStyle = _a.contentContainerStyle, renderScrollComponent = _a.renderScrollComponent, restProps = tslib_1.__rest(_a, ["drawDistance", "removeClippedSubviews", "stickyHeaderIndices", "horizontal", "onEndReachedThreshold", "estimatedListSize", "initialScrollIndex", "style", "contentContainerStyle", "renderScrollComponent"]);
// RecyclerListView simply ignores if initialScrollIndex is set to 0 because it doesn't understand headers
// Using initialOffset to force RLV to scroll to the right place
var initialOffset = (this.isInitialScrollIndexInFirstRow() && this.distanceFromWindow) ||
undefined;
var finalDrawDistance = drawDistance === undefined
? PlatformHelper_1.PlatformConfig.defaultDrawDistance
: drawDistance;
return (react_1.default.createElement(StickyHeaderContainer, { overrideRowRenderer: this.stickyOverrideRowRenderer, applyWindowCorrection: this.applyWindowCorrection, stickyHeaderIndices: stickyHeaderIndices, style: this.props.horizontal
? tslib_1.__assign({}, this.getTransform()) : tslib_1.__assign({ flex: 1, overflow: "hidden" }, this.getTransform()) },
react_1.default.createElement(recyclerlistview_1.ProgressiveListView, tslib_1.__assign({}, restProps, { ref: this.recyclerRef, layoutProvider: this.state.layoutProvider, dataProvider: this.state.dataProvider, rowRenderer: this.emptyRowRenderer, canChangeSize: true, isHorizontal: Boolean(horizontal), scrollViewProps: tslib_1.__assign({ onScrollBeginDrag: this.onScrollBeginDrag, onLayout: this.handleSizeChange, refreshControl: this.props.refreshControl || this.getRefreshControl(),
// Min values are being used to suppress RLV's bounded exception
style: { minHeight: 1, minWidth: 1 }, contentContainerStyle: tslib_1.__assign({ backgroundColor: this.contentStyle.backgroundColor,
// Required to handle a scrollview bug. Check: https://github.com/Shopify/flash-list/pull/187
minHeight: 1, minWidth: 1 }, (0, ContentContainerUtils_1.getContentContainerPadding)(this.contentStyle, horizontal)) }, this.props.overrideProps), forceNonDeterministicRendering: true, renderItemContainer: this.itemContainer, renderContentContainer: this.container, onEndReached: this.onEndReached, onEndReachedThresholdRelative: onEndReachedThreshold || undefined, extendedState: this.state.extraData, layoutSize: estimatedListSize, maxRenderAhead: 3 * finalDrawDistance, finalRenderAheadOffset: finalDrawDistance, renderAheadStep: finalDrawDistance, initialRenderIndex: (!this.isInitialScrollIndexInFirstRow() && initialScrollIndex) ||
undefined, initialOffset: initialOffset, onItemLayout: this.onItemLayout, onScroll: this.onScroll, onVisibleIndicesChanged: this.viewabilityManager.shouldListenToVisibleIndices
? this.viewabilityManager.onVisibleIndicesChanged
: undefined, windowCorrectionConfig: this.getUpdatedWindowCorrectionConfig(), itemAnimator: this.itemAnimator, suppressBoundedSizeException: true, externalScrollView: renderScrollComponent }))));
};
FlashList.prototype.getUpdatedWindowCorrectionConfig = function () {
// If the initial scroll index is in the first row then we're forcing RLV to use initialOffset and thus we need to disable window correction
// This isn't clean but it's the only way to get RLV to scroll to the right place
// TODO: Remove this when RLV fixes this. Current implementation will also fail if column span is overridden in the first row.
if (this.isInitialScrollIndexInFirstRow()) {
this.windowCorrectionConfig.applyToInitialOffset = false;
}
else {
this.windowCorrectionConfig.applyToInitialOffset = true;
}
this.windowCorrectionConfig.value.windowShift = -this.distanceFromWindow;
return this.windowCorrectionConfig;
};
FlashList.prototype.isInitialScrollIndexInFirstRow = function () {
var _a;
return (((_a = this.props.initialScrollIndex) !== null && _a !== void 0 ? _a : this.state.numColumns) <
this.state.numColumns);
};
FlashList.prototype.validateListSize = function (event) {
var _a = event.nativeEvent.layout, height = _a.height, width = _a.width;
this.clearRenderSizeWarningTimeout();
if (Math.floor(height) <= 1 || Math.floor(width) <= 1) {
this.renderedSizeWarningTimeoutId = setTimeout(function () {
console.warn(Warnings_1.default.unusableRenderedSize);
}, 1000);
}
};
FlashList.prototype.getTransform = function () {
var transformStyle = this.props.horizontal
? this.transformStyleHorizontal
: this.transformStyle;
return (this.props.inverted && transformStyle) || undefined;
};
FlashList.prototype.getValidComponent = function (component) {
var PassedComponent = component;
return ((react_1.default.isValidElement(PassedComponent) && PassedComponent) ||
(PassedComponent && react_1.default.createElement(PassedComponent, null)) ||
null);
};
Object.defineProperty(FlashList.prototype, "isStickyEnabled", {
get: function () {
var _a;
var currentOffset = ((_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.getCurrentScrollOffset()) || 0;
return currentOffset >= this.distanceFromWindow;
},
enumerable: false,
configurable: true
});
/**
* Disables recycling for the next frame so that layout animations run well.
* Warning: Avoid this when making large changes to the data as the list might draw too much to run animations. Single item insertions/deletions
* should be good. With recycling paused the list cannot do much optimization.
* The next render will run as normal and reuse items.
*/
FlashList.prototype.prepareForLayoutAnimationRender = function () {
var _a;
if (this.props.keyExtractor === null ||
this.props.keyExtractor === undefined) {
console.warn(Warnings_1.default.missingKeyExtractor);
}
else {
(_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.prepareForLayoutAnimationRender();
}
};
FlashList.prototype.scrollToEnd = function (params) {
var _a;
(_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.scrollToEnd(Boolean(params === null || params === void 0 ? void 0 : params.animated));
};
FlashList.prototype.scrollToIndex = function (params) {
var _a, _b, _c, _d, _e;
var layout = (_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.getLayout(params.index);
var listSize = (_b = this.rlvRef) === null || _b === void 0 ? void 0 : _b.getRenderedSize();
if (layout && listSize) {
var itemOffset = this.props.horizontal ? layout.x : layout.y;
var fixedDimension = this.props.horizontal
? listSize.width
: listSize.height;
var itemSize = this.props.horizontal ? layout.width : layout.height;
var scrollOffset = Math.max(0, itemOffset - ((_c = params.viewPosition) !== null && _c !== void 0 ? _c : 0) * (fixedDimension - itemSize)) - ((_d = params.viewOffset) !== null && _d !== void 0 ? _d : 0);
(_e = this.rlvRef) === null || _e === void 0 ? void 0 : _e.scrollToOffset(scrollOffset, scrollOffset, Boolean(params.animated), true);
}
};
FlashList.prototype.scrollToItem = function (params) {
var _a, _b;
var index = (_b = (_a = this.props.data) === null || _a === void 0 ? void 0 : _a.indexOf(params.item)) !== null && _b !== void 0 ? _b : -1;
if (index >= 0) {
this.scrollToIndex(tslib_1.__assign(tslib_1.__assign({}, params), { index: index }));
}
};
FlashList.prototype.scrollToOffset = function (params) {
var _a;
var x = this.props.horizontal ? params.offset : 0;
var y = this.props.horizontal ? 0 : params.offset;
(_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.scrollToOffset(x, y, Boolean(params.animated));
};
FlashList.prototype.getScrollableNode = function () {
var _a, _b;
return ((_b = (_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.getScrollableNode) === null || _b === void 0 ? void 0 : _b.call(_a)) || null;
};
Object.defineProperty(FlashList.prototype, "recyclerlistview_unsafe", {
/**
* Allows access to internal recyclerlistview. This is useful for enabling access to its public APIs.
* Warning: We may swap recyclerlistview for something else in the future. Use with caution.
*/
/* eslint-disable @typescript-eslint/naming-convention */
get: function () {
return this.rlvRef;
},
enumerable: false,
configurable: true
});
Object.defineProperty(FlashList.prototype, "firstItemOffset", {
/**
* Specifies how far the first item is from top of the list. This would normally be a sum of header size and top/left padding applied to the list.
*/
get: function () {
return this.distanceFromWindow;
},
enumerable: false,
configurable: true
});
/**
* FlashList will skip using layout cache on next update. Can be useful when you know the layout will change drastically for example, orientation change when used as a carousel.
*/
FlashList.prototype.clearLayoutCacheOnUpdate = function () {
this.state.layoutProvider.markExpired();
};
/**
* Returns the dimensions of the child container.
* @returns {Object} The dimensions of the child container.
*/
FlashList.prototype.getChildContainerDimensions = function () {
var _a;
return (_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.getContentDimension();
};
/**
* Returns the layout of the item at the given index.
* @param index - The index of the item to get the layout for.
* @returns {Object} The layout of the item at the given index.
*/
FlashList.prototype.getLayout = function (index) {
var _a;
return (_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.getLayout(index);
};
/**
* Returns the size of the list.
* @returns {Object} The size of the list.
*/
FlashList.prototype.getWindowSize = function () {
var _a;
return (_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.getRenderedSize();
};
/**
* Returns the absolute last scroll offset of the list.
* @returns {number} The absolute last scroll offset of the list.
*/
FlashList.prototype.getAbsoluteLastScrollOffset = function () {
var _a, _b;
return (_b = (_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.getCurrentScrollOffset()) !== null && _b !== void 0 ? _b : 0;
};
/**
* Returns the first item offset of the list.
* @returns {number} The first item offset of the list.
*/
FlashList.prototype.getFirstItemOffset = function () {
return this.firstItemOffset;
};
FlashList.prototype.getFirstVisibleIndex = function () {
var _a, _b;
return (_b = (_a = this.rlvRef) === null || _a === void 0 ? void 0 : _a.findApproxFirstVisibleIndex()) !== null && _b !== void 0 ? _b : -1;
};
FlashList.defaultProps = {
data: [],
numColumns: 1,
};
return FlashList;
}(react_1.default.PureComponent));
exports.default = FlashList;
//# sourceMappingURL=FlashList.js.map