From e8e577ea06e20407b66239746dfac1248e111aa5 Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Fri, 28 Apr 2023 13:54:54 +0200 Subject: [PATCH 1/6] feat: add caretHeight and caretYoffset to TextInput component --- .../Components/TextInput/TextInput.d.ts | 12 ++++ .../Components/TextInput/TextInput.flow.js | 12 ++++ .../Components/TextInput/TextInput.js | 14 ++++ .../Text/TextInput/Multiline/RCTUITextView.h | 2 + .../Text/TextInput/Multiline/RCTUITextView.mm | 69 ++++++++++++++++++- .../RCTBackedTextInputViewProtocol.h | 2 + .../TextInput/RCTBaseTextInputViewManager.mm | 2 + .../TextInput/RCTTextInputComponentView.mm | 8 +++ .../TextInput/RCTTextInputUtils.mm | 2 + .../components/iostextinput/primitives.h | 13 ++++ .../iostextinput/propsConversions.h | 12 ++++ 11 files changed, 147 insertions(+), 1 deletion(-) diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts index 7234cbb3c325c5..2d70da8fce876e 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts @@ -668,6 +668,18 @@ export interface TextInputProps */ caretHidden?: boolean | undefined; + /** + * Allows to adjust caret height. + * The default value is 0, which means the height of the caret will be calculated automatically + */ + caretHeight?: number | undefined; + + /** + * Allows to adjust caret postiion relative to the Y axis + * The default value is 0. + */ + caretYOffset?: number | undefined; + /** * If true, context menu is hidden. The default value is false. */ diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index 638acd7c7925a2..f6be6411021392 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -591,6 +591,18 @@ export type Props = $ReadOnly<{| */ caretHidden?: ?boolean, + /** + * Allows to adjust caret height. + * The default value is 0, which means the height of the caret will be calculated automatically + */ + + caretYOffset?: ?number, + /** + * Allows to adjust caret postiion relative to the Y axis + * The default value is 0. + */ + caretYHeight?: ?number, + /* * If `true`, contextMenuHidden is hidden. The default value is `false`. */ diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index 7b522fe5dcb026..be56da0c6a9520 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -365,6 +365,18 @@ type IOSProps = $ReadOnly<{| * @platform ios */ smartInsertDelete?: ?boolean, + + /** + * Allows to adjust caret height. + * The default value is 0, which means the height of the caret will be calculated automatically + */ + caretYOffset?: ?number, + + /** + * Allows to adjust caret postiion relative to the Y axis + * The default value is 0. + */ + caretHeight?: ?number, |}>; type AndroidProps = $ReadOnly<{| @@ -1503,6 +1515,8 @@ function InternalTextInput(props: Props): React.Node { style, )} text={text} + caretYOffset={props.caretYOffset} + caretHeight={props.caretHeight} /> ); } else if (Platform.OS === 'android') { diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h index 205f9943262add..94b32923d7d9f7 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h @@ -35,6 +35,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) UITextFieldViewMode clearButtonMode; @property (nonatomic, assign) BOOL caretHidden; +@property (nonatomic, assign) CGFloat caretYOffset; +@property (nonatomic, assign) CGFloat caretHeight; @property (nonatomic, strong, nullable) NSString *inputAccessoryViewID; diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 582b49c1ef4f4b..fb1c2d5ddc4c82 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -13,6 +13,41 @@ #import #import +//the UITextSelectionRect subclass needs to be created because the original version is not writable +@interface CustomTextSelectionRect : UITextSelectionRect + +@property (nonatomic) CGRect _rect; +@property (nonatomic) NSWritingDirection _writingDirection; +@property (nonatomic) BOOL _containsStart; // Returns YES if the rect contains the start of the selection. +@property (nonatomic) BOOL _containsEnd; // Returns YES if the rect contains the end of the selection. +@property (nonatomic) BOOL _isVertical; // Returns YES if the rect is for vertically oriented text. + +@end + +@implementation CustomTextSelectionRect + +- (CGRect)rect { + return __rect; +} + +- (NSWritingDirection)writingDirection { + return __writingDirection; +} + +- (BOOL)containsStart { + return __containsStart; +} + +- (BOOL)containsEnd { + return __containsEnd; +} + +- (BOOL)isVertical { + return __isVertical; +} + +@end + @implementation RCTUITextView { UILabel *_placeholderView; UITextView *_detachedTextView; @@ -307,11 +342,43 @@ - (void)_updatePlaceholder - (CGRect)caretRectForPosition:(UITextPosition *)position { + CGRect originalRect = [super caretRectForPosition:position]; + if (_caretHidden) { return CGRectZero; } - return [super caretRectForPosition:position]; + if(_caretYOffset != 0) { + originalRect.origin.y += _caretYOffset; + } + + if(_caretHeight != 0) { + originalRect.size.height = _caretHeight; + } + return originalRect; +} + +- (NSArray *)selectionRectsForRange:(UITextRange *)range { + NSArray *superRects = [super selectionRectsForRange:range]; + if(_caretYOffset != 0 && _caretHeight != 0) { + NSMutableArray *customTextSelectionRects = [NSMutableArray array]; + + for (UITextSelectionRect *rect in superRects) { + CustomTextSelectionRect *customTextRect = [[CustomTextSelectionRect alloc] init]; + + customTextRect._rect = CGRectMake(rect.rect.origin.x, rect.rect.origin.y + _caretYOffset, rect.rect.size.width, _caretHeight); + customTextRect._writingDirection = rect.writingDirection; + customTextRect._containsStart = rect.containsStart; + customTextRect._containsEnd = rect.containsEnd; + customTextRect._isVertical = rect.isVertical; + [customTextSelectionRects addObject:customTextRect]; + } + + return customTextSelectionRects; + + } + return superRects; + } #pragma mark - Utility Methods diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h index a8719ecd4d0165..2bd9581f8b2007 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h +++ b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h @@ -28,6 +28,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL contextMenuHidden; @property (nonatomic, assign, getter=isEditable) BOOL editable; @property (nonatomic, assign) BOOL caretHidden; +@property (nonatomic, assign) CGFloat caretYOffset; +@property (nonatomic, assign) CGFloat caretHeight; @property (nonatomic, assign) BOOL enablesReturnKeyAutomatically; @property (nonatomic, assign) UITextFieldViewMode clearButtonMode; @property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled; diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm index 6d3d18b11ebe80..47e16be69cb2e6 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm @@ -44,6 +44,8 @@ @implementation RCTBaseTextInputViewManager { RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, UIColor) RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType) RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL) +RCT_REMAP_VIEW_PROPERTY(caretYOffset, backedTextInputView.caretYOffset, CGFloat) +RCT_REMAP_VIEW_PROPERTY(caretHeight, backedTextInputView.caretHeight, CGFloat) RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode) RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL) RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 44e74da5cea06f..d90766d24d75c2 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -151,6 +151,14 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & _backedTextInputView.caretHidden = newTextInputProps.traits.caretHidden; } + if(newTextInputProps.traits.caretYOffset != oldTextInputProps.traits.caretYOffset) { + _backedTextInputView.caretYOffset = newTextInputProps.traits.caretYOffset; + } + + if(newTextInputProps.traits.caretHeight != oldTextInputProps.traits.caretHeight) { + _backedTextInputView.caretHeight = newTextInputProps.traits.caretHeight; + } + if (newTextInputProps.traits.clearButtonMode != oldTextInputProps.traits.clearButtonMode) { _backedTextInputView.clearButtonMode = RCTUITextFieldViewModeFromTextInputAccessoryVisibilityMode(newTextInputProps.traits.clearButtonMode); diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm index d4b91c921b1114..79b28643714e62 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm @@ -38,6 +38,8 @@ void RCTCopyBackedTextInput( toTextInput.keyboardAppearance = fromTextInput.keyboardAppearance; toTextInput.spellCheckingType = fromTextInput.spellCheckingType; toTextInput.caretHidden = fromTextInput.caretHidden; + toTextInput.caretYOffset = fromTextInput.caretYOffset; + toTextInput.caretHeight = toTextInput.caretHeight; toTextInput.clearButtonMode = fromTextInput.clearButtonMode; toTextInput.scrollEnabled = fromTextInput.scrollEnabled; toTextInput.secureTextEntry = fromTextInput.secureTextEntry; diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h index 664c0ccf0496ac..870c0136f733c4 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h @@ -155,6 +155,19 @@ class TextInputTraits final { */ bool caretHidden{false}; + /* + * iOS-only (inherently iOS-specific) + * Default value: 0 with a default font. + */ + + int caretHeight{0}; + + /* + * iOS-only (inherently iOS-specific) + * Default value: 0 means that the caret offset will have the default value + */ + int caretYOffset{0}; + /* * Controls the visibility of a `Clean` button. * iOS-only (implemented only on iOS for now) diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/propsConversions.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/propsConversions.h index 109f5a1237be0a..2a722f75cd8096 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/propsConversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/propsConversions.h @@ -75,6 +75,18 @@ static TextInputTraits convertRawProp( "caretHidden", sourceTraits.caretHidden, defaultTraits.caretHidden); + traits.caretYOffset = convertRawProp( + context, + rawProps, + "caretYOffset", + sourceTraits.caretYOffset, + defaultTraits.caretYOffset); + traits.caretHeight= convertRawProp( + context, + rawProps, + "caretHeight", + sourceTraits.caretHeight, + defaultTraits.caretHeight); traits.clearButtonMode = convertRawProp( context, rawProps, From 148d16294a902684f8bd5083043476159afaa03d Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Thu, 4 May 2023 11:36:18 +0200 Subject: [PATCH 2/6] minor changes after code review --- .../Libraries/Components/TextInput/TextInput.d.ts | 4 +++- .../Libraries/Components/TextInput/TextInput.flow.js | 6 ++++-- .../Libraries/Components/TextInput/TextInput.js | 6 +++--- .../Libraries/Text/TextInput/Multiline/RCTUITextView.mm | 5 +++-- .../Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm | 2 +- .../ios/react/renderer/components/iostextinput/primitives.h | 1 - 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts index 2d70da8fce876e..94300e36782661 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts @@ -671,12 +671,14 @@ export interface TextInputProps /** * Allows to adjust caret height. * The default value is 0, which means the height of the caret will be calculated automatically + * @platform ios */ caretHeight?: number | undefined; /** - * Allows to adjust caret postiion relative to the Y axis + * Allows to adjust caret position relative to the Y axis * The default value is 0. + * @platform ios */ caretYOffset?: number | undefined; diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index f6be6411021392..8088e1606f9ee5 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -594,12 +594,14 @@ export type Props = $ReadOnly<{| /** * Allows to adjust caret height. * The default value is 0, which means the height of the caret will be calculated automatically + * @platform ios */ - caretYOffset?: ?number, + /** - * Allows to adjust caret postiion relative to the Y axis + * Allows to adjust caret position relative to the Y axis * The default value is 0. + * @platform ios */ caretYHeight?: ?number, diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index be56da0c6a9520..72a5ea347c36d1 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -369,12 +369,14 @@ type IOSProps = $ReadOnly<{| /** * Allows to adjust caret height. * The default value is 0, which means the height of the caret will be calculated automatically + * @platform ios */ caretYOffset?: ?number, /** - * Allows to adjust caret postiion relative to the Y axis + * Allows to adjust caret position relative to the Y axis * The default value is 0. + * @platform ios */ caretHeight?: ?number, |}>; @@ -1515,8 +1517,6 @@ function InternalTextInput(props: Props): React.Node { style, )} text={text} - caretYOffset={props.caretYOffset} - caretHeight={props.caretHeight} /> ); } else if (Platform.OS === 'android') { diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index fb1c2d5ddc4c82..991c2590d8df12 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -352,10 +352,11 @@ - (CGRect)caretRectForPosition:(UITextPosition *)position originalRect.origin.y += _caretYOffset; } - if(_caretHeight != 0) { + if(_caretHeight != 0) { originalRect.size.height = _caretHeight; } - return originalRect; + + return originalRect; } - (NSArray *)selectionRectsForRange:(UITextRange *)range { diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm index 79b28643714e62..15beb67af72f87 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm @@ -39,7 +39,7 @@ void RCTCopyBackedTextInput( toTextInput.spellCheckingType = fromTextInput.spellCheckingType; toTextInput.caretHidden = fromTextInput.caretHidden; toTextInput.caretYOffset = fromTextInput.caretYOffset; - toTextInput.caretHeight = toTextInput.caretHeight; + toTextInput.caretHeight = fromTextInput.caretHeight; toTextInput.clearButtonMode = fromTextInput.clearButtonMode; toTextInput.scrollEnabled = fromTextInput.scrollEnabled; toTextInput.secureTextEntry = fromTextInput.secureTextEntry; diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h index 870c0136f733c4..90ab92134b6f2e 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h @@ -159,7 +159,6 @@ class TextInputTraits final { * iOS-only (inherently iOS-specific) * Default value: 0 with a default font. */ - int caretHeight{0}; /* From 1f1d08bb40e8f4106c6e04f7827dfbf3f3704d2f Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Fri, 28 Apr 2023 13:54:54 +0200 Subject: [PATCH 3/6] feat: add caretHeight and caretYoffset to TextInput component --- .../react-native/Libraries/Components/TextInput/TextInput.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index 72a5ea347c36d1..5abff201df447a 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -1517,6 +1517,8 @@ function InternalTextInput(props: Props): React.Node { style, )} text={text} + caretYOffset={props.caretYOffset} + caretHeight={props.caretHeight} /> ); } else if (Platform.OS === 'android') { From f55a9ffeedcd1f7b50702d0f75b0d4950846ab37 Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Thu, 4 May 2023 11:36:18 +0200 Subject: [PATCH 4/6] minor changes after code review --- .../react-native/Libraries/Components/TextInput/TextInput.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index 5abff201df447a..72a5ea347c36d1 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -1517,8 +1517,6 @@ function InternalTextInput(props: Props): React.Node { style, )} text={text} - caretYOffset={props.caretYOffset} - caretHeight={props.caretHeight} /> ); } else if (Platform.OS === 'android') { From f91c45f9d364c0f8b725315b5b15bf2a5543319f Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Mon, 26 Feb 2024 09:04:57 +0100 Subject: [PATCH 5/6] remove double double underscores and fix error --- .../TextInput/RCTTextInputViewConfig.js | 2 + .../Text/TextInput/Multiline/RCTUITextView.mm | 74 +++++++++---------- .../TextInput/Singleline/RCTUITextField.h | 2 + 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js index f91026796ce9cb..16b0024b785ba1 100644 --- a/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js +++ b/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js @@ -124,6 +124,8 @@ const RCTTextInputViewConfig = { editable: true, inputAccessoryViewID: true, caretHidden: true, + caretHeight: true, + caretYOffset: true, enablesReturnKeyAutomatically: true, placeholderTextColor: { process: require('../../StyleSheet/processColor').default, diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 991c2590d8df12..750898c6cebfc8 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -16,35 +16,27 @@ //the UITextSelectionRect subclass needs to be created because the original version is not writable @interface CustomTextSelectionRect : UITextSelectionRect -@property (nonatomic) CGRect _rect; -@property (nonatomic) NSWritingDirection _writingDirection; -@property (nonatomic) BOOL _containsStart; // Returns YES if the rect contains the start of the selection. -@property (nonatomic) BOOL _containsEnd; // Returns YES if the rect contains the end of the selection. -@property (nonatomic) BOOL _isVertical; // Returns YES if the rect is for vertically oriented text. +@property (nonatomic, assign) CGRect rect; +@property (nonatomic, assign) NSWritingDirection writingDirection; +@property (nonatomic, assign) BOOL containsStart; // Returns YES if the rect contains the start of the selection. +@property (nonatomic, assign) BOOL containsEnd; // Returns YES if the rect contains the end of the selection. +@property (nonatomic, assign) BOOL isVertical; // Returns YES if the rect is for vertically oriented text. @end -@implementation CustomTextSelectionRect - -- (CGRect)rect { - return __rect; -} - -- (NSWritingDirection)writingDirection { - return __writingDirection; +@implementation CustomTextSelectionRect { + CGRect _customRect; + NSWritingDirection _customWritingDirection; + BOOL _customContainsStart; + BOOL _customContainsEnd; + BOOL _customIsVertical; } -- (BOOL)containsStart { - return __containsStart; -} - -- (BOOL)containsEnd { - return __containsEnd; -} - -- (BOOL)isVertical { - return __isVertical; -} +@synthesize rect = _customRect; +@synthesize writingDirection = _customWritingDirection; +@synthesize containsStart = _customContainsStart; +@synthesize containsEnd = _customContainsEnd; +@synthesize isVertical = _customIsVertical; @end @@ -360,25 +352,25 @@ - (CGRect)caretRectForPosition:(UITextPosition *)position } - (NSArray *)selectionRectsForRange:(UITextRange *)range { - NSArray *superRects = [super selectionRectsForRange:range]; - if(_caretYOffset != 0 && _caretHeight != 0) { - NSMutableArray *customTextSelectionRects = [NSMutableArray array]; - - for (UITextSelectionRect *rect in superRects) { - CustomTextSelectionRect *customTextRect = [[CustomTextSelectionRect alloc] init]; - - customTextRect._rect = CGRectMake(rect.rect.origin.x, rect.rect.origin.y + _caretYOffset, rect.rect.size.width, _caretHeight); - customTextRect._writingDirection = rect.writingDirection; - customTextRect._containsStart = rect.containsStart; - customTextRect._containsEnd = rect.containsEnd; - customTextRect._isVertical = rect.isVertical; - [customTextSelectionRects addObject:customTextRect]; - } + NSArray *superRects = [super selectionRectsForRange:range]; + if(_caretYOffset != 0 && _caretHeight != 0) { + NSMutableArray *customTextSelectionRects = [NSMutableArray array]; - return customTextSelectionRects; + for (UITextSelectionRect *rect in superRects) { + CustomTextSelectionRect *customTextRect = [[CustomTextSelectionRect alloc] init]; - } - return superRects; + customTextRect.rect = CGRectMake(rect.rect.origin.x, rect.rect.origin.y + _caretYOffset, rect.rect.size.width, _caretHeight); + customTextRect.writingDirection = rect.writingDirection; + customTextRect.containsStart = rect.containsStart; + customTextRect.containsEnd = rect.containsEnd; + customTextRect.isVertical = rect.isVertical; + [customTextSelectionRects addObject:customTextRect]; + } + + return customTextSelectionRects; + + } + return superRects; } diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h index 91f8eb087acf87..0687407393b1e1 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h @@ -22,6 +22,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, weak) id textInputDelegate; @property (nonatomic, assign) BOOL caretHidden; +@property (nonatomic, assign) BOOL caretYOffset; +@property (nonatomic, assign) BOOL caretHeight; @property (nonatomic, assign) BOOL contextMenuHidden; @property (nonatomic, assign, readonly) BOOL textWasPasted; @property (nonatomic, assign, readonly) BOOL dictationRecognizing; From 1f3fd22b5e6ea6e3331893cebc54182004c0c8d0 Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Fri, 5 Apr 2024 13:05:32 +0200 Subject: [PATCH 6/6] changes after cr --- .../Text/TextInput/Multiline/RCTUITextView.mm | 10 +++++----- .../__tests__/__snapshots__/public-api-test.js.snap | 12 ------------ 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 750898c6cebfc8..f752f722db5a3f 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -13,8 +13,8 @@ #import #import -//the UITextSelectionRect subclass needs to be created because the original version is not writable -@interface CustomTextSelectionRect : UITextSelectionRect +// subclass needs to be created as UITextSelectionRect is an abstract base class +@interface RCTTextSelectionRect : UITextSelectionRect @property (nonatomic, assign) CGRect rect; @property (nonatomic, assign) NSWritingDirection writingDirection; @@ -24,7 +24,7 @@ @interface CustomTextSelectionRect : UITextSelectionRect @end -@implementation CustomTextSelectionRect { +@implementation RCTTextSelectionRect { CGRect _customRect; NSWritingDirection _customWritingDirection; BOOL _customContainsStart; @@ -351,13 +351,13 @@ - (CGRect)caretRectForPosition:(UITextPosition *)position return originalRect; } -- (NSArray *)selectionRectsForRange:(UITextRange *)range { +- (NSArray *)selectionRectsForRange:(UITextRange *)range { NSArray *superRects = [super selectionRectsForRange:range]; if(_caretYOffset != 0 && _caretHeight != 0) { NSMutableArray *customTextSelectionRects = [NSMutableArray array]; for (UITextSelectionRect *rect in superRects) { - CustomTextSelectionRect *customTextRect = [[CustomTextSelectionRect alloc] init]; + RCTTextSelectionRect *customTextRect = [[RCTTextSelectionRect alloc] init]; customTextRect.rect = CGRectMake(rect.rect.origin.x, rect.rect.origin.y + _caretYOffset, rect.rect.size.width, _caretHeight); customTextRect.writingDirection = rect.writingDirection; diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index de27ba219ed603..5fc6328813722a 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -2405,18 +2405,6 @@ declare export default HostComponent; " `; -exports[`public API should not change unintentionally Libraries/Components/TextInput/InputAccessoryView.js 1`] = ` -"type Props = $ReadOnly<{| - +children: React.Node, - nativeID?: ?string, - style?: ?ViewStyleProp, - backgroundColor?: ?ColorValue, -|}>; -declare const InputAccessoryView: React.AbstractComponent; -declare export default typeof InputAccessoryView; -" -`; - exports[`public API should not change unintentionally Libraries/Components/TextInput/RCTInputAccessoryViewNativeComponent.js 1`] = ` "export * from \\"../../../src/private/specs/components/RCTInputAccessoryViewNativeComponent\\"; declare export default typeof RCTInputAccessoryViewNativeComponent;