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

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 (260) hide show
  1. package/{dist/animated.d.mts → animated.d.mts} +1 -0
  2. package/{dist/animated.d.ts → animated.d.ts} +1 -0
  3. package/{dist/index.d.mts → index.d.mts} +8 -1
  4. package/{dist/index.d.ts → index.d.ts} +8 -1
  5. package/{dist/index.js → index.js} +50 -4
  6. package/{dist/index.mjs → index.mjs} +50 -4
  7. package/{dist/keyboard-controller.d.mts → keyboard-controller.d.mts} +4 -0
  8. package/{dist/keyboard-controller.d.ts → keyboard-controller.d.ts} +4 -0
  9. package/package.json +34 -88
  10. package/.claude/settings.local.json +0 -8
  11. package/.cursor/rules/changelog.mdc +0 -60
  12. package/.github/FUNDING.yml +0 -15
  13. package/.gitignore +0 -5
  14. package/.prettierrc.json +0 -5
  15. package/.vscode/settings.json +0 -14
  16. package/CLAUDE.md +0 -126
  17. package/biome.json +0 -46
  18. package/bun.lock +0 -1289
  19. package/bunfig.toml +0 -2
  20. package/dist/CHANGELOG.md +0 -119
  21. package/dist/LICENSE +0 -21
  22. package/dist/README.md +0 -139
  23. package/dist/package.json +0 -35
  24. package/example/README.md +0 -40
  25. package/example/api/data/genres.json +0 -23
  26. package/example/api/data/playlist/10402-10749.json +0 -1
  27. package/example/api/data/playlist/10402-10770.json +0 -1
  28. package/example/api/data/playlist/10402-37.json +0 -1
  29. package/example/api/data/playlist/10749-10752.json +0 -1
  30. package/example/api/data/playlist/10749-10770.json +0 -1
  31. package/example/api/data/playlist/10749-37.json +0 -1
  32. package/example/api/data/playlist/10749-878.json +0 -1
  33. package/example/api/data/playlist/10751-10402.json +0 -1
  34. package/example/api/data/playlist/10751-10752.json +0 -1
  35. package/example/api/data/playlist/10751-37.json +0 -1
  36. package/example/api/data/playlist/10751-53.json +0 -1
  37. package/example/api/data/playlist/10751-878.json +0 -1
  38. package/example/api/data/playlist/10751-9648.json +0 -1
  39. package/example/api/data/playlist/10752-37.json +0 -1
  40. package/example/api/data/playlist/12-10402.json +0 -1
  41. package/example/api/data/playlist/12-10749.json +0 -1
  42. package/example/api/data/playlist/12-18.json +0 -1
  43. package/example/api/data/playlist/12-27.json +0 -1
  44. package/example/api/data/playlist/12-35.json +0 -1
  45. package/example/api/data/playlist/14-36.json +0 -1
  46. package/example/api/data/playlist/14-878.json +0 -1
  47. package/example/api/data/playlist/16-10751.json +0 -1
  48. package/example/api/data/playlist/16-10770.json +0 -1
  49. package/example/api/data/playlist/16-35.json +0 -1
  50. package/example/api/data/playlist/16-36.json +0 -1
  51. package/example/api/data/playlist/16-53.json +0 -1
  52. package/example/api/data/playlist/18-10751.json +0 -1
  53. package/example/api/data/playlist/18-10752.json +0 -1
  54. package/example/api/data/playlist/18-37.json +0 -1
  55. package/example/api/data/playlist/18-53.json +0 -1
  56. package/example/api/data/playlist/18-878.json +0 -1
  57. package/example/api/data/playlist/27-10749.json +0 -1
  58. package/example/api/data/playlist/27-10770.json +0 -1
  59. package/example/api/data/playlist/28-10749.json +0 -1
  60. package/example/api/data/playlist/28-10751.json +0 -1
  61. package/example/api/data/playlist/28-10770.json +0 -1
  62. package/example/api/data/playlist/28-16.json +0 -1
  63. package/example/api/data/playlist/28-18.json +0 -1
  64. package/example/api/data/playlist/28-36.json +0 -1
  65. package/example/api/data/playlist/28-37.json +0 -1
  66. package/example/api/data/playlist/28-53.json +0 -1
  67. package/example/api/data/playlist/28-80.json +0 -1
  68. package/example/api/data/playlist/28-99.json +0 -1
  69. package/example/api/data/playlist/35-10749.json +0 -1
  70. package/example/api/data/playlist/35-10751.json +0 -1
  71. package/example/api/data/playlist/35-10752.json +0 -1
  72. package/example/api/data/playlist/35-27.json +0 -1
  73. package/example/api/data/playlist/35-36.json +0 -1
  74. package/example/api/data/playlist/35-53.json +0 -1
  75. package/example/api/data/playlist/35-80.json +0 -1
  76. package/example/api/data/playlist/36-37.json +0 -1
  77. package/example/api/data/playlist/36-878.json +0 -1
  78. package/example/api/data/playlist/36-9648.json +0 -1
  79. package/example/api/data/playlist/53-10752.json +0 -1
  80. package/example/api/data/playlist/80-10770.json +0 -1
  81. package/example/api/data/playlist/80-14.json +0 -1
  82. package/example/api/data/playlist/80-18.json +0 -1
  83. package/example/api/data/playlist/80-37.json +0 -1
  84. package/example/api/data/playlist/878-37.json +0 -1
  85. package/example/api/data/playlist/9648-10770.json +0 -1
  86. package/example/api/data/playlist/9648-37.json +0 -1
  87. package/example/api/data/playlist/9648-53.json +0 -1
  88. package/example/api/data/playlist/9648-878.json +0 -1
  89. package/example/api/data/playlist/99-10749.json +0 -1
  90. package/example/api/data/playlist/99-14.json +0 -1
  91. package/example/api/data/playlist/99-18.json +0 -1
  92. package/example/api/data/playlist/99-27.json +0 -1
  93. package/example/api/data/playlist/99-53.json +0 -1
  94. package/example/api/data/playlist/99-9648.json +0 -1
  95. package/example/api/data/playlist/index.ts +0 -73
  96. package/example/api/data/rows.json +0 -1
  97. package/example/api/index.ts +0 -36
  98. package/example/app/(tabs)/_layout.tsx +0 -60
  99. package/example/app/(tabs)/cards.tsx +0 -81
  100. package/example/app/(tabs)/index.tsx +0 -205
  101. package/example/app/(tabs)/moviesL.tsx +0 -7
  102. package/example/app/(tabs)/moviesLR.tsx +0 -7
  103. package/example/app/+not-found.tsx +0 -32
  104. package/example/app/_layout.tsx +0 -34
  105. package/example/app/accurate-scrollto/index.tsx +0 -125
  106. package/example/app/accurate-scrollto-2/index.tsx +0 -52
  107. package/example/app/accurate-scrollto-huge/index.tsx +0 -128
  108. package/example/app/add-to-end/index.tsx +0 -82
  109. package/example/app/ai-chat/index.tsx +0 -236
  110. package/example/app/bidirectional-infinite-list/index.tsx +0 -133
  111. package/example/app/cards-columns/index.tsx +0 -37
  112. package/example/app/cards-flashlist/index.tsx +0 -122
  113. package/example/app/cards-flatlist/index.tsx +0 -94
  114. package/example/app/cards-no-recycle/index.tsx +0 -110
  115. package/example/app/cards-renderItem.tsx +0 -354
  116. package/example/app/chat-example/index.tsx +0 -167
  117. package/example/app/chat-infinite/index.tsx +0 -239
  118. package/example/app/chat-keyboard/index.tsx +0 -248
  119. package/example/app/chat-resize-outer/index.tsx +0 -247
  120. package/example/app/columns/index.tsx +0 -78
  121. package/example/app/countries/index.tsx +0 -182
  122. package/example/app/countries-flashlist/index.tsx +0 -163
  123. package/example/app/countries-reorder/index.tsx +0 -187
  124. package/example/app/extra-data/index.tsx +0 -86
  125. package/example/app/filter-elements/filter-data-provider.tsx +0 -55
  126. package/example/app/filter-elements/index.tsx +0 -118
  127. package/example/app/initial-scroll-index/index.tsx +0 -106
  128. package/example/app/initial-scroll-index/renderFixedItem.tsx +0 -215
  129. package/example/app/initial-scroll-index-free-height/index.tsx +0 -70
  130. package/example/app/initial-scroll-index-keyed/index.tsx +0 -62
  131. package/example/app/lazy-list/index.tsx +0 -123
  132. package/example/app/movies-flashlist/index.tsx +0 -7
  133. package/example/app/mutable-cells/index.tsx +0 -104
  134. package/example/app/video-feed/index.tsx +0 -119
  135. package/example/app.config.js +0 -22
  136. package/example/app.json +0 -45
  137. package/example/assets/fonts/SpaceMono-Regular.ttf +0 -0
  138. package/example/assets/images/adaptive-icon.png +0 -0
  139. package/example/assets/images/favicon.png +0 -0
  140. package/example/assets/images/icon.png +0 -0
  141. package/example/assets/images/partial-react-logo.png +0 -0
  142. package/example/assets/images/react-logo.png +0 -0
  143. package/example/assets/images/react-logo@2x.png +0 -0
  144. package/example/assets/images/react-logo@3x.png +0 -0
  145. package/example/assets/images/splash-icon.png +0 -0
  146. package/example/autoscroll.sh +0 -101
  147. package/example/bun.lock +0 -2266
  148. package/example/bunfig.toml +0 -2
  149. package/example/components/Breathe.tsx +0 -54
  150. package/example/components/Circle.tsx +0 -69
  151. package/example/components/Collapsible.tsx +0 -44
  152. package/example/components/ExternalLink.tsx +0 -24
  153. package/example/components/HapticTab.tsx +0 -18
  154. package/example/components/HelloWave.tsx +0 -37
  155. package/example/components/Movies.tsx +0 -179
  156. package/example/components/ParallaxScrollView.tsx +0 -81
  157. package/example/components/ThemedText.tsx +0 -60
  158. package/example/components/ThemedView.tsx +0 -14
  159. package/example/components/__tests__/ThemedText-test.tsx +0 -10
  160. package/example/components/__tests__/__snapshots__/ThemedText-test.tsx.snap +0 -24
  161. package/example/components/ui/IconSymbol.ios.tsx +0 -32
  162. package/example/components/ui/IconSymbol.tsx +0 -43
  163. package/example/components/ui/TabBarBackground.ios.tsx +0 -22
  164. package/example/components/ui/TabBarBackground.tsx +0 -6
  165. package/example/constants/Colors.ts +0 -26
  166. package/example/constants/constants.ts +0 -5
  167. package/example/constants/useScrollTest.ts +0 -19
  168. package/example/hooks/useColorScheme.ts +0 -1
  169. package/example/hooks/useColorScheme.web.ts +0 -8
  170. package/example/hooks/useThemeColor.ts +0 -22
  171. package/example/ios/.xcode.env +0 -11
  172. package/example/ios/Podfile +0 -64
  173. package/example/ios/Podfile.lock +0 -2767
  174. package/example/ios/Podfile.properties.json +0 -5
  175. package/example/ios/listtest/AppDelegate.swift +0 -70
  176. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
  177. package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/Contents.json +0 -14
  178. package/example/ios/listtest/Images.xcassets/Contents.json +0 -6
  179. package/example/ios/listtest/Images.xcassets/SplashScreenBackground.colorset/Contents.json +0 -20
  180. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/Contents.json +0 -23
  181. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image.png +0 -0
  182. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@2x.png +0 -0
  183. package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@3x.png +0 -0
  184. package/example/ios/listtest/Info.plist +0 -85
  185. package/example/ios/listtest/PrivacyInfo.xcprivacy +0 -48
  186. package/example/ios/listtest/SplashScreen.storyboard +0 -42
  187. package/example/ios/listtest/Supporting/Expo.plist +0 -12
  188. package/example/ios/listtest/listtest-Bridging-Header.h +0 -3
  189. package/example/ios/listtest/listtest.entitlements +0 -5
  190. package/example/ios/listtest.xcodeproj/project.pbxproj +0 -547
  191. package/example/ios/listtest.xcodeproj/xcshareddata/xcschemes/listtest.xcscheme +0 -88
  192. package/example/ios/listtest.xcworkspace/contents.xcworkspacedata +0 -10
  193. package/example/metro.config.js +0 -16
  194. package/example/package.json +0 -73
  195. package/example/scripts/reset-project.js +0 -84
  196. package/example/tsconfig.json +0 -26
  197. package/posttsup.ts +0 -24
  198. package/src/Container.tsx +0 -176
  199. package/src/Containers.tsx +0 -85
  200. package/src/ContextContainer.ts +0 -145
  201. package/src/DebugView.tsx +0 -83
  202. package/src/LazyLegendList.tsx +0 -41
  203. package/src/LeanView.tsx +0 -18
  204. package/src/LegendList.tsx +0 -558
  205. package/src/ListComponent.tsx +0 -191
  206. package/src/ScrollAdjust.tsx +0 -24
  207. package/src/ScrollAdjustHandler.ts +0 -26
  208. package/src/Separator.tsx +0 -14
  209. package/src/animated.tsx +0 -6
  210. package/src/calculateItemsInView.ts +0 -363
  211. package/src/calculateOffsetForIndex.ts +0 -23
  212. package/src/calculateOffsetWithOffsetPosition.ts +0 -26
  213. package/src/checkAllSizesKnown.ts +0 -17
  214. package/src/checkAtBottom.ts +0 -36
  215. package/src/checkAtTop.ts +0 -27
  216. package/src/checkThreshold.ts +0 -30
  217. package/src/constants.ts +0 -11
  218. package/src/createColumnWrapperStyle.ts +0 -16
  219. package/src/doInitialAllocateContainers.ts +0 -40
  220. package/src/doMaintainScrollAtEnd.ts +0 -34
  221. package/src/findAvailableContainers.ts +0 -98
  222. package/src/finishScrollTo.ts +0 -8
  223. package/src/getId.ts +0 -21
  224. package/src/getItemSize.ts +0 -52
  225. package/src/getRenderedItem.ts +0 -34
  226. package/src/getScrollVelocity.ts +0 -47
  227. package/src/handleLayout.ts +0 -70
  228. package/src/helpers.ts +0 -39
  229. package/src/index.ts +0 -11
  230. package/src/keyboard-controller.tsx +0 -63
  231. package/src/onScroll.ts +0 -66
  232. package/src/prepareMVCP.ts +0 -50
  233. package/src/reanimated.tsx +0 -63
  234. package/src/requestAdjust.ts +0 -41
  235. package/src/scrollTo.ts +0 -40
  236. package/src/scrollToIndex.ts +0 -34
  237. package/src/setDidLayout.ts +0 -25
  238. package/src/setPaddingTop.ts +0 -28
  239. package/src/state.tsx +0 -304
  240. package/src/types.ts +0 -610
  241. package/src/updateAlignItemsPaddingTop.ts +0 -18
  242. package/src/updateAllPositions.ts +0 -130
  243. package/src/updateItemSize.ts +0 -203
  244. package/src/updateTotalSize.ts +0 -44
  245. package/src/useAnimatedValue.ts +0 -6
  246. package/src/useCombinedRef.ts +0 -22
  247. package/src/useInit.ts +0 -17
  248. package/src/useSyncLayout.tsx +0 -68
  249. package/src/useValue$.ts +0 -53
  250. package/src/viewability.ts +0 -279
  251. package/tsconfig.json +0 -59
  252. package/tsup.config.ts +0 -21
  253. /package/{dist/animated.js → animated.js} +0 -0
  254. /package/{dist/animated.mjs → animated.mjs} +0 -0
  255. /package/{dist/keyboard-controller.js → keyboard-controller.js} +0 -0
  256. /package/{dist/keyboard-controller.mjs → keyboard-controller.mjs} +0 -0
  257. /package/{dist/reanimated.d.mts → reanimated.d.mts} +0 -0
  258. /package/{dist/reanimated.d.ts → reanimated.d.ts} +0 -0
  259. /package/{dist/reanimated.js → reanimated.js} +0 -0
  260. /package/{dist/reanimated.mjs → reanimated.mjs} +0 -0
