@legendapp/list 3.0.0-beta.8 → 3.0.0
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/.DS_Store +0 -0
- package/CHANGELOG.md +21 -1
- package/README.md +8 -2
- package/animated.d.ts +659 -5
- package/animated.js +2 -2
- package/animated.mjs +1 -1
- package/keyboard-legacy.d.ts +226 -0
- package/keyboard-legacy.js +456 -0
- package/keyboard-legacy.mjs +435 -0
- package/keyboard.d.ts +261 -9
- package/keyboard.js +114 -135
- package/keyboard.mjs +115 -137
- package/package.json +55 -5
- package/{types-DjNeqVEk.d.mts → react-native.d.ts} +318 -278
- package/react-native.js +6453 -0
- package/react-native.mjs +6424 -0
- package/react-native.web.d.ts +771 -0
- package/react-native.web.js +7111 -0
- package/react-native.web.mjs +7082 -0
- package/react.d.ts +771 -0
- package/react.js +7111 -0
- package/react.mjs +7082 -0
- package/reanimated.d.ts +681 -8
- package/reanimated.js +225 -29
- package/reanimated.mjs +227 -31
- package/section-list.d.ts +663 -5
- package/section-list.js +39 -3720
- package/section-list.mjs +37 -3719
- package/animated.d.mts +0 -9
- package/index.d.mts +0 -23
- package/index.d.ts +0 -23
- package/index.js +0 -3826
- package/index.mjs +0 -3798
- package/index.native.d.mts +0 -23
- package/index.native.d.ts +0 -23
- package/index.native.js +0 -3580
- package/index.native.mjs +0 -3552
- package/keyboard-controller.d.mts +0 -12
- package/keyboard-controller.d.ts +0 -12
- package/keyboard-controller.js +0 -69
- package/keyboard-controller.mjs +0 -48
- package/keyboard.d.mts +0 -13
- package/reanimated.d.mts +0 -18
- package/section-list.d.mts +0 -113
- package/section-list.native.d.mts +0 -113
- package/section-list.native.d.ts +0 -113
- package/section-list.native.js +0 -3738
- package/section-list.native.mjs +0 -3717
- package/types-DjNeqVEk.d.ts +0 -669
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ScrollViewComponent, ScrollResponderMixin, Insets as Insets$1 } from 'react-native';
|
|
3
|
+
import { ScrollEvent, ScrollHandlerProcessed } from 'react-native-reanimated';
|
|
4
|
+
import { AnimatedLegendListProps } from '@legendapp/list/reanimated';
|
|
5
|
+
|
|
6
|
+
interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
7
|
+
data: boolean;
|
|
8
|
+
size: boolean;
|
|
9
|
+
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type ListenerType = "activeStickyIndex" | "anchoredEndSpaceSize" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
13
|
+
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
14
|
+
type ListenerTypeValueMap = {
|
|
15
|
+
activeStickyIndex: number;
|
|
16
|
+
anchoredEndSpaceSize: number;
|
|
17
|
+
animatedScrollY: any;
|
|
18
|
+
debugComputedScroll: number;
|
|
19
|
+
debugRawScroll: number;
|
|
20
|
+
extraData: any;
|
|
21
|
+
footerSize: number;
|
|
22
|
+
headerSize: number;
|
|
23
|
+
isAtEnd: boolean;
|
|
24
|
+
isAtStart: boolean;
|
|
25
|
+
isNearEnd: boolean;
|
|
26
|
+
isNearStart: boolean;
|
|
27
|
+
isWithinMaintainScrollAtEndThreshold: boolean;
|
|
28
|
+
lastItemKeys: string[];
|
|
29
|
+
lastPositionUpdate: number;
|
|
30
|
+
maintainVisibleContentPosition: MaintainVisibleContentPositionNormalized;
|
|
31
|
+
numColumns: number;
|
|
32
|
+
numContainers: number;
|
|
33
|
+
numContainersPooled: number;
|
|
34
|
+
otherAxisSize: number;
|
|
35
|
+
readyToRender: boolean;
|
|
36
|
+
scrollAdjust: number;
|
|
37
|
+
scrollAdjustPending: number;
|
|
38
|
+
scrollAdjustUserOffset: number;
|
|
39
|
+
scrollSize: {
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
};
|
|
43
|
+
snapToOffsets: number[];
|
|
44
|
+
stylePaddingTop: number;
|
|
45
|
+
totalSize: number;
|
|
46
|
+
} & {
|
|
47
|
+
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
48
|
+
} & {
|
|
49
|
+
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
50
|
+
} & {
|
|
51
|
+
[K in ListenerType as K extends `containerPosition${number}` ? K : never]: number;
|
|
52
|
+
} & {
|
|
53
|
+
[K in ListenerType as K extends `containerColumn${number}` ? K : never]: number;
|
|
54
|
+
} & {
|
|
55
|
+
[K in ListenerType as K extends `containerSpan${number}` ? K : never]: number;
|
|
56
|
+
} & {
|
|
57
|
+
[K in ListenerType as K extends `containerSticky${number}` ? K : never]: boolean;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
interface Insets {
|
|
61
|
+
top: number;
|
|
62
|
+
left: number;
|
|
63
|
+
bottom: number;
|
|
64
|
+
right: number;
|
|
65
|
+
}
|
|
66
|
+
interface LegendListAverageItemSize {
|
|
67
|
+
average: number;
|
|
68
|
+
count: number;
|
|
69
|
+
}
|
|
70
|
+
type LegendListState = {
|
|
71
|
+
activeStickyIndex: number;
|
|
72
|
+
contentLength: number;
|
|
73
|
+
data: readonly any[];
|
|
74
|
+
elementAtIndex: (index: number) => any;
|
|
75
|
+
end: number;
|
|
76
|
+
endBuffered: number;
|
|
77
|
+
isAtEnd: boolean;
|
|
78
|
+
isAtStart: boolean;
|
|
79
|
+
isNearEnd: boolean;
|
|
80
|
+
isNearStart: boolean;
|
|
81
|
+
isEndReached: boolean;
|
|
82
|
+
isStartReached: boolean;
|
|
83
|
+
isWithinMaintainScrollAtEndThreshold: boolean;
|
|
84
|
+
getAverageItemSizes: () => Record<string, LegendListAverageItemSize>;
|
|
85
|
+
listen: <T extends LegendListListenerType>(listenerType: T, callback: (value: ListenerTypeValueMap[T]) => void) => () => void;
|
|
86
|
+
listenToPosition: (key: string, callback: (value: number) => void) => () => void;
|
|
87
|
+
positionAtIndex: (index: number) => number;
|
|
88
|
+
positionByKey: (key: string) => number | undefined;
|
|
89
|
+
scroll: number;
|
|
90
|
+
scrollLength: number;
|
|
91
|
+
scrollVelocity: number;
|
|
92
|
+
sizeAtIndex: (index: number) => number;
|
|
93
|
+
sizes: Map<string, number>;
|
|
94
|
+
start: number;
|
|
95
|
+
startBuffered: number;
|
|
96
|
+
};
|
|
97
|
+
type LegendListRef$1 = {
|
|
98
|
+
/**
|
|
99
|
+
* Displays the scroll indicators momentarily.
|
|
100
|
+
*/
|
|
101
|
+
flashScrollIndicators(): void;
|
|
102
|
+
/**
|
|
103
|
+
* Returns the native ScrollView component reference.
|
|
104
|
+
*/
|
|
105
|
+
getNativeScrollRef(): any;
|
|
106
|
+
/**
|
|
107
|
+
* Returns the scroll responder instance for handling scroll events.
|
|
108
|
+
*/
|
|
109
|
+
getScrollableNode(): any;
|
|
110
|
+
/**
|
|
111
|
+
* Returns the ScrollResponderMixin for advanced scroll handling.
|
|
112
|
+
*/
|
|
113
|
+
getScrollResponder(): any;
|
|
114
|
+
/**
|
|
115
|
+
* Returns the internal state of the scroll virtualization.
|
|
116
|
+
*/
|
|
117
|
+
getState(): LegendListState;
|
|
118
|
+
/**
|
|
119
|
+
* Scrolls a specific index into view.
|
|
120
|
+
* @param params - Parameters for scrolling.
|
|
121
|
+
* @param params.animated - If true, animates the scroll. Default: true.
|
|
122
|
+
* @param params.index - The index to scroll to.
|
|
123
|
+
*/
|
|
124
|
+
scrollIndexIntoView(params: {
|
|
125
|
+
animated?: boolean | undefined;
|
|
126
|
+
index: number;
|
|
127
|
+
}): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Scrolls a specific index into view.
|
|
130
|
+
* @param params - Parameters for scrolling.
|
|
131
|
+
* @param params.animated - If true, animates the scroll. Default: true.
|
|
132
|
+
* @param params.item - The item to scroll to.
|
|
133
|
+
*/
|
|
134
|
+
scrollItemIntoView(params: {
|
|
135
|
+
animated?: boolean | undefined;
|
|
136
|
+
item: any;
|
|
137
|
+
}): Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Scrolls to the end of the list.
|
|
140
|
+
* @param options - Options for scrolling.
|
|
141
|
+
* @param options.animated - If true, animates the scroll. Default: true.
|
|
142
|
+
* @param options.viewOffset - Offset from the target position.
|
|
143
|
+
*/
|
|
144
|
+
scrollToEnd(options?: {
|
|
145
|
+
animated?: boolean | undefined;
|
|
146
|
+
viewOffset?: number | undefined;
|
|
147
|
+
}): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Scrolls to a specific index in the list.
|
|
150
|
+
* @param params - Parameters for scrolling.
|
|
151
|
+
* @param params.animated - If true, animates the scroll. Default: true.
|
|
152
|
+
* @param params.index - The index to scroll to.
|
|
153
|
+
* @param params.viewOffset - Offset from the target position.
|
|
154
|
+
* @param params.viewPosition - Position of the item in the viewport (0 to 1).
|
|
155
|
+
*/
|
|
156
|
+
scrollToIndex(params: {
|
|
157
|
+
animated?: boolean | undefined;
|
|
158
|
+
index: number;
|
|
159
|
+
viewOffset?: number | undefined;
|
|
160
|
+
viewPosition?: number | undefined;
|
|
161
|
+
}): Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* Scrolls to a specific item in the list.
|
|
164
|
+
* @param params - Parameters for scrolling.
|
|
165
|
+
* @param params.animated - If true, animates the scroll. Default: true.
|
|
166
|
+
* @param params.item - The item to scroll to.
|
|
167
|
+
* @param params.viewOffset - Offset from the target position.
|
|
168
|
+
* @param params.viewPosition - Position of the item in the viewport (0 to 1).
|
|
169
|
+
*/
|
|
170
|
+
scrollToItem(params: {
|
|
171
|
+
animated?: boolean | undefined;
|
|
172
|
+
item: any;
|
|
173
|
+
viewOffset?: number | undefined;
|
|
174
|
+
viewPosition?: number | undefined;
|
|
175
|
+
}): Promise<void>;
|
|
176
|
+
/**
|
|
177
|
+
* Scrolls to a specific offset in pixels.
|
|
178
|
+
* @param params - Parameters for scrolling.
|
|
179
|
+
* @param params.offset - The pixel offset to scroll to.
|
|
180
|
+
* @param params.animated - If true, animates the scroll. Default: true.
|
|
181
|
+
*/
|
|
182
|
+
scrollToOffset(params: {
|
|
183
|
+
offset: number;
|
|
184
|
+
animated?: boolean | undefined;
|
|
185
|
+
}): Promise<void>;
|
|
186
|
+
/**
|
|
187
|
+
* Sets or adds to the offset of the visible content anchor.
|
|
188
|
+
* @param value - The offset to set or add.
|
|
189
|
+
* @param animated - If true, uses Animated to animate the change.
|
|
190
|
+
*/
|
|
191
|
+
setVisibleContentAnchorOffset(value: number | ((val: number) => number)): void;
|
|
192
|
+
/**
|
|
193
|
+
* Sets whether scroll processing is enabled.
|
|
194
|
+
* @param enabled - If true, scroll processing is enabled.
|
|
195
|
+
*/
|
|
196
|
+
setScrollProcessingEnabled(enabled: boolean): void;
|
|
197
|
+
/**
|
|
198
|
+
* Clears internal virtualization caches.
|
|
199
|
+
* @param options - Cache clearing options.
|
|
200
|
+
* @param options.mode - `sizes` clears measurement caches. `full` also clears key/position caches.
|
|
201
|
+
*/
|
|
202
|
+
clearCaches(options?: {
|
|
203
|
+
mode?: "sizes" | "full";
|
|
204
|
+
}): void;
|
|
205
|
+
/**
|
|
206
|
+
* Reports an externally measured content inset. Pass null/undefined to clear.
|
|
207
|
+
* Values are merged on top of props/animated/native insets.
|
|
208
|
+
*/
|
|
209
|
+
reportContentInset(inset?: Partial<Insets> | null): void;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
type LegendListRef = Omit<LegendListRef$1, "getNativeScrollRef" | "getScrollResponder" | "reportContentInset"> & {
|
|
213
|
+
getNativeScrollRef(): React.ElementRef<typeof ScrollViewComponent>;
|
|
214
|
+
getScrollResponder(): ScrollResponderMixin;
|
|
215
|
+
reportContentInset(inset?: Partial<Insets$1> | null): void;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
type KeyboardOnScrollCallback = (event: ScrollEvent) => void;
|
|
219
|
+
type KeyboardOnScrollHandler = KeyboardOnScrollCallback | ScrollHandlerProcessed<Record<string, unknown>>;
|
|
220
|
+
declare const KeyboardAvoidingLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "onScroll" | "automaticallyAdjustContentInsets" | "contentInset"> & {
|
|
221
|
+
onScroll?: KeyboardOnScrollHandler;
|
|
222
|
+
contentInset?: Insets$1 | undefined;
|
|
223
|
+
safeAreaInsetBottom?: number;
|
|
224
|
+
} & React.RefAttributes<LegendListRef>) => React.ReactElement | null;
|
|
225
|
+
|
|
226
|
+
export { KeyboardAvoidingLegendList };
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var reactNative$1 = require('react-native');
|
|
5
|
+
var reactNativeKeyboardController = require('react-native-keyboard-controller');
|
|
6
|
+
var reactNativeReanimated = require('react-native-reanimated');
|
|
7
|
+
var reactNative = require('@legendapp/list/react-native');
|
|
8
|
+
var reanimated = require('@legendapp/list/reanimated');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
29
|
+
|
|
30
|
+
// src/integrations/keyboard-legacy.tsx
|
|
31
|
+
var { typedForwardRef, useCombinedRef } = reactNative.internal;
|
|
32
|
+
var clampProgress = (progress) => {
|
|
33
|
+
"worklet";
|
|
34
|
+
return Math.min(1, Math.max(0, progress));
|
|
35
|
+
};
|
|
36
|
+
var calculateKeyboardInset = (height, safeAreaInsetBottom) => {
|
|
37
|
+
"worklet";
|
|
38
|
+
return Math.max(0, height - safeAreaInsetBottom);
|
|
39
|
+
};
|
|
40
|
+
var calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
|
|
41
|
+
"worklet";
|
|
42
|
+
if (alignItemsAtEnd) {
|
|
43
|
+
return keyboardHeight;
|
|
44
|
+
} else {
|
|
45
|
+
const availableSpace = Math.max(0, scrollLength - contentLength);
|
|
46
|
+
return Math.max(0, keyboardHeight - availableSpace);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var calculateKeyboardTargetOffset = (startOffset, keyboardHeight, isOpening, progress) => {
|
|
50
|
+
"worklet";
|
|
51
|
+
const normalizedProgress = isOpening ? progress : 1 - progress;
|
|
52
|
+
const delta = (isOpening ? keyboardHeight : -keyboardHeight) * normalizedProgress;
|
|
53
|
+
return Math.max(0, startOffset + delta);
|
|
54
|
+
};
|
|
55
|
+
var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
|
|
56
|
+
const {
|
|
57
|
+
contentContainerStyle: contentContainerStyleProp,
|
|
58
|
+
contentInset: contentInsetProp,
|
|
59
|
+
horizontal,
|
|
60
|
+
onMetricsChange: onMetricsChangeProp,
|
|
61
|
+
onContentSizeChange: onContentSizeChangeProp,
|
|
62
|
+
onLayout: onLayoutProp,
|
|
63
|
+
onScroll: onScrollProp,
|
|
64
|
+
safeAreaInsetBottom = 0,
|
|
65
|
+
style: styleProp,
|
|
66
|
+
...rest
|
|
67
|
+
} = props;
|
|
68
|
+
const { alignItemsAtEnd } = props;
|
|
69
|
+
const styleFlattened = reactNative$1.StyleSheet.flatten(styleProp);
|
|
70
|
+
const refLegendList = React.useRef(null);
|
|
71
|
+
const combinedRef = useCombinedRef(forwardedRef, refLegendList);
|
|
72
|
+
const isIos = reactNative$1.Platform.OS === "ios";
|
|
73
|
+
const isAndroid = reactNative$1.Platform.OS === "android";
|
|
74
|
+
const scrollViewRef = reactNativeReanimated.useAnimatedRef();
|
|
75
|
+
const scrollOffsetY = reactNativeReanimated.useSharedValue(0);
|
|
76
|
+
const animatedOffsetY = reactNativeReanimated.useSharedValue(null);
|
|
77
|
+
const scrollOffsetAtKeyboardStart = reactNativeReanimated.useSharedValue(0);
|
|
78
|
+
const animationMode = reactNativeReanimated.useSharedValue("idle");
|
|
79
|
+
const keyboardInset = reactNativeReanimated.useSharedValue(0);
|
|
80
|
+
const keyboardHeight = reactNativeReanimated.useSharedValue(0);
|
|
81
|
+
const contentLength = reactNativeReanimated.useSharedValue(0);
|
|
82
|
+
const scrollLength = reactNativeReanimated.useSharedValue(0);
|
|
83
|
+
const isOpening = reactNativeReanimated.useSharedValue(false);
|
|
84
|
+
const didInteractive = reactNativeReanimated.useSharedValue(false);
|
|
85
|
+
const shouldUpdateAlignItemsAtEndMinSize = reactNativeReanimated.useSharedValue(false);
|
|
86
|
+
const isKeyboardOpen = reactNativeReanimated.useSharedValue(false);
|
|
87
|
+
const hasSeenKeyboardTransition = reactNativeReanimated.useSharedValue(false);
|
|
88
|
+
const skipKeyboardAnimationForCurrentTransition = reactNativeReanimated.useSharedValue(false);
|
|
89
|
+
const keyboardInsetRef = React.useRef(0);
|
|
90
|
+
const [alignItemsAtEndMinSize, setAlignItemsAtEndMinSize] = React.useState(void 0);
|
|
91
|
+
const onScrollValue = onScrollProp;
|
|
92
|
+
const onScrollCallback = typeof onScrollValue === "function" ? onScrollValue : void 0;
|
|
93
|
+
const onScrollProcessed = onScrollValue && typeof onScrollValue === "object" && "workletEventHandler" in onScrollValue ? onScrollValue : null;
|
|
94
|
+
const onScrollCallbackIsWorklet = React.useMemo(
|
|
95
|
+
() => onScrollCallback ? reactNativeReanimated.isWorkletFunction(onScrollCallback) : false,
|
|
96
|
+
[onScrollCallback]
|
|
97
|
+
);
|
|
98
|
+
const handleContentSizeChange = React.useCallback(
|
|
99
|
+
(width, height) => {
|
|
100
|
+
const nextContentLength = horizontal ? width : height;
|
|
101
|
+
if (Number.isFinite(nextContentLength) && nextContentLength > 0) {
|
|
102
|
+
contentLength.set(nextContentLength);
|
|
103
|
+
}
|
|
104
|
+
onContentSizeChangeProp == null ? void 0 : onContentSizeChangeProp(width, height);
|
|
105
|
+
},
|
|
106
|
+
[contentLength, horizontal, onContentSizeChangeProp]
|
|
107
|
+
);
|
|
108
|
+
const handleLayout = React.useCallback(
|
|
109
|
+
(event) => {
|
|
110
|
+
const nextScrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
|
|
111
|
+
if (Number.isFinite(nextScrollLength) && nextScrollLength > 0) {
|
|
112
|
+
scrollLength.set(nextScrollLength);
|
|
113
|
+
}
|
|
114
|
+
onLayoutProp == null ? void 0 : onLayoutProp(event);
|
|
115
|
+
},
|
|
116
|
+
[horizontal, onLayoutProp, scrollLength]
|
|
117
|
+
);
|
|
118
|
+
const scrollHandler = reactNativeReanimated.useAnimatedScrollHandler(
|
|
119
|
+
(event) => {
|
|
120
|
+
if (animationMode.get() !== "running" || didInteractive.get()) {
|
|
121
|
+
scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
|
|
122
|
+
}
|
|
123
|
+
if (onScrollCallback) {
|
|
124
|
+
if (onScrollCallbackIsWorklet) {
|
|
125
|
+
onScrollCallback(event);
|
|
126
|
+
} else {
|
|
127
|
+
reactNativeReanimated.runOnJS(onScrollCallback)(event);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
[horizontal, onScrollCallback, onScrollCallbackIsWorklet]
|
|
132
|
+
);
|
|
133
|
+
const composedScrollHandler = reactNativeReanimated.useComposedEventHandler([
|
|
134
|
+
scrollHandler,
|
|
135
|
+
onScrollProcessed
|
|
136
|
+
]);
|
|
137
|
+
const finalScrollHandler = onScrollProcessed ? composedScrollHandler : scrollHandler;
|
|
138
|
+
const setScrollProcessingEnabled = React.useCallback(
|
|
139
|
+
(enabled) => {
|
|
140
|
+
var _a;
|
|
141
|
+
return (_a = refLegendList.current) == null ? void 0 : _a.setScrollProcessingEnabled(enabled);
|
|
142
|
+
},
|
|
143
|
+
[refLegendList]
|
|
144
|
+
);
|
|
145
|
+
const reportContentInset = React.useCallback(
|
|
146
|
+
(bottom) => {
|
|
147
|
+
var _a;
|
|
148
|
+
return (_a = refLegendList.current) == null ? void 0 : _a.reportContentInset({ bottom });
|
|
149
|
+
},
|
|
150
|
+
[refLegendList]
|
|
151
|
+
);
|
|
152
|
+
const clearAlignItemsAtEndMinSize = React.useCallback(() => {
|
|
153
|
+
setAlignItemsAtEndMinSize((prev) => prev === void 0 ? prev : void 0);
|
|
154
|
+
}, []);
|
|
155
|
+
const updateAlignItemsAtEndMinSize = React.useCallback(
|
|
156
|
+
(nextKeyboardInset) => {
|
|
157
|
+
var _a;
|
|
158
|
+
if (isAndroid) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (nextKeyboardInset !== void 0) {
|
|
162
|
+
keyboardInsetRef.current = nextKeyboardInset;
|
|
163
|
+
}
|
|
164
|
+
if (!alignItemsAtEnd || horizontal) {
|
|
165
|
+
clearAlignItemsAtEndMinSize();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
|
|
169
|
+
if (!state) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const currentInset = keyboardInsetRef.current;
|
|
173
|
+
if (currentInset <= 0) {
|
|
174
|
+
clearAlignItemsAtEndMinSize();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (state.scrollLength <= 0) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const nextMinSize = Math.max(0, state.scrollLength - currentInset);
|
|
181
|
+
setAlignItemsAtEndMinSize((prev) => prev === nextMinSize ? prev : nextMinSize);
|
|
182
|
+
},
|
|
183
|
+
[alignItemsAtEnd, clearAlignItemsAtEndMinSize, horizontal, isAndroid]
|
|
184
|
+
);
|
|
185
|
+
const updateScrollMetrics = React.useCallback(() => {
|
|
186
|
+
var _a;
|
|
187
|
+
const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
|
|
188
|
+
if (!state) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
contentLength.set(state.contentLength);
|
|
192
|
+
if (animationMode.get() !== "running") {
|
|
193
|
+
scrollOffsetY.set(state.scroll);
|
|
194
|
+
}
|
|
195
|
+
scrollLength.set(state.scrollLength);
|
|
196
|
+
updateAlignItemsAtEndMinSize();
|
|
197
|
+
}, [animationMode, contentLength, scrollLength, scrollOffsetY, updateAlignItemsAtEndMinSize]);
|
|
198
|
+
const handleMetricsChange = React.useCallback(
|
|
199
|
+
(metrics) => {
|
|
200
|
+
updateScrollMetrics();
|
|
201
|
+
onMetricsChangeProp == null ? void 0 : onMetricsChangeProp(metrics);
|
|
202
|
+
},
|
|
203
|
+
[onMetricsChangeProp, updateScrollMetrics]
|
|
204
|
+
);
|
|
205
|
+
React.useEffect(() => {
|
|
206
|
+
updateScrollMetrics();
|
|
207
|
+
}, [updateScrollMetrics]);
|
|
208
|
+
React.useEffect(() => {
|
|
209
|
+
updateAlignItemsAtEndMinSize();
|
|
210
|
+
}, [updateAlignItemsAtEndMinSize]);
|
|
211
|
+
const getEffectiveKeyboardHeightFromInset = React.useCallback(
|
|
212
|
+
(nextKeyboardInset) => {
|
|
213
|
+
"worklet";
|
|
214
|
+
return calculateEffectiveKeyboardHeight(
|
|
215
|
+
nextKeyboardInset,
|
|
216
|
+
contentLength.get(),
|
|
217
|
+
scrollLength.get(),
|
|
218
|
+
alignItemsAtEnd
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
[alignItemsAtEnd, contentLength, scrollLength]
|
|
222
|
+
);
|
|
223
|
+
const getEffectiveKeyboardHeightFromEvent = React.useCallback(
|
|
224
|
+
(eventHeight) => {
|
|
225
|
+
"worklet";
|
|
226
|
+
const nextKeyboardInset = calculateKeyboardInset(eventHeight, safeAreaInsetBottom);
|
|
227
|
+
return getEffectiveKeyboardHeightFromInset(nextKeyboardInset);
|
|
228
|
+
},
|
|
229
|
+
[getEffectiveKeyboardHeightFromInset, safeAreaInsetBottom]
|
|
230
|
+
);
|
|
231
|
+
reactNativeKeyboardController.useKeyboardHandler(
|
|
232
|
+
// biome-ignore assist/source/useSortedKeys: prefer start/move/end
|
|
233
|
+
{
|
|
234
|
+
onStart: (event) => {
|
|
235
|
+
"worklet";
|
|
236
|
+
const progress = clampProgress(event.progress);
|
|
237
|
+
const shouldSkipInitialCloseAnimation = !hasSeenKeyboardTransition.get() && !isKeyboardOpen.get() && keyboardHeight.get() <= 0 && progress <= 0 && event.height <= 0;
|
|
238
|
+
skipKeyboardAnimationForCurrentTransition.set(shouldSkipInitialCloseAnimation);
|
|
239
|
+
hasSeenKeyboardTransition.set(true);
|
|
240
|
+
if (isKeyboardOpen.get() && progress >= 1 && event.height > 0) {
|
|
241
|
+
didInteractive.set(false);
|
|
242
|
+
animationMode.set("idle");
|
|
243
|
+
reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(true);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (shouldSkipInitialCloseAnimation) {
|
|
247
|
+
isOpening.set(false);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
animationMode.set("running");
|
|
251
|
+
if (!didInteractive.get()) {
|
|
252
|
+
if (event.height > 0) {
|
|
253
|
+
keyboardHeight.set(calculateKeyboardInset(event.height, safeAreaInsetBottom));
|
|
254
|
+
}
|
|
255
|
+
const vIsOpening = progress > 0;
|
|
256
|
+
isOpening.set(vIsOpening);
|
|
257
|
+
shouldUpdateAlignItemsAtEndMinSize.set(
|
|
258
|
+
!!alignItemsAtEnd && !horizontal && contentLength.get() < scrollLength.get()
|
|
259
|
+
);
|
|
260
|
+
if (!shouldUpdateAlignItemsAtEndMinSize.get()) {
|
|
261
|
+
reactNativeReanimated.runOnJS(clearAlignItemsAtEndMinSize)();
|
|
262
|
+
}
|
|
263
|
+
const vScrollOffset = scrollOffsetY.get();
|
|
264
|
+
scrollOffsetAtKeyboardStart.set(vScrollOffset);
|
|
265
|
+
if (isIos) {
|
|
266
|
+
const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromInset(keyboardHeight.get());
|
|
267
|
+
const targetOffset = Math.max(
|
|
268
|
+
0,
|
|
269
|
+
vIsOpening ? vScrollOffset + vEffectiveKeyboardHeight : vScrollOffset - vEffectiveKeyboardHeight
|
|
270
|
+
);
|
|
271
|
+
scrollOffsetY.set(targetOffset);
|
|
272
|
+
animatedOffsetY.set(targetOffset);
|
|
273
|
+
keyboardInset.set(vEffectiveKeyboardHeight);
|
|
274
|
+
reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(vEffectiveKeyboardHeight);
|
|
275
|
+
} else if (isAndroid) {
|
|
276
|
+
animatedOffsetY.set(vScrollOffset);
|
|
277
|
+
}
|
|
278
|
+
reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
onInteractive: (event) => {
|
|
282
|
+
"worklet";
|
|
283
|
+
if (animationMode.get() !== "running") {
|
|
284
|
+
reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(false);
|
|
285
|
+
}
|
|
286
|
+
animationMode.set("running");
|
|
287
|
+
if (!didInteractive.get()) {
|
|
288
|
+
didInteractive.set(true);
|
|
289
|
+
}
|
|
290
|
+
if (isAndroid && !horizontal) {
|
|
291
|
+
const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
|
|
292
|
+
keyboardInset.set(newInset);
|
|
293
|
+
}
|
|
294
|
+
if (shouldUpdateAlignItemsAtEndMinSize.get() && !horizontal && alignItemsAtEnd) {
|
|
295
|
+
const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromEvent(event.height);
|
|
296
|
+
reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(vEffectiveKeyboardHeight);
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
onMove: (event) => {
|
|
300
|
+
"worklet";
|
|
301
|
+
const vIsOpening = isOpening.get();
|
|
302
|
+
const progress = clampProgress(event.progress);
|
|
303
|
+
const skipKeyboardAnimation = skipKeyboardAnimationForCurrentTransition.get();
|
|
304
|
+
if (skipKeyboardAnimation) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (isAndroid) {
|
|
308
|
+
if (!didInteractive.get()) {
|
|
309
|
+
const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromInset(keyboardHeight.get());
|
|
310
|
+
const targetOffset = calculateKeyboardTargetOffset(
|
|
311
|
+
scrollOffsetAtKeyboardStart.get(),
|
|
312
|
+
vEffectiveKeyboardHeight,
|
|
313
|
+
vIsOpening,
|
|
314
|
+
progress
|
|
315
|
+
);
|
|
316
|
+
scrollOffsetY.set(targetOffset);
|
|
317
|
+
animatedOffsetY.set(targetOffset);
|
|
318
|
+
}
|
|
319
|
+
if (!horizontal) {
|
|
320
|
+
const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
|
|
321
|
+
keyboardInset.set(newInset);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (!horizontal && alignItemsAtEnd && !vIsOpening && shouldUpdateAlignItemsAtEndMinSize.get()) {
|
|
325
|
+
const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromEvent(event.height);
|
|
326
|
+
reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(vEffectiveKeyboardHeight);
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
onEnd: (event) => {
|
|
330
|
+
"worklet";
|
|
331
|
+
const wasInteractive = didInteractive.get();
|
|
332
|
+
const skipKeyboardAnimation = skipKeyboardAnimationForCurrentTransition.get();
|
|
333
|
+
const vMode = animationMode.get();
|
|
334
|
+
animationMode.set("idle");
|
|
335
|
+
if (skipKeyboardAnimation) {
|
|
336
|
+
skipKeyboardAnimationForCurrentTransition.set(false);
|
|
337
|
+
didInteractive.set(false);
|
|
338
|
+
isOpening.set(false);
|
|
339
|
+
isKeyboardOpen.set(false);
|
|
340
|
+
keyboardHeight.set(0);
|
|
341
|
+
if (!horizontal) {
|
|
342
|
+
keyboardInset.set(0);
|
|
343
|
+
reactNativeReanimated.runOnJS(reportContentInset)(0);
|
|
344
|
+
reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(0);
|
|
345
|
+
}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (vMode === "running") {
|
|
349
|
+
const progress = clampProgress(event.progress);
|
|
350
|
+
const vEffectiveKeyboardHeight = getEffectiveKeyboardHeightFromInset(keyboardHeight.get());
|
|
351
|
+
const vIsOpening = isOpening.get();
|
|
352
|
+
if (!wasInteractive) {
|
|
353
|
+
const targetOffset = calculateKeyboardTargetOffset(
|
|
354
|
+
scrollOffsetAtKeyboardStart.get(),
|
|
355
|
+
vEffectiveKeyboardHeight,
|
|
356
|
+
vIsOpening,
|
|
357
|
+
progress
|
|
358
|
+
);
|
|
359
|
+
scrollOffsetY.set(targetOffset);
|
|
360
|
+
animatedOffsetY.set(targetOffset);
|
|
361
|
+
}
|
|
362
|
+
reactNativeReanimated.runOnJS(setScrollProcessingEnabled)(true);
|
|
363
|
+
didInteractive.set(false);
|
|
364
|
+
isKeyboardOpen.set(event.height > 0);
|
|
365
|
+
if (event.height > 0) {
|
|
366
|
+
keyboardHeight.set(calculateKeyboardInset(event.height, safeAreaInsetBottom));
|
|
367
|
+
}
|
|
368
|
+
if (!horizontal) {
|
|
369
|
+
const newInset = calculateKeyboardInset(event.height, safeAreaInsetBottom);
|
|
370
|
+
keyboardInset.set(newInset);
|
|
371
|
+
reactNativeReanimated.runOnJS(reportContentInset)(newInset);
|
|
372
|
+
if (!vIsOpening) {
|
|
373
|
+
reactNativeReanimated.runOnJS(updateAlignItemsAtEndMinSize)(newInset);
|
|
374
|
+
}
|
|
375
|
+
if (newInset <= 0) {
|
|
376
|
+
animatedOffsetY.set(scrollOffsetY.get());
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
[
|
|
383
|
+
alignItemsAtEnd,
|
|
384
|
+
clearAlignItemsAtEndMinSize,
|
|
385
|
+
getEffectiveKeyboardHeightFromEvent,
|
|
386
|
+
getEffectiveKeyboardHeightFromInset,
|
|
387
|
+
horizontal,
|
|
388
|
+
isAndroid,
|
|
389
|
+
isIos,
|
|
390
|
+
reportContentInset,
|
|
391
|
+
safeAreaInsetBottom,
|
|
392
|
+
setScrollProcessingEnabled,
|
|
393
|
+
updateAlignItemsAtEndMinSize
|
|
394
|
+
]
|
|
395
|
+
);
|
|
396
|
+
const animatedProps = reactNativeReanimated.useAnimatedProps(() => {
|
|
397
|
+
"worklet";
|
|
398
|
+
var _a, _b, _c, _d;
|
|
399
|
+
const vAnimatedOffsetY = animatedOffsetY.get();
|
|
400
|
+
const baseProps = {
|
|
401
|
+
contentOffset: vAnimatedOffsetY === null ? void 0 : {
|
|
402
|
+
x: 0,
|
|
403
|
+
y: vAnimatedOffsetY
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
if (isIos) {
|
|
407
|
+
const keyboardInsetBottom = keyboardInset.get();
|
|
408
|
+
const contentInset = {
|
|
409
|
+
bottom: ((_a = contentInsetProp == null ? void 0 : contentInsetProp.bottom) != null ? _a : 0) + (horizontal ? 0 : keyboardInsetBottom),
|
|
410
|
+
left: (_b = contentInsetProp == null ? void 0 : contentInsetProp.left) != null ? _b : 0,
|
|
411
|
+
right: (_c = contentInsetProp == null ? void 0 : contentInsetProp.right) != null ? _c : 0,
|
|
412
|
+
top: (_d = contentInsetProp == null ? void 0 : contentInsetProp.top) != null ? _d : 0
|
|
413
|
+
};
|
|
414
|
+
return Object.assign(baseProps, {
|
|
415
|
+
contentInset
|
|
416
|
+
});
|
|
417
|
+
} else {
|
|
418
|
+
return baseProps;
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
const androidAnimatedStyle = reactNativeReanimated.useAnimatedStyle(
|
|
422
|
+
() => ({
|
|
423
|
+
...styleFlattened || {},
|
|
424
|
+
marginBottom: keyboardInset.get()
|
|
425
|
+
}),
|
|
426
|
+
[styleProp, keyboardInset]
|
|
427
|
+
);
|
|
428
|
+
const style = isAndroid ? androidAnimatedStyle : styleProp;
|
|
429
|
+
const contentContainerStyle = React.useMemo(() => {
|
|
430
|
+
if (alignItemsAtEndMinSize === void 0) {
|
|
431
|
+
return contentContainerStyleProp;
|
|
432
|
+
}
|
|
433
|
+
const minSizeStyle = horizontal ? { minWidth: alignItemsAtEndMinSize } : { minHeight: alignItemsAtEndMinSize };
|
|
434
|
+
return contentContainerStyleProp ? [contentContainerStyleProp, minSizeStyle] : minSizeStyle;
|
|
435
|
+
}, [alignItemsAtEndMinSize, contentContainerStyleProp, horizontal]);
|
|
436
|
+
return /* @__PURE__ */ React__namespace.createElement(
|
|
437
|
+
reanimated.AnimatedLegendList,
|
|
438
|
+
{
|
|
439
|
+
...rest,
|
|
440
|
+
animatedProps,
|
|
441
|
+
automaticallyAdjustContentInsets: false,
|
|
442
|
+
contentContainerStyle,
|
|
443
|
+
keyboardDismissMode: "interactive",
|
|
444
|
+
onContentSizeChange: handleContentSizeChange,
|
|
445
|
+
onLayout: handleLayout,
|
|
446
|
+
onMetricsChange: handleMetricsChange,
|
|
447
|
+
onScroll: finalScrollHandler,
|
|
448
|
+
ref: combinedRef,
|
|
449
|
+
refScrollView: scrollViewRef,
|
|
450
|
+
scrollIndicatorInsets: { bottom: 0, top: 0 },
|
|
451
|
+
style
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
exports.KeyboardAvoidingLegendList = KeyboardAvoidingLegendList;
|