Skip to content

Commit 7eef5bc

Browse files
Add option to enforce pasting plain text
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 #1350
1 parent 377063c commit 7eef5bc

File tree

9 files changed

+74
-20
lines changed

9 files changed

+74
-20
lines changed

Libraries/Components/TextInput/TextInput.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,26 @@ type MacOSProps = $ReadOnly<{|
370370
*/
371371
clearTextOnSubmit?: ?boolean,
372372

373+
/**
374+
* Fired when a supported element is pasted
375+
*
376+
* @platform macos
377+
*/
378+
onPaste?: (event: PasteEvent) => void, // TODO(macOS GH#774)
379+
380+
/**
381+
* Enables Paste support for certain types of pasted types
382+
*
383+
* Possible values for `pastedTypes` are:
384+
*
385+
* - `'fileUrl'`
386+
* - `'image'`
387+
* - `'string'`
388+
*
389+
* @platform macos
390+
*/
391+
pastedTypes?: PastedTypesType,
392+
373393
/**
374394
* Configures keys that can be used to submit editing for the TextInput. Defaults to 'Enter' key.
375395
* @platform macos
@@ -537,10 +557,13 @@ type AndroidProps = $ReadOnly<{|
537557
underlineColorAndroid?: ?ColorValue,
538558
|}>;
539559

560+
export type PasteType = 'fileUrl' | 'image' | 'string'; // TODO(macOS GH#774)
561+
export type PastedTypesType = PasteType | $ReadOnlyArray<PasteType>; // TODO(macOS GH#774)
562+
540563
export type Props = $ReadOnly<{|
541564
...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
542565
...IOSProps,
543-
...MacOSProps,
566+
...MacOSProps, // TODO(macOS GH#774)
544567
...AndroidProps,
545568

546569
/**
@@ -786,13 +809,6 @@ export type Props = $ReadOnly<{|
786809
*/
787810
onPressOut?: ?(event: PressEvent) => mixed,
788811

789-
/**
790-
* Fired when a supported element is pasted
791-
*
792-
* @platform macos
793-
*/
794-
onPaste?: (event: PasteEvent) => void, // TODO(macOS GH#774)
795-
796812
/**
797813
* Callback that is called when the text input selection is changed.
798814
* This will be called with

Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
1111

1212
@interface RCTMultilineTextInputView : RCTBaseTextInputView
1313

14+
#if TARGET_OS_OSX // [TODO(macOS GH#774)
15+
- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes;
16+
#endif // ]TODO(macOS GH#774)
1417
@end
1518

1619
NS_ASSUME_NONNULL_END

Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ - (void)setEnableFocusRing:(BOOL)enableFocusRing {
9999
}
100100
}
101101

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

104107
#pragma mark - UIScrollViewDelegate

Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import <React/RCTMultilineTextInputViewManager.h>
99
#import <React/RCTMultilineTextInputView.h>
10+
#import <React/RCTUITextView.h> // TODO(macOS GH#774)
1011

1112
@implementation RCTMultilineTextInputViewManager
1213

@@ -22,4 +23,14 @@ - (RCTUIView *)view // TODO(macOS ISS#3536887)
2223
RCT_REMAP_NOT_OSX_VIEW_PROPERTY(dataDetectorTypes, backedTextInputView.dataDetectorTypes, UIDataDetectorTypes) // TODO(macOS GH#774)
2324
RCT_REMAP_OSX_VIEW_PROPERTY(dataDetectorTypes, backedTextInputView.enabledTextCheckingTypes, NSTextCheckingTypes) // TODO(macOS GH#774)
2425

26+
#if TARGET_OS_OSX // [TODO(macOS GH#774)
27+
RCT_CUSTOM_VIEW_PROPERTY(pastedTypes, NSArray<NSPasteboardType>*, RCTUITextView)
28+
{
29+
NSArray<NSPasteboardType> *types = json ? [RCTConvert NSPasteboardTypeArray:json] : nil;
30+
if ([view respondsToSelector:@selector(setReadablePasteBoardTypes:)]) {
31+
[view setReadablePasteBoardTypes: types];
32+
}
33+
}
34+
#endif // ]TODO(macOS GH#774)
35+
2536
@end

Libraries/Text/TextInput/Multiline/RCTUITextView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
5353
@property (nonatomic, assign) NSTextAlignment textAlignment;
5454
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;
5555
- (NSSize)sizeThatFits:(NSSize)size;
56+
- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes;
5657
#endif // ]TODO(macOS GH#774)
5758

5859
@end

Libraries/Text/TextInput/Multiline/RCTUITextView.m

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ @implementation RCTUITextView
2121
#endif // TODO(macOS GH#774)
2222
RCTBackedTextViewDelegateAdapter *_textInputDelegateAdapter;
2323
NSDictionary<NSAttributedStringKey, id> *_defaultTextAttributes;
24+
#if TARGET_OS_OSX // [TODO(macOS GH#774)
25+
NSArray<NSPasteboardType> *_readablePasteboardTypes;
26+
#endif // TODO(macOS GH#774)
2427
}
2528

2629
static UIFont *defaultPlaceholderFont()
@@ -177,6 +180,11 @@ - (void)setText:(NSString *)text
177180
self.string = text;
178181
}
179182

183+
- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes
184+
{
185+
_readablePasteboardTypes = readablePasteboardTypes;
186+
}
187+
180188
- (void)setTypingAttributes:(__unused NSDictionary *)typingAttributes
181189
{
182190
// Prevent NSTextView from changing its own typing attributes out from under us.
@@ -344,9 +352,7 @@ - (BOOL)performDragOperation:(id<NSDraggingInfo>)draggingInfo
344352
}
345353
- (NSArray *)readablePasteboardTypes
346354
{
347-
NSArray *types = [super readablePasteboardTypes];
348-
// TODO: Optionally support files/images with a prop
349-
return [types arrayByAddingObjectsFromArray:@[NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];
355+
return _readablePasteboardTypes ? _readablePasteboardTypes : [super readablePasteboardTypes];
350356
}
351357

352358
#endif // ]TODO(macOS GH#774)

Libraries/Text/TextInput/RCTBaseTextInputView.m

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#import <React/RCTInputAccessoryViewContent.h>
2020
#import <React/RCTTextAttributes.h>
2121
#import <React/RCTTextSelection.h>
22+
#import <React/RCTUITextView.h> // TODO(macOS GH#774)
2223
#import "../RCTTextUIKit.h" // TODO(macOS GH#774)
2324

2425
@implementation RCTBaseTextInputView {
@@ -680,10 +681,11 @@ - (BOOL)textInputShouldHandleKeyEvent:(NSEvent *)event {
680681
- (BOOL)textInputShouldHandlePaste:(__unused id)sender
681682
{
682683
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
683-
NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];
684-
684+
NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSPasteboardTypeFileURL, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];
685+
NSArray<NSPasteboardType>* pastedTypes = ((RCTUITextView*) self.backedTextInputView).readablePasteboardTypes;
686+
685687
// If there's a fileType that is of interest, notify JS. Also blocks notifying JS if it's a text paste
686-
if (_onPaste && fileType != nil) {
688+
if (_onPaste && fileType != nil && [pastedTypes containsObject:fileType]) {
687689
_onPaste([self dataTransferInfoFromPasteboard:pasteboard]);
688690
}
689691

React/Base/RCTConvert.m

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,11 +1233,12 @@ + (NSArray *)CGColorArray:(id)json
12331233
}
12341234

12351235
if ([type isEqualToString:@"fileUrl"]) {
1236-
return @[NSFilenamesPboardType];
1236+
return @[NSPasteboardTypeFileURL];
12371237
} else if ([type isEqualToString:@"image"]) {
12381238
return @[NSPasteboardTypePNG, NSPasteboardTypeTIFF];
1239+
} else if ([type isEqualToString:@"string"]) {
1240+
return @[NSPasteboardTypeString];
12391241
}
1240-
12411242
return @[];
12421243
}
12431244

@@ -1246,11 +1247,11 @@ + (NSArray *)CGColorArray:(id)json
12461247
if ([json isKindOfClass:[NSString class]]) {
12471248
return [RCTConvert NSPasteboardType:json];
12481249
} else if ([json isKindOfClass:[NSArray class]]) {
1249-
NSMutableArray *mutablePastboardTypes = [NSMutableArray new];
1250+
NSMutableArray *mutablePasteboardTypes = [NSMutableArray new];
12501251
for (NSString *type in json) {
1251-
[mutablePastboardTypes addObjectsFromArray:[RCTConvert NSPasteboardType:type]];
1252-
return mutablePastboardTypes.copy;
1252+
[mutablePasteboardTypes addObjectsFromArray:[RCTConvert NSPasteboardType:type]];
12531253
}
1254+
return mutablePasteboardTypes.copy;
12541255
}
12551256
return @[];
12561257
}

packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,18 @@ function OnPaste(): React.Node {
427427
appendLog(JSON.stringify(e.nativeEvent.dataTransfer.types));
428428
setImageUri(e.nativeEvent.dataTransfer.files[0].uri);
429429
}}
430-
placeholder="MULTI LINE with onPaste() for PNG and TIFF images"
430+
pastedTypes={['string']}
431+
placeholder="MULTI LINE with onPaste() text from clipboard"
432+
/>
433+
<TextInput
434+
multiline={true}
435+
style={styles.multiline}
436+
onPaste={(e: PasteEvent) => {
437+
appendLog(JSON.stringify(e.nativeEvent.dataTransfer.types));
438+
setImageUri(e.nativeEvent.dataTransfer.files[0].uri);
439+
}}
440+
pastedTypes={['fileUrl', 'image', 'string']}
441+
placeholder="MULTI LINE with onPaste() for PNG/TIFF images from clipboard or fileUrl (via Finder) and text from clipboard"
431442
/>
432443
<Text style={{height: 30}}>{log.join('\n')}</Text>
433444
<Image

0 commit comments

Comments
 (0)