@@ -1,130 +0,0 @@
1
- import { getId } from "./getId";
2
- import { getItemSize } from "./getItemSize";
3
- import { getScrollVelocity } from "./getScrollVelocity";
4
- import { roundSize } from "./helpers";
5
- import { type StateContext, peek$ } from "./state";
6
- import type { InternalState } from "./types";
7
- import { updateTotalSize } from "./updateTotalSize";
8
-
9
- export function updateAllPositions(ctx: StateContext, state: InternalState, dataChanged?: boolean) {
10
- const { averageSizes, columns, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizesKnown } = state;
11
- const data = state.props.data;
12
- const numColumns = peek$(ctx, "numColumns");
13
- const indexByKeyForChecking = __DEV__ ? new Map() : undefined;
14
- const scrollVelocity = getScrollVelocity(state);
15
-
16
- if (dataChanged) {
17
- indexByKey.clear();
18
- idCache.clear();
19
- }
20
-
21
- // TODO: Hook this up to actual item types later once we have item types
22
- const itemType = "";
23
- let averageSize = averageSizes[itemType]?.avg;
24
- if (averageSize !== undefined) {
25
- averageSize = roundSize(averageSize);
26
- }
27
-
28
- // Check if we should use backwards optimization when scrolling up
29
- const shouldUseBackwards =
30
- !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data!.length;
31
-
32
- if (shouldUseBackwards && firstFullyOnScreenIndex !== undefined) {
33
- // Get the current position of firstFullyOnScreenIndex as anchor
34
- const anchorId = getId(state, firstFullyOnScreenIndex)!;
35
- const anchorPosition = positions.get(anchorId);
36
-
37
- // If we don't have the anchor position, fall back to regular behavior
38
- if (anchorPosition !== undefined) {
39
- // Start from the anchor and go backwards
40
- let currentRowTop = anchorPosition;
41
- let maxSizeInRow = 0;
42
- let bailout = false;
43
-
44
- // Process items backwards from firstFullyOnScreenIndex - 1 to 0
45
- for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
46
- const id = idCache.get(i) ?? getId(state, i)!;
47
- const size = sizesKnown.get(id) ?? getItemSize(state, id, i, data[i], averageSize);
48
- const itemColumn = columns.get(id)!;
49
-
50
- maxSizeInRow = Math.max(maxSizeInRow, size);
51
-
52
- // When we reach column 1, we're at the start of a new row going backwards
53
- if (itemColumn === 1) {
54
- currentRowTop -= maxSizeInRow;
55
- maxSizeInRow = 0;
56
- }
57
-
58
- // Check if position goes too low - bail if so
59
- if (currentRowTop < -2000) {
60
- bailout = true;
61
- break;
62
- }
63
-
64
- // Update position for this item (columns and indexByKey already set)
65
- positions.set(id, currentRowTop);
66
- }
67
-
68
- if (!bailout) {
69
- // We successfully processed backwards, we're done
70
- updateTotalSize(ctx, state);
71
- return;
72
- }
73
- }
74
- }
75
-
76
- // Regular ascending behavior (either not scrolling up or bailed out)
77
- let currentRowTop = 0;
78
- let column = 1;
79
- let maxSizeInRow = 0;
80
-
81
- const hasColumns = numColumns > 1;
82
- const needsIndexByKey = dataChanged || indexByKey.size === 0;
83
-
84
- // Note that this loop is micro-optimized because it's a hot path
85
- const dataLength = data!.length;
86
- for (let i = 0; i < dataLength; i++) {
87
- // Inline the map get calls to avoid the overhead of the function call
88
- const id = idCache.get(i) ?? getId(state, i)!;
89
- const size = sizesKnown.get(id) ?? getItemSize(state, id, i, data[i], averageSize);
90
-
91
- // Set index mapping for this item
92
- if (__DEV__ && needsIndexByKey) {
93
- if (indexByKeyForChecking!.has(id)) {
94
- console.error(
95
- `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`,
96
- );
97
- }
98
- indexByKeyForChecking!.set(id, i);
99
- }
100
-
101
- // Set position for this item
102
- positions.set(id, currentRowTop);
103
-
104
- // Update indexByKey if needed
105
- if (needsIndexByKey) {
106
- indexByKey.set(id, i);
107
- }
108
-
109
- // Set column for this item
110
- columns.set(id, column);
111
-
112
- if (hasColumns) {
113
- if (size > maxSizeInRow) {
114
- maxSizeInRow = size;
115
- }
116
-
117
- column++;
118
- if (column > numColumns) {
119
- // Move to next row
120
- currentRowTop += maxSizeInRow;
121
- column = 1;
122
- maxSizeInRow = 0;
123
- }
124
- } else {
125
- currentRowTop += size;
126
- }
127
- }
128
-
129
- updateTotalSize(ctx, state);
130
- }
@@ -1,203 +0,0 @@
1
- import type { LayoutRectangle } from "react-native";
2
- import { calculateItemsInView } from "./calculateItemsInView";
3
- import { checkAllSizesKnown } from "./checkAllSizesKnown";
4
- import { IsNewArchitecture } from "./constants";
5
- import { doMaintainScrollAtEnd } from "./doMaintainScrollAtEnd";
6
- import { getItemSize } from "./getItemSize";
7
- import { requestAdjust } from "./requestAdjust";
8
- import { type StateContext, peek$, set$ } from "./state";
9
- import type { InternalState, MaintainScrollAtEndOptions } from "./types";
10
-
11
- export function updateItemSizes(
12
- ctx: StateContext,
13
- state: InternalState,
14
- itemUpdates: { itemKey: string; sizeObj: { width: number; height: number } }[],
15
- ) {
16
- const {
17
- props: {
18
- horizontal,
19
- maintainVisibleContentPosition,
20
- suggestEstimatedItemSize,
21
- onItemSizeChanged,
22
- data,
23
- maintainScrollAtEnd,
24
- },
25
- } = state;
26
-
27
- if (!data) return;
28
-
29
- let needsRecalculate = false;
30
- let shouldMaintainScrollAtEnd = false;
31
- let minIndexSizeChanged: number | undefined;
32
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
33
-
34
- for (const { itemKey, sizeObj } of itemUpdates) {
35
- const index = state.indexByKey.get(itemKey)!;
36
- const prevSizeKnown = state.sizesKnown.get(itemKey);
37
-
38
- const diff = updateOneItemSize(state, itemKey, sizeObj);
39
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
40
-
41
- if (diff !== 0) {
42
- minIndexSizeChanged = minIndexSizeChanged !== undefined ? Math.min(minIndexSizeChanged, index) : index;
43
-
44
- // Handle scrolling adjustments
45
- if (
46
- state.scrollingTo?.viewPosition &&
47
- maintainVisibleContentPosition &&
48
- index === state.scrollingTo.index
49
- ) {
50
- requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
51
- }
52
-
53
- // Check if item is in view
54
- const { startBuffered, endBuffered } = state;
55
- needsRecalculate ||= index >= startBuffered && index <= endBuffered;
56
- if (!needsRecalculate) {
57
- const numContainers = ctx.values.get("numContainers") as number;
58
- for (let i = 0; i < numContainers; i++) {
59
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
60
- needsRecalculate = true;
61
- break;
62
- }
63
- }
64
- }
65
-
66
- // Handle other axis size
67
- if (state.needsOtherAxisSize) {
68
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
69
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
70
- }
71
-
72
- // Check if we should maintain scroll at end
73
- if (prevSizeKnown !== undefined && Math.abs(prevSizeKnown - size) > 5) {
74
- shouldMaintainScrollAtEnd = true;
75
- }
76
-
77
- // Call onItemSizeChanged callback
78
- onItemSizeChanged?.({
79
- size,
80
- previous: size - diff,
81
- index,
82
- itemKey,
83
- itemData: state.props.data[index],
84
- });
85
- }
86
- }
87
-
88
- // Update state with minimum changed index
89
- if (minIndexSizeChanged !== undefined) {
90
- state.minIndexSizeChanged =
91
- state.minIndexSizeChanged !== undefined
92
- ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged)
93
- : minIndexSizeChanged;
94
- }
95
-
96
- // Handle dev warning about estimated size
97
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== undefined) {
98
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
99
- state.timeoutSizeMessage = setTimeout(() => {
100
- state.timeoutSizeMessage = undefined;
101
- const num = state.sizesKnown.size;
102
- const avg = state.averageSizes[""]?.avg;
103
- console.warn(
104
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`,
105
- );
106
- }, 1000);
107
- }
108
-
109
- const cur = peek$(ctx, "otherAxisSize");
110
- if (!cur || maxOtherAxisSize > cur) {
111
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
112
- }
113
-
114
- const containersDidLayout = peek$(ctx, "containersDidLayout");
115
-
116
- if (containersDidLayout || checkAllSizesKnown(state)) {
117
- if (needsRecalculate) {
118
- state.scrollForNextCalculateItemsInView = undefined;
119
-
120
- calculateItemsInView(ctx, state, { doMVCP: true });
121
- }
122
- if (shouldMaintainScrollAtEnd) {
123
- if (maintainScrollAtEnd === true || (maintainScrollAtEnd as MaintainScrollAtEndOptions).onItemLayout) {
124
- doMaintainScrollAtEnd(ctx, state, false);
125
- }
126
- }
127
- }
128
- }
129
-
130
- export function updateItemSize(
131
- ctx: StateContext,
132
- state: InternalState,
133
- itemKey: string,
134
- sizeObj: { width: number; height: number },
135
- ) {
136
- if (IsNewArchitecture) {
137
- const { sizesKnown } = state;
138
- const numContainers = ctx.values.get("numContainers") as number;
139
- const changes: { itemKey: string; sizeObj: { width: number; height: number } }[] = [];
140
-
141
- // Run through all containers and if we don't already have a known size then measure the item
142
- // This is useful because when multiple items render in one frame, the first container fires a
143
- // useLayoutEffect and we can measure all containers before their useLayoutEffects fire after a delay.
144
- // This lets use fix any gaps/overlaps that might be visible before the useLayoutEffects fire for each container.
145
- for (let i = 0; i < numContainers; i++) {
146
- const containerItemKey = peek$(ctx, `containerItemKey${i}`);
147
- if (itemKey === containerItemKey) {
148
- // If it's this item just use the param
149
- changes.push({ itemKey, sizeObj });
150
- } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== undefined) {
151
- const containerRef = ctx.viewRefs.get(i);
152
- if (containerRef?.current) {
153
- let measured: LayoutRectangle;
154
- containerRef.current.measure((x, y, width, height) => {
155
- measured = { x, y, width, height };
156
- });
157
-
158
- if (measured!) {
159
- changes.push({ itemKey: containerItemKey, sizeObj: measured });
160
- }
161
- }
162
- }
163
- }
164
-
165
- if (changes.length > 0) {
166
- updateItemSizes(ctx, state, changes);
167
- }
168
- } else {
169
- updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
170
- }
171
- }
172
-
173
- export function updateOneItemSize(state: InternalState, itemKey: string, sizeObj: { width: number; height: number }) {
174
- const {
175
- sizes,
176
- indexByKey,
177
- sizesKnown,
178
- averageSizes,
179
- props: { data, horizontal },
180
- } = state;
181
- if (!data) return 0;
182
-
183
- const index = indexByKey.get(itemKey)!;
184
- const prevSize = getItemSize(state, itemKey, index, data as any);
185
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
186
-
187
- sizesKnown.set(itemKey, size);
188
-
189
- // Update averages
190
- const itemType = "";
191
- let averages = averageSizes[itemType];
192
- if (!averages) {
193
- averages = averageSizes[itemType] = { num: 0, avg: 0 };
194
- }
195
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
196
- averages.num++;
197
-
198
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
199
- sizes.set(itemKey, size);
200
- return size - prevSize;
201
- }
202
- return 0;
203
- }
@@ -1,44 +0,0 @@
1
- import { getId } from "./getId";
2
- import { getItemSize } from "./getItemSize";
3
- import { type StateContext, set$ } from "./state";
4
- import type { InternalState } from "./types";
5
- import { updateAlignItemsPaddingTop } from "./updateAlignItemsPaddingTop";
6
-
7
- export function updateTotalSize(ctx: StateContext, state: InternalState) {
8
- const {
9
- positions,
10
- props: { data },
11
- } = state;
12
-
13
- if (data.length === 0) {
14
- addTotalSize(ctx, state, null, 0);
15
- } else {
16
- const lastId = getId(state, data.length - 1);
17
- if (lastId !== undefined) {
18
- const lastPosition = positions.get(lastId);
19
- if (lastPosition !== undefined) {
20
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
21
- // TODO: This is likely incorrect for columns with rows having different heights, need to get max size of the last row
22
- if (lastSize !== undefined) {
23
- const totalSize = lastPosition + lastSize;
24
- addTotalSize(ctx, state, null, totalSize);
25
- }
26
- }
27
- }
28
- }
29
- }
30
-
31
- function addTotalSize(ctx: StateContext, state: InternalState, key: string | null, add: number) {
32
- const { alignItemsAtEnd } = state.props;
33
- if (key === null) {
34
- state.totalSize = add;
35
- } else {
36
- state.totalSize += add;
37
- }
38
-
39
- set$(ctx, "totalSize", state.totalSize);
40
-
41
- if (alignItemsAtEnd) {
42
- updateAlignItemsPaddingTop(ctx, state);
43
- }
44
- }
@@ -1,6 +0,0 @@
1
- import { useRef } from "react";
2
- import { Animated } from "react-native";
3
-
4
- export const useAnimatedValue = (initialValue: number): Animated.Value => {
5
- return useRef(new Animated.Value(initialValue)).current;
6
- };
@@ -1,22 +0,0 @@
1
- import { useCallback } from "react";
2
- import { isFunction } from "./helpers";
3
-
4
- type RefItem<T> = ((element: T | null) => void) | React.MutableRefObject<T | null> | null | undefined;
5
-
6
- export const useCombinedRef = <T>(...refs: RefItem<T>[]) => {
7
- const callback = useCallback((element: T | null) => {
8
- for (const ref of refs) {
9
- if (!ref) {
10
- continue;
11
- }
12
-
13
- if (isFunction(ref)) {
14
- ref(element);
15
- } else {
16
- ref.current = element;
17
- }
18
- }
19
- }, refs);
20
-
21
- return callback;
22
- };
package/src/useInit.ts DELETED
@@ -1,17 +0,0 @@
1
- import { useRef } from "react";
2
-
3
- const symbolFirst = Symbol();
4
- // A hook that runs a callback only once during the first render.
5
- // It should happen during render, not in useEffect, so that any setState calls during the callback
6
- // will trigger a re-render immediately rather than waiting for a next render.
7
- // See https://react.dev/reference/react/useState#storing-information-from-previous-renders
8
- export function useInit<T>(cb: () => T) {
9
- const refValue = useRef<T | typeof symbolFirst>(symbolFirst);
10
-
11
- // Run inline during first render only
12
- if (refValue.current === symbolFirst) {
13
- refValue.current = cb();
14
- }
15
-
16
- return refValue.current;
17
- }
@@ -1,68 +0,0 @@
1
- import { useCallback, useLayoutEffect, useRef, useState } from "react";
2
- import type { LayoutChangeEvent, LayoutRectangle, View } from "react-native";
3
-
4
- export function useSyncLayoutState<T extends View = View>({
5
- getValue,
6
- debounce,
7
- onChange: onChangeProp,
8
- }: {
9
- getValue: (rectangle: LayoutRectangle) => number;
10
- debounce?: number | undefined;
11
- onChange: (rectangle: LayoutRectangle, fromLayoutEffect: boolean) => void;
12
- }) {
13
- const debounceTimeoutRef = useRef<any>(null);
14
- const [value, setValue] = useState(0);
15
-
16
- const onChange = useCallback(
17
- (rectangle: LayoutRectangle, fromLayoutEffect: boolean) => {
18
- const height = getValue(rectangle);
19
-
20
- if (debounce === undefined) {
21
- setValue(height);
22
- } else {
23
- // Clear previous timeout if it exists
24
- if (debounceTimeoutRef.current) {
25
- clearTimeout(debounceTimeoutRef.current);
26
- }
27
-
28
- // Debounce the setViewHeight call
29
- debounceTimeoutRef.current = setTimeout(() => {
30
- debounceTimeoutRef.current = null;
31
- setValue(height);
32
- }, debounce);
33
- }
34
-
35
- onChangeProp?.(rectangle, fromLayoutEffect);
36
- },
37
- [getValue, debounce],
38
- );
39
-
40
- const { onLayout, ref } = useSyncLayout<T>({ onChange });
41
-
42
- return { value, onLayout, ref };
43
- }
44
-
45
- export function useSyncLayout<T extends View = View>({
46
- onChange,
47
- }: {
48
- onChange: (rectangle: LayoutRectangle, fromLayoutEffect: boolean) => void;
49
- }) {
50
- const ref = useRef<T | null>(null);
51
-
52
- const onLayout = useCallback(
53
- (event: LayoutChangeEvent) => {
54
- onChange(event.nativeEvent.layout, false);
55
- },
56
- [onChange],
57
- );
58
-
59
- useLayoutEffect(() => {
60
- if (ref.current) {
61
- ref.current.measure((x, y, width, height) => {
62
- onChange({ x, y, width, height }, true);
63
- });
64
- }
65
- }, []);
66
-
67
- return { onLayout, ref };
68
- }
package/src/useValue$.ts DELETED
@@ -1,53 +0,0 @@
1
- import { useMemo } from "react";
2
- import { listen$, peek$, useStateContext } from "./state";
3
- import type { ListenerType } from "./state";
4
- import { useAnimatedValue } from "./useAnimatedValue";
5
-
6
- export function useValue$(
7
- key: ListenerType,
8
- params?: {
9
- getValue?: (value: number) => number;
10
- delay?: number | ((value: number, prevValue: number | undefined) => number);
11
- },
12
- ) {
13
- const { getValue, delay } = params || {};
14
- const ctx = useStateContext();
15
- const animValue = useAnimatedValue((getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) ?? 0);
16
- useMemo(() => {
17
- let newValue: number | undefined = undefined;
18
- let prevValue: number | undefined = undefined;
19
- let didQueueTask = false;
20
- listen$(ctx, key, (v) => {
21
- newValue = getValue ? getValue(v) : v;
22
-
23
- if (delay !== undefined) {
24
- // Queue into a microtask because setting the value immediately was making the value
25
- // not actually set. I think it has to do with setting during useLayoutEffect, but I'm not sure.
26
- // This seems to be an optimization for setting totalSize because that can happen multiple times per frame
27
- // so we skip setting the value immediately if using the microtask version.
28
- const fn = () => {
29
- didQueueTask = false;
30
- if (newValue !== undefined) {
31
- animValue.setValue(newValue!);
32
- }
33
- };
34
- const delayValue = typeof delay === "function" ? delay(newValue!, prevValue) : delay;
35
- prevValue = newValue;
36
- if (!didQueueTask) {
37
- didQueueTask = true;
38
- if (delayValue === 0) {
39
- queueMicrotask(fn);
40
- } else {
41
- // We're not clearing the timeout because we want it to run in the timeout from the first change
42
- // but just not run multiple times.
43
- setTimeout(fn, delayValue);
44
- }
45
- }
46
- } else {
47
- animValue.setValue(newValue!);
48
- }
49
- });
50
- }, []);
51
-
52
- return animValue;
53
- }