@sdcx/bottom-sheet 1.0.5 → 1.0.7

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.
@@ -13,7 +13,10 @@ Pod::Spec.new do |s|
13
13
  s.platforms = { :ios => min_ios_version_supported }
14
14
  s.source = { :git => "https://github.com/github-account/bottom-sheet.git", :tag => "#{s.version}" }
15
15
 
16
- s.source_files = "ios/**/*.{h,m,mm}"
16
+ s.source_files = "ios/**/*.{h,m,mm}", "common/cpp/**/*.{cpp,h}"
17
+ s.pod_target_xcconfig = {
18
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\""
19
+ }
17
20
 
18
21
  install_modules_dependencies(s)
19
22
  end
@@ -87,6 +87,9 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
87
87
 
88
88
  private int contentHeight = -1;
89
89
 
90
+ /** 子 View 的布局 top,用于计算 getContentOriginOffset 的差值 (实际 top - layoutContentTop) */
91
+ private int layoutContentTop = -1;
92
+
90
93
  @Override
91
94
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
92
95
  if (viewDragHelper == null) {
@@ -114,10 +117,20 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
114
117
 
115
118
  getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
116
119
  int top = contentView.getTop();
120
+ boolean isFirstLayout = layoutContentTop < 0;
121
+ if (layoutContentTop < 0) {
122
+ layoutContentTop = top;
123
+ }
117
124
  if (status == COLLAPSED) {
118
125
  child.offsetTopAndBottom(collapsedOffset - top);
119
126
  } else if (status == EXPANDED) {
120
- child.offsetTopAndBottom(expandedOffset - top);
127
+ if (isFirstLayout) {
128
+ // 与 iOS 一致:首次 layout 且为 expanded 时先置于 collapsed 再播放展开动画
129
+ child.offsetTopAndBottom(collapsedOffset - top);
130
+ ViewCompat.postOnAnimation(child, () -> settleToStatus(contentView, EXPANDED));
131
+ } else {
132
+ child.offsetTopAndBottom(expandedOffset - top);
133
+ }
121
134
  } else if (status == HIDDEN) {
122
135
  child.offsetTopAndBottom(getHeight() - top);
123
136
  }
@@ -530,6 +543,10 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
530
543
 
531
544
  void dispatchOnSlide(int top) {
532
545
  if (contentView != null) {
546
+ if (contentView instanceof BottomSheetContentView && layoutContentTop >= 0) {
547
+ int offsetY = top - layoutContentTop;
548
+ ((BottomSheetContentView) contentView).updateContentOffset(offsetY);
549
+ }
533
550
  sentEvent(new OnSlideEvent(UIManagerHelper.getSurfaceId(reactContext), getId(), top, expandedOffset, collapsedOffset));
534
551
  }
535
552
  }
@@ -0,0 +1,39 @@
1
+ package com.reactnative.bottomsheet;
2
+
3
+ import android.content.Context;
4
+
5
+ import com.facebook.react.bridge.Arguments;
6
+ import com.facebook.react.bridge.WritableMap;
7
+ import com.facebook.react.uimanager.PixelUtil;
8
+ import com.facebook.react.uimanager.StateWrapper;
9
+ import com.facebook.react.views.view.ReactViewGroup;
10
+
11
+ /**
12
+ * Content view for BottomSheet. Implements getContentOriginOffset via state so that
13
+ * hit-testing uses the correct coordinates when the parent BottomSheet moves this view.
14
+ */
15
+ public class BottomSheetContentView extends ReactViewGroup {
16
+
17
+ @SuppressWarnings("NullableProblems")
18
+ private StateWrapper stateWrapper;
19
+
20
+ public BottomSheetContentView(Context context) {
21
+ super(context);
22
+ }
23
+
24
+ public void setStateWrapper(StateWrapper wrapper) {
25
+ this.stateWrapper = wrapper;
26
+ }
27
+
28
+ /**
29
+ * Updates Fabric state with content offset (actual top - layout top) so that
30
+ * getContentOriginOffset can correct hit-testing. Called by the parent BottomSheet.
31
+ */
32
+ public void updateContentOffset(int offsetPx) {
33
+ if (stateWrapper != null) {
34
+ WritableMap map = Arguments.createMap();
35
+ map.putDouble("contentOffset", PixelUtil.toDIPFromPixel(offsetPx));
36
+ stateWrapper.updateState(map);
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,46 @@
1
+ package com.reactnative.bottomsheet;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ import com.facebook.react.uimanager.ReactStylesDiffMap;
7
+ import com.facebook.react.uimanager.StateWrapper;
8
+ import com.facebook.react.uimanager.ThemedReactContext;
9
+ import com.facebook.react.uimanager.ViewGroupManager;
10
+ import com.facebook.react.uimanager.ViewManagerDelegate;
11
+ import com.facebook.react.viewmanagers.BottomSheetContentViewManagerDelegate;
12
+ import com.facebook.react.viewmanagers.BottomSheetContentViewManagerInterface;
13
+
14
+ public class BottomSheetContentViewManager extends ViewGroupManager<BottomSheetContentView>
15
+ implements BottomSheetContentViewManagerInterface<BottomSheetContentView> {
16
+
17
+ private final BottomSheetContentViewManagerDelegate<BottomSheetContentView, BottomSheetContentViewManager> mDelegate =
18
+ new BottomSheetContentViewManagerDelegate<>(this);
19
+
20
+ @Override
21
+ protected ViewManagerDelegate<BottomSheetContentView> getDelegate() {
22
+ return mDelegate;
23
+ }
24
+
25
+ @NonNull
26
+ @Override
27
+ public String getName() {
28
+ return "BottomSheetContentView";
29
+ }
30
+
31
+ @NonNull
32
+ @Override
33
+ protected BottomSheetContentView createViewInstance(@NonNull ThemedReactContext context) {
34
+ return new BottomSheetContentView(context);
35
+ }
36
+
37
+ @Nullable
38
+ @Override
39
+ public Object updateState(
40
+ @NonNull BottomSheetContentView view,
41
+ ReactStylesDiffMap props,
42
+ StateWrapper stateWrapper) {
43
+ view.setStateWrapper(stateWrapper);
44
+ return super.updateState(view, props, stateWrapper);
45
+ }
46
+ }
@@ -2,6 +2,7 @@ package com.reactnative.bottomsheet;
2
2
 
3
3
  import androidx.annotation.NonNull;
4
4
 
5
+ import java.util.Arrays;
5
6
  import java.util.Collections;
6
7
  import java.util.List;
7
8
 
@@ -20,6 +21,6 @@ public class BottomSheetPackage implements ReactPackage {
20
21
  @NonNull
21
22
  @Override
22
23
  public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
23
- return Collections.singletonList(new BottomSheetManager());
24
+ return Arrays.asList(new BottomSheetManager(), new BottomSheetContentViewManager());
24
25
  }
25
26
  }
@@ -0,0 +1,91 @@
1
+ cmake_minimum_required(VERSION 3.13)
2
+ set(CMAKE_VERBOSE_MAKEFILE ON)
3
+
4
+ set(LIB_LITERAL bottomsheet)
5
+ set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL})
6
+
7
+ set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
8
+ set(LIB_COMMON_DIR ${LIB_ANDROID_DIR}/../common/cpp)
9
+ set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni)
10
+ set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL})
11
+
12
+ file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp)
13
+ file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_JNI_DIR}/*.cpp ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp)
14
+
15
+ add_library(
16
+ ${LIB_TARGET_NAME}
17
+ SHARED
18
+ ${LIB_CUSTOM_SRCS}
19
+ ${LIB_CODEGEN_SRCS}
20
+ )
21
+
22
+ target_include_directories(
23
+ ${LIB_TARGET_NAME}
24
+ PUBLIC
25
+ .
26
+ ${LIB_COMMON_DIR}
27
+ ${LIB_ANDROID_GENERATED_JNI_DIR}
28
+ ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}
29
+ )
30
+
31
+ if (REACTNATIVE_MERGED_SO)
32
+ target_link_libraries(
33
+ ${LIB_TARGET_NAME}
34
+ fbjni
35
+ jsi
36
+ reactnative
37
+ )
38
+ else()
39
+ target_link_libraries(
40
+ ${LIB_TARGET_NAME}
41
+ fbjni
42
+ folly_runtime
43
+ glog
44
+ jsi
45
+ react_codegen_rncore
46
+ react_debug
47
+ react_render_componentregistry
48
+ react_render_core
49
+ react_render_debug
50
+ react_render_graphics
51
+ react_render_imagemanager
52
+ react_render_mapbuffer
53
+ react_utils
54
+ react_nativemodule_core
55
+ rrc_image
56
+ turbomodulejsijni
57
+ rrc_view
58
+ yoga
59
+ )
60
+ endif()
61
+
62
+ if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 81)
63
+ target_compile_reactnative_options(${LIB_TARGET_NAME} PUBLIC)
64
+ else()
65
+ target_compile_options(
66
+ ${LIB_TARGET_NAME}
67
+ PRIVATE
68
+ -fexceptions
69
+ -frtti
70
+ -std=c++20
71
+ -Wall
72
+ -Wpedantic
73
+ -Wno-gnu-zero-variadic-macro-arguments
74
+ )
75
+ endif()
76
+
77
+ target_compile_options(
78
+ ${LIB_TARGET_NAME}
79
+ PRIVATE
80
+ -DLOG_TAG=\"ReactNative\"
81
+ -fexceptions
82
+ -frtti
83
+ -std=c++20
84
+ -Wall
85
+ )
86
+
87
+ target_include_directories(
88
+ ${CMAKE_PROJECT_NAME}
89
+ PUBLIC
90
+ ${CMAKE_CURRENT_SOURCE_DIR}
91
+ )
@@ -0,0 +1,17 @@
1
+ #pragma once
2
+
3
+ #include <ReactCommon/JavaTurboModule.h>
4
+ #include <ReactCommon/TurboModule.h>
5
+ #include <jsi/jsi.h>
6
+ #include <react/renderer/components/bottomsheet/BottomSheetContentViewComponentDescriptor.h>
7
+
8
+ namespace facebook {
9
+ namespace react {
10
+
11
+ JSI_EXPORT
12
+ std::shared_ptr<TurboModule> bottomsheet_ModuleProvider(
13
+ const std::string &moduleName,
14
+ const JavaTurboModule::InitParams &params);
15
+
16
+ } // namespace react
17
+ } // namespace facebook
@@ -0,0 +1,18 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/bottomsheet/BottomSheetContentViewShadowNode.h>
4
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
5
+
6
+ namespace facebook {
7
+ namespace react {
8
+
9
+ /*
10
+ * Descriptor for <BottomSheetContentView> component.
11
+ */
12
+ class BottomSheetContentViewComponentDescriptor final
13
+ : public ConcreteComponentDescriptor<BottomSheetContentViewShadowNode> {
14
+ using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
15
+ };
16
+
17
+ } // namespace react
18
+ } // namespace facebook
@@ -0,0 +1,19 @@
1
+ #include "BottomSheetContentViewShadowNode.h"
2
+
3
+ namespace facebook {
4
+ namespace react {
5
+
6
+ extern const char BottomSheetContentViewComponentName[] = "BottomSheetContentView";
7
+
8
+ Point BottomSheetContentViewShadowNode::getContentOriginOffset(bool includeTransform) const {
9
+ auto stateData = getStateData();
10
+ auto contentOffset = stateData.contentOffset;
11
+
12
+ return {
13
+ .x = 0,
14
+ .y = static_cast<Float>(contentOffset),
15
+ };
16
+ }
17
+
18
+ } // namespace react
19
+ } // namespace facebook
@@ -0,0 +1,32 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+ #include <react/renderer/components/bottomsheet/BottomSheetContentViewState.h>
5
+ #include <react/renderer/components/bottomsheet/EventEmitters.h>
6
+ #include <react/renderer/components/bottomsheet/Props.h>
7
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
8
+
9
+ namespace facebook {
10
+ namespace react {
11
+
12
+ JSI_EXPORT extern const char BottomSheetContentViewComponentName[];
13
+
14
+ /*
15
+ * ShadowNode for <BottomSheetContentView>. getContentOriginOffset returns
16
+ * the view's top offset so that RN hit-testing uses the correct coordinates
17
+ * when the parent BottomSheet has moved this content view.
18
+ */
19
+ class JSI_EXPORT BottomSheetContentViewShadowNode final
20
+ : public ConcreteViewShadowNode<
21
+ BottomSheetContentViewComponentName,
22
+ BottomSheetContentViewProps,
23
+ ViewEventEmitter,
24
+ BottomSheetContentViewState> {
25
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
26
+
27
+ public:
28
+ Point getContentOriginOffset(bool includeTransform) const override;
29
+ };
30
+
31
+ } // namespace react
32
+ } // namespace facebook
@@ -0,0 +1,15 @@
1
+ #include "BottomSheetContentViewState.h"
2
+
3
+ namespace facebook {
4
+ namespace react {
5
+
6
+ #ifdef ANDROID
7
+ folly::dynamic BottomSheetContentViewState::getDynamic() const {
8
+ folly::dynamic data = folly::dynamic::object();
9
+ data["contentOffset"] = contentOffset;
10
+ return data;
11
+ }
12
+ #endif
13
+
14
+ } // namespace react
15
+ } // namespace facebook
@@ -0,0 +1,42 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/bottomsheet/Props.h>
4
+
5
+ #ifdef ANDROID
6
+ #include <folly/dynamic.h>
7
+ #include <react/renderer/mapbuffer/MapBuffer.h>
8
+ #include <react/renderer/mapbuffer/MapBufferBuilder.h>
9
+ #endif
10
+
11
+ namespace facebook {
12
+ namespace react {
13
+
14
+ /*
15
+ * State for <BottomSheetContentView> component. contentOffset is the offset
16
+ * (actual top - layout top) of this view. Used by getContentOriginOffset
17
+ * so that hit-testing uses the correct content origin when the sheet moves the view.
18
+ */
19
+ class JSI_EXPORT BottomSheetContentViewState final {
20
+ public:
21
+ using Shared = std::shared_ptr<const BottomSheetContentViewState>;
22
+
23
+ BottomSheetContentViewState() = default;
24
+
25
+ #ifdef ANDROID
26
+ BottomSheetContentViewState(
27
+ BottomSheetContentViewState const &previousState,
28
+ folly::dynamic data) {
29
+ contentOffset = data.getDefault("contentOffset", previousState.contentOffset).asDouble();
30
+ }
31
+ #endif
32
+
33
+ double contentOffset{};
34
+
35
+ #ifdef ANDROID
36
+ folly::dynamic getDynamic() const;
37
+ MapBuffer getMapBuffer() const { return MapBufferBuilder::EMPTY(); }
38
+ #endif
39
+ };
40
+
41
+ } // namespace react
42
+ } // namespace facebook
@@ -0,0 +1,5 @@
1
+ import type { HostComponent, ViewProps } from 'react-native';
2
+ export interface NativeProps extends ViewProps {
3
+ }
4
+ declare const _default: HostComponent<NativeProps>;
5
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { codegenNativeComponent } from 'react-native';
2
+ export default codegenNativeComponent('BottomSheetContentView', {
3
+ interfaceOnly: true,
4
+ });
package/dist/index.js CHANGED
@@ -1,18 +1,19 @@
1
1
  import React from 'react';
