@legendapp/list 3.0.0-beta.20 → 3.0.0-beta.21

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
@@ -249,7 +249,8 @@ var ENABLE_DEVMODE = IS_DEV && false;
249
249
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
250
250
 
251
251
  // src/constants-platform.native.ts
252
- var IsNewArchitecture = global.nativeFabricUIManager != null;
252
+ var f = global.nativeFabricUIManager;
253
+ var IsNewArchitecture = f !== void 0 && f != null;
253
254
  var useAnimatedValue = (initialValue) => {
254
255
  const [animAnimatedValue] = React2.useState(() => new reactNative.Animated.Value(initialValue));
255
256
  return animAnimatedValue;
@@ -2352,7 +2353,7 @@ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2352
2353
  Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
2353
2354
  );
2354
2355
  }
2355
- function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2356
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, needNewContainersSet, startBuffered, endBuffered) {
2356
2357
  var _a3;
2357
2358
  const state = ctx.state;
2358
2359
  const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
@@ -2362,18 +2363,20 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2362
2363
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
2363
2364
  const stickyIndex = stickyArray[idx];
2364
2365
  const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
2365
- if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
2366
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered) && !needNewContainersSet.has(stickyIndex)) {
2367
+ needNewContainersSet.add(stickyIndex);
2366
2368
  needNewContainers.push(stickyIndex);
2367
2369
  }
2368
2370
  }
2369
2371
  }
2370
- function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2372
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2371
2373
  var _a3, _b, _c;
2372
2374
  const state = ctx.state;
