import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:google_fonts/google_fonts.dart'; // import 'package:uae_stat/config/my_theme.dart'; /// Characters allowed while typing an email (matches typical local-part + domain). final List kEmailAddressInputFormatters = [ FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9@._%+-]')), ]; class ThemedFormField extends HookWidget { ThemedFormField({ super.key, this.hintText, this.imgPath, this.txtwidth, this.txtheight, required this.controller, this.validator, this.isObscurable = false, this.hintColor, this.backgroundColor, this.highlightColor, this.borderColor, this.bordedRad, this.errorBorderColor, this.errorTextColor, this.readOnly = false, // ✅ new this.isdense = false, // ✅ new this.keyboardType, // ✅ new this.maxLength, // ✅ new this.inputFormatters, this.isShowCursor, this.onChanged, this.verticalPad, this.horizonalPad, this.enableBorderWidth, this.textColr, this.errFieldFont, this.errFieldHgt, }); final double? verticalPad; final double? horizonalPad; final double? bordedRad; final double? enableBorderWidth; final String? hintText; final Color? textColr; final Color? highlightColor; final String? imgPath; final String? Function(String? text)? validator; final TextEditingController controller; final bool isObscurable; final Color? hintColor; final Color? backgroundColor; final Color? borderColor; final Color? errorBorderColor; final Color? errorTextColor; final double? errFieldFont; final double? errFieldHgt; final double? txtwidth; final bool readOnly; final bool isdense; final bool? isShowCursor; final TextInputType? keyboardType; final int? maxLength; final double? txtheight; final List? inputFormatters; // void Function(dynamic value)? onChanged; final ValueChanged? onChanged; @override Widget build(BuildContext context) { final isObscured = useState(true); final boxDecoration = BoxDecoration( borderRadius: BorderRadius.circular(10), // boxShadow: [ // BoxShadow( // color: Colors.black26, // shadow color // offset: Offset(0, 2), // x=0, y=4 → shadow goes downward // blurRadius: 2, // soften the shadow // spreadRadius: 0.2, // expand shadow // ), // ], ); final obscureBtn = IconButton( onPressed: () => isObscured.value = !isObscured.value, icon: Icon( isObscured.value ? Icons.visibility_off_outlined : Icons.visibility_outlined, color: const Color(0xff9EA2A9), ), ); final inputDecoration = InputDecoration( isDense: isdense, // errorStyle: TextStyle(color: Color(0xFFD83731)), // errorStyle: TextStyle( // color: Color(0xFFD83731), // fontSize: errFieldFont ?? 12, // height: errFieldHgt ?? 10, // ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: errorBorderColor ?? Color(0xFFD83731), width: 1, ), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: errorBorderColor ?? Color(0xFFD83731), width: 1, ), ), filled: true, fillColor: backgroundColor ?? Colors.white, // contentPadding: EdgeInsets.symmetric( // vertical: verticalPad ?? 12, // horizontal: horizonalPad ?? 15, // ), contentPadding: EdgeInsets.symmetric( vertical: verticalPad ?? 10, horizontal: 10, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(bordedRad ?? 10), // borderSide: BorderSide(color: Color(0xFF50A398)), borderSide: BorderSide( color: borderColor ?? Color(0xFFFFFFFF), width: enableBorderWidth ?? 1, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(bordedRad ?? 10), // borderSide: BorderSide(color: Color(0xFF50A398)), borderSide: BorderSide( color: borderColor ?? backgroundColor ?? Color(0xFFFFFFFF), width: enableBorderWidth ?? 1, ), ), focusedBorder: readOnly ? OutlineInputBorder( borderRadius: BorderRadius.circular(10), // borderSide: BorderSide(color: Color(0xFF50A398)), borderSide: BorderSide(color: borderColor ?? Color(0xFFFFFFFF)), ) : OutlineInputBorder( borderRadius: BorderRadius.circular(bordedRad ?? 10), borderSide: BorderSide( color: highlightColor ?? borderColor ?? Color(0xFF50A398), width: 2, ), ), hintText: hintText, hintStyle: TextStyle( // ✅ dynamic hint color color: const Color(0xFFC3C6CB), ), // labelText: hintText, // labelStyle: GoogleFonts.inter( // fontSize: 10, // // color: Colors.black, // customize here // color: Colors.red, // customize here // fontWeight: FontWeight.w400, // ), prefixIconConstraints: const BoxConstraints( maxWidth: 25 + 16 + 10, maxHeight: 25 + (8 * 2), ), prefixIcon: imgPath != null ? Padding( padding: const EdgeInsetsDirectional.only(start: 16, end: 10), child: Image.asset( imgPath!, fit: BoxFit.fitHeight, height: 25, width: 25, ), ) : null, suffixIcon: isObscurable ? obscureBtn : null, ); return Container( width: txtwidth ?? MediaQuery.of(context).size.width, height: txtheight ?? null, child: DecoratedBox( decoration: boxDecoration, child: TextFormField( controller: controller, decoration: inputDecoration, validator: validator, obscureText: isObscurable && isObscured.value, readOnly: readOnly, // ✅ now supported keyboardType: keyboardType, // ✅ e.g. TextInputType.number maxLength: maxLength, // ✅ max length showCursor: isShowCursor ?? true, enableInteractiveSelection: isShowCursor ?? true, inputFormatters: inputFormatters ?? (keyboardType == TextInputType.emailAddress ? kEmailAddressInputFormatters : null), // ✅ allow multiline if user sets maxLines / minLines minLines: (keyboardType == TextInputType.multiline) ? 3 : 1, maxLines: (keyboardType == TextInputType.multiline) ? null : 1, style: GoogleFonts.inter( fontSize: 12, // 👈 Change this to your desired size fontWeight: FontWeight.w400, // optional color: textColr ?? Colors.black, // optional ), onChanged: onChanged, ), ), ); } } class UpperCaseTextFormatter extends TextInputFormatter { @override TextEditingValue formatEditUpdate( TextEditingValue oldValue, TextEditingValue newValue, ) { return TextEditingValue( text: newValue.text.toUpperCase(), selection: newValue.selection, ); } }