@legendapp/list 2.0.0-next.0 → 2.0.0-next.2

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.
Files changed (262) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.cursor/rules/changelog.mdc +60 -0
  3. package/.github/FUNDING.yml +15 -0
  4. package/.gitignore +5 -0
  5. package/.prettierrc.json +5 -0
  6. package/.vscode/settings.json +14 -0
  7. package/CLAUDE.md +126 -0
  8. package/biome.json +46 -0
  9. package/bun.lock +1289 -0
  10. package/bunfig.toml +2 -0
  11. package/dist/CHANGELOG.md +119 -0
  12. package/dist/LICENSE +21 -0
  13. package/dist/README.md +139 -0
  14. package/{animated.d.mts → dist/animated.d.mts} +1 -1
  15. package/{animated.d.ts → dist/animated.d.ts} +1 -1
  16. package/{index.d.mts → dist/index.d.mts} +63 -15
  17. package/{index.d.ts → dist/index.d.ts} +63 -15
  18. package/dist/index.js +2525 -0
  19. package/dist/index.mjs +2497 -0
  20. package/{keyboard-controller.d.mts → dist/keyboard-controller.d.mts} +4 -4
  21. package/{keyboard-controller.d.ts → dist/keyboard-controller.d.ts} +4 -4
  22. package/dist/package.json +35 -0
  23. package/example/README.md +40 -0
  24. package/example/api/data/genres.json +23 -0
  25. package/example/api/data/playlist/10402-10749.json +1 -0
  26. package/example/api/data/playlist/10402-10770.json +1 -0
  27. package/example/api/data/playlist/10402-37.json +1 -0
  28. package/example/api/data/playlist/10749-10752.json +1 -0
  29. package/example/api/data/playlist/10749-10770.json +1 -0
  30. package/example/api/data/playlist/10749-37.json +1 -0
  31. package/example/api/data/playlist/10749-878.json +1 -0
  32. package/example/api/data/playlist/10751-10402.json +1 -0
  33. package/example/api/data/playlist/10751-10752.json +1 -0
  34. package/example/api/data/playlist/10751-37.json +1 -0
  35. package/example/api/data/playlist/10751-53.json +1 -0
  36. package/example/api/data/playlist/10751-878.json +1 -0
  37. package/example/api/data/playlist/10751-9648.json +1 -0
  38. package/example/api/data/playlist/10752-37.json +1 -0
  39. package/example/api/data/playlist/12-10402.json +1 -0
  40. package/example/api/data/playlist/12-10749.json +1 -0
  41. package/example/api/data/playlist/12-18.json +1 -0
  42. package/example/api/data/playlist/12-27.json +1 -0
  43. package/example/api/data/playlist/12-35.json +1 -0
  44. package/example/api/data/playlist/14-36.json +1 -0
  45. package/example/api/data/playlist/14-878.json +1 -0
  46. package/example/api/data/playlist/16-10751.json +1 -0
  47. package/example/api/data/playlist/16-10770.json +1 -0
  48. package/example/api/data/playlist/16-35.json +1 -0
  49. package/example/api/data/playlist/16-36.json +1 -0
  50. package/example/api/data/playlist/16-53.json +1 -0
  51. package/example/api/data/playlist/18-10751.json +1 -0
  52. package/example/api/data/playlist/18-10752.json +1 -0
  53. package/example/api/data/playlist/18-37.json +1 -0
  54. package/example/api/data/playlist/18-53.json +1 -0
  55. package/example/api/data/playlist/18-878.json +1 -0
  56. package/example/api/data/playlist/27-10749.json +1 -0
  57. package/example/api/data/playlist/27-10770.json +1 -0
  58. package/example/api/data/playlist/28-10749.json +1 -0
  59. package/example/api/data/playlist/28-10751.json +1 -0
  60. package/example/api/data/playlist/28-10770.json +1 -0
  61. package/example/api/data/playlist/28-16.json +1 -0
  62. package/example/api/data/playlist/28-18.json +1 -0
  63. package/example/api/data/playlist/28-36.json +1 -0
  64. package/example/api/data/playlist/28-37.json +1 -0
  65. package/example/api/data/playlist/28-53.json +1 -0
  66. package/example/api/data/playlist/28-80.json +1 -0
  67. package/example/api/data/playlist/28-99.json +1 -0
  68. package/example/api/data/playlist/35-10749.json +1 -0
  69. package/example/api/data/playlist/35-10751.json +1 -0
  70. package/example/api/data/playlist/35-10752.json +1 -0
  71. package/example/api/data/playlist/35-27.json +1 -0
  72. package/example/api/data/playlist/35-36.json +1 -0
  73. package/example/api/data/playlist/35-53.json +1 -0
  74. package/example/api/data/playlist/35-80.json +1 -0
  75. package/example/api/data/playlist/36-37.json +1 -0
  76. package/example/api/data/playlist/36-878.json +1 -0
  77. package/example/api/data/playlist/36-9648.json +1 -0
  78. package/example/api/data/playlist/53-10752.json +1 -0
  79. package/example/api/data/playlist/80-10770.json +1 -0
  80. package/example/api/data/playlist/80-14.json +1 -0
  81. package/example/api/data/playlist/80-18.json +1 -0
  82. package/example/api/data/playlist/80-37.json +1 -0
  83. package/example/api/data/playlist/878-37.json +1 -0
  84. package/example/api/data/playlist/9648-10770.json +1 -0
  85. package/example/api/data/playlist/9648-37.json +1 -0
  86. package/example/api/data/playlist/9648-53.json +1 -0
  87. package/example/api/data/playlist/9648-878.json +1 -0
  88. package/example/api/data/playlist/99-10749.json +1 -0
  89. package/example/api/data/playlist/99-14.json +1 -0
  90. package/example/api/data/playlist/99-18.json +1 -0
  91. package/example/api/data/playlist/99-27.json +1 -0
  92. package/example/api/data/playlist/99-53.json +1 -0
  93. package/example/api/data/playlist/99-9648.json +1 -0
  94. package/example/api/data/playlist/index.ts +73 -0
  95. package/example/api/data/rows.json +1 -0
  96. package/example/api/index.ts +36 -0
  97. package/example/app/(tabs)/_layout.tsx +60 -0
  98. package/example/app/(tabs)/cards.tsx +81 -0
  99. package/example/app/(tabs)/index.tsx +205 -0
  100. package/example/app/(tabs)/moviesL.tsx +7 -0
  101. package/example/app/(tabs)/moviesLR.tsx +7 -0
  102. package/example/app/+not-found.tsx +32 -0
  103. package/example/app/_layout.tsx +34 -0
  104. package/example/app/accurate-scrollto/index.tsx +125 -0
  105. package/example/app/accurate-scrollto-2/index.tsx +52 -0
  106. package/example/app/accurate-scrollto-huge/index.tsx +128 -0
  107. package/example/app/add-to-end/index.tsx +82 -0
  108. package/example/app/ai-chat/index.tsx +236 -0
  109. package/example/app/bidirectional-infinite-list/index.tsx +133 -0
  110. package/example/app/cards-columns/index.tsx +37 -0
  111. package/example/app/cards-flashlist/index.tsx +122 -0
  112. package/example/app/cards-flatlist/index.tsx +94 -0
  113. package/example/app/cards-no-recycle/index.tsx +110 -0
  114. package/example/app/cards-renderItem.tsx +354 -0
  115. package/example/app/chat-example/index.tsx +167 -0
  116. package/example/app/chat-infinite/index.tsx +239 -0
  117. package/example/app/chat-keyboard/index.tsx +248 -0
  118. package/example/app/chat-resize-outer/index.tsx +247 -0
  119. package/example/app/columns/index.tsx +78 -0
  120. package/example/app/countries/index.tsx +182 -0
  121. package/example/app/countries-flashlist/index.tsx +163 -0
  122. package/example/app/countries-reorder/index.tsx +187 -0
  123. package/example/app/extra-data/index.tsx +86 -0
  124. package/example/app/filter-elements/filter-data-provider.tsx +55 -0
  125. package/example/app/filter-elements/index.tsx +118 -0
  126. package/example/app/initial-scroll-index/index.tsx +106 -0
  127. package/example/app/initial-scroll-index/renderFixedItem.tsx +215 -0
  128. package/example/app/initial-scroll-index-free-height/index.tsx +70 -0
  129. package/example/app/initial-scroll-index-keyed/index.tsx +62 -0
  130. package/example/app/lazy-list/index.tsx +123 -0
  131. package/example/app/movies-flashlist/index.tsx +7 -0
  132. package/example/app/mutable-cells/index.tsx +104 -0
  133. package/example/app/video-feed/index.tsx +119 -0
  134. package/example/app.config.js +22 -0
  135. package/example/app.json +45 -0
  136. package/example/assets/fonts/SpaceMono-Regular.ttf +0 -0
  137. package/example/assets/images/adaptive-icon.png +0 -0
  138. package/example/assets/images/favicon.png +0 -0
  139. package/example/assets/images/icon.png +0 -0
  140. package/example/assets/images/partial-react-logo.png +0 -0
  141. package/example/assets/images/react-logo.png +0 -0
  142. package/example/assets/images/react-logo@2x.png +0 -0
  143. package/example/assets/images/react-logo@3x.png +0 -0
  144. package/example/assets/images/splash-icon.png +0 -0
  145. package/example/autoscroll.sh +101 -0
  146. package/example/bun.lock +2266 -0
  147. package/example/bunfig.toml +2 -0
  148. package/example/components/Breathe.tsx +54 -0
  149. package/example/components/Circle.tsx +69 -0
  150. package/example/components/Collapsible.tsx +44 -0
  151. package/example/components/ExternalLink.tsx +24 -0
  152. package/example/components/HapticTab.tsx +18 -0
  153. package/example/components/HelloWave.tsx +37 -0
  154. package/example/components/Movies.tsx +179 -0
  155. package/example/components/ParallaxScrollView.tsx +81 -0
  156. package/example/components/ThemedText.tsx +60 -0
  157. package/example/components/ThemedView.tsx +14 -0
  158. package/example/components/__tests__/ThemedText-test.tsx +10 -0
  159. package/example/components/__tests__/__snapshots__/ThemedText-test.tsx.snap +24 -0
  160. package/example/components/ui/IconSymbol.ios.tsx +32 -0
  161. package/example/components/ui/IconSymbol.tsx +43 -0
  162. package/example/components/ui/TabBarBackground.ios.tsx +22 -0
  163. package/example/components/ui/TabBarBackground.tsx +6 -0
  164. package/example/constants/Colors.ts +26 -0
  165. package/example/constants/constants.ts +5 -0
  166. package/example/constants/useScrollTest.ts +19 -0
  167. package/example/hooks/useColorScheme.ts +1 -0
  168. package/example/hooks/useColorScheme.web.ts +8 -0
  169. package/example/hooks/useThemeColor.ts +22 -0
  170. package/example/ios/.xcode.env +11 -0
  171. package/example/ios/Podfile +64 -0
  172. package/example/ios/Podfile.lock +2767 -0
  173. package/example/ios/Podfile.properties.json +5 -0
  174. package/example/ios/listtest/AppDelegate.swift +70 -0
  175. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
  176. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/Contents.json +14 -0
  177. package/example/ios/listtest/Images.xcassets/Contents.json +6 -0
  178. package/example/ios/listtest/Images.xcassets/SplashScreenBackground.colorset/Contents.json +20 -0
  179. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/Contents.json +23 -0
  180. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image.png +0 -0
  181. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@2x.png +0 -0
  182. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@3x.png +0 -0
  183. package/example/ios/listtest/Info.plist +85 -0
  184. package/example/ios/listtest/PrivacyInfo.xcprivacy +48 -0
  185. package/example/ios/listtest/SplashScreen.storyboard +42 -0
  186. package/example/ios/listtest/Supporting/Expo.plist +12 -0
  187. package/example/ios/listtest/listtest-Bridging-Header.h +3 -0
  188. package/example/ios/listtest/listtest.entitlements +5 -0
  189. package/example/ios/listtest.xcodeproj/project.pbxproj +547 -0
  190. package/example/ios/listtest.xcodeproj/xcshareddata/xcschemes/listtest.xcscheme +88 -0
  191. package/example/ios/listtest.xcworkspace/contents.xcworkspacedata +10 -0
  192. package/example/metro.config.js +16 -0
  193. package/example/package.json +73 -0
  194. package/example/scripts/reset-project.js +84 -0
  195. package/example/tsconfig.json +26 -0
  196. package/package.json +88 -34
  197. package/posttsup.ts +24 -0
  198. package/src/Container.tsx +176 -0
  199. package/src/Containers.tsx +85 -0
  200. package/src/ContextContainer.ts +145 -0
  201. package/src/DebugView.tsx +83 -0
  202. package/src/LazyLegendList.tsx +41 -0
  203. package/src/LeanView.tsx +18 -0
  204. package/src/LegendList.tsx +558 -0
  205. package/src/ListComponent.tsx +191 -0
  206. package/src/ScrollAdjust.tsx +24 -0
  207. package/src/ScrollAdjustHandler.ts +26 -0
  208. package/src/Separator.tsx +14 -0
  209. package/src/animated.tsx +6 -0
  210. package/src/calculateItemsInView.ts +363 -0
  211. package/src/calculateOffsetForIndex.ts +23 -0
  212. package/src/calculateOffsetWithOffsetPosition.ts +26 -0
  213. package/src/checkAllSizesKnown.ts +17 -0
  214. package/src/checkAtBottom.ts +36 -0
  215. package/src/checkAtTop.ts +27 -0
  216. package/src/checkThreshold.ts +30 -0
  217. package/src/constants.ts +11 -0
  218. package/src/createColumnWrapperStyle.ts +16 -0
  219. package/src/doInitialAllocateContainers.ts +40 -0
  220. package/src/doMaintainScrollAtEnd.ts +34 -0
  221. package/src/findAvailableContainers.ts +98 -0
  222. package/src/finishScrollTo.ts +8 -0
  223. package/src/getId.ts +21 -0
  224. package/src/getItemSize.ts +52 -0
  225. package/src/getRenderedItem.ts +34 -0
  226. package/src/getScrollVelocity.ts +47 -0
  227. package/src/handleLayout.ts +70 -0
  228. package/src/helpers.ts +39 -0
  229. package/src/index.ts +11 -0
  230. package/src/keyboard-controller.tsx +63 -0
  231. package/src/onScroll.ts +66 -0
  232. package/src/prepareMVCP.ts +50 -0
  233. package/src/reanimated.tsx +63 -0
  234. package/src/requestAdjust.ts +41 -0
  235. package/src/scrollTo.ts +40 -0
  236. package/src/scrollToIndex.ts +34 -0
  237. package/src/setDidLayout.ts +25 -0
  238. package/src/setPaddingTop.ts +28 -0
  239. package/src/state.tsx +304 -0
  240. package/src/types.ts +610 -0
  241. package/src/updateAlignItemsPaddingTop.ts +18 -0
  242. package/src/updateAllPositions.ts +130 -0
  243. package/src/updateItemSize.ts +203 -0
  244. package/src/updateTotalSize.ts +44 -0
  245. package/src/useAnimatedValue.ts +6 -0
  246. package/src/useCombinedRef.ts +22 -0
  247. package/src/useInit.ts +17 -0
  248. package/src/useSyncLayout.tsx +68 -0
  249. package/src/useValue$.ts +53 -0
  250. package/src/viewability.ts +279 -0
  251. package/tsconfig.json +59 -0
  252. package/tsup.config.ts +21 -0
  253. package/index.js +0 -2348
  254. package/index.mjs +0 -2320
  255. /package/{animated.js → dist/animated.js} +0 -0
  256. /package/{animated.mjs → dist/animated.mjs} +0 -0
  257. /package/{keyboard-controller.js → dist/keyboard-controller.js} +0 -0
  258. /package/{keyboard-controller.mjs → dist/keyboard-controller.mjs} +0 -0
  259. /package/{reanimated.d.mts → dist/reanimated.d.mts} +0 -0
  260. /package/{reanimated.d.ts → dist/reanimated.d.ts} +0 -0
  261. /package/{reanimated.js → dist/reanimated.js} +0 -0
  262. /package/{reanimated.mjs → dist/reanimated.mjs} +0 -0
