diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index 91f2bb51c..18dc1fbf1 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -2064,7 +2064,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FBLazyVector: c12d2108050e27952983d565a232f6f7b1ad5e69 - hermes-engine: 57506c1404e8b80c5386de18743e0d02c8d4f681 + hermes-engine: c50a496dd5a3974cde1b7d14a944bee1ee64ca0c RCTDeprecation: 3280799c14232a56e5a44f92981a8ee33bc69fd9 RCTRequired: 9854a51b0f65ccf43ea0b744df4d70fce339db32 RCTSwiftUI: 96986e49a4fdc2c2103929dee2641e1b57edf33d @@ -2073,7 +2073,7 @@ SPEC CHECKSUMS: React: 7ef36630d07638043a134a7dd2ec17e0be10fc3c React-callinvoker: af4e8fe1d60ab63dd8d74c2a68988064c2848954 React-Core: c0fb1df65eb0ed7a8633841831f05f93c3eb3aff - React-Core-prebuilt: cd92350bf2041dde22a9bc0b8984d9c70d179ca1 + React-Core-prebuilt: 25c9d7a48b3bd78017d44e80de5fbb3eb139328d React-CoreModules: 7dfe7962360355f1547c85ab52e1fc4b57f17127 React-cxxreact: 9e9c7f1710bc58abebf924813b5e825b99adb8e5 React-debug: 38389b86e3570558ec73dd4cbc0cd2f2eec47a51 @@ -2135,7 +2135,7 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: 625d2f6d9d5ef01acc9dfe2b5385504bbffd2ad0 ReactCodegen: 27937747ddc743fcb66a8dc19e8edf60188d94cc ReactCommon: cc0e38600f82487c5fe5d29150abb6fa9d981986 - ReactNativeDependencies: cebf665879bab2908201494cc5a9760dbdf0a637 + ReactNativeDependencies: 8febfeb298c1be3a3699aac801aec086f0580694 ReactNativeEnriched: 790e857a207566a6dc34e7b45480b88bddf79bed Yoga: 772166513f9cd2d61a6251d0dacbbfaa5b537479 diff --git a/ios/EnrichedTextInputView.h b/ios/EnrichedTextInputView.h index c39b77adc..8ef225583 100644 --- a/ios/EnrichedTextInputView.h +++ b/ios/EnrichedTextInputView.h @@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN @public BOOL blockEmitting; } +- (CGSize)measureSize:(CGFloat)maxWidth; - (void)emitOnLinkDetectedEvent:(NSString *)text url:(NSString *)url range:(NSRange)range; @@ -40,8 +41,6 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)handleStyleBlocksAndConflicts:(StyleType)type range:(NSRange)range; - (NSArray *)getPresentStyleTypesFrom:(NSArray *)types range:(NSRange)range; -- (CGSize)measureInitialSizeWithMaxWidth:(CGFloat)maxWidth; -- (void)commitSize:(CGSize)size; @end NS_ASSUME_NONNULL_END diff --git a/ios/EnrichedTextInputView.mm b/ios/EnrichedTextInputView.mm index 0046152cf..c10512032 100644 --- a/ios/EnrichedTextInputView.mm +++ b/ios/EnrichedTextInputView.mm @@ -76,7 +76,8 @@ - (instancetype)initWithFrame:(CGRect)frame { _props = defaultProps; [self setDefaults]; [self setupTextView]; - [self addSubview:textView]; + [self setupPlaceholderLabel]; + self.contentView = textView; } return self; } @@ -264,14 +265,31 @@ - (void)setupTextView { textView.delegate = self; textView.input = self; textView.layoutManager.input = self; - textView.autoresizingMask = - UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; textView.adjustsFontForContentSizeCategory = YES; [textView addGestureRecognizer:[[TextBlockTapGestureRecognizer alloc] initWithInput:self action:@selector(onTextBlockTap:)]]; } +- (void)setupPlaceholderLabel { + _placeholderLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _placeholderLabel.translatesAutoresizingMaskIntoConstraints = NO; + [textView addSubview:_placeholderLabel]; + [NSLayoutConstraint activateConstraints:@[ + [_placeholderLabel.leadingAnchor + constraintEqualToAnchor:textView.leadingAnchor], + [_placeholderLabel.widthAnchor + constraintEqualToAnchor:textView.widthAnchor], + [_placeholderLabel.topAnchor constraintEqualToAnchor:textView.topAnchor], + [_placeholderLabel.bottomAnchor + constraintEqualToAnchor:textView.bottomAnchor] + ]]; + _placeholderLabel.lineBreakMode = NSLineBreakByTruncatingTail; + _placeholderLabel.text = @""; + _placeholderLabel.hidden = YES; + _placeholderLabel.adjustsFontForContentSizeCategory = YES; +} + // MARK: - Props - (void)updateProps:(Props::Shared const &)props @@ -717,6 +735,9 @@ - (void)updateProps:(Props::Shared const &)props [[NSParagraphStyle alloc] init]; textView.typingAttributes = defaultTypingAttributes; textView.selectedRange = prevSelectedRange; + + // update the placeholder as well + [self refreshPlaceholderLabelStyles]; } // editable @@ -744,14 +765,24 @@ - (void)updateProps:(Props::Shared const &)props // placeholderTextColor if (newViewProps.placeholderTextColor != oldViewProps.placeholderTextColor) { - textView.placeholderColor = - RCTUIColorFromSharedColor(newViewProps.placeholderTextColor); + // some real color + if (isColorMeaningful(newViewProps.placeholderTextColor)) { + _placeholderColor = + RCTUIColorFromSharedColor(newViewProps.placeholderTextColor); + } else { + _placeholderColor = nullptr; + } + [self refreshPlaceholderLabelStyles]; } // placeholder if (newViewProps.placeholder != oldViewProps.placeholder) { - [textView - setPlaceholderText:[NSString fromCppString:newViewProps.placeholder]]; + _placeholderLabel.text = [NSString fromCppString:newViewProps.placeholder]; + [self refreshPlaceholderLabelStyles]; + // additionally show placeholder on first mount if it should be there + if (isFirstMount && textView.text.length == 0) { + [self setPlaceholderLabelShown:YES]; + } } // mention indicators @@ -827,17 +858,75 @@ - (void)updateProps:(Props::Shared const &)props if (isFirstMount && newViewProps.autoFocus) { [textView reactFocus]; } - [textView updatePlaceholderVisibility]; } -- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics - oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics { - [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; +- (void)setPlaceholderLabelShown:(BOOL)shown { + if (shown) { + [self refreshPlaceholderLabelStyles]; + _placeholderLabel.hidden = NO; + } else { + _placeholderLabel.hidden = YES; + } +} + +- (void)refreshPlaceholderLabelStyles { + NSMutableDictionary *newAttrs = [defaultTypingAttributes mutableCopy]; + if (_placeholderColor != nullptr) { + newAttrs[NSForegroundColorAttributeName] = _placeholderColor; + } + NSAttributedString *newAttrStr = + [[NSAttributedString alloc] initWithString:_placeholderLabel.text + attributes:newAttrs]; + _placeholderLabel.attributedText = newAttrStr; +} + +// MARK: - Measuring and states + +- (CGSize)measureSize:(CGFloat)maxWidth { + // copy the the whole attributed string + NSMutableAttributedString *currentStr = [[NSMutableAttributedString alloc] + initWithAttributedString:textView.textStorage]; + + // edge case: empty input should still be of a height of a single line, so we + // add a mock "I" character + if ([currentStr length] == 0) { + [currentStr + appendAttributedString:[[NSAttributedString alloc] + initWithString:@"I" + attributes:textView.typingAttributes]]; + } + + // edge case: input with only a zero width space should still be of a height + // of a single line, so we add a mock "I" character + if ([currentStr length] == 1 && + [[currentStr.string substringWithRange:NSMakeRange(0, 1)] + isEqualToString:@"\u200B"]) { + [currentStr + appendAttributedString:[[NSAttributedString alloc] + initWithString:@"I" + attributes:textView.typingAttributes]]; + } + + // edge case: trailing newlines aren't counted towards height calculations, so + // we add a mock "I" character + if (currentStr.length > 0) { + unichar lastChar = + [currentStr.string characterAtIndex:currentStr.length - 1]; + if ([[NSCharacterSet newlineCharacterSet] characterIsMember:lastChar]) { + [currentStr + appendAttributedString:[[NSAttributedString alloc] + initWithString:@"I" + attributes:defaultTypingAttributes]]; + } + } - textView.frame = UIEdgeInsetsInsetRect( - self.bounds, RCTUIEdgeInsetsFromEdgeInsets(layoutMetrics.borderWidth)); - textView.textContainerInset = RCTUIEdgeInsetsFromEdgeInsets( - layoutMetrics.contentInsets - layoutMetrics.borderWidth); + CGRect boundingBox = + [currentStr boundingRectWithSize:CGSizeMake(maxWidth, CGFLOAT_MAX) + options:NSStringDrawingUsesLineFragmentOrigin | + NSStringDrawingUsesFontLeading + context:nullptr]; + + return CGSizeMake(maxWidth, ceil(boundingBox.size.height)); } // make sure the newest state is kept in _state property @@ -850,42 +939,18 @@ - (void)updateState:(State::Shared const &)state // componentView) so we need to run a single height calculation for any // initial values if (oldState == nullptr) { - [self commitSize:textView.textContainer.size]; + [self tryUpdatingHeight]; } } -- (void)commitSize:(CGSize)size { +- (void)tryUpdatingHeight { if (_state == nullptr) { return; } - + _componentViewHeightUpdateCounter++; auto selfRef = wrapManagedObjectWeakly(self); - facebook::react::Size newSize{.width = size.width, .height = size.height}; _state->updateState( - facebook::react::EnrichedTextInputViewState(newSize, selfRef)); -} - -- (CGSize)measureInitialSizeWithMaxWidth:(CGFloat)maxWidth { - NSTextContainer *container = textView.textContainer; - NSLayoutManager *layoutManager = textView.layoutManager; - - container.size = CGSizeMake(maxWidth, CGFLOAT_MAX); - - [layoutManager ensureLayoutForTextContainer:container]; - - CGRect used = [layoutManager usedRectForTextContainer:container]; - CGFloat height = ceil(used.size.height); - - // Empty text fallback - if (textView.textStorage.length == 0) { - UIFont *font = - textView.typingAttributes[NSFontAttributeName] ?: textView.font; - if (font) { - height = ceil(font.lineHeight); - } - } - - return CGSizeMake(maxWidth, height); + EnrichedTextInputViewState(_componentViewHeightUpdateCounter, selfRef)); } // MARK: - Active styles @@ -1607,7 +1672,12 @@ - (void)anyTextMayHaveBeenModified { } // placholder management - [textView updatePlaceholderVisibility]; + if (!_placeholderLabel.hidden && textView.textStorage.string.length > 0) { + [self setPlaceholderLabelShown:NO]; + } else if (textView.textStorage.string.length == 0 && + _placeholderLabel.hidden) { + [self setPlaceholderLabelShown:YES]; + } if (![textView.textStorage.string isEqualToString:_recentInputString]) { // modified words handling @@ -1643,9 +1713,57 @@ - (void)anyTextMayHaveBeenModified { } } + // update height on each character change + [self tryUpdatingHeight]; // update active styles as well [self tryUpdatingActiveStyles]; [self layoutAttachments]; + // update drawing - schedule debounced relayout + [self scheduleRelayoutIfNeeded]; +} + +// Debounced relayout helper - coalesces multiple requests into one per runloop +// tick +- (void)scheduleRelayoutIfNeeded { + // Cancel any previously scheduled invocation to debounce + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(_performRelayout) + object:nil]; + // Schedule on next runloop cycle + [self performSelector:@selector(_performRelayout) + withObject:nil + afterDelay:0]; +} + +- (void)_performRelayout { + if (!textView) { + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + NSRange wholeRange = + NSMakeRange(0, self->textView.textStorage.string.length); + NSRange actualRange = NSMakeRange(0, 0); + [self->textView.layoutManager + invalidateLayoutForCharacterRange:wholeRange + actualCharacterRange:&actualRange]; + [self->textView.layoutManager ensureLayoutForCharacterRange:actualRange]; + [self->textView.layoutManager + invalidateDisplayForCharacterRange:wholeRange]; + + // We have to explicitly set contentSize + // That way textView knows if content overflows and if should be scrollable + // We recall measureSize here because value returned from previous + // measureSize may not be up-to date at that point + CGSize measuredSize = [self measureSize:self->textView.frame.size.width]; + self->textView.contentSize = measuredSize; + }); +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + // used to run all lifecycle callbacks + [self anyTextMayHaveBeenModified]; } // MARK: - UITextView delegate methods @@ -1821,7 +1939,7 @@ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { defaultTypingAttributes = newTypingAttrs; textView.typingAttributes = defaultTypingAttributes; - [textView refreshPlaceholder]; + [self refreshPlaceholderLabelStyles]; NSRange prevSelectedRange = textView.selectedRange; diff --git a/ios/inputTextView/InputTextView.h b/ios/inputTextView/InputTextView.h index a3e82eec1..6ddac2e91 100644 --- a/ios/inputTextView/InputTextView.h +++ b/ios/inputTextView/InputTextView.h @@ -3,8 +3,4 @@ @interface InputTextView : UITextView @property(nonatomic, weak) id input; -@property(nonatomic, copy, nullable) NSString *placeholderText; -@property(nonatomic, strong, nullable) UIColor *placeholderColor; -- (void)updatePlaceholderVisibility; -- (void)refreshPlaceholder; @end diff --git a/ios/inputTextView/InputTextView.mm b/ios/inputTextView/InputTextView.mm index 0fa69f99f..076d1639d 100644 --- a/ios/inputTextView/InputTextView.mm +++ b/ios/inputTextView/InputTextView.mm @@ -4,27 +4,7 @@ #import "TextInsertionUtils.h" #import -@implementation InputTextView { - UILabel *_placeholderView; - CGSize _lastCommittedSize; -}; - -- (instancetype)initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame])) { - _placeholderView = [[UILabel alloc] initWithFrame:self.bounds]; - _placeholderView.isAccessibilityElement = NO; - _placeholderView.numberOfLines = 0; - _placeholderView.adjustsFontForContentSizeCategory = YES; - [self addSubview:_placeholderView]; - - self.textContainer.lineFragmentPadding = 0; - self.scrollEnabled = YES; - self.scrollsToTop = NO; - self.alwaysBounceVertical = YES; - _lastCommittedSize = CGSizeZero; - } - return self; -} +@implementation InputTextView - (void)copy:(id)sender { EnrichedTextInputView *typedInput = (EnrichedTextInputView *)_input; @@ -280,79 +260,6 @@ - (void)cut:(id)sender { [typedInput anyTextMayHaveBeenModified]; } -- (void)updatePlaceholderVisibility { - BOOL shouldShow = - self.placeholderText.length > 0 && self.textStorage.length == 0; - - _placeholderView.hidden = !shouldShow; -} - -- (void)setText:(NSString *)text { - [super setText:text]; - [self updatePlaceholderVisibility]; -} - -- (void)setAttributedText:(NSAttributedString *)attributedText { - [super setAttributedText:attributedText]; - [self updatePlaceholderVisibility]; -} - -- (void)setPlaceholderText:(NSString *)newPlaceholderText { - _placeholderText = newPlaceholderText; - [self refreshPlaceholder]; -} - -- (void)refreshPlaceholder { - EnrichedTextInputView *typedInput = (EnrichedTextInputView *)_input; - if (typedInput == nullptr) { - return; - } - - NSMutableDictionary *attributes = - [typedInput->defaultTypingAttributes mutableCopy]; - - if (_placeholderColor) { - attributes[NSForegroundColorAttributeName] = _placeholderColor; - } - - NSString *placeholder = _placeholderText ?: @""; - - _placeholderView.attributedText = - [[NSAttributedString alloc] initWithString:placeholder - attributes:attributes]; - - [self updatePlaceholderVisibility]; - - [self setNeedsLayout]; -} - -- (void)layoutSubviews { - [super layoutSubviews]; - - CGRect textFrame = - UIEdgeInsetsInsetRect(self.bounds, self.textContainerInset); - - CGFloat placeholderHeight = - [_placeholderView sizeThatFits:textFrame.size].height; - - textFrame.size.height = MIN(placeholderHeight, textFrame.size.height); - - _placeholderView.frame = textFrame; - - CGRect usedRect = - [self.layoutManager usedRectForTextContainer:self.textContainer]; - - CGSize newSize = usedRect.size; - - if (CGSizeEqualToSize(newSize, _lastCommittedSize)) { - return; - } - - _lastCommittedSize = newSize; - - [_input commitSize:newSize]; -} - - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { if (action == @selector(paste:)) { UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; diff --git a/ios/internals/EnrichedTextInputViewShadowNode.h b/ios/internals/EnrichedTextInputViewShadowNode.h index dc9a6d5de..9789e9b76 100644 --- a/ios/internals/EnrichedTextInputViewShadowNode.h +++ b/ios/internals/EnrichedTextInputViewShadowNode.h @@ -17,7 +17,6 @@ class EnrichedTextInputViewShadowNode : public ConcreteViewShadowNode< EnrichedTextInputViewComponentName, EnrichedTextInputViewProps, EnrichedTextInputViewEventEmitter, EnrichedTextInputViewState> { - public: using ConcreteViewShadowNode::ConcreteViewShadowNode; EnrichedTextInputViewShadowNode(const ShadowNodeFragment &fragment, @@ -26,7 +25,6 @@ class EnrichedTextInputViewShadowNode EnrichedTextInputViewShadowNode(const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment); void dirtyLayoutIfNeeded(); - Size measureContent(const LayoutContext &layoutContext, const LayoutConstraints &layoutConstraints) const override; @@ -39,7 +37,7 @@ class EnrichedTextInputViewShadowNode } private: - mutable Size _prevContentSize{NAN, NAN}; + int localForceHeightRecalculationCounter_; id setupMockTextInputView_() const; }; diff --git a/ios/internals/EnrichedTextInputViewShadowNode.mm b/ios/internals/EnrichedTextInputViewShadowNode.mm index 5a4e1cf18..6d560564e 100644 --- a/ios/internals/EnrichedTextInputViewShadowNode.mm +++ b/ios/internals/EnrichedTextInputViewShadowNode.mm @@ -1,5 +1,5 @@ #import "EnrichedTextInputViewShadowNode.h" - +#import "CoreText/CoreText.h" #import #import #import @@ -10,16 +10,15 @@ extern const char EnrichedTextInputViewComponentName[] = "EnrichedTextInputView"; -void EnrichedTextInputViewShadowNode::dirtyLayoutIfNeeded() { - const auto &state = getStateData(); - const auto nextSize = state.getContentSize(); - - if (_prevContentSize != nextSize) { - _prevContentSize = nextSize; - YGNodeMarkDirty(&yogaNode_); - } +EnrichedTextInputViewShadowNode::EnrichedTextInputViewShadowNode( + const ShadowNodeFragment &fragment, const ShadowNodeFamily::Shared &family, + ShadowNodeTraits traits) + : ConcreteViewShadowNode(fragment, family, traits) { + localForceHeightRecalculationCounter_ = 0; } +// mock input is used for the first measure calls that need to be done when the +// real input isn't defined yet id EnrichedTextInputViewShadowNode::setupMockTextInputView_() const { // it's rendered far away from the viewport const int veryFarAway = 20000; @@ -33,63 +32,72 @@ } EnrichedTextInputViewShadowNode::EnrichedTextInputViewShadowNode( - const ShadowNode &source, const ShadowNodeFragment &fragment) - : ConcreteViewShadowNode(source, fragment) { - - const auto &oldState = - static_cast(source) - .getStateData(); - - const auto &newState = getStateData(); + const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment) + : ConcreteViewShadowNode(sourceShadowNode, fragment) { + dirtyLayoutIfNeeded(); +} - const auto &oldSize = oldState.getContentSize(); - const auto &newSize = newState.getContentSize(); +void EnrichedTextInputViewShadowNode::dirtyLayoutIfNeeded() { + const auto state = this->getStateData(); + const int receivedCounter = state.getForceHeightRecalculationCounter(); - if (newSize != oldSize) { + if (receivedCounter > localForceHeightRecalculationCounter_) { + localForceHeightRecalculationCounter_ = receivedCounter; YGNodeMarkDirty(&yogaNode_); } } -EnrichedTextInputViewShadowNode::EnrichedTextInputViewShadowNode( - const ShadowNodeFragment &fragment, const ShadowNodeFamily::Shared &family, - ShadowNodeTraits traits) - : ConcreteViewShadowNode(fragment, family, traits) { - _prevContentSize = {}; -} - Size EnrichedTextInputViewShadowNode::measureContent( - const LayoutContext &, const LayoutConstraints &constraints) const { + const LayoutContext &layoutContext, + const LayoutConstraints &layoutConstraints) const { const auto state = this->getStateData(); const auto componentRef = state.getComponentViewRef(); RCTInternalGenericWeakWrapper *weakWrapper = (RCTInternalGenericWeakWrapper *)unwrapManagedObject(componentRef); + if (weakWrapper != nullptr) { id componentObject = weakWrapper.object; EnrichedTextInputView *typedComponentObject = (EnrichedTextInputView *)componentObject; if (typedComponentObject != nullptr) { - auto size = state.getContentSize(); - _prevContentSize = size; - return constraints.clamp(size); + __block CGSize estimatedSize; + + // synchronously dispatch to main thread if needed + if ([NSThread isMainThread]) { + estimatedSize = [typedComponentObject + measureSize:layoutConstraints.maximumSize.width]; + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ + estimatedSize = [typedComponentObject + measureSize:layoutConstraints.maximumSize.width]; + }); + } + + return {estimatedSize.width, + MIN(estimatedSize.height, layoutConstraints.maximumSize.height)}; } - } - __block CGSize estimatedSize; - // synchronously dispatch to main thread if needed - if ([NSThread isMainThread]) { - EnrichedTextInputView *mockTextInputView = setupMockTextInputView_(); - estimatedSize = [mockTextInputView - measureInitialSizeWithMaxWidth:constraints.maximumSize.width]; } else { - dispatch_sync(dispatch_get_main_queue(), ^{ + __block CGSize estimatedSize; + + // synchronously dispatch to main thread if needed + if ([NSThread isMainThread]) { EnrichedTextInputView *mockTextInputView = setupMockTextInputView_(); - estimatedSize = [mockTextInputView - measureInitialSizeWithMaxWidth:constraints.maximumSize.width]; - }); + estimatedSize = + [mockTextInputView measureSize:layoutConstraints.maximumSize.width]; + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ + EnrichedTextInputView *mockTextInputView = setupMockTextInputView_(); + estimatedSize = + [mockTextInputView measureSize:layoutConstraints.maximumSize.width]; + }); + } + + return {estimatedSize.width, + MIN(estimatedSize.height, layoutConstraints.maximumSize.height)}; } - return {estimatedSize.width, - MIN(estimatedSize.height, constraints.maximumSize.height)}; + return Size(); } } // namespace facebook::react diff --git a/ios/internals/EnrichedTextInputViewState.cpp b/ios/internals/EnrichedTextInputViewState.cpp new file mode 100644 index 000000000..52df8613d --- /dev/null +++ b/ios/internals/EnrichedTextInputViewState.cpp @@ -0,0 +1,10 @@ +#include "EnrichedTextInputViewState.h" + +namespace facebook::react { +int EnrichedTextInputViewState::getForceHeightRecalculationCounter() const { + return forceHeightRecalculationCounter_; +} +std::shared_ptr EnrichedTextInputViewState::getComponentViewRef() const { + return componentViewRef_; +} +} // namespace facebook::react diff --git a/ios/internals/EnrichedTextInputViewState.h b/ios/internals/EnrichedTextInputViewState.h index d32926b39..3da93fe50 100644 --- a/ios/internals/EnrichedTextInputViewState.h +++ b/ios/internals/EnrichedTextInputViewState.h @@ -1,24 +1,21 @@ #pragma once -#include +#include namespace facebook::react { class EnrichedTextInputViewState { public: - EnrichedTextInputViewState() = default; - - explicit EnrichedTextInputViewState(Size contentSize, - std::shared_ptr ref) - : contentSize_(contentSize), componentViewRef_(std::move(ref)) {} - - const Size &getContentSize() const { return contentSize_; } - - const std::shared_ptr getComponentViewRef() const { - return componentViewRef_; + EnrichedTextInputViewState() + : forceHeightRecalculationCounter_(0), componentViewRef_(nullptr) {} + EnrichedTextInputViewState(int counter, std::shared_ptr ref) { + forceHeightRecalculationCounter_ = counter; + componentViewRef_ = ref; } + int getForceHeightRecalculationCounter() const; + std::shared_ptr getComponentViewRef() const; private: - Size contentSize_{}; + int forceHeightRecalculationCounter_{}; std::shared_ptr componentViewRef_{}; };