Skip to content

Commit

Permalink
Add option to enforce pasting plain text
Browse files Browse the repository at this point in the history
There are use cases in which we want to ignore the base class [NSTextView readablePasteboardTypes] return values, which mostly, include RTF and formatted URL types
We want to ignore them in favor of plain text (NSPasteboardTypeString).

This change allows to opt into a custom list of supported paste types.

This is a follow-up to microsoft#1350
  • Loading branch information
christophpurrer committed Sep 8, 2022
1 parent 15d2dbd commit cb85f51
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 16 deletions.
33 changes: 26 additions & 7 deletions Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,28 @@ type IOSProps = $ReadOnly<{|
textContentType?: ?TextContentType,
|}>;

type MacOSProps = $ReadOnly<{|
/**
* Fired when a supported element is pasted
*
* @platform macos
*/
onPaste?: (event: PasteEvent) => void, // TODO(macOS GH#774)

/**
* Enables Paste support for certain types of pasted types
*
* Possible values for `pastedTypes` are:
*
* - `'fileUrl'`
* - `'image'`
* - `'string'`
*
* @platform macos
*/
pastedTypes?: PastedTypesType, // TODO(macOS GH#774)
|}>;

type AndroidProps = $ReadOnly<{|
/**
* Specifies autocomplete hints for the system, so it can provide autofill. On Android, the system will always attempt to offer autofill by using heuristics to identify the type of content.
Expand Down Expand Up @@ -512,9 +534,13 @@ type AndroidProps = $ReadOnly<{|
underlineColorAndroid?: ?ColorValue,
|}>;

export type PasteType = 'fileUrl' | 'image' | 'string'; // TODO(macOS GH#774)
export type PastedTypesType = PasteType | $ReadOnlyArray<PasteType>; // TODO(macOS GH#774)

export type Props = $ReadOnly<{|
...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
...IOSProps,
...MacOSProps,
...AndroidProps,

/**
Expand Down Expand Up @@ -760,13 +786,6 @@ export type Props = $ReadOnly<{|
*/
onPressOut?: ?(event: PressEvent) => mixed,

/**
* Fired when a supported element is pasted
*
* @platform macos
*/
onPaste?: (event: PasteEvent) => void, // TODO(macOS GH#774)

/**
* Callback that is called when the text input selection is changed.
* This will be called with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
NS_ASSUME_NONNULL_BEGIN

@interface RCTMultilineTextInputView : RCTBaseTextInputView

- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes;
@end

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

- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes {
[_backedTextInputView setReadablePasteBoardTypes:readablePasteboardTypes];
}
#endif // ]TODO(macOS GH#774)

#pragma mark - UIScrollViewDelegate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import <React/RCTMultilineTextInputViewManager.h>
#import <React/RCTMultilineTextInputView.h>
#import <React/RCTUITextView.h>

@implementation RCTMultilineTextInputViewManager

Expand All @@ -22,4 +23,14 @@ - (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)

#if TARGET_OS_OSX // [TODO(macOS GH#774)
RCT_CUSTOM_VIEW_PROPERTY(pastedTypes, NSArray<NSPasteboardType>*, RCTUITextView)
{
NSArray<NSPasteboardType> *types = json ? [RCTConvert NSPasteboardTypeArray:json] : nil;
if ([view respondsToSelector:@selector(setReadablePasteBoardTypes:)]) {
[view setReadablePasteBoardTypes: types];
}
}
#endif // ]TODO(macOS GH#774)

@end
1 change: 1 addition & 0 deletions Libraries/Text/TextInput/Multiline/RCTUITextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) NSTextAlignment textAlignment;
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;
- (NSSize)sizeThatFits:(NSSize)size;
- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes;
#endif // ]TODO(macOS GH#774)

@end
Expand Down
10 changes: 7 additions & 3 deletions Libraries/Text/TextInput/Multiline/RCTUITextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ @implementation RCTUITextView
#endif // TODO(macOS GH#774)
RCTBackedTextViewDelegateAdapter *_textInputDelegateAdapter;
NSDictionary<NSAttributedStringKey, id> *_defaultTextAttributes;
NSArray<NSPasteboardType> *_readablePasteboardTypes;
}

static UIFont *defaultPlaceholderFont()
Expand Down Expand Up @@ -177,6 +178,11 @@ - (void)setText:(NSString *)text
self.string = text;
}

- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes
{
_readablePasteboardTypes = readablePasteboardTypes;
}

- (void)setTypingAttributes:(__unused NSDictionary *)typingAttributes
{
// Prevent NSTextView from changing its own typing attributes out from under us.
Expand Down Expand Up @@ -344,9 +350,7 @@ - (BOOL)performDragOperation:(id<NSDraggingInfo>)draggingInfo
}
- (NSArray *)readablePasteboardTypes
{
NSArray *types = [super readablePasteboardTypes];
// TODO: Optionally support files/images with a prop
return [types arrayByAddingObjectsFromArray:@[NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];
return _readablePasteboardTypes ? _readablePasteboardTypes : [super readablePasteboardTypes];
}

#endif // ]TODO(macOS GH#774)
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Text/TextInput/RCTBaseTextInputView.m
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ - (BOOL)textInputShouldHandleKeyEvent:(NSEvent *)event {
- (BOOL)textInputShouldHandlePaste:(__unused id)sender
{
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];
NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSPasteboardTypeFileURL, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];

// If there's a fileType that is of interest, notify JS. Also blocks notifying JS if it's a text paste
if (_onPaste && fileType != nil) {
Expand Down
9 changes: 5 additions & 4 deletions React/Base/RCTConvert.m
Original file line number Diff line number Diff line change
Expand Up @@ -1233,11 +1233,12 @@ + (NSArray *)CGColorArray:(id)json
}

if ([type isEqualToString:@"fileUrl"]) {
return @[NSFilenamesPboardType];
return @[NSPasteboardTypeFileURL];
} else if ([type isEqualToString:@"image"]) {
return @[NSPasteboardTypePNG, NSPasteboardTypeTIFF];
} else if ([type isEqualToString:@"string"]) {
return @[NSPasteboardTypeString];
}

return @[];
}

Expand All @@ -1248,9 +1249,9 @@ + (NSArray *)CGColorArray:(id)json
} else if ([json isKindOfClass:[NSArray class]]) {
NSMutableArray *mutablePastboardTypes = [NSMutableArray new];
for (NSString *type in json) {
[mutablePastboardTypes addObjectsFromArray:[RCTConvert NSPasteboardType:type]];
return mutablePastboardTypes.copy;
[mutablePastboardTypes addObjectsFromArray:[RCTConvert NSPasteboardType:type]];
}
return mutablePastboardTypes.copy;
}
return @[];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ function OnPaste(): React.Node {
appendLog(JSON.stringify(e.nativeEvent.dataTransfer.types));
setImageUri(e.nativeEvent.dataTransfer.files[0].uri);
}}
pastedTypes={['fileUrl', 'image', 'string']}
placeholder="MULTI LINE with onPaste() for PNG and TIFF images"
/>
<Text style={{height: 30}}>{log.join('\n')}</Text>
Expand Down

0 comments on commit cb85f51

Please sign in to comment.