waterui 0.3.0

A modern UI framework for Rust
import CWaterUI
import OSLog

#if canImport(UIKit)
  import UIKit
#elseif canImport(AppKit)
  import AppKit
#endif

/// Component for IgnorableMetadata<MaterialBackground>.
///
/// Applies a native blur effect behind the wrapped view content.
/// Uses NSVisualEffectView on macOS and UIVisualEffectView on iOS.
@MainActor
final class WuiMaterialBackground: PlatformView, WuiComponent {
  static var rawId: CWaterUI.WuiTypeId { waterui_ignorable_metadata_material_background_id() }

  private let contentView: any WuiComponent
  #if canImport(UIKit)
    private let blurView: UIVisualEffectView
  #elseif canImport(AppKit)
    private let blurView: NSVisualEffectView
  #endif

  var stretchAxis: WuiStretchAxis {
    contentView.stretchAxis
  }

  required init(anyview: OpaquePointer, env: WuiEnvironment) {
    let metadata = waterui_force_as_ignorable_metadata_material_background(anyview)

    // Resolve the content
    self.contentView = WuiAnyView.resolve(anyview: metadata.content, env: env)

    // Create blur view with appropriate material
    #if canImport(UIKit)
      let blurEffect = UIBlurEffect(style: Self.uiBlurStyle(from: metadata.material))
      self.blurView = UIVisualEffectView(effect: blurEffect)
    #elseif canImport(AppKit)
      self.blurView = NSVisualEffectView()
      let material = Self.nsMaterial(from: metadata.material)
      blurView.material = material
      // Match typical AppKit/SF Symbols vibrancy behavior:
      // - Titlebar/HUD materials blend behind the window
      // - Sidebar/content materials blend within the window
      switch material {
      case .titlebar, .hudWindow:
        blurView.blendingMode = .behindWindow
      default:
        blurView.blendingMode = .withinWindow
      }
      blurView.state = .active
    #endif

    super.init(frame: .zero)

    #if canImport(AppKit)
      wantsLayer = true
    #endif

    // Add blur view first (behind content)
    blurView.translatesAutoresizingMaskIntoConstraints = false
    addSubview(blurView)

    // Add content on top
    contentView.translatesAutoresizingMaskIntoConstraints = false
    addSubview(contentView)

    // Setup constraints
    NSLayoutConstraint.activate([
      blurView.leadingAnchor.constraint(equalTo: leadingAnchor),
      blurView.trailingAnchor.constraint(equalTo: trailingAnchor),
      blurView.topAnchor.constraint(equalTo: topAnchor),
      blurView.bottomAnchor.constraint(equalTo: bottomAnchor),
      contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
      contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
      contentView.topAnchor.constraint(equalTo: topAnchor),
      contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
    ])

    Logger.waterui.debug(
      "MaterialBackground created with material: \(String(describing: metadata.material))")
  }

  @available(*, unavailable)
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  #if canImport(UIKit)
    private static func uiBlurStyle(from material: WuiMaterial) -> UIBlurEffect.Style {
      switch material {
      case WuiMaterial_UltraThin:
        return .systemUltraThinMaterial
      case WuiMaterial_Thin:
        return .systemThinMaterial
      case WuiMaterial_Regular:
        return .systemMaterial
      case WuiMaterial_Thick:
        return .systemThickMaterial
      case WuiMaterial_UltraThick:
        return .systemChromeMaterial
      default:
        fatalError("Unsupported WaterUI material: \(material.rawValue)")
      }
    }
  #endif

  #if canImport(AppKit)
    private static func nsMaterial(from material: WuiMaterial) -> NSVisualEffectView.Material {
      switch material {
      case WuiMaterial_UltraThin:
        return .hudWindow
      case WuiMaterial_Thin:
        return .titlebar
      case WuiMaterial_Regular:
        return .menu
      case WuiMaterial_Thick:
        return .sidebar
      case WuiMaterial_UltraThick:
        return .sidebar
      default:
        fatalError("Unsupported WaterUI material: \(material.rawValue)")
      }
    }
  #endif

  func layoutPriority() -> Int32 {
    contentView.layoutPriority()
  }

  func sizeThatFits(_ proposal: WuiProposalSize) -> CGSize {
    contentView.sizeThatFits(proposal)
  }

  #if canImport(UIKit)
    override func layoutSubviews() {
      super.layoutSubviews()
    }
  #elseif canImport(AppKit)
    nonisolated override var isFlipped: Bool { true }

    override func layout() {
      super.layout()
    }
  #endif
}