Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions Sources/OpenSwiftUICore/Animation/Transition/BlurTransition.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//
// BlurTransition.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete
// ID: A4BD5A1CB1233579E2E5EB40492B5E89 (SwiftUI)

public import Foundation

// MARK: - AnyTransition + blur

@_spi(Private)
@available(OpenSwiftUI_v5_0, *)
extension AnyTransition {

/// Creates a transition that blurs the view when being inserted or removed.
///
/// - Parameter radius: The blur radius. The default value is `10`.
///
/// - Returns: A transition that applies a blur effect.
public static func blur(radius: CGFloat = 10) -> AnyTransition {
.init(BlurAndFadeTransition(radius: radius))
}
}

// MARK: - Transition + blurReplace

@available(OpenSwiftUI_v5_0, *)
extension Transition where Self == BlurReplaceTransition {

/// A transition that animates the insertion or removal of a view
/// by combining blurring and scaling effects.
@MainActor
@preconcurrency
public static func blurReplace(_ config: BlurReplaceTransition.Configuration = .downUp) -> Self {
return Self(configuration: config)
}

/// A transition that animates the insertion or removal of a view
/// by combining blurring and scaling effects.
@_alwaysEmitIntoClient
@MainActor
@preconcurrency
public static var blurReplace: BlurReplaceTransition {
blurReplace(.downUp)
}
}

// MARK: - BlurReplaceTransition

/// A transition that animates the insertion or removal of a view by
/// combining blurring and scaling effects.
@available(OpenSwiftUI_v5_0, *)
@MainActor
@preconcurrency
public struct BlurReplaceTransition: Transition {

// MARK: - BlurReplaceTransition.Configuration

/// Configuration properties for a transition.
public struct Configuration: Equatable {
package enum Storage: Equatable {
case downUp
case upUp
}

package var storage: Storage

package init(_ storage: Storage) {
self.storage = storage
}

/// A configuration that requests a transition that scales the
/// view down while removing it and up while inserting it.
public static let downUp = Configuration(.downUp)

/// A configuration that requests a transition that scales the
/// view up while both removing and inserting it.
public static let upUp = Configuration(.upUp)
}

/// The transition configuration.
public var configuration: Configuration

/// Creates a new transition.
///
/// - Parameter configuration: the transition configuration.
public init(configuration: Configuration) {
self.configuration = configuration
}

public func body(content: Content, phase: TransitionPhase) -> some View {
let scale: CGFloat = switch phase {
case .identity: 1.0
case .willAppear: 0.9
case .didDisappear: configuration.storage == .upUp ? 1.1 : 0.9
}
content
.opacity(phase.isIdentity ? 1 : 0)
.blur(radius: phase.isIdentity ? 0 : 7)
.scaleEffect(scale)
}

public func _makeContentTransition(transition: inout _Transition_ContentTransition) {
guard case .effects = transition.operation else {
transition.result = .bool(true)
return
}
transition.result = .effects(configuration.effects)
}
}

@available(*, unavailable)
extension BlurReplaceTransition: Sendable {}

@available(*, unavailable)
extension BlurReplaceTransition.Configuration: Sendable {}

// MARK: - BlurReplaceTransition.Configuration + effects

@available(OpenSwiftUI_v5_0, *)
extension BlurReplaceTransition.Configuration {

fileprivate var effects: [ContentTransition.Effect] {
let opacityEffect = ContentTransition.Effect(
type: .opacity,
begin: 0.33,
duration: 0.67
)
let blurEffect = ContentTransition.Effect(
type: .blur(radius: 7),
begin: 0.33,
duration: 0.67
)
let scaleEffect = ContentTransition.Effect(
type: .scale(0.9),
begin: 0.33,
duration: 0.67,
flags: .init(rawValue: storage == .upUp ? 1 : 0)
)
return [opacityEffect, blurEffect, scaleEffect]
}
}

// MARK: - BlurAndFadeTransition

private struct BlurAndFadeTransition: Transition {
var radius: CGFloat

func body(content: Content, phase: TransitionPhase) -> some View {
content
.blur(radius: phase.isIdentity ? 0 : radius)
.opacity(phase.isIdentity ? 1 : 0)
}

func _makeContentTransition(transition: inout _Transition_ContentTransition) {
guard case .effects = transition.operation else {
transition.result = .bool(true)
return
}
let blurEffect = ContentTransition.Effect(.blur(radius: radius))
let opacityEffect = ContentTransition.Effect(.opacity)
transition.result = .effects([blurEffect, opacityEffect])
}
}

@available(*, unavailable)
extension BlurAndFadeTransition: Sendable {}
Loading