@thiagobueno/rn-selectable-text 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ios/SelectableTextView.mm +49 -57
- package/package.json +1 -1
|
@@ -20,8 +20,6 @@ using namespace facebook::react;
|
|
|
20
20
|
|
|
21
21
|
- (void)didMoveToWindow {
|
|
22
22
|
[super didMoveToWindow];
|
|
23
|
-
// FIX: iOS 16+ text selection bug after navigation.
|
|
24
|
-
// When returning to the screen, we force iOS to re-evaluate the interaction state.
|
|
25
23
|
if (self.window) {
|
|
26
24
|
BOOL wasSelectable = self.selectable;
|
|
27
25
|
self.selectable = NO;
|
|
@@ -31,12 +29,8 @@ using namespace facebook::react;
|
|
|
31
29
|
|
|
32
30
|
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
|
33
31
|
{
|
|
34
|
-
// FIX:
|
|
35
|
-
//
|
|
36
|
-
if (action == @selector(copy:) || action == @selector(selectAll:)) {
|
|
37
|
-
return YES;
|
|
38
|
-
}
|
|
39
|
-
|
|
32
|
+
// FIX: Remove hardcoded YES. We delegate entirely to the parent logic
|
|
33
|
+
// to allow complete suppression of the menu in Custom Mode.
|
|
40
34
|
if (self.parentSelectableTextView) {
|
|
41
35
|
return [self.parentSelectableTextView canPerformAction:action withSender:sender];
|
|
42
36
|
}
|
|
@@ -63,7 +57,6 @@ using namespace facebook::react;
|
|
|
63
57
|
}
|
|
64
58
|
}
|
|
65
59
|
|
|
66
|
-
// Intercepts physical keyboard "Copy" and nullifies the action to keep it custom
|
|
67
60
|
- (void)copy:(id)sender
|
|
68
61
|
{
|
|
69
62
|
// Silently blocked
|
|
@@ -142,7 +135,6 @@ using namespace facebook::react;
|
|
|
142
135
|
- (void)prepareForRecycle {
|
|
143
136
|
[super prepareForRecycle];
|
|
144
137
|
|
|
145
|
-
// FIX: Force drop focus when leaving screen
|
|
146
138
|
[_customTextView resignFirstResponder];
|
|
147
139
|
|
|
148
140
|
[[UIMenuController sharedMenuController] hideMenuFromView:_customTextView];
|
|
@@ -151,7 +143,6 @@ using namespace facebook::react;
|
|
|
151
143
|
_customTextView.text = nil;
|
|
152
144
|
_customTextView.selectedTextRange = nil;
|
|
153
145
|
|
|
154
|
-
// CRITICAL FIX: Do NOT clear _menuOptions here. Fabric's prop diffing will handle updates.
|
|
155
146
|
[self unhideAllViews:self];
|
|
156
147
|
}
|
|
157
148
|
|
|
@@ -241,19 +232,14 @@ using namespace facebook::react;
|
|
|
241
232
|
#pragma mark - UITextViewDelegate
|
|
242
233
|
|
|
243
234
|
// ====================================================================
|
|
244
|
-
//
|
|
235
|
+
// REAL-TIME CUSTOM MODE TRACKING
|
|
245
236
|
// ====================================================================
|
|
246
|
-
- (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// CUSTOM INVISIBLE MODE: Suppress native menu if array is empty
|
|
253
|
-
// ====================================================================
|
|
254
|
-
if (_menuOptions.count == 0) {
|
|
255
|
-
NSString *selectedText = [textView.text substringWithRange:range];
|
|
256
|
-
if (selectedText.length > 0) {
|
|
237
|
+
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
238
|
+
{
|
|
239
|
+
if (textView.selectedRange.length > 0) {
|
|
240
|
+
// INVISIBLE MODE (ALL IOS VERSIONS)
|
|
241
|
+
if (_menuOptions.count == 0) {
|
|
242
|
+
NSString *selectedText = [textView.text substringWithRange:textView.selectedRange];
|
|
257
243
|
if (auto eventEmitter = std::static_pointer_cast<const SelectableTextViewEventEmitter>(_eventEmitter)) {
|
|
258
244
|
SelectableTextViewEventEmitter::OnSelection selectionEvent = {
|
|
259
245
|
.chosenOption = std::string("CUSTOM_MODE"),
|
|
@@ -261,10 +247,43 @@ using namespace facebook::react;
|
|
|
261
247
|
};
|
|
262
248
|
eventEmitter->onSelection(selectionEvent);
|
|
263
249
|
}
|
|
250
|
+
return;
|
|
264
251
|
}
|
|
265
|
-
|
|
252
|
+
|
|
253
|
+
// STANDARD MODE
|
|
254
|
+
if (@available(iOS 16.0, *)) {
|
|
255
|
+
return;
|
|
256
|
+
} else {
|
|
257
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
258
|
+
[self showCustomMenu];
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
[[UIMenuController sharedMenuController] hideMenuFromView:_customTextView];
|
|
263
|
+
|
|
264
|
+
// IF SELECTION IS CLEARED, NOTIFY JS TO HIDE THE BOTTOM SHEET
|
|
265
|
+
if (_menuOptions.count == 0) {
|
|
266
|
+
if (auto eventEmitter = std::static_pointer_cast<const SelectableTextViewEventEmitter>(_eventEmitter)) {
|
|
267
|
+
SelectableTextViewEventEmitter::OnSelection selectionEvent = {
|
|
268
|
+
.chosenOption = std::string("CUSTOM_MODE"),
|
|
269
|
+
.highlightedText = std::string("")
|
|
270
|
+
};
|
|
271
|
+
eventEmitter->onSelection(selectionEvent);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ====================================================================
|
|
278
|
+
// THE NEW IOS 16+ API
|
|
279
|
+
// ====================================================================
|
|
280
|
+
- (UIMenu *)textView:(UITextView *)textView editMenuForTextInRange:(NSRange)range suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0)) {
|
|
281
|
+
|
|
282
|
+
if (_menuOptions.count == 0) {
|
|
266
283
|
return [UIMenu menuWithTitle:@"" children:@[]];
|
|
267
284
|
}
|
|
285
|
+
|
|
286
|
+
[textView becomeFirstResponder];
|
|
268
287
|
|
|
269
288
|
NSMutableArray<UIMenuElement *> *customActions = [[NSMutableArray alloc] init];
|
|
270
289
|
|
|
@@ -278,36 +297,6 @@ using namespace facebook::react;
|
|
|
278
297
|
return [UIMenu menuWithTitle:@"" children:customActions];
|
|
279
298
|
}
|
|
280
299
|
|
|
281
|
-
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
282
|
-
{
|
|
283
|
-
if (@available(iOS 16.0, *)) {
|
|
284
|
-
return;
|
|
285
|
-
} else {
|
|
286
|
-
if (textView.selectedRange.length > 0) {
|
|
287
|
-
|
|
288
|
-
// CUSTOM INVISIBLE MODE FOR IOS < 16
|
|
289
|
-
if (_menuOptions.count == 0) {
|
|
290
|
-
NSString *selectedText = [textView.text substringWithRange:textView.selectedRange];
|
|
291
|
-
if (auto eventEmitter = std::static_pointer_cast<const SelectableTextViewEventEmitter>(_eventEmitter)) {
|
|
292
|
-
SelectableTextViewEventEmitter::OnSelection selectionEvent = {
|
|
293
|
-
.chosenOption = std::string("CUSTOM_MODE"),
|
|
294
|
-
.highlightedText = std::string([selectedText UTF8String])
|
|
295
|
-
};
|
|
296
|
-
eventEmitter->onSelection(selectionEvent);
|
|
297
|
-
}
|
|
298
|
-
[[UIMenuController sharedMenuController] hideMenuFromView:_customTextView];
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
dispatch_async(dispatch_get_main_queue(), ^{
|
|
303
|
-
[self showCustomMenu];
|
|
304
|
-
});
|
|
305
|
-
} else {
|
|
306
|
-
[[UIMenuController sharedMenuController] hideMenuFromView:_customTextView];
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
300
|
- (void)showCustomMenu
|
|
312
301
|
{
|
|
313
302
|
if (![_customTextView canBecomeFirstResponder]) return;
|
|
@@ -346,17 +335,20 @@ using namespace facebook::react;
|
|
|
346
335
|
}
|
|
347
336
|
|
|
348
337
|
// ====================================================================
|
|
349
|
-
//
|
|
338
|
+
// SUPPRESS SYSTEM MENU IN CUSTOM MODE
|
|
350
339
|
// ====================================================================
|
|
351
340
|
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
|
352
341
|
{
|
|
342
|
+
// 100% INVISIBLE MODE: iOS is forbidden to render any bubble menu
|
|
343
|
+
if (_menuOptions.count == 0) {
|
|
344
|
+
return NO;
|
|
345
|
+
}
|
|
346
|
+
|
|
353
347
|
NSString *selectorName = NSStringFromSelector(action);
|
|
354
348
|
if ([selectorName hasPrefix:@"customAction_"] && [selectorName hasSuffix:@":"]) {
|
|
355
349
|
return YES;
|
|
356
350
|
}
|
|
357
351
|
|
|
358
|
-
// We tell iOS that we can perform standard actions.
|
|
359
|
-
// This convinces the system not to abort the menu rendering.
|
|
360
352
|
if (action == @selector(copy:) || action == @selector(selectAll:)) {
|
|
361
353
|
return YES;
|
|
362
354
|
}
|