@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
@@ -116,8 +116,4 @@ Both platforms provide the same API and functionality.
116
116
 
117
117
  ## License
118
118
 
119
- MIT
120
-
121
- ---
122
-
123
- Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
119
+ MIT
@@ -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
- // Called when action mode is destroyed
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+ (Estável, Rápida e Imune a Crashes)
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 APENAS o nosso menu customizado, esmagando as opções padrões da Apple
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thiagobueno/rn-selectable-text",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "description": "A library for custom text selection menus",
6
6
  "main": "./lib/module/index.js",