@@ -6,18 +6,31 @@ enum POSButtonSize {
66 case extraSmall
77}
88
9- /// Filled button style in POS that can show a loading indicator.
9+ /// Button state for different visual presentations
10+ enum POSButtonState {
11+ case idle
12+ case loading
13+ case success
14+ }
15+
16+ /// Filled button style in POS that can show loading and success states.
1017struct POSFilledButtonStyle : ButtonStyle {
1118 private let size : POSButtonSize
12- private let isLoading : Bool
19+ private let state : POSButtonState
1320
1421 init ( size: POSButtonSize , isLoading: Bool = false ) {
1522 self . size = size
16- self . isLoading = isLoading
23+ self . state = isLoading ? . loading : . idle
24+ }
25+
26+ init ( size: POSButtonSize , state: POSButtonState ) {
27+ self . size = size
28+ self . state = state
1729 }
1830
1931 func makeBody( configuration: Configuration ) -> some View {
20- POSButton ( configuration: configuration, variant: . filled, size: size, isLoading: isLoading)
32+ POSButtonStyleInternal ( configuration: configuration, variant: . filled, size: size, state: state)
33+ . disabled ( state != . idle)
2134 }
2235}
2336
@@ -30,32 +43,35 @@ struct POSOutlinedButtonStyle: ButtonStyle {
3043 }
3144
3245 func makeBody( configuration: Configuration ) -> some View {
33- POSButton ( configuration: configuration, variant: . outlined, size: size, isLoading : false )
46+ POSButtonStyleInternal ( configuration: configuration, variant: . outlined, size: size, state : . idle )
3447 }
3548}
3649
50+
3751/// The visual variant of the POS button.
3852fileprivate enum POSButtonVariant {
3953 case filled
4054 case outlined
4155}
4256
43- private struct POSButton : View {
57+ private struct POSButtonStyleInternal : View {
4458 @Environment ( \. isEnabled) var isEnabled
4559
4660 let configuration : ButtonStyleConfiguration
4761 let variant : POSButtonVariant
4862 let size : POSButtonSize
49- let isLoading : Bool
63+ let state : POSButtonState
5064
5165 var body : some View {
5266 Group {
5367 containerView {
5468 ZStack ( alignment: . center) {
5569 configuration. label
56- . opacity ( isLoading ? 0 : 1 )
70+ . opacity ( state == . idle ? 1 : 0 )
5771 progressView
58- . renderedIf ( isLoading)
72+ . renderedIf ( state == . loading)
73+ successView
74+ . renderedIf ( state == . success)
5975 }
6076 }
6177 }
@@ -91,12 +107,18 @@ private struct POSButton: View {
91107 . progressViewStyle ( POSButtonProgressViewStyle ( size: size. progressViewDimensions. size, lineWidth: size. progressViewDimensions. lineWidth) )
92108 }
93109
110+ private var successView : some View {
111+ Image ( systemName: " checkmark.circle " )
112+ . font ( size == . normal ? . title2 : . body)
113+ . foregroundColor ( . posOnPrimaryContainer)
114+ }
115+
94116 private var backgroundColor : Color {
95117 switch ( variant, isEnabled) {
96118 case ( . filled, true ) :
97119 . posPrimaryContainer
98120 case ( . filled, false ) :
99- isLoading ? . posPrimaryContainer : . posDisabledContainer
121+ state != . idle ? . posPrimaryContainer : . posDisabledContainer
100122 case ( . outlined, _) :
101123 . clear
102124 }
@@ -125,9 +147,9 @@ private struct POSButton: View {
125147 }
126148}
127149
128- // MARK: - POSButton Constants
150+ // MARK: - POSButtonStyleInternal Constants
129151
130- private extension POSButton {
152+ private extension POSButtonStyleInternal {
131153 enum Constants {
132154 static let cornerRadius : CGFloat = POSCornerRadiusStyle . medium. value
133155 static let borderStrokeWidth : CGFloat = 2.0
@@ -190,6 +212,10 @@ struct POSButtonStyle_Previews: View {
190212 LoadingPreviewSection ( title: " Loading Buttons - Normal " , size: . normal)
191213
192214 LoadingPreviewSection ( title: " Loading Buttons - Extra Small " , size: . extraSmall)
215+
216+ LoadingStatePreviewSection ( title: " Loading State Buttons - Normal " , size: . normal)
217+
218+ LoadingStatePreviewSection ( title: " Loading State Buttons - Extra Small " , size: . extraSmall)
193219
194220 // Example with long text
195221 VStack ( alignment: . leading, spacing: POSSpacing . medium) {
@@ -262,6 +288,40 @@ private struct LoadingPreviewSection: View {
262288 }
263289}
264290
291+ private struct LoadingStatePreviewSection : View {
292+ let title : String
293+ let size : POSButtonSize
294+ @State private var currentState : POSButtonState = . idle
295+
296+ var body : some View {
297+ VStack ( alignment: . leading, spacing: POSSpacing . medium) {
298+ Text ( title)
299+ . font ( . headline)
300+
301+ Button ( " Cycle States " ) {
302+ switch currentState {
303+ case . idle:
304+ currentState = . loading
305+ case . loading:
306+ currentState = . success
307+ case . success:
308+ currentState = . idle
309+ }
310+ }
311+ . buttonStyle ( POSFilledButtonStyle ( size: size, state: currentState) )
312+
313+ Button ( " Idle State " ) { }
314+ . buttonStyle ( POSFilledButtonStyle ( size: size, state: . idle) )
315+
316+ Button ( " Loading State " ) { }
317+ . buttonStyle ( POSFilledButtonStyle ( size: size, state: . loading) )
318+
319+ Button ( " Success State " ) { }
320+ . buttonStyle ( POSFilledButtonStyle ( size: size, state: . success) )
321+ }
322+ }
323+ }
324+
265325#Preview( " Button Styles " ) {
266326 POSButtonStyle_Previews ( )
267327}
0 commit comments