2
- import { StyleSheet, View } from 'react-native';
2
+ import { StyleSheet } from 'react-native';
3
3
  import splitLayoutProps from './splitLayoutProps';
4
4
  import BottomSheetNativeComponent from './BottomSheetNativeComponent';
5
+ import BottomSheetContentViewNativeComponent from './BottomSheetContentViewNativeComponent';
5
6
  function BottomSheet(props) {
6
7
  const { style, contentContainerStyle, children, peekHeight = 200, draggable = true, state = 'collapsed', fitToContents, ...rest } = props;
7
8
  const { outer, inner } = splitLayoutProps(StyleSheet.flatten(style));
8
9
  return (<BottomSheetNativeComponent style={[StyleSheet.absoluteFill, outer]} peekHeight={peekHeight} draggable={draggable} status={state} {...rest}>
9
- <View style={[
10
+ <BottomSheetContentViewNativeComponent style={[
10
11
  fitToContents ? styles.fitToContents : StyleSheet.absoluteFill,
11
12
  inner,
12
13
  contentContainerStyle,
13
14
  ]} collapsable={false}>
14
15
  {children}
15
- </View>
16
+ </BottomSheetContentViewNativeComponent>
16
17
  </BottomSheetNativeComponent>);
17
18
  }
18
19
  const styles = StyleSheet.create({
@@ -1,7 +1,7 @@
1
1
  import { ViewStyle } from 'react-native';
2
2
  export default function splitLayoutProps(props?: ViewStyle): {
3
3
  outer: {
4
- [key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").GradientValue[] | Readonly<{
4
+ [key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").BackgroundImageValue[] | readonly import("react-native").BackgroundSizeValue[] | readonly import("react-native").BackgroundPositionValue[] | readonly import("react-native").BackgroundRepeatValue[] | Readonly<{
5
5
  width: number;
6
6
  height: number;
7
7
  }> | readonly (({
@@ -202,7 +202,7 @@ export default function splitLayoutProps(props?: ViewStyle): {
202
202
  }))[] | (string | number)[] | number[] | null | undefined;
203
203
  };
204
204
  inner: {
205
- [key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").GradientValue[] | Readonly<{
205
+ [key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").BackgroundImageValue[] | readonly import("react-native").BackgroundSizeValue[] | readonly import("react-native").BackgroundPositionValue[] | readonly import("react-native").BackgroundRepeatValue[] | Readonly<{
206
206
  width: number;
207
207
  height: number;
208
208
  }> | readonly (({
@@ -2,6 +2,8 @@
2
2
  #import "RNBottomSheetStateChangedEvent.h"
3
3
  #import "RNBottomSheetOffsetChangedEvent.h"
4
4
 
5
+ #import "RNBottomSheetContentView.h"
6
+
5
7
  #import <react/renderer/components/bottomsheet/ComponentDescriptors.h>
6
8
  #import <react/renderer/components/bottomsheet/EventEmitters.h>
7
9
  #import <react/renderer/components/bottomsheet/Props.h>
@@ -58,6 +60,7 @@ using namespace facebook::react;
58
60
  __weak UIView *_rootView;
59
61
  BOOL _isInitialRender;
60
62
  __weak UIView *_reactRootView;
63
+ CGFloat _layoutContentTop; // 子 View 的布局 origin.y,用于 contentOffset = 实际 top - 布局 top
61
64
  }
62
65
 
63
66
  // Needed because of this: https://github.com/facebook/react-native/pull/37274
@@ -84,6 +87,7 @@ using namespace facebook::react;
84
87
  _status = BottomSheetStatus::Collapsed;
85
88
  _finalStatus = BottomSheetStatus::Collapsed;
86
89
  _isInitialRender = YES;
90
+ _layoutContentTop = NAN;
87
91
  }
88
92
  return self;
89
93
  }
@@ -228,7 +232,7 @@ using namespace facebook::react;
228
232
 
229
233
  dispatch_async(dispatch_get_main_queue(), ^{
230
234
  if (self.finalStatus == BottomSheetStatus::Expanded && self->_isInitialRender) {
231
- [self settleToStatus:self.finalStatus withFling:NO];
235
+ [self settleToStatus:self.finalStatus withFling:YES];
232
236
  }
233
237
 
234
238
  self->_isInitialRender = NO;
@@ -238,6 +242,18 @@ using namespace facebook::react;
238
242
  - (void)layoutChild {
239
243
  if (!CGRectEqualToRect(self.child.frame, CGRectZero) && !CGRectEqualToRect(self.frame, CGRectZero)) {
240
244
  [self calculateOffset];
245
+ // 仅当当前 frame.origin.y 不是“本轮要设的目标”时才视为布局结果并捕获,避免初始 collapsed + peekHeight 0 时误把已是 maxY 的 frame 当布局
246
+ if (isnan(_layoutContentTop)) {
247
+ CGFloat currentY = self.child.frame.origin.y;
248
+ CGFloat targetY = (self.status == BottomSheetStatus::Collapsed) ? self.maxY
249
+ : (self.status == BottomSheetStatus::Expanded) ? self.minY
250
+ : (CGFloat)self.frame.size.height;
251
+ if (fabs(currentY - targetY) > 0.5) {
252
+ _layoutContentTop = currentY;
253
+ } else {
254
+ _layoutContentTop = self.minY; // 无法区分时假定布局在 minY(展开位)
255
+ }
256
+ }
241
257
  if (self.status == BottomSheetStatus::Collapsed) {
242
258
  self.child.frame = CGRectOffset(self.child.frame, 0, self.maxY - self.child.frame.origin.y);
243
259
  } else if (self.status == BottomSheetStatus::Expanded) {
@@ -461,6 +477,11 @@ using namespace facebook::react;
461
477
  if (top < 0 || self.maxY == 0) {
462
478
  return;
463
479
  }
480
+ // 传的是「实际 top - 布局 top」的差值,供 getContentOriginOffset 做 hit-test 校正
481
+ if ([self.child respondsToSelector:@selector(updateContentOffset:)]) {
482
+ CGFloat offsetY = top - _layoutContentTop;
483
+ [(id)self.child updateContentOffset:offsetY];
484
+ }
464
485
 
465
486
  CGFloat progress = fmin((top - self.minY) * 1.0f / (self.maxY - self.minY), 1);
466
487
  BottomSheetEventEmitter::OnSlide payload = BottomSheetEventEmitter::OnSlide{
@@ -509,7 +530,7 @@ using namespace facebook::react;
509
530
  }
510
531
 
511
532
  - (void)stopWatchBottomSheetTransition {
512
- if(_displayLink){
533
+ if (_displayLink) {
513
534
  [_displayLink invalidate];
514
535
  _displayLink = nil;
515
536
  }
@@ -0,0 +1,12 @@
1
+ #import <React/RCTViewComponentView.h>
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @interface RNBottomSheetContentView : RCTViewComponentView
7
+
8
+ - (void)updateContentOffset:(CGFloat)contentOffset;
9
+
10
+ @end
11
+
12
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,47 @@
1
+ #import "RNBottomSheetContentView.h"
2
+
3
+ #import <react/renderer/components/bottomsheet/BottomSheetContentViewComponentDescriptor.h>
4
+ #import <react/renderer/components/bottomsheet/BottomSheetContentViewShadowNode.h>
5
+ #import <react/renderer/components/bottomsheet/EventEmitters.h>
6
+ #import <react/renderer/components/bottomsheet/Props.h>
7
+ #import <react/renderer/components/bottomsheet/RCTComponentViewHelpers.h>
8
+
9
+ using namespace facebook::react;
10
+
11
+ @implementation RNBottomSheetContentView {
12
+ std::shared_ptr<const BottomSheetContentViewShadowNode::ConcreteState> _state;
13
+ }
14
+
15
+ + (void)load {
16
+ [super load];
17
+ }
18
+
19
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
20
+ return concreteComponentDescriptorProvider<BottomSheetContentViewComponentDescriptor>();
21
+ }
22
+
23
+ - (instancetype)initWithFrame:(CGRect)frame {
24
+ if (self = [super initWithFrame:frame]) {
25
+ static const auto defaultProps = std::make_shared<const BottomSheetContentViewProps>();
26
+ _props = defaultProps;
27
+ }
28
+ return self;
29
+ }
30
+
31
+ - (void)updateState:(const facebook::react::State::Shared &)state oldState:(const facebook::react::State::Shared &)oldState {
32
+ _state = std::static_pointer_cast<const BottomSheetContentViewShadowNode::ConcreteState>(state);
33
+ }
34
+
35
+ - (void)updateContentOffset:(CGFloat)contentOffset {
36
+ if (!_state) {
37
+ return;
38
+ }
39
+ _state->updateState(
40
+ [contentOffset](const BottomSheetContentViewShadowNode::ConcreteState::Data &oldData) -> BottomSheetContentViewShadowNode::ConcreteState::SharedData {
41
+ auto newData = oldData;
42
+ newData.contentOffset = static_cast<double>(contentOffset);
43
+ return std::make_shared<BottomSheetContentViewShadowNode::ConcreteState::Data>(newData);
44
+ });
45
+ }
46
+
47
+ @end
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sdcx/bottom-sheet",
3
3
  "description": "A react-native BottomSheet component.",
4
- "version": "1.0.5",
4
+ "version": "1.0.7",
5
5
  "main": "./dist/index",
6
6
  "module": "./dist/index",
7
7
  "types": "./dist/index.d.ts",
@@ -13,6 +13,7 @@
13
13
  "dist",
14
14
  "android",
15
15
  "ios",
16
+ "common",
16
17
  "react-native.config.js",
17
18
  "RNBottomSheet.podspec",
18
19
  "!android/build",
@@ -48,7 +49,8 @@
48
49
  },
49
50
  "ios": {
50
51
  "componentProvider": {
51
- "BottomSheet": "RNBottomSheet"
52
+ "BottomSheet": "RNBottomSheet",
53
+ "BottomSheetContentView": "RNBottomSheetContentView"
52
54
  }
53
55
  }
54
56
  }
@@ -3,7 +3,8 @@ module.exports = {
3
3
  platforms: {
4
4
  android: {
5
5
  libraryName: 'bottomsheet',
6
- componentDescriptors: ['BottomSheetComponentDescriptor'],
6
+ componentDescriptors: ['BottomSheetContentViewComponentDescriptor'],
7
+ cmakeListsPath: 'src/main/jni/CMakeLists.txt',
7
8
  },
8
9
  },
9
10
  },
@@ -0,0 +1,8 @@
1
+ import type { HostComponent, ViewProps } from 'react-native';
2
+ import { codegenNativeComponent } from 'react-native';
3
+
4
+ export interface NativeProps extends ViewProps {}
5
+
6
+ export default codegenNativeComponent<NativeProps>('BottomSheetContentView', {
7
+ interfaceOnly: true,
8
+ }) as HostComponent<NativeProps>;
package/src/index.tsx CHANGED
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import { NativeSyntheticEvent, StyleSheet, View, ViewProps } from 'react-native';
2
+ import { NativeSyntheticEvent, StyleSheet, ViewProps } from 'react-native';
3
3
  import splitLayoutProps from './splitLayoutProps';
4
4
  import BottomSheetNativeComponent from './BottomSheetNativeComponent';
5
+ import BottomSheetContentViewNativeComponent from './BottomSheetContentViewNativeComponent';
5
6
  import type { OnStateChangedEventPayload, OnSlideEventPayload } from './BottomSheetNativeComponent';
6
7
 
7
8
  export type BottomSheetState = 'collapsed' | 'expanded' | 'hidden';
@@ -38,7 +39,7 @@ function BottomSheet(props: BottomSheetProps) {
38
39
  status={state}
39
40
  {...rest}
40
41
  >
41
- <View
42
+ <BottomSheetContentViewNativeComponent
42
43
  style={[
43
44
  fitToContents ? styles.fitToContents : StyleSheet.absoluteFill,
44
45
  inner,
@@ -47,7 +48,7 @@ function BottomSheet(props: BottomSheetProps) {
47
48
  collapsable={false}
48
49
  >
49
50
  {children}
50
- </View>
51
+ </BottomSheetContentViewNativeComponent>
51
52
  </BottomSheetNativeComponent>
52
53
  );
53
54
  }