2373
2375
  for (const containerIndex of state.stickyContainerPool) {
2374
2376
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2375
2377
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
2376
2378
  if (itemIndex === void 0) continue;
2379
+ if (alwaysRenderIndicesSet.has(itemIndex)) continue;
2377
2380
  const arrayIdx = stickyArray.indexOf(itemIndex);
2378
2381
  if (arrayIdx === -1) {
2379
2382
  state.stickyContainerPool.delete(containerIndex);
@@ -2405,7 +2408,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentSt
2405
2408
  function calculateItemsInView(ctx, params = {}) {
2406
2409
  const state = ctx.state;
2407
2410
  reactNative.unstable_batchedUpdates(() => {
2408
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2411
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
2409
2412
  const {
2410
2413
  columns,
2411
2414
  containerItemKeys,
@@ -2415,7 +2418,15 @@ function calculateItemsInView(ctx, params = {}) {
2415
2418
  initialScroll,
2416
2419
  minIndexSizeChanged,
2417
2420
  positions,
2418
- props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2421
+ props: {
2422
+ alwaysRenderIndicesArr,
2423
+ alwaysRenderIndicesSet,
2424
+ getItemType,
2425
+ itemsAreEqual,
2426
+ keyExtractor,
2427
+ onStickyHeaderChange,
2428
+ scrollBuffer
2429
+ },
2419
2430
  scrollForNextCalculateItemsInView,
2420
2431
  scrollLength,
2421
2432
  sizes,
@@ -2425,6 +2436,8 @@ function calculateItemsInView(ctx, params = {}) {
2425
2436
  const { data } = state.props;
2426
2437
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
2427
2438
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2439
+ const alwaysRenderArr = alwaysRenderIndicesArr || [];
2440
+ const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2428
2441
  const prevNumContainers = peek$(ctx, "numContainers");
2429
2442
  if (!data || scrollLength === 0 || !prevNumContainers) {
2430
2443
  if (!IsNewArchitecture && state.initialAnchor) {
@@ -2607,12 +2620,24 @@ function calculateItemsInView(ctx, params = {}) {
2607
2620
  }
2608
2621
  if (startBuffered !== null && endBuffered !== null) {
2609
2622
  const needNewContainers = [];
2623
+ const needNewContainersSet = /* @__PURE__ */ new Set();
2610
2624
  for (let i = startBuffered; i <= endBuffered; i++) {
2611
2625
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2612
2626
  if (!containerItemKeys.has(id)) {
2627
+ needNewContainersSet.add(i);
2613
2628
  needNewContainers.push(i);
2614
2629
  }
2615
2630
  }
2631
+ if (alwaysRenderArr.length > 0) {
2632
+ for (const index of alwaysRenderArr) {
2633
+ if (index < 0 || index >= dataLength) continue;
2634
+ const id = (_i = idCache[index]) != null ? _i : getId(state, index);
2635
+ if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
2636
+ needNewContainersSet.add(index);
2637
+ needNewContainers.push(index);
2638
+ }
2639
+ }
2640
+ }
2616
2641
  if (stickyIndicesArr.length > 0) {
2617
2642
  handleStickyActivation(
2618
2643
  ctx,
@@ -2620,6 +2645,7 @@ function calculateItemsInView(ctx, params = {}) {
2620
2645
  stickyIndicesArr,
2621
2646
  currentStickyIdx,
2622
2647
  needNewContainers,
2648
+ needNewContainersSet,
2623
2649
  startBuffered,
2624
2650
  endBuffered
2625
2651
  );
@@ -2643,7 +2669,7 @@ function calculateItemsInView(ctx, params = {}) {
2643
2669
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2644
2670
  const i = needNewContainers[idx];
2645
2671
  const containerIndex = availableContainers[idx];
2646
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2672
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
2647
2673
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2648
2674
  if (oldKey && oldKey !== id) {
2649
2675
  containerItemKeys.delete(oldKey);
@@ -2655,14 +2681,23 @@ function calculateItemsInView(ctx, params = {}) {
2655
2681
  }
2656
2682
  containerItemKeys.set(id, containerIndex);
2657
2683
  const containerSticky = `containerSticky${containerIndex}`;
2658
- if (stickyIndicesSet.has(i)) {
2684
+ const isSticky = stickyIndicesSet.has(i);
2685
+ const isAlwaysRender = alwaysRenderSet.has(i);
2686
+ if (isSticky) {
2659
2687
  set$(ctx, containerSticky, true);
2660
2688
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2661
2689
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2662
2690
  state.stickyContainerPool.add(containerIndex);
2663
- } else if (peek$(ctx, containerSticky)) {
2664
- set$(ctx, containerSticky, false);
2665
- state.stickyContainerPool.delete(containerIndex);
2691
+ } else {
2692
+ if (peek$(ctx, containerSticky)) {
2693
+ set$(ctx, containerSticky, false);
2694
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2695
+ }
2696
+ if (isAlwaysRender) {
2697
+ state.stickyContainerPool.add(containerIndex);
2698
+ } else if (state.stickyContainerPool.has(containerIndex)) {
2699
+ state.stickyContainerPool.delete(containerIndex);
2700
+ }
2666
2701
  }
2667
2702
  if (containerIndex >= numContainers) {
2668
2703
  numContainers = containerIndex + 1;
@@ -2675,9 +2710,27 @@ function calculateItemsInView(ctx, params = {}) {
2675
2710
  }
2676
2711
  }
2677
2712
  }
2713
+ if (alwaysRenderArr.length > 0) {
2714
+ for (const index of alwaysRenderArr) {
2715
+ if (index < 0 || index >= dataLength) continue;
2716
+ const id = (_k = idCache[index]) != null ? _k : getId(state, index);
2717
+ const containerIndex = containerItemKeys.get(id);
2718
+ if (containerIndex !== void 0) {
2719
+ state.stickyContainerPool.add(containerIndex);
2720
+ }
2721
+ }
2722
+ }
2678
2723
  }
2679
- if (stickyIndicesArr.length > 0) {
2680
- handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2724
+ if (state.stickyContainerPool.size > 0) {
2725
+ handleStickyRecycling(
2726
+ ctx,
2727
+ stickyIndicesArr,
2728
+ scroll,
2729
+ scrollBuffer,
2730
+ currentStickyIdx,
2731
+ pendingRemoval,
2732
+ alwaysRenderSet
2733
+ );
2681
2734
  }
2682
2735
  let didChangePositions = false;
2683
2736
  for (let i = 0; i < numContainers; i++) {
@@ -2700,7 +2753,7 @@ function calculateItemsInView(ctx, params = {}) {
2700
2753
  const itemIndex = indexByKey.get(itemKey);
2701
2754
  const item = data[itemIndex];
2702
2755
  if (item !== void 0) {
2703
- const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2756
+ const id = (_l = idCache[itemIndex]) != null ? _l : getId(state, itemIndex);
2704
2757
  const positionValue = positions.get(id);
2705
2758
  if (positionValue === void 0) {
2706
2759
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -3340,6 +3393,54 @@ function createImperativeHandle(ctx) {
3340
3393
  }
3341
3394
  };
3342
3395
  }
3396
+
3397
+ // src/utils/getAlwaysRenderIndices.ts
3398
+ var sortAsc = (a, b) => a - b;
3399
+ var toCount = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
3400
+ var addIndex = (result, dataLength, index) => {
3401
+ if (index >= 0 && index < dataLength) {
3402
+ result.add(index);
3403
+ }
3404
+ };
3405
+ function getAlwaysRenderIndices(config, data, keyExtractor) {
3406
+ var _a3, _b;
3407
+ if (!config || data.length === 0) {
3408
+ return [];
3409
+ }
3410
+ const result = /* @__PURE__ */ new Set();
3411
+ const dataLength = data.length;
3412
+ const topCount = toCount(config.top);
3413
+ if (topCount > 0) {
3414
+ for (let i = 0; i < Math.min(topCount, dataLength); i++) {
3415
+ addIndex(result, dataLength, i);
3416
+ }
3417
+ }
3418
+ const bottomCount = toCount(config.bottom);
3419
+ if (bottomCount > 0) {
3420
+ for (let i = Math.max(0, dataLength - bottomCount); i < dataLength; i++) {
3421
+ addIndex(result, dataLength, i);
3422
+ }
3423
+ }
3424
+ if ((_a3 = config.indices) == null ? void 0 : _a3.length) {
3425
+ for (const index of config.indices) {
3426
+ if (!Number.isFinite(index)) continue;
3427
+ addIndex(result, dataLength, Math.floor(index));
3428
+ }
3429
+ }
3430
+ if ((_b = config.keys) == null ? void 0 : _b.length) {
3431
+ const keys = new Set(config.keys);
3432
+ for (let i = 0; i < dataLength && keys.size > 0; i++) {
3433
+ const key = keyExtractor(data[i], i);
3434
+ if (keys.has(key)) {
3435
+ addIndex(result, dataLength, i);
3436
+ keys.delete(key);
3437
+ }
3438
+ }
3439
+ }
3440
+ const indices = Array.from(result);
3441
+ indices.sort(sortAsc);
3442
+ return indices;
3443
+ }
3343
3444
  function getRenderedItem(ctx, key) {
3344
3445
  var _a3;
3345
3446
  const state = ctx.state;
@@ -3456,9 +3557,10 @@ var LegendList = typedMemo(
3456
3557
  })
3457
3558
  );
3458
3559
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3459
- var _a3, _b;
3560
+ var _a3, _b, _c, _d;
3460
3561
  const {
3461
3562
  alignItemsAtEnd = false,
3563
+ alwaysRender,
3462
3564
  columnWrapperStyle,
3463
3565
  contentContainerStyle: contentContainerStyleProp,
3464
3566
  contentInset,
@@ -3487,6 +3589,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3487
3589
  onEndReached,
3488
3590
  onEndReachedThreshold = 0.5,
3489
3591
  onItemSizeChanged,
3592
+ onMetricsChange,
3490
3593
  onLayout: onLayoutProp,
3491
3594
  onLoad,
3492
3595
  onMomentumScrollEnd,
@@ -3535,6 +3638,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3535
3638
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3536
3639
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3537
3640
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3641
+ const alwaysRenderIndices = React2.useMemo(() => {
3642
+ const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
3643
+ return { arr: indices, set: new Set(indices) };
3644
+ }, [
3645
+ alwaysRender == null ? void 0 : alwaysRender.top,
3646
+ alwaysRender == null ? void 0 : alwaysRender.bottom,
3647
+ (_a3 = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _a3.join(","),
3648
+ (_b = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _b.join(","),
3649
+ dataProp,
3650
+ dataVersion,
3651
+ keyExtractor
3652
+ ]);
3538
3653
  if (IS_DEV && stickyIndicesDeprecated && !stickyHeaderIndicesProp) {
3539
3654
  warnDevOnce(
3540
3655
  "stickyIndices",
@@ -3566,7 +3681,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3566
3681
  attempts: 0,
3567
3682
  index: initialScrollProp.index,
3568
3683
  settledTicks: 0,
3569
- viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3684
+ viewOffset: (_c = initialScrollProp.viewOffset) != null ? _c : 0,
3570
3685
  viewPosition: initialScrollProp.viewPosition
3571
3686
  } : void 0,
3572
3687
  initialScroll: initialScrollProp,
@@ -3626,6 +3741,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3626
3741
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3627
3742
  state.props = {
3628
3743
  alignItemsAtEnd,
3744
+ alwaysRender,
3745
+ alwaysRenderIndicesArr: alwaysRenderIndices.arr,
3746
+ alwaysRenderIndicesSet: alwaysRenderIndices.set,
3629
3747
  animatedProps: animatedPropsInternal,
3630
3748
  contentInset,
3631
3749
  data: dataProp,
@@ -3803,6 +3921,34 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3803
3921
  stylePaddingBottomState,
3804
3922
  stylePaddingTopState
3805
3923
  ]);
3924
+ React2.useEffect(() => {
3925
+ if (!onMetricsChange) {
3926
+ return;
3927
+ }
3928
+ let lastMetrics;
3929
+ const emitMetrics = () => {
3930
+ const metrics = {
3931
+ alignItemsAtEndPadding: peek$(ctx, "alignItemsPaddingTop") || 0,
3932
+ footerSize: peek$(ctx, "footerSize") || 0,
3933
+ headerSize: peek$(ctx, "headerSize") || 0
3934
+ };
3935
+ if (!lastMetrics || metrics.alignItemsAtEndPadding !== lastMetrics.alignItemsAtEndPadding || metrics.headerSize !== lastMetrics.headerSize || metrics.footerSize !== lastMetrics.footerSize) {
3936
+ lastMetrics = metrics;
3937
+ onMetricsChange(metrics);
3938
+ }
3939
+ };
3940
+ emitMetrics();
3941
+ const unsubscribe = [
3942
+ listen$(ctx, "alignItemsPaddingTop", emitMetrics),
3943
+ listen$(ctx, "headerSize", emitMetrics),
3944
+ listen$(ctx, "footerSize", emitMetrics)
3945
+ ];
3946
+ return () => {
3947
+ for (const unsub of unsubscribe) {
3948
+ unsub();
3949
+ }
3950
+ };
3951
+ }, [ctx, onMetricsChange]);
3806
3952
  React2.useEffect(() => {
3807
3953
  const viewability = setupViewability({
3808
3954
  onViewableItemsChanged,
@@ -3865,7 +4011,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3865
4011
  }
3866
4012
  ),
3867
4013
  refScrollView: combinedRef,
3868
- scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
4014
+ scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
3869
4015
  scrollEventThrottle: 0,
3870
4016
  snapToIndices,
3871
4017
  stickyHeaderConfig,
package/index.native.mjs CHANGED
@@ -228,7 +228,8 @@ var ENABLE_DEVMODE = IS_DEV && false;
228
228
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
229
229
 
230
230
  // src/constants-platform.native.ts
231
- var IsNewArchitecture = global.nativeFabricUIManager != null;
231
+ var f = global.nativeFabricUIManager;
232
+ var IsNewArchitecture = f !== void 0 && f != null;
232
233
  var useAnimatedValue = (initialValue) => {
233
234
  const [animAnimatedValue] = useState(() => new Animated.Value(initialValue));
234
235
  return animAnimatedValue;
@@ -2331,7 +2332,7 @@ function getActiveStickyIndices(ctx, stickyHeaderIndices) {
2331
2332
  Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
2332
2333
  );
2333
2334
  }
2334
- function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2335
+ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, needNewContainersSet, startBuffered, endBuffered) {
2335
2336
  var _a3;
2336
2337
  const state = ctx.state;
2337
2338
  const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
@@ -2341,18 +2342,20 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2341
2342
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
2342
2343
  const stickyIndex = stickyArray[idx];
2343
2344
  const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
2344
- if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
2345
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered) && !needNewContainersSet.has(stickyIndex)) {
2346
+ needNewContainersSet.add(stickyIndex);
2345
2347
  needNewContainers.push(stickyIndex);
2346
2348
  }
2347
2349
  }
2348
2350
  }
2349
- function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2351
+ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2350
2352
  var _a3, _b, _c;
2351
2353
  const state = ctx.state;
2352
2354
  for (const containerIndex of state.stickyContainerPool) {
2353
2355
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
2354
2356
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
2355
2357
  if (itemIndex === void 0) continue;
2358
+ if (alwaysRenderIndicesSet.has(itemIndex)) continue;
2356
2359
  const arrayIdx = stickyArray.indexOf(itemIndex);
2357
2360
  if (arrayIdx === -1) {
2358
2361
  state.stickyContainerPool.delete(containerIndex);
@@ -2384,7 +2387,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentSt
2384
2387
  function calculateItemsInView(ctx, params = {}) {
2385
2388
  const state = ctx.state;
2386
2389
  unstable_batchedUpdates(() => {
2387
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2390
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
2388
2391
  const {
2389
2392
  columns,
2390
2393
  containerItemKeys,
@@ -2394,7 +2397,15 @@ function calculateItemsInView(ctx, params = {}) {
2394
2397
  initialScroll,
2395
2398
  minIndexSizeChanged,
2396
2399
  positions,
2397
- props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2400
+ props: {
2401
+ alwaysRenderIndicesArr,
2402
+ alwaysRenderIndicesSet,
2403
+ getItemType,
2404
+ itemsAreEqual,
2405
+ keyExtractor,
2406
+ onStickyHeaderChange,
2407
+ scrollBuffer
2408
+ },
2398
2409
  scrollForNextCalculateItemsInView,
2399
2410
  scrollLength,
2400
2411
  sizes,
@@ -2404,6 +2415,8 @@ function calculateItemsInView(ctx, params = {}) {
2404
2415
  const { data } = state.props;
2405
2416
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
2406
2417
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
2418
+ const alwaysRenderArr = alwaysRenderIndicesArr || [];
2419
+ const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
2407
2420
  const prevNumContainers = peek$(ctx, "numContainers");
2408
2421
  if (!data || scrollLength === 0 || !prevNumContainers) {
2409
2422
  if (!IsNewArchitecture && state.initialAnchor) {
@@ -2586,12 +2599,24 @@ function calculateItemsInView(ctx, params = {}) {
2586
2599
  }
2587
2600
  if (startBuffered !== null && endBuffered !== null) {
2588
2601
  const needNewContainers = [];
2602
+ const needNewContainersSet = /* @__PURE__ */ new Set();
2589
2603
  for (let i = startBuffered; i <= endBuffered; i++) {
2590
2604
  const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2591
2605
  if (!containerItemKeys.has(id)) {
2606
+ needNewContainersSet.add(i);
2592
2607
  needNewContainers.push(i);
2593
2608
  }
2594
2609
  }
2610
+ if (alwaysRenderArr.length > 0) {
2611
+ for (const index of alwaysRenderArr) {
2612
+ if (index < 0 || index >= dataLength) continue;
2613
+ const id = (_i = idCache[index]) != null ? _i : getId(state, index);
2614
+ if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
2615
+ needNewContainersSet.add(index);
2616
+ needNewContainers.push(index);
2617
+ }
2618
+ }
2619
+ }
2595
2620
  if (stickyIndicesArr.length > 0) {
2596
2621
  handleStickyActivation(
2597
2622
  ctx,
@@ -2599,6 +2624,7 @@ function calculateItemsInView(ctx, params = {}) {
2599
2624
  stickyIndicesArr,
2600
2625
  currentStickyIdx,
2601
2626
  needNewContainers,
2627
+ needNewContainersSet,
2602
2628
  startBuffered,
2603
2629
  endBuffered
2604
2630
  );
@@ -2622,7 +2648,7 @@ function calculateItemsInView(ctx, params = {}) {
2622
2648
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2623
2649
  const i = needNewContainers[idx];
2624
2650
  const containerIndex = availableContainers[idx];
2625
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2651
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
2626
2652
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2627
2653
  if (oldKey && oldKey !== id) {
2628
2654
  containerItemKeys.delete(oldKey);
@@ -2634,14 +2660,23 @@ function calculateItemsInView(ctx, params = {}) {
2634
2660
  }
2635
2661
  containerItemKeys.set(id, containerIndex);
2636
2662
  const containerSticky = `containerSticky${containerIndex}`;
2637
- if (stickyIndicesSet.has(i)) {
2663
+ const isSticky = stickyIndicesSet.has(i);
2664
+ const isAlwaysRender = alwaysRenderSet.has(i);
2665
+ if (isSticky) {
2638
2666
  set$(ctx, containerSticky, true);
2639
2667
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2640
2668
  set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2641
2669
  state.stickyContainerPool.add(containerIndex);
2642
- } else if (peek$(ctx, containerSticky)) {
2643
- set$(ctx, containerSticky, false);
2644
- state.stickyContainerPool.delete(containerIndex);
2670
+ } else {
2671
+ if (peek$(ctx, containerSticky)) {
2672
+ set$(ctx, containerSticky, false);
2673
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2674
+ }
2675
+ if (isAlwaysRender) {
2676
+ state.stickyContainerPool.add(containerIndex);
2677
+ } else if (state.stickyContainerPool.has(containerIndex)) {
2678
+ state.stickyContainerPool.delete(containerIndex);
2679
+ }
2645
2680
  }
2646
2681
  if (containerIndex >= numContainers) {
2647
2682
  numContainers = containerIndex + 1;
@@ -2654,9 +2689,27 @@ function calculateItemsInView(ctx, params = {}) {
2654
2689
  }
2655
2690
  }
2656
2691
  }
2692
+ if (alwaysRenderArr.length > 0) {
2693
+ for (const index of alwaysRenderArr) {
2694
+ if (index < 0 || index >= dataLength) continue;
2695
+ const id = (_k = idCache[index]) != null ? _k : getId(state, index);
2696
+ const containerIndex = containerItemKeys.get(id);
2697
+ if (containerIndex !== void 0) {
2698
+ state.stickyContainerPool.add(containerIndex);
2699
+ }
2700
+ }
2701
+ }
2657
2702
  }
2658
- if (stickyIndicesArr.length > 0) {
2659
- handleStickyRecycling(ctx, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2703
+ if (state.stickyContainerPool.size > 0) {
2704
+ handleStickyRecycling(
2705
+ ctx,
2706
+ stickyIndicesArr,
2707
+ scroll,
2708
+ scrollBuffer,
2709
+ currentStickyIdx,
2710
+ pendingRemoval,
2711
+ alwaysRenderSet
2712
+ );
2660
2713
  }
2661
2714
  let didChangePositions = false;
2662
2715
  for (let i = 0; i < numContainers; i++) {
@@ -2679,7 +2732,7 @@ function calculateItemsInView(ctx, params = {}) {
2679
2732
  const itemIndex = indexByKey.get(itemKey);
2680
2733
  const item = data[itemIndex];
2681
2734
  if (item !== void 0) {
2682
- const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2735
+ const id = (_l = idCache[itemIndex]) != null ? _l : getId(state, itemIndex);
2683
2736
  const positionValue = positions.get(id);
2684
2737
  if (positionValue === void 0) {
2685
2738
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -3319,6 +3372,54 @@ function createImperativeHandle(ctx) {
3319
3372
  }
3320
3373
  };
3321
3374
  }
3375
+
3376
+ // src/utils/getAlwaysRenderIndices.ts
3377
+ var sortAsc = (a, b) => a - b;
3378
+ var toCount = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
3379
+ var addIndex = (result, dataLength, index) => {
3380
+ if (index >= 0 && index < dataLength) {
3381
+ result.add(index);
3382
+ }
3383
+ };
3384
+ function getAlwaysRenderIndices(config, data, keyExtractor) {
3385
+ var _a3, _b;
3386
+ if (!config || data.length === 0) {
3387
+ return [];
3388
+ }
3389
+ const result = /* @__PURE__ */ new Set();
3390
+ const dataLength = data.length;
3391
+ const topCount = toCount(config.top);
3392
+ if (topCount > 0) {
3393
+ for (let i = 0; i < Math.min(topCount, dataLength); i++) {
3394
+ addIndex(result, dataLength, i);
3395
+ }
3396
+ }
3397
+ const bottomCount = toCount(config.bottom);
3398
+ if (bottomCount > 0) {
3399
+ for (let i = Math.max(0, dataLength - bottomCount); i < dataLength; i++) {
3400
+ addIndex(result, dataLength, i);
3401
+ }
3402
+ }
3403
+ if ((_a3 = config.indices) == null ? void 0 : _a3.length) {
3404
+ for (const index of config.indices) {
3405
+ if (!Number.isFinite(index)) continue;
3406
+ addIndex(result, dataLength, Math.floor(index));
3407
+ }
3408
+ }
3409
+ if ((_b = config.keys) == null ? void 0 : _b.length) {
3410
+ const keys = new Set(config.keys);
3411
+ for (let i = 0; i < dataLength && keys.size > 0; i++) {
3412
+ const key = keyExtractor(data[i], i);
3413
+ if (keys.has(key)) {
3414
+ addIndex(result, dataLength, i);
3415
+ keys.delete(key);
3416
+ }
3417
+ }
3418
+ }
3419
+ const indices = Array.from(result);
3420
+ indices.sort(sortAsc);
3421
+ return indices;
3422
+ }
3322
3423
  function getRenderedItem(ctx, key) {
3323
3424
  var _a3;
3324
3425
  const state = ctx.state;
@@ -3435,9 +3536,10 @@ var LegendList = typedMemo(
3435
3536
  })
3436
3537
  );
3437
3538
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3438
- var _a3, _b;
3539
+ var _a3, _b, _c, _d;
3439
3540
  const {
3440
3541
  alignItemsAtEnd = false,
3542
+ alwaysRender,
3441
3543
  columnWrapperStyle,
3442
3544
  contentContainerStyle: contentContainerStyleProp,
3443
3545
  contentInset,
@@ -3466,6 +3568,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3466
3568
  onEndReached,
3467
3569
  onEndReachedThreshold = 0.5,
3468
3570
  onItemSizeChanged,
3571
+ onMetricsChange,
3469
3572
  onLayout: onLayoutProp,
3470
3573
  onLoad,
3471
3574
  onMomentumScrollEnd,
@@ -3514,6 +3617,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3514
3617
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
3515
3618
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3516
3619
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3620
+ const alwaysRenderIndices = useMemo(() => {
3621
+ const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
3622
+ return { arr: indices, set: new Set(indices) };
3623
+ }, [
3624
+ alwaysRender == null ? void 0 : alwaysRender.top,
3625
+ alwaysRender == null ? void 0 : alwaysRender.bottom,
3626
+ (_a3 = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _a3.join(","),
3627
+ (_b = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _b.join(","),
3628
+ dataProp,
3629
+ dataVersion,
3630
+ keyExtractor
3631
+ ]);
3517
3632
  if (IS_DEV && stickyIndicesDeprecated && !stickyHeaderIndicesProp) {
3518
3633
  warnDevOnce(
3519
3634
  "stickyIndices",
@@ -3545,7 +3660,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3545
3660
  attempts: 0,
3546
3661
  index: initialScrollProp.index,
3547
3662
  settledTicks: 0,
3548
- viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3663
+ viewOffset: (_c = initialScrollProp.viewOffset) != null ? _c : 0,
3549
3664
  viewPosition: initialScrollProp.viewPosition
3550
3665
  } : void 0,
3551
3666
  initialScroll: initialScrollProp,
@@ -3605,6 +3720,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3605
3720
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3606
3721
  state.props = {
3607
3722
  alignItemsAtEnd,
3723
+ alwaysRender,
3724
+ alwaysRenderIndicesArr: alwaysRenderIndices.arr,
3725
+ alwaysRenderIndicesSet: alwaysRenderIndices.set,
3608
3726
  animatedProps: animatedPropsInternal,
3609
3727
  contentInset,
3610
3728
  data: dataProp,
@@ -3782,6 +3900,34 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3782
3900
  stylePaddingBottomState,
3783
3901
  stylePaddingTopState
3784
3902
  ]);
3903
+ useEffect(() => {
3904
+ if (!onMetricsChange) {
3905
+ return;
3906
+ }
3907
+ let lastMetrics;
3908
+ const emitMetrics = () => {
3909
+ const metrics = {
3910
+ alignItemsAtEndPadding: peek$(ctx, "alignItemsPaddingTop") || 0,
3911
+ footerSize: peek$(ctx, "footerSize") || 0,
3912
+ headerSize: peek$(ctx, "headerSize") || 0
3913
+ };
3914
+ if (!lastMetrics || metrics.alignItemsAtEndPadding !== lastMetrics.alignItemsAtEndPadding || metrics.headerSize !== lastMetrics.headerSize || metrics.footerSize !== lastMetrics.footerSize) {
3915
+ lastMetrics = metrics;
3916
+ onMetricsChange(metrics);
3917
+ }
3918
+ };
3919
+ emitMetrics();
3920
+ const unsubscribe = [
3921
+ listen$(ctx, "alignItemsPaddingTop", emitMetrics),
3922
+ listen$(ctx, "headerSize", emitMetrics),
3923
+ listen$(ctx, "footerSize", emitMetrics)
3924
+ ];
3925
+ return () => {
3926
+ for (const unsub of unsubscribe) {
3927
+ unsub();
3928
+ }
3929
+ };
3930
+ }, [ctx, onMetricsChange]);
3785
3931
  useEffect(() => {
3786
3932
  const viewability = setupViewability({
3787
3933
  onViewableItemsChanged,
@@ -3844,7 +3990,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3844
3990
  }
3845
3991
  ),
3846
3992
  refScrollView: combinedRef,
3847
- scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3993
+ scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
3848
3994
  scrollEventThrottle: 0,
3849
3995
  snapToIndices,
3850
3996
  stickyHeaderConfig,
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import { LegendList as LegendList$1, LegendListProps, LegendListRef } from '@legendapp/list';
3
+ import { AnimatedLegendList } from '@legendapp/list/animated';
4
+ import { AnimatedLegendList as AnimatedLegendList$1 } from '@legendapp/list/reanimated';
5
+
6
+ declare const LegendList: <ItemT, ListT extends typeof LegendList$1 | typeof AnimatedLegendList | typeof AnimatedLegendList$1 = (<T>(props: LegendListProps<T> & React.RefAttributes<LegendListRef>) => React.ReactNode) & {
7
+ displayName?: string;
8
+ }>(props: (LegendListProps<ItemT> & {
9
+ LegendList?: ListT;
10
+ }) & React.RefAttributes<LegendListRef>) => React.ReactNode;
11
+
12
+ export { LegendList };