@legendapp/list 3.0.0-beta.37 → 3.0.0-beta.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.native.js CHANGED
@@ -342,7 +342,7 @@ function useValue$(key, params) {
342
342
  }, []);
343
343
  return animValue;
344
344
  }
345
- var typedMemo = React2.memo;
345
+ var typedMemo = React2__namespace.memo;
346
346
  var getComponent = (Component) => {
347
347
  if (React2__namespace.isValidElement(Component)) {
348
348
  return Component;
@@ -634,8 +634,8 @@ function useOnLayoutSync({
634
634
  }
635
635
  var Platform2 = ReactNative.Platform;
636
636
  var PlatformAdjustBreaksScroll = Platform2.OS === "android";
637
- var typedForwardRef = React2.forwardRef;
638
- var typedMemo2 = React2.memo;
637
+ var typedForwardRef = React2__namespace.forwardRef;
638
+ var typedMemo2 = React2__namespace.memo;
639
639
 
640
640
  // src/utils/isInMVCPActiveMode.native.ts
641
641
  function isInMVCPActiveMode(state) {
@@ -836,7 +836,6 @@ var Containers = typedMemo(function Containers2({
836
836
  updateItemSize: updateItemSize2,
837
837
  getRenderedItem: getRenderedItem2
838
838
  }) {
839
- var _a3;
840
839
  const ctx = useStateContext();
841
840
  const columnWrapperStyle = ctx.columnWrapperStyle;
842
841
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
@@ -844,13 +843,11 @@ var Containers = typedMemo(function Containers2({
844
843
  // Use a microtask if increasing the size significantly, otherwise use a timeout
845
844
  // If this is the initial scroll, we don't want to delay because we want to update the size immediately
846
845
  delay: (value, prevValue) => {
847
- var _a4;
848
- return !((_a4 = ctx.state) == null ? void 0 : _a4.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
846
+ var _a3;
847
+ return !((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
849
848
  }
850
849
  });
851
- const readyToRenderOpacity = useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 });
852
- const shouldWaitForReadyToRender = !!waitForInitialLayout && (!IsNewArchitecture || !!((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll));
853
- const animOpacity = shouldWaitForReadyToRender ? readyToRenderOpacity : void 0;
850
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 }) : void 0;
854
851
  const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
855
852
  const containers = [];
856
853
  for (let i = 0; i < numContainers; i++) {
@@ -916,7 +913,7 @@ function SnapWrapper({ ScrollComponent, ...props }) {
916
913
  return /* @__PURE__ */ React2__namespace.createElement(ScrollComponent, { ...props, snapToOffsets });
917
914
  }
918
915
  var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
919
- const ref = refView != null ? refView : React2.useRef();
916
+ const ref = refView != null ? refView : React2.useRef(null);
920
917
  const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
921
918
  return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ...rest, onLayout, ref });
922
919
  };
@@ -1353,7 +1350,6 @@ function finishScrollTo(ctx) {
1353
1350
  state.initialScroll = void 0;
1354
1351
  state.initialAnchor = void 0;
1355
1352
  state.scrollingTo = void 0;
1356
- state.stableTarget = void 0;
1357
1353
  if (state.pendingTotalSize !== void 0) {
1358
1354
  addTotalSize(ctx, null, state.pendingTotalSize);
1359
1355
  }
@@ -1370,14 +1366,6 @@ function finishScrollTo(ctx) {
1370
1366
  }
1371
1367
 
1372
1368
  // src/core/checkFinishedScroll.ts
1373
- function getCurrentTargetOffset(ctx, scrollingTo) {
1374
- if (scrollingTo.index !== void 0) {
1375
- const baseOffset = calculateOffsetForIndex(ctx, scrollingTo.index);
1376
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, scrollingTo);
1377
- return clampScrollOffset(ctx, resolvedOffset, scrollingTo);
1378
- }
1379
- return clampScrollOffset(ctx, scrollingTo.offset, scrollingTo);
1380
- }
1381
1369
  function checkFinishedScroll(ctx) {
1382
1370
  ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1383
1371
  }
@@ -1387,30 +1375,20 @@ function checkFinishedScrollFrame(ctx) {
1387
1375
  const { state } = ctx;
1388
1376
  state.animFrameCheckFinishedScroll = void 0;
1389
1377
  const scroll = state.scrollPending;
1390
- const clampedTargetOffset = getCurrentTargetOffset(ctx, scrollingTo);
1391
- if (Math.abs(scrollingTo.offset - clampedTargetOffset) >= 1) {
1392
- state.scrollingTo = { ...scrollingTo, offset: clampedTargetOffset };
1393
- }
1378
+ const adjust = state.scrollAdjustHandler.getAdjust();
1379
+ const clampedTargetOffset = clampScrollOffset(
1380
+ ctx,
1381
+ scrollingTo.offset - (scrollingTo.viewOffset || 0),
1382
+ scrollingTo
1383
+ );
1394
1384
  const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
1395
1385
  const diff1 = Math.abs(scroll - clampedTargetOffset);
1386
+ const diff2 = Math.abs(diff1 - adjust);
1396
1387
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1397
- const isAtTarget = diff1 < 1;
1398
- const previousStableTarget = state.stableTarget;
1399
- const hasStableTargetFrame = !!previousStableTarget && Math.abs(previousStableTarget.target - clampedTargetOffset) < 1 && Math.abs(previousStableTarget.scroll - scroll) < 1;
1400
- if (isAtTarget && !hasStableTargetFrame) {
1401
- state.stableTarget = { scroll, target: clampedTargetOffset };
1402
- state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1403
- return;
1404
- }
1405
- if (!isAtTarget) {
1406
- state.stableTarget = void 0;
1407
- }
1388
+ const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
1408
1389
  if (isNotOverscrolled && isAtTarget) {
1409
- state.stableTarget = void 0;
1410
1390
  finishScrollTo(ctx);
1411
1391
  }
1412
- } else {
1413
- ctx.state.stableTarget = void 0;
1414
1392
  }
1415
1393
  }
1416
1394
  function checkFinishedScrollFallback(ctx) {
@@ -1476,9 +1454,8 @@ function scrollTo(ctx, params) {
1476
1454
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1477
1455
  offset = clampScrollOffset(ctx, offset, scrollTarget);
1478
1456
  state.scrollHistory.length = 0;
1479
- state.stableTarget = void 0;
1480
1457
  if (!noScrollingTo) {
1481
- state.scrollingTo = { ...scrollTarget, offset };
1458
+ state.scrollingTo = scrollTarget;
1482
1459
  }
1483
1460
  state.scrollPending = offset;
1484
1461
  if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
@@ -3537,20 +3514,69 @@ function createColumnWrapperStyle(contentContainerStyle) {
3537
3514
  }
3538
3515
  }
3539
3516
 
3517
+ // src/utils/hasActiveMVCPAnchorLock.ts
3518
+ function hasActiveMVCPAnchorLock(state) {
3519
+ const lock = state.mvcpAnchorLock;
3520
+ if (!lock) {
3521
+ return false;
3522
+ }
3523
+ if (Date.now() > lock.expiresAt) {
3524
+ state.mvcpAnchorLock = void 0;
3525
+ return false;
3526
+ }
3527
+ return true;
3528
+ }
3529
+
3540
3530
  // src/utils/createImperativeHandle.ts
3541
3531
  function createImperativeHandle(ctx) {
3542
3532
  const state = ctx.state;
3533
+ const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
3534
+ const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
3535
+ let imperativeScrollToken = 0;
3536
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0 || hasActiveMVCPAnchorLock(state);
3537
+ const runWhenSettled = (token, run) => {
3538
+ const startedAt = Date.now();
3539
+ let stableFrames = 0;
3540
+ const check = () => {
3541
+ if (token !== imperativeScrollToken) {
3542
+ return;
3543
+ }
3544
+ if (isSettlingAfterDataChange()) {
3545
+ stableFrames = 0;
3546
+ } else {
3547
+ stableFrames += 1;
3548
+ }
3549
+ const timedOut = Date.now() - startedAt >= IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS;
3550
+ if (stableFrames >= IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES || timedOut) {
3551
+ run();
3552
+ return;
3553
+ }
3554
+ requestAnimationFrame(check);
3555
+ };
3556
+ requestAnimationFrame(check);
3557
+ };
3543
3558
  const runScrollWithPromise = (run) => new Promise((resolve) => {
3544
3559
  var _a3;
3560
+ const token = ++imperativeScrollToken;
3545
3561
  (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
3546
3562
  state.pendingScrollResolve = resolve;
3547
- const didStartScroll = run();
3548
- if (!didStartScroll || !state.scrollingTo) {
3549
- if (state.pendingScrollResolve === resolve) {
3550
- state.pendingScrollResolve = void 0;
3563
+ const runNow = () => {
3564
+ if (token !== imperativeScrollToken) {
3565
+ return;
3566
+ }
3567
+ const didStartScroll = run();
3568
+ if (!didStartScroll || !state.scrollingTo) {
3569
+ if (state.pendingScrollResolve === resolve) {
3570
+ state.pendingScrollResolve = void 0;
3571
+ }
3572
+ resolve();
3551
3573
  }
3552
- resolve();
3574
+ };
3575
+ if (isSettlingAfterDataChange()) {
3576
+ runWhenSettled(token, runNow);
3577
+ return;
3553
3578
  }
3579
+ runNow();
3554
3580
  });
3555
3581
  const scrollIndexIntoView = (options) => {
3556
3582
  if (state) {
@@ -3609,6 +3635,8 @@ function createImperativeHandle(ctx) {
3609
3635
  endBuffered: state.endBuffered,
3610
3636
  isAtEnd: state.isAtEnd,
3611
3637
  isAtStart: state.isAtStart,
3638
+ isEndReached: state.isEndReached,
3639
+ isStartReached: state.isStartReached,
3612
3640
  listen: (signalName, cb) => listen$(ctx, signalName, cb),
3613
3641
  listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3614
3642
  positionAtIndex: (index) => state.positions[index],
@@ -3860,7 +3888,7 @@ var LegendList = typedMemo2(
3860
3888
  })
3861
3889
  );
3862
3890
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3863
- var _a3, _b, _c, _d;
3891
+ var _a3, _b, _c, _d, _e;
3864
3892
  const {
3865
3893
  alignItemsAtEnd = false,
3866
3894
  alwaysRender,
@@ -3989,7 +4017,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3989
4017
  );
3990
4018
  }
3991
4019
  const useWindowScrollResolved = Platform2.OS === "web" && !!useWindowScroll && !renderScrollComponent;
3992
- const refState = React2.useRef();
4020
+ const refState = React2.useRef(void 0);
3993
4021
  const hasOverrideItemLayout = !!overrideItemLayout;
3994
4022
  const prevHasOverrideItemLayout = React2.useRef(hasOverrideItemLayout);
3995
4023
  if (!refState.current) {
@@ -4341,6 +4369,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4341
4369
  []
4342
4370
  );
4343
4371
  const onScrollHandler = useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, fns.onScroll);
4372
+ const refreshControlElement = refreshControl;
4344
4373
  return /* @__PURE__ */ React2__namespace.createElement(React2__namespace.Fragment, null, /* @__PURE__ */ React2__namespace.createElement(
4345
4374
  ListComponent,
4346
4375
  {
@@ -4359,9 +4388,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4359
4388
  onMomentumScrollEnd: fns.onMomentumScrollEnd,
4360
4389
  onScroll: onScrollHandler,
4361
4390
  recycleItems,
4362
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControl, {
4363
- progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
4364
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
4391
+ refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControlElement, {
4392
+ progressViewOffset: ((_d = refreshControlElement.props.progressViewOffset) != null ? _d : 0) + stylePaddingTopState
4393
+ }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
4365
4394
  ReactNative.RefreshControl,
4366
4395
  {
4367
4396
  onRefresh,
@@ -4371,7 +4400,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4371
4400
  ),
4372
4401
  refScrollView: combinedRef,
4373
4402
  renderScrollComponent,
4374
- scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
4403
+ scrollAdjustHandler: (_e = refState.current) == null ? void 0 : _e.scrollAdjustHandler,
4375
4404
  scrollEventThrottle: 0,
4376
4405
  snapToIndices,
4377
4406
  stickyHeaderIndices,
package/index.native.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React2 from 'react';
2
- import React2__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, memo, forwardRef, useContext } from 'react';
2
+ import React2__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useContext } from 'react';
3
3
  import * as ReactNative from 'react-native';
4
4
  import { Animated, View as View$1, Text as Text$1, Platform, StyleSheet as StyleSheet$1, RefreshControl, Dimensions } from 'react-native';
5
5
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
@@ -321,7 +321,7 @@ function useValue$(key, params) {
321
321
  }, []);
322
322
  return animValue;
323
323
  }
324
- var typedMemo = memo;
324
+ var typedMemo = React2.memo;
325
325
  var getComponent = (Component) => {
326
326
  if (React2.isValidElement(Component)) {
327
327
  return Component;
@@ -613,8 +613,8 @@ function useOnLayoutSync({
613
613
  }
614
614
  var Platform2 = Platform;
615
615
  var PlatformAdjustBreaksScroll = Platform2.OS === "android";
616
- var typedForwardRef = forwardRef;
617
- var typedMemo2 = memo;
616
+ var typedForwardRef = React2.forwardRef;
617
+ var typedMemo2 = React2.memo;
618
618
 
619
619
  // src/utils/isInMVCPActiveMode.native.ts
620
620
  function isInMVCPActiveMode(state) {
@@ -815,7 +815,6 @@ var Containers = typedMemo(function Containers2({
815
815
  updateItemSize: updateItemSize2,
816
816
  getRenderedItem: getRenderedItem2
817
817
  }) {
818
- var _a3;
819
818
  const ctx = useStateContext();
820
819
  const columnWrapperStyle = ctx.columnWrapperStyle;
821
820
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
@@ -823,13 +822,11 @@ var Containers = typedMemo(function Containers2({
823
822
  // Use a microtask if increasing the size significantly, otherwise use a timeout
824
823
  // If this is the initial scroll, we don't want to delay because we want to update the size immediately
825
824
  delay: (value, prevValue) => {
826
- var _a4;
827
- return !((_a4 = ctx.state) == null ? void 0 : _a4.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
825
+ var _a3;
826
+ return !((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
828
827
  }
829
828
  });
830
- const readyToRenderOpacity = useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 });
831
- const shouldWaitForReadyToRender = !!waitForInitialLayout && (!IsNewArchitecture || !!((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll));
832
- const animOpacity = shouldWaitForReadyToRender ? readyToRenderOpacity : void 0;
829
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 }) : void 0;
833
830
  const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
834
831
  const containers = [];
835
832
  for (let i = 0; i < numContainers; i++) {
@@ -895,7 +892,7 @@ function SnapWrapper({ ScrollComponent, ...props }) {
895
892
  return /* @__PURE__ */ React2.createElement(ScrollComponent, { ...props, snapToOffsets });
896
893
  }
897
894
  var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
898
- const ref = refView != null ? refView : useRef();
895
+ const ref = refView != null ? refView : useRef(null);
899
896
  const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
900
897
  return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
901
898
  };
@@ -1332,7 +1329,6 @@ function finishScrollTo(ctx) {
1332
1329
  state.initialScroll = void 0;
1333
1330
  state.initialAnchor = void 0;
1334
1331
  state.scrollingTo = void 0;
1335
- state.stableTarget = void 0;
1336
1332
  if (state.pendingTotalSize !== void 0) {
1337
1333
  addTotalSize(ctx, null, state.pendingTotalSize);
1338
1334
  }
@@ -1349,14 +1345,6 @@ function finishScrollTo(ctx) {
1349
1345
  }
1350
1346
 
1351
1347
  // src/core/checkFinishedScroll.ts
1352
- function getCurrentTargetOffset(ctx, scrollingTo) {
1353
- if (scrollingTo.index !== void 0) {
1354
- const baseOffset = calculateOffsetForIndex(ctx, scrollingTo.index);
1355
- const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, scrollingTo);
1356
- return clampScrollOffset(ctx, resolvedOffset, scrollingTo);
1357
- }
1358
- return clampScrollOffset(ctx, scrollingTo.offset, scrollingTo);
1359
- }
1360
1348
  function checkFinishedScroll(ctx) {
1361
1349
  ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1362
1350
  }
@@ -1366,30 +1354,20 @@ function checkFinishedScrollFrame(ctx) {
1366
1354
  const { state } = ctx;
1367
1355
  state.animFrameCheckFinishedScroll = void 0;
1368
1356
  const scroll = state.scrollPending;
1369
- const clampedTargetOffset = getCurrentTargetOffset(ctx, scrollingTo);
1370
- if (Math.abs(scrollingTo.offset - clampedTargetOffset) >= 1) {
1371
- state.scrollingTo = { ...scrollingTo, offset: clampedTargetOffset };
1372
- }
1357
+ const adjust = state.scrollAdjustHandler.getAdjust();
1358
+ const clampedTargetOffset = clampScrollOffset(
1359
+ ctx,
1360
+ scrollingTo.offset - (scrollingTo.viewOffset || 0),
1361
+ scrollingTo
1362
+ );
1373
1363
  const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
1374
1364
  const diff1 = Math.abs(scroll - clampedTargetOffset);
1365
+ const diff2 = Math.abs(diff1 - adjust);
1375
1366
  const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
1376
- const isAtTarget = diff1 < 1;
1377
- const previousStableTarget = state.stableTarget;
1378
- const hasStableTargetFrame = !!previousStableTarget && Math.abs(previousStableTarget.target - clampedTargetOffset) < 1 && Math.abs(previousStableTarget.scroll - scroll) < 1;
1379
- if (isAtTarget && !hasStableTargetFrame) {
1380
- state.stableTarget = { scroll, target: clampedTargetOffset };
1381
- state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1382
- return;
1383
- }
1384
- if (!isAtTarget) {
1385
- state.stableTarget = void 0;
1386
- }
1367
+ const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
1387
1368
  if (isNotOverscrolled && isAtTarget) {
1388
- state.stableTarget = void 0;
1389
1369
  finishScrollTo(ctx);
1390
1370
  }
1391
- } else {
1392
- ctx.state.stableTarget = void 0;
1393
1371
  }
1394
1372
  }
1395
1373
  function checkFinishedScrollFallback(ctx) {
@@ -1455,9 +1433,8 @@ function scrollTo(ctx, params) {
1455
1433
  let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
1456
1434
  offset = clampScrollOffset(ctx, offset, scrollTarget);
1457
1435
  state.scrollHistory.length = 0;
1458
- state.stableTarget = void 0;
1459
1436
  if (!noScrollingTo) {
1460
- state.scrollingTo = { ...scrollTarget, offset };
1437
+ state.scrollingTo = scrollTarget;
1461
1438
  }
1462
1439
  state.scrollPending = offset;
1463
1440
  if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
@@ -3516,20 +3493,69 @@ function createColumnWrapperStyle(contentContainerStyle) {
3516
3493
  }
3517
3494
  }
3518
3495
 
3496
+ // src/utils/hasActiveMVCPAnchorLock.ts
3497
+ function hasActiveMVCPAnchorLock(state) {
3498
+ const lock = state.mvcpAnchorLock;
3499
+ if (!lock) {
3500
+ return false;
3501
+ }
3502
+ if (Date.now() > lock.expiresAt) {
3503
+ state.mvcpAnchorLock = void 0;
3504
+ return false;
3505
+ }
3506
+ return true;
3507
+ }
3508
+
3519
3509
  // src/utils/createImperativeHandle.ts
3520
3510
  function createImperativeHandle(ctx) {
3521
3511
  const state = ctx.state;
3512
+ const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
3513
+ const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
3514
+ let imperativeScrollToken = 0;
3515
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0 || hasActiveMVCPAnchorLock(state);
3516
+ const runWhenSettled = (token, run) => {
3517
+ const startedAt = Date.now();
3518
+ let stableFrames = 0;
3519
+ const check = () => {
3520
+ if (token !== imperativeScrollToken) {
3521
+ return;
3522
+ }
3523
+ if (isSettlingAfterDataChange()) {
3524
+ stableFrames = 0;
3525
+ } else {
3526
+ stableFrames += 1;
3527
+ }
3528
+ const timedOut = Date.now() - startedAt >= IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS;
3529
+ if (stableFrames >= IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES || timedOut) {
3530
+ run();
3531
+ return;
3532
+ }
3533
+ requestAnimationFrame(check);
3534
+ };
3535
+ requestAnimationFrame(check);
3536
+ };
3522
3537
  const runScrollWithPromise = (run) => new Promise((resolve) => {
3523
3538
  var _a3;
3539
+ const token = ++imperativeScrollToken;
3524
3540
  (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
3525
3541
  state.pendingScrollResolve = resolve;
3526
- const didStartScroll = run();
3527
- if (!didStartScroll || !state.scrollingTo) {
3528
- if (state.pendingScrollResolve === resolve) {
3529
- state.pendingScrollResolve = void 0;
3542
+ const runNow = () => {
3543
+ if (token !== imperativeScrollToken) {
3544
+ return;
3545
+ }
3546
+ const didStartScroll = run();
3547
+ if (!didStartScroll || !state.scrollingTo) {
3548
+ if (state.pendingScrollResolve === resolve) {
3549
+ state.pendingScrollResolve = void 0;
3550
+ }
3551
+ resolve();
3530
3552
  }
3531
- resolve();
3553
+ };
3554
+ if (isSettlingAfterDataChange()) {
3555
+ runWhenSettled(token, runNow);
3556
+ return;
3532
3557
  }
3558
+ runNow();
3533
3559
  });
3534
3560
  const scrollIndexIntoView = (options) => {
3535
3561
  if (state) {
@@ -3588,6 +3614,8 @@ function createImperativeHandle(ctx) {
3588
3614
  endBuffered: state.endBuffered,
3589
3615
  isAtEnd: state.isAtEnd,
3590
3616
  isAtStart: state.isAtStart,
3617
+ isEndReached: state.isEndReached,
3618
+ isStartReached: state.isStartReached,
3591
3619
  listen: (signalName, cb) => listen$(ctx, signalName, cb),
3592
3620
  listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3593
3621
  positionAtIndex: (index) => state.positions[index],
@@ -3839,7 +3867,7 @@ var LegendList = typedMemo2(
3839
3867
  })
3840
3868
  );
3841
3869
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3842
- var _a3, _b, _c, _d;
3870
+ var _a3, _b, _c, _d, _e;
3843
3871
  const {
3844
3872
  alignItemsAtEnd = false,
3845
3873
  alwaysRender,
@@ -3968,7 +3996,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3968
3996
  );
3969
3997
  }
3970
3998
  const useWindowScrollResolved = Platform2.OS === "web" && !!useWindowScroll && !renderScrollComponent;
3971
- const refState = useRef();
3999
+ const refState = useRef(void 0);
3972
4000
  const hasOverrideItemLayout = !!overrideItemLayout;
3973
4001
  const prevHasOverrideItemLayout = useRef(hasOverrideItemLayout);
3974
4002
  if (!refState.current) {
@@ -4320,6 +4348,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4320
4348
  []
4321
4349
  );
4322
4350
  const onScrollHandler = useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, fns.onScroll);
4351
+ const refreshControlElement = refreshControl;
4323
4352
  return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
4324
4353
  ListComponent,
4325
4354
  {
@@ -4338,9 +4367,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4338
4367
  onMomentumScrollEnd: fns.onMomentumScrollEnd,
4339
4368
  onScroll: onScrollHandler,
4340
4369
  recycleItems,
4341
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
4342
- progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
4343
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2.createElement(
4370
+ refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControlElement, {
4371
+ progressViewOffset: ((_d = refreshControlElement.props.progressViewOffset) != null ? _d : 0) + stylePaddingTopState
4372
+ }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2.createElement(
4344
4373
  RefreshControl,
4345
4374
  {
4346
4375
  onRefresh,
@@ -4350,7 +4379,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4350
4379
  ),
4351
4380
  refScrollView: combinedRef,
4352
4381
  renderScrollComponent,
4353
- scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
4382
+ scrollAdjustHandler: (_e = refState.current) == null ? void 0 : _e.scrollAdjustHandler,
4354
4383
  scrollEventThrottle: 0,
4355
4384
  snapToIndices,
4356
4385
  stickyHeaderIndices,