diff --git a/Sources/SstUI/Controls.swift b/Sources/SstUI/Controls.swift index 72c2241..622914d 100644 --- a/Sources/SstUI/Controls.swift +++ b/Sources/SstUI/Controls.swift @@ -105,3 +105,39 @@ public struct LampView: View { .accessibilityHidden(true) } } + +/// A two-position rocker switch: a key cap sliding in a recessed track. +public struct RockerToggleStyle: ToggleStyle { + public init() {} + + public func makeBody(configuration: Configuration) -> some View { + HStack(spacing: Space.s4) { + configuration.label + Button { + configuration.isOn.toggle() + } label: { + RockerTrack(isOn: configuration.isOn) + } + .buttonStyle(.plain) + .accessibilityValue(configuration.isOn ? "aan" : "uit") + } + } + + private struct RockerTrack: View { + let isOn: Bool + @Environment(\.accessibilityReduceMotion) private var reduceMotion + + var body: some View { + ZStack(alignment: isOn ? .trailing : .leading) { + WellBackground() + PhysicalSurface( + fill: AnyShapeStyle(LinearGradient(colors: [Palette.surfaceKeyHigh, Palette.surfaceKeyLow], startPoint: .top, endPoint: .bottom)), + cornerRadius: Radius.sm, shadows: Shadows.keyRaised) + .frame(width: Size.switchWidth / 2, height: Size.switchHeight - Space.s2) + .padding(Space.s1) + } + .frame(width: Size.switchWidth, height: Size.switchHeight) + .animation(reduceMotion ? nil : .easeOut(duration: Motion.durationFast), value: isOn) + } + } +}