fix: Prevent GenexButton crash with unbounded width constraints

Use LayoutBuilder to detect whether parent provides bounded width.
When fullWidth=true in an unbounded context (e.g. Row without
Expanded), gracefully fall back to content-sized width instead of
forcing SizedBox(width: double.infinity) which triggers
"BoxConstraints forces an infinite width" assertion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-11 07:08:09 -08:00
parent 5abb614d03
commit 665e494b4a
1 changed files with 50 additions and 52 deletions

View File

@ -53,78 +53,76 @@ class GenexButton extends StatelessWidget {
final effectiveOnPressed = isLoading ? null : onPressed; final effectiveOnPressed = isLoading ? null : onPressed;
Widget button;
switch (variant) { switch (variant) {
case GenexButtonVariant.primary: case GenexButtonVariant.primary:
return SizedBox( button = ElevatedButton(
width: fullWidth ? double.infinity : null, onPressed: effectiveOnPressed,
height: _height, style: ElevatedButton.styleFrom(
child: ElevatedButton( backgroundColor: AppColors.primary,
onPressed: effectiveOnPressed, foregroundColor: Colors.white,
style: ElevatedButton.styleFrom( disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.4),
backgroundColor: AppColors.primary, disabledForegroundColor: Colors.white70,
foregroundColor: Colors.white, elevation: 0,
disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.4), shape: RoundedRectangleBorder(
disabledForegroundColor: Colors.white70, borderRadius: AppSpacing.borderRadiusMd,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
textStyle: _textStyle,
), ),
child: child, textStyle: _textStyle,
), ),
child: child,
); );
case GenexButtonVariant.secondary: case GenexButtonVariant.secondary:
return SizedBox( button = ElevatedButton(
width: fullWidth ? double.infinity : null, onPressed: effectiveOnPressed,
height: _height, style: ElevatedButton.styleFrom(
child: ElevatedButton( backgroundColor: AppColors.primarySurface,
onPressed: effectiveOnPressed, foregroundColor: AppColors.primary,
style: ElevatedButton.styleFrom( elevation: 0,
backgroundColor: AppColors.primarySurface, shape: RoundedRectangleBorder(
foregroundColor: AppColors.primary, borderRadius: AppSpacing.borderRadiusMd,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
textStyle: _textStyle,
), ),
child: child, textStyle: _textStyle,
), ),
child: child,
); );
case GenexButtonVariant.outline: case GenexButtonVariant.outline:
return SizedBox( button = OutlinedButton(
width: fullWidth ? double.infinity : null, onPressed: effectiveOnPressed,
height: _height, style: OutlinedButton.styleFrom(
child: OutlinedButton( foregroundColor: AppColors.primary,
onPressed: effectiveOnPressed, side: const BorderSide(color: AppColors.primary, width: 1.5),
style: OutlinedButton.styleFrom( shape: RoundedRectangleBorder(
foregroundColor: AppColors.primary, borderRadius: AppSpacing.borderRadiusMd,
side: const BorderSide(color: AppColors.primary, width: 1.5),
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
textStyle: _textStyle,
), ),
child: child, textStyle: _textStyle,
), ),
child: child,
); );
case GenexButtonVariant.text: case GenexButtonVariant.text:
return SizedBox( button = TextButton(
height: _height, onPressed: effectiveOnPressed,
child: TextButton( style: TextButton.styleFrom(
onPressed: effectiveOnPressed, foregroundColor: AppColors.primary,
style: TextButton.styleFrom( textStyle: _textStyle,
foregroundColor: AppColors.primary,
textStyle: _textStyle,
),
child: child,
), ),
child: child,
); );
} }
// Use LayoutBuilder to safely handle fullWidth in unbounded contexts (e.g. Row)
if (fullWidth) {
return LayoutBuilder(
builder: (context, constraints) => SizedBox(
width: constraints.hasBoundedWidth ? double.infinity : null,
height: _height,
child: button,
),
);
}
return SizedBox(height: _height, child: button);
} }
double get _height { double get _height {