@swmansion/react-native-bottom-sheet 0.7.0-next.5 → 0.7.0-next.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.
- package/ReactNativeBottomSheet.podspec +3 -2
- package/android/src/main/java/com/swmansion/reactnativebottomsheet/BottomSheetView.kt +28 -3
- package/android/src/main/java/com/swmansion/reactnativebottomsheet/BottomSheetViewManager.kt +11 -0
- package/android/src/main/jni/CMakeLists.txt +78 -0
- package/common/cpp/react/renderer/components/ReactNativeBottomSheetSpec/BottomSheetViewShadowNode.cpp +28 -0
- package/common/cpp/react/renderer/components/ReactNativeBottomSheetSpec/BottomSheetViewState.h +36 -0
- package/common/cpp/react/renderer/components/ReactNativeBottomSheetSpec/ComponentDescriptors.h +19 -0
- package/common/cpp/react/renderer/components/ReactNativeBottomSheetSpec/ShadowNodes.h +25 -0
- package/package.json +2 -1
- package/react-native.config.js +11 -1
|
@@ -13,11 +13,12 @@ Pod::Spec.new do |s|
|
|
|
13
13
|
s.platforms = { :ios => min_ios_version_supported }
|
|
14
14
|
s.source = { :git => "https://github.com/software-mansion-labs/react-native-bottom-sheet.git", :tag => "#{s.version}" }
|
|
15
15
|
|
|
16
|
-
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
|
|
16
|
+
s.source_files = ["ios/**/*.{h,m,mm,cpp,swift}", "common/**/*.{h,cpp}"]
|
|
17
17
|
s.private_header_files = "ios/**/*.h"
|
|
18
18
|
s.swift_version = "5.0"
|
|
19
19
|
s.pod_target_xcconfig = {
|
|
20
|
-
"DEFINES_MODULE" => "YES"
|
|
20
|
+
"DEFINES_MODULE" => "YES",
|
|
21
|
+
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\""
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
install_modules_dependencies(s)
|
|
@@ -11,7 +11,9 @@ import android.widget.FrameLayout
|
|
|
11
11
|
import androidx.dynamicanimation.animation.DynamicAnimation
|
|
12
12
|
import androidx.dynamicanimation.animation.SpringAnimation
|
|
13
13
|
import androidx.dynamicanimation.animation.SpringForce
|
|
14
|
+
import com.facebook.react.bridge.Arguments
|
|
14
15
|
import com.facebook.react.uimanager.PointerEvents
|
|
16
|
+
import com.facebook.react.uimanager.StateWrapper
|
|
15
17
|
import com.facebook.react.views.view.ReactViewGroup
|
|
16
18
|
import kotlin.math.abs
|
|
17
19
|
|
|
@@ -27,6 +29,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
27
29
|
// MARK: - Listener
|
|
28
30
|
|
|
29
31
|
var listener: BottomSheetViewListener? = null
|
|
32
|
+
var stateWrapper: StateWrapper? = null
|
|
30
33
|
|
|
31
34
|
// MARK: - State
|
|
32
35
|
|
|
@@ -48,6 +51,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
48
51
|
|
|
49
52
|
// Touch tracking
|
|
50
53
|
private var initialTouchY = 0f
|
|
54
|
+
private var initialTouchX = 0f
|
|
51
55
|
private var lastTouchY = 0f
|
|
52
56
|
private var activePointerId = MotionEvent.INVALID_POINTER_ID
|
|
53
57
|
|
|
@@ -129,6 +133,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
129
133
|
|
|
130
134
|
if (activeAnimation != null || isPanning) return
|
|
131
135
|
sheetContainer.translationY = translationY(targetIndex)
|
|
136
|
+
updateShadowState(sheetContainer.translationY)
|
|
132
137
|
}
|
|
133
138
|
|
|
134
139
|
private fun layoutSheetChildren() {
|
|
@@ -207,6 +212,19 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
207
212
|
val maxHeight = detentSpecs.lastOrNull()?.height ?: height.toFloat()
|
|
208
213
|
val ty = sheetContainer.translationY
|
|
209
214
|
listener?.onPositionChange(((maxHeight - ty) / density).toDouble())
|
|
215
|
+
updateShadowState(ty)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private var lastShadowOffsetY = Float.NaN
|
|
219
|
+
|
|
220
|
+
private fun updateShadowState(translationY: Float) {
|
|
221
|
+
val offsetY = (translationY / density).toDouble()
|
|
222
|
+
if (offsetY.toFloat() == lastShadowOffsetY) return
|
|
223
|
+
lastShadowOffsetY = offsetY.toFloat()
|
|
224
|
+
val sw = stateWrapper ?: return
|
|
225
|
+
val map = Arguments.createMap()
|
|
226
|
+
map.putDouble("contentOffsetY", offsetY)
|
|
227
|
+
sw.updateState(map)
|
|
210
228
|
}
|
|
211
229
|
|
|
212
230
|
// MARK: - Choreographer (position tracking during animation)
|
|
@@ -282,12 +300,13 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
282
300
|
|
|
283
301
|
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
|
284
302
|
val sheetTop = sheetContainer.top + sheetContainer.translationY
|
|
285
|
-
if (ev.y < sheetTop) {
|
|
303
|
+
if (ev.actionMasked == MotionEvent.ACTION_DOWN && ev.y < sheetTop) {
|
|
286
304
|
return false
|
|
287
305
|
}
|
|
288
306
|
|
|
289
307
|
when (ev.actionMasked) {
|
|
290
308
|
MotionEvent.ACTION_DOWN -> {
|
|
309
|
+
initialTouchX = ev.x
|
|
291
310
|
initialTouchY = ev.y
|
|
292
311
|
lastTouchY = ev.y
|
|
293
312
|
activePointerId = ev.getPointerId(0)
|
|
@@ -296,10 +315,12 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
296
315
|
if (activePointerId == MotionEvent.INVALID_POINTER_ID) return false
|
|
297
316
|
val pointerIndex = ev.findPointerIndex(activePointerId)
|
|
298
317
|
if (pointerIndex < 0) return false
|
|
318
|
+
val x = ev.getX(pointerIndex)
|
|
299
319
|
val y = ev.getY(pointerIndex)
|
|
320
|
+
val dx = x - initialTouchX
|
|
300
321
|
val dy = y - initialTouchY
|
|
301
322
|
|
|
302
|
-
if (abs(dy) > touchSlop) {
|
|
323
|
+
if (abs(dy) > touchSlop && abs(dy) > abs(dx)) {
|
|
303
324
|
if (!isAtMaxDraggable) {
|
|
304
325
|
lastTouchY = y
|
|
305
326
|
requestDisallowInterceptTouchEvent(false)
|
|
@@ -313,6 +334,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
313
334
|
}
|
|
314
335
|
}
|
|
315
336
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
|
337
|
+
initialTouchX = 0f
|
|
316
338
|
activePointerId = MotionEvent.INVALID_POINTER_ID
|
|
317
339
|
}
|
|
318
340
|
}
|
|
@@ -321,7 +343,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
321
343
|
|
|
322
344
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
323
345
|
val sheetTop = sheetContainer.top + sheetContainer.translationY
|
|
324
|
-
if (event.y < sheetTop) {
|
|
346
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN && event.y < sheetTop) {
|
|
325
347
|
return false
|
|
326
348
|
}
|
|
327
349
|
|
|
@@ -418,9 +440,12 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
418
440
|
hasLaidOut = false
|
|
419
441
|
isPanning = false
|
|
420
442
|
initialTouchY = 0f
|
|
443
|
+
initialTouchX = 0f
|
|
421
444
|
lastTouchY = 0f
|
|
422
445
|
activePointerId = MotionEvent.INVALID_POINTER_ID
|
|
423
446
|
sheetContainer.translationY = 0f
|
|
424
447
|
sheetContainer.removeAllViews()
|
|
448
|
+
stateWrapper = null
|
|
449
|
+
lastShadowOffsetY = Float.NaN
|
|
425
450
|
}
|
|
426
451
|
}
|
package/android/src/main/java/com/swmansion/reactnativebottomsheet/BottomSheetViewManager.kt
CHANGED
|
@@ -3,6 +3,8 @@ package com.swmansion.reactnativebottomsheet
|
|
|
3
3
|
import android.view.View
|
|
4
4
|
import com.facebook.react.bridge.ReadableArray
|
|
5
5
|
import com.facebook.react.module.annotations.ReactModule
|
|
6
|
+
import com.facebook.react.uimanager.ReactStylesDiffMap
|
|
7
|
+
import com.facebook.react.uimanager.StateWrapper
|
|
6
8
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
7
9
|
import com.facebook.react.uimanager.ViewGroupManager
|
|
8
10
|
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
@@ -63,6 +65,15 @@ class BottomSheetViewManager :
|
|
|
63
65
|
parent.removeSheetChildAt(index)
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
override fun updateState(
|
|
69
|
+
view: BottomSheetView,
|
|
70
|
+
props: ReactStylesDiffMap,
|
|
71
|
+
stateWrapper: StateWrapper?,
|
|
72
|
+
): Any? {
|
|
73
|
+
view.stateWrapper = stateWrapper
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
76
|
+
|
|
66
77
|
override fun needsCustomLayoutForChildren(): Boolean = true
|
|
67
78
|
|
|
68
79
|
override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.13)
|
|
2
|
+
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
3
|
+
|
|
4
|
+
set(LIB_LITERAL ReactNativeBottomSheetSpec)
|
|
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 ${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
|
+
# Custom headers must come before generated headers so that our ShadowNodes.h
|
|
23
|
+
# and ComponentDescriptors.h take precedence over the codegen type aliases.
|
|
24
|
+
target_include_directories(
|
|
25
|
+
${LIB_TARGET_NAME}
|
|
26
|
+
PUBLIC
|
|
27
|
+
${LIB_COMMON_DIR}
|
|
28
|
+
${LIB_ANDROID_GENERATED_JNI_DIR}
|
|
29
|
+
${LIB_ANDROID_GENERATED_COMPONENTS_DIR}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if (REACTNATIVE_MERGED_SO)
|
|
33
|
+
target_link_libraries(
|
|
34
|
+
${LIB_TARGET_NAME}
|
|
35
|
+
fbjni
|
|
36
|
+
jsi
|
|
37
|
+
reactnative
|
|
38
|
+
)
|
|
39
|
+
else()
|
|
40
|
+
target_link_libraries(
|
|
41
|
+
${LIB_TARGET_NAME}
|
|
42
|
+
fbjni
|
|
43
|
+
folly_runtime
|
|
44
|
+
glog
|
|
45
|
+
jsi
|
|
46
|
+
react_codegen_rncore
|
|
47
|
+
react_debug
|
|
48
|
+
react_nativemodule_core
|
|
49
|
+
react_render_core
|
|
50
|
+
react_render_debug
|
|
51
|
+
react_render_graphics
|
|
52
|
+
react_render_mapbuffer
|
|
53
|
+
react_render_componentregistry
|
|
54
|
+
react_utils
|
|
55
|
+
rrc_view
|
|
56
|
+
turbomodulejsijni
|
|
57
|
+
yoga
|
|
58
|
+
)
|
|
59
|
+
endif()
|
|
60
|
+
|
|
61
|
+
target_include_directories(
|
|
62
|
+
${CMAKE_PROJECT_NAME}
|
|
63
|
+
PUBLIC
|
|
64
|
+
${CMAKE_CURRENT_SOURCE_DIR}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
|
|
68
|
+
target_compile_reactnative_options(${LIB_TARGET_NAME} PUBLIC)
|
|
69
|
+
else()
|
|
70
|
+
target_compile_options(
|
|
71
|
+
${LIB_TARGET_NAME}
|
|
72
|
+
PRIVATE
|
|
73
|
+
-fexceptions
|
|
74
|
+
-frtti
|
|
75
|
+
-std=c++20
|
|
76
|
+
-Wall
|
|
77
|
+
)
|
|
78
|
+
endif()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#include "ShadowNodes.h"
|
|
2
|
+
|
|
3
|
+
#include <yoga/Yoga.h>
|
|
4
|
+
|
|
5
|
+
namespace facebook::react {
|
|
6
|
+
|
|
7
|
+
void BottomSheetViewShadowNode::adjustLayoutWithState() {
|
|
8
|
+
#ifdef ANDROID
|
|
9
|
+
ensureUnsealed();
|
|
10
|
+
|
|
11
|
+
auto state =
|
|
12
|
+
std::static_pointer_cast<const BottomSheetViewShadowNode::ConcreteState>(
|
|
13
|
+
getState());
|
|
14
|
+
auto stateData = state->getData();
|
|
15
|
+
|
|
16
|
+
auto adjustedStyle = getConcreteProps().yogaStyle;
|
|
17
|
+
auto newPaddingTop =
|
|
18
|
+
yoga::Style::Length::points(stateData.contentOffsetY);
|
|
19
|
+
|
|
20
|
+
if (adjustedStyle.padding(yoga::Edge::Top) != newPaddingTop) {
|
|
21
|
+
adjustedStyle.setPadding(yoga::Edge::Top, newPaddingTop);
|
|
22
|
+
yogaNode_.setStyle(adjustedStyle);
|
|
23
|
+
yogaNode_.setDirty(true);
|
|
24
|
+
}
|
|
25
|
+
#endif
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
} // namespace facebook::react
|
package/common/cpp/react/renderer/components/ReactNativeBottomSheetSpec/BottomSheetViewState.h
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef ANDROID
|
|
4
|
+
#include <folly/dynamic.h>
|
|
5
|
+
#include <react/renderer/mapbuffer/MapBuffer.h>
|
|
6
|
+
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
|
|
7
|
+
#endif
|
|
8
|
+
|
|
9
|
+
namespace facebook::react {
|
|
10
|
+
|
|
11
|
+
class BottomSheetViewState final {
|
|
12
|
+
public:
|
|
13
|
+
BottomSheetViewState() = default;
|
|
14
|
+
|
|
15
|
+
#ifdef ANDROID
|
|
16
|
+
BottomSheetViewState(
|
|
17
|
+
const BottomSheetViewState& previousState,
|
|
18
|
+
folly::dynamic data)
|
|
19
|
+
: contentOffsetY(
|
|
20
|
+
static_cast<float>(data["contentOffsetY"].getDouble())) {}
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
float contentOffsetY{0};
|
|
24
|
+
|
|
25
|
+
#ifdef ANDROID
|
|
26
|
+
folly::dynamic getDynamic() const {
|
|
27
|
+
return folly::dynamic::object("contentOffsetY", contentOffsetY);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
MapBuffer getMapBuffer() const {
|
|
31
|
+
return MapBufferBuilder::EMPTY();
|
|
32
|
+
}
|
|
33
|
+
#endif
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
} // namespace facebook::react
|
package/common/cpp/react/renderer/components/ReactNativeBottomSheetSpec/ComponentDescriptors.h
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <react/renderer/components/ReactNativeBottomSheetSpec/ShadowNodes.h>
|
|
4
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
5
|
+
|
|
6
|
+
namespace facebook::react {
|
|
7
|
+
|
|
8
|
+
class BottomSheetViewComponentDescriptor final
|
|
9
|
+
: public ConcreteComponentDescriptor<BottomSheetViewShadowNode> {
|
|
10
|
+
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
|
|
11
|
+
|
|
12
|
+
void adopt(ShadowNode& shadowNode) const override {
|
|
13
|
+
auto& node = static_cast<BottomSheetViewShadowNode&>(shadowNode);
|
|
14
|
+
node.adjustLayoutWithState();
|
|
15
|
+
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <jsi/jsi.h>
|
|
4
|
+
#include <react/renderer/components/ReactNativeBottomSheetSpec/BottomSheetViewState.h>
|
|
5
|
+
#include <react/renderer/components/ReactNativeBottomSheetSpec/EventEmitters.h>
|
|
6
|
+
#include <react/renderer/components/ReactNativeBottomSheetSpec/Props.h>
|
|
7
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
8
|
+
|
|
9
|
+
namespace facebook::react {
|
|
10
|
+
|
|
11
|
+
JSI_EXPORT extern const char BottomSheetViewComponentName[];
|
|
12
|
+
|
|
13
|
+
class JSI_EXPORT BottomSheetViewShadowNode final
|
|
14
|
+
: public ConcreteViewShadowNode<
|
|
15
|
+
BottomSheetViewComponentName,
|
|
16
|
+
BottomSheetViewProps,
|
|
17
|
+
BottomSheetViewEventEmitter,
|
|
18
|
+
BottomSheetViewState> {
|
|
19
|
+
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
20
|
+
|
|
21
|
+
public:
|
|
22
|
+
void adjustLayoutWithState();
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
} // namespace facebook::react
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swmansion/react-native-bottom-sheet",
|
|
3
|
-
"version": "0.7.0-next.
|
|
3
|
+
"version": "0.7.0-next.7",
|
|
4
4
|
"description": "Provides bottom-sheet components for React Native.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"lib",
|
|
18
18
|
"android",
|
|
19
19
|
"ios",
|
|
20
|
+
"common",
|
|
20
21
|
"cpp",
|
|
21
22
|
"*.podspec",
|
|
22
23
|
"react-native.config.js",
|
package/react-native.config.js
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
|
-
module.exports = {
|
|
1
|
+
module.exports = {
|
|
2
|
+
dependency: {
|
|
3
|
+
platforms: {
|
|
4
|
+
android: {
|
|
5
|
+
libraryName: 'ReactNativeBottomSheetSpec',
|
|
6
|
+
componentDescriptors: ['BottomSheetViewComponentDescriptor'],
|
|
7
|
+
cmakeListsPath: 'src/main/jni/CMakeLists.txt',
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
};
|