Skip to content

Commit d9acfcc

Browse files
authored
feat: add fluent wrapper for UIButton.Configuration (#53)
1 parent 70d5b62 commit d9acfcc

File tree

1 file changed

+390
-0
lines changed

1 file changed

+390
-0
lines changed
Lines changed: 390 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,390 @@
1+
//
2+
// flex-ui
3+
// Copyright © 2026 Space Code. All rights reserved.
4+
//
5+
6+
import UIKit
7+
8+
// MARK: - UIButton.Configuration + FlexCompatible
9+
10+
@available(iOS 15.0, *)
11+
extension UIButton.Configuration: FlexCompatible {}
12+
13+
@available(iOS 15.0, *)
14+
public extension FlexUI where Component == UIButton.Configuration {
15+
/// Sets the button title.
16+
///
17+
/// - Parameter title: The title text to display.
18+
/// - Returns: The current instance of `FlexUI` for further configuration.
19+
@discardableResult
20+
func title(_ title: String?) -> FlexUI<UIButton.Configuration> {
21+
var config = component
22+
config.title = title
23+
return FlexUI(component: config)
24+
}
25+
26+
/// Sets the attributed title.
27+
///
28+
/// - Parameter attributedTitle: The attributed title to display.
29+
/// - Returns: The current instance of `FlexUI` for further configuration.
30+
@discardableResult
31+
func attributedTitle(_ attributedTitle: AttributedString?) -> FlexUI<UIButton.Configuration> {
32+
var config = component
33+
config.attributedTitle = attributedTitle
34+
return FlexUI(component: config)
35+
}
36+
37+
/// Sets the title alignment.
38+
///
39+
/// - Parameter alignment: The title alignment.
40+
/// - Returns: The current instance of `FlexUI` for further configuration.
41+
@discardableResult
42+
func titleAlignment(_ alignment: UIButton.Configuration.TitleAlignment) -> FlexUI<UIButton.Configuration> {
43+
var config = component
44+
config.titleAlignment = alignment
45+
return FlexUI(component: config)
46+
}
47+
48+
/// Sets the title line break mode.
49+
///
50+
/// - Parameter mode: The line break mode.
51+
/// - Returns: The current instance of `FlexUI` for further configuration.
52+
@discardableResult
53+
func titleLineBreakMode(_ mode: NSLineBreakMode) -> FlexUI<UIButton.Configuration> {
54+
var config = component
55+
config.titleLineBreakMode = mode
56+
return FlexUI(component: config)
57+
}
58+
59+
/// Sets the button subtitle.
60+
///
61+
/// - Parameter subtitle: The subtitle text to display.
62+
/// - Returns: The current instance of `FlexUI` for further configuration.
63+
@discardableResult
64+
func subtitle(_ subtitle: String?) -> FlexUI<UIButton.Configuration> {
65+
var config = component
66+
config.subtitle = subtitle
67+
return FlexUI(component: config)
68+
}
69+
70+
/// Sets the attributed subtitle.
71+
///
72+
/// - Parameter attributedSubtitle: The attributed subtitle to display.
73+
/// - Returns: The current instance of `FlexUI` for further configuration.
74+
@discardableResult
75+
func attributedSubtitle(_ attributedSubtitle: AttributedString?) -> FlexUI<UIButton.Configuration> {
76+
var config = component
77+
config.attributedSubtitle = attributedSubtitle
78+
return FlexUI(component: config)
79+
}
80+
81+
/// Sets the subtitle line break mode.
82+
///
83+
/// - Parameter mode: The line break mode.
84+
/// - Returns: The current instance of `FlexUI` for further configuration.
85+
@discardableResult
86+
func subtitleLineBreakMode(_ mode: NSLineBreakMode) -> FlexUI<UIButton.Configuration> {
87+
var config = component
88+
config.subtitleLineBreakMode = mode
89+
return FlexUI(component: config)
90+
}
91+
92+
// MARK: - Image Configuration
93+
94+
/// Sets the button image.
95+
///
96+
/// - Parameter image: The image to display.
97+
/// - Returns: The current instance of `FlexUI` for further configuration.
98+
@discardableResult
99+
func image(_ image: UIImage?) -> FlexUI<UIButton.Configuration> {
100+
var config = component
101+
config.image = image
102+
return FlexUI(component: config)
103+
}
104+
105+
/// Sets the button image using SF Symbol name.
106+
///
107+
/// - Parameter systemName: The SF Symbol name.
108+
/// - Returns: The current instance of `FlexUI` for further configuration.
109+
@discardableResult
110+
func systemImage(_ systemName: String) -> FlexUI<UIButton.Configuration> {
111+
var config = component
112+
config.image = UIImage(systemName: systemName)
113+
return FlexUI(component: config)
114+
}
115+
116+
/// Sets the image placement relative to the title.
117+
///
118+
/// - Parameter placement: The image placement.
119+
/// - Returns: The current instance of `FlexUI` for further configuration.
120+
@discardableResult
121+
func imagePlacement(_ placement: NSDirectionalRectEdge) -> FlexUI<UIButton.Configuration> {
122+
var config = component
123+
config.imagePlacement = placement
124+
return FlexUI(component: config)
125+
}
126+
127+
/// Sets the padding between the image and title.
128+
///
129+
/// - Parameter padding: The padding value.
130+
/// - Returns: The current instance of `FlexUI` for further configuration.
131+
@discardableResult
132+
func imagePadding(_ padding: CGFloat) -> FlexUI<UIButton.Configuration> {
133+
var config = component
134+
config.imagePadding = padding
135+
return FlexUI(component: config)
136+
}
137+
138+
/// Sets whether the image should be treated as a symbol.
139+
///
140+
/// - Parameter preferredSymbolConfiguration: The symbol configuration.
141+
/// - Returns: The current instance of `FlexUI` for further configuration.
142+
@discardableResult
143+
func preferredSymbolConfiguration(
144+
_ preferredSymbolConfiguration: UIImage.SymbolConfiguration?
145+
) -> FlexUI<UIButton.Configuration> {
146+
var config = component
147+
config.preferredSymbolConfigurationForImage = preferredSymbolConfiguration
148+
return FlexUI(component: config)
149+
}
150+
151+
/// Sets the image color transformer.
152+
///
153+
/// - Parameter transformer: The color transformer.
154+
/// - Returns: The current instance of `FlexUI` for further configuration.
155+
@discardableResult
156+
func imageColorTransformer(_ transformer: UIConfigurationColorTransformer?) -> FlexUI<UIButton.Configuration> {
157+
var config = component
158+
config.imageColorTransformer = transformer
159+
return FlexUI(component: config)
160+
}
161+
162+
/// Sets the background configuration.
163+
///
164+
/// - Parameter background: The background configuration.
165+
/// - Returns: The current instance of `FlexUI` for further configuration.
166+
@discardableResult
167+
func background(_ background: UIBackgroundConfiguration) -> FlexUI<UIButton.Configuration> {
168+
var config = component
169+
config.background = background
170+
return FlexUI(component: config)
171+
}
172+
173+
/// Sets the background color.
174+
///
175+
/// - Parameter color: The background color.
176+
/// - Returns: The current instance of `FlexUI` for further configuration.
177+
@discardableResult
178+
func backgroundColor(_ color: UIColor?) -> FlexUI<UIButton.Configuration> {
179+
var config = component
180+
config.background.backgroundColor = color
181+
return FlexUI(component: config)
182+
}
183+
184+
/// Sets the corner radius.
185+
///
186+
/// - Parameter radius: The corner radius value.
187+
/// - Returns: The current instance of `FlexUI` for further configuration.
188+
@discardableResult
189+
func cornerRadius(_ radius: CGFloat) -> FlexUI<UIButton.Configuration> {
190+
var config = component
191+
config.background.cornerRadius = radius
192+
return FlexUI(component: config)
193+
}
194+
195+
/// Sets the corner style.
196+
///
197+
/// - Parameter style: The corner style.
198+
/// - Returns: The current instance of `FlexUI` for further configuration.
199+
@discardableResult
200+
func cornerStyle(_ style: UIButton.Configuration.CornerStyle) -> FlexUI<UIButton.Configuration> {
201+
var config = component
202+
config.cornerStyle = style
203+
return FlexUI(component: config)
204+
}
205+
206+
// MARK: - Size Configuration
207+
208+
/// Sets the button size.
209+
///
210+
/// - Parameter size: The button size.
211+
/// - Returns: The current instance of `FlexUI` for further configuration.
212+
@discardableResult
213+
func buttonSize(_ size: UIButton.Configuration.Size) -> FlexUI<UIButton.Configuration> {
214+
var config = component
215+
config.buttonSize = size
216+
return FlexUI(component: config)
217+
}
218+
219+
/// Sets the base foreground color.
220+
///
221+
/// - Parameter color: The foreground color.
222+
/// - Returns: The current instance of `FlexUI` for further configuration.
223+
@discardableResult
224+
func baseForegroundColor(_ color: UIColor?) -> FlexUI<UIButton.Configuration> {
225+
var config = component
226+
config.baseForegroundColor = color
227+
return FlexUI(component: config)
228+
}
229+
230+
/// Sets the base background color.
231+
///
232+
/// - Parameter color: The background color.
233+
/// - Returns: The current instance of `FlexUI` for further configuration.
234+
@discardableResult
235+
func baseBackgroundColor(_ color: UIColor?) -> FlexUI<UIButton.Configuration> {
236+
var config = component
237+
config.baseBackgroundColor = color
238+
return FlexUI(component: config)
239+
}
240+
241+
// MARK: - Content Insets
242+
243+
/// Sets the content insets.
244+
///
245+
/// - Parameter insets: The directional edge insets.
246+
/// - Returns: The current instance of `FlexUI` for further configuration.
247+
@discardableResult
248+
func contentInsets(_ insets: NSDirectionalEdgeInsets) -> FlexUI<UIButton.Configuration> {
249+
var config = component
250+
config.contentInsets = insets
251+
return FlexUI(component: config)
252+
}
253+
254+
/// Sets uniform content insets.
255+
///
256+
/// - Parameter inset: The inset value for all edges.
257+
/// - Returns: The current instance of `FlexUI` for further configuration.
258+
@discardableResult
259+
func contentInsets(_ inset: CGFloat) -> FlexUI<UIButton.Configuration> {
260+
var config = component
261+
config.contentInsets = NSDirectionalEdgeInsets(
262+
top: inset,
263+
leading: inset,
264+
bottom: inset,
265+
trailing: inset
266+
)
267+
return FlexUI(component: config)
268+
}
269+
270+
/// Sets horizontal and vertical content insets.
271+
///
272+
/// - Parameters:
273+
/// - horizontal: The horizontal inset value.
274+
/// - vertical: The vertical inset value.
275+
/// - Returns: The current instance of `FlexUI` for further configuration.
276+
@discardableResult
277+
func contentInsets(horizontal: CGFloat, vertical: CGFloat) -> FlexUI<UIButton.Configuration> {
278+
var config = component
279+
config.contentInsets = NSDirectionalEdgeInsets(
280+
top: vertical,
281+
leading: horizontal,
282+
bottom: vertical,
283+
trailing: horizontal
284+
)
285+
return FlexUI(component: config)
286+
}
287+
288+
/// Sets the activity indicator visibility.
289+
///
290+
/// - Parameter showing: Whether to show the activity indicator.
291+
/// - Returns: The current instance of `FlexUI` for further configuration.
292+
@discardableResult
293+
func showsActivityIndicator(_ showing: Bool) -> FlexUI<UIButton.Configuration> {
294+
var config = component
295+
config.showsActivityIndicator = showing
296+
return FlexUI(component: config)
297+
}
298+
299+
/// Sets the activity indicator color transformer.
300+
///
301+
/// - Parameter transformer: The color transformer.
302+
/// - Returns: The current instance of `FlexUI` for further configuration.
303+
@discardableResult
304+
func activityIndicatorColorTransformer(_ transformer: UIConfigurationColorTransformer?) -> FlexUI<UIButton.Configuration> {
305+
var config = component
306+
config.activityIndicatorColorTransformer = transformer
307+
return FlexUI(component: config)
308+
}
309+
310+
/// Sets whether to automatically update for button state.
311+
///
312+
/// - Parameter updates: Whether to automatically update.
313+
/// - Returns: The current instance of `FlexUI` for further configuration.
314+
@discardableResult
315+
func automaticallyUpdateForSelection(_ updates: Bool) -> FlexUI<UIButton.Configuration> {
316+
var config = component
317+
config.automaticallyUpdateForSelection = updates
318+
return FlexUI(component: config)
319+
}
320+
321+
/// Sets the Mac idiom style.
322+
///
323+
/// - Parameter style: The Mac idiom style.
324+
/// - Returns: The current instance of `FlexUI` for further configuration.
325+
@discardableResult
326+
func macIdiomStyle(_ style: UIButton.Configuration.MacIdiomStyle) -> FlexUI<UIButton.Configuration> {
327+
var config = component
328+
config.macIdiomStyle = style
329+
return FlexUI(component: config)
330+
}
331+
332+
/// Sets the title text attributes transformer.
333+
///
334+
/// - Parameter transformer: The text attributes transformer.
335+
/// - Returns: The current instance of `FlexUI` for further configuration.
336+
@discardableResult
337+
func titleTextAttributesTransformer(
338+
_ transformer: UIConfigurationTextAttributesTransformer?
339+
) -> FlexUI<UIButton.Configuration> {
340+
var config = component
341+
config.titleTextAttributesTransformer = transformer
342+
return FlexUI(component: config)
343+
}
344+
345+
/// Sets the subtitle text attributes transformer.
346+
///
347+
/// - Parameter transformer: The text attributes transformer.
348+
/// - Returns: The current instance of `FlexUI` for further configuration.
349+
@discardableResult
350+
func subtitleTextAttributesTransformer(
351+
_ transformer: UIConfigurationTextAttributesTransformer?
352+
) -> FlexUI<UIButton.Configuration> {
353+
var config = component
354+
config.subtitleTextAttributesTransformer = transformer
355+
return FlexUI(component: config)
356+
}
357+
358+
/// Sets the button as a primary action button with filled style.
359+
///
360+
/// - Returns: The current instance of `FlexUI` for further configuration.
361+
@discardableResult
362+
func primaryActionStyle() -> FlexUI<UIButton.Configuration> {
363+
var config = component
364+
config.buttonSize = .large
365+
config.cornerStyle = .large
366+
return FlexUI(component: config)
367+
}
368+
369+
/// Sets the button as a secondary action button with tinted style.
370+
///
371+
/// - Returns: The current instance of `FlexUI` for further configuration.
372+
@discardableResult
373+
func secondaryActionStyle() -> FlexUI<UIButton.Configuration> {
374+
var config = component
375+
config.buttonSize = .medium
376+
config.cornerStyle = .medium
377+
return FlexUI(component: config)
378+
}
379+
380+
/// Applies a custom configuration using a closure.
381+
///
382+
/// - Parameter configure: A closure to configure the button configuration.
383+
/// - Returns: The current instance of `FlexUI` for further configuration.
384+
@discardableResult
385+
func configure(_ configure: (inout UIButton.Configuration) -> Void) -> FlexUI<UIButton.Configuration> {
386+
var config = component
387+
configure(&config)
388+
return FlexUI(component: config)
389+
}
390+
}

0 commit comments

Comments
 (0)