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

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.
@@ -0,0 +1,361 @@
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 calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
67
+ "worklet";
68
+ if (alignItemsAtEnd) {
69
+ return keyboardHeight;
70
+ } else {
71
+ const availableSpace = Math.max(0, scrollLength - contentLength);
72
+ return Math.max(0, keyboardHeight - availableSpace);
73
+ }
74
+ };
75
+ var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
76
+ "worklet";
77
+ return Math.min(keyboardHeight, alignItemsAtEndPadding);
78
+ };
79
+ var calculateTopInset = (safeAreaInsetTop, isNewArchitecture, extraTopInset) => {
80
+ "worklet";
81
+ return (isNewArchitecture ? 0 : safeAreaInsetTop * 2) + extraTopInset;
82
+ };
83
+ var calculateKeyboardTargetOffset = (startOffset, keyboardHeight, isOpening, progress) => {
84
+ "worklet";
85
+ const normalizedProgress = isOpening ? progress : 1 - progress;
86
+ const delta = (isOpening ? keyboardHeight : -keyboardHeight) * normalizedProgress;
87
+ return Math.max(0, startOffset + delta);
88
+ };
89
+ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
90
+ const {
91
+ contentInset: contentInsetProp,
92
+ horizontal,
93
+ onMetricsChange: onMetricsChangeProp,
94
+ onScroll: onScrollProp,
95
+ safeAreaInsets = { bottom: 0, top: 0 },
96
+ style: styleProp,
97
+ ...rest
98
+ } = props;
99
+ const { alignItemsAtEnd } = props;
100
+ const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
101
+ const refLegendList = React.useRef(null);
102
+ const combinedRef = useCombinedRef(forwardedRef, refLegendList);
103
+ const isIos = reactNative.Platform.OS === "ios";
104
+ const isAndroid = reactNative.Platform.OS === "android";
105
+ const scrollViewRef = reactNativeReanimated.useAnimatedRef();
106
+ const scrollOffsetY = reactNativeReanimated.useSharedValue(0);
107
+ const animatedOffsetY = reactNativeReanimated.useSharedValue(null);
108
+ const scrollOffsetAtKeyboardStart = reactNativeReanimated.useSharedValue(0);
109
+ const mode = reactNativeReanimated.useSharedValue("idle");
110
+ const keyboardInset = reactNativeReanimated.useSharedValue({ bottom: 0, top: 0 });
111
+ const keyboardHeight = reactNativeReanimated.useSharedValue(0);
112
+ const contentLength = reactNativeReanimated.useSharedValue(0);
113
+ const scrollLength = reactNativeReanimated.useSharedValue(0);
114
+ const alignItemsAtEndPadding = reactNativeReanimated.useSharedValue(0);
115
+ const isOpening = reactNativeReanimated.useSharedValue(false);
116
+ const didInteractive = reactNativeReanimated.useSharedValue(false);
117
+ const { top: safeAreaInsetTop, bottom: safeAreaInsetBottom } = safeAreaInsets;
118
+ const isKeyboardOpen = reactNativeReanimated.useSharedValue(false);
119
+ const scrollHandler = reactNativeReanimated.useAnimatedScrollHandler(
120
+ (event) => {
121
+ if (mode.get() !== "running" || didInteractive.get()) {
122
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
123
+ }
124
+ if (onScrollProp) {
125
+ reactNativeReanimated.runOnJS(onScrollProp)(event);
126
+ }
127
+ },
128
+ [onScrollProp, horizontal]
129
+ );
130
+ const setScrollProcessingEnabled = React.useCallback(
131
+ (enabled) => {
132
+ var _a;
133
+ return (_a = refLegendList.current) == null ? void 0 : _a.setScrollProcessingEnabled(enabled);
134
+ },
135
+ [refLegendList]
136
+ );
137
+ const updateScrollMetrics = React.useCallback(() => {
138
+ var _a;
139
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
140
+ if (!state) {
141
+ return;
142
+ }
143
+ contentLength.set(state.contentLength);
144
+ scrollLength.set(state.scrollLength);
145
+ }, [contentLength, scrollLength]);
146
+ const handleMetricsChange = React.useCallback(
147
+ (metrics) => {
148
+ updateScrollMetrics();
149
+ const nextPadding = metrics.alignItemsAtEndPadding || 0;
150
+ alignItemsAtEndPadding.set(nextPadding);
151
+ if (!horizontal) {
152
+ reactNativeReanimated.runOnUI((padding, safeInsetTop, isNewArchitecture) => {
153
+ "worklet";
154
+ if (!isKeyboardOpen.get()) {
155
+ return;
156
+ }
157
+ const vKeyboardHeight = keyboardHeight.get();
158
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
159
+ vKeyboardHeight,
160
+ contentLength.get(),
161
+ scrollLength.get(),
162
+ alignItemsAtEnd
163
+ );
164
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, padding);
165
+ const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
166
+ keyboardInset.set({
167
+ bottom: keyboardInset.get().bottom,
168
+ top: topInset
169
+ });
170
+ })(nextPadding, safeAreaInsetTop, IsNewArchitecture);
171
+ }
172
+ onMetricsChangeProp == null ? void 0 : onMetricsChangeProp(metrics);
173
+ },
174
+ [
175
+ alignItemsAtEndPadding,
176
+ horizontal,
177
+ isKeyboardOpen,
178
+ keyboardHeight,
179
+ keyboardInset,
180
+ onMetricsChangeProp,
181
+ safeAreaInsetTop,
182
+ updateScrollMetrics
183
+ ]
184
+ );
185
+ reactNativeKeyboardController.useKeyboardHandler(
186
+ // biome-ignore assist/source/useSortedKeys: prefer start/move/end
187
+ {
188
+ onStart: (event) => {
189
+ "worklet";
190
+ mode.set("running");
191
+ const progress = clampProgress(event.progress);
192
+ if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
193
+ return;
194
+ }
195
+ if (!didInteractive.get()) {
196
+ if (event.height > 0) {
197
+ keyboardHeight.set(event.height - safeAreaInsetBottom);
198
+ }
199
+ isOpening.set(progress > 0);
200
+ scrollOffsetAtKeyboardStart.set(scrollOffsetY.get());
201
+ animatedOffsetY.set(scrollOffsetY.get());
202
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
203
+ }
204
+ },
205
+ onInteractive: (event) => {
206
+ "worklet";
207
+ if (mode.get() !== "running") {
208
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
209
+ }
210
+ mode.set("running");
211
+ if (!didInteractive.get()) {
212
+ if (!isAndroid && !IsNewArchitecture) {
213
+ keyboardInset.set({
214
+ bottom: keyboardInset.get().bottom,
215
+ // Legacy iOS uses a doubled top inset to keep content below the status bar.
216
+ top: calculateTopInset(safeAreaInsetTop, IsNewArchitecture, 0)
217
+ });
218
+ }
219
+ didInteractive.set(true);
220
+ }
221
+ if (isAndroid && !horizontal) {
222
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
223
+ keyboardInset.set({ bottom: newInset, top: safeAreaInsetTop * 2 });
224
+ }
225
+ },
226
+ onMove: (event) => {
227
+ "worklet";
228
+ if (!didInteractive.get()) {
229
+ const progress = clampProgress(event.progress);
230
+ const vIsOpening = isOpening.get();
231
+ const vKeyboardHeight = keyboardHeight.get();
232
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
233
+ vKeyboardHeight,
234
+ contentLength.get(),
235
+ scrollLength.get(),
236
+ alignItemsAtEnd
237
+ );
238
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
239
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
240
+ const targetOffset = calculateKeyboardTargetOffset(
241
+ scrollOffsetAtKeyboardStart.get(),
242
+ vEffectiveKeyboardHeight,
243
+ vIsOpening,
244
+ progress
245
+ );
246
+ scrollOffsetY.set(targetOffset);
247
+ animatedOffsetY.set(targetOffset);
248
+ if (!horizontal) {
249
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
250
+ const topInset = calculateTopInset(
251
+ safeAreaInsetTop,
252
+ IsNewArchitecture,
253
+ vIsOpening ? vTopInset : 0
254
+ );
255
+ keyboardInset.set({
256
+ bottom: newInset,
257
+ // Add top padding only while opening to keep end-aligned items visible.
258
+ top: topInset
259
+ });
260
+ }
261
+ }
262
+ },
263
+ onEnd: (event) => {
264
+ "worklet";
265
+ const wasInteractive = didInteractive.get();
266
+ const vMode = mode.get();
267
+ mode.set("idle");
268
+ if (vMode === "running") {
269
+ const progress = clampProgress(event.progress);
270
+ const vKeyboardHeight = keyboardHeight.get();
271
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
272
+ vKeyboardHeight,
273
+ contentLength.get(),
274
+ scrollLength.get(),
275
+ alignItemsAtEnd
276
+ );
277
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
278
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
279
+ const vIsOpening = isOpening.get();
280
+ if (!wasInteractive) {
281
+ const targetOffset = calculateKeyboardTargetOffset(
282
+ scrollOffsetAtKeyboardStart.get(),
283
+ vEffectiveKeyboardHeight,
284
+ vIsOpening,
285
+ progress
286
+ );
287
+ scrollOffsetY.set(targetOffset);
288
+ animatedOffsetY.set(targetOffset);
289
+ }
290
+ reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(true);
291
+ didInteractive.set(false);
292
+ isKeyboardOpen.set(event.height > 0);
293
+ if (!horizontal) {
294
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
295
+ const topInset = calculateTopInset(
296
+ safeAreaInsetTop,
297
+ IsNewArchitecture,
298
+ event.height > 0 ? vTopInset : 0
299
+ );
300
+ keyboardInset.set({
301
+ bottom: newInset,
302
+ // Preserve end-aligned padding only while the keyboard is visible.
303
+ top: topInset
304
+ });
305
+ if (newInset <= 0) {
306
+ animatedOffsetY.set(scrollOffsetY.get());
307
+ }
308
+ }
309
+ }
310
+ }
311
+ },
312
+ [alignItemsAtEnd, safeAreaInsetBottom, scrollViewRef]
313
+ );
314
+ const animatedProps = reactNativeReanimated.useAnimatedProps(() => {
315
+ "worklet";
316
+ var _a, _b, _c, _d;
317
+ const vAnimatedOffsetY = animatedOffsetY.get();
318
+ const baseProps = {
319
+ contentOffset: vAnimatedOffsetY === null ? void 0 : {
320
+ x: 0,
321
+ y: vAnimatedOffsetY
322
+ }
323
+ };
324
+ const { top: keyboardInsetTop, bottom: keyboardInsetBottom } = keyboardInset.get();
325
+ return isIos ? Object.assign(baseProps, {
326
+ contentInset: {
327
+ bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInsetBottom),
328
+ left: (_b = contentInsetProp == null ? void 0 : contentInsetProp.left) != null ? _b : 0,
329
+ right: (_c = contentInsetProp == null ? void 0 : contentInsetProp.right) != null ? _c : 0,
330
+ top: ((_d = contentInsetProp == null ? void 0 : contentInsetProp.top) != null ? _d : 0) - keyboardInsetTop
331
+ }
332
+ }) : baseProps;
333
+ });
334
+ const style = isAndroid ? reactNativeReanimated.useAnimatedStyle(
335
+ () => {
336
+ var _a;
337
+ return {
338
+ ...styleFlattened || {},
339
+ marginBottom: (_a = keyboardInset.get().bottom) != null ? _a : 0
340
+ };
341
+ },
342
+ [styleProp, keyboardInset]
343
+ ) : void 0;
344
+ return /* @__PURE__ */ React__namespace.createElement(
345
+ reanimated.AnimatedLegendList,
346
+ {
347
+ ...rest,
348
+ animatedProps,
349
+ keyboardDismissMode: "interactive",
350
+ onMetricsChange: handleMetricsChange,
351
+ onScroll: scrollHandler,
352
+ ref: combinedRef,
353
+ refScrollView: scrollViewRef,
354
+ scrollIndicatorInsets: { bottom: 0, top: 0 },
355
+ style
356
+ }
357
+ );
358
+ });
359
+
360
+ exports.KeyboardAvoidingLegendList = KeyboardAvoidingLegendList;
361
+ exports.LegendList = KeyboardAvoidingLegendList;
@@ -0,0 +1,339 @@
1
+ import * as React from 'react';
2
+ import { forwardRef, useRef, useCallback } from 'react';
3
+ import { StyleSheet, Platform } from 'react-native';
4
+ import { useKeyboardHandler } from 'react-native-keyboard-controller';
5
+ import { useAnimatedRef, useSharedValue, useAnimatedScrollHandler, runOnJS, runOnUI, useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated';
6
+ import { AnimatedLegendList } from '@legendapp/list/reanimated';
7
+
8
+ // src/integrations/keyboard.tsx
9
+
10
+ // src/constants-platform.native.ts
11
+ var f = global.nativeFabricUIManager;
12
+ var IsNewArchitecture = f !== void 0 && f != null;
13
+
14
+ // src/utils/helpers.ts
15
+ function isFunction(obj) {
16
+ return typeof obj === "function";
17
+ }
18
+
19
+ // src/hooks/useCombinedRef.ts
20
+ var useCombinedRef = (...refs) => {
21
+ const callback = useCallback((element) => {
22
+ for (const ref of refs) {
23
+ if (!ref) {
24
+ continue;
25
+ }
26
+ if (isFunction(ref)) {
27
+ ref(element);
28
+ } else {
29
+ ref.current = element;
30
+ }
31
+ }
32
+ }, refs);
33
+ return callback;
34
+ };
35
+
36
+ // src/integrations/keyboard.tsx
37
+ var clampProgress = (progress) => {
38
+ "worklet";
39
+ return Math.min(1, Math.max(0, progress));
40
+ };
41
+ var calculateKeyboardInset = (height, safeAreaInsetBottom, isNewArchitecture) => {
42
+ "worklet";
43
+ return isNewArchitecture ? Math.max(0, height - safeAreaInsetBottom) : Math.max(isNewArchitecture ? 0 : -safeAreaInsetBottom, height - safeAreaInsetBottom * 2);
44
+ };
45
+ var calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
46
+ "worklet";
47
+ if (alignItemsAtEnd) {
48
+ return keyboardHeight;
49
+ } else {
50
+ const availableSpace = Math.max(0, scrollLength - contentLength);
51
+ return Math.max(0, keyboardHeight - availableSpace);
52
+ }
53
+ };
54
+ var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
55
+ "worklet";
56
+ return Math.min(keyboardHeight, alignItemsAtEndPadding);
57
+ };
58
+ var calculateTopInset = (safeAreaInsetTop, isNewArchitecture, extraTopInset) => {
59
+ "worklet";
60
+ return (isNewArchitecture ? 0 : safeAreaInsetTop * 2) + extraTopInset;
61
+ };
62
+ var calculateKeyboardTargetOffset = (startOffset, keyboardHeight, isOpening, progress) => {
63
+ "worklet";
64
+ const normalizedProgress = isOpening ? progress : 1 - progress;
65
+ const delta = (isOpening ? keyboardHeight : -keyboardHeight) * normalizedProgress;
66
+ return Math.max(0, startOffset + delta);
67
+ };
68
+ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
69
+ const {
70
+ contentInset: contentInsetProp,
71
+ horizontal,
72
+ onMetricsChange: onMetricsChangeProp,
73
+ onScroll: onScrollProp,
74
+ safeAreaInsets = { bottom: 0, top: 0 },
75
+ style: styleProp,
76
+ ...rest
77
+ } = props;
78
+ const { alignItemsAtEnd } = props;
79
+ const styleFlattened = StyleSheet.flatten(styleProp);
80
+ const refLegendList = useRef(null);
81
+ const combinedRef = useCombinedRef(forwardedRef, refLegendList);
82
+ const isIos = Platform.OS === "ios";
83
+ const isAndroid = Platform.OS === "android";
84
+ const scrollViewRef = useAnimatedRef();
85
+ const scrollOffsetY = useSharedValue(0);
86
+ const animatedOffsetY = useSharedValue(null);
87
+ const scrollOffsetAtKeyboardStart = useSharedValue(0);
88
+ const mode = useSharedValue("idle");
89
+ const keyboardInset = useSharedValue({ bottom: 0, top: 0 });
90
+ const keyboardHeight = useSharedValue(0);
91
+ const contentLength = useSharedValue(0);
92
+ const scrollLength = useSharedValue(0);
93
+ const alignItemsAtEndPadding = useSharedValue(0);
94
+ const isOpening = useSharedValue(false);
95
+ const didInteractive = useSharedValue(false);
96
+ const { top: safeAreaInsetTop, bottom: safeAreaInsetBottom } = safeAreaInsets;
97
+ const isKeyboardOpen = useSharedValue(false);
98
+ const scrollHandler = useAnimatedScrollHandler(
99
+ (event) => {
100
+ if (mode.get() !== "running" || didInteractive.get()) {
101
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
102
+ }
103
+ if (onScrollProp) {
104
+ runOnJS(onScrollProp)(event);
105
+ }
106
+ },
107
+ [onScrollProp, horizontal]
108
+ );
109
+ const setScrollProcessingEnabled = useCallback(
110
+ (enabled) => {
111
+ var _a;
112
+ return (_a = refLegendList.current) == null ? void 0 : _a.setScrollProcessingEnabled(enabled);
113
+ },
114
+ [refLegendList]
115
+ );
116
+ const updateScrollMetrics = useCallback(() => {
117
+ var _a;
118
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
119
+ if (!state) {
120
+ return;
121
+ }
122
+ contentLength.set(state.contentLength);
123
+ scrollLength.set(state.scrollLength);
124
+ }, [contentLength, scrollLength]);
125
+ const handleMetricsChange = useCallback(
126
+ (metrics) => {
127
+ updateScrollMetrics();
128
+ const nextPadding = metrics.alignItemsAtEndPadding || 0;
129
+ alignItemsAtEndPadding.set(nextPadding);
130
+ if (!horizontal) {
131
+ runOnUI((padding, safeInsetTop, isNewArchitecture) => {
132
+ "worklet";
133
+ if (!isKeyboardOpen.get()) {
134
+ return;
135
+ }
136
+ const vKeyboardHeight = keyboardHeight.get();
137
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
138
+ vKeyboardHeight,
139
+ contentLength.get(),
140
+ scrollLength.get(),
141
+ alignItemsAtEnd
142
+ );
143
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, padding);
144
+ const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
145
+ keyboardInset.set({
146
+ bottom: keyboardInset.get().bottom,
147
+ top: topInset
148
+ });
149
+ })(nextPadding, safeAreaInsetTop, IsNewArchitecture);
150
+ }
151
+ onMetricsChangeProp == null ? void 0 : onMetricsChangeProp(metrics);
152
+ },
153
+ [
154
+ alignItemsAtEndPadding,
155
+ horizontal,
156
+ isKeyboardOpen,
157
+ keyboardHeight,
158
+ keyboardInset,
159
+ onMetricsChangeProp,
160
+ safeAreaInsetTop,
161
+ updateScrollMetrics
162
+ ]
163
+ );
164
+ useKeyboardHandler(
165
+ // biome-ignore assist/source/useSortedKeys: prefer start/move/end
166
+ {
167
+ onStart: (event) => {
168
+ "worklet";
169
+ mode.set("running");
170
+ const progress = clampProgress(event.progress);
171
+ if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
172
+ return;
173
+ }
174
+ if (!didInteractive.get()) {
175
+ if (event.height > 0) {
176
+ keyboardHeight.set(event.height - safeAreaInsetBottom);
177
+ }
178
+ isOpening.set(progress > 0);
179
+ scrollOffsetAtKeyboardStart.set(scrollOffsetY.get());
180
+ animatedOffsetY.set(scrollOffsetY.get());
181
+ runOnJS(setScrollProcessingEnabled)(false);
182
+ }
183
+ },
184
+ onInteractive: (event) => {
185
+ "worklet";
186
+ if (mode.get() !== "running") {
187
+ runOnJS(setScrollProcessingEnabled)(false);
188
+ }
189
+ mode.set("running");
190
+ if (!didInteractive.get()) {
191
+ if (!isAndroid && !IsNewArchitecture) {
192
+ keyboardInset.set({
193
+ bottom: keyboardInset.get().bottom,
194
+ // Legacy iOS uses a doubled top inset to keep content below the status bar.
195
+ top: calculateTopInset(safeAreaInsetTop, IsNewArchitecture, 0)
196
+ });
197
+ }
198
+ didInteractive.set(true);
199
+ }
200
+ if (isAndroid && !horizontal) {
201
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
202
+ keyboardInset.set({ bottom: newInset, top: safeAreaInsetTop * 2 });
203
+ }
204
+ },
205
+ onMove: (event) => {
206
+ "worklet";
207
+ if (!didInteractive.get()) {
208
+ const progress = clampProgress(event.progress);
209
+ const vIsOpening = isOpening.get();
210
+ const vKeyboardHeight = keyboardHeight.get();
211
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
212
+ vKeyboardHeight,
213
+ contentLength.get(),
214
+ scrollLength.get(),
215
+ alignItemsAtEnd
216
+ );
217
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
218
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
219
+ const targetOffset = calculateKeyboardTargetOffset(
220
+ scrollOffsetAtKeyboardStart.get(),
221
+ vEffectiveKeyboardHeight,
222
+ vIsOpening,
223
+ progress
224
+ );
225
+ scrollOffsetY.set(targetOffset);
226
+ animatedOffsetY.set(targetOffset);
227
+ if (!horizontal) {
228
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
229
+ const topInset = calculateTopInset(
230
+ safeAreaInsetTop,
231
+ IsNewArchitecture,
232
+ vIsOpening ? vTopInset : 0
233
+ );
234
+ keyboardInset.set({
235
+ bottom: newInset,
236
+ // Add top padding only while opening to keep end-aligned items visible.
237
+ top: topInset
238
+ });
239
+ }
240
+ }
241
+ },
242
+ onEnd: (event) => {
243
+ "worklet";
244
+ const wasInteractive = didInteractive.get();
245
+ const vMode = mode.get();
246
+ mode.set("idle");
247
+ if (vMode === "running") {
248
+ const progress = clampProgress(event.progress);
249
+ const vKeyboardHeight = keyboardHeight.get();
250
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
251
+ vKeyboardHeight,
252
+ contentLength.get(),
253
+ scrollLength.get(),
254
+ alignItemsAtEnd
255
+ );
256
+ const vAlignItemsPadding = alignItemsAtEndPadding.get();
257
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
258
+ const vIsOpening = isOpening.get();
259
+ if (!wasInteractive) {
260
+ const targetOffset = calculateKeyboardTargetOffset(
261
+ scrollOffsetAtKeyboardStart.get(),
262
+ vEffectiveKeyboardHeight,
263
+ vIsOpening,
264
+ progress
265
+ );
266
+ scrollOffsetY.set(targetOffset);
267
+ animatedOffsetY.set(targetOffset);
268
+ }
269
+ runOnJS(setScrollProcessingEnabled)(true);
270
+ didInteractive.set(false);
271
+ isKeyboardOpen.set(event.height > 0);
272
+ if (!horizontal) {
273
+ const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom, IsNewArchitecture);
274
+ const topInset = calculateTopInset(
275
+ safeAreaInsetTop,
276
+ IsNewArchitecture,
277
+ event.height > 0 ? vTopInset : 0
278
+ );
279
+ keyboardInset.set({
280
+ bottom: newInset,
281
+ // Preserve end-aligned padding only while the keyboard is visible.
282
+ top: topInset
283
+ });
284
+ if (newInset <= 0) {
285
+ animatedOffsetY.set(scrollOffsetY.get());
286
+ }
287
+ }
288
+ }
289
+ }
290
+ },
291
+ [alignItemsAtEnd, safeAreaInsetBottom, scrollViewRef]
292
+ );
293
+ const animatedProps = useAnimatedProps(() => {
294
+ "worklet";
295
+ var _a, _b, _c, _d;
296
+ const vAnimatedOffsetY = animatedOffsetY.get();
297
+ const baseProps = {
298
+ contentOffset: vAnimatedOffsetY === null ? void 0 : {
299
+ x: 0,
300
+ y: vAnimatedOffsetY
301
+ }
302
+ };
303
+ const { top: keyboardInsetTop, bottom: keyboardInsetBottom } = keyboardInset.get();
304
+ return isIos ? Object.assign(baseProps, {
305
+ contentInset: {
306
+ bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInsetBottom),
307
+ left: (_b = contentInsetProp == null ? void 0 : contentInsetProp.left) != null ? _b : 0,
308
+ right: (_c = contentInsetProp == null ? void 0 : contentInsetProp.right) != null ? _c : 0,
309
+ top: ((_d = contentInsetProp == null ? void 0 : contentInsetProp.top) != null ? _d : 0) - keyboardInsetTop
310
+ }
311
+ }) : baseProps;
312
+ });
313
+ const style = isAndroid ? useAnimatedStyle(
314
+ () => {
315
+ var _a;
316
+ return {
317
+ ...styleFlattened || {},
318
+ marginBottom: (_a = keyboardInset.get().bottom) != null ? _a : 0
319
+ };
320
+ },
321
+ [styleProp, keyboardInset]
322
+ ) : void 0;
323
+ return /* @__PURE__ */ React.createElement(
324
+ AnimatedLegendList,
325
+ {
326
+ ...rest,
327
+ animatedProps,
328
+ keyboardDismissMode: "interactive",
329
+ onMetricsChange: handleMetricsChange,
330
+ onScroll: scrollHandler,
331
+ ref: combinedRef,
332
+ refScrollView: scrollViewRef,
333
+ scrollIndicatorInsets: { bottom: 0, top: 0 },
334
+ style
335
+ }
336
+ );
337
+ });
338
+
339
+ export { KeyboardAvoidingLegendList, KeyboardAvoidingLegendList as LegendList };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.0.0-beta.20",
3
+ "version": "3.0.0-beta.22",
4
4
  "description": "Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
5
5
  "sideEffects": false,
6
6
  "private": false,