From cc4aa0cd9dd257327459a19263e322ea1cb510b3 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Wed, 23 Apr 2025 15:55:24 +0530 Subject: [PATCH 01/11] feat: url card envfield textfield turned multiline, further will be done as per instructions --- lib/screens/common_widgets/env_trigger_field.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/screens/common_widgets/env_trigger_field.dart b/lib/screens/common_widgets/env_trigger_field.dart index a7e470e76..ff6d7b32f 100644 --- a/lib/screens/common_widgets/env_trigger_field.dart +++ b/lib/screens/common_widgets/env_trigger_field.dart @@ -117,6 +117,7 @@ class EnvironmentTriggerFieldState extends State { return ExtendedTextField( controller: textEditingController, focusNode: focusnode, + maxLines: null, decoration: widget.decoration, style: widget.style, onChanged: widget.onChanged, From ad7b3ca32893b8f678f45a52273aca55e14f5dff Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Thu, 24 Apr 2025 00:50:24 +0530 Subject: [PATCH 02/11] fix: field becomes single line when not focused --- .../common_widgets/env_trigger_field.dart | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/screens/common_widgets/env_trigger_field.dart b/lib/screens/common_widgets/env_trigger_field.dart index ff6d7b32f..961295c05 100644 --- a/lib/screens/common_widgets/env_trigger_field.dart +++ b/lib/screens/common_widgets/env_trigger_field.dart @@ -41,20 +41,29 @@ class EnvironmentTriggerField extends StatefulWidget { class EnvironmentTriggerFieldState extends State { late TextEditingController controller; late FocusNode _focusNode; + bool _isFocused = false; @override void initState() { super.initState(); controller = widget.controller ?? TextEditingController.fromValue(TextEditingValue( - text: widget.initialValue!, - selection: - TextSelection.collapsed(offset: widget.initialValue!.length))); + text: widget.initialValue ?? '', + selection: TextSelection.collapsed( + offset: widget.initialValue?.length ?? 0))); _focusNode = widget.focusNode ?? FocusNode(); + _focusNode.addListener(_handleFocusChange); + } + + void _handleFocusChange() { + setState(() { + _isFocused = _focusNode.hasFocus; + }); } @override void dispose() { + _focusNode.removeListener(_handleFocusChange); controller.dispose(); _focusNode.dispose(); super.dispose(); @@ -67,9 +76,9 @@ class EnvironmentTriggerFieldState extends State { (oldWidget.initialValue != widget.initialValue)) { controller = widget.controller ?? TextEditingController.fromValue(TextEditingValue( - text: widget.initialValue!, + text: widget.initialValue ?? '', selection: TextSelection.collapsed( - offset: widget.initialValue!.length))); + offset: widget.initialValue?.length ?? 0))); } } @@ -117,7 +126,7 @@ class EnvironmentTriggerFieldState extends State { return ExtendedTextField( controller: textEditingController, focusNode: focusnode, - maxLines: null, + maxLines: _isFocused ? null : 1, decoration: widget.decoration, style: widget.style, onChanged: widget.onChanged, @@ -130,4 +139,4 @@ class EnvironmentTriggerFieldState extends State { }, ); } -} +} \ No newline at end of file From adb9ea81bcbb13bef859f06426567dc3d985f12f Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Thu, 24 Apr 2025 00:56:43 +0530 Subject: [PATCH 03/11] feat: smoothen variation in textfield size --- .../common_widgets/env_trigger_field.dart | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/screens/common_widgets/env_trigger_field.dart b/lib/screens/common_widgets/env_trigger_field.dart index 961295c05..d5193f1f2 100644 --- a/lib/screens/common_widgets/env_trigger_field.dart +++ b/lib/screens/common_widgets/env_trigger_field.dart @@ -123,18 +123,23 @@ class EnvironmentTriggerFieldState extends State { }), ], fieldViewBuilder: (context, textEditingController, focusnode) { - return ExtendedTextField( - controller: textEditingController, - focusNode: focusnode, - maxLines: _isFocused ? null : 1, - decoration: widget.decoration, - style: widget.style, - onChanged: widget.onChanged, - onSubmitted: widget.onFieldSubmitted, - specialTextSpanBuilder: EnvRegExpSpanBuilder(), - onTapOutside: (event) { - _focusNode.unfocus(); - }, + return AnimatedSize( + duration: const Duration(milliseconds: 200), + curve: Curves.easeInOut, + child: ExtendedTextField( + controller: textEditingController, + focusNode: focusnode, + maxLines: _isFocused ? null : 1, + minLines: 1, + decoration: widget.decoration, + style: widget.style, + onChanged: widget.onChanged, + onSubmitted: widget.onFieldSubmitted, + specialTextSpanBuilder: EnvRegExpSpanBuilder(), + onTapOutside: (event) { + _focusNode.unfocus(); + }, + ), ); }, ); From 667651c67f2dc889b381c790881515b62e37bbc2 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Thu, 24 Apr 2025 18:31:21 +0530 Subject: [PATCH 04/11] feat: environment edit textfields turned multiline --- .../envvar/editor_pane/variables_pane.dart | 4 +- lib/widgets/field_cell.dart | 20 +++-- .../lib/widgets/textfield_outlined.dart | 76 +++++++++++++------ 3 files changed, 67 insertions(+), 33 deletions(-) diff --git a/lib/screens/envvar/editor_pane/variables_pane.dart b/lib/screens/envvar/editor_pane/variables_pane.dart index af3a1e398..cb0f79b09 100644 --- a/lib/screens/envvar/editor_pane/variables_pane.dart +++ b/lib/screens/envvar/editor_pane/variables_pane.dart @@ -195,7 +195,7 @@ class EditEnvironmentVariablesState dividerThickness: 0, horizontalMargin: 0, headingRowHeight: 0, - dataRowHeight: kDataTableRowHeight, + dataRowHeight: null, // Allow dynamic row height bottomMargin: kDataTableBottomPadding, isVerticalScrollBarVisible: true, columns: columns, @@ -227,4 +227,4 @@ class EditEnvironmentVariablesState ], ); } -} +} \ No newline at end of file diff --git a/lib/widgets/field_cell.dart b/lib/widgets/field_cell.dart index 278de67f7..4fb9e8d80 100644 --- a/lib/widgets/field_cell.dart +++ b/lib/widgets/field_cell.dart @@ -19,13 +19,17 @@ class CellField extends StatelessWidget { @override Widget build(BuildContext context) { - return ADOutlinedTextField( - keyId: keyId, - initialValue: initialValue, - hintText: hintText, - hintTextFontSize: Theme.of(context).textTheme.bodySmall?.fontSize, - onChanged: onChanged, - colorScheme: colorScheme, + return SizedBox( + width: double.infinity, // Ensure the text field takes full cell width + child: ADOutlinedTextField( + keyId: keyId, + initialValue: initialValue, + hintText: hintText, + hintTextFontSize: Theme.of(context).textTheme.bodySmall?.fontSize, + onChanged: onChanged, + colorScheme: colorScheme, + isDense: true, // Compact rendering + ), ); } -} +} \ No newline at end of file diff --git a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart index b9b2588d2..bd200af02 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import '../tokens/tokens.dart'; import 'decoration_input_textfield.dart'; -class ADOutlinedTextField extends StatelessWidget { +class ADOutlinedTextField extends StatefulWidget { const ADOutlinedTextField({ super.key, this.keyId, @@ -50,35 +50,65 @@ class ADOutlinedTextField extends StatelessWidget { final void Function(String)? onChanged; final ColorScheme? colorScheme; + @override + State createState() => _ADOutlinedTextFieldState(); +} + +class _ADOutlinedTextFieldState extends State { + late FocusNode _focusNode; + bool _isFocused = false; + + @override + void initState() { + super.initState(); + _focusNode = FocusNode(); + _focusNode.addListener(_handleFocusChange); + } + + void _handleFocusChange() { + setState(() { + _isFocused = _focusNode.hasFocus; + }); + } + + @override + void dispose() { + _focusNode.removeListener(_handleFocusChange); + _focusNode.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - var clrScheme = colorScheme ?? Theme.of(context).colorScheme; + var clrScheme = widget.colorScheme ?? Theme.of(context).colorScheme; return TextFormField( - key: keyId != null ? Key(keyId!) : null, - controller: controller, - readOnly: readOnly, - enabled: enabled, - maxLines: maxLines, - expands: expands, - initialValue: initialValue, - style: textStyle ?? + key: widget.keyId != null ? Key(widget.keyId!) : null, + controller: widget.controller, + focusNode: _focusNode, + readOnly: widget.readOnly, + enabled: widget.enabled, + maxLines: _isFocused ? null : 1, // Multi-line when focused, single-line otherwise + keyboardType: TextInputType.multiline, // Support newlines + expands: widget.expands, + initialValue: widget.initialValue, + style: widget.textStyle ?? kCodeStyle.copyWith( - fontSize: textFontSize, - color: textColor ?? clrScheme.onSurface, + fontSize: widget.textFontSize, + color: widget.textColor ?? clrScheme.onSurface, ), decoration: getTextFieldInputDecoration( clrScheme, - fillColor: fillColor, - hintText: hintText, - hintTextStyle: hintTextStyle, - hintTextFontSize: hintTextFontSize, - hintTextColor: hintTextColor, - contentPadding: contentPadding, - focussedBorderColor: focussedBorderColor, - enabledBorderColor: enabledBorderColor, - isDense: isDense, + fillColor: widget.fillColor, + hintText: widget.hintText, + hintTextStyle: widget.hintTextStyle, + hintTextFontSize: widget.hintTextFontSize, + hintTextColor: widget.hintTextColor, + contentPadding: widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + focussedBorderColor: widget.focussedBorderColor, + enabledBorderColor: widget.enabledBorderColor, + isDense: widget.isDense ?? true, // Ensure compact rendering ), - onChanged: onChanged, + onChanged: widget.onChanged, ); } -} +} \ No newline at end of file From 2763823ed9ce6344efc1ca43f673f9fb932e719d Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Fri, 25 Apr 2025 22:06:48 +0530 Subject: [PATCH 05/11] feat: collection pane/side pane search field turned multi-line --- .../lib/widgets/textfield_raw.dart | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/apidash_design_system/lib/widgets/textfield_raw.dart b/packages/apidash_design_system/lib/widgets/textfield_raw.dart index a58964178..366bcbcd6 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_raw.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_raw.dart @@ -1,7 +1,7 @@ import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; -class ADRawTextField extends StatelessWidget { +class ADRawTextField extends StatefulWidget { const ADRawTextField({ super.key, this.onChanged, @@ -19,23 +19,50 @@ class ADRawTextField extends StatelessWidget { final TextStyle? style; final bool readOnly; + @override + State createState() => _ADRawTextFieldState(); +} + +class _ADRawTextFieldState extends State { + bool isFocused = false; + @override + void initState() { + isFocused = false; + super.initState(); + } + + void alterFocus(bool val) { + setState(() { + isFocused = val; + }); + } + @override Widget build(BuildContext context) { - return TextField( - readOnly: readOnly, - controller: controller, - onChanged: onChanged, - style: style, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - hintText: hintText, - hintStyle: hintTextStyle, - contentPadding: kPv8, + return AnimatedSize( + duration: Duration(milliseconds: 200), + curve: Curves.easeInOut, + child: TextField( + onTap: () => alterFocus(true), + readOnly: widget.readOnly, + controller: widget.controller, + onSubmitted: (value) => alterFocus(false), + maxLines: isFocused ? null : 1, + minLines: 1, + onChanged: widget.onChanged, + style: widget.style, + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + hintText: widget.hintText, + hintStyle: widget.hintTextStyle, + contentPadding: kPv8, + ), + onTapOutside: (PointerDownEvent event) { + FocusManager.instance.primaryFocus?.unfocus(); + alterFocus(false); + }, ), - onTapOutside: (PointerDownEvent event) { - FocusManager.instance.primaryFocus?.unfocus(); - }, ); } } From e0fce1e7fab0b5301b4555ce57c36ae3aaae278d Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Wed, 30 Apr 2025 15:32:35 +0530 Subject: [PATCH 06/11] feat: multi-line box above the field appears (still some issues persist) --- .../lib/widgets/textfield_outlined.dart | 123 ++++++++++++++---- 1 file changed, 95 insertions(+), 28 deletions(-) diff --git a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart index bd200af02..d8a85bdf0 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart @@ -56,12 +56,14 @@ class ADOutlinedTextField extends StatefulWidget { class _ADOutlinedTextFieldState extends State { late FocusNode _focusNode; + late TextEditingController _controller; bool _isFocused = false; @override void initState() { super.initState(); _focusNode = FocusNode(); + _controller = widget.controller ?? TextEditingController(text: widget.initialValue); _focusNode.addListener(_handleFocusChange); } @@ -73,42 +75,107 @@ class _ADOutlinedTextFieldState extends State { @override void dispose() { + if (widget.controller == null) { + _controller.dispose(); + } _focusNode.removeListener(_handleFocusChange); _focusNode.dispose(); super.dispose(); } + int _calculateLineCount(String text, TextStyle textStyle, double maxWidth) { + final textPainter = TextPainter( + text: TextSpan(text: text, style: textStyle), + textDirection: TextDirection.ltr, + maxLines: null, + ); + textPainter.layout(maxWidth: maxWidth); + return textPainter.computeLineMetrics().length; + } + @override Widget build(BuildContext context) { var clrScheme = widget.colorScheme ?? Theme.of(context).colorScheme; - return TextFormField( - key: widget.keyId != null ? Key(widget.keyId!) : null, - controller: widget.controller, - focusNode: _focusNode, - readOnly: widget.readOnly, - enabled: widget.enabled, - maxLines: _isFocused ? null : 1, // Multi-line when focused, single-line otherwise - keyboardType: TextInputType.multiline, // Support newlines - expands: widget.expands, - initialValue: widget.initialValue, - style: widget.textStyle ?? - kCodeStyle.copyWith( - fontSize: widget.textFontSize, - color: widget.textColor ?? clrScheme.onSurface, - ), - decoration: getTextFieldInputDecoration( - clrScheme, - fillColor: widget.fillColor, - hintText: widget.hintText, - hintTextStyle: widget.hintTextStyle, - hintTextFontSize: widget.hintTextFontSize, - hintTextColor: widget.hintTextColor, - contentPadding: widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8), - focussedBorderColor: widget.focussedBorderColor, - enabledBorderColor: widget.enabledBorderColor, - isDense: widget.isDense ?? true, // Ensure compact rendering - ), - onChanged: widget.onChanged, + final textStyle = widget.textStyle ?? + kCodeStyle.copyWith( + fontSize: widget.textFontSize, + color: widget.textColor ?? clrScheme.onSurface, + ); + final contentPadding = widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8); + final horizontalPadding = contentPadding is EdgeInsets ? contentPadding.horizontal : 16.0; + + return LayoutBuilder( + builder: (context, constraints) { + final maxWidth = constraints.maxWidth - horizontalPadding; + final text = _controller.text.isEmpty ? widget.hintText ?? '' : _controller.text; + final lineCount = _calculateLineCount(text, textStyle, maxWidth); + final isMultiLine = lineCount > 1; + final showOverlayBox = _isFocused && isMultiLine; + + return Stack( + clipBehavior: Clip.none, + children: [ + TextFormField( + key: widget.keyId != null ? Key(widget.keyId!) : null, + controller: _controller, + focusNode: _focusNode, + readOnly: widget.readOnly, + enabled: widget.enabled, + maxLines: _isFocused ? null : 1, + keyboardType: TextInputType.multiline, + expands: widget.expands, + style: textStyle, + decoration: getTextFieldInputDecoration( + clrScheme, + fillColor: widget.fillColor, + hintText: widget.hintText, + hintTextStyle: widget.hintTextStyle, + hintTextFontSize: widget.hintTextFontSize, + hintTextColor: widget.hintTextColor, + contentPadding: contentPadding, + focussedBorderColor: widget.focussedBorderColor, + enabledBorderColor: widget.enabledBorderColor, + isDense: widget.isDense ?? true, + ), + onChanged: (value) { + widget.onChanged?.call(value); + setState(() {}); // Trigger rebuild to update line count + }, + ), + if (showOverlayBox) + Positioned( + top: 0, + left: 0, + right: 0, + child: Material( + elevation: 4, + borderRadius: BorderRadius.circular(8), + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: clrScheme.surface, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: widget.focussedBorderColor ?? clrScheme.primary, + ), + ), + child: SingleChildScrollView( + child: Text( + _controller.text.isEmpty ? widget.hintText ?? '' : _controller.text, + style: textStyle.copyWith( + color: _controller.text.isEmpty + ? (widget.hintTextColor ?? clrScheme.onSurface.withOpacity(0.6)) + : (widget.textColor ?? clrScheme.onSurface), + ), + ), + ), + ), + ), + ), + ], + ); + }, ); } } \ No newline at end of file From 7d476f68cc4c5dfe53b2f424990ef40a1a798430 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Fri, 2 May 2025 21:34:59 +0530 Subject: [PATCH 07/11] update: textformfield overlay not hidden by other fields and works fine, need cursor and interaction yet --- .../envvar/editor_pane/variables_pane.dart | 65 +++++++++- lib/widgets/field_cell.dart | 3 + .../lib/widgets/textfield_outlined.dart | 120 +++++++----------- 3 files changed, 115 insertions(+), 73 deletions(-) diff --git a/lib/screens/envvar/editor_pane/variables_pane.dart b/lib/screens/envvar/editor_pane/variables_pane.dart index cb0f79b09..6901ad009 100644 --- a/lib/screens/envvar/editor_pane/variables_pane.dart +++ b/lib/screens/envvar/editor_pane/variables_pane.dart @@ -23,6 +23,7 @@ class EditEnvironmentVariablesState final random = Random.secure(); late List variableRows; bool isAddingRow = false; + OverlayEntry? _overlayEntry; @override void initState() { @@ -30,6 +31,64 @@ class EditEnvironmentVariablesState seed = random.nextInt(kRandMax); } + @override + void dispose() { + _removeOverlay(); + super.dispose(); + } + + void _removeOverlay() { + _overlayEntry?.remove(); + _overlayEntry = null; + } + + void _showOverlay( + GlobalKey key, String text, TextStyle textStyle, ColorScheme clrScheme) { + _removeOverlay(); + + final RenderBox renderBox = + key.currentContext!.findRenderObject() as RenderBox; + final position = renderBox.localToGlobal(Offset.zero); + final size = renderBox.size; + + _overlayEntry = OverlayEntry( + builder: (context) => Positioned( + left: position.dx, + top: position.dy, + width: size.width, + child: Material( + elevation: 8, + borderRadius: BorderRadius.circular(8), + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: clrScheme.surface, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: kColorWhite.withOpacity(0.5)), + ), + child: SingleChildScrollView( + child: Text( + text, + style: textStyle, + ), + ), + ), + ), + ), + ); + + Overlay.of(context).insert(_overlayEntry!); + } + + void _onOverlayToggle(bool show, GlobalKey key, String text, + TextStyle textStyle, ColorScheme clrScheme) { + if (show) { + _showOverlay(key, text, textStyle, clrScheme); + } else { + _removeOverlay(); + } + } + void _onFieldChange(String selectedId) { final environment = ref.read(selectedEnvironmentModelProvider); final secrets = getEnvironmentSecrets(environment); @@ -118,6 +177,7 @@ class EditEnvironmentVariablesState _onFieldChange(selectedId!); }, colorScheme: Theme.of(context).colorScheme, + onOverlayToggle: _onOverlayToggle, ), ), DataCell( @@ -146,6 +206,7 @@ class EditEnvironmentVariablesState _onFieldChange(selectedId!); }, colorScheme: Theme.of(context).colorScheme, + onOverlayToggle: _onOverlayToggle, ), ), DataCell( @@ -195,7 +256,7 @@ class EditEnvironmentVariablesState dividerThickness: 0, horizontalMargin: 0, headingRowHeight: 0, - dataRowHeight: null, // Allow dynamic row height + dataRowHeight: null, bottomMargin: kDataTableBottomPadding, isVerticalScrollBarVisible: true, columns: columns, @@ -227,4 +288,4 @@ class EditEnvironmentVariablesState ], ); } -} \ No newline at end of file +} diff --git a/lib/widgets/field_cell.dart b/lib/widgets/field_cell.dart index 4fb9e8d80..d4284a45a 100644 --- a/lib/widgets/field_cell.dart +++ b/lib/widgets/field_cell.dart @@ -9,6 +9,7 @@ class CellField extends StatelessWidget { this.hintText, this.onChanged, this.colorScheme, + this.onOverlayToggle }); final String keyId; @@ -16,6 +17,7 @@ class CellField extends StatelessWidget { final String? hintText; final void Function(String)? onChanged; final ColorScheme? colorScheme; + final void Function(bool, GlobalKey>, String, TextStyle, ColorScheme)? onOverlayToggle; @override Widget build(BuildContext context) { @@ -27,6 +29,7 @@ class CellField extends StatelessWidget { hintText: hintText, hintTextFontSize: Theme.of(context).textTheme.bodySmall?.fontSize, onChanged: onChanged, + onOverlayToggle: onOverlayToggle, colorScheme: colorScheme, isDense: true, // Compact rendering ), diff --git a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart index d8a85bdf0..04fa1b0a3 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart @@ -26,6 +26,7 @@ class ADOutlinedTextField extends StatefulWidget { this.isDense, this.onChanged, this.colorScheme, + this.onOverlayToggle, // Callback to toggle overlay }); final String? keyId; @@ -49,6 +50,7 @@ class ADOutlinedTextField extends StatefulWidget { final Color? enabledBorderColor; final void Function(String)? onChanged; final ColorScheme? colorScheme; + final void Function(bool, GlobalKey, String, TextStyle, ColorScheme)? onOverlayToggle; @override State createState() => _ADOutlinedTextFieldState(); @@ -58,6 +60,7 @@ class _ADOutlinedTextFieldState extends State { late FocusNode _focusNode; late TextEditingController _controller; bool _isFocused = false; + final GlobalKey _textFieldKey = GlobalKey(); @override void initState() { @@ -71,6 +74,7 @@ class _ADOutlinedTextFieldState extends State { setState(() { _isFocused = _focusNode.hasFocus; }); + _updateOverlay(); } @override @@ -80,6 +84,7 @@ class _ADOutlinedTextFieldState extends State { } _focusNode.removeListener(_handleFocusChange); _focusNode.dispose(); + widget.onOverlayToggle?.call(false, _textFieldKey, '', TextStyle(), Theme.of(context).colorScheme); super.dispose(); } @@ -93,8 +98,7 @@ class _ADOutlinedTextFieldState extends State { return textPainter.computeLineMetrics().length; } - @override - Widget build(BuildContext context) { + void _updateOverlay() { var clrScheme = widget.colorScheme ?? Theme.of(context).colorScheme; final textStyle = widget.textStyle ?? kCodeStyle.copyWith( @@ -104,77 +108,51 @@ class _ADOutlinedTextFieldState extends State { final contentPadding = widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8); final horizontalPadding = contentPadding is EdgeInsets ? contentPadding.horizontal : 16.0; - return LayoutBuilder( - builder: (context, constraints) { - final maxWidth = constraints.maxWidth - horizontalPadding; - final text = _controller.text.isEmpty ? widget.hintText ?? '' : _controller.text; - final lineCount = _calculateLineCount(text, textStyle, maxWidth); - final isMultiLine = lineCount > 1; - final showOverlayBox = _isFocused && isMultiLine; + final maxWidth = context.size!.width - horizontalPadding; + final text = _controller.text.isEmpty ? widget.hintText ?? '' : _controller.text; + final lineCount = _calculateLineCount(text, textStyle, maxWidth); + final isMultiLine = lineCount > 1; + final showOverlay = _isFocused && isMultiLine; + + widget.onOverlayToggle?.call(showOverlay, _textFieldKey, text, textStyle, clrScheme); + } - return Stack( - clipBehavior: Clip.none, - children: [ - TextFormField( - key: widget.keyId != null ? Key(widget.keyId!) : null, - controller: _controller, - focusNode: _focusNode, - readOnly: widget.readOnly, - enabled: widget.enabled, - maxLines: _isFocused ? null : 1, - keyboardType: TextInputType.multiline, - expands: widget.expands, - style: textStyle, - decoration: getTextFieldInputDecoration( - clrScheme, - fillColor: widget.fillColor, - hintText: widget.hintText, - hintTextStyle: widget.hintTextStyle, - hintTextFontSize: widget.hintTextFontSize, - hintTextColor: widget.hintTextColor, - contentPadding: contentPadding, - focussedBorderColor: widget.focussedBorderColor, - enabledBorderColor: widget.enabledBorderColor, - isDense: widget.isDense ?? true, - ), - onChanged: (value) { - widget.onChanged?.call(value); - setState(() {}); // Trigger rebuild to update line count - }, - ), - if (showOverlayBox) - Positioned( - top: 0, - left: 0, - right: 0, - child: Material( - elevation: 4, - borderRadius: BorderRadius.circular(8), - child: Container( - width: double.infinity, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: clrScheme.surface, - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: widget.focussedBorderColor ?? clrScheme.primary, - ), - ), - child: SingleChildScrollView( - child: Text( - _controller.text.isEmpty ? widget.hintText ?? '' : _controller.text, - style: textStyle.copyWith( - color: _controller.text.isEmpty - ? (widget.hintTextColor ?? clrScheme.onSurface.withOpacity(0.6)) - : (widget.textColor ?? clrScheme.onSurface), - ), - ), - ), - ), - ), - ), - ], + @override + Widget build(BuildContext context) { + var clrScheme = widget.colorScheme ?? Theme.of(context).colorScheme; + final textStyle = widget.textStyle ?? + kCodeStyle.copyWith( + fontSize: widget.textFontSize, + color: widget.textColor ?? clrScheme.onSurface, ); + final contentPadding = widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8); + + return TextFormField( + key: _textFieldKey, + controller: _controller, + focusNode: _focusNode, + readOnly: widget.readOnly, + enabled: widget.enabled, + maxLines: _isFocused ? null : 1, + keyboardType: TextInputType.multiline, + expands: widget.expands, + style: textStyle, + decoration: getTextFieldInputDecoration( + clrScheme, + fillColor: widget.fillColor, + hintText: widget.hintText, + hintTextStyle: widget.hintTextStyle, + hintTextFontSize: widget.hintTextFontSize, + hintTextColor: widget.hintTextColor, + contentPadding: contentPadding, + focussedBorderColor: widget.focussedBorderColor, + enabledBorderColor: widget.enabledBorderColor, + isDense: widget.isDense ?? true, + ), + onChanged: (value) { + widget.onChanged?.call(value); + setState(() {}); + _updateOverlay(); }, ); } From 14f6924b6c829b701acd39e3840a8d955cb64741 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Sat, 3 May 2025 00:51:32 +0530 Subject: [PATCH 08/11] update: overlay is textfield now but on re-focusing it does not show multi-line --- .../envvar/editor_pane/variables_pane.dart | 55 ++++++++++++++----- lib/widgets/field_cell.dart | 17 ++++-- .../lib/widgets/textfield_outlined.dart | 48 ++++++++++++++-- 3 files changed, 99 insertions(+), 21 deletions(-) diff --git a/lib/screens/envvar/editor_pane/variables_pane.dart b/lib/screens/envvar/editor_pane/variables_pane.dart index 6901ad009..d361cbf27 100644 --- a/lib/screens/envvar/editor_pane/variables_pane.dart +++ b/lib/screens/envvar/editor_pane/variables_pane.dart @@ -24,6 +24,7 @@ class EditEnvironmentVariablesState late List variableRows; bool isAddingRow = false; OverlayEntry? _overlayEntry; + FocusNode? _currentFocusNode; @override void initState() { @@ -40,17 +41,34 @@ class EditEnvironmentVariablesState void _removeOverlay() { _overlayEntry?.remove(); _overlayEntry = null; + _currentFocusNode?.removeListener(_handleOverlayFocusChange); + _currentFocusNode = null; + } + + void _handleOverlayFocusChange() { + if (_currentFocusNode != null && !_currentFocusNode!.hasFocus) { + _removeOverlay(); + } } void _showOverlay( - GlobalKey key, String text, TextStyle textStyle, ColorScheme clrScheme) { + GlobalKey key, + String text, + TextStyle textStyle, + ColorScheme clrScheme, + FocusNode focusNode, + TextEditingController controller, + InputDecoration decoration, + ) { _removeOverlay(); - final RenderBox renderBox = - key.currentContext!.findRenderObject() as RenderBox; + final RenderBox renderBox = key.currentContext!.findRenderObject() as RenderBox; final position = renderBox.localToGlobal(Offset.zero); final size = renderBox.size; + _currentFocusNode = focusNode; + _currentFocusNode?.addListener(_handleOverlayFocusChange); + _overlayEntry = OverlayEntry( builder: (context) => Positioned( left: position.dx, @@ -66,11 +84,14 @@ class EditEnvironmentVariablesState borderRadius: BorderRadius.circular(8), border: Border.all(color: kColorWhite.withOpacity(0.5)), ), - child: SingleChildScrollView( - child: Text( - text, - style: textStyle, - ), + child: TextField( + controller: controller, + focusNode: focusNode, + style: textStyle, + decoration: decoration, + maxLines: null, + keyboardType: TextInputType.multiline, + autofocus: true, ), ), ), @@ -80,10 +101,18 @@ class EditEnvironmentVariablesState Overlay.of(context).insert(_overlayEntry!); } - void _onOverlayToggle(bool show, GlobalKey key, String text, - TextStyle textStyle, ColorScheme clrScheme) { + void _onOverlayToggle( + bool show, + GlobalKey key, + String text, + TextStyle textStyle, + ColorScheme clrScheme, + FocusNode focusNode, + TextEditingController controller, + InputDecoration decoration, + ) { if (show) { - _showOverlay(key, text, textStyle, clrScheme); + _showOverlay(key, text, textStyle, clrScheme, focusNode, controller, decoration); } else { _removeOverlay(); } @@ -126,7 +155,7 @@ class EditEnvironmentVariablesState fixedWidth: 30, ), DataColumn2( - label: Text("Variable value"), + label: Text(" jars value"), ), DataColumn2( label: Text(''), @@ -288,4 +317,4 @@ class EditEnvironmentVariablesState ], ); } -} +} \ No newline at end of file diff --git a/lib/widgets/field_cell.dart b/lib/widgets/field_cell.dart index d4284a45a..588592f75 100644 --- a/lib/widgets/field_cell.dart +++ b/lib/widgets/field_cell.dart @@ -9,7 +9,7 @@ class CellField extends StatelessWidget { this.hintText, this.onChanged, this.colorScheme, - this.onOverlayToggle + this.onOverlayToggle, }); final String keyId; @@ -17,12 +17,21 @@ class CellField extends StatelessWidget { final String? hintText; final void Function(String)? onChanged; final ColorScheme? colorScheme; - final void Function(bool, GlobalKey>, String, TextStyle, ColorScheme)? onOverlayToggle; + final void Function( + bool, + GlobalKey>, + String, + TextStyle, + ColorScheme, + FocusNode, + TextEditingController, + InputDecoration, + )? onOverlayToggle; @override Widget build(BuildContext context) { return SizedBox( - width: double.infinity, // Ensure the text field takes full cell width + width: double.infinity, child: ADOutlinedTextField( keyId: keyId, initialValue: initialValue, @@ -31,7 +40,7 @@ class CellField extends StatelessWidget { onChanged: onChanged, onOverlayToggle: onOverlayToggle, colorScheme: colorScheme, - isDense: true, // Compact rendering + isDense: true, ), ); } diff --git a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart index 04fa1b0a3..c2ef98c9d 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart @@ -26,7 +26,7 @@ class ADOutlinedTextField extends StatefulWidget { this.isDense, this.onChanged, this.colorScheme, - this.onOverlayToggle, // Callback to toggle overlay + this.onOverlayToggle, }); final String? keyId; @@ -50,7 +50,16 @@ class ADOutlinedTextField extends StatefulWidget { final Color? enabledBorderColor; final void Function(String)? onChanged; final ColorScheme? colorScheme; - final void Function(bool, GlobalKey, String, TextStyle, ColorScheme)? onOverlayToggle; + final void Function( + bool, + GlobalKey, + String, + TextStyle, + ColorScheme, + FocusNode, + TextEditingController, + InputDecoration, + )? onOverlayToggle; @override State createState() => _ADOutlinedTextFieldState(); @@ -84,7 +93,16 @@ class _ADOutlinedTextFieldState extends State { } _focusNode.removeListener(_handleFocusChange); _focusNode.dispose(); - widget.onOverlayToggle?.call(false, _textFieldKey, '', TextStyle(), Theme.of(context).colorScheme); + widget.onOverlayToggle?.call( + false, + _textFieldKey, + '', + TextStyle(), + Theme.of(context).colorScheme, + _focusNode, + _controller, + InputDecoration(), + ); super.dispose(); } @@ -114,7 +132,29 @@ class _ADOutlinedTextFieldState extends State { final isMultiLine = lineCount > 1; final showOverlay = _isFocused && isMultiLine; - widget.onOverlayToggle?.call(showOverlay, _textFieldKey, text, textStyle, clrScheme); + final decoration = getTextFieldInputDecoration( + clrScheme, + fillColor: widget.fillColor, + hintText: widget.hintText, + hintTextStyle: widget.hintTextStyle, + hintTextFontSize: widget.hintTextFontSize, + hintTextColor: widget.hintTextColor, + contentPadding: contentPadding, + focussedBorderColor: widget.focussedBorderColor, + enabledBorderColor: widget.enabledBorderColor, + isDense: widget.isDense ?? true, + ); + + widget.onOverlayToggle?.call( + showOverlay, + _textFieldKey, + text, + textStyle, + clrScheme, + _focusNode, + _controller, + decoration, + ); } @override From 626cb4c023020340c62a9df5cd371183f49bf5a3 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Sat, 3 May 2025 01:55:05 +0530 Subject: [PATCH 09/11] update: on focusing again, the overlay displays itself correctly. --- .../lib/widgets/textfield_outlined.dart | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart index c2ef98c9d..cf52787dd 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart @@ -69,6 +69,7 @@ class _ADOutlinedTextFieldState extends State { late FocusNode _focusNode; late TextEditingController _controller; bool _isFocused = false; + bool _isMultiLine = false; final GlobalKey _textFieldKey = GlobalKey(); @override @@ -77,13 +78,22 @@ class _ADOutlinedTextFieldState extends State { _focusNode = FocusNode(); _controller = widget.controller ?? TextEditingController(text: widget.initialValue); _focusNode.addListener(_handleFocusChange); + // Initial check for multiline state + WidgetsBinding.instance.addPostFrameCallback((_) { + _checkMultiLineAndUpdateOverlay(); + }); } void _handleFocusChange() { - setState(() { - _isFocused = _focusNode.hasFocus; - }); - _updateOverlay(); + final wasFocused = _isFocused; + _isFocused = _focusNode.hasFocus; + + if (_isFocused != wasFocused) { + setState(() { + // Update the maxLines based on focus + }); + _checkMultiLineAndUpdateOverlay(); + } } @override @@ -116,7 +126,7 @@ class _ADOutlinedTextFieldState extends State { return textPainter.computeLineMetrics().length; } - void _updateOverlay() { + void _checkMultiLineAndUpdateOverlay() { var clrScheme = widget.colorScheme ?? Theme.of(context).colorScheme; final textStyle = widget.textStyle ?? kCodeStyle.copyWith( @@ -126,11 +136,23 @@ class _ADOutlinedTextFieldState extends State { final contentPadding = widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8); final horizontalPadding = contentPadding is EdgeInsets ? contentPadding.horizontal : 16.0; - final maxWidth = context.size!.width - horizontalPadding; + // Safely calculate maxWidth + double maxWidth = double.infinity; + if (_textFieldKey.currentContext != null) { + final renderBox = _textFieldKey.currentContext!.findRenderObject() as RenderBox?; + if (renderBox != null && renderBox.hasSize) { + maxWidth = renderBox.size.width - horizontalPadding; + } + } + final text = _controller.text.isEmpty ? widget.hintText ?? '' : _controller.text; final lineCount = _calculateLineCount(text, textStyle, maxWidth); final isMultiLine = lineCount > 1; - final showOverlay = _isFocused && isMultiLine; + + // Update the multiline state + _isMultiLine = isMultiLine; + + final showOverlay = _isFocused && _isMultiLine; final decoration = getTextFieldInputDecoration( clrScheme, @@ -191,8 +213,14 @@ class _ADOutlinedTextFieldState extends State { ), onChanged: (value) { widget.onChanged?.call(value); - setState(() {}); - _updateOverlay(); + _checkMultiLineAndUpdateOverlay(); + }, + onTap: () { + if (!_isFocused) { + _isFocused = true; + setState(() {}); + } + _checkMultiLineAndUpdateOverlay(); }, ); } From f987c95a38a760de73a2fff8b5b51a6dd5771b42 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Sat, 3 May 2025 04:19:45 +0530 Subject: [PATCH 10/11] fix: border of overlay --- lib/screens/envvar/editor_pane/variables_pane.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/screens/envvar/editor_pane/variables_pane.dart b/lib/screens/envvar/editor_pane/variables_pane.dart index d361cbf27..4194a5c96 100644 --- a/lib/screens/envvar/editor_pane/variables_pane.dart +++ b/lib/screens/envvar/editor_pane/variables_pane.dart @@ -78,11 +78,11 @@ class EditEnvironmentVariablesState elevation: 8, borderRadius: BorderRadius.circular(8), child: Container( - padding: const EdgeInsets.all(8), + // padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: clrScheme.surface, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: kColorWhite.withOpacity(0.5)), + // borderRadius: BorderRadius.circular(8), + // border: Border.all(color: kColorWhite.withOpacity(0.5)), ), child: TextField( controller: controller, From dff4789800e5e65021b9752ada232209bd778561 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Sat, 17 May 2025 14:06:16 +0530 Subject: [PATCH 11/11] fix: fixed multi-focus issues in the text field --- .../envvar/editor_pane/variables_pane.dart | 103 ++++++++------- .../lib/widgets/textfield_outlined.dart | 118 +++++++++++------- 2 files changed, 131 insertions(+), 90 deletions(-) diff --git a/lib/screens/envvar/editor_pane/variables_pane.dart b/lib/screens/envvar/editor_pane/variables_pane.dart index a0a1ed195..b6228238e 100644 --- a/lib/screens/envvar/editor_pane/variables_pane.dart +++ b/lib/screens/envvar/editor_pane/variables_pane.dart @@ -78,11 +78,8 @@ class EditEnvironmentVariablesState elevation: 8, borderRadius: BorderRadius.circular(8), child: Container( - // padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: clrScheme.surface, - // borderRadius: BorderRadius.circular(8), - // border: Border.all(color: kColorWhite.withOpacity(0.5)), ), child: TextField( controller: controller, @@ -92,6 +89,10 @@ class EditEnvironmentVariablesState maxLines: null, keyboardType: TextInputType.multiline, autofocus: true, + onSubmitted: (_) { + focusNode.unfocus(); + _removeOverlay(); + }, ), ), ), @@ -265,57 +266,63 @@ class EditEnvironmentVariablesState }, ); - return Stack( - children: [ - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: kBorderRadius12, - ), - margin: kPh10t10, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Expanded( - child: Theme( - data: Theme.of(context) - .copyWith(scrollbarTheme: kDataTableScrollbarTheme), - child: DataTable2( - columnSpacing: 12, - dividerThickness: 0, - horizontalMargin: 0, - headingRowHeight: 0, - dataRowHeight: null, - bottomMargin: kDataTableBottomPadding, - isVerticalScrollBarVisible: true, - columns: columns, - rows: dataRows, + return GestureDetector( + onTap: () { + FocusScope.of(context).requestFocus(FocusNode()); + _removeOverlay(); + }, + child: Stack( + children: [ + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: kBorderRadius12, + ), + margin: kPh10t10, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Theme( + data: Theme.of(context) + .copyWith(scrollbarTheme: kDataTableScrollbarTheme), + child: DataTable2( + columnSpacing: 12, + dividerThickness: 0, + horizontalMargin: 0, + headingRowHeight: 0, + dataRowHeight: null, + bottomMargin: kDataTableBottomPadding, + isVerticalScrollBarVisible: true, + columns: columns, + rows: dataRows, + ), ), ), - ), - if (!kIsMobile) kVSpacer40, - ], + if (!kIsMobile) kVSpacer40, + ], + ), ), - ), - if (!kIsMobile) - Align( - alignment: Alignment.bottomCenter, - child: Padding( - padding: kPb15, - child: ElevatedButton.icon( - onPressed: () { - variableRows.add(kEnvironmentVariableEmptyModel); - _onFieldChange(selectedId!); - }, - icon: const Icon(Icons.add), - label: const Text( - kLabelAddVariable, - style: kTextStyleButton, + if (!kIsMobile) + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: kPb15, + child: ElevatedButton.icon( + onPressed: () { + variableRows.add(kEnvironmentVariableEmptyModel); + _onFieldChange(selectedId!); + }, + icon: const Icon(Icons.add), + label: const Text( + kLabelAddVariable, + style: kTextStyleButton, + ), ), ), ), - ), - ], + ], + ), ); } } \ No newline at end of file diff --git a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart index cf52787dd..f5db007b9 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import '../tokens/tokens.dart'; import 'decoration_input_textfield.dart'; @@ -78,7 +79,6 @@ class _ADOutlinedTextFieldState extends State { _focusNode = FocusNode(); _controller = widget.controller ?? TextEditingController(text: widget.initialValue); _focusNode.addListener(_handleFocusChange); - // Initial check for multiline state WidgetsBinding.instance.addPostFrameCallback((_) { _checkMultiLineAndUpdateOverlay(); }); @@ -89,20 +89,26 @@ class _ADOutlinedTextFieldState extends State { _isFocused = _focusNode.hasFocus; if (_isFocused != wasFocused) { - setState(() { - // Update the maxLines based on focus - }); + setState(() {}); _checkMultiLineAndUpdateOverlay(); } + + if (!_isFocused && widget.onOverlayToggle != null) { + widget.onOverlayToggle!( + false, + _textFieldKey, + _controller.text, + TextStyle(), + Theme.of(context).colorScheme, + _focusNode, + _controller, + InputDecoration(), + ); + } } @override void dispose() { - if (widget.controller == null) { - _controller.dispose(); - } - _focusNode.removeListener(_handleFocusChange); - _focusNode.dispose(); widget.onOverlayToggle?.call( false, _textFieldKey, @@ -113,6 +119,11 @@ class _ADOutlinedTextFieldState extends State { _controller, InputDecoration(), ); + if (widget.controller == null) { + _controller.dispose(); + } + _focusNode.removeListener(_handleFocusChange); + _focusNode.dispose(); super.dispose(); } @@ -136,7 +147,6 @@ class _ADOutlinedTextFieldState extends State { final contentPadding = widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8); final horizontalPadding = contentPadding is EdgeInsets ? contentPadding.horizontal : 16.0; - // Safely calculate maxWidth double maxWidth = double.infinity; if (_textFieldKey.currentContext != null) { final renderBox = _textFieldKey.currentContext!.findRenderObject() as RenderBox?; @@ -149,7 +159,6 @@ class _ADOutlinedTextFieldState extends State { final lineCount = _calculateLineCount(text, textStyle, maxWidth); final isMultiLine = lineCount > 1; - // Update the multiline state _isMultiLine = isMultiLine; final showOverlay = _isFocused && _isMultiLine; @@ -189,39 +198,64 @@ class _ADOutlinedTextFieldState extends State { ); final contentPadding = widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8); - return TextFormField( - key: _textFieldKey, - controller: _controller, - focusNode: _focusNode, - readOnly: widget.readOnly, - enabled: widget.enabled, - maxLines: _isFocused ? null : 1, - keyboardType: TextInputType.multiline, - expands: widget.expands, - style: textStyle, - decoration: getTextFieldInputDecoration( - clrScheme, - fillColor: widget.fillColor, - hintText: widget.hintText, - hintTextStyle: widget.hintTextStyle, - hintTextFontSize: widget.hintTextFontSize, - hintTextColor: widget.hintTextColor, - contentPadding: contentPadding, - focussedBorderColor: widget.focussedBorderColor, - enabledBorderColor: widget.enabledBorderColor, - isDense: widget.isDense ?? true, - ), - onChanged: (value) { - widget.onChanged?.call(value); - _checkMultiLineAndUpdateOverlay(); - }, - onTap: () { - if (!_isFocused) { - _isFocused = true; - setState(() {}); + return RawKeyboardListener( + focusNode: FocusNode(), + onKey: (RawKeyEvent event) { + if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { + _focusNode.unfocus(); + widget.onChanged?.call(_controller.text); + widget.onOverlayToggle?.call( + false, + _textFieldKey, + _controller.text, + textStyle, + clrScheme, + _focusNode, + _controller, + InputDecoration(), + ); } - _checkMultiLineAndUpdateOverlay(); }, + child: TextFormField( + key: _textFieldKey, + controller: _controller, + focusNode: _focusNode, + readOnly: widget.readOnly, + enabled: widget.enabled, + maxLines: _isFocused ? null : 1, + keyboardType: TextInputType.multiline, + expands: widget.expands, + style: textStyle, + decoration: getTextFieldInputDecoration( + clrScheme, + fillColor: widget.fillColor, + hintText: widget.hintText, + hintTextStyle: widget.hintTextStyle, + hintTextFontSize: widget.hintTextFontSize, + hintTextColor: widget.hintTextColor, + contentPadding: contentPadding, + focussedBorderColor: widget.focussedBorderColor, + enabledBorderColor: widget.enabledBorderColor, + isDense: widget.isDense ?? true, + ), + onChanged: (value) { + widget.onChanged?.call(value); + _checkMultiLineAndUpdateOverlay(); + }, + onTap: () { + if (!_isFocused) { + FocusScope.of(context).requestFocus(FocusNode()); + _focusNode.requestFocus(); + _isFocused = true; + setState(() {}); + } + _checkMultiLineAndUpdateOverlay(); + }, + onFieldSubmitted: (_) { + _focusNode.unfocus(); + widget.onChanged?.call(_controller.text); + }, + ), ); } } \ No newline at end of file