Skip to content

Commit d53b633

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 8f5b6f6 commit d53b633

File tree

9 files changed

+60
-15
lines changed

9 files changed

+60
-15
lines changed

Libraries/Components/TextInput/TextInput.js

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,28 @@ type IOSProps = $ReadOnly<{|
353353
textContentType?: ?TextContentType,
354354
|}>;
355355

356+
type MacOSProps = $ReadOnly<{|
357+
/**
358+
* Fired when a supported element is pasted
359+
*
360+
* @platform macos
361+
*/
362+
onPaste?: (event: PasteEvent) => void, // TODO(macOS GH#774)
363+
364+
/**
365+
* Enables Paste support for certain types of pasted types
366+
*
367+
* Possible values for `pastedTypes` are:
368+
*
369+
* - `'fileUrl'`
370+
* - `'image'`
371+
* - `'string'`
372+
*
373+
* @platform macos
374+
*/
375+
pastedTypes?: PastedTypesType, // TODO(macOS GH#774)
376+
|}>;
377+
356378
type AndroidProps = $ReadOnly<{|
357379
/**
358380
* 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.
@@ -512,9 +534,13 @@ type AndroidProps = $ReadOnly<{|
512534
underlineColorAndroid?: ?ColorValue,
513535
|}>;
514536

537+
export type PasteType = 'fileUrl' | 'image' | 'string'; // TODO(macOS GH#774)
538+
export type PastedTypesType = PasteType | $ReadOnlyArray<PasteType>; // TODO(macOS GH#774)
539+
515540
export type Props = $ReadOnly<{|
516541
...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
517542
...IOSProps,
543+
...MacOSProps,
518544
...AndroidProps,
519545

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

763-
/**
764-
* Fired when a supported element is pasted
765-
*
766-
* @platform macos
767-
*/
768-
onPaste?: (event: PasteEvent) => void, // TODO(macOS GH#774)
769-
770789
/**
771790
* Callback that is called when the text input selection is changed.
772791
* 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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ - (BOOL)textInputShouldHandleKeyEvent:(NSEvent *)event {
639639
- (BOOL)textInputShouldHandlePaste:(__unused id)sender
640640
{
641641
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
642-
NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];
642+
NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSPasteboardTypeFileURL, NSPasteboardTypePNG, NSPasteboardTypeTIFF]];
643643

644644
// If there's a fileType that is of interest, notify JS. Also blocks notifying JS if it's a text paste
645645
if (_onPaste && fileType != nil) {

React/Base/RCTConvert.m

Lines changed: 5 additions & 4 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

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

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ function OnPaste(): React.Node {
422422
appendLog(JSON.stringify(e.nativeEvent.dataTransfer.types));
423423
setImageUri(e.nativeEvent.dataTransfer.files[0].uri);
424424
}}
425+
pastedTypes={['fileUrl', 'image', 'string']}
425426
placeholder="MULTI LINE with onPaste() for PNG and TIFF images"
426427
/>
427428
<Text style={{height: 30}}>{log.join('\n')}</Text>

0 commit comments

Comments
 (0)