Bedrock/Sources/Bedrock/Views/Settings/SegmentedPicker.swift

98 lines
3.0 KiB
Swift

//
// SegmentedPicker.swift
// Bedrock
//
// A horizontal segmented picker with capsule-style buttons.
//
import SwiftUI
/// A horizontal segmented picker with capsule-style buttons.
///
/// Use this for selecting from a small number of options (2-4).
///
/// ```swift
/// SegmentedPicker(
/// title: "Theme",
/// options: [("Light", "light"), ("Dark", "dark"), ("System", "system")],
/// selection: $theme
/// )
/// ```
public struct SegmentedPicker<T: Equatable>: View {
/// The title/label for the picker.
public let title: String
/// The available options as (label, value) pairs.
public let options: [(String, T)]
/// Binding to the selected value.
@Binding public var selection: T
/// The accent color for the selected button.
public let accentColor: Color
/// Creates a segmented picker.
/// - Parameters:
/// - title: The title label.
/// - options: Array of (label, value) tuples.
/// - selection: Binding to selected value.
/// - accentColor: The accent color (default: primary accent).
public init(
title: String,
options: [(String, T)],
selection: Binding<T>,
accentColor: Color = .Accent.primary
) {
self.title = title
self.options = options
self._selection = selection
self.accentColor = accentColor
}
public var body: some View {
VStack(alignment: .leading, spacing: Design.Spacing.small) {
Text(title).styled(.subheadingEmphasis, emphasis: .inverse)
HStack(spacing: Design.Spacing.small) {
ForEach(options.indices, id: \.self) { index in
let option = options[index]
Button {
selection = option.1
} label: {
Text(option.0)
.styled(.subheadingEmphasis, emphasis: .custom(selection == option.1 ? .black : .white.opacity(Design.Opacity.strong)))
.padding(.vertical, Design.Spacing.small)
.frame(maxWidth: .infinity)
.background(
Capsule()
.fill(selection == option.1 ? accentColor : Color.white.opacity(Design.Opacity.subtle))
)
}
.buttonStyle(.plain)
}
}
}
.padding(.vertical, Design.Spacing.small)
}
}
// MARK: - Preview
#Preview {
VStack(spacing: Design.Spacing.medium) {
SegmentedPicker(
title: "Animation Speed",
options: [("Fast", "fast"), ("Normal", "normal"), ("Slow", "slow")],
selection: .constant("normal")
)
SegmentedPicker(
title: "Theme",
options: [("Light", 0), ("Dark", 1)],
selection: .constant(1)
)
}
.padding()
.background(Color.Surface.overlay)
}