@rific/scroll-view 1.0.0 → 1.1.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/README.md +2 -0
- package/dist/index.js +21 -12
- package/dist/index.mjs +15 -6
- package/package.json +3 -3
- package/src/PullSearch.tsx +3 -1
- package/src/internal/useScrollHandler.ts +7 -2
- package/src/internal/useStickyHeaders.ts +3 -1
- package/src/useKeyboardInset.ts +4 -2
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Blur-chrome scroll system for React Native. Drop-in replacements for `ScrollView`, `FlatList`, and `SectionList` with floating headers and footers, pull-to-search, keyboard awareness, horizontal paging, and frosted-glass chrome.
|
|
4
4
|
|
|
5
|
+
**[Live demo](https://rific.jaydeaton.com/demos/scroll-view)**
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```sh
|
package/dist/index.js
CHANGED
|
@@ -90,6 +90,7 @@ var styles = import_react_native2.StyleSheet.create({
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
// src/internal/useScrollHandler.ts
|
|
93
|
+
var import_core = require("@rific/core");
|
|
93
94
|
var import_react3 = require("react");
|
|
94
95
|
var import_react_native_reanimated3 = require("react-native-reanimated");
|
|
95
96
|
|
|
@@ -338,6 +339,8 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
338
339
|
const { chromeHosted, chromeWritable, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared, stackHeightShared } = (0, import_react3.useContext)(ScrollViewContext);
|
|
339
340
|
const snapUpAccum = (0, import_react_native_reanimated3.useSharedValue)(0);
|
|
340
341
|
const fromBottomBounce = (0, import_react_native_reanimated3.useSharedValue)(false);
|
|
342
|
+
const remountSyncedKey = (0, import_core.useWorkletCallback)((y) => onRemountSynced?.(y));
|
|
343
|
+
const remountSyncRetryKey = (0, import_core.useWorkletCallback)((y) => onRemountSyncRetry?.(y));
|
|
341
344
|
return (0, import_react_native_reanimated3.useAnimatedScrollHandler)(
|
|
342
345
|
{
|
|
343
346
|
onScroll: ({ contentOffset: { x, y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
|
|
@@ -346,9 +349,9 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
346
349
|
const target = remountSyncTarget.value;
|
|
347
350
|
if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
|
|
348
351
|
remountSyncTarget.value = null;
|
|
349
|
-
if (onRemountSynced) (0, import_react_native_reanimated3.runOnJS)(
|
|
352
|
+
if (onRemountSynced) (0, import_react_native_reanimated3.runOnJS)(import_core.callWorkletCallback)(remountSyncedKey, y);
|
|
350
353
|
} else if (onRemountSyncRetry) {
|
|
351
|
-
(0, import_react_native_reanimated3.runOnJS)(
|
|
354
|
+
(0, import_react_native_reanimated3.runOnJS)(import_core.callWorkletCallback)(remountSyncRetryKey, y);
|
|
352
355
|
}
|
|
353
356
|
return;
|
|
354
357
|
}
|
|
@@ -432,21 +435,23 @@ var import_react_native_reanimated5 = require("react-native-reanimated");
|
|
|
432
435
|
var import_react_native_safe_area_context = require("react-native-safe-area-context");
|
|
433
436
|
|
|
434
437
|
// src/useKeyboardInset.ts
|
|
438
|
+
var import_core2 = require("@rific/core");
|
|
435
439
|
var import_react4 = require("react");
|
|
436
440
|
var import_react_native4 = require("react-native");
|
|
437
441
|
var import_react_native_keyboard_controller = require("react-native-keyboard-controller");
|
|
438
442
|
var import_react_native_reanimated4 = require("react-native-reanimated");
|
|
439
443
|
var useKeyboardInsetNative = () => {
|
|
440
444
|
const [keyboardHeight, setKeyboardHeight] = (0, import_react4.useState)(0);
|
|
445
|
+
const keyboardHeightKey = (0, import_core2.useWorkletCallback)(setKeyboardHeight);
|
|
441
446
|
(0, import_react_native_keyboard_controller.useKeyboardHandler)(
|
|
442
447
|
{
|
|
443
448
|
onMove: (e) => {
|
|
444
449
|
"worklet";
|
|
445
|
-
(0, import_react_native_reanimated4.runOnJS)(
|
|
450
|
+
(0, import_react_native_reanimated4.runOnJS)(import_core2.callWorkletCallback)(keyboardHeightKey, e.height);
|
|
446
451
|
},
|
|
447
452
|
onEnd: (e) => {
|
|
448
453
|
"worklet";
|
|
449
|
-
(0, import_react_native_reanimated4.runOnJS)(
|
|
454
|
+
(0, import_react_native_reanimated4.runOnJS)(import_core2.callWorkletCallback)(keyboardHeightKey, e.height);
|
|
450
455
|
}
|
|
451
456
|
},
|
|
452
457
|
[]
|
|
@@ -929,6 +934,7 @@ var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", r
|
|
|
929
934
|
var FlatList = (0, import_react9.memo)(FlatListInner);
|
|
930
935
|
|
|
931
936
|
// src/PullSearch.tsx
|
|
937
|
+
var import_core3 = require("@rific/core");
|
|
932
938
|
var import_react10 = require("react");
|
|
933
939
|
var import_react_native9 = require("react-native");
|
|
934
940
|
var import_react_native_paper3 = require("react-native-paper");
|
|
@@ -951,13 +957,14 @@ var PullSearch = (0, import_react10.forwardRef)(function PullSearch2({ debounce,
|
|
|
951
957
|
focus: () => inputRef.current?.focus()
|
|
952
958
|
}));
|
|
953
959
|
const blurInput = (0, import_react10.useCallback)(() => inputRef.current?.blur(), []);
|
|
960
|
+
const blurKey = (0, import_core3.useWorkletCallback)(blurInput);
|
|
954
961
|
(0, import_react_native_reanimated9.useAnimatedReaction)(
|
|
955
962
|
() => {
|
|
956
963
|
if (barHeight === 0) return false;
|
|
957
964
|
return scrollPosition.value >= -(headerHeight ?? 0) + barHeight;
|
|
958
965
|
},
|
|
959
966
|
(isHidden, wasHidden) => {
|
|
960
|
-
if (isHidden && !wasHidden) (0, import_react_native_reanimated9.runOnJS)(
|
|
967
|
+
if (isHidden && !wasHidden) (0, import_react_native_reanimated9.runOnJS)(import_core3.callWorkletCallback)(blurKey);
|
|
961
968
|
},
|
|
962
969
|
// scrollPosition has to be listed too, not just read - see useStickyHeaders' useAnimatedReaction
|
|
963
970
|
// for why: on web, without reanimated's Babel plugin active, an unlisted SharedValue mutation
|
|
@@ -1003,23 +1010,23 @@ var styles5 = import_react_native9.StyleSheet.create({
|
|
|
1003
1010
|
});
|
|
1004
1011
|
|
|
1005
1012
|
// src/redux/scrollViewSlice.ts
|
|
1006
|
-
var
|
|
1013
|
+
var import_core5 = require("@rific/core");
|
|
1007
1014
|
|
|
1008
1015
|
// src/ScrollViewSettingsContext.ts
|
|
1009
|
-
var
|
|
1016
|
+
var import_core4 = require("@rific/core");
|
|
1010
1017
|
var defaultScrollViewSettings = {
|
|
1011
1018
|
backActionFixed: true,
|
|
1012
1019
|
footerFixed: false,
|
|
1013
1020
|
headerFixed: false,
|
|
1014
1021
|
snapBack: false
|
|
1015
1022
|
};
|
|
1016
|
-
var settingsContext = (0,
|
|
1023
|
+
var settingsContext = (0, import_core4.createSettingsContext)(defaultScrollViewSettings);
|
|
1017
1024
|
var ScrollViewSettingsContext = settingsContext.Context;
|
|
1018
1025
|
var scrollViewSettingsProvider = settingsContext.Provider;
|
|
1019
1026
|
var scrollViewUseSettings = settingsContext.useSettings;
|
|
1020
1027
|
|
|
1021
1028
|
// src/redux/scrollViewSlice.ts
|
|
1022
|
-
var scrollViewSlice = (0,
|
|
1029
|
+
var scrollViewSlice = (0, import_core5.createSettingsSlice)("scrollView", {
|
|
1023
1030
|
initialState: defaultScrollViewSettings,
|
|
1024
1031
|
fieldSetters: []
|
|
1025
1032
|
});
|
|
@@ -1135,8 +1142,8 @@ var ScrollViewChromeProvider = ({ children, footprint, overhang = 0, snapBack =
|
|
|
1135
1142
|
};
|
|
1136
1143
|
|
|
1137
1144
|
// src/ScrollViewConfig.tsx
|
|
1138
|
-
var
|
|
1139
|
-
var scrollViewConfig = (0,
|
|
1145
|
+
var import_core6 = require("@rific/core");
|
|
1146
|
+
var scrollViewConfig = (0, import_core6.createModuleConfig)();
|
|
1140
1147
|
var configureScrollView = scrollViewConfig.configure;
|
|
1141
1148
|
var getScrollViewConfig = scrollViewConfig.getConfig;
|
|
1142
1149
|
var ScrollViewConfigProvider = scrollViewConfig.Provider;
|
|
@@ -1453,6 +1460,7 @@ var import_react_native_gesture_handler4 = require("react-native-gesture-handler
|
|
|
1453
1460
|
var import_react_native_reanimated16 = __toESM(require("react-native-reanimated"));
|
|
1454
1461
|
|
|
1455
1462
|
// src/internal/useStickyHeaders.ts
|
|
1463
|
+
var import_core7 = require("@rific/core");
|
|
1456
1464
|
var import_react18 = require("react");
|
|
1457
1465
|
var import_react_native_reanimated15 = require("react-native-reanimated");
|
|
1458
1466
|
var import_react_native_safe_area_context5 = require("react-native-safe-area-context");
|
|
@@ -1462,6 +1470,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1462
1470
|
const sectionYPositions = (0, import_react_native_reanimated15.useSharedValue)([]);
|
|
1463
1471
|
const sectionHeights = (0, import_react_native_reanimated15.useSharedValue)([]);
|
|
1464
1472
|
const [activeIndex, setActiveIndex] = (0, import_react18.useState)(-1);
|
|
1473
|
+
const activeIndexKey = (0, import_core7.useWorkletCallback)(setActiveIndex);
|
|
1465
1474
|
const contentIndexShared = (0, import_react_native_reanimated15.useSharedValue)(-1);
|
|
1466
1475
|
(0, import_react18.useLayoutEffect)(() => {
|
|
1467
1476
|
contentIndexShared.value = activeIndex;
|
|
@@ -1493,7 +1502,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1493
1502
|
return active;
|
|
1494
1503
|
},
|
|
1495
1504
|
(curr, prev) => {
|
|
1496
|
-
if (curr !== prev) (0, import_react_native_reanimated15.runOnJS)(
|
|
1505
|
+
if (curr !== prev) (0, import_react_native_reanimated15.runOnJS)(import_core7.callWorkletCallback)(activeIndexKey, curr);
|
|
1497
1506
|
},
|
|
1498
1507
|
// Same web-only reanimated gap as useAnimatedStyle elsewhere in this file: this "prepare"
|
|
1499
1508
|
// function's own SharedValue reads (sectionYPositions, headerHeightShared, scrollPosition,
|
package/dist/index.mjs
CHANGED
|
@@ -31,6 +31,7 @@ var styles = StyleSheet.create({
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
// src/internal/useScrollHandler.ts
|
|
34
|
+
import { callWorkletCallback, useWorkletCallback } from "@rific/core";
|
|
34
35
|
import { useContext as useContext2 } from "react";
|
|
35
36
|
import { runOnJS, useAnimatedScrollHandler, useSharedValue as useSharedValue2, withTiming } from "react-native-reanimated";
|
|
36
37
|
|
|
@@ -279,6 +280,8 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
279
280
|
const { chromeHosted, chromeWritable, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared, stackHeightShared } = useContext2(ScrollViewContext);
|
|
280
281
|
const snapUpAccum = useSharedValue2(0);
|
|
281
282
|
const fromBottomBounce = useSharedValue2(false);
|
|
283
|
+
const remountSyncedKey = useWorkletCallback((y) => onRemountSynced?.(y));
|
|
284
|
+
const remountSyncRetryKey = useWorkletCallback((y) => onRemountSyncRetry?.(y));
|
|
282
285
|
return useAnimatedScrollHandler(
|
|
283
286
|
{
|
|
284
287
|
onScroll: ({ contentOffset: { x, y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
|
|
@@ -287,9 +290,9 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
287
290
|
const target = remountSyncTarget.value;
|
|
288
291
|
if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
|
|
289
292
|
remountSyncTarget.value = null;
|
|
290
|
-
if (onRemountSynced) runOnJS(
|
|
293
|
+
if (onRemountSynced) runOnJS(callWorkletCallback)(remountSyncedKey, y);
|
|
291
294
|
} else if (onRemountSyncRetry) {
|
|
292
|
-
runOnJS(
|
|
295
|
+
runOnJS(callWorkletCallback)(remountSyncRetryKey, y);
|
|
293
296
|
}
|
|
294
297
|
return;
|
|
295
298
|
}
|
|
@@ -373,21 +376,23 @@ import { useAnimatedStyle, useSharedValue as useSharedValue3, withTiming as with
|
|
|
373
376
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
374
377
|
|
|
375
378
|
// src/useKeyboardInset.ts
|
|
379
|
+
import { callWorkletCallback as callWorkletCallback2, useWorkletCallback as useWorkletCallback2 } from "@rific/core";
|
|
376
380
|
import { useState as useState2 } from "react";
|
|
377
381
|
import { Platform as Platform2 } from "react-native";
|
|
378
382
|
import { useKeyboardHandler } from "react-native-keyboard-controller";
|
|
379
383
|
import { runOnJS as runOnJS2 } from "react-native-reanimated";
|
|
380
384
|
var useKeyboardInsetNative = () => {
|
|
381
385
|
const [keyboardHeight, setKeyboardHeight] = useState2(0);
|
|
386
|
+
const keyboardHeightKey = useWorkletCallback2(setKeyboardHeight);
|
|
382
387
|
useKeyboardHandler(
|
|
383
388
|
{
|
|
384
389
|
onMove: (e) => {
|
|
385
390
|
"worklet";
|
|
386
|
-
runOnJS2(
|
|
391
|
+
runOnJS2(callWorkletCallback2)(keyboardHeightKey, e.height);
|
|
387
392
|
},
|
|
388
393
|
onEnd: (e) => {
|
|
389
394
|
"worklet";
|
|
390
|
-
runOnJS2(
|
|
395
|
+
runOnJS2(callWorkletCallback2)(keyboardHeightKey, e.height);
|
|
391
396
|
}
|
|
392
397
|
},
|
|
393
398
|
[]
|
|
@@ -870,6 +875,7 @@ var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", r
|
|
|
870
875
|
var FlatList = memo2(FlatListInner);
|
|
871
876
|
|
|
872
877
|
// src/PullSearch.tsx
|
|
878
|
+
import { callWorkletCallback as callWorkletCallback3, useWorkletCallback as useWorkletCallback3 } from "@rific/core";
|
|
873
879
|
import { forwardRef, useCallback as useCallback5, useContext as useContext8, useEffect as useEffect3, useImperativeHandle, useRef as useRef5, useState as useState4 } from "react";
|
|
874
880
|
import { StyleSheet as StyleSheet4 } from "react-native";
|
|
875
881
|
import { Searchbar, useTheme as useTheme3 } from "react-native-paper";
|
|
@@ -892,13 +898,14 @@ var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHei
|
|
|
892
898
|
focus: () => inputRef.current?.focus()
|
|
893
899
|
}));
|
|
894
900
|
const blurInput = useCallback5(() => inputRef.current?.blur(), []);
|
|
901
|
+
const blurKey = useWorkletCallback3(blurInput);
|
|
895
902
|
useAnimatedReaction(
|
|
896
903
|
() => {
|
|
897
904
|
if (barHeight === 0) return false;
|
|
898
905
|
return scrollPosition.value >= -(headerHeight ?? 0) + barHeight;
|
|
899
906
|
},
|
|
900
907
|
(isHidden, wasHidden) => {
|
|
901
|
-
if (isHidden && !wasHidden) runOnJS3(
|
|
908
|
+
if (isHidden && !wasHidden) runOnJS3(callWorkletCallback3)(blurKey);
|
|
902
909
|
},
|
|
903
910
|
// scrollPosition has to be listed too, not just read - see useStickyHeaders' useAnimatedReaction
|
|
904
911
|
// for why: on web, without reanimated's Babel plugin active, an unlisted SharedValue mutation
|
|
@@ -1394,6 +1401,7 @@ import { Gesture as Gesture4, GestureDetector as GestureDetector4 } from "react-
|
|
|
1394
1401
|
import Animated7, { runOnUI as runOnUI3, useSharedValue as useSharedValue10 } from "react-native-reanimated";
|
|
1395
1402
|
|
|
1396
1403
|
// src/internal/useStickyHeaders.ts
|
|
1404
|
+
import { callWorkletCallback as callWorkletCallback4, useWorkletCallback as useWorkletCallback4 } from "@rific/core";
|
|
1397
1405
|
import { useCallback as useCallback9, useContext as useContext13, useLayoutEffect as useLayoutEffect8, useRef as useRef10, useState as useState7 } from "react";
|
|
1398
1406
|
import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as useSharedValue9 } from "react-native-reanimated";
|
|
1399
1407
|
import { useSafeAreaInsets as useSafeAreaInsets5 } from "react-native-safe-area-context";
|
|
@@ -1403,6 +1411,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1403
1411
|
const sectionYPositions = useSharedValue9([]);
|
|
1404
1412
|
const sectionHeights = useSharedValue9([]);
|
|
1405
1413
|
const [activeIndex, setActiveIndex] = useState7(-1);
|
|
1414
|
+
const activeIndexKey = useWorkletCallback4(setActiveIndex);
|
|
1406
1415
|
const contentIndexShared = useSharedValue9(-1);
|
|
1407
1416
|
useLayoutEffect8(() => {
|
|
1408
1417
|
contentIndexShared.value = activeIndex;
|
|
@@ -1434,7 +1443,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1434
1443
|
return active;
|
|
1435
1444
|
},
|
|
1436
1445
|
(curr, prev) => {
|
|
1437
|
-
if (curr !== prev) runOnJS4(
|
|
1446
|
+
if (curr !== prev) runOnJS4(callWorkletCallback4)(activeIndexKey, curr);
|
|
1438
1447
|
},
|
|
1439
1448
|
// Same web-only reanimated gap as useAnimatedStyle elsewhere in this file: this "prepare"
|
|
1440
1449
|
// function's own SharedValue reads (sectionYPositions, headerHeightShared, scrollPosition,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rific/scroll-view",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Blur styled scroll system for React Native. Floating headers/footers, keyboard awareness, and scroll-away chrome",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@infinitetoken/tsconfig": "^0.6.0",
|
|
67
67
|
"@reduxjs/toolkit": "^2.12.0",
|
|
68
68
|
"@rific/auto-paper": "^0.13.3",
|
|
69
|
-
"@rific/core": "^0.
|
|
69
|
+
"@rific/core": "^0.5.0",
|
|
70
70
|
"@testing-library/dom": "^10.4.1",
|
|
71
71
|
"@testing-library/react": "^16.3.2",
|
|
72
72
|
"@types/jest": "^30.0.0",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
94
|
"@rific/auto-paper": ">=0.10.0",
|
|
95
|
-
"@rific/core": ">=0.
|
|
95
|
+
"@rific/core": ">=0.5.0",
|
|
96
96
|
"react": ">=19.0.0",
|
|
97
97
|
"react-native": ">=0.83.0",
|
|
98
98
|
"react-native-gesture-handler": ">=2.0.0 <4.0.0",
|
package/src/PullSearch.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { callWorkletCallback, useWorkletCallback } from '@rific/core'
|
|
1
2
|
import { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react'
|
|
2
3
|
import { type LayoutChangeEvent, StyleSheet, type TextInput } from 'react-native'
|
|
3
4
|
import { Searchbar, useTheme } from 'react-native-paper'
|
|
@@ -38,6 +39,7 @@ export const PullSearch = forwardRef<PullSearchHandle, PullSearchProps>(function
|
|
|
38
39
|
}))
|
|
39
40
|
|
|
40
41
|
const blurInput = useCallback(() => inputRef.current?.blur(), [])
|
|
42
|
+
const blurKey = useWorkletCallback(blurInput)
|
|
41
43
|
|
|
42
44
|
useAnimatedReaction(
|
|
43
45
|
() => {
|
|
@@ -45,7 +47,7 @@ export const PullSearch = forwardRef<PullSearchHandle, PullSearchProps>(function
|
|
|
45
47
|
return scrollPosition.value >= -(headerHeight ?? 0) + barHeight
|
|
46
48
|
},
|
|
47
49
|
(isHidden, wasHidden) => {
|
|
48
|
-
if (isHidden && !wasHidden) runOnJS(
|
|
50
|
+
if (isHidden && !wasHidden) runOnJS(callWorkletCallback)(blurKey)
|
|
49
51
|
},
|
|
50
52
|
// scrollPosition has to be listed too, not just read - see useStickyHeaders' useAnimatedReaction
|
|
51
53
|
// for why: on web, without reanimated's Babel plugin active, an unlisted SharedValue mutation
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { callWorkletCallback, useWorkletCallback } from '@rific/core'
|
|
1
2
|
import { useContext } from 'react'
|
|
2
3
|
import type { SharedValue } from 'react-native-reanimated'
|
|
3
4
|
import { runOnJS, useAnimatedScrollHandler, useSharedValue, withTiming } from 'react-native-reanimated'
|
|
@@ -24,6 +25,10 @@ export function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold
|
|
|
24
25
|
const { chromeHosted, chromeWritable, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared, stackHeightShared } = useContext(ScrollViewContext)
|
|
25
26
|
const snapUpAccum = useSharedValue(0)
|
|
26
27
|
const fromBottomBounce = useSharedValue(false)
|
|
28
|
+
// Worklets never get the consumer's callbacks themselves: react-native-worklets holds a runOnJS target natively for as
|
|
29
|
+
// long as the worklet lives, which pinned the list. They call the module-level callWorkletCallback by key.
|
|
30
|
+
const remountSyncedKey = useWorkletCallback((y: number) => onRemountSynced?.(y))
|
|
31
|
+
const remountSyncRetryKey = useWorkletCallback((y: number) => onRemountSyncRetry?.(y))
|
|
27
32
|
|
|
28
33
|
return useAnimatedScrollHandler(
|
|
29
34
|
{
|
|
@@ -33,9 +38,9 @@ export function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold
|
|
|
33
38
|
const target = remountSyncTarget.value
|
|
34
39
|
if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
|
|
35
40
|
remountSyncTarget.value = null
|
|
36
|
-
if (onRemountSynced) runOnJS(
|
|
41
|
+
if (onRemountSynced) runOnJS(callWorkletCallback)(remountSyncedKey, y)
|
|
37
42
|
} else if (onRemountSyncRetry) {
|
|
38
|
-
runOnJS(
|
|
43
|
+
runOnJS(callWorkletCallback)(remountSyncRetryKey, y)
|
|
39
44
|
}
|
|
40
45
|
return
|
|
41
46
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { callWorkletCallback, useWorkletCallback } from '@rific/core'
|
|
1
2
|
import { useCallback, useContext, useLayoutEffect, useRef, useState } from 'react'
|
|
2
3
|
import { runOnJS, useAnimatedReaction, useAnimatedStyle, useSharedValue } from 'react-native-reanimated'
|
|
3
4
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
@@ -19,6 +20,7 @@ export function useStickyHeaders(headerFixed: boolean, enabled: boolean): Sticky
|
|
|
19
20
|
const sectionYPositions = useSharedValue<number[]>([])
|
|
20
21
|
const sectionHeights = useSharedValue<number[]>([])
|
|
21
22
|
const [activeIndex, setActiveIndex] = useState(-1)
|
|
23
|
+
const activeIndexKey = useWorkletCallback(setActiveIndex)
|
|
22
24
|
// Mirrors activeIndex React state but lives on the UI thread for overlayStyle.
|
|
23
25
|
// Updated via useLayoutEffect so content and style always change together.
|
|
24
26
|
const contentIndexShared = useSharedValue(-1)
|
|
@@ -60,7 +62,7 @@ export function useStickyHeaders(headerFixed: boolean, enabled: boolean): Sticky
|
|
|
60
62
|
return active
|
|
61
63
|
},
|
|
62
64
|
(curr, prev) => {
|
|
63
|
-
if (curr !== prev) runOnJS(
|
|
65
|
+
if (curr !== prev) runOnJS(callWorkletCallback)(activeIndexKey, curr)
|
|
64
66
|
},
|
|
65
67
|
// Same web-only reanimated gap as useAnimatedStyle elsewhere in this file: this "prepare"
|
|
66
68
|
// function's own SharedValue reads (sectionYPositions, headerHeightShared, scrollPosition,
|
package/src/useKeyboardInset.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { callWorkletCallback, useWorkletCallback } from '@rific/core'
|
|
1
2
|
import { useState } from 'react'
|
|
2
3
|
import { Platform } from 'react-native'
|
|
3
4
|
import { useKeyboardHandler } from 'react-native-keyboard-controller'
|
|
@@ -5,15 +6,16 @@ import { runOnJS } from 'react-native-reanimated'
|
|
|
5
6
|
|
|
6
7
|
const useKeyboardInsetNative = () => {
|
|
7
8
|
const [keyboardHeight, setKeyboardHeight] = useState(0)
|
|
9
|
+
const keyboardHeightKey = useWorkletCallback(setKeyboardHeight)
|
|
8
10
|
useKeyboardHandler(
|
|
9
11
|
{
|
|
10
12
|
onMove: (e) => {
|
|
11
13
|
'worklet'
|
|
12
|
-
runOnJS(
|
|
14
|
+
runOnJS(callWorkletCallback)(keyboardHeightKey, e.height)
|
|
13
15
|
},
|
|
14
16
|
onEnd: (e) => {
|
|
15
17
|
'worklet'
|
|
16
|
-
runOnJS(
|
|
18
|
+
runOnJS(callWorkletCallback)(keyboardHeightKey, e.height)
|
|
17
19
|
}
|
|
18
20
|
},
|
|
19
21
|
[]
|