@legendapp/list
Version:
Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.
1,435 lines (1,411 loc) • 247 kB
JavaScript
import * as React2 from 'react';
import { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useContext } from 'react';
import * as ReactNative from 'react-native';
import { Animated, Platform as Platform$1, View as View$1, Text as Text$1, StyleSheet as StyleSheet$1, RefreshControl, Dimensions, I18nManager } from 'react-native';
import { useSyncExternalStore } from 'use-sync-external-store/shim';
// src/components/LegendList.tsx
Animated.View;
var View = View$1;
var Text = Text$1;
var Platform = Platform$1;
var PlatformAdjustBreaksScroll = Platform.OS === "android";
// src/utils/rtl.ts
function clampHorizontalOffset(offset, maxOffset) {
if (maxOffset === void 0) {
return offset;
}
return Math.max(0, Math.min(maxOffset, offset));
}
function getHorizontalMaxOffset(state, contentWidth) {
if (contentWidth === void 0 || !Number.isFinite(contentWidth) || !Number.isFinite(state.scrollLength) || contentWidth <= state.scrollLength) {
return contentWidth !== void 0 && Number.isFinite(contentWidth) && Number.isFinite(state.scrollLength) ? 0 : void 0;
}
return Math.max(0, contentWidth - state.scrollLength);
}
function getDefaultHorizontalRTLScrollType() {
return Platform.OS === "web" ? "normal" : "inverted";
}
function getNativeHorizontalRTLScrollType(state) {
var _a3;
return (_a3 = state == null ? void 0 : state.horizontalRTLScrollType) != null ? _a3 : getDefaultHorizontalRTLScrollType();
}
function isRTLProps(props) {
var _a3;
return (_a3 = props == null ? void 0 : props.rtl) != null ? _a3 : !!I18nManager.isRTL;
}
function isHorizontalRTL(state) {
return isHorizontalRTLProps(state == null ? void 0 : state.props);
}
function isHorizontalRTLProps(props) {
return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
}
function getLogicalHorizontalMaxOffset(state, contentWidth) {
var _a3;
return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
}
function getHorizontalInsetEnd(state, inset) {
if (!inset) {
return 0;
}
return (isHorizontalRTL(state) ? inset.left : inset.right) || 0;
}
function toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, listSize) {
if (!isHorizontalRTL(state) || listSize === void 0 || !Number.isFinite(listSize)) {
return logicalPosition;
}
return Math.max(0, listSize - logicalPosition - itemSize);
}
function toNativeHorizontalOffset(state, logicalOffset, contentWidth) {
if (!state || !isHorizontalRTL(state)) {
return logicalOffset;
}
const maxOffset = getHorizontalMaxOffset(state, contentWidth);
const clampedLogicalOffset = clampHorizontalOffset(logicalOffset, maxOffset);
const mode = getNativeHorizontalRTLScrollType(state);
if (mode === "negative") {
return clampedLogicalOffset === 0 ? 0 : -clampedLogicalOffset;
}
if (mode === "inverted") {
if (maxOffset === void 0) {
return clampedLogicalOffset;
}
return clampHorizontalOffset(maxOffset - clampedLogicalOffset, maxOffset);
}
return clampedLogicalOffset;
}
function toLogicalHorizontalOffset(state, rawOffset, contentWidth) {
if (!isHorizontalRTL(state)) {
state.horizontalRTLScrollType = void 0;
return rawOffset;
}
const maxOffset = getHorizontalMaxOffset(state, contentWidth);
if (rawOffset < 0) {
state.horizontalRTLScrollType = "negative";
return clampHorizontalOffset(-rawOffset, maxOffset);
}
if (maxOffset === void 0) {
return rawOffset;
}
const normalOffset = rawOffset;
const invertedOffset = maxOffset - rawOffset;
if (!Number.isFinite(invertedOffset)) {
state.horizontalRTLScrollType = "normal";
return normalOffset;
}
const previousMode = state.horizontalRTLScrollType;
if (previousMode === "inverted") {
return clampHorizontalOffset(invertedOffset, maxOffset);
}
if (previousMode === "normal") {
return clampHorizontalOffset(normalOffset, maxOffset);
}
if (!state.hasScrolled) {
const defaultMode = getDefaultHorizontalRTLScrollType();
state.horizontalRTLScrollType = defaultMode;
return clampHorizontalOffset(defaultMode === "inverted" ? invertedOffset : normalOffset, maxOffset);
}
const referenceScroll = state.scroll;
const distanceNormal = Math.abs(normalOffset - referenceScroll);
const distanceInverted = Math.abs(invertedOffset - referenceScroll);
const useInverted = distanceInverted + 0.5 < distanceNormal;
state.horizontalRTLScrollType = useInverted ? "inverted" : "normal";
return clampHorizontalOffset(useInverted ? invertedOffset : normalOffset, maxOffset);
}
var createAnimatedValue = (value) => new Animated.Value(value);
// src/state/state.tsx
var ContextState = React2.createContext(null);
var contextNum = 0;
function StateProvider({ children }) {
const [value] = React2.useState(() => ({
animatedScrollY: createAnimatedValue(0),
columnWrapperStyle: void 0,
contextNum: contextNum++,
listeners: /* @__PURE__ */ new Map(),
mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
mapViewabilityValues: /* @__PURE__ */ new Map(),
positionListeners: /* @__PURE__ */ new Map(),
state: void 0,
values: /* @__PURE__ */ new Map([
["stylePaddingTop", 0],
["headerSize", 0],
["numContainers", 0],
["activeStickyIndex", -1],
["isAtEnd", false],
["isAtStart", false],
["isNearEnd", false],
["isNearStart", false],
["isWithinMaintainScrollAtEndThreshold", false],
["totalSize", 0],
["scrollAdjustPending", 0]
]),
viewRefs: /* @__PURE__ */ new Map()
}));
return /* @__PURE__ */ React2.createElement(ContextState.Provider, { value }, children);
}
function useStateContext() {
return React2.useContext(ContextState);
}
function createSelectorFunctionsArr(ctx, signalNames) {
let lastValues = [];
let lastSignalValues = [];
return {
get: () => {
const currentValues = [];
let hasChanged = false;
for (let i = 0; i < signalNames.length; i++) {
const value = peek$(ctx, signalNames[i]);
currentValues.push(value);
if (value !== lastSignalValues[i]) {
hasChanged = true;
}
}
lastSignalValues = currentValues;
if (hasChanged) {
lastValues = currentValues;
}
return lastValues;
},
subscribe: (cb) => {
const listeners = [];
for (const signalName of signalNames) {
listeners.push(listen$(ctx, signalName, cb));
}
return () => {
for (const listener of listeners) {
listener();
}
};
}
};
}
function listen$(ctx, signalName, cb) {
const { listeners } = ctx;
let setListeners = listeners.get(signalName);
if (!setListeners) {
setListeners = /* @__PURE__ */ new Set();
listeners.set(signalName, setListeners);
}
setListeners.add(cb);
return () => setListeners.delete(cb);
}
function peek$(ctx, signalName) {
const { values } = ctx;
return values.get(signalName);
}
function set$(ctx, signalName, value) {
const { listeners, values } = ctx;
if (values.get(signalName) !== value) {
values.set(signalName, value);
const setListeners = listeners.get(signalName);
if (setListeners) {
for (const listener of setListeners) {
listener(value);
}
}
}
}
function listenPosition$(ctx, key, cb) {
const { positionListeners } = ctx;
let setListeners = positionListeners.get(key);
if (!setListeners) {
setListeners = /* @__PURE__ */ new Set();
positionListeners.set(key, setListeners);
}
setListeners.add(cb);
return () => setListeners.delete(cb);
}
function notifyPosition$(ctx, key, value) {
const { positionListeners } = ctx;
const setListeners = positionListeners.get(key);
if (setListeners) {
for (const listener of setListeners) {
listener(value);
}
}
}
function useArr$(signalNames) {
const ctx = React2.useContext(ContextState);
const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
const value = useSyncExternalStore(subscribe, get, get);
return value;
}
function useSelector$(signalName, selector) {
const ctx = React2.useContext(ContextState);
const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
const getSelectedValue = React2.useCallback(() => selector(get()[0]), [get, selector]);
const value = useSyncExternalStore(subscribe, getSelectedValue, getSelectedValue);
return value;
}
// src/state/getContentInsetEnd.ts
function getContentInsetEndAdjustmentEnd(adjustment) {
return Math.max(0, adjustment != null ? adjustment : 0);
}
function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
var _a3, _b;
const state = ctx.state;
const { props } = state;
const horizontal = props.horizontal;
const contentInset = props.contentInset;
const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
const baseEndInset = (horizontal ? getHorizontalInsetEnd(state, baseInset) : baseInset == null ? void 0 : baseInset.bottom) || 0;
const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
);
const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
if (overrideInset) {
const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
return Math.max(
((horizontal ? getHorizontalInsetEnd(state, mergedInset) : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
anchoredEndInset
);
}
return Math.max(adjustedBaseEndInset, anchoredEndInset);
}
// src/state/getContentSize.ts
function getContentSize(ctx) {
var _a3;
const { values, state } = ctx;
const stylePaddingTop = values.get("stylePaddingTop") || 0;
const stylePaddingBottom = state.props.stylePaddingBottom || 0;
const headerSize = values.get("headerSize") || 0;
const footerSize = values.get("footerSize") || 0;
const contentInsetBottom = getContentInsetEnd(ctx);
const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
}
// src/components/DebugView.tsx
var DebugRow = ({ children }) => {
return /* @__PURE__ */ React2.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
};
React2.memo(function DebugView2() {
const ctx = useStateContext();
const [
totalSize = 0,
scrollAdjust = 0,
rawScroll = 0,
scroll = 0,
_numContainers = 0,
_numContainersPooled = 0,
isAtEnd = false
] = useArr$([
"totalSize",
"scrollAdjust",
"debugRawScroll",
"debugComputedScroll",
"numContainers",
"numContainersPooled",
"isAtEnd"
]);
const contentSize = getContentSize(ctx);
const [, forceUpdate] = useReducer((x) => x + 1, 0);
useInterval(() => {
forceUpdate();
}, 100);
return /* @__PURE__ */ React2.createElement(
View,
{
pointerEvents: "none",
style: {
// height: 100,
backgroundColor: "#FFFFFFCC",
borderRadius: 4,
padding: 4,
paddingBottom: 4,
paddingLeft: 4,
position: "absolute",
right: 0,
top: 0
}
},
/* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2.createElement(Text, null, totalSize.toFixed(2))),
/* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2.createElement(Text, null, contentSize.toFixed(2))),
/* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(isAtEnd))),
/* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
/* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React2.createElement(Text, null, rawScroll.toFixed(2))),
/* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React2.createElement(Text, null, scroll.toFixed(2)))
);
});
function useInterval(callback, delay) {
useEffect(() => {
const interval = setInterval(callback, delay);
return () => clearInterval(interval);
}, [delay]);
}
// src/components/stickyPositionUtils.ts
function getStickyPushLimit(state, index, itemKey) {
if (!itemKey) {
return void 0;
}
const currentSize = state.sizes.get(itemKey);
if (!(currentSize && currentSize > 0)) {
return void 0;
}
const stickyIndexInArray = state.props.stickyHeaderIndicesArr.indexOf(index);
if (stickyIndexInArray === -1) {
return void 0;
}
const nextStickyIndex = state.props.stickyHeaderIndicesArr[stickyIndexInArray + 1];
if (nextStickyIndex === void 0) {
return void 0;
}
const nextStickyPosition = state.positions[nextStickyIndex];
if (nextStickyPosition === void 0) {
return void 0;
}
return nextStickyPosition - currentSize;
}
// src/utils/devEnvironment.ts
var metroDev = typeof __DEV__ !== "undefined" ? __DEV__ : void 0;
var _a;
var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
var _a2;
var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
// src/constants.ts
var POSITION_OUT_OF_VIEW = -1e7;
var EDGE_POSITION_EPSILON = 1;
var ENABLE_DEVMODE = IS_DEV && false;
var ENABLE_DEBUG_VIEW = IS_DEV && false;
// src/constants-platform.native.ts
var f = global.nativeFabricUIManager;
var IsNewArchitecture = f !== void 0 && f != null;
var useAnimatedValue = (initialValue) => {
const [animAnimatedValue] = useState(() => new Animated.Value(initialValue));
return animAnimatedValue;
};
// src/hooks/useValue$.ts
function useValue$(key, params) {
const { getValue } = params || {};
const ctx = useStateContext();
const getNewValue = () => {
var _a3;
return (_a3 = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a3 : 0;
};
const animValue = useAnimatedValue(getNewValue());
useLayoutEffect(() => {
const syncCurrentValue = () => {
animValue.setValue(getNewValue());
};
const unsubscribe = listen$(ctx, key, syncCurrentValue);
syncCurrentValue();
return unsubscribe;
}, [animValue, ctx, key]);
return animValue;
}
var typedForwardRef = React2.forwardRef;
var typedMemo = React2.memo;
var getComponent = (Component) => {
if (React2.isValidElement(Component)) {
return Component;
}
if (Component) {
return /* @__PURE__ */ React2.createElement(Component, null);
}
return null;
};
// src/components/PositionView.native.tsx
var PositionViewState = typedMemo(function PositionViewState2({
id,
horizontal,
style,
refView,
...rest
}) {
const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([`containerPosition${id}`, `containerItemKey${id}`]);
return /* @__PURE__ */ React2.createElement(View$1, { ref: refView, style: [style, horizontal ? { left: position } : { top: position }], ...rest });
});
var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
id,
horizontal,
style,
refView,
...rest
}) {
const position$ = useValue$(`containerPosition${id}`, {
getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
});
const position = horizontal ? { left: position$ } : { top: position$ };
return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: [style, position], ...rest });
});
var PositionViewSticky = typedMemo(function PositionViewSticky2({
id,
horizontal,
style,
refView,
animatedScrollY,
index,
stickyHeaderConfig,
children,
...rest
}) {
const ctx = useStateContext();
const [position = POSITION_OUT_OF_VIEW, headerSize = 0, stylePaddingTop = 0, itemKey, _totalSize = 0] = useArr$([
`containerPosition${id}`,
"headerSize",
"stylePaddingTop",
`containerItemKey${id}`,
"totalSize"
]);
const pushLimit = React2.useMemo(
() => getStickyPushLimit(ctx.state, index, itemKey),
[ctx.state, index, itemKey, _totalSize]
);
const transform = React2.useMemo(() => {
var _a3;
if (animatedScrollY) {
const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
const stickyStart = position + headerSize + stylePaddingTop - stickyConfigOffset;
let nextStickyPosition;
if (pushLimit !== void 0) {
if (pushLimit <= position) {
nextStickyPosition = pushLimit;
} else {
nextStickyPosition = animatedScrollY.interpolate({
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
inputRange: [stickyStart, stickyStart + (pushLimit - position)],
outputRange: [position, pushLimit]
});
}
} else {
nextStickyPosition = animatedScrollY.interpolate({
extrapolateLeft: "clamp",
extrapolateRight: "extend",
inputRange: [stickyStart, stickyStart + 5e3],
outputRange: [position, position + 5e3]
});
}
return horizontal ? [{ translateX: nextStickyPosition }] : [{ translateY: nextStickyPosition }];
}
}, [animatedScrollY, headerSize, position, pushLimit, stylePaddingTop, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
const viewStyle = React2.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
const renderStickyHeaderBackdrop = React2.useMemo(() => {
if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
return null;
}
return /* @__PURE__ */ React2.createElement(
View$1,
{
style: {
inset: 0,
pointerEvents: "none",
position: "absolute"
}
},
getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
);
}, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
});
var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
function useInit(cb) {
useState(() => cb());
}
// src/utils/helpers.ts
function isFunction(obj) {
return typeof obj === "function";
}
function isArray(obj) {
return Array.isArray(obj);
}
var warned = /* @__PURE__ */ new Set();
function warnDevOnce(id, text) {
if (IS_DEV && !warned.has(id)) {
warned.add(id);
console.warn(`[legend-list] ${text}`);
}
}
function roundSize(size) {
return Math.floor(size * 8) / 8;
}
function isNullOrUndefined(value) {
return value === null || value === void 0;
}
function comparatorDefault(a, b) {
return a - b;
}
function getPadding(s, type) {
var _a3, _b, _c;
const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
}
function extractPadding(style, contentContainerStyle, type) {
return getPadding(style, type) + getPadding(contentContainerStyle, type);
}
function findContainerId(ctx, key) {
var _a3, _b;
const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
if (directMatch !== void 0) {
return directMatch;
}
const numContainers = peek$(ctx, "numContainers");
for (let i = 0; i < numContainers; i++) {
const itemKey = peek$(ctx, `containerItemKey${i}`);
if (itemKey === key) {
return i;
}
}
return -1;
}
// src/state/ContextContainer.ts
var ContextContainer = createContext(null);
function useContextContainer() {
return useContext(ContextContainer);
}
function useViewability(callback, configId) {
const ctx = useStateContext();
const containerContext = useContextContainer();
useInit(() => {
if (!containerContext) {
return;
}
const { containerId } = containerContext;
const key = containerId + (configId != null ? configId : "");
const value = ctx.mapViewabilityValues.get(key);
if (value) {
callback(value);
}
});
useEffect(() => {
if (!containerContext) {
return;
}
const { containerId } = containerContext;
const key = containerId + (configId != null ? configId : "");
ctx.mapViewabilityCallbacks.set(key, callback);
return () => {
ctx.mapViewabilityCallbacks.delete(key);
};
}, [ctx, callback, configId, containerContext]);
}
function useViewabilityAmount(callback) {
const ctx = useStateContext();
const containerContext = useContextContainer();
useInit(() => {
if (!containerContext) {
return;
}
const { containerId } = containerContext;
const value = ctx.mapViewabilityAmountValues.get(containerId);
if (value) {
callback(value);
}
});
useEffect(() => {
if (!containerContext) {
return;
}
const { containerId } = containerContext;
ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
return () => {
ctx.mapViewabilityAmountCallbacks.delete(containerId);
};
}, [ctx, callback, containerContext]);
}
function useRecyclingEffect(effect) {
const containerContext = useContextContainer();
const prevValues = useRef({
prevIndex: void 0,
prevItem: void 0
});
useEffect(() => {
if (!containerContext) {
return;
}
const { index, value } = containerContext;
let ret;
if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
ret = effect({
index,
item: value,
prevIndex: prevValues.current.prevIndex,
prevItem: prevValues.current.prevItem
});
}
prevValues.current = {
prevIndex: index,
prevItem: value
};
return ret;
}, [effect, containerContext]);
}
function useRecyclingState(valueOrFun) {
var _a3, _b;
const containerContext = useContextContainer();
const computeValue = (ctx) => {
if (isFunction(valueOrFun)) {
const initializer = valueOrFun;
return ctx ? initializer({
index: ctx.index,
item: ctx.value,
prevIndex: void 0,
prevItem: void 0
}) : initializer();
}
return valueOrFun;
};
const [stateValue, setStateValue] = useState(() => {
return computeValue(containerContext);
});
const prevItemKeyRef = useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
prevItemKeyRef.current = currentItemKey;
setStateValue(computeValue(containerContext));
}
const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
const setState = useCallback(
(newState) => {
if (!triggerLayout) {
return;
}
setStateValue((prevValue) => {
return isFunction(newState) ? newState(prevValue) : newState;
});
triggerLayout();
},
[triggerLayout]
);
return [stateValue, setState];
}
function useIsLastItem() {
const containerContext = useContextContainer();
const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
if (containerContext) {
const { itemKey } = containerContext;
if (!isNullOrUndefined(itemKey)) {
return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
}
}
return false;
});
return isLast;
}
function useListScrollSize() {
const [scrollSize] = useArr$(["scrollSize"]);
return scrollSize;
}
var noop = () => {
};
function useSyncLayout() {
const containerContext = useContextContainer();
if (IsNewArchitecture && containerContext) {
const { triggerLayout: syncLayout } = containerContext;
return syncLayout;
} else {
return noop;
}
}
// src/components/Separator.tsx
function Separator({ ItemSeparatorComponent, leadingItem }) {
const isLastItem = useIsLastItem();
return isLastItem ? null : /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem });
}
function useOnLayoutSync({
ref,
onLayoutProp,
onLayoutChange
}, deps = []) {
const lastLayoutRef = useRef(null);
const onLayout = useCallback(
(event) => {
var _a3, _b;
const { layout } = event.nativeEvent;
if (layout.height !== ((_a3 = lastLayoutRef.current) == null ? void 0 : _a3.height) || layout.width !== ((_b = lastLayoutRef.current) == null ? void 0 : _b.width)) {
onLayoutChange(layout, false);
lastLayoutRef.current = layout;
}
onLayoutProp == null ? void 0 : onLayoutProp(event);
},
[onLayoutChange, onLayoutProp]
);
if (IsNewArchitecture) {
useLayoutEffect(() => {
if (ref.current) {
ref.current.measure((x, y, width, height) => {
const layout = { height, width, x, y };
lastLayoutRef.current = layout;
onLayoutChange(layout, true);
});
}
}, deps);
}
return { onLayout };
}
// src/utils/isInMVCPActiveMode.native.ts
function isInMVCPActiveMode(state) {
return state.dataChangeNeedsScrollUpdate;
}
// src/components/Container.tsx
function getContainerPositionStyle({
columnWrapperStyle,
horizontal,
hasItemSeparator,
isHorizontalRTLList,
numColumns,
otherAxisPos,
otherAxisSize
}) {
let paddingStyles;
if (columnWrapperStyle) {
const { columnGap, rowGap, gap } = columnWrapperStyle;
if (horizontal) {
paddingStyles = {
paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
paddingRight: columnGap || gap || void 0,
paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
};
} else {
paddingStyles = {
paddingBottom: rowGap || gap || void 0,
paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
};
}
}
return horizontal ? {
boxSizing: paddingStyles ? "border-box" : void 0,
direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
flexDirection: hasItemSeparator ? "row" : void 0,
height: otherAxisSize,
left: 0,
position: "absolute",
top: otherAxisPos,
...paddingStyles || {}
} : {
boxSizing: paddingStyles ? "border-box" : void 0,
left: otherAxisPos,
position: "absolute",
right: numColumns > 1 ? null : 0,
top: 0,
width: otherAxisSize,
...paddingStyles || {}
};
}
var Container = typedMemo(function Container2({
id,
itemKey,
recycleItems,
horizontal,
getRenderedItem: getRenderedItem2,
updateItemSize: updateItemSize2,
ItemSeparatorComponent,
stickyHeaderConfig
}) {
const ctx = useStateContext();
const { columnWrapperStyle, animatedScrollY } = ctx;
const isHorizontalRTLList = isHorizontalRTL(ctx.state);
const positionComponentInternal = ctx.state.props.positionComponentInternal;
const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
`containerColumn${id}`,
`containerSpan${id}`,
`containerItemData${id}`,
"numColumns",
"extraData",
`containerSticky${id}`
]);
const itemLayoutRef = useRef({
didLayout: false,
horizontal,
itemKey,
pendingShrinkToken: 0,
updateItemSize: updateItemSize2
});
itemLayoutRef.current.horizontal = horizontal;
itemLayoutRef.current.itemKey = itemKey;
itemLayoutRef.current.updateItemSize = updateItemSize2;
const ref = useRef(null);
const [layoutRenderCount, forceLayoutRender] = useState(0);
const resolvedColumn = column > 0 ? column : 1;
const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
const otherAxisSize = numColumns > 1 ? `${resolvedSpan / numColumns * 100}%` : void 0;
const style = useMemo(
() => getContainerPositionStyle({
columnWrapperStyle,
hasItemSeparator: !!ItemSeparatorComponent,
horizontal,
isHorizontalRTLList,
numColumns,
otherAxisPos,
otherAxisSize
}),
[
horizontal,
isHorizontalRTLList,
otherAxisPos,
otherAxisSize,
columnWrapperStyle,
numColumns,
ItemSeparatorComponent
]
);
const renderedItemInfo = useMemo(
() => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
[itemKey, data, extraData]
);
const { index, renderedItem } = renderedItemInfo || {};
const contextValue = useMemo(() => {
ctx.viewRefs.set(id, ref);
return {
containerId: id,
index,
itemKey,
triggerLayout: () => {
forceLayoutRender((v) => v + 1);
},
value: data
};
}, [id, itemKey, index, data]);
const onLayoutChange = useCallback((rectangle) => {
var _a3, _b;
const {
horizontal: currentHorizontal,
itemKey: currentItemKey,
updateItemSize: updateItemSizeFn,
lastSize,
pendingShrinkToken
} = itemLayoutRef.current;
if (isNullOrUndefined(currentItemKey)) {
return;
}
itemLayoutRef.current.didLayout = true;
let layout = rectangle;
const axis = currentHorizontal ? "width" : "height";
const size = roundSize(rectangle[axis]);
const prevSize = lastSize ? roundSize(lastSize[axis]) : void 0;
const doUpdate = () => {
itemLayoutRef.current.lastSize = layout;
updateItemSizeFn(currentItemKey, layout);
itemLayoutRef.current.didLayout = true;
};
const shouldDeferWebShrinkLayoutUpdate = Platform.OS === "web" && !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
if (shouldDeferWebShrinkLayoutUpdate) {
const token = pendingShrinkToken + 1;
itemLayoutRef.current.pendingShrinkToken = token;
requestAnimationFrame(() => {
var _a4;
if (itemLayoutRef.current.pendingShrinkToken !== token) {
return;
}
const element = ref.current;
const rect = (_a4 = element == null ? void 0 : element.getBoundingClientRect) == null ? void 0 : _a4.call(element);
if (rect) {
layout = { height: rect.height, width: rect.width };
}
doUpdate();
});
return;
}
if (IsNewArchitecture || size > 0) {
doUpdate();
} else {
(_b = (_a3 = ref.current) == null ? void 0 : _a3.measure) == null ? void 0 : _b.call(_a3, (_x, _y, width, height) => {
layout = { height, width };
doUpdate();
});
}
}, []);
const { onLayout } = useOnLayoutSync(
{
onLayoutChange,
ref},
[itemKey, layoutRenderCount]
);
if (!IsNewArchitecture) {
useEffect(() => {
if (!isNullOrUndefined(itemKey)) {
itemLayoutRef.current.didLayout = false;
const timeout = setTimeout(() => {
if (!itemLayoutRef.current.didLayout) {
const {
itemKey: currentItemKey,
lastSize,
updateItemSize: updateItemSizeFn
} = itemLayoutRef.current;
if (lastSize && !isNullOrUndefined(currentItemKey)) {
updateItemSizeFn(currentItemKey, lastSize);
itemLayoutRef.current.didLayout = true;
}
}
}, 16);
return () => {
clearTimeout(timeout);
};
}
}, [itemKey]);
}
const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : positionComponentInternal ? positionComponentInternal : PositionView;
return /* @__PURE__ */ React2.createElement(
PositionComponent,
{
animatedScrollY: isSticky ? animatedScrollY : void 0,
horizontal,
id,
index,
key: recycleItems ? void 0 : itemKey,
onLayout,
refView: ref,
stickyHeaderConfig,
style
},
/* @__PURE__ */ React2.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React2.createElement(Separator, { ItemSeparatorComponent, leadingItem: renderedItemInfo.item }))
);
});
// src/components/ContainerSlot.tsx
function ContainerSlotBase({
id,
horizontal,
recycleItems,
ItemSeparatorComponent,
updateItemSize: updateItemSize2,
getRenderedItem: getRenderedItem2,
stickyHeaderConfig,
ContainerComponent = Container
}) {
const [itemKey] = useArr$([`containerItemKey${id}`]);
if (itemKey === void 0) {
return null;
}
return /* @__PURE__ */ React2.createElement(
ContainerComponent,
{
getRenderedItem: getRenderedItem2,
horizontal,
ItemSeparatorComponent,
id,
itemKey,
recycleItems,
stickyHeaderConfig,
updateItemSize: updateItemSize2
}
);
}
var ContainerSlot = typedMemo(function ContainerSlot2(props) {
return /* @__PURE__ */ React2.createElement(ContainerSlotBase, { ...props });
});
// src/components/Containers.native.tsx
var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal }) {
const ctx = useStateContext();
const columnWrapperStyle = ctx.columnWrapperStyle;
const animSize = useValue$("totalSize");
const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
const style = horizontal ? {
height: otherAxisSize || "100%",
minHeight: otherAxisSize,
opacity: readyToRender ? 1 : 0,
width: animSize
} : { height: animSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0 };
if (columnWrapperStyle) {
const { columnGap, rowGap, gap } = columnWrapperStyle;
const gapX = columnGap || gap || 0;
const gapY = rowGap || gap || 0;
if (horizontal) {
if (gapY && numColumns > 1) {
style.marginVertical = -gapY / 2;
}
if (gapX) {
style.marginRight = -gapX;
}
} else {
if (gapX && numColumns > 1) {
style.marginHorizontal = -gapX;
}
if (gapY) {
style.marginBottom = -gapY;
}
}
}
return /* @__PURE__ */ React2.createElement(Animated.View, { style }, children);
});
var Containers = typedMemo(function Containers2({
horizontal,
recycleItems,
ItemSeparatorComponent,
stickyHeaderConfig,
updateItemSize: updateItemSize2,
getRenderedItem: getRenderedItem2
}) {
const [numContainersPooled] = useArr$(["numContainersPooled"]);
const containers = [];
for (let i = 0; i < numContainersPooled; i++) {
containers.push(
/* @__PURE__ */ React2.createElement(
ContainerSlot,
{
getRenderedItem: getRenderedItem2,
horizontal,
ItemSeparatorComponent,
id: i,
key: i,
recycleItems,
stickyHeaderConfig,
updateItemSize: updateItemSize2
}
)
);
}
return /* @__PURE__ */ React2.createElement(ContainersLayer, { horizontal }, containers);
});
var ListComponentScrollView = Animated.ScrollView;
// src/components/listComponentStyles.ts
function getAutoOtherAxisStyle({
horizontal,
needsOtherAxisSize,
otherAxisSize
}) {
if (!needsOtherAxisSize || !otherAxisSize || otherAxisSize <= 0) {
return void 0;
}
return horizontal ? { height: otherAxisSize } : { width: otherAxisSize };
}
function ScrollAdjust() {
var _a3;
const ctx = useStateContext();
const bias = 1e7;
const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
const horizontal = !!((_a3 = ctx.state) == null ? void 0 : _a3.props.horizontal);
return /* @__PURE__ */ React2.createElement(
View$1,
{
style: {
height: 0,
left: horizontal ? scrollOffset : 0,
position: "absolute",
top: horizontal ? 0 : scrollOffset,
width: 0
}
}
);
}
var SnapWrapper = React2.forwardRef(function SnapWrapperInner({ ScrollComponent, ...props }, ref) {
const [snapToOffsets] = useArr$(["snapToOffsets"]);
return /* @__PURE__ */ React2.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
});
function WebAnchoredEndSpace({ horizontal }) {
const ctx = useStateContext();
const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
const shouldRenderAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && (anchoredEndSpaceSize || 0) > 0;
if (!shouldRenderAnchoredEndSpace) {
return null;
}
const style = horizontal ? { height: "100%", width: anchoredEndSpaceSize || 0 } : { height: anchoredEndSpaceSize || 0 };
return /* @__PURE__ */ React2.createElement("div", { style }, null);
}
function useLatestRef(value) {
const ref = React2.useRef(value);
ref.current = value;
return ref;
}
// src/hooks/useStableRenderComponent.tsx
function useStableRenderComponent(renderComponent, mapProps) {
const renderComponentRef = useLatestRef(renderComponent);
const mapPropsRef = useLatestRef(mapProps);
return React2.useMemo(
() => React2.forwardRef(
(props, ref) => {
var _a3, _b;
return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
}
),
[mapPropsRef, renderComponentRef]
);
}
var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
const localRef = useRef(null);
const ref = refView != null ? refView : localRef;
const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
};
// src/components/ListComponent.tsx
var ListComponent = typedMemo(function ListComponent2({
canRender,
style,
contentContainerStyle,
horizontal,
initialContentOffset,
recycleItems,
ItemSeparatorComponent,
alignItemsAtEnd: _alignItemsAtEnd,
onScroll: onScroll2,
onLayout,
ListHeaderComponent,
ListHeaderComponentStyle,
ListFooterComponent,
ListFooterComponentStyle,
ListEmptyComponent,
getRenderedItem: getRenderedItem2,
updateItemSize: updateItemSize2,
refScrollView,
renderScrollComponent,
onLayoutFooter,
scrollAdjustHandler,
snapToIndices,
stickyHeaderConfig,
stickyHeaderIndices,
useWindowScroll = false,
...rest
}) {
const ctx = useStateContext();
const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
const autoOtherAxisStyle = getAutoOtherAxisStyle({
horizontal,
needsOtherAxisSize: ctx.state.needsOtherAxisSize,
otherAxisSize
});
const CustomScrollComponent = useStableRenderComponent(
renderScrollComponent,
(props, ref) => ({ ...props, ref })
);
const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
useLayoutEffect(() => {
if (!ListHeaderComponent) {
set$(ctx, "headerSize", 0);
}
if (!ListFooterComponent) {
set$(ctx, "footerSize", 0);
}
}, [ListHeaderComponent, ListFooterComponent, ctx]);
const onLayoutHeader = useCallback(
(rect) => {
const size = rect[horizontal ? "width" : "height"];
set$(ctx, "headerSize", size);
},
[ctx, horizontal]
);
const onLayoutFooterInternal = useCallback(
(rect, fromLayoutEffect) => {
const size = rect[horizontal ? "width" : "height"];
set$(ctx, "footerSize", size);
onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
},
[ctx, horizontal, onLayoutFooter]
);
return /* @__PURE__ */ React2.createElement(
SnapOrScroll,
{
...rest,
...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
contentContainerStyle: [
horizontal ? {
height: "100%"
} : {},
contentContainerStyle
],
contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
horizontal,
maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
onLayout,
onScroll: onScroll2,
ref: refScrollView,
ScrollComponent: snapToIndices ? ScrollComponent : void 0,
style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
},
/* @__PURE__ */ React2.createElement(ScrollAdjust, null),
ListHeaderComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
ListEmptyComponent && getComponent(ListEmptyComponent),
canRender && !ListEmptyComponent && /* @__PURE__ */ React2.createElement(
Containers,
{
getRenderedItem: getRenderedItem2,
horizontal,
ItemSeparatorComponent,
recycleItems,
stickyHeaderConfig,
updateItemSize: updateItemSize2
}
),
ListFooterComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
Platform.OS === "web" && /* @__PURE__ */ React2.createElement(WebAnchoredEndSpace, { horizontal }),
IS_DEV && ENABLE_DEVMODE
);
});
var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
function useDevChecksImpl(props) {
const ctx = useStateContext();
const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
useEffect(() => {
if (useWindowScroll && renderScrollComponent) {
warnDevOnce(
"useWindowScrollRenderScrollComponent",
"useWindowScroll is not supported when renderScrollComponent is provided."
);
}
}, [renderScrollComponent, useWindowScroll]);
useEffect(() => {
if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
warnDevOnce(
"keyExtractor",
"Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
);
}
}, [childrenMode, ctx, keyExtractor]);
useEffect(() => {
const state = ctx.state;
const dataLength = state.props.data.length;
const useWindowScrollResolved = state.props.useWindowScroll;
if (Platform.OS !== "web" || useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
return;
}
const warnIfUnboundedOuterSize = () => {
const readyToRender = peek$(ctx, "readyToRender");
const numContainers = peek$(ctx, "numContainers") || 0;
const totalSize = peek$(ctx, "totalSize") || 0;
const scrollLength = ctx.state.scrollLength || 0;
if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
return;
}
const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
if (rendersAlmostEverything && viewportMatchesContent) {
warnDevOnce(
"webUnboundedOuterSize",
"LegendList appears to have an unbounded outer height on web, so virtualization is effectively disabled. Set a bounded height or flex: 1 on the list container, or use useWindowScroll."
);
}
};
warnIfUnboundedOuterSize();
const unsubscribe = [
listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
];
return () => {
for (const unsub of unsubscribe) {
unsub();
}
};
}, [ctx]);
}
function useDevChecksNoop(_props) {
}
var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
// src/core/deferredPublicOnScroll.ts
function withResolvedContentOffset(state, event, resolvedOffset) {
return {
...event,
nativeEvent: {
...event.nativeEvent,
contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
}
};
}
function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
var _a3, _b, _c, _d;
const state = ctx.state;
const deferredEvent = state.deferredPublicOnScrollEvent;
state.deferredPublicOnScrollEvent = void 0;
if (deferredEvent) {
(_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
_c,
withResolvedContentOffset(
state,
deferredEvent,
(_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
)
);
}
}
// src/core/initialScrollSession.ts
var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
function hasInitialScrollSessionCompletion(completion) {
return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
}
function clearInitialScrollSession(state) {
state.initialScrollSession = void 0;
return void 0;
}
function createInitialScrollSession(options) {
const { bootstrap, completion, kind, previousDataLength } = options;
return kind === "offset" ? {
completion,
kind,
previousDataLength
} : {
bootstrap,
completion,
kind,
previousDataLength
};
}
function ensureInitialScrollSessionCompletion(state, kind = ((_b) => (_b = ((_a3) => (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind)()) != null ? _b : "bootstrap")()) {
var _a4, _b2;
if (!state.initialScrollSession) {
state.initialScrollSession = createInitialScrollSession({
completion: {},
kind,
previousDataLength: 0
});
} else if (state.initialScrollSession.kind !== kind) {
state.initialScrollSession = createInitialScrollSession({
bootstrap: state.initialScrollSession.kind === "bootstrap" ? state.initialScrollSession.bootstrap : void 0,
completion: state.initialScrollSession.completion,
kind,
previousDataLength: state.initialScrollSession.previousDataLength
});
}
(_b2 = (_a4 = state.initialScrollSession).completion) != null ? _b2 : _a4.completion = {};
return state.initialScrollSession.completion;
}
var initialScrollCompletion = {
didDispatchNativeScroll(state) {
var _a3, _b;
return !!((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.didDispatchNativeScroll);
},
didRetrySilentInitialScroll(state) {
var _a3, _b;
return !!((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.didRetrySilentInitialScroll);
},
markInitialScrollNativeDispatch(state) {
ensureInitialScrollSessionCompletion(state).didDispatchNativeScroll = true;
},
markSilentInitialScrollRetry(state) {
ensureInitialScrollSessionCompletion(state).didRetrySilentInitialScroll = true;
},
resetFlags(state) {
if (!state.initialScrollSession) {
return;
}
const completion = ensureInitialScrollSessionCompletion(state, state.initialScrollSession.kind);
completion.didDispatchNativeScroll = void 0;
completion.didRetrySilentInitialScroll = void 0;
}
};
var initialScrollWatchdog = {
clear(state) {
initialScrollWatchdog.set(state, void 0);
},
didReachTarget(newScroll, watchdog) {
const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
return nextDistance <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
},
get(state) {
var _a3, _b;
return (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.watchdog;
},
hasNonZeroTargetOffset(targetOffset) {
return targetOffset !== void 0 && targetOffset > INITIAL_SCROLL_MIN_TARGET_OFFSET;
},
isAtZeroTargetOffset(targetOffset) {
return targetOffset <= INITIAL_SCROLL_MIN_TARGET_OFFSET;
},
set(state, watchdog) {
var _a3, _b;
if (!watchdog && !((_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.completion) == null ? void 0 : _b.watchdog)) {
return;
}
const completion = ensureInitialScrollSessionCompletion(state);
completion.watchdog = watchdog ? {
startScrol