import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; const double _kFieldSpacing = 8; const double _kFieldCaptionSpacing = 6; /// 폼 필드 라벨과 본문을 일관되게 배치하기 위한 위젯. class SuperportFormField extends StatelessWidget { const SuperportFormField({ super.key, required this.label, required this.child, this.required = false, this.caption, this.errorText, this.trailing, this.spacing = _kFieldSpacing, }); final String label; final Widget child; final bool required; final String? caption; final String? errorText; final Widget? trailing; final double spacing; @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); final captionStyle = theme.textTheme.muted.copyWith(fontSize: 12); final errorStyle = theme.textTheme.small.copyWith( fontSize: 12, color: theme.colorScheme.destructive, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: _FieldLabel(label: label, required: required), ), if (trailing != null) trailing!, ], ), SizedBox(height: spacing), child, if (errorText != null && errorText!.isNotEmpty) Padding( padding: const EdgeInsets.only(top: _kFieldCaptionSpacing), child: Text(errorText!, style: errorStyle), ) else if (caption != null && caption!.isNotEmpty) Padding( padding: const EdgeInsets.only(top: _kFieldCaptionSpacing), child: Text(caption!, style: captionStyle), ), ], ); } } /// `ShadInput`을 Superport 스타일에 맞게 설정한 텍스트 필드. class SuperportTextInput extends StatelessWidget { const SuperportTextInput({ super.key, this.controller, this.placeholder, this.onChanged, this.onSubmitted, this.keyboardType, this.enabled = true, this.readOnly = false, this.maxLines = 1, this.leading, this.trailing, }); final TextEditingController? controller; final Widget? placeholder; final ValueChanged? onChanged; final ValueChanged? onSubmitted; final TextInputType? keyboardType; final bool enabled; final bool readOnly; final int maxLines; final Widget? leading; final Widget? trailing; @override Widget build(BuildContext context) { return ShadInput( controller: controller, placeholder: placeholder, enabled: enabled, readOnly: readOnly, keyboardType: keyboardType, maxLines: maxLines, leading: leading, trailing: trailing, onChanged: onChanged, onSubmitted: onSubmitted, ); } } /// `ShadSwitch`를 라벨과 함께 사용하기 위한 헬퍼. class SuperportSwitchField extends StatelessWidget { const SuperportSwitchField({ super.key, required this.value, required this.onChanged, this.label, this.caption, }); final bool value; final ValueChanged onChanged; final String? label; final String? caption; @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ if (label != null) Text(label!, style: theme.textTheme.small), const SizedBox(height: 8), ShadSwitch(value: value, onChanged: onChanged), if (caption != null && caption!.isNotEmpty) Padding( padding: const EdgeInsets.only(top: _kFieldCaptionSpacing), child: Text(caption!, style: theme.textTheme.muted), ), ], ); } } class _FieldLabel extends StatelessWidget { const _FieldLabel({required this.label, required this.required}); final String label; final bool required; @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); final textStyle = theme.textTheme.small.copyWith( fontWeight: FontWeight.w600, ); return Row( mainAxisSize: MainAxisSize.min, children: [ Text(label, style: textStyle), if (required) Padding( padding: const EdgeInsets.only(left: 4), child: Text( '*', style: theme.textTheme.small.copyWith( color: theme.colorScheme.destructive, fontWeight: FontWeight.w600, ), ), ), ], ); } }