## Tapping a heart / like button

- Use case: User taps a heart to like a post; the icon pops and a soft tap confirms it.
- Feel: A single soft, rounded tap — warm rather than clicky. Slightly stronger when liking than unliking.
- APIs: .sensoryFeedback(.impact(flexibility: .soft)), UIImpactFeedbackGenerator(style: .soft)
- Minimum OS: iOS 17+ / iOS 13+

### SwiftUI (iOS 17+)

```swift
import SwiftUI

struct LikeButton: View {
    @State private var isLiked = false

    var body: some View {
        Button {
            withAnimation(.spring(response: 0.3, dampingFraction: 0.5)) {
                isLiked.toggle()
            }
        } label: {
            Image(systemName: isLiked ? "heart.fill" : "heart")
                .font(.title)
                .foregroundStyle(isLiked ? .red : .secondary)
                .scaleEffect(isLiked ? 1.15 : 1.0)
        }
        // Soft tap when liking, lighter when unliking
        .sensoryFeedback(trigger: isLiked) { _, liked in
            .impact(flexibility: .soft, intensity: liked ? 0.8 : 0.5)
        }
    }
}
```

### UIKit

```swift
import UIKit

final class LikeButton: UIButton {
    private let haptic = UIImpactFeedbackGenerator(style: .soft)
    private(set) var isLiked = false

    override init(frame: CGRect) {
        super.init(frame: frame)
        setImage(UIImage(systemName: "heart"), for: .normal)
        addTarget(self, action: #selector(touchDown), for: .touchDown)
        addTarget(self, action: #selector(toggleLike), for: .touchUpInside)
    }
    required init?(coder: NSCoder) { fatalError() }

    @objc private func touchDown() {
        haptic.prepare() // wake the engine before the finger lifts
    }

    @objc private func toggleLike() {
        isLiked.toggle()
        haptic.impactOccurred(intensity: isLiked ? 0.8 : 0.5)
        setImage(UIImage(systemName: isLiked ? "heart.fill" : "heart"), for: .normal)
        tintColor = isLiked ? .systemRed : .secondaryLabel
    }
}
```

### Notes
- Asymmetric intensity (stronger like, weaker unlike) mirrors the emotional weight of the action.
- Sync the haptic with the peak of the scale animation, not the touch-down.
