Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 40 additions & 6 deletions Sources/ComponentsKit/Components/InputField/SUInputField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public struct SUInputField<FocusValue: Hashable>: View {
///
/// When the `localFocus` value matches `globalFocus`, this input field becomes focused.
/// This enables centralized focus management for multiple text inputs and input fields within a single view.
@FocusState.Binding public var globalFocus: FocusValue
public let globalFocus: FocusState<FocusValue>.Binding?

/// The unique value for this field to match against the global focus state to determine whether this input field is focused.
///
Expand All @@ -24,7 +24,7 @@ public struct SUInputField<FocusValue: Hashable>: View {
///
/// - Warning: The `localFocus` value must be unique to each text input and input field, to ensure that different
/// text inputs and input fields within the same view can be independently focused based on the shared `globalFocus`.
public var localFocus: FocusValue
public let localFocus: FocusValue

// MARK: Initialization

Expand All @@ -41,7 +41,7 @@ public struct SUInputField<FocusValue: Hashable>: View {
model: InputFieldVM = .init()
) {
self._text = text
self._globalFocus = globalFocus
self.globalFocus = globalFocus
self.localFocus = localFocus
self.model = model
}
Expand Down Expand Up @@ -71,7 +71,7 @@ public struct SUInputField<FocusValue: Hashable>: View {
.tint(self.model.tintColor.color)
.font(self.model.preferredFont.font)
.foregroundStyle(self.model.foregroundColor.color)
.focused(self.$globalFocus, equals: self.localFocus)
.applyFocus(globalFocus: self.globalFocus, localFocus: self.localFocus)
.disabled(!self.model.isEnabled)
.keyboardType(self.model.keyboardType)
.submitLabel(self.model.submitType.submitLabel)
Expand All @@ -82,7 +82,7 @@ public struct SUInputField<FocusValue: Hashable>: View {
.frame(height: self.model.height)
.background(self.model.backgroundColor.color)
.onTapGesture {
self.globalFocus = self.localFocus
self.globalFocus?.wrappedValue = self.localFocus
}
.clipShape(
RoundedRectangle(
Expand All @@ -92,6 +92,22 @@ public struct SUInputField<FocusValue: Hashable>: View {
}
}

// MARK: Helpers

extension View {
@ViewBuilder
fileprivate func applyFocus<FocusValue: Hashable>(
globalFocus: FocusState<FocusValue>.Binding?,
localFocus: FocusValue,
) -> some View {
if let globalFocus {
self.focused(globalFocus, equals: localFocus)
} else {
self
}
}
}

// MARK: - Boolean Focus Value

extension SUInputField where FocusValue == Bool {
Expand All @@ -106,7 +122,25 @@ extension SUInputField where FocusValue == Bool {
model: InputFieldVM = .init()
) {
self._text = text
self._globalFocus = isFocused
self.globalFocus = isFocused
self.localFocus = true
self.model = model
}
}

// MARK: - No Focus Value

extension SUInputField where FocusValue == Bool {
/// Initializer.
/// - Parameters:
/// - text: A Binding value to control the inputted text.
/// - model: A model that defines the appearance properties.
public init(
text: Binding<String>,
model: InputFieldVM = .init()
) {
self._text = text
self.globalFocus = nil
self.localFocus = true
self.model = model
}
Expand Down
40 changes: 35 additions & 5 deletions Sources/ComponentsKit/Components/TextInput/SUTextInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public struct SUTextInput<FocusValue: Hashable>: View {
///
/// When the `localFocus` value matches `globalFocus`, this text input becomes focused.
/// This enables centralized focus management for multiple text inputs and input fields within a single view.
@FocusState.Binding public var globalFocus: FocusValue
public let globalFocus: FocusState<FocusValue>.Binding?

/// The unique value for this field to match against the global focus state to determine whether this text input is focused.
///
Expand All @@ -24,7 +24,7 @@ public struct SUTextInput<FocusValue: Hashable>: View {
///
/// - Warning: The `localFocus` value must be unique to each text input and input field, to ensure that different
/// text inputs and input fields within the same view can be independently focused based on the shared `globalFocus`.
public var localFocus: FocusValue
public let localFocus: FocusValue

@State private var textEditorPreferredHeight: CGFloat = 0

Expand All @@ -43,7 +43,7 @@ public struct SUTextInput<FocusValue: Hashable>: View {
model: TextInputVM = .init()
) {
self._text = text
self._globalFocus = globalFocus
self.globalFocus = globalFocus
self.localFocus = localFocus
self.model = model
}
Expand All @@ -67,7 +67,7 @@ public struct SUTextInput<FocusValue: Hashable>: View {
.font(self.model.preferredFont.font)
.foregroundStyle(self.model.foregroundColor.color)
.tint(self.model.tintColor.color)
.focused(self.$globalFocus, equals: self.localFocus)
.applyFocus(globalFocus: self.globalFocus, localFocus: self.localFocus)
.disabled(!self.model.isEnabled)
.keyboardType(self.model.keyboardType)
.submitLabel(self.model.submitType.submitLabel)
Expand Down Expand Up @@ -154,6 +154,18 @@ extension View {
UITextView.appearance().textContainer.lineFragmentPadding = 0
}
}

@ViewBuilder
fileprivate func applyFocus<FocusValue: Hashable>(
globalFocus: FocusState<FocusValue>.Binding?,
localFocus: FocusValue,
) -> some View {
if let globalFocus {
self.focused(globalFocus, equals: localFocus)
} else {
self
}
}
}

// MARK: - Boolean Focus Value
Expand All @@ -170,7 +182,25 @@ extension SUTextInput where FocusValue == Bool {
model: TextInputVM = .init()
) {
self._text = text
self._globalFocus = isFocused
self.globalFocus = isFocused
self.localFocus = true
self.model = model
}
}

// MARK: - No Focus Value

extension SUTextInput where FocusValue == Bool {
/// Initializer.
/// - Parameters:
/// - text: A Binding value to control the inputted text.
/// - model: A model that defines the appearance properties.
public init(
text: Binding<String>,
model: TextInputVM = .init()
) {
self._text = text
self.globalFocus = nil
self.localFocus = true
self.model = model
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/ComponentsKit/Components/TextInput/UKTextInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,11 @@ extension UKTextInput {
}

static func textView(_ textView: UITextView, padding: CGFloat) {
textView.textContainerInset = .init(inset: padding)
textView.textContainer.lineFragmentPadding = 0
textView.textContainerInset.top = padding
textView.textContainerInset.left = padding
textView.textContainerInset.right = padding
textView.textContainerInset.bottom = padding
}

static func placeholder(
Expand Down