/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #import "RCTInputAccessoryComponentView.h" #import #import #import #import #import #import #import #import "RCTInputAccessoryContentView.h" #import "RCTFabricComponentsPlugins.h" using namespace facebook::react; static UIView *_Nullable RCTFindTextInputWithNativeId(UIView *view, NSString *nativeId) { if ([view respondsToSelector:@selector(inputAccessoryViewID)] && [view respondsToSelector:@selector(setInputAccessoryView:)]) { UIView *typed = (UIView *)view; if (!nativeId || [typed.inputAccessoryViewID isEqualToString:nativeId]) { return typed; } } for (UIView *subview in view.subviews) { UIView *result = RCTFindTextInputWithNativeId(subview, nativeId); if (result) { return result; } } return nil; } @implementation RCTInputAccessoryComponentView { InputAccessoryShadowNode::ConcreteState::Shared _state; RCTInputAccessoryContentView *_contentView; RCTSurfaceTouchHandler *_touchHandler; UIView __weak *_textInput; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; _contentView = [RCTInputAccessoryContentView new]; _touchHandler = [RCTSurfaceTouchHandler new]; [_touchHandler attachToView:_contentView]; } return self; } - (void)didMoveToWindow { [super didMoveToWindow]; if (self.window && !_textInput) { if (self.nativeId) { _textInput = RCTFindTextInputWithNativeId(self.window, self.nativeId); _textInput.inputAccessoryView = _contentView; } else { _textInput = RCTFindTextInputWithNativeId(_contentView, nil); } if (!self.nativeId) { [self becomeFirstResponder]; } } } - (BOOL)canBecomeFirstResponder { return true; } - (UIView *)inputAccessoryView { return _contentView; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { [_contentView insertSubview:childComponentView atIndex:index]; } - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { [childComponentView removeFromSuperview]; } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { auto const &oldInputAccessoryProps = *std::static_pointer_cast(_props); auto const &newInputAccessoryProps = *std::static_pointer_cast(props); if (newInputAccessoryProps.backgroundColor != oldInputAccessoryProps.backgroundColor) { _contentView.backgroundColor = RCTUIColorFromSharedColor(newInputAccessoryProps.backgroundColor); } [super updateProps:props oldProps:oldProps]; self.hidden = true; } - (void)updateState:(const facebook::react::State::Shared &)state oldState:(const facebook::react::State::Shared &)oldState { _state = std::static_pointer_cast(state); CGSize oldScreenSize = RCTCGSizeFromSize(_state->getData().viewportSize); CGSize viewportSize = RCTViewportSize(); viewportSize.height = std::nan(""); if (oldScreenSize.width != viewportSize.width) { auto stateData = InputAccessoryState{RCTSizeFromCGSize(viewportSize)}; _state->updateState(std::move(stateData)); } } - (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics oldLayoutMetrics:(LayoutMetrics const &)oldLayoutMetrics { [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; [_contentView setFrame:RCTCGRectFromRect(layoutMetrics.getContentFrame())]; } - (void)prepareForRecycle { [super prepareForRecycle]; _state.reset(); _textInput = nil; } @end Class RCTInputAccessoryCls(void) { return RCTInputAccessoryComponentView.class; }