@legendapp/list 3.0.0-beta.4 → 3.0.0-beta.41

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 (49) hide show
  1. package/.DS_Store +0 -0
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +9 -2
  4. package/animated.d.ts +620 -5
  5. package/animated.js +2 -2
  6. package/animated.mjs +1 -1
  7. package/index.d.ts +1227 -11
  8. package/index.js +2594 -1023
  9. package/index.mjs +2593 -1024
  10. package/index.native.js +2347 -961
  11. package/index.native.mjs +2327 -943
  12. package/keyboard-test.d.ts +206 -0
  13. package/keyboard-test.js +34 -0
  14. package/keyboard-test.mjs +13 -0
  15. package/keyboard.d.ts +206 -8
  16. package/keyboard.js +340 -32
  17. package/keyboard.mjs +343 -34
  18. package/package.json +62 -1
  19. package/{types-JPHClxiw.d.mts → react-native.d.ts} +436 -158
  20. package/react-native.js +4942 -0
  21. package/react-native.mjs +4911 -0
  22. package/{types-JPHClxiw.d.ts → react-native.web.d.ts} +493 -158
  23. package/react-native.web.js +5357 -0
  24. package/react-native.web.mjs +5326 -0
  25. package/{types-YNdphn_A.d.mts → react.d.ts} +493 -158
  26. package/react.js +5357 -0
  27. package/react.mjs +5326 -0
  28. package/reanimated.d.ts +631 -7
  29. package/reanimated.js +156 -30
  30. package/reanimated.mjs +155 -29
  31. package/section-list.d.ts +620 -5
  32. package/section-list.js +38 -3679
  33. package/section-list.mjs +34 -3676
  34. package/animated.d.mts +0 -9
  35. package/index.d.mts +0 -23
  36. package/index.native.d.mts +0 -23
  37. package/index.native.d.ts +0 -23
  38. package/keyboard-controller.d.mts +0 -12
  39. package/keyboard-controller.d.ts +0 -12
  40. package/keyboard-controller.js +0 -69
  41. package/keyboard-controller.mjs +0 -48
  42. package/keyboard.d.mts +0 -13
  43. package/reanimated.d.mts +0 -18
  44. package/section-list.d.mts +0 -113
  45. package/section-list.native.d.mts +0 -113
  46. package/section-list.native.d.ts +0 -113
  47. package/section-list.native.js +0 -3700
  48. package/section-list.native.mjs +0 -3679
  49. package/types-YNdphn_A.d.ts +0 -670
package/keyboard.js CHANGED
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var reactNative = require('react-native');
4
+ var reactNative$1 = require('react-native');
5
5
  var reactNativeKeyboardController = require('react-native-keyboard-controller');
6
6
  var reactNativeReanimated = require('react-native-reanimated');
7
+ var reactNative = require('@legendapp/list/react-native');
7
8
  var reanimated = require('@legendapp/list/reanimated');
8
9
 
