diff --git a/apps/basic-example/src/App.tsx b/apps/basic-example/src/App.tsx index fceb9a2ba2..c2c3714337 100644 --- a/apps/basic-example/src/App.tsx +++ b/apps/basic-example/src/App.tsx @@ -6,6 +6,7 @@ import Navigator from './Navigator'; import NativeDetector from './NativeDetector'; import RuntimeDecoration from './RuntimeDecoration'; +import ContentsButton from './ContentsButton'; const EXAMPLES = [ { @@ -16,6 +17,10 @@ const EXAMPLES = [ name: 'Native Detector', component: NativeDetector, }, + { + name: 'Contents Button', + component: ContentsButton, + }, ]; const Stack = Navigator.create(); diff --git a/apps/basic-example/src/ContentsButton.tsx b/apps/basic-example/src/ContentsButton.tsx new file mode 100644 index 0000000000..23906db5ad --- /dev/null +++ b/apps/basic-example/src/ContentsButton.tsx @@ -0,0 +1,522 @@ +import React from 'react'; +import { View, StyleSheet, Text, SafeAreaView } from 'react-native'; +import { + GestureHandlerRootView, + ScrollView, + RectButton, +} from 'react-native-gesture-handler'; + +export default function ComplexUI() { + return ( + + + + + + + + + + + + + + + + + + ); +} + +const colors = ['#782AEB', '#38ACDD', '#57B495', '#FF6259', '#FFD61E']; + +function Avatars() { + return ( + + {colors.map((color) => ( + + {color.slice(1, 3)} + + ))} + + ); +} + +function Gallery() { + return ( + + Basic Gallery + + + + + + + + + + ); +} + +function SizeConstraints() { + return ( + + Size Constraints + + + Min/Max + + + 1:1 + + + Flex + + + + ); +} + +function FlexboxTests() { + return ( + + Flexbox Layouts + + + Start + + + Center + + + End + + + + + Wrap 1 + + + Wrap 2 + + + Wrap 3 + + + Wrap 4 + + + + ); +} + +function PositioningTests() { + return ( + + Positioning + + + Z-Index + + + Absolute + + + Relative + + + + ); +} + +function SpacingTests() { + return ( + + Spacing & Overflow + + + Padding + + + Margin + + + Overflow Hidden Test + + + + ); +} + +function VisualEffects() { + return ( + + Visual Effects + + + Shadow + + + Opacity + + + + ); +} + +function ComplexCombinations() { + return ( + + Complex Combinations + + + Complex 1 + + + Complex 2 + + + Complex 3 + + + Complex 4 + + + + ); +} + +function Transforms() { + return ( + + Transform + + + Transform + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#f5f5f5', + }, + scrollContent: { + paddingBottom: 50, + }, + paddedContainer: { + padding: 16, + }, + section: { + marginBottom: 30, + }, + sectionTitle: { + fontSize: 18, + fontWeight: 'bold', + marginBottom: 12, + color: '#333', + }, + gap: { + gap: 10, + }, + row: { + flexDirection: 'row', + }, + + // Avatar styles + avatars: { + width: 90, + height: 90, + borderWidth: 2, + borderColor: '#001A72', + borderTopLeftRadius: 30, + borderTopRightRadius: 5, + borderBottomLeftRadius: 5, + borderBottomRightRadius: 30, + marginHorizontal: 4, + alignItems: 'center', + justifyContent: 'center', + }, + avatarLabel: { + color: '#F8F9FF', + fontSize: 24, + fontWeight: 'bold', + }, + + // Gallery styles + fullWidthButton: { + width: '100%', + height: 160, + backgroundColor: '#FF6259', + borderTopRightRadius: 30, + borderTopLeftRadius: 30, + borderWidth: 1, + borderColor: '#000', + }, + leftButton: { + flex: 1, + height: 160, + backgroundColor: '#FFD61E', + borderBottomLeftRadius: 30, + borderWidth: 5, + borderColor: '#000', + }, + rightButton: { + flex: 1, + backgroundColor: '#782AEB', + height: 160, + borderBottomRightRadius: 30, + borderWidth: 8, + borderColor: '#000', + }, + + // Size constraint styles + minMaxButton: { + minWidth: 80, + maxWidth: 120, + minHeight: 40, + maxHeight: 80, + backgroundColor: '#38ACDD', + borderRadius: 10, + justifyContent: 'center', + alignItems: 'center', + }, + aspectRatioButton: { + width: 80, + aspectRatio: 1, + backgroundColor: '#57B495', + borderRadius: 40, + justifyContent: 'center', + alignItems: 'center', + }, + flexGrowButton: { + flexGrow: 1, + height: 60, + backgroundColor: '#FF6259', + borderRadius: 15, + justifyContent: 'center', + alignItems: 'center', + }, + + // Flexbox styles + flexContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + height: 80, + backgroundColor: '#e0e0e0', + borderRadius: 10, + padding: 10, + marginBottom: 10, + }, + flexStart: { + alignSelf: 'flex-start', + backgroundColor: '#782AEB', + padding: 10, + borderRadius: 5, + }, + flexCenter: { + alignSelf: 'center', + backgroundColor: '#38ACDD', + padding: 10, + borderRadius: 5, + }, + flexEnd: { + alignSelf: 'flex-end', + backgroundColor: '#57B495', + padding: 10, + borderRadius: 5, + }, + flexWrapContainer: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: 5, + }, + wrapItem: { + width: '48%', + height: 50, + backgroundColor: '#FFD61E', + borderRadius: 8, + justifyContent: 'center', + alignItems: 'center', + }, + + // Positioning styles + positionContainer: { + height: 80, + backgroundColor: '#e0e0e0', + borderRadius: 10, + position: 'relative', + }, + absoluteButton: { + position: 'absolute', + top: 10, + right: 10, + backgroundColor: '#FF6259', + padding: 8, + borderRadius: 5, + }, + relativeButton: { + position: 'relative', + top: 20, + left: 20, + backgroundColor: '#782AEB', + padding: 8, + borderRadius: 5, + }, + zIndexButton: { + position: 'absolute', + top: 10, + left: 10, + zIndex: 10, + backgroundColor: '#57B495', + padding: 8, + borderRadius: 5, + }, + + // Spacing styles + paddingButton: { + flex: 1, + backgroundColor: '#38ACDD', + paddingVertical: 20, + paddingHorizontal: 15, + borderRadius: 10, + justifyContent: 'center', + alignItems: 'center', + }, + marginButton: { + flex: 1, + backgroundColor: '#FFD61E', + margin: 10, + padding: 10, + borderRadius: 10, + justifyContent: 'center', + alignItems: 'center', + }, + overflowButton: { + flex: 1, + height: 60, + backgroundColor: '#782AEB', + borderRadius: 10, + overflow: 'hidden', + justifyContent: 'center', + alignItems: 'center', + }, + + // Visual effect styles + shadowButton: { + flex: 1, + height: 60, + backgroundColor: '#FF6259', + borderRadius: 10, + justifyContent: 'center', + alignItems: 'center', + shadowColor: '#000', + shadowOffset: { width: 0, height: 4 }, + shadowOpacity: 0.3, + shadowRadius: 8, + elevation: 8, + }, + opacityButton: { + flex: 1, + height: 60, + backgroundColor: '#782AEB', + borderRadius: 10, + justifyContent: 'center', + alignItems: 'center', + opacity: 0.7, + }, + + // Complex combination styles + complexGrid: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: 10, + }, + complexButton1: { + width: '48%', + height: 100, + backgroundColor: '#FF6259', + borderRadius: 20, + borderWidth: 2, + borderColor: '#782AEB', + justifyContent: 'center', + alignItems: 'center', + shadowColor: '#000', + shadowOffset: { width: 2, height: 2 }, + shadowOpacity: 0.2, + shadowRadius: 4, + elevation: 4, + marginBottom: 5, + }, + complexButton2: { + width: '48%', + minHeight: 80, + maxHeight: 120, + backgroundColor: '#38ACDD', + borderTopLeftRadius: 30, + borderBottomRightRadius: 30, + paddingVertical: 15, + paddingHorizontal: 10, + justifyContent: 'center', + alignItems: 'center', + overflow: 'hidden', + }, + complexButton3: { + width: '48%', + aspectRatio: 1.5, + backgroundColor: '#57B495', + borderRadius: 15, + borderWidth: 4, + borderColor: '#FFD61E', + justifyContent: 'center', + alignItems: 'center', + opacity: 0.9, + marginTop: 10, + }, + complexButton4: { + width: '48%', + height: 80, + backgroundColor: '#FFD61E', + borderRadius: 10, + borderWidth: 1, + borderColor: '#FF6259', + justifyContent: 'center', + alignItems: 'center', + shadowColor: '#782AEB', + shadowOffset: { width: 0, height: 6 }, + shadowOpacity: 0.4, + shadowRadius: 10, + elevation: 10, + marginTop: 10, + }, + + // Transform styles + transformButton: { + width: '48%', + height: 100, + backgroundColor: '#38ACDD', + borderRadius: 15, + justifyContent: 'center', + alignItems: 'center', + transform: [{ translateX: 100 }, { rotate: '15deg' }, { scale: 1.1 }], + }, + + // Text styles + buttonText: { + color: 'white', + fontWeight: 'bold', + textAlign: 'center', + }, + longText: { + color: 'white', + fontWeight: 'bold', + textAlign: 'center', + fontSize: 16, + }, +}); diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt index 95f071671f..d5c7001e20 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt @@ -11,6 +11,7 @@ import com.facebook.react.module.model.ReactModuleInfo import com.facebook.react.module.model.ReactModuleInfoProvider import com.facebook.react.uimanager.ViewManager import com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager +import com.swmansion.gesturehandler.react.RNGestureHandlerButtonWrapperViewManager import com.swmansion.gesturehandler.react.RNGestureHandlerDetectorViewManager import com.swmansion.gesturehandler.react.RNGestureHandlerModule import com.swmansion.gesturehandler.react.RNGestureHandlerRootViewManager @@ -34,6 +35,9 @@ class RNGestureHandlerPackage : RNGestureHandlerDetectorViewManager.REACT_CLASS to ModuleSpec.viewManagerSpec { RNGestureHandlerDetectorViewManager() }, + RNGestureHandlerButtonWrapperViewManager.REACT_CLASS to ModuleSpec.viewManagerSpec { + RNGestureHandlerButtonWrapperViewManager() + }, ) } @@ -41,6 +45,7 @@ class RNGestureHandlerPackage : RNGestureHandlerRootViewManager(), RNGestureHandlerButtonViewManager(), RNGestureHandlerDetectorViewManager(), + RNGestureHandlerButtonWrapperViewManager(), ) override fun getViewManagerNames(reactContext: ReactApplicationContext) = viewManagers.keys.toList() diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonWrapperViewManager.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonWrapperViewManager.kt new file mode 100644 index 0000000000..7137243bd7 --- /dev/null +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonWrapperViewManager.kt @@ -0,0 +1,30 @@ +package com.swmansion.gesturehandler.react + +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.ViewGroupManager +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.viewmanagers.RNGestureHandlerButtonWrapperManagerDelegate +import com.facebook.react.viewmanagers.RNGestureHandlerButtonWrapperManagerInterface +import com.facebook.react.views.view.ReactViewGroup + +@ReactModule(name = RNGestureHandlerButtonWrapperViewManager.REACT_CLASS) +class RNGestureHandlerButtonWrapperViewManager : + ViewGroupManager(), + RNGestureHandlerButtonWrapperManagerInterface { + private val mDelegate: ViewManagerDelegate = + RNGestureHandlerButtonWrapperManagerDelegate< + ReactViewGroup, + RNGestureHandlerButtonWrapperViewManager, + >(this) + + override fun getDelegate(): ViewManagerDelegate = mDelegate + + override fun getName() = REACT_CLASS + + override fun createViewInstance(reactContext: ThemedReactContext) = ReactViewGroup(reactContext) + + companion object { + const val REACT_CLASS = "RNGestureHandlerButtonWrapper" + } +} diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonWrapper.h b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonWrapper.h new file mode 100644 index 0000000000..c94ecf946e --- /dev/null +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonWrapper.h @@ -0,0 +1,19 @@ +#if !TARGET_OS_OSX +#import +#else +#import +#endif + +#import + +#import + +using namespace facebook::react; + +NS_ASSUME_NONNULL_BEGIN + +@interface RNGestureHandlerButtonWrapper : RCTViewComponentView + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonWrapper.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonWrapper.mm new file mode 100644 index 0000000000..526c7743d6 --- /dev/null +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonWrapper.mm @@ -0,0 +1,46 @@ +#import "RNGestureHandlerButtonWrapper.h" +#import "RNGestureHandlerButtonWrapperComponentDescriptor.h" +#import "RNGestureHandlerModule.h" + +#import +#import + +#import +#import +#import + +@interface RNGestureHandlerButtonWrapper () +@end + +@implementation RNGestureHandlerButtonWrapper + +#if TARGET_OS_OSX ++ (BOOL)shouldBeRecycled +{ + return NO; +} +#endif + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + } + + return self; +} + +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +@end + +Class RNGestureHandlerButtonWrapperCls(void) +{ + return RNGestureHandlerButtonWrapper.class; +} diff --git a/packages/react-native-gesture-handler/package.json b/packages/react-native-gesture-handler/package.json index e6bdb0fd70..e0e7269ee5 100644 --- a/packages/react-native-gesture-handler/package.json +++ b/packages/react-native-gesture-handler/package.json @@ -129,7 +129,8 @@ "ios": { "componentProvider": { "RNGestureHandlerButton": "RNGestureHandlerButtonComponentView", - "RNGestureHandlerDetector": "RNGestureHandlerDetector" + "RNGestureHandlerDetector": "RNGestureHandlerDetector", + "RNGestureHandlerButtonWrapper": "RNGestureHandlerButtonWrapper" } } }, diff --git a/packages/react-native-gesture-handler/react-native.config.js b/packages/react-native-gesture-handler/react-native.config.js index 4ec41154cd..46e3de4682 100644 --- a/packages/react-native-gesture-handler/react-native.config.js +++ b/packages/react-native-gesture-handler/react-native.config.js @@ -2,7 +2,10 @@ module.exports = { dependency: { platforms: { android: { - componentDescriptors: ['RNGestureHandlerDetectorComponentDescriptor'], + componentDescriptors: [ + 'RNGestureHandlerDetectorComponentDescriptor', + 'RNGestureHandlerButtonWrapperComponentDescriptor', + ], cmakeListsPath: './CMakeLists.txt', }, }, diff --git a/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/ComponentDescriptors.h b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/ComponentDescriptors.h index d9f3374c48..5621db20e7 100644 --- a/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/ComponentDescriptors.h +++ b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/ComponentDescriptors.h @@ -15,12 +15,14 @@ #include #include +#include #include namespace facebook::react { using RNGestureHandlerButtonComponentDescriptor = ConcreteComponentDescriptor; + using RNGestureHandlerRootViewComponentDescriptor = ConcreteComponentDescriptor; diff --git a/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperComponentDescriptor.h b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperComponentDescriptor.h new file mode 100644 index 0000000000..c3323ae823 --- /dev/null +++ b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperComponentDescriptor.h @@ -0,0 +1,32 @@ + +/** + * This code was generated by + * [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be + * lost once the code is regenerated. + * + * @generated by codegen project: GenerateComponentDescriptorH.js + */ + +#pragma once + +#include + +#include "RNGestureHandlerButtonWrapperShadowNode.h" + +namespace facebook::react { + +class RNGestureHandlerButtonWrapperComponentDescriptor final + : public ConcreteComponentDescriptor< + RNGestureHandlerButtonWrapperShadowNode> { + using ConcreteComponentDescriptor::ConcreteComponentDescriptor; + void adopt(ShadowNode &shadowNode) const override { + react_native_assert( + dynamic_cast(&shadowNode)); + + ConcreteComponentDescriptor::adopt(shadowNode); + } +}; + +} // namespace facebook::react diff --git a/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperShadowNode.cpp b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperShadowNode.cpp new file mode 100644 index 0000000000..9b327dad51 --- /dev/null +++ b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperShadowNode.cpp @@ -0,0 +1,78 @@ + +#include + +#include "RNGestureHandlerButtonWrapperShadowNode.h" + +namespace facebook::react { + +extern const char RNGestureHandlerButtonWrapperComponentName[] = + "RNGestureHandlerButtonWrapper"; + +void RNGestureHandlerButtonWrapperShadowNode::initialize() { + // When the button wrapper is cloned and has a child node, the child node + // should be cloned as well to ensure it is mutable. + if (!getChildren().empty()) { + prepareChildren(); + } +} + +void RNGestureHandlerButtonWrapperShadowNode::prepareChildren() { + const auto &children = getChildren(); + react_native_assert( + children.size() == 1 && + "RNGestureHandlerButtonWrapper received more than one child"); + + const auto directChild = children[0]; + react_native_assert( + directChild->getChildren().size() == 1 && + "RNGestureHandlerButtonWrapper received more than one grandchild"); + + const auto clonedChild = directChild->clone({}); + + const auto childWithProtectedAccess = + std::static_pointer_cast( + clonedChild); + childWithProtectedAccess->traits_.unset(ShadowNodeTraits::ForceFlattenView); + + replaceChild(*directChild, clonedChild); + + const auto grandChild = clonedChild->getChildren()[0]; + const auto clonedGrandChild = grandChild->clone({}); + clonedChild->replaceChild(*grandChild, clonedGrandChild); +} + +void RNGestureHandlerButtonWrapperShadowNode::appendChild( + const std::shared_ptr &child) { + YogaLayoutableShadowNode::appendChild(child); + prepareChildren(); +} + +void RNGestureHandlerButtonWrapperShadowNode::layout( + LayoutContext layoutContext) { + YogaLayoutableShadowNode::layout(layoutContext); + react_native_assert(getChildren().size() == 1); + react_native_assert(getChildren()[0]->getChildren().size() == 1); + + auto child = std::static_pointer_cast( + getChildren()[0]); + auto grandChild = std::static_pointer_cast( + child->getChildren()[0]); + + child->ensureUnsealed(); + grandChild->ensureUnsealed(); + + auto mutableChild = std::const_pointer_cast(child); + auto mutableGrandChild = + std::const_pointer_cast(grandChild); + + // TODO: figure out the correct way to setup metrics between button wrapper + // and the child + auto metrics = grandChild->getLayoutMetrics(); + mutableChild->setLayoutMetrics(metrics); + + auto metricsNoOrigin = grandChild->getLayoutMetrics(); + metricsNoOrigin.frame.origin = Point{}; + mutableGrandChild->setLayoutMetrics(metricsNoOrigin); +} + +} // namespace facebook::react diff --git a/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperShadowNode.h b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperShadowNode.h new file mode 100644 index 0000000000..79c87ea6bd --- /dev/null +++ b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperShadowNode.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "RNGestureHandlerButtonWrapperState.h" + +namespace facebook::react { + +JSI_EXPORT extern const char RNGestureHandlerButtonWrapperComponentName[]; + +/* + * `ShadowNode` for component. + */ +class RNGestureHandlerButtonWrapperShadowNode final + : public ConcreteViewShadowNode< + RNGestureHandlerButtonWrapperComponentName, + RNGestureHandlerButtonWrapperProps, + RNGestureHandlerButtonWrapperEventEmitter, + RNGestureHandlerButtonWrapperState> { + public: + RNGestureHandlerButtonWrapperShadowNode( + const ShadowNodeFragment &fragment, + const ShadowNodeFamily::Shared &family, + ShadowNodeTraits traits) + : ConcreteViewShadowNode(fragment, family, traits) { + initialize(); + } + + RNGestureHandlerButtonWrapperShadowNode( + const ShadowNode &sourceShadowNode, + const ShadowNodeFragment &fragment) + : ConcreteViewShadowNode(sourceShadowNode, fragment) { + initialize(); + } + + void layout(LayoutContext layoutContext) override; + void appendChild(const std::shared_ptr &child) override; + + private: + void initialize(); + void prepareChildren(); +}; + +} // namespace facebook::react diff --git a/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperState.h b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperState.h new file mode 100644 index 0000000000..7d9fa242e0 --- /dev/null +++ b/packages/react-native-gesture-handler/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerButtonWrapperState.h @@ -0,0 +1,32 @@ +/** + * This code was generated by + * [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be + * lost once the code is regenerated. + * + * @generated by codegen project: GenerateStateH.js + */ +#pragma once + +#ifdef ANDROID +#include +#endif + +namespace facebook::react { + +class RNGestureHandlerButtonWrapperState { + public: + RNGestureHandlerButtonWrapperState() = default; + +#ifdef ANDROID + RNGestureHandlerButtonWrapperState( + RNGestureHandlerButtonWrapperState const &previousState, + folly::dynamic data){}; + folly::dynamic getDynamic() const { + return {}; + }; +#endif +}; + +} // namespace facebook::react diff --git a/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx b/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx index b6f0c391c0..a3e1a6026a 100644 --- a/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx +++ b/packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx @@ -1,5 +1,147 @@ -import { HostComponent } from 'react-native'; +import { HostComponent, StyleSheet, View } from 'react-native'; import type { RawButtonProps } from './GestureButtonsProps'; import RNGestureHandlerButtonNativeComponent from '../specs/RNGestureHandlerButtonNativeComponent'; +import RNGestureHandlerButtonWrapperNativeComponent from '../specs/RNGestureHandlerButtonWrapperNativeComponent'; +import { useMemo } from 'react'; -export default RNGestureHandlerButtonNativeComponent as HostComponent; +const ButtonComponent = + RNGestureHandlerButtonNativeComponent as HostComponent; + +export default function GestureHandlerButton({ + style, + ...rest +}: RawButtonProps) { + const flattenedStyle = useMemo(() => StyleSheet.flatten(style), [style]); + + const { + // Layout properties + display, + width, + height, + minWidth, + maxWidth, + minHeight, + maxHeight, + flex, + flexGrow, + flexShrink, + flexBasis, + flexDirection, + flexWrap, + justifyContent, + alignItems, + alignContent, + alignSelf, + aspectRatio, + gap, + rowGap, + columnGap, + margin, + marginTop, + marginBottom, + marginLeft, + marginRight, + marginVertical, + marginHorizontal, + marginStart, + marginEnd, + padding, + paddingTop, + paddingBottom, + paddingLeft, + paddingRight, + paddingVertical, + paddingHorizontal, + paddingStart, + paddingEnd, + position, + top, + right, + bottom, + left, + start, + end, + overflow, + + // Visual properties + ...restStyle + } = flattenedStyle; + + // Layout styles for ButtonComponent + const layoutStyle = useMemo( + () => ({ + display, + width, + height, + minWidth, + maxWidth, + minHeight, + maxHeight, + flex, + flexGrow, + flexShrink, + flexBasis, + flexDirection, + flexWrap, + justifyContent, + alignItems, + alignContent, + alignSelf, + aspectRatio, + gap, + rowGap, + columnGap, + margin, + marginTop, + marginBottom, + marginLeft, + marginRight, + marginVertical, + marginHorizontal, + marginStart, + marginEnd, + padding, + paddingTop, + paddingBottom, + paddingLeft, + paddingRight, + paddingVertical, + paddingHorizontal, + paddingStart, + paddingEnd, + position, + top, + right, + bottom, + left, + start, + end, + overflow, + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [flattenedStyle] + ); + + return ( + + + + + + ); +} + +const styles = StyleSheet.create({ + contents: { + display: 'contents', + }, + overflowHidden: { + overflow: 'hidden', + }, +}); diff --git a/packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonWrapperNativeComponent.ts b/packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonWrapperNativeComponent.ts new file mode 100644 index 0000000000..d84e610aaa --- /dev/null +++ b/packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonWrapperNativeComponent.ts @@ -0,0 +1,11 @@ +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; +import type { ViewProps } from 'react-native'; + +interface NativeProps extends ViewProps {} + +export default codegenNativeComponent( + 'RNGestureHandlerButtonWrapper', + { + interfaceOnly: true, + } +);