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;
Widget button;
switch (variant) {
case GenexButtonVariant.primary:
return SizedBox(
width: fullWidth ? double.infinity : null,
height: _height,
child: ElevatedButton(
onPressed: effectiveOnPressed,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.4),
disabledForegroundColor: Colors.white70,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
textStyle: _textStyle,
button = ElevatedButton(
onPressed: effectiveOnPressed,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.4),
disabledForegroundColor: Colors.white70,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
child: child,
textStyle: _textStyle,
),
child: child,
);
case GenexButtonVariant.secondary:
return SizedBox(
width: fullWidth ? double.infinity : null,
height: _height,
child: ElevatedButton(
onPressed: effectiveOnPressed,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primarySurface,
foregroundColor: AppColors.primary,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
textStyle: _textStyle,
button = ElevatedButton(
onPressed: effectiveOnPressed,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primarySurface,
foregroundColor: AppColors.primary,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
child: child,
textStyle: _textStyle,
),
child: child,
);
case GenexButtonVariant.outline:
return SizedBox(
width: fullWidth ? double.infinity : null,
height: _height,
child: OutlinedButton(
onPressed: effectiveOnPressed,
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.primary,
side: const BorderSide(color: AppColors.primary, width: 1.5),
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
textStyle: _textStyle,
button = OutlinedButton(
onPressed: effectiveOnPressed,
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.primary,
side: const BorderSide(color: AppColors.primary, width: 1.5),
shape: RoundedRectangleBorder(
borderRadius: AppSpacing.borderRadiusMd,
),
child: child,
textStyle: _textStyle,
),
child: child,
);
case GenexButtonVariant.text:
return SizedBox(
height: _height,
child: TextButton(
onPressed: effectiveOnPressed,
style: TextButton.styleFrom(
foregroundColor: AppColors.primary,
textStyle: _textStyle,
),
child: child,
button = TextButton(
onPressed: effectiveOnPressed,
style: TextButton.styleFrom(
foregroundColor: AppColors.primary,
textStyle: _textStyle,
),
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 {