fCCNeumorphicDecoration function

BoxDecoration fCCNeumorphicDecoration({
  1. required ThemeData theme,
  2. required Color baseColor,
  3. double borderRadiusValue = 24,
  4. NeumorphicStyle style = NeumorphicStyle.lowered,
  5. bool transparentBackground = false,
  6. double? borderWidth,
  7. Color? borderColor,
  8. double protrusionIntensity = 1.0,
})

Implementation

BoxDecoration fCCNeumorphicDecoration({
  required ThemeData theme,
  required Color baseColor,
  double borderRadiusValue = 24,
  NeumorphicStyle style = NeumorphicStyle.lowered,
  bool transparentBackground = false,
  double? borderWidth,
  Color? borderColor,
  double protrusionIntensity = 1.0,
}) {
  final intensity = protrusionIntensity.clamp(0.0, 2.0);
  final lift = (0.7 + 0.5 * intensity); // controls contrast and shadow travel

  final hslBase = HSLColor.fromColor(baseColor);
  final shadows = _computeNeumorphicShadows(theme, baseColor);
  final topShadow = shadows.topShadow;
  final bottomShadow = shadows.bottomShadow;
  final isDark = shadows.isDark;

  final effectiveBorderWidth =
      borderWidth ?? 0.0; // default: no outline unless asked for
  final effectiveBorderColor = borderColor ??
      (theme.brightness == Brightness.dark
          ? Color.lerp(bottomShadow, baseColor, 0.2)
          : Color.lerp(topShadow, bottomShadow, 0.35)) ??
      baseColor.withValues(
          alpha: theme.brightness == Brightness.dark ? 0.35 : 0.6);

  final radius = BorderRadius.circular(borderRadiusValue);

  if (style == NeumorphicStyle.protruded) {
    final bgOpacity = transparentBackground ? 0.88 : 0.96;
    final bgTop = hslBase
        .withLightness((hslBase.lightness + 0.06 * lift).clamp(0.0, 1.0))
        .toColor()
        .withValues(alpha: bgOpacity);
    final bgBottom = hslBase
        .withLightness((hslBase.lightness - 0.06 * lift).clamp(0.0, 1.0))
        .toColor()
        .withValues(alpha: bgOpacity);

    return BoxDecoration(
      color: null,
      gradient: LinearGradient(
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
        colors: [bgTop, bgBottom],
      ),
      borderRadius: radius,
      border: effectiveBorderWidth > 0
          ? Border.all(
              color: effectiveBorderColor,
              width: effectiveBorderWidth,
            )
          : null,
      boxShadow: [
        BoxShadow(
          color: topShadow.withValues(
              alpha: (isDark ? 0.3 : 0.45 + 0.15 * intensity).clamp(0.0, 0.85)),
          offset: Offset(
            -(6 + 4 * intensity),
            -(6 + 4 * intensity),
          ),
          blurRadius: 12 + 4 * intensity,
          spreadRadius: -(2.5 + intensity),
        ),
        BoxShadow(
          color: bottomShadow.withValues(
              alpha: (isDark ? 0.45 : 0.60 + 0.15 * intensity).clamp(0.0, 0.9)),
          offset: Offset(
            8 + 5 * intensity,
            8 + 5 * intensity,
          ),
          blurRadius: 18 + 5 * intensity,
          spreadRadius: 2 + intensity,
        ),
      ],
    );
  }

  // Slightly stronger shadows for better separation on light/transparent cards.
  final shadowScale = (0.5 + 0.6 * intensity).clamp(0.6, 1.5);
  final double baseOffset = 8 * shadowScale;
  final double baseBlur = 14 * shadowScale;

  return BoxDecoration(
    color: transparentBackground
        ? baseColor.withValues(alpha: 0.08)
        : baseColor.withValues(alpha: 0.92),
    borderRadius: radius,
    boxShadow: [
      BoxShadow(
        color: bottomShadow.withValues(
            alpha: ((isDark ? 0.4 : 0.6) * shadowScale).clamp(0.0, 1.0)),
        offset: Offset(baseOffset, baseOffset),
        blurRadius: baseBlur,
        inset: true,
      ),
      BoxShadow(
        color: topShadow.withValues(
            alpha: ((isDark ? 0.6 : 0.8) * shadowScale).clamp(0.0, 1.0)),
        offset: Offset(-baseOffset, -baseOffset),
        blurRadius: baseBlur,
        inset: true,
      ),
    ],
  );
}