import SwiftUI /// Button whose chrome scales, not just its label. /// /// The system `.bordered` style sizes its padding, height and corner radius /// from `controlSize`, which has four fixed steps — setting a larger font on it /// grows the text inside a button that stays the same size. This style derives /// every dimension from the zoom multiplier instead. struct ScaledButtonStyle: ButtonStyle { let scale: CGFloat /// Text-only variant, for secondary actions like "Открыть". var borderless = false func makeBody(configuration: Configuration) -> some View { Label(configuration: configuration, scale: scale, borderless: borderless) } /// Not named `Body`: that collides with `ButtonStyle`'s own associated type. private struct Label: View { let configuration: ButtonStyleConfiguration let scale: CGFloat let borderless: Bool /// A custom style has to dim itself — SwiftUI only does that for the /// built-in ones. @Environment(\.isEnabled) private var isEnabled var body: some View { configuration.label .font(.system(size: 12 * scale)) .lineLimit(1) .padding(.horizontal, borderless ? 2 * scale : 10 * scale) .padding(.vertical, borderless ? 1 * scale : 5 * scale) .background(background) .foregroundStyle(borderless ? Color.accentColor : Color.primary) .opacity(isEnabled ? (configuration.isPressed ? 0.7 : 1) : 0.4) .contentShape(Rectangle()) } @ViewBuilder private var background: some View { if borderless { Color.clear } else { RoundedRectangle(cornerRadius: 6 * scale, style: .continuous) .fill(Color.primary.opacity(configuration.isPressed ? 0.16 : 0.08)) .overlay( RoundedRectangle(cornerRadius: 6 * scale, style: .continuous) .strokeBorder(Color.primary.opacity(0.12), lineWidth: 1) ) } } } }