react-native-keyboard-controller 1.20.7 → 1.21.0-beta.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.
Files changed (73) hide show
  1. package/android/.settings/org.eclipse.buildship.core.prefs +2 -0
  2. package/android/src/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +2 -0
  3. package/android/src/fabric/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +30 -0
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/ClippingScrollViewDecoratorViewManagerImpl.kt +13 -0
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/views/ClippingScrollViewDecoratorView.kt +37 -0
  6. package/android/src/paper/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +24 -0
  7. package/ios/KeyboardController.xcodeproj/xcuserdata/kirylziusko.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  8. package/ios/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  9. package/ios/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  10. package/ios/Tests/Tests.xcodeproj/project.xcworkspace/xcuserdata/kirylziusko.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  11. package/ios/Tests/Tests.xcodeproj/xcuserdata/kirylziusko.xcuserdatad/xcschemes/xcschememanagement.plist +32 -0
  12. package/ios/animations/KeyboardAnimation.swift +2 -2
  13. package/ios/animations/SpringAnimation.swift +1 -1
  14. package/ios/animations/TimingAnimation.swift +1 -3
  15. package/ios/delegates/KCTextInputCompositeDelegate.swift +2 -2
  16. package/ios/extensions/CGFloat.swift +1 -3
  17. package/ios/interactive/KeyboardAreaExtender.swift +2 -1
  18. package/ios/observers/FocusedInputObserver.swift +4 -2
  19. package/ios/observers/movement/KeyboardTrackingView.swift +4 -1
  20. package/ios/observers/movement/observer/KeyboardMovementObserver+Interactive.swift +4 -0
  21. package/ios/protocols/TextInput.swift +1 -1
  22. package/ios/swizzling/UIResponderSwizzle.swift +2 -4
  23. package/ios/traversal/FocusedInputHolder.swift +3 -3
  24. package/ios/traversal/KeyboardView.swift +1 -1
  25. package/ios/traversal/ViewHierarchyNavigator.swift +2 -2
  26. package/ios/views/KeyboardControllerViewManager.swift +5 -5
  27. package/lib/commonjs/bindings.js +7 -1
  28. package/lib/commonjs/bindings.js.map +1 -1
  29. package/lib/commonjs/bindings.native.js +4 -1
  30. package/lib/commonjs/bindings.native.js.map +1 -1
  31. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +77 -22
  32. package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
  33. package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js +43 -0
  34. package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js.map +1 -0
  35. package/lib/commonjs/components/ScrollViewWithBottomPadding/styles.js +14 -0
  36. package/lib/commonjs/components/ScrollViewWithBottomPadding/styles.js.map +1 -0
  37. package/lib/commonjs/components/hooks/useScrollState.js +43 -0
  38. package/lib/commonjs/components/hooks/useScrollState.js.map +1 -0
  39. package/lib/commonjs/specs/ClippingScrollViewDecoratorViewNativeComponent.js +12 -0
  40. package/lib/commonjs/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -0
  41. package/lib/commonjs/types/views.js.map +1 -1
  42. package/lib/module/bindings.js +6 -0
  43. package/lib/module/bindings.js.map +1 -1
  44. package/lib/module/bindings.native.js +3 -0
  45. package/lib/module/bindings.native.js.map +1 -1
  46. package/lib/module/components/KeyboardAwareScrollView/index.js +78 -23
  47. package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
  48. package/lib/module/components/ScrollViewWithBottomPadding/index.js +35 -0
  49. package/lib/module/components/ScrollViewWithBottomPadding/index.js.map +1 -0
  50. package/lib/module/components/ScrollViewWithBottomPadding/styles.js +8 -0
  51. package/lib/module/components/ScrollViewWithBottomPadding/styles.js.map +1 -0
  52. package/lib/module/components/hooks/useScrollState.js +37 -0
  53. package/lib/module/components/hooks/useScrollState.js.map +1 -0
  54. package/lib/module/specs/ClippingScrollViewDecoratorViewNativeComponent.js +6 -0
  55. package/lib/module/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -0
  56. package/lib/module/types/views.js.map +1 -1
  57. package/lib/typescript/bindings.d.ts +7 -1
  58. package/lib/typescript/bindings.native.d.ts +1 -0
  59. package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +3 -2
  60. package/lib/typescript/components/ScrollViewWithBottomPadding/index.d.ts +12 -0
  61. package/lib/typescript/components/ScrollViewWithBottomPadding/styles.d.ts +6 -0
  62. package/lib/typescript/components/hooks/useScrollState.d.ts +14 -0
  63. package/lib/typescript/specs/ClippingScrollViewDecoratorViewNativeComponent.d.ts +8 -0
  64. package/lib/typescript/types/views.d.ts +4 -0
  65. package/package.json +4 -3
  66. package/src/bindings.native.ts +5 -0
  67. package/src/bindings.ts +8 -0
  68. package/src/components/KeyboardAwareScrollView/index.tsx +111 -28
  69. package/src/components/ScrollViewWithBottomPadding/index.tsx +72 -0
  70. package/src/components/ScrollViewWithBottomPadding/styles.ts +9 -0
  71. package/src/components/hooks/useScrollState.ts +59 -0
  72. package/src/specs/ClippingScrollViewDecoratorViewNativeComponent.ts +17 -0
  73. package/src/types/views.ts +6 -0
