99
1010#import " RCTText.h"
1111
12+ #import < MobileCoreServices/UTCoreTypes.h>
13+
1214#import " RCTShadowText.h"
1315#import " RCTUtils.h"
1416#import " UIView+React.h"
@@ -28,6 +30,7 @@ @implementation RCTText
2830{
2931 NSTextStorage *_textStorage;
3032 CAShapeLayer *_highlightLayer;
33+ UILongPressGestureRecognizer *_longPressGestureRecognizer;
3134}
3235
3336- (instancetype )initWithFrame : (CGRect)frame
@@ -51,6 +54,22 @@ - (NSString *)description
5154 return [superDescription stringByReplacingCharactersInRange: semicolonRange withString: replacement];
5255}
5356
57+ - (void )setSelectable : (BOOL )selectable
58+ {
59+ if (_selectable == selectable) {
60+ return ;
61+ }
62+
63+ _selectable = selectable;
64+
65+ if (_selectable) {
66+ [self enableContextMenu ];
67+ }
68+ else {
69+ [self disableContextMenu ];
70+ }
71+ }
72+
5473- (void )reactSetFrame : (CGRect)frame
5574{
5675 // Text looks super weird if its frame is animated.
@@ -177,4 +196,72 @@ - (NSString *)accessibilityLabel
177196 return _textStorage.string ;
178197}
179198
199+ #pragma mark - Context Menu
200+
201+ - (void )enableContextMenu
202+ {
203+ _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc ] initWithTarget: self action: @selector (handleLongPress: )];
204+ [self addGestureRecognizer: _longPressGestureRecognizer];
205+ }
206+
207+ - (void )disableContextMenu
208+ {
209+ [self removeGestureRecognizer: _longPressGestureRecognizer];
210+ _longPressGestureRecognizer = nil ;
211+ }
212+
213+ - (void )handleLongPress : (UILongPressGestureRecognizer *)gesture
214+ {
215+ #if !TARGET_OS_TV
216+ UIMenuController *menuController = [UIMenuController sharedMenuController ];
217+
218+ if (menuController.isMenuVisible ) {
219+ return ;
220+ }
221+
222+ if (!self.isFirstResponder ) {
223+ [self becomeFirstResponder ];
224+ }
225+
226+ [menuController setTargetRect: self .bounds inView: self ];
227+ [menuController setMenuVisible: YES animated: YES ];
228+ #endif
229+ }
230+
231+ - (BOOL )canBecomeFirstResponder
232+ {
233+ return _selectable;
234+ }
235+
236+ - (BOOL )canPerformAction : (SEL )action withSender : (id )sender
237+ {
238+ if (action == @selector (copy: )) {
239+ return YES ;
240+ }
241+
242+ return [super canPerformAction: action withSender: sender];
243+ }
244+
245+ - (void )copy : (id )sender
246+ {
247+ #if !TARGET_OS_TV
248+ NSAttributedString *attributedString = _textStorage;
249+
250+ NSMutableDictionary *item = [NSMutableDictionary new ];
251+
252+ NSData *rtf = [attributedString dataFromRange: NSMakeRange (0 , attributedString.length)
253+ documentAttributes: @{NSDocumentTypeDocumentAttribute : NSRTFDTextDocumentType }
254+ error: nil ];
255+
256+ if (rtf) {
257+ [item setObject: rtf forKey: (id )kUTTypeFlatRTFD ];
258+ }
259+
260+ [item setObject: attributedString.string forKey: (id )kUTTypeUTF8PlainText ];
261+
262+ UIPasteboard *pasteboard = [UIPasteboard generalPasteboard ];
263+ pasteboard.items = @[item];
264+ #endif
265+ }
266+
180267@end
0 commit comments