// SPDX-License-Identifier: MIT // Copyright (c) 2026 Oscar Canton and SwiftUI Blocks contributors import SwiftUI extension ContainerValues { @Entry var subviewCardTint: Color = .accentColor } extension View { /// The color of the card this view gets inside a `SubviewCardContainer`. func subviewCardTint(_ color: Color) -> some View { containerValue(\.subviewCardTint, color) } } /// A container that turns every child of its `@ViewBuilder` into a tinted card. /// /// `ForEach(subviews:)` sees each resolved child, so it works the same for /// static views and for children that come from a `ForEach` or an `if`. struct SubviewCardContainer: View { var spacing: CGFloat = 12 @ViewBuilder var content: Content @Environment(\.accessibilityReduceMotion) private var reduceMotion var body: some View { VStack(spacing: spacing) { ForEach(subviews: content) { subview in let tint = subview.containerValues.subviewCardTint subview .frame(maxWidth: .infinity, alignment: .leading) .padding(16) .padding(.leading, 6) .background(tint.opacity(0.16), in: .rect(cornerRadius: 18)) .overlay(alignment: .leading) { Capsule() .fill(tint.gradient) .frame(width: 5) .padding(.vertical, 12) .padding(.leading, 8) .accessibilityHidden(true) } .transition(reduceMotion ? .opacity : .scale(scale: 0.9).combined(with: .opacity)) } } } } // MARK: - Demo struct SubviewCardContainerDemo: View { private static let colors: [Color] = [.pink, .orange, .teal, .purple, .green] @State private var reminders = 1 @Environment(\.accessibilityReduceMotion) private var reduceMotion var body: some View { VStack(spacing: 16) { ScrollView { VStack(alignment: .leading, spacing: 20) { Text("Today") .font(.system(.largeTitle, design: .rounded, weight: .bold)) SubviewCardContainer { Label("A static child", systemImage: "square.fill") .font(.headline) .subviewCardTint(.indigo) Text("Plain text becomes a card too, with no wrapper around it.") .subviewCardTint(.blue) ForEach(0..