@@ -1,6 +1,7 @@
1
1
  import { NativeEventEmitter, Platform } from "react-native";
2
2
 
3
3
  import type {
4
+ ClippingScrollViewProps,
4
5
  FocusedInputEventsModule,
5
6
  KeyboardBackgroundViewProps,
6
7
  KeyboardControllerNativeModule,
@@ -71,3 +72,7 @@ export const RCTKeyboardExtender: React.FC<KeyboardExtenderProps> =
71
72
  Platform.OS === "ios"
72
73
  ? require("./specs/KeyboardExtenderNativeComponent").default
73
74
  : ({ children }: KeyboardExtenderProps) => children;
75
+ export const ClippingScrollView: React.FC<KeyboardBackgroundViewProps> =
76
+ Platform.OS === "android"
77
+ ? require("./specs/ClippingScrollViewDecoratorViewNativeComponent").default
78
+ : ({ children }: ClippingScrollViewProps) => children;
package/src/bindings.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { View } from "react-native";
2
2
 
3
3
  import type {
4
+ ClippingScrollViewProps,
4
5
  FocusedInputEventsModule,
5
6
  KeyboardBackgroundViewProps,
6
7
  KeyboardControllerNativeModule,
@@ -82,3 +83,10 @@ export const KeyboardBackgroundView =
82
83
  */
83
84
  export const RCTKeyboardExtender =
84
85
  View as unknown as React.FC<KeyboardExtenderProps>;
86
+ /**
87
+ * A decorator that will clip the content of the `ScrollView`. It helps to simulate `contentInset` behavior on Android.
88
+ * Supports only `bottom` property (`paddingBottom` is not supported property of `ScrollView.style`).
89
+ * Using this component we can modify bottom inset without having a fake view.
90
+ */
91
+ export const ClippingScrollView =
92
+ View as unknown as React.FC<ClippingScrollViewProps>;
@@ -12,8 +12,7 @@ import Reanimated, {
12
12
  scrollTo,
13
13
  useAnimatedReaction,
14
14
  useAnimatedRef,
15
- useAnimatedStyle,
16
- useScrollViewOffset,
15
+ useDerivedValue,
17
16
  useSharedValue,
18
17
  } from "react-native-reanimated";
19
18
 
@@ -24,10 +23,13 @@ import {
24
23
  } from "../../hooks";
25
24
  import { findNodeHandle } from "../../utils/findNodeHandle";
26
25
  import useCombinedRef from "../hooks/useCombinedRef";
26
+ import useScrollState from "../hooks/useScrollState";
27
+ import ScrollViewWithBottomPadding from "../ScrollViewWithBottomPadding";
27
28
 
28
29
  import { useSmoothKeyboardHandler } from "./useSmoothKeyboardHandler";
29
30
  import { debounce, scrollDistanceWithRespectToSnapPoints } from "./utils";
30
31
 
32
+ import type { AnimatedScrollViewComponent } from "../ScrollViewWithBottomPadding";
31
33
  import type {
32
34
  LayoutChangeEvent,
33
35
  ScrollView,
@@ -49,7 +51,7 @@ export type KeyboardAwareScrollViewProps = {
49
51
  /** Adjusting the bottom spacing of KeyboardAwareScrollView. Default is `0`. */
50
52
  extraKeyboardSpace?: number;
51
53
  /** Custom component for `ScrollView`. Default is `ScrollView`. */
52
- ScrollViewComponent?: React.ComponentType<ScrollViewProps>;
54
+ ScrollViewComponent?: AnimatedScrollViewComponent;
53
55
  } & ScrollViewProps;
54
56
  export type KeyboardAwareScrollViewRef = {
55
57
  assureFocusedInputVisible: () => void;
@@ -131,7 +133,11 @@ const KeyboardAwareScrollView = forwardRef<
131
133
  const onRef = useCombinedRef(scrollViewAnimatedRef, scrollViewRef);
132
134
  const scrollViewTarget = useSharedValue<number | null>(null);
133
135
  const scrollPosition = useSharedValue(0);
134
- const position = useScrollViewOffset(scrollViewAnimatedRef);
136
+ const {
137
+ offset: position,
138
+ layout: scrollViewLayout,
139
+ size: scrollViewContentSize,
140
+ } = useScrollState(scrollViewAnimatedRef);
135
141
  const currentKeyboardFrameHeight = useSharedValue(0);
136
142
  const keyboardHeight = useSharedValue(0);
137
143
  const keyboardWillAppear = useSharedValue(false);
@@ -142,6 +148,8 @@ const KeyboardAwareScrollView = forwardRef<
142
148
  const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);
143
149
  const lastSelection =
144
150
  useSharedValue<FocusedInputSelectionChangedEvent | null>(null);
151
+ const ghostViewSpace = useSharedValue(-1);
152
+ const pendingSelectionForFocus = useSharedValue(false);
145
153
 
146
154
  const { height } = useWindowDimensions();
147
155
 
@@ -213,6 +221,30 @@ const KeyboardAwareScrollView = forwardRef<
213
221
  },
214
222
  [bottomOffset, enabled, height, snapToOffsets],
215
223
  );
224
+ const removeGhostPadding = useCallback((e: number) => {
225
+ "worklet";
226
+
227
+ // new `ScrollViewWithBottomPadding` behavior: if we hide keyboard and we are in the end of `ScrollView`
228
+ // then we always need to scroll back, because we apply a padding that doesn't change layout, so we will
229
+ // not have auto scroll back in this case
230
+ if (!keyboardWillAppear.value && ghostViewSpace.value > 0) {
231
+ scrollTo(
232
+ scrollViewAnimatedRef,
233
+ 0,
234
+ scrollPosition.value -
235
+ interpolate(
236
+ e,
237
+ [initialKeyboardSize.value, keyboardHeight.value],
238
+ [ghostViewSpace.value, 0],
239
+ ),
240
+ false,
241
+ );
242
+
243
+ return true;
244
+ }
245
+
246
+ return false;
247
+ }, []);
216
248
  const performScrollWithPositionRestoration = useCallback(
217
249
  (newPosition: number) => {
218
250
  "worklet";
@@ -293,7 +325,18 @@ const KeyboardAwareScrollView = forwardRef<
293
325
  lastSelection.value = e;
294
326
 
295
327
  if (e.target !== lastTarget) {
296
- // ignore this event, because "focus changed" event handled in `useSmoothKeyboardHandler`
328
+ if (pendingSelectionForFocus.value) {
329
+ // selection arrived after onStart - complete the deferred setup
330
+ pendingSelectionForFocus.value = false;
331
+ updateLayoutFromSelection();
332
+
333
+ // if keyboard was already visible (focus change, no onMove expected),
334
+ // perform the deferred scroll now
335
+ if (!keyboardWillAppear.value && keyboardHeight.value > 0) {
336
+ position.value += maybeScroll(keyboardHeight.value, true);
337
+ }
338
+ }
339
+
297
340
  return;
298
341
  }
299
342
  // caret in the end + end coordinates has been changed -> we moved to a new line
@@ -311,7 +354,12 @@ const KeyboardAwareScrollView = forwardRef<
311
354
 
312
355
  onChangeTextHandler();
313
356
  },
314
- [scrollFromCurrentPosition, onChangeTextHandler],
357
+ [
358
+ scrollFromCurrentPosition,
359
+ onChangeTextHandler,
360
+ updateLayoutFromSelection,
361
+ maybeScroll,
362
+ ],
315
363
  );
316
364
 
317
365
  useFocusedInputHandler(
@@ -344,6 +392,7 @@ const KeyboardAwareScrollView = forwardRef<
344
392
  // on back transition need to interpolate as [0, keyboardHeight]
345
393
  initialKeyboardSize.value = 0;
346
394
  scrollPosition.value = scrollBeforeKeyboardMovement.value;
395
+ pendingSelectionForFocus.value = false;
347
396
  }
348
397
 
349
398
  if (
@@ -360,17 +409,40 @@ const KeyboardAwareScrollView = forwardRef<
360
409
  // focus was changed
361
410
  if (focusWasChanged) {
362
411
  tag.value = e.target;
363
- // save position of focused text input when keyboard starts to move
364
- updateLayoutFromSelection();
412
+
413
+ if (lastSelection.value?.target === e.target) {
414
+ // selection arrived before onStart - use it to update layout
415
+ updateLayoutFromSelection();
416
+ pendingSelectionForFocus.value = false;
417
+ } else {
418
+ // selection hasn't arrived yet for the new target.
419
+ // use input layout as-is; will be refined when selection arrives.
420
+ if (input.value) {
421
+ layout.value = input.value;
422
+ }
423
+ pendingSelectionForFocus.value = true;
424
+ }
425
+
365
426
  // save current scroll position - when keyboard will hide we'll reuse
366
427
  // this value to achieve smooth hide effect
367
428
  scrollBeforeKeyboardMovement.value = position.value;
368
429
  }
369
430
 
370
431
  if (focusWasChanged && !keyboardWillAppear.value) {
371
- // update position on scroll value, so `onEnd` handler
372
- // will pick up correct values
373
- position.value += maybeScroll(e.height, true);
432
+ if (!pendingSelectionForFocus.value) {
433
+ // update position on scroll value, so `onEnd` handler
434
+ // will pick up correct values
435
+ position.value += maybeScroll(e.height, true);
436
+ }
437
+ }
438
+
439
+ ghostViewSpace.value =
440
+ position.value +
441
+ scrollViewLayout.value.height -
442
+ scrollViewContentSize.value.height;
443
+
444
+ if (ghostViewSpace.value > 0) {
445
+ scrollPosition.value = position.value;
374
446
  }
375
447
  },
376
448
  onMove: (e) => {
@@ -378,6 +450,10 @@ const KeyboardAwareScrollView = forwardRef<
378
450
 
379
451
  syncKeyboardFrame(e);
380
452
 
453
+ if (removeGhostPadding(e.height)) {
454
+ return;
455
+ }
456
+
381
457
  // if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
382
458
  if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
383
459
  maybeScroll(e.height);
@@ -386,13 +462,24 @@ const KeyboardAwareScrollView = forwardRef<
386
462
  onEnd: (e) => {
387
463
  "worklet";
388
464
 
465
+ removeGhostPadding(e.height);
466
+
389
467
  keyboardHeight.value = e.height;
390
468
  scrollPosition.value = position.value;
391
469
 
470
+ if (e.height === 0) {
471
+ lastSelection.value = null;
472
+ }
473
+
392
474
  syncKeyboardFrame(e);
393
475
  },
394
476
  },
395
- [maybeScroll, disableScrollOnKeyboardHide, syncKeyboardFrame],
477
+ [
478
+ maybeScroll,
479
+ removeGhostPadding,
480
+ disableScrollOnKeyboardHide,
481
+ syncKeyboardFrame,
482
+ ],
396
483
  );
