Skip to content

Commit

Permalink
[RN][macos] Fix disable scrolling for multiline text input
Browse files Browse the repository at this point in the history
Summary:
# Context

RN iOS supports disabling scrolling via `scrollEnabled` prop for multiline text inputs.
https://reactnative.dev/docs/0.68/textinput#scrollenabled-ios

This does [not work](microsoft#925) on MacOS

Since MacOS does not use `UITextView` which inherits from `UIScrollView`, the view manager property was set but not actually passed down to the underlying scroll view.

`RCTMultilineTextInputView` creates a `RCTUIScrollView` which is where we need to disable scrolling.
https://www.internalfb.com/code/archon_react_native_macos/[fde4113acd89fb13ee11636c48b59eac49c21bae]/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m?lines=31

`RCTUIScrollView` inherits from `NSScrollView` which does not have a `scrollEnabled` property, but there is an api we can use to disable scrolling when the property is set.

https://developer.apple.com/documentation/appkit/nsscrollview/1403494-scrollwheel

# Usage

NOTE: Only works with `multiline={true}`

```
<TextInput multiline={true} scrollEnabled={false} ... />
```

# Change

* Only expose the `scrollEnabled` property on `RCTMultilineTextInputView`.
  * `RCTSinglelineTextInputView` does not have scrolling so this property is unused.
* `RCTMultilineTextInputView` delegates the `scrollEnabled` to it's underlying `_scrollView`
* `RCTUIScrollView` defaults initial `scrollEnabled` to `YES`
* `RCTUIScrollView` disables scrolling when the `scrollEnabled` is `NO`

Test Plan:
## Zeratul

```
MDSTextInput
        {...textInputProps}
        {...(IS_MAC
          ? {multiline: true, blurOnSubmit: true, scrollEnabled: false}
          : {})} // workaround for T110399243
```

|before|after|
| https://pxl.cl/27gQp|https://pxl.cl/27gQr|

## RN Tester

|before|after|
|https://pxl.cl/27gRd|https://pxl.cl/27gRh|

Reviewers: lyahdav, ericroz, ackchiu, #seller_expansion

Reviewed By: lyahdav

Differential Revision: https://phabricator.intern.facebook.com/D37659010

Tasks: T120776572

Tags: marketplace, marketplace_seller_expansion

# Conflicts:
#	Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m
#	Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.m
#	Libraries/Text/TextInput/RCTBaseTextInputViewManager.m

# Conflicts:
#	Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m
#	React/Base/RCTUIKit.h
#	React/Base/macOS/RCTUIKit.m
  • Loading branch information
Shawn Dempsey authored and christophpurrer committed Aug 9, 2022
1 parent 54fa917 commit 166941a
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ NS_ASSUME_NONNULL_BEGIN

@interface RCTMultilineTextInputView : RCTBaseTextInputView

#if TARGET_OS_OSX
@property (nonatomic, assign) BOOL scrollEnabled;
#endif

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ - (void)setEnableFocusRing:(BOOL)enableFocusRing {
}
}

- (void)setScrollEnabled:(BOOL)scrollEnabled
{
_scrollView.scrollEnabled = scrollEnabled;
}

- (BOOL)scrollEnabled
{
return _scrollView.isScrollEnabled;
}
#endif // ]TODO(macOS GH#774)

#pragma mark - UIScrollViewDelegate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ - (RCTUIView *)view // TODO(macOS ISS#3536887)

RCT_REMAP_NOT_OSX_VIEW_PROPERTY(dataDetectorTypes, backedTextInputView.dataDetectorTypes, UIDataDetectorTypes) // TODO(macOS GH#774)
RCT_REMAP_OSX_VIEW_PROPERTY(dataDetectorTypes, backedTextInputView.enabledTextCheckingTypes, NSTextCheckingTypes) // TODO(macOS GH#774)
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)

@end
2 changes: 1 addition & 1 deletion Libraries/Text/TextInput/Multiline/RCTUITextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;

