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