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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -0
  3. package/animated.native.d.mts +9 -0
  4. package/animated.native.d.ts +9 -0
  5. package/animated.native.js +9 -0
  6. package/animated.native.mjs +7 -0
  7. package/index.d.mts +781 -10
  8. package/index.d.ts +781 -10
  9. package/index.js +973 -530
  10. package/index.mjs +973 -532
  11. package/index.native.d.mts +781 -10
  12. package/index.native.d.ts +781 -10
  13. package/index.native.js +981 -494
  14. package/index.native.mjs +980 -495
  15. package/keyboard-controller.native.d.mts +12 -0
  16. package/keyboard-controller.native.d.ts +12 -0
  17. package/keyboard-controller.native.js +69 -0
  18. package/keyboard-controller.native.mjs +48 -0
  19. package/keyboard.d.mts +5 -2
  20. package/keyboard.d.ts +5 -2
  21. package/keyboard.js +232 -28
  22. package/keyboard.mjs +235 -31
  23. package/keyboard.native.d.mts +16 -0
  24. package/keyboard.native.d.ts +16 -0
  25. package/keyboard.native.js +318 -0
  26. package/keyboard.native.mjs +296 -0
  27. package/package.json +1 -1
  28. package/reanimated.d.mts +3 -3
  29. package/reanimated.d.ts +3 -3
  30. package/reanimated.js +15 -4
  31. package/reanimated.mjs +14 -3
  32. package/reanimated.native.d.mts +18 -0
  33. package/reanimated.native.d.ts +18 -0
  34. package/reanimated.native.js +89 -0
  35. package/reanimated.native.mjs +65 -0
  36. package/section-list.d.mts +1 -2
  37. package/section-list.d.ts +1 -2
  38. package/section-list.js +36 -3670
  39. package/section-list.mjs +34 -3669
  40. package/section-list.native.d.mts +1 -2
  41. package/section-list.native.d.ts +1 -2
  42. package/section-list.native.js +36 -3449
  43. package/section-list.native.mjs +33 -3447
  44. package/types-JPHClxiw.d.mts +0 -670
  45. package/types-JPHClxiw.d.ts +0 -670
  46. package/types-YNdphn_A.d.mts +0 -670
  47. package/types-YNdphn_A.d.ts +0 -670
package/keyboard.mjs CHANGED
@@ -1,87 +1,291 @@
1
1
  import * as React from 'react';
2
- import { forwardRef } from 'react';
3
- import { Platform } from 'react-native';
2
+ import { forwardRef, useRef, useCallback } from 'react';
3
+ import { StyleSheet, Platform } from 'react-native';
4
4
  import { useKeyboardHandler } from 'react-native-keyboard-controller';