9
10
  function _interopNamespace(e) {
@@ -27,78 +28,386 @@ function _interopNamespace(e) {
27
28
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
29
 
29
30
  // src/integrations/keyboard.tsx
30
- var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
31
+ var { useCombinedRef } = reactNative.internal;
32
+ var clampProgress = (progress) => {
33
+ "worklet";
34
+ return Math.min(1, Math.max(0, progress));
35
+ };
36
+ var calculateKeyboardInset = (height, safeAreaInsetBottom) => {
37
+ "worklet";
38
+ return Math.max(0, height - safeAreaInsetBottom);
39
+ };
40
+ var calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
41
+ "worklet";
42
+ if (alignItemsAtEnd) {
43
+ return keyboardHeight;
44
+ } else {
45
+ const availableSpace = Math.max(0, scrollLength - contentLength);
46
+ return Math.max(0, keyboardHeight - availableSpace);
47
+ }
48
+ };
49
+ var calculateKeyboardTargetOffset = (startOffset, keyboardHeight, isOpening, progress) => {
50
+ "worklet";
51
+ const normalizedProgress = isOpening ? progress : 1 - progress;
52
+ const delta = (isOpening ? keyboardHeight : -keyboardHeight) * normalizedProgress;
53
+ return Math.max(0, startOffset + delta);
54
+ };
55
+ var KeyboardAvoidingLegendList = reactNative.typedForwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
31
56
  const {
57
+ contentContainerStyle: contentContainerStyleProp,
32
58
  contentInset: contentInsetProp,
33
59
  horizontal,
60
+ onMetricsChange: onMetricsChangeProp,
61
+ onContentSizeChange: onContentSizeChangeProp,
62
+ onLayout: onLayoutProp,
34
63
  onScroll: onScrollProp,
35
64
  safeAreaInsetBottom = 0,
65
+ style: styleProp,
36
66
  ...rest
37
67
  } = props;
68
+ const { alignItemsAtEnd } = props;
69
+ const styleFlattened = reactNative$1.StyleSheet.flatten(styleProp);
70
+ const refLegendList = React.useRef(null);
71
+ const combinedRef = useCombinedRef(forwardedRef, refLegendList);
72
+ const isIos = reactNative$1.Platform.OS === "ios";
73
+ const isAndroid = reactNative$1.Platform.OS === "android";
38
74
  const scrollViewRef = reactNativeReanimated.useAnimatedRef();
39
75
  const scrollOffsetY = reactNativeReanimated.useSharedValue(0);
76
+ const animatedOffsetY = reactNativeReanimated.useSharedValue(null);
40
77
  const scrollOffsetAtKeyboardStart = reactNativeReanimated.useSharedValue(0);
78
+ const animationMode = reactNativeReanimated.useSharedValue("idle");
41
79
  const keyboardInset = reactNativeReanimated.useSharedValue(0);
80
+ const keyboardHeight = reactNativeReanimated.useSharedValue(0);
81
+ const contentLength = reactNativeReanimated.useSharedValue(0);
82
+ const scrollLength = reactNativeReanimated.useSharedValue(0);
83
+ const isOpening = reactNativeReanimated.useSharedValue(false);
84
+ const didInteractive = reactNativeReanimated.useSharedValue(false);
85
+ const shouldUpdateAlignItemsAtEndMinSize = reactNativeReanimated.useSharedValue(false);
86
+ const isKeyboardOpen = reactNativeReanimated.useSharedValue(false);
87
+ const keyboardInsetRef = React.useRef(0);
88
+ const [alignItemsAtEndMinSize, setAlignItemsAtEndMinSize] = React.useState(void 0);
89
+ const onScrollValue = onScrollProp;
90
+ const onScrollCallback = typeof onScrollValue === "function" ? onScrollValue : void 0;
91
+ const onScrollProcessed = onScrollValue && typeof onScrollValue === "object" && "workletEventHandler" in onScrollValue ? onScrollValue : null;
92
+ const onScrollCallbackIsWorklet = React.useMemo(
93
+ () => onScrollCallback ? reactNativeReanimated.isWorkletFunction(onScrollCallback) : false,
94
+ [onScrollCallback]
95
+ );
96
+ const handleContentSizeChange = React.useCallback(
97
+ (width, height) => {
98
+ const nextContentLength = horizontal ? width : height;
99
+ if (Number.isFinite(nextContentLength) && nextContentLength > 0) {
100
+ contentLength.set(nextContentLength);
101
+ }
102
+ onContentSizeChangeProp == null ? void 0 : onContentSizeChangeProp(width, height);
103
+ },
104
+ [contentLength, horizontal, onContentSizeChangeProp]
105
+ );
106
+ const handleLayout = React.useCallback(
107
+ (event) => {
108
+ const nextScrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
109
+ if (Number.isFinite(nextScrollLength) && nextScrollLength > 0) {
110
+ scrollLength.set(nextScrollLength);
111
+ }
112
+ onLayoutProp == null ? void 0 : onLayoutProp(event);
113
+ },
114
+ [horizontal, onLayoutProp, scrollLength]
115
+ );
42
116
  const scrollHandler = reactNativeReanimated.useAnimatedScrollHandler(
43
117
  (event) => {
44
- scrollOffsetY.value = event.contentOffset[horizontal ? "x" : "y"];
45
- if (onScrollProp) {
46
- reactNativeReanimated.runOnJS(onScrollProp)(event);
118
+ if (animationMode.get() !== "running" || didInteractive.get()) {
119
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
120
+ }
121
+ if (onScrollCallback) {
122
+ if (onScrollCallbackIsWorklet) {
123
+ onScrollCallback(event);
124
+ } else {
125
+ reactNativeReanimated.runOnJS(onScrollCallback)(event);
126
+ }
127
+ }
128
+ },
129
+ [horizontal, onScrollCallback, onScrollCallbackIsWorklet]
130
+ );
131
+ const composedScrollHandler = reactNativeReanimated.useComposedEventHandler([
132
+ scrollHandler,
133
+ onScrollProcessed
134
+ ]);
135
+ const finalScrollHandler = onScrollProcessed ? composedScrollHandler : scrollHandler;
136
+ const setScrollProcessingEnabled = React.useCallback(
137
+ (enabled) => {
138
+ var _a;
139
+ return (_a = refLegendList.current) == null ? void 0 : _a.setScrollProcessingEnabled(enabled);
140
+ },
141
+ [refLegendList]
142
+ );
143
+ const reportContentInset = React.useCallback(
144
+ (bottom) => {
145
+ var _a;
146
+ return (_a = refLegendList.current) == null ? void 0 : _a.reportContentInset({ bottom });
147
+ },
148
+ [refLegendList]
149
+ );
150
+ const clearAlignItemsAtEndMinSize = React.useCallback(() => {
151
+ setAlignItemsAtEndMinSize((prev) => prev === void 0 ? prev : void 0);
152
+ }, []);
153
+ const updateAlignItemsAtEndMinSize = React.useCallback(
154
+ (nextKeyboardInset) => {
155
+ var _a;
156
+ if (isAndroid) {
157
+ return;
158
+ }
159
+ if (nextKeyboardInset !== void 0) {
160
+ keyboardInsetRef.current = nextKeyboardInset;
161
+ }
162
+ if (!alignItemsAtEnd || horizontal) {
163
+ clearAlignItemsAtEndMinSize();
164
+ return;
165
+ }
166
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
167
+ if (!state) {
168
+ return;
169
+ }
170
+ const currentInset = keyboardInsetRef.current;
171
+ if (currentInset <= 0) {
172
+ clearAlignItemsAtEndMinSize();
173
+ return;
174
+ }
175
+ if (state.scrollLength <= 0) {
176
+ return;
47
177
  }
178
+ const nextMinSize = Math.max(0, state.scrollLength - currentInset);
179
+ setAlignItemsAtEndMinSize((prev) => prev === nextMinSize ? prev : nextMinSize);
48
180
  },
49
- [onScrollProp, horizontal]
181
+ [alignItemsAtEnd, clearAlignItemsAtEndMinSize, horizontal]
182
+ );
183
+ const updateScrollMetrics = React.useCallback(() => {
184
+ var _a;
185
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
186
+ if (!state) {
187
+ return;
188
+ }
189
+ contentLength.set(state.contentLength);
190
+ scrollLength.set(state.scrollLength);
191
+ updateAlignItemsAtEndMinSize();
192
+ }, [contentLength, scrollLength, updateAlignItemsAtEndMinSize]);
193
+ const handleMetricsChange = React.useCallback(
194
+ (metrics) => {
195
+ updateScrollMetrics();
196
+ onMetricsChangeProp == null ? void 0 : onMetricsChangeProp(metrics);
197
+ },
198
+ [onMetricsChangeProp, updateScrollMetrics]
199
+ );
200
+ React.useEffect(() => {
201
+ updateAlignItemsAtEndMinSize();
202
+ }, [updateAlignItemsAtEndMinSize]);
203
+ const getEffectiveKeyboardHeightFromInset = React.useCallback(
204
+ (nextKeyboardInset) => {
205
+ "worklet";
206
+ return calculateEffectiveKeyboardHeight(
207
+ nextKeyboardInset,
208
+ contentLength.get(),
209
+ scrollLength.get(),
210
+ alignItemsAtEnd
211
+ );
212
+ },
213
+ [alignItemsAtEnd, contentLength, scrollLength]
214
+ );
215
+ const getEffectiveKeyboardHeightFromEvent = React.useCallback(
216
+ (eventHeight) => {
217
+ "worklet";
218
+ const nextKeyboardInset = calculateKeyboardInset(eventHeight, safeAreaInsetBottom);
219
+ return getEffectiveKeyboardHeightFromInset(nextKeyboardInset);
220
+ },
221
+ [getEffectiveKeyboardHeightFromInset, safeAreaInsetBottom]
50
222
  );
51
223
  reactNativeKeyboardController.useKeyboardHandler(
52
224
  // biome-ignore assist/source/useSortedKeys: prefer start/move/end
53
225
  {
54
- onStart: () => {
226
+ onStart: (event) => {
227
+ "worklet";
228
+ const progress = clampProgress(event.progress);
229
+ if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
230
+ didInteractive.set(false);
231
+ animationMode.set("idle");
232
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(true);
233
+ return;
234
+ }
235
+ animationMode.set("running");
236
+ if (!didInteractive.get()) {
237
+ if (event.height > 0) {
238
+ keyboardHeight.set(calculateKeyboardInset(event.height, safeAreaInsetBottom));
239
+ }
240
+ const vIsOpening = progress > 0;
241
+ isOpening.set(vIsOpening);
242
+ shouldUpdateAlignItemsAtEndMinSize.set(
243
+ !!alignItemsAtEnd && !horizontal && contentLength.get() < scrollLength.get()
244
+ );
245
+ if (!shouldUpdateAlignItemsAtEndMinSize.get()) {
246
+ reactNativeReanimated.runOnJS(clearAlignItemsAtEndMinSize)();
247
+ }
248
+ const vScrollOffset = scrollOffsetY.get();
249
+ scrollOffsetAtKeyboardStart.set(vScrollOffset);
250
+ if (isIos) {
251
+ const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromInset(keyboardHeight.get());
252
+ const targetOffset = Math.max(
253
+ 0,
254
+ vIsOpening ? vScrollOffset + vEffectiveKeyboardHeight : vScrollOffset - vEffectiveKeyboardHeight
255
+ );
256
+ scrollOffsetY.set(targetOffset);
257
+ animatedOffsetY.set(targetOffset);
258
+ keyboardInset.set(vEffectiveKeyboardHeight);
259
+ reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(vEffectiveKeyboardHeight);
260
+ } else if (isAndroid) {
261
+ animatedOffsetY.set(vScrollOffset);
262
+ }
263
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
264
+ }
265
+ },
266
+ onInteractive: (event) => {
55
267
  "worklet";
56
- scrollOffsetAtKeyboardStart.value = scrollOffsetY.value;
268
+ if (animationMode.get() !== "running") {
269
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
270
+ }
271
+ animationMode.set("running");
272
+ if (!didInteractive.get()) {
273
+ didInteractive.set(true);
274
+ }
275
+ if (isAndroid && !horizontal) {
276
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
277
+ keyboardInset.set(newInset);
278
+ }
279
+ if (shouldUpdateAlignItemsAtEndMinSize.get() && !horizontal && alignItemsAtEnd) {
280
+ const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromEvent(event.height);
281
+ reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(vEffectiveKeyboardHeight);
282
+ }
57
283
  },
58
284
  onMove: (event) => {
59
285
  "worklet";
60
- const targetOffset = scrollOffsetAtKeyboardStart.value + event.height;
61
- scrollOffsetY.value = targetOffset;
62
- reactNativeReanimated.scrollTo(scrollViewRef, 0, targetOffset, false);
63
- if (!horizontal) {
64
- keyboardInset.value = Math.max(0, event.height - safeAreaInsetBottom);
286
+ const vIsOpening = isOpening.get();
287
+ if (isAndroid) {
288
+ if (!didInteractive.get()) {
289
+ const progress = clampProgress(event.progress);
290
+ const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromInset(keyboardHeight.get());
291
+ const targetOffset = calculateKeyboardTargetOffset(
292
+ scrollOffsetAtKeyboardStart.get(),
293
+ vEffectiveKeyboardHeight,
294
+ vIsOpening,
295
+ progress
296
+ );
297
+ scrollOffsetY.set(targetOffset);
298
+ animatedOffsetY.set(targetOffset);
299
+ }
300
+ if (!horizontal) {
301
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
302
+ keyboardInset.set(newInset);
303
+ }
304
+ }
305
+ if (!horizontal && alignItemsAtEnd && !vIsOpening && shouldUpdateAlignItemsAtEndMinSize.get()) {
306
+ const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromEvent(event.height);
307
+ reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(vEffectiveKeyboardHeight);
65
308
  }
66
309
  },
67
310
  onEnd: (event) => {
68
311
  "worklet";
69
- const targetOffset = scrollOffsetAtKeyboardStart.value + event.height;
70
- scrollOffsetY.value = targetOffset;
71
- reactNativeReanimated.scrollTo(scrollViewRef, 0, targetOffset, false);
72
- if (!horizontal) {
73
- keyboardInset.value = Math.max(0, event.height - safeAreaInsetBottom);
312
+ const wasInteractive = didInteractive.get();
313
+ const vMode = animationMode.get();
314
+ animationMode.set("idle");
315
+ if (vMode === "running") {
316
+ const progress = clampProgress(event.progress);
317
+ const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromInset(keyboardHeight.get());
318
+ const vIsOpening = isOpening.get();
319
+ if (!wasInteractive) {
320
+ const targetOffset = calculateKeyboardTargetOffset(
321
+ scrollOffsetAtKeyboardStart.get(),
322
+ vEffectiveKeyboardHeight,
323
+ vIsOpening,
324
+ progress
325
+ );
326
+ scrollOffsetY.set(targetOffset);
327
+ animatedOffsetY.set(targetOffset);
328
+ }
329
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(true);
330
+ didInteractive.set(false);
331
+ isKeyboardOpen.set(event.height > 0);
332
+ if (!horizontal) {
333
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
334
+ keyboardInset.set(newInset);
335
+ reactNativeReanimated.runOnJS(reportContentInset)(newInset);
336
+ if (!vIsOpening) {
337
+ reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(newInset);
338
+ }
339
+ if (newInset <= 0) {
340
+ animatedOffsetY.set(scrollOffsetY.get());
341
+ }
342
+ }
74
343
  }
75
344
  }
76
345
  },
77
- [scrollViewRef, safeAreaInsetBottom]
346
+ [
347
+ alignItemsAtEnd,
348
+ clearAlignItemsAtEndMinSize,
349
+ getEffectiveKeyboardHeightFromEvent,
350
+ getEffectiveKeyboardHeightFromInset,
351
+ horizontal,
352
+ reportContentInset,
353
+ safeAreaInsetBottom,
354
+ scrollViewRef,
355
+ setScrollProcessingEnabled,
356
+ updateAlignItemsAtEndMinSize
357
+ ]
78
358
  );
79
- const animatedProps = reactNative.Platform.OS === "ios" ? reactNativeReanimated.useAnimatedProps(() => {
359
+ const animatedProps = reactNativeReanimated.useAnimatedProps(() => {
80
360
  "worklet";
81
361
  var _a, _b, _c, _d;
82
- return {
83
- contentInset: {
84
- bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInset.value),
362
+ const vAnimatedOffsetY = animatedOffsetY.get();
363
+ const baseProps = {
364
+ contentOffset: vAnimatedOffsetY === null ? void 0 : {
365
+ x: 0,
366
+ y: vAnimatedOffsetY
367
+ }
368
+ };
369
+ if (isIos) {
370
+ const keyboardInsetBottom = keyboardInset.get();
371
+ const contentInset = {
372
+ bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInsetBottom),
85
373
  left: (_b = contentInsetProp == null ? void 0 : contentInsetProp.left) != null ? _b : 0,
86
374
  right: (_c = contentInsetProp == null ? void 0 : contentInsetProp.right) != null ? _c : 0,
87
375
  top: (_d = contentInsetProp == null ? void 0 : contentInsetProp.top) != null ? _d : 0
88
- }
89
- };
90
- }) : void 0;
91
- const style = reactNative.Platform.OS !== "ios" ? reactNativeReanimated.useAnimatedStyle(() => ({
92
- marginBottom: keyboardInset.value
93
- })) : void 0;
376
+ };
377
+ return Object.assign(baseProps, {
378
+ contentInset
379
+ });
380
+ } else {
381
+ return baseProps;
382
+ }
383
+ });
384
+ const style = isAndroid ? reactNativeReanimated.useAnimatedStyle(
385
+ () => ({
386
+ ...styleFlattened || {},
387
+ marginBottom: keyboardInset.get()
388
+ }),
389
+ [styleProp, keyboardInset]
390
+ ) : styleProp;
391
+ const contentContainerStyle = React.useMemo(() => {
392
+ if (alignItemsAtEndMinSize === void 0) {
393
+ return contentContainerStyleProp;
394
+ }
395
+ const minSizeStyle = horizontal ? { minWidth: alignItemsAtEndMinSize } : { minHeight: alignItemsAtEndMinSize };
396
+ return contentContainerStyleProp ? [contentContainerStyleProp, minSizeStyle] : minSizeStyle;
397
+ }, [alignItemsAtEndMinSize, contentContainerStyleProp, horizontal]);
94
398
  return /* @__PURE__ */ React__namespace.createElement(
95
399
  reanimated.AnimatedLegendList,
96
400
  {
97
401
  ...rest,
98
402
  animatedProps,
403
+ automaticallyAdjustContentInsets: false,
404
+ contentContainerStyle,
99
405
  keyboardDismissMode: "interactive",
100
- onScroll: scrollHandler,
101
- ref: forwardedRef,
406
+ onContentSizeChange: handleContentSizeChange,
407
+ onLayout: handleLayout,
408
+ onMetricsChange: handleMetricsChange,
409
+ onScroll: finalScrollHandler,
410
+ ref: combinedRef,
102
411
  refScrollView: scrollViewRef,
103
412
  scrollIndicatorInsets: { bottom: 0, top: 0 },
104
413
  style
@@ -107,4 +416,3 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
107
416
  });
108
417
 
109
418
  exports.KeyboardAvoidingLegendList = KeyboardAvoidingLegendList;
110
- exports.LegendList = KeyboardAvoidingLegendList;