#if TARGET_OS_OSX // [TODO(macOS GH#774)
@property (nonatomic, assign) BOOL scrollEnabled;
@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
@property (nonatomic, strong, nullable) RCTUIColor *selectionColor; // TODO(OSS Candidate ISS#2710739)
@property (nonatomic, assign) UIEdgeInsets textContainerInsets;
@property (nonatomic, copy) NSString *text;
Expand Down
5 changes: 2 additions & 3 deletions Libraries/Text/TextInput/RCTBaseTextInputViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ @implementation RCTBaseTextInputViewManager
RCT_REMAP_OSX_VIEW_PROPERTY(spellCheck, backedTextInputView.continuousSpellCheckingEnabled, BOOL) // TODO(macOS GH#774)
RCT_REMAP_NOT_OSX_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL) // TODO(macOS GH#774)
RCT_REMAP_NOT_OSX_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode) // TODO(macOS GH#774)
RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL)
RCT_REMAP_NOT_OSX_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL) // TODO(macOS GH#774)
RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL)
RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
Expand All @@ -72,11 +71,11 @@ @implementation RCTBaseTextInputViewManager
RCT_EXPORT_VIEW_PROPERTY(onSubmitEditing, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(submitKeyEvents, NSArray<NSDictionary *>);

#if TARGET_OS_OSX // TODO(macOS ISS#2323203)
#if TARGET_OS_OSX // TODO(macOS GH#774)
RCT_EXPORT_VIEW_PROPERTY(onAutoCorrectToggle, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onSpellCheckToggle, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGrammarCheckToggle, RCTBubblingEventBlock);
#endif // TODO(macOS ISS#2323203)
#endif // TODO(macOS GH#774)

RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onKeyPressSync, RCTDirectEventBlock)
Expand Down
1 change: 1 addition & 0 deletions React/Base/RCTUIKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ CGPathRef UIBezierPathCreateCGPathRef(UIBezierPath *path);
@property (nonatomic, assign) BOOL alwaysBounceVertical;
// macOS specific properties
@property (nonatomic, assign) BOOL enableFocusRing;
@property (nonatomic, assign, getter=isScrollEnabled) BOOL scrollEnabled;

@end

Expand Down
19 changes: 19 additions & 0 deletions React/Base/macOS/RCTUIKit.m
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,15 @@ - (void)setEnableFocusRing:(BOOL)enableFocusRing {
}
}

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.scrollEnabled = YES;
}

return self;
}

// UIScrollView properties missing from NSScrollView
- (CGPoint)contentOffset
{
Expand Down Expand Up @@ -548,6 +557,16 @@ - (void)setAlwaysBounceVertical:(BOOL)alwaysBounceVertical
self.verticalScrollElasticity = alwaysBounceVertical ? NSScrollElasticityAllowed : NSScrollElasticityNone;
}

- (void)scrollWheel:(NSEvent *)theEvent
{
if (self.isScrollEnabled == NO) {
[[self nextResponder] scrollWheel:theEvent];
return;
}

[super scrollWheel:theEvent];
}

@end

BOOL RCTUIViewSetClipsToBounds(RCTPlatformView *view)
Expand Down
3 changes: 1 addition & 2 deletions React/Views/ScrollView/RCTScrollView.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ @interface RCTCustomScrollView :
#else // [TODO(macOS GH#774)
+ (BOOL)isCompatibleWithResponsiveScrolling;
@property (nonatomic, assign, getter=isInverted) BOOL inverted;
@property (nonatomic, assign, getter=isScrollEnabled) BOOL scrollEnabled;
@property (nonatomic, strong) NSPanGestureRecognizer *panGestureRecognizer;
#endif // ]TODO(macOS GH#774)
@end
Expand Down Expand Up @@ -114,7 +113,7 @@ - (BOOL)isFlipped

- (void)scrollWheel:(NSEvent *)theEvent
{
if (!self.scrollEnabled) {
if (!self.isScrollEnabled) {
[[self nextResponder] scrollWheel:theEvent];
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,12 @@ exports.examples = ([
multiline={true}
style={styles.multiline}
/>
<TextInput
placeholder="multiline text input with scroll disabled"
multiline={true}
scrollEnabled={false}
style={styles.multiline}
/>
<TextInput
defaultValue="uneditable multiline text input with phone number detection: 88888888."
editable={false}
Expand Down

0 comments on commit 166941a

Please sign in to comment.