5
- import { useAnimatedRef, useSharedValue, useAnimatedScrollHandler, runOnJS, scrollTo, useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated';
5
+ import { useAnimatedRef, useSharedValue, useAnimatedScrollHandler, runOnJS, runOnUI, useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated';
6
6
  import { AnimatedLegendList } from '@legendapp/list/reanimated';
7
7
 
8
8
  // src/integrations/keyboard.tsx
9
+
10
+ // src/constants-platform.ts
11
+ var IsNewArchitecture = true;
12
+
13
+ // src/utils/helpers.ts
14
+ function isFunction(obj) {
15
+ return typeof obj === "function";
16
+ }
17
+
18
+ // src/hooks/useCombinedRef.ts
19
+ var useCombinedRef = (...refs) => {
20
+ const callback = useCallback((element) => {
21
+ for (const ref of refs) {
22
+ if (!ref) {
23
+ continue;
24
+ }
25
+ if (isFunction(ref)) {
26
+ ref(element);
27
+ } else {
28
+ ref.current = element;
29
+ }
30
+ }
31
+ }, refs);
32
+ return callback;
33
+ };
34
+
35
+ // src/integrations/keyboard.tsx
36
+ var clampProgress = (progress) => {
37
+ "worklet";
38
+ return Math.min(1, Math.max(0, progress));
39
+ };
40
+ var calculateKeyboardInset = (height, safeAreaInsetBottom, isNewArchitecture) => {
41
+ "worklet";
42
+ return Math.max(0, height - safeAreaInsetBottom) ;
43
+ };
44
+ var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
45
+ "worklet";
46
+ return Math.min(keyboardHeight, alignItemsAtEndPadding);
47
+ };
48
+ var calculateTopInset = (safeAreaInsetTop, isNewArchitecture, extraTopInset) => {
49
+ "worklet";
50
+ return (isNewArchitecture ? 0 : safeAreaInsetTop * 2) + extraTopInset;
51
+ };
52
+ var calculateKeyboardTargetOffset = (startOffset, keyboardHeight, isOpening, progress) => {
53
+ "worklet";
54
+ const normalizedProgress = isOpening ? progress : 1 - progress;
55
+ const delta = (isOpening ? keyboardHeight : -keyboardHeight) * normalizedProgress;
56
+ return Math.max(0, startOffset + delta);
57
+ };
9
58
  var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
10
59
  const {
11
60
  contentInset: contentInsetProp,
12
61
  horizontal,
62
+ onMetricsChange: onMetricsChangeProp,
13
63
  onScroll: onScrollProp,
14
- scrollEventThrottle,
15
- safeAreaInsetBottom = 0,
64
+ safeAreaInsets = { bottom: 0, top: 0 },
65
+ style: styleProp,
16
66
  ...rest
17
67
  } = props;
18
- const resolvedScrollEventThrottle = scrollEventThrottle != null ? scrollEventThrottle : 16;
68
+ const styleFlattened = StyleSheet.flatten(styleProp);
69
+ const refLegendList = useRef(null);
70
+ const combinedRef = useCombinedRef(forwardedRef, refLegendList);
71
+ const isIos = Platform.OS === "ios";
72
+ const isAndroid = Platform.OS === "android";
19
73
  const scrollViewRef = useAnimatedRef();
20
74
  const scrollOffsetY = useSharedValue(0);
75
+ const animatedOffsetY = useSharedValue(null);
21
76
  const scrollOffsetAtKeyboardStart = useSharedValue(0);
22
- const keyboardInset = useSharedValue(0);
77
+ const mode = useSharedValue("idle");
78
+ const keyboardInset = useSharedValue({ bottom: 0, top: 0 });
79
+ const keyboardHeight = useSharedValue(0);
80
+ const alignItemsAtEndPadding = useSharedValue(0);
81
+ const isOpening = useSharedValue(false);
82
+ const didInteractive = useSharedValue(false);
83
+ const { top: safeAreaInsetTop, bottom: safeAreaInsetBottom } = safeAreaInsets;
84
+ const isKeyboardOpen = useSharedValue(false);
23
85
  const scrollHandler = useAnimatedScrollHandler(
24
86
  (event) => {
25
- scrollOffsetY.value = event.contentOffset[horizontal ? "x" : "y"];
87
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
26
88
  if (onScrollProp) {
27
89
  runOnJS(onScrollProp)(event);
28
90
  }
29
91
  },
30
92
  [onScrollProp, horizontal]
31
93
  );
94
+ const setScrollProcessingEnabled = useCallback(
95
+ (enabled) => {
96
+ var _a;
97
+ return (_a = refLegendList.current) == null ? void 0 : _a.setScrollProcessingEnabled(enabled);
98
+ },
99
+ [refLegendList]
100
+ );
101
+ const handleMetricsChange = useCallback(
102
+ (metrics) => {
103
+ const nextPadding = metrics.alignItemsAtEndPadding || 0;
104
+ alignItemsAtEndPadding.set(nextPadding);
105
+ if (!horizontal) {
106
+ runOnUI((padding, safeInsetTop, isNewArchitecture) => {
107
+ "worklet";
108
+ if (!isKeyboardOpen.get()) {
109
+ return;
110
+ }
111
+ const vKeyboardHeight = keyboardHeight.get();
112
+ const vTopInset = calculateEndPaddingInset(vKeyboardHeight, padding);
113
+ const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
114
+ keyboardInset.set({
115
+ bottom: keyboardInset.get().bottom,
116
+ top: topInset
117
+ });
118
+ })(nextPadding, safeAreaInsetTop, IsNewArchitecture);
119
+ }
120
+ onMetricsChangeProp == null ? void 0 : onMetricsChangeProp(metrics);
121
+ },
122
+ [
123
+ alignItemsAtEndPadding,
124
+ horizontal,
125
+ isKeyboardOpen,
126
+ keyboardHeight,
127
+ keyboardInset,
128
+ onMetricsChangeProp,
129
+ safeAreaInsetTop
130
+ ]
131
+ );
32
132
  useKeyboardHandler(
33
133
  // biome-ignore assist/source/useSortedKeys: prefer start/move/end
34
134
  {
35
- onStart: () => {
135
+ onStart: (event) => {
136
+ "worklet";
137
+ mode.set("running");
138
+ const progress = clampProgress(event.progress);
139
+ if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
140
+ return;
141
+ }
142
+ if (!didInteractive.get()) {
143
+ if (event.height > 0) {
144
+ keyboardHeight.set(event.height - safeAreaInsetBottom);
145
+ }
146
+ isOpening.set(progress > 0);
147
+ scrollOffsetAtKeyboardStart.set(scrollOffsetY.get());
148
+ animatedOffsetY.set(scrollOffsetY.get());
149
+ runOnJS(setScrollProcessingEnabled)(false);
150
+ }
151
+ },
152
+ onInteractive: (event) => {
36
153
  "worklet";
37
- scrollOffsetAtKeyboardStart.value = scrollOffsetY.value;
154
+ if (mode.get() !== "running") {
155
+ runOnJS(setScrollProcessingEnabled)(false);
156
+ }
157
+ mode.set("running");
158
+ if (!didInteractive.get()) {
159
+ if (!isAndroid && !IsNewArchitecture) {
160
+ keyboardInset.set({
161
+ bottom: keyboardInset.get().bottom,
162
+ // Legacy iOS uses a doubled top inset to keep content below the status bar.
163
+ top: calculateTopInset(safeAreaInsetTop, IsNewArchitecture, 0)
164
+ });
165
+ }
166
+ didInteractive.set(true);
167
+ }
168
+ if (isAndroid && !horizontal) {
169
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
170
+ keyboardInset.set({ bottom: newInset, top: safeAreaInsetTop * 2 });
171
+ }
38
172
  },
39
173
  onMove: (event) => {
40
174
  "worklet";
41
- const targetOffset = scrollOffsetAtKeyboardStart.value + event.height;
42
- scrollOffsetY.value = targetOffset;
43
- scrollTo(scrollViewRef, 0, targetOffset, false);
44
- if (!horizontal) {
45
- keyboardInset.value = Math.max(0, event.height - safeAreaInsetBottom);
175
+ if (!didInteractive.get()) {
176
+ const progress = clampProgress(event.progress);
177
+ const vIsOpening = isOpening.get();
178
+ const vKeyboardHeight = keyboardHeight.get();
179
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
180
+ const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
181
+ const targetOffset = calculateKeyboardTargetOffset(
182
+ scrollOffsetAtKeyboardStart.get(),
183
+ vKeyboardHeight,
184
+ vIsOpening,
185
+ progress
186
+ );
187
+ scrollOffsetY.set(targetOffset);
188
+ animatedOffsetY.set(targetOffset);
189
+ if (!horizontal) {
190
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
191
+ const topInset = calculateTopInset(
192
+ safeAreaInsetTop,
193
+ IsNewArchitecture,
194
+ vIsOpening ? vTopInset : 0
195
+ );
196
+ keyboardInset.set({
197
+ bottom: newInset,
198
+ // Add top padding only while opening to keep end-aligned items visible.
199
+ top: topInset
200
+ });
201
+ }
46
202
  }
47
203
  },
48
204
  onEnd: (event) => {
49
205
  "worklet";
50
- const targetOffset = scrollOffsetAtKeyboardStart.value + event.height;
51
- scrollOffsetY.value = targetOffset;
52
- scrollTo(scrollViewRef, 0, targetOffset, false);
53
- if (!horizontal) {
54
- keyboardInset.value = Math.max(0, event.height - safeAreaInsetBottom);
206
+ const wasInteractive = didInteractive.get();
207
+ const vMode = mode.get();
208
+ mode.set("idle");
209
+ if (vMode === "running") {
210
+ const progress = clampProgress(event.progress);
211
+ const vKeyboardHeight = keyboardHeight.get();
212
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
213
+ const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
214
+ const vIsOpening = isOpening.get();
215
+ if (!wasInteractive) {
216
+ const targetOffset = calculateKeyboardTargetOffset(
217
+ scrollOffsetAtKeyboardStart.get(),
218
+ vKeyboardHeight,
219
+ vIsOpening,
220
+ progress
221
+ );
222
+ scrollOffsetY.set(targetOffset);
223
+ animatedOffsetY.set(targetOffset);
224
+ }
225
+ runOnJS(setScrollProcessingEnabled)(true);
226
+ didInteractive.set(false);
227
+ isKeyboardOpen.set(event.height > 0);
228
+ if (!horizontal) {
229
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
230
+ const topInset = calculateTopInset(
231
+ safeAreaInsetTop,
232
+ IsNewArchitecture,
233
+ event.height > 0 ? vTopInset : 0
234
+ );
235
+ keyboardInset.set({
236
+ bottom: newInset,
237
+ // Preserve end-aligned padding only while the keyboard is visible.
238
+ top: topInset
239
+ });
240
+ if (newInset <= 0) {
241
+ animatedOffsetY.set(scrollOffsetY.get());
242
+ }
243
+ }
55
244
  }
56
245
  }
57
246
  },
58
247
  [scrollViewRef, safeAreaInsetBottom]
59
248
  );
60
- const animatedProps = Platform.OS === "ios" ? useAnimatedProps(() => {
249
+ const animatedProps = useAnimatedProps(() => {
61
250
  "worklet";
62
251
  var _a, _b, _c, _d;
63
- return {
252
+ const vAnimatedOffsetY = animatedOffsetY.get();
253
+ const baseProps = {
254
+ contentOffset: vAnimatedOffsetY === null ? void 0 : {
255
+ x: 0,
256
+ y: vAnimatedOffsetY
257
+ }
258
+ };
259
+ const { top: keyboardInsetTop, bottom: keyboardInsetBottom } = keyboardInset.get();
260
+ return isIos ? Object.assign(baseProps, {
64
261
  contentInset: {
65
- bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInset.value),
262
+ bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInsetBottom),
66
263
  left: (_b = contentInsetProp == null ? void 0 : contentInsetProp.left) != null ? _b : 0,
67
264
  right: (_c = contentInsetProp == null ? void 0 : contentInsetProp.right) != null ? _c : 0,
68
- top: (_d = contentInsetProp == null ? void 0 : contentInsetProp.top) != null ? _d : 0
265
+ top: ((_d = contentInsetProp == null ? void 0 : contentInsetProp.top) != null ? _d : 0) - keyboardInsetTop
69
266
  }
70
- };
71
- }) : void 0;
72
- const style = Platform.OS !== "ios" ? useAnimatedStyle(() => ({
73
- marginBottom: keyboardInset.value
74
- })) : void 0;
267
+ }) : baseProps;
268
+ });
269
+ const style = isAndroid ? useAnimatedStyle(
270
+ () => {
271
+ var _a;
272
+ return {
273
+ ...styleFlattened || {},
274
+ marginBottom: (_a = keyboardInset.get().bottom) != null ? _a : 0
275
+ };
276
+ },
277
+ [styleProp, keyboardInset]
278
+ ) : void 0;
75
279
  return /* @__PURE__ */ React.createElement(
76
280
  AnimatedLegendList,
77
281
  {
78
282
  ...rest,
79
283
  animatedProps,
80
284
  keyboardDismissMode: "interactive",
285
+ onMetricsChange: handleMetricsChange,
81
286
  onScroll: scrollHandler,
82
- ref: forwardedRef,
287
+ ref: combinedRef,
83
288
  refScrollView: scrollViewRef,
84
- scrollEventThrottle: resolvedScrollEventThrottle,
85
289
  scrollIndicatorInsets: { bottom: 0, top: 0 },
86
290
  style
87
291
  }
@@ -0,0 +1,16 @@
1
+ import * as React from 'react';
2
+ import { Insets } from 'react-native';
3
+ import { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes';
4
+ import { LegendListRef } from '@legendapp/list';
5
+ import { AnimatedLegendListProps } from '@legendapp/list/reanimated';
6
+
7
+ declare const KeyboardAvoidingLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "onScroll" | "contentInset"> & {
8
+ onScroll?: (event: ReanimatedScrollEvent) => void;
9
+ contentInset?: Insets | undefined;
10
+ safeAreaInsets?: {
11
+ top: number;
12
+ bottom: number;
13
+ };
14
+ } & React.RefAttributes<LegendListRef>) => React.ReactNode;
15
+
16
+ export { KeyboardAvoidingLegendList, KeyboardAvoidingLegendList as LegendList };
@@ -0,0 +1,16 @@
1
+ import * as React from 'react';
2
+ import { Insets } from 'react-native';
3
+ import { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes';
4
+ import { LegendListRef } from '@legendapp/list';
5
+ import { AnimatedLegendListProps } from '@legendapp/list/reanimated';
6
+
7
+ declare const KeyboardAvoidingLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "onScroll" | "contentInset"> & {
8
+ onScroll?: (event: ReanimatedScrollEvent) => void;
9
+ contentInset?: Insets | undefined;
10
+ safeAreaInsets?: {
11
+ top: number;
12
+ bottom: number;
13
+ };
14
+ } & React.RefAttributes<LegendListRef>) => React.ReactNode;
15
+
16
+ export { KeyboardAvoidingLegendList, KeyboardAvoidingLegendList as LegendList };
@@ -0,0 +1,318 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var reactNative = require('react-native');
5
+ var reactNativeKeyboardController = require('react-native-keyboard-controller');
6
+ var reactNativeReanimated = require('react-native-reanimated');
7
+ var reanimated = require('@legendapp/list/reanimated');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
+
29
+ // src/integrations/keyboard.tsx
30
+
31
+ // src/constants-platform.native.ts
32
+ var f = global.nativeFabricUIManager;
33
+ var IsNewArchitecture = f !== void 0 && f != null;
34
+
35
+ // src/utils/helpers.ts
36
+ function isFunction(obj) {
37
+ return typeof obj === "function";
38
+ }
39
+
40
+ // src/hooks/useCombinedRef.ts
41
+ var useCombinedRef = (...refs) => {
42
+ const callback = React.useCallback((element) => {
43
+ for (const ref of refs) {
44
+ if (!ref) {
45
+ continue;
46
+ }
47
+ if (isFunction(ref)) {
48
+ ref(element);
49
+ } else {
50
+ ref.current = element;
51
+ }
52
+ }
53
+ }, refs);
54
+ return callback;
55
+ };
56
+
57
+ // src/integrations/keyboard.tsx
58
+ var clampProgress = (progress) => {
59
+ "worklet";
60
+ return Math.min(1, Math.max(0, progress));
61
+ };
62
+ var calculateKeyboardInset = (height, safeAreaInsetBottom, isNewArchitecture) => {
63
+ "worklet";
64
+ return isNewArchitecture ? Math.max(0, height - safeAreaInsetBottom) : Math.max(isNewArchitecture ? 0 : -safeAreaInsetBottom, height - safeAreaInsetBottom * 2);
65
+ };
66
+ var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
67
+ "worklet";
68
+ return Math.min(keyboardHeight, alignItemsAtEndPadding);
69
+ };
70
+ var calculateTopInset = (safeAreaInsetTop, isNewArchitecture, extraTopInset) => {
71
+ "worklet";
72
+ return (isNewArchitecture ? 0 : safeAreaInsetTop * 2) + extraTopInset;
73
+ };
74
+ var calculateKeyboardTargetOffset = (startOffset, keyboardHeight, isOpening, progress) => {
75
+ "worklet";
76
+ const normalizedProgress = isOpening ? progress : 1 - progress;
77
+ const delta = (isOpening ? keyboardHeight : -keyboardHeight) * normalizedProgress;
78
+ return Math.max(0, startOffset + delta);
79
+ };
80
+ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
81
+ const {
82
+ contentInset: contentInsetProp,
83
+ horizontal,
84
+ onMetricsChange: onMetricsChangeProp,
85
+ onScroll: onScrollProp,
86
+ safeAreaInsets = { bottom: 0, top: 0 },
87
+ style: styleProp,
88
+ ...rest
89
+ } = props;
90
+ const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
91
+ const refLegendList = React.useRef(null);
92
+ const combinedRef = useCombinedRef(forwardedRef, refLegendList);
93
+ const isIos = reactNative.Platform.OS === "ios";
94
+ const isAndroid = reactNative.Platform.OS === "android";
95
+ const scrollViewRef = reactNativeReanimated.useAnimatedRef();
96
+ const scrollOffsetY = reactNativeReanimated.useSharedValue(0);
97
+ const animatedOffsetY = reactNativeReanimated.useSharedValue(null);
98
+ const scrollOffsetAtKeyboardStart = reactNativeReanimated.useSharedValue(0);
99
+ const mode = reactNativeReanimated.useSharedValue("idle");
100
+ const keyboardInset = reactNativeReanimated.useSharedValue({ bottom: 0, top: 0 });
101
+ const keyboardHeight = reactNativeReanimated.useSharedValue(0);
102
+ const alignItemsAtEndPadding = reactNativeReanimated.useSharedValue(0);
103
+ const isOpening = reactNativeReanimated.useSharedValue(false);
104
+ const didInteractive = reactNativeReanimated.useSharedValue(false);
105
+ const { top: safeAreaInsetTop, bottom: safeAreaInsetBottom } = safeAreaInsets;
106
+ const isKeyboardOpen = reactNativeReanimated.useSharedValue(false);
107
+ const scrollHandler = reactNativeReanimated.useAnimatedScrollHandler(
108
+ (event) => {
109
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
110
+ if (onScrollProp) {
111
+ reactNativeReanimated.runOnJS(onScrollProp)(event);
112
+ }
113
+ },
114
+ [onScrollProp, horizontal]
115
+ );
116
+ const setScrollProcessingEnabled = React.useCallback(
117
+ (enabled) => {
118
+ var _a;
119
+ return (_a = refLegendList.current) == null ? void 0 : _a.setScrollProcessingEnabled(enabled);
120
+ },
121
+ [refLegendList]
122
+ );
123
+ const handleMetricsChange = React.useCallback(
124
+ (metrics) => {
125
+ const nextPadding = metrics.alignItemsAtEndPadding || 0;
126
+ alignItemsAtEndPadding.set(nextPadding);
127
+ if (!horizontal) {
128
+ reactNativeReanimated.runOnUI((padding, safeInsetTop, isNewArchitecture) => {
129
+ "worklet";
130
+ if (!isKeyboardOpen.get()) {
131
+ return;
132
+ }
133
+ const vKeyboardHeight = keyboardHeight.get();
134
+ const vTopInset = calculateEndPaddingInset(vKeyboardHeight, padding);
135
+ const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
136
+ keyboardInset.set({
137
+ bottom: keyboardInset.get().bottom,
138
+ top: topInset
139
+ });
140
+ })(nextPadding, safeAreaInsetTop, IsNewArchitecture);
141
+ }
142
+ onMetricsChangeProp == null ? void 0 : onMetricsChangeProp(metrics);
143
+ },
144
+ [
145
+ alignItemsAtEndPadding,
146
+ horizontal,
147
+ isKeyboardOpen,
148
+ keyboardHeight,
149
+ keyboardInset,
150
+ onMetricsChangeProp,
151
+ safeAreaInsetTop
152
+ ]
153
+ );
154
+ reactNativeKeyboardController.useKeyboardHandler(
155
+ // biome-ignore assist/source/useSortedKeys: prefer start/move/end
156
+ {
157
+ onStart: (event) => {
158
+ "worklet";
159
+ mode.set("running");
160
+ const progress = clampProgress(event.progress);
161
+ if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
162
+ return;
163
+ }
164
+ if (!didInteractive.get()) {
165
+ if (event.height > 0) {
166
+ keyboardHeight.set(event.height - safeAreaInsetBottom);
167
+ }
168
+ isOpening.set(progress > 0);
169
+ scrollOffsetAtKeyboardStart.set(scrollOffsetY.get());
170
+ animatedOffsetY.set(scrollOffsetY.get());
171
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
172
+ }
173
+ },
174
+ onInteractive: (event) => {
175
+ "worklet";
176
+ if (mode.get() !== "running") {
177
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
178
+ }
179
+ mode.set("running");
180
+ if (!didInteractive.get()) {
181
+ if (!isAndroid && !IsNewArchitecture) {
182
+ keyboardInset.set({
183
+ bottom: keyboardInset.get().bottom,
184
+ // Legacy iOS uses a doubled top inset to keep content below the status bar.
185
+ top: calculateTopInset(safeAreaInsetTop, IsNewArchitecture, 0)
186
+ });
187
+ }
188
+ didInteractive.set(true);
189
+ }
190
+ if (isAndroid && !horizontal) {
191
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
192
+ keyboardInset.set({ bottom: newInset, top: safeAreaInsetTop * 2 });
193
+ }
194
+ },
195
+ onMove: (event) => {
196
+ "worklet";
197
+ if (!didInteractive.get()) {
198
+ const progress = clampProgress(event.progress);
199
+ const vIsOpening = isOpening.get();
200
+ const vKeyboardHeight = keyboardHeight.get();
201
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
202
+ const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
203
+ const targetOffset = calculateKeyboardTargetOffset(
204
+ scrollOffsetAtKeyboardStart.get(),
205
+ vKeyboardHeight,
206
+ vIsOpening,
207
+ progress
208
+ );
209
+ scrollOffsetY.set(targetOffset);
210
+ animatedOffsetY.set(targetOffset);
211
+ if (!horizontal) {
212
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
213
+ const topInset = calculateTopInset(
214
+ safeAreaInsetTop,
215
+ IsNewArchitecture,
216
+ vIsOpening ? vTopInset : 0
217
+ );
218
+ keyboardInset.set({
219
+ bottom: newInset,
220
+ // Add top padding only while opening to keep end-aligned items visible.
221
+ top: topInset
222
+ });
223
+ }
224
+ }
225
+ },
226
+ onEnd: (event) => {
227
+ "worklet";
228
+ const wasInteractive = didInteractive.get();
229
+ const vMode = mode.get();
230
+ mode.set("idle");
231
+ if (vMode === "running") {
232
+ const progress = clampProgress(event.progress);
233
+ const vKeyboardHeight = keyboardHeight.get();
234
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
235
+ const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
236
+ const vIsOpening = isOpening.get();
237
+ if (!wasInteractive) {
238
+ const targetOffset = calculateKeyboardTargetOffset(
239
+ scrollOffsetAtKeyboardStart.get(),
240
+ vKeyboardHeight,
241
+ vIsOpening,
242
+ progress
243
+ );
244
+ scrollOffsetY.set(targetOffset);
245
+ animatedOffsetY.set(targetOffset);
246
+ }
247
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(true);
248
+ didInteractive.set(false);
249
+ isKeyboardOpen.set(event.height > 0);
250
+ if (!horizontal) {
251
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
252
+ const topInset = calculateTopInset(
253
+ safeAreaInsetTop,
254
+ IsNewArchitecture,
255
+ event.height > 0 ? vTopInset : 0
256
+ );
257
+ keyboardInset.set({
258
+ bottom: newInset,
259
+ // Preserve end-aligned padding only while the keyboard is visible.
260
+ top: topInset
261
+ });
262
+ if (newInset <= 0) {
263
+ animatedOffsetY.set(scrollOffsetY.get());
264
+ }
265
+ }
266
+ }
267
+ }
268
+ },
269
+ [scrollViewRef, safeAreaInsetBottom]
270
+ );
271
+ const animatedProps = reactNativeReanimated.useAnimatedProps(() => {
272
+ "worklet";
273
+ var _a, _b, _c, _d;
274
+ const vAnimatedOffsetY = animatedOffsetY.get();
275
+ const baseProps = {
276
+ contentOffset: vAnimatedOffsetY === null ? void 0 : {
277
+ x: 0,
278
+ y: vAnimatedOffsetY
279
+ }
280
+ };
281
+ const { top: keyboardInsetTop, bottom: keyboardInsetBottom } = keyboardInset.get();
282
+ return isIos ? Object.assign(baseProps, {
283
+ contentInset: {
284
+ bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInsetBottom),
285
+ left: (_b = contentInsetProp == null ? void 0 : contentInsetProp.left) != null ? _b : 0,
286
+ right: (_c = contentInsetProp == null ? void 0 : contentInsetProp.right) != null ? _c : 0,
287
+ top: ((_d = contentInsetProp == null ? void 0 : contentInsetProp.top) != null ? _d : 0) - keyboardInsetTop
288
+ }
289
+ }) : baseProps;
290
+ });
291
+ const style = isAndroid ? reactNativeReanimated.useAnimatedStyle(
292
+ () => {
293
+ var _a;
294
+ return {
295
+ ...styleFlattened || {},
296
+ marginBottom: (_a = keyboardInset.get().bottom) != null ? _a : 0
297
+ };
298
+ },
299
+ [styleProp, keyboardInset]
300
+ ) : void 0;
301
+ return /* @__PURE__ */ React__namespace.createElement(
302
+ reanimated.AnimatedLegendList,
303
+ {
304
+ ...rest,
305
+ animatedProps,
306
+ keyboardDismissMode: "interactive",
307
+ onMetricsChange: handleMetricsChange,
308
+ onScroll: scrollHandler,
309
+ ref: combinedRef,
310
+ refScrollView: scrollViewRef,
311
+ scrollIndicatorInsets: { bottom: 0, top: 0 },
312
+ style
313
+ }
314
+ );
315
+ });
316
+
317
+ exports.KeyboardAvoidingLegendList = KeyboardAvoidingLegendList;
318
+ exports.LegendList = KeyboardAvoidingLegendList;