@legendapp/list 3.0.0-beta.20 → 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.
- 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 +24 -1
- package/index.d.ts +24 -1
- package/index.js +162 -17
- package/index.mjs +162 -17
- package/index.native.d.mts +794 -0
- package/index.native.d.ts +794 -0
- package/index.native.js +163 -17
- package/index.native.mjs +163 -17
- 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 +103 -13
- package/keyboard.mjs +104 -14
- package/keyboard.native.d.mts +16 -0
- package/keyboard.native.d.ts +16 -0
- package/keyboard.native.js +318 -0
- package/keyboard.native.mjs +296 -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
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { LegendList as LegendList$1, LegendListProps, LegendListRef } from '@legendapp/list';
|
|
3
|
+
import { AnimatedLegendList } from '@legendapp/list/animated';
|
|
4
|
+
import { AnimatedLegendList as AnimatedLegendList$1 } from '@legendapp/list/reanimated';
|
|
5
|
+
|
|
6
|
+
declare const LegendList: <ItemT, ListT extends typeof LegendList$1 | typeof AnimatedLegendList | typeof AnimatedLegendList$1 = (<T>(props: LegendListProps<T> & React.RefAttributes<LegendListRef>) => React.ReactNode) & {
|
|
7
|
+
displayName?: string;
|
|
8
|
+
}>(props: (LegendListProps<ItemT> & {
|
|
9
|
+
LegendList?: ListT;
|
|
10
|
+
}) & React.RefAttributes<LegendListRef>) => React.ReactNode;
|
|
11
|
+
|
|
12
|
+
export { LegendList };
|
|
@@ -0,0 +1,69 @@
|
|
|
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 list = require('@legendapp/list');
|
|
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-controller.tsx
|
|
30
|
+
var typedForwardRef = React.forwardRef;
|
|
31
|
+
var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
|
|
32
|
+
const {
|
|
33
|
+
LegendList: LegendListProp,
|
|
34
|
+
contentContainerStyle: contentContainerStyleProp,
|
|
35
|
+
scrollIndicatorInsets: scrollIndicatorInsetsProp,
|
|
36
|
+
...rest
|
|
37
|
+
} = props;
|
|
38
|
+
const [padding, setPadding] = React.useState(0);
|
|
39
|
+
const updatePadding = (height) => {
|
|
40
|
+
setPadding(height);
|
|
41
|
+
};
|
|
42
|
+
reactNativeKeyboardController.useKeyboardHandler({
|
|
43
|
+
onEnd: (e) => {
|
|
44
|
+
"worklet";
|
|
45
|
+
reactNativeReanimated.runOnJS(updatePadding)(e.height);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const LegendListComponent = LegendListProp != null ? LegendListProp : list.LegendList;
|
|
49
|
+
const contentContainerStyleFlattened = reactNative.StyleSheet.flatten(contentContainerStyleProp) || {};
|
|
50
|
+
const contentContainerStyle = { ...contentContainerStyleFlattened, paddingTop: padding };
|
|
51
|
+
const scrollIndicatorInsets = scrollIndicatorInsetsProp ? { ...scrollIndicatorInsetsProp } : {};
|
|
52
|
+
if (!props.horizontal) {
|
|
53
|
+
scrollIndicatorInsets.top = ((scrollIndicatorInsets == null ? void 0 : scrollIndicatorInsets.top) || 0) + padding;
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
// @ts-expect-error TODO: Fix this type
|
|
57
|
+
/* @__PURE__ */ React__namespace.createElement(
|
|
58
|
+
LegendListComponent,
|
|
59
|
+
{
|
|
60
|
+
...rest,
|
|
61
|
+
contentContainerStyle,
|
|
62
|
+
ref: forwardedRef,
|
|
63
|
+
scrollIndicatorInsets
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
exports.LegendList = LegendList;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useState, forwardRef } from 'react';
|
|
3
|
+
import { StyleSheet } from 'react-native';
|
|
4
|
+
import { useKeyboardHandler } from 'react-native-keyboard-controller';
|
|
5
|
+
import { runOnJS } from 'react-native-reanimated';
|
|
6
|
+
import { LegendList as LegendList$1 } from '@legendapp/list';
|
|
7
|
+
|
|
8
|
+
// src/integrations/keyboard-controller.tsx
|
|
9
|
+
var typedForwardRef = forwardRef;
|
|
10
|
+
var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
|
|
11
|
+
const {
|
|
12
|
+
LegendList: LegendListProp,
|
|
13
|
+
contentContainerStyle: contentContainerStyleProp,
|
|
14
|
+
scrollIndicatorInsets: scrollIndicatorInsetsProp,
|
|
15
|
+
...rest
|
|
16
|
+
} = props;
|
|
17
|
+
const [padding, setPadding] = useState(0);
|
|
18
|
+
const updatePadding = (height) => {
|
|
19
|
+
setPadding(height);
|
|
20
|
+
};
|
|
21
|
+
useKeyboardHandler({
|
|
22
|
+
onEnd: (e) => {
|
|
23
|
+
"worklet";
|
|
24
|
+
runOnJS(updatePadding)(e.height);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList$1;
|
|
28
|
+
const contentContainerStyleFlattened = StyleSheet.flatten(contentContainerStyleProp) || {};
|
|
29
|
+
const contentContainerStyle = { ...contentContainerStyleFlattened, paddingTop: padding };
|
|
30
|
+
const scrollIndicatorInsets = scrollIndicatorInsetsProp ? { ...scrollIndicatorInsetsProp } : {};
|
|
31
|
+
if (!props.horizontal) {
|
|
32
|
+
scrollIndicatorInsets.top = ((scrollIndicatorInsets == null ? void 0 : scrollIndicatorInsets.top) || 0) + padding;
|
|
33
|
+
}
|
|
34
|
+
return (
|
|
35
|
+
// @ts-expect-error TODO: Fix this type
|
|
36
|
+
/* @__PURE__ */ React.createElement(
|
|
37
|
+
LegendListComponent,
|
|
38
|
+
{
|
|
39
|
+
...rest,
|
|
40
|
+
contentContainerStyle,
|
|
41
|
+
ref: forwardedRef,
|
|
42
|
+
scrollIndicatorInsets
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export { LegendList };
|
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,14 +54,33 @@ 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 calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
|
|
66
|
+
"worklet";
|
|
67
|
+
return Math.min(keyboardHeight, alignItemsAtEndPadding);
|
|
68
|
+
};
|
|
69
|
+
var calculateTopInset = (safeAreaInsetTop, isNewArchitecture, extraTopInset) => {
|
|
70
|
+
"worklet";
|
|
71
|
+
return (isNewArchitecture ? 0 : safeAreaInsetTop * 2) + extraTopInset;
|
|
72
|
+
};
|
|
73
|
+
var calculateKeyboardTargetOffset = (startOffset, keyboardHeight, isOpening, progress) => {
|
|
74
|
+
"worklet";
|
|
75
|
+
const normalizedProgress = isOpening ? progress : 1 - progress;
|
|
76
|
+
const delta = (isOpening ? keyboardHeight : -keyboardHeight) * normalizedProgress;
|
|
77
|
+
return Math.max(0, startOffset + delta);
|
|
78
|
+
};
|
|
58
79
|
var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
|
|
59
80
|
const {
|
|
60
81
|
contentInset: contentInsetProp,
|
|
61
82
|
horizontal,
|
|
83
|
+
onMetricsChange: onMetricsChangeProp,
|
|
62
84
|
onScroll: onScrollProp,
|
|
63
85
|
safeAreaInsets = { bottom: 0, top: 0 },
|
|
64
86
|
style: styleProp,
|
|
@@ -76,6 +98,7 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
|
|
|
76
98
|
const mode = reactNativeReanimated.useSharedValue("idle");
|
|
77
99
|
const keyboardInset = reactNativeReanimated.useSharedValue({ bottom: 0, top: 0 });
|
|
78
100
|
const keyboardHeight = reactNativeReanimated.useSharedValue(0);
|
|
101
|
+
const alignItemsAtEndPadding = reactNativeReanimated.useSharedValue(0);
|
|
79
102
|
const isOpening = reactNativeReanimated.useSharedValue(false);
|
|
80
103
|
const didInteractive = reactNativeReanimated.useSharedValue(false);
|
|
81
104
|
const { top: safeAreaInsetTop, bottom: safeAreaInsetBottom } = safeAreaInsets;
|
|
@@ -96,20 +119,52 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
|
|
|
96
119
|
},
|
|
97
120
|
[refLegendList]
|
|
98
121
|
);
|
|
122
|
+
const handleMetricsChange = React.useCallback(
|
|
123
|
+
(metrics) => {
|
|
124
|
+
const nextPadding = metrics.alignItemsAtEndPadding || 0;
|
|
125
|
+
alignItemsAtEndPadding.set(nextPadding);
|
|
126
|
+
if (!horizontal) {
|
|
127
|
+
reactNativeReanimated.runOnUI((padding, safeInsetTop, isNewArchitecture) => {
|
|
128
|
+
"worklet";
|
|
129
|
+
if (!isKeyboardOpen.get()) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const vKeyboardHeight = keyboardHeight.get();
|
|
133
|
+
const vTopInset = calculateEndPaddingInset(vKeyboardHeight, padding);
|
|
134
|
+
const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
|
|
135
|
+
keyboardInset.set({
|
|
136
|
+
bottom: keyboardInset.get().bottom,
|
|
137
|
+
top: topInset
|
|
138
|
+
});
|
|
139
|
+
})(nextPadding, safeAreaInsetTop, IsNewArchitecture);
|
|
140
|
+
}
|
|
141
|
+
onMetricsChangeProp == null ? void 0 : onMetricsChangeProp(metrics);
|
|
142
|
+
},
|
|
143
|
+
[
|
|
144
|
+
alignItemsAtEndPadding,
|
|
145
|
+
horizontal,
|
|
146
|
+
isKeyboardOpen,
|
|
147
|
+
keyboardHeight,
|
|
148
|
+
keyboardInset,
|
|
149
|
+
onMetricsChangeProp,
|
|
150
|
+
safeAreaInsetTop
|
|
151
|
+
]
|
|
152
|
+
);
|
|
99
153
|
reactNativeKeyboardController.useKeyboardHandler(
|
|
100
154
|
// biome-ignore assist/source/useSortedKeys: prefer start/move/end
|
|
101
155
|
{
|
|
102
156
|
onStart: (event) => {
|
|
103
157
|
"worklet";
|
|
104
158
|
mode.set("running");
|
|
105
|
-
|
|
159
|
+
const progress = clampProgress(event.progress);
|
|
160
|
+
if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
|
|
106
161
|
return;
|
|
107
162
|
}
|
|
108
163
|
if (!didInteractive.get()) {
|
|
109
164
|
if (event.height > 0) {
|
|
110
165
|
keyboardHeight.set(event.height - safeAreaInsetBottom);
|
|
111
166
|
}
|
|
112
|
-
isOpening.set(
|
|
167
|
+
isOpening.set(progress > 0);
|
|
113
168
|
scrollOffsetAtKeyboardStart.set(scrollOffsetY.get());
|
|
114
169
|
animatedOffsetY.set(scrollOffsetY.get());
|
|
115
170
|
reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
|
|
@@ -122,6 +177,13 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
|
|
|
122
177
|
}
|
|
123
178
|
mode.set("running");
|
|
124
179
|
if (!didInteractive.get()) {
|
|
180
|
+
if (!isAndroid && !IsNewArchitecture) {
|
|
181
|
+
keyboardInset.set({
|
|
182
|
+
bottom: keyboardInset.get().bottom,
|
|
183
|
+
// Legacy iOS uses a doubled top inset to keep content below the status bar.
|
|
184
|
+
top: calculateTopInset(safeAreaInsetTop, IsNewArchitecture, 0)
|
|
185
|
+
});
|
|
186
|
+
}
|
|
125
187
|
didInteractive.set(true);
|
|
126
188
|
}
|
|
127
189
|
if (isAndroid && !horizontal) {
|
|
@@ -132,18 +194,31 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
|
|
|
132
194
|
onMove: (event) => {
|
|
133
195
|
"worklet";
|
|
134
196
|
if (!didInteractive.get()) {
|
|
197
|
+
const progress = clampProgress(event.progress);
|
|
135
198
|
const vIsOpening = isOpening.get();
|
|
136
199
|
const vKeyboardHeight = keyboardHeight.get();
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
scrollOffsetAtKeyboardStart.get()
|
|
200
|
+
const vAlignItemsPadding = alignItemsAtEndPadding.get();
|
|
201
|
+
const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
|
|
202
|
+
const targetOffset = calculateKeyboardTargetOffset(
|
|
203
|
+
scrollOffsetAtKeyboardStart.get(),
|
|
204
|
+
vKeyboardHeight,
|
|
205
|
+
vIsOpening,
|
|
206
|
+
progress
|
|
141
207
|
);
|
|
142
208
|
scrollOffsetY.set(targetOffset);
|
|
143
209
|
animatedOffsetY.set(targetOffset);
|
|
144
210
|
if (!horizontal) {
|
|
145
211
|
const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
|
|
146
|
-
|
|
212
|
+
const topInset = calculateTopInset(
|
|
213
|
+
safeAreaInsetTop,
|
|
214
|
+
IsNewArchitecture,
|
|
215
|
+
vIsOpening ? vTopInset : 0
|
|
216
|
+
);
|
|
217
|
+
keyboardInset.set({
|
|
218
|
+
bottom: newInset,
|
|
219
|
+
// Add top padding only while opening to keep end-aligned items visible.
|
|
220
|
+
top: topInset
|
|
221
|
+
});
|
|
147
222
|
}
|
|
148
223
|
}
|
|
149
224
|
},
|
|
@@ -153,12 +228,17 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
|
|
|
153
228
|
const vMode = mode.get();
|
|
154
229
|
mode.set("idle");
|
|
155
230
|
if (vMode === "running") {
|
|
231
|
+
const progress = clampProgress(event.progress);
|
|
232
|
+
const vKeyboardHeight = keyboardHeight.get();
|
|
233
|
+
const vAlignItemsPadding = alignItemsAtEndPadding.get();
|
|
234
|
+
const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
|
|
235
|
+
const vIsOpening = isOpening.get();
|
|
156
236
|
if (!wasInteractive) {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
237
|
+
const targetOffset = calculateKeyboardTargetOffset(
|
|
238
|
+
scrollOffsetAtKeyboardStart.get(),
|
|
239
|
+
vKeyboardHeight,
|
|
240
|
+
vIsOpening,
|
|
241
|
+
progress
|
|
162
242
|
);
|
|
163
243
|
scrollOffsetY.set(targetOffset);
|
|
164
244
|
animatedOffsetY.set(targetOffset);
|
|
@@ -168,7 +248,16 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
|
|
|
168
248
|
isKeyboardOpen.set(event.height > 0);
|
|
169
249
|
if (!horizontal) {
|
|
170
250
|
const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
|
|
171
|
-
|
|
251
|
+
const topInset = calculateTopInset(
|
|
252
|
+
safeAreaInsetTop,
|
|
253
|
+
IsNewArchitecture,
|
|
254
|
+
event.height > 0 ? vTopInset : 0
|
|
255
|
+
);
|
|
256
|
+
keyboardInset.set({
|
|
257
|
+
bottom: newInset,
|
|
258
|
+
// Preserve end-aligned padding only while the keyboard is visible.
|
|
259
|
+
top: topInset
|
|
260
|
+
});
|
|
172
261
|
if (newInset <= 0) {
|
|
173
262
|
animatedOffsetY.set(scrollOffsetY.get());
|
|
174
263
|
}
|
|
@@ -214,6 +303,7 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
|
|
|
214
303
|
...rest,
|
|
215
304
|
animatedProps,
|
|
216
305
|
keyboardDismissMode: "interactive",
|
|
306
|
+
onMetricsChange: handleMetricsChange,
|
|
217
307
|
onScroll: scrollHandler,
|
|
218
308
|
ref: combinedRef,
|
|
219
309
|
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,14 +33,33 @@ 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 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
|
+
};
|
|
37
58
|
var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
|
|
38
59
|
const {
|
|
39
60
|
contentInset: contentInsetProp,
|
|
40
61
|
horizontal,
|
|
62
|
+
onMetricsChange: onMetricsChangeProp,
|
|
41
63
|
onScroll: onScrollProp,
|
|
42
64
|
safeAreaInsets = { bottom: 0, top: 0 },
|
|
43
65
|
style: styleProp,
|
|
@@ -55,6 +77,7 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
|
|
|
55
77
|
const mode = useSharedValue("idle");
|
|
56
78
|
const keyboardInset = useSharedValue({ bottom: 0, top: 0 });
|
|
57
79
|
const keyboardHeight = useSharedValue(0);
|
|
80
|
+
const alignItemsAtEndPadding = useSharedValue(0);
|
|
58
81
|
const isOpening = useSharedValue(false);
|
|
59
82
|
const didInteractive = useSharedValue(false);
|
|
60
83
|
const { top: safeAreaInsetTop, bottom: safeAreaInsetBottom } = safeAreaInsets;
|
|
@@ -75,20 +98,52 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
|
|
|
75
98
|
},
|
|
76
99
|
[refLegendList]
|
|
77
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
|
+
);
|
|
78
132
|
useKeyboardHandler(
|
|
79
133
|
// biome-ignore assist/source/useSortedKeys: prefer start/move/end
|
|
80
134
|
{
|
|
81
135
|
onStart: (event) => {
|
|
82
136
|
"worklet";
|
|
83
137
|
mode.set("running");
|
|
84
|
-
|
|
138
|
+
const progress = clampProgress(event.progress);
|
|
139
|
+
if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
|
|
85
140
|
return;
|
|
86
141
|
}
|
|
87
142
|
if (!didInteractive.get()) {
|
|
88
143
|
if (event.height > 0) {
|
|
89
144
|
keyboardHeight.set(event.height - safeAreaInsetBottom);
|
|
90
145
|
}
|
|
91
|
-
isOpening.set(
|
|
146
|
+
isOpening.set(progress > 0);
|
|
92
147
|
scrollOffsetAtKeyboardStart.set(scrollOffsetY.get());
|
|
93
148
|
animatedOffsetY.set(scrollOffsetY.get());
|
|
94
149
|
runOnJS(setScrollProcessingEnabled)(false);
|
|
@@ -101,6 +156,13 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
|
|
|
101
156
|
}
|
|
102
157
|
mode.set("running");
|
|
103
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
|
+
}
|
|
104
166
|
didInteractive.set(true);
|
|
105
167
|
}
|
|
106
168
|
if (isAndroid && !horizontal) {
|
|
@@ -111,18 +173,31 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
|
|
|
111
173
|
onMove: (event) => {
|
|
112
174
|
"worklet";
|
|
113
175
|
if (!didInteractive.get()) {
|
|
176
|
+
const progress = clampProgress(event.progress);
|
|
114
177
|
const vIsOpening = isOpening.get();
|
|
115
178
|
const vKeyboardHeight = keyboardHeight.get();
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
scrollOffsetAtKeyboardStart.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
|
|
120
186
|
);
|
|
121
187
|
scrollOffsetY.set(targetOffset);
|
|
122
188
|
animatedOffsetY.set(targetOffset);
|
|
123
189
|
if (!horizontal) {
|
|
124
190
|
const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
|
|
125
|
-
|
|
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
|
+
});
|
|
126
201
|
}
|
|
127
202
|
}
|
|
128
203
|
},
|
|
@@ -132,12 +207,17 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
|
|
|
132
207
|
const vMode = mode.get();
|
|
133
208
|
mode.set("idle");
|
|
134
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();
|
|
135
215
|
if (!wasInteractive) {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
216
|
+
const targetOffset = calculateKeyboardTargetOffset(
|
|
217
|
+
scrollOffsetAtKeyboardStart.get(),
|
|
218
|
+
vKeyboardHeight,
|
|
219
|
+
vIsOpening,
|
|
220
|
+
progress
|
|
141
221
|
);
|
|
142
222
|
scrollOffsetY.set(targetOffset);
|
|
143
223
|
animatedOffsetY.set(targetOffset);
|
|
@@ -147,7 +227,16 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
|
|
|
147
227
|
isKeyboardOpen.set(event.height > 0);
|
|
148
228
|
if (!horizontal) {
|
|
149
229
|
const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
|
|
150
|
-
|
|
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
|
+
});
|
|
151
240
|
if (newInset <= 0) {
|
|
152
241
|
animatedOffsetY.set(scrollOffsetY.get());
|
|
153
242
|
}
|
|
@@ -193,6 +282,7 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
|
|
|
193
282
|
...rest,
|
|
194
283
|
animatedProps,
|
|
195
284
|
keyboardDismissMode: "interactive",
|
|
285
|
+
onMetricsChange: handleMetricsChange,
|
|
196
286
|
onScroll: scrollHandler,
|
|
197
287
|
ref: combinedRef,
|
|
198
288
|
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 };
|