220 lines
8.7 KiB
Plaintext
220 lines
8.7 KiB
Plaintext
#ifdef RCT_NEW_ARCH_ENABLED
|
|
|
|
#import "RNGestureHandlerButtonComponentView.h"
|
|
|
|
#import <React/RCTConversions.h>
|
|
#import <React/RCTFabricComponentsPlugins.h>
|
|
|
|
#import <react/renderer/components/rngesturehandler_codegen/ComponentDescriptors.h>
|
|
#import <react/renderer/components/rngesturehandler_codegen/EventEmitters.h>
|
|
#import <react/renderer/components/rngesturehandler_codegen/Props.h>
|
|
#import <react/renderer/components/rngesturehandler_codegen/RCTComponentViewHelpers.h>
|
|
|
|
#import "RNGestureHandlerButton.h"
|
|
|
|
using namespace facebook::react;
|
|
|
|
@interface RNGestureHandlerButtonComponentView () <RCTRNGestureHandlerButtonViewProtocol>
|
|
@end
|
|
|
|
@implementation RNGestureHandlerButtonComponentView {
|
|
RNGestureHandlerButton *_buttonView;
|
|
}
|
|
|
|
#if TARGET_OS_OSX
|
|
// Here we want to disable view recycling on buttons. Listeners are not removed from views when they're being unmounted,
|
|
// therefore after navigating through other screens buttons may have different actions then they are supposed to have.
|
|
+ (BOOL)shouldBeRecycled
|
|
{
|
|
return NO;
|
|
}
|
|
#endif
|
|
|
|
// Needed because of this: https://github.com/facebook/react-native/pull/37274
|
|
+ (void)load
|
|
{
|
|
[super load];
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
if (self = [super initWithFrame:frame]) {
|
|
static const auto defaultProps = std::make_shared<const RNGestureHandlerButtonProps>();
|
|
_props = defaultProps;
|
|
_buttonView = [[RNGestureHandlerButton alloc] initWithFrame:self.bounds];
|
|
|
|
self.contentView = _buttonView;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)mountChildComponentView:(RNGHUIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
{
|
|
[_buttonView mountChildComponentView:childComponentView index:index];
|
|
}
|
|
|
|
- (void)unmountChildComponentView:(RNGHUIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
{
|
|
[_buttonView unmountChildComponentView:childComponentView index:index];
|
|
}
|
|
|
|
- (LayoutMetrics)buildWrapperMetrics:(const LayoutMetrics &)metrics
|
|
{
|
|
LayoutMetrics result = metrics;
|
|
result.borderWidth = EdgeInsets::ZERO;
|
|
result.contentInsets = EdgeInsets::ZERO;
|
|
return result;
|
|
}
|
|
|
|
- (LayoutMetrics)buildButtonMetrics:(const LayoutMetrics &)metrics
|
|
{
|
|
LayoutMetrics result = metrics;
|
|
result.frame.origin = {0, 0};
|
|
return result;
|
|
}
|
|
|
|
- (void)updateLayoutMetrics:(const facebook::react::LayoutMetrics &)layoutMetrics
|
|
oldLayoutMetrics:(const facebook::react::LayoutMetrics &)oldLayoutMetrics
|
|
{
|
|
// due to nested structure of Button and ComponentView, layout metrics for both
|
|
// need to be modified:
|
|
// - wrapper shouldn't have any insets as they should be applied to the button
|
|
// so that it can intercept touches on padding and borders, applying them
|
|
// twice breaks expected layout
|
|
// - frame origin needs to be zeroes on metrics of the button as it should fill
|
|
// the entirety of the wrapper component
|
|
const LayoutMetrics wrapperMetrics = [self buildWrapperMetrics:layoutMetrics];
|
|
const LayoutMetrics oldWrapperMetrics = [self buildWrapperMetrics:oldLayoutMetrics];
|
|
|
|
const LayoutMetrics buttonMetrics = [self buildButtonMetrics:layoutMetrics];
|
|
const LayoutMetrics oldbuttonMetrics = [self buildButtonMetrics:oldLayoutMetrics];
|
|
|
|
[super updateLayoutMetrics:wrapperMetrics oldLayoutMetrics:oldWrapperMetrics];
|
|
[_buttonView updateLayoutMetrics:buttonMetrics oldLayoutMetrics:oldbuttonMetrics];
|
|
}
|
|
|
|
#pragma mark - RCTComponentViewProtocol
|
|
|
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
{
|
|
return concreteComponentDescriptorProvider<RNGestureHandlerButtonComponentDescriptor>();
|
|
}
|
|
|
|
#if TARGET_OS_IOS
|
|
// Taken from
|
|
// https://github.com/facebook/react-native/blob/b226049a4a28ea3f7f32266269fb76340c324d42/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm#L343
|
|
- (void)setAccessibilityProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
|
|
{
|
|
const auto &oldButtonProps = *std::static_pointer_cast<const RNGestureHandlerButtonProps>(oldProps);
|
|
const auto &newButtonProps = *std::static_pointer_cast<const RNGestureHandlerButtonProps>(props);
|
|
|
|
if (!oldProps || oldButtonProps.accessible != newButtonProps.accessible) {
|
|
_buttonView.isAccessibilityElement = newButtonProps.accessible;
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityLabel != newButtonProps.accessibilityLabel) {
|
|
_buttonView.accessibilityLabel = RCTNSStringFromStringNilIfEmpty(newButtonProps.accessibilityLabel);
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityLanguage != newButtonProps.accessibilityLanguage) {
|
|
_buttonView.accessibilityLanguage = RCTNSStringFromStringNilIfEmpty(newButtonProps.accessibilityLanguage);
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityHint != newButtonProps.accessibilityHint) {
|
|
_buttonView.accessibilityHint = RCTNSStringFromStringNilIfEmpty(newButtonProps.accessibilityHint);
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityViewIsModal != newButtonProps.accessibilityViewIsModal) {
|
|
_buttonView.accessibilityViewIsModal = newButtonProps.accessibilityViewIsModal;
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityElementsHidden != newButtonProps.accessibilityElementsHidden) {
|
|
_buttonView.accessibilityElementsHidden = newButtonProps.accessibilityElementsHidden;
|
|
}
|
|
|
|
if (!oldProps ||
|
|
oldButtonProps.accessibilityShowsLargeContentViewer != newButtonProps.accessibilityShowsLargeContentViewer) {
|
|
if (@available(iOS 13.0, *)) {
|
|
if (newButtonProps.accessibilityShowsLargeContentViewer) {
|
|
_buttonView.showsLargeContentViewer = YES;
|
|
UILargeContentViewerInteraction *interaction = [[UILargeContentViewerInteraction alloc] init];
|
|
[_buttonView addInteraction:interaction];
|
|
} else {
|
|
_buttonView.showsLargeContentViewer = NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityLargeContentTitle != newButtonProps.accessibilityLargeContentTitle) {
|
|
if (@available(iOS 13.0, *)) {
|
|
_buttonView.largeContentTitle = RCTNSStringFromStringNilIfEmpty(newButtonProps.accessibilityLargeContentTitle);
|
|
}
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityTraits != newButtonProps.accessibilityTraits) {
|
|
_buttonView.accessibilityTraits =
|
|
RCTUIAccessibilityTraitsFromAccessibilityTraits(newButtonProps.accessibilityTraits);
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityState != newButtonProps.accessibilityState) {
|
|
_buttonView.accessibilityTraits &= ~(UIAccessibilityTraitNotEnabled | UIAccessibilityTraitSelected);
|
|
const auto accessibilityState = newButtonProps.accessibilityState.value_or(AccessibilityState{});
|
|
if (accessibilityState.selected) {
|
|
_buttonView.accessibilityTraits |= UIAccessibilityTraitSelected;
|
|
}
|
|
if (accessibilityState.disabled) {
|
|
_buttonView.accessibilityTraits |= UIAccessibilityTraitNotEnabled;
|
|
}
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityIgnoresInvertColors != newButtonProps.accessibilityIgnoresInvertColors) {
|
|
_buttonView.accessibilityIgnoresInvertColors = newButtonProps.accessibilityIgnoresInvertColors;
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.accessibilityValue != newButtonProps.accessibilityValue) {
|
|
if (newButtonProps.accessibilityValue.text.has_value()) {
|
|
_buttonView.accessibilityValue = RCTNSStringFromStringNilIfEmpty(newButtonProps.accessibilityValue.text.value());
|
|
} else if (
|
|
newButtonProps.accessibilityValue.now.has_value() && newButtonProps.accessibilityValue.min.has_value() &&
|
|
newButtonProps.accessibilityValue.max.has_value()) {
|
|
CGFloat val = (CGFloat)(newButtonProps.accessibilityValue.now.value()) /
|
|
(newButtonProps.accessibilityValue.max.value() - newButtonProps.accessibilityValue.min.value());
|
|
_buttonView.accessibilityValue = [NSNumberFormatter localizedStringFromNumber:@(val)
|
|
numberStyle:NSNumberFormatterPercentStyle];
|
|
;
|
|
} else {
|
|
_buttonView.accessibilityValue = nil;
|
|
}
|
|
}
|
|
|
|
if (!oldProps || oldButtonProps.testId != newButtonProps.testId) {
|
|
UIView *accessibilityView = (UIView *)_buttonView;
|
|
accessibilityView.accessibilityIdentifier = RCTNSStringFromString(newButtonProps.testId);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
|
|
{
|
|
const auto &newProps = *std::static_pointer_cast<const RNGestureHandlerButtonProps>(props);
|
|
|
|
_buttonView.userEnabled = newProps.enabled;
|
|
#if !TARGET_OS_TV && !TARGET_OS_OSX
|
|
_buttonView.exclusiveTouch = newProps.exclusive;
|
|
[self setAccessibilityProps:props oldProps:oldProps];
|
|
#endif
|
|
_buttonView.hitTestEdgeInsets = UIEdgeInsetsMake(
|
|
-newProps.hitSlop.top, -newProps.hitSlop.left, -newProps.hitSlop.bottom, -newProps.hitSlop.right);
|
|
|
|
[super updateProps:props oldProps:oldProps];
|
|
}
|
|
@end
|
|
|
|
Class<RCTComponentViewProtocol> RNGestureHandlerButtonCls(void)
|
|
{
|
|
return RNGestureHandlerButtonComponentView.class;
|
|
}
|
|
|
|
#endif // RCT_NEW_ARCH_ENABLED
|