package/index.mjs DELETED
@@ -1,2320 +0,0 @@
1
- import * as React2 from 'react';
2
- import { useReducer, useEffect, createContext, useMemo, useState, useRef, useCallback, useLayoutEffect, useImperativeHandle, useContext, forwardRef, memo } from 'react';
3
- import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl } from 'react-native';
4
- import { useSyncExternalStore } from 'use-sync-external-store/shim';
5
-
6
- // src/LegendList.tsx
7
- var ContextState = React2.createContext(null);
8
- function StateProvider({ children }) {
9
- const [value] = React2.useState(() => ({
10
- listeners: /* @__PURE__ */ new Map(),
11
- values: /* @__PURE__ */ new Map([
12
- ["alignItemsPaddingTop", 0],
13
- ["stylePaddingTop", 0],
14
- ["headerSize", 0]
15
- ]),
16
- mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
17
- mapViewabilityValues: /* @__PURE__ */ new Map(),
18
- mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
19
- mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
20
- columnWrapperStyle: void 0,
21
- viewRefs: /* @__PURE__ */ new Map()
22
- }));
23
- return /* @__PURE__ */ React2.createElement(ContextState.Provider, { value }, children);
24
- }
25
- function useStateContext() {
26
- return React2.useContext(ContextState);
27
- }
28
- function createSelectorFunctionsArr(ctx, signalNames) {
29
- let lastValues = [];
30
- let lastSignalValues = [];
31
- return {
32
- subscribe: (cb) => {
33
- const listeners = [];
34
- for (const signalName of signalNames) {
35
- listeners.push(listen$(ctx, signalName, cb));
36
- }
37
- return () => {
38
- for (const listener of listeners) {
39
- listener();
40
- }
41
- };
42
- },
43
- get: () => {
44
- const currentValues = [];
45
- let hasChanged = false;
46
- for (let i = 0; i < signalNames.length; i++) {
47
- const value = peek$(ctx, signalNames[i]);
48
- currentValues.push(value);
49
- if (value !== lastSignalValues[i]) {
50
- hasChanged = true;
51
- }
52
- }
53
- lastSignalValues = currentValues;
54
- if (hasChanged) {
55
- lastValues = currentValues;
56
- }
57
- return lastValues;
58
- }
59
- };
60
- }
61
- function listen$(ctx, signalName, cb) {
62
- const { listeners } = ctx;
63
- let setListeners = listeners.get(signalName);
64
- if (!setListeners) {
65
- setListeners = /* @__PURE__ */ new Set();
66
- listeners.set(signalName, setListeners);
67
- }
68
- setListeners.add(cb);
69
- return () => setListeners.delete(cb);
70
- }
71
- function peek$(ctx, signalName) {
72
- const { values } = ctx;
73
- return values.get(signalName);
74
- }
75
- function set$(ctx, signalName, value) {
76
- const { listeners, values } = ctx;
77
- if (values.get(signalName) !== value) {
78
- values.set(signalName, value);
79
- const setListeners = listeners.get(signalName);
80
- if (setListeners) {
81
- for (const listener of setListeners) {
82
- listener(value);
83
- }
84
- }
85
- }
86
- }
87
- function getContentSize(ctx) {
88
- const { values } = ctx;
89
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
90
- const headerSize = values.get("headerSize") || 0;
91
- const footerSize = values.get("footerSize") || 0;
92
- const totalSize = values.get("totalSize") || 0;
93
- return headerSize + footerSize + totalSize + stylePaddingTop;
94
- }
95
- function useArr$(signalNames) {
96
- const ctx = React2.useContext(ContextState);
97
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
98
- const value = useSyncExternalStore(subscribe, get);
99
- return value;
100
- }
101
- function useSelector$(signalName, selector) {
102
- const ctx = React2.useContext(ContextState);
103
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
104
- const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
105
- return value;
106
- }
107
-
108
- // src/DebugView.tsx
109
- var DebugRow = ({ children }) => {
110
- return /* @__PURE__ */ React2.createElement(View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
111
- };
112
- var DebugView = React2.memo(function DebugView2({ state }) {
113
- const ctx = useStateContext();
114
- const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, numContainers = 0, numContainersPooled = 0] = useArr$([
115
- "totalSize",
116
- "scrollAdjust",
117
- "debugRawScroll",
118
- "debugComputedScroll",
119
- "numContainers",
120
- "numContainersPooled"
121
- ]);
122
- const contentSize = getContentSize(ctx);
123
- const [, forceUpdate] = useReducer((x) => x + 1, 0);
124
- useInterval(() => {
125
- forceUpdate();
126
- }, 100);
127
- return /* @__PURE__ */ React2.createElement(
128
- View,
129
- {
130
- style: {
131
- position: "absolute",
132
- top: 0,
133
- right: 0,
134
- paddingLeft: 4,
135
- paddingBottom: 4,
136
- // height: 100,
137
- backgroundColor: "#FFFFFFCC",
138
- padding: 4,
139
- borderRadius: 4
140
- },
141
- pointerEvents: "none"
142
- },
143
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2.createElement(Text, null, totalSize.toFixed(2))),
144
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2.createElement(Text, null, contentSize.toFixed(2))),
145
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(state.isAtEnd))),
146
- /* @__PURE__ */ React2.createElement(Text, null),
147
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
148
- /* @__PURE__ */ React2.createElement(Text, null),
149
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React2.createElement(Text, null, rawScroll.toFixed(2))),
150
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React2.createElement(Text, null, scroll.toFixed(2)))
151
- );
152
- });
153
- function useInterval(callback, delay) {
154
- useEffect(() => {
155
- const interval = setInterval(callback, delay);
156
- return () => clearInterval(interval);
157
- }, [delay]);
158
- }
159
-
160
- // src/helpers.ts
161
- function isFunction(obj) {
162
- return typeof obj === "function";
163
- }
164
- function isArray(obj) {
165
- return Array.isArray(obj);
166
- }
167
- var warned = /* @__PURE__ */ new Set();
168
- function warnDevOnce(id, text) {
169
- if (__DEV__ && !warned.has(id)) {
170
- warned.add(id);
171
- console.warn(`[legend-list] ${text}`);
172
- }
173
- }
174
- function isNullOrUndefined(value) {
175
- return value === null || value === void 0;
176
- }
177
- function comparatorByDistance(a, b) {
178
- return b.distance - a.distance;
179
- }
180
- function comparatorDefault(a, b) {
181
- return a - b;
182
- }
183
- function getPadding(s, type) {
184
- var _a, _b, _c;
185
- return (_c = (_b = (_a = s[`padding${type}`]) != null ? _a : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
186
- }
187
- function extractPadding(style, contentContainerStyle, type) {
188
- return getPadding(style, type) + getPadding(contentContainerStyle, type);
189
- }
190
- var symbolFirst = Symbol();
191
- function useInit(cb) {
192
- const refValue = useRef(symbolFirst);
193
- if (refValue.current === symbolFirst) {
194
- refValue.current = cb();
195
- }
196
- return refValue.current;
197
- }
198
-
199
- // src/ContextContainer.ts
200
- var ContextContainer = createContext(null);
201
- function useViewability(callback, configId) {
202
- const ctx = useStateContext();
203
- const { containerId } = useContext(ContextContainer);
204
- const key = containerId + (configId != null ? configId : "");
205
- useInit(() => {
206
- const value = ctx.mapViewabilityValues.get(key);
207
- if (value) {
208
- callback(value);
209
- }
210
- });
211
- ctx.mapViewabilityCallbacks.set(key, callback);
212
- useEffect(
213
- () => () => {
214
- ctx.mapViewabilityCallbacks.delete(key);
215
- },
216
- []
217
- );
218
- }
219
- function useViewabilityAmount(callback) {
220
- const ctx = useStateContext();
221
- const { containerId } = useContext(ContextContainer);
222
- useInit(() => {
223
- const value = ctx.mapViewabilityAmountValues.get(containerId);
224
- if (value) {
225
- callback(value);
226
- }
227
- });
228
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
229
- useEffect(
230
- () => () => {
231
- ctx.mapViewabilityAmountCallbacks.delete(containerId);
232
- },
233
- []
234
- );
235
- }
236
- function useRecyclingEffect(effect) {
237
- const { index, value } = useContext(ContextContainer);
238
- const prevValues = useRef({
239
- prevIndex: void 0,
240
- prevItem: void 0
241
- });
242
- useEffect(() => {
243
- let ret = void 0;
244
- if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
245
- ret = effect({
246
- index,
247
- item: value,
248
- prevIndex: prevValues.current.prevIndex,
249
- prevItem: prevValues.current.prevItem
250
- });
251
- }
252
- prevValues.current = {
253
- prevIndex: index,
254
- prevItem: value
255
- };
256
- return ret;
257
- }, [index, value]);
258
- }
259
- function useRecyclingState(valueOrFun) {
260
- const { index, value, itemKey, triggerLayout } = useContext(ContextContainer);
261
- const refState = useRef({
262
- itemKey: null,
263
- value: null
264
- });
265
- const [_, setRenderNum] = useState(0);
266
- if (refState.current.itemKey !== itemKey) {
267
- refState.current.itemKey = itemKey;
268
- refState.current.value = isFunction(valueOrFun) ? valueOrFun({
269
- index,
270
- item: value,
271
- prevIndex: void 0,
272
- prevItem: void 0
273
- }) : valueOrFun;
274
- }
275
- const setState = useCallback(
276
- (newState) => {
277
- refState.current.value = isFunction(newState) ? newState(refState.current.value) : newState;
278
- setRenderNum((v) => v + 1);
279
- triggerLayout();
280
- },
281
- [triggerLayout]
282
- );
283
- return [refState.current.value, setState];
284
- }
285
- function useIsLastItem() {
286
- const { itemKey } = useContext(ContextContainer);
287
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
288
- return isLast;
289
- }
290
- function useListScrollSize() {
291
- const [scrollSize] = useArr$(["scrollSize"]);
292
- return scrollSize;
293
- }
294
- var LeanViewComponent = React2.forwardRef((props, ref) => {
295
- return React2.createElement("RCTView", { ...props, ref });
296
- });
297
- LeanViewComponent.displayName = "RCTView";
298
- var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComponent : View;
299
-
300
- // src/constants.ts
301
- var POSITION_OUT_OF_VIEW = -1e7;
302
- var ENABLE_DEVMODE = __DEV__ && false;
303
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
304
- var IsNewArchitecture = global.nativeFabricUIManager != null;
305
-
306
- // src/Container.tsx
307
- var Container = ({
308
- id,
309
- recycleItems,
310
- horizontal,
311
- getRenderedItem,
312
- updateItemSize,
313
- ItemSeparatorComponent
314
- }) => {
315
- const ctx = useStateContext();
316
- const columnWrapperStyle = ctx.columnWrapperStyle;
317
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, lastItemKeys, extraData] = useArr$([
318
- `containerColumn${id}`,
319
- `containerItemData${id}`,
320
- `containerItemKey${id}`,
321
- `containerPosition${id}`,
322
- "numColumns",
323
- "lastItemKeys",
324
- "extraData"
325
- ]);
326
- const refLastSize = useRef();
327
- const ref = useRef(null);
328
- const [layoutRenderCount, forceLayoutRender] = useState(0);
329
- const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
330
- const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
331
- const isALastItem = lastItemKeys.includes(itemKey);
332
- let didLayout = false;
333
- let paddingStyles;
334
- if (columnWrapperStyle) {
335
- const { columnGap, rowGap, gap } = columnWrapperStyle;
336
- if (horizontal) {
337
- paddingStyles = {
338
- paddingRight: !isALastItem ? columnGap || gap || void 0 : void 0,
339
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
340
- };
341
- } else {
342
- paddingStyles = {
343
- paddingBottom: !isALastItem ? rowGap || gap || void 0 : void 0,
344
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
345
- };
346
- }
347
- }
348
- const style = horizontal ? {
349
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
350
- position: "absolute",
351
- top: otherAxisPos,
352
- height: otherAxisSize,
353
- left: position,
354
- ...paddingStyles || {}
355
- } : {
356
- position: "absolute",
357
- left: otherAxisPos,
358
- right: numColumns > 1 ? null : 0,
359
- width: otherAxisSize,
360
- top: position,
361
- ...paddingStyles || {}
362
- };
363
- const renderedItemInfo = useMemo(
364
- () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
365
- [itemKey, data, extraData]
366
- );
367
- const { index, renderedItem } = renderedItemInfo || {};
368
- const triggerLayout = useCallback(() => {
369
- forceLayoutRender((v) => v + 1);
370
- }, []);
371
- const contextValue = useMemo(() => {
372
- ctx.viewRefs.set(id, ref);
373
- return { containerId: id, itemKey, index, value: data, triggerLayout };
374
- }, [id, itemKey, index, data]);
375
- const onLayout = (event) => {
376
- var _a, _b;
377
- if (!isNullOrUndefined(itemKey)) {
378
- didLayout = true;
379
- let layout = event.nativeEvent.layout;
380
- const size = layout[horizontal ? "width" : "height"];
381
- const doUpdate = () => {
382
- refLastSize.current = { width: layout.width, height: layout.height };
383
- updateItemSize(itemKey, layout);
384
- };
385
- if (IsNewArchitecture || size > 0) {
386
- doUpdate();
387
- } else {
388
- (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (x, y, width, height) => {
389
- layout = { width, height };
390
- doUpdate();
391
- });
392
- }
393
- }
394
- };
395
- if (IsNewArchitecture) {
396
- useLayoutEffect(() => {
397
- var _a, _b;
398
- if (!isNullOrUndefined(itemKey)) {
399
- const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
400
- if (measured) {
401
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
402
- if (size) {
403
- updateItemSize(itemKey, measured);
404
- }
405
- }
406
- }
407
- }, [itemKey, layoutRenderCount, isALastItem]);
408
- } else {
409
- useEffect(() => {
410
- if (!isNullOrUndefined(itemKey)) {
411
- const timeout = setTimeout(() => {
412
- if (!didLayout && refLastSize.current) {
413
- updateItemSize(itemKey, refLastSize.current);
414
- }
415
- }, 16);
416
- return () => {
417
- clearTimeout(timeout);
418
- };
419
- }
420
- }, [itemKey]);
421
- }
422
- return /* @__PURE__ */ React2.createElement(LeanView, { style, onLayout, ref, key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !isALastItem && /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
423
- };
424
- var typedForwardRef = forwardRef;
425
- var typedMemo = memo;
426
- var useAnimatedValue = (initialValue) => {
427
- return useRef(new Animated.Value(initialValue)).current;
428
- };
429
-
430
- // src/useValue$.ts
431
- function useValue$(key, params) {
432
- var _a;
433
- const { getValue, delay } = params || {};
434
- const ctx = useStateContext();
435
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
436
- useMemo(() => {
437
- let newValue = void 0;
438
- let prevValue = void 0;
439
- let didQueueTask = false;
440
- listen$(ctx, key, (v) => {
441
- newValue = getValue ? getValue(v) : v;
442
- if (delay !== void 0) {
443
- const fn = () => {
444
- didQueueTask = false;
445
- if (newValue !== void 0) {
446
- animValue.setValue(newValue);
447
- }
448
- };
449
- const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
450
- prevValue = newValue;
451
- if (!didQueueTask) {
452
- didQueueTask = true;
453
- if (delayValue === 0) {
454
- queueMicrotask(fn);
455
- } else {
456
- setTimeout(fn, delayValue);
457
- }
458
- }
459
- } else {
460
- animValue.setValue(newValue);
461
- }
462
- });
463
- }, []);
464
- return animValue;
465
- }
466
-
467
- // src/Containers.tsx
468
- var Containers = typedMemo(function Containers2({
469
- horizontal,
470
- recycleItems,
471
- ItemSeparatorComponent,
472
- waitForInitialLayout,
473
- updateItemSize,
474
- getRenderedItem
475
- }) {
476
- const ctx = useStateContext();
477
- const columnWrapperStyle = ctx.columnWrapperStyle;
478
- const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
479
- const animSize = useValue$("totalSize", {
480
- // Use a microtask if increasing the size significantly, otherwise use a timeout
481
- delay: (value, prevValue) => !prevValue || value - prevValue > 20 ? 0 : 200
482
- });
483
- const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
484
- const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
485
- const containers = [];
486
- for (let i = 0; i < numContainers; i++) {
487
- containers.push(
488
- /* @__PURE__ */ React2.createElement(
489
- Container,
490
- {
491
- id: i,
492
- key: i,
493
- recycleItems,
494
- horizontal,
495
- getRenderedItem,
496
- updateItemSize,
497
- ItemSeparatorComponent
498
- }
499
- )
500
- );
501
- }
502
- const style = horizontal ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize } : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
503
- if (columnWrapperStyle && numColumns > 1) {
504
- const { columnGap, rowGap, gap } = columnWrapperStyle;
505
- if (horizontal) {
506
- const my = (rowGap || gap || 0) / 2;
507
- if (my) {
508
- style.marginVertical = -my;
509
- }
510
- } else {
511
- const mx = (columnGap || gap || 0) / 2;
512
- if (mx) {
513
- style.marginHorizontal = -mx;
514
- }
515
- }
516
- }
517
- return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
518
- });
519
- function ScrollAdjust() {
520
- const bias = 1e7;
521
- const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
522
- const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
523
- return /* @__PURE__ */ React2.createElement(
524
- View,
525
- {
526
- style: {
527
- position: "absolute",
528
- height: 0,
529
- width: 0,
530
- top: scrollOffset,
531
- left: 0
532
- }
533
- }
534
- );
535
- }
536
- function useSyncLayout({
537
- onChange
538
- }) {
539
- const ref = useRef(null);
540
- const onLayout = useCallback(
541
- (event) => {
542
- onChange(event.nativeEvent.layout, false);
543
- },
544
- [onChange]
545
- );
546
- useLayoutEffect(() => {
547
- if (ref.current) {
548
- ref.current.measure((x, y, width, height) => {
549
- onChange({ x, y, width, height }, true);
550
- });
551
- }
552
- }, []);
553
- return { onLayout, ref };
554
- }
555
-
556
- // src/ListComponent.tsx
557
- var getComponent = (Component) => {
558
- if (React2.isValidElement(Component)) {
559
- return Component;
560
- }
561
- if (Component) {
562
- return /* @__PURE__ */ React2.createElement(Component, null);
563
- }
564
- return null;
565
- };
566
- var Padding = () => {
567
- const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
568
- return /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } });
569
- };
570
- var PaddingDevMode = () => {
571
- const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
572
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React2.createElement(
573
- Animated.View,
574
- {
575
- style: {
576
- position: "absolute",
577
- top: 0,
578
- height: animPaddingTop,
579
- left: 0,
580
- right: 0,
581
- backgroundColor: "green"
582
- }
583
- }
584
- ));
585
- };
586
- var ListComponent = typedMemo(function ListComponent2({
587
- canRender,
588
- style,
589
- contentContainerStyle,
590
- horizontal,
591
- initialContentOffset,
592
- recycleItems,
593
- ItemSeparatorComponent,
594
- alignItemsAtEnd,
595
- waitForInitialLayout,
596
- handleScroll,
597
- onLayout,
598
- ListHeaderComponent,
599
- ListHeaderComponentStyle,
600
- ListFooterComponent,
601
- ListFooterComponentStyle,
602
- ListEmptyComponent,
603
- getRenderedItem,
604
- updateItemSize,
605
- refScrollView,
606
- maintainVisibleContentPosition,
607
- renderScrollComponent,
608
- scrollAdjustHandler,
609
- onLayoutHeader,
610
- ...rest
611
- }) {
612
- const ctx = useStateContext();
613
- const { onLayout: onLayoutHeaderSync, ref: refHeader } = useSyncLayout({
614
- onChange: onLayoutHeader
615
- });
616
- const ScrollComponent = renderScrollComponent ? useMemo(
617
- () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
618
- [renderScrollComponent]
619
- ) : ScrollView;
620
- React2.useEffect(() => {
621
- if (canRender) {
622
- setTimeout(() => {
623
- scrollAdjustHandler.setMounted();
624
- }, 0);
625
- }
626
- }, [canRender]);
627
- return /* @__PURE__ */ React2.createElement(
628
- ScrollComponent,
629
- {
630
- ...rest,
631
- style,
632
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
633
- contentContainerStyle: [
634
- contentContainerStyle,
635
- horizontal ? {
636
- height: "100%"
637
- } : {}
638
- ],
639
- onScroll: handleScroll,
640
- onLayout,
641
- horizontal,
642
- contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
643
- ref: refScrollView
644
- },
645
- maintainVisibleContentPosition && /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
646
- ENABLE_DEVMODE ? /* @__PURE__ */ React2.createElement(PaddingDevMode, null) : /* @__PURE__ */ React2.createElement(Padding, null),
647
- ListHeaderComponent && /* @__PURE__ */ React2.createElement(View, { style: ListHeaderComponentStyle, onLayout: onLayoutHeaderSync, ref: refHeader }, getComponent(ListHeaderComponent)),
648
- ListEmptyComponent && getComponent(ListEmptyComponent),
649
- canRender && /* @__PURE__ */ React2.createElement(
650
- Containers,
651
- {
652
- horizontal,
653
- recycleItems,
654
- waitForInitialLayout,
655
- getRenderedItem,
656
- ItemSeparatorComponent,
657
- updateItemSize
658
- }
659
- ),
660
- ListFooterComponent && /* @__PURE__ */ React2.createElement(
661
- View,
662
- {
663
- style: ListFooterComponentStyle,
664
- onLayout: (event) => {
665
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
666
- set$(ctx, "footerSize", size);
667
- }
668
- },
669
- getComponent(ListFooterComponent)
670
- )
671
- );
672
- });
673
-
674
- // src/ScrollAdjustHandler.ts
675
- var ScrollAdjustHandler = class {
676
- constructor(ctx) {
677
- this.appliedAdjust = 0;
678
- this.mounted = false;
679
- this.context = ctx;
680
- }
681
- requestAdjust(add) {
682
- const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
683
- this.appliedAdjust = add + oldAdjustTop;
684
- const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
685
- if (this.mounted) {
686
- set();
687
- } else {
688
- requestAnimationFrame(set);
689
- }
690
- }
691
- setMounted() {
692
- this.mounted = true;
693
- }
694
- };
695
- var useCombinedRef = (...refs) => {
696
- const callback = useCallback((element) => {
697
- for (const ref of refs) {
698
- if (!ref) {
699
- continue;
700
- }
701
- if (isFunction(ref)) {
702
- ref(element);
703
- } else {
704
- ref.current = element;
705
- }
706
- }
707
- }, refs);
708
- return callback;
709
- };
710
-
711
- // src/viewability.ts
712
- var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
713
- function setupViewability(props) {
714
- let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
715
- if (viewabilityConfig || onViewableItemsChanged) {
716
- viewabilityConfigCallbackPairs = [
717
- ...viewabilityConfigCallbackPairs || [],
718
- {
719
- viewabilityConfig: viewabilityConfig || {
720
- viewAreaCoveragePercentThreshold: 0
721
- },
722
- onViewableItemsChanged
723
- }
724
- ];
725
- }
726
- if (viewabilityConfigCallbackPairs) {
727
- for (const pair of viewabilityConfigCallbackPairs) {
728
- mapViewabilityConfigCallbackPairs.set(pair.viewabilityConfig.id, {
729
- viewableItems: [],
730
- start: -1,
731
- end: -1,
732
- previousStart: -1,
733
- previousEnd: -1
734
- });
735
- }
736
- }
737
- return viewabilityConfigCallbackPairs;
738
- }
739
- function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId, scrollSize, start, end) {
740
- for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
741
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(
742
- viewabilityConfigCallbackPair.viewabilityConfig.id
743
- );
744
- viewabilityState.start = start;
745
- viewabilityState.end = end;
746
- if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
747
- const timer = setTimeout(() => {
748
- state.timeouts.delete(timer);
749
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
750
- }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
751
- state.timeouts.add(timer);
752
- } else {
753
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
754
- }
755
- }
756
- }
757
- function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize) {
758
- const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
759
- const configId = viewabilityConfig.id;
760
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
761
- const { viewableItems: previousViewableItems, start, end } = viewabilityState;
762
- const viewabilityTokens = /* @__PURE__ */ new Map();
763
- for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
764
- viewabilityTokens.set(
765
- containerId,
766
- computeViewability(
767
- state,
768
- ctx,
769
- viewabilityConfig,
770
- containerId,
771
- value.key,
772
- scrollSize,
773
- value.item,
774
- value.index
775
- )
776
- );
777
- }
778
- const changed = [];
779
- if (previousViewableItems) {
780
- for (const viewToken of previousViewableItems) {
781
- const containerId = findContainerId(ctx, viewToken.key);
782
- if (!isViewable(
783
- state,
784
- ctx,
785
- viewabilityConfig,
786
- containerId,
787
- viewToken.key,
788
- scrollSize,
789
- viewToken.item,
790
- viewToken.index
791
- )) {
792
- viewToken.isViewable = false;
793
- changed.push(viewToken);
794
- }
795
- }
796
- }
797
- const viewableItems = [];
798
- for (let i = start; i <= end; i++) {
799
- const item = data[i];
800
- if (item) {
801
- const key = getId(i);
802
- const containerId = findContainerId(ctx, key);
803
- if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
804
- const viewToken = {
805
- item,
806
- key,
807
- index: i,
808
- isViewable: true,
809
- containerId
810
- };
811
- viewableItems.push(viewToken);
812
- if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
813
- changed.push(viewToken);
814
- }
815
- }
816
- }
817
- }
818
- Object.assign(viewabilityState, {
819
- viewableItems,
820
- previousStart: start,
821
- previousEnd: end
822
- });
823
- if (changed.length > 0) {
824
- viewabilityState.viewableItems = viewableItems;
825
- for (let i = 0; i < changed.length; i++) {
826
- const change = changed[i];
827
- maybeUpdateViewabilityCallback(ctx, configId, change.containerId, change);
828
- }
829
- if (onViewableItemsChanged) {
830
- onViewableItemsChanged({ viewableItems, changed });
831
- }
832
- }
833
- for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
834
- if (value.sizeVisible < 0) {
835
- ctx.mapViewabilityAmountValues.delete(containerId);
836
- }
837
- }
838
- }
839
- function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
840
- const { sizes, positions, scroll: scrollState } = state;
841
- const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
842
- const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
843
- const viewAreaMode = viewAreaCoveragePercentThreshold != null;
844
- const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
845
- const scroll = scrollState - topPad;
846
- const top = positions.get(key) - scroll;
847
- const size = sizes.get(key) || 0;
848
- const bottom = top + size;
849
- const isEntirelyVisible = top >= 0 && bottom <= scrollSize && bottom > top;
850
- const sizeVisible = isEntirelyVisible ? size : Math.min(bottom, scrollSize) - Math.max(top, 0);
851
- const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
852
- const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
853
- const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
854
- const isViewable2 = percent >= viewablePercentThreshold;
855
- const value = {
856
- index,
857
- isViewable: isViewable2,
858
- item,
859
- key,
860
- percentVisible,
861
- percentOfScroller,
862
- sizeVisible,
863
- size,
864
- scrollSize,
865
- containerId
866
- };
867
- if (JSON.stringify(value) !== JSON.stringify(ctx.mapViewabilityAmountValues.get(containerId))) {
868
- ctx.mapViewabilityAmountValues.set(containerId, value);
869
- const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
870
- if (cb) {
871
- cb(value);
872
- }
873
- }
874
- return value;
875
- }
876
- function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
877
- const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
878
- return value.isViewable;
879
- }
880
- function findContainerId(ctx, key) {
881
- const numContainers = peek$(ctx, "numContainers");
882
- for (let i = 0; i < numContainers; i++) {
883
- const itemKey = peek$(ctx, `containerItemKey${i}`);
884
- if (itemKey === key) {
885
- return i;
886
- }
887
- }
888
- return -1;
889
- }
890
- function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
891
- const key = containerId + configId;
892
- ctx.mapViewabilityValues.set(key, viewToken);
893
- const cb = ctx.mapViewabilityCallbacks.get(key);
894
- cb == null ? void 0 : cb(viewToken);
895
- }
896
-
897
- // src/LegendList.tsx
898
- var DEFAULT_DRAW_DISTANCE = 250;
899
- var DEFAULT_ITEM_SIZE = 100;
900
- function createColumnWrapperStyle(contentContainerStyle) {
901
- const { gap, columnGap, rowGap } = contentContainerStyle;
902
- if (gap || columnGap || rowGap) {
903
- contentContainerStyle.gap = void 0;
904
- contentContainerStyle.columnGap = void 0;
905
- contentContainerStyle.rowGap = void 0;
906
- return {
907
- gap,
908
- columnGap,
909
- rowGap
910
- };
911
- }
912
- }
913
- var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
914
- return /* @__PURE__ */ React2.createElement(StateProvider, null, /* @__PURE__ */ React2.createElement(LegendListInner, { ...props, ref: forwardedRef }));
915
- });
916
- var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
917
- var _a;
918
- const {
919
- data: dataProp = [],
920
- initialScrollIndex: initialScrollIndexProp,
921
- initialScrollOffset,
922
- horizontal,
923
- drawDistance = 250,
924
- recycleItems = false,
925
- onEndReachedThreshold = 0.5,
926
- onStartReachedThreshold = 0.5,
927
- maintainScrollAtEnd = false,
928
- maintainScrollAtEndThreshold = 0.1,
929
- alignItemsAtEnd = false,
930
- maintainVisibleContentPosition = false,
931
- onScroll: onScrollProp,
932
- onMomentumScrollEnd,
933
- numColumns: numColumnsProp = 1,
934
- columnWrapperStyle,
935
- keyExtractor: keyExtractorProp,
936
- renderItem: renderItem2,
937
- estimatedListSize,
938
- estimatedItemSize: estimatedItemSizeProp,
939
- getEstimatedItemSize,
940
- suggestEstimatedItemSize,
941
- ListHeaderComponent,
942
- ListEmptyComponent,
943
- onItemSizeChanged,
944
- refScrollView,
945
- waitForInitialLayout = true,
946
- extraData,
947
- contentContainerStyle: contentContainerStyleProp,
948
- style: styleProp,
949
- onLayout: onLayoutProp,
950
- onRefresh,
951
- refreshing,
952
- progressViewOffset,
953
- refreshControl,
954
- initialContainerPoolRatio = 2,
955
- viewabilityConfig,
956
- viewabilityConfigCallbackPairs,
957
- onViewableItemsChanged,
958
- ...rest
959
- } = props;
960
- const [renderNum, setRenderNum] = useState(0);
961
- const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
962
- const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
963
- const refLoadStartTime = useRef(Date.now());
964
- const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
965
- const callbacks = useRef({
966
- onStartReached: rest.onStartReached,
967
- onEndReached: rest.onEndReached
968
- });
969
- callbacks.current.onStartReached = rest.onStartReached;
970
- callbacks.current.onEndReached = rest.onEndReached;
971
- const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
972
- const style = { ...StyleSheet.flatten(styleProp) };
973
- const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
974
- const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
975
- const ctx = useStateContext();
976
- ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
977
- const refScroller = useRef(null);
978
- const combinedRef = useCombinedRef(refScroller, refScrollView);
979
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
980
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
981
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
982
- const refState = useRef();
983
- const getId = (index) => {
984
- const state = refState.current;
985
- if (!(state == null ? void 0 : state.data)) {
986
- return "";
987
- }
988
- const data = state.data;
989
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
990
- const id = ret;
991
- state.idCache.set(index, id);
992
- return id;
993
- };
994
- const getItemSize = (key, index, data, useAverageSize = false) => {
995
- const state = refState.current;
996
- const sizeKnown = state.sizesKnown.get(key);
997
- if (sizeKnown !== void 0) {
998
- return sizeKnown;
999
- }
1000
- const sizePrevious = state.sizes.get(key);
1001
- if (sizePrevious !== void 0) {
1002
- return sizePrevious;
1003
- }
1004
- const size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
1005
- state.sizes.set(key, size);
1006
- return size;
1007
- };
1008
- const calculateOffsetForIndex = (index) => {
1009
- var _a2;
1010
- let position = 0;
1011
- if (index !== void 0) {
1012
- position = ((_a2 = refState.current) == null ? void 0 : _a2.positions.get(getId(index))) || 0;
1013
- }
1014
- const paddingTop = peek$(ctx, "stylePaddingTop");
1015
- if (paddingTop) {
1016
- position += paddingTop;
1017
- }
1018
- const headerSize = peek$(ctx, "headerSize");
1019
- if (headerSize) {
1020
- position += headerSize;
1021
- }
1022
- return position;
1023
- };
1024
- const calculateOffsetWithOffsetPosition = (offsetParam, params) => {
1025
- const { index, viewOffset, viewPosition } = params;
1026
- let offset = offsetParam;
1027
- const state = refState.current;
1028
- if (viewOffset) {
1029
- offset -= viewOffset;
1030
- }
1031
- if (viewPosition !== void 0 && index !== void 0) {
1032
- offset -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1033
- }
1034
- return offset;
1035
- };
1036
- if (!refState.current) {
1037
- const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { width: 0, height: 0 } : Dimensions.get("window"))[horizontal ? "width" : "height"];
1038
- refState.current = {
1039
- sizes: /* @__PURE__ */ new Map(),
1040
- positions: /* @__PURE__ */ new Map(),
1041
- columns: /* @__PURE__ */ new Map(),
1042
- pendingAdjust: 0,
1043
- isStartReached: false,
1044
- isEndReached: false,
1045
- isAtEnd: false,
1046
- isAtStart: false,
1047
- data: dataProp,
1048
- scrollLength: initialScrollLength,
1049
- startBuffered: -1,
1050
- startNoBuffer: -1,
1051
- endBuffered: -1,
1052
- endNoBuffer: -1,
1053
- firstFullyOnScreenIndex: -1,
1054
- scroll: 0,
1055
- totalSize: 0,
1056
- timeouts: /* @__PURE__ */ new Set(),
1057
- viewabilityConfigCallbackPairs: void 0,
1058
- renderItem: void 0,
1059
- scrollAdjustHandler: new ScrollAdjustHandler(ctx),
1060
- nativeMarginTop: 0,
1061
- scrollPrev: 0,
1062
- scrollPrevTime: 0,
1063
- scrollTime: 0,
1064
- scrollPending: 0,
1065
- indexByKey: /* @__PURE__ */ new Map(),
1066
- scrollHistory: [],
1067
- sizesKnown: /* @__PURE__ */ new Map(),
1068
- timeoutSizeMessage: 0,
1069
- startReachedBlockedByTimer: false,
1070
- endReachedBlockedByTimer: false,
1071
- scrollForNextCalculateItemsInView: void 0,
1072
- enableScrollForNextCalculateItemsInView: true,
1073
- minIndexSizeChanged: 0,
1074
- queuedCalculateItemsInView: 0,
1075
- lastBatchingAction: Date.now(),
1076
- averageSizes: {},
1077
- onScroll: onScrollProp,
1078
- idsInView: [],
1079
- containerItemKeys: /* @__PURE__ */ new Set(),
1080
- idCache: /* @__PURE__ */ new Map()
1081
- };
1082
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
1083
- set$(ctx, "extraData", extraData);
1084
- }
1085
- const didDataChange = refState.current.data !== dataProp;
1086
- refState.current.data = dataProp;
1087
- refState.current.onScroll = onScrollProp;
1088
- const getScrollVelocity = () => {
1089
- const { scrollHistory } = refState.current;
1090
- let velocity = 0;
1091
- if (scrollHistory.length >= 1) {
1092
- const newest = scrollHistory[scrollHistory.length - 1];
1093
- let oldest;
1094
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1095
- const entry = scrollHistory[i];
1096
- const nextEntry = scrollHistory[i + 1];
1097
- if (i > 0) {
1098
- const prevEntry = scrollHistory[i - 1];
1099
- const prevDirection = entry.scroll - prevEntry.scroll;
1100
- const currentDirection = nextEntry.scroll - entry.scroll;
1101
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1102
- break;
1103
- }
1104
- }
1105
- }
1106
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1107
- const entry = scrollHistory[i];
1108
- if (newest.time - entry.time <= 1e3) {
1109
- oldest = entry;
1110
- break;
1111
- }
1112
- }
1113
- if (oldest) {
1114
- const scrollDiff = newest.scroll - oldest.scroll;
1115
- const timeDiff = newest.time - oldest.time;
1116
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1117
- }
1118
- }
1119
- return velocity;
1120
- };
1121
- const updateAllPositions = (dataChanged) => {
1122
- var _a2, _b, _c;
1123
- const { columns, data, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizes } = refState.current;
1124
- const numColumns = (_a2 = peek$(ctx, "numColumns")) != null ? _a2 : numColumnsProp;
1125
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1126
- const scrollVelocity = getScrollVelocity();
1127
- if (dataChanged) {
1128
- indexByKey.clear();
1129
- idCache.clear();
1130
- }
1131
- const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1132
- if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1133
- const anchorId = getId(firstFullyOnScreenIndex);
1134
- const anchorPosition = positions.get(anchorId);
1135
- if (anchorPosition !== void 0) {
1136
- let currentRowTop2 = anchorPosition;
1137
- let maxSizeInRow2 = 0;
1138
- let bailout = false;
1139
- for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1140
- const id = getId(i);
1141
- const size = getItemSize(id, i, data[i], false);
1142
- const itemColumn = columns.get(id);
1143
- maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1144
- if (itemColumn === 1) {
1145
- currentRowTop2 -= maxSizeInRow2;
1146
- maxSizeInRow2 = 0;
1147
- }
1148
- if (currentRowTop2 < -2e3) {
1149
- bailout = true;
1150
- break;
1151
- }
1152
- positions.set(id, currentRowTop2);
1153
- }
1154
- if (!bailout) {
1155
- updateTotalSize();
1156
- return;
1157
- }
1158
- }
1159
- }
1160
- let currentRowTop = 0;
1161
- let column = 1;
1162
- let maxSizeInRow = 0;
1163
- const hasColumns = numColumns > 1;
1164
- const needsIndexByKey = dataChanged || indexByKey.size === 0;
1165
- const dataLength = data.length;
1166
- for (let i = 0; i < dataLength; i++) {
1167
- const id = (_b = idCache.get(i)) != null ? _b : getId(i);
1168
- const size = (_c = sizes.get(id)) != null ? _c : getItemSize(id, i, data[i], false);
1169
- if (__DEV__ && needsIndexByKey) {
1170
- if (indexByKeyForChecking.has(id)) {
1171
- console.error(
1172
- `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1173
- );
1174
- }
1175
- indexByKeyForChecking.set(id, i);
1176
- }
1177
- positions.set(id, currentRowTop);
1178
- if (needsIndexByKey) {
1179
- indexByKey.set(id, i);
1180
- }
1181
- columns.set(id, column);
1182
- if (hasColumns) {
1183
- if (size > maxSizeInRow) {
1184
- maxSizeInRow = size;
1185
- }
1186
- column++;
1187
- if (column > numColumns) {
1188
- currentRowTop += maxSizeInRow;
1189
- column = 1;
1190
- maxSizeInRow = 0;
1191
- }
1192
- } else {
1193
- currentRowTop += size;
1194
- }
1195
- }
1196
- updateTotalSize();
1197
- };
1198
- const scrollToIndex = ({
1199
- index,
1200
- viewOffset = 0,
1201
- animated = true,
1202
- viewPosition
1203
- }) => {
1204
- const state = refState.current;
1205
- if (index >= state.data.length) {
1206
- index = state.data.length - 1;
1207
- } else if (index < 0) {
1208
- index = 0;
1209
- }
1210
- const firstIndexOffset = calculateOffsetForIndex(index);
1211
- const isLast = index === state.data.length - 1;
1212
- if (isLast && viewPosition === void 0) {
1213
- viewPosition = 1;
1214
- }
1215
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1216
- state.scrollForNextCalculateItemsInView = void 0;
1217
- scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition: viewPosition != null ? viewPosition : 0, viewOffset });
1218
- };
1219
- const setDidLayout = () => {
1220
- refState.current.queuedInitialLayout = true;
1221
- checkAtBottom();
1222
- set$(ctx, "containersDidLayout", true);
1223
- if (props.onLoad) {
1224
- props.onLoad({ elapsedTimeInMs: Date.now() - refLoadStartTime.current });
1225
- }
1226
- };
1227
- const addTotalSize = useCallback((key, add) => {
1228
- const state = refState.current;
1229
- if (key === null) {
1230
- state.totalSize = add;
1231
- } else {
1232
- state.totalSize += add;
1233
- }
1234
- set$(ctx, "totalSize", state.totalSize);
1235
- if (alignItemsAtEnd) {
1236
- updateAlignItemsPaddingTop();
1237
- }
1238
- }, []);
1239
- const checkAllSizesKnown = useCallback(() => {
1240
- const { startBuffered, endBuffered, sizesKnown } = refState.current;
1241
- if (endBuffered !== null) {
1242
- let areAllKnown = true;
1243
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1244
- const key = getId(i);
1245
- areAllKnown && (areAllKnown = sizesKnown.has(key));
1246
- }
1247
- return areAllKnown;
1248
- }
1249
- return false;
1250
- }, []);
1251
- const requestAdjust = (positionDiff) => {
1252
- if (Math.abs(positionDiff) > 0.1) {
1253
- const state = refState.current;
1254
- const doit = () => {
1255
- state.scrollAdjustHandler.requestAdjust(positionDiff);
1256
- };
1257
- state.scroll += positionDiff;
1258
- state.scrollForNextCalculateItemsInView = void 0;
1259
- if (peek$(ctx, "containersDidLayout")) {
1260
- doit();
1261
- } else {
1262
- requestAnimationFrame(doit);
1263
- }
1264
- const threshold = state.scroll - positionDiff / 2;
1265
- if (!state.ignoreScrollFromMVCP) {
1266
- state.ignoreScrollFromMVCP = {};
1267
- }
1268
- if (positionDiff > 0) {
1269
- state.ignoreScrollFromMVCP.lt = threshold;
1270
- } else {
1271
- state.ignoreScrollFromMVCP.gt = threshold;
1272
- }
1273
- if (state.ignoreScrollFromMVCPTimeout) {
1274
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1275
- }
1276
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
1277
- state.ignoreScrollFromMVCP = void 0;
1278
- }, 100);
1279
- }
1280
- };
1281
- const prepareMVCP = useCallback(() => {
1282
- const state = refState.current;
1283
- const { positions, scrollingTo } = state;
1284
- let prevPosition;
1285
- let targetId;
1286
- let targetIndex;
1287
- const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1288
- if (maintainVisibleContentPosition) {
1289
- const indexByKey = state.indexByKey;
1290
- if (scrollTarget !== void 0) {
1291
- targetId = getId(scrollTarget);
1292
- targetIndex = scrollTarget;
1293
- } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1294
- targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
1295
- targetIndex = indexByKey.get(targetId);
1296
- }
1297
- if (targetId !== void 0 && targetIndex !== void 0) {
1298
- prevPosition = positions.get(targetId);
1299
- }
1300
- }
1301
- return () => {
1302
- if (targetId !== void 0 && prevPosition !== void 0) {
1303
- const newPosition = positions.get(targetId);
1304
- if (newPosition !== void 0) {
1305
- const positionDiff = newPosition - prevPosition;
1306
- if (Math.abs(positionDiff) > 0.1) {
1307
- requestAdjust(positionDiff);
1308
- }
1309
- }
1310
- }
1311
- };
1312
- }, []);
1313
- const calculateItemsInView = useCallback((params = {}) => {
1314
- var _a2, _b, _c, _d, _e, _f, _g, _h;
1315
- const state = refState.current;
1316
- const {
1317
- data,
1318
- scrollLength,
1319
- startBufferedId: startBufferedIdOrig,
1320
- positions,
1321
- columns,
1322
- containerItemKeys,
1323
- idCache,
1324
- sizes,
1325
- indexByKey,
1326
- scrollForNextCalculateItemsInView,
1327
- enableScrollForNextCalculateItemsInView,
1328
- minIndexSizeChanged
1329
- } = state;
1330
- if (!data || scrollLength === 0) {
1331
- return;
1332
- }
1333
- const totalSize = peek$(ctx, "totalSize");
1334
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1335
- const numColumns = peek$(ctx, "numColumns");
1336
- const previousScrollAdjust = 0;
1337
- const { dataChanged, doMVCP } = params;
1338
- const speed = getScrollVelocity();
1339
- if (doMVCP || dataChanged) {
1340
- const checkMVCP = doMVCP ? prepareMVCP() : void 0;
1341
- updateAllPositions(dataChanged);
1342
- checkMVCP == null ? void 0 : checkMVCP();
1343
- }
1344
- const scrollExtra = 0;
1345
- const useAverageSize = false;
1346
- const { queuedInitialLayout } = state;
1347
- let { scroll: scrollState } = state;
1348
- if (!queuedInitialLayout && initialScroll) {
1349
- const updatedOffset = calculateOffsetWithOffsetPosition(
1350
- calculateOffsetForIndex(initialScroll.index),
1351
- initialScroll
1352
- );
1353
- scrollState = updatedOffset;
1354
- }
1355
- const scrollAdjustPad = -previousScrollAdjust - topPad;
1356
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
1357
- if (scroll + scrollLength > totalSize) {
1358
- scroll = totalSize - scrollLength;
1359
- }
1360
- if (ENABLE_DEBUG_VIEW) {
1361
- set$(ctx, "debugRawScroll", scrollState);
1362
- set$(ctx, "debugComputedScroll", scroll);
1363
- }
1364
- let scrollBufferTop = scrollBuffer;
1365
- let scrollBufferBottom = scrollBuffer;
1366
- if (speed > 0) {
1367
- scrollBufferTop = scrollBuffer * 0.5;
1368
- scrollBufferBottom = scrollBuffer * 1.5;
1369
- } else {
1370
- scrollBufferTop = scrollBuffer * 1.5;
1371
- scrollBufferBottom = scrollBuffer * 0.5;
1372
- }
1373
- const scrollTopBuffered = scroll - scrollBufferTop;
1374
- const scrollBottom = scroll + scrollLength;
1375
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1376
- if (scrollForNextCalculateItemsInView) {
1377
- const { top, bottom } = scrollForNextCalculateItemsInView;
1378
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1379
- return;
1380
- }
1381
- }
1382
- let startNoBuffer = null;
1383
- let startBuffered = null;
1384
- let startBufferedId = null;
1385
- let endNoBuffer = null;
1386
- let endBuffered = null;
1387
- let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1388
- if (minIndexSizeChanged !== void 0) {
1389
- loopStart = Math.min(minIndexSizeChanged, loopStart);
1390
- state.minIndexSizeChanged = void 0;
1391
- }
1392
- for (let i = loopStart; i >= 0; i--) {
1393
- const id = (_a2 = idCache.get(i)) != null ? _a2 : getId(i);
1394
- const top = positions.get(id);
1395
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(id, i, data[i], useAverageSize);
1396
- const bottom = top + size;
1397
- if (bottom > scroll - scrollBuffer) {
1398
- loopStart = i;
1399
- } else {
1400
- break;
1401
- }
1402
- }
1403
- const loopStartMod = loopStart % numColumns;
1404
- if (loopStartMod > 0) {
1405
- loopStart -= loopStartMod;
1406
- }
1407
- let foundEnd = false;
1408
- let nextTop;
1409
- let nextBottom;
1410
- const prevNumContainers = ctx.values.get("numContainers");
1411
- let maxIndexRendered = 0;
1412
- for (let i = 0; i < prevNumContainers; i++) {
1413
- const key = peek$(ctx, `containerItemKey${i}`);
1414
- if (key !== void 0) {
1415
- const index = indexByKey.get(key);
1416
- maxIndexRendered = Math.max(maxIndexRendered, index);
1417
- }
1418
- }
1419
- let firstFullyOnScreenIndex;
1420
- const dataLength = data.length;
1421
- for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1422
- const id = (_c = idCache.get(i)) != null ? _c : getId(i);
1423
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(id, i, data[i], useAverageSize);
1424
- const top = positions.get(id);
1425
- if (!foundEnd) {
1426
- if (startNoBuffer === null && top + size > scroll) {
1427
- startNoBuffer = i;
1428
- }
1429
- if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1430
- firstFullyOnScreenIndex = i;
1431
- }
1432
- if (startBuffered === null && top + size > scrollTopBuffered) {
1433
- startBuffered = i;
1434
- startBufferedId = id;
1435
- nextTop = top;
1436
- }
1437
- if (startNoBuffer !== null) {
1438
- if (top <= scrollBottom) {
1439
- endNoBuffer = i;
1440
- }
1441
- if (top <= scrollBottomBuffered) {
1442
- endBuffered = i;
1443
- nextBottom = top + size;
1444
- } else {
1445
- foundEnd = true;
1446
- }
1447
- }
1448
- }
1449
- }
1450
- const idsInView = [];
1451
- for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1452
- const id = (_e = idCache.get(i)) != null ? _e : getId(i);
1453
- idsInView.push(id);
1454
- }
1455
- Object.assign(state, {
1456
- startBuffered,
1457
- startBufferedId,
1458
- startNoBuffer,
1459
- endBuffered,
1460
- endNoBuffer,
1461
- idsInView,
1462
- firstFullyOnScreenIndex
1463
- });
1464
- if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1465
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1466
- top: nextTop,
1467
- bottom: nextBottom
1468
- } : void 0;
1469
- }
1470
- const numContainers = peek$(ctx, "numContainers");
1471
- const pendingRemoval = [];
1472
- if (dataChanged) {
1473
- for (let i = 0; i < numContainers; i++) {
1474
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1475
- if (!keyExtractorProp || itemKey && indexByKey.get(itemKey) === void 0) {
1476
- pendingRemoval.push(i);
1477
- }
1478
- }
1479
- }
1480
- if (startBuffered !== null && endBuffered !== null) {
1481
- let numContainers2 = prevNumContainers;
1482
- const needNewContainers = [];
1483
- for (let i = startBuffered; i <= endBuffered; i++) {
1484
- const id = (_f = idCache.get(i)) != null ? _f : getId(i);
1485
- if (!containerItemKeys.has(id)) {
1486
- needNewContainers.push(i);
1487
- }
1488
- }
1489
- if (needNewContainers.length > 0) {
1490
- const availableContainers = findAvailableContainers(
1491
- needNewContainers.length,
1492
- startBuffered,
1493
- endBuffered,
1494
- pendingRemoval
1495
- );
1496
- for (let idx = 0; idx < needNewContainers.length; idx++) {
1497
- const i = needNewContainers[idx];
1498
- const containerIndex = availableContainers[idx];
1499
- const id = (_g = idCache.get(i)) != null ? _g : getId(i);
1500
- const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
1501
- if (oldKey && oldKey !== id) {
1502
- containerItemKeys.delete(oldKey);
1503
- }
1504
- set$(ctx, `containerItemKey${containerIndex}`, id);
1505
- set$(ctx, `containerItemData${containerIndex}`, data[i]);
1506
- containerItemKeys.add(id);
1507
- if (containerIndex >= numContainers2) {
1508
- numContainers2 = containerIndex + 1;
1509
- }
1510
- }
1511
- if (numContainers2 !== prevNumContainers) {
1512
- set$(ctx, "numContainers", numContainers2);
1513
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
1514
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1515
- }
1516
- }
1517
- }
1518
- for (let i = 0; i < numContainers2; i++) {
1519
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1520
- if (pendingRemoval.includes(i)) {
1521
- if (itemKey) {
1522
- containerItemKeys.delete(itemKey);
1523
- }
1524
- set$(ctx, `containerItemKey${i}`, void 0);
1525
- set$(ctx, `containerItemData${i}`, void 0);
1526
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1527
- set$(ctx, `containerColumn${i}`, -1);
1528
- } else {
1529
- const itemIndex = indexByKey.get(itemKey);
1530
- const item = data[itemIndex];
1531
- if (item !== void 0) {
1532
- const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(itemIndex);
1533
- const position = positions.get(id);
1534
- if (position === void 0) {
1535
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1536
- } else {
1537
- const pos = positions.get(id);
1538
- const column = columns.get(id) || 1;
1539
- const prevPos = peek$(ctx, `containerPosition${i}`);
1540
- const prevColumn = peek$(ctx, `containerColumn${i}`);
1541
- const prevData = peek$(ctx, `containerItemData${i}`);
1542
- if (!prevPos || pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1543
- set$(ctx, `containerPosition${i}`, pos);
1544
- }
1545
- if (column >= 0 && column !== prevColumn) {
1546
- set$(ctx, `containerColumn${i}`, column);
1547
- }
1548
- if (prevData !== item) {
1549
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
1550
- }
1551
- }
1552
- }
1553
- }
1554
- }
1555
- }
1556
- if (!queuedInitialLayout && endBuffered !== null) {
1557
- if (checkAllSizesKnown()) {
1558
- setDidLayout();
1559
- }
1560
- }
1561
- if (viewabilityConfigCallbackPairs) {
1562
- updateViewableItems(
1563
- state,
1564
- ctx,
1565
- viewabilityConfigCallbackPairs,
1566
- getId,
1567
- scrollLength,
1568
- startNoBuffer,
1569
- endNoBuffer
1570
- );
1571
- }
1572
- }, []);
1573
- const setPaddingTop = ({
1574
- stylePaddingTop,
1575
- alignItemsPaddingTop
1576
- }) => {
1577
- if (stylePaddingTop !== void 0) {
1578
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1579
- if (stylePaddingTop < prevStylePaddingTop) {
1580
- const prevTotalSize = peek$(ctx, "totalSize") || 0;
1581
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1582
- setTimeout(() => {
1583
- set$(ctx, "totalSize", prevTotalSize);
1584
- }, 16);
1585
- }
1586
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1587
- }
1588
- if (alignItemsPaddingTop !== void 0) {
1589
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1590
- }
1591
- };
1592
- const updateAlignItemsPaddingTop = () => {
1593
- if (alignItemsAtEnd) {
1594
- const { data, scrollLength } = refState.current;
1595
- let alignItemsPaddingTop = 0;
1596
- if ((data == null ? void 0 : data.length) > 0) {
1597
- const contentSize = getContentSize(ctx);
1598
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1599
- }
1600
- setPaddingTop({ alignItemsPaddingTop });
1601
- }
1602
- };
1603
- const finishScrollTo = () => {
1604
- const state = refState.current;
1605
- if (state) {
1606
- state.scrollingTo = void 0;
1607
- state.scrollHistory.length = 0;
1608
- }
1609
- };
1610
- const scrollTo = (params = {}) => {
1611
- var _a2;
1612
- const state = refState.current;
1613
- const { animated } = params;
1614
- const offset = calculateOffsetWithOffsetPosition(params.offset, params);
1615
- state.scrollHistory.length = 0;
1616
- state.scrollingTo = params;
1617
- state.scrollPending = offset;
1618
- (_a2 = refScroller.current) == null ? void 0 : _a2.scrollTo({
1619
- x: horizontal ? offset : 0,
1620
- y: horizontal ? 0 : offset,
1621
- animated: !!animated
1622
- });
1623
- if (!animated) {
1624
- refState.current.scroll = offset;
1625
- setTimeout(finishScrollTo, 100);
1626
- }
1627
- };
1628
- const doMaintainScrollAtEnd = (animated) => {
1629
- const state = refState.current;
1630
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1631
- const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1632
- if (paddingTop > 0) {
1633
- state.scroll = 0;
1634
- }
1635
- requestAnimationFrame(() => {
1636
- var _a2;
1637
- state.maintainingScrollAtEnd = true;
1638
- (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
1639
- animated
1640
- });
1641
- setTimeout(
1642
- () => {
1643
- state.maintainingScrollAtEnd = false;
1644
- },
1645
- 0
1646
- );
1647
- });
1648
- return true;
1649
- }
1650
- };
1651
- const checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1652
- const distanceAbs = Math.abs(distance);
1653
- const isAtThreshold = atThreshold || distanceAbs < threshold;
1654
- if (!isReached && !isBlockedByTimer) {
1655
- if (isAtThreshold) {
1656
- onReached == null ? void 0 : onReached(distance);
1657
- blockTimer == null ? void 0 : blockTimer(true);
1658
- setTimeout(() => {
1659
- blockTimer == null ? void 0 : blockTimer(false);
1660
- }, 700);
1661
- return true;
1662
- }
1663
- } else {
1664
- if (distance >= 1.3 * threshold) {
1665
- return false;
1666
- }
1667
- }
1668
- return isReached;
1669
- };
1670
- const checkAtBottom = () => {
1671
- if (!refState.current) {
1672
- return;
1673
- }
1674
- const { queuedInitialLayout, scrollLength, scroll, maintainingScrollAtEnd } = refState.current;
1675
- const contentSize = getContentSize(ctx);
1676
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1677
- const distanceFromEnd = contentSize - scroll - scrollLength;
1678
- const isContentLess = contentSize < scrollLength;
1679
- refState.current.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1680
- refState.current.isEndReached = checkThreshold(
1681
- distanceFromEnd,
1682
- isContentLess,
1683
- onEndReachedThreshold * scrollLength,
1684
- refState.current.isEndReached,
1685
- refState.current.endReachedBlockedByTimer,
1686
- (distance) => {
1687
- var _a2, _b;
1688
- return (_b = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b.call(_a2, { distanceFromEnd: distance });
1689
- },
1690
- (block) => {
1691
- refState.current.endReachedBlockedByTimer = block;
1692
- }
1693
- );
1694
- }
1695
- };
1696
- const checkAtTop = () => {
1697
- if (!refState.current) {
1698
- return;
1699
- }
1700
- const { scrollLength, scroll } = refState.current;
1701
- const distanceFromTop = scroll;
1702
- refState.current.isAtStart = distanceFromTop <= 0;
1703
- refState.current.isStartReached = checkThreshold(
1704
- distanceFromTop,
1705
- false,
1706
- onStartReachedThreshold * scrollLength,
1707
- refState.current.isStartReached,
1708
- refState.current.startReachedBlockedByTimer,
1709
- (distance) => {
1710
- var _a2, _b;
1711
- return (_b = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b.call(_a2, { distanceFromStart: distance });
1712
- },
1713
- (block) => {
1714
- refState.current.startReachedBlockedByTimer = block;
1715
- }
1716
- );
1717
- };
1718
- const checkResetContainers = (isFirst2) => {
1719
- const state = refState.current;
1720
- if (state) {
1721
- state.data = dataProp;
1722
- if (!isFirst2) {
1723
- calculateItemsInView({ dataChanged: true, doMVCP: true });
1724
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1725
- if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1726
- state.isEndReached = false;
1727
- }
1728
- if (!didMaintainScrollAtEnd) {
1729
- checkAtTop();
1730
- checkAtBottom();
1731
- }
1732
- }
1733
- }
1734
- };
1735
- const updateTotalSize = () => {
1736
- const { data, positions } = refState.current;
1737
- if (data.length === 0) {
1738
- addTotalSize(null, 0);
1739
- } else {
1740
- const lastId = getId(data.length - 1);
1741
- if (lastId !== void 0) {
1742
- const lastPosition = positions.get(lastId);
1743
- if (lastPosition !== void 0) {
1744
- const lastSize = getItemSize(lastId, data.length - 1, data[dataProp.length - 1]);
1745
- if (lastSize !== void 0) {
1746
- const totalSize = lastPosition + lastSize;
1747
- addTotalSize(null, totalSize);
1748
- }
1749
- }
1750
- }
1751
- }
1752
- };
1753
- const findAvailableContainers = (numNeeded, startBuffered, endBuffered, pendingRemoval) => {
1754
- const state = refState.current;
1755
- const numContainers = peek$(ctx, "numContainers");
1756
- const result = [];
1757
- const availableContainers = [];
1758
- for (let u = 0; u < numContainers; u++) {
1759
- const key = peek$(ctx, `containerItemKey${u}`);
1760
- let isOk = key === void 0;
1761
- if (!isOk) {
1762
- const index = pendingRemoval.indexOf(u);
1763
- if (index !== -1) {
1764
- pendingRemoval.splice(index, 1);
1765
- isOk = true;
1766
- }
1767
- }
1768
- if (isOk) {
1769
- result.push(u);
1770
- if (result.length >= numNeeded) {
1771
- return result;
1772
- }
1773
- }
1774
- }
1775
- for (let u = 0; u < numContainers; u++) {
1776
- const key = peek$(ctx, `containerItemKey${u}`);
1777
- if (key === void 0) continue;
1778
- const index = state.indexByKey.get(key);
1779
- if (index < startBuffered) {
1780
- availableContainers.push({ index: u, distance: startBuffered - index });
1781
- } else if (index > endBuffered) {
1782
- availableContainers.push({ index: u, distance: index - endBuffered });
1783
- }
1784
- }
1785
- const remaining = numNeeded - result.length;
1786
- if (remaining > 0) {
1787
- if (availableContainers.length > 0) {
1788
- if (availableContainers.length > remaining) {
1789
- availableContainers.sort(comparatorByDistance);
1790
- availableContainers.length = remaining;
1791
- }
1792
- for (const container of availableContainers) {
1793
- result.push(container.index);
1794
- }
1795
- }
1796
- const stillNeeded = numNeeded - result.length;
1797
- if (stillNeeded > 0) {
1798
- for (let i = 0; i < stillNeeded; i++) {
1799
- result.push(numContainers + i);
1800
- }
1801
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1802
- console.warn(
1803
- "[legend-list] No unused container available, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize or increasing initialContainerPoolRatio.",
1804
- {
1805
- debugInfo: {
1806
- numContainers,
1807
- numNeeded,
1808
- stillNeeded,
1809
- numContainersPooled: peek$(ctx, "numContainersPooled")
1810
- }
1811
- }
1812
- );
1813
- }
1814
- }
1815
- }
1816
- return result.sort(comparatorDefault);
1817
- };
1818
- const isFirst = !refState.current.renderItem;
1819
- const memoizedLastItemKeys = useMemo(() => {
1820
- if (!dataProp.length) return [];
1821
- return Array.from(
1822
- { length: Math.min(numColumnsProp, dataProp.length) },
1823
- (_, i) => getId(dataProp.length - 1 - i)
1824
- );
1825
- }, [dataProp, numColumnsProp]);
1826
- const initalizeStateVars = () => {
1827
- set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1828
- set$(ctx, "numColumns", numColumnsProp);
1829
- const prevPaddingTop = peek$(ctx, "stylePaddingTop");
1830
- setPaddingTop({ stylePaddingTop: stylePaddingTopState });
1831
- refState.current.stylePaddingBottom = stylePaddingBottomState;
1832
- const paddingDiff = stylePaddingTopState - prevPaddingTop;
1833
- if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
1834
- requestAdjust(paddingDiff);
1835
- }
1836
- };
1837
- if (isFirst) {
1838
- initalizeStateVars();
1839
- updateAllPositions();
1840
- }
1841
- const initialContentOffset = useMemo(() => {
1842
- const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(initialScrollIndex);
1843
- refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
1844
- if (initialContentOffset2 > 0) {
1845
- scrollTo({ offset: initialContentOffset2, animated: false, index: initialScrollIndex });
1846
- }
1847
- return initialContentOffset2;
1848
- }, [renderNum]);
1849
- if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1850
- refState.current.lastBatchingAction = Date.now();
1851
- if (!keyExtractorProp && !isFirst && didDataChange) {
1852
- __DEV__ && warnDevOnce(
1853
- "keyExtractor",
1854
- "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."
1855
- );
1856
- refState.current.sizes.clear();
1857
- refState.current.positions.clear();
1858
- }
1859
- }
1860
- useLayoutEffect(() => {
1861
- var _a2, _b;
1862
- if (IsNewArchitecture) {
1863
- const measured = (_b = (_a2 = refScroller.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
1864
- if (measured) {
1865
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
1866
- if (size) {
1867
- handleLayout(measured);
1868
- }
1869
- }
1870
- }
1871
- if (!isFirst) {
1872
- calculateItemsInView({ doMVCP: true });
1873
- }
1874
- }, [dataProp]);
1875
- const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
1876
- const size = rect[horizontal ? "width" : "height"];
1877
- set$(ctx, "headerSize", size);
1878
- if (initialScroll) {
1879
- if (IsNewArchitecture && Platform.OS !== "android") {
1880
- if (fromLayoutEffect) {
1881
- setRenderNum((v) => v + 1);
1882
- }
1883
- } else {
1884
- setTimeout(() => {
1885
- scrollToIndex({ ...initialScroll, animated: false });
1886
- }, 17);
1887
- }
1888
- }
1889
- }, []);
1890
- useLayoutEffect(() => {
1891
- const didAllocateContainers = doInitialAllocateContainers();
1892
- if (!didAllocateContainers) {
1893
- checkResetContainers(
1894
- /*isFirst*/
1895
- isFirst
1896
- );
1897
- }
1898
- }, [dataProp, numColumnsProp]);
1899
- useLayoutEffect(() => {
1900
- set$(ctx, "extraData", extraData);
1901
- }, [extraData]);
1902
- refState.current.renderItem = renderItem2;
1903
- useLayoutEffect(initalizeStateVars, [
1904
- memoizedLastItemKeys.join(","),
1905
- numColumnsProp,
1906
- stylePaddingTopState,
1907
- stylePaddingBottomState
1908
- ]);
1909
- const getRenderedItem = useCallback((key) => {
1910
- const state = refState.current;
1911
- if (!state) {
1912
- return null;
1913
- }
1914
- const { data, indexByKey } = state;
1915
- const index = indexByKey.get(key);
1916
- if (index === void 0) {
1917
- return null;
1918
- }
1919
- const renderItemProp = refState.current.renderItem;
1920
- let renderedItem = null;
1921
- if (renderItemProp) {
1922
- const itemProps = {
1923
- item: data[index],
1924
- index,
1925
- extraData: peek$(ctx, "extraData")
1926
- };
1927
- renderedItem = React2.createElement(renderItemProp, itemProps);
1928
- }
1929
- return { index, item: data[index], renderedItem };
1930
- }, []);
1931
- const doInitialAllocateContainers = () => {
1932
- const state = refState.current;
1933
- const { scrollLength, data } = state;
1934
- if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1935
- const averageItemSize = getEstimatedItemSize ? getEstimatedItemSize(0, data[0]) : estimatedItemSize;
1936
- const Extra = 1.5;
1937
- const numContainers = Math.ceil(
1938
- (scrollLength + scrollBuffer * 2) / averageItemSize * numColumnsProp * Extra
1939
- );
1940
- for (let i = 0; i < numContainers; i++) {
1941
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1942
- set$(ctx, `containerColumn${i}`, -1);
1943
- }
1944
- set$(ctx, "numContainers", numContainers);
1945
- set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
1946
- if (!IsNewArchitecture) {
1947
- if (initialScroll) {
1948
- requestAnimationFrame(() => {
1949
- calculateItemsInView();
1950
- });
1951
- } else {
1952
- calculateItemsInView();
1953
- }
1954
- }
1955
- return true;
1956
- }
1957
- };
1958
- useEffect(() => {
1959
- const state = refState.current;
1960
- const viewability = setupViewability({
1961
- viewabilityConfig,
1962
- viewabilityConfigCallbackPairs,
1963
- onViewableItemsChanged
1964
- });
1965
- state.viewabilityConfigCallbackPairs = viewability;
1966
- state.enableScrollForNextCalculateItemsInView = !viewability;
1967
- }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
1968
- if (!IsNewArchitecture) {
1969
- useInit(() => {
1970
- doInitialAllocateContainers();
1971
- });
1972
- }
1973
- const updateOneItemSize = useCallback((itemKey, sizeObj) => {
1974
- const state = refState.current;
1975
- const { sizes, indexByKey, sizesKnown, data, averageSizes } = state;
1976
- if (!data) return 0;
1977
- const index = indexByKey.get(itemKey);
1978
- const prevSize = getItemSize(itemKey, index, data);
1979
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1980
- sizesKnown.set(itemKey, size);
1981
- const itemType = "";
1982
- let averages = averageSizes[itemType];
1983
- if (!averages) {
1984
- averages = averageSizes[itemType] = { num: 0, avg: 0 };
1985
- }
1986
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
1987
- averages.num++;
1988
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
1989
- sizes.set(itemKey, size);
1990
- return size - prevSize;
1991
- }
1992
- return 0;
1993
- }, []);
1994
- const updateItemSizes = useCallback(
1995
- (itemUpdates) => {
1996
- var _a2;
1997
- const state = refState.current;
1998
- if (!state.data) return;
1999
- let needsRecalculate = false;
2000
- let shouldMaintainScrollAtEnd = false;
2001
- let minIndexSizeChanged;
2002
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2003
- for (const { itemKey, sizeObj } of itemUpdates) {
2004
- const index = state.indexByKey.get(itemKey);
2005
- const prevSizeKnown = state.sizesKnown.get(itemKey);
2006
- const diff = updateOneItemSize(itemKey, sizeObj);
2007
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2008
- if (diff !== 0) {
2009
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2010
- if (((_a2 = state.scrollingTo) == null ? void 0 : _a2.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index) {
2011
- requestAdjust(diff * state.scrollingTo.viewPosition);
2012
- }
2013
- const { startBuffered, endBuffered } = state;
2014
- needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2015
- if (!needsRecalculate) {
2016
- const numContainers = ctx.values.get("numContainers");
2017
- for (let i = 0; i < numContainers; i++) {
2018
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2019
- needsRecalculate = true;
2020
- break;
2021
- }
2022
- }
2023
- }
2024
- if (state.needsOtherAxisSize) {
2025
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2026
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2027
- }
2028
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2029
- shouldMaintainScrollAtEnd = true;
2030
- }
2031
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2032
- size,
2033
- previous: size - diff,
2034
- index,
2035
- itemKey,
2036
- itemData: state.data[index]
2037
- });
2038
- }
2039
- }
2040
- if (minIndexSizeChanged !== void 0) {
2041
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2042
- }
2043
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2044
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2045
- state.timeoutSizeMessage = setTimeout(() => {
2046
- var _a3;
2047
- state.timeoutSizeMessage = void 0;
2048
- const num = state.sizesKnown.size;
2049
- const avg = (_a3 = state.averageSizes[""]) == null ? void 0 : _a3.avg;
2050
- console.warn(
2051
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2052
- );
2053
- }, 1e3);
2054
- }
2055
- const cur = peek$(ctx, "otherAxisSize");
2056
- if (!cur || maxOtherAxisSize > cur) {
2057
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
2058
- }
2059
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2060
- if (containersDidLayout || checkAllSizesKnown()) {
2061
- if (needsRecalculate) {
2062
- state.scrollForNextCalculateItemsInView = void 0;
2063
- calculateItemsInView({ doMVCP: true });
2064
- }
2065
- if (shouldMaintainScrollAtEnd) {
2066
- doMaintainScrollAtEnd(false);
2067
- }
2068
- }
2069
- },
2070
- []
2071
- );
2072
- const updateItemSize = useCallback((itemKey, sizeObj) => {
2073
- var _a2, _b;
2074
- if (IsNewArchitecture) {
2075
- const { sizesKnown } = refState.current;
2076
- const numContainers = ctx.values.get("numContainers");
2077
- const changes = [];
2078
- for (let i = 0; i < numContainers; i++) {
2079
- const containerItemKey = peek$(ctx, `containerItemKey${i}`);
2080
- if (itemKey === containerItemKey) {
2081
- changes.push({ itemKey, sizeObj });
2082
- } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
2083
- const containerRef = ctx.viewRefs.get(i);
2084
- if (containerRef) {
2085
- const measured = (_b = (_a2 = containerRef.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2086
- if (measured) {
2087
- changes.push({ itemKey: containerItemKey, sizeObj: measured });
2088
- }
2089
- }
2090
- }
2091
- }
2092
- if (changes.length > 0) {
2093
- updateItemSizes(changes);
2094
- }
2095
- } else {
2096
- updateItemSizes([{ itemKey, sizeObj }]);
2097
- }
2098
- }, []);
2099
- const handleLayout = useCallback((size) => {
2100
- const scrollLength = size[horizontal ? "width" : "height"];
2101
- const otherAxisSize = size[horizontal ? "height" : "width"];
2102
- const state = refState.current;
2103
- const didChange = scrollLength !== state.scrollLength;
2104
- const prevOtherAxisSize = state.otherAxisSize;
2105
- state.scrollLength = scrollLength;
2106
- state.otherAxisSize = otherAxisSize;
2107
- state.lastBatchingAction = Date.now();
2108
- state.scrollForNextCalculateItemsInView = void 0;
2109
- doInitialAllocateContainers();
2110
- if (didChange) {
2111
- calculateItemsInView({ doMVCP: true });
2112
- }
2113
- if (didChange || otherAxisSize !== prevOtherAxisSize) {
2114
- set$(ctx, "scrollSize", { width: size.width, height: size.height });
2115
- }
2116
- doMaintainScrollAtEnd(false);
2117
- updateAlignItemsPaddingTop();
2118
- checkAtBottom();
2119
- checkAtTop();
2120
- if (refState.current) {
2121
- refState.current.needsOtherAxisSize = otherAxisSize - (stylePaddingTopState || 0) < 10;
2122
- }
2123
- if (__DEV__ && scrollLength === 0) {
2124
- warnDevOnce(
2125
- "height0",
2126
- `List ${horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2127
- );
2128
- }
2129
- calculateItemsInView({ doMVCP: true });
2130
- setCanRender(true);
2131
- }, []);
2132
- const onLayout = useCallback((event) => {
2133
- const layout = event.nativeEvent.layout;
2134
- handleLayout(layout);
2135
- if (onLayoutProp) {
2136
- onLayoutProp(event);
2137
- }
2138
- }, []);
2139
- const handleScroll = useCallback(
2140
- (event) => {
2141
- var _a2, _b, _c, _d;
2142
- if (((_b = (_a2 = event.nativeEvent) == null ? void 0 : _a2.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2143
- return;
2144
- }
2145
- const state = refState.current;
2146
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
2147
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2148
- if (ignoreScrollFromMVCP && !state.scrollingTo) {
2149
- const { lt, gt } = ignoreScrollFromMVCP;
2150
- if (lt && newScroll < lt || gt && newScroll > gt) {
2151
- return;
2152
- }
2153
- }
2154
- state.scrollPending = newScroll;
2155
- updateScroll(newScroll);
2156
- (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2157
- },
2158
- []
2159
- );
2160
- const updateScroll = useCallback((newScroll) => {
2161
- const state = refState.current;
2162
- const scrollingTo = state.scrollingTo;
2163
- state.hasScrolled = true;
2164
- state.lastBatchingAction = Date.now();
2165
- const currentTime = performance.now();
2166
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2167
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2168
- }
2169
- if (state.scrollHistory.length > 5) {
2170
- state.scrollHistory.shift();
2171
- }
2172
- state.scrollPrev = state.scroll;
2173
- state.scrollPrevTime = state.scrollTime;
2174
- state.scroll = newScroll;
2175
- state.scrollTime = currentTime;
2176
- calculateItemsInView();
2177
- checkAtBottom();
2178
- checkAtTop();
2179
- }, []);
2180
- useImperativeHandle(
2181
- forwardedRef,
2182
- () => {
2183
- const scrollIndexIntoView = (options) => {
2184
- if (refState.current) {
2185
- const { index, ...rest2 } = options;
2186
- const { startNoBuffer, endNoBuffer } = refState.current;
2187
- if (index < startNoBuffer || index > endNoBuffer) {
2188
- const viewPosition = index < startNoBuffer ? 0 : 1;
2189
- scrollToIndex({
2190
- ...rest2,
2191
- viewPosition,
2192
- index
2193
- });
2194
- }
2195
- }
2196
- };
2197
- return {
2198
- flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2199
- getNativeScrollRef: () => refScroller.current,
2200
- getScrollableNode: () => refScroller.current.getScrollableNode(),
2201
- getScrollResponder: () => refScroller.current.getScrollResponder(),
2202
- getState: () => {
2203
- const state = refState.current;
2204
- return state ? {
2205
- contentLength: state.totalSize,
2206
- end: state.endNoBuffer,
2207
- endBuffered: state.endBuffered,
2208
- isAtEnd: state.isAtEnd,
2209
- isAtStart: state.isAtStart,
2210
- scroll: state.scroll,
2211
- scrollLength: state.scrollLength,
2212
- start: state.startNoBuffer,
2213
- startBuffered: state.startBuffered,
2214
- sizes: state.sizesKnown,
2215
- sizeAtIndex: (index) => state.sizesKnown.get(getId(index))
2216
- } : {};
2217
- },
2218
- scrollIndexIntoView,
2219
- scrollItemIntoView: ({ item, ...props2 }) => {
2220
- const { data } = refState.current;
2221
- const index = data.indexOf(item);
2222
- if (index !== -1) {
2223
- scrollIndexIntoView({ index, ...props2 });
2224
- }
2225
- },
2226
- scrollToIndex,
2227
- scrollToItem: ({ item, ...props2 }) => {
2228
- const { data } = refState.current;
2229
- const index = data.indexOf(item);
2230
- if (index !== -1) {
2231
- scrollToIndex({ index, ...props2 });
2232
- }
2233
- },
2234
- scrollToOffset: (params) => scrollTo(params),
2235
- scrollToEnd: (options) => {
2236
- const { data, stylePaddingBottom } = refState.current;
2237
- const index = data.length - 1;
2238
- if (index !== -1) {
2239
- const paddingBottom = stylePaddingBottom || 0;
2240
- const footerSize = peek$(ctx, "footerSize") || 0;
2241
- scrollToIndex({
2242
- index,
2243
- viewPosition: 1,
2244
- viewOffset: -paddingBottom - footerSize,
2245
- ...options
2246
- });
2247
- }
2248
- },
2249
- setVisibleContentAnchorOffset: (value) => {
2250
- const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2251
- set$(ctx, "scrollAdjustUserOffset", val);
2252
- }
2253
- };
2254
- },
2255
- []
2256
- );
2257
- if (Platform.OS === "web") {
2258
- useEffect(() => {
2259
- if (initialContentOffset) {
2260
- scrollTo({ offset: initialContentOffset, animated: false });
2261
- }
2262
- }, []);
2263
- }
2264
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
2265
- ListComponent,
2266
- {
2267
- ...rest,
2268
- canRender,
2269
- horizontal,
2270
- refScrollView: combinedRef,
2271
- initialContentOffset,
2272
- getRenderedItem,
2273
- updateItemSize,
2274
- handleScroll,
2275
- onMomentumScrollEnd: (event) => {
2276
- requestAnimationFrame(() => {
2277
- finishScrollTo();
2278
- });
2279
- if (onMomentumScrollEnd) {
2280
- onMomentumScrollEnd(event);
2281
- }
2282
- },
2283
- onLayout,
2284
- recycleItems,
2285
- alignItemsAtEnd,
2286
- ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
2287
- ListHeaderComponent,
2288
- maintainVisibleContentPosition,
2289
- scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2290
- waitForInitialLayout,
2291
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
2292
- progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2293
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2.createElement(
2294
- RefreshControl,
2295
- {
2296
- refreshing: !!refreshing,
2297
- onRefresh,
2298
- progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState
2299
- }
2300
- ),
2301
- style,
2302
- contentContainerStyle,
2303
- scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2304
- onLayoutHeader
2305
- }
2306
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
2307
- });
2308
- var typedForwardRef2 = forwardRef;
2309
- var renderItem = ({ item }) => item;
2310
- var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
2311
- const { LegendList: LegendListProp, children, ...rest } = props;
2312
- const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList;
2313
- const data = (isArray(children) ? children : React2.Children.toArray(children)).flat(1);
2314
- return (
2315
- // @ts-expect-error TODO: Fix this type
2316
- /* @__PURE__ */ React2.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2317
- );
2318
- });
2319
-
2320
- export { LazyLegendList, LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };