Skip to content

Commit 5aa1c63

Browse files
authored
Adding responsiveTextFieldPlaceholderColor modifier to update a ResponsiveTextField's placeholder color (#18)
1 parent b72eda3 commit 5aa1c63

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

Sources/ResponsiveTextField/ResponsiveTextField+EnvironmentValues.swift

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ extension ResponsiveTextField {
1919
static let defaultValue: UIFont = .preferredFont(forTextStyle: .body)
2020
}
2121

22+
fileprivate struct PlaceholderColorKey: EnvironmentKey {
23+
static let defaultValue: UIColor = UIColor.black.withAlphaComponent(0.25)
24+
}
25+
2226
fileprivate struct TextColorKey: EnvironmentKey {
2327
static let defaultValue: UIColor = .black
2428
}
@@ -49,6 +53,11 @@ extension EnvironmentValues {
4953
set { self[ResponsiveTextField.FontKey.self] = newValue }
5054
}
5155

56+
var textFieldPlaceholderColor: UIColor {
57+
get { self[ResponsiveTextField.PlaceholderColorKey.self] }
58+
set { self[ResponsiveTextField.PlaceholderColorKey.self] = newValue }
59+
}
60+
5261
var textFieldTextColor: UIColor {
5362
get { self[ResponsiveTextField.TextColorKey.self] }
5463
set { self[ResponsiveTextField.TextColorKey.self] = newValue }

Sources/ResponsiveTextField/ResponsiveTextField.swift

+27-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import CombineSchedulers
1313
///
1414
public struct ResponsiveTextField {
1515
/// The text field placeholder string.
16-
let placeholder: String
16+
let placeholder: String?
1717

1818
/// A binding to the text state that will hold the typed text
1919
let text: Binding<String>
@@ -56,6 +56,10 @@ public struct ResponsiveTextField {
5656
@Environment(\.textFieldFont)
5757
var font: UIFont
5858

59+
/// Sets the text field placeholder color - use the `.responsiveTextFieldPlaceholderColor()` modifier.
60+
@Environment(\.textFieldPlaceholderColor)
61+
var placeholderColor: UIColor
62+
5963
/// When `true`, configures the text field to automatically adjust its font based on the content size category.
6064
///
6165
/// - Note: When set to `true`, the underlying text field will not respond to changes to the `textFieldFont`
@@ -123,7 +127,7 @@ public struct ResponsiveTextField {
123127
var standardEditActionHandler: StandardEditActionHandling<UITextField>?
124128

125129
public init(
126-
placeholder: String,
130+
placeholder: String?,
127131
text: Binding<String>,
128132
isSecure: Bool = false,
129133
adjustsFontForContentSizeCategory: Bool = true,
@@ -330,6 +334,14 @@ extension ResponsiveTextField: UIViewRepresentable {
330334
textField.textColor = textColor
331335
textField.textAlignment = textAlignment
332336
textField.returnKeyType = returnKeyType
337+
338+
if let placeholder {
339+
textField.attributedPlaceholder = NSAttributedString(
340+
string: placeholder,
341+
attributes: [NSAttributedString.Key.foregroundColor: self.placeholderColor]
342+
)
343+
}
344+
333345
textField.delegate = context.coordinator
334346
textField.addTarget(context.coordinator,
335347
action: #selector(Coordinator.textFieldTextChanged(_:)),
@@ -357,6 +369,13 @@ extension ResponsiveTextField: UIViewRepresentable {
357369
uiView.textColor = textColor
358370
uiView.textAlignment = textAlignment
359371

372+
if let placeholder {
373+
uiView.attributedPlaceholder = NSAttributedString(
374+
string: placeholder,
375+
attributes: [NSAttributedString.Key.foregroundColor: self.placeholderColor]
376+
)
377+
}
378+
360379
if !adjustsFontForContentSizeCategory {
361380
// We should only support dynamic font changes using our own environment
362381
// value if dynamic type support is disabled otherwise we will override
@@ -553,6 +572,11 @@ public extension View {
553572
environment(\.textFieldTextColor, color)
554573
}
555574

575+
/// Sets the text field placeholder text color on any child `ResponsiveTextField` views.
576+
func responsiveTextFieldPlaceholderColor(_ color: UIColor) -> some View {
577+
environment(\.textFieldPlaceholderColor, color)
578+
}
579+
556580
/// Sets the text field text alignment on any child `ResponsiveTextField` views.
557581
func responsiveTextFieldTextAlignment(_ alignment: NSTextAlignment) -> some View {
558582
environment(\.textFieldTextAlignment, alignment)
@@ -603,6 +627,7 @@ struct ResponsiveTextField_Previews: PreviewProvider {
603627
TextFieldPreview(configuration: .email, text: "[email protected]")
604628
.responsiveTextFieldFont(.preferredFont(forTextStyle: .body))
605629
.responsiveTextFieldTextColor(.systemBlue)
630+
.responsiveTextFieldPlaceholderColor(.gray)
606631
.previewLayout(.sizeThatFits)
607632
.environment(\.sizeCategory, .extraExtraExtraLarge)
608633
.previewDisplayName("Dynamic Font Size")

Tests/ResponsiveTextFieldTests/ResponsiveTextFieldTests.swift

+16
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,22 @@ final class ResponsiveTextFieldTests: XCTestCase {
7575
)
7676
}
7777

78+
@MainActor
79+
func testPlaceholderTextFieldWithText() {
80+
assertSnapshot(
81+
of: ResponsiveTextField(
82+
placeholder: "Placeholder Text",
83+
text: .constant("Textfield with some text"),
84+
isSecure: false,
85+
firstResponderDemand: nil,
86+
configuration: .empty
87+
)
88+
.responsiveTextFieldTextColor(UIColor.systemBlue)
89+
.padding(),
90+
as: .fixedSizeTextFieldImage
91+
)
92+
}
93+
7894
@MainActor
7995
func testTextFieldCustomTextAlignment() {
8096
assertSnapshot(

0 commit comments

Comments
 (0)