397
484
 
398
485
  const synchronize = useCallback(async () => {
@@ -443,32 +530,28 @@ const KeyboardAwareScrollView = forwardRef<
443
530
  [],
444
531
  );
445
532
 
446
- const view = useAnimatedStyle(
447
- () =>
448
- enabled
449
- ? {
450
- // animations become choppy when scrolling to the end of the `ScrollView` (when the last input is focused)
451
- // this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
452
- // by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
453
- // from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
454
- // re-calculation on every animation frame and it helps to achieve smooth animation.
455
- // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
456
- paddingBottom: currentKeyboardFrameHeight.value + 1,
457
- }
458
- : {},
533
+ // animations become choppy when scrolling to the end of the `ScrollView` (when the last input is focused)
534
+ // this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
535
+ // by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
536
+ // from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
537
+ // re-calculation on every animation frame and it helps to achieve smooth animation.
538
+ // see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
539
+ const padding = useDerivedValue(
540
+ () => (enabled ? currentKeyboardFrameHeight.value + 1 : 0),
459
541
  [enabled],
460
542
  );
461
543
 
462
544
  return (
463
- <ScrollViewComponent
545
+ <ScrollViewWithBottomPadding
464
546
  ref={onRef}
465
547
  {...rest}
548
+ bottomPadding={padding}
466
549
  scrollEventThrottle={16}
550
+ ScrollViewComponent={ScrollViewComponent}
467
551
  onLayout={onScrollViewLayout}
468
552
  >
469
553
  {children}
470
- {enabled && <Reanimated.View style={view} />}
471
- </ScrollViewComponent>
554
+ </ScrollViewWithBottomPadding>
472
555
  );
473
556
  },
474
557
  );
