// AUTO-GENERATED widget — matches web form elements import 'package:flutter/material.dart'; import '../inou_theme.dart'; /// Text input field class InouTextField extends StatelessWidget { final String? label; final String? placeholder; final TextEditingController? controller; final bool obscureText; final TextInputType? keyboardType; final int? maxLength; final bool isCode; final ValueChanged? onChanged; const InouTextField({ super.key, this.label, this.placeholder, this.controller, this.obscureText = false, this.keyboardType, this.maxLength, this.isCode = false, this.onChanged, }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (label != null) ...[ Text( label!, style: InouTheme.labelLarge, ), const SizedBox(height: 4), ], TextField( controller: controller, obscureText: obscureText, keyboardType: keyboardType, maxLength: maxLength, textAlign: isCode ? TextAlign.center : TextAlign.start, onChanged: onChanged, style: isCode ? TextStyle( fontSize: 22, fontWeight: FontWeight.w500, letterSpacing: 8, fontFamily: 'SF Mono', ) : InouTheme.bodyMedium, decoration: InputDecoration( hintText: placeholder, counterText: '', ), ), ], ); } } /// Dropdown select class InouSelect extends StatelessWidget { final String? label; final T? value; final List> options; final ValueChanged? onChanged; const InouSelect({ super.key, this.label, this.value, required this.options, this.onChanged, }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (label != null) ...[ Text(label!, style: InouTheme.labelLarge), const SizedBox(height: 4), ], Container( padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( color: InouTheme.bgCard, border: Border.all(color: InouTheme.border), borderRadius: InouTheme.borderRadiusMd, ), child: DropdownButtonHideUnderline( child: DropdownButton( value: value, isExpanded: true, items: options .map((o) => DropdownMenuItem( value: o.value, child: Text(o.label), )) .toList(), onChanged: onChanged, ), ), ), ], ); } } class InouSelectOption { final T value; final String label; const InouSelectOption({required this.value, required this.label}); } /// Radio group class InouRadioGroup extends StatelessWidget { final T? value; final List> options; final ValueChanged? onChanged; const InouRadioGroup({ super.key, this.value, required this.options, this.onChanged, }); @override Widget build(BuildContext context) { return Row( children: options.map((option) { return Padding( padding: const EdgeInsets.only(right: 16), child: InkWell( onTap: () => onChanged?.call(option.value), child: Row( mainAxisSize: MainAxisSize.min, children: [ Radio( value: option.value, groupValue: value, onChanged: onChanged, activeColor: InouTheme.accent, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), Text(option.label, style: InouTheme.bodyMedium), ], ), ), ); }).toList(), ); } } class InouRadioOption { final T value; final String label; const InouRadioOption({required this.value, required this.label}); } /// Checkbox class InouCheckbox extends StatelessWidget { final bool value; final String label; final ValueChanged? onChanged; const InouCheckbox({ super.key, required this.value, required this.label, this.onChanged, }); @override Widget build(BuildContext context) { return InkWell( onTap: () => onChanged?.call(!value), child: Row( children: [ Checkbox( value: value, onChanged: onChanged, activeColor: InouTheme.accent, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), Expanded( child: Text( label, style: InouTheme.bodyMedium.copyWith(color: InouTheme.textMuted), ), ), ], ), ); } }