@rific/scroll-view 1.0.0 → 1.1.1
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 +100 -88
- package/dist/index.mjs +22 -10
- package/package.json +5 -4
- package/src/PullSearch.tsx +5 -2
- package/src/internal/useScrollHandler.ts +9 -3
- package/src/internal/useStickyHeaders.ts +5 -2
- package/src/useKeyboardInset.ts +5 -3
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
|
@@ -61,7 +61,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
61
61
|
var import_react6 = require("react");
|
|
62
62
|
var import_react_native6 = require("react-native");
|
|
63
63
|
var import_react_native_gesture_handler = require("react-native-gesture-handler");
|
|
64
|
-
var
|
|
64
|
+
var import_react_native_reanimated5 = require("react-native-reanimated");
|
|
65
65
|
|
|
66
66
|
// src/internal/RefreshControl.tsx
|
|
67
67
|
var import_react_native = require("react-native");
|
|
@@ -90,8 +90,10 @@ 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");
|
|
96
|
+
var import_react_native_worklets = require("react-native-worklets");
|
|
95
97
|
|
|
96
98
|
// src/ScrollViewContext.ts
|
|
97
99
|
var import_react = require("react");
|
|
@@ -338,6 +340,8 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
338
340
|
const { chromeHosted, chromeWritable, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared, stackHeightShared } = (0, import_react3.useContext)(ScrollViewContext);
|
|
339
341
|
const snapUpAccum = (0, import_react_native_reanimated3.useSharedValue)(0);
|
|
340
342
|
const fromBottomBounce = (0, import_react_native_reanimated3.useSharedValue)(false);
|
|
343
|
+
const remountSyncedKey = (0, import_core.useWorkletCallback)((y) => onRemountSynced?.(y));
|
|
344
|
+
const remountSyncRetryKey = (0, import_core.useWorkletCallback)((y) => onRemountSyncRetry?.(y));
|
|
341
345
|
return (0, import_react_native_reanimated3.useAnimatedScrollHandler)(
|
|
342
346
|
{
|
|
343
347
|
onScroll: ({ contentOffset: { x, y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
|
|
@@ -346,9 +350,9 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
346
350
|
const target = remountSyncTarget.value;
|
|
347
351
|
if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
|
|
348
352
|
remountSyncTarget.value = null;
|
|
349
|
-
if (onRemountSynced) (0,
|
|
353
|
+
if (onRemountSynced) (0, import_react_native_worklets.scheduleOnRN)(import_core.callWorkletCallback, remountSyncedKey, y);
|
|
350
354
|
} else if (onRemountSyncRetry) {
|
|
351
|
-
(0,
|
|
355
|
+
(0, import_react_native_worklets.scheduleOnRN)(import_core.callWorkletCallback, remountSyncRetryKey, y);
|
|
352
356
|
}
|
|
353
357
|
return;
|
|
354
358
|
}
|
|
@@ -428,25 +432,27 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
428
432
|
// src/internal/useScrollList.ts
|
|
429
433
|
var import_react5 = require("react");
|
|
430
434
|
var import_react_native5 = require("react-native");
|
|
431
|
-
var
|
|
435
|
+
var import_react_native_reanimated4 = require("react-native-reanimated");
|
|
432
436
|
var import_react_native_safe_area_context = require("react-native-safe-area-context");
|
|
433
437
|
|
|
434
438
|
// src/useKeyboardInset.ts
|
|
439
|
+
var import_core2 = require("@rific/core");
|
|
435
440
|
var import_react4 = require("react");
|
|
436
441
|
var import_react_native4 = require("react-native");
|
|
437
442
|
var import_react_native_keyboard_controller = require("react-native-keyboard-controller");
|
|
438
|
-
var
|
|
443
|
+
var import_react_native_worklets2 = require("react-native-worklets");
|
|
439
444
|
var useKeyboardInsetNative = () => {
|
|
440
445
|
const [keyboardHeight, setKeyboardHeight] = (0, import_react4.useState)(0);
|
|
446
|
+
const keyboardHeightKey = (0, import_core2.useWorkletCallback)(setKeyboardHeight);
|
|
441
447
|
(0, import_react_native_keyboard_controller.useKeyboardHandler)(
|
|
442
448
|
{
|
|
443
449
|
onMove: (e) => {
|
|
444
450
|
"worklet";
|
|
445
|
-
(0,
|
|
451
|
+
(0, import_react_native_worklets2.scheduleOnRN)(import_core2.callWorkletCallback, keyboardHeightKey, e.height);
|
|
446
452
|
},
|
|
447
453
|
onEnd: (e) => {
|
|
448
454
|
"worklet";
|
|
449
|
-
(0,
|
|
455
|
+
(0, import_react_native_worklets2.scheduleOnRN)(import_core2.callWorkletCallback, keyboardHeightKey, e.height);
|
|
450
456
|
}
|
|
451
457
|
},
|
|
452
458
|
[]
|
|
@@ -482,25 +488,25 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
482
488
|
const [startedWithHeader] = (0, import_react5.useState)(headerHeight !== null);
|
|
483
489
|
const insetContentOffset = (0, import_react5.useMemo)(() => ({ x: 0, y: headerHeight !== null ? -headerHeight + (startedWithHeader && !isHorizontal && pullSearchHeight ? pullSearchHeight : 0) : 0 }), [headerHeight, isHorizontal, pullSearchHeight, startedWithHeader]);
|
|
484
490
|
const contentOffset = usesContentInset ? insetContentOffset : ZERO_OFFSET;
|
|
485
|
-
const chipHidden = (0,
|
|
486
|
-
const chipStyle = (0,
|
|
491
|
+
const chipHidden = (0, import_react_native_reanimated4.useSharedValue)(1);
|
|
492
|
+
const chipStyle = (0, import_react_native_reanimated4.useAnimatedStyle)(() => {
|
|
487
493
|
const pointerEvents = chipHidden.value ? "none" : "box-none";
|
|
488
494
|
if (isHorizontal) {
|
|
489
495
|
return {
|
|
490
|
-
opacity: chipHidden.value ? (0,
|
|
496
|
+
opacity: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(0) : (0, import_react_native_reanimated4.withTiming)(1),
|
|
491
497
|
pointerEvents,
|
|
492
498
|
top: Math.max(headerHeightShared.value, insets.top) + 4,
|
|
493
|
-
transform: [{ translateX: chipHidden.value ? (0,
|
|
499
|
+
transform: [{ translateX: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated4.withTiming)(0) }]
|
|
494
500
|
};
|
|
495
501
|
}
|
|
496
502
|
const h = headerHeightShared.value;
|
|
497
503
|
const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
498
504
|
const top = Math.max(h - slide, insets.top) + 4;
|
|
499
505
|
return {
|
|
500
|
-
opacity: chipHidden.value ? (0,
|
|
506
|
+
opacity: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(0) : (0, import_react_native_reanimated4.withTiming)(1),
|
|
501
507
|
pointerEvents,
|
|
502
508
|
top,
|
|
503
|
-
transform: [{ translateY: chipHidden.value ? (0,
|
|
509
|
+
transform: [{ translateY: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated4.withTiming)(0) }]
|
|
504
510
|
};
|
|
505
511
|
}, [isHorizontal, headerFixed, headerHeightShared, insets.top, chipHidden, snapBackHeaderShared, headerOffset, scrollPosition, pullSearchHeightShared]);
|
|
506
512
|
return { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed, headerHeight, insets, isHorizontal: isHorizontal ?? false };
|
|
@@ -512,14 +518,14 @@ var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilter
|
|
|
512
518
|
const { ListHeaderComponent: listHeaderComponent, contentContainerStyle: externalContentContainerStyle, ...restProps } = props;
|
|
513
519
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
|
|
514
520
|
const { listGeneration, onListUnmount } = (0, import_react6.useContext)(ScrollViewContext);
|
|
515
|
-
const capturedGeneration = (0,
|
|
521
|
+
const capturedGeneration = (0, import_react_native_reanimated5.useSharedValue)(-1);
|
|
516
522
|
(0, import_react6.useLayoutEffect)(() => {
|
|
517
523
|
const generation = listGeneration.value;
|
|
518
524
|
if (import_react_native6.Platform.OS === "web") {
|
|
519
525
|
capturedGeneration.value = generation;
|
|
520
526
|
return;
|
|
521
527
|
}
|
|
522
|
-
(0,
|
|
528
|
+
(0, import_react_native_reanimated5.runOnUI)((gen) => {
|
|
523
529
|
"worklet";
|
|
524
530
|
capturedGeneration.value = gen;
|
|
525
531
|
})(generation);
|
|
@@ -594,7 +600,7 @@ var import_auto_paper2 = require("@rific/auto-paper");
|
|
|
594
600
|
var import_react7 = require("react");
|
|
595
601
|
var import_react_native7 = require("react-native");
|
|
596
602
|
var import_react_native_paper2 = require("react-native-paper");
|
|
597
|
-
var
|
|
603
|
+
var import_react_native_reanimated6 = __toESM(require("react-native-reanimated"));
|
|
598
604
|
var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
|
|
599
605
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
600
606
|
var DOT_FULL = 8;
|
|
@@ -609,15 +615,15 @@ var PILL_HEIGHT = DOT_FULL + PILL_PAD_V * 2;
|
|
|
609
615
|
var PILL_RADIUS = PILL_HEIGHT / 2;
|
|
610
616
|
var PILL_WIDTH = CLIP_WIDTH + PILL_PAD_H * 2;
|
|
611
617
|
var Dot = ({ activeColor, index, inactiveColor, pageWidth, scrollPosition }) => {
|
|
612
|
-
const circleStyle = (0,
|
|
618
|
+
const circleStyle = (0, import_react_native_reanimated6.useAnimatedStyle)(() => {
|
|
613
619
|
const page = scrollPosition.value / pageWidth;
|
|
614
620
|
const distance = Math.abs(index - page);
|
|
615
621
|
const t = Math.max(0, Math.min((distance - 0.5) / 2, 1));
|
|
616
622
|
const size = DOT_FULL + (DOT_SMALL - DOT_FULL) * t;
|
|
617
|
-
const backgroundColor = (0,
|
|
623
|
+
const backgroundColor = (0, import_react_native_reanimated6.interpolateColor)(t, [0, 1], [activeColor, inactiveColor]);
|
|
618
624
|
return { backgroundColor, borderRadius: size / 2, height: size, width: size };
|
|
619
625
|
}, [scrollPosition, pageWidth, index, activeColor, inactiveColor]);
|
|
620
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles3.dotContainer, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles3.dotContainer, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated6.default.View, { style: circleStyle }) });
|
|
621
627
|
};
|
|
622
628
|
var HorizontalDots = ({ total }) => {
|
|
623
629
|
const { blur, footerHeightShared, scrollPosition } = (0, import_react7.useContext)(ScrollViewContext);
|
|
@@ -627,21 +633,21 @@ var HorizontalDots = ({ total }) => {
|
|
|
627
633
|
const insetsBottom = insets.bottom;
|
|
628
634
|
const activeColor = theme.colors.primary;
|
|
629
635
|
const inactiveColor = theme.colors.outlineVariant;
|
|
630
|
-
const pillContainerStyle = (0,
|
|
636
|
+
const pillContainerStyle = (0, import_react_native_reanimated6.useAnimatedStyle)(
|
|
631
637
|
() => ({
|
|
632
638
|
bottom: Math.max(footerHeightShared.value, insetsBottom) + 8
|
|
633
639
|
}),
|
|
634
640
|
[footerHeightShared, insetsBottom]
|
|
635
641
|
);
|
|
636
|
-
const rowStyle = (0,
|
|
642
|
+
const rowStyle = (0, import_react_native_reanimated6.useAnimatedStyle)(() => {
|
|
637
643
|
const page = scrollPosition.value / width;
|
|
638
644
|
const maxOffset = Math.max(0, (total - CLIP_COUNT) * DOT_STEP);
|
|
639
645
|
const offset = Math.max(0, Math.min((page - (CLIP_COUNT - 1) / 2) * DOT_STEP, maxOffset));
|
|
640
646
|
return { transform: [{ translateX: -offset }] };
|
|
641
647
|
}, [scrollPosition, width, total]);
|
|
642
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated6.default.View, { pointerEvents: "none", style: [styles3.pillContainer, pillContainerStyle], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native7.View, { style: styles3.pill, children: [
|
|
643
649
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_auto_paper2.BlurView, { blur, style: import_react_native7.StyleSheet.absoluteFill }),
|
|
644
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles3.dotsClip, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
650
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native7.View, { style: styles3.dotsClip, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated6.default.View, { style: [styles3.dotsRow, rowStyle], children: Array.from({ length: total }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dot, { activeColor, index: i, inactiveColor, pageWidth: width, scrollPosition }, i)) }) })
|
|
645
651
|
] }) });
|
|
646
652
|
};
|
|
647
653
|
var styles3 = import_react_native7.StyleSheet.create({
|
|
@@ -661,7 +667,7 @@ var styles3 = import_react_native7.StyleSheet.create({
|
|
|
661
667
|
|
|
662
668
|
// src/internal/useScrollHandlerJS.ts
|
|
663
669
|
var import_react8 = require("react");
|
|
664
|
-
var
|
|
670
|
+
var import_react_native_reanimated7 = require("react-native-reanimated");
|
|
665
671
|
var REMOUNT_RETRY_TOLERANCE = 1;
|
|
666
672
|
var REMOUNT_RETRY_MAX_ATTEMPTS = 8;
|
|
667
673
|
function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, jsListGeneration, remountTarget = null, scrollTo }) {
|
|
@@ -727,8 +733,8 @@ function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 10
|
|
|
727
733
|
if (yn >= -headerHeightShared.value + pullSearchHeightShared.value) snapUpAccum.current -= delta;
|
|
728
734
|
if (snapUpAccum.current >= 10) {
|
|
729
735
|
snapUpAccum.current = 999;
|
|
730
|
-
if (snapHeader) headerOffset.value = (0,
|
|
731
|
-
if (snapFooter) footerOffset.value = (0,
|
|
736
|
+
if (snapHeader) headerOffset.value = (0, import_react_native_reanimated7.withTiming)(0, { duration: 200 });
|
|
737
|
+
if (snapFooter) footerOffset.value = (0, import_react_native_reanimated7.withTiming)(0, { duration: 200 });
|
|
732
738
|
}
|
|
733
739
|
}
|
|
734
740
|
}
|
|
@@ -744,7 +750,7 @@ function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 10
|
|
|
744
750
|
const settle = (0, import_react8.useCallback)(
|
|
745
751
|
(revealing) => {
|
|
746
752
|
if (!chromeHosted || footerFixed || !chromeWritable.value) return;
|
|
747
|
-
footerOffset.value = (0,
|
|
753
|
+
footerOffset.value = (0, import_react_native_reanimated7.withTiming)(revealing ? 0 : chromeSettleTarget(footerOffset.value, stackHeightShared.value), { duration: 200 });
|
|
748
754
|
},
|
|
749
755
|
[chromeHosted, chromeWritable, footerFixed, footerOffset, stackHeightShared]
|
|
750
756
|
);
|
|
@@ -929,10 +935,12 @@ var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", r
|
|
|
929
935
|
var FlatList = (0, import_react9.memo)(FlatListInner);
|
|
930
936
|
|
|
931
937
|
// src/PullSearch.tsx
|
|
938
|
+
var import_core3 = require("@rific/core");
|
|
932
939
|
var import_react10 = require("react");
|
|
933
940
|
var import_react_native9 = require("react-native");
|
|
934
941
|
var import_react_native_paper3 = require("react-native-paper");
|
|
935
|
-
var
|
|
942
|
+
var import_react_native_reanimated8 = __toESM(require("react-native-reanimated"));
|
|
943
|
+
var import_react_native_worklets3 = require("react-native-worklets");
|
|
936
944
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
937
945
|
var PullSearch = (0, import_react10.forwardRef)(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
|
|
938
946
|
const { headerHeight, scrollPosition } = (0, import_react10.useContext)(ScrollViewContext);
|
|
@@ -951,13 +959,14 @@ var PullSearch = (0, import_react10.forwardRef)(function PullSearch2({ debounce,
|
|
|
951
959
|
focus: () => inputRef.current?.focus()
|
|
952
960
|
}));
|
|
953
961
|
const blurInput = (0, import_react10.useCallback)(() => inputRef.current?.blur(), []);
|
|
954
|
-
(0,
|
|
962
|
+
const blurKey = (0, import_core3.useWorkletCallback)(blurInput);
|
|
963
|
+
(0, import_react_native_reanimated8.useAnimatedReaction)(
|
|
955
964
|
() => {
|
|
956
965
|
if (barHeight === 0) return false;
|
|
957
966
|
return scrollPosition.value >= -(headerHeight ?? 0) + barHeight;
|
|
958
967
|
},
|
|
959
968
|
(isHidden, wasHidden) => {
|
|
960
|
-
if (isHidden && !wasHidden) (0,
|
|
969
|
+
if (isHidden && !wasHidden) (0, import_react_native_worklets3.scheduleOnRN)(import_core3.callWorkletCallback, blurKey);
|
|
961
970
|
},
|
|
962
971
|
// scrollPosition has to be listed too, not just read - see useStickyHeaders' useAnimatedReaction
|
|
963
972
|
// for why: on web, without reanimated's Babel plugin active, an unlisted SharedValue mutation
|
|
@@ -988,14 +997,14 @@ var PullSearch = (0, import_react10.forwardRef)(function PullSearch2({ debounce,
|
|
|
988
997
|
onChangeText(normalizedValue);
|
|
989
998
|
return void 0;
|
|
990
999
|
}, [debounce, onChangeText, value]);
|
|
991
|
-
const animatedStyle = (0,
|
|
1000
|
+
const animatedStyle = (0, import_react_native_reanimated8.useAnimatedStyle)(() => {
|
|
992
1001
|
if (barHeight === 0) return { opacity: 0 };
|
|
993
1002
|
const h = headerHeight ?? 0;
|
|
994
1003
|
const showY = -h;
|
|
995
1004
|
const hideY = -h + barHeight;
|
|
996
|
-
return { opacity: (0,
|
|
1005
|
+
return { opacity: (0, import_react_native_reanimated8.interpolate)(scrollPosition.value, [showY, hideY], [1, 0], import_react_native_reanimated8.Extrapolation.CLAMP) };
|
|
997
1006
|
}, [barHeight, headerHeight, scrollPosition]);
|
|
998
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_reanimated8.default.View, { onLayout: handleLayout, style: [styles5.container, animatedStyle], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper3.Searchbar, { autoCorrect: false, onChangeText: (text) => setValue((text || "").trimStart()), onClearIconPress: handleClear, placeholder, placeholderTextColor: theme.colors.onSurfaceVariant, ref: inputRef, spellCheck: false, style: styles5.input, value }) });
|
|
999
1008
|
});
|
|
1000
1009
|
var styles5 = import_react_native9.StyleSheet.create({
|
|
1001
1010
|
container: { paddingVertical: 8 },
|
|
@@ -1003,23 +1012,23 @@ var styles5 = import_react_native9.StyleSheet.create({
|
|
|
1003
1012
|
});
|
|
1004
1013
|
|
|
1005
1014
|
// src/redux/scrollViewSlice.ts
|
|
1006
|
-
var
|
|
1015
|
+
var import_core5 = require("@rific/core");
|
|
1007
1016
|
|
|
1008
1017
|
// src/ScrollViewSettingsContext.ts
|
|
1009
|
-
var
|
|
1018
|
+
var import_core4 = require("@rific/core");
|
|
1010
1019
|
var defaultScrollViewSettings = {
|
|
1011
1020
|
backActionFixed: true,
|
|
1012
1021
|
footerFixed: false,
|
|
1013
1022
|
headerFixed: false,
|
|
1014
1023
|
snapBack: false
|
|
1015
1024
|
};
|
|
1016
|
-
var settingsContext = (0,
|
|
1025
|
+
var settingsContext = (0, import_core4.createSettingsContext)(defaultScrollViewSettings);
|
|
1017
1026
|
var ScrollViewSettingsContext = settingsContext.Context;
|
|
1018
1027
|
var scrollViewSettingsProvider = settingsContext.Provider;
|
|
1019
1028
|
var scrollViewUseSettings = settingsContext.useSettings;
|
|
1020
1029
|
|
|
1021
1030
|
// src/redux/scrollViewSlice.ts
|
|
1022
|
-
var scrollViewSlice = (0,
|
|
1031
|
+
var scrollViewSlice = (0, import_core5.createSettingsSlice)("scrollView", {
|
|
1023
1032
|
initialState: defaultScrollViewSettings,
|
|
1024
1033
|
fieldSetters: []
|
|
1025
1034
|
});
|
|
@@ -1030,21 +1039,21 @@ var scrollViewReducer = scrollViewSlice.reducer;
|
|
|
1030
1039
|
var import_react11 = require("react");
|
|
1031
1040
|
var import_react_native10 = require("react-native");
|
|
1032
1041
|
var import_react_native_gesture_handler3 = require("react-native-gesture-handler");
|
|
1033
|
-
var
|
|
1042
|
+
var import_react_native_reanimated9 = __toESM(require("react-native-reanimated"));
|
|
1034
1043
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1035
1044
|
var ScrollViewInner = ({ chipProps, chipThreshold, children, contentContainerStyle: externalContentContainerStyle, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, style, ...props }) => {
|
|
1036
1045
|
const scrollView = (0, import_react11.useRef)(null);
|
|
1037
1046
|
const isHorizontal = horizontal === true;
|
|
1038
1047
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
|
|
1039
1048
|
const { listGeneration, onListUnmount } = (0, import_react11.useContext)(ScrollViewContext);
|
|
1040
|
-
const capturedGeneration = (0,
|
|
1049
|
+
const capturedGeneration = (0, import_react_native_reanimated9.useSharedValue)(-1);
|
|
1041
1050
|
(0, import_react11.useLayoutEffect)(() => {
|
|
1042
1051
|
const generation = listGeneration.value;
|
|
1043
1052
|
if (import_react_native10.Platform.OS === "web") {
|
|
1044
1053
|
capturedGeneration.value = generation;
|
|
1045
1054
|
return;
|
|
1046
1055
|
}
|
|
1047
|
-
(0,
|
|
1056
|
+
(0, import_react_native_reanimated9.runOnUI)((gen) => {
|
|
1048
1057
|
"worklet";
|
|
1049
1058
|
capturedGeneration.value = gen;
|
|
1050
1059
|
})(generation);
|
|
@@ -1075,7 +1084,7 @@ var ScrollViewInner = ({ chipProps, chipThreshold, children, contentContainerSty
|
|
|
1075
1084
|
const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
|
|
1076
1085
|
const content = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native10.View, { style: containerStyle, children: [
|
|
1077
1086
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1078
|
-
|
|
1087
|
+
import_react_native_reanimated9.default.ScrollView,
|
|
1079
1088
|
{
|
|
1080
1089
|
...props,
|
|
1081
1090
|
contentContainerStyle: contentPadding ? [externalContentContainerStyle, contentPadding] : externalContentContainerStyle,
|
|
@@ -1102,7 +1111,7 @@ var ScrollView = (0, import_react11.memo)(ScrollViewInner);
|
|
|
1102
1111
|
|
|
1103
1112
|
// src/ScrollViewChromeProvider.tsx
|
|
1104
1113
|
var import_react13 = require("react");
|
|
1105
|
-
var
|
|
1114
|
+
var import_react_native_reanimated10 = require("react-native-reanimated");
|
|
1106
1115
|
|
|
1107
1116
|
// src/ScrollViewChromeContext.ts
|
|
1108
1117
|
var import_react12 = require("react");
|
|
@@ -1114,7 +1123,7 @@ var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
|
1114
1123
|
var REVEAL_DURATION = 200;
|
|
1115
1124
|
var alwaysActive = () => true;
|
|
1116
1125
|
var ScrollViewChromeProvider = ({ children, footprint, overhang = 0, snapBack = true, useIsActive = alwaysActive }) => {
|
|
1117
|
-
const offset = (0,
|
|
1126
|
+
const offset = (0, import_react_native_reanimated10.useSharedValue)(0);
|
|
1118
1127
|
const [claims, setClaims] = (0, import_react13.useState)([]);
|
|
1119
1128
|
const [pins, setPins] = (0, import_react13.useState)(0);
|
|
1120
1129
|
const activeId = claims.length > 0 ? claims[claims.length - 1] : null;
|
|
@@ -1124,7 +1133,7 @@ var ScrollViewChromeProvider = ({ children, footprint, overhang = 0, snapBack =
|
|
|
1124
1133
|
const addPin = (0, import_react13.useCallback)(() => setPins((current) => current + 1), []);
|
|
1125
1134
|
const removePin = (0, import_react13.useCallback)(() => setPins((current) => Math.max(0, current - 1)), []);
|
|
1126
1135
|
const reveal = (0, import_react13.useCallback)(() => {
|
|
1127
|
-
offset.value = (0,
|
|
1136
|
+
offset.value = (0, import_react_native_reanimated10.withTiming)(0, { duration: REVEAL_DURATION });
|
|
1128
1137
|
}, [offset]);
|
|
1129
1138
|
(0, import_react13.useEffect)(() => {
|
|
1130
1139
|
reveal();
|
|
@@ -1135,8 +1144,8 @@ var ScrollViewChromeProvider = ({ children, footprint, overhang = 0, snapBack =
|
|
|
1135
1144
|
};
|
|
1136
1145
|
|
|
1137
1146
|
// src/ScrollViewConfig.tsx
|
|
1138
|
-
var
|
|
1139
|
-
var scrollViewConfig = (0,
|
|
1147
|
+
var import_core6 = require("@rific/core");
|
|
1148
|
+
var scrollViewConfig = (0, import_core6.createModuleConfig)();
|
|
1140
1149
|
var configureScrollView = scrollViewConfig.configure;
|
|
1141
1150
|
var getScrollViewConfig = scrollViewConfig.getConfig;
|
|
1142
1151
|
var ScrollViewConfigProvider = scrollViewConfig.Provider;
|
|
@@ -1145,7 +1154,7 @@ var ScrollViewConfigProvider = scrollViewConfig.Provider;
|
|
|
1145
1154
|
var import_auto_paper3 = require("@rific/auto-paper");
|
|
1146
1155
|
var import_react14 = require("react");
|
|
1147
1156
|
var import_react_native11 = require("react-native");
|
|
1148
|
-
var
|
|
1157
|
+
var import_react_native_reanimated11 = __toESM(require("react-native-reanimated"));
|
|
1149
1158
|
var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
|
|
1150
1159
|
var import_jsx_runtime9 = (
|
|
1151
1160
|
// bottom: tabBarHeight (not the styles.footer default of 0) - a consuming app's own persistent
|
|
@@ -1175,7 +1184,7 @@ var ScrollViewFooter = ({ children, style }) => {
|
|
|
1175
1184
|
}) => {
|
|
1176
1185
|
if (footerHeight !== height) setFooterHeight(height);
|
|
1177
1186
|
};
|
|
1178
|
-
const footerStyle = (0,
|
|
1187
|
+
const footerStyle = (0, import_react_native_reanimated11.useAnimatedStyle)(() => {
|
|
1179
1188
|
if (chromeHosted) return { transform: [{ translateY: Math.min(Math.max(footerOffset.value, 0), stackHeightShared.value) }] };
|
|
1180
1189
|
if (footerFixed) return { transform: [{ translateY: 0 }] };
|
|
1181
1190
|
if (snapBackFooterShared.value) return { transform: [{ translateY: footerOffset.value }] };
|
|
@@ -1195,7 +1204,7 @@ var ScrollViewFooter = ({ children, style }) => {
|
|
|
1195
1204
|
const rowPaddingBottom = footerFixed && footerAboveKeyboard ? Math.max(bottomPadding - keyboardHeight, 0) : bottomPadding;
|
|
1196
1205
|
const footerBottom = chromeHosted && footerFixed && footerAboveKeyboard ? Math.max(tabBarHeight - keyboardHeight, 0) : tabBarHeight;
|
|
1197
1206
|
const { paddingBottom: consumerPaddingBottom, ...restStyle } = style ?? {};
|
|
1198
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated11.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, { bottom: footerBottom, paddingBottom: containerPaddingBottom }, footerStyle], children: [
|
|
1199
1208
|
(footerHeight ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper3.BlurView, { blur, style: import_react_native11.StyleSheet.absoluteFill }),
|
|
1200
1209
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native11.View, { ref: rowRef, style: [styles6.row, restStyle, { paddingBottom: rowPaddingBottom + (typeof consumerPaddingBottom === "number" ? consumerPaddingBottom : 0) }], children })
|
|
1201
1210
|
] });
|
|
@@ -1210,7 +1219,7 @@ var import_auto_paper4 = require("@rific/auto-paper");
|
|
|
1210
1219
|
var import_react15 = require("react");
|
|
1211
1220
|
var import_react_native12 = require("react-native");
|
|
1212
1221
|
var import_react_native_paper4 = require("react-native-paper");
|
|
1213
|
-
var
|
|
1222
|
+
var import_react_native_reanimated12 = __toESM(require("react-native-reanimated"));
|
|
1214
1223
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
1215
1224
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1216
1225
|
var ActionBg = ({ blur, style }) => blur ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [import_react_native12.StyleSheet.absoluteFill, styles7.actionBg, style], children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_auto_paper4.BlurView, { blur: true, style: import_react_native12.StyleSheet.absoluteFill }) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [import_react_native12.StyleSheet.absoluteFill, styles7.actionBg, style], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper4.Surface, { style: import_react_native12.StyleSheet.absoluteFill, elevation: 1, children: null }) });
|
|
@@ -1221,7 +1230,7 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1221
1230
|
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
1222
1231
|
const theme = (0, import_react_native_paper4.useTheme)();
|
|
1223
1232
|
const top = topInset ? insets.top : 0;
|
|
1224
|
-
const measuredShared = (0,
|
|
1233
|
+
const measuredShared = (0, import_react_native_reanimated12.useSharedValue)(false);
|
|
1225
1234
|
const handleLayout = ({
|
|
1226
1235
|
nativeEvent: {
|
|
1227
1236
|
layout: { height }
|
|
@@ -1241,21 +1250,21 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1241
1250
|
const actionMargin = 4;
|
|
1242
1251
|
const contentMinHeight = actionSize + 2 * actionMargin;
|
|
1243
1252
|
const unmeasuredHeight = top + contentMinHeight;
|
|
1244
|
-
const translateStyle = (0,
|
|
1253
|
+
const translateStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
|
|
1245
1254
|
if (headerFixed) return { transform: [{ translateY: 0 }] };
|
|
1246
1255
|
if (snapBackHeaderShared.value) return { transform: [{ translateY: headerOffset.value }] };
|
|
1247
1256
|
const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value;
|
|
1248
1257
|
if (effective <= 0) return { transform: [{ translateY: 0 }] };
|
|
1249
1258
|
return { transform: [{ translateY: -effective }] };
|
|
1250
1259
|
}, [headerFixed, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1251
|
-
const blurStyle = (0,
|
|
1260
|
+
const blurStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
|
|
1252
1261
|
if (!measuredShared.value) return { height: unmeasuredHeight };
|
|
1253
1262
|
if (!headerHeightShared.value) return { height: 0 };
|
|
1254
1263
|
if (headerFixed) return { height: headerHeightShared.value };
|
|
1255
1264
|
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value);
|
|
1256
1265
|
return { height: Math.max(headerHeightShared.value + translateY, top) };
|
|
1257
1266
|
}, [headerFixed, top, unmeasuredHeight, measuredShared, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1258
|
-
const progressStyle = (0,
|
|
1267
|
+
const progressStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
|
|
1259
1268
|
const h = headerHeightShared.value;
|
|
1260
1269
|
if (headerFixed) return { top: h };
|
|
1261
1270
|
const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
@@ -1269,8 +1278,8 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1269
1278
|
const leadingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", left: actionMargin, position: "absolute", top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
|
|
1270
1279
|
const trailingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", position: "absolute", right: actionMargin, top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
|
|
1271
1280
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
1272
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1273
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1281
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_reanimated12.default.View, { pointerEvents: "none", style: [styles7.blur, blurStyle], children: headerHeight !== 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_auto_paper4.BlurView, { blur, style: [styles7.blurInner, { height: headerHeight ?? unmeasuredHeight }] }) }),
|
|
1282
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_reanimated12.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [headerHeight === null ? styles7.headerInit : styles7.header, translateStyle], children: [
|
|
1274
1283
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { ref: contentRef, style: [{ paddingTop: top }, style], children: children ?? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: [styles7.content, { minHeight: contentMinHeight }], children: [
|
|
1275
1284
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: styles7.side }),
|
|
1276
1285
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: styles7.spacer }),
|
|
@@ -1281,18 +1290,18 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1281
1290
|
] }) }),
|
|
1282
1291
|
!blur && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [styles7.divider, { backgroundColor: theme.colors.outlineVariant }] })
|
|
1283
1292
|
] }),
|
|
1284
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1285
|
-
backAction && (effectiveBackActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1293
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_reanimated12.default.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper4.ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
|
|
1294
|
+
backAction && (effectiveBackActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_reanimated12.default.View, { style: leadingStyle, children: [
|
|
1286
1295
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionBg, { blur, style: actionStyle }),
|
|
1287
1296
|
backActionElement
|
|
1288
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1297
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_reanimated12.default.View, { style: [leadingStyle, translateStyle], children: [
|
|
1289
1298
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionBg, { blur, style: actionStyle }),
|
|
1290
1299
|
backActionElement
|
|
1291
1300
|
] })),
|
|
1292
1301
|
trailingAction && (trailingActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: trailingStyle, children: [
|
|
1293
1302
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionBg, { blur, style: actionStyle }),
|
|
1294
1303
|
trailingAction
|
|
1295
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1304
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_reanimated12.default.View, { style: [trailingStyle, translateStyle], children: [
|
|
1296
1305
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionBg, { blur, style: actionStyle }),
|
|
1297
1306
|
trailingAction
|
|
1298
1307
|
] }))
|
|
@@ -1318,7 +1327,7 @@ var styles7 = import_react_native12.StyleSheet.create({
|
|
|
1318
1327
|
var import_auto_paper5 = require("@rific/auto-paper");
|
|
1319
1328
|
var import_react17 = require("react");
|
|
1320
1329
|
var import_react_native13 = require("react-native");
|
|
1321
|
-
var
|
|
1330
|
+
var import_react_native_reanimated13 = require("react-native-reanimated");
|
|
1322
1331
|
|
|
1323
1332
|
// src/internal/ChromeRegistrar.tsx
|
|
1324
1333
|
var import_react16 = require("react");
|
|
@@ -1359,24 +1368,24 @@ var ScrollViewProvider = ({ blur, chrome, children, fixed = false, footerAboveKe
|
|
|
1359
1368
|
const [footerHeight, setFooterHeightState] = (0, import_react17.useState)(null);
|
|
1360
1369
|
const [progress, setProgress] = (0, import_react17.useState)(null);
|
|
1361
1370
|
const [progressing, setProgressing] = (0, import_react17.useState)(false);
|
|
1362
|
-
const scrollPosition = (0,
|
|
1363
|
-
const listGeneration = (0,
|
|
1371
|
+
const scrollPosition = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1372
|
+
const listGeneration = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1364
1373
|
const jsListGeneration = (0, import_react17.useRef)(0);
|
|
1365
|
-
const headerHeightShared = (0,
|
|
1366
|
-
const footerHeightShared = (0,
|
|
1367
|
-
const headerOffset = (0,
|
|
1368
|
-
const ownFooterOffset = (0,
|
|
1369
|
-
const ownStackHeight = (0,
|
|
1374
|
+
const headerHeightShared = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1375
|
+
const footerHeightShared = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1376
|
+
const headerOffset = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1377
|
+
const ownFooterOffset = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1378
|
+
const ownStackHeight = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1370
1379
|
const footerOffset = chromeHost ? chromeHost.offset : ownFooterOffset;
|
|
1371
|
-
const chromeWritable = (0,
|
|
1380
|
+
const chromeWritable = (0, import_react_native_reanimated13.useSharedValue)(!chromeHosted);
|
|
1372
1381
|
(0, import_react17.useEffect)(() => {
|
|
1373
1382
|
if (!chromeHosted) chromeWritable.value = true;
|
|
1374
1383
|
}, [chromeHosted, chromeWritable]);
|
|
1375
1384
|
const revealChrome = chromeHost?.reveal;
|
|
1376
1385
|
const stackHeightShared = chromeHosted ? ownStackHeight : footerHeightShared;
|
|
1377
|
-
const pullSearchHeightShared = (0,
|
|
1378
|
-
const snapBackHeaderShared = (0,
|
|
1379
|
-
const snapBackFooterShared = (0,
|
|
1386
|
+
const pullSearchHeightShared = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
1387
|
+
const snapBackHeaderShared = (0, import_react_native_reanimated13.useSharedValue)(false);
|
|
1388
|
+
const snapBackFooterShared = (0, import_react_native_reanimated13.useSharedValue)(false);
|
|
1380
1389
|
(0, import_react17.useEffect)(() => {
|
|
1381
1390
|
snapBackHeaderShared.value = effectiveSnapBackHeader ?? effectiveSnapBack;
|
|
1382
1391
|
snapBackFooterShared.value = chromeHosted ? chromeSnapBack : effectiveSnapBackFooter ?? effectiveSnapBack;
|
|
@@ -1450,25 +1459,28 @@ var ScrollViewSettingsProvider = scrollViewSettingsProvider;
|
|
|
1450
1459
|
var import_react19 = require("react");
|
|
1451
1460
|
var import_react_native14 = require("react-native");
|
|
1452
1461
|
var import_react_native_gesture_handler4 = require("react-native-gesture-handler");
|
|
1453
|
-
var
|
|
1462
|
+
var import_react_native_reanimated15 = __toESM(require("react-native-reanimated"));
|
|
1454
1463
|
|
|
1455
1464
|
// src/internal/useStickyHeaders.ts
|
|
1465
|
+
var import_core7 = require("@rific/core");
|
|
1456
1466
|
var import_react18 = require("react");
|
|
1457
|
-
var
|
|
1467
|
+
var import_react_native_reanimated14 = require("react-native-reanimated");
|
|
1458
1468
|
var import_react_native_safe_area_context5 = require("react-native-safe-area-context");
|
|
1469
|
+
var import_react_native_worklets4 = require("react-native-worklets");
|
|
1459
1470
|
function useStickyHeaders(headerFixed, enabled) {
|
|
1460
1471
|
const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = (0, import_react18.useContext)(ScrollViewContext);
|
|
1461
1472
|
const insetsTop = (0, import_react_native_safe_area_context5.useSafeAreaInsets)().top;
|
|
1462
|
-
const sectionYPositions = (0,
|
|
1463
|
-
const sectionHeights = (0,
|
|
1473
|
+
const sectionYPositions = (0, import_react_native_reanimated14.useSharedValue)([]);
|
|
1474
|
+
const sectionHeights = (0, import_react_native_reanimated14.useSharedValue)([]);
|
|
1464
1475
|
const [activeIndex, setActiveIndex] = (0, import_react18.useState)(-1);
|
|
1465
|
-
const
|
|
1476
|
+
const activeIndexKey = (0, import_core7.useWorkletCallback)(setActiveIndex);
|
|
1477
|
+
const contentIndexShared = (0, import_react_native_reanimated14.useSharedValue)(-1);
|
|
1466
1478
|
(0, import_react18.useLayoutEffect)(() => {
|
|
1467
1479
|
contentIndexShared.value = activeIndex;
|
|
1468
1480
|
}, [activeIndex, contentIndexShared]);
|
|
1469
1481
|
const positionsCache = (0, import_react18.useRef)([]);
|
|
1470
1482
|
const heightsCache = (0, import_react18.useRef)([]);
|
|
1471
|
-
(0,
|
|
1483
|
+
(0, import_react_native_reanimated14.useAnimatedReaction)(
|
|
1472
1484
|
() => {
|
|
1473
1485
|
if (!enabled) return -1;
|
|
1474
1486
|
const positions = sectionYPositions.value;
|
|
@@ -1493,7 +1505,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1493
1505
|
return active;
|
|
1494
1506
|
},
|
|
1495
1507
|
(curr, prev) => {
|
|
1496
|
-
if (curr !== prev) (0,
|
|
1508
|
+
if (curr !== prev) (0, import_react_native_worklets4.scheduleOnRN)(import_core7.callWorkletCallback, activeIndexKey, curr);
|
|
1497
1509
|
},
|
|
1498
1510
|
// Same web-only reanimated gap as useAnimatedStyle elsewhere in this file: this "prepare"
|
|
1499
1511
|
// function's own SharedValue reads (sectionYPositions, headerHeightShared, scrollPosition,
|
|
@@ -1502,7 +1514,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1502
1514
|
// then never again on web, permanently freezing activeIndex/the active sticky section.
|
|
1503
1515
|
[enabled, headerFixed, insetsTop, sectionYPositions, headerHeightShared, scrollPosition, snapBackHeaderShared, headerOffset, pullSearchHeightShared]
|
|
1504
1516
|
);
|
|
1505
|
-
const clipStyle = (0,
|
|
1517
|
+
const clipStyle = (0, import_react_native_reanimated14.useAnimatedStyle)(() => {
|
|
1506
1518
|
const hHeight = headerHeightShared.value;
|
|
1507
1519
|
const scrollPos = scrollPosition.value;
|
|
1508
1520
|
let stickyTop;
|
|
@@ -1516,7 +1528,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1516
1528
|
}
|
|
1517
1529
|
return { top: stickyTop };
|
|
1518
1530
|
}, [enabled, headerFixed, insetsTop, headerHeightShared, scrollPosition, snapBackHeaderShared, headerOffset, pullSearchHeightShared]);
|
|
1519
|
-
const overlayStyle = (0,
|
|
1531
|
+
const overlayStyle = (0, import_react_native_reanimated14.useAnimatedStyle)(() => {
|
|
1520
1532
|
const hidden = { opacity: 0, top: 0, transform: [{ translateY: 0 }] };
|
|
1521
1533
|
if (!enabled) return hidden;
|
|
1522
1534
|
const index = contentIndexShared.value;
|
|
@@ -1568,20 +1580,20 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1568
1580
|
|
|
1569
1581
|
// src/SectionList.tsx
|
|
1570
1582
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1571
|
-
var AnimatedSectionList =
|
|
1583
|
+
var AnimatedSectionList = import_react_native_reanimated15.default.createAnimatedComponent(import_react_native14.SectionList);
|
|
1572
1584
|
var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: externalContentContainerStyle, initialNumToRender = 20, maxToRenderPerBatch = 50, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onContentSizeChange, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, removeClippedSubviews = false, sections, showsVerticalScrollIndicator, style, ref: externalRef, windowSize = 100, ...props }) => {
|
|
1573
1585
|
const scrollView = (0, import_react19.useRef)(null);
|
|
1574
1586
|
const { stickySectionHeadersEnabled = true, renderSectionHeader, ...passThroughProps } = props;
|
|
1575
1587
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed, headerHeight } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, hideUntilMeasured: true, keyboardAware, pullSearchHeight, style });
|
|
1576
1588
|
const { listGeneration, onListUnmount } = (0, import_react19.useContext)(ScrollViewContext);
|
|
1577
|
-
const capturedGeneration = (0,
|
|
1589
|
+
const capturedGeneration = (0, import_react_native_reanimated15.useSharedValue)(-1);
|
|
1578
1590
|
(0, import_react19.useLayoutEffect)(() => {
|
|
1579
1591
|
const generation = listGeneration.value;
|
|
1580
1592
|
if (import_react_native14.Platform.OS === "web") {
|
|
1581
1593
|
capturedGeneration.value = generation;
|
|
1582
1594
|
return;
|
|
1583
1595
|
}
|
|
1584
|
-
(0,
|
|
1596
|
+
(0, import_react_native_reanimated15.runOnUI)((gen) => {
|
|
1585
1597
|
"worklet";
|
|
1586
1598
|
capturedGeneration.value = gen;
|
|
1587
1599
|
})(generation);
|
|
@@ -1702,7 +1714,7 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
|
|
|
1702
1714
|
),
|
|
1703
1715
|
hiddenHeader && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native14.View, { pointerEvents: "none", style: styles8.measureContainer, children: hiddenHeader }),
|
|
1704
1716
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScrollViewChip, { chipProps, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
|
|
1705
|
-
usesCustomSticky && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1717
|
+
usesCustomSticky && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_reanimated15.default.View, { pointerEvents: "none", style: [styles8.stickyClip, clipStyle], children: activeIndex >= 0 && activeIndex < sections.length && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_reanimated15.default.View, { style: [styles8.stickyOverlay, overlayStyle], children: renderSectionHeader({ section: sections[activeIndex] }) }) })
|
|
1706
1718
|
] });
|
|
1707
1719
|
return detectorGesture ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_gesture_handler4.GestureDetector, { gesture: detectorGesture, children: content }) : content;
|
|
1708
1720
|
};
|
|
@@ -1722,14 +1734,14 @@ var useScrollView = () => {
|
|
|
1722
1734
|
|
|
1723
1735
|
// src/useScrollViewChrome.ts
|
|
1724
1736
|
var import_react21 = require("react");
|
|
1725
|
-
var
|
|
1737
|
+
var import_react_native_reanimated16 = require("react-native-reanimated");
|
|
1726
1738
|
var noop = () => {
|
|
1727
1739
|
};
|
|
1728
1740
|
var useScrollViewChromeStyle = () => {
|
|
1729
1741
|
const chrome = (0, import_react21.useContext)(ScrollViewChromeContext);
|
|
1730
|
-
const fallback = (0,
|
|
1742
|
+
const fallback = (0, import_react_native_reanimated16.useSharedValue)(0);
|
|
1731
1743
|
const offset = chrome?.offset ?? fallback;
|
|
1732
|
-
return (0,
|
|
1744
|
+
return (0, import_react_native_reanimated16.useAnimatedStyle)(() => ({ transform: [{ translateY: offset.value }] }), [offset]);
|
|
1733
1745
|
};
|
|
1734
1746
|
var useScrollViewChromePin = (active) => {
|
|
1735
1747
|
const chrome = (0, import_react21.useContext)(ScrollViewChromeContext);
|
package/dist/index.mjs
CHANGED
|
@@ -31,8 +31,10 @@ 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
|
-
import {
|
|
36
|
+
import { useAnimatedScrollHandler, useSharedValue as useSharedValue2, withTiming } from "react-native-reanimated";
|
|
37
|
+
import { scheduleOnRN } from "react-native-worklets";
|
|
36
38
|
|
|
37
39
|
// src/ScrollViewContext.ts
|
|
38
40
|
import { createContext } from "react";
|
|
@@ -279,6 +281,8 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
279
281
|
const { chromeHosted, chromeWritable, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared, stackHeightShared } = useContext2(ScrollViewContext);
|
|
280
282
|
const snapUpAccum = useSharedValue2(0);
|
|
281
283
|
const fromBottomBounce = useSharedValue2(false);
|
|
284
|
+
const remountSyncedKey = useWorkletCallback((y) => onRemountSynced?.(y));
|
|
285
|
+
const remountSyncRetryKey = useWorkletCallback((y) => onRemountSyncRetry?.(y));
|
|
282
286
|
return useAnimatedScrollHandler(
|
|
283
287
|
{
|
|
284
288
|
onScroll: ({ contentOffset: { x, y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
|
|
@@ -287,9 +291,9 @@ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100,
|
|
|
287
291
|
const target = remountSyncTarget.value;
|
|
288
292
|
if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
|
|
289
293
|
remountSyncTarget.value = null;
|
|
290
|
-
if (onRemountSynced)
|
|
294
|
+
if (onRemountSynced) scheduleOnRN(callWorkletCallback, remountSyncedKey, y);
|
|
291
295
|
} else if (onRemountSyncRetry) {
|
|
292
|
-
|
|
296
|
+
scheduleOnRN(callWorkletCallback, remountSyncRetryKey, y);
|
|
293
297
|
}
|
|
294
298
|
return;
|
|
295
299
|
}
|
|
@@ -373,21 +377,23 @@ import { useAnimatedStyle, useSharedValue as useSharedValue3, withTiming as with
|
|
|
373
377
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
374
378
|
|
|
375
379
|
// src/useKeyboardInset.ts
|
|
380
|
+
import { callWorkletCallback as callWorkletCallback2, useWorkletCallback as useWorkletCallback2 } from "@rific/core";
|
|
376
381
|
import { useState as useState2 } from "react";
|
|
377
382
|
import { Platform as Platform2 } from "react-native";
|
|
378
383
|
import { useKeyboardHandler } from "react-native-keyboard-controller";
|
|
379
|
-
import {
|
|
384
|
+
import { scheduleOnRN as scheduleOnRN2 } from "react-native-worklets";
|
|
380
385
|
var useKeyboardInsetNative = () => {
|
|
381
386
|
const [keyboardHeight, setKeyboardHeight] = useState2(0);
|
|
387
|
+
const keyboardHeightKey = useWorkletCallback2(setKeyboardHeight);
|
|
382
388
|
useKeyboardHandler(
|
|
383
389
|
{
|
|
384
390
|
onMove: (e) => {
|
|
385
391
|
"worklet";
|
|
386
|
-
|
|
392
|
+
scheduleOnRN2(callWorkletCallback2, keyboardHeightKey, e.height);
|
|
387
393
|
},
|
|
388
394
|
onEnd: (e) => {
|
|
389
395
|
"worklet";
|
|
390
|
-
|
|
396
|
+
scheduleOnRN2(callWorkletCallback2, keyboardHeightKey, e.height);
|
|
391
397
|
}
|
|
392
398
|
},
|
|
393
399
|
[]
|
|
@@ -870,10 +876,12 @@ var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", r
|
|
|
870
876
|
var FlatList = memo2(FlatListInner);
|
|
871
877
|
|
|
872
878
|
// src/PullSearch.tsx
|
|
879
|
+
import { callWorkletCallback as callWorkletCallback3, useWorkletCallback as useWorkletCallback3 } from "@rific/core";
|
|
873
880
|
import { forwardRef, useCallback as useCallback5, useContext as useContext8, useEffect as useEffect3, useImperativeHandle, useRef as useRef5, useState as useState4 } from "react";
|
|
874
881
|
import { StyleSheet as StyleSheet4 } from "react-native";
|
|
875
882
|
import { Searchbar, useTheme as useTheme3 } from "react-native-paper";
|
|
876
|
-
import Animated3, { Extrapolation, interpolate,
|
|
883
|
+
import Animated3, { Extrapolation, interpolate, useAnimatedReaction, useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
|
|
884
|
+
import { scheduleOnRN as scheduleOnRN3 } from "react-native-worklets";
|
|
877
885
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
878
886
|
var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
|
|
879
887
|
const { headerHeight, scrollPosition } = useContext8(ScrollViewContext);
|
|
@@ -892,13 +900,14 @@ var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHei
|
|
|
892
900
|
focus: () => inputRef.current?.focus()
|
|
893
901
|
}));
|
|
894
902
|
const blurInput = useCallback5(() => inputRef.current?.blur(), []);
|
|
903
|
+
const blurKey = useWorkletCallback3(blurInput);
|
|
895
904
|
useAnimatedReaction(
|
|
896
905
|
() => {
|
|
897
906
|
if (barHeight === 0) return false;
|
|
898
907
|
return scrollPosition.value >= -(headerHeight ?? 0) + barHeight;
|
|
899
908
|
},
|
|
900
909
|
(isHidden, wasHidden) => {
|
|
901
|
-
if (isHidden && !wasHidden)
|
|
910
|
+
if (isHidden && !wasHidden) scheduleOnRN3(callWorkletCallback3, blurKey);
|
|
902
911
|
},
|
|
903
912
|
// scrollPosition has to be listed too, not just read - see useStickyHeaders' useAnimatedReaction
|
|
904
913
|
// for why: on web, without reanimated's Babel plugin active, an unlisted SharedValue mutation
|
|
@@ -1394,15 +1403,18 @@ import { Gesture as Gesture4, GestureDetector as GestureDetector4 } from "react-
|
|
|
1394
1403
|
import Animated7, { runOnUI as runOnUI3, useSharedValue as useSharedValue10 } from "react-native-reanimated";
|
|
1395
1404
|
|
|
1396
1405
|
// src/internal/useStickyHeaders.ts
|
|
1406
|
+
import { callWorkletCallback as callWorkletCallback4, useWorkletCallback as useWorkletCallback4 } from "@rific/core";
|
|
1397
1407
|
import { useCallback as useCallback9, useContext as useContext13, useLayoutEffect as useLayoutEffect8, useRef as useRef10, useState as useState7 } from "react";
|
|
1398
|
-
import {
|
|
1408
|
+
import { useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as useSharedValue9 } from "react-native-reanimated";
|
|
1399
1409
|
import { useSafeAreaInsets as useSafeAreaInsets5 } from "react-native-safe-area-context";
|
|
1410
|
+
import { scheduleOnRN as scheduleOnRN4 } from "react-native-worklets";
|
|
1400
1411
|
function useStickyHeaders(headerFixed, enabled) {
|
|
1401
1412
|
const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext13(ScrollViewContext);
|
|
1402
1413
|
const insetsTop = useSafeAreaInsets5().top;
|
|
1403
1414
|
const sectionYPositions = useSharedValue9([]);
|
|
1404
1415
|
const sectionHeights = useSharedValue9([]);
|
|
1405
1416
|
const [activeIndex, setActiveIndex] = useState7(-1);
|
|
1417
|
+
const activeIndexKey = useWorkletCallback4(setActiveIndex);
|
|
1406
1418
|
const contentIndexShared = useSharedValue9(-1);
|
|
1407
1419
|
useLayoutEffect8(() => {
|
|
1408
1420
|
contentIndexShared.value = activeIndex;
|
|
@@ -1434,7 +1446,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
1434
1446
|
return active;
|
|
1435
1447
|
},
|
|
1436
1448
|
(curr, prev) => {
|
|
1437
|
-
if (curr !== prev)
|
|
1449
|
+
if (curr !== prev) scheduleOnRN4(callWorkletCallback4, activeIndexKey, curr);
|
|
1438
1450
|
},
|
|
1439
1451
|
// Same web-only reanimated gap as useAnimatedStyle elsewhere in this file: this "prepare"
|
|
1440
1452
|
// 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.1",
|
|
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,14 +92,15 @@
|
|
|
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",
|
|
99
99
|
"react-native-keyboard-controller": ">=1.0.0",
|
|
100
100
|
"react-native-paper": ">=5.0.0",
|
|
101
101
|
"react-native-reanimated": ">=4.0.0",
|
|
102
|
-
"react-native-safe-area-context": ">=5.0.0"
|
|
102
|
+
"react-native-safe-area-context": ">=5.0.0",
|
|
103
|
+
"react-native-worklets": ">=0.5.0"
|
|
103
104
|
},
|
|
104
105
|
"publishConfig": {
|
|
105
106
|
"access": "public"
|
package/src/PullSearch.tsx
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
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'
|
|
4
|
-
import Animated, { Extrapolation, interpolate,
|
|
5
|
+
import Animated, { Extrapolation, interpolate, useAnimatedReaction, useAnimatedStyle } from 'react-native-reanimated'
|
|
6
|
+
import { scheduleOnRN } from 'react-native-worklets'
|
|
5
7
|
|
|
6
8
|
import { ScrollViewContext } from './ScrollViewContext'
|
|
7
9
|
|
|
@@ -38,6 +40,7 @@ export const PullSearch = forwardRef<PullSearchHandle, PullSearchProps>(function
|
|
|
38
40
|
}))
|
|
39
41
|
|
|
40
42
|
const blurInput = useCallback(() => inputRef.current?.blur(), [])
|
|
43
|
+
const blurKey = useWorkletCallback(blurInput)
|
|
41
44
|
|
|
42
45
|
useAnimatedReaction(
|
|
43
46
|
() => {
|
|
@@ -45,7 +48,7 @@ export const PullSearch = forwardRef<PullSearchHandle, PullSearchProps>(function
|
|
|
45
48
|
return scrollPosition.value >= -(headerHeight ?? 0) + barHeight
|
|
46
49
|
},
|
|
47
50
|
(isHidden, wasHidden) => {
|
|
48
|
-
if (isHidden && !wasHidden)
|
|
51
|
+
if (isHidden && !wasHidden) scheduleOnRN(callWorkletCallback, blurKey)
|
|
49
52
|
},
|
|
50
53
|
// scrollPosition has to be listed too, not just read - see useStickyHeaders' useAnimatedReaction
|
|
51
54
|
// for why: on web, without reanimated's Babel plugin active, an unlisted SharedValue mutation
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { callWorkletCallback, useWorkletCallback } from '@rific/core'
|
|
1
2
|
import { useContext } from 'react'
|
|
2
3
|
import type { SharedValue } from 'react-native-reanimated'
|
|
3
|
-
import {
|
|
4
|
+
import { useAnimatedScrollHandler, useSharedValue, withTiming } from 'react-native-reanimated'
|
|
5
|
+
import { scheduleOnRN } from 'react-native-worklets'
|
|
4
6
|
|
|
5
7
|
import { ScrollViewContext } from '../ScrollViewContext'
|
|
6
8
|
import { REMOUNT_SYNC_TOLERANCE } from '../useScrollInit'
|
|
@@ -24,6 +26,10 @@ export function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold
|
|
|
24
26
|
const { chromeHosted, chromeWritable, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared, stackHeightShared } = useContext(ScrollViewContext)
|
|
25
27
|
const snapUpAccum = useSharedValue(0)
|
|
26
28
|
const fromBottomBounce = useSharedValue(false)
|
|
29
|
+
// Worklets never get the consumer's callbacks themselves: react-native-worklets holds a runOnJS target natively for as
|
|
30
|
+
// long as the worklet lives, which pinned the list. They call the module-level callWorkletCallback by key.
|
|
31
|
+
const remountSyncedKey = useWorkletCallback((y: number) => onRemountSynced?.(y))
|
|
32
|
+
const remountSyncRetryKey = useWorkletCallback((y: number) => onRemountSyncRetry?.(y))
|
|
27
33
|
|
|
28
34
|
return useAnimatedScrollHandler(
|
|
29
35
|
{
|
|
@@ -33,9 +39,9 @@ export function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold
|
|
|
33
39
|
const target = remountSyncTarget.value
|
|
34
40
|
if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
|
|
35
41
|
remountSyncTarget.value = null
|
|
36
|
-
if (onRemountSynced)
|
|
42
|
+
if (onRemountSynced) scheduleOnRN(callWorkletCallback, remountSyncedKey, y)
|
|
37
43
|
} else if (onRemountSyncRetry) {
|
|
38
|
-
|
|
44
|
+
scheduleOnRN(callWorkletCallback, remountSyncRetryKey, y)
|
|
39
45
|
}
|
|
40
46
|
return
|
|
41
47
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { callWorkletCallback, useWorkletCallback } from '@rific/core'
|
|
1
2
|
import { useCallback, useContext, useLayoutEffect, useRef, useState } from 'react'
|
|
2
|
-
import {
|
|
3
|
+
import { useAnimatedReaction, useAnimatedStyle, useSharedValue } from 'react-native-reanimated'
|
|
3
4
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
5
|
+
import { scheduleOnRN } from 'react-native-worklets'
|
|
4
6
|
|
|
5
7
|
import { ScrollViewContext } from '../ScrollViewContext'
|
|
6
8
|
|
|
@@ -19,6 +21,7 @@ export function useStickyHeaders(headerFixed: boolean, enabled: boolean): Sticky
|
|
|
19
21
|
const sectionYPositions = useSharedValue<number[]>([])
|
|
20
22
|
const sectionHeights = useSharedValue<number[]>([])
|
|
21
23
|
const [activeIndex, setActiveIndex] = useState(-1)
|
|
24
|
+
const activeIndexKey = useWorkletCallback(setActiveIndex)
|
|
22
25
|
// Mirrors activeIndex React state but lives on the UI thread for overlayStyle.
|
|
23
26
|
// Updated via useLayoutEffect so content and style always change together.
|
|
24
27
|
const contentIndexShared = useSharedValue(-1)
|
|
@@ -60,7 +63,7 @@ export function useStickyHeaders(headerFixed: boolean, enabled: boolean): Sticky
|
|
|
60
63
|
return active
|
|
61
64
|
},
|
|
62
65
|
(curr, prev) => {
|
|
63
|
-
if (curr !== prev)
|
|
66
|
+
if (curr !== prev) scheduleOnRN(callWorkletCallback, activeIndexKey, curr)
|
|
64
67
|
},
|
|
65
68
|
// Same web-only reanimated gap as useAnimatedStyle elsewhere in this file: this "prepare"
|
|
66
69
|
// function's own SharedValue reads (sectionYPositions, headerHeightShared, scrollPosition,
|
package/src/useKeyboardInset.ts
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
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'
|
|
4
|
-
import {
|
|
5
|
+
import { scheduleOnRN } from 'react-native-worklets'
|
|
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
|
-
|
|
14
|
+
scheduleOnRN(callWorkletCallback, keyboardHeightKey, e.height)
|
|
13
15
|
},
|
|
14
16
|
onEnd: (e) => {
|
|
15
17
|
'worklet'
|
|
16
|
-
|
|
18
|
+
scheduleOnRN(callWorkletCallback, keyboardHeightKey, e.height)
|
|
17
19
|
}
|
|
18
20
|
},
|
|
19
21
|
[]
|