@@ -0,0 +1,72 @@
1
+ import React, { forwardRef } from "react";
2
+ import { Platform } from "react-native";
3
+ import Reanimated, { useAnimatedProps } from "react-native-reanimated";
4
+
5
+ import { ClippingScrollView } from "../../bindings";
6
+
7
+ import styles from "./styles";
8
+
9
+ import type { ScrollViewProps } from "react-native";
10
+ import type { SharedValue } from "react-native-reanimated";
11
+
12
+ const ReanimatedClippingScrollView =
13
+ Platform.OS === "android"
14
+ ? Reanimated.createAnimatedComponent(ClippingScrollView)
15
+ : ClippingScrollView;
16
+
17
+ type AnimatedScrollViewProps = React.ComponentProps<
18
+ typeof Reanimated.ScrollView
19
+ >;
20
+
21
+ export type AnimatedScrollViewComponent = React.ForwardRefExoticComponent<
22
+ AnimatedScrollViewProps & React.RefAttributes<Reanimated.ScrollView>
23
+ >;
24
+
25
+ type ScrollViewWithBottomPaddingProps = {
26
+ ScrollViewComponent: AnimatedScrollViewComponent;
27
+ children?: React.ReactNode;
28
+ bottomPadding: SharedValue<number>;
29
+ } & ScrollViewProps;
30
+
31
+ const ScrollViewWithBottomPadding = forwardRef<
32
+ Reanimated.ScrollView,
33
+ ScrollViewWithBottomPaddingProps
34
+ >(
35
+ (
36
+ { ScrollViewComponent, bottomPadding, contentInset, children, ...rest },
37
+ ref,
38
+ ) => {
39
+ const animatedProps = useAnimatedProps(
40
+ () => ({
41
+ // iOS prop
42
+ contentInset: {
43
+ bottom: bottomPadding.value + (contentInset?.bottom || 0),
44
+ top: contentInset?.top,
45
+ right: contentInset?.right,
46
+ left: contentInset?.left,
47
+ },
48
+ // Android prop
49
+ contentInsetBottom: bottomPadding.value,
50
+ }),
51
+ [
52
+ contentInset?.bottom,
53
+ contentInset?.top,
54
+ contentInset?.right,
55
+ contentInset?.left,
56
+ ],
57
+ );
58
+
59
+ return (
60
+ <ReanimatedClippingScrollView
61
+ animatedProps={animatedProps}
62
+ style={styles.container}
63
+ >
64
+ <ScrollViewComponent ref={ref} animatedProps={animatedProps} {...rest}>
65
+ {children}
66
+ </ScrollViewComponent>
67
+ </ReanimatedClippingScrollView>
68
+ );
69
+ },
70
+ );
71
+
72
+ export default ScrollViewWithBottomPadding;
@@ -0,0 +1,9 @@
1
+ import { StyleSheet } from "react-native";
2
+
3
+ const styles = StyleSheet.create({
4
+ container: {
5
+ flex: 1,
6
+ },
7
+ });
8
+
9
+ export default styles;
@@ -0,0 +1,59 @@
1
+ import { useEffect } from "react";
2
+ import { useEvent, useSharedValue } from "react-native-reanimated";
3
+
4
+ import { useEventHandlerRegistration } from "../../internal";
5
+
6
+ import type { AnimatedRef } from "react-native-reanimated";
7
+ import type Reanimated from "react-native-reanimated";
8
+
9
+ const NATIVE_SCROLL_EVENT_NAMES = [
10
+ "onScroll",
11
+ "onScrollBeginDrag",
12
+ "onScrollEndDrag",
13
+ "onMomentumScrollBegin",
14
+ "onMomentumScrollEnd",
15
+ ];
16
+
17
+ type ScrollEvent = {
18
+ contentOffset: {
19
+ x: number;
20
+ y: number;
21
+ };
22
+ layoutMeasurement: {
23
+ width: number;
24
+ height: number;
25
+ };
26
+ contentSize: {
27
+ width: number;
28
+ height: number;
29
+ };
30
+ };
31
+
32
+ const useScrollState = (ref: AnimatedRef<Reanimated.ScrollView>) => {
33
+ const offset = useSharedValue(0);
34
+ const layout = useSharedValue({ width: 0, height: 0 });
35
+ const size = useSharedValue({ width: 0, height: 0 });
36
+
37
+ const register = useEventHandlerRegistration(ref);
38
+
39
+ const eventHandler = useEvent((event: ScrollEvent) => {
40
+ "worklet";
41
+
42
+ // eslint-disable-next-line react-compiler/react-compiler
43
+ offset.value = event.contentOffset.y;
44
+ layout.value = event.layoutMeasurement;
45
+ size.value = event.contentSize;
46
+ }, NATIVE_SCROLL_EVENT_NAMES);
47
+
48
+ useEffect(() => {
49
+ const cleanup = register(eventHandler);
50
+
51
+ return () => {
52
+ cleanup();
53
+ };
54
+ }, []);
55
+
56
+ return { offset, layout, size };
57
+ };
58
+
59
+ export default useScrollState;
@@ -0,0 +1,17 @@
1
+ import { codegenNativeComponent } from "react-native";
2
+
3
+ import type { HostComponent } from "react-native";
4
+ import type { ViewProps } from "react-native";
5
+ import type { Double } from "react-native/Libraries/Types/CodegenTypes";
6
+
7
+ export interface NativeProps extends ViewProps {
8
+ contentInsetBottom: Double;
9
+ }
10
+
11
+ export default codegenNativeComponent<NativeProps>(
12
+ "ClippingScrollViewDecoratorView",
13
+ {
14
+ interfaceOnly: true,
15
+ excludedPlatforms: ["iOS"],
16
+ },
17
+ ) as HostComponent<NativeProps>;
@@ -49,3 +49,9 @@ export type KeyboardExtenderProps = PropsWithChildren<{
49
49
  /** Controls whether this `KeyboardExtender` instance should take an effect. Default is `true`. */
50
50
  enabled?: boolean;
51
51
  }>;
52
+ export type ClippingScrollViewProps = PropsWithChildren<
53
+ ViewProps & {
54
+ /** An additional space that gets applied to the bottom of the `ScrollView` (inside a scrollable content). Default is `0`. */
55
+ contentInsetBottom?: number;
56
+ }
57
+ >;