Skip to content

Commit 9a1c2e8

Browse files
committed
Add Stepper control
1 parent a687258 commit 9a1c2e8

1 file changed

Lines changed: 76 additions & 0 deletions

File tree

  • AndroidSwiftUICore/Sources/AndroidSwiftUICore/Primitives
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//
2+
// Stepper.swift
3+
// AndroidSwiftUICore
4+
//
5+
// A control that increments or decrements a value. The core registers the two
6+
// edge actions as callbacks; the interpreter renders a label plus − / + buttons.
7+
//
8+
9+
public struct Stepper<Label: View>: View {
10+
11+
internal let label: Label
12+
internal let onIncrement: () -> Void
13+
internal let onDecrement: () -> Void
14+
15+
public init(
16+
onIncrement: @escaping () -> Void,
17+
onDecrement: @escaping () -> Void,
18+
@ViewBuilder label: () -> Label
19+
) {
20+
self.label = label()
21+
self.onIncrement = onIncrement
22+
self.onDecrement = onDecrement
23+
}
24+
25+
public typealias Body = Never
26+
}
27+
28+
public extension Stepper where Label == Text {
29+
30+
init<S: StringProtocol, V: Strideable>(
31+
_ title: S,
32+
value: Binding<V>,
33+
in bounds: ClosedRange<V>,
34+
step: V.Stride = 1
35+
) {
36+
self.init(
37+
onIncrement: {
38+
let next = value.wrappedValue.advanced(by: step)
39+
if next <= bounds.upperBound { value.wrappedValue = next }
40+
},
41+
onDecrement: {
42+
let previous = value.wrappedValue.advanced(by: -step)
43+
if previous >= bounds.lowerBound { value.wrappedValue = previous }
44+
},
45+
label: { Text(title) }
46+
)
47+
}
48+
49+
init<S: StringProtocol, V: Strideable>(
50+
_ title: S,
51+
value: Binding<V>,
52+
step: V.Stride = 1
53+
) {
54+
self.init(
55+
onIncrement: { value.wrappedValue = value.wrappedValue.advanced(by: step) },
56+
onDecrement: { value.wrappedValue = value.wrappedValue.advanced(by: -step) },
57+
label: { Text(title) }
58+
)
59+
}
60+
}
61+
62+
extension Stepper: PrimitiveView {
63+
public func _render(in context: ResolveContext) -> RenderNode {
64+
let incrementID = context.callbacks.register(.void(onIncrement))
65+
let decrementID = context.callbacks.register(.void(onDecrement))
66+
return RenderNode(
67+
type: "Stepper",
68+
id: context.path,
69+
props: [
70+
"onIncrement": .int(Int(incrementID)),
71+
"onDecrement": .int(Int(decrementID)),
72+
],
73+
children: Evaluator.resolveChildren(label, context.descending("label"))
74+
)
75+
}
76+
}

0 commit comments

Comments
 (0)