Repository: flutter-form-builder-ecosystem/flutter_form_builder

Issue:
[FormBuilderTextField]: Please add onTapOutside function to make keyboard dismiss if click outside
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Package/Plugin version

9.0.0

### What you'd like to happen

```Markdown
I want to implement the onTapOutside callback to dismiss keyboard when click outside the textField
```


### Alternatives you've considered

_No response_

### Aditional information

_No response_


Discussion: This is a feature for `FormBuilderTextField`?
> This is a feature for `FormBuilderTextField`?

yes, please

Fix patch:
diff --git a/lib/src/fields/form_builder_text_field.dart b/lib/src/fields/form_builder_text_field.dart
index 2708a94f7..e4d32d5ac 100644
--- a/lib/src/fields/form_builder_text_field.dart
+++ b/lib/src/fields/form_builder_text_field.dart
@@ -203,6 +203,17 @@ class FormBuilderTextField extends FormBuilderFieldDecoration<String> {
   /// {@endtemplate}
   final GestureTapCallback? onTap;
 
+  /// {@template flutter.material.textfield.onTapOutside}
+  /// A callback to be invoked when a tap is detected outside of this TapRegion
+  /// and any other region with the same groupId, if any.
+  ///
+  /// The PointerDownEvent passed to the function is the event that caused the
+  /// notification. If this region is part of a group (i.e. groupId is set),
+  /// then it's possible that the event may be outside of this immediate region,
+  /// although it will be within the region of one of the group members.
+  /// {@endtemplate}
+  final TapRegionCallback? onTapOutside;
+
   /// The cursor for a mouse pointer when it enters or is hovering over the
   /// widget.
   ///
@@ -322,6 +333,7 @@ class FormBuilderTextField extends FormBuilderFieldDecoration<String> {
     this.minLines,
     this.showCursor,
     this.onTap,
+    this.onTapOutside,
     this.enableSuggestions = false,
     this.textAlignVertical,
     this.dragStartBehavior = DragStartBehavior.start,
@@ -381,6 +393,7 @@ class FormBuilderTextField extends FormBuilderFieldDecoration<String> {
               expands: expands,
               maxLength: maxLength,
               onTap: onTap,
+              onTapOutside: onTapOutside,
               onEditingComplete: onEditingComplete,
               onSubmitted: onSubmitted,
               inputFormatters: inputFormatters,


Test patch:
diff --git a/test/form_builder_text_field_test.dart b/test/form_builder_text_field_test.dart
index a5e945837..1542016b3 100644
--- a/test/form_builder_text_field_test.dart
+++ b/test/form_builder_text_field_test.dart
@@ -1,3 +1,4 @@
+import 'package:flutter/material.dart';
 import 'package:flutter_form_builder/flutter_form_builder.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -43,6 +44,11 @@ void main() {
       initialValueOnForm: 'ok',
     ),
   );
+
+  testWidgets(
+    'FormBuilderTextField triggers onTapOutside',
+    (tester) => _testFormBuilderTextFieldOnTapOutsideCallback(tester),
+  );
 }
 
 Future<void> _testFormBuilderTextFieldWithInitialValue(
@@ -75,3 +81,20 @@ Future<void> _testFormBuilderTextFieldWithInitialValue(
 
   expect(changedCount, 1);
 }
+
+Future<void> _testFormBuilderTextFieldOnTapOutsideCallback(
+    WidgetTester tester) async {
+  const textFieldName = 'Hello 🪐';
+  bool triggered = false;
+
+  var testWidget = FormBuilderTextField(
+    name: textFieldName,
+    onTapOutside: (event) => triggered = true,
+  );
+  await tester.pumpWidget(buildTestableFieldWidget(
+    testWidget,
+  ));
+  final textField = tester.firstWidget(find.byType(TextField)) as TextField;
+  textField.onTapOutside?.call(const PointerDownEvent());
+  expect(triggered, true);
+}