@thiagobueno/rn-selectable-text 1.0.0 → 1.0.1
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/README.md
CHANGED
|
@@ -16,6 +16,9 @@ class SelectableTextView : FrameLayout {
|
|
|
16
16
|
private var menuOptions: Array<String> = emptyArray()
|
|
17
17
|
private var textView: TextView? = null
|
|
18
18
|
|
|
19
|
+
// A MÁGICA: Variável para segurar a referência do menu nativo do Android
|
|
20
|
+
private var currentActionMode: ActionMode? = null
|
|
21
|
+
|
|
19
22
|
constructor(context: Context?) : super(context!!)
|
|
20
23
|
constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs)
|
|
21
24
|
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
|
@@ -45,6 +48,8 @@ class SelectableTextView : FrameLayout {
|
|
|
45
48
|
textView.setTextIsSelectable(true)
|
|
46
49
|
textView.customSelectionActionModeCallback = object : ActionMode.Callback {
|
|
47
50
|
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
|
51
|
+
// Salva a referência da barra nativa do Android assim que ela nasce
|
|
52
|
+
currentActionMode = mode
|
|
48
53
|
return true
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -70,7 +75,8 @@ class SelectableTextView : FrameLayout {
|
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
|
73
|
-
//
|
|
78
|
+
// Limpa a referência quando o próprio usuário fecha o menu tocando fora
|
|
79
|
+
currentActionMode = null
|
|
74
80
|
}
|
|
75
81
|
}
|
|
76
82
|
}
|
|
@@ -94,4 +100,16 @@ class SelectableTextView : FrameLayout {
|
|
|
94
100
|
setupTextView()
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
|
-
|
|
103
|
+
|
|
104
|
+
// ====================================================================
|
|
105
|
+
// A CIRURGIA DE SEGURANÇA (Prevenção do Bug das Views que Somem)
|
|
106
|
+
// ====================================================================
|
|
107
|
+
override fun onDetachedFromWindow() {
|
|
108
|
+
super.onDetachedFromWindow()
|
|
109
|
+
// Se o React Native decidir remover essa View da tela (scroll ou navegação)
|
|
110
|
+
// e a barra nativa ainda estiver aberta, nós a fechamos à força.
|
|
111
|
+
// Isso devolve a memória e libera a UI Thread do Android.
|
|
112
|
+
currentActionMode?.finish()
|
|
113
|
+
currentActionMode = null
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -46,9 +46,10 @@ using namespace facebook::react;
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// Intercepta o "Copiar" de teclados físicos e anula a ação
|
|
49
50
|
- (void)copy:(id)sender
|
|
50
51
|
{
|
|
51
|
-
// Bloqueado
|
|
52
|
+
// Bloqueado silenciosamente
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
@end
|
|
@@ -221,30 +222,27 @@ using namespace facebook::react;
|
|
|
221
222
|
#pragma mark - UITextViewDelegate
|
|
222
223
|
|
|
223
224
|
// ====================================================================
|
|
224
|
-
// A NOVA API DO IOS 16+
|
|
225
|
+
// A NOVA API DO IOS 16+
|
|
225
226
|
// ====================================================================
|
|
226
227
|
- (UIMenu *)textView:(UITextView *)textView editMenuForTextInRange:(NSRange)range suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0)) {
|
|
227
228
|
NSMutableArray<UIMenuElement *> *customActions = [[NSMutableArray alloc] init];
|
|
228
229
|
|
|
229
230
|
for (NSString *option in _menuOptions) {
|
|
230
|
-
// Mapeia o botão diretamente para nossa função sem precisar de hacks de string
|
|
231
231
|
UIAction *action = [UIAction actionWithTitle:option image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
|
|
232
232
|
[self handleMenuSelection:option];
|
|
233
233
|
}];
|
|
234
234
|
[customActions addObject:action];
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
// Retorna
|
|
237
|
+
// Retorna apenas nosso menu. A ação "Copiar" nativa exigida pelo sistema é engolida e não aparece.
|
|
238
238
|
return [UIMenu menuWithTitle:@"" children:customActions];
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
242
242
|
{
|
|
243
243
|
if (@available(iOS 16.0, *)) {
|
|
244
|
-
// No iOS 16+, a Apple cuida da exibição do menu automaticamente via delegate
|
|
245
244
|
return;
|
|
246
245
|
} else {
|
|
247
|
-
// Fallback legado para iPhones antigos (iOS 15 ou menor)
|
|
248
246
|
if (textView.selectedRange.length > 0 && _menuOptions.count > 0) {
|
|
249
247
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
250
248
|
[self showCustomMenu];
|
|
@@ -255,7 +253,6 @@ using namespace facebook::react;
|
|
|
255
253
|
}
|
|
256
254
|
}
|
|
257
255
|
|
|
258
|
-
// Fallback apenas para iOS 15 e inferiores
|
|
259
256
|
- (void)showCustomMenu
|
|
260
257
|
{
|
|
261
258
|
if (![_customTextView canBecomeFirstResponder]) return;
|
|
@@ -293,12 +290,23 @@ using namespace facebook::react;
|
|
|
293
290
|
return YES;
|
|
294
291
|
}
|
|
295
292
|
|
|
293
|
+
// ====================================================================
|
|
294
|
+
// O TRUQUE PARA FORÇAR O MENU A ABRIR
|
|
295
|
+
// ====================================================================
|
|
296
296
|
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
|
297
297
|
{
|
|
298
298
|
NSString *selectorName = NSStringFromSelector(action);
|
|
299
299
|
if ([selectorName hasPrefix:@"customAction_"] && [selectorName hasSuffix:@":"]) {
|
|
300
300
|
return YES;
|
|
301
301
|
}
|
|
302
|
+
|
|
303
|
+
if (@available(iOS 16.0, *)) {
|
|
304
|
+
// Dizemos para o iOS que podemos copiar. Isso convence o sistema a não abortar o menu.
|
|
305
|
+
if (action == @selector(copy:)) {
|
|
306
|
+
return YES;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
302
310
|
return NO;
|
|
303
311
|
}
|
